diff options
Diffstat (limited to 'contrib/llvm/tools/clang/include')
428 files changed, 191901 insertions, 0 deletions
diff --git a/contrib/llvm/tools/clang/include/clang-c/BuildSystem.h b/contrib/llvm/tools/clang/include/clang-c/BuildSystem.h new file mode 100644 index 0000000..8d323a4 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang-c/BuildSystem.h @@ -0,0 +1,156 @@ +/*==-- clang-c/BuildSystem.h - Utilities for use by build systems -*- C -*-===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header provides various utilities for use by build systems. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_CLANG_C_BUILDSYSTEM_H +#define LLVM_CLANG_C_BUILDSYSTEM_H + +#include "clang-c/Platform.h" +#include "clang-c/CXErrorCode.h" +#include "clang-c/CXString.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup BUILD_SYSTEM Build system utilities + * @{ + */ + +/** + * \brief Return the timestamp for use with Clang's + * \c -fbuild-session-timestamp= option. + */ +CINDEX_LINKAGE unsigned long long clang_getBuildSessionTimestamp(void); + +/** + * \brief Object encapsulating information about overlaying virtual + * file/directories over the real file system. + */ +typedef struct CXVirtualFileOverlayImpl *CXVirtualFileOverlay; + +/** + * \brief Create a \c CXVirtualFileOverlay object. + * Must be disposed with \c clang_VirtualFileOverlay_dispose(). + * + * \param options is reserved, always pass 0. + */ +CINDEX_LINKAGE CXVirtualFileOverlay +clang_VirtualFileOverlay_create(unsigned options); + +/** + * \brief Map an absolute virtual file path to an absolute real one. + * The virtual path must be canonicalized (not contain "."/".."). + * \returns 0 for success, non-zero to indicate an error. + */ +CINDEX_LINKAGE enum CXErrorCode +clang_VirtualFileOverlay_addFileMapping(CXVirtualFileOverlay, + const char *virtualPath, + const char *realPath); + +/** + * \brief Set the case sensitivity for the \c CXVirtualFileOverlay object. + * The \c CXVirtualFileOverlay object is case-sensitive by default, this + * option can be used to override the default. + * \returns 0 for success, non-zero to indicate an error. + */ +CINDEX_LINKAGE enum CXErrorCode +clang_VirtualFileOverlay_setCaseSensitivity(CXVirtualFileOverlay, + int caseSensitive); + +/** + * \brief Write out the \c CXVirtualFileOverlay object to a char buffer. + * + * \param options is reserved, always pass 0. + * \param out_buffer_ptr pointer to receive the buffer pointer, which should be + * disposed using \c clang_free(). + * \param out_buffer_size pointer to receive the buffer size. + * \returns 0 for success, non-zero to indicate an error. + */ +CINDEX_LINKAGE enum CXErrorCode +clang_VirtualFileOverlay_writeToBuffer(CXVirtualFileOverlay, unsigned options, + char **out_buffer_ptr, + unsigned *out_buffer_size); + +/** + * \brief free memory allocated by libclang, such as the buffer returned by + * \c CXVirtualFileOverlay() or \c clang_ModuleMapDescriptor_writeToBuffer(). + * + * \param buffer memory pointer to free. + */ +CINDEX_LINKAGE void clang_free(void *buffer); + +/** + * \brief Dispose a \c CXVirtualFileOverlay object. + */ +CINDEX_LINKAGE void clang_VirtualFileOverlay_dispose(CXVirtualFileOverlay); + +/** + * \brief Object encapsulating information about a module.map file. + */ +typedef struct CXModuleMapDescriptorImpl *CXModuleMapDescriptor; + +/** + * \brief Create a \c CXModuleMapDescriptor object. + * Must be disposed with \c clang_ModuleMapDescriptor_dispose(). + * + * \param options is reserved, always pass 0. + */ +CINDEX_LINKAGE CXModuleMapDescriptor +clang_ModuleMapDescriptor_create(unsigned options); + +/** + * \brief Sets the framework module name that the module.map describes. + * \returns 0 for success, non-zero to indicate an error. + */ +CINDEX_LINKAGE enum CXErrorCode +clang_ModuleMapDescriptor_setFrameworkModuleName(CXModuleMapDescriptor, + const char *name); + +/** + * \brief Sets the umbrealla header name that the module.map describes. + * \returns 0 for success, non-zero to indicate an error. + */ +CINDEX_LINKAGE enum CXErrorCode +clang_ModuleMapDescriptor_setUmbrellaHeader(CXModuleMapDescriptor, + const char *name); + +/** + * \brief Write out the \c CXModuleMapDescriptor object to a char buffer. + * + * \param options is reserved, always pass 0. + * \param out_buffer_ptr pointer to receive the buffer pointer, which should be + * disposed using \c clang_free(). + * \param out_buffer_size pointer to receive the buffer size. + * \returns 0 for success, non-zero to indicate an error. + */ +CINDEX_LINKAGE enum CXErrorCode +clang_ModuleMapDescriptor_writeToBuffer(CXModuleMapDescriptor, unsigned options, + char **out_buffer_ptr, + unsigned *out_buffer_size); + +/** + * \brief Dispose a \c CXModuleMapDescriptor object. + */ +CINDEX_LINKAGE void clang_ModuleMapDescriptor_dispose(CXModuleMapDescriptor); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* CLANG_C_BUILD_SYSTEM_H */ + diff --git a/contrib/llvm/tools/clang/include/clang-c/CXCompilationDatabase.h b/contrib/llvm/tools/clang/include/clang-c/CXCompilationDatabase.h new file mode 100644 index 0000000..9359abf --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang-c/CXCompilationDatabase.h @@ -0,0 +1,176 @@ +/*===-- clang-c/CXCompilationDatabase.h - Compilation database ---*- C -*-===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header provides a public inferface to use CompilationDatabase without *| +|* the full Clang C++ API. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_CLANG_C_CXCOMPILATIONDATABASE_H +#define LLVM_CLANG_C_CXCOMPILATIONDATABASE_H + +#include "clang-c/Platform.h" +#include "clang-c/CXString.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup COMPILATIONDB CompilationDatabase functions + * \ingroup CINDEX + * + * @{ + */ + +/** + * A compilation database holds all information used to compile files in a + * project. For each file in the database, it can be queried for the working + * directory or the command line used for the compiler invocation. + * + * Must be freed by \c clang_CompilationDatabase_dispose + */ +typedef void * CXCompilationDatabase; + +/** + * \brief Contains the results of a search in the compilation database + * + * When searching for the compile command for a file, the compilation db can + * return several commands, as the file may have been compiled with + * different options in different places of the project. This choice of compile + * commands is wrapped in this opaque data structure. It must be freed by + * \c clang_CompileCommands_dispose. + */ +typedef void * CXCompileCommands; + +/** + * \brief Represents the command line invocation to compile a specific file. + */ +typedef void * CXCompileCommand; + +/** + * \brief Error codes for Compilation Database + */ +typedef enum { + /* + * \brief No error occurred + */ + CXCompilationDatabase_NoError = 0, + + /* + * \brief Database can not be loaded + */ + CXCompilationDatabase_CanNotLoadDatabase = 1 + +} CXCompilationDatabase_Error; + +/** + * \brief Creates a compilation database from the database found in directory + * buildDir. For example, CMake can output a compile_commands.json which can + * be used to build the database. + * + * It must be freed by \c clang_CompilationDatabase_dispose. + */ +CINDEX_LINKAGE CXCompilationDatabase +clang_CompilationDatabase_fromDirectory(const char *BuildDir, + CXCompilationDatabase_Error *ErrorCode); + +/** + * \brief Free the given compilation database + */ +CINDEX_LINKAGE void +clang_CompilationDatabase_dispose(CXCompilationDatabase); + +/** + * \brief Find the compile commands used for a file. The compile commands + * must be freed by \c clang_CompileCommands_dispose. + */ +CINDEX_LINKAGE CXCompileCommands +clang_CompilationDatabase_getCompileCommands(CXCompilationDatabase, + const char *CompleteFileName); + +/** + * \brief Get all the compile commands in the given compilation database. + */ +CINDEX_LINKAGE CXCompileCommands +clang_CompilationDatabase_getAllCompileCommands(CXCompilationDatabase); + +/** + * \brief Free the given CompileCommands + */ +CINDEX_LINKAGE void clang_CompileCommands_dispose(CXCompileCommands); + +/** + * \brief Get the number of CompileCommand we have for a file + */ +CINDEX_LINKAGE unsigned +clang_CompileCommands_getSize(CXCompileCommands); + +/** + * \brief Get the I'th CompileCommand for a file + * + * Note : 0 <= i < clang_CompileCommands_getSize(CXCompileCommands) + */ +CINDEX_LINKAGE CXCompileCommand +clang_CompileCommands_getCommand(CXCompileCommands, unsigned I); + +/** + * \brief Get the working directory where the CompileCommand was executed from + */ +CINDEX_LINKAGE CXString +clang_CompileCommand_getDirectory(CXCompileCommand); + +/** + * \brief Get the filename associated with the CompileCommand. + */ +CINDEX_LINKAGE CXString +clang_CompileCommand_getFilename(CXCompileCommand); + +/** + * \brief Get the number of arguments in the compiler invocation. + * + */ +CINDEX_LINKAGE unsigned +clang_CompileCommand_getNumArgs(CXCompileCommand); + +/** + * \brief Get the I'th argument value in the compiler invocations + * + * Invariant : + * - argument 0 is the compiler executable + */ +CINDEX_LINKAGE CXString +clang_CompileCommand_getArg(CXCompileCommand, unsigned I); + +/** + * \brief Get the number of source mappings for the compiler invocation. + */ +CINDEX_LINKAGE unsigned +clang_CompileCommand_getNumMappedSources(CXCompileCommand); + +/** + * \brief Get the I'th mapped source path for the compiler invocation. + */ +CINDEX_LINKAGE CXString +clang_CompileCommand_getMappedSourcePath(CXCompileCommand, unsigned I); + +/** + * \brief Get the I'th mapped source content for the compiler invocation. + */ +CINDEX_LINKAGE CXString +clang_CompileCommand_getMappedSourceContent(CXCompileCommand, unsigned I); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/contrib/llvm/tools/clang/include/clang-c/CXErrorCode.h b/contrib/llvm/tools/clang/include/clang-c/CXErrorCode.h new file mode 100644 index 0000000..aff73b7 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang-c/CXErrorCode.h @@ -0,0 +1,64 @@ +/*===-- clang-c/CXErrorCode.h - C Index Error Codes --------------*- C -*-===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header provides the CXErrorCode enumerators. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_CLANG_C_CXERRORCODE_H +#define LLVM_CLANG_C_CXERRORCODE_H + +#include "clang-c/Platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Error codes returned by libclang routines. + * + * Zero (\c CXError_Success) is the only error code indicating success. Other + * error codes, including not yet assigned non-zero values, indicate errors. + */ +enum CXErrorCode { + /** + * \brief No error. + */ + CXError_Success = 0, + + /** + * \brief A generic error code, no further details are available. + * + * Errors of this kind can get their own specific error codes in future + * libclang versions. + */ + CXError_Failure = 1, + + /** + * \brief libclang crashed while performing the requested operation. + */ + CXError_Crashed = 2, + + /** + * \brief The function detected that the arguments violate the function + * contract. + */ + CXError_InvalidArguments = 3, + + /** + * \brief An AST deserialization error has occurred. + */ + CXError_ASTReadError = 4 +}; + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/contrib/llvm/tools/clang/include/clang-c/CXString.h b/contrib/llvm/tools/clang/include/clang-c/CXString.h new file mode 100644 index 0000000..68ab7bc --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang-c/CXString.h @@ -0,0 +1,71 @@ +/*===-- clang-c/CXString.h - C Index strings --------------------*- C -*-===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header provides the interface to C Index strings. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_CLANG_C_CXSTRING_H +#define LLVM_CLANG_C_CXSTRING_H + +#include "clang-c/Platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup CINDEX_STRING String manipulation routines + * \ingroup CINDEX + * + * @{ + */ + +/** + * \brief A character string. + * + * The \c CXString type is used to return strings from the interface when + * the ownership of that string might differ from one call to the next. + * Use \c clang_getCString() to retrieve the string data and, once finished + * with the string data, call \c clang_disposeString() to free the string. + */ +typedef struct { + const void *data; + unsigned private_flags; +} CXString; + +typedef struct { + CXString *Strings; + unsigned Count; +} CXStringSet; + +/** + * \brief Retrieve the character data associated with the given string. + */ +CINDEX_LINKAGE const char *clang_getCString(CXString string); + +/** + * \brief Free the given string. + */ +CINDEX_LINKAGE void clang_disposeString(CXString string); + +/** + * \brief Free the given string set. + */ +CINDEX_LINKAGE void clang_disposeStringSet(CXStringSet *set); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/contrib/llvm/tools/clang/include/clang-c/Documentation.h b/contrib/llvm/tools/clang/include/clang-c/Documentation.h new file mode 100644 index 0000000..89373b1 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang-c/Documentation.h @@ -0,0 +1,554 @@ +/*==-- clang-c/Documentation.h - Utilities for comment processing -*- C -*-===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header provides a supplementary interface for inspecting *| +|* documentation comments. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_CLANG_C_DOCUMENTATION_H +#define LLVM_CLANG_C_DOCUMENTATION_H + +#include "clang-c/Index.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup CINDEX_COMMENT Comment introspection + * + * The routines in this group provide access to information in documentation + * comments. These facilities are distinct from the core and may be subject to + * their own schedule of stability and deprecation. + * + * @{ + */ + +/** + * \brief A parsed comment. + */ +typedef struct { + const void *ASTNode; + CXTranslationUnit TranslationUnit; +} CXComment; + +/** + * \brief Given a cursor that represents a documentable entity (e.g., + * declaration), return the associated parsed comment as a + * \c CXComment_FullComment AST node. + */ +CINDEX_LINKAGE CXComment clang_Cursor_getParsedComment(CXCursor C); + +/** + * \brief Describes the type of the comment AST node (\c CXComment). A comment + * node can be considered block content (e. g., paragraph), inline content + * (plain text) or neither (the root AST node). + */ +enum CXCommentKind { + /** + * \brief Null comment. No AST node is constructed at the requested location + * because there is no text or a syntax error. + */ + CXComment_Null = 0, + + /** + * \brief Plain text. Inline content. + */ + CXComment_Text = 1, + + /** + * \brief A command with word-like arguments that is considered inline content. + * + * For example: \\c command. + */ + CXComment_InlineCommand = 2, + + /** + * \brief HTML start tag with attributes (name-value pairs). Considered + * inline content. + * + * For example: + * \verbatim + * <br> <br /> <a href="http://example.org/"> + * \endverbatim + */ + CXComment_HTMLStartTag = 3, + + /** + * \brief HTML end tag. Considered inline content. + * + * For example: + * \verbatim + * </a> + * \endverbatim + */ + CXComment_HTMLEndTag = 4, + + /** + * \brief A paragraph, contains inline comment. The paragraph itself is + * block content. + */ + CXComment_Paragraph = 5, + + /** + * \brief A command that has zero or more word-like arguments (number of + * word-like arguments depends on command name) and a paragraph as an + * argument. Block command is block content. + * + * Paragraph argument is also a child of the block command. + * + * For example: \\brief has 0 word-like arguments and a paragraph argument. + * + * AST nodes of special kinds that parser knows about (e. g., \\param + * command) have their own node kinds. + */ + CXComment_BlockCommand = 6, + + /** + * \brief A \\param or \\arg command that describes the function parameter + * (name, passing direction, description). + * + * For example: \\param [in] ParamName description. + */ + CXComment_ParamCommand = 7, + + /** + * \brief A \\tparam command that describes a template parameter (name and + * description). + * + * For example: \\tparam T description. + */ + CXComment_TParamCommand = 8, + + /** + * \brief A verbatim block command (e. g., preformatted code). Verbatim + * block has an opening and a closing command and contains multiple lines of + * text (\c CXComment_VerbatimBlockLine child nodes). + * + * For example: + * \\verbatim + * aaa + * \\endverbatim + */ + CXComment_VerbatimBlockCommand = 9, + + /** + * \brief A line of text that is contained within a + * CXComment_VerbatimBlockCommand node. + */ + CXComment_VerbatimBlockLine = 10, + + /** + * \brief A verbatim line command. Verbatim line has an opening command, + * a single line of text (up to the newline after the opening command) and + * has no closing command. + */ + CXComment_VerbatimLine = 11, + + /** + * \brief A full comment attached to a declaration, contains block content. + */ + CXComment_FullComment = 12 +}; + +/** + * \brief The most appropriate rendering mode for an inline command, chosen on + * command semantics in Doxygen. + */ +enum CXCommentInlineCommandRenderKind { + /** + * \brief Command argument should be rendered in a normal font. + */ + CXCommentInlineCommandRenderKind_Normal, + + /** + * \brief Command argument should be rendered in a bold font. + */ + CXCommentInlineCommandRenderKind_Bold, + + /** + * \brief Command argument should be rendered in a monospaced font. + */ + CXCommentInlineCommandRenderKind_Monospaced, + + /** + * \brief Command argument should be rendered emphasized (typically italic + * font). + */ + CXCommentInlineCommandRenderKind_Emphasized +}; + +/** + * \brief Describes parameter passing direction for \\param or \\arg command. + */ +enum CXCommentParamPassDirection { + /** + * \brief The parameter is an input parameter. + */ + CXCommentParamPassDirection_In, + + /** + * \brief The parameter is an output parameter. + */ + CXCommentParamPassDirection_Out, + + /** + * \brief The parameter is an input and output parameter. + */ + CXCommentParamPassDirection_InOut +}; + +/** + * \param Comment AST node of any kind. + * + * \returns the type of the AST node. + */ +CINDEX_LINKAGE enum CXCommentKind clang_Comment_getKind(CXComment Comment); + +/** + * \param Comment AST node of any kind. + * + * \returns number of children of the AST node. + */ +CINDEX_LINKAGE unsigned clang_Comment_getNumChildren(CXComment Comment); + +/** + * \param Comment AST node of any kind. + * + * \param ChildIdx child index (zero-based). + * + * \returns the specified child of the AST node. + */ +CINDEX_LINKAGE +CXComment clang_Comment_getChild(CXComment Comment, unsigned ChildIdx); + +/** + * \brief A \c CXComment_Paragraph node is considered whitespace if it contains + * only \c CXComment_Text nodes that are empty or whitespace. + * + * Other AST nodes (except \c CXComment_Paragraph and \c CXComment_Text) are + * never considered whitespace. + * + * \returns non-zero if \c Comment is whitespace. + */ +CINDEX_LINKAGE unsigned clang_Comment_isWhitespace(CXComment Comment); + +/** + * \returns non-zero if \c Comment is inline content and has a newline + * immediately following it in the comment text. Newlines between paragraphs + * do not count. + */ +CINDEX_LINKAGE +unsigned clang_InlineContentComment_hasTrailingNewline(CXComment Comment); + +/** + * \param Comment a \c CXComment_Text AST node. + * + * \returns text contained in the AST node. + */ +CINDEX_LINKAGE CXString clang_TextComment_getText(CXComment Comment); + +/** + * \param Comment a \c CXComment_InlineCommand AST node. + * + * \returns name of the inline command. + */ +CINDEX_LINKAGE +CXString clang_InlineCommandComment_getCommandName(CXComment Comment); + +/** + * \param Comment a \c CXComment_InlineCommand AST node. + * + * \returns the most appropriate rendering mode, chosen on command + * semantics in Doxygen. + */ +CINDEX_LINKAGE enum CXCommentInlineCommandRenderKind +clang_InlineCommandComment_getRenderKind(CXComment Comment); + +/** + * \param Comment a \c CXComment_InlineCommand AST node. + * + * \returns number of command arguments. + */ +CINDEX_LINKAGE +unsigned clang_InlineCommandComment_getNumArgs(CXComment Comment); + +/** + * \param Comment a \c CXComment_InlineCommand AST node. + * + * \param ArgIdx argument index (zero-based). + * + * \returns text of the specified argument. + */ +CINDEX_LINKAGE +CXString clang_InlineCommandComment_getArgText(CXComment Comment, + unsigned ArgIdx); + +/** + * \param Comment a \c CXComment_HTMLStartTag or \c CXComment_HTMLEndTag AST + * node. + * + * \returns HTML tag name. + */ +CINDEX_LINKAGE CXString clang_HTMLTagComment_getTagName(CXComment Comment); + +/** + * \param Comment a \c CXComment_HTMLStartTag AST node. + * + * \returns non-zero if tag is self-closing (for example, <br />). + */ +CINDEX_LINKAGE +unsigned clang_HTMLStartTagComment_isSelfClosing(CXComment Comment); + +/** + * \param Comment a \c CXComment_HTMLStartTag AST node. + * + * \returns number of attributes (name-value pairs) attached to the start tag. + */ +CINDEX_LINKAGE unsigned clang_HTMLStartTag_getNumAttrs(CXComment Comment); + +/** + * \param Comment a \c CXComment_HTMLStartTag AST node. + * + * \param AttrIdx attribute index (zero-based). + * + * \returns name of the specified attribute. + */ +CINDEX_LINKAGE +CXString clang_HTMLStartTag_getAttrName(CXComment Comment, unsigned AttrIdx); + +/** + * \param Comment a \c CXComment_HTMLStartTag AST node. + * + * \param AttrIdx attribute index (zero-based). + * + * \returns value of the specified attribute. + */ +CINDEX_LINKAGE +CXString clang_HTMLStartTag_getAttrValue(CXComment Comment, unsigned AttrIdx); + +/** + * \param Comment a \c CXComment_BlockCommand AST node. + * + * \returns name of the block command. + */ +CINDEX_LINKAGE +CXString clang_BlockCommandComment_getCommandName(CXComment Comment); + +/** + * \param Comment a \c CXComment_BlockCommand AST node. + * + * \returns number of word-like arguments. + */ +CINDEX_LINKAGE +unsigned clang_BlockCommandComment_getNumArgs(CXComment Comment); + +/** + * \param Comment a \c CXComment_BlockCommand AST node. + * + * \param ArgIdx argument index (zero-based). + * + * \returns text of the specified word-like argument. + */ +CINDEX_LINKAGE +CXString clang_BlockCommandComment_getArgText(CXComment Comment, + unsigned ArgIdx); + +/** + * \param Comment a \c CXComment_BlockCommand or + * \c CXComment_VerbatimBlockCommand AST node. + * + * \returns paragraph argument of the block command. + */ +CINDEX_LINKAGE +CXComment clang_BlockCommandComment_getParagraph(CXComment Comment); + +/** + * \param Comment a \c CXComment_ParamCommand AST node. + * + * \returns parameter name. + */ +CINDEX_LINKAGE +CXString clang_ParamCommandComment_getParamName(CXComment Comment); + +/** + * \param Comment a \c CXComment_ParamCommand AST node. + * + * \returns non-zero if the parameter that this AST node represents was found + * in the function prototype and \c clang_ParamCommandComment_getParamIndex + * function will return a meaningful value. + */ +CINDEX_LINKAGE +unsigned clang_ParamCommandComment_isParamIndexValid(CXComment Comment); + +/** + * \param Comment a \c CXComment_ParamCommand AST node. + * + * \returns zero-based parameter index in function prototype. + */ +CINDEX_LINKAGE +unsigned clang_ParamCommandComment_getParamIndex(CXComment Comment); + +/** + * \param Comment a \c CXComment_ParamCommand AST node. + * + * \returns non-zero if parameter passing direction was specified explicitly in + * the comment. + */ +CINDEX_LINKAGE +unsigned clang_ParamCommandComment_isDirectionExplicit(CXComment Comment); + +/** + * \param Comment a \c CXComment_ParamCommand AST node. + * + * \returns parameter passing direction. + */ +CINDEX_LINKAGE +enum CXCommentParamPassDirection clang_ParamCommandComment_getDirection( + CXComment Comment); + +/** + * \param Comment a \c CXComment_TParamCommand AST node. + * + * \returns template parameter name. + */ +CINDEX_LINKAGE +CXString clang_TParamCommandComment_getParamName(CXComment Comment); + +/** + * \param Comment a \c CXComment_TParamCommand AST node. + * + * \returns non-zero if the parameter that this AST node represents was found + * in the template parameter list and + * \c clang_TParamCommandComment_getDepth and + * \c clang_TParamCommandComment_getIndex functions will return a meaningful + * value. + */ +CINDEX_LINKAGE +unsigned clang_TParamCommandComment_isParamPositionValid(CXComment Comment); + +/** + * \param Comment a \c CXComment_TParamCommand AST node. + * + * \returns zero-based nesting depth of this parameter in the template parameter list. + * + * For example, + * \verbatim + * template<typename C, template<typename T> class TT> + * void test(TT<int> aaa); + * \endverbatim + * for C and TT nesting depth is 0, + * for T nesting depth is 1. + */ +CINDEX_LINKAGE +unsigned clang_TParamCommandComment_getDepth(CXComment Comment); + +/** + * \param Comment a \c CXComment_TParamCommand AST node. + * + * \returns zero-based parameter index in the template parameter list at a + * given nesting depth. + * + * For example, + * \verbatim + * template<typename C, template<typename T> class TT> + * void test(TT<int> aaa); + * \endverbatim + * for C and TT nesting depth is 0, so we can ask for index at depth 0: + * at depth 0 C's index is 0, TT's index is 1. + * + * For T nesting depth is 1, so we can ask for index at depth 0 and 1: + * at depth 0 T's index is 1 (same as TT's), + * at depth 1 T's index is 0. + */ +CINDEX_LINKAGE +unsigned clang_TParamCommandComment_getIndex(CXComment Comment, unsigned Depth); + +/** + * \param Comment a \c CXComment_VerbatimBlockLine AST node. + * + * \returns text contained in the AST node. + */ +CINDEX_LINKAGE +CXString clang_VerbatimBlockLineComment_getText(CXComment Comment); + +/** + * \param Comment a \c CXComment_VerbatimLine AST node. + * + * \returns text contained in the AST node. + */ +CINDEX_LINKAGE CXString clang_VerbatimLineComment_getText(CXComment Comment); + +/** + * \brief Convert an HTML tag AST node to string. + * + * \param Comment a \c CXComment_HTMLStartTag or \c CXComment_HTMLEndTag AST + * node. + * + * \returns string containing an HTML tag. + */ +CINDEX_LINKAGE CXString clang_HTMLTagComment_getAsString(CXComment Comment); + +/** + * \brief Convert a given full parsed comment to an HTML fragment. + * + * Specific details of HTML layout are subject to change. Don't try to parse + * this HTML back into an AST, use other APIs instead. + * + * Currently the following CSS classes are used: + * \li "para-brief" for \\brief paragraph and equivalent commands; + * \li "para-returns" for \\returns paragraph and equivalent commands; + * \li "word-returns" for the "Returns" word in \\returns paragraph. + * + * Function argument documentation is rendered as a \<dl\> list with arguments + * sorted in function prototype order. CSS classes used: + * \li "param-name-index-NUMBER" for parameter name (\<dt\>); + * \li "param-descr-index-NUMBER" for parameter description (\<dd\>); + * \li "param-name-index-invalid" and "param-descr-index-invalid" are used if + * parameter index is invalid. + * + * Template parameter documentation is rendered as a \<dl\> list with + * parameters sorted in template parameter list order. CSS classes used: + * \li "tparam-name-index-NUMBER" for parameter name (\<dt\>); + * \li "tparam-descr-index-NUMBER" for parameter description (\<dd\>); + * \li "tparam-name-index-other" and "tparam-descr-index-other" are used for + * names inside template template parameters; + * \li "tparam-name-index-invalid" and "tparam-descr-index-invalid" are used if + * parameter position is invalid. + * + * \param Comment a \c CXComment_FullComment AST node. + * + * \returns string containing an HTML fragment. + */ +CINDEX_LINKAGE CXString clang_FullComment_getAsHTML(CXComment Comment); + +/** + * \brief Convert a given full parsed comment to an XML document. + * + * A Relax NG schema for the XML can be found in comment-xml-schema.rng file + * inside clang source tree. + * + * \param Comment a \c CXComment_FullComment AST node. + * + * \returns string containing an XML document. + */ +CINDEX_LINKAGE CXString clang_FullComment_getAsXML(CXComment Comment); + +/** + * @} + */ + + +#ifdef __cplusplus +} +#endif + +#endif /* CLANG_C_DOCUMENTATION_H */ + diff --git a/contrib/llvm/tools/clang/include/clang-c/Index.h b/contrib/llvm/tools/clang/include/clang-c/Index.h new file mode 100644 index 0000000..09e2160 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang-c/Index.h @@ -0,0 +1,5835 @@ +/*===-- clang-c/Index.h - Indexing Public C Interface -------------*- C -*-===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header provides a public inferface to a Clang library for extracting *| +|* high-level symbol information from source files without exposing the full *| +|* Clang C++ API. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_CLANG_C_INDEX_H +#define LLVM_CLANG_C_INDEX_H + +#include <time.h> + +#include "clang-c/Platform.h" +#include "clang-c/CXErrorCode.h" +#include "clang-c/CXString.h" +#include "clang-c/BuildSystem.h" + +/** + * \brief The version constants for the libclang API. + * CINDEX_VERSION_MINOR should increase when there are API additions. + * CINDEX_VERSION_MAJOR is intended for "major" source/ABI breaking changes. + * + * The policy about the libclang API was always to keep it source and ABI + * compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable. + */ +#define CINDEX_VERSION_MAJOR 0 +#define CINDEX_VERSION_MINOR 32 + +#define CINDEX_VERSION_ENCODE(major, minor) ( \ + ((major) * 10000) \ + + ((minor) * 1)) + +#define CINDEX_VERSION CINDEX_VERSION_ENCODE( \ + CINDEX_VERSION_MAJOR, \ + CINDEX_VERSION_MINOR ) + +#define CINDEX_VERSION_STRINGIZE_(major, minor) \ + #major"."#minor +#define CINDEX_VERSION_STRINGIZE(major, minor) \ + CINDEX_VERSION_STRINGIZE_(major, minor) + +#define CINDEX_VERSION_STRING CINDEX_VERSION_STRINGIZE( \ + CINDEX_VERSION_MAJOR, \ + CINDEX_VERSION_MINOR) + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup CINDEX libclang: C Interface to Clang + * + * The C Interface to Clang provides a relatively small API that exposes + * facilities for parsing source code into an abstract syntax tree (AST), + * loading already-parsed ASTs, traversing the AST, associating + * physical source locations with elements within the AST, and other + * facilities that support Clang-based development tools. + * + * This C interface to Clang will never provide all of the information + * representation stored in Clang's C++ AST, nor should it: the intent is to + * maintain an API that is relatively stable from one release to the next, + * providing only the basic functionality needed to support development tools. + * + * To avoid namespace pollution, data types are prefixed with "CX" and + * functions are prefixed with "clang_". + * + * @{ + */ + +/** + * \brief An "index" that consists of a set of translation units that would + * typically be linked together into an executable or library. + */ +typedef void *CXIndex; + +/** + * \brief A single translation unit, which resides in an index. + */ +typedef struct CXTranslationUnitImpl *CXTranslationUnit; + +/** + * \brief Opaque pointer representing client data that will be passed through + * to various callbacks and visitors. + */ +typedef void *CXClientData; + +/** + * \brief Provides the contents of a file that has not yet been saved to disk. + * + * Each CXUnsavedFile instance provides the name of a file on the + * system along with the current contents of that file that have not + * yet been saved to disk. + */ +struct CXUnsavedFile { + /** + * \brief The file whose contents have not yet been saved. + * + * This file must already exist in the file system. + */ + const char *Filename; + + /** + * \brief A buffer containing the unsaved contents of this file. + */ + const char *Contents; + + /** + * \brief The length of the unsaved contents of this buffer. + */ + unsigned long Length; +}; + +/** + * \brief Describes the availability of a particular entity, which indicates + * whether the use of this entity will result in a warning or error due to + * it being deprecated or unavailable. + */ +enum CXAvailabilityKind { + /** + * \brief The entity is available. + */ + CXAvailability_Available, + /** + * \brief The entity is available, but has been deprecated (and its use is + * not recommended). + */ + CXAvailability_Deprecated, + /** + * \brief The entity is not available; any use of it will be an error. + */ + CXAvailability_NotAvailable, + /** + * \brief The entity is available, but not accessible; any use of it will be + * an error. + */ + CXAvailability_NotAccessible +}; + +/** + * \brief Describes a version number of the form major.minor.subminor. + */ +typedef struct CXVersion { + /** + * \brief The major version number, e.g., the '10' in '10.7.3'. A negative + * value indicates that there is no version number at all. + */ + int Major; + /** + * \brief The minor version number, e.g., the '7' in '10.7.3'. This value + * will be negative if no minor version number was provided, e.g., for + * version '10'. + */ + int Minor; + /** + * \brief The subminor version number, e.g., the '3' in '10.7.3'. This value + * will be negative if no minor or subminor version number was provided, + * e.g., in version '10' or '10.7'. + */ + int Subminor; +} CXVersion; + +/** + * \brief Provides a shared context for creating translation units. + * + * It provides two options: + * + * - excludeDeclarationsFromPCH: When non-zero, allows enumeration of "local" + * declarations (when loading any new translation units). A "local" declaration + * is one that belongs in the translation unit itself and not in a precompiled + * header that was used by the translation unit. If zero, all declarations + * will be enumerated. + * + * Here is an example: + * + * \code + * // excludeDeclsFromPCH = 1, displayDiagnostics=1 + * Idx = clang_createIndex(1, 1); + * + * // IndexTest.pch was produced with the following command: + * // "clang -x c IndexTest.h -emit-ast -o IndexTest.pch" + * TU = clang_createTranslationUnit(Idx, "IndexTest.pch"); + * + * // This will load all the symbols from 'IndexTest.pch' + * clang_visitChildren(clang_getTranslationUnitCursor(TU), + * TranslationUnitVisitor, 0); + * clang_disposeTranslationUnit(TU); + * + * // This will load all the symbols from 'IndexTest.c', excluding symbols + * // from 'IndexTest.pch'. + * char *args[] = { "-Xclang", "-include-pch=IndexTest.pch" }; + * TU = clang_createTranslationUnitFromSourceFile(Idx, "IndexTest.c", 2, args, + * 0, 0); + * clang_visitChildren(clang_getTranslationUnitCursor(TU), + * TranslationUnitVisitor, 0); + * clang_disposeTranslationUnit(TU); + * \endcode + * + * This process of creating the 'pch', loading it separately, and using it (via + * -include-pch) allows 'excludeDeclsFromPCH' to remove redundant callbacks + * (which gives the indexer the same performance benefit as the compiler). + */ +CINDEX_LINKAGE CXIndex clang_createIndex(int excludeDeclarationsFromPCH, + int displayDiagnostics); + +/** + * \brief Destroy the given index. + * + * The index must not be destroyed until all of the translation units created + * within that index have been destroyed. + */ +CINDEX_LINKAGE void clang_disposeIndex(CXIndex index); + +typedef enum { + /** + * \brief Used to indicate that no special CXIndex options are needed. + */ + CXGlobalOpt_None = 0x0, + + /** + * \brief Used to indicate that threads that libclang creates for indexing + * purposes should use background priority. + * + * Affects #clang_indexSourceFile, #clang_indexTranslationUnit, + * #clang_parseTranslationUnit, #clang_saveTranslationUnit. + */ + CXGlobalOpt_ThreadBackgroundPriorityForIndexing = 0x1, + + /** + * \brief Used to indicate that threads that libclang creates for editing + * purposes should use background priority. + * + * Affects #clang_reparseTranslationUnit, #clang_codeCompleteAt, + * #clang_annotateTokens + */ + CXGlobalOpt_ThreadBackgroundPriorityForEditing = 0x2, + + /** + * \brief Used to indicate that all threads that libclang creates should use + * background priority. + */ + CXGlobalOpt_ThreadBackgroundPriorityForAll = + CXGlobalOpt_ThreadBackgroundPriorityForIndexing | + CXGlobalOpt_ThreadBackgroundPriorityForEditing + +} CXGlobalOptFlags; + +/** + * \brief Sets general options associated with a CXIndex. + * + * For example: + * \code + * CXIndex idx = ...; + * clang_CXIndex_setGlobalOptions(idx, + * clang_CXIndex_getGlobalOptions(idx) | + * CXGlobalOpt_ThreadBackgroundPriorityForIndexing); + * \endcode + * + * \param options A bitmask of options, a bitwise OR of CXGlobalOpt_XXX flags. + */ +CINDEX_LINKAGE void clang_CXIndex_setGlobalOptions(CXIndex, unsigned options); + +/** + * \brief Gets the general options associated with a CXIndex. + * + * \returns A bitmask of options, a bitwise OR of CXGlobalOpt_XXX flags that + * are associated with the given CXIndex object. + */ +CINDEX_LINKAGE unsigned clang_CXIndex_getGlobalOptions(CXIndex); + +/** + * \defgroup CINDEX_FILES File manipulation routines + * + * @{ + */ + +/** + * \brief A particular source file that is part of a translation unit. + */ +typedef void *CXFile; + +/** + * \brief Retrieve the complete file and path name of the given file. + */ +CINDEX_LINKAGE CXString clang_getFileName(CXFile SFile); + +/** + * \brief Retrieve the last modification time of the given file. + */ +CINDEX_LINKAGE time_t clang_getFileTime(CXFile SFile); + +/** + * \brief Uniquely identifies a CXFile, that refers to the same underlying file, + * across an indexing session. + */ +typedef struct { + unsigned long long data[3]; +} CXFileUniqueID; + +/** + * \brief Retrieve the unique ID for the given \c file. + * + * \param file the file to get the ID for. + * \param outID stores the returned CXFileUniqueID. + * \returns If there was a failure getting the unique ID, returns non-zero, + * otherwise returns 0. +*/ +CINDEX_LINKAGE int clang_getFileUniqueID(CXFile file, CXFileUniqueID *outID); + +/** + * \brief Determine whether the given header is guarded against + * multiple inclusions, either with the conventional + * \#ifndef/\#define/\#endif macro guards or with \#pragma once. + */ +CINDEX_LINKAGE unsigned +clang_isFileMultipleIncludeGuarded(CXTranslationUnit tu, CXFile file); + +/** + * \brief Retrieve a file handle within the given translation unit. + * + * \param tu the translation unit + * + * \param file_name the name of the file. + * + * \returns the file handle for the named file in the translation unit \p tu, + * or a NULL file handle if the file was not a part of this translation unit. + */ +CINDEX_LINKAGE CXFile clang_getFile(CXTranslationUnit tu, + const char *file_name); + +/** + * \brief Returns non-zero if the \c file1 and \c file2 point to the same file, + * or they are both NULL. + */ +CINDEX_LINKAGE int clang_File_isEqual(CXFile file1, CXFile file2); + +/** + * @} + */ + +/** + * \defgroup CINDEX_LOCATIONS Physical source locations + * + * Clang represents physical source locations in its abstract syntax tree in + * great detail, with file, line, and column information for the majority of + * the tokens parsed in the source code. These data types and functions are + * used to represent source location information, either for a particular + * point in the program or for a range of points in the program, and extract + * specific location information from those data types. + * + * @{ + */ + +/** + * \brief Identifies a specific source location within a translation + * unit. + * + * Use clang_getExpansionLocation() or clang_getSpellingLocation() + * to map a source location to a particular file, line, and column. + */ +typedef struct { + const void *ptr_data[2]; + unsigned int_data; +} CXSourceLocation; + +/** + * \brief Identifies a half-open character range in the source code. + * + * Use clang_getRangeStart() and clang_getRangeEnd() to retrieve the + * starting and end locations from a source range, respectively. + */ +typedef struct { + const void *ptr_data[2]; + unsigned begin_int_data; + unsigned end_int_data; +} CXSourceRange; + +/** + * \brief Retrieve a NULL (invalid) source location. + */ +CINDEX_LINKAGE CXSourceLocation clang_getNullLocation(void); + +/** + * \brief Determine whether two source locations, which must refer into + * the same translation unit, refer to exactly the same point in the source + * code. + * + * \returns non-zero if the source locations refer to the same location, zero + * if they refer to different locations. + */ +CINDEX_LINKAGE unsigned clang_equalLocations(CXSourceLocation loc1, + CXSourceLocation loc2); + +/** + * \brief Retrieves the source location associated with a given file/line/column + * in a particular translation unit. + */ +CINDEX_LINKAGE CXSourceLocation clang_getLocation(CXTranslationUnit tu, + CXFile file, + unsigned line, + unsigned column); +/** + * \brief Retrieves the source location associated with a given character offset + * in a particular translation unit. + */ +CINDEX_LINKAGE CXSourceLocation clang_getLocationForOffset(CXTranslationUnit tu, + CXFile file, + unsigned offset); + +/** + * \brief Returns non-zero if the given source location is in a system header. + */ +CINDEX_LINKAGE int clang_Location_isInSystemHeader(CXSourceLocation location); + +/** + * \brief Returns non-zero if the given source location is in the main file of + * the corresponding translation unit. + */ +CINDEX_LINKAGE int clang_Location_isFromMainFile(CXSourceLocation location); + +/** + * \brief Retrieve a NULL (invalid) source range. + */ +CINDEX_LINKAGE CXSourceRange clang_getNullRange(void); + +/** + * \brief Retrieve a source range given the beginning and ending source + * locations. + */ +CINDEX_LINKAGE CXSourceRange clang_getRange(CXSourceLocation begin, + CXSourceLocation end); + +/** + * \brief Determine whether two ranges are equivalent. + * + * \returns non-zero if the ranges are the same, zero if they differ. + */ +CINDEX_LINKAGE unsigned clang_equalRanges(CXSourceRange range1, + CXSourceRange range2); + +/** + * \brief Returns non-zero if \p range is null. + */ +CINDEX_LINKAGE int clang_Range_isNull(CXSourceRange range); + +/** + * \brief Retrieve the file, line, column, and offset represented by + * the given source location. + * + * If the location refers into a macro expansion, retrieves the + * location of the macro expansion. + * + * \param location the location within a source file that will be decomposed + * into its parts. + * + * \param file [out] if non-NULL, will be set to the file to which the given + * source location points. + * + * \param line [out] if non-NULL, will be set to the line to which the given + * source location points. + * + * \param column [out] if non-NULL, will be set to the column to which the given + * source location points. + * + * \param offset [out] if non-NULL, will be set to the offset into the + * buffer to which the given source location points. + */ +CINDEX_LINKAGE void clang_getExpansionLocation(CXSourceLocation location, + CXFile *file, + unsigned *line, + unsigned *column, + unsigned *offset); + +/** + * \brief Retrieve the file, line, column, and offset represented by + * the given source location, as specified in a # line directive. + * + * Example: given the following source code in a file somefile.c + * + * \code + * #123 "dummy.c" 1 + * + * static int func(void) + * { + * return 0; + * } + * \endcode + * + * the location information returned by this function would be + * + * File: dummy.c Line: 124 Column: 12 + * + * whereas clang_getExpansionLocation would have returned + * + * File: somefile.c Line: 3 Column: 12 + * + * \param location the location within a source file that will be decomposed + * into its parts. + * + * \param filename [out] if non-NULL, will be set to the filename of the + * source location. Note that filenames returned will be for "virtual" files, + * which don't necessarily exist on the machine running clang - e.g. when + * parsing preprocessed output obtained from a different environment. If + * a non-NULL value is passed in, remember to dispose of the returned value + * using \c clang_disposeString() once you've finished with it. For an invalid + * source location, an empty string is returned. + * + * \param line [out] if non-NULL, will be set to the line number of the + * source location. For an invalid source location, zero is returned. + * + * \param column [out] if non-NULL, will be set to the column number of the + * source location. For an invalid source location, zero is returned. + */ +CINDEX_LINKAGE void clang_getPresumedLocation(CXSourceLocation location, + CXString *filename, + unsigned *line, + unsigned *column); + +/** + * \brief Legacy API to retrieve the file, line, column, and offset represented + * by the given source location. + * + * This interface has been replaced by the newer interface + * #clang_getExpansionLocation(). See that interface's documentation for + * details. + */ +CINDEX_LINKAGE void clang_getInstantiationLocation(CXSourceLocation location, + CXFile *file, + unsigned *line, + unsigned *column, + unsigned *offset); + +/** + * \brief Retrieve the file, line, column, and offset represented by + * the given source location. + * + * If the location refers into a macro instantiation, return where the + * location was originally spelled in the source file. + * + * \param location the location within a source file that will be decomposed + * into its parts. + * + * \param file [out] if non-NULL, will be set to the file to which the given + * source location points. + * + * \param line [out] if non-NULL, will be set to the line to which the given + * source location points. + * + * \param column [out] if non-NULL, will be set to the column to which the given + * source location points. + * + * \param offset [out] if non-NULL, will be set to the offset into the + * buffer to which the given source location points. + */ +CINDEX_LINKAGE void clang_getSpellingLocation(CXSourceLocation location, + CXFile *file, + unsigned *line, + unsigned *column, + unsigned *offset); + +/** + * \brief Retrieve the file, line, column, and offset represented by + * the given source location. + * + * If the location refers into a macro expansion, return where the macro was + * expanded or where the macro argument was written, if the location points at + * a macro argument. + * + * \param location the location within a source file that will be decomposed + * into its parts. + * + * \param file [out] if non-NULL, will be set to the file to which the given + * source location points. + * + * \param line [out] if non-NULL, will be set to the line to which the given + * source location points. + * + * \param column [out] if non-NULL, will be set to the column to which the given + * source location points. + * + * \param offset [out] if non-NULL, will be set to the offset into the + * buffer to which the given source location points. + */ +CINDEX_LINKAGE void clang_getFileLocation(CXSourceLocation location, + CXFile *file, + unsigned *line, + unsigned *column, + unsigned *offset); + +/** + * \brief Retrieve a source location representing the first character within a + * source range. + */ +CINDEX_LINKAGE CXSourceLocation clang_getRangeStart(CXSourceRange range); + +/** + * \brief Retrieve a source location representing the last character within a + * source range. + */ +CINDEX_LINKAGE CXSourceLocation clang_getRangeEnd(CXSourceRange range); + +/** + * \brief Identifies an array of ranges. + */ +typedef struct { + /** \brief The number of ranges in the \c ranges array. */ + unsigned count; + /** + * \brief An array of \c CXSourceRanges. + */ + CXSourceRange *ranges; +} CXSourceRangeList; + +/** + * \brief Retrieve all ranges that were skipped by the preprocessor. + * + * The preprocessor will skip lines when they are surrounded by an + * if/ifdef/ifndef directive whose condition does not evaluate to true. + */ +CINDEX_LINKAGE CXSourceRangeList *clang_getSkippedRanges(CXTranslationUnit tu, + CXFile file); + +/** + * \brief Destroy the given \c CXSourceRangeList. + */ +CINDEX_LINKAGE void clang_disposeSourceRangeList(CXSourceRangeList *ranges); + +/** + * @} + */ + +/** + * \defgroup CINDEX_DIAG Diagnostic reporting + * + * @{ + */ + +/** + * \brief Describes the severity of a particular diagnostic. + */ +enum CXDiagnosticSeverity { + /** + * \brief A diagnostic that has been suppressed, e.g., by a command-line + * option. + */ + CXDiagnostic_Ignored = 0, + + /** + * \brief This diagnostic is a note that should be attached to the + * previous (non-note) diagnostic. + */ + CXDiagnostic_Note = 1, + + /** + * \brief This diagnostic indicates suspicious code that may not be + * wrong. + */ + CXDiagnostic_Warning = 2, + + /** + * \brief This diagnostic indicates that the code is ill-formed. + */ + CXDiagnostic_Error = 3, + + /** + * \brief This diagnostic indicates that the code is ill-formed such + * that future parser recovery is unlikely to produce useful + * results. + */ + CXDiagnostic_Fatal = 4 +}; + +/** + * \brief A single diagnostic, containing the diagnostic's severity, + * location, text, source ranges, and fix-it hints. + */ +typedef void *CXDiagnostic; + +/** + * \brief A group of CXDiagnostics. + */ +typedef void *CXDiagnosticSet; + +/** + * \brief Determine the number of diagnostics in a CXDiagnosticSet. + */ +CINDEX_LINKAGE unsigned clang_getNumDiagnosticsInSet(CXDiagnosticSet Diags); + +/** + * \brief Retrieve a diagnostic associated with the given CXDiagnosticSet. + * + * \param Diags the CXDiagnosticSet to query. + * \param Index the zero-based diagnostic number to retrieve. + * + * \returns the requested diagnostic. This diagnostic must be freed + * via a call to \c clang_disposeDiagnostic(). + */ +CINDEX_LINKAGE CXDiagnostic clang_getDiagnosticInSet(CXDiagnosticSet Diags, + unsigned Index); + +/** + * \brief Describes the kind of error that occurred (if any) in a call to + * \c clang_loadDiagnostics. + */ +enum CXLoadDiag_Error { + /** + * \brief Indicates that no error occurred. + */ + CXLoadDiag_None = 0, + + /** + * \brief Indicates that an unknown error occurred while attempting to + * deserialize diagnostics. + */ + CXLoadDiag_Unknown = 1, + + /** + * \brief Indicates that the file containing the serialized diagnostics + * could not be opened. + */ + CXLoadDiag_CannotLoad = 2, + + /** + * \brief Indicates that the serialized diagnostics file is invalid or + * corrupt. + */ + CXLoadDiag_InvalidFile = 3 +}; + +/** + * \brief Deserialize a set of diagnostics from a Clang diagnostics bitcode + * file. + * + * \param file The name of the file to deserialize. + * \param error A pointer to a enum value recording if there was a problem + * deserializing the diagnostics. + * \param errorString A pointer to a CXString for recording the error string + * if the file was not successfully loaded. + * + * \returns A loaded CXDiagnosticSet if successful, and NULL otherwise. These + * diagnostics should be released using clang_disposeDiagnosticSet(). + */ +CINDEX_LINKAGE CXDiagnosticSet clang_loadDiagnostics(const char *file, + enum CXLoadDiag_Error *error, + CXString *errorString); + +/** + * \brief Release a CXDiagnosticSet and all of its contained diagnostics. + */ +CINDEX_LINKAGE void clang_disposeDiagnosticSet(CXDiagnosticSet Diags); + +/** + * \brief Retrieve the child diagnostics of a CXDiagnostic. + * + * This CXDiagnosticSet does not need to be released by + * clang_disposeDiagnosticSet. + */ +CINDEX_LINKAGE CXDiagnosticSet clang_getChildDiagnostics(CXDiagnostic D); + +/** + * \brief Determine the number of diagnostics produced for the given + * translation unit. + */ +CINDEX_LINKAGE unsigned clang_getNumDiagnostics(CXTranslationUnit Unit); + +/** + * \brief Retrieve a diagnostic associated with the given translation unit. + * + * \param Unit the translation unit to query. + * \param Index the zero-based diagnostic number to retrieve. + * + * \returns the requested diagnostic. This diagnostic must be freed + * via a call to \c clang_disposeDiagnostic(). + */ +CINDEX_LINKAGE CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit, + unsigned Index); + +/** + * \brief Retrieve the complete set of diagnostics associated with a + * translation unit. + * + * \param Unit the translation unit to query. + */ +CINDEX_LINKAGE CXDiagnosticSet + clang_getDiagnosticSetFromTU(CXTranslationUnit Unit); + +/** + * \brief Destroy a diagnostic. + */ +CINDEX_LINKAGE void clang_disposeDiagnostic(CXDiagnostic Diagnostic); + +/** + * \brief Options to control the display of diagnostics. + * + * The values in this enum are meant to be combined to customize the + * behavior of \c clang_formatDiagnostic(). + */ +enum CXDiagnosticDisplayOptions { + /** + * \brief Display the source-location information where the + * diagnostic was located. + * + * When set, diagnostics will be prefixed by the file, line, and + * (optionally) column to which the diagnostic refers. For example, + * + * \code + * test.c:28: warning: extra tokens at end of #endif directive + * \endcode + * + * This option corresponds to the clang flag \c -fshow-source-location. + */ + CXDiagnostic_DisplaySourceLocation = 0x01, + + /** + * \brief If displaying the source-location information of the + * diagnostic, also include the column number. + * + * This option corresponds to the clang flag \c -fshow-column. + */ + CXDiagnostic_DisplayColumn = 0x02, + + /** + * \brief If displaying the source-location information of the + * diagnostic, also include information about source ranges in a + * machine-parsable format. + * + * This option corresponds to the clang flag + * \c -fdiagnostics-print-source-range-info. + */ + CXDiagnostic_DisplaySourceRanges = 0x04, + + /** + * \brief Display the option name associated with this diagnostic, if any. + * + * The option name displayed (e.g., -Wconversion) will be placed in brackets + * after the diagnostic text. This option corresponds to the clang flag + * \c -fdiagnostics-show-option. + */ + CXDiagnostic_DisplayOption = 0x08, + + /** + * \brief Display the category number associated with this diagnostic, if any. + * + * The category number is displayed within brackets after the diagnostic text. + * This option corresponds to the clang flag + * \c -fdiagnostics-show-category=id. + */ + CXDiagnostic_DisplayCategoryId = 0x10, + + /** + * \brief Display the category name associated with this diagnostic, if any. + * + * The category name is displayed within brackets after the diagnostic text. + * This option corresponds to the clang flag + * \c -fdiagnostics-show-category=name. + */ + CXDiagnostic_DisplayCategoryName = 0x20 +}; + +/** + * \brief Format the given diagnostic in a manner that is suitable for display. + * + * This routine will format the given diagnostic to a string, rendering + * the diagnostic according to the various options given. The + * \c clang_defaultDiagnosticDisplayOptions() function returns the set of + * options that most closely mimics the behavior of the clang compiler. + * + * \param Diagnostic The diagnostic to print. + * + * \param Options A set of options that control the diagnostic display, + * created by combining \c CXDiagnosticDisplayOptions values. + * + * \returns A new string containing for formatted diagnostic. + */ +CINDEX_LINKAGE CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, + unsigned Options); + +/** + * \brief Retrieve the set of display options most similar to the + * default behavior of the clang compiler. + * + * \returns A set of display options suitable for use with \c + * clang_formatDiagnostic(). + */ +CINDEX_LINKAGE unsigned clang_defaultDiagnosticDisplayOptions(void); + +/** + * \brief Determine the severity of the given diagnostic. + */ +CINDEX_LINKAGE enum CXDiagnosticSeverity +clang_getDiagnosticSeverity(CXDiagnostic); + +/** + * \brief Retrieve the source location of the given diagnostic. + * + * This location is where Clang would print the caret ('^') when + * displaying the diagnostic on the command line. + */ +CINDEX_LINKAGE CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic); + +/** + * \brief Retrieve the text of the given diagnostic. + */ +CINDEX_LINKAGE CXString clang_getDiagnosticSpelling(CXDiagnostic); + +/** + * \brief Retrieve the name of the command-line option that enabled this + * diagnostic. + * + * \param Diag The diagnostic to be queried. + * + * \param Disable If non-NULL, will be set to the option that disables this + * diagnostic (if any). + * + * \returns A string that contains the command-line option used to enable this + * warning, such as "-Wconversion" or "-pedantic". + */ +CINDEX_LINKAGE CXString clang_getDiagnosticOption(CXDiagnostic Diag, + CXString *Disable); + +/** + * \brief Retrieve the category number for this diagnostic. + * + * Diagnostics can be categorized into groups along with other, related + * diagnostics (e.g., diagnostics under the same warning flag). This routine + * retrieves the category number for the given diagnostic. + * + * \returns The number of the category that contains this diagnostic, or zero + * if this diagnostic is uncategorized. + */ +CINDEX_LINKAGE unsigned clang_getDiagnosticCategory(CXDiagnostic); + +/** + * \brief Retrieve the name of a particular diagnostic category. This + * is now deprecated. Use clang_getDiagnosticCategoryText() + * instead. + * + * \param Category A diagnostic category number, as returned by + * \c clang_getDiagnosticCategory(). + * + * \returns The name of the given diagnostic category. + */ +CINDEX_DEPRECATED CINDEX_LINKAGE +CXString clang_getDiagnosticCategoryName(unsigned Category); + +/** + * \brief Retrieve the diagnostic category text for a given diagnostic. + * + * \returns The text of the given diagnostic category. + */ +CINDEX_LINKAGE CXString clang_getDiagnosticCategoryText(CXDiagnostic); + +/** + * \brief Determine the number of source ranges associated with the given + * diagnostic. + */ +CINDEX_LINKAGE unsigned clang_getDiagnosticNumRanges(CXDiagnostic); + +/** + * \brief Retrieve a source range associated with the diagnostic. + * + * A diagnostic's source ranges highlight important elements in the source + * code. On the command line, Clang displays source ranges by + * underlining them with '~' characters. + * + * \param Diagnostic the diagnostic whose range is being extracted. + * + * \param Range the zero-based index specifying which range to + * + * \returns the requested source range. + */ +CINDEX_LINKAGE CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diagnostic, + unsigned Range); + +/** + * \brief Determine the number of fix-it hints associated with the + * given diagnostic. + */ +CINDEX_LINKAGE unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diagnostic); + +/** + * \brief Retrieve the replacement information for a given fix-it. + * + * Fix-its are described in terms of a source range whose contents + * should be replaced by a string. This approach generalizes over + * three kinds of operations: removal of source code (the range covers + * the code to be removed and the replacement string is empty), + * replacement of source code (the range covers the code to be + * replaced and the replacement string provides the new code), and + * insertion (both the start and end of the range point at the + * insertion location, and the replacement string provides the text to + * insert). + * + * \param Diagnostic The diagnostic whose fix-its are being queried. + * + * \param FixIt The zero-based index of the fix-it. + * + * \param ReplacementRange The source range whose contents will be + * replaced with the returned replacement string. Note that source + * ranges are half-open ranges [a, b), so the source code should be + * replaced from a and up to (but not including) b. + * + * \returns A string containing text that should be replace the source + * code indicated by the \c ReplacementRange. + */ +CINDEX_LINKAGE CXString clang_getDiagnosticFixIt(CXDiagnostic Diagnostic, + unsigned FixIt, + CXSourceRange *ReplacementRange); + +/** + * @} + */ + +/** + * \defgroup CINDEX_TRANSLATION_UNIT Translation unit manipulation + * + * The routines in this group provide the ability to create and destroy + * translation units from files, either by parsing the contents of the files or + * by reading in a serialized representation of a translation unit. + * + * @{ + */ + +/** + * \brief Get the original translation unit source file name. + */ +CINDEX_LINKAGE CXString +clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit); + +/** + * \brief Return the CXTranslationUnit for a given source file and the provided + * command line arguments one would pass to the compiler. + * + * Note: The 'source_filename' argument is optional. If the caller provides a + * NULL pointer, the name of the source file is expected to reside in the + * specified command line arguments. + * + * Note: When encountered in 'clang_command_line_args', the following options + * are ignored: + * + * '-c' + * '-emit-ast' + * '-fsyntax-only' + * '-o \<output file>' (both '-o' and '\<output file>' are ignored) + * + * \param CIdx The index object with which the translation unit will be + * associated. + * + * \param source_filename The name of the source file to load, or NULL if the + * source file is included in \p clang_command_line_args. + * + * \param num_clang_command_line_args The number of command-line arguments in + * \p clang_command_line_args. + * + * \param clang_command_line_args The command-line arguments that would be + * passed to the \c clang executable if it were being invoked out-of-process. + * These command-line options will be parsed and will affect how the translation + * unit is parsed. Note that the following options are ignored: '-c', + * '-emit-ast', '-fsyntax-only' (which is the default), and '-o \<output file>'. + * + * \param num_unsaved_files the number of unsaved file entries in \p + * unsaved_files. + * + * \param unsaved_files the files that have not yet been saved to disk + * but may be required for code completion, including the contents of + * those files. The contents and name of these files (as specified by + * CXUnsavedFile) are copied when necessary, so the client only needs to + * guarantee their validity until the call to this function returns. + */ +CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnitFromSourceFile( + CXIndex CIdx, + const char *source_filename, + int num_clang_command_line_args, + const char * const *clang_command_line_args, + unsigned num_unsaved_files, + struct CXUnsavedFile *unsaved_files); + +/** + * \brief Same as \c clang_createTranslationUnit2, but returns + * the \c CXTranslationUnit instead of an error code. In case of an error this + * routine returns a \c NULL \c CXTranslationUnit, without further detailed + * error codes. + */ +CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnit( + CXIndex CIdx, + const char *ast_filename); + +/** + * \brief Create a translation unit from an AST file (\c -emit-ast). + * + * \param[out] out_TU A non-NULL pointer to store the created + * \c CXTranslationUnit. + * + * \returns Zero on success, otherwise returns an error code. + */ +CINDEX_LINKAGE enum CXErrorCode clang_createTranslationUnit2( + CXIndex CIdx, + const char *ast_filename, + CXTranslationUnit *out_TU); + +/** + * \brief Flags that control the creation of translation units. + * + * The enumerators in this enumeration type are meant to be bitwise + * ORed together to specify which options should be used when + * constructing the translation unit. + */ +enum CXTranslationUnit_Flags { + /** + * \brief Used to indicate that no special translation-unit options are + * needed. + */ + CXTranslationUnit_None = 0x0, + + /** + * \brief Used to indicate that the parser should construct a "detailed" + * preprocessing record, including all macro definitions and instantiations. + * + * Constructing a detailed preprocessing record requires more memory + * and time to parse, since the information contained in the record + * is usually not retained. However, it can be useful for + * applications that require more detailed information about the + * behavior of the preprocessor. + */ + CXTranslationUnit_DetailedPreprocessingRecord = 0x01, + + /** + * \brief Used to indicate that the translation unit is incomplete. + * + * When a translation unit is considered "incomplete", semantic + * analysis that is typically performed at the end of the + * translation unit will be suppressed. For example, this suppresses + * the completion of tentative declarations in C and of + * instantiation of implicitly-instantiation function templates in + * C++. This option is typically used when parsing a header with the + * intent of producing a precompiled header. + */ + CXTranslationUnit_Incomplete = 0x02, + + /** + * \brief Used to indicate that the translation unit should be built with an + * implicit precompiled header for the preamble. + * + * An implicit precompiled header is used as an optimization when a + * particular translation unit is likely to be reparsed many times + * when the sources aren't changing that often. In this case, an + * implicit precompiled header will be built containing all of the + * initial includes at the top of the main file (what we refer to as + * the "preamble" of the file). In subsequent parses, if the + * preamble or the files in it have not changed, \c + * clang_reparseTranslationUnit() will re-use the implicit + * precompiled header to improve parsing performance. + */ + CXTranslationUnit_PrecompiledPreamble = 0x04, + + /** + * \brief Used to indicate that the translation unit should cache some + * code-completion results with each reparse of the source file. + * + * Caching of code-completion results is a performance optimization that + * introduces some overhead to reparsing but improves the performance of + * code-completion operations. + */ + CXTranslationUnit_CacheCompletionResults = 0x08, + + /** + * \brief Used to indicate that the translation unit will be serialized with + * \c clang_saveTranslationUnit. + * + * This option is typically used when parsing a header with the intent of + * producing a precompiled header. + */ + CXTranslationUnit_ForSerialization = 0x10, + + /** + * \brief DEPRECATED: Enabled chained precompiled preambles in C++. + * + * Note: this is a *temporary* option that is available only while + * we are testing C++ precompiled preamble support. It is deprecated. + */ + CXTranslationUnit_CXXChainedPCH = 0x20, + + /** + * \brief Used to indicate that function/method bodies should be skipped while + * parsing. + * + * This option can be used to search for declarations/definitions while + * ignoring the usages. + */ + CXTranslationUnit_SkipFunctionBodies = 0x40, + + /** + * \brief Used to indicate that brief documentation comments should be + * included into the set of code completions returned from this translation + * unit. + */ + CXTranslationUnit_IncludeBriefCommentsInCodeCompletion = 0x80, + + /** + * \brief Used to indicate that the precompiled preamble should be created on + * the first parse. Otherwise it will be created on the first reparse. This + * trades runtime on the first parse (serializing the preamble takes time) for + * reduced runtime on the second parse (can now reuse the preamble). + */ + CXTranslationUnit_CreatePreambleOnFirstParse = 0x100 +}; + +/** + * \brief Returns the set of flags that is suitable for parsing a translation + * unit that is being edited. + * + * The set of flags returned provide options for \c clang_parseTranslationUnit() + * to indicate that the translation unit is likely to be reparsed many times, + * either explicitly (via \c clang_reparseTranslationUnit()) or implicitly + * (e.g., by code completion (\c clang_codeCompletionAt())). The returned flag + * set contains an unspecified set of optimizations (e.g., the precompiled + * preamble) geared toward improving the performance of these routines. The + * set of optimizations enabled may change from one version to the next. + */ +CINDEX_LINKAGE unsigned clang_defaultEditingTranslationUnitOptions(void); + +/** + * \brief Same as \c clang_parseTranslationUnit2, but returns + * the \c CXTranslationUnit instead of an error code. In case of an error this + * routine returns a \c NULL \c CXTranslationUnit, without further detailed + * error codes. + */ +CINDEX_LINKAGE CXTranslationUnit +clang_parseTranslationUnit(CXIndex CIdx, + const char *source_filename, + const char *const *command_line_args, + int num_command_line_args, + struct CXUnsavedFile *unsaved_files, + unsigned num_unsaved_files, + unsigned options); + +/** + * \brief Parse the given source file and the translation unit corresponding + * to that file. + * + * This routine is the main entry point for the Clang C API, providing the + * ability to parse a source file into a translation unit that can then be + * queried by other functions in the API. This routine accepts a set of + * command-line arguments so that the compilation can be configured in the same + * way that the compiler is configured on the command line. + * + * \param CIdx The index object with which the translation unit will be + * associated. + * + * \param source_filename The name of the source file to load, or NULL if the + * source file is included in \c command_line_args. + * + * \param command_line_args The command-line arguments that would be + * passed to the \c clang executable if it were being invoked out-of-process. + * These command-line options will be parsed and will affect how the translation + * unit is parsed. Note that the following options are ignored: '-c', + * '-emit-ast', '-fsyntax-only' (which is the default), and '-o \<output file>'. + * + * \param num_command_line_args The number of command-line arguments in + * \c command_line_args. + * + * \param unsaved_files the files that have not yet been saved to disk + * but may be required for parsing, including the contents of + * those files. The contents and name of these files (as specified by + * CXUnsavedFile) are copied when necessary, so the client only needs to + * guarantee their validity until the call to this function returns. + * + * \param num_unsaved_files the number of unsaved file entries in \p + * unsaved_files. + * + * \param options A bitmask of options that affects how the translation unit + * is managed but not its compilation. This should be a bitwise OR of the + * CXTranslationUnit_XXX flags. + * + * \param[out] out_TU A non-NULL pointer to store the created + * \c CXTranslationUnit, describing the parsed code and containing any + * diagnostics produced by the compiler. + * + * \returns Zero on success, otherwise returns an error code. + */ +CINDEX_LINKAGE enum CXErrorCode +clang_parseTranslationUnit2(CXIndex CIdx, + const char *source_filename, + const char *const *command_line_args, + int num_command_line_args, + struct CXUnsavedFile *unsaved_files, + unsigned num_unsaved_files, + unsigned options, + CXTranslationUnit *out_TU); + +/** + * \brief Same as clang_parseTranslationUnit2 but requires a full command line + * for \c command_line_args including argv[0]. This is useful if the standard + * library paths are relative to the binary. + */ +CINDEX_LINKAGE enum CXErrorCode clang_parseTranslationUnit2FullArgv( + CXIndex CIdx, const char *source_filename, + const char *const *command_line_args, int num_command_line_args, + struct CXUnsavedFile *unsaved_files, unsigned num_unsaved_files, + unsigned options, CXTranslationUnit *out_TU); + +/** + * \brief Flags that control how translation units are saved. + * + * The enumerators in this enumeration type are meant to be bitwise + * ORed together to specify which options should be used when + * saving the translation unit. + */ +enum CXSaveTranslationUnit_Flags { + /** + * \brief Used to indicate that no special saving options are needed. + */ + CXSaveTranslationUnit_None = 0x0 +}; + +/** + * \brief Returns the set of flags that is suitable for saving a translation + * unit. + * + * The set of flags returned provide options for + * \c clang_saveTranslationUnit() by default. The returned flag + * set contains an unspecified set of options that save translation units with + * the most commonly-requested data. + */ +CINDEX_LINKAGE unsigned clang_defaultSaveOptions(CXTranslationUnit TU); + +/** + * \brief Describes the kind of error that occurred (if any) in a call to + * \c clang_saveTranslationUnit(). + */ +enum CXSaveError { + /** + * \brief Indicates that no error occurred while saving a translation unit. + */ + CXSaveError_None = 0, + + /** + * \brief Indicates that an unknown error occurred while attempting to save + * the file. + * + * This error typically indicates that file I/O failed when attempting to + * write the file. + */ + CXSaveError_Unknown = 1, + + /** + * \brief Indicates that errors during translation prevented this attempt + * to save the translation unit. + * + * Errors that prevent the translation unit from being saved can be + * extracted using \c clang_getNumDiagnostics() and \c clang_getDiagnostic(). + */ + CXSaveError_TranslationErrors = 2, + + /** + * \brief Indicates that the translation unit to be saved was somehow + * invalid (e.g., NULL). + */ + CXSaveError_InvalidTU = 3 +}; + +/** + * \brief Saves a translation unit into a serialized representation of + * that translation unit on disk. + * + * Any translation unit that was parsed without error can be saved + * into a file. The translation unit can then be deserialized into a + * new \c CXTranslationUnit with \c clang_createTranslationUnit() or, + * if it is an incomplete translation unit that corresponds to a + * header, used as a precompiled header when parsing other translation + * units. + * + * \param TU The translation unit to save. + * + * \param FileName The file to which the translation unit will be saved. + * + * \param options A bitmask of options that affects how the translation unit + * is saved. This should be a bitwise OR of the + * CXSaveTranslationUnit_XXX flags. + * + * \returns A value that will match one of the enumerators of the CXSaveError + * enumeration. Zero (CXSaveError_None) indicates that the translation unit was + * saved successfully, while a non-zero value indicates that a problem occurred. + */ +CINDEX_LINKAGE int clang_saveTranslationUnit(CXTranslationUnit TU, + const char *FileName, + unsigned options); + +/** + * \brief Destroy the specified CXTranslationUnit object. + */ +CINDEX_LINKAGE void clang_disposeTranslationUnit(CXTranslationUnit); + +/** + * \brief Flags that control the reparsing of translation units. + * + * The enumerators in this enumeration type are meant to be bitwise + * ORed together to specify which options should be used when + * reparsing the translation unit. + */ +enum CXReparse_Flags { + /** + * \brief Used to indicate that no special reparsing options are needed. + */ + CXReparse_None = 0x0 +}; + +/** + * \brief Returns the set of flags that is suitable for reparsing a translation + * unit. + * + * The set of flags returned provide options for + * \c clang_reparseTranslationUnit() by default. The returned flag + * set contains an unspecified set of optimizations geared toward common uses + * of reparsing. The set of optimizations enabled may change from one version + * to the next. + */ +CINDEX_LINKAGE unsigned clang_defaultReparseOptions(CXTranslationUnit TU); + +/** + * \brief Reparse the source files that produced this translation unit. + * + * This routine can be used to re-parse the source files that originally + * created the given translation unit, for example because those source files + * have changed (either on disk or as passed via \p unsaved_files). The + * source code will be reparsed with the same command-line options as it + * was originally parsed. + * + * Reparsing a translation unit invalidates all cursors and source locations + * that refer into that translation unit. This makes reparsing a translation + * unit semantically equivalent to destroying the translation unit and then + * creating a new translation unit with the same command-line arguments. + * However, it may be more efficient to reparse a translation + * unit using this routine. + * + * \param TU The translation unit whose contents will be re-parsed. The + * translation unit must originally have been built with + * \c clang_createTranslationUnitFromSourceFile(). + * + * \param num_unsaved_files The number of unsaved file entries in \p + * unsaved_files. + * + * \param unsaved_files The files that have not yet been saved to disk + * but may be required for parsing, including the contents of + * those files. The contents and name of these files (as specified by + * CXUnsavedFile) are copied when necessary, so the client only needs to + * guarantee their validity until the call to this function returns. + * + * \param options A bitset of options composed of the flags in CXReparse_Flags. + * The function \c clang_defaultReparseOptions() produces a default set of + * options recommended for most uses, based on the translation unit. + * + * \returns 0 if the sources could be reparsed. A non-zero error code will be + * returned if reparsing was impossible, such that the translation unit is + * invalid. In such cases, the only valid call for \c TU is + * \c clang_disposeTranslationUnit(TU). The error codes returned by this + * routine are described by the \c CXErrorCode enum. + */ +CINDEX_LINKAGE int clang_reparseTranslationUnit(CXTranslationUnit TU, + unsigned num_unsaved_files, + struct CXUnsavedFile *unsaved_files, + unsigned options); + +/** + * \brief Categorizes how memory is being used by a translation unit. + */ +enum CXTUResourceUsageKind { + CXTUResourceUsage_AST = 1, + CXTUResourceUsage_Identifiers = 2, + CXTUResourceUsage_Selectors = 3, + CXTUResourceUsage_GlobalCompletionResults = 4, + CXTUResourceUsage_SourceManagerContentCache = 5, + CXTUResourceUsage_AST_SideTables = 6, + CXTUResourceUsage_SourceManager_Membuffer_Malloc = 7, + CXTUResourceUsage_SourceManager_Membuffer_MMap = 8, + CXTUResourceUsage_ExternalASTSource_Membuffer_Malloc = 9, + CXTUResourceUsage_ExternalASTSource_Membuffer_MMap = 10, + CXTUResourceUsage_Preprocessor = 11, + CXTUResourceUsage_PreprocessingRecord = 12, + CXTUResourceUsage_SourceManager_DataStructures = 13, + CXTUResourceUsage_Preprocessor_HeaderSearch = 14, + CXTUResourceUsage_MEMORY_IN_BYTES_BEGIN = CXTUResourceUsage_AST, + CXTUResourceUsage_MEMORY_IN_BYTES_END = + CXTUResourceUsage_Preprocessor_HeaderSearch, + + CXTUResourceUsage_First = CXTUResourceUsage_AST, + CXTUResourceUsage_Last = CXTUResourceUsage_Preprocessor_HeaderSearch +}; + +/** + * \brief Returns the human-readable null-terminated C string that represents + * the name of the memory category. This string should never be freed. + */ +CINDEX_LINKAGE +const char *clang_getTUResourceUsageName(enum CXTUResourceUsageKind kind); + +typedef struct CXTUResourceUsageEntry { + /* \brief The memory usage category. */ + enum CXTUResourceUsageKind kind; + /* \brief Amount of resources used. + The units will depend on the resource kind. */ + unsigned long amount; +} CXTUResourceUsageEntry; + +/** + * \brief The memory usage of a CXTranslationUnit, broken into categories. + */ +typedef struct CXTUResourceUsage { + /* \brief Private data member, used for queries. */ + void *data; + + /* \brief The number of entries in the 'entries' array. */ + unsigned numEntries; + + /* \brief An array of key-value pairs, representing the breakdown of memory + usage. */ + CXTUResourceUsageEntry *entries; + +} CXTUResourceUsage; + +/** + * \brief Return the memory usage of a translation unit. This object + * should be released with clang_disposeCXTUResourceUsage(). + */ +CINDEX_LINKAGE CXTUResourceUsage clang_getCXTUResourceUsage(CXTranslationUnit TU); + +CINDEX_LINKAGE void clang_disposeCXTUResourceUsage(CXTUResourceUsage usage); + +/** + * @} + */ + +/** + * \brief Describes the kind of entity that a cursor refers to. + */ +enum CXCursorKind { + /* Declarations */ + /** + * \brief A declaration whose specific kind is not exposed via this + * interface. + * + * Unexposed declarations have the same operations as any other kind + * of declaration; one can extract their location information, + * spelling, find their definitions, etc. However, the specific kind + * of the declaration is not reported. + */ + CXCursor_UnexposedDecl = 1, + /** \brief A C or C++ struct. */ + CXCursor_StructDecl = 2, + /** \brief A C or C++ union. */ + CXCursor_UnionDecl = 3, + /** \brief A C++ class. */ + CXCursor_ClassDecl = 4, + /** \brief An enumeration. */ + CXCursor_EnumDecl = 5, + /** + * \brief A field (in C) or non-static data member (in C++) in a + * struct, union, or C++ class. + */ + CXCursor_FieldDecl = 6, + /** \brief An enumerator constant. */ + CXCursor_EnumConstantDecl = 7, + /** \brief A function. */ + CXCursor_FunctionDecl = 8, + /** \brief A variable. */ + CXCursor_VarDecl = 9, + /** \brief A function or method parameter. */ + CXCursor_ParmDecl = 10, + /** \brief An Objective-C \@interface. */ + CXCursor_ObjCInterfaceDecl = 11, + /** \brief An Objective-C \@interface for a category. */ + CXCursor_ObjCCategoryDecl = 12, + /** \brief An Objective-C \@protocol declaration. */ + CXCursor_ObjCProtocolDecl = 13, + /** \brief An Objective-C \@property declaration. */ + CXCursor_ObjCPropertyDecl = 14, + /** \brief An Objective-C instance variable. */ + CXCursor_ObjCIvarDecl = 15, + /** \brief An Objective-C instance method. */ + CXCursor_ObjCInstanceMethodDecl = 16, + /** \brief An Objective-C class method. */ + CXCursor_ObjCClassMethodDecl = 17, + /** \brief An Objective-C \@implementation. */ + CXCursor_ObjCImplementationDecl = 18, + /** \brief An Objective-C \@implementation for a category. */ + CXCursor_ObjCCategoryImplDecl = 19, + /** \brief A typedef. */ + CXCursor_TypedefDecl = 20, + /** \brief A C++ class method. */ + CXCursor_CXXMethod = 21, + /** \brief A C++ namespace. */ + CXCursor_Namespace = 22, + /** \brief A linkage specification, e.g. 'extern "C"'. */ + CXCursor_LinkageSpec = 23, + /** \brief A C++ constructor. */ + CXCursor_Constructor = 24, + /** \brief A C++ destructor. */ + CXCursor_Destructor = 25, + /** \brief A C++ conversion function. */ + CXCursor_ConversionFunction = 26, + /** \brief A C++ template type parameter. */ + CXCursor_TemplateTypeParameter = 27, + /** \brief A C++ non-type template parameter. */ + CXCursor_NonTypeTemplateParameter = 28, + /** \brief A C++ template template parameter. */ + CXCursor_TemplateTemplateParameter = 29, + /** \brief A C++ function template. */ + CXCursor_FunctionTemplate = 30, + /** \brief A C++ class template. */ + CXCursor_ClassTemplate = 31, + /** \brief A C++ class template partial specialization. */ + CXCursor_ClassTemplatePartialSpecialization = 32, + /** \brief A C++ namespace alias declaration. */ + CXCursor_NamespaceAlias = 33, + /** \brief A C++ using directive. */ + CXCursor_UsingDirective = 34, + /** \brief A C++ using declaration. */ + CXCursor_UsingDeclaration = 35, + /** \brief A C++ alias declaration */ + CXCursor_TypeAliasDecl = 36, + /** \brief An Objective-C \@synthesize definition. */ + CXCursor_ObjCSynthesizeDecl = 37, + /** \brief An Objective-C \@dynamic definition. */ + CXCursor_ObjCDynamicDecl = 38, + /** \brief An access specifier. */ + CXCursor_CXXAccessSpecifier = 39, + + CXCursor_FirstDecl = CXCursor_UnexposedDecl, + CXCursor_LastDecl = CXCursor_CXXAccessSpecifier, + + /* References */ + CXCursor_FirstRef = 40, /* Decl references */ + CXCursor_ObjCSuperClassRef = 40, + CXCursor_ObjCProtocolRef = 41, + CXCursor_ObjCClassRef = 42, + /** + * \brief A reference to a type declaration. + * + * A type reference occurs anywhere where a type is named but not + * declared. For example, given: + * + * \code + * typedef unsigned size_type; + * size_type size; + * \endcode + * + * The typedef is a declaration of size_type (CXCursor_TypedefDecl), + * while the type of the variable "size" is referenced. The cursor + * referenced by the type of size is the typedef for size_type. + */ + CXCursor_TypeRef = 43, + CXCursor_CXXBaseSpecifier = 44, + /** + * \brief A reference to a class template, function template, template + * template parameter, or class template partial specialization. + */ + CXCursor_TemplateRef = 45, + /** + * \brief A reference to a namespace or namespace alias. + */ + CXCursor_NamespaceRef = 46, + /** + * \brief A reference to a member of a struct, union, or class that occurs in + * some non-expression context, e.g., a designated initializer. + */ + CXCursor_MemberRef = 47, + /** + * \brief A reference to a labeled statement. + * + * This cursor kind is used to describe the jump to "start_over" in the + * goto statement in the following example: + * + * \code + * start_over: + * ++counter; + * + * goto start_over; + * \endcode + * + * A label reference cursor refers to a label statement. + */ + CXCursor_LabelRef = 48, + + /** + * \brief A reference to a set of overloaded functions or function templates + * that has not yet been resolved to a specific function or function template. + * + * An overloaded declaration reference cursor occurs in C++ templates where + * a dependent name refers to a function. For example: + * + * \code + * template<typename T> void swap(T&, T&); + * + * struct X { ... }; + * void swap(X&, X&); + * + * template<typename T> + * void reverse(T* first, T* last) { + * while (first < last - 1) { + * swap(*first, *--last); + * ++first; + * } + * } + * + * struct Y { }; + * void swap(Y&, Y&); + * \endcode + * + * Here, the identifier "swap" is associated with an overloaded declaration + * reference. In the template definition, "swap" refers to either of the two + * "swap" functions declared above, so both results will be available. At + * instantiation time, "swap" may also refer to other functions found via + * argument-dependent lookup (e.g., the "swap" function at the end of the + * example). + * + * The functions \c clang_getNumOverloadedDecls() and + * \c clang_getOverloadedDecl() can be used to retrieve the definitions + * referenced by this cursor. + */ + CXCursor_OverloadedDeclRef = 49, + + /** + * \brief A reference to a variable that occurs in some non-expression + * context, e.g., a C++ lambda capture list. + */ + CXCursor_VariableRef = 50, + + CXCursor_LastRef = CXCursor_VariableRef, + + /* Error conditions */ + CXCursor_FirstInvalid = 70, + CXCursor_InvalidFile = 70, + CXCursor_NoDeclFound = 71, + CXCursor_NotImplemented = 72, + CXCursor_InvalidCode = 73, + CXCursor_LastInvalid = CXCursor_InvalidCode, + + /* Expressions */ + CXCursor_FirstExpr = 100, + + /** + * \brief An expression whose specific kind is not exposed via this + * interface. + * + * Unexposed expressions have the same operations as any other kind + * of expression; one can extract their location information, + * spelling, children, etc. However, the specific kind of the + * expression is not reported. + */ + CXCursor_UnexposedExpr = 100, + + /** + * \brief An expression that refers to some value declaration, such + * as a function, variable, or enumerator. + */ + CXCursor_DeclRefExpr = 101, + + /** + * \brief An expression that refers to a member of a struct, union, + * class, Objective-C class, etc. + */ + CXCursor_MemberRefExpr = 102, + + /** \brief An expression that calls a function. */ + CXCursor_CallExpr = 103, + + /** \brief An expression that sends a message to an Objective-C + object or class. */ + CXCursor_ObjCMessageExpr = 104, + + /** \brief An expression that represents a block literal. */ + CXCursor_BlockExpr = 105, + + /** \brief An integer literal. + */ + CXCursor_IntegerLiteral = 106, + + /** \brief A floating point number literal. + */ + CXCursor_FloatingLiteral = 107, + + /** \brief An imaginary number literal. + */ + CXCursor_ImaginaryLiteral = 108, + + /** \brief A string literal. + */ + CXCursor_StringLiteral = 109, + + /** \brief A character literal. + */ + CXCursor_CharacterLiteral = 110, + + /** \brief A parenthesized expression, e.g. "(1)". + * + * This AST node is only formed if full location information is requested. + */ + CXCursor_ParenExpr = 111, + + /** \brief This represents the unary-expression's (except sizeof and + * alignof). + */ + CXCursor_UnaryOperator = 112, + + /** \brief [C99 6.5.2.1] Array Subscripting. + */ + CXCursor_ArraySubscriptExpr = 113, + + /** \brief A builtin binary operation expression such as "x + y" or + * "x <= y". + */ + CXCursor_BinaryOperator = 114, + + /** \brief Compound assignment such as "+=". + */ + CXCursor_CompoundAssignOperator = 115, + + /** \brief The ?: ternary operator. + */ + CXCursor_ConditionalOperator = 116, + + /** \brief An explicit cast in C (C99 6.5.4) or a C-style cast in C++ + * (C++ [expr.cast]), which uses the syntax (Type)expr. + * + * For example: (int)f. + */ + CXCursor_CStyleCastExpr = 117, + + /** \brief [C99 6.5.2.5] + */ + CXCursor_CompoundLiteralExpr = 118, + + /** \brief Describes an C or C++ initializer list. + */ + CXCursor_InitListExpr = 119, + + /** \brief The GNU address of label extension, representing &&label. + */ + CXCursor_AddrLabelExpr = 120, + + /** \brief This is the GNU Statement Expression extension: ({int X=4; X;}) + */ + CXCursor_StmtExpr = 121, + + /** \brief Represents a C11 generic selection. + */ + CXCursor_GenericSelectionExpr = 122, + + /** \brief Implements the GNU __null extension, which is a name for a null + * pointer constant that has integral type (e.g., int or long) and is the same + * size and alignment as a pointer. + * + * The __null extension is typically only used by system headers, which define + * NULL as __null in C++ rather than using 0 (which is an integer that may not + * match the size of a pointer). + */ + CXCursor_GNUNullExpr = 123, + + /** \brief C++'s static_cast<> expression. + */ + CXCursor_CXXStaticCastExpr = 124, + + /** \brief C++'s dynamic_cast<> expression. + */ + CXCursor_CXXDynamicCastExpr = 125, + + /** \brief C++'s reinterpret_cast<> expression. + */ + CXCursor_CXXReinterpretCastExpr = 126, + + /** \brief C++'s const_cast<> expression. + */ + CXCursor_CXXConstCastExpr = 127, + + /** \brief Represents an explicit C++ type conversion that uses "functional" + * notion (C++ [expr.type.conv]). + * + * Example: + * \code + * x = int(0.5); + * \endcode + */ + CXCursor_CXXFunctionalCastExpr = 128, + + /** \brief A C++ typeid expression (C++ [expr.typeid]). + */ + CXCursor_CXXTypeidExpr = 129, + + /** \brief [C++ 2.13.5] C++ Boolean Literal. + */ + CXCursor_CXXBoolLiteralExpr = 130, + + /** \brief [C++0x 2.14.7] C++ Pointer Literal. + */ + CXCursor_CXXNullPtrLiteralExpr = 131, + + /** \brief Represents the "this" expression in C++ + */ + CXCursor_CXXThisExpr = 132, + + /** \brief [C++ 15] C++ Throw Expression. + * + * This handles 'throw' and 'throw' assignment-expression. When + * assignment-expression isn't present, Op will be null. + */ + CXCursor_CXXThrowExpr = 133, + + /** \brief A new expression for memory allocation and constructor calls, e.g: + * "new CXXNewExpr(foo)". + */ + CXCursor_CXXNewExpr = 134, + + /** \brief A delete expression for memory deallocation and destructor calls, + * e.g. "delete[] pArray". + */ + CXCursor_CXXDeleteExpr = 135, + + /** \brief A unary expression. + */ + CXCursor_UnaryExpr = 136, + + /** \brief An Objective-C string literal i.e. @"foo". + */ + CXCursor_ObjCStringLiteral = 137, + + /** \brief An Objective-C \@encode expression. + */ + CXCursor_ObjCEncodeExpr = 138, + + /** \brief An Objective-C \@selector expression. + */ + CXCursor_ObjCSelectorExpr = 139, + + /** \brief An Objective-C \@protocol expression. + */ + CXCursor_ObjCProtocolExpr = 140, + + /** \brief An Objective-C "bridged" cast expression, which casts between + * Objective-C pointers and C pointers, transferring ownership in the process. + * + * \code + * NSString *str = (__bridge_transfer NSString *)CFCreateString(); + * \endcode + */ + CXCursor_ObjCBridgedCastExpr = 141, + + /** \brief Represents a C++0x pack expansion that produces a sequence of + * expressions. + * + * A pack expansion expression contains a pattern (which itself is an + * expression) followed by an ellipsis. For example: + * + * \code + * template<typename F, typename ...Types> + * void forward(F f, Types &&...args) { + * f(static_cast<Types&&>(args)...); + * } + * \endcode + */ + CXCursor_PackExpansionExpr = 142, + + /** \brief Represents an expression that computes the length of a parameter + * pack. + * + * \code + * template<typename ...Types> + * struct count { + * static const unsigned value = sizeof...(Types); + * }; + * \endcode + */ + CXCursor_SizeOfPackExpr = 143, + + /* \brief Represents a C++ lambda expression that produces a local function + * object. + * + * \code + * void abssort(float *x, unsigned N) { + * std::sort(x, x + N, + * [](float a, float b) { + * return std::abs(a) < std::abs(b); + * }); + * } + * \endcode + */ + CXCursor_LambdaExpr = 144, + + /** \brief Objective-c Boolean Literal. + */ + CXCursor_ObjCBoolLiteralExpr = 145, + + /** \brief Represents the "self" expression in an Objective-C method. + */ + CXCursor_ObjCSelfExpr = 146, + + /** \brief OpenMP 4.0 [2.4, Array Section]. + */ + CXCursor_OMPArraySectionExpr = 147, + + CXCursor_LastExpr = CXCursor_OMPArraySectionExpr, + + /* Statements */ + CXCursor_FirstStmt = 200, + /** + * \brief A statement whose specific kind is not exposed via this + * interface. + * + * Unexposed statements have the same operations as any other kind of + * statement; one can extract their location information, spelling, + * children, etc. However, the specific kind of the statement is not + * reported. + */ + CXCursor_UnexposedStmt = 200, + + /** \brief A labelled statement in a function. + * + * This cursor kind is used to describe the "start_over:" label statement in + * the following example: + * + * \code + * start_over: + * ++counter; + * \endcode + * + */ + CXCursor_LabelStmt = 201, + + /** \brief A group of statements like { stmt stmt }. + * + * This cursor kind is used to describe compound statements, e.g. function + * bodies. + */ + CXCursor_CompoundStmt = 202, + + /** \brief A case statement. + */ + CXCursor_CaseStmt = 203, + + /** \brief A default statement. + */ + CXCursor_DefaultStmt = 204, + + /** \brief An if statement + */ + CXCursor_IfStmt = 205, + + /** \brief A switch statement. + */ + CXCursor_SwitchStmt = 206, + + /** \brief A while statement. + */ + CXCursor_WhileStmt = 207, + + /** \brief A do statement. + */ + CXCursor_DoStmt = 208, + + /** \brief A for statement. + */ + CXCursor_ForStmt = 209, + + /** \brief A goto statement. + */ + CXCursor_GotoStmt = 210, + + /** \brief An indirect goto statement. + */ + CXCursor_IndirectGotoStmt = 211, + + /** \brief A continue statement. + */ + CXCursor_ContinueStmt = 212, + + /** \brief A break statement. + */ + CXCursor_BreakStmt = 213, + + /** \brief A return statement. + */ + CXCursor_ReturnStmt = 214, + + /** \brief A GCC inline assembly statement extension. + */ + CXCursor_GCCAsmStmt = 215, + CXCursor_AsmStmt = CXCursor_GCCAsmStmt, + + /** \brief Objective-C's overall \@try-\@catch-\@finally statement. + */ + CXCursor_ObjCAtTryStmt = 216, + + /** \brief Objective-C's \@catch statement. + */ + CXCursor_ObjCAtCatchStmt = 217, + + /** \brief Objective-C's \@finally statement. + */ + CXCursor_ObjCAtFinallyStmt = 218, + + /** \brief Objective-C's \@throw statement. + */ + CXCursor_ObjCAtThrowStmt = 219, + + /** \brief Objective-C's \@synchronized statement. + */ + CXCursor_ObjCAtSynchronizedStmt = 220, + + /** \brief Objective-C's autorelease pool statement. + */ + CXCursor_ObjCAutoreleasePoolStmt = 221, + + /** \brief Objective-C's collection statement. + */ + CXCursor_ObjCForCollectionStmt = 222, + + /** \brief C++'s catch statement. + */ + CXCursor_CXXCatchStmt = 223, + + /** \brief C++'s try statement. + */ + CXCursor_CXXTryStmt = 224, + + /** \brief C++'s for (* : *) statement. + */ + CXCursor_CXXForRangeStmt = 225, + + /** \brief Windows Structured Exception Handling's try statement. + */ + CXCursor_SEHTryStmt = 226, + + /** \brief Windows Structured Exception Handling's except statement. + */ + CXCursor_SEHExceptStmt = 227, + + /** \brief Windows Structured Exception Handling's finally statement. + */ + CXCursor_SEHFinallyStmt = 228, + + /** \brief A MS inline assembly statement extension. + */ + CXCursor_MSAsmStmt = 229, + + /** \brief The null statement ";": C99 6.8.3p3. + * + * This cursor kind is used to describe the null statement. + */ + CXCursor_NullStmt = 230, + + /** \brief Adaptor class for mixing declarations with statements and + * expressions. + */ + CXCursor_DeclStmt = 231, + + /** \brief OpenMP parallel directive. + */ + CXCursor_OMPParallelDirective = 232, + + /** \brief OpenMP SIMD directive. + */ + CXCursor_OMPSimdDirective = 233, + + /** \brief OpenMP for directive. + */ + CXCursor_OMPForDirective = 234, + + /** \brief OpenMP sections directive. + */ + CXCursor_OMPSectionsDirective = 235, + + /** \brief OpenMP section directive. + */ + CXCursor_OMPSectionDirective = 236, + + /** \brief OpenMP single directive. + */ + CXCursor_OMPSingleDirective = 237, + + /** \brief OpenMP parallel for directive. + */ + CXCursor_OMPParallelForDirective = 238, + + /** \brief OpenMP parallel sections directive. + */ + CXCursor_OMPParallelSectionsDirective = 239, + + /** \brief OpenMP task directive. + */ + CXCursor_OMPTaskDirective = 240, + + /** \brief OpenMP master directive. + */ + CXCursor_OMPMasterDirective = 241, + + /** \brief OpenMP critical directive. + */ + CXCursor_OMPCriticalDirective = 242, + + /** \brief OpenMP taskyield directive. + */ + CXCursor_OMPTaskyieldDirective = 243, + + /** \brief OpenMP barrier directive. + */ + CXCursor_OMPBarrierDirective = 244, + + /** \brief OpenMP taskwait directive. + */ + CXCursor_OMPTaskwaitDirective = 245, + + /** \brief OpenMP flush directive. + */ + CXCursor_OMPFlushDirective = 246, + + /** \brief Windows Structured Exception Handling's leave statement. + */ + CXCursor_SEHLeaveStmt = 247, + + /** \brief OpenMP ordered directive. + */ + CXCursor_OMPOrderedDirective = 248, + + /** \brief OpenMP atomic directive. + */ + CXCursor_OMPAtomicDirective = 249, + + /** \brief OpenMP for SIMD directive. + */ + CXCursor_OMPForSimdDirective = 250, + + /** \brief OpenMP parallel for SIMD directive. + */ + CXCursor_OMPParallelForSimdDirective = 251, + + /** \brief OpenMP target directive. + */ + CXCursor_OMPTargetDirective = 252, + + /** \brief OpenMP teams directive. + */ + CXCursor_OMPTeamsDirective = 253, + + /** \brief OpenMP taskgroup directive. + */ + CXCursor_OMPTaskgroupDirective = 254, + + /** \brief OpenMP cancellation point directive. + */ + CXCursor_OMPCancellationPointDirective = 255, + + /** \brief OpenMP cancel directive. + */ + CXCursor_OMPCancelDirective = 256, + + /** \brief OpenMP target data directive. + */ + CXCursor_OMPTargetDataDirective = 257, + + /** \brief OpenMP taskloop directive. + */ + CXCursor_OMPTaskLoopDirective = 258, + + /** \brief OpenMP taskloop simd directive. + */ + CXCursor_OMPTaskLoopSimdDirective = 259, + + /** \brief OpenMP distribute directive. + */ + CXCursor_OMPDistributeDirective = 260, + + CXCursor_LastStmt = CXCursor_OMPDistributeDirective, + + /** + * \brief Cursor that represents the translation unit itself. + * + * The translation unit cursor exists primarily to act as the root + * cursor for traversing the contents of a translation unit. + */ + CXCursor_TranslationUnit = 300, + + /* Attributes */ + CXCursor_FirstAttr = 400, + /** + * \brief An attribute whose specific kind is not exposed via this + * interface. + */ + CXCursor_UnexposedAttr = 400, + + CXCursor_IBActionAttr = 401, + CXCursor_IBOutletAttr = 402, + CXCursor_IBOutletCollectionAttr = 403, + CXCursor_CXXFinalAttr = 404, + CXCursor_CXXOverrideAttr = 405, + CXCursor_AnnotateAttr = 406, + CXCursor_AsmLabelAttr = 407, + CXCursor_PackedAttr = 408, + CXCursor_PureAttr = 409, + CXCursor_ConstAttr = 410, + CXCursor_NoDuplicateAttr = 411, + CXCursor_CUDAConstantAttr = 412, + CXCursor_CUDADeviceAttr = 413, + CXCursor_CUDAGlobalAttr = 414, + CXCursor_CUDAHostAttr = 415, + CXCursor_CUDASharedAttr = 416, + CXCursor_VisibilityAttr = 417, + CXCursor_DLLExport = 418, + CXCursor_DLLImport = 419, + CXCursor_LastAttr = CXCursor_DLLImport, + + /* Preprocessing */ + CXCursor_PreprocessingDirective = 500, + CXCursor_MacroDefinition = 501, + CXCursor_MacroExpansion = 502, + CXCursor_MacroInstantiation = CXCursor_MacroExpansion, + CXCursor_InclusionDirective = 503, + CXCursor_FirstPreprocessing = CXCursor_PreprocessingDirective, + CXCursor_LastPreprocessing = CXCursor_InclusionDirective, + + /* Extra Declarations */ + /** + * \brief A module import declaration. + */ + CXCursor_ModuleImportDecl = 600, + CXCursor_TypeAliasTemplateDecl = 601, + CXCursor_FirstExtraDecl = CXCursor_ModuleImportDecl, + CXCursor_LastExtraDecl = CXCursor_TypeAliasTemplateDecl, + + /** + * \brief A code completion overload candidate. + */ + CXCursor_OverloadCandidate = 700 +}; + +/** + * \brief A cursor representing some element in the abstract syntax tree for + * a translation unit. + * + * The cursor abstraction unifies the different kinds of entities in a + * program--declaration, statements, expressions, references to declarations, + * etc.--under a single "cursor" abstraction with a common set of operations. + * Common operation for a cursor include: getting the physical location in + * a source file where the cursor points, getting the name associated with a + * cursor, and retrieving cursors for any child nodes of a particular cursor. + * + * Cursors can be produced in two specific ways. + * clang_getTranslationUnitCursor() produces a cursor for a translation unit, + * from which one can use clang_visitChildren() to explore the rest of the + * translation unit. clang_getCursor() maps from a physical source location + * to the entity that resides at that location, allowing one to map from the + * source code into the AST. + */ +typedef struct { + enum CXCursorKind kind; + int xdata; + const void *data[3]; +} CXCursor; + +/** + * \defgroup CINDEX_CURSOR_MANIP Cursor manipulations + * + * @{ + */ + +/** + * \brief Retrieve the NULL cursor, which represents no entity. + */ +CINDEX_LINKAGE CXCursor clang_getNullCursor(void); + +/** + * \brief Retrieve the cursor that represents the given translation unit. + * + * The translation unit cursor can be used to start traversing the + * various declarations within the given translation unit. + */ +CINDEX_LINKAGE CXCursor clang_getTranslationUnitCursor(CXTranslationUnit); + +/** + * \brief Determine whether two cursors are equivalent. + */ +CINDEX_LINKAGE unsigned clang_equalCursors(CXCursor, CXCursor); + +/** + * \brief Returns non-zero if \p cursor is null. + */ +CINDEX_LINKAGE int clang_Cursor_isNull(CXCursor cursor); + +/** + * \brief Compute a hash value for the given cursor. + */ +CINDEX_LINKAGE unsigned clang_hashCursor(CXCursor); + +/** + * \brief Retrieve the kind of the given cursor. + */ +CINDEX_LINKAGE enum CXCursorKind clang_getCursorKind(CXCursor); + +/** + * \brief Determine whether the given cursor kind represents a declaration. + */ +CINDEX_LINKAGE unsigned clang_isDeclaration(enum CXCursorKind); + +/** + * \brief Determine whether the given cursor kind represents a simple + * reference. + * + * Note that other kinds of cursors (such as expressions) can also refer to + * other cursors. Use clang_getCursorReferenced() to determine whether a + * particular cursor refers to another entity. + */ +CINDEX_LINKAGE unsigned clang_isReference(enum CXCursorKind); + +/** + * \brief Determine whether the given cursor kind represents an expression. + */ +CINDEX_LINKAGE unsigned clang_isExpression(enum CXCursorKind); + +/** + * \brief Determine whether the given cursor kind represents a statement. + */ +CINDEX_LINKAGE unsigned clang_isStatement(enum CXCursorKind); + +/** + * \brief Determine whether the given cursor kind represents an attribute. + */ +CINDEX_LINKAGE unsigned clang_isAttribute(enum CXCursorKind); + +/** + * \brief Determine whether the given cursor kind represents an invalid + * cursor. + */ +CINDEX_LINKAGE unsigned clang_isInvalid(enum CXCursorKind); + +/** + * \brief Determine whether the given cursor kind represents a translation + * unit. + */ +CINDEX_LINKAGE unsigned clang_isTranslationUnit(enum CXCursorKind); + +/*** + * \brief Determine whether the given cursor represents a preprocessing + * element, such as a preprocessor directive or macro instantiation. + */ +CINDEX_LINKAGE unsigned clang_isPreprocessing(enum CXCursorKind); + +/*** + * \brief Determine whether the given cursor represents a currently + * unexposed piece of the AST (e.g., CXCursor_UnexposedStmt). + */ +CINDEX_LINKAGE unsigned clang_isUnexposed(enum CXCursorKind); + +/** + * \brief Describe the linkage of the entity referred to by a cursor. + */ +enum CXLinkageKind { + /** \brief This value indicates that no linkage information is available + * for a provided CXCursor. */ + CXLinkage_Invalid, + /** + * \brief This is the linkage for variables, parameters, and so on that + * have automatic storage. This covers normal (non-extern) local variables. + */ + CXLinkage_NoLinkage, + /** \brief This is the linkage for static variables and static functions. */ + CXLinkage_Internal, + /** \brief This is the linkage for entities with external linkage that live + * in C++ anonymous namespaces.*/ + CXLinkage_UniqueExternal, + /** \brief This is the linkage for entities with true, external linkage. */ + CXLinkage_External +}; + +/** + * \brief Determine the linkage of the entity referred to by a given cursor. + */ +CINDEX_LINKAGE enum CXLinkageKind clang_getCursorLinkage(CXCursor cursor); + +enum CXVisibilityKind { + /** \brief This value indicates that no visibility information is available + * for a provided CXCursor. */ + CXVisibility_Invalid, + + /** \brief Symbol not seen by the linker. */ + CXVisibility_Hidden, + /** \brief Symbol seen by the linker but resolves to a symbol inside this object. */ + CXVisibility_Protected, + /** \brief Symbol seen by the linker and acts like a normal symbol. */ + CXVisibility_Default +}; + +/** + * \brief Describe the visibility of the entity referred to by a cursor. + * + * This returns the default visibility if not explicitly specified by + * a visibility attribute. The default visibility may be changed by + * commandline arguments. + * + * \param cursor The cursor to query. + * + * \returns The visibility of the cursor. + */ +CINDEX_LINKAGE enum CXVisibilityKind clang_getCursorVisibility(CXCursor cursor); + +/** + * \brief Determine the availability of the entity that this cursor refers to, + * taking the current target platform into account. + * + * \param cursor The cursor to query. + * + * \returns The availability of the cursor. + */ +CINDEX_LINKAGE enum CXAvailabilityKind +clang_getCursorAvailability(CXCursor cursor); + +/** + * Describes the availability of a given entity on a particular platform, e.g., + * a particular class might only be available on Mac OS 10.7 or newer. + */ +typedef struct CXPlatformAvailability { + /** + * \brief A string that describes the platform for which this structure + * provides availability information. + * + * Possible values are "ios" or "macosx". + */ + CXString Platform; + /** + * \brief The version number in which this entity was introduced. + */ + CXVersion Introduced; + /** + * \brief The version number in which this entity was deprecated (but is + * still available). + */ + CXVersion Deprecated; + /** + * \brief The version number in which this entity was obsoleted, and therefore + * is no longer available. + */ + CXVersion Obsoleted; + /** + * \brief Whether the entity is unconditionally unavailable on this platform. + */ + int Unavailable; + /** + * \brief An optional message to provide to a user of this API, e.g., to + * suggest replacement APIs. + */ + CXString Message; +} CXPlatformAvailability; + +/** + * \brief Determine the availability of the entity that this cursor refers to + * on any platforms for which availability information is known. + * + * \param cursor The cursor to query. + * + * \param always_deprecated If non-NULL, will be set to indicate whether the + * entity is deprecated on all platforms. + * + * \param deprecated_message If non-NULL, will be set to the message text + * provided along with the unconditional deprecation of this entity. The client + * is responsible for deallocating this string. + * + * \param always_unavailable If non-NULL, will be set to indicate whether the + * entity is unavailable on all platforms. + * + * \param unavailable_message If non-NULL, will be set to the message text + * provided along with the unconditional unavailability of this entity. The + * client is responsible for deallocating this string. + * + * \param availability If non-NULL, an array of CXPlatformAvailability instances + * that will be populated with platform availability information, up to either + * the number of platforms for which availability information is available (as + * returned by this function) or \c availability_size, whichever is smaller. + * + * \param availability_size The number of elements available in the + * \c availability array. + * + * \returns The number of platforms (N) for which availability information is + * available (which is unrelated to \c availability_size). + * + * Note that the client is responsible for calling + * \c clang_disposeCXPlatformAvailability to free each of the + * platform-availability structures returned. There are + * \c min(N, availability_size) such structures. + */ +CINDEX_LINKAGE int +clang_getCursorPlatformAvailability(CXCursor cursor, + int *always_deprecated, + CXString *deprecated_message, + int *always_unavailable, + CXString *unavailable_message, + CXPlatformAvailability *availability, + int availability_size); + +/** + * \brief Free the memory associated with a \c CXPlatformAvailability structure. + */ +CINDEX_LINKAGE void +clang_disposeCXPlatformAvailability(CXPlatformAvailability *availability); + +/** + * \brief Describe the "language" of the entity referred to by a cursor. + */ +enum CXLanguageKind { + CXLanguage_Invalid = 0, + CXLanguage_C, + CXLanguage_ObjC, + CXLanguage_CPlusPlus +}; + +/** + * \brief Determine the "language" of the entity referred to by a given cursor. + */ +CINDEX_LINKAGE enum CXLanguageKind clang_getCursorLanguage(CXCursor cursor); + +/** + * \brief Returns the translation unit that a cursor originated from. + */ +CINDEX_LINKAGE CXTranslationUnit clang_Cursor_getTranslationUnit(CXCursor); + +/** + * \brief A fast container representing a set of CXCursors. + */ +typedef struct CXCursorSetImpl *CXCursorSet; + +/** + * \brief Creates an empty CXCursorSet. + */ +CINDEX_LINKAGE CXCursorSet clang_createCXCursorSet(void); + +/** + * \brief Disposes a CXCursorSet and releases its associated memory. + */ +CINDEX_LINKAGE void clang_disposeCXCursorSet(CXCursorSet cset); + +/** + * \brief Queries a CXCursorSet to see if it contains a specific CXCursor. + * + * \returns non-zero if the set contains the specified cursor. +*/ +CINDEX_LINKAGE unsigned clang_CXCursorSet_contains(CXCursorSet cset, + CXCursor cursor); + +/** + * \brief Inserts a CXCursor into a CXCursorSet. + * + * \returns zero if the CXCursor was already in the set, and non-zero otherwise. +*/ +CINDEX_LINKAGE unsigned clang_CXCursorSet_insert(CXCursorSet cset, + CXCursor cursor); + +/** + * \brief Determine the semantic parent of the given cursor. + * + * The semantic parent of a cursor is the cursor that semantically contains + * the given \p cursor. For many declarations, the lexical and semantic parents + * are equivalent (the lexical parent is returned by + * \c clang_getCursorLexicalParent()). They diverge when declarations or + * definitions are provided out-of-line. For example: + * + * \code + * class C { + * void f(); + * }; + * + * void C::f() { } + * \endcode + * + * In the out-of-line definition of \c C::f, the semantic parent is + * the class \c C, of which this function is a member. The lexical parent is + * the place where the declaration actually occurs in the source code; in this + * case, the definition occurs in the translation unit. In general, the + * lexical parent for a given entity can change without affecting the semantics + * of the program, and the lexical parent of different declarations of the + * same entity may be different. Changing the semantic parent of a declaration, + * on the other hand, can have a major impact on semantics, and redeclarations + * of a particular entity should all have the same semantic context. + * + * In the example above, both declarations of \c C::f have \c C as their + * semantic context, while the lexical context of the first \c C::f is \c C + * and the lexical context of the second \c C::f is the translation unit. + * + * For global declarations, the semantic parent is the translation unit. + */ +CINDEX_LINKAGE CXCursor clang_getCursorSemanticParent(CXCursor cursor); + +/** + * \brief Determine the lexical parent of the given cursor. + * + * The lexical parent of a cursor is the cursor in which the given \p cursor + * was actually written. For many declarations, the lexical and semantic parents + * are equivalent (the semantic parent is returned by + * \c clang_getCursorSemanticParent()). They diverge when declarations or + * definitions are provided out-of-line. For example: + * + * \code + * class C { + * void f(); + * }; + * + * void C::f() { } + * \endcode + * + * In the out-of-line definition of \c C::f, the semantic parent is + * the class \c C, of which this function is a member. The lexical parent is + * the place where the declaration actually occurs in the source code; in this + * case, the definition occurs in the translation unit. In general, the + * lexical parent for a given entity can change without affecting the semantics + * of the program, and the lexical parent of different declarations of the + * same entity may be different. Changing the semantic parent of a declaration, + * on the other hand, can have a major impact on semantics, and redeclarations + * of a particular entity should all have the same semantic context. + * + * In the example above, both declarations of \c C::f have \c C as their + * semantic context, while the lexical context of the first \c C::f is \c C + * and the lexical context of the second \c C::f is the translation unit. + * + * For declarations written in the global scope, the lexical parent is + * the translation unit. + */ +CINDEX_LINKAGE CXCursor clang_getCursorLexicalParent(CXCursor cursor); + +/** + * \brief Determine the set of methods that are overridden by the given + * method. + * + * In both Objective-C and C++, a method (aka virtual member function, + * in C++) can override a virtual method in a base class. For + * Objective-C, a method is said to override any method in the class's + * base class, its protocols, or its categories' protocols, that has the same + * selector and is of the same kind (class or instance). + * If no such method exists, the search continues to the class's superclass, + * its protocols, and its categories, and so on. A method from an Objective-C + * implementation is considered to override the same methods as its + * corresponding method in the interface. + * + * For C++, a virtual member function overrides any virtual member + * function with the same signature that occurs in its base + * classes. With multiple inheritance, a virtual member function can + * override several virtual member functions coming from different + * base classes. + * + * In all cases, this function determines the immediate overridden + * method, rather than all of the overridden methods. For example, if + * a method is originally declared in a class A, then overridden in B + * (which in inherits from A) and also in C (which inherited from B), + * then the only overridden method returned from this function when + * invoked on C's method will be B's method. The client may then + * invoke this function again, given the previously-found overridden + * methods, to map out the complete method-override set. + * + * \param cursor A cursor representing an Objective-C or C++ + * method. This routine will compute the set of methods that this + * method overrides. + * + * \param overridden A pointer whose pointee will be replaced with a + * pointer to an array of cursors, representing the set of overridden + * methods. If there are no overridden methods, the pointee will be + * set to NULL. The pointee must be freed via a call to + * \c clang_disposeOverriddenCursors(). + * + * \param num_overridden A pointer to the number of overridden + * functions, will be set to the number of overridden functions in the + * array pointed to by \p overridden. + */ +CINDEX_LINKAGE void clang_getOverriddenCursors(CXCursor cursor, + CXCursor **overridden, + unsigned *num_overridden); + +/** + * \brief Free the set of overridden cursors returned by \c + * clang_getOverriddenCursors(). + */ +CINDEX_LINKAGE void clang_disposeOverriddenCursors(CXCursor *overridden); + +/** + * \brief Retrieve the file that is included by the given inclusion directive + * cursor. + */ +CINDEX_LINKAGE CXFile clang_getIncludedFile(CXCursor cursor); + +/** + * @} + */ + +/** + * \defgroup CINDEX_CURSOR_SOURCE Mapping between cursors and source code + * + * Cursors represent a location within the Abstract Syntax Tree (AST). These + * routines help map between cursors and the physical locations where the + * described entities occur in the source code. The mapping is provided in + * both directions, so one can map from source code to the AST and back. + * + * @{ + */ + +/** + * \brief Map a source location to the cursor that describes the entity at that + * location in the source code. + * + * clang_getCursor() maps an arbitrary source location within a translation + * unit down to the most specific cursor that describes the entity at that + * location. For example, given an expression \c x + y, invoking + * clang_getCursor() with a source location pointing to "x" will return the + * cursor for "x"; similarly for "y". If the cursor points anywhere between + * "x" or "y" (e.g., on the + or the whitespace around it), clang_getCursor() + * will return a cursor referring to the "+" expression. + * + * \returns a cursor representing the entity at the given source location, or + * a NULL cursor if no such entity can be found. + */ +CINDEX_LINKAGE CXCursor clang_getCursor(CXTranslationUnit, CXSourceLocation); + +/** + * \brief Retrieve the physical location of the source constructor referenced + * by the given cursor. + * + * The location of a declaration is typically the location of the name of that + * declaration, where the name of that declaration would occur if it is + * unnamed, or some keyword that introduces that particular declaration. + * The location of a reference is where that reference occurs within the + * source code. + */ +CINDEX_LINKAGE CXSourceLocation clang_getCursorLocation(CXCursor); + +/** + * \brief Retrieve the physical extent of the source construct referenced by + * the given cursor. + * + * The extent of a cursor starts with the file/line/column pointing at the + * first character within the source construct that the cursor refers to and + * ends with the last character within that source construct. For a + * declaration, the extent covers the declaration itself. For a reference, + * the extent covers the location of the reference (e.g., where the referenced + * entity was actually used). + */ +CINDEX_LINKAGE CXSourceRange clang_getCursorExtent(CXCursor); + +/** + * @} + */ + +/** + * \defgroup CINDEX_TYPES Type information for CXCursors + * + * @{ + */ + +/** + * \brief Describes the kind of type + */ +enum CXTypeKind { + /** + * \brief Represents an invalid type (e.g., where no type is available). + */ + CXType_Invalid = 0, + + /** + * \brief A type whose specific kind is not exposed via this + * interface. + */ + CXType_Unexposed = 1, + + /* Builtin types */ + CXType_Void = 2, + CXType_Bool = 3, + CXType_Char_U = 4, + CXType_UChar = 5, + CXType_Char16 = 6, + CXType_Char32 = 7, + CXType_UShort = 8, + CXType_UInt = 9, + CXType_ULong = 10, + CXType_ULongLong = 11, + CXType_UInt128 = 12, + CXType_Char_S = 13, + CXType_SChar = 14, + CXType_WChar = 15, + CXType_Short = 16, + CXType_Int = 17, + CXType_Long = 18, + CXType_LongLong = 19, + CXType_Int128 = 20, + CXType_Float = 21, + CXType_Double = 22, + CXType_LongDouble = 23, + CXType_NullPtr = 24, + CXType_Overload = 25, + CXType_Dependent = 26, + CXType_ObjCId = 27, + CXType_ObjCClass = 28, + CXType_ObjCSel = 29, + CXType_FirstBuiltin = CXType_Void, + CXType_LastBuiltin = CXType_ObjCSel, + + CXType_Complex = 100, + CXType_Pointer = 101, + CXType_BlockPointer = 102, + CXType_LValueReference = 103, + CXType_RValueReference = 104, + CXType_Record = 105, + CXType_Enum = 106, + CXType_Typedef = 107, + CXType_ObjCInterface = 108, + CXType_ObjCObjectPointer = 109, + CXType_FunctionNoProto = 110, + CXType_FunctionProto = 111, + CXType_ConstantArray = 112, + CXType_Vector = 113, + CXType_IncompleteArray = 114, + CXType_VariableArray = 115, + CXType_DependentSizedArray = 116, + CXType_MemberPointer = 117, + CXType_Auto = 118 +}; + +/** + * \brief Describes the calling convention of a function type + */ +enum CXCallingConv { + CXCallingConv_Default = 0, + CXCallingConv_C = 1, + CXCallingConv_X86StdCall = 2, + CXCallingConv_X86FastCall = 3, + CXCallingConv_X86ThisCall = 4, + CXCallingConv_X86Pascal = 5, + CXCallingConv_AAPCS = 6, + CXCallingConv_AAPCS_VFP = 7, + /* Value 8 was PnaclCall, but it was never used, so it could safely be re-used. */ + CXCallingConv_IntelOclBicc = 9, + CXCallingConv_X86_64Win64 = 10, + CXCallingConv_X86_64SysV = 11, + CXCallingConv_X86VectorCall = 12, + + CXCallingConv_Invalid = 100, + CXCallingConv_Unexposed = 200 +}; + +/** + * \brief The type of an element in the abstract syntax tree. + * + */ +typedef struct { + enum CXTypeKind kind; + void *data[2]; +} CXType; + +/** + * \brief Retrieve the type of a CXCursor (if any). + */ +CINDEX_LINKAGE CXType clang_getCursorType(CXCursor C); + +/** + * \brief Pretty-print the underlying type using the rules of the + * language of the translation unit from which it came. + * + * If the type is invalid, an empty string is returned. + */ +CINDEX_LINKAGE CXString clang_getTypeSpelling(CXType CT); + +/** + * \brief Retrieve the underlying type of a typedef declaration. + * + * If the cursor does not reference a typedef declaration, an invalid type is + * returned. + */ +CINDEX_LINKAGE CXType clang_getTypedefDeclUnderlyingType(CXCursor C); + +/** + * \brief Retrieve the integer type of an enum declaration. + * + * If the cursor does not reference an enum declaration, an invalid type is + * returned. + */ +CINDEX_LINKAGE CXType clang_getEnumDeclIntegerType(CXCursor C); + +/** + * \brief Retrieve the integer value of an enum constant declaration as a signed + * long long. + * + * If the cursor does not reference an enum constant declaration, LLONG_MIN is returned. + * Since this is also potentially a valid constant value, the kind of the cursor + * must be verified before calling this function. + */ +CINDEX_LINKAGE long long clang_getEnumConstantDeclValue(CXCursor C); + +/** + * \brief Retrieve the integer value of an enum constant declaration as an unsigned + * long long. + * + * If the cursor does not reference an enum constant declaration, ULLONG_MAX is returned. + * Since this is also potentially a valid constant value, the kind of the cursor + * must be verified before calling this function. + */ +CINDEX_LINKAGE unsigned long long clang_getEnumConstantDeclUnsignedValue(CXCursor C); + +/** + * \brief Retrieve the bit width of a bit field declaration as an integer. + * + * If a cursor that is not a bit field declaration is passed in, -1 is returned. + */ +CINDEX_LINKAGE int clang_getFieldDeclBitWidth(CXCursor C); + +/** + * \brief Retrieve the number of non-variadic arguments associated with a given + * cursor. + * + * The number of arguments can be determined for calls as well as for + * declarations of functions or methods. For other cursors -1 is returned. + */ +CINDEX_LINKAGE int clang_Cursor_getNumArguments(CXCursor C); + +/** + * \brief Retrieve the argument cursor of a function or method. + * + * The argument cursor can be determined for calls as well as for declarations + * of functions or methods. For other cursors and for invalid indices, an + * invalid cursor is returned. + */ +CINDEX_LINKAGE CXCursor clang_Cursor_getArgument(CXCursor C, unsigned i); + +/** + * \brief Describes the kind of a template argument. + * + * See the definition of llvm::clang::TemplateArgument::ArgKind for full + * element descriptions. + */ +enum CXTemplateArgumentKind { + CXTemplateArgumentKind_Null, + CXTemplateArgumentKind_Type, + CXTemplateArgumentKind_Declaration, + CXTemplateArgumentKind_NullPtr, + CXTemplateArgumentKind_Integral, + CXTemplateArgumentKind_Template, + CXTemplateArgumentKind_TemplateExpansion, + CXTemplateArgumentKind_Expression, + CXTemplateArgumentKind_Pack, + /* Indicates an error case, preventing the kind from being deduced. */ + CXTemplateArgumentKind_Invalid +}; + +/** + *\brief Returns the number of template args of a function decl representing a + * template specialization. + * + * If the argument cursor cannot be converted into a template function + * declaration, -1 is returned. + * + * For example, for the following declaration and specialization: + * template <typename T, int kInt, bool kBool> + * void foo() { ... } + * + * template <> + * void foo<float, -7, true>(); + * + * The value 3 would be returned from this call. + */ +CINDEX_LINKAGE int clang_Cursor_getNumTemplateArguments(CXCursor C); + +/** + * \brief Retrieve the kind of the I'th template argument of the CXCursor C. + * + * If the argument CXCursor does not represent a FunctionDecl, an invalid + * template argument kind is returned. + * + * For example, for the following declaration and specialization: + * template <typename T, int kInt, bool kBool> + * void foo() { ... } + * + * template <> + * void foo<float, -7, true>(); + * + * For I = 0, 1, and 2, Type, Integral, and Integral will be returned, + * respectively. + */ +CINDEX_LINKAGE enum CXTemplateArgumentKind clang_Cursor_getTemplateArgumentKind( + CXCursor C, unsigned I); + +/** + * \brief Retrieve a CXType representing the type of a TemplateArgument of a + * function decl representing a template specialization. + * + * If the argument CXCursor does not represent a FunctionDecl whose I'th + * template argument has a kind of CXTemplateArgKind_Integral, an invalid type + * is returned. + * + * For example, for the following declaration and specialization: + * template <typename T, int kInt, bool kBool> + * void foo() { ... } + * + * template <> + * void foo<float, -7, true>(); + * + * If called with I = 0, "float", will be returned. + * Invalid types will be returned for I == 1 or 2. + */ +CINDEX_LINKAGE CXType clang_Cursor_getTemplateArgumentType(CXCursor C, + unsigned I); + +/** + * \brief Retrieve the value of an Integral TemplateArgument (of a function + * decl representing a template specialization) as a signed long long. + * + * It is undefined to call this function on a CXCursor that does not represent a + * FunctionDecl or whose I'th template argument is not an integral value. + * + * For example, for the following declaration and specialization: + * template <typename T, int kInt, bool kBool> + * void foo() { ... } + * + * template <> + * void foo<float, -7, true>(); + * + * If called with I = 1 or 2, -7 or true will be returned, respectively. + * For I == 0, this function's behavior is undefined. + */ +CINDEX_LINKAGE long long clang_Cursor_getTemplateArgumentValue(CXCursor C, + unsigned I); + +/** + * \brief Retrieve the value of an Integral TemplateArgument (of a function + * decl representing a template specialization) as an unsigned long long. + * + * It is undefined to call this function on a CXCursor that does not represent a + * FunctionDecl or whose I'th template argument is not an integral value. + * + * For example, for the following declaration and specialization: + * template <typename T, int kInt, bool kBool> + * void foo() { ... } + * + * template <> + * void foo<float, 2147483649, true>(); + * + * If called with I = 1 or 2, 2147483649 or true will be returned, respectively. + * For I == 0, this function's behavior is undefined. + */ +CINDEX_LINKAGE unsigned long long clang_Cursor_getTemplateArgumentUnsignedValue( + CXCursor C, unsigned I); + +/** + * \brief Determine whether two CXTypes represent the same type. + * + * \returns non-zero if the CXTypes represent the same type and + * zero otherwise. + */ +CINDEX_LINKAGE unsigned clang_equalTypes(CXType A, CXType B); + +/** + * \brief Return the canonical type for a CXType. + * + * Clang's type system explicitly models typedefs and all the ways + * a specific type can be represented. The canonical type is the underlying + * type with all the "sugar" removed. For example, if 'T' is a typedef + * for 'int', the canonical type for 'T' would be 'int'. + */ +CINDEX_LINKAGE CXType clang_getCanonicalType(CXType T); + +/** + * \brief Determine whether a CXType has the "const" qualifier set, + * without looking through typedefs that may have added "const" at a + * different level. + */ +CINDEX_LINKAGE unsigned clang_isConstQualifiedType(CXType T); + +/** + * \brief Determine whether a CXType has the "volatile" qualifier set, + * without looking through typedefs that may have added "volatile" at + * a different level. + */ +CINDEX_LINKAGE unsigned clang_isVolatileQualifiedType(CXType T); + +/** + * \brief Determine whether a CXType has the "restrict" qualifier set, + * without looking through typedefs that may have added "restrict" at a + * different level. + */ +CINDEX_LINKAGE unsigned clang_isRestrictQualifiedType(CXType T); + +/** + * \brief For pointer types, returns the type of the pointee. + */ +CINDEX_LINKAGE CXType clang_getPointeeType(CXType T); + +/** + * \brief Return the cursor for the declaration of the given type. + */ +CINDEX_LINKAGE CXCursor clang_getTypeDeclaration(CXType T); + +/** + * Returns the Objective-C type encoding for the specified declaration. + */ +CINDEX_LINKAGE CXString clang_getDeclObjCTypeEncoding(CXCursor C); + +/** + * \brief Retrieve the spelling of a given CXTypeKind. + */ +CINDEX_LINKAGE CXString clang_getTypeKindSpelling(enum CXTypeKind K); + +/** + * \brief Retrieve the calling convention associated with a function type. + * + * If a non-function type is passed in, CXCallingConv_Invalid is returned. + */ +CINDEX_LINKAGE enum CXCallingConv clang_getFunctionTypeCallingConv(CXType T); + +/** + * \brief Retrieve the return type associated with a function type. + * + * If a non-function type is passed in, an invalid type is returned. + */ +CINDEX_LINKAGE CXType clang_getResultType(CXType T); + +/** + * \brief Retrieve the number of non-variadic parameters associated with a + * function type. + * + * If a non-function type is passed in, -1 is returned. + */ +CINDEX_LINKAGE int clang_getNumArgTypes(CXType T); + +/** + * \brief Retrieve the type of a parameter of a function type. + * + * If a non-function type is passed in or the function does not have enough + * parameters, an invalid type is returned. + */ +CINDEX_LINKAGE CXType clang_getArgType(CXType T, unsigned i); + +/** + * \brief Return 1 if the CXType is a variadic function type, and 0 otherwise. + */ +CINDEX_LINKAGE unsigned clang_isFunctionTypeVariadic(CXType T); + +/** + * \brief Retrieve the return type associated with a given cursor. + * + * This only returns a valid type if the cursor refers to a function or method. + */ +CINDEX_LINKAGE CXType clang_getCursorResultType(CXCursor C); + +/** + * \brief Return 1 if the CXType is a POD (plain old data) type, and 0 + * otherwise. + */ +CINDEX_LINKAGE unsigned clang_isPODType(CXType T); + +/** + * \brief Return the element type of an array, complex, or vector type. + * + * If a type is passed in that is not an array, complex, or vector type, + * an invalid type is returned. + */ +CINDEX_LINKAGE CXType clang_getElementType(CXType T); + +/** + * \brief Return the number of elements of an array or vector type. + * + * If a type is passed in that is not an array or vector type, + * -1 is returned. + */ +CINDEX_LINKAGE long long clang_getNumElements(CXType T); + +/** + * \brief Return the element type of an array type. + * + * If a non-array type is passed in, an invalid type is returned. + */ +CINDEX_LINKAGE CXType clang_getArrayElementType(CXType T); + +/** + * \brief Return the array size of a constant array. + * + * If a non-array type is passed in, -1 is returned. + */ +CINDEX_LINKAGE long long clang_getArraySize(CXType T); + +/** + * \brief List the possible error codes for \c clang_Type_getSizeOf, + * \c clang_Type_getAlignOf, \c clang_Type_getOffsetOf and + * \c clang_Cursor_getOffsetOf. + * + * A value of this enumeration type can be returned if the target type is not + * a valid argument to sizeof, alignof or offsetof. + */ +enum CXTypeLayoutError { + /** + * \brief Type is of kind CXType_Invalid. + */ + CXTypeLayoutError_Invalid = -1, + /** + * \brief The type is an incomplete Type. + */ + CXTypeLayoutError_Incomplete = -2, + /** + * \brief The type is a dependent Type. + */ + CXTypeLayoutError_Dependent = -3, + /** + * \brief The type is not a constant size type. + */ + CXTypeLayoutError_NotConstantSize = -4, + /** + * \brief The Field name is not valid for this record. + */ + CXTypeLayoutError_InvalidFieldName = -5 +}; + +/** + * \brief Return the alignment of a type in bytes as per C++[expr.alignof] + * standard. + * + * If the type declaration is invalid, CXTypeLayoutError_Invalid is returned. + * If the type declaration is an incomplete type, CXTypeLayoutError_Incomplete + * is returned. + * If the type declaration is a dependent type, CXTypeLayoutError_Dependent is + * returned. + * If the type declaration is not a constant size type, + * CXTypeLayoutError_NotConstantSize is returned. + */ +CINDEX_LINKAGE long long clang_Type_getAlignOf(CXType T); + +/** + * \brief Return the class type of an member pointer type. + * + * If a non-member-pointer type is passed in, an invalid type is returned. + */ +CINDEX_LINKAGE CXType clang_Type_getClassType(CXType T); + +/** + * \brief Return the size of a type in bytes as per C++[expr.sizeof] standard. + * + * If the type declaration is invalid, CXTypeLayoutError_Invalid is returned. + * If the type declaration is an incomplete type, CXTypeLayoutError_Incomplete + * is returned. + * If the type declaration is a dependent type, CXTypeLayoutError_Dependent is + * returned. + */ +CINDEX_LINKAGE long long clang_Type_getSizeOf(CXType T); + +/** + * \brief Return the offset of a field named S in a record of type T in bits + * as it would be returned by __offsetof__ as per C++11[18.2p4] + * + * If the cursor is not a record field declaration, CXTypeLayoutError_Invalid + * is returned. + * If the field's type declaration is an incomplete type, + * CXTypeLayoutError_Incomplete is returned. + * If the field's type declaration is a dependent type, + * CXTypeLayoutError_Dependent is returned. + * If the field's name S is not found, + * CXTypeLayoutError_InvalidFieldName is returned. + */ +CINDEX_LINKAGE long long clang_Type_getOffsetOf(CXType T, const char *S); + +/** + * \brief Return the offset of the field represented by the Cursor. + * + * If the cursor is not a field declaration, -1 is returned. + * If the cursor semantic parent is not a record field declaration, + * CXTypeLayoutError_Invalid is returned. + * If the field's type declaration is an incomplete type, + * CXTypeLayoutError_Incomplete is returned. + * If the field's type declaration is a dependent type, + * CXTypeLayoutError_Dependent is returned. + * If the field's name S is not found, + * CXTypeLayoutError_InvalidFieldName is returned. + */ +CINDEX_LINKAGE long long clang_Cursor_getOffsetOfField(CXCursor C); + +/** + * \brief Determine whether the given cursor represents an anonymous record + * declaration. + */ +CINDEX_LINKAGE unsigned clang_Cursor_isAnonymous(CXCursor C); + +enum CXRefQualifierKind { + /** \brief No ref-qualifier was provided. */ + CXRefQualifier_None = 0, + /** \brief An lvalue ref-qualifier was provided (\c &). */ + CXRefQualifier_LValue, + /** \brief An rvalue ref-qualifier was provided (\c &&). */ + CXRefQualifier_RValue +}; + +/** + * \brief Returns the number of template arguments for given class template + * specialization, or -1 if type \c T is not a class template specialization. + * + * Variadic argument packs count as only one argument, and can not be inspected + * further. + */ +CINDEX_LINKAGE int clang_Type_getNumTemplateArguments(CXType T); + +/** + * \brief Returns the type template argument of a template class specialization + * at given index. + * + * This function only returns template type arguments and does not handle + * template template arguments or variadic packs. + */ +CINDEX_LINKAGE CXType clang_Type_getTemplateArgumentAsType(CXType T, unsigned i); + +/** + * \brief Retrieve the ref-qualifier kind of a function or method. + * + * The ref-qualifier is returned for C++ functions or methods. For other types + * or non-C++ declarations, CXRefQualifier_None is returned. + */ +CINDEX_LINKAGE enum CXRefQualifierKind clang_Type_getCXXRefQualifier(CXType T); + +/** + * \brief Returns non-zero if the cursor specifies a Record member that is a + * bitfield. + */ +CINDEX_LINKAGE unsigned clang_Cursor_isBitField(CXCursor C); + +/** + * \brief Returns 1 if the base class specified by the cursor with kind + * CX_CXXBaseSpecifier is virtual. + */ +CINDEX_LINKAGE unsigned clang_isVirtualBase(CXCursor); + +/** + * \brief Represents the C++ access control level to a base class for a + * cursor with kind CX_CXXBaseSpecifier. + */ +enum CX_CXXAccessSpecifier { + CX_CXXInvalidAccessSpecifier, + CX_CXXPublic, + CX_CXXProtected, + CX_CXXPrivate +}; + +/** + * \brief Returns the access control level for the referenced object. + * + * If the cursor refers to a C++ declaration, its access control level within its + * parent scope is returned. Otherwise, if the cursor refers to a base specifier or + * access specifier, the specifier itself is returned. + */ +CINDEX_LINKAGE enum CX_CXXAccessSpecifier clang_getCXXAccessSpecifier(CXCursor); + +/** + * \brief Represents the storage classes as declared in the source. CX_SC_Invalid + * was added for the case that the passed cursor in not a declaration. + */ +enum CX_StorageClass { + CX_SC_Invalid, + CX_SC_None, + CX_SC_Extern, + CX_SC_Static, + CX_SC_PrivateExtern, + CX_SC_OpenCLWorkGroupLocal, + CX_SC_Auto, + CX_SC_Register +}; + +/** + * \brief Returns the storage class for a function or variable declaration. + * + * If the passed in Cursor is not a function or variable declaration, + * CX_SC_Invalid is returned else the storage class. + */ +CINDEX_LINKAGE enum CX_StorageClass clang_Cursor_getStorageClass(CXCursor); + +/** + * \brief Determine the number of overloaded declarations referenced by a + * \c CXCursor_OverloadedDeclRef cursor. + * + * \param cursor The cursor whose overloaded declarations are being queried. + * + * \returns The number of overloaded declarations referenced by \c cursor. If it + * is not a \c CXCursor_OverloadedDeclRef cursor, returns 0. + */ +CINDEX_LINKAGE unsigned clang_getNumOverloadedDecls(CXCursor cursor); + +/** + * \brief Retrieve a cursor for one of the overloaded declarations referenced + * by a \c CXCursor_OverloadedDeclRef cursor. + * + * \param cursor The cursor whose overloaded declarations are being queried. + * + * \param index The zero-based index into the set of overloaded declarations in + * the cursor. + * + * \returns A cursor representing the declaration referenced by the given + * \c cursor at the specified \c index. If the cursor does not have an + * associated set of overloaded declarations, or if the index is out of bounds, + * returns \c clang_getNullCursor(); + */ +CINDEX_LINKAGE CXCursor clang_getOverloadedDecl(CXCursor cursor, + unsigned index); + +/** + * @} + */ + +/** + * \defgroup CINDEX_ATTRIBUTES Information for attributes + * + * @{ + */ + +/** + * \brief For cursors representing an iboutletcollection attribute, + * this function returns the collection element type. + * + */ +CINDEX_LINKAGE CXType clang_getIBOutletCollectionType(CXCursor); + +/** + * @} + */ + +/** + * \defgroup CINDEX_CURSOR_TRAVERSAL Traversing the AST with cursors + * + * These routines provide the ability to traverse the abstract syntax tree + * using cursors. + * + * @{ + */ + +/** + * \brief Describes how the traversal of the children of a particular + * cursor should proceed after visiting a particular child cursor. + * + * A value of this enumeration type should be returned by each + * \c CXCursorVisitor to indicate how clang_visitChildren() proceed. + */ +enum CXChildVisitResult { + /** + * \brief Terminates the cursor traversal. + */ + CXChildVisit_Break, + /** + * \brief Continues the cursor traversal with the next sibling of + * the cursor just visited, without visiting its children. + */ + CXChildVisit_Continue, + /** + * \brief Recursively traverse the children of this cursor, using + * the same visitor and client data. + */ + CXChildVisit_Recurse +}; + +/** + * \brief Visitor invoked for each cursor found by a traversal. + * + * This visitor function will be invoked for each cursor found by + * clang_visitCursorChildren(). Its first argument is the cursor being + * visited, its second argument is the parent visitor for that cursor, + * and its third argument is the client data provided to + * clang_visitCursorChildren(). + * + * The visitor should return one of the \c CXChildVisitResult values + * to direct clang_visitCursorChildren(). + */ +typedef enum CXChildVisitResult (*CXCursorVisitor)(CXCursor cursor, + CXCursor parent, + CXClientData client_data); + +/** + * \brief Visit the children of a particular cursor. + * + * This function visits all the direct children of the given cursor, + * invoking the given \p visitor function with the cursors of each + * visited child. The traversal may be recursive, if the visitor returns + * \c CXChildVisit_Recurse. The traversal may also be ended prematurely, if + * the visitor returns \c CXChildVisit_Break. + * + * \param parent the cursor whose child may be visited. All kinds of + * cursors can be visited, including invalid cursors (which, by + * definition, have no children). + * + * \param visitor the visitor function that will be invoked for each + * child of \p parent. + * + * \param client_data pointer data supplied by the client, which will + * be passed to the visitor each time it is invoked. + * + * \returns a non-zero value if the traversal was terminated + * prematurely by the visitor returning \c CXChildVisit_Break. + */ +CINDEX_LINKAGE unsigned clang_visitChildren(CXCursor parent, + CXCursorVisitor visitor, + CXClientData client_data); +#ifdef __has_feature +# if __has_feature(blocks) +/** + * \brief Visitor invoked for each cursor found by a traversal. + * + * This visitor block will be invoked for each cursor found by + * clang_visitChildrenWithBlock(). Its first argument is the cursor being + * visited, its second argument is the parent visitor for that cursor. + * + * The visitor should return one of the \c CXChildVisitResult values + * to direct clang_visitChildrenWithBlock(). + */ +typedef enum CXChildVisitResult + (^CXCursorVisitorBlock)(CXCursor cursor, CXCursor parent); + +/** + * Visits the children of a cursor using the specified block. Behaves + * identically to clang_visitChildren() in all other respects. + */ +unsigned clang_visitChildrenWithBlock(CXCursor parent, + CXCursorVisitorBlock block); +# endif +#endif + +/** + * @} + */ + +/** + * \defgroup CINDEX_CURSOR_XREF Cross-referencing in the AST + * + * These routines provide the ability to determine references within and + * across translation units, by providing the names of the entities referenced + * by cursors, follow reference cursors to the declarations they reference, + * and associate declarations with their definitions. + * + * @{ + */ + +/** + * \brief Retrieve a Unified Symbol Resolution (USR) for the entity referenced + * by the given cursor. + * + * A Unified Symbol Resolution (USR) is a string that identifies a particular + * entity (function, class, variable, etc.) within a program. USRs can be + * compared across translation units to determine, e.g., when references in + * one translation refer to an entity defined in another translation unit. + */ +CINDEX_LINKAGE CXString clang_getCursorUSR(CXCursor); + +/** + * \brief Construct a USR for a specified Objective-C class. + */ +CINDEX_LINKAGE CXString clang_constructUSR_ObjCClass(const char *class_name); + +/** + * \brief Construct a USR for a specified Objective-C category. + */ +CINDEX_LINKAGE CXString + clang_constructUSR_ObjCCategory(const char *class_name, + const char *category_name); + +/** + * \brief Construct a USR for a specified Objective-C protocol. + */ +CINDEX_LINKAGE CXString + clang_constructUSR_ObjCProtocol(const char *protocol_name); + +/** + * \brief Construct a USR for a specified Objective-C instance variable and + * the USR for its containing class. + */ +CINDEX_LINKAGE CXString clang_constructUSR_ObjCIvar(const char *name, + CXString classUSR); + +/** + * \brief Construct a USR for a specified Objective-C method and + * the USR for its containing class. + */ +CINDEX_LINKAGE CXString clang_constructUSR_ObjCMethod(const char *name, + unsigned isInstanceMethod, + CXString classUSR); + +/** + * \brief Construct a USR for a specified Objective-C property and the USR + * for its containing class. + */ +CINDEX_LINKAGE CXString clang_constructUSR_ObjCProperty(const char *property, + CXString classUSR); + +/** + * \brief Retrieve a name for the entity referenced by this cursor. + */ +CINDEX_LINKAGE CXString clang_getCursorSpelling(CXCursor); + +/** + * \brief Retrieve a range for a piece that forms the cursors spelling name. + * Most of the times there is only one range for the complete spelling but for + * Objective-C methods and Objective-C message expressions, there are multiple + * pieces for each selector identifier. + * + * \param pieceIndex the index of the spelling name piece. If this is greater + * than the actual number of pieces, it will return a NULL (invalid) range. + * + * \param options Reserved. + */ +CINDEX_LINKAGE CXSourceRange clang_Cursor_getSpellingNameRange(CXCursor, + unsigned pieceIndex, + unsigned options); + +/** + * \brief Retrieve the display name for the entity referenced by this cursor. + * + * The display name contains extra information that helps identify the cursor, + * such as the parameters of a function or template or the arguments of a + * class template specialization. + */ +CINDEX_LINKAGE CXString clang_getCursorDisplayName(CXCursor); + +/** \brief For a cursor that is a reference, retrieve a cursor representing the + * entity that it references. + * + * Reference cursors refer to other entities in the AST. For example, an + * Objective-C superclass reference cursor refers to an Objective-C class. + * This function produces the cursor for the Objective-C class from the + * cursor for the superclass reference. If the input cursor is a declaration or + * definition, it returns that declaration or definition unchanged. + * Otherwise, returns the NULL cursor. + */ +CINDEX_LINKAGE CXCursor clang_getCursorReferenced(CXCursor); + +/** + * \brief For a cursor that is either a reference to or a declaration + * of some entity, retrieve a cursor that describes the definition of + * that entity. + * + * Some entities can be declared multiple times within a translation + * unit, but only one of those declarations can also be a + * definition. For example, given: + * + * \code + * int f(int, int); + * int g(int x, int y) { return f(x, y); } + * int f(int a, int b) { return a + b; } + * int f(int, int); + * \endcode + * + * there are three declarations of the function "f", but only the + * second one is a definition. The clang_getCursorDefinition() + * function will take any cursor pointing to a declaration of "f" + * (the first or fourth lines of the example) or a cursor referenced + * that uses "f" (the call to "f' inside "g") and will return a + * declaration cursor pointing to the definition (the second "f" + * declaration). + * + * If given a cursor for which there is no corresponding definition, + * e.g., because there is no definition of that entity within this + * translation unit, returns a NULL cursor. + */ +CINDEX_LINKAGE CXCursor clang_getCursorDefinition(CXCursor); + +/** + * \brief Determine whether the declaration pointed to by this cursor + * is also a definition of that entity. + */ +CINDEX_LINKAGE unsigned clang_isCursorDefinition(CXCursor); + +/** + * \brief Retrieve the canonical cursor corresponding to the given cursor. + * + * In the C family of languages, many kinds of entities can be declared several + * times within a single translation unit. For example, a structure type can + * be forward-declared (possibly multiple times) and later defined: + * + * \code + * struct X; + * struct X; + * struct X { + * int member; + * }; + * \endcode + * + * The declarations and the definition of \c X are represented by three + * different cursors, all of which are declarations of the same underlying + * entity. One of these cursor is considered the "canonical" cursor, which + * is effectively the representative for the underlying entity. One can + * determine if two cursors are declarations of the same underlying entity by + * comparing their canonical cursors. + * + * \returns The canonical cursor for the entity referred to by the given cursor. + */ +CINDEX_LINKAGE CXCursor clang_getCanonicalCursor(CXCursor); + +/** + * \brief If the cursor points to a selector identifier in an Objective-C + * method or message expression, this returns the selector index. + * + * After getting a cursor with #clang_getCursor, this can be called to + * determine if the location points to a selector identifier. + * + * \returns The selector index if the cursor is an Objective-C method or message + * expression and the cursor is pointing to a selector identifier, or -1 + * otherwise. + */ +CINDEX_LINKAGE int clang_Cursor_getObjCSelectorIndex(CXCursor); + +/** + * \brief Given a cursor pointing to a C++ method call or an Objective-C + * message, returns non-zero if the method/message is "dynamic", meaning: + * + * For a C++ method: the call is virtual. + * For an Objective-C message: the receiver is an object instance, not 'super' + * or a specific class. + * + * If the method/message is "static" or the cursor does not point to a + * method/message, it will return zero. + */ +CINDEX_LINKAGE int clang_Cursor_isDynamicCall(CXCursor C); + +/** + * \brief Given a cursor pointing to an Objective-C message, returns the CXType + * of the receiver. + */ +CINDEX_LINKAGE CXType clang_Cursor_getReceiverType(CXCursor C); + +/** + * \brief Property attributes for a \c CXCursor_ObjCPropertyDecl. + */ +typedef enum { + CXObjCPropertyAttr_noattr = 0x00, + CXObjCPropertyAttr_readonly = 0x01, + CXObjCPropertyAttr_getter = 0x02, + CXObjCPropertyAttr_assign = 0x04, + CXObjCPropertyAttr_readwrite = 0x08, + CXObjCPropertyAttr_retain = 0x10, + CXObjCPropertyAttr_copy = 0x20, + CXObjCPropertyAttr_nonatomic = 0x40, + CXObjCPropertyAttr_setter = 0x80, + CXObjCPropertyAttr_atomic = 0x100, + CXObjCPropertyAttr_weak = 0x200, + CXObjCPropertyAttr_strong = 0x400, + CXObjCPropertyAttr_unsafe_unretained = 0x800 +} CXObjCPropertyAttrKind; + +/** + * \brief Given a cursor that represents a property declaration, return the + * associated property attributes. The bits are formed from + * \c CXObjCPropertyAttrKind. + * + * \param reserved Reserved for future use, pass 0. + */ +CINDEX_LINKAGE unsigned clang_Cursor_getObjCPropertyAttributes(CXCursor C, + unsigned reserved); + +/** + * \brief 'Qualifiers' written next to the return and parameter types in + * Objective-C method declarations. + */ +typedef enum { + CXObjCDeclQualifier_None = 0x0, + CXObjCDeclQualifier_In = 0x1, + CXObjCDeclQualifier_Inout = 0x2, + CXObjCDeclQualifier_Out = 0x4, + CXObjCDeclQualifier_Bycopy = 0x8, + CXObjCDeclQualifier_Byref = 0x10, + CXObjCDeclQualifier_Oneway = 0x20 +} CXObjCDeclQualifierKind; + +/** + * \brief Given a cursor that represents an Objective-C method or parameter + * declaration, return the associated Objective-C qualifiers for the return + * type or the parameter respectively. The bits are formed from + * CXObjCDeclQualifierKind. + */ +CINDEX_LINKAGE unsigned clang_Cursor_getObjCDeclQualifiers(CXCursor C); + +/** + * \brief Given a cursor that represents an Objective-C method or property + * declaration, return non-zero if the declaration was affected by "@optional". + * Returns zero if the cursor is not such a declaration or it is "@required". + */ +CINDEX_LINKAGE unsigned clang_Cursor_isObjCOptional(CXCursor C); + +/** + * \brief Returns non-zero if the given cursor is a variadic function or method. + */ +CINDEX_LINKAGE unsigned clang_Cursor_isVariadic(CXCursor C); + +/** + * \brief Given a cursor that represents a declaration, return the associated + * comment's source range. The range may include multiple consecutive comments + * with whitespace in between. + */ +CINDEX_LINKAGE CXSourceRange clang_Cursor_getCommentRange(CXCursor C); + +/** + * \brief Given a cursor that represents a declaration, return the associated + * comment text, including comment markers. + */ +CINDEX_LINKAGE CXString clang_Cursor_getRawCommentText(CXCursor C); + +/** + * \brief Given a cursor that represents a documentable entity (e.g., + * declaration), return the associated \\brief paragraph; otherwise return the + * first paragraph. + */ +CINDEX_LINKAGE CXString clang_Cursor_getBriefCommentText(CXCursor C); + +/** + * @} + */ + +/** \defgroup CINDEX_MANGLE Name Mangling API Functions + * + * @{ + */ + +/** + * \brief Retrieve the CXString representing the mangled name of the cursor. + */ +CINDEX_LINKAGE CXString clang_Cursor_getMangling(CXCursor); + +/** + * \brief Retrieve the CXStrings representing the mangled symbols of the C++ + * constructor or destructor at the cursor. + */ +CINDEX_LINKAGE CXStringSet *clang_Cursor_getCXXManglings(CXCursor); + +/** + * @} + */ + +/** + * \defgroup CINDEX_MODULE Module introspection + * + * The functions in this group provide access to information about modules. + * + * @{ + */ + +typedef void *CXModule; + +/** + * \brief Given a CXCursor_ModuleImportDecl cursor, return the associated module. + */ +CINDEX_LINKAGE CXModule clang_Cursor_getModule(CXCursor C); + +/** + * \brief Given a CXFile header file, return the module that contains it, if one + * exists. + */ +CINDEX_LINKAGE CXModule clang_getModuleForFile(CXTranslationUnit, CXFile); + +/** + * \param Module a module object. + * + * \returns the module file where the provided module object came from. + */ +CINDEX_LINKAGE CXFile clang_Module_getASTFile(CXModule Module); + +/** + * \param Module a module object. + * + * \returns the parent of a sub-module or NULL if the given module is top-level, + * e.g. for 'std.vector' it will return the 'std' module. + */ +CINDEX_LINKAGE CXModule clang_Module_getParent(CXModule Module); + +/** + * \param Module a module object. + * + * \returns the name of the module, e.g. for the 'std.vector' sub-module it + * will return "vector". + */ +CINDEX_LINKAGE CXString clang_Module_getName(CXModule Module); + +/** + * \param Module a module object. + * + * \returns the full name of the module, e.g. "std.vector". + */ +CINDEX_LINKAGE CXString clang_Module_getFullName(CXModule Module); + +/** + * \param Module a module object. + * + * \returns non-zero if the module is a system one. + */ +CINDEX_LINKAGE int clang_Module_isSystem(CXModule Module); + +/** + * \param Module a module object. + * + * \returns the number of top level headers associated with this module. + */ +CINDEX_LINKAGE unsigned clang_Module_getNumTopLevelHeaders(CXTranslationUnit, + CXModule Module); + +/** + * \param Module a module object. + * + * \param Index top level header index (zero-based). + * + * \returns the specified top level header associated with the module. + */ +CINDEX_LINKAGE +CXFile clang_Module_getTopLevelHeader(CXTranslationUnit, + CXModule Module, unsigned Index); + +/** + * @} + */ + +/** + * \defgroup CINDEX_CPP C++ AST introspection + * + * The routines in this group provide access information in the ASTs specific + * to C++ language features. + * + * @{ + */ + +/** + * \brief Determine if a C++ field is declared 'mutable'. + */ +CINDEX_LINKAGE unsigned clang_CXXField_isMutable(CXCursor C); + +/** + * \brief Determine if a C++ member function or member function template is + * pure virtual. + */ +CINDEX_LINKAGE unsigned clang_CXXMethod_isPureVirtual(CXCursor C); + +/** + * \brief Determine if a C++ member function or member function template is + * declared 'static'. + */ +CINDEX_LINKAGE unsigned clang_CXXMethod_isStatic(CXCursor C); + +/** + * \brief Determine if a C++ member function or member function template is + * explicitly declared 'virtual' or if it overrides a virtual method from + * one of the base classes. + */ +CINDEX_LINKAGE unsigned clang_CXXMethod_isVirtual(CXCursor C); + +/** + * \brief Determine if a C++ member function or member function template is + * declared 'const'. + */ +CINDEX_LINKAGE unsigned clang_CXXMethod_isConst(CXCursor C); + +/** + * \brief Given a cursor that represents a template, determine + * the cursor kind of the specializations would be generated by instantiating + * the template. + * + * This routine can be used to determine what flavor of function template, + * class template, or class template partial specialization is stored in the + * cursor. For example, it can describe whether a class template cursor is + * declared with "struct", "class" or "union". + * + * \param C The cursor to query. This cursor should represent a template + * declaration. + * + * \returns The cursor kind of the specializations that would be generated + * by instantiating the template \p C. If \p C is not a template, returns + * \c CXCursor_NoDeclFound. + */ +CINDEX_LINKAGE enum CXCursorKind clang_getTemplateCursorKind(CXCursor C); + +/** + * \brief Given a cursor that may represent a specialization or instantiation + * of a template, retrieve the cursor that represents the template that it + * specializes or from which it was instantiated. + * + * This routine determines the template involved both for explicit + * specializations of templates and for implicit instantiations of the template, + * both of which are referred to as "specializations". For a class template + * specialization (e.g., \c std::vector<bool>), this routine will return + * either the primary template (\c std::vector) or, if the specialization was + * instantiated from a class template partial specialization, the class template + * partial specialization. For a class template partial specialization and a + * function template specialization (including instantiations), this + * this routine will return the specialized template. + * + * For members of a class template (e.g., member functions, member classes, or + * static data members), returns the specialized or instantiated member. + * Although not strictly "templates" in the C++ language, members of class + * templates have the same notions of specializations and instantiations that + * templates do, so this routine treats them similarly. + * + * \param C A cursor that may be a specialization of a template or a member + * of a template. + * + * \returns If the given cursor is a specialization or instantiation of a + * template or a member thereof, the template or member that it specializes or + * from which it was instantiated. Otherwise, returns a NULL cursor. + */ +CINDEX_LINKAGE CXCursor clang_getSpecializedCursorTemplate(CXCursor C); + +/** + * \brief Given a cursor that references something else, return the source range + * covering that reference. + * + * \param C A cursor pointing to a member reference, a declaration reference, or + * an operator call. + * \param NameFlags A bitset with three independent flags: + * CXNameRange_WantQualifier, CXNameRange_WantTemplateArgs, and + * CXNameRange_WantSinglePiece. + * \param PieceIndex For contiguous names or when passing the flag + * CXNameRange_WantSinglePiece, only one piece with index 0 is + * available. When the CXNameRange_WantSinglePiece flag is not passed for a + * non-contiguous names, this index can be used to retrieve the individual + * pieces of the name. See also CXNameRange_WantSinglePiece. + * + * \returns The piece of the name pointed to by the given cursor. If there is no + * name, or if the PieceIndex is out-of-range, a null-cursor will be returned. + */ +CINDEX_LINKAGE CXSourceRange clang_getCursorReferenceNameRange(CXCursor C, + unsigned NameFlags, + unsigned PieceIndex); + +enum CXNameRefFlags { + /** + * \brief Include the nested-name-specifier, e.g. Foo:: in x.Foo::y, in the + * range. + */ + CXNameRange_WantQualifier = 0x1, + + /** + * \brief Include the explicit template arguments, e.g. \<int> in x.f<int>, + * in the range. + */ + CXNameRange_WantTemplateArgs = 0x2, + + /** + * \brief If the name is non-contiguous, return the full spanning range. + * + * Non-contiguous names occur in Objective-C when a selector with two or more + * parameters is used, or in C++ when using an operator: + * \code + * [object doSomething:here withValue:there]; // Objective-C + * return some_vector[1]; // C++ + * \endcode + */ + CXNameRange_WantSinglePiece = 0x4 +}; + +/** + * @} + */ + +/** + * \defgroup CINDEX_LEX Token extraction and manipulation + * + * The routines in this group provide access to the tokens within a + * translation unit, along with a semantic mapping of those tokens to + * their corresponding cursors. + * + * @{ + */ + +/** + * \brief Describes a kind of token. + */ +typedef enum CXTokenKind { + /** + * \brief A token that contains some kind of punctuation. + */ + CXToken_Punctuation, + + /** + * \brief A language keyword. + */ + CXToken_Keyword, + + /** + * \brief An identifier (that is not a keyword). + */ + CXToken_Identifier, + + /** + * \brief A numeric, string, or character literal. + */ + CXToken_Literal, + + /** + * \brief A comment. + */ + CXToken_Comment +} CXTokenKind; + +/** + * \brief Describes a single preprocessing token. + */ +typedef struct { + unsigned int_data[4]; + void *ptr_data; +} CXToken; + +/** + * \brief Determine the kind of the given token. + */ +CINDEX_LINKAGE CXTokenKind clang_getTokenKind(CXToken); + +/** + * \brief Determine the spelling of the given token. + * + * The spelling of a token is the textual representation of that token, e.g., + * the text of an identifier or keyword. + */ +CINDEX_LINKAGE CXString clang_getTokenSpelling(CXTranslationUnit, CXToken); + +/** + * \brief Retrieve the source location of the given token. + */ +CINDEX_LINKAGE CXSourceLocation clang_getTokenLocation(CXTranslationUnit, + CXToken); + +/** + * \brief Retrieve a source range that covers the given token. + */ +CINDEX_LINKAGE CXSourceRange clang_getTokenExtent(CXTranslationUnit, CXToken); + +/** + * \brief Tokenize the source code described by the given range into raw + * lexical tokens. + * + * \param TU the translation unit whose text is being tokenized. + * + * \param Range the source range in which text should be tokenized. All of the + * tokens produced by tokenization will fall within this source range, + * + * \param Tokens this pointer will be set to point to the array of tokens + * that occur within the given source range. The returned pointer must be + * freed with clang_disposeTokens() before the translation unit is destroyed. + * + * \param NumTokens will be set to the number of tokens in the \c *Tokens + * array. + * + */ +CINDEX_LINKAGE void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range, + CXToken **Tokens, unsigned *NumTokens); + +/** + * \brief Annotate the given set of tokens by providing cursors for each token + * that can be mapped to a specific entity within the abstract syntax tree. + * + * This token-annotation routine is equivalent to invoking + * clang_getCursor() for the source locations of each of the + * tokens. The cursors provided are filtered, so that only those + * cursors that have a direct correspondence to the token are + * accepted. For example, given a function call \c f(x), + * clang_getCursor() would provide the following cursors: + * + * * when the cursor is over the 'f', a DeclRefExpr cursor referring to 'f'. + * * when the cursor is over the '(' or the ')', a CallExpr referring to 'f'. + * * when the cursor is over the 'x', a DeclRefExpr cursor referring to 'x'. + * + * Only the first and last of these cursors will occur within the + * annotate, since the tokens "f" and "x' directly refer to a function + * and a variable, respectively, but the parentheses are just a small + * part of the full syntax of the function call expression, which is + * not provided as an annotation. + * + * \param TU the translation unit that owns the given tokens. + * + * \param Tokens the set of tokens to annotate. + * + * \param NumTokens the number of tokens in \p Tokens. + * + * \param Cursors an array of \p NumTokens cursors, whose contents will be + * replaced with the cursors corresponding to each token. + */ +CINDEX_LINKAGE void clang_annotateTokens(CXTranslationUnit TU, + CXToken *Tokens, unsigned NumTokens, + CXCursor *Cursors); + +/** + * \brief Free the given set of tokens. + */ +CINDEX_LINKAGE void clang_disposeTokens(CXTranslationUnit TU, + CXToken *Tokens, unsigned NumTokens); + +/** + * @} + */ + +/** + * \defgroup CINDEX_DEBUG Debugging facilities + * + * These routines are used for testing and debugging, only, and should not + * be relied upon. + * + * @{ + */ + +/* for debug/testing */ +CINDEX_LINKAGE CXString clang_getCursorKindSpelling(enum CXCursorKind Kind); +CINDEX_LINKAGE void clang_getDefinitionSpellingAndExtent(CXCursor, + const char **startBuf, + const char **endBuf, + unsigned *startLine, + unsigned *startColumn, + unsigned *endLine, + unsigned *endColumn); +CINDEX_LINKAGE void clang_enableStackTraces(void); +CINDEX_LINKAGE void clang_executeOnThread(void (*fn)(void*), void *user_data, + unsigned stack_size); + +/** + * @} + */ + +/** + * \defgroup CINDEX_CODE_COMPLET Code completion + * + * Code completion involves taking an (incomplete) source file, along with + * knowledge of where the user is actively editing that file, and suggesting + * syntactically- and semantically-valid constructs that the user might want to + * use at that particular point in the source code. These data structures and + * routines provide support for code completion. + * + * @{ + */ + +/** + * \brief A semantic string that describes a code-completion result. + * + * A semantic string that describes the formatting of a code-completion + * result as a single "template" of text that should be inserted into the + * source buffer when a particular code-completion result is selected. + * Each semantic string is made up of some number of "chunks", each of which + * contains some text along with a description of what that text means, e.g., + * the name of the entity being referenced, whether the text chunk is part of + * the template, or whether it is a "placeholder" that the user should replace + * with actual code,of a specific kind. See \c CXCompletionChunkKind for a + * description of the different kinds of chunks. + */ +typedef void *CXCompletionString; + +/** + * \brief A single result of code completion. + */ +typedef struct { + /** + * \brief The kind of entity that this completion refers to. + * + * The cursor kind will be a macro, keyword, or a declaration (one of the + * *Decl cursor kinds), describing the entity that the completion is + * referring to. + * + * \todo In the future, we would like to provide a full cursor, to allow + * the client to extract additional information from declaration. + */ + enum CXCursorKind CursorKind; + + /** + * \brief The code-completion string that describes how to insert this + * code-completion result into the editing buffer. + */ + CXCompletionString CompletionString; +} CXCompletionResult; + +/** + * \brief Describes a single piece of text within a code-completion string. + * + * Each "chunk" within a code-completion string (\c CXCompletionString) is + * either a piece of text with a specific "kind" that describes how that text + * should be interpreted by the client or is another completion string. + */ +enum CXCompletionChunkKind { + /** + * \brief A code-completion string that describes "optional" text that + * could be a part of the template (but is not required). + * + * The Optional chunk is the only kind of chunk that has a code-completion + * string for its representation, which is accessible via + * \c clang_getCompletionChunkCompletionString(). The code-completion string + * describes an additional part of the template that is completely optional. + * For example, optional chunks can be used to describe the placeholders for + * arguments that match up with defaulted function parameters, e.g. given: + * + * \code + * void f(int x, float y = 3.14, double z = 2.71828); + * \endcode + * + * The code-completion string for this function would contain: + * - a TypedText chunk for "f". + * - a LeftParen chunk for "(". + * - a Placeholder chunk for "int x" + * - an Optional chunk containing the remaining defaulted arguments, e.g., + * - a Comma chunk for "," + * - a Placeholder chunk for "float y" + * - an Optional chunk containing the last defaulted argument: + * - a Comma chunk for "," + * - a Placeholder chunk for "double z" + * - a RightParen chunk for ")" + * + * There are many ways to handle Optional chunks. Two simple approaches are: + * - Completely ignore optional chunks, in which case the template for the + * function "f" would only include the first parameter ("int x"). + * - Fully expand all optional chunks, in which case the template for the + * function "f" would have all of the parameters. + */ + CXCompletionChunk_Optional, + /** + * \brief Text that a user would be expected to type to get this + * code-completion result. + * + * There will be exactly one "typed text" chunk in a semantic string, which + * will typically provide the spelling of a keyword or the name of a + * declaration that could be used at the current code point. Clients are + * expected to filter the code-completion results based on the text in this + * chunk. + */ + CXCompletionChunk_TypedText, + /** + * \brief Text that should be inserted as part of a code-completion result. + * + * A "text" chunk represents text that is part of the template to be + * inserted into user code should this particular code-completion result + * be selected. + */ + CXCompletionChunk_Text, + /** + * \brief Placeholder text that should be replaced by the user. + * + * A "placeholder" chunk marks a place where the user should insert text + * into the code-completion template. For example, placeholders might mark + * the function parameters for a function declaration, to indicate that the + * user should provide arguments for each of those parameters. The actual + * text in a placeholder is a suggestion for the text to display before + * the user replaces the placeholder with real code. + */ + CXCompletionChunk_Placeholder, + /** + * \brief Informative text that should be displayed but never inserted as + * part of the template. + * + * An "informative" chunk contains annotations that can be displayed to + * help the user decide whether a particular code-completion result is the + * right option, but which is not part of the actual template to be inserted + * by code completion. + */ + CXCompletionChunk_Informative, + /** + * \brief Text that describes the current parameter when code-completion is + * referring to function call, message send, or template specialization. + * + * A "current parameter" chunk occurs when code-completion is providing + * information about a parameter corresponding to the argument at the + * code-completion point. For example, given a function + * + * \code + * int add(int x, int y); + * \endcode + * + * and the source code \c add(, where the code-completion point is after the + * "(", the code-completion string will contain a "current parameter" chunk + * for "int x", indicating that the current argument will initialize that + * parameter. After typing further, to \c add(17, (where the code-completion + * point is after the ","), the code-completion string will contain a + * "current paremeter" chunk to "int y". + */ + CXCompletionChunk_CurrentParameter, + /** + * \brief A left parenthesis ('('), used to initiate a function call or + * signal the beginning of a function parameter list. + */ + CXCompletionChunk_LeftParen, + /** + * \brief A right parenthesis (')'), used to finish a function call or + * signal the end of a function parameter list. + */ + CXCompletionChunk_RightParen, + /** + * \brief A left bracket ('['). + */ + CXCompletionChunk_LeftBracket, + /** + * \brief A right bracket (']'). + */ + CXCompletionChunk_RightBracket, + /** + * \brief A left brace ('{'). + */ + CXCompletionChunk_LeftBrace, + /** + * \brief A right brace ('}'). + */ + CXCompletionChunk_RightBrace, + /** + * \brief A left angle bracket ('<'). + */ + CXCompletionChunk_LeftAngle, + /** + * \brief A right angle bracket ('>'). + */ + CXCompletionChunk_RightAngle, + /** + * \brief A comma separator (','). + */ + CXCompletionChunk_Comma, + /** + * \brief Text that specifies the result type of a given result. + * + * This special kind of informative chunk is not meant to be inserted into + * the text buffer. Rather, it is meant to illustrate the type that an + * expression using the given completion string would have. + */ + CXCompletionChunk_ResultType, + /** + * \brief A colon (':'). + */ + CXCompletionChunk_Colon, + /** + * \brief A semicolon (';'). + */ + CXCompletionChunk_SemiColon, + /** + * \brief An '=' sign. + */ + CXCompletionChunk_Equal, + /** + * Horizontal space (' '). + */ + CXCompletionChunk_HorizontalSpace, + /** + * Vertical space ('\n'), after which it is generally a good idea to + * perform indentation. + */ + CXCompletionChunk_VerticalSpace +}; + +/** + * \brief Determine the kind of a particular chunk within a completion string. + * + * \param completion_string the completion string to query. + * + * \param chunk_number the 0-based index of the chunk in the completion string. + * + * \returns the kind of the chunk at the index \c chunk_number. + */ +CINDEX_LINKAGE enum CXCompletionChunkKind +clang_getCompletionChunkKind(CXCompletionString completion_string, + unsigned chunk_number); + +/** + * \brief Retrieve the text associated with a particular chunk within a + * completion string. + * + * \param completion_string the completion string to query. + * + * \param chunk_number the 0-based index of the chunk in the completion string. + * + * \returns the text associated with the chunk at index \c chunk_number. + */ +CINDEX_LINKAGE CXString +clang_getCompletionChunkText(CXCompletionString completion_string, + unsigned chunk_number); + +/** + * \brief Retrieve the completion string associated with a particular chunk + * within a completion string. + * + * \param completion_string the completion string to query. + * + * \param chunk_number the 0-based index of the chunk in the completion string. + * + * \returns the completion string associated with the chunk at index + * \c chunk_number. + */ +CINDEX_LINKAGE CXCompletionString +clang_getCompletionChunkCompletionString(CXCompletionString completion_string, + unsigned chunk_number); + +/** + * \brief Retrieve the number of chunks in the given code-completion string. + */ +CINDEX_LINKAGE unsigned +clang_getNumCompletionChunks(CXCompletionString completion_string); + +/** + * \brief Determine the priority of this code completion. + * + * The priority of a code completion indicates how likely it is that this + * particular completion is the completion that the user will select. The + * priority is selected by various internal heuristics. + * + * \param completion_string The completion string to query. + * + * \returns The priority of this completion string. Smaller values indicate + * higher-priority (more likely) completions. + */ +CINDEX_LINKAGE unsigned +clang_getCompletionPriority(CXCompletionString completion_string); + +/** + * \brief Determine the availability of the entity that this code-completion + * string refers to. + * + * \param completion_string The completion string to query. + * + * \returns The availability of the completion string. + */ +CINDEX_LINKAGE enum CXAvailabilityKind +clang_getCompletionAvailability(CXCompletionString completion_string); + +/** + * \brief Retrieve the number of annotations associated with the given + * completion string. + * + * \param completion_string the completion string to query. + * + * \returns the number of annotations associated with the given completion + * string. + */ +CINDEX_LINKAGE unsigned +clang_getCompletionNumAnnotations(CXCompletionString completion_string); + +/** + * \brief Retrieve the annotation associated with the given completion string. + * + * \param completion_string the completion string to query. + * + * \param annotation_number the 0-based index of the annotation of the + * completion string. + * + * \returns annotation string associated with the completion at index + * \c annotation_number, or a NULL string if that annotation is not available. + */ +CINDEX_LINKAGE CXString +clang_getCompletionAnnotation(CXCompletionString completion_string, + unsigned annotation_number); + +/** + * \brief Retrieve the parent context of the given completion string. + * + * The parent context of a completion string is the semantic parent of + * the declaration (if any) that the code completion represents. For example, + * a code completion for an Objective-C method would have the method's class + * or protocol as its context. + * + * \param completion_string The code completion string whose parent is + * being queried. + * + * \param kind DEPRECATED: always set to CXCursor_NotImplemented if non-NULL. + * + * \returns The name of the completion parent, e.g., "NSObject" if + * the completion string represents a method in the NSObject class. + */ +CINDEX_LINKAGE CXString +clang_getCompletionParent(CXCompletionString completion_string, + enum CXCursorKind *kind); + +/** + * \brief Retrieve the brief documentation comment attached to the declaration + * that corresponds to the given completion string. + */ +CINDEX_LINKAGE CXString +clang_getCompletionBriefComment(CXCompletionString completion_string); + +/** + * \brief Retrieve a completion string for an arbitrary declaration or macro + * definition cursor. + * + * \param cursor The cursor to query. + * + * \returns A non-context-sensitive completion string for declaration and macro + * definition cursors, or NULL for other kinds of cursors. + */ +CINDEX_LINKAGE CXCompletionString +clang_getCursorCompletionString(CXCursor cursor); + +/** + * \brief Contains the results of code-completion. + * + * This data structure contains the results of code completion, as + * produced by \c clang_codeCompleteAt(). Its contents must be freed by + * \c clang_disposeCodeCompleteResults. + */ +typedef struct { + /** + * \brief The code-completion results. + */ + CXCompletionResult *Results; + + /** + * \brief The number of code-completion results stored in the + * \c Results array. + */ + unsigned NumResults; +} CXCodeCompleteResults; + +/** + * \brief Flags that can be passed to \c clang_codeCompleteAt() to + * modify its behavior. + * + * The enumerators in this enumeration can be bitwise-OR'd together to + * provide multiple options to \c clang_codeCompleteAt(). + */ +enum CXCodeComplete_Flags { + /** + * \brief Whether to include macros within the set of code + * completions returned. + */ + CXCodeComplete_IncludeMacros = 0x01, + + /** + * \brief Whether to include code patterns for language constructs + * within the set of code completions, e.g., for loops. + */ + CXCodeComplete_IncludeCodePatterns = 0x02, + + /** + * \brief Whether to include brief documentation within the set of code + * completions returned. + */ + CXCodeComplete_IncludeBriefComments = 0x04 +}; + +/** + * \brief Bits that represent the context under which completion is occurring. + * + * The enumerators in this enumeration may be bitwise-OR'd together if multiple + * contexts are occurring simultaneously. + */ +enum CXCompletionContext { + /** + * \brief The context for completions is unexposed, as only Clang results + * should be included. (This is equivalent to having no context bits set.) + */ + CXCompletionContext_Unexposed = 0, + + /** + * \brief Completions for any possible type should be included in the results. + */ + CXCompletionContext_AnyType = 1 << 0, + + /** + * \brief Completions for any possible value (variables, function calls, etc.) + * should be included in the results. + */ + CXCompletionContext_AnyValue = 1 << 1, + /** + * \brief Completions for values that resolve to an Objective-C object should + * be included in the results. + */ + CXCompletionContext_ObjCObjectValue = 1 << 2, + /** + * \brief Completions for values that resolve to an Objective-C selector + * should be included in the results. + */ + CXCompletionContext_ObjCSelectorValue = 1 << 3, + /** + * \brief Completions for values that resolve to a C++ class type should be + * included in the results. + */ + CXCompletionContext_CXXClassTypeValue = 1 << 4, + + /** + * \brief Completions for fields of the member being accessed using the dot + * operator should be included in the results. + */ + CXCompletionContext_DotMemberAccess = 1 << 5, + /** + * \brief Completions for fields of the member being accessed using the arrow + * operator should be included in the results. + */ + CXCompletionContext_ArrowMemberAccess = 1 << 6, + /** + * \brief Completions for properties of the Objective-C object being accessed + * using the dot operator should be included in the results. + */ + CXCompletionContext_ObjCPropertyAccess = 1 << 7, + + /** + * \brief Completions for enum tags should be included in the results. + */ + CXCompletionContext_EnumTag = 1 << 8, + /** + * \brief Completions for union tags should be included in the results. + */ + CXCompletionContext_UnionTag = 1 << 9, + /** + * \brief Completions for struct tags should be included in the results. + */ + CXCompletionContext_StructTag = 1 << 10, + + /** + * \brief Completions for C++ class names should be included in the results. + */ + CXCompletionContext_ClassTag = 1 << 11, + /** + * \brief Completions for C++ namespaces and namespace aliases should be + * included in the results. + */ + CXCompletionContext_Namespace = 1 << 12, + /** + * \brief Completions for C++ nested name specifiers should be included in + * the results. + */ + CXCompletionContext_NestedNameSpecifier = 1 << 13, + + /** + * \brief Completions for Objective-C interfaces (classes) should be included + * in the results. + */ + CXCompletionContext_ObjCInterface = 1 << 14, + /** + * \brief Completions for Objective-C protocols should be included in + * the results. + */ + CXCompletionContext_ObjCProtocol = 1 << 15, + /** + * \brief Completions for Objective-C categories should be included in + * the results. + */ + CXCompletionContext_ObjCCategory = 1 << 16, + /** + * \brief Completions for Objective-C instance messages should be included + * in the results. + */ + CXCompletionContext_ObjCInstanceMessage = 1 << 17, + /** + * \brief Completions for Objective-C class messages should be included in + * the results. + */ + CXCompletionContext_ObjCClassMessage = 1 << 18, + /** + * \brief Completions for Objective-C selector names should be included in + * the results. + */ + CXCompletionContext_ObjCSelectorName = 1 << 19, + + /** + * \brief Completions for preprocessor macro names should be included in + * the results. + */ + CXCompletionContext_MacroName = 1 << 20, + + /** + * \brief Natural language completions should be included in the results. + */ + CXCompletionContext_NaturalLanguage = 1 << 21, + + /** + * \brief The current context is unknown, so set all contexts. + */ + CXCompletionContext_Unknown = ((1 << 22) - 1) +}; + +/** + * \brief Returns a default set of code-completion options that can be + * passed to\c clang_codeCompleteAt(). + */ +CINDEX_LINKAGE unsigned clang_defaultCodeCompleteOptions(void); + +/** + * \brief Perform code completion at a given location in a translation unit. + * + * This function performs code completion at a particular file, line, and + * column within source code, providing results that suggest potential + * code snippets based on the context of the completion. The basic model + * for code completion is that Clang will parse a complete source file, + * performing syntax checking up to the location where code-completion has + * been requested. At that point, a special code-completion token is passed + * to the parser, which recognizes this token and determines, based on the + * current location in the C/Objective-C/C++ grammar and the state of + * semantic analysis, what completions to provide. These completions are + * returned via a new \c CXCodeCompleteResults structure. + * + * Code completion itself is meant to be triggered by the client when the + * user types punctuation characters or whitespace, at which point the + * code-completion location will coincide with the cursor. For example, if \c p + * is a pointer, code-completion might be triggered after the "-" and then + * after the ">" in \c p->. When the code-completion location is afer the ">", + * the completion results will provide, e.g., the members of the struct that + * "p" points to. The client is responsible for placing the cursor at the + * beginning of the token currently being typed, then filtering the results + * based on the contents of the token. For example, when code-completing for + * the expression \c p->get, the client should provide the location just after + * the ">" (e.g., pointing at the "g") to this code-completion hook. Then, the + * client can filter the results based on the current token text ("get"), only + * showing those results that start with "get". The intent of this interface + * is to separate the relatively high-latency acquisition of code-completion + * results from the filtering of results on a per-character basis, which must + * have a lower latency. + * + * \param TU The translation unit in which code-completion should + * occur. The source files for this translation unit need not be + * completely up-to-date (and the contents of those source files may + * be overridden via \p unsaved_files). Cursors referring into the + * translation unit may be invalidated by this invocation. + * + * \param complete_filename The name of the source file where code + * completion should be performed. This filename may be any file + * included in the translation unit. + * + * \param complete_line The line at which code-completion should occur. + * + * \param complete_column The column at which code-completion should occur. + * Note that the column should point just after the syntactic construct that + * initiated code completion, and not in the middle of a lexical token. + * + * \param unsaved_files the Tiles that have not yet been saved to disk + * but may be required for parsing or code completion, including the + * contents of those files. The contents and name of these files (as + * specified by CXUnsavedFile) are copied when necessary, so the + * client only needs to guarantee their validity until the call to + * this function returns. + * + * \param num_unsaved_files The number of unsaved file entries in \p + * unsaved_files. + * + * \param options Extra options that control the behavior of code + * completion, expressed as a bitwise OR of the enumerators of the + * CXCodeComplete_Flags enumeration. The + * \c clang_defaultCodeCompleteOptions() function returns a default set + * of code-completion options. + * + * \returns If successful, a new \c CXCodeCompleteResults structure + * containing code-completion results, which should eventually be + * freed with \c clang_disposeCodeCompleteResults(). If code + * completion fails, returns NULL. + */ +CINDEX_LINKAGE +CXCodeCompleteResults *clang_codeCompleteAt(CXTranslationUnit TU, + const char *complete_filename, + unsigned complete_line, + unsigned complete_column, + struct CXUnsavedFile *unsaved_files, + unsigned num_unsaved_files, + unsigned options); + +/** + * \brief Sort the code-completion results in case-insensitive alphabetical + * order. + * + * \param Results The set of results to sort. + * \param NumResults The number of results in \p Results. + */ +CINDEX_LINKAGE +void clang_sortCodeCompletionResults(CXCompletionResult *Results, + unsigned NumResults); + +/** + * \brief Free the given set of code-completion results. + */ +CINDEX_LINKAGE +void clang_disposeCodeCompleteResults(CXCodeCompleteResults *Results); + +/** + * \brief Determine the number of diagnostics produced prior to the + * location where code completion was performed. + */ +CINDEX_LINKAGE +unsigned clang_codeCompleteGetNumDiagnostics(CXCodeCompleteResults *Results); + +/** + * \brief Retrieve a diagnostic associated with the given code completion. + * + * \param Results the code completion results to query. + * \param Index the zero-based diagnostic number to retrieve. + * + * \returns the requested diagnostic. This diagnostic must be freed + * via a call to \c clang_disposeDiagnostic(). + */ +CINDEX_LINKAGE +CXDiagnostic clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *Results, + unsigned Index); + +/** + * \brief Determines what completions are appropriate for the context + * the given code completion. + * + * \param Results the code completion results to query + * + * \returns the kinds of completions that are appropriate for use + * along with the given code completion results. + */ +CINDEX_LINKAGE +unsigned long long clang_codeCompleteGetContexts( + CXCodeCompleteResults *Results); + +/** + * \brief Returns the cursor kind for the container for the current code + * completion context. The container is only guaranteed to be set for + * contexts where a container exists (i.e. member accesses or Objective-C + * message sends); if there is not a container, this function will return + * CXCursor_InvalidCode. + * + * \param Results the code completion results to query + * + * \param IsIncomplete on return, this value will be false if Clang has complete + * information about the container. If Clang does not have complete + * information, this value will be true. + * + * \returns the container kind, or CXCursor_InvalidCode if there is not a + * container + */ +CINDEX_LINKAGE +enum CXCursorKind clang_codeCompleteGetContainerKind( + CXCodeCompleteResults *Results, + unsigned *IsIncomplete); + +/** + * \brief Returns the USR for the container for the current code completion + * context. If there is not a container for the current context, this + * function will return the empty string. + * + * \param Results the code completion results to query + * + * \returns the USR for the container + */ +CINDEX_LINKAGE +CXString clang_codeCompleteGetContainerUSR(CXCodeCompleteResults *Results); + +/** + * \brief Returns the currently-entered selector for an Objective-C message + * send, formatted like "initWithFoo:bar:". Only guaranteed to return a + * non-empty string for CXCompletionContext_ObjCInstanceMessage and + * CXCompletionContext_ObjCClassMessage. + * + * \param Results the code completion results to query + * + * \returns the selector (or partial selector) that has been entered thus far + * for an Objective-C message send. + */ +CINDEX_LINKAGE +CXString clang_codeCompleteGetObjCSelector(CXCodeCompleteResults *Results); + +/** + * @} + */ + +/** + * \defgroup CINDEX_MISC Miscellaneous utility functions + * + * @{ + */ + +/** + * \brief Return a version string, suitable for showing to a user, but not + * intended to be parsed (the format is not guaranteed to be stable). + */ +CINDEX_LINKAGE CXString clang_getClangVersion(void); + +/** + * \brief Enable/disable crash recovery. + * + * \param isEnabled Flag to indicate if crash recovery is enabled. A non-zero + * value enables crash recovery, while 0 disables it. + */ +CINDEX_LINKAGE void clang_toggleCrashRecovery(unsigned isEnabled); + + /** + * \brief Visitor invoked for each file in a translation unit + * (used with clang_getInclusions()). + * + * This visitor function will be invoked by clang_getInclusions() for each + * file included (either at the top-level or by \#include directives) within + * a translation unit. The first argument is the file being included, and + * the second and third arguments provide the inclusion stack. The + * array is sorted in order of immediate inclusion. For example, + * the first element refers to the location that included 'included_file'. + */ +typedef void (*CXInclusionVisitor)(CXFile included_file, + CXSourceLocation* inclusion_stack, + unsigned include_len, + CXClientData client_data); + +/** + * \brief Visit the set of preprocessor inclusions in a translation unit. + * The visitor function is called with the provided data for every included + * file. This does not include headers included by the PCH file (unless one + * is inspecting the inclusions in the PCH file itself). + */ +CINDEX_LINKAGE void clang_getInclusions(CXTranslationUnit tu, + CXInclusionVisitor visitor, + CXClientData client_data); + +/** + * @} + */ + +/** \defgroup CINDEX_REMAPPING Remapping functions + * + * @{ + */ + +/** + * \brief A remapping of original source files and their translated files. + */ +typedef void *CXRemapping; + +/** + * \brief Retrieve a remapping. + * + * \param path the path that contains metadata about remappings. + * + * \returns the requested remapping. This remapping must be freed + * via a call to \c clang_remap_dispose(). Can return NULL if an error occurred. + */ +CINDEX_LINKAGE CXRemapping clang_getRemappings(const char *path); + +/** + * \brief Retrieve a remapping. + * + * \param filePaths pointer to an array of file paths containing remapping info. + * + * \param numFiles number of file paths. + * + * \returns the requested remapping. This remapping must be freed + * via a call to \c clang_remap_dispose(). Can return NULL if an error occurred. + */ +CINDEX_LINKAGE +CXRemapping clang_getRemappingsFromFileList(const char **filePaths, + unsigned numFiles); + +/** + * \brief Determine the number of remappings. + */ +CINDEX_LINKAGE unsigned clang_remap_getNumFiles(CXRemapping); + +/** + * \brief Get the original and the associated filename from the remapping. + * + * \param original If non-NULL, will be set to the original filename. + * + * \param transformed If non-NULL, will be set to the filename that the original + * is associated with. + */ +CINDEX_LINKAGE void clang_remap_getFilenames(CXRemapping, unsigned index, + CXString *original, CXString *transformed); + +/** + * \brief Dispose the remapping. + */ +CINDEX_LINKAGE void clang_remap_dispose(CXRemapping); + +/** + * @} + */ + +/** \defgroup CINDEX_HIGH Higher level API functions + * + * @{ + */ + +enum CXVisitorResult { + CXVisit_Break, + CXVisit_Continue +}; + +typedef struct { + void *context; + enum CXVisitorResult (*visit)(void *context, CXCursor, CXSourceRange); +} CXCursorAndRangeVisitor; + +typedef enum { + /** + * \brief Function returned successfully. + */ + CXResult_Success = 0, + /** + * \brief One of the parameters was invalid for the function. + */ + CXResult_Invalid = 1, + /** + * \brief The function was terminated by a callback (e.g. it returned + * CXVisit_Break) + */ + CXResult_VisitBreak = 2 + +} CXResult; + +/** + * \brief Find references of a declaration in a specific file. + * + * \param cursor pointing to a declaration or a reference of one. + * + * \param file to search for references. + * + * \param visitor callback that will receive pairs of CXCursor/CXSourceRange for + * each reference found. + * The CXSourceRange will point inside the file; if the reference is inside + * a macro (and not a macro argument) the CXSourceRange will be invalid. + * + * \returns one of the CXResult enumerators. + */ +CINDEX_LINKAGE CXResult clang_findReferencesInFile(CXCursor cursor, CXFile file, + CXCursorAndRangeVisitor visitor); + +/** + * \brief Find #import/#include directives in a specific file. + * + * \param TU translation unit containing the file to query. + * + * \param file to search for #import/#include directives. + * + * \param visitor callback that will receive pairs of CXCursor/CXSourceRange for + * each directive found. + * + * \returns one of the CXResult enumerators. + */ +CINDEX_LINKAGE CXResult clang_findIncludesInFile(CXTranslationUnit TU, + CXFile file, + CXCursorAndRangeVisitor visitor); + +#ifdef __has_feature +# if __has_feature(blocks) + +typedef enum CXVisitorResult + (^CXCursorAndRangeVisitorBlock)(CXCursor, CXSourceRange); + +CINDEX_LINKAGE +CXResult clang_findReferencesInFileWithBlock(CXCursor, CXFile, + CXCursorAndRangeVisitorBlock); + +CINDEX_LINKAGE +CXResult clang_findIncludesInFileWithBlock(CXTranslationUnit, CXFile, + CXCursorAndRangeVisitorBlock); + +# endif +#endif + +/** + * \brief The client's data object that is associated with a CXFile. + */ +typedef void *CXIdxClientFile; + +/** + * \brief The client's data object that is associated with a semantic entity. + */ +typedef void *CXIdxClientEntity; + +/** + * \brief The client's data object that is associated with a semantic container + * of entities. + */ +typedef void *CXIdxClientContainer; + +/** + * \brief The client's data object that is associated with an AST file (PCH + * or module). + */ +typedef void *CXIdxClientASTFile; + +/** + * \brief Source location passed to index callbacks. + */ +typedef struct { + void *ptr_data[2]; + unsigned int_data; +} CXIdxLoc; + +/** + * \brief Data for ppIncludedFile callback. + */ +typedef struct { + /** + * \brief Location of '#' in the \#include/\#import directive. + */ + CXIdxLoc hashLoc; + /** + * \brief Filename as written in the \#include/\#import directive. + */ + const char *filename; + /** + * \brief The actual file that the \#include/\#import directive resolved to. + */ + CXFile file; + int isImport; + int isAngled; + /** + * \brief Non-zero if the directive was automatically turned into a module + * import. + */ + int isModuleImport; +} CXIdxIncludedFileInfo; + +/** + * \brief Data for IndexerCallbacks#importedASTFile. + */ +typedef struct { + /** + * \brief Top level AST file containing the imported PCH, module or submodule. + */ + CXFile file; + /** + * \brief The imported module or NULL if the AST file is a PCH. + */ + CXModule module; + /** + * \brief Location where the file is imported. Applicable only for modules. + */ + CXIdxLoc loc; + /** + * \brief Non-zero if an inclusion directive was automatically turned into + * a module import. Applicable only for modules. + */ + int isImplicit; + +} CXIdxImportedASTFileInfo; + +typedef enum { + CXIdxEntity_Unexposed = 0, + CXIdxEntity_Typedef = 1, + CXIdxEntity_Function = 2, + CXIdxEntity_Variable = 3, + CXIdxEntity_Field = 4, + CXIdxEntity_EnumConstant = 5, + + CXIdxEntity_ObjCClass = 6, + CXIdxEntity_ObjCProtocol = 7, + CXIdxEntity_ObjCCategory = 8, + + CXIdxEntity_ObjCInstanceMethod = 9, + CXIdxEntity_ObjCClassMethod = 10, + CXIdxEntity_ObjCProperty = 11, + CXIdxEntity_ObjCIvar = 12, + + CXIdxEntity_Enum = 13, + CXIdxEntity_Struct = 14, + CXIdxEntity_Union = 15, + + CXIdxEntity_CXXClass = 16, + CXIdxEntity_CXXNamespace = 17, + CXIdxEntity_CXXNamespaceAlias = 18, + CXIdxEntity_CXXStaticVariable = 19, + CXIdxEntity_CXXStaticMethod = 20, + CXIdxEntity_CXXInstanceMethod = 21, + CXIdxEntity_CXXConstructor = 22, + CXIdxEntity_CXXDestructor = 23, + CXIdxEntity_CXXConversionFunction = 24, + CXIdxEntity_CXXTypeAlias = 25, + CXIdxEntity_CXXInterface = 26 + +} CXIdxEntityKind; + +typedef enum { + CXIdxEntityLang_None = 0, + CXIdxEntityLang_C = 1, + CXIdxEntityLang_ObjC = 2, + CXIdxEntityLang_CXX = 3 +} CXIdxEntityLanguage; + +/** + * \brief Extra C++ template information for an entity. This can apply to: + * CXIdxEntity_Function + * CXIdxEntity_CXXClass + * CXIdxEntity_CXXStaticMethod + * CXIdxEntity_CXXInstanceMethod + * CXIdxEntity_CXXConstructor + * CXIdxEntity_CXXConversionFunction + * CXIdxEntity_CXXTypeAlias + */ +typedef enum { + CXIdxEntity_NonTemplate = 0, + CXIdxEntity_Template = 1, + CXIdxEntity_TemplatePartialSpecialization = 2, + CXIdxEntity_TemplateSpecialization = 3 +} CXIdxEntityCXXTemplateKind; + +typedef enum { + CXIdxAttr_Unexposed = 0, + CXIdxAttr_IBAction = 1, + CXIdxAttr_IBOutlet = 2, + CXIdxAttr_IBOutletCollection = 3 +} CXIdxAttrKind; + +typedef struct { + CXIdxAttrKind kind; + CXCursor cursor; + CXIdxLoc loc; +} CXIdxAttrInfo; + +typedef struct { + CXIdxEntityKind kind; + CXIdxEntityCXXTemplateKind templateKind; + CXIdxEntityLanguage lang; + const char *name; + const char *USR; + CXCursor cursor; + const CXIdxAttrInfo *const *attributes; + unsigned numAttributes; +} CXIdxEntityInfo; + +typedef struct { + CXCursor cursor; +} CXIdxContainerInfo; + +typedef struct { + const CXIdxAttrInfo *attrInfo; + const CXIdxEntityInfo *objcClass; + CXCursor classCursor; + CXIdxLoc classLoc; +} CXIdxIBOutletCollectionAttrInfo; + +typedef enum { + CXIdxDeclFlag_Skipped = 0x1 +} CXIdxDeclInfoFlags; + +typedef struct { + const CXIdxEntityInfo *entityInfo; + CXCursor cursor; + CXIdxLoc loc; + const CXIdxContainerInfo *semanticContainer; + /** + * \brief Generally same as #semanticContainer but can be different in + * cases like out-of-line C++ member functions. + */ + const CXIdxContainerInfo *lexicalContainer; + int isRedeclaration; + int isDefinition; + int isContainer; + const CXIdxContainerInfo *declAsContainer; + /** + * \brief Whether the declaration exists in code or was created implicitly + * by the compiler, e.g. implicit Objective-C methods for properties. + */ + int isImplicit; + const CXIdxAttrInfo *const *attributes; + unsigned numAttributes; + + unsigned flags; + +} CXIdxDeclInfo; + +typedef enum { + CXIdxObjCContainer_ForwardRef = 0, + CXIdxObjCContainer_Interface = 1, + CXIdxObjCContainer_Implementation = 2 +} CXIdxObjCContainerKind; + +typedef struct { + const CXIdxDeclInfo *declInfo; + CXIdxObjCContainerKind kind; +} CXIdxObjCContainerDeclInfo; + +typedef struct { + const CXIdxEntityInfo *base; + CXCursor cursor; + CXIdxLoc loc; +} CXIdxBaseClassInfo; + +typedef struct { + const CXIdxEntityInfo *protocol; + CXCursor cursor; + CXIdxLoc loc; +} CXIdxObjCProtocolRefInfo; + +typedef struct { + const CXIdxObjCProtocolRefInfo *const *protocols; + unsigned numProtocols; +} CXIdxObjCProtocolRefListInfo; + +typedef struct { + const CXIdxObjCContainerDeclInfo *containerInfo; + const CXIdxBaseClassInfo *superInfo; + const CXIdxObjCProtocolRefListInfo *protocols; +} CXIdxObjCInterfaceDeclInfo; + +typedef struct { + const CXIdxObjCContainerDeclInfo *containerInfo; + const CXIdxEntityInfo *objcClass; + CXCursor classCursor; + CXIdxLoc classLoc; + const CXIdxObjCProtocolRefListInfo *protocols; +} CXIdxObjCCategoryDeclInfo; + +typedef struct { + const CXIdxDeclInfo *declInfo; + const CXIdxEntityInfo *getter; + const CXIdxEntityInfo *setter; +} CXIdxObjCPropertyDeclInfo; + +typedef struct { + const CXIdxDeclInfo *declInfo; + const CXIdxBaseClassInfo *const *bases; + unsigned numBases; +} CXIdxCXXClassDeclInfo; + +/** + * \brief Data for IndexerCallbacks#indexEntityReference. + */ +typedef enum { + /** + * \brief The entity is referenced directly in user's code. + */ + CXIdxEntityRef_Direct = 1, + /** + * \brief An implicit reference, e.g. a reference of an Objective-C method + * via the dot syntax. + */ + CXIdxEntityRef_Implicit = 2 +} CXIdxEntityRefKind; + +/** + * \brief Data for IndexerCallbacks#indexEntityReference. + */ +typedef struct { + CXIdxEntityRefKind kind; + /** + * \brief Reference cursor. + */ + CXCursor cursor; + CXIdxLoc loc; + /** + * \brief The entity that gets referenced. + */ + const CXIdxEntityInfo *referencedEntity; + /** + * \brief Immediate "parent" of the reference. For example: + * + * \code + * Foo *var; + * \endcode + * + * The parent of reference of type 'Foo' is the variable 'var'. + * For references inside statement bodies of functions/methods, + * the parentEntity will be the function/method. + */ + const CXIdxEntityInfo *parentEntity; + /** + * \brief Lexical container context of the reference. + */ + const CXIdxContainerInfo *container; +} CXIdxEntityRefInfo; + +/** + * \brief A group of callbacks used by #clang_indexSourceFile and + * #clang_indexTranslationUnit. + */ +typedef struct { + /** + * \brief Called periodically to check whether indexing should be aborted. + * Should return 0 to continue, and non-zero to abort. + */ + int (*abortQuery)(CXClientData client_data, void *reserved); + + /** + * \brief Called at the end of indexing; passes the complete diagnostic set. + */ + void (*diagnostic)(CXClientData client_data, + CXDiagnosticSet, void *reserved); + + CXIdxClientFile (*enteredMainFile)(CXClientData client_data, + CXFile mainFile, void *reserved); + + /** + * \brief Called when a file gets \#included/\#imported. + */ + CXIdxClientFile (*ppIncludedFile)(CXClientData client_data, + const CXIdxIncludedFileInfo *); + + /** + * \brief Called when a AST file (PCH or module) gets imported. + * + * AST files will not get indexed (there will not be callbacks to index all + * the entities in an AST file). The recommended action is that, if the AST + * file is not already indexed, to initiate a new indexing job specific to + * the AST file. + */ + CXIdxClientASTFile (*importedASTFile)(CXClientData client_data, + const CXIdxImportedASTFileInfo *); + + /** + * \brief Called at the beginning of indexing a translation unit. + */ + CXIdxClientContainer (*startedTranslationUnit)(CXClientData client_data, + void *reserved); + + void (*indexDeclaration)(CXClientData client_data, + const CXIdxDeclInfo *); + + /** + * \brief Called to index a reference of an entity. + */ + void (*indexEntityReference)(CXClientData client_data, + const CXIdxEntityRefInfo *); + +} IndexerCallbacks; + +CINDEX_LINKAGE int clang_index_isEntityObjCContainerKind(CXIdxEntityKind); +CINDEX_LINKAGE const CXIdxObjCContainerDeclInfo * +clang_index_getObjCContainerDeclInfo(const CXIdxDeclInfo *); + +CINDEX_LINKAGE const CXIdxObjCInterfaceDeclInfo * +clang_index_getObjCInterfaceDeclInfo(const CXIdxDeclInfo *); + +CINDEX_LINKAGE +const CXIdxObjCCategoryDeclInfo * +clang_index_getObjCCategoryDeclInfo(const CXIdxDeclInfo *); + +CINDEX_LINKAGE const CXIdxObjCProtocolRefListInfo * +clang_index_getObjCProtocolRefListInfo(const CXIdxDeclInfo *); + +CINDEX_LINKAGE const CXIdxObjCPropertyDeclInfo * +clang_index_getObjCPropertyDeclInfo(const CXIdxDeclInfo *); + +CINDEX_LINKAGE const CXIdxIBOutletCollectionAttrInfo * +clang_index_getIBOutletCollectionAttrInfo(const CXIdxAttrInfo *); + +CINDEX_LINKAGE const CXIdxCXXClassDeclInfo * +clang_index_getCXXClassDeclInfo(const CXIdxDeclInfo *); + +/** + * \brief For retrieving a custom CXIdxClientContainer attached to a + * container. + */ +CINDEX_LINKAGE CXIdxClientContainer +clang_index_getClientContainer(const CXIdxContainerInfo *); + +/** + * \brief For setting a custom CXIdxClientContainer attached to a + * container. + */ +CINDEX_LINKAGE void +clang_index_setClientContainer(const CXIdxContainerInfo *,CXIdxClientContainer); + +/** + * \brief For retrieving a custom CXIdxClientEntity attached to an entity. + */ +CINDEX_LINKAGE CXIdxClientEntity +clang_index_getClientEntity(const CXIdxEntityInfo *); + +/** + * \brief For setting a custom CXIdxClientEntity attached to an entity. + */ +CINDEX_LINKAGE void +clang_index_setClientEntity(const CXIdxEntityInfo *, CXIdxClientEntity); + +/** + * \brief An indexing action/session, to be applied to one or multiple + * translation units. + */ +typedef void *CXIndexAction; + +/** + * \brief An indexing action/session, to be applied to one or multiple + * translation units. + * + * \param CIdx The index object with which the index action will be associated. + */ +CINDEX_LINKAGE CXIndexAction clang_IndexAction_create(CXIndex CIdx); + +/** + * \brief Destroy the given index action. + * + * The index action must not be destroyed until all of the translation units + * created within that index action have been destroyed. + */ +CINDEX_LINKAGE void clang_IndexAction_dispose(CXIndexAction); + +typedef enum { + /** + * \brief Used to indicate that no special indexing options are needed. + */ + CXIndexOpt_None = 0x0, + + /** + * \brief Used to indicate that IndexerCallbacks#indexEntityReference should + * be invoked for only one reference of an entity per source file that does + * not also include a declaration/definition of the entity. + */ + CXIndexOpt_SuppressRedundantRefs = 0x1, + + /** + * \brief Function-local symbols should be indexed. If this is not set + * function-local symbols will be ignored. + */ + CXIndexOpt_IndexFunctionLocalSymbols = 0x2, + + /** + * \brief Implicit function/class template instantiations should be indexed. + * If this is not set, implicit instantiations will be ignored. + */ + CXIndexOpt_IndexImplicitTemplateInstantiations = 0x4, + + /** + * \brief Suppress all compiler warnings when parsing for indexing. + */ + CXIndexOpt_SuppressWarnings = 0x8, + + /** + * \brief Skip a function/method body that was already parsed during an + * indexing session associated with a \c CXIndexAction object. + * Bodies in system headers are always skipped. + */ + CXIndexOpt_SkipParsedBodiesInSession = 0x10 + +} CXIndexOptFlags; + +/** + * \brief Index the given source file and the translation unit corresponding + * to that file via callbacks implemented through #IndexerCallbacks. + * + * \param client_data pointer data supplied by the client, which will + * be passed to the invoked callbacks. + * + * \param index_callbacks Pointer to indexing callbacks that the client + * implements. + * + * \param index_callbacks_size Size of #IndexerCallbacks structure that gets + * passed in index_callbacks. + * + * \param index_options A bitmask of options that affects how indexing is + * performed. This should be a bitwise OR of the CXIndexOpt_XXX flags. + * + * \param[out] out_TU pointer to store a \c CXTranslationUnit that can be + * reused after indexing is finished. Set to \c NULL if you do not require it. + * + * \returns 0 on success or if there were errors from which the compiler could + * recover. If there is a failure from which there is no recovery, returns + * a non-zero \c CXErrorCode. + * + * The rest of the parameters are the same as #clang_parseTranslationUnit. + */ +CINDEX_LINKAGE int clang_indexSourceFile(CXIndexAction, + CXClientData client_data, + IndexerCallbacks *index_callbacks, + unsigned index_callbacks_size, + unsigned index_options, + const char *source_filename, + const char * const *command_line_args, + int num_command_line_args, + struct CXUnsavedFile *unsaved_files, + unsigned num_unsaved_files, + CXTranslationUnit *out_TU, + unsigned TU_options); + +/** + * \brief Same as clang_indexSourceFile but requires a full command line + * for \c command_line_args including argv[0]. This is useful if the standard + * library paths are relative to the binary. + */ +CINDEX_LINKAGE int clang_indexSourceFileFullArgv( + CXIndexAction, CXClientData client_data, IndexerCallbacks *index_callbacks, + unsigned index_callbacks_size, unsigned index_options, + const char *source_filename, const char *const *command_line_args, + int num_command_line_args, struct CXUnsavedFile *unsaved_files, + unsigned num_unsaved_files, CXTranslationUnit *out_TU, unsigned TU_options); + +/** + * \brief Index the given translation unit via callbacks implemented through + * #IndexerCallbacks. + * + * The order of callback invocations is not guaranteed to be the same as + * when indexing a source file. The high level order will be: + * + * -Preprocessor callbacks invocations + * -Declaration/reference callbacks invocations + * -Diagnostic callback invocations + * + * The parameters are the same as #clang_indexSourceFile. + * + * \returns If there is a failure from which there is no recovery, returns + * non-zero, otherwise returns 0. + */ +CINDEX_LINKAGE int clang_indexTranslationUnit(CXIndexAction, + CXClientData client_data, + IndexerCallbacks *index_callbacks, + unsigned index_callbacks_size, + unsigned index_options, + CXTranslationUnit); + +/** + * \brief Retrieve the CXIdxFile, file, line, column, and offset represented by + * the given CXIdxLoc. + * + * If the location refers into a macro expansion, retrieves the + * location of the macro expansion and if it refers into a macro argument + * retrieves the location of the argument. + */ +CINDEX_LINKAGE void clang_indexLoc_getFileLocation(CXIdxLoc loc, + CXIdxClientFile *indexFile, + CXFile *file, + unsigned *line, + unsigned *column, + unsigned *offset); + +/** + * \brief Retrieve the CXSourceLocation represented by the given CXIdxLoc. + */ +CINDEX_LINKAGE +CXSourceLocation clang_indexLoc_getCXSourceLocation(CXIdxLoc loc); + +/** + * \brief Visitor invoked for each field found by a traversal. + * + * This visitor function will be invoked for each field found by + * \c clang_Type_visitFields. Its first argument is the cursor being + * visited, its second argument is the client data provided to + * \c clang_Type_visitFields. + * + * The visitor should return one of the \c CXVisitorResult values + * to direct \c clang_Type_visitFields. + */ +typedef enum CXVisitorResult (*CXFieldVisitor)(CXCursor C, + CXClientData client_data); + +/** + * \brief Visit the fields of a particular type. + * + * This function visits all the direct fields of the given cursor, + * invoking the given \p visitor function with the cursors of each + * visited field. The traversal may be ended prematurely, if + * the visitor returns \c CXFieldVisit_Break. + * + * \param T the record type whose field may be visited. + * + * \param visitor the visitor function that will be invoked for each + * field of \p T. + * + * \param client_data pointer data supplied by the client, which will + * be passed to the visitor each time it is invoked. + * + * \returns a non-zero value if the traversal was terminated + * prematurely by the visitor returning \c CXFieldVisit_Break. + */ +CINDEX_LINKAGE unsigned clang_Type_visitFields(CXType T, + CXFieldVisitor visitor, + CXClientData client_data); + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/contrib/llvm/tools/clang/include/clang-c/Platform.h b/contrib/llvm/tools/clang/include/clang-c/Platform.h new file mode 100644 index 0000000..e2a4dcc --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang-c/Platform.h @@ -0,0 +1,45 @@ +/*===-- clang-c/Platform.h - C Index platform decls -------------*- C -*-===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header provides platform specific macros (dllimport, deprecated, ...) *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_CLANG_C_PLATFORM_H +#define LLVM_CLANG_C_PLATFORM_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 + +#ifdef __GNUC__ + #define CINDEX_DEPRECATED __attribute__((deprecated)) +#else + #ifdef _MSC_VER + #define CINDEX_DEPRECATED __declspec(deprecated) + #else + #define CINDEX_DEPRECATED + #endif +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/contrib/llvm/tools/clang/include/clang-c/module.modulemap b/contrib/llvm/tools/clang/include/clang-c/module.modulemap new file mode 100644 index 0000000..95a59d6 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang-c/module.modulemap @@ -0,0 +1,4 @@ +module Clang_C { + umbrella "." + module * { export * } +} diff --git a/contrib/llvm/tools/clang/include/clang/ARCMigrate/ARCMT.h b/contrib/llvm/tools/clang/include/clang/ARCMigrate/ARCMT.h new file mode 100644 index 0000000..7408186 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/ARCMigrate/ARCMT.h @@ -0,0 +1,131 @@ +//===-- ARCMT.h - ARC Migration Rewriter ------------------------*- 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_ARCMIGRATE_ARCMT_H +#define LLVM_CLANG_ARCMIGRATE_ARCMT_H + +#include "clang/ARCMigrate/FileRemapper.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Frontend/CompilerInvocation.h" + +namespace clang { + class ASTContext; + class DiagnosticConsumer; + class PCHContainerOperations; + +namespace arcmt { + class MigrationPass; + +/// \brief Creates an AST with the provided CompilerInvocation but with these +/// changes: +/// -if a PCH/PTH is set, the original header is used instead +/// -Automatic Reference Counting mode is enabled +/// +/// It then checks the AST and produces errors/warning for ARC migration issues +/// that the user needs to handle manually. +/// +/// \param emitPremigrationARCErrors if true all ARC errors will get emitted +/// even if the migrator can fix them, but the function will still return false +/// if all ARC errors can be fixed. +/// +/// \param plistOut if non-empty, it is the file path to store the plist with +/// the pre-migration ARC diagnostics. +/// +/// \returns false if no error is produced, true otherwise. +bool +checkForManualIssues(CompilerInvocation &CI, const FrontendInputFile &Input, + std::shared_ptr<PCHContainerOperations> PCHContainerOps, + DiagnosticConsumer *DiagClient, + bool emitPremigrationARCErrors = false, + StringRef plistOut = StringRef()); + +/// \brief Works similar to checkForManualIssues but instead of checking, it +/// applies automatic modifications to source files to conform to ARC. +/// +/// \returns false if no error is produced, true otherwise. +bool +applyTransformations(CompilerInvocation &origCI, + const FrontendInputFile &Input, + std::shared_ptr<PCHContainerOperations> PCHContainerOps, + DiagnosticConsumer *DiagClient); + +/// \brief Applies automatic modifications and produces temporary files +/// and metadata into the \p outputDir path. +/// +/// \param emitPremigrationARCErrors if true all ARC errors will get emitted +/// even if the migrator can fix them, but the function will still return false +/// if all ARC errors can be fixed. +/// +/// \param plistOut if non-empty, it is the file path to store the plist with +/// the pre-migration ARC diagnostics. +/// +/// \returns false if no error is produced, true otherwise. +bool migrateWithTemporaryFiles( + CompilerInvocation &origCI, const FrontendInputFile &Input, + std::shared_ptr<PCHContainerOperations> PCHContainerOps, + DiagnosticConsumer *DiagClient, StringRef outputDir, + bool emitPremigrationARCErrors, StringRef plistOut); + +/// \brief Get the set of file remappings from the \p outputDir path that +/// migrateWithTemporaryFiles produced. +/// +/// \returns false if no error is produced, true otherwise. +bool getFileRemappings(std::vector<std::pair<std::string,std::string> > &remap, + StringRef outputDir, + DiagnosticConsumer *DiagClient); + +/// \brief Get the set of file remappings from a list of files with remapping +/// info. +/// +/// \returns false if no error is produced, true otherwise. +bool getFileRemappingsFromFileList( + std::vector<std::pair<std::string,std::string> > &remap, + ArrayRef<StringRef> remapFiles, + DiagnosticConsumer *DiagClient); + +typedef void (*TransformFn)(MigrationPass &pass); + +std::vector<TransformFn> getAllTransformations(LangOptions::GCMode OrigGCMode, + bool NoFinalizeRemoval); + +class MigrationProcess { + CompilerInvocation OrigCI; + std::shared_ptr<PCHContainerOperations> PCHContainerOps; + DiagnosticConsumer *DiagClient; + FileRemapper Remapper; + +public: + bool HadARCErrors; + + MigrationProcess(const CompilerInvocation &CI, + std::shared_ptr<PCHContainerOperations> PCHContainerOps, + DiagnosticConsumer *diagClient, + StringRef outputDir = StringRef()); + + class RewriteListener { + public: + virtual ~RewriteListener(); + + virtual void start(ASTContext &Ctx) { } + virtual void finish() { } + + virtual void insert(SourceLocation loc, StringRef text) { } + virtual void remove(CharSourceRange range) { } + }; + + bool applyTransform(TransformFn trans, RewriteListener *listener = nullptr); + + FileRemapper &getRemapper() { return Remapper; } +}; + +} // end namespace arcmt + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/ARCMigrate/ARCMTActions.h b/contrib/llvm/tools/clang/include/clang/ARCMigrate/ARCMTActions.h new file mode 100644 index 0000000..c830aa3 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/ARCMigrate/ARCMTActions.h @@ -0,0 +1,76 @@ +//===--- ARCMTActions.h - ARC Migrate Tool Frontend Actions -----*- 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_ARCMIGRATE_ARCMTACTIONS_H +#define LLVM_CLANG_ARCMIGRATE_ARCMTACTIONS_H + +#include "clang/ARCMigrate/FileRemapper.h" +#include "clang/Frontend/FrontendAction.h" +#include <memory> + +namespace clang { +namespace arcmt { + +class CheckAction : public WrapperFrontendAction { +protected: + bool BeginInvocation(CompilerInstance &CI) override; + +public: + CheckAction(FrontendAction *WrappedAction); +}; + +class ModifyAction : public WrapperFrontendAction { +protected: + bool BeginInvocation(CompilerInstance &CI) override; + +public: + ModifyAction(FrontendAction *WrappedAction); +}; + +class MigrateSourceAction : public ASTFrontendAction { + FileRemapper Remapper; +protected: + bool BeginInvocation(CompilerInstance &CI) override; + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override; +}; + +class MigrateAction : public WrapperFrontendAction { + std::string MigrateDir; + std::string PlistOut; + bool EmitPremigrationARCErros; +protected: + bool BeginInvocation(CompilerInstance &CI) override; + +public: + MigrateAction(FrontendAction *WrappedAction, StringRef migrateDir, + StringRef plistOut, + bool emitPremigrationARCErrors); +}; + +/// \brief Migrates to modern ObjC syntax. +class ObjCMigrateAction : public WrapperFrontendAction { + std::string MigrateDir; + unsigned ObjCMigAction; + FileRemapper Remapper; + CompilerInstance *CompInst; +public: + ObjCMigrateAction(FrontendAction *WrappedAction, StringRef migrateDir, + unsigned migrateAction); + +protected: + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override; + bool BeginInvocation(CompilerInstance &CI) override; +}; + +} +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/ARCMigrate/FileRemapper.h b/contrib/llvm/tools/clang/include/clang/ARCMigrate/FileRemapper.h new file mode 100644 index 0000000..53b88e9 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/ARCMigrate/FileRemapper.h @@ -0,0 +1,77 @@ +//===-- FileRemapper.h - File Remapping Helper ------------------*- 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_ARCMIGRATE_FILEREMAPPER_H +#define LLVM_CLANG_ARCMIGRATE_FILEREMAPPER_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/StringRef.h" +#include <memory> + +namespace llvm { + class MemoryBuffer; +} + +namespace clang { + class FileManager; + class FileEntry; + class DiagnosticsEngine; + class PreprocessorOptions; + +namespace arcmt { + +class FileRemapper { + // FIXME: Reuse the same FileManager for multiple ASTContexts. + std::unique_ptr<FileManager> FileMgr; + + typedef llvm::PointerUnion<const FileEntry *, llvm::MemoryBuffer *> Target; + typedef llvm::DenseMap<const FileEntry *, Target> MappingsTy; + MappingsTy FromToMappings; + + llvm::DenseMap<const FileEntry *, const FileEntry *> ToFromMappings; + +public: + FileRemapper(); + ~FileRemapper(); + + bool initFromDisk(StringRef outputDir, DiagnosticsEngine &Diag, + bool ignoreIfFilesChanged); + bool initFromFile(StringRef filePath, DiagnosticsEngine &Diag, + bool ignoreIfFilesChanged); + bool flushToDisk(StringRef outputDir, DiagnosticsEngine &Diag); + bool flushToFile(StringRef outputPath, DiagnosticsEngine &Diag); + + bool overwriteOriginal(DiagnosticsEngine &Diag, + StringRef outputDir = StringRef()); + + void remap(StringRef filePath, std::unique_ptr<llvm::MemoryBuffer> memBuf); + + void applyMappings(PreprocessorOptions &PPOpts) const; + + void clear(StringRef outputDir = StringRef()); + +private: + void remap(const FileEntry *file, std::unique_ptr<llvm::MemoryBuffer> memBuf); + void remap(const FileEntry *file, const FileEntry *newfile); + + const FileEntry *getOriginalFile(StringRef filePath); + void resetTarget(Target &targ); + + bool report(const Twine &err, DiagnosticsEngine &Diag); + + std::string getRemapInfoFile(StringRef outputDir); +}; + +} // end namespace arcmt + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/APValue.h b/contrib/llvm/tools/clang/include/clang/AST/APValue.h new file mode 100644 index 0000000..e58c219 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/APValue.h @@ -0,0 +1,452 @@ +//===--- APValue.h - Union class for APFloat/APSInt/Complex -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the APValue class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_APVALUE_H +#define LLVM_CLANG_AST_APVALUE_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/PointerUnion.h" + +namespace clang { + class AddrLabelExpr; + class ASTContext; + class CharUnits; + class DiagnosticBuilder; + class Expr; + class FieldDecl; + class Decl; + class ValueDecl; + class CXXRecordDecl; + class QualType; + +/// APValue - This class implements a discriminated union of [uninitialized] +/// [APSInt] [APFloat], [Complex APSInt] [Complex APFloat], [Expr + Offset], +/// [Vector: N * APValue], [Array: N * APValue] +class APValue { + typedef llvm::APSInt APSInt; + typedef llvm::APFloat APFloat; +public: + enum ValueKind { + Uninitialized, + Int, + Float, + ComplexInt, + ComplexFloat, + LValue, + Vector, + Array, + Struct, + Union, + MemberPointer, + AddrLabelDiff + }; + typedef llvm::PointerUnion<const ValueDecl *, const Expr *> LValueBase; + typedef llvm::PointerIntPair<const Decl *, 1, bool> BaseOrMemberType; + union LValuePathEntry { + /// BaseOrMember - The FieldDecl or CXXRecordDecl indicating the next item + /// in the path. An opaque value of type BaseOrMemberType. + void *BaseOrMember; + /// ArrayIndex - The array index of the next item in the path. + uint64_t ArrayIndex; + }; + struct NoLValuePath {}; + struct UninitArray {}; + struct UninitStruct {}; +private: + ValueKind Kind; + + struct ComplexAPSInt { + APSInt Real, Imag; + ComplexAPSInt() : Real(1), Imag(1) {} + }; + struct ComplexAPFloat { + APFloat Real, Imag; + ComplexAPFloat() : Real(0.0), Imag(0.0) {} + }; + struct LV; + struct Vec { + APValue *Elts; + unsigned NumElts; + Vec() : Elts(nullptr), NumElts(0) {} + ~Vec() { delete[] Elts; } + }; + struct Arr { + APValue *Elts; + unsigned NumElts, ArrSize; + Arr(unsigned NumElts, unsigned ArrSize); + ~Arr(); + }; + struct StructData { + APValue *Elts; + unsigned NumBases; + unsigned NumFields; + StructData(unsigned NumBases, unsigned NumFields); + ~StructData(); + }; + struct UnionData { + const FieldDecl *Field; + APValue *Value; + UnionData(); + ~UnionData(); + }; + struct AddrLabelDiffData { + const AddrLabelExpr* LHSExpr; + const AddrLabelExpr* RHSExpr; + }; + struct MemberPointerData; + + // We ensure elsewhere that Data is big enough for LV and MemberPointerData. + typedef llvm::AlignedCharArrayUnion<void *, APSInt, APFloat, ComplexAPSInt, + ComplexAPFloat, Vec, Arr, StructData, + UnionData, AddrLabelDiffData> DataType; + static const size_t DataSize = sizeof(DataType); + + DataType Data; + +public: + APValue() : Kind(Uninitialized) {} + explicit APValue(APSInt I) : Kind(Uninitialized) { + MakeInt(); setInt(std::move(I)); + } + explicit APValue(APFloat F) : Kind(Uninitialized) { + MakeFloat(); setFloat(std::move(F)); + } + explicit APValue(const APValue *E, unsigned N) : Kind(Uninitialized) { + MakeVector(); setVector(E, N); + } + APValue(APSInt R, APSInt I) : Kind(Uninitialized) { + MakeComplexInt(); setComplexInt(std::move(R), std::move(I)); + } + APValue(APFloat R, APFloat I) : Kind(Uninitialized) { + MakeComplexFloat(); setComplexFloat(std::move(R), std::move(I)); + } + APValue(const APValue &RHS); + APValue(APValue &&RHS) : Kind(Uninitialized) { swap(RHS); } + APValue(LValueBase B, const CharUnits &O, NoLValuePath N, unsigned CallIndex) + : Kind(Uninitialized) { + MakeLValue(); setLValue(B, O, N, CallIndex); + } + APValue(LValueBase B, const CharUnits &O, ArrayRef<LValuePathEntry> Path, + bool OnePastTheEnd, unsigned CallIndex) + : Kind(Uninitialized) { + MakeLValue(); setLValue(B, O, Path, OnePastTheEnd, CallIndex); + } + APValue(UninitArray, unsigned InitElts, unsigned Size) : Kind(Uninitialized) { + MakeArray(InitElts, Size); + } + APValue(UninitStruct, unsigned B, unsigned M) : Kind(Uninitialized) { + MakeStruct(B, M); + } + explicit APValue(const FieldDecl *D, const APValue &V = APValue()) + : Kind(Uninitialized) { + MakeUnion(); setUnion(D, V); + } + APValue(const ValueDecl *Member, bool IsDerivedMember, + ArrayRef<const CXXRecordDecl*> Path) : Kind(Uninitialized) { + MakeMemberPointer(Member, IsDerivedMember, Path); + } + APValue(const AddrLabelExpr* LHSExpr, const AddrLabelExpr* RHSExpr) + : Kind(Uninitialized) { + MakeAddrLabelDiff(); setAddrLabelDiff(LHSExpr, RHSExpr); + } + + ~APValue() { + MakeUninit(); + } + + /// \brief Returns whether the object performed allocations. + /// + /// If APValues are constructed via placement new, \c needsCleanup() + /// indicates whether the destructor must be called in order to correctly + /// free all allocated memory. + bool needsCleanup() const; + + /// \brief Swaps the contents of this and the given APValue. + void swap(APValue &RHS); + + ValueKind getKind() const { return Kind; } + bool isUninit() const { return Kind == Uninitialized; } + bool isInt() const { return Kind == Int; } + bool isFloat() const { return Kind == Float; } + bool isComplexInt() const { return Kind == ComplexInt; } + bool isComplexFloat() const { return Kind == ComplexFloat; } + bool isLValue() const { return Kind == LValue; } + bool isVector() const { return Kind == Vector; } + bool isArray() const { return Kind == Array; } + bool isStruct() const { return Kind == Struct; } + bool isUnion() const { return Kind == Union; } + bool isMemberPointer() const { return Kind == MemberPointer; } + bool isAddrLabelDiff() const { return Kind == AddrLabelDiff; } + + void dump() const; + void dump(raw_ostream &OS) const; + + void printPretty(raw_ostream &OS, ASTContext &Ctx, QualType Ty) const; + std::string getAsString(ASTContext &Ctx, QualType Ty) const; + + APSInt &getInt() { + assert(isInt() && "Invalid accessor"); + return *(APSInt*)(char*)Data.buffer; + } + const APSInt &getInt() const { + return const_cast<APValue*>(this)->getInt(); + } + + APFloat &getFloat() { + assert(isFloat() && "Invalid accessor"); + return *(APFloat*)(char*)Data.buffer; + } + const APFloat &getFloat() const { + return const_cast<APValue*>(this)->getFloat(); + } + + APSInt &getComplexIntReal() { + assert(isComplexInt() && "Invalid accessor"); + return ((ComplexAPSInt*)(char*)Data.buffer)->Real; + } + const APSInt &getComplexIntReal() const { + return const_cast<APValue*>(this)->getComplexIntReal(); + } + + APSInt &getComplexIntImag() { + assert(isComplexInt() && "Invalid accessor"); + return ((ComplexAPSInt*)(char*)Data.buffer)->Imag; + } + const APSInt &getComplexIntImag() const { + return const_cast<APValue*>(this)->getComplexIntImag(); + } + + APFloat &getComplexFloatReal() { + assert(isComplexFloat() && "Invalid accessor"); + return ((ComplexAPFloat*)(char*)Data.buffer)->Real; + } + const APFloat &getComplexFloatReal() const { + return const_cast<APValue*>(this)->getComplexFloatReal(); + } + + APFloat &getComplexFloatImag() { + assert(isComplexFloat() && "Invalid accessor"); + return ((ComplexAPFloat*)(char*)Data.buffer)->Imag; + } + const APFloat &getComplexFloatImag() const { + return const_cast<APValue*>(this)->getComplexFloatImag(); + } + + const LValueBase getLValueBase() const; + CharUnits &getLValueOffset(); + const CharUnits &getLValueOffset() const { + return const_cast<APValue*>(this)->getLValueOffset(); + } + bool isLValueOnePastTheEnd() const; + bool hasLValuePath() const; + ArrayRef<LValuePathEntry> getLValuePath() const; + unsigned getLValueCallIndex() const; + + APValue &getVectorElt(unsigned I) { + assert(isVector() && "Invalid accessor"); + assert(I < getVectorLength() && "Index out of range"); + return ((Vec*)(char*)Data.buffer)->Elts[I]; + } + const APValue &getVectorElt(unsigned I) const { + return const_cast<APValue*>(this)->getVectorElt(I); + } + unsigned getVectorLength() const { + assert(isVector() && "Invalid accessor"); + return ((const Vec*)(const void *)Data.buffer)->NumElts; + } + + APValue &getArrayInitializedElt(unsigned I) { + assert(isArray() && "Invalid accessor"); + assert(I < getArrayInitializedElts() && "Index out of range"); + return ((Arr*)(char*)Data.buffer)->Elts[I]; + } + const APValue &getArrayInitializedElt(unsigned I) const { + return const_cast<APValue*>(this)->getArrayInitializedElt(I); + } + bool hasArrayFiller() const { + return getArrayInitializedElts() != getArraySize(); + } + APValue &getArrayFiller() { + assert(isArray() && "Invalid accessor"); + assert(hasArrayFiller() && "No array filler"); + return ((Arr*)(char*)Data.buffer)->Elts[getArrayInitializedElts()]; + } + const APValue &getArrayFiller() const { + return const_cast<APValue*>(this)->getArrayFiller(); + } + unsigned getArrayInitializedElts() const { + assert(isArray() && "Invalid accessor"); + return ((const Arr*)(const void *)Data.buffer)->NumElts; + } + unsigned getArraySize() const { + assert(isArray() && "Invalid accessor"); + return ((const Arr*)(const void *)Data.buffer)->ArrSize; + } + + unsigned getStructNumBases() const { + assert(isStruct() && "Invalid accessor"); + return ((const StructData*)(const char*)Data.buffer)->NumBases; + } + unsigned getStructNumFields() const { + assert(isStruct() && "Invalid accessor"); + return ((const StructData*)(const char*)Data.buffer)->NumFields; + } + APValue &getStructBase(unsigned i) { + assert(isStruct() && "Invalid accessor"); + return ((StructData*)(char*)Data.buffer)->Elts[i]; + } + APValue &getStructField(unsigned i) { + assert(isStruct() && "Invalid accessor"); + return ((StructData*)(char*)Data.buffer)->Elts[getStructNumBases() + i]; + } + const APValue &getStructBase(unsigned i) const { + return const_cast<APValue*>(this)->getStructBase(i); + } + const APValue &getStructField(unsigned i) const { + return const_cast<APValue*>(this)->getStructField(i); + } + + const FieldDecl *getUnionField() const { + assert(isUnion() && "Invalid accessor"); + return ((const UnionData*)(const char*)Data.buffer)->Field; + } + APValue &getUnionValue() { + assert(isUnion() && "Invalid accessor"); + return *((UnionData*)(char*)Data.buffer)->Value; + } + const APValue &getUnionValue() const { + return const_cast<APValue*>(this)->getUnionValue(); + } + + const ValueDecl *getMemberPointerDecl() const; + bool isMemberPointerToDerivedMember() const; + ArrayRef<const CXXRecordDecl*> getMemberPointerPath() const; + + const AddrLabelExpr* getAddrLabelDiffLHS() const { + assert(isAddrLabelDiff() && "Invalid accessor"); + return ((const AddrLabelDiffData*)(const char*)Data.buffer)->LHSExpr; + } + const AddrLabelExpr* getAddrLabelDiffRHS() const { + assert(isAddrLabelDiff() && "Invalid accessor"); + return ((const AddrLabelDiffData*)(const char*)Data.buffer)->RHSExpr; + } + + void setInt(APSInt I) { + assert(isInt() && "Invalid accessor"); + *(APSInt *)(char *)Data.buffer = std::move(I); + } + void setFloat(APFloat F) { + assert(isFloat() && "Invalid accessor"); + *(APFloat *)(char *)Data.buffer = std::move(F); + } + void setVector(const APValue *E, unsigned N) { + assert(isVector() && "Invalid accessor"); + ((Vec*)(char*)Data.buffer)->Elts = new APValue[N]; + ((Vec*)(char*)Data.buffer)->NumElts = N; + for (unsigned i = 0; i != N; ++i) + ((Vec*)(char*)Data.buffer)->Elts[i] = E[i]; + } + void setComplexInt(APSInt R, APSInt I) { + assert(R.getBitWidth() == I.getBitWidth() && + "Invalid complex int (type mismatch)."); + assert(isComplexInt() && "Invalid accessor"); + ((ComplexAPSInt *)(char *)Data.buffer)->Real = std::move(R); + ((ComplexAPSInt *)(char *)Data.buffer)->Imag = std::move(I); + } + void setComplexFloat(APFloat R, APFloat I) { + assert(&R.getSemantics() == &I.getSemantics() && + "Invalid complex float (type mismatch)."); + assert(isComplexFloat() && "Invalid accessor"); + ((ComplexAPFloat *)(char *)Data.buffer)->Real = std::move(R); + ((ComplexAPFloat *)(char *)Data.buffer)->Imag = std::move(I); + } + void setLValue(LValueBase B, const CharUnits &O, NoLValuePath, + unsigned CallIndex); + void setLValue(LValueBase B, const CharUnits &O, + ArrayRef<LValuePathEntry> Path, bool OnePastTheEnd, + unsigned CallIndex); + void setUnion(const FieldDecl *Field, const APValue &Value) { + assert(isUnion() && "Invalid accessor"); + ((UnionData*)(char*)Data.buffer)->Field = Field; + *((UnionData*)(char*)Data.buffer)->Value = Value; + } + void setAddrLabelDiff(const AddrLabelExpr* LHSExpr, + const AddrLabelExpr* RHSExpr) { + ((AddrLabelDiffData*)(char*)Data.buffer)->LHSExpr = LHSExpr; + ((AddrLabelDiffData*)(char*)Data.buffer)->RHSExpr = RHSExpr; + } + + /// Assign by swapping from a copy of the RHS. + APValue &operator=(APValue RHS) { + swap(RHS); + return *this; + } + +private: + void DestroyDataAndMakeUninit(); + void MakeUninit() { + if (Kind != Uninitialized) + DestroyDataAndMakeUninit(); + } + void MakeInt() { + assert(isUninit() && "Bad state change"); + new ((void*)Data.buffer) APSInt(1); + Kind = Int; + } + void MakeFloat() { + assert(isUninit() && "Bad state change"); + new ((void*)(char*)Data.buffer) APFloat(0.0); + Kind = Float; + } + void MakeVector() { + assert(isUninit() && "Bad state change"); + new ((void*)(char*)Data.buffer) Vec(); + Kind = Vector; + } + void MakeComplexInt() { + assert(isUninit() && "Bad state change"); + new ((void*)(char*)Data.buffer) ComplexAPSInt(); + Kind = ComplexInt; + } + void MakeComplexFloat() { + assert(isUninit() && "Bad state change"); + new ((void*)(char*)Data.buffer) ComplexAPFloat(); + Kind = ComplexFloat; + } + void MakeLValue(); + void MakeArray(unsigned InitElts, unsigned Size); + void MakeStruct(unsigned B, unsigned M) { + assert(isUninit() && "Bad state change"); + new ((void*)(char*)Data.buffer) StructData(B, M); + Kind = Struct; + } + void MakeUnion() { + assert(isUninit() && "Bad state change"); + new ((void*)(char*)Data.buffer) UnionData(); + Kind = Union; + } + void MakeMemberPointer(const ValueDecl *Member, bool IsDerivedMember, + ArrayRef<const CXXRecordDecl*> Path); + void MakeAddrLabelDiff() { + assert(isUninit() && "Bad state change"); + new ((void*)(char*)Data.buffer) AddrLabelDiffData(); + Kind = AddrLabelDiff; + } +}; + +} // end namespace clang. + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/AST.h b/contrib/llvm/tools/clang/include/clang/AST/AST.h new file mode 100644 index 0000000..6db351d --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/AST.h @@ -0,0 +1,28 @@ +//===--- AST.h - "Umbrella" header for AST library --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interface to the AST classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_AST_H +#define LLVM_CLANG_AST_AST_H + +// This header exports all AST interfaces. +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/Type.h" + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/ASTConsumer.h b/contrib/llvm/tools/clang/include/clang/AST/ASTConsumer.h new file mode 100644 index 0000000..b2730e4 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/ASTConsumer.h @@ -0,0 +1,159 @@ +//===--- ASTConsumer.h - Abstract interface for reading ASTs ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ASTConsumer class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_ASTCONSUMER_H +#define LLVM_CLANG_AST_ASTCONSUMER_H + +#include "llvm/ADT/StringRef.h" + +namespace clang { + class ASTContext; + class CXXMethodDecl; + class CXXRecordDecl; + class Decl; + class DeclGroupRef; + class ASTMutationListener; + class ASTDeserializationListener; // layering violation because void* is ugly + class SemaConsumer; // layering violation required for safe SemaConsumer + class TagDecl; + class VarDecl; + class FunctionDecl; + class ImportDecl; + +/// ASTConsumer - This is an abstract interface that should be implemented by +/// clients that read ASTs. This abstraction layer allows the client to be +/// independent of the AST producer (e.g. parser vs AST dump file reader, etc). +class ASTConsumer { + /// \brief Whether this AST consumer also requires information about + /// semantic analysis. + bool SemaConsumer; + + friend class SemaConsumer; + +public: + ASTConsumer() : SemaConsumer(false) { } + + virtual ~ASTConsumer() {} + + /// Initialize - This is called to initialize the consumer, providing the + /// ASTContext. + virtual void Initialize(ASTContext &Context) {} + + /// HandleTopLevelDecl - Handle the specified top-level declaration. This is + /// called by the parser to process every top-level Decl*. + /// + /// \returns true to continue parsing, or false to abort parsing. + virtual bool HandleTopLevelDecl(DeclGroupRef D); + + /// \brief This callback is invoked each time an inline method definition is + /// completed. + virtual void HandleInlineMethodDefinition(CXXMethodDecl *D) {} + + /// HandleInterestingDecl - Handle the specified interesting declaration. This + /// is called by the AST reader when deserializing things that might interest + /// the consumer. The default implementation forwards to HandleTopLevelDecl. + virtual void HandleInterestingDecl(DeclGroupRef D); + + /// HandleTranslationUnit - This method is called when the ASTs for entire + /// translation unit have been parsed. + virtual void HandleTranslationUnit(ASTContext &Ctx) {} + + /// HandleTagDeclDefinition - This callback is invoked each time a TagDecl + /// (e.g. struct, union, enum, class) is completed. This allows the client to + /// hack on the type, which can occur at any point in the file (because these + /// can be defined in declspecs). + virtual void HandleTagDeclDefinition(TagDecl *D) {} + + /// \brief This callback is invoked the first time each TagDecl is required to + /// be complete. + virtual void HandleTagDeclRequiredDefinition(const TagDecl *D) {} + + /// \brief Invoked when a function is implicitly instantiated. + /// Note that at this point point it does not have a body, its body is + /// instantiated at the end of the translation unit and passed to + /// HandleTopLevelDecl. + virtual void HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) {} + + /// \brief Handle the specified top-level declaration that occurred inside + /// and ObjC container. + /// The default implementation ignored them. + virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef D); + + /// \brief Handle an ImportDecl that was implicitly created due to an + /// inclusion directive. + /// The default implementation passes it to HandleTopLevelDecl. + virtual void HandleImplicitImportDecl(ImportDecl *D); + + /// \brief Handle a pragma that appends to Linker Options. Currently this + /// only exists to support Microsoft's #pragma comment(linker, "/foo"). + virtual void HandleLinkerOptionPragma(llvm::StringRef Opts) {} + + /// \brief Handle a pragma that emits a mismatch identifier and value to the + /// object file for the linker to work with. Currently, this only exists to + /// support Microsoft's #pragma detect_mismatch. + virtual void HandleDetectMismatch(llvm::StringRef Name, + llvm::StringRef Value) {} + + /// \brief Handle a dependent library created by a pragma in the source. + /// Currently this only exists to support Microsoft's + /// #pragma comment(lib, "/foo"). + virtual void HandleDependentLibrary(llvm::StringRef Lib) {} + + /// CompleteTentativeDefinition - Callback invoked at the end of a translation + /// unit to notify the consumer that the given tentative definition should be + /// completed. + /// + /// The variable declaration itself will be a tentative + /// definition. If it had an incomplete array type, its type will + /// have already been changed to an array of size 1. However, the + /// declaration remains a tentative definition and has not been + /// modified by the introduction of an implicit zero initializer. + virtual void CompleteTentativeDefinition(VarDecl *D) {} + + /// HandleCXXStaticMemberVarInstantiation - Tell the consumer that this + // variable has been instantiated. + virtual void HandleCXXStaticMemberVarInstantiation(VarDecl *D) {} + + /// \brief Callback involved at the end of a translation unit to + /// notify the consumer that a vtable for the given C++ class is + /// required. + /// + /// \param RD The class whose vtable was used. + virtual void HandleVTable(CXXRecordDecl *RD) {} + + /// \brief If the consumer is interested in entities getting modified after + /// their initial creation, it should return a pointer to + /// an ASTMutationListener here. + virtual ASTMutationListener *GetASTMutationListener() { return nullptr; } + + /// \brief If the consumer is interested in entities being deserialized from + /// AST files, it should return a pointer to a ASTDeserializationListener here + virtual ASTDeserializationListener *GetASTDeserializationListener() { + return nullptr; + } + + /// PrintStats - If desired, print any statistics. + virtual void PrintStats() {} + + /// \brief This callback is called for each function if the Parser was + /// initialized with \c SkipFunctionBodies set to \c true. + /// + /// \return \c true if the function's body should be skipped. The function + /// body may be parsed anyway if it is needed (for instance, if it contains + /// the code completion point or is constexpr). + virtual bool shouldSkipFunctionBody(Decl *D) { return true; } +}; + +} // end namespace clang. + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/ASTContext.h b/contrib/llvm/tools/clang/include/clang/AST/ASTContext.h new file mode 100644 index 0000000..b66009e --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/ASTContext.h @@ -0,0 +1,2672 @@ +//===--- ASTContext.h - Context to hold long-lived AST nodes ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the clang::ASTContext interface. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_ASTCONTEXT_H +#define LLVM_CLANG_AST_ASTCONTEXT_H + +#include "clang/AST/ASTTypeTraits.h" +#include "clang/AST/CanonicalType.h" +#include "clang/AST/CommentCommandTraits.h" +#include "clang/AST/Decl.h" +#include "clang/AST/ExternalASTSource.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/PrettyPrinter.h" +#include "clang/AST/RawCommentList.h" +#include "clang/AST/TemplateName.h" +#include "clang/AST/Type.h" +#include "clang/Basic/AddressSpaces.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/Module.h" +#include "clang/Basic/OperatorKinds.h" +#include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/SanitizerBlacklist.h" +#include "clang/Basic/VersionTuple.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/TinyPtrVector.h" +#include "llvm/Support/Allocator.h" +#include <memory> +#include <vector> + +namespace llvm { + struct fltSemantics; +} + +namespace clang { + class FileManager; + class AtomicExpr; + class ASTRecordLayout; + class BlockExpr; + class CharUnits; + class DiagnosticsEngine; + class Expr; + class ASTMutationListener; + class IdentifierTable; + class MaterializeTemporaryExpr; + class SelectorTable; + class TargetInfo; + class CXXABI; + class MangleNumberingContext; + // Decls + class MangleContext; + class ObjCIvarDecl; + class ObjCPropertyDecl; + class UnresolvedSetIterator; + class UsingDecl; + class UsingShadowDecl; + class VTableContextBase; + + namespace Builtin { class Context; } + enum BuiltinTemplateKind : int; + + namespace comments { + class FullComment; + } + + struct TypeInfo { + uint64_t Width; + unsigned Align; + bool AlignIsRequired : 1; + TypeInfo() : Width(0), Align(0), AlignIsRequired(false) {} + TypeInfo(uint64_t Width, unsigned Align, bool AlignIsRequired) + : Width(Width), Align(Align), AlignIsRequired(AlignIsRequired) {} + }; + +/// \brief Holds long-lived AST nodes (such as types and decls) that can be +/// referred to throughout the semantic analysis of a file. +class ASTContext : public RefCountedBase<ASTContext> { + ASTContext &this_() { return *this; } + + mutable SmallVector<Type *, 0> Types; + mutable llvm::FoldingSet<ExtQuals> ExtQualNodes; + mutable llvm::FoldingSet<ComplexType> ComplexTypes; + mutable llvm::FoldingSet<PointerType> PointerTypes; + mutable llvm::FoldingSet<AdjustedType> AdjustedTypes; + mutable llvm::FoldingSet<BlockPointerType> BlockPointerTypes; + mutable llvm::FoldingSet<LValueReferenceType> LValueReferenceTypes; + mutable llvm::FoldingSet<RValueReferenceType> RValueReferenceTypes; + mutable llvm::FoldingSet<MemberPointerType> MemberPointerTypes; + mutable llvm::FoldingSet<ConstantArrayType> ConstantArrayTypes; + mutable llvm::FoldingSet<IncompleteArrayType> IncompleteArrayTypes; + mutable std::vector<VariableArrayType*> VariableArrayTypes; + mutable llvm::FoldingSet<DependentSizedArrayType> DependentSizedArrayTypes; + mutable llvm::FoldingSet<DependentSizedExtVectorType> + DependentSizedExtVectorTypes; + mutable llvm::FoldingSet<VectorType> VectorTypes; + mutable llvm::FoldingSet<FunctionNoProtoType> FunctionNoProtoTypes; + mutable llvm::ContextualFoldingSet<FunctionProtoType, ASTContext&> + FunctionProtoTypes; + mutable llvm::FoldingSet<DependentTypeOfExprType> DependentTypeOfExprTypes; + mutable llvm::FoldingSet<DependentDecltypeType> DependentDecltypeTypes; + mutable llvm::FoldingSet<TemplateTypeParmType> TemplateTypeParmTypes; + mutable llvm::FoldingSet<SubstTemplateTypeParmType> + SubstTemplateTypeParmTypes; + mutable llvm::FoldingSet<SubstTemplateTypeParmPackType> + SubstTemplateTypeParmPackTypes; + mutable llvm::ContextualFoldingSet<TemplateSpecializationType, ASTContext&> + TemplateSpecializationTypes; + mutable llvm::FoldingSet<ParenType> ParenTypes; + mutable llvm::FoldingSet<ElaboratedType> ElaboratedTypes; + mutable llvm::FoldingSet<DependentNameType> DependentNameTypes; + mutable llvm::ContextualFoldingSet<DependentTemplateSpecializationType, + ASTContext&> + DependentTemplateSpecializationTypes; + llvm::FoldingSet<PackExpansionType> PackExpansionTypes; + mutable llvm::FoldingSet<ObjCObjectTypeImpl> ObjCObjectTypes; + mutable llvm::FoldingSet<ObjCObjectPointerType> ObjCObjectPointerTypes; + mutable llvm::FoldingSet<AutoType> AutoTypes; + mutable llvm::FoldingSet<AtomicType> AtomicTypes; + llvm::FoldingSet<AttributedType> AttributedTypes; + + mutable llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames; + mutable llvm::FoldingSet<DependentTemplateName> DependentTemplateNames; + mutable llvm::FoldingSet<SubstTemplateTemplateParmStorage> + SubstTemplateTemplateParms; + mutable llvm::ContextualFoldingSet<SubstTemplateTemplateParmPackStorage, + ASTContext&> + SubstTemplateTemplateParmPacks; + + /// \brief The set of nested name specifiers. + /// + /// This set is managed by the NestedNameSpecifier class. + mutable llvm::FoldingSet<NestedNameSpecifier> NestedNameSpecifiers; + mutable NestedNameSpecifier *GlobalNestedNameSpecifier; + friend class NestedNameSpecifier; + + /// \brief A cache mapping from RecordDecls to ASTRecordLayouts. + /// + /// This is lazily created. This is intentionally not serialized. + mutable llvm::DenseMap<const RecordDecl*, const ASTRecordLayout*> + ASTRecordLayouts; + mutable llvm::DenseMap<const ObjCContainerDecl*, const ASTRecordLayout*> + ObjCLayouts; + + /// \brief A cache from types to size and alignment information. + typedef llvm::DenseMap<const Type *, struct TypeInfo> TypeInfoMap; + mutable TypeInfoMap MemoizedTypeInfo; + + /// \brief A cache mapping from CXXRecordDecls to key functions. + llvm::DenseMap<const CXXRecordDecl*, LazyDeclPtr> KeyFunctions; + + /// \brief Mapping from ObjCContainers to their ObjCImplementations. + llvm::DenseMap<ObjCContainerDecl*, ObjCImplDecl*> ObjCImpls; + + /// \brief Mapping from ObjCMethod to its duplicate declaration in the same + /// interface. + llvm::DenseMap<const ObjCMethodDecl*,const ObjCMethodDecl*> ObjCMethodRedecls; + + /// \brief Mapping from __block VarDecls to their copy initialization expr. + llvm::DenseMap<const VarDecl*, Expr*> BlockVarCopyInits; + + /// \brief Mapping from class scope functions specialization to their + /// template patterns. + llvm::DenseMap<const FunctionDecl*, FunctionDecl*> + ClassScopeSpecializationPattern; + + /// \brief Mapping from materialized temporaries with static storage duration + /// that appear in constant initializers to their evaluated values. These are + /// allocated in a std::map because their address must be stable. + llvm::DenseMap<const MaterializeTemporaryExpr *, APValue *> + MaterializedTemporaryValues; + + /// \brief Representation of a "canonical" template template parameter that + /// is used in canonical template names. + class CanonicalTemplateTemplateParm : public llvm::FoldingSetNode { + TemplateTemplateParmDecl *Parm; + + public: + CanonicalTemplateTemplateParm(TemplateTemplateParmDecl *Parm) + : Parm(Parm) { } + + TemplateTemplateParmDecl *getParam() const { return Parm; } + + void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Parm); } + + static void Profile(llvm::FoldingSetNodeID &ID, + TemplateTemplateParmDecl *Parm); + }; + mutable llvm::FoldingSet<CanonicalTemplateTemplateParm> + CanonTemplateTemplateParms; + + TemplateTemplateParmDecl * + getCanonicalTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTP) const; + + /// \brief The typedef for the __int128_t type. + mutable TypedefDecl *Int128Decl; + + /// \brief The typedef for the __uint128_t type. + mutable TypedefDecl *UInt128Decl; + + /// \brief The typedef for the __float128 stub type. + mutable TypeDecl *Float128StubDecl; + + /// \brief The typedef for the target specific predefined + /// __builtin_va_list type. + mutable TypedefDecl *BuiltinVaListDecl; + + /// The typedef for the predefined \c __builtin_ms_va_list type. + mutable TypedefDecl *BuiltinMSVaListDecl; + + /// \brief The typedef for the predefined \c id type. + mutable TypedefDecl *ObjCIdDecl; + + /// \brief The typedef for the predefined \c SEL type. + mutable TypedefDecl *ObjCSelDecl; + + /// \brief The typedef for the predefined \c Class type. + mutable TypedefDecl *ObjCClassDecl; + + /// \brief The typedef for the predefined \c Protocol class in Objective-C. + mutable ObjCInterfaceDecl *ObjCProtocolClassDecl; + + /// \brief The typedef for the predefined 'BOOL' type. + mutable TypedefDecl *BOOLDecl; + + // Typedefs which may be provided defining the structure of Objective-C + // pseudo-builtins + QualType ObjCIdRedefinitionType; + QualType ObjCClassRedefinitionType; + QualType ObjCSelRedefinitionType; + + /// The identifier 'NSObject'. + IdentifierInfo *NSObjectName = nullptr; + + /// The identifier 'NSCopying'. + IdentifierInfo *NSCopyingName = nullptr; + + /// The identifier '__make_integer_seq'. + mutable IdentifierInfo *MakeIntegerSeqName = nullptr; + + QualType ObjCConstantStringType; + mutable RecordDecl *CFConstantStringTypeDecl; + + mutable QualType ObjCSuperType; + + QualType ObjCNSStringType; + + /// \brief The typedef declaration for the Objective-C "instancetype" type. + TypedefDecl *ObjCInstanceTypeDecl; + + /// \brief The type for the C FILE type. + TypeDecl *FILEDecl; + + /// \brief The type for the C jmp_buf type. + TypeDecl *jmp_bufDecl; + + /// \brief The type for the C sigjmp_buf type. + TypeDecl *sigjmp_bufDecl; + + /// \brief The type for the C ucontext_t type. + TypeDecl *ucontext_tDecl; + + /// \brief Type for the Block descriptor for Blocks CodeGen. + /// + /// Since this is only used for generation of debug info, it is not + /// serialized. + mutable RecordDecl *BlockDescriptorType; + + /// \brief Type for the Block descriptor for Blocks CodeGen. + /// + /// Since this is only used for generation of debug info, it is not + /// serialized. + mutable RecordDecl *BlockDescriptorExtendedType; + + /// \brief Declaration for the CUDA cudaConfigureCall function. + FunctionDecl *cudaConfigureCallDecl; + + /// \brief Keeps track of all declaration attributes. + /// + /// Since so few decls have attrs, we keep them in a hash map instead of + /// wasting space in the Decl class. + llvm::DenseMap<const Decl*, AttrVec*> DeclAttrs; + + /// \brief A mapping from non-redeclarable declarations in modules that were + /// merged with other declarations to the canonical declaration that they were + /// merged into. + llvm::DenseMap<Decl*, Decl*> MergedDecls; + + /// \brief A mapping from a defining declaration to a list of modules (other + /// than the owning module of the declaration) that contain merged + /// definitions of that entity. + llvm::DenseMap<NamedDecl*, llvm::TinyPtrVector<Module*>> MergedDefModules; + +public: + /// \brief A type synonym for the TemplateOrInstantiation mapping. + typedef llvm::PointerUnion<VarTemplateDecl *, MemberSpecializationInfo *> + TemplateOrSpecializationInfo; + +private: + + /// \brief A mapping to contain the template or declaration that + /// a variable declaration describes or was instantiated from, + /// respectively. + /// + /// For non-templates, this value will be NULL. For variable + /// declarations that describe a variable template, this will be a + /// pointer to a VarTemplateDecl. For static data members + /// of class template specializations, this will be the + /// MemberSpecializationInfo referring to the member variable that was + /// instantiated or specialized. Thus, the mapping will keep track of + /// the static data member templates from which static data members of + /// class template specializations were instantiated. + /// + /// Given the following example: + /// + /// \code + /// template<typename T> + /// struct X { + /// static T value; + /// }; + /// + /// template<typename T> + /// T X<T>::value = T(17); + /// + /// int *x = &X<int>::value; + /// \endcode + /// + /// This mapping will contain an entry that maps from the VarDecl for + /// X<int>::value to the corresponding VarDecl for X<T>::value (within the + /// class template X) and will be marked TSK_ImplicitInstantiation. + llvm::DenseMap<const VarDecl *, TemplateOrSpecializationInfo> + TemplateOrInstantiation; + + /// \brief Keeps track of the declaration from which a UsingDecl was + /// created during instantiation. + /// + /// The source declaration is always a UsingDecl, an UnresolvedUsingValueDecl, + /// or an UnresolvedUsingTypenameDecl. + /// + /// For example: + /// \code + /// template<typename T> + /// struct A { + /// void f(); + /// }; + /// + /// template<typename T> + /// struct B : A<T> { + /// using A<T>::f; + /// }; + /// + /// template struct B<int>; + /// \endcode + /// + /// This mapping will contain an entry that maps from the UsingDecl in + /// B<int> to the UnresolvedUsingDecl in B<T>. + llvm::DenseMap<UsingDecl *, NamedDecl *> InstantiatedFromUsingDecl; + + llvm::DenseMap<UsingShadowDecl*, UsingShadowDecl*> + InstantiatedFromUsingShadowDecl; + + llvm::DenseMap<FieldDecl *, FieldDecl *> InstantiatedFromUnnamedFieldDecl; + + /// \brief Mapping that stores the methods overridden by a given C++ + /// member function. + /// + /// Since most C++ member functions aren't virtual and therefore + /// don't override anything, we store the overridden functions in + /// this map on the side rather than within the CXXMethodDecl structure. + typedef llvm::TinyPtrVector<const CXXMethodDecl*> CXXMethodVector; + llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector> OverriddenMethods; + + /// \brief Mapping from each declaration context to its corresponding + /// mangling numbering context (used for constructs like lambdas which + /// need to be consistently numbered for the mangler). + llvm::DenseMap<const DeclContext *, MangleNumberingContext *> + MangleNumberingContexts; + + /// \brief Side-table of mangling numbers for declarations which rarely + /// need them (like static local vars). + llvm::DenseMap<const NamedDecl *, unsigned> MangleNumbers; + llvm::DenseMap<const VarDecl *, unsigned> StaticLocalNumbers; + + /// \brief Mapping that stores parameterIndex values for ParmVarDecls when + /// that value exceeds the bitfield size of ParmVarDeclBits.ParameterIndex. + typedef llvm::DenseMap<const VarDecl *, unsigned> ParameterIndexTable; + ParameterIndexTable ParamIndices; + + ImportDecl *FirstLocalImport; + ImportDecl *LastLocalImport; + + TranslationUnitDecl *TUDecl; + mutable ExternCContextDecl *ExternCContext; + mutable BuiltinTemplateDecl *MakeIntegerSeqDecl; + + /// \brief The associated SourceManager object.a + SourceManager &SourceMgr; + + /// \brief The language options used to create the AST associated with + /// this ASTContext object. + LangOptions &LangOpts; + + /// \brief Blacklist object that is used by sanitizers to decide which + /// entities should not be instrumented. + std::unique_ptr<SanitizerBlacklist> SanitizerBL; + + /// \brief The allocator used to create AST objects. + /// + /// AST objects are never destructed; rather, all memory associated with the + /// AST objects will be released when the ASTContext itself is destroyed. + mutable llvm::BumpPtrAllocator BumpAlloc; + + /// \brief Allocator for partial diagnostics. + PartialDiagnostic::StorageAllocator DiagAllocator; + + /// \brief The current C++ ABI. + std::unique_ptr<CXXABI> ABI; + CXXABI *createCXXABI(const TargetInfo &T); + + /// \brief The logical -> physical address space map. + const LangAS::Map *AddrSpaceMap; + + /// \brief Address space map mangling must be used with language specific + /// address spaces (e.g. OpenCL/CUDA) + bool AddrSpaceMapMangling; + + friend class ASTDeclReader; + friend class ASTReader; + friend class ASTWriter; + friend class CXXRecordDecl; + + const TargetInfo *Target; + const TargetInfo *AuxTarget; + clang::PrintingPolicy PrintingPolicy; + +public: + IdentifierTable &Idents; + SelectorTable &Selectors; + Builtin::Context &BuiltinInfo; + mutable DeclarationNameTable DeclarationNames; + IntrusiveRefCntPtr<ExternalASTSource> ExternalSource; + ASTMutationListener *Listener; + + /// \brief Contains parents of a node. + typedef llvm::SmallVector<ast_type_traits::DynTypedNode, 2> ParentVector; + + /// \brief Maps from a node to its parents. This is used for nodes that have + /// pointer identity only, which are more common and we can save space by + /// only storing a unique pointer to them. + typedef llvm::DenseMap<const void *, + llvm::PointerUnion4<const Decl *, const Stmt *, + ast_type_traits::DynTypedNode *, + ParentVector *>> ParentMapPointers; + + /// Parent map for nodes without pointer identity. We store a full + /// DynTypedNode for all keys. + typedef llvm::DenseMap< + ast_type_traits::DynTypedNode, + llvm::PointerUnion4<const Decl *, const Stmt *, + ast_type_traits::DynTypedNode *, ParentVector *>> + ParentMapOtherNodes; + + /// Container for either a single DynTypedNode or for an ArrayRef to + /// DynTypedNode. For use with ParentMap. + class DynTypedNodeList { + typedef ast_type_traits::DynTypedNode DynTypedNode; + llvm::AlignedCharArrayUnion<ast_type_traits::DynTypedNode, + ArrayRef<DynTypedNode>> Storage; + bool IsSingleNode; + + public: + DynTypedNodeList(const DynTypedNode &N) : IsSingleNode(true) { + new (Storage.buffer) DynTypedNode(N); + } + DynTypedNodeList(ArrayRef<DynTypedNode> A) : IsSingleNode(false) { + new (Storage.buffer) ArrayRef<DynTypedNode>(A); + } + + const ast_type_traits::DynTypedNode *begin() const { + if (!IsSingleNode) + return reinterpret_cast<const ArrayRef<DynTypedNode> *>(Storage.buffer) + ->begin(); + return reinterpret_cast<const DynTypedNode *>(Storage.buffer); + } + + const ast_type_traits::DynTypedNode *end() const { + if (!IsSingleNode) + return reinterpret_cast<const ArrayRef<DynTypedNode> *>(Storage.buffer) + ->end(); + return reinterpret_cast<const DynTypedNode *>(Storage.buffer) + 1; + } + + size_t size() const { return end() - begin(); } + bool empty() const { return begin() == end(); } + const DynTypedNode &operator[](size_t N) const { + assert(N < size() && "Out of bounds!"); + return *(begin() + N); + } + }; + + /// \brief Returns the parents of the given node. + /// + /// Note that this will lazily compute the parents of all nodes + /// and store them for later retrieval. Thus, the first call is O(n) + /// in the number of AST nodes. + /// + /// Caveats and FIXMEs: + /// Calculating the parent map over all AST nodes will need to load the + /// full AST. This can be undesirable in the case where the full AST is + /// expensive to create (for example, when using precompiled header + /// preambles). Thus, there are good opportunities for optimization here. + /// One idea is to walk the given node downwards, looking for references + /// to declaration contexts - once a declaration context is found, compute + /// the parent map for the declaration context; if that can satisfy the + /// request, loading the whole AST can be avoided. Note that this is made + /// more complex by statements in templates having multiple parents - those + /// problems can be solved by building closure over the templated parts of + /// the AST, which also avoids touching large parts of the AST. + /// Additionally, we will want to add an interface to already give a hint + /// where to search for the parents, for example when looking at a statement + /// inside a certain function. + /// + /// 'NodeT' can be one of Decl, Stmt, Type, TypeLoc, + /// NestedNameSpecifier or NestedNameSpecifierLoc. + template <typename NodeT> DynTypedNodeList getParents(const NodeT &Node) { + return getParents(ast_type_traits::DynTypedNode::create(Node)); + } + + DynTypedNodeList getParents(const ast_type_traits::DynTypedNode &Node); + + const clang::PrintingPolicy &getPrintingPolicy() const { + return PrintingPolicy; + } + + void setPrintingPolicy(const clang::PrintingPolicy &Policy) { + PrintingPolicy = Policy; + } + + SourceManager& getSourceManager() { return SourceMgr; } + const SourceManager& getSourceManager() const { return SourceMgr; } + + llvm::BumpPtrAllocator &getAllocator() const { + return BumpAlloc; + } + + void *Allocate(size_t Size, unsigned Align = 8) const { + return BumpAlloc.Allocate(Size, Align); + } + template <typename T> T *Allocate(size_t Num = 1) const { + return static_cast<T *>(Allocate(Num * sizeof(T), llvm::alignOf<T>())); + } + void Deallocate(void *Ptr) const { } + + /// Return the total amount of physical memory allocated for representing + /// AST nodes and type information. + size_t getASTAllocatedMemory() const { + return BumpAlloc.getTotalMemory(); + } + /// Return the total memory used for various side tables. + size_t getSideTableAllocatedMemory() const; + + PartialDiagnostic::StorageAllocator &getDiagAllocator() { + return DiagAllocator; + } + + const TargetInfo &getTargetInfo() const { return *Target; } + const TargetInfo *getAuxTargetInfo() const { return AuxTarget; } + + /// getIntTypeForBitwidth - + /// sets integer QualTy according to specified details: + /// bitwidth, signed/unsigned. + /// Returns empty type if there is no appropriate target types. + QualType getIntTypeForBitwidth(unsigned DestWidth, + unsigned Signed) const; + /// getRealTypeForBitwidth - + /// sets floating point QualTy according to specified bitwidth. + /// Returns empty type if there is no appropriate target types. + QualType getRealTypeForBitwidth(unsigned DestWidth) const; + + bool AtomicUsesUnsupportedLibcall(const AtomicExpr *E) const; + + const LangOptions& getLangOpts() const { return LangOpts; } + + const SanitizerBlacklist &getSanitizerBlacklist() const { + return *SanitizerBL; + } + + DiagnosticsEngine &getDiagnostics() const; + + FullSourceLoc getFullLoc(SourceLocation Loc) const { + return FullSourceLoc(Loc,SourceMgr); + } + + /// \brief All comments in this translation unit. + RawCommentList Comments; + + /// \brief True if comments are already loaded from ExternalASTSource. + mutable bool CommentsLoaded; + + class RawCommentAndCacheFlags { + public: + enum Kind { + /// We searched for a comment attached to the particular declaration, but + /// didn't find any. + /// + /// getRaw() == 0. + NoCommentInDecl = 0, + + /// We have found a comment attached to this particular declaration. + /// + /// getRaw() != 0. + FromDecl, + + /// This declaration does not have an attached comment, and we have + /// searched the redeclaration chain. + /// + /// If getRaw() == 0, the whole redeclaration chain does not have any + /// comments. + /// + /// If getRaw() != 0, it is a comment propagated from other + /// redeclaration. + FromRedecl + }; + + Kind getKind() const LLVM_READONLY { + return Data.getInt(); + } + + void setKind(Kind K) { + Data.setInt(K); + } + + const RawComment *getRaw() const LLVM_READONLY { + return Data.getPointer(); + } + + void setRaw(const RawComment *RC) { + Data.setPointer(RC); + } + + const Decl *getOriginalDecl() const LLVM_READONLY { + return OriginalDecl; + } + + void setOriginalDecl(const Decl *Orig) { + OriginalDecl = Orig; + } + + private: + llvm::PointerIntPair<const RawComment *, 2, Kind> Data; + const Decl *OriginalDecl; + }; + + /// \brief Mapping from declarations to comments attached to any + /// redeclaration. + /// + /// Raw comments are owned by Comments list. This mapping is populated + /// lazily. + mutable llvm::DenseMap<const Decl *, RawCommentAndCacheFlags> RedeclComments; + + /// \brief Mapping from declarations to parsed comments attached to any + /// redeclaration. + mutable llvm::DenseMap<const Decl *, comments::FullComment *> ParsedComments; + + /// \brief Return the documentation comment attached to a given declaration, + /// without looking into cache. + RawComment *getRawCommentForDeclNoCache(const Decl *D) const; + +public: + RawCommentList &getRawCommentList() { + return Comments; + } + + void addComment(const RawComment &RC) { + assert(LangOpts.RetainCommentsFromSystemHeaders || + !SourceMgr.isInSystemHeader(RC.getSourceRange().getBegin())); + Comments.addComment(RC, BumpAlloc); + } + + /// \brief Return the documentation comment attached to a given declaration. + /// Returns NULL if no comment is attached. + /// + /// \param OriginalDecl if not NULL, is set to declaration AST node that had + /// the comment, if the comment we found comes from a redeclaration. + const RawComment * + getRawCommentForAnyRedecl(const Decl *D, + const Decl **OriginalDecl = nullptr) const; + + /// Return parsed documentation comment attached to a given declaration. + /// Returns NULL if no comment is attached. + /// + /// \param PP the Preprocessor used with this TU. Could be NULL if + /// preprocessor is not available. + comments::FullComment *getCommentForDecl(const Decl *D, + const Preprocessor *PP) const; + + /// Return parsed documentation comment attached to a given declaration. + /// Returns NULL if no comment is attached. Does not look at any + /// redeclarations of the declaration. + comments::FullComment *getLocalCommentForDeclUncached(const Decl *D) const; + + comments::FullComment *cloneFullComment(comments::FullComment *FC, + const Decl *D) const; + +private: + mutable comments::CommandTraits CommentCommandTraits; + + /// \brief Iterator that visits import declarations. + class import_iterator { + ImportDecl *Import; + + public: + typedef ImportDecl *value_type; + typedef ImportDecl *reference; + typedef ImportDecl *pointer; + typedef int difference_type; + typedef std::forward_iterator_tag iterator_category; + + import_iterator() : Import() {} + explicit import_iterator(ImportDecl *Import) : Import(Import) {} + + reference operator*() const { return Import; } + pointer operator->() const { return Import; } + + import_iterator &operator++() { + Import = ASTContext::getNextLocalImport(Import); + return *this; + } + + import_iterator operator++(int) { + import_iterator Other(*this); + ++(*this); + return Other; + } + + friend bool operator==(import_iterator X, import_iterator Y) { + return X.Import == Y.Import; + } + + friend bool operator!=(import_iterator X, import_iterator Y) { + return X.Import != Y.Import; + } + }; + +public: + comments::CommandTraits &getCommentCommandTraits() const { + return CommentCommandTraits; + } + + /// \brief Retrieve the attributes for the given declaration. + AttrVec& getDeclAttrs(const Decl *D); + + /// \brief Erase the attributes corresponding to the given declaration. + void eraseDeclAttrs(const Decl *D); + + /// \brief If this variable is an instantiated static data member of a + /// class template specialization, returns the templated static data member + /// from which it was instantiated. + // FIXME: Remove ? + MemberSpecializationInfo *getInstantiatedFromStaticDataMember( + const VarDecl *Var); + + TemplateOrSpecializationInfo + getTemplateOrSpecializationInfo(const VarDecl *Var); + + FunctionDecl *getClassScopeSpecializationPattern(const FunctionDecl *FD); + + void setClassScopeSpecializationPattern(FunctionDecl *FD, + FunctionDecl *Pattern); + + /// \brief Note that the static data member \p Inst is an instantiation of + /// the static data member template \p Tmpl of a class template. + void setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl, + TemplateSpecializationKind TSK, + SourceLocation PointOfInstantiation = SourceLocation()); + + void setTemplateOrSpecializationInfo(VarDecl *Inst, + TemplateOrSpecializationInfo TSI); + + /// \brief If the given using decl \p Inst is an instantiation of a + /// (possibly unresolved) using decl from a template instantiation, + /// return it. + NamedDecl *getInstantiatedFromUsingDecl(UsingDecl *Inst); + + /// \brief Remember that the using decl \p Inst is an instantiation + /// of the using decl \p Pattern of a class template. + void setInstantiatedFromUsingDecl(UsingDecl *Inst, NamedDecl *Pattern); + + void setInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst, + UsingShadowDecl *Pattern); + UsingShadowDecl *getInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst); + + FieldDecl *getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field); + + void setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, FieldDecl *Tmpl); + + // Access to the set of methods overridden by the given C++ method. + typedef CXXMethodVector::const_iterator overridden_cxx_method_iterator; + overridden_cxx_method_iterator + overridden_methods_begin(const CXXMethodDecl *Method) const; + + overridden_cxx_method_iterator + overridden_methods_end(const CXXMethodDecl *Method) const; + + unsigned overridden_methods_size(const CXXMethodDecl *Method) const; + + /// \brief Note that the given C++ \p Method overrides the given \p + /// Overridden method. + void addOverriddenMethod(const CXXMethodDecl *Method, + const CXXMethodDecl *Overridden); + + /// \brief Return C++ or ObjC overridden methods for the given \p Method. + /// + /// An ObjC method is considered to override any method in the class's + /// base classes, its protocols, or its categories' protocols, that has + /// the same selector and is of the same kind (class or instance). + /// A method in an implementation is not considered as overriding the same + /// method in the interface or its categories. + void getOverriddenMethods( + const NamedDecl *Method, + SmallVectorImpl<const NamedDecl *> &Overridden) const; + + /// \brief Notify the AST context that a new import declaration has been + /// parsed or implicitly created within this translation unit. + void addedLocalImportDecl(ImportDecl *Import); + + static ImportDecl *getNextLocalImport(ImportDecl *Import) { + return Import->NextLocalImport; + } + + typedef llvm::iterator_range<import_iterator> import_range; + import_range local_imports() const { + return import_range(import_iterator(FirstLocalImport), import_iterator()); + } + + Decl *getPrimaryMergedDecl(Decl *D) { + Decl *Result = MergedDecls.lookup(D); + return Result ? Result : D; + } + void setPrimaryMergedDecl(Decl *D, Decl *Primary) { + MergedDecls[D] = Primary; + } + + /// \brief Note that the definition \p ND has been merged into module \p M, + /// and should be visible whenever \p M is visible. + void mergeDefinitionIntoModule(NamedDecl *ND, Module *M, + bool NotifyListeners = true); + /// \brief Clean up the merged definition list. Call this if you might have + /// added duplicates into the list. + void deduplicateMergedDefinitonsFor(NamedDecl *ND); + + /// \brief Get the additional modules in which the definition \p Def has + /// been merged. + ArrayRef<Module*> getModulesWithMergedDefinition(NamedDecl *Def) { + auto MergedIt = MergedDefModules.find(Def); + if (MergedIt == MergedDefModules.end()) + return None; + return MergedIt->second; + } + + TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl; } + + ExternCContextDecl *getExternCContextDecl() const; + BuiltinTemplateDecl *getMakeIntegerSeqDecl() const; + + // Builtin Types. + CanQualType VoidTy; + CanQualType BoolTy; + CanQualType CharTy; + CanQualType WCharTy; // [C++ 3.9.1p5]. + CanQualType WideCharTy; // Same as WCharTy in C++, integer type in C99. + CanQualType WIntTy; // [C99 7.24.1], integer type unchanged by default promotions. + 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 HalfTy; // [OpenCL 6.1.1.1], ARM NEON + CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy; + CanQualType VoidPtrTy, NullPtrTy; + CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy; + CanQualType BuiltinFnTy; + CanQualType PseudoObjectTy, ARCUnbridgedCastTy; + CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy; + CanQualType ObjCBuiltinBoolTy; + CanQualType OCLImage1dTy, OCLImage1dArrayTy, OCLImage1dBufferTy; + CanQualType OCLImage2dTy, OCLImage2dArrayTy, OCLImage2dDepthTy; + CanQualType OCLImage2dArrayDepthTy, OCLImage2dMSAATy, OCLImage2dArrayMSAATy; + CanQualType OCLImage2dMSAADepthTy, OCLImage2dArrayMSAADepthTy; + CanQualType OCLImage3dTy; + CanQualType OCLSamplerTy, OCLEventTy, OCLClkEventTy; + CanQualType OCLQueueTy, OCLNDRangeTy, OCLReserveIDTy; + CanQualType OMPArraySectionTy; + + // Types for deductions in C++0x [stmt.ranged]'s desugaring. Built on demand. + mutable QualType AutoDeductTy; // Deduction against 'auto'. + mutable QualType AutoRRefDeductTy; // Deduction against 'auto &&'. + + // Decl used to help define __builtin_va_list for some targets. + // The decl is built when constructing 'BuiltinVaListDecl'. + mutable Decl *VaListTagDecl; + + ASTContext(LangOptions &LOpts, SourceManager &SM, IdentifierTable &idents, + SelectorTable &sels, Builtin::Context &builtins); + + ~ASTContext(); + + /// \brief Attach an external AST source to the AST context. + /// + /// The external AST source provides the ability to load parts of + /// the abstract syntax tree as needed from some external storage, + /// e.g., a precompiled header. + void setExternalSource(IntrusiveRefCntPtr<ExternalASTSource> Source); + + /// \brief Retrieve a pointer to the external AST source associated + /// with this AST context, if any. + ExternalASTSource *getExternalSource() const { + return ExternalSource.get(); + } + + /// \brief Attach an AST mutation listener to the AST context. + /// + /// The AST mutation listener provides the ability to track modifications to + /// the abstract syntax tree entities committed after they were initially + /// created. + void setASTMutationListener(ASTMutationListener *Listener) { + this->Listener = Listener; + } + + /// \brief Retrieve a pointer to the AST mutation listener associated + /// with this AST context, if any. + ASTMutationListener *getASTMutationListener() const { return Listener; } + + void PrintStats() const; + const SmallVectorImpl<Type *>& getTypes() const { return Types; } + + BuiltinTemplateDecl *buildBuiltinTemplateDecl(BuiltinTemplateKind BTK, + const IdentifierInfo *II) const; + + /// \brief Create a new implicit TU-level CXXRecordDecl or RecordDecl + /// declaration. + RecordDecl *buildImplicitRecord(StringRef Name, + RecordDecl::TagKind TK = TTK_Struct) const; + + /// \brief Create a new implicit TU-level typedef declaration. + TypedefDecl *buildImplicitTypedef(QualType T, StringRef Name) const; + + /// \brief Retrieve the declaration for the 128-bit signed integer type. + TypedefDecl *getInt128Decl() const; + + /// \brief Retrieve the declaration for the 128-bit unsigned integer type. + TypedefDecl *getUInt128Decl() const; + + /// \brief Retrieve the declaration for a 128-bit float stub type. + TypeDecl *getFloat128StubType() const; + + //===--------------------------------------------------------------------===// + // Type Constructors + //===--------------------------------------------------------------------===// + +private: + /// \brief Return a type with extended qualifiers. + QualType getExtQualType(const Type *Base, Qualifiers Quals) const; + + QualType getTypeDeclTypeSlow(const TypeDecl *Decl) const; + +public: + /// \brief Return the uniqued reference to the type for an address space + /// qualified type with the specified type and address space. + /// + /// The resulting type has a union of the qualifiers from T and the address + /// space. If T already has an address space specifier, it is silently + /// replaced. + QualType getAddrSpaceQualType(QualType T, unsigned AddressSpace) const; + + /// \brief Return the uniqued reference to the type for an Objective-C + /// gc-qualified type. + /// + /// The retulting type has a union of the qualifiers from T and the gc + /// attribute. + QualType getObjCGCQualType(QualType T, Qualifiers::GC gcAttr) const; + + /// \brief Return the uniqued reference to the type for a \c restrict + /// qualified type. + /// + /// The resulting type has a union of the qualifiers from \p T and + /// \c restrict. + QualType getRestrictType(QualType T) const { + return T.withFastQualifiers(Qualifiers::Restrict); + } + + /// \brief Return the uniqued reference to the type for a \c volatile + /// qualified type. + /// + /// The resulting type has a union of the qualifiers from \p T and + /// \c volatile. + QualType getVolatileType(QualType T) const { + return T.withFastQualifiers(Qualifiers::Volatile); + } + + /// \brief Return the uniqued reference to the type for a \c const + /// qualified type. + /// + /// The resulting type has a union of the qualifiers from \p T and \c const. + /// + /// It can be reasonably expected that this will always be equivalent to + /// calling T.withConst(). + QualType getConstType(QualType T) const { return T.withConst(); } + + /// \brief Change the ExtInfo on a function type. + const FunctionType *adjustFunctionType(const FunctionType *Fn, + FunctionType::ExtInfo EInfo); + + /// Adjust the given function result type. + CanQualType getCanonicalFunctionResultType(QualType ResultType) const; + + /// \brief Change the result type of a function type once it is deduced. + void adjustDeducedFunctionResultType(FunctionDecl *FD, QualType ResultType); + + /// \brief Change the exception specification on a function once it is + /// delay-parsed, instantiated, or computed. + void adjustExceptionSpec(FunctionDecl *FD, + const FunctionProtoType::ExceptionSpecInfo &ESI, + bool AsWritten = false); + + /// \brief Return the uniqued reference to the type for a complex + /// number with the specified element type. + QualType getComplexType(QualType T) const; + CanQualType getComplexType(CanQualType T) const { + return CanQualType::CreateUnsafe(getComplexType((QualType) T)); + } + + /// \brief Return the uniqued reference to the type for a pointer to + /// the specified type. + QualType getPointerType(QualType T) const; + CanQualType getPointerType(CanQualType T) const { + return CanQualType::CreateUnsafe(getPointerType((QualType) T)); + } + + /// \brief Return the uniqued reference to a type adjusted from the original + /// type to a new type. + QualType getAdjustedType(QualType Orig, QualType New) const; + CanQualType getAdjustedType(CanQualType Orig, CanQualType New) const { + return CanQualType::CreateUnsafe( + getAdjustedType((QualType)Orig, (QualType)New)); + } + + /// \brief Return the uniqued reference to the decayed version of the given + /// type. Can only be called on array and function types which decay to + /// pointer types. + QualType getDecayedType(QualType T) const; + CanQualType getDecayedType(CanQualType T) const { + return CanQualType::CreateUnsafe(getDecayedType((QualType) T)); + } + + /// \brief Return the uniqued reference to the atomic type for the specified + /// type. + QualType getAtomicType(QualType T) const; + + /// \brief Return the uniqued reference to the type for a block of the + /// specified type. + QualType getBlockPointerType(QualType T) const; + + /// Gets the struct used to keep track of the descriptor for pointer to + /// blocks. + QualType getBlockDescriptorType() const; + + /// Gets the struct used to keep track of the extended descriptor for + /// pointer to blocks. + QualType getBlockDescriptorExtendedType() const; + + void setcudaConfigureCallDecl(FunctionDecl *FD) { + cudaConfigureCallDecl = FD; + } + FunctionDecl *getcudaConfigureCallDecl() { + return cudaConfigureCallDecl; + } + + /// Returns true iff we need copy/dispose helpers for the given type. + bool BlockRequiresCopying(QualType Ty, const VarDecl *D); + + + /// Returns true, if given type has a known lifetime. HasByrefExtendedLayout is set + /// to false in this case. If HasByrefExtendedLayout returns true, byref variable + /// has extended lifetime. + bool getByrefLifetime(QualType Ty, + Qualifiers::ObjCLifetime &Lifetime, + bool &HasByrefExtendedLayout) const; + + /// \brief Return the uniqued reference to the type for an lvalue reference + /// to the specified type. + QualType getLValueReferenceType(QualType T, bool SpelledAsLValue = true) + const; + + /// \brief Return the uniqued reference to the type for an rvalue reference + /// to the specified type. + QualType getRValueReferenceType(QualType T) const; + + /// \brief Return the uniqued reference to the type for a member pointer to + /// the specified type in the specified class. + /// + /// The class \p Cls is a \c Type because it could be a dependent name. + QualType getMemberPointerType(QualType T, const Type *Cls) const; + + /// \brief Return a non-unique reference to the type for a variable array of + /// the specified element type. + QualType getVariableArrayType(QualType EltTy, Expr *NumElts, + ArrayType::ArraySizeModifier ASM, + unsigned IndexTypeQuals, + SourceRange Brackets) const; + + /// \brief Return a non-unique reference to the type for a dependently-sized + /// array of the specified element type. + /// + /// FIXME: We will need these to be uniqued, or at least comparable, at some + /// point. + QualType getDependentSizedArrayType(QualType EltTy, Expr *NumElts, + ArrayType::ArraySizeModifier ASM, + unsigned IndexTypeQuals, + SourceRange Brackets) const; + + /// \brief Return a unique reference to the type for an incomplete array of + /// the specified element type. + QualType getIncompleteArrayType(QualType EltTy, + ArrayType::ArraySizeModifier ASM, + unsigned IndexTypeQuals) const; + + /// \brief Return the unique reference to the type for a constant array of + /// the specified element type. + QualType getConstantArrayType(QualType EltTy, const llvm::APInt &ArySize, + ArrayType::ArraySizeModifier ASM, + unsigned IndexTypeQuals) const; + + /// \brief Returns a vla type where known sizes are replaced with [*]. + QualType getVariableArrayDecayedType(QualType Ty) const; + + /// \brief Return the unique reference to a vector type of the specified + /// element type and size. + /// + /// \pre \p VectorType must be a built-in type. + QualType getVectorType(QualType VectorType, unsigned NumElts, + VectorType::VectorKind VecKind) const; + + /// \brief Return the unique reference to an extended vector type + /// of the specified element type and size. + /// + /// \pre \p VectorType must be a built-in type. + QualType getExtVectorType(QualType VectorType, unsigned NumElts) const; + + /// \pre Return a non-unique reference to the type for a dependently-sized + /// vector of the specified element type. + /// + /// FIXME: We will need these to be uniqued, or at least comparable, at some + /// point. + QualType getDependentSizedExtVectorType(QualType VectorType, + Expr *SizeExpr, + SourceLocation AttrLoc) const; + + /// \brief Return a K&R style C function type like 'int()'. + QualType getFunctionNoProtoType(QualType ResultTy, + const FunctionType::ExtInfo &Info) const; + + QualType getFunctionNoProtoType(QualType ResultTy) const { + return getFunctionNoProtoType(ResultTy, FunctionType::ExtInfo()); + } + + /// \brief Return a normal function type with a typed argument list. + QualType getFunctionType(QualType ResultTy, ArrayRef<QualType> Args, + const FunctionProtoType::ExtProtoInfo &EPI) const; + + /// \brief Return the unique reference to the type for the specified type + /// declaration. + QualType getTypeDeclType(const TypeDecl *Decl, + const TypeDecl *PrevDecl = nullptr) const { + assert(Decl && "Passed null for Decl param"); + if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); + + if (PrevDecl) { + assert(PrevDecl->TypeForDecl && "previous decl has no TypeForDecl"); + Decl->TypeForDecl = PrevDecl->TypeForDecl; + return QualType(PrevDecl->TypeForDecl, 0); + } + + return getTypeDeclTypeSlow(Decl); + } + + /// \brief Return the unique reference to the type for the specified + /// typedef-name decl. + QualType getTypedefType(const TypedefNameDecl *Decl, + QualType Canon = QualType()) const; + + QualType getRecordType(const RecordDecl *Decl) const; + + QualType getEnumType(const EnumDecl *Decl) const; + + QualType getInjectedClassNameType(CXXRecordDecl *Decl, QualType TST) const; + + QualType getAttributedType(AttributedType::Kind attrKind, + QualType modifiedType, + QualType equivalentType); + + QualType getSubstTemplateTypeParmType(const TemplateTypeParmType *Replaced, + QualType Replacement) const; + QualType getSubstTemplateTypeParmPackType( + const TemplateTypeParmType *Replaced, + const TemplateArgument &ArgPack); + + QualType + getTemplateTypeParmType(unsigned Depth, unsigned Index, + bool ParameterPack, + TemplateTypeParmDecl *ParmDecl = nullptr) const; + + QualType getTemplateSpecializationType(TemplateName T, + const TemplateArgument *Args, + unsigned NumArgs, + QualType Canon = QualType()) const; + + QualType getCanonicalTemplateSpecializationType(TemplateName T, + const TemplateArgument *Args, + unsigned NumArgs) const; + + QualType getTemplateSpecializationType(TemplateName T, + const TemplateArgumentListInfo &Args, + QualType Canon = QualType()) const; + + TypeSourceInfo * + getTemplateSpecializationTypeInfo(TemplateName T, SourceLocation TLoc, + const TemplateArgumentListInfo &Args, + QualType Canon = QualType()) const; + + QualType getParenType(QualType NamedType) const; + + QualType getElaboratedType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, + QualType NamedType) const; + QualType getDependentNameType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, + const IdentifierInfo *Name, + QualType Canon = QualType()) const; + + QualType getDependentTemplateSpecializationType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, + const IdentifierInfo *Name, + const TemplateArgumentListInfo &Args) const; + QualType getDependentTemplateSpecializationType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, + const IdentifierInfo *Name, + unsigned NumArgs, + const TemplateArgument *Args) const; + + QualType getPackExpansionType(QualType Pattern, + Optional<unsigned> NumExpansions); + + QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl, + ObjCInterfaceDecl *PrevDecl = nullptr) const; + + /// Legacy interface: cannot provide type arguments or __kindof. + QualType getObjCObjectType(QualType Base, + ObjCProtocolDecl * const *Protocols, + unsigned NumProtocols) const; + + QualType getObjCObjectType(QualType Base, + ArrayRef<QualType> typeArgs, + ArrayRef<ObjCProtocolDecl *> protocols, + bool isKindOf) const; + + bool ObjCObjectAdoptsQTypeProtocols(QualType QT, ObjCInterfaceDecl *Decl); + /// QIdProtocolsAdoptObjCObjectProtocols - Checks that protocols in + /// QT's qualified-id protocol list adopt all protocols in IDecl's list + /// of protocols. + bool QIdProtocolsAdoptObjCObjectProtocols(QualType QT, + ObjCInterfaceDecl *IDecl); + + /// \brief Return a ObjCObjectPointerType type for the given ObjCObjectType. + QualType getObjCObjectPointerType(QualType OIT) const; + + /// \brief GCC extension. + QualType getTypeOfExprType(Expr *e) const; + QualType getTypeOfType(QualType t) const; + + /// \brief C++11 decltype. + QualType getDecltypeType(Expr *e, QualType UnderlyingType) const; + + /// \brief Unary type transforms + QualType getUnaryTransformType(QualType BaseType, QualType UnderlyingType, + UnaryTransformType::UTTKind UKind) const; + + /// \brief C++11 deduced auto type. + QualType getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, + bool IsDependent) const; + + /// \brief C++11 deduction pattern for 'auto' type. + QualType getAutoDeductType() const; + + /// \brief C++11 deduction pattern for 'auto &&' type. + QualType getAutoRRefDeductType() const; + + /// \brief Return the unique reference to the type for the specified TagDecl + /// (struct/union/class/enum) decl. + QualType getTagDeclType(const TagDecl *Decl) const; + + /// \brief Return the unique type for "size_t" (C99 7.17), defined in + /// <stddef.h>. + /// + /// The sizeof operator requires this (C99 6.5.3.4p4). + CanQualType getSizeType() const; + + /// \brief Return the unique type for "intmax_t" (C99 7.18.1.5), defined in + /// <stdint.h>. + CanQualType getIntMaxType() const; + + /// \brief Return the unique type for "uintmax_t" (C99 7.18.1.5), defined in + /// <stdint.h>. + CanQualType getUIntMaxType() const; + + /// \brief Return the unique wchar_t type available in C++ (and available as + /// __wchar_t as a Microsoft extension). + QualType getWCharType() const { return WCharTy; } + + /// \brief Return the type of wide characters. In C++, this returns the + /// unique wchar_t type. In C99, this returns a type compatible with the type + /// defined in <stddef.h> as defined by the target. + QualType getWideCharType() const { return WideCharTy; } + + /// \brief Return the type of "signed wchar_t". + /// + /// Used when in C++, as a GCC extension. + QualType getSignedWCharType() const; + + /// \brief Return the type of "unsigned wchar_t". + /// + /// Used when in C++, as a GCC extension. + QualType getUnsignedWCharType() const; + + /// \brief In C99, this returns a type compatible with the type + /// defined in <stddef.h> as defined by the target. + QualType getWIntType() const { return WIntTy; } + + /// \brief Return a type compatible with "intptr_t" (C99 7.18.1.4), + /// as defined by the target. + QualType getIntPtrType() const; + + /// \brief Return a type compatible with "uintptr_t" (C99 7.18.1.4), + /// as defined by the target. + QualType getUIntPtrType() const; + + /// \brief Return the unique type for "ptrdiff_t" (C99 7.17) defined in + /// <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9). + QualType getPointerDiffType() const; + + /// \brief Return the unique type for "pid_t" defined in + /// <sys/types.h>. We need this to compute the correct type for vfork(). + QualType getProcessIDType() const; + + /// \brief Return the C structure type used to represent constant CFStrings. + QualType getCFConstantStringType() const; + + /// \brief Returns the C struct type for objc_super + QualType getObjCSuperType() const; + void setObjCSuperType(QualType ST) { ObjCSuperType = ST; } + + /// Get the structure type used to representation CFStrings, or NULL + /// if it hasn't yet been built. + QualType getRawCFConstantStringType() const { + if (CFConstantStringTypeDecl) + return getTagDeclType(CFConstantStringTypeDecl); + return QualType(); + } + void setCFConstantStringType(QualType T); + + // This setter/getter represents the ObjC type for an NSConstantString. + void setObjCConstantStringInterface(ObjCInterfaceDecl *Decl); + QualType getObjCConstantStringInterface() const { + return ObjCConstantStringType; + } + + QualType getObjCNSStringType() const { + return ObjCNSStringType; + } + + void setObjCNSStringType(QualType T) { + ObjCNSStringType = T; + } + + /// \brief Retrieve the type that \c id has been defined to, which may be + /// different from the built-in \c id if \c id has been typedef'd. + QualType getObjCIdRedefinitionType() const { + if (ObjCIdRedefinitionType.isNull()) + return getObjCIdType(); + return ObjCIdRedefinitionType; + } + + /// \brief Set the user-written type that redefines \c id. + void setObjCIdRedefinitionType(QualType RedefType) { + ObjCIdRedefinitionType = RedefType; + } + + /// \brief Retrieve the type that \c Class has been defined to, which may be + /// different from the built-in \c Class if \c Class has been typedef'd. + QualType getObjCClassRedefinitionType() const { + if (ObjCClassRedefinitionType.isNull()) + return getObjCClassType(); + return ObjCClassRedefinitionType; + } + + /// \brief Set the user-written type that redefines 'SEL'. + void setObjCClassRedefinitionType(QualType RedefType) { + ObjCClassRedefinitionType = RedefType; + } + + /// \brief Retrieve the type that 'SEL' has been defined to, which may be + /// different from the built-in 'SEL' if 'SEL' has been typedef'd. + QualType getObjCSelRedefinitionType() const { + if (ObjCSelRedefinitionType.isNull()) + return getObjCSelType(); + return ObjCSelRedefinitionType; + } + + + /// \brief Set the user-written type that redefines 'SEL'. + void setObjCSelRedefinitionType(QualType RedefType) { + ObjCSelRedefinitionType = RedefType; + } + + /// Retrieve the identifier 'NSObject'. + IdentifierInfo *getNSObjectName() { + if (!NSObjectName) { + NSObjectName = &Idents.get("NSObject"); + } + + return NSObjectName; + } + + /// Retrieve the identifier 'NSCopying'. + IdentifierInfo *getNSCopyingName() { + if (!NSCopyingName) { + NSCopyingName = &Idents.get("NSCopying"); + } + + return NSCopyingName; + } + + IdentifierInfo *getMakeIntegerSeqName() const { + if (!MakeIntegerSeqName) + MakeIntegerSeqName = &Idents.get("__make_integer_seq"); + return MakeIntegerSeqName; + } + + /// \brief Retrieve the Objective-C "instancetype" type, if already known; + /// otherwise, returns a NULL type; + QualType getObjCInstanceType() { + return getTypeDeclType(getObjCInstanceTypeDecl()); + } + + /// \brief Retrieve the typedef declaration corresponding to the Objective-C + /// "instancetype" type. + TypedefDecl *getObjCInstanceTypeDecl(); + + /// \brief Set the type for the C FILE type. + void setFILEDecl(TypeDecl *FILEDecl) { this->FILEDecl = FILEDecl; } + + /// \brief Retrieve the C FILE type. + QualType getFILEType() const { + if (FILEDecl) + return getTypeDeclType(FILEDecl); + return QualType(); + } + + /// \brief Set the type for the C jmp_buf type. + void setjmp_bufDecl(TypeDecl *jmp_bufDecl) { + this->jmp_bufDecl = jmp_bufDecl; + } + + /// \brief Retrieve the C jmp_buf type. + QualType getjmp_bufType() const { + if (jmp_bufDecl) + return getTypeDeclType(jmp_bufDecl); + return QualType(); + } + + /// \brief Set the type for the C sigjmp_buf type. + void setsigjmp_bufDecl(TypeDecl *sigjmp_bufDecl) { + this->sigjmp_bufDecl = sigjmp_bufDecl; + } + + /// \brief Retrieve the C sigjmp_buf type. + QualType getsigjmp_bufType() const { + if (sigjmp_bufDecl) + return getTypeDeclType(sigjmp_bufDecl); + return QualType(); + } + + /// \brief Set the type for the C ucontext_t type. + void setucontext_tDecl(TypeDecl *ucontext_tDecl) { + this->ucontext_tDecl = ucontext_tDecl; + } + + /// \brief Retrieve the C ucontext_t type. + QualType getucontext_tType() const { + if (ucontext_tDecl) + return getTypeDeclType(ucontext_tDecl); + return QualType(); + } + + /// \brief The result type of logical operations, '<', '>', '!=', etc. + QualType getLogicalOperationType() const { + return getLangOpts().CPlusPlus ? BoolTy : IntTy; + } + + /// \brief Emit the Objective-CC type encoding for the given type \p T into + /// \p S. + /// + /// If \p Field is specified then record field names are also encoded. + void getObjCEncodingForType(QualType T, std::string &S, + const FieldDecl *Field=nullptr, + QualType *NotEncodedT=nullptr) const; + + /// \brief Emit the Objective-C property type encoding for the given + /// type \p T into \p S. + void getObjCEncodingForPropertyType(QualType T, std::string &S) const; + + void getLegacyIntegralTypeEncoding(QualType &t) const; + + /// \brief Put the string version of the type qualifiers \p QT into \p S. + void getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT, + std::string &S) const; + + /// \brief Emit the encoded type for the function \p Decl into \p S. + /// + /// This is in the same format as Objective-C method encodings. + /// + /// \returns true if an error occurred (e.g., because one of the parameter + /// types is incomplete), false otherwise. + bool getObjCEncodingForFunctionDecl(const FunctionDecl *Decl, std::string& S); + + /// \brief Emit the encoded type for the method declaration \p Decl into + /// \p S. + /// + /// \returns true if an error occurred (e.g., because one of the parameter + /// types is incomplete), false otherwise. + bool getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, std::string &S, + bool Extended = false) + const; + + /// \brief Return the encoded type for this block declaration. + std::string getObjCEncodingForBlock(const BlockExpr *blockExpr) const; + + /// getObjCEncodingForPropertyDecl - Return the encoded type for + /// this method declaration. If non-NULL, Container must be either + /// an ObjCCategoryImplDecl or ObjCImplementationDecl; it should + /// only be NULL when getting encodings for protocol properties. + void getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD, + const Decl *Container, + std::string &S) const; + + bool ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto, + ObjCProtocolDecl *rProto) const; + + ObjCPropertyImplDecl *getObjCPropertyImplDeclForPropertyDecl( + const ObjCPropertyDecl *PD, + const Decl *Container) const; + + /// \brief Return the size of type \p T for Objective-C encoding purpose, + /// in characters. + CharUnits getObjCEncodingTypeSize(QualType T) const; + + /// \brief Retrieve the typedef corresponding to the predefined \c id type + /// in Objective-C. + TypedefDecl *getObjCIdDecl() const; + + /// \brief Represents the Objective-CC \c id type. + /// + /// This is set up lazily, by Sema. \c id is always a (typedef for a) + /// pointer type, a pointer to a struct. + QualType getObjCIdType() const { + return getTypeDeclType(getObjCIdDecl()); + } + + /// \brief Retrieve the typedef corresponding to the predefined 'SEL' type + /// in Objective-C. + TypedefDecl *getObjCSelDecl() const; + + /// \brief Retrieve the type that corresponds to the predefined Objective-C + /// 'SEL' type. + QualType getObjCSelType() const { + return getTypeDeclType(getObjCSelDecl()); + } + + /// \brief Retrieve the typedef declaration corresponding to the predefined + /// Objective-C 'Class' type. + TypedefDecl *getObjCClassDecl() const; + + /// \brief Represents the Objective-C \c Class type. + /// + /// This is set up lazily, by Sema. \c Class is always a (typedef for a) + /// pointer type, a pointer to a struct. + QualType getObjCClassType() const { + return getTypeDeclType(getObjCClassDecl()); + } + + /// \brief Retrieve the Objective-C class declaration corresponding to + /// the predefined \c Protocol class. + ObjCInterfaceDecl *getObjCProtocolDecl() const; + + /// \brief Retrieve declaration of 'BOOL' typedef + TypedefDecl *getBOOLDecl() const { + return BOOLDecl; + } + + /// \brief Save declaration of 'BOOL' typedef + void setBOOLDecl(TypedefDecl *TD) { + BOOLDecl = TD; + } + + /// \brief type of 'BOOL' type. + QualType getBOOLType() const { + return getTypeDeclType(getBOOLDecl()); + } + + /// \brief Retrieve the type of the Objective-C \c Protocol class. + QualType getObjCProtoType() const { + return getObjCInterfaceType(getObjCProtocolDecl()); + } + + /// \brief Retrieve the C type declaration corresponding to the predefined + /// \c __builtin_va_list type. + TypedefDecl *getBuiltinVaListDecl() const; + + /// \brief Retrieve the type of the \c __builtin_va_list type. + QualType getBuiltinVaListType() const { + return getTypeDeclType(getBuiltinVaListDecl()); + } + + /// \brief Retrieve the C type declaration corresponding to the predefined + /// \c __va_list_tag type used to help define the \c __builtin_va_list type + /// for some targets. + Decl *getVaListTagDecl() const; + + /// Retrieve the C type declaration corresponding to the predefined + /// \c __builtin_ms_va_list type. + TypedefDecl *getBuiltinMSVaListDecl() const; + + /// Retrieve the type of the \c __builtin_ms_va_list type. + QualType getBuiltinMSVaListType() const { + return getTypeDeclType(getBuiltinMSVaListDecl()); + } + + /// \brief Return a type with additional \c const, \c volatile, or + /// \c restrict qualifiers. + QualType getCVRQualifiedType(QualType T, unsigned CVR) const { + return getQualifiedType(T, Qualifiers::fromCVRMask(CVR)); + } + + /// \brief Un-split a SplitQualType. + QualType getQualifiedType(SplitQualType split) const { + return getQualifiedType(split.Ty, split.Quals); + } + + /// \brief Return a type with additional qualifiers. + QualType getQualifiedType(QualType T, Qualifiers Qs) const { + if (!Qs.hasNonFastQualifiers()) + return T.withFastQualifiers(Qs.getFastQualifiers()); + QualifierCollector Qc(Qs); + const Type *Ptr = Qc.strip(T); + return getExtQualType(Ptr, Qc); + } + + /// \brief Return a type with additional qualifiers. + QualType getQualifiedType(const Type *T, Qualifiers Qs) const { + if (!Qs.hasNonFastQualifiers()) + return QualType(T, Qs.getFastQualifiers()); + return getExtQualType(T, Qs); + } + + /// \brief Return a type with the given lifetime qualifier. + /// + /// \pre Neither type.ObjCLifetime() nor \p lifetime may be \c OCL_None. + QualType getLifetimeQualifiedType(QualType type, + Qualifiers::ObjCLifetime lifetime) { + assert(type.getObjCLifetime() == Qualifiers::OCL_None); + assert(lifetime != Qualifiers::OCL_None); + + Qualifiers qs; + qs.addObjCLifetime(lifetime); + return getQualifiedType(type, qs); + } + + /// getUnqualifiedObjCPointerType - Returns version of + /// Objective-C pointer type with lifetime qualifier removed. + QualType getUnqualifiedObjCPointerType(QualType type) const { + if (!type.getTypePtr()->isObjCObjectPointerType() || + !type.getQualifiers().hasObjCLifetime()) + return type; + Qualifiers Qs = type.getQualifiers(); + Qs.removeObjCLifetime(); + return getQualifiedType(type.getUnqualifiedType(), Qs); + } + + DeclarationNameInfo getNameForTemplate(TemplateName Name, + SourceLocation NameLoc) const; + + TemplateName getOverloadedTemplateName(UnresolvedSetIterator Begin, + UnresolvedSetIterator End) const; + + TemplateName getQualifiedTemplateName(NestedNameSpecifier *NNS, + bool TemplateKeyword, + TemplateDecl *Template) const; + + TemplateName getDependentTemplateName(NestedNameSpecifier *NNS, + const IdentifierInfo *Name) const; + TemplateName getDependentTemplateName(NestedNameSpecifier *NNS, + OverloadedOperatorKind Operator) const; + TemplateName getSubstTemplateTemplateParm(TemplateTemplateParmDecl *param, + TemplateName replacement) const; + TemplateName getSubstTemplateTemplateParmPack(TemplateTemplateParmDecl *Param, + const TemplateArgument &ArgPack) const; + + enum GetBuiltinTypeError { + GE_None, ///< No error + GE_Missing_stdio, ///< Missing a type from <stdio.h> + GE_Missing_setjmp, ///< Missing a type from <setjmp.h> + GE_Missing_ucontext ///< Missing a type from <ucontext.h> + }; + + /// \brief Return the type for the specified builtin. + /// + /// If \p IntegerConstantArgs is non-null, it is filled in with a bitmask of + /// arguments to the builtin that are required to be integer constant + /// expressions. + QualType GetBuiltinType(unsigned ID, GetBuiltinTypeError &Error, + unsigned *IntegerConstantArgs = nullptr) const; + +private: + CanQualType getFromTargetType(unsigned Type) const; + TypeInfo getTypeInfoImpl(const Type *T) const; + + //===--------------------------------------------------------------------===// + // Type Predicates. + //===--------------------------------------------------------------------===// + +public: + /// \brief Return one of the GCNone, Weak or Strong Objective-C garbage + /// collection attributes. + Qualifiers::GC getObjCGCAttrKind(QualType Ty) const; + + /// \brief Return true if the given vector types are of the same unqualified + /// type or if they are equivalent to the same GCC vector type. + /// + /// \note This ignores whether they are target-specific (AltiVec or Neon) + /// types. + bool areCompatibleVectorTypes(QualType FirstVec, QualType SecondVec); + + /// \brief Return true if this is an \c NSObject object with its \c NSObject + /// attribute set. + static bool isObjCNSObjectType(QualType Ty) { + return Ty->isObjCNSObjectType(); + } + + //===--------------------------------------------------------------------===// + // Type Sizing and Analysis + //===--------------------------------------------------------------------===// + + /// \brief Return the APFloat 'semantics' for the specified scalar floating + /// point type. + const llvm::fltSemantics &getFloatTypeSemantics(QualType T) const; + + /// \brief Get the size and alignment of the specified complete type in bits. + TypeInfo getTypeInfo(const Type *T) const; + TypeInfo getTypeInfo(QualType T) const { return getTypeInfo(T.getTypePtr()); } + + /// \brief Get default simd alignment of the specified complete type in bits. + unsigned getOpenMPDefaultSimdAlign(QualType T) const; + + /// \brief Return the size of the specified (complete) type \p T, in bits. + uint64_t getTypeSize(QualType T) const { return getTypeInfo(T).Width; } + uint64_t getTypeSize(const Type *T) const { return getTypeInfo(T).Width; } + + /// \brief Return the size of the character type, in bits. + uint64_t getCharWidth() const { + return getTypeSize(CharTy); + } + + /// \brief Convert a size in bits to a size in characters. + CharUnits toCharUnitsFromBits(int64_t BitSize) const; + + /// \brief Convert a size in characters to a size in bits. + int64_t toBits(CharUnits CharSize) const; + + /// \brief Return the size of the specified (complete) type \p T, in + /// characters. + CharUnits getTypeSizeInChars(QualType T) const; + CharUnits getTypeSizeInChars(const Type *T) const; + + /// \brief Return the ABI-specified alignment of a (complete) type \p T, in + /// bits. + unsigned getTypeAlign(QualType T) const { return getTypeInfo(T).Align; } + unsigned getTypeAlign(const Type *T) const { return getTypeInfo(T).Align; } + + /// \brief Return the ABI-specified alignment of a (complete) type \p T, in + /// characters. + CharUnits getTypeAlignInChars(QualType T) const; + CharUnits getTypeAlignInChars(const Type *T) const; + + // getTypeInfoDataSizeInChars - Return the size of a type, in chars. If the + // type is a record, its data size is returned. + std::pair<CharUnits, CharUnits> getTypeInfoDataSizeInChars(QualType T) const; + + std::pair<CharUnits, CharUnits> getTypeInfoInChars(const Type *T) const; + std::pair<CharUnits, CharUnits> getTypeInfoInChars(QualType T) const; + + /// \brief Determine if the alignment the type has was required using an + /// alignment attribute. + bool isAlignmentRequired(const Type *T) const; + bool isAlignmentRequired(QualType T) const; + + /// \brief Return the "preferred" alignment of the specified type \p T for + /// the current target, in bits. + /// + /// This can be different than the ABI alignment in cases where it is + /// beneficial for performance to overalign a data type. + unsigned getPreferredTypeAlign(const Type *T) const; + + /// \brief Return the default alignment for __attribute__((aligned)) on + /// this target, to be used if no alignment value is specified. + unsigned getTargetDefaultAlignForAttributeAligned(void) const; + + /// \brief Return the alignment in bits that should be given to a + /// global variable with type \p T. + unsigned getAlignOfGlobalVar(QualType T) const; + + /// \brief Return the alignment in characters that should be given to a + /// global variable with type \p T. + CharUnits getAlignOfGlobalVarInChars(QualType T) const; + + /// \brief Return a conservative estimate of the alignment of the specified + /// decl \p D. + /// + /// \pre \p D must not be a bitfield type, as bitfields do not have a valid + /// alignment. + /// + /// If \p ForAlignof, references are treated like their underlying type + /// and large arrays don't get any special treatment. If not \p ForAlignof + /// it computes the value expected by CodeGen: references are treated like + /// pointers and large arrays get extra alignment. + CharUnits getDeclAlign(const Decl *D, bool ForAlignof = false) const; + + /// \brief Get or compute information about the layout of the specified + /// record (struct/union/class) \p D, which indicates its size and field + /// position information. + const ASTRecordLayout &getASTRecordLayout(const RecordDecl *D) const; + + /// \brief Get or compute information about the layout of the specified + /// Objective-C interface. + const ASTRecordLayout &getASTObjCInterfaceLayout(const ObjCInterfaceDecl *D) + const; + + void DumpRecordLayout(const RecordDecl *RD, raw_ostream &OS, + bool Simple = false) const; + + /// \brief Get or compute information about the layout of the specified + /// Objective-C implementation. + /// + /// This may differ from the interface if synthesized ivars are present. + const ASTRecordLayout & + getASTObjCImplementationLayout(const ObjCImplementationDecl *D) const; + + /// \brief Get our current best idea for the key function of the + /// given record decl, or NULL if there isn't one. + /// + /// The key function is, according to the Itanium C++ ABI section 5.2.3: + /// ...the first non-pure virtual function that is not inline at the + /// point of class definition. + /// + /// Other ABIs use the same idea. However, the ARM C++ ABI ignores + /// virtual functions that are defined 'inline', which means that + /// the result of this computation can change. + const CXXMethodDecl *getCurrentKeyFunction(const CXXRecordDecl *RD); + + /// \brief Observe that the given method cannot be a key function. + /// Checks the key-function cache for the method's class and clears it + /// if matches the given declaration. + /// + /// This is used in ABIs where out-of-line definitions marked + /// inline are not considered to be key functions. + /// + /// \param method should be the declaration from the class definition + void setNonKeyFunction(const CXXMethodDecl *method); + + /// Loading virtual member pointers using the virtual inheritance model + /// always results in an adjustment using the vbtable even if the index is + /// zero. + /// + /// This is usually OK because the first slot in the vbtable points + /// backwards to the top of the MDC. However, the MDC might be reusing a + /// vbptr from an nv-base. In this case, the first slot in the vbtable + /// points to the start of the nv-base which introduced the vbptr and *not* + /// the MDC. Modify the NonVirtualBaseAdjustment to account for this. + CharUnits getOffsetOfBaseWithVBPtr(const CXXRecordDecl *RD) const; + + /// Get the offset of a FieldDecl or IndirectFieldDecl, in bits. + uint64_t getFieldOffset(const ValueDecl *FD) const; + + bool isNearlyEmpty(const CXXRecordDecl *RD) const; + + VTableContextBase *getVTableContext(); + + MangleContext *createMangleContext(); + + void DeepCollectObjCIvars(const ObjCInterfaceDecl *OI, bool leafClass, + SmallVectorImpl<const ObjCIvarDecl*> &Ivars) const; + + unsigned CountNonClassIvars(const ObjCInterfaceDecl *OI) const; + void CollectInheritedProtocols(const Decl *CDecl, + llvm::SmallPtrSet<ObjCProtocolDecl*, 8> &Protocols); + + //===--------------------------------------------------------------------===// + // Type Operators + //===--------------------------------------------------------------------===// + + /// \brief Return the canonical (structural) type corresponding to the + /// specified potentially non-canonical type \p T. + /// + /// The non-canonical version of a type may have many "decorated" versions of + /// types. Decorators can include typedefs, 'typeof' operators, etc. The + /// returned type is guaranteed to be free of any of these, allowing two + /// canonical types to be compared for exact equality with a simple pointer + /// comparison. + CanQualType getCanonicalType(QualType T) const { + return CanQualType::CreateUnsafe(T.getCanonicalType()); + } + + const Type *getCanonicalType(const Type *T) const { + return T->getCanonicalTypeInternal().getTypePtr(); + } + + /// \brief Return the canonical parameter type corresponding to the specific + /// potentially non-canonical one. + /// + /// Qualifiers are stripped off, functions are turned into function + /// pointers, and arrays decay one level into pointers. + CanQualType getCanonicalParamType(QualType T) const; + + /// \brief Determine whether the given types \p T1 and \p T2 are equivalent. + bool hasSameType(QualType T1, QualType T2) const { + return getCanonicalType(T1) == getCanonicalType(T2); + } + + bool hasSameType(const Type *T1, const Type *T2) const { + return getCanonicalType(T1) == getCanonicalType(T2); + } + + /// \brief Return this type as a completely-unqualified array type, + /// capturing the qualifiers in \p Quals. + /// + /// This will remove the minimal amount of sugaring from the types, similar + /// to the behavior of QualType::getUnqualifiedType(). + /// + /// \param T is the qualified type, which may be an ArrayType + /// + /// \param Quals will receive the full set of qualifiers that were + /// applied to the array. + /// + /// \returns if this is an array type, the completely unqualified array type + /// that corresponds to it. Otherwise, returns T.getUnqualifiedType(). + QualType getUnqualifiedArrayType(QualType T, Qualifiers &Quals); + + /// \brief Determine whether the given types are equivalent after + /// cvr-qualifiers have been removed. + bool hasSameUnqualifiedType(QualType T1, QualType T2) const { + return getCanonicalType(T1).getTypePtr() == + getCanonicalType(T2).getTypePtr(); + } + + bool hasSameNullabilityTypeQualifier(QualType SubT, QualType SuperT, + bool IsParam) const { + auto SubTnullability = SubT->getNullability(*this); + auto SuperTnullability = SuperT->getNullability(*this); + if (SubTnullability.hasValue() == SuperTnullability.hasValue()) { + // Neither has nullability; return true + if (!SubTnullability) + return true; + // Both have nullability qualifier. + if (*SubTnullability == *SuperTnullability || + *SubTnullability == NullabilityKind::Unspecified || + *SuperTnullability == NullabilityKind::Unspecified) + return true; + + if (IsParam) { + // Ok for the superclass method parameter to be "nonnull" and the subclass + // method parameter to be "nullable" + return (*SuperTnullability == NullabilityKind::NonNull && + *SubTnullability == NullabilityKind::Nullable); + } + else { + // For the return type, it's okay for the superclass method to specify + // "nullable" and the subclass method specify "nonnull" + return (*SuperTnullability == NullabilityKind::Nullable && + *SubTnullability == NullabilityKind::NonNull); + } + } + return true; + } + + bool ObjCMethodsAreEqual(const ObjCMethodDecl *MethodDecl, + const ObjCMethodDecl *MethodImp); + + bool UnwrapSimilarPointerTypes(QualType &T1, QualType &T2); + + /// \brief Retrieves the "canonical" nested name specifier for a + /// given nested name specifier. + /// + /// The canonical nested name specifier is a nested name specifier + /// that uniquely identifies a type or namespace within the type + /// system. For example, given: + /// + /// \code + /// namespace N { + /// struct S { + /// template<typename T> struct X { typename T* type; }; + /// }; + /// } + /// + /// template<typename T> struct Y { + /// typename N::S::X<T>::type member; + /// }; + /// \endcode + /// + /// Here, the nested-name-specifier for N::S::X<T>:: will be + /// S::X<template-param-0-0>, since 'S' and 'X' are uniquely defined + /// by declarations in the type system and the canonical type for + /// the template type parameter 'T' is template-param-0-0. + NestedNameSpecifier * + getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const; + + /// \brief Retrieves the default calling convention for the current target. + CallingConv getDefaultCallingConvention(bool isVariadic, + bool IsCXXMethod) const; + + /// \brief Retrieves the "canonical" template name that refers to a + /// given template. + /// + /// The canonical template name is the simplest expression that can + /// be used to refer to a given template. For most templates, this + /// expression is just the template declaration itself. For example, + /// the template std::vector can be referred to via a variety of + /// names---std::vector, \::std::vector, vector (if vector is in + /// scope), etc.---but all of these names map down to the same + /// TemplateDecl, which is used to form the canonical template name. + /// + /// Dependent template names are more interesting. Here, the + /// template name could be something like T::template apply or + /// std::allocator<T>::template rebind, where the nested name + /// specifier itself is dependent. In this case, the canonical + /// template name uses the shortest form of the dependent + /// nested-name-specifier, which itself contains all canonical + /// types, values, and templates. + TemplateName getCanonicalTemplateName(TemplateName Name) const; + + /// \brief Determine whether the given template names refer to the same + /// template. + bool hasSameTemplateName(TemplateName X, TemplateName Y); + + /// \brief Retrieve the "canonical" template argument. + /// + /// The canonical template argument is the simplest template argument + /// (which may be a type, value, expression, or declaration) that + /// expresses the value of the argument. + TemplateArgument getCanonicalTemplateArgument(const TemplateArgument &Arg) + const; + + /// Type Query functions. If the type is an instance of the specified class, + /// return the Type pointer for the underlying maximally pretty type. This + /// is a member of ASTContext because this may need to do some amount of + /// canonicalization, e.g. to move type qualifiers into the element type. + const ArrayType *getAsArrayType(QualType T) const; + const ConstantArrayType *getAsConstantArrayType(QualType T) const { + return dyn_cast_or_null<ConstantArrayType>(getAsArrayType(T)); + } + const VariableArrayType *getAsVariableArrayType(QualType T) const { + return dyn_cast_or_null<VariableArrayType>(getAsArrayType(T)); + } + const IncompleteArrayType *getAsIncompleteArrayType(QualType T) const { + return dyn_cast_or_null<IncompleteArrayType>(getAsArrayType(T)); + } + const DependentSizedArrayType *getAsDependentSizedArrayType(QualType T) + const { + return dyn_cast_or_null<DependentSizedArrayType>(getAsArrayType(T)); + } + + /// \brief Return the innermost element type of an array type. + /// + /// For example, will return "int" for int[m][n] + QualType getBaseElementType(const ArrayType *VAT) const; + + /// \brief Return the innermost element type of a type (which needn't + /// actually be an array type). + QualType getBaseElementType(QualType QT) const; + + /// \brief Return number of constant array elements. + uint64_t getConstantArrayElementCount(const ConstantArrayType *CA) const; + + /// \brief Perform adjustment on the parameter type of a function. + /// + /// This routine adjusts the given parameter type @p T to the actual + /// parameter type used by semantic analysis (C99 6.7.5.3p[7,8], + /// C++ [dcl.fct]p3). The adjusted parameter type is returned. + QualType getAdjustedParameterType(QualType T) const; + + /// \brief Retrieve the parameter type as adjusted for use in the signature + /// of a function, decaying array and function types and removing top-level + /// cv-qualifiers. + QualType getSignatureParameterType(QualType T) const; + + QualType getExceptionObjectType(QualType T) const; + + /// \brief Return the properly qualified result of decaying the specified + /// array type to a pointer. + /// + /// This operation is non-trivial when handling typedefs etc. The canonical + /// type of \p T must be an array type, this returns a pointer to a properly + /// qualified element of the array. + /// + /// See C99 6.7.5.3p7 and C99 6.3.2.1p3. + QualType getArrayDecayedType(QualType T) const; + + /// \brief Return the type that \p PromotableType will promote to: C99 + /// 6.3.1.1p2, assuming that \p PromotableType is a promotable integer type. + QualType getPromotedIntegerType(QualType PromotableType) const; + + /// \brief Recurses in pointer/array types until it finds an Objective-C + /// retainable type and returns its ownership. + Qualifiers::ObjCLifetime getInnerObjCOwnership(QualType T) const; + + /// \brief Whether this is a promotable bitfield reference according + /// to C99 6.3.1.1p2, bullet 2 (and GCC extensions). + /// + /// \returns the type this bit-field will promote to, or NULL if no + /// promotion occurs. + QualType isPromotableBitField(Expr *E) const; + + /// \brief Return the highest ranked integer type, see C99 6.3.1.8p1. + /// + /// If \p LHS > \p RHS, returns 1. If \p LHS == \p RHS, returns 0. If + /// \p LHS < \p RHS, return -1. + int getIntegerTypeOrder(QualType LHS, QualType RHS) const; + + /// \brief Compare the rank of the two specified floating point types, + /// ignoring the domain of the type (i.e. 'double' == '_Complex double'). + /// + /// If \p LHS > \p RHS, returns 1. If \p LHS == \p RHS, returns 0. If + /// \p LHS < \p RHS, return -1. + int getFloatingTypeOrder(QualType LHS, QualType RHS) const; + + /// \brief Return a real floating point or a complex type (based on + /// \p typeDomain/\p typeSize). + /// + /// \param typeDomain a real floating point or complex type. + /// \param typeSize a real floating point or complex type. + QualType getFloatingTypeOfSizeWithinDomain(QualType typeSize, + QualType typeDomain) const; + + unsigned getTargetAddressSpace(QualType T) const { + return getTargetAddressSpace(T.getQualifiers()); + } + + unsigned getTargetAddressSpace(Qualifiers Q) const { + return getTargetAddressSpace(Q.getAddressSpace()); + } + + unsigned getTargetAddressSpace(unsigned AS) const { + if (AS < LangAS::Offset || AS >= LangAS::Offset + LangAS::Count) + return AS; + else + return (*AddrSpaceMap)[AS - LangAS::Offset]; + } + + bool addressSpaceMapManglingFor(unsigned AS) const { + return AddrSpaceMapMangling || + AS < LangAS::Offset || + AS >= LangAS::Offset + LangAS::Count; + } + +private: + // Helper for integer ordering + unsigned getIntegerRank(const Type *T) const; + +public: + + //===--------------------------------------------------------------------===// + // Type Compatibility Predicates + //===--------------------------------------------------------------------===// + + /// Compatibility predicates used to check assignment expressions. + bool typesAreCompatible(QualType T1, QualType T2, + bool CompareUnqualified = false); // C99 6.2.7p1 + + bool propertyTypesAreCompatible(QualType, QualType); + bool typesAreBlockPointerCompatible(QualType, QualType); + + bool isObjCIdType(QualType T) const { + return T == getObjCIdType(); + } + bool isObjCClassType(QualType T) const { + return T == getObjCClassType(); + } + bool isObjCSelType(QualType T) const { + return T == getObjCSelType(); + } + bool ObjCQualifiedIdTypesAreCompatible(QualType LHS, QualType RHS, + bool ForCompare); + + bool ObjCQualifiedClassTypesAreCompatible(QualType LHS, QualType RHS); + + // Check the safety of assignment from LHS to RHS + bool canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT, + const ObjCObjectPointerType *RHSOPT); + bool canAssignObjCInterfaces(const ObjCObjectType *LHS, + const ObjCObjectType *RHS); + bool canAssignObjCInterfacesInBlockPointer( + const ObjCObjectPointerType *LHSOPT, + const ObjCObjectPointerType *RHSOPT, + bool BlockReturnType); + bool areComparableObjCPointerTypes(QualType LHS, QualType RHS); + QualType areCommonBaseCompatible(const ObjCObjectPointerType *LHSOPT, + const ObjCObjectPointerType *RHSOPT); + bool canBindObjCObjectType(QualType To, QualType From); + + // Functions for calculating composite types + QualType mergeTypes(QualType, QualType, bool OfBlockPointer=false, + bool Unqualified = false, bool BlockReturnType = false); + QualType mergeFunctionTypes(QualType, QualType, bool OfBlockPointer=false, + bool Unqualified = false); + QualType mergeFunctionParameterTypes(QualType, QualType, + bool OfBlockPointer = false, + bool Unqualified = false); + QualType mergeTransparentUnionType(QualType, QualType, + bool OfBlockPointer=false, + bool Unqualified = false); + + QualType mergeObjCGCQualifiers(QualType, QualType); + + bool FunctionTypesMatchOnNSConsumedAttrs( + const FunctionProtoType *FromFunctionType, + const FunctionProtoType *ToFunctionType); + + void ResetObjCLayout(const ObjCContainerDecl *CD); + + //===--------------------------------------------------------------------===// + // Integer Predicates + //===--------------------------------------------------------------------===// + + // The width of an integer, as defined in C99 6.2.6.2. This is the number + // of bits in an integer type excluding any padding bits. + unsigned getIntWidth(QualType T) const; + + // Per C99 6.2.5p6, for every signed integer type, there is a corresponding + // unsigned integer type. This method takes a signed type, and returns the + // corresponding unsigned integer type. + QualType getCorrespondingUnsignedType(QualType T) const; + + //===--------------------------------------------------------------------===// + // Integer Values + //===--------------------------------------------------------------------===// + + /// \brief Make an APSInt of the appropriate width and signedness for the + /// given \p Value and integer \p Type. + llvm::APSInt MakeIntValue(uint64_t Value, QualType Type) const { + llvm::APSInt Res(getIntWidth(Type), + !Type->isSignedIntegerOrEnumerationType()); + Res = Value; + return Res; + } + + bool isSentinelNullExpr(const Expr *E); + + /// \brief Get the implementation of the ObjCInterfaceDecl \p D, or NULL if + /// none exists. + ObjCImplementationDecl *getObjCImplementation(ObjCInterfaceDecl *D); + /// \brief Get the implementation of the ObjCCategoryDecl \p D, or NULL if + /// none exists. + ObjCCategoryImplDecl *getObjCImplementation(ObjCCategoryDecl *D); + + /// \brief Return true if there is at least one \@implementation in the TU. + bool AnyObjCImplementation() { + return !ObjCImpls.empty(); + } + + /// \brief Set the implementation of ObjCInterfaceDecl. + void setObjCImplementation(ObjCInterfaceDecl *IFaceD, + ObjCImplementationDecl *ImplD); + /// \brief Set the implementation of ObjCCategoryDecl. + void setObjCImplementation(ObjCCategoryDecl *CatD, + ObjCCategoryImplDecl *ImplD); + + /// \brief Get the duplicate declaration of a ObjCMethod in the same + /// interface, or null if none exists. + const ObjCMethodDecl * + getObjCMethodRedeclaration(const ObjCMethodDecl *MD) const; + + void setObjCMethodRedeclaration(const ObjCMethodDecl *MD, + const ObjCMethodDecl *Redecl); + + /// \brief Returns the Objective-C interface that \p ND belongs to if it is + /// an Objective-C method/property/ivar etc. that is part of an interface, + /// otherwise returns null. + const ObjCInterfaceDecl *getObjContainingInterface(const NamedDecl *ND) const; + + /// \brief Set the copy inialization expression of a block var decl. + void setBlockVarCopyInits(VarDecl*VD, Expr* Init); + /// \brief Get the copy initialization expression of the VarDecl \p VD, or + /// NULL if none exists. + Expr *getBlockVarCopyInits(const VarDecl* VD); + + /// \brief Allocate an uninitialized TypeSourceInfo. + /// + /// The caller should initialize the memory held by TypeSourceInfo using + /// the TypeLoc wrappers. + /// + /// \param T the type that will be the basis for type source info. This type + /// should refer to how the declarator was written in source code, not to + /// what type semantic analysis resolved the declarator to. + /// + /// \param Size the size of the type info to create, or 0 if the size + /// should be calculated based on the type. + TypeSourceInfo *CreateTypeSourceInfo(QualType T, unsigned Size = 0) const; + + /// \brief Allocate a TypeSourceInfo where all locations have been + /// initialized to a given location, which defaults to the empty + /// location. + TypeSourceInfo * + getTrivialTypeSourceInfo(QualType T, + SourceLocation Loc = SourceLocation()) const; + + /// \brief Add a deallocation callback that will be invoked when the + /// ASTContext is destroyed. + /// + /// \param Callback A callback function that will be invoked on destruction. + /// + /// \param Data Pointer data that will be provided to the callback function + /// when it is called. + void AddDeallocation(void (*Callback)(void*), void *Data); + + GVALinkage GetGVALinkageForFunction(const FunctionDecl *FD) const; + GVALinkage GetGVALinkageForVariable(const VarDecl *VD); + + /// \brief Determines if the decl can be CodeGen'ed or deserialized from PCH + /// lazily, only when used; this is only relevant for function or file scoped + /// var definitions. + /// + /// \returns true if the function/var must be CodeGen'ed/deserialized even if + /// it is not used. + bool DeclMustBeEmitted(const Decl *D); + + const CXXConstructorDecl * + getCopyConstructorForExceptionObject(CXXRecordDecl *RD); + + void addCopyConstructorForExceptionObject(CXXRecordDecl *RD, + CXXConstructorDecl *CD); + + void addDefaultArgExprForConstructor(const CXXConstructorDecl *CD, + unsigned ParmIdx, Expr *DAE); + + Expr *getDefaultArgExprForConstructor(const CXXConstructorDecl *CD, + unsigned ParmIdx); + + void addTypedefNameForUnnamedTagDecl(TagDecl *TD, TypedefNameDecl *TND); + + TypedefNameDecl *getTypedefNameForUnnamedTagDecl(const TagDecl *TD); + + void addDeclaratorForUnnamedTagDecl(TagDecl *TD, DeclaratorDecl *DD); + + DeclaratorDecl *getDeclaratorForUnnamedTagDecl(const TagDecl *TD); + + void setManglingNumber(const NamedDecl *ND, unsigned Number); + unsigned getManglingNumber(const NamedDecl *ND) const; + + void setStaticLocalNumber(const VarDecl *VD, unsigned Number); + unsigned getStaticLocalNumber(const VarDecl *VD) const; + + /// \brief Retrieve the context for computing mangling numbers in the given + /// DeclContext. + MangleNumberingContext &getManglingNumberContext(const DeclContext *DC); + + MangleNumberingContext *createMangleNumberingContext() const; + + /// \brief Used by ParmVarDecl to store on the side the + /// index of the parameter when it exceeds the size of the normal bitfield. + void setParameterIndex(const ParmVarDecl *D, unsigned index); + + /// \brief Used by ParmVarDecl to retrieve on the side the + /// index of the parameter when it exceeds the size of the normal bitfield. + unsigned getParameterIndex(const ParmVarDecl *D) const; + + /// \brief Get the storage for the constant value of a materialized temporary + /// of static storage duration. + APValue *getMaterializedTemporaryValue(const MaterializeTemporaryExpr *E, + bool MayCreate); + + //===--------------------------------------------------------------------===// + // Statistics + //===--------------------------------------------------------------------===// + + /// \brief The number of implicitly-declared default constructors. + static unsigned NumImplicitDefaultConstructors; + + /// \brief The number of implicitly-declared default constructors for + /// which declarations were built. + static unsigned NumImplicitDefaultConstructorsDeclared; + + /// \brief The number of implicitly-declared copy constructors. + static unsigned NumImplicitCopyConstructors; + + /// \brief The number of implicitly-declared copy constructors for + /// which declarations were built. + static unsigned NumImplicitCopyConstructorsDeclared; + + /// \brief The number of implicitly-declared move constructors. + static unsigned NumImplicitMoveConstructors; + + /// \brief The number of implicitly-declared move constructors for + /// which declarations were built. + static unsigned NumImplicitMoveConstructorsDeclared; + + /// \brief The number of implicitly-declared copy assignment operators. + static unsigned NumImplicitCopyAssignmentOperators; + + /// \brief The number of implicitly-declared copy assignment operators for + /// which declarations were built. + static unsigned NumImplicitCopyAssignmentOperatorsDeclared; + + /// \brief The number of implicitly-declared move assignment operators. + static unsigned NumImplicitMoveAssignmentOperators; + + /// \brief The number of implicitly-declared move assignment operators for + /// which declarations were built. + static unsigned NumImplicitMoveAssignmentOperatorsDeclared; + + /// \brief The number of implicitly-declared destructors. + static unsigned NumImplicitDestructors; + + /// \brief The number of implicitly-declared destructors for which + /// declarations were built. + static unsigned NumImplicitDestructorsDeclared; + +private: + ASTContext(const ASTContext &) = delete; + void operator=(const ASTContext &) = delete; + +public: + /// \brief Initialize built-in types. + /// + /// This routine may only be invoked once for a given ASTContext object. + /// It is normally invoked after ASTContext construction. + /// + /// \param Target The target + void InitBuiltinTypes(const TargetInfo &Target, + const TargetInfo *AuxTarget = nullptr); + +private: + void InitBuiltinType(CanQualType &R, BuiltinType::Kind K); + + // Return the Objective-C type encoding for a given type. + void getObjCEncodingForTypeImpl(QualType t, std::string &S, + bool ExpandPointedToStructures, + bool ExpandStructures, + const FieldDecl *Field, + bool OutermostType = false, + bool EncodingProperty = false, + bool StructField = false, + bool EncodeBlockParameters = false, + bool EncodeClassNames = false, + bool EncodePointerToObjCTypedef = false, + QualType *NotEncodedT=nullptr) const; + + // Adds the encoding of the structure's members. + void getObjCEncodingForStructureImpl(RecordDecl *RD, std::string &S, + const FieldDecl *Field, + bool includeVBases = true, + QualType *NotEncodedT=nullptr) const; +public: + // Adds the encoding of a method parameter or return type. + void getObjCEncodingForMethodParameter(Decl::ObjCDeclQualifier QT, + QualType T, std::string& S, + bool Extended) const; + + /// \brief Returns true if this is an inline-initialized static data member + /// which is treated as a definition for MSVC compatibility. + bool isMSStaticDataMemberInlineDefinition(const VarDecl *VD) const; + +private: + const ASTRecordLayout & + getObjCLayout(const ObjCInterfaceDecl *D, + const ObjCImplementationDecl *Impl) const; + + /// \brief A set of deallocations that should be performed when the + /// ASTContext is destroyed. + // FIXME: We really should have a better mechanism in the ASTContext to + // manage running destructors for types which do variable sized allocation + // within the AST. In some places we thread the AST bump pointer allocator + // into the datastructures which avoids this mess during deallocation but is + // wasteful of memory, and here we require a lot of error prone book keeping + // in order to track and run destructors while we're tearing things down. + typedef llvm::SmallVector<std::pair<void (*)(void *), void *>, 16> + DeallocationFunctionsAndArguments; + DeallocationFunctionsAndArguments Deallocations; + + // FIXME: This currently contains the set of StoredDeclMaps used + // by DeclContext objects. This probably should not be in ASTContext, + // but we include it here so that ASTContext can quickly deallocate them. + llvm::PointerIntPair<StoredDeclsMap*,1> LastSDM; + + friend class DeclContext; + friend class DeclarationNameTable; + void ReleaseDeclContextMaps(); + void ReleaseParentMapEntries(); + + std::unique_ptr<ParentMapPointers> PointerParents; + std::unique_ptr<ParentMapOtherNodes> OtherParents; + + std::unique_ptr<VTableContextBase> VTContext; + +public: + enum PragmaSectionFlag : unsigned { + PSF_None = 0, + PSF_Read = 0x1, + PSF_Write = 0x2, + PSF_Execute = 0x4, + PSF_Implicit = 0x8, + PSF_Invalid = 0x80000000U, + }; + + struct SectionInfo { + DeclaratorDecl *Decl; + SourceLocation PragmaSectionLocation; + int SectionFlags; + SectionInfo() {} + SectionInfo(DeclaratorDecl *Decl, + SourceLocation PragmaSectionLocation, + int SectionFlags) + : Decl(Decl), + PragmaSectionLocation(PragmaSectionLocation), + SectionFlags(SectionFlags) {} + }; + + llvm::StringMap<SectionInfo> SectionInfos; +}; + +/// \brief Utility function for constructing a nullary selector. +static inline Selector GetNullarySelector(StringRef 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(StringRef name, ASTContext& Ctx) { + IdentifierInfo* II = &Ctx.Idents.get(name); + return Ctx.Selectors.getSelector(1, &II); +} + +} // end namespace clang + +// operator new and delete aren't allowed inside namespaces. + +/// @brief Placement new for using the ASTContext's allocator. +/// +/// This placement form of operator new uses the ASTContext's allocator for +/// obtaining memory. +/// +/// IMPORTANT: These are also declared in clang/AST/AttrIterator.h! Any changes +/// here need to also be made there. +/// +/// We intentionally avoid using a nothrow specification here so that the calls +/// to this operator will not perform a null check on the result -- the +/// underlying allocator never returns null pointers. +/// +/// Usage looks like this (assuming there's an ASTContext 'Context' in scope): +/// @code +/// // Default alignment (8) +/// IntegerLiteral *Ex = new (Context) IntegerLiteral(arguments); +/// // Specific alignment +/// IntegerLiteral *Ex2 = new (Context, 4) IntegerLiteral(arguments); +/// @endcode +/// Memory allocated through this placement new operator does not need to be +/// explicitly freed, as ASTContext will free all of this memory when it gets +/// destroyed. Please note that you cannot use delete on the pointer. +/// +/// @param Bytes The number of bytes to allocate. Calculated by the compiler. +/// @param C The ASTContext that provides the allocator. +/// @param Alignment The alignment of the allocated memory (if the underlying +/// allocator supports it). +/// @return The allocated memory. Could be NULL. +inline void *operator new(size_t Bytes, const clang::ASTContext &C, + size_t Alignment) { + return C.Allocate(Bytes, Alignment); +} +/// @brief Placement delete companion to the new above. +/// +/// This operator is just a companion to the new above. There is no way of +/// invoking it directly; see the new operator for more details. This operator +/// is called implicitly by the compiler if a placement new expression using +/// the ASTContext throws in the object constructor. +inline void operator delete(void *Ptr, const clang::ASTContext &C, size_t) { + C.Deallocate(Ptr); +} + +/// This placement form of operator new[] uses the ASTContext's allocator for +/// obtaining memory. +/// +/// We intentionally avoid using a nothrow specification here so that the calls +/// to this operator will not perform a null check on the result -- the +/// underlying allocator never returns null pointers. +/// +/// Usage looks like this (assuming there's an ASTContext 'Context' in scope): +/// @code +/// // Default alignment (8) +/// char *data = new (Context) char[10]; +/// // Specific alignment +/// char *data = new (Context, 4) char[10]; +/// @endcode +/// Memory allocated through this placement new[] operator does not need to be +/// explicitly freed, as ASTContext will free all of this memory when it gets +/// destroyed. Please note that you cannot use delete on the pointer. +/// +/// @param Bytes The number of bytes to allocate. Calculated by the compiler. +/// @param C The ASTContext that provides the allocator. +/// @param Alignment The alignment of the allocated memory (if the underlying +/// allocator supports it). +/// @return The allocated memory. Could be NULL. +inline void *operator new[](size_t Bytes, const clang::ASTContext& C, + size_t Alignment = 8) { + return C.Allocate(Bytes, Alignment); +} + +/// @brief Placement delete[] companion to the new[] above. +/// +/// This operator is just a companion to the new[] above. There is no way of +/// invoking it directly; see the new[] operator for more details. This operator +/// is called implicitly by the compiler if a placement new[] expression using +/// the ASTContext throws in the object constructor. +inline void operator delete[](void *Ptr, const clang::ASTContext &C, size_t) { + C.Deallocate(Ptr); +} + +/// \brief Create the representation of a LazyGenerationalUpdatePtr. +template <typename Owner, typename T, + void (clang::ExternalASTSource::*Update)(Owner)> +typename clang::LazyGenerationalUpdatePtr<Owner, T, Update>::ValueType + clang::LazyGenerationalUpdatePtr<Owner, T, Update>::makeValue( + const clang::ASTContext &Ctx, T Value) { + // Note, this is implemented here so that ExternalASTSource.h doesn't need to + // include ASTContext.h. We explicitly instantiate it for all relevant types + // in ASTContext.cpp. + if (auto *Source = Ctx.getExternalSource()) + return new (Ctx) LazyData(Source, Value); + return Value; +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/ASTDiagnostic.h b/contrib/llvm/tools/clang/include/clang/AST/ASTDiagnostic.h new file mode 100644 index 0000000..27c85e6 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/ASTDiagnostic.h @@ -0,0 +1,47 @@ +//===--- ASTDiagnostic.h - Diagnostics for the AST library ------*- 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_AST_ASTDIAGNOSTIC_H +#define LLVM_CLANG_AST_ASTDIAGNOSTIC_H + +#include "clang/Basic/Diagnostic.h" + +namespace clang { + namespace diag { + enum { +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\ + SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM, +#define ASTSTART +#include "clang/Basic/DiagnosticASTKinds.inc" +#undef DIAG + NUM_BUILTIN_AST_DIAGNOSTICS + }; + } // end namespace diag + + /// \brief DiagnosticsEngine argument formatting function for diagnostics that + /// involve AST nodes. + /// + /// This function formats diagnostic arguments for various AST nodes, + /// including types, declaration names, nested name specifiers, and + /// declaration contexts, into strings that can be printed as part of + /// diagnostics. It is meant to be used as the argument to + /// \c DiagnosticsEngine::SetArgToStringFn(), where the cookie is an \c + /// ASTContext pointer. + void FormatASTNodeDiagnosticArgument( + DiagnosticsEngine::ArgumentKind Kind, + intptr_t Val, + StringRef Modifier, + StringRef Argument, + ArrayRef<DiagnosticsEngine::ArgumentValue> PrevArgs, + SmallVectorImpl<char> &Output, + void *Cookie, + ArrayRef<intptr_t> QualTypeVals); +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/ASTFwd.h b/contrib/llvm/tools/clang/include/clang/AST/ASTFwd.h new file mode 100644 index 0000000..003d489 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/ASTFwd.h @@ -0,0 +1,33 @@ +//===--- ASTFwd.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===--------------------------------------------------------------===// +/// +/// \file +/// \brief Forward declaration of all AST node types. +/// +//===-------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_ASTFWD_H +#define LLVM_CLANG_AST_ASTFWD_H + +namespace clang { + +class Decl; +#define DECL(DERIVED, BASE) class DERIVED##Decl; +#include "clang/AST/DeclNodes.inc" +class Stmt; +#define STMT(DERIVED, BASE) class DERIVED; +#include "clang/AST/StmtNodes.inc" +class Type; +#define TYPE(DERIVED, BASE) class DERIVED##Type; +#include "clang/AST/TypeNodes.def" +class CXXCtorInitializer; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/ASTImporter.h b/contrib/llvm/tools/clang/include/clang/AST/ASTImporter.h new file mode 100644 index 0000000..ee48955 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/ASTImporter.h @@ -0,0 +1,295 @@ +//===--- ASTImporter.h - Importing ASTs from other Contexts -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ASTImporter class which imports AST nodes from one +// context into another context. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_ASTIMPORTER_H +#define LLVM_CLANG_AST_ASTIMPORTER_H + +#include "clang/AST/DeclarationName.h" +#include "clang/AST/Type.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { + class ASTContext; + class Decl; + class DeclContext; + class DiagnosticsEngine; + class Expr; + class FileManager; + class IdentifierInfo; + class NestedNameSpecifier; + class Stmt; + class TypeSourceInfo; + + /// \brief Imports selected nodes from one AST context into another context, + /// merging AST nodes where appropriate. + class ASTImporter { + public: + typedef llvm::DenseSet<std::pair<Decl *, Decl *> > NonEquivalentDeclSet; + + private: + /// \brief The contexts we're importing to and from. + ASTContext &ToContext, &FromContext; + + /// \brief The file managers we're importing to and from. + FileManager &ToFileManager, &FromFileManager; + + /// \brief Whether to perform a minimal import. + bool Minimal; + + /// \brief Whether the last diagnostic came from the "from" context. + bool LastDiagFromFrom; + + /// \brief Mapping from the already-imported types in the "from" context + /// to the corresponding types in the "to" context. + llvm::DenseMap<const Type *, const Type *> ImportedTypes; + + /// \brief Mapping from the already-imported declarations in the "from" + /// context to the corresponding declarations in the "to" context. + llvm::DenseMap<Decl *, Decl *> ImportedDecls; + + /// \brief Mapping from the already-imported statements in the "from" + /// context to the corresponding statements in the "to" context. + llvm::DenseMap<Stmt *, Stmt *> ImportedStmts; + + /// \brief Mapping from the already-imported FileIDs in the "from" source + /// manager to the corresponding FileIDs in the "to" source manager. + llvm::DenseMap<FileID, FileID> ImportedFileIDs; + + /// \brief Imported, anonymous tag declarations that are missing their + /// corresponding typedefs. + SmallVector<TagDecl *, 4> AnonTagsWithPendingTypedefs; + + /// \brief Declaration (from, to) pairs that are known not to be equivalent + /// (which we have already complained about). + NonEquivalentDeclSet NonEquivalentDecls; + + public: + /// \brief Create a new AST importer. + /// + /// \param ToContext The context we'll be importing into. + /// + /// \param ToFileManager The file manager we'll be importing into. + /// + /// \param FromContext The context we'll be importing from. + /// + /// \param FromFileManager The file manager we'll be importing into. + /// + /// \param MinimalImport If true, the importer will attempt to import + /// as little as it can, e.g., by importing declarations as forward + /// declarations that can be completed at a later point. + ASTImporter(ASTContext &ToContext, FileManager &ToFileManager, + ASTContext &FromContext, FileManager &FromFileManager, + bool MinimalImport); + + virtual ~ASTImporter(); + + /// \brief Whether the importer will perform a minimal import, creating + /// to-be-completed forward declarations when possible. + bool isMinimalImport() const { return Minimal; } + + /// \brief Import the given type from the "from" context into the "to" + /// context. + /// + /// \returns the equivalent type in the "to" context, or a NULL type if + /// an error occurred. + QualType Import(QualType FromT); + + /// \brief Import the given type source information from the + /// "from" context into the "to" context. + /// + /// \returns the equivalent type source information in the "to" + /// context, or NULL if an error occurred. + TypeSourceInfo *Import(TypeSourceInfo *FromTSI); + + /// \brief Import the given declaration from the "from" context into the + /// "to" context. + /// + /// \returns the equivalent declaration in the "to" context, or a NULL type + /// if an error occurred. + Decl *Import(Decl *FromD); + + /// \brief Return the copy of the given declaration in the "to" context if + /// it has already been imported from the "from" context. Otherwise return + /// NULL. + Decl *GetAlreadyImportedOrNull(Decl *FromD); + + /// \brief Import the given declaration context from the "from" + /// AST context into the "to" AST context. + /// + /// \returns the equivalent declaration context in the "to" + /// context, or a NULL type if an error occurred. + DeclContext *ImportContext(DeclContext *FromDC); + + /// \brief Import the given expression from the "from" context into the + /// "to" context. + /// + /// \returns the equivalent expression in the "to" context, or NULL if + /// an error occurred. + Expr *Import(Expr *FromE); + + /// \brief Import the given statement from the "from" context into the + /// "to" context. + /// + /// \returns the equivalent statement in the "to" context, or NULL if + /// an error occurred. + Stmt *Import(Stmt *FromS); + + /// \brief Import the given nested-name-specifier from the "from" + /// context into the "to" context. + /// + /// \returns the equivalent nested-name-specifier in the "to" + /// context, or NULL if an error occurred. + NestedNameSpecifier *Import(NestedNameSpecifier *FromNNS); + + /// \brief Import the given nested-name-specifier from the "from" + /// context into the "to" context. + /// + /// \returns the equivalent nested-name-specifier in the "to" + /// context. + NestedNameSpecifierLoc Import(NestedNameSpecifierLoc FromNNS); + + /// \brief Import the goven template name from the "from" context into the + /// "to" context. + TemplateName Import(TemplateName From); + + /// \brief Import the given source location from the "from" context into + /// the "to" context. + /// + /// \returns the equivalent source location in the "to" context, or an + /// invalid source location if an error occurred. + SourceLocation Import(SourceLocation FromLoc); + + /// \brief Import the given source range from the "from" context into + /// the "to" context. + /// + /// \returns the equivalent source range in the "to" context, or an + /// invalid source location if an error occurred. + SourceRange Import(SourceRange FromRange); + + /// \brief Import the given declaration name from the "from" + /// context into the "to" context. + /// + /// \returns the equivalent declaration name in the "to" context, + /// or an empty declaration name if an error occurred. + DeclarationName Import(DeclarationName FromName); + + /// \brief Import the given identifier from the "from" context + /// into the "to" context. + /// + /// \returns the equivalent identifier in the "to" context. + IdentifierInfo *Import(const IdentifierInfo *FromId); + + /// \brief Import the given Objective-C selector from the "from" + /// context into the "to" context. + /// + /// \returns the equivalent selector in the "to" context. + Selector Import(Selector FromSel); + + /// \brief Import the given file ID from the "from" context into the + /// "to" context. + /// + /// \returns the equivalent file ID in the source manager of the "to" + /// context. + FileID Import(FileID); + + /// \brief Import the definition of the given declaration, including all of + /// the declarations it contains. + /// + /// This routine is intended to be used + void ImportDefinition(Decl *From); + + /// \brief Cope with a name conflict when importing a declaration into the + /// given context. + /// + /// This routine is invoked whenever there is a name conflict while + /// importing a declaration. The returned name will become the name of the + /// imported declaration. By default, the returned name is the same as the + /// original name, leaving the conflict unresolve such that name lookup + /// for this name is likely to find an ambiguity later. + /// + /// Subclasses may override this routine to resolve the conflict, e.g., by + /// renaming the declaration being imported. + /// + /// \param Name the name of the declaration being imported, which conflicts + /// with other declarations. + /// + /// \param DC the declaration context (in the "to" AST context) in which + /// the name is being imported. + /// + /// \param IDNS the identifier namespace in which the name will be found. + /// + /// \param Decls the set of declarations with the same name as the + /// declaration being imported. + /// + /// \param NumDecls the number of conflicting declarations in \p Decls. + /// + /// \returns the name that the newly-imported declaration should have. + virtual DeclarationName HandleNameConflict(DeclarationName Name, + DeclContext *DC, + unsigned IDNS, + NamedDecl **Decls, + unsigned NumDecls); + + /// \brief Retrieve the context that AST nodes are being imported into. + ASTContext &getToContext() const { return ToContext; } + + /// \brief Retrieve the context that AST nodes are being imported from. + ASTContext &getFromContext() const { return FromContext; } + + /// \brief Retrieve the file manager that AST nodes are being imported into. + FileManager &getToFileManager() const { return ToFileManager; } + + /// \brief Retrieve the file manager that AST nodes are being imported from. + FileManager &getFromFileManager() const { return FromFileManager; } + + /// \brief Report a diagnostic in the "to" context. + DiagnosticBuilder ToDiag(SourceLocation Loc, unsigned DiagID); + + /// \brief Report a diagnostic in the "from" context. + DiagnosticBuilder FromDiag(SourceLocation Loc, unsigned DiagID); + + /// \brief Return the set of declarations that we know are not equivalent. + NonEquivalentDeclSet &getNonEquivalentDecls() { return NonEquivalentDecls; } + + /// \brief Called for ObjCInterfaceDecl, ObjCProtocolDecl, and TagDecl. + /// Mark the Decl as complete, filling it in as much as possible. + /// + /// \param D A declaration in the "to" context. + virtual void CompleteDecl(Decl* D); + + /// \brief Note that we have imported the "from" declaration by mapping it + /// to the (potentially-newly-created) "to" declaration. + /// + /// Subclasses can override this function to observe all of the \c From -> + /// \c To declaration mappings as they are imported. + virtual Decl *Imported(Decl *From, Decl *To); + + /// \brief Called by StructuralEquivalenceContext. If a RecordDecl is + /// being compared to another RecordDecl as part of import, completing the + /// other RecordDecl may trigger importation of the first RecordDecl. This + /// happens especially for anonymous structs. If the original of the second + /// RecordDecl can be found, we can complete it without the need for + /// importation, eliminating this loop. + virtual Decl *GetOriginalDecl(Decl *To) { return nullptr; } + + /// \brief Determine whether the given types are structurally + /// equivalent. + bool IsStructurallyEquivalent(QualType From, QualType To, + bool Complain = true); + }; +} + +#endif // LLVM_CLANG_AST_ASTIMPORTER_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/ASTLambda.h b/contrib/llvm/tools/clang/include/clang/AST/ASTLambda.h new file mode 100644 index 0000000..69df2d8 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/ASTLambda.h @@ -0,0 +1,80 @@ +//===--- ASTLambda.h - Lambda Helper Functions --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file provides some common utility functions for processing +/// Lambda related AST Constructs. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_ASTLAMBDA_H +#define LLVM_CLANG_AST_ASTLAMBDA_H + +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" + +namespace clang { +inline StringRef getLambdaStaticInvokerName() { + return "__invoke"; +} +// This function returns true if M is a specialization, a template, +// or a non-generic lambda call operator. +inline bool isLambdaCallOperator(const CXXMethodDecl *MD) { + const CXXRecordDecl *LambdaClass = MD->getParent(); + if (!LambdaClass || !LambdaClass->isLambda()) return false; + return MD->getOverloadedOperator() == OO_Call; +} + +inline bool isLambdaCallOperator(const DeclContext *DC) { + if (!DC || !isa<CXXMethodDecl>(DC)) return false; + return isLambdaCallOperator(cast<CXXMethodDecl>(DC)); +} + +inline bool isGenericLambdaCallOperatorSpecialization(const CXXMethodDecl *MD) { + if (!MD) return false; + const CXXRecordDecl *LambdaClass = MD->getParent(); + if (LambdaClass && LambdaClass->isGenericLambda()) + return isLambdaCallOperator(MD) && + MD->isFunctionTemplateSpecialization(); + return false; +} + +inline bool isLambdaConversionOperator(CXXConversionDecl *C) { + return C ? C->getParent()->isLambda() : false; +} + +inline bool isLambdaConversionOperator(Decl *D) { + if (!D) return false; + if (CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(D)) + return isLambdaConversionOperator(Conv); + if (FunctionTemplateDecl *F = dyn_cast<FunctionTemplateDecl>(D)) + if (CXXConversionDecl *Conv = + dyn_cast_or_null<CXXConversionDecl>(F->getTemplatedDecl())) + return isLambdaConversionOperator(Conv); + return false; +} + +inline bool isGenericLambdaCallOperatorSpecialization(DeclContext *DC) { + return isGenericLambdaCallOperatorSpecialization( + dyn_cast<CXXMethodDecl>(DC)); +} + + +// This returns the parent DeclContext ensuring that the correct +// parent DeclContext is returned for Lambdas +inline DeclContext *getLambdaAwareParentOfDeclContext(DeclContext *DC) { + if (isLambdaCallOperator(DC)) + return DC->getParent()->getParent(); + else + return DC->getParent(); +} + +} // clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/ASTMutationListener.h b/contrib/llvm/tools/clang/include/clang/AST/ASTMutationListener.h new file mode 100644 index 0000000..3ff392d --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/ASTMutationListener.h @@ -0,0 +1,127 @@ +//===--- ASTMutationListener.h - AST Mutation Interface --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ASTMutationListener interface. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_ASTMUTATIONLISTENER_H +#define LLVM_CLANG_AST_ASTMUTATIONLISTENER_H + +namespace clang { + class Attr; + class ClassTemplateDecl; + class ClassTemplateSpecializationDecl; + class CXXDestructorDecl; + class CXXRecordDecl; + class Decl; + class DeclContext; + class FunctionDecl; + class FunctionTemplateDecl; + class Module; + class NamedDecl; + class ObjCCategoryDecl; + class ObjCContainerDecl; + class ObjCInterfaceDecl; + class ObjCPropertyDecl; + class QualType; + class RecordDecl; + class TagDecl; + class VarDecl; + class VarTemplateDecl; + class VarTemplateSpecializationDecl; + +/// \brief An abstract interface that should be implemented by listeners +/// that want to be notified when an AST entity gets modified after its +/// initial creation. +class ASTMutationListener { +public: + virtual ~ASTMutationListener(); + + /// \brief A new TagDecl definition was completed. + virtual void CompletedTagDefinition(const TagDecl *D) { } + + /// \brief A new declaration with name has been added to a DeclContext. + virtual void AddedVisibleDecl(const DeclContext *DC, const Decl *D) {} + + /// \brief An implicit member was added after the definition was completed. + virtual void AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D) {} + + /// \brief A template specialization (or partial one) was added to the + /// template declaration. + virtual void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD, + const ClassTemplateSpecializationDecl *D) {} + + /// \brief A template specialization (or partial one) was added to the + /// template declaration. + virtual void + AddedCXXTemplateSpecialization(const VarTemplateDecl *TD, + const VarTemplateSpecializationDecl *D) {} + + /// \brief A template specialization (or partial one) was added to the + /// template declaration. + virtual void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, + const FunctionDecl *D) {} + + /// \brief A function's exception specification has been evaluated or + /// instantiated. + virtual void ResolvedExceptionSpec(const FunctionDecl *FD) {} + + /// \brief A function's return type has been deduced. + virtual void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType); + + /// \brief A virtual destructor's operator delete has been resolved. + virtual void ResolvedOperatorDelete(const CXXDestructorDecl *DD, + const FunctionDecl *Delete) {} + + /// \brief An implicit member got a definition. + virtual void CompletedImplicitDefinition(const FunctionDecl *D) {} + + /// \brief A static data member was implicitly instantiated. + virtual void StaticDataMemberInstantiated(const VarDecl *D) {} + + /// \brief A function template's definition was instantiated. + virtual void FunctionDefinitionInstantiated(const FunctionDecl *D) {} + + /// \brief A new objc category class was added for an interface. + virtual void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD, + const ObjCInterfaceDecl *IFD) {} + + /// \brief A declaration is marked used which was not previously marked used. + /// + /// \param D the declaration marked used + virtual void DeclarationMarkedUsed(const Decl *D) {} + + /// \brief A declaration is marked as OpenMP threadprivate which was not + /// previously marked as threadprivate. + /// + /// \param D the declaration marked OpenMP threadprivate. + virtual void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) {} + + /// \brief A definition has been made visible by being redefined locally. + /// + /// \param D The definition that was previously not visible. + /// \param M The containing module in which the definition was made visible, + /// if any. + virtual void RedefinedHiddenDefinition(const NamedDecl *D, Module *M) {} + + /// \brief An attribute was added to a RecordDecl + /// + /// \param Attr The attribute that was added to the Record + /// + /// \param Record The RecordDecl that got a new attribute + virtual void AddedAttributeToRecord(const Attr *Attr, + const RecordDecl *Record) {} + + // NOTE: If new methods are added they should also be added to + // MultiplexASTMutationListener. +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/ASTTypeTraits.h b/contrib/llvm/tools/clang/include/clang/AST/ASTTypeTraits.h new file mode 100644 index 0000000..dcaac80 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/ASTTypeTraits.h @@ -0,0 +1,509 @@ +//===--- ASTTypeTraits.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Provides a dynamic type identifier and a dynamically typed node container +// that can be used to store an AST base node at runtime in the same storage in +// a type safe way. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_ASTTYPETRAITS_H +#define LLVM_CLANG_AST_ASTTYPETRAITS_H + +#include "clang/AST/ASTFwd.h" +#include "clang/AST/Decl.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/TypeLoc.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/Support/AlignOf.h" + +namespace llvm { + +class raw_ostream; + +} + +namespace clang { + +struct PrintingPolicy; + +namespace ast_type_traits { + +/// \brief Kind identifier. +/// +/// It can be constructed from any node kind and allows for runtime type +/// hierarchy checks. +/// Use getFromNodeKind<T>() to construct them. +class ASTNodeKind { +public: + /// \brief Empty identifier. It matches nothing. + ASTNodeKind() : KindId(NKI_None) {} + + /// \brief Construct an identifier for T. + template <class T> + static ASTNodeKind getFromNodeKind() { + return ASTNodeKind(KindToKindId<T>::Id); + } + + /// \{ + /// \brief Construct an identifier for the dynamic type of the node + static ASTNodeKind getFromNode(const Decl &D); + static ASTNodeKind getFromNode(const Stmt &S); + static ASTNodeKind getFromNode(const Type &T); + /// \} + + /// \brief Returns \c true if \c this and \c Other represent the same kind. + bool isSame(ASTNodeKind Other) const; + + /// \brief Returns \c true only for the default \c ASTNodeKind() + bool isNone() const { return KindId == NKI_None; } + + /// \brief Returns \c true if \c this is a base kind of (or same as) \c Other. + /// \param Distance If non-null, used to return the distance between \c this + /// and \c Other in the class hierarchy. + bool isBaseOf(ASTNodeKind Other, unsigned *Distance = nullptr) const; + + /// \brief String representation of the kind. + StringRef asStringRef() const; + + /// \brief Strict weak ordering for ASTNodeKind. + bool operator<(const ASTNodeKind &Other) const { + return KindId < Other.KindId; + } + + /// \brief Return the most derived type between \p Kind1 and \p Kind2. + /// + /// Return ASTNodeKind() if they are not related. + static ASTNodeKind getMostDerivedType(ASTNodeKind Kind1, ASTNodeKind Kind2); + + /// \brief Return the most derived common ancestor between Kind1 and Kind2. + /// + /// Return ASTNodeKind() if they are not related. + static ASTNodeKind getMostDerivedCommonAncestor(ASTNodeKind Kind1, + ASTNodeKind Kind2); + + /// \brief Hooks for using ASTNodeKind as a key in a DenseMap. + struct DenseMapInfo { + // ASTNodeKind() is a good empty key because it is represented as a 0. + static inline ASTNodeKind getEmptyKey() { return ASTNodeKind(); } + // NKI_NumberOfKinds is not a valid value, so it is good for a + // tombstone key. + static inline ASTNodeKind getTombstoneKey() { + return ASTNodeKind(NKI_NumberOfKinds); + } + static unsigned getHashValue(const ASTNodeKind &Val) { return Val.KindId; } + static bool isEqual(const ASTNodeKind &LHS, const ASTNodeKind &RHS) { + return LHS.KindId == RHS.KindId; + } + }; + + /// Check if the given ASTNodeKind identifies a type that offers pointer + /// identity. This is useful for the fast path in DynTypedNode. + bool hasPointerIdentity() const { + return KindId > NKI_LastKindWithoutPointerIdentity; + } + +private: + /// \brief Kind ids. + /// + /// Includes all possible base and derived kinds. + enum NodeKindId { + NKI_None, + NKI_TemplateArgument, + NKI_NestedNameSpecifierLoc, + NKI_QualType, + NKI_TypeLoc, + NKI_LastKindWithoutPointerIdentity = NKI_TypeLoc, + NKI_CXXCtorInitializer, + NKI_NestedNameSpecifier, + NKI_Decl, +#define DECL(DERIVED, BASE) NKI_##DERIVED##Decl, +#include "clang/AST/DeclNodes.inc" + NKI_Stmt, +#define STMT(DERIVED, BASE) NKI_##DERIVED, +#include "clang/AST/StmtNodes.inc" + NKI_Type, +#define TYPE(DERIVED, BASE) NKI_##DERIVED##Type, +#include "clang/AST/TypeNodes.def" + NKI_NumberOfKinds + }; + + /// \brief Use getFromNodeKind<T>() to construct the kind. + ASTNodeKind(NodeKindId KindId) : KindId(KindId) {} + + /// \brief Returns \c true if \c Base is a base kind of (or same as) \c + /// Derived. + /// \param Distance If non-null, used to return the distance between \c Base + /// and \c Derived in the class hierarchy. + static bool isBaseOf(NodeKindId Base, NodeKindId Derived, unsigned *Distance); + + /// \brief Helper meta-function to convert a kind T to its enum value. + /// + /// This struct is specialized below for all known kinds. + template <class T> struct KindToKindId { + static const NodeKindId Id = NKI_None; + }; + template <class T> + struct KindToKindId<const T> : KindToKindId<T> {}; + + /// \brief Per kind info. + struct KindInfo { + /// \brief The id of the parent kind, or None if it has no parent. + NodeKindId ParentId; + /// \brief Name of the kind. + const char *Name; + }; + static const KindInfo AllKindInfo[NKI_NumberOfKinds]; + + NodeKindId KindId; +}; + +#define KIND_TO_KIND_ID(Class) \ + template <> struct ASTNodeKind::KindToKindId<Class> { \ + static const NodeKindId Id = NKI_##Class; \ + }; +KIND_TO_KIND_ID(CXXCtorInitializer) +KIND_TO_KIND_ID(TemplateArgument) +KIND_TO_KIND_ID(NestedNameSpecifier) +KIND_TO_KIND_ID(NestedNameSpecifierLoc) +KIND_TO_KIND_ID(QualType) +KIND_TO_KIND_ID(TypeLoc) +KIND_TO_KIND_ID(Decl) +KIND_TO_KIND_ID(Stmt) +KIND_TO_KIND_ID(Type) +#define DECL(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Decl) +#include "clang/AST/DeclNodes.inc" +#define STMT(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED) +#include "clang/AST/StmtNodes.inc" +#define TYPE(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Type) +#include "clang/AST/TypeNodes.def" +#undef KIND_TO_KIND_ID + +inline raw_ostream &operator<<(raw_ostream &OS, ASTNodeKind K) { + OS << K.asStringRef(); + return OS; +} + +/// \brief A dynamically typed AST node container. +/// +/// Stores an AST node in a type safe way. This allows writing code that +/// works with different kinds of AST nodes, despite the fact that they don't +/// have a common base class. +/// +/// Use \c create(Node) to create a \c DynTypedNode from an AST node, +/// and \c get<T>() to retrieve the node as type T if the types match. +/// +/// See \c ASTNodeKind for which node base types are currently supported; +/// You can create DynTypedNodes for all nodes in the inheritance hierarchy of +/// the supported base types. +class DynTypedNode { +public: + /// \brief Creates a \c DynTypedNode from \c Node. + template <typename T> + static DynTypedNode create(const T &Node) { + return BaseConverter<T>::create(Node); + } + + /// \brief Retrieve the stored node as type \c T. + /// + /// Returns NULL if the stored node does not have a type that is + /// convertible to \c T. + /// + /// For types that have identity via their pointer in the AST + /// (like \c Stmt, \c Decl, \c Type and \c NestedNameSpecifier) the returned + /// pointer points to the referenced AST node. + /// For other types (like \c QualType) the value is stored directly + /// in the \c DynTypedNode, and the returned pointer points at + /// the storage inside DynTypedNode. For those nodes, do not + /// use the pointer outside the scope of the DynTypedNode. + template <typename T> + const T *get() const { + return BaseConverter<T>::get(NodeKind, Storage.buffer); + } + + /// \brief Retrieve the stored node as type \c T. + /// + /// Similar to \c get(), but asserts that the type is what we are expecting. + template <typename T> + const T &getUnchecked() const { + return BaseConverter<T>::getUnchecked(NodeKind, Storage.buffer); + } + + ASTNodeKind getNodeKind() const { return NodeKind; } + + /// \brief Returns a pointer that identifies the stored AST node. + /// + /// Note that this is not supported by all AST nodes. For AST nodes + /// that don't have a pointer-defined identity inside the AST, this + /// method returns NULL. + const void *getMemoizationData() const { + return NodeKind.hasPointerIdentity() + ? *reinterpret_cast<void *const *>(Storage.buffer) + : nullptr; + } + + /// \brief Prints the node to the given output stream. + void print(llvm::raw_ostream &OS, const PrintingPolicy &PP) const; + + /// \brief Dumps the node to the given output stream. + void dump(llvm::raw_ostream &OS, SourceManager &SM) const; + + /// \brief For nodes which represent textual entities in the source code, + /// return their SourceRange. For all other nodes, return SourceRange(). + SourceRange getSourceRange() const; + + /// @{ + /// \brief Imposes an order on \c DynTypedNode. + /// + /// Supports comparison of nodes that support memoization. + /// FIXME: Implement comparsion for other node types (currently + /// only Stmt, Decl, Type and NestedNameSpecifier return memoization data). + bool operator<(const DynTypedNode &Other) const { + if (!NodeKind.isSame(Other.NodeKind)) + return NodeKind < Other.NodeKind; + + if (ASTNodeKind::getFromNodeKind<QualType>().isSame(NodeKind)) + return getUnchecked<QualType>().getAsOpaquePtr() < + Other.getUnchecked<QualType>().getAsOpaquePtr(); + + if (ASTNodeKind::getFromNodeKind<TypeLoc>().isSame(NodeKind)) { + auto TLA = getUnchecked<TypeLoc>(); + auto TLB = Other.getUnchecked<TypeLoc>(); + return std::make_pair(TLA.getType().getAsOpaquePtr(), + TLA.getOpaqueData()) < + std::make_pair(TLB.getType().getAsOpaquePtr(), + TLB.getOpaqueData()); + } + + if (ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>().isSame( + NodeKind)) { + auto NNSLA = getUnchecked<NestedNameSpecifierLoc>(); + auto NNSLB = Other.getUnchecked<NestedNameSpecifierLoc>(); + return std::make_pair(NNSLA.getNestedNameSpecifier(), + NNSLA.getOpaqueData()) < + std::make_pair(NNSLB.getNestedNameSpecifier(), + NNSLB.getOpaqueData()); + } + + assert(getMemoizationData() && Other.getMemoizationData()); + return getMemoizationData() < Other.getMemoizationData(); + } + bool operator==(const DynTypedNode &Other) const { + // DynTypedNode::create() stores the exact kind of the node in NodeKind. + // If they contain the same node, their NodeKind must be the same. + if (!NodeKind.isSame(Other.NodeKind)) + return false; + + // FIXME: Implement for other types. + if (ASTNodeKind::getFromNodeKind<QualType>().isSame(NodeKind)) + return getUnchecked<QualType>() == Other.getUnchecked<QualType>(); + + if (ASTNodeKind::getFromNodeKind<TypeLoc>().isSame(NodeKind)) + return getUnchecked<TypeLoc>() == Other.getUnchecked<TypeLoc>(); + + if (ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>().isSame(NodeKind)) + return getUnchecked<NestedNameSpecifierLoc>() == + Other.getUnchecked<NestedNameSpecifierLoc>(); + + assert(getMemoizationData() && Other.getMemoizationData()); + return getMemoizationData() == Other.getMemoizationData(); + } + bool operator!=(const DynTypedNode &Other) const { + return !operator==(Other); + } + /// @} + + /// \brief Hooks for using DynTypedNode as a key in a DenseMap. + struct DenseMapInfo { + static inline DynTypedNode getEmptyKey() { + DynTypedNode Node; + Node.NodeKind = ASTNodeKind::DenseMapInfo::getEmptyKey(); + return Node; + } + static inline DynTypedNode getTombstoneKey() { + DynTypedNode Node; + Node.NodeKind = ASTNodeKind::DenseMapInfo::getTombstoneKey(); + return Node; + } + static unsigned getHashValue(const DynTypedNode &Val) { + // FIXME: Add hashing support for the remaining types. + if (ASTNodeKind::getFromNodeKind<TypeLoc>().isSame(Val.NodeKind)) { + auto TL = Val.getUnchecked<TypeLoc>(); + return llvm::hash_combine(TL.getType().getAsOpaquePtr(), + TL.getOpaqueData()); + } + + if (ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>().isSame( + Val.NodeKind)) { + auto NNSL = Val.getUnchecked<NestedNameSpecifierLoc>(); + return llvm::hash_combine(NNSL.getNestedNameSpecifier(), + NNSL.getOpaqueData()); + } + + assert(Val.getMemoizationData()); + return llvm::hash_value(Val.getMemoizationData()); + } + static bool isEqual(const DynTypedNode &LHS, const DynTypedNode &RHS) { + auto Empty = ASTNodeKind::DenseMapInfo::getEmptyKey(); + auto TombStone = ASTNodeKind::DenseMapInfo::getTombstoneKey(); + return (ASTNodeKind::DenseMapInfo::isEqual(LHS.NodeKind, Empty) && + ASTNodeKind::DenseMapInfo::isEqual(RHS.NodeKind, Empty)) || + (ASTNodeKind::DenseMapInfo::isEqual(LHS.NodeKind, TombStone) && + ASTNodeKind::DenseMapInfo::isEqual(RHS.NodeKind, TombStone)) || + LHS == RHS; + } + }; + +private: + /// \brief Takes care of converting from and to \c T. + template <typename T, typename EnablerT = void> struct BaseConverter; + + /// \brief Converter that uses dyn_cast<T> from a stored BaseT*. + template <typename T, typename BaseT> struct DynCastPtrConverter { + static const T *get(ASTNodeKind NodeKind, const char Storage[]) { + if (ASTNodeKind::getFromNodeKind<T>().isBaseOf(NodeKind)) + return &getUnchecked(NodeKind, Storage); + return nullptr; + } + static const T &getUnchecked(ASTNodeKind NodeKind, const char Storage[]) { + assert(ASTNodeKind::getFromNodeKind<T>().isBaseOf(NodeKind)); + return *cast<T>(static_cast<const BaseT *>( + *reinterpret_cast<const void *const *>(Storage))); + } + static DynTypedNode create(const BaseT &Node) { + DynTypedNode Result; + Result.NodeKind = ASTNodeKind::getFromNode(Node); + new (Result.Storage.buffer) const void *(&Node); + return Result; + } + }; + + /// \brief Converter that stores T* (by pointer). + template <typename T> struct PtrConverter { + static const T *get(ASTNodeKind NodeKind, const char Storage[]) { + if (ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind)) + return &getUnchecked(NodeKind, Storage); + return nullptr; + } + static const T &getUnchecked(ASTNodeKind NodeKind, const char Storage[]) { + assert(ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind)); + return *static_cast<const T *>( + *reinterpret_cast<const void *const *>(Storage)); + } + static DynTypedNode create(const T &Node) { + DynTypedNode Result; + Result.NodeKind = ASTNodeKind::getFromNodeKind<T>(); + new (Result.Storage.buffer) const void *(&Node); + return Result; + } + }; + + /// \brief Converter that stores T (by value). + template <typename T> struct ValueConverter { + static const T *get(ASTNodeKind NodeKind, const char Storage[]) { + if (ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind)) + return reinterpret_cast<const T *>(Storage); + return nullptr; + } + static const T &getUnchecked(ASTNodeKind NodeKind, const char Storage[]) { + assert(ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind)); + return *reinterpret_cast<const T *>(Storage); + } + static DynTypedNode create(const T &Node) { + DynTypedNode Result; + Result.NodeKind = ASTNodeKind::getFromNodeKind<T>(); + new (Result.Storage.buffer) T(Node); + return Result; + } + }; + + ASTNodeKind NodeKind; + + /// \brief Stores the data of the node. + /// + /// Note that we can store \c Decls, \c Stmts, \c Types, + /// \c NestedNameSpecifiers and \c CXXCtorInitializer by pointer as they are + /// guaranteed to be unique pointers pointing to dedicated storage in the AST. + /// \c QualTypes, \c NestedNameSpecifierLocs, \c TypeLocs and + /// \c TemplateArguments on the other hand do not have storage or unique + /// pointers and thus need to be stored by value. + llvm::AlignedCharArrayUnion<const void *, TemplateArgument, + NestedNameSpecifierLoc, QualType, + TypeLoc> Storage; +}; + +template <typename T> +struct DynTypedNode::BaseConverter< + T, typename std::enable_if<std::is_base_of<Decl, T>::value>::type> + : public DynCastPtrConverter<T, Decl> {}; + +template <typename T> +struct DynTypedNode::BaseConverter< + T, typename std::enable_if<std::is_base_of<Stmt, T>::value>::type> + : public DynCastPtrConverter<T, Stmt> {}; + +template <typename T> +struct DynTypedNode::BaseConverter< + T, typename std::enable_if<std::is_base_of<Type, T>::value>::type> + : public DynCastPtrConverter<T, Type> {}; + +template <> +struct DynTypedNode::BaseConverter< + NestedNameSpecifier, void> : public PtrConverter<NestedNameSpecifier> {}; + +template <> +struct DynTypedNode::BaseConverter< + CXXCtorInitializer, void> : public PtrConverter<CXXCtorInitializer> {}; + +template <> +struct DynTypedNode::BaseConverter< + TemplateArgument, void> : public ValueConverter<TemplateArgument> {}; + +template <> +struct DynTypedNode::BaseConverter< + NestedNameSpecifierLoc, + void> : public ValueConverter<NestedNameSpecifierLoc> {}; + +template <> +struct DynTypedNode::BaseConverter<QualType, + void> : public ValueConverter<QualType> {}; + +template <> +struct DynTypedNode::BaseConverter< + TypeLoc, void> : public ValueConverter<TypeLoc> {}; + +// The only operation we allow on unsupported types is \c get. +// This allows to conveniently use \c DynTypedNode when having an arbitrary +// AST node that is not supported, but prevents misuse - a user cannot create +// a DynTypedNode from arbitrary types. +template <typename T, typename EnablerT> struct DynTypedNode::BaseConverter { + static const T *get(ASTNodeKind NodeKind, const char Storage[]) { + return NULL; + } +}; + +} // end namespace ast_type_traits +} // end namespace clang + +namespace llvm { + +template <> +struct DenseMapInfo<clang::ast_type_traits::ASTNodeKind> + : clang::ast_type_traits::ASTNodeKind::DenseMapInfo {}; + +template <> +struct DenseMapInfo<clang::ast_type_traits::DynTypedNode> + : clang::ast_type_traits::DynTypedNode::DenseMapInfo {}; + +} // end namespace llvm + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/ASTUnresolvedSet.h b/contrib/llvm/tools/clang/include/clang/AST/ASTUnresolvedSet.h new file mode 100644 index 0000000..9078a0e --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/ASTUnresolvedSet.h @@ -0,0 +1,110 @@ +//===-- ASTUnresolvedSet.h - Unresolved sets of declarations ---*- 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 an UnresolvedSet-like class, whose contents are +// allocated using the allocator associated with an ASTContext. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_ASTUNRESOLVEDSET_H +#define LLVM_CLANG_AST_ASTUNRESOLVEDSET_H + +#include "clang/AST/ASTVector.h" +#include "clang/AST/UnresolvedSet.h" + +namespace clang { + +/// \brief An UnresolvedSet-like class which uses the ASTContext's allocator. +class ASTUnresolvedSet { + struct DeclsTy : ASTVector<DeclAccessPair> { + DeclsTy() {} + DeclsTy(ASTContext &C, unsigned N) : ASTVector<DeclAccessPair>(C, N) {} + + bool isLazy() const { return getTag(); } + void setLazy(bool Lazy) { setTag(Lazy); } + }; + + DeclsTy Decls; + + friend class LazyASTUnresolvedSet; + +public: + ASTUnresolvedSet() {} + ASTUnresolvedSet(ASTContext &C, unsigned N) : Decls(C, N) {} + + typedef UnresolvedSetIterator iterator; + typedef UnresolvedSetIterator const_iterator; + + iterator begin() { return iterator(Decls.begin()); } + iterator end() { return iterator(Decls.end()); } + + const_iterator begin() const { return const_iterator(Decls.begin()); } + const_iterator end() const { return const_iterator(Decls.end()); } + + void addDecl(ASTContext &C, NamedDecl *D, AccessSpecifier AS) { + Decls.push_back(DeclAccessPair::make(D, AS), C); + } + + /// Replaces the given declaration with the new one, once. + /// + /// \return true if the set changed + bool replace(const NamedDecl *Old, NamedDecl *New, AccessSpecifier AS) { + for (DeclsTy::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) { + if (I->getDecl() == Old) { + I->set(New, AS); + return true; + } + } + return false; + } + + void erase(unsigned I) { Decls[I] = Decls.pop_back_val(); } + + void clear() { Decls.clear(); } + + bool empty() const { return Decls.empty(); } + unsigned size() const { return Decls.size(); } + + void reserve(ASTContext &C, unsigned N) { + Decls.reserve(C, N); + } + + void append(ASTContext &C, iterator I, iterator E) { + Decls.append(C, I.I, E.I); + } + + DeclAccessPair &operator[](unsigned I) { return Decls[I]; } + const DeclAccessPair &operator[](unsigned I) const { return Decls[I]; } +}; + +/// \brief An UnresolvedSet-like class that might not have been loaded from the +/// external AST source yet. +class LazyASTUnresolvedSet { + mutable ASTUnresolvedSet Impl; + + void getFromExternalSource(ASTContext &C) const; + +public: + ASTUnresolvedSet &get(ASTContext &C) const { + if (Impl.Decls.isLazy()) + getFromExternalSource(C); + return Impl; + } + + void reserve(ASTContext &C, unsigned N) { Impl.reserve(C, N); } + void addLazyDecl(ASTContext &C, uintptr_t ID, AccessSpecifier AS) { + assert(Impl.empty() || Impl.Decls.isLazy()); + Impl.Decls.setLazy(true); + Impl.addDecl(C, reinterpret_cast<NamedDecl*>(ID << 2), AS); + } +}; + +} // namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/ASTVector.h b/contrib/llvm/tools/clang/include/clang/AST/ASTVector.h new file mode 100644 index 0000000..79453bf --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/ASTVector.h @@ -0,0 +1,405 @@ +//===- ASTVector.h - Vector that uses ASTContext for allocation --*- 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 ASTVector, a vector ADT whose contents are +// allocated using the allocator associated with an ASTContext.. +// +//===----------------------------------------------------------------------===// + +// FIXME: Most of this is copy-and-paste from BumpVector.h and SmallVector.h. +// We can refactor this core logic into something common. + +#ifndef LLVM_CLANG_AST_ASTVECTOR_H +#define LLVM_CLANG_AST_ASTVECTOR_H + +#include "clang/AST/AttrIterator.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/type_traits.h" +#include <algorithm> +#include <cstring> +#include <memory> + +namespace clang { + class ASTContext; + +template<typename T> +class ASTVector { +private: + T *Begin, *End; + llvm::PointerIntPair<T*, 1, bool> Capacity; + + void setEnd(T *P) { this->End = P; } + +protected: + // Make a tag bit available to users of this class. + // FIXME: This is a horrible hack. + bool getTag() const { return Capacity.getInt(); } + void setTag(bool B) { Capacity.setInt(B); } + +public: + // Default ctor - Initialize to empty. + ASTVector() : Begin(nullptr), End(nullptr), Capacity(nullptr, false) {} + + ASTVector(ASTVector &&O) : Begin(O.Begin), End(O.End), Capacity(O.Capacity) { + O.Begin = O.End = nullptr; + O.Capacity.setPointer(nullptr); + O.Capacity.setInt(false); + } + + ASTVector(const ASTContext &C, unsigned N) + : Begin(nullptr), End(nullptr), Capacity(nullptr, false) { + reserve(C, N); + } + + ASTVector &operator=(ASTVector &&RHS) { + ASTVector O(std::move(RHS)); + using std::swap; + swap(Begin, O.Begin); + swap(End, O.End); + swap(Capacity, O.Capacity); + return *this; + } + + ~ASTVector() { + if (std::is_class<T>::value) { + // Destroy the constructed elements in the vector. + destroy_range(Begin, End); + } + } + + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef T* iterator; + typedef const T* const_iterator; + + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + typedef std::reverse_iterator<iterator> reverse_iterator; + + typedef T& reference; + typedef const T& const_reference; + typedef T* pointer; + typedef const T* const_pointer; + + // forward iterator creation methods. + iterator begin() { return Begin; } + const_iterator begin() const { return Begin; } + iterator end() { return End; } + const_iterator end() const { return End; } + + // reverse iterator creation methods. + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); } + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { return const_reverse_iterator(begin());} + + bool empty() const { return Begin == End; } + size_type size() const { return End-Begin; } + + reference operator[](unsigned idx) { + assert(Begin + idx < End); + return Begin[idx]; + } + const_reference operator[](unsigned idx) const { + assert(Begin + idx < End); + return Begin[idx]; + } + + reference front() { + return begin()[0]; + } + const_reference front() const { + return begin()[0]; + } + + reference back() { + return end()[-1]; + } + const_reference back() const { + return end()[-1]; + } + + void pop_back() { + --End; + End->~T(); + } + + T pop_back_val() { + T Result = back(); + pop_back(); + return Result; + } + + void clear() { + if (std::is_class<T>::value) { + destroy_range(Begin, End); + } + End = Begin; + } + + /// data - Return a pointer to the vector's buffer, even if empty(). + pointer data() { + return pointer(Begin); + } + + /// data - Return a pointer to the vector's buffer, even if empty(). + const_pointer data() const { + return const_pointer(Begin); + } + + void push_back(const_reference Elt, const ASTContext &C) { + if (End < this->capacity_ptr()) { + Retry: + new (End) T(Elt); + ++End; + return; + } + grow(C); + goto Retry; + } + + void reserve(const ASTContext &C, unsigned N) { + if (unsigned(this->capacity_ptr()-Begin) < N) + grow(C, N); + } + + /// capacity - Return the total number of elements in the currently allocated + /// buffer. + size_t capacity() const { return this->capacity_ptr() - Begin; } + + /// append - Add the specified range to the end of the SmallVector. + /// + template<typename in_iter> + void append(const ASTContext &C, in_iter in_start, in_iter in_end) { + size_type NumInputs = std::distance(in_start, in_end); + + if (NumInputs == 0) + return; + + // Grow allocated space if needed. + if (NumInputs > size_type(this->capacity_ptr()-this->end())) + this->grow(C, this->size()+NumInputs); + + // Copy the new elements over. + // TODO: NEED To compile time dispatch on whether in_iter is a random access + // iterator to use the fast uninitialized_copy. + std::uninitialized_copy(in_start, in_end, this->end()); + this->setEnd(this->end() + NumInputs); + } + + /// append - Add the specified range to the end of the SmallVector. + /// + void append(const ASTContext &C, size_type NumInputs, const T &Elt) { + // Grow allocated space if needed. + if (NumInputs > size_type(this->capacity_ptr()-this->end())) + this->grow(C, this->size()+NumInputs); + + // Copy the new elements over. + std::uninitialized_fill_n(this->end(), NumInputs, Elt); + this->setEnd(this->end() + NumInputs); + } + + /// uninitialized_copy - Copy the range [I, E) onto the uninitialized memory + /// starting with "Dest", constructing elements into it as needed. + template<typename It1, typename It2> + static void uninitialized_copy(It1 I, It1 E, It2 Dest) { + std::uninitialized_copy(I, E, Dest); + } + + iterator insert(const ASTContext &C, iterator I, const T &Elt) { + if (I == this->end()) { // Important special case for empty vector. + push_back(Elt, C); + return this->end()-1; + } + + if (this->End < this->capacity_ptr()) { + Retry: + new (this->end()) T(this->back()); + this->setEnd(this->end()+1); + // Push everything else over. + std::copy_backward(I, this->end()-1, this->end()); + *I = Elt; + return I; + } + size_t EltNo = I-this->begin(); + this->grow(C); + I = this->begin()+EltNo; + goto Retry; + } + + iterator insert(const ASTContext &C, iterator I, size_type NumToInsert, + const T &Elt) { + // Convert iterator to elt# to avoid invalidating iterator when we reserve() + size_t InsertElt = I - this->begin(); + + if (I == this->end()) { // Important special case for empty vector. + append(C, NumToInsert, Elt); + return this->begin() + InsertElt; + } + + // Ensure there is enough space. + reserve(C, static_cast<unsigned>(this->size() + NumToInsert)); + + // Uninvalidate the iterator. + I = this->begin()+InsertElt; + + // If there are more elements between the insertion point and the end of the + // range than there are being inserted, we can use a simple approach to + // insertion. Since we already reserved space, we know that this won't + // reallocate the vector. + if (size_t(this->end()-I) >= NumToInsert) { + T *OldEnd = this->end(); + append(C, this->end()-NumToInsert, this->end()); + + // Copy the existing elements that get replaced. + std::copy_backward(I, OldEnd-NumToInsert, OldEnd); + + std::fill_n(I, NumToInsert, Elt); + return I; + } + + // Otherwise, we're inserting more elements than exist already, and we're + // not inserting at the end. + + // Copy over the elements that we're about to overwrite. + T *OldEnd = this->end(); + this->setEnd(this->end() + NumToInsert); + size_t NumOverwritten = OldEnd-I; + this->uninitialized_copy(I, OldEnd, this->end()-NumOverwritten); + + // Replace the overwritten part. + std::fill_n(I, NumOverwritten, Elt); + + // Insert the non-overwritten middle part. + std::uninitialized_fill_n(OldEnd, NumToInsert-NumOverwritten, Elt); + return I; + } + + template<typename ItTy> + iterator insert(const ASTContext &C, iterator I, ItTy From, ItTy To) { + // Convert iterator to elt# to avoid invalidating iterator when we reserve() + size_t InsertElt = I - this->begin(); + + if (I == this->end()) { // Important special case for empty vector. + append(C, From, To); + return this->begin() + InsertElt; + } + + size_t NumToInsert = std::distance(From, To); + + // Ensure there is enough space. + reserve(C, static_cast<unsigned>(this->size() + NumToInsert)); + + // Uninvalidate the iterator. + I = this->begin()+InsertElt; + + // If there are more elements between the insertion point and the end of the + // range than there are being inserted, we can use a simple approach to + // insertion. Since we already reserved space, we know that this won't + // reallocate the vector. + if (size_t(this->end()-I) >= NumToInsert) { + T *OldEnd = this->end(); + append(C, this->end()-NumToInsert, this->end()); + + // Copy the existing elements that get replaced. + std::copy_backward(I, OldEnd-NumToInsert, OldEnd); + + std::copy(From, To, I); + return I; + } + + // Otherwise, we're inserting more elements than exist already, and we're + // not inserting at the end. + + // Copy over the elements that we're about to overwrite. + T *OldEnd = this->end(); + this->setEnd(this->end() + NumToInsert); + size_t NumOverwritten = OldEnd-I; + this->uninitialized_copy(I, OldEnd, this->end()-NumOverwritten); + + // Replace the overwritten part. + for (; NumOverwritten > 0; --NumOverwritten) { + *I = *From; + ++I; ++From; + } + + // Insert the non-overwritten middle part. + this->uninitialized_copy(From, To, OldEnd); + return I; + } + + void resize(const ASTContext &C, unsigned N, const T &NV) { + if (N < this->size()) { + this->destroy_range(this->begin()+N, this->end()); + this->setEnd(this->begin()+N); + } else if (N > this->size()) { + if (this->capacity() < N) + this->grow(C, N); + construct_range(this->end(), this->begin()+N, NV); + this->setEnd(this->begin()+N); + } + } + +private: + /// grow - double the size of the allocated memory, guaranteeing space for at + /// least one more element or MinSize if specified. + void grow(const ASTContext &C, size_type MinSize = 1); + + void construct_range(T *S, T *E, const T &Elt) { + for (; S != E; ++S) + new (S) T(Elt); + } + + void destroy_range(T *S, T *E) { + while (S != E) { + --E; + E->~T(); + } + } + +protected: + const_iterator capacity_ptr() const { + return (iterator) Capacity.getPointer(); + } + iterator capacity_ptr() { return (iterator)Capacity.getPointer(); } +}; + +// Define this out-of-line to dissuade the C++ compiler from inlining it. +template <typename T> +void ASTVector<T>::grow(const ASTContext &C, size_t MinSize) { + size_t CurCapacity = this->capacity(); + size_t CurSize = size(); + size_t NewCapacity = 2*CurCapacity; + if (NewCapacity < MinSize) + NewCapacity = MinSize; + + // Allocate the memory from the ASTContext. + T *NewElts = new (C, llvm::alignOf<T>()) T[NewCapacity]; + + // Copy the elements over. + if (Begin != End) { + if (std::is_class<T>::value) { + std::uninitialized_copy(Begin, End, NewElts); + // Destroy the original elements. + destroy_range(Begin, End); + } else { + // Use memcpy for PODs (std::uninitialized_copy optimizes to memmove). + memcpy(NewElts, Begin, CurSize * sizeof(T)); + } + } + + // ASTContext never frees any memory. + Begin = NewElts; + End = NewElts+CurSize; + Capacity.setPointer(Begin+NewCapacity); +} + +} // end: clang namespace +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/Attr.h b/contrib/llvm/tools/clang/include/clang/AST/Attr.h new file mode 100644 index 0000000..8b80e9f --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/Attr.h @@ -0,0 +1,169 @@ +//===--- Attr.h - Classes for representing attributes ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Attr interface and subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_ATTR_H +#define LLVM_CLANG_AST_ATTR_H + +#include "clang/AST/AttrIterator.h" +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "clang/Basic/AttrKinds.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/Sanitizers.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/VersionTuple.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> + +namespace clang { + class ASTContext; + class IdentifierInfo; + class ObjCInterfaceDecl; + class Expr; + class QualType; + class FunctionDecl; + class TypeSourceInfo; + +/// Attr - This represents one attribute. +class Attr { +private: + SourceRange Range; + unsigned AttrKind : 16; + +protected: + /// An index into the spelling list of an + /// attribute defined in Attr.td file. + unsigned SpellingListIndex : 4; + bool Inherited : 1; + bool IsPackExpansion : 1; + bool Implicit : 1; + bool IsLateParsed : 1; + bool DuplicatesAllowed : 1; + + void *operator new(size_t bytes) LLVM_NOEXCEPT { + llvm_unreachable("Attrs cannot be allocated with regular 'new'."); + } + void operator delete(void *data) LLVM_NOEXCEPT { + llvm_unreachable("Attrs cannot be released with regular 'delete'."); + } + +public: + // Forward so that the regular new and delete do not hide global ones. + void *operator new(size_t Bytes, ASTContext &C, + size_t Alignment = 8) LLVM_NOEXCEPT { + return ::operator new(Bytes, C, Alignment); + } + void operator delete(void *Ptr, ASTContext &C, + size_t Alignment) LLVM_NOEXCEPT { + return ::operator delete(Ptr, C, Alignment); + } + +protected: + Attr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex, + bool IsLateParsed, bool DuplicatesAllowed) + : Range(R), AttrKind(AK), SpellingListIndex(SpellingListIndex), + Inherited(false), IsPackExpansion(false), Implicit(false), + IsLateParsed(IsLateParsed), DuplicatesAllowed(DuplicatesAllowed) {} + +public: + + attr::Kind getKind() const { + return static_cast<attr::Kind>(AttrKind); + } + + unsigned getSpellingListIndex() const { return SpellingListIndex; } + const char *getSpelling() const; + + SourceLocation getLocation() const { return Range.getBegin(); } + SourceRange getRange() const { return Range; } + void setRange(SourceRange R) { Range = R; } + + bool isInherited() const { return Inherited; } + + /// \brief Returns true if the attribute has been implicitly created instead + /// of explicitly written by the user. + bool isImplicit() const { return Implicit; } + void setImplicit(bool I) { Implicit = I; } + + void setPackExpansion(bool PE) { IsPackExpansion = PE; } + bool isPackExpansion() const { return IsPackExpansion; } + + // Clone this attribute. + Attr *clone(ASTContext &C) const; + + bool isLateParsed() const { return IsLateParsed; } + + // Pretty print this attribute. + void printPretty(raw_ostream &OS, const PrintingPolicy &Policy) const; + + /// \brief By default, attributes cannot be duplicated when being merged; + /// however, an attribute can override this. Returns true if the attribute + /// can be duplicated when merging. + bool duplicatesAllowed() const { return DuplicatesAllowed; } +}; + +class InheritableAttr : public Attr { +protected: + InheritableAttr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex, + bool IsLateParsed, bool DuplicatesAllowed) + : Attr(AK, R, SpellingListIndex, IsLateParsed, DuplicatesAllowed) {} + +public: + void setInherited(bool I) { Inherited = I; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Attr *A) { + return A->getKind() <= attr::LAST_INHERITABLE; + } +}; + +class InheritableParamAttr : public InheritableAttr { +protected: + InheritableParamAttr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex, + bool IsLateParsed, bool DuplicatesAllowed) + : InheritableAttr(AK, R, SpellingListIndex, IsLateParsed, + DuplicatesAllowed) {} + +public: + // Implement isa/cast/dyncast/etc. + static bool classof(const Attr *A) { + // Relies on relative order of enum emission with respect to MS inheritance + // attrs. + return A->getKind() <= attr::LAST_INHERITABLE_PARAM; + } +}; + +#include "clang/AST/Attrs.inc" + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const Attr *At) { + DB.AddTaggedVal(reinterpret_cast<intptr_t>(At), + DiagnosticsEngine::ak_attr); + return DB; +} + +inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + const Attr *At) { + PD.AddTaggedVal(reinterpret_cast<intptr_t>(At), + DiagnosticsEngine::ak_attr); + return PD; +} +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/AttrIterator.h b/contrib/llvm/tools/clang/include/clang/AST/AttrIterator.h new file mode 100644 index 0000000..a0c8030 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/AttrIterator.h @@ -0,0 +1,142 @@ +//===--- AttrIterator.h - Classes for attribute iteration -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Attr vector and specific_attr_iterator interfaces. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_ATTRITERATOR_H +#define LLVM_CLANG_AST_ATTRITERATOR_H + +#include "clang/Basic/LLVM.h" +#include <iterator> + +namespace clang { + class ASTContext; + class Attr; +} + +// Defined in ASTContext.h +void *operator new(size_t Bytes, const clang::ASTContext &C, + size_t Alignment = 8); +// FIXME: Being forced to not have a default argument here due to redeclaration +// rules on default arguments sucks +void *operator new[](size_t Bytes, const clang::ASTContext &C, + size_t Alignment); + +// It is good practice to pair new/delete operators. Also, MSVC gives many +// warnings if a matching delete overload is not declared, even though the +// throw() spec guarantees it will not be implicitly called. +void operator delete(void *Ptr, const clang::ASTContext &C, size_t); +void operator delete[](void *Ptr, const clang::ASTContext &C, size_t); + +namespace clang { + +/// AttrVec - A vector of Attr, which is how they are stored on the AST. +typedef SmallVector<Attr*, 2> AttrVec; +typedef SmallVector<const Attr*, 2> ConstAttrVec; + +/// specific_attr_iterator - Iterates over a subrange of an AttrVec, only +/// providing attributes that are of a specific type. +template <typename SpecificAttr, typename Container = AttrVec> +class specific_attr_iterator { + typedef typename Container::const_iterator Iterator; + + /// Current - The current, underlying iterator. + /// In order to ensure we don't dereference an invalid iterator unless + /// specifically requested, we don't necessarily advance this all the + /// way. Instead, we advance it when an operation is requested; if the + /// operation is acting on what should be a past-the-end iterator, + /// then we offer no guarantees, but this way we do not dereference a + /// past-the-end iterator when we move to a past-the-end position. + mutable Iterator Current; + + void AdvanceToNext() const { + while (!isa<SpecificAttr>(*Current)) + ++Current; + } + + void AdvanceToNext(Iterator I) const { + while (Current != I && !isa<SpecificAttr>(*Current)) + ++Current; + } + +public: + typedef SpecificAttr* value_type; + typedef SpecificAttr* reference; + typedef SpecificAttr* pointer; + typedef std::forward_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + + specific_attr_iterator() : Current() { } + explicit specific_attr_iterator(Iterator i) : Current(i) { } + + reference operator*() const { + AdvanceToNext(); + return cast<SpecificAttr>(*Current); + } + pointer operator->() const { + AdvanceToNext(); + return cast<SpecificAttr>(*Current); + } + + specific_attr_iterator& operator++() { + ++Current; + return *this; + } + specific_attr_iterator operator++(int) { + specific_attr_iterator Tmp(*this); + ++(*this); + return Tmp; + } + + friend bool operator==(specific_attr_iterator Left, + specific_attr_iterator Right) { + assert((Left.Current == nullptr) == (Right.Current == nullptr)); + if (Left.Current < Right.Current) + Left.AdvanceToNext(Right.Current); + else + Right.AdvanceToNext(Left.Current); + return Left.Current == Right.Current; + } + friend bool operator!=(specific_attr_iterator Left, + specific_attr_iterator Right) { + return !(Left == Right); + } +}; + +template <typename SpecificAttr, typename Container> +inline specific_attr_iterator<SpecificAttr, Container> + specific_attr_begin(const Container& container) { + return specific_attr_iterator<SpecificAttr, Container>(container.begin()); +} +template <typename SpecificAttr, typename Container> +inline specific_attr_iterator<SpecificAttr, Container> + specific_attr_end(const Container& container) { + return specific_attr_iterator<SpecificAttr, Container>(container.end()); +} + +template <typename SpecificAttr, typename Container> +inline bool hasSpecificAttr(const Container& container) { + return specific_attr_begin<SpecificAttr>(container) != + specific_attr_end<SpecificAttr>(container); +} +template <typename SpecificAttr, typename Container> +inline SpecificAttr *getSpecificAttr(const Container& container) { + specific_attr_iterator<SpecificAttr, Container> i = + specific_attr_begin<SpecificAttr>(container); + if (i != specific_attr_end<SpecificAttr>(container)) + return *i; + else + return nullptr; +} + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/BaseSubobject.h b/contrib/llvm/tools/clang/include/clang/AST/BaseSubobject.h new file mode 100644 index 0000000..da538e3 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/BaseSubobject.h @@ -0,0 +1,87 @@ +//===--- BaseSubobject.h - BaseSubobject class ----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides a definition of the BaseSubobject class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_BASESUBOBJECT_H +#define LLVM_CLANG_AST_BASESUBOBJECT_H + +#include "clang/AST/CharUnits.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/type_traits.h" + +namespace clang { + class CXXRecordDecl; + +// BaseSubobject - Uniquely identifies a direct or indirect base class. +// Stores both the base class decl and the offset from the most derived class to +// the base class. Used for vtable and VTT generation. +class BaseSubobject { + /// Base - The base class declaration. + const CXXRecordDecl *Base; + + /// BaseOffset - The offset from the most derived class to the base class. + CharUnits BaseOffset; + +public: + BaseSubobject() { } + BaseSubobject(const CXXRecordDecl *Base, CharUnits BaseOffset) + : Base(Base), BaseOffset(BaseOffset) { } + + /// getBase - Returns the base class declaration. + const CXXRecordDecl *getBase() const { return Base; } + + /// getBaseOffset - Returns the base class offset. + CharUnits getBaseOffset() const { return BaseOffset; } + + friend bool operator==(const BaseSubobject &LHS, const BaseSubobject &RHS) { + return LHS.Base == RHS.Base && LHS.BaseOffset == RHS.BaseOffset; + } +}; + +} // end namespace clang + +namespace llvm { + +template<> struct DenseMapInfo<clang::BaseSubobject> { + static clang::BaseSubobject getEmptyKey() { + return clang::BaseSubobject( + DenseMapInfo<const clang::CXXRecordDecl *>::getEmptyKey(), + clang::CharUnits::fromQuantity(DenseMapInfo<int64_t>::getEmptyKey())); + } + + static clang::BaseSubobject getTombstoneKey() { + return clang::BaseSubobject( + DenseMapInfo<const clang::CXXRecordDecl *>::getTombstoneKey(), + clang::CharUnits::fromQuantity(DenseMapInfo<int64_t>::getTombstoneKey())); + } + + static unsigned getHashValue(const clang::BaseSubobject &Base) { + typedef std::pair<const clang::CXXRecordDecl *, clang::CharUnits> PairTy; + return DenseMapInfo<PairTy>::getHashValue(PairTy(Base.getBase(), + Base.getBaseOffset())); + } + + static bool isEqual(const clang::BaseSubobject &LHS, + const clang::BaseSubobject &RHS) { + return LHS == RHS; + } +}; + +// It's OK to treat BaseSubobject as a POD type. +template <> struct isPodLike<clang::BaseSubobject> { + static const bool value = true; +}; + +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/BuiltinTypes.def b/contrib/llvm/tools/clang/include/clang/AST/BuiltinTypes.def new file mode 100644 index 0000000..85e237a --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/BuiltinTypes.def @@ -0,0 +1,261 @@ +//===-- BuiltinTypeNodes.def - Metadata about BuiltinTypes ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the database about various builtin singleton types. +// +// BuiltinType::Id is the enumerator defining the type. +// +// Context.SingletonId is the global singleton of this type. Some global +// singletons are shared by multiple types. +// +// BUILTIN_TYPE(Id, SingletonId) - A builtin type that has not been +// covered by any other #define. Defining this macro covers all +// the builtins. +// +// SIGNED_TYPE(Id, SingletonId) - A signed integral type. +// +// UNSIGNED_TYPE(Id, SingletonId) - An unsigned integral type. +// +// FLOATING_TYPE(Id, SingletonId) - A floating-point type. +// +// PLACEHOLDER_TYPE(Id, SingletonId) - A placeholder type. Placeholder +// types are used to perform context-sensitive checking of specific +// forms of expression. +// +// SHARED_SINGLETON_TYPE(Expansion) - The given expansion corresponds +// to a builtin which uses a shared singleton type. +// +//===----------------------------------------------------------------------===// + +#ifndef SIGNED_TYPE +#define SIGNED_TYPE(Id, SingletonId) BUILTIN_TYPE(Id, SingletonId) +#endif + +#ifndef UNSIGNED_TYPE +#define UNSIGNED_TYPE(Id, SingletonId) BUILTIN_TYPE(Id, SingletonId) +#endif + +#ifndef FLOATING_TYPE +#define FLOATING_TYPE(Id, SingletonId) BUILTIN_TYPE(Id, SingletonId) +#endif + +#ifndef PLACEHOLDER_TYPE +#define PLACEHOLDER_TYPE(Id, SingletonId) BUILTIN_TYPE(Id, SingletonId) +#endif + +#ifndef SHARED_SINGLETON_TYPE +#define SHARED_SINGLETON_TYPE(Expansion) Expansion +#endif + +//===- Builtin Types ------------------------------------------------------===// + +// void +BUILTIN_TYPE(Void, VoidTy) + +//===- Unsigned Types -----------------------------------------------------===// + +// 'bool' in C++, '_Bool' in C99 +UNSIGNED_TYPE(Bool, BoolTy) + +// 'char' for targets where it's unsigned +SHARED_SINGLETON_TYPE(UNSIGNED_TYPE(Char_U, CharTy)) + +// 'unsigned char', explicitly qualified +UNSIGNED_TYPE(UChar, UnsignedCharTy) + +// 'wchar_t' for targets where it's unsigned +SHARED_SINGLETON_TYPE(UNSIGNED_TYPE(WChar_U, WCharTy)) + +// 'char16_t' in C++ +UNSIGNED_TYPE(Char16, Char16Ty) + +// 'char32_t' in C++ +UNSIGNED_TYPE(Char32, Char32Ty) + +// 'unsigned short' +UNSIGNED_TYPE(UShort, UnsignedShortTy) + +// 'unsigned int' +UNSIGNED_TYPE(UInt, UnsignedIntTy) + +// 'unsigned long' +UNSIGNED_TYPE(ULong, UnsignedLongTy) + +// 'unsigned long long' +UNSIGNED_TYPE(ULongLong, UnsignedLongLongTy) + +// '__uint128_t' +UNSIGNED_TYPE(UInt128, UnsignedInt128Ty) + +//===- Signed Types -------------------------------------------------------===// + +// 'char' for targets where it's signed +SHARED_SINGLETON_TYPE(SIGNED_TYPE(Char_S, CharTy)) + +// 'signed char', explicitly qualified +SIGNED_TYPE(SChar, SignedCharTy) + +// 'wchar_t' for targets where it's signed +SHARED_SINGLETON_TYPE(SIGNED_TYPE(WChar_S, WCharTy)) + +// 'short' or 'signed short' +SIGNED_TYPE(Short, ShortTy) + +// 'int' or 'signed int' +SIGNED_TYPE(Int, IntTy) + +// 'long' or 'signed long' +SIGNED_TYPE(Long, LongTy) + +// 'long long' or 'signed long long' +SIGNED_TYPE(LongLong, LongLongTy) + +// '__int128_t' +SIGNED_TYPE(Int128, Int128Ty) + +//===- Floating point types -----------------------------------------------===// + +// 'half' in OpenCL, '__fp16' in ARM NEON. +FLOATING_TYPE(Half, HalfTy) + +// 'float' +FLOATING_TYPE(Float, FloatTy) + +// 'double' +FLOATING_TYPE(Double, DoubleTy) + +// 'long double' +FLOATING_TYPE(LongDouble, LongDoubleTy) + +//===- Language-specific types --------------------------------------------===// + +// This is the type of C++0x 'nullptr'. +BUILTIN_TYPE(NullPtr, NullPtrTy) + +// The primitive Objective C 'id' type. The user-visible 'id' +// type is a typedef of an ObjCObjectPointerType to an +// ObjCObjectType with this as its base. In fact, this only ever +// shows up in an AST as the base type of an ObjCObjectType. +BUILTIN_TYPE(ObjCId, ObjCBuiltinIdTy) + +// The primitive Objective C 'Class' type. The user-visible +// 'Class' type is a typedef of an ObjCObjectPointerType to an +// ObjCObjectType with this as its base. In fact, this only ever +// shows up in an AST as the base type of an ObjCObjectType. +BUILTIN_TYPE(ObjCClass, ObjCBuiltinClassTy) + +// The primitive Objective C 'SEL' type. The user-visible 'SEL' +// type is a typedef of a PointerType to this. +BUILTIN_TYPE(ObjCSel, ObjCBuiltinSelTy) + +// OpenCL image types. +BUILTIN_TYPE(OCLImage1d, OCLImage1dTy) +BUILTIN_TYPE(OCLImage1dArray, OCLImage1dArrayTy) +BUILTIN_TYPE(OCLImage1dBuffer, OCLImage1dBufferTy) +BUILTIN_TYPE(OCLImage2d, OCLImage2dTy) +BUILTIN_TYPE(OCLImage2dArray, OCLImage2dArrayTy) +BUILTIN_TYPE(OCLImage2dDepth, OCLImage2dDepthTy) +BUILTIN_TYPE(OCLImage2dArrayDepth, OCLImage2dArrayDepthTy) +BUILTIN_TYPE(OCLImage2dMSAA, OCLImage2dMSAATy) +BUILTIN_TYPE(OCLImage2dArrayMSAA, OCLImage2dArrayMSAATy) +BUILTIN_TYPE(OCLImage2dMSAADepth, OCLImage2dMSAADepthTy) +BUILTIN_TYPE(OCLImage2dArrayMSAADepth, OCLImage2dArrayMSAADepthTy) +BUILTIN_TYPE(OCLImage3d, OCLImage3dTy) + +// OpenCL sampler_t. +BUILTIN_TYPE(OCLSampler, OCLSamplerTy) + +// OpenCL event_t. +BUILTIN_TYPE(OCLEvent, OCLEventTy) + +// OpenCL clk_event_t. +BUILTIN_TYPE(OCLClkEvent, OCLClkEventTy) + +// OpenCL queue_t. +BUILTIN_TYPE(OCLQueue, OCLQueueTy) + +// OpenCL ndrange_t. +BUILTIN_TYPE(OCLNDRange, OCLNDRangeTy) + +// OpenCL reserve_id_t. +BUILTIN_TYPE(OCLReserveID, OCLReserveIDTy) + +// This represents the type of an expression whose type is +// totally unknown, e.g. 'T::foo'. It is permitted for this to +// appear in situations where the structure of the type is +// theoretically deducible. +BUILTIN_TYPE(Dependent, DependentTy) + +// The type of an unresolved overload set. A placeholder type. +// Expressions with this type have one of the following basic +// forms, with parentheses generally permitted: +// foo # possibly qualified, not if an implicit access +// foo # possibly qualified, not if an implicit access +// &foo # possibly qualified, not if an implicit access +// x->foo # only if might be a static member function +// &x->foo # only if might be a static member function +// &Class::foo # when a pointer-to-member; sub-expr also has this type +// OverloadExpr::find can be used to analyze the expression. +// +// Overload should be the first placeholder type, or else change +// BuiltinType::isNonOverloadPlaceholderType() +PLACEHOLDER_TYPE(Overload, OverloadTy) + +// The type of a bound C++ non-static member function. +// A placeholder type. Expressions with this type have one of the +// following basic forms: +// foo # if an implicit access +// x->foo # if only contains non-static members +PLACEHOLDER_TYPE(BoundMember, BoundMemberTy) + +// The type of an expression which refers to a pseudo-object, +// such as those introduced by Objective C's @property or +// VS.NET's __property declarations. A placeholder type. The +// pseudo-object is actually accessed by emitting a call to +// some sort of function or method; typically there is a pair +// of a setter and a getter, with the setter used if the +// pseudo-object reference is used syntactically as the +// left-hand-side of an assignment operator. +// +// A pseudo-object reference naming an Objective-C @property is +// always a dot access with a base of object-pointer type, +// e.g. 'x.foo'. +// +// In VS.NET, a __property declaration creates an implicit +// member with an associated name, which can then be named +// in any of the normal ways an ordinary member could be. +PLACEHOLDER_TYPE(PseudoObject, PseudoObjectTy) + +// __builtin_any_type. A placeholder type. Useful for clients +// like debuggers that don't know what type to give something. +// Only a small number of operations are valid on expressions of +// unknown type, most notably explicit casts. +PLACEHOLDER_TYPE(UnknownAny, UnknownAnyTy) + +PLACEHOLDER_TYPE(BuiltinFn, BuiltinFnTy) + +// The type of a cast which, in ARC, would normally require a +// __bridge, but which might be okay depending on the immediate +// context. +PLACEHOLDER_TYPE(ARCUnbridgedCast, ARCUnbridgedCastTy) + +// A placeholder type for OpenMP array sections. +PLACEHOLDER_TYPE(OMPArraySection, OMPArraySectionTy) + +#ifdef LAST_BUILTIN_TYPE +LAST_BUILTIN_TYPE(OMPArraySection) +#undef LAST_BUILTIN_TYPE +#endif + +#undef SHARED_SINGLETON_TYPE +#undef PLACEHOLDER_TYPE +#undef FLOATING_TYPE +#undef SIGNED_TYPE +#undef UNSIGNED_TYPE +#undef BUILTIN_TYPE diff --git a/contrib/llvm/tools/clang/include/clang/AST/CXXInheritance.h b/contrib/llvm/tools/clang/include/clang/AST/CXXInheritance.h new file mode 100644 index 0000000..8587260 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/CXXInheritance.h @@ -0,0 +1,365 @@ +//===------ CXXInheritance.h - C++ Inheritance ------------------*- 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 routines that help analyzing C++ inheritance hierarchies. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_CXXINHERITANCE_H +#define LLVM_CLANG_AST_CXXINHERITANCE_H + +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeOrdering.h" +#include "llvm/ADT/MapVector.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallVector.h" +#include <cassert> +#include <list> +#include <map> + +namespace clang { + +class CXXBaseSpecifier; +class CXXMethodDecl; +class CXXRecordDecl; +class NamedDecl; + +/// \brief Represents an element in a path from a derived class to a +/// base class. +/// +/// Each step in the path references the link from a +/// derived class to one of its direct base classes, along with a +/// base "number" that identifies which base subobject of the +/// original derived class we are referencing. +struct CXXBasePathElement { + /// \brief The base specifier that states the link from a derived + /// class to a base class, which will be followed by this base + /// path element. + const CXXBaseSpecifier *Base; + + /// \brief The record decl of the class that the base is a base of. + const CXXRecordDecl *Class; + + /// \brief Identifies which base class subobject (of type + /// \c Base->getType()) this base path element refers to. + /// + /// This value is only valid if \c !Base->isVirtual(), because there + /// is no base numbering for the zero or one virtual bases of a + /// given type. + int SubobjectNumber; +}; + +/// \brief Represents a path from a specific derived class +/// (which is not represented as part of the path) to a particular +/// (direct or indirect) base class subobject. +/// +/// Individual elements in the path are described by the \c CXXBasePathElement +/// structure, which captures both the link from a derived class to one of its +/// direct bases and identification describing which base class +/// subobject is being used. +class CXXBasePath : public SmallVector<CXXBasePathElement, 4> { +public: + CXXBasePath() : Access(AS_public) {} + + /// \brief The access along this inheritance path. This is only + /// calculated when recording paths. AS_none is a special value + /// used to indicate a path which permits no legal access. + AccessSpecifier Access; + + /// \brief The set of declarations found inside this base class + /// subobject. + DeclContext::lookup_result Decls; + + void clear() { + SmallVectorImpl<CXXBasePathElement>::clear(); + Access = AS_public; + } +}; + +/// BasePaths - Represents the set of paths from a derived class to +/// one of its (direct or indirect) bases. For example, given the +/// following class hierarchy: +/// +/// @code +/// class A { }; +/// class B : public A { }; +/// class C : public A { }; +/// class D : public B, public C{ }; +/// @endcode +/// +/// There are two potential BasePaths to represent paths from D to a +/// base subobject of type A. One path is (D,0) -> (B,0) -> (A,0) +/// and another is (D,0)->(C,0)->(A,1). These two paths actually +/// refer to two different base class subobjects of the same type, +/// so the BasePaths object refers to an ambiguous path. On the +/// other hand, consider the following class hierarchy: +/// +/// @code +/// class A { }; +/// class B : public virtual A { }; +/// class C : public virtual A { }; +/// class D : public B, public C{ }; +/// @endcode +/// +/// Here, there are two potential BasePaths again, (D, 0) -> (B, 0) +/// -> (A,v) and (D, 0) -> (C, 0) -> (A, v), but since both of them +/// refer to the same base class subobject of type A (the virtual +/// one), there is no ambiguity. +class CXXBasePaths { + /// \brief The type from which this search originated. + CXXRecordDecl *Origin; + + /// Paths - The actual set of paths that can be taken from the + /// derived class to the same base class. + std::list<CXXBasePath> Paths; + + /// ClassSubobjects - Records the class subobjects for each class + /// type that we've seen. The first element in the pair says + /// whether we found a path to a virtual base for that class type, + /// while the element contains the number of non-virtual base + /// class subobjects for that class type. The key of the map is + /// the cv-unqualified canonical type of the base class subobject. + llvm::SmallDenseMap<QualType, std::pair<bool, unsigned>, 8> ClassSubobjects; + + /// FindAmbiguities - Whether Sema::IsDerivedFrom should try find + /// ambiguous paths while it is looking for a path from a derived + /// type to a base type. + bool FindAmbiguities; + + /// RecordPaths - Whether Sema::IsDerivedFrom should record paths + /// while it is determining whether there are paths from a derived + /// type to a base type. + bool RecordPaths; + + /// DetectVirtual - Whether Sema::IsDerivedFrom should abort the search + /// if it finds a path that goes across a virtual base. The virtual class + /// is also recorded. + bool DetectVirtual; + + /// ScratchPath - A BasePath that is used by Sema::lookupInBases + /// to help build the set of paths. + CXXBasePath ScratchPath; + + /// DetectedVirtual - The base class that is virtual. + const RecordType *DetectedVirtual; + + /// \brief Array of the declarations that have been found. This + /// array is constructed only if needed, e.g., to iterate over the + /// results within LookupResult. + std::unique_ptr<NamedDecl *[]> DeclsFound; + unsigned NumDeclsFound; + + friend class CXXRecordDecl; + + void ComputeDeclsFound(); + + bool lookupInBases(ASTContext &Context, const CXXRecordDecl *Record, + CXXRecordDecl::BaseMatchesCallback BaseMatches); + +public: + typedef std::list<CXXBasePath>::iterator paths_iterator; + typedef std::list<CXXBasePath>::const_iterator const_paths_iterator; + typedef NamedDecl **decl_iterator; + + /// BasePaths - Construct a new BasePaths structure to record the + /// paths for a derived-to-base search. + explicit CXXBasePaths(bool FindAmbiguities = true, bool RecordPaths = true, + bool DetectVirtual = true) + : FindAmbiguities(FindAmbiguities), RecordPaths(RecordPaths), + DetectVirtual(DetectVirtual), DetectedVirtual(nullptr), + NumDeclsFound(0) {} + + paths_iterator begin() { return Paths.begin(); } + paths_iterator end() { return Paths.end(); } + const_paths_iterator begin() const { return Paths.begin(); } + const_paths_iterator end() const { return Paths.end(); } + + CXXBasePath& front() { return Paths.front(); } + const CXXBasePath& front() const { return Paths.front(); } + + typedef llvm::iterator_range<decl_iterator> decl_range; + decl_range found_decls(); + + /// \brief Determine whether the path from the most-derived type to the + /// given base type is ambiguous (i.e., it refers to multiple subobjects of + /// the same base type). + bool isAmbiguous(CanQualType BaseType); + + /// \brief Whether we are finding multiple paths to detect ambiguities. + bool isFindingAmbiguities() const { return FindAmbiguities; } + + /// \brief Whether we are recording paths. + bool isRecordingPaths() const { return RecordPaths; } + + /// \brief Specify whether we should be recording paths or not. + void setRecordingPaths(bool RP) { RecordPaths = RP; } + + /// \brief Whether we are detecting virtual bases. + bool isDetectingVirtual() const { return DetectVirtual; } + + /// \brief The virtual base discovered on the path (if we are merely + /// detecting virtuals). + const RecordType* getDetectedVirtual() const { + return DetectedVirtual; + } + + /// \brief Retrieve the type from which this base-paths search + /// began + CXXRecordDecl *getOrigin() const { return Origin; } + void setOrigin(CXXRecordDecl *Rec) { Origin = Rec; } + + /// \brief Clear the base-paths results. + void clear(); + + /// \brief Swap this data structure's contents with another CXXBasePaths + /// object. + void swap(CXXBasePaths &Other); +}; + +/// \brief Uniquely identifies a virtual method within a class +/// hierarchy by the method itself and a class subobject number. +struct UniqueVirtualMethod { + UniqueVirtualMethod() + : Method(nullptr), Subobject(0), InVirtualSubobject(nullptr) { } + + UniqueVirtualMethod(CXXMethodDecl *Method, unsigned Subobject, + const CXXRecordDecl *InVirtualSubobject) + : Method(Method), Subobject(Subobject), + InVirtualSubobject(InVirtualSubobject) { } + + /// \brief The overriding virtual method. + CXXMethodDecl *Method; + + /// \brief The subobject in which the overriding virtual method + /// resides. + unsigned Subobject; + + /// \brief The virtual base class subobject of which this overridden + /// virtual method is a part. Note that this records the closest + /// derived virtual base class subobject. + const CXXRecordDecl *InVirtualSubobject; + + friend bool operator==(const UniqueVirtualMethod &X, + const UniqueVirtualMethod &Y) { + return X.Method == Y.Method && X.Subobject == Y.Subobject && + X.InVirtualSubobject == Y.InVirtualSubobject; + } + + friend bool operator!=(const UniqueVirtualMethod &X, + const UniqueVirtualMethod &Y) { + return !(X == Y); + } +}; + +/// \brief The set of methods that override a given virtual method in +/// each subobject where it occurs. +/// +/// The first part of the pair is the subobject in which the +/// overridden virtual function occurs, while the second part of the +/// pair is the virtual method that overrides it (including the +/// subobject in which that virtual function occurs). +class OverridingMethods { + typedef SmallVector<UniqueVirtualMethod, 4> ValuesT; + typedef llvm::MapVector<unsigned, ValuesT> MapType; + MapType Overrides; + +public: + // Iterate over the set of subobjects that have overriding methods. + typedef MapType::iterator iterator; + typedef MapType::const_iterator const_iterator; + iterator begin() { return Overrides.begin(); } + const_iterator begin() const { return Overrides.begin(); } + iterator end() { return Overrides.end(); } + const_iterator end() const { return Overrides.end(); } + unsigned size() const { return Overrides.size(); } + + // Iterate over the set of overriding virtual methods in a given + // subobject. + typedef SmallVectorImpl<UniqueVirtualMethod>::iterator + overriding_iterator; + typedef SmallVectorImpl<UniqueVirtualMethod>::const_iterator + overriding_const_iterator; + + // Add a new overriding method for a particular subobject. + void add(unsigned OverriddenSubobject, UniqueVirtualMethod Overriding); + + // Add all of the overriding methods from "other" into overrides for + // this method. Used when merging the overrides from multiple base + // class subobjects. + void add(const OverridingMethods &Other); + + // Replace all overriding virtual methods in all subobjects with the + // given virtual method. + void replaceAll(UniqueVirtualMethod Overriding); +}; + +/// \brief A mapping from each virtual member function to its set of +/// final overriders. +/// +/// Within a class hierarchy for a given derived class, each virtual +/// member function in that hierarchy has one or more "final +/// overriders" (C++ [class.virtual]p2). A final overrider for a +/// virtual function "f" is the virtual function that will actually be +/// invoked when dispatching a call to "f" through the +/// vtable. Well-formed classes have a single final overrider for each +/// virtual function; in abstract classes, the final overrider for at +/// least one virtual function is a pure virtual function. Due to +/// multiple, virtual inheritance, it is possible for a class to have +/// more than one final overrider. Athough this is an error (per C++ +/// [class.virtual]p2), it is not considered an error here: the final +/// overrider map can represent multiple final overriders for a +/// method, and it is up to the client to determine whether they are +/// problem. For example, the following class \c D has two final +/// overriders for the virtual function \c A::f(), one in \c C and one +/// in \c D: +/// +/// \code +/// struct A { virtual void f(); }; +/// struct B : virtual A { virtual void f(); }; +/// struct C : virtual A { virtual void f(); }; +/// struct D : B, C { }; +/// \endcode +/// +/// This data structure contains a mapping from every virtual +/// function *that does not override an existing virtual function* and +/// in every subobject where that virtual function occurs to the set +/// of virtual functions that override it. Thus, the same virtual +/// function \c A::f can actually occur in multiple subobjects of type +/// \c A due to multiple inheritance, and may be overridden by +/// different virtual functions in each, as in the following example: +/// +/// \code +/// struct A { virtual void f(); }; +/// struct B : A { virtual void f(); }; +/// struct C : A { virtual void f(); }; +/// struct D : B, C { }; +/// \endcode +/// +/// Unlike in the previous example, where the virtual functions \c +/// B::f and \c C::f both overrode \c A::f in the same subobject of +/// type \c A, in this example the two virtual functions both override +/// \c A::f but in *different* subobjects of type A. This is +/// represented by numbering the subobjects in which the overridden +/// and the overriding virtual member functions are located. Subobject +/// 0 represents the virtual base class subobject of that type, while +/// subobject numbers greater than 0 refer to non-virtual base class +/// subobjects of that type. +class CXXFinalOverriderMap + : public llvm::MapVector<const CXXMethodDecl *, OverridingMethods> { }; + +/// \brief A set of all the primary bases for a class. +class CXXIndirectPrimaryBaseSet + : public llvm::SmallSet<const CXXRecordDecl*, 32> { }; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/CanonicalType.h b/contrib/llvm/tools/clang/include/clang/AST/CanonicalType.h new file mode 100644 index 0000000..b25800b --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/CanonicalType.h @@ -0,0 +1,665 @@ +//===-- CanonicalType.h - C Language Family Type Representation -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the CanQual class template, which provides access to +// canonical types. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_CANONICALTYPE_H +#define LLVM_CLANG_AST_CANONICALTYPE_H + +#include "clang/AST/Type.h" +#include "llvm/ADT/iterator.h" +#include "llvm/Support/Casting.h" + +namespace clang { + +template<typename T> class CanProxy; +template<typename T> struct CanProxyAdaptor; + +//----------------------------------------------------------------------------// +// Canonical, qualified type template +//----------------------------------------------------------------------------// + +/// \brief Represents a canonical, potentially-qualified type. +/// +/// The CanQual template is a lightweight smart pointer that provides access +/// to the canonical representation of a type, where all typedefs and other +/// syntactic sugar has been eliminated. A CanQualType may also have various +/// qualifiers (const, volatile, restrict) attached to it. +/// +/// The template type parameter @p T is one of the Type classes (PointerType, +/// BuiltinType, etc.). The type stored within @c CanQual<T> will be of that +/// type (or some subclass of that type). The typedef @c CanQualType is just +/// a shorthand for @c CanQual<Type>. +/// +/// An instance of @c CanQual<T> can be implicitly converted to a +/// @c CanQual<U> when T is derived from U, which essentially provides an +/// implicit upcast. For example, @c CanQual<LValueReferenceType> can be +/// converted to @c CanQual<ReferenceType>. Note that any @c CanQual type can +/// be implicitly converted to a QualType, but the reverse operation requires +/// a call to ASTContext::getCanonicalType(). +/// +/// +template<typename T = Type> +class CanQual { + /// \brief The actual, canonical type. + QualType Stored; + +public: + /// \brief Constructs a NULL canonical type. + CanQual() : Stored() { } + + /// \brief Converting constructor that permits implicit upcasting of + /// canonical type pointers. + template <typename U> + CanQual(const CanQual<U> &Other, + typename std::enable_if<std::is_base_of<T, U>::value, int>::type = 0); + + /// \brief Retrieve the underlying type pointer, which refers to a + /// canonical type. + /// + /// The underlying pointer must not be NULL. + const T *getTypePtr() const { return cast<T>(Stored.getTypePtr()); } + + /// \brief Retrieve the underlying type pointer, which refers to a + /// canonical type, or NULL. + /// + const T *getTypePtrOrNull() const { + return cast_or_null<T>(Stored.getTypePtrOrNull()); + } + + /// \brief Implicit conversion to a qualified type. + operator QualType() const { return Stored; } + + /// \brief Implicit conversion to bool. + explicit operator bool() const { return !isNull(); } + + bool isNull() const { + return Stored.isNull(); + } + + SplitQualType split() const { return Stored.split(); } + + /// \brief Retrieve a canonical type pointer with a different static type, + /// upcasting or downcasting as needed. + /// + /// The getAs() function is typically used to try to downcast to a + /// more specific (canonical) type in the type system. For example: + /// + /// @code + /// void f(CanQual<Type> T) { + /// if (CanQual<PointerType> Ptr = T->getAs<PointerType>()) { + /// // look at Ptr's pointee type + /// } + /// } + /// @endcode + /// + /// \returns A proxy pointer to the same type, but with the specified + /// static type (@p U). If the dynamic type is not the specified static type + /// or a derived class thereof, a NULL canonical type. + template<typename U> CanProxy<U> getAs() const; + + template<typename U> CanProxy<U> castAs() const; + + /// \brief Overloaded arrow operator that produces a canonical type + /// proxy. + CanProxy<T> operator->() const; + + /// \brief Retrieve all qualifiers. + Qualifiers getQualifiers() const { return Stored.getLocalQualifiers(); } + + /// \brief Retrieve the const/volatile/restrict qualifiers. + unsigned getCVRQualifiers() const { return Stored.getLocalCVRQualifiers(); } + + /// \brief Determines whether this type has any qualifiers + bool hasQualifiers() const { return Stored.hasLocalQualifiers(); } + + bool isConstQualified() const { + return Stored.isLocalConstQualified(); + } + bool isVolatileQualified() const { + return Stored.isLocalVolatileQualified(); + } + bool isRestrictQualified() const { + return Stored.isLocalRestrictQualified(); + } + + /// \brief Determines if this canonical type is furthermore + /// canonical as a parameter. The parameter-canonicalization + /// process decays arrays to pointers and drops top-level qualifiers. + bool isCanonicalAsParam() const { + return Stored.isCanonicalAsParam(); + } + + /// \brief Retrieve the unqualified form of this type. + CanQual<T> getUnqualifiedType() const; + + /// \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 + /// the @p Other canonical type. + bool isMoreQualifiedThan(CanQual<T> Other) const { + return Stored.isMoreQualifiedThan(Other.Stored); + } + + /// \brief Determines whether this canonical type is at least as qualified as + /// the @p Other canonical type. + bool isAtLeastAsQualifiedAs(CanQual<T> Other) const { + return Stored.isAtLeastAsQualifiedAs(Other.Stored); + } + + /// \brief If the canonical type is a reference type, returns the type that + /// it refers to; otherwise, returns the type itself. + CanQual<Type> getNonReferenceType() const; + + /// \brief Retrieve the internal representation of this canonical type. + void *getAsOpaquePtr() const { return Stored.getAsOpaquePtr(); } + + /// \brief Construct a canonical type from its internal representation. + static CanQual<T> getFromOpaquePtr(void *Ptr); + + /// \brief Builds a canonical type from a QualType. + /// + /// This routine is inherently unsafe, because it requires the user to + /// ensure that the given type is a canonical type with the correct + // (dynamic) type. + static CanQual<T> CreateUnsafe(QualType Other); + + void dump() const { Stored.dump(); } + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddPointer(getAsOpaquePtr()); + } +}; + +template<typename T, typename U> +inline bool operator==(CanQual<T> x, CanQual<U> y) { + return x.getAsOpaquePtr() == y.getAsOpaquePtr(); +} + +template<typename T, typename U> +inline bool operator!=(CanQual<T> x, CanQual<U> y) { + return x.getAsOpaquePtr() != y.getAsOpaquePtr(); +} + +/// \brief Represents a canonical, potentially-qualified type. +typedef CanQual<Type> CanQualType; + +inline CanQualType Type::getCanonicalTypeUnqualified() const { + return CanQualType::CreateUnsafe(getCanonicalTypeInternal()); +} + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + CanQualType T) { + DB << static_cast<QualType>(T); + return DB; +} + +//----------------------------------------------------------------------------// +// Internal proxy classes used by canonical types +//----------------------------------------------------------------------------// + +#define LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(Accessor) \ +CanQualType Accessor() const { \ +return CanQualType::CreateUnsafe(this->getTypePtr()->Accessor()); \ +} + +#define LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Type, Accessor) \ +Type Accessor() const { return this->getTypePtr()->Accessor(); } + +/// \brief Base class of all canonical proxy types, which is responsible for +/// storing the underlying canonical type and providing basic conversions. +template<typename T> +class CanProxyBase { +protected: + CanQual<T> Stored; + +public: + /// \brief Retrieve the pointer to the underlying Type + const T *getTypePtr() const { return Stored.getTypePtr(); } + + /// \brief Implicit conversion to the underlying pointer. + /// + /// Also provides the ability to use canonical type proxies in a Boolean + // context,e.g., + /// @code + /// if (CanQual<PointerType> Ptr = T->getAs<PointerType>()) { ... } + /// @endcode + operator const T*() const { return this->Stored.getTypePtrOrNull(); } + + /// \brief Try to convert the given canonical type to a specific structural + /// type. + template<typename U> CanProxy<U> getAs() const { + return this->Stored.template getAs<U>(); + } + + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Type::TypeClass, getTypeClass) + + // Type predicates + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjectType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIncompleteType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIncompleteOrObjectType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVariablyModifiedType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIntegerType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isEnumeralType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBooleanType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isCharType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isWideCharType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIntegralType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIntegralOrEnumerationType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isRealFloatingType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isComplexType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isAnyComplexType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isFloatingType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isRealType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isArithmeticType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVoidType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isDerivedType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isScalarType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isAggregateType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isAnyPointerType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVoidPointerType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isFunctionPointerType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isMemberFunctionPointerType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isClassType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isStructureType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isInterfaceType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isStructureOrClassType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isUnionType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isComplexIntegerType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isNullPtrType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isDependentType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isOverloadableType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isArrayType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasPointerRepresentation) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasObjCPointerRepresentation) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasIntegerRepresentation) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasSignedIntegerRepresentation) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasUnsignedIntegerRepresentation) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasFloatingRepresentation) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isPromotableIntegerType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isSignedIntegerType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isUnsignedIntegerType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isSignedIntegerOrEnumerationType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isUnsignedIntegerOrEnumerationType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isConstantSizeType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isSpecifierType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(CXXRecordDecl*, getAsCXXRecordDecl) + + /// \brief Retrieve the proxy-adaptor type. + /// + /// This arrow operator is used when CanProxyAdaptor has been specialized + /// for the given type T. In that case, we reference members of the + /// CanProxyAdaptor specialization. Otherwise, this operator will be hidden + /// by the arrow operator in the primary CanProxyAdaptor template. + const CanProxyAdaptor<T> *operator->() const { + return static_cast<const CanProxyAdaptor<T> *>(this); + } +}; + +/// \brief Replacable canonical proxy adaptor class that provides the link +/// between a canonical type and the accessors of the type. +/// +/// The CanProxyAdaptor is a replaceable class template that is instantiated +/// as part of each canonical proxy type. The primary template merely provides +/// redirection to the underlying type (T), e.g., @c PointerType. One can +/// provide specializations of this class template for each underlying type +/// that provide accessors returning canonical types (@c CanQualType) rather +/// than the more typical @c QualType, to propagate the notion of "canonical" +/// through the system. +template<typename T> +struct CanProxyAdaptor : CanProxyBase<T> { }; + +/// \brief Canonical proxy type returned when retrieving the members of a +/// canonical type or as the result of the @c CanQual<T>::getAs member +/// function. +/// +/// The CanProxy type mainly exists as a proxy through which operator-> will +/// look to either map down to a raw T* (e.g., PointerType*) or to a proxy +/// type that provides canonical-type access to the fields of the type. +template<typename T> +class CanProxy : public CanProxyAdaptor<T> { +public: + /// \brief Build a NULL proxy. + CanProxy() { } + + /// \brief Build a proxy to the given canonical type. + CanProxy(CanQual<T> Stored) { this->Stored = Stored; } + + /// \brief Implicit conversion to the stored canonical type. + operator CanQual<T>() const { return this->Stored; } +}; + +} // end namespace clang + +namespace llvm { + +/// Implement simplify_type for CanQual<T>, so that we can dyn_cast from +/// CanQual<T> to a specific Type class. We're prefer isa/dyn_cast/cast/etc. +/// to return smart pointer (proxies?). +template<typename T> +struct simplify_type< ::clang::CanQual<T> > { + typedef const T *SimpleType; + static SimpleType getSimplifiedValue(::clang::CanQual<T> Val) { + return Val.getTypePtr(); + } +}; + +// Teach SmallPtrSet that CanQual<T> is "basically a pointer". +template<typename T> +class PointerLikeTypeTraits<clang::CanQual<T> > { +public: + static inline void *getAsVoidPointer(clang::CanQual<T> P) { + return P.getAsOpaquePtr(); + } + static inline clang::CanQual<T> getFromVoidPointer(void *P) { + return clang::CanQual<T>::getFromOpaquePtr(P); + } + // qualifier information is encoded in the low bits. + enum { NumLowBitsAvailable = 0 }; +}; + +} // end namespace llvm + +namespace clang { + +//----------------------------------------------------------------------------// +// Canonical proxy adaptors for canonical type nodes. +//----------------------------------------------------------------------------// + +/// \brief Iterator adaptor that turns an iterator over canonical QualTypes +/// into an iterator over CanQualTypes. +template <typename InputIterator> +struct CanTypeIterator + : llvm::iterator_adaptor_base< + CanTypeIterator<InputIterator>, InputIterator, + typename std::iterator_traits<InputIterator>::iterator_category, + CanQualType, + typename std::iterator_traits<InputIterator>::difference_type, + CanProxy<Type>, CanQualType> { + CanTypeIterator() {} + explicit CanTypeIterator(InputIterator Iter) + : CanTypeIterator::iterator_adaptor_base(std::move(Iter)) {} + + CanQualType operator*() const { return CanQualType::CreateUnsafe(*this->I); } + CanProxy<Type> operator->() const; +}; + +template<> +struct CanProxyAdaptor<ComplexType> : public CanProxyBase<ComplexType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) +}; + +template<> +struct CanProxyAdaptor<PointerType> : public CanProxyBase<PointerType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) +}; + +template<> +struct CanProxyAdaptor<BlockPointerType> + : public CanProxyBase<BlockPointerType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) +}; + +template<> +struct CanProxyAdaptor<ReferenceType> : public CanProxyBase<ReferenceType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) +}; + +template<> +struct CanProxyAdaptor<LValueReferenceType> + : public CanProxyBase<LValueReferenceType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) +}; + +template<> +struct CanProxyAdaptor<RValueReferenceType> + : public CanProxyBase<RValueReferenceType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) +}; + +template<> +struct CanProxyAdaptor<MemberPointerType> + : public CanProxyBase<MemberPointerType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const Type *, getClass) +}; + +// CanProxyAdaptors for arrays are intentionally unimplemented because +// they are not safe. +template<> struct CanProxyAdaptor<ArrayType>; +template<> struct CanProxyAdaptor<ConstantArrayType>; +template<> struct CanProxyAdaptor<IncompleteArrayType>; +template<> struct CanProxyAdaptor<VariableArrayType>; +template<> struct CanProxyAdaptor<DependentSizedArrayType>; + +template<> +struct CanProxyAdaptor<DependentSizedExtVectorType> + : public CanProxyBase<DependentSizedExtVectorType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const Expr *, getSizeExpr) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getAttributeLoc) +}; + +template<> +struct CanProxyAdaptor<VectorType> : public CanProxyBase<VectorType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumElements) +}; + +template<> +struct CanProxyAdaptor<ExtVectorType> : public CanProxyBase<ExtVectorType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumElements) +}; + +template<> +struct CanProxyAdaptor<FunctionType> : public CanProxyBase<FunctionType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getReturnType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(FunctionType::ExtInfo, getExtInfo) +}; + +template<> +struct CanProxyAdaptor<FunctionNoProtoType> + : public CanProxyBase<FunctionNoProtoType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getReturnType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(FunctionType::ExtInfo, getExtInfo) +}; + +template<> +struct CanProxyAdaptor<FunctionProtoType> + : public CanProxyBase<FunctionProtoType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getReturnType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(FunctionType::ExtInfo, getExtInfo) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumParams) + CanQualType getParamType(unsigned i) const { + return CanQualType::CreateUnsafe(this->getTypePtr()->getParamType(i)); + } + + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVariadic) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getTypeQuals) + + typedef CanTypeIterator<FunctionProtoType::param_type_iterator> + param_type_iterator; + + param_type_iterator param_type_begin() const { + return param_type_iterator(this->getTypePtr()->param_type_begin()); + } + + param_type_iterator param_type_end() const { + return param_type_iterator(this->getTypePtr()->param_type_end()); + } + + // Note: canonical function types never have exception specifications +}; + +template<> +struct CanProxyAdaptor<TypeOfType> : public CanProxyBase<TypeOfType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getUnderlyingType) +}; + +template<> +struct CanProxyAdaptor<DecltypeType> : public CanProxyBase<DecltypeType> { + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Expr *, getUnderlyingExpr) + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getUnderlyingType) +}; + +template <> +struct CanProxyAdaptor<UnaryTransformType> + : public CanProxyBase<UnaryTransformType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getBaseType) + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getUnderlyingType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(UnaryTransformType::UTTKind, getUTTKind) +}; + +template<> +struct CanProxyAdaptor<TagType> : public CanProxyBase<TagType> { + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(TagDecl *, getDecl) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined) +}; + +template<> +struct CanProxyAdaptor<RecordType> : public CanProxyBase<RecordType> { + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(RecordDecl *, getDecl) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasConstFields) +}; + +template<> +struct CanProxyAdaptor<EnumType> : public CanProxyBase<EnumType> { + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(EnumDecl *, getDecl) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined) +}; + +template<> +struct CanProxyAdaptor<TemplateTypeParmType> + : public CanProxyBase<TemplateTypeParmType> { + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getDepth) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getIndex) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isParameterPack) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(TemplateTypeParmDecl *, getDecl) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(IdentifierInfo *, getIdentifier) +}; + +template<> +struct CanProxyAdaptor<ObjCObjectType> + : public CanProxyBase<ObjCObjectType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getBaseType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const ObjCInterfaceDecl *, + getInterface) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCUnqualifiedId) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCUnqualifiedClass) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCQualifiedId) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCQualifiedClass) + + typedef ObjCObjectPointerType::qual_iterator qual_iterator; + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(qual_iterator, qual_begin) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(qual_iterator, qual_end) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, qual_empty) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumProtocols) +}; + +template<> +struct CanProxyAdaptor<ObjCObjectPointerType> + : public CanProxyBase<ObjCObjectPointerType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const ObjCInterfaceType *, + getInterfaceType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCIdType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCClassType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCQualifiedIdType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCQualifiedClassType) + + typedef ObjCObjectPointerType::qual_iterator qual_iterator; + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(qual_iterator, qual_begin) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(qual_iterator, qual_end) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, qual_empty) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumProtocols) +}; + +//----------------------------------------------------------------------------// +// Method and function definitions +//----------------------------------------------------------------------------// +template<typename T> +inline CanQual<T> CanQual<T>::getUnqualifiedType() const { + return CanQual<T>::CreateUnsafe(Stored.getLocalUnqualifiedType()); +} + +template<typename T> +inline CanQual<Type> CanQual<T>::getNonReferenceType() const { + if (CanQual<ReferenceType> RefType = getAs<ReferenceType>()) + return RefType->getPointeeType(); + else + return *this; +} + +template<typename T> +CanQual<T> CanQual<T>::getFromOpaquePtr(void *Ptr) { + CanQual<T> Result; + Result.Stored = QualType::getFromOpaquePtr(Ptr); + assert((!Result || Result.Stored.getAsOpaquePtr() == (void*)-1 || + Result.Stored.isCanonical()) && "Type is not canonical!"); + return Result; +} + +template<typename T> +CanQual<T> CanQual<T>::CreateUnsafe(QualType Other) { + assert((Other.isNull() || Other.isCanonical()) && "Type is not canonical!"); + assert((Other.isNull() || isa<T>(Other.getTypePtr())) && + "Dynamic type does not meet the static type's requires"); + CanQual<T> Result; + Result.Stored = Other; + return Result; +} + +template<typename T> +template<typename U> +CanProxy<U> CanQual<T>::getAs() const { + ArrayType_cannot_be_used_with_getAs<U> at; + (void)at; + + if (Stored.isNull()) + return CanProxy<U>(); + + if (isa<U>(Stored.getTypePtr())) + return CanQual<U>::CreateUnsafe(Stored); + + return CanProxy<U>(); +} + +template<typename T> +template<typename U> +CanProxy<U> CanQual<T>::castAs() const { + ArrayType_cannot_be_used_with_getAs<U> at; + (void)at; + + assert(!Stored.isNull() && isa<U>(Stored.getTypePtr())); + return CanQual<U>::CreateUnsafe(Stored); +} + +template<typename T> +CanProxy<T> CanQual<T>::operator->() const { + return CanProxy<T>(*this); +} + +template <typename InputIterator> +CanProxy<Type> CanTypeIterator<InputIterator>::operator->() const { + return CanProxy<Type>(*this); +} + +} + + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/CharUnits.h b/contrib/llvm/tools/clang/include/clang/AST/CharUnits.h new file mode 100644 index 0000000..1d22bcc --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/CharUnits.h @@ -0,0 +1,240 @@ +//===--- CharUnits.h - Character units for sizes and offsets ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the CharUnits class +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_CHARUNITS_H +#define LLVM_CLANG_AST_CHARUNITS_H + +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/MathExtras.h" + +namespace clang { + + /// CharUnits - This is an opaque type for sizes expressed in character units. + /// Instances of this type represent a quantity as a multiple of the size + /// of the standard C type, char, on the target architecture. As an opaque + /// type, CharUnits protects you from accidentally combining operations on + /// quantities in bit units and character units. + /// + /// In both C and C++, an object of type 'char', 'signed char', or 'unsigned + /// char' occupies exactly one byte, so 'character unit' and 'byte' refer to + /// the same quantity of storage. However, we use the term 'character unit' + /// rather than 'byte' to avoid an implication that a character unit is + /// exactly 8 bits. + /// + /// For portability, never assume that a target character is 8 bits wide. Use + /// CharUnit values wherever you calculate sizes, offsets, or alignments + /// in character units. + class CharUnits { + public: + typedef int64_t QuantityType; + + private: + QuantityType Quantity; + + explicit CharUnits(QuantityType C) : Quantity(C) {} + + public: + + /// CharUnits - A default constructor. + CharUnits() : Quantity(0) {} + + /// Zero - Construct a CharUnits quantity of zero. + static CharUnits Zero() { + return CharUnits(0); + } + + /// One - Construct a CharUnits quantity of one. + static CharUnits One() { + return CharUnits(1); + } + + /// fromQuantity - Construct a CharUnits quantity from a raw integer type. + static CharUnits fromQuantity(QuantityType Quantity) { + return CharUnits(Quantity); + } + + // Compound assignment. + CharUnits& operator+= (const CharUnits &Other) { + Quantity += Other.Quantity; + return *this; + } + CharUnits& operator++ () { + ++Quantity; + return *this; + } + CharUnits operator++ (int) { + return CharUnits(Quantity++); + } + CharUnits& operator-= (const CharUnits &Other) { + Quantity -= Other.Quantity; + return *this; + } + CharUnits& operator-- () { + --Quantity; + return *this; + } + CharUnits operator-- (int) { + return CharUnits(Quantity--); + } + + // Comparison operators. + bool operator== (const CharUnits &Other) const { + return Quantity == Other.Quantity; + } + bool operator!= (const CharUnits &Other) const { + return Quantity != Other.Quantity; + } + + // Relational operators. + bool operator< (const CharUnits &Other) const { + return Quantity < Other.Quantity; + } + bool operator<= (const CharUnits &Other) const { + return Quantity <= Other.Quantity; + } + bool operator> (const CharUnits &Other) const { + return Quantity > Other.Quantity; + } + bool operator>= (const CharUnits &Other) const { + return Quantity >= Other.Quantity; + } + + // Other predicates. + + /// isZero - Test whether the quantity equals zero. + bool isZero() const { return Quantity == 0; } + + /// isOne - Test whether the quantity equals one. + bool isOne() const { return Quantity == 1; } + + /// isPositive - Test whether the quantity is greater than zero. + bool isPositive() const { return Quantity > 0; } + + /// isNegative - Test whether the quantity is less than zero. + bool isNegative() const { return Quantity < 0; } + + /// isPowerOfTwo - Test whether the quantity is a power of two. + /// Zero is not a power of two. + bool isPowerOfTwo() const { + return (Quantity & -Quantity) == Quantity; + } + + /// Test whether this is a multiple of the other value. + /// + /// Among other things, this promises that + /// self.RoundUpToAlignment(N) will just return self. + bool isMultipleOf(CharUnits N) const { + return (*this % N) == 0; + } + + // Arithmetic operators. + CharUnits operator* (QuantityType N) const { + return CharUnits(Quantity * N); + } + CharUnits operator/ (QuantityType N) const { + return CharUnits(Quantity / N); + } + QuantityType operator/ (const CharUnits &Other) const { + return Quantity / Other.Quantity; + } + CharUnits operator% (QuantityType N) const { + return CharUnits(Quantity % N); + } + QuantityType operator% (const CharUnits &Other) const { + return Quantity % Other.Quantity; + } + CharUnits operator+ (const CharUnits &Other) const { + return CharUnits(Quantity + Other.Quantity); + } + CharUnits operator- (const CharUnits &Other) const { + return CharUnits(Quantity - Other.Quantity); + } + CharUnits operator- () const { + return CharUnits(-Quantity); + } + + + // Conversions. + + /// getQuantity - Get the raw integer representation of this quantity. + QuantityType getQuantity() const { return Quantity; } + + /// RoundUpToAlignment - Returns the next integer (mod 2**64) that is + /// greater than or equal to this quantity and is a multiple of \p Align. + /// Align must be non-zero. + CharUnits RoundUpToAlignment(const CharUnits &Align) const { + return CharUnits(llvm::RoundUpToAlignment(Quantity, + Align.Quantity)); + } + + /// Given that this is a non-zero alignment value, what is the + /// alignment at the given offset? + CharUnits alignmentAtOffset(CharUnits offset) const { + assert(Quantity != 0 && "offsetting from unknown alignment?"); + return CharUnits(llvm::MinAlign(Quantity, offset.Quantity)); + } + + /// Given that this is the alignment of the first element of an + /// array, return the minimum alignment of any element in the array. + CharUnits alignmentOfArrayElement(CharUnits elementSize) const { + // Since we don't track offsetted alignments, the alignment of + // the second element (or any odd element) will be minimally + // aligned. + return alignmentAtOffset(elementSize); + } + + + }; // class CharUnit +} // namespace clang + +inline clang::CharUnits operator* (clang::CharUnits::QuantityType Scale, + const clang::CharUnits &CU) { + return CU * Scale; +} + +namespace llvm { + +template<> struct DenseMapInfo<clang::CharUnits> { + static clang::CharUnits getEmptyKey() { + clang::CharUnits::QuantityType Quantity = + DenseMapInfo<clang::CharUnits::QuantityType>::getEmptyKey(); + + return clang::CharUnits::fromQuantity(Quantity); + } + + static clang::CharUnits getTombstoneKey() { + clang::CharUnits::QuantityType Quantity = + DenseMapInfo<clang::CharUnits::QuantityType>::getTombstoneKey(); + + return clang::CharUnits::fromQuantity(Quantity); + } + + static unsigned getHashValue(const clang::CharUnits &CU) { + clang::CharUnits::QuantityType Quantity = CU.getQuantity(); + return DenseMapInfo<clang::CharUnits::QuantityType>::getHashValue(Quantity); + } + + static bool isEqual(const clang::CharUnits &LHS, + const clang::CharUnits &RHS) { + return LHS == RHS; + } +}; + +template <> struct isPodLike<clang::CharUnits> { + static const bool value = true; +}; + +} // end namespace llvm + +#endif // LLVM_CLANG_AST_CHARUNITS_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/Comment.h b/contrib/llvm/tools/clang/include/clang/AST/Comment.h new file mode 100644 index 0000000..94470cb --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/Comment.h @@ -0,0 +1,1142 @@ +//===--- Comment.h - Comment AST nodes --------------------------*- 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 comment AST nodes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_COMMENT_H +#define LLVM_CLANG_AST_COMMENT_H + +#include "clang/AST/CommentCommandTraits.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/Type.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { +class Decl; +class ParmVarDecl; +class TemplateParameterList; + +namespace comments { +class FullComment; + +/// Describes the syntax that was used in a documentation command. +/// +/// Exact values of this enumeration are important because they used to select +/// parts of diagnostic messages. Audit diagnostics before changing or adding +/// a new value. +enum CommandMarkerKind { + /// Command started with a backslash character: + /// \code + /// \foo + /// \endcode + CMK_Backslash = 0, + + /// Command started with an 'at' character: + /// \code + /// @foo + /// \endcode + CMK_At = 1 +}; + +/// Any part of the comment. +/// Abstract class. +class Comment { +protected: + /// Preferred location to show caret. + SourceLocation Loc; + + /// Source range of this AST node. + SourceRange Range; + + class CommentBitfields { + friend class Comment; + + /// Type of this AST node. + unsigned Kind : 8; + }; + enum { NumCommentBits = 8 }; + + class InlineContentCommentBitfields { + friend class InlineContentComment; + + unsigned : NumCommentBits; + + /// True if there is a newline after this inline content node. + /// (There is no separate AST node for a newline.) + unsigned HasTrailingNewline : 1; + }; + enum { NumInlineContentCommentBits = NumCommentBits + 1 }; + + class TextCommentBitfields { + friend class TextComment; + + unsigned : NumInlineContentCommentBits; + + /// True if \c IsWhitespace field contains a valid value. + mutable unsigned IsWhitespaceValid : 1; + + /// True if this comment AST node contains only whitespace. + mutable unsigned IsWhitespace : 1; + }; + enum { NumTextCommentBits = NumInlineContentCommentBits + 2 }; + + class InlineCommandCommentBitfields { + friend class InlineCommandComment; + + unsigned : NumInlineContentCommentBits; + + unsigned RenderKind : 2; + unsigned CommandID : CommandInfo::NumCommandIDBits; + }; + enum { NumInlineCommandCommentBits = NumInlineContentCommentBits + 2 + + CommandInfo::NumCommandIDBits }; + + class HTMLTagCommentBitfields { + friend class HTMLTagComment; + + unsigned : NumInlineContentCommentBits; + + /// True if we found that this tag is malformed in some way. + unsigned IsMalformed : 1; + }; + enum { NumHTMLTagCommentBits = NumInlineContentCommentBits + 1 }; + + class HTMLStartTagCommentBitfields { + friend class HTMLStartTagComment; + + unsigned : NumHTMLTagCommentBits; + + /// True if this tag is self-closing (e. g., <br />). This is based on tag + /// spelling in comment (plain <br> would not set this flag). + unsigned IsSelfClosing : 1; + }; + enum { NumHTMLStartTagCommentBits = NumHTMLTagCommentBits + 1 }; + + class ParagraphCommentBitfields { + friend class ParagraphComment; + + unsigned : NumCommentBits; + + /// True if \c IsWhitespace field contains a valid value. + mutable unsigned IsWhitespaceValid : 1; + + /// True if this comment AST node contains only whitespace. + mutable unsigned IsWhitespace : 1; + }; + enum { NumParagraphCommentBits = NumCommentBits + 2 }; + + class BlockCommandCommentBitfields { + friend class BlockCommandComment; + + unsigned : NumCommentBits; + + unsigned CommandID : CommandInfo::NumCommandIDBits; + + /// Describes the syntax that was used in a documentation command. + /// Contains values from CommandMarkerKind enum. + unsigned CommandMarker : 1; + }; + enum { NumBlockCommandCommentBits = NumCommentBits + + CommandInfo::NumCommandIDBits + 1 }; + + class ParamCommandCommentBitfields { + friend class ParamCommandComment; + + unsigned : NumBlockCommandCommentBits; + + /// Parameter passing direction, see ParamCommandComment::PassDirection. + unsigned Direction : 2; + + /// True if direction was specified explicitly in the comment. + unsigned IsDirectionExplicit : 1; + }; + enum { NumParamCommandCommentBits = NumBlockCommandCommentBits + 3 }; + + union { + CommentBitfields CommentBits; + InlineContentCommentBitfields InlineContentCommentBits; + TextCommentBitfields TextCommentBits; + InlineCommandCommentBitfields InlineCommandCommentBits; + HTMLTagCommentBitfields HTMLTagCommentBits; + HTMLStartTagCommentBitfields HTMLStartTagCommentBits; + ParagraphCommentBitfields ParagraphCommentBits; + BlockCommandCommentBitfields BlockCommandCommentBits; + ParamCommandCommentBitfields ParamCommandCommentBits; + }; + + void setSourceRange(SourceRange SR) { + Range = SR; + } + + void setLocation(SourceLocation L) { + Loc = L; + } + +public: + enum CommentKind { + NoCommentKind = 0, +#define COMMENT(CLASS, PARENT) CLASS##Kind, +#define COMMENT_RANGE(BASE, FIRST, LAST) \ + First##BASE##Constant=FIRST##Kind, Last##BASE##Constant=LAST##Kind, +#define LAST_COMMENT_RANGE(BASE, FIRST, LAST) \ + First##BASE##Constant=FIRST##Kind, Last##BASE##Constant=LAST##Kind +#define ABSTRACT_COMMENT(COMMENT) +#include "clang/AST/CommentNodes.inc" + }; + + Comment(CommentKind K, + SourceLocation LocBegin, + SourceLocation LocEnd) : + Loc(LocBegin), Range(SourceRange(LocBegin, LocEnd)) { + CommentBits.Kind = K; + } + + CommentKind getCommentKind() const { + return static_cast<CommentKind>(CommentBits.Kind); + } + + const char *getCommentKindName() const; + + void dump() const; + void dumpColor() const; + void dump(const ASTContext &Context) const; + void dump(raw_ostream &OS, const CommandTraits *Traits, + const SourceManager *SM) const; + + SourceRange getSourceRange() const LLVM_READONLY { return Range; } + + SourceLocation getLocStart() const LLVM_READONLY { + return Range.getBegin(); + } + + SourceLocation getLocEnd() const LLVM_READONLY { + return Range.getEnd(); + } + + SourceLocation getLocation() const LLVM_READONLY { return Loc; } + + typedef Comment * const *child_iterator; + + child_iterator child_begin() const; + child_iterator child_end() const; + + // TODO: const child iterator + + unsigned child_count() const { + return child_end() - child_begin(); + } +}; + +/// Inline content (contained within a block). +/// Abstract class. +class InlineContentComment : public Comment { +protected: + InlineContentComment(CommentKind K, + SourceLocation LocBegin, + SourceLocation LocEnd) : + Comment(K, LocBegin, LocEnd) { + InlineContentCommentBits.HasTrailingNewline = 0; + } + +public: + static bool classof(const Comment *C) { + return C->getCommentKind() >= FirstInlineContentCommentConstant && + C->getCommentKind() <= LastInlineContentCommentConstant; + } + + void addTrailingNewline() { + InlineContentCommentBits.HasTrailingNewline = 1; + } + + bool hasTrailingNewline() const { + return InlineContentCommentBits.HasTrailingNewline; + } +}; + +/// Plain text. +class TextComment : public InlineContentComment { + StringRef Text; + +public: + TextComment(SourceLocation LocBegin, + SourceLocation LocEnd, + StringRef Text) : + InlineContentComment(TextCommentKind, LocBegin, LocEnd), + Text(Text) { + TextCommentBits.IsWhitespaceValid = false; + } + + static bool classof(const Comment *C) { + return C->getCommentKind() == TextCommentKind; + } + + child_iterator child_begin() const { return nullptr; } + + child_iterator child_end() const { return nullptr; } + + StringRef getText() const LLVM_READONLY { return Text; } + + bool isWhitespace() const { + if (TextCommentBits.IsWhitespaceValid) + return TextCommentBits.IsWhitespace; + + TextCommentBits.IsWhitespace = isWhitespaceNoCache(); + TextCommentBits.IsWhitespaceValid = true; + return TextCommentBits.IsWhitespace; + } + +private: + bool isWhitespaceNoCache() const; +}; + +/// A command with word-like arguments that is considered inline content. +class InlineCommandComment : public InlineContentComment { +public: + struct Argument { + SourceRange Range; + StringRef Text; + + Argument(SourceRange Range, StringRef Text) : Range(Range), Text(Text) { } + }; + + /// The most appropriate rendering mode for this command, chosen on command + /// semantics in Doxygen. + enum RenderKind { + RenderNormal, + RenderBold, + RenderMonospaced, + RenderEmphasized + }; + +protected: + /// Command arguments. + ArrayRef<Argument> Args; + +public: + InlineCommandComment(SourceLocation LocBegin, + SourceLocation LocEnd, + unsigned CommandID, + RenderKind RK, + ArrayRef<Argument> Args) : + InlineContentComment(InlineCommandCommentKind, LocBegin, LocEnd), + Args(Args) { + InlineCommandCommentBits.RenderKind = RK; + InlineCommandCommentBits.CommandID = CommandID; + } + + static bool classof(const Comment *C) { + return C->getCommentKind() == InlineCommandCommentKind; + } + + child_iterator child_begin() const { return nullptr; } + + child_iterator child_end() const { return nullptr; } + + unsigned getCommandID() const { + return InlineCommandCommentBits.CommandID; + } + + StringRef getCommandName(const CommandTraits &Traits) const { + return Traits.getCommandInfo(getCommandID())->Name; + } + + SourceRange getCommandNameRange() const { + return SourceRange(getLocStart().getLocWithOffset(-1), + getLocEnd()); + } + + RenderKind getRenderKind() const { + return static_cast<RenderKind>(InlineCommandCommentBits.RenderKind); + } + + unsigned getNumArgs() const { + return Args.size(); + } + + StringRef getArgText(unsigned Idx) const { + return Args[Idx].Text; + } + + SourceRange getArgRange(unsigned Idx) const { + return Args[Idx].Range; + } +}; + +/// Abstract class for opening and closing HTML tags. HTML tags are always +/// treated as inline content (regardless HTML semantics). +class HTMLTagComment : public InlineContentComment { +protected: + StringRef TagName; + SourceRange TagNameRange; + + HTMLTagComment(CommentKind K, + SourceLocation LocBegin, + SourceLocation LocEnd, + StringRef TagName, + SourceLocation TagNameBegin, + SourceLocation TagNameEnd) : + InlineContentComment(K, LocBegin, LocEnd), + TagName(TagName), + TagNameRange(TagNameBegin, TagNameEnd) { + setLocation(TagNameBegin); + HTMLTagCommentBits.IsMalformed = 0; + } + +public: + static bool classof(const Comment *C) { + return C->getCommentKind() >= FirstHTMLTagCommentConstant && + C->getCommentKind() <= LastHTMLTagCommentConstant; + } + + StringRef getTagName() const LLVM_READONLY { return TagName; } + + SourceRange getTagNameSourceRange() const LLVM_READONLY { + SourceLocation L = getLocation(); + return SourceRange(L.getLocWithOffset(1), + L.getLocWithOffset(1 + TagName.size())); + } + + bool isMalformed() const { + return HTMLTagCommentBits.IsMalformed; + } + + void setIsMalformed() { + HTMLTagCommentBits.IsMalformed = 1; + } +}; + +/// An opening HTML tag with attributes. +class HTMLStartTagComment : public HTMLTagComment { +public: + class Attribute { + public: + SourceLocation NameLocBegin; + StringRef Name; + + SourceLocation EqualsLoc; + + SourceRange ValueRange; + StringRef Value; + + Attribute() { } + + Attribute(SourceLocation NameLocBegin, StringRef Name) : + NameLocBegin(NameLocBegin), Name(Name), + EqualsLoc(SourceLocation()), + ValueRange(SourceRange()), Value(StringRef()) + { } + + Attribute(SourceLocation NameLocBegin, StringRef Name, + SourceLocation EqualsLoc, + SourceRange ValueRange, StringRef Value) : + NameLocBegin(NameLocBegin), Name(Name), + EqualsLoc(EqualsLoc), + ValueRange(ValueRange), Value(Value) + { } + + SourceLocation getNameLocEnd() const { + return NameLocBegin.getLocWithOffset(Name.size()); + } + + SourceRange getNameRange() const { + return SourceRange(NameLocBegin, getNameLocEnd()); + } + }; + +private: + ArrayRef<Attribute> Attributes; + +public: + HTMLStartTagComment(SourceLocation LocBegin, + StringRef TagName) : + HTMLTagComment(HTMLStartTagCommentKind, + LocBegin, LocBegin.getLocWithOffset(1 + TagName.size()), + TagName, + LocBegin.getLocWithOffset(1), + LocBegin.getLocWithOffset(1 + TagName.size())) { + HTMLStartTagCommentBits.IsSelfClosing = false; + } + + static bool classof(const Comment *C) { + return C->getCommentKind() == HTMLStartTagCommentKind; + } + + child_iterator child_begin() const { return nullptr; } + + child_iterator child_end() const { return nullptr; } + + unsigned getNumAttrs() const { + return Attributes.size(); + } + + const Attribute &getAttr(unsigned Idx) const { + return Attributes[Idx]; + } + + void setAttrs(ArrayRef<Attribute> Attrs) { + Attributes = Attrs; + if (!Attrs.empty()) { + const Attribute &Attr = Attrs.back(); + SourceLocation L = Attr.ValueRange.getEnd(); + if (L.isValid()) + Range.setEnd(L); + else { + Range.setEnd(Attr.getNameLocEnd()); + } + } + } + + void setGreaterLoc(SourceLocation GreaterLoc) { + Range.setEnd(GreaterLoc); + } + + bool isSelfClosing() const { + return HTMLStartTagCommentBits.IsSelfClosing; + } + + void setSelfClosing() { + HTMLStartTagCommentBits.IsSelfClosing = true; + } +}; + +/// A closing HTML tag. +class HTMLEndTagComment : public HTMLTagComment { +public: + HTMLEndTagComment(SourceLocation LocBegin, + SourceLocation LocEnd, + StringRef TagName) : + HTMLTagComment(HTMLEndTagCommentKind, + LocBegin, LocEnd, + TagName, + LocBegin.getLocWithOffset(2), + LocBegin.getLocWithOffset(2 + TagName.size())) + { } + + static bool classof(const Comment *C) { + return C->getCommentKind() == HTMLEndTagCommentKind; + } + + child_iterator child_begin() const { return nullptr; } + + child_iterator child_end() const { return nullptr; } +}; + +/// Block content (contains inline content). +/// Abstract class. +class BlockContentComment : public Comment { +protected: + BlockContentComment(CommentKind K, + SourceLocation LocBegin, + SourceLocation LocEnd) : + Comment(K, LocBegin, LocEnd) + { } + +public: + static bool classof(const Comment *C) { + return C->getCommentKind() >= FirstBlockContentCommentConstant && + C->getCommentKind() <= LastBlockContentCommentConstant; + } +}; + +/// A single paragraph that contains inline content. +class ParagraphComment : public BlockContentComment { + ArrayRef<InlineContentComment *> Content; + +public: + ParagraphComment(ArrayRef<InlineContentComment *> Content) : + BlockContentComment(ParagraphCommentKind, + SourceLocation(), + SourceLocation()), + Content(Content) { + if (Content.empty()) { + ParagraphCommentBits.IsWhitespace = true; + ParagraphCommentBits.IsWhitespaceValid = true; + return; + } + + ParagraphCommentBits.IsWhitespaceValid = false; + + setSourceRange(SourceRange(Content.front()->getLocStart(), + Content.back()->getLocEnd())); + setLocation(Content.front()->getLocStart()); + } + + static bool classof(const Comment *C) { + return C->getCommentKind() == ParagraphCommentKind; + } + + child_iterator child_begin() const { + return reinterpret_cast<child_iterator>(Content.begin()); + } + + child_iterator child_end() const { + return reinterpret_cast<child_iterator>(Content.end()); + } + + bool isWhitespace() const { + if (ParagraphCommentBits.IsWhitespaceValid) + return ParagraphCommentBits.IsWhitespace; + + ParagraphCommentBits.IsWhitespace = isWhitespaceNoCache(); + ParagraphCommentBits.IsWhitespaceValid = true; + return ParagraphCommentBits.IsWhitespace; + } + +private: + bool isWhitespaceNoCache() const; +}; + +/// A command that has zero or more word-like arguments (number of word-like +/// arguments depends on command name) and a paragraph as an argument +/// (e. g., \\brief). +class BlockCommandComment : public BlockContentComment { +public: + struct Argument { + SourceRange Range; + StringRef Text; + + Argument() { } + Argument(SourceRange Range, StringRef Text) : Range(Range), Text(Text) { } + }; + +protected: + /// Word-like arguments. + ArrayRef<Argument> Args; + + /// Paragraph argument. + ParagraphComment *Paragraph; + + BlockCommandComment(CommentKind K, + SourceLocation LocBegin, + SourceLocation LocEnd, + unsigned CommandID, + CommandMarkerKind CommandMarker) : + BlockContentComment(K, LocBegin, LocEnd), + Paragraph(nullptr) { + setLocation(getCommandNameBeginLoc()); + BlockCommandCommentBits.CommandID = CommandID; + BlockCommandCommentBits.CommandMarker = CommandMarker; + } + +public: + BlockCommandComment(SourceLocation LocBegin, + SourceLocation LocEnd, + unsigned CommandID, + CommandMarkerKind CommandMarker) : + BlockContentComment(BlockCommandCommentKind, LocBegin, LocEnd), + Paragraph(nullptr) { + setLocation(getCommandNameBeginLoc()); + BlockCommandCommentBits.CommandID = CommandID; + BlockCommandCommentBits.CommandMarker = CommandMarker; + } + + static bool classof(const Comment *C) { + return C->getCommentKind() >= FirstBlockCommandCommentConstant && + C->getCommentKind() <= LastBlockCommandCommentConstant; + } + + child_iterator child_begin() const { + return reinterpret_cast<child_iterator>(&Paragraph); + } + + child_iterator child_end() const { + return reinterpret_cast<child_iterator>(&Paragraph + 1); + } + + unsigned getCommandID() const { + return BlockCommandCommentBits.CommandID; + } + + StringRef getCommandName(const CommandTraits &Traits) const { + return Traits.getCommandInfo(getCommandID())->Name; + } + + SourceLocation getCommandNameBeginLoc() const { + return getLocStart().getLocWithOffset(1); + } + + SourceRange getCommandNameRange(const CommandTraits &Traits) const { + StringRef Name = getCommandName(Traits); + return SourceRange(getCommandNameBeginLoc(), + getLocStart().getLocWithOffset(1 + Name.size())); + } + + unsigned getNumArgs() const { + return Args.size(); + } + + StringRef getArgText(unsigned Idx) const { + return Args[Idx].Text; + } + + SourceRange getArgRange(unsigned Idx) const { + return Args[Idx].Range; + } + + void setArgs(ArrayRef<Argument> A) { + Args = A; + if (Args.size() > 0) { + SourceLocation NewLocEnd = Args.back().Range.getEnd(); + if (NewLocEnd.isValid()) + setSourceRange(SourceRange(getLocStart(), NewLocEnd)); + } + } + + ParagraphComment *getParagraph() const LLVM_READONLY { + return Paragraph; + } + + bool hasNonWhitespaceParagraph() const { + return Paragraph && !Paragraph->isWhitespace(); + } + + void setParagraph(ParagraphComment *PC) { + Paragraph = PC; + SourceLocation NewLocEnd = PC->getLocEnd(); + if (NewLocEnd.isValid()) + setSourceRange(SourceRange(getLocStart(), NewLocEnd)); + } + + CommandMarkerKind getCommandMarker() const LLVM_READONLY { + return static_cast<CommandMarkerKind>( + BlockCommandCommentBits.CommandMarker); + } +}; + +/// Doxygen \\param command. +class ParamCommandComment : public BlockCommandComment { +private: + /// Parameter index in the function declaration. + unsigned ParamIndex; + +public: + enum : unsigned { + InvalidParamIndex = ~0U, + VarArgParamIndex = ~0U/*InvalidParamIndex*/ - 1U + }; + + ParamCommandComment(SourceLocation LocBegin, + SourceLocation LocEnd, + unsigned CommandID, + CommandMarkerKind CommandMarker) : + BlockCommandComment(ParamCommandCommentKind, LocBegin, LocEnd, + CommandID, CommandMarker), + ParamIndex(InvalidParamIndex) { + ParamCommandCommentBits.Direction = In; + ParamCommandCommentBits.IsDirectionExplicit = false; + } + + static bool classof(const Comment *C) { + return C->getCommentKind() == ParamCommandCommentKind; + } + + enum PassDirection { + In, + Out, + InOut + }; + + static const char *getDirectionAsString(PassDirection D); + + PassDirection getDirection() const LLVM_READONLY { + return static_cast<PassDirection>(ParamCommandCommentBits.Direction); + } + + bool isDirectionExplicit() const LLVM_READONLY { + return ParamCommandCommentBits.IsDirectionExplicit; + } + + void setDirection(PassDirection Direction, bool Explicit) { + ParamCommandCommentBits.Direction = Direction; + ParamCommandCommentBits.IsDirectionExplicit = Explicit; + } + + bool hasParamName() const { + return getNumArgs() > 0; + } + + StringRef getParamName(const FullComment *FC) const; + + StringRef getParamNameAsWritten() const { + return Args[0].Text; + } + + SourceRange getParamNameRange() const { + return Args[0].Range; + } + + bool isParamIndexValid() const LLVM_READONLY { + return ParamIndex != InvalidParamIndex; + } + + bool isVarArgParam() const LLVM_READONLY { + return ParamIndex == VarArgParamIndex; + } + + void setIsVarArgParam() { + ParamIndex = VarArgParamIndex; + assert(isParamIndexValid()); + } + + unsigned getParamIndex() const LLVM_READONLY { + assert(isParamIndexValid()); + assert(!isVarArgParam()); + return ParamIndex; + } + + void setParamIndex(unsigned Index) { + ParamIndex = Index; + assert(isParamIndexValid()); + assert(!isVarArgParam()); + } +}; + +/// Doxygen \\tparam command, describes a template parameter. +class TParamCommandComment : public BlockCommandComment { +private: + /// If this template parameter name was resolved (found in template parameter + /// list), then this stores a list of position indexes in all template + /// parameter lists. + /// + /// For example: + /// \verbatim + /// template<typename C, template<typename T> class TT> + /// void test(TT<int> aaa); + /// \endverbatim + /// For C: Position = { 0 } + /// For TT: Position = { 1 } + /// For T: Position = { 1, 0 } + ArrayRef<unsigned> Position; + +public: + TParamCommandComment(SourceLocation LocBegin, + SourceLocation LocEnd, + unsigned CommandID, + CommandMarkerKind CommandMarker) : + BlockCommandComment(TParamCommandCommentKind, LocBegin, LocEnd, CommandID, + CommandMarker) + { } + + static bool classof(const Comment *C) { + return C->getCommentKind() == TParamCommandCommentKind; + } + + bool hasParamName() const { + return getNumArgs() > 0; + } + + StringRef getParamName(const FullComment *FC) const; + + StringRef getParamNameAsWritten() const { + return Args[0].Text; + } + + SourceRange getParamNameRange() const { + return Args[0].Range; + } + + bool isPositionValid() const LLVM_READONLY { + return !Position.empty(); + } + + unsigned getDepth() const { + assert(isPositionValid()); + return Position.size(); + } + + unsigned getIndex(unsigned Depth) const { + assert(isPositionValid()); + return Position[Depth]; + } + + void setPosition(ArrayRef<unsigned> NewPosition) { + Position = NewPosition; + assert(isPositionValid()); + } +}; + +/// A line of text contained in a verbatim block. +class VerbatimBlockLineComment : public Comment { + StringRef Text; + +public: + VerbatimBlockLineComment(SourceLocation LocBegin, + StringRef Text) : + Comment(VerbatimBlockLineCommentKind, + LocBegin, + LocBegin.getLocWithOffset(Text.size())), + Text(Text) + { } + + static bool classof(const Comment *C) { + return C->getCommentKind() == VerbatimBlockLineCommentKind; + } + + child_iterator child_begin() const { return nullptr; } + + child_iterator child_end() const { return nullptr; } + + StringRef getText() const LLVM_READONLY { + return Text; + } +}; + +/// A verbatim block command (e. g., preformatted code). Verbatim block has an +/// opening and a closing command and contains multiple lines of text +/// (VerbatimBlockLineComment nodes). +class VerbatimBlockComment : public BlockCommandComment { +protected: + StringRef CloseName; + SourceLocation CloseNameLocBegin; + ArrayRef<VerbatimBlockLineComment *> Lines; + +public: + VerbatimBlockComment(SourceLocation LocBegin, + SourceLocation LocEnd, + unsigned CommandID) : + BlockCommandComment(VerbatimBlockCommentKind, + LocBegin, LocEnd, CommandID, + CMK_At) // FIXME: improve source fidelity. + { } + + static bool classof(const Comment *C) { + return C->getCommentKind() == VerbatimBlockCommentKind; + } + + child_iterator child_begin() const { + return reinterpret_cast<child_iterator>(Lines.begin()); + } + + child_iterator child_end() const { + return reinterpret_cast<child_iterator>(Lines.end()); + } + + void setCloseName(StringRef Name, SourceLocation LocBegin) { + CloseName = Name; + CloseNameLocBegin = LocBegin; + } + + void setLines(ArrayRef<VerbatimBlockLineComment *> L) { + Lines = L; + } + + StringRef getCloseName() const { + return CloseName; + } + + unsigned getNumLines() const { + return Lines.size(); + } + + StringRef getText(unsigned LineIdx) const { + return Lines[LineIdx]->getText(); + } +}; + +/// A verbatim line command. Verbatim line has an opening command, a single +/// line of text (up to the newline after the opening command) and has no +/// closing command. +class VerbatimLineComment : public BlockCommandComment { +protected: + StringRef Text; + SourceLocation TextBegin; + +public: + VerbatimLineComment(SourceLocation LocBegin, + SourceLocation LocEnd, + unsigned CommandID, + SourceLocation TextBegin, + StringRef Text) : + BlockCommandComment(VerbatimLineCommentKind, + LocBegin, LocEnd, + CommandID, + CMK_At), // FIXME: improve source fidelity. + Text(Text), + TextBegin(TextBegin) + { } + + static bool classof(const Comment *C) { + return C->getCommentKind() == VerbatimLineCommentKind; + } + + child_iterator child_begin() const { return nullptr; } + + child_iterator child_end() const { return nullptr; } + + StringRef getText() const { + return Text; + } + + SourceRange getTextRange() const { + return SourceRange(TextBegin, getLocEnd()); + } +}; + +/// Information about the declaration, useful to clients of FullComment. +struct DeclInfo { + /// Declaration the comment is actually attached to (in the source). + /// Should not be NULL. + const Decl *CommentDecl; + + /// CurrentDecl is the declaration with which the FullComment is associated. + /// + /// It can be different from \c CommentDecl. It happens when we we decide + /// that the comment originally attached to \c CommentDecl is fine for + /// \c CurrentDecl too (for example, for a redeclaration or an overrider of + /// \c CommentDecl). + /// + /// The information in the DeclInfo corresponds to CurrentDecl. + const Decl *CurrentDecl; + + /// Parameters that can be referenced by \\param if \c CommentDecl is something + /// that we consider a "function". + ArrayRef<const ParmVarDecl *> ParamVars; + + /// Function return type if \c CommentDecl is something that we consider + /// a "function". + QualType ReturnType; + + /// Template parameters that can be referenced by \\tparam if \c CommentDecl is + /// a template (\c IsTemplateDecl or \c IsTemplatePartialSpecialization is + /// true). + const TemplateParameterList *TemplateParameters; + + /// A simplified description of \c CommentDecl kind that should be good enough + /// for documentation rendering purposes. + enum DeclKind { + /// Everything else not explicitly mentioned below. + OtherKind, + + /// Something that we consider a "function": + /// \li function, + /// \li function template, + /// \li function template specialization, + /// \li member function, + /// \li member function template, + /// \li member function template specialization, + /// \li ObjC method, + /// \li a typedef for a function pointer, member function pointer, + /// ObjC block. + FunctionKind, + + /// Something that we consider a "class": + /// \li class/struct, + /// \li class template, + /// \li class template (partial) specialization. + ClassKind, + + /// Something that we consider a "variable": + /// \li namespace scope variables; + /// \li static and non-static class data members; + /// \li enumerators. + VariableKind, + + /// A C++ namespace. + NamespaceKind, + + /// A C++ typedef-name (a 'typedef' decl specifier or alias-declaration), + /// see \c TypedefNameDecl. + TypedefKind, + + /// An enumeration or scoped enumeration. + EnumKind + }; + + /// What kind of template specialization \c CommentDecl is. + enum TemplateDeclKind { + NotTemplate, + Template, + TemplateSpecialization, + TemplatePartialSpecialization + }; + + /// If false, only \c CommentDecl is valid. + unsigned IsFilled : 1; + + /// Simplified kind of \c CommentDecl, see \c DeclKind enum. + unsigned Kind : 3; + + /// Is \c CommentDecl a template declaration. + unsigned TemplateKind : 2; + + /// Is \c CommentDecl an ObjCMethodDecl. + unsigned IsObjCMethod : 1; + + /// Is \c CommentDecl a non-static member function of C++ class or + /// instance method of ObjC class. + /// Can be true only if \c IsFunctionDecl is true. + unsigned IsInstanceMethod : 1; + + /// Is \c CommentDecl a static member function of C++ class or + /// class method of ObjC class. + /// Can be true only if \c IsFunctionDecl is true. + unsigned IsClassMethod : 1; + + void fill(); + + DeclKind getKind() const LLVM_READONLY { + return static_cast<DeclKind>(Kind); + } + + TemplateDeclKind getTemplateKind() const LLVM_READONLY { + return static_cast<TemplateDeclKind>(TemplateKind); + } +}; + +/// A full comment attached to a declaration, contains block content. +class FullComment : public Comment { + ArrayRef<BlockContentComment *> Blocks; + DeclInfo *ThisDeclInfo; + +public: + FullComment(ArrayRef<BlockContentComment *> Blocks, DeclInfo *D) : + Comment(FullCommentKind, SourceLocation(), SourceLocation()), + Blocks(Blocks), ThisDeclInfo(D) { + if (Blocks.empty()) + return; + + setSourceRange(SourceRange(Blocks.front()->getLocStart(), + Blocks.back()->getLocEnd())); + setLocation(Blocks.front()->getLocStart()); + } + + static bool classof(const Comment *C) { + return C->getCommentKind() == FullCommentKind; + } + + child_iterator child_begin() const { + return reinterpret_cast<child_iterator>(Blocks.begin()); + } + + child_iterator child_end() const { + return reinterpret_cast<child_iterator>(Blocks.end()); + } + + const Decl *getDecl() const LLVM_READONLY { + return ThisDeclInfo->CommentDecl; + } + + const DeclInfo *getDeclInfo() const LLVM_READONLY { + if (!ThisDeclInfo->IsFilled) + ThisDeclInfo->fill(); + return ThisDeclInfo; + } + + ArrayRef<BlockContentComment *> getBlocks() const { return Blocks; } + +}; +} // end namespace comments +} // end namespace clang + +#endif + diff --git a/contrib/llvm/tools/clang/include/clang/AST/CommentBriefParser.h b/contrib/llvm/tools/clang/include/clang/AST/CommentBriefParser.h new file mode 100644 index 0000000..be5b8ee --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/CommentBriefParser.h @@ -0,0 +1,55 @@ +//===--- CommentBriefParser.h - Dumb comment parser -------------*- 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 very simple Doxygen comment parser. +// +//===----------------------------------------------------------------------===// + + +#ifndef LLVM_CLANG_AST_COMMENTBRIEFPARSER_H +#define LLVM_CLANG_AST_COMMENTBRIEFPARSER_H + +#include "clang/AST/CommentLexer.h" + +namespace clang { +namespace comments { + +/// A very simple comment parser that extracts "a brief description". +/// +/// Due to a variety of comment styles, it considers the following as "a brief +/// description", in order of priority: +/// \li a \\brief or \\short command, +/// \li the first paragraph, +/// \li a \\result or \\return or \\returns paragraph. +class BriefParser { + Lexer &L; + + const CommandTraits &Traits; + + /// Current lookahead token. + Token Tok; + + SourceLocation ConsumeToken() { + SourceLocation Loc = Tok.getLocation(); + L.lex(Tok); + return Loc; + } + +public: + BriefParser(Lexer &L, const CommandTraits &Traits); + + /// Return the best "brief description" we can find. + std::string Parse(); +}; + +} // end namespace comments +} // end namespace clang + +#endif + diff --git a/contrib/llvm/tools/clang/include/clang/AST/CommentCommandTraits.h b/contrib/llvm/tools/clang/include/clang/AST/CommentCommandTraits.h new file mode 100644 index 0000000..289f2fd --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/CommentCommandTraits.h @@ -0,0 +1,189 @@ +//===--- CommentCommandTraits.h - Comment command properties ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the class that provides information about comment +// commands. +// +//===----------------------------------------------------------------------===// + + +#ifndef LLVM_CLANG_AST_COMMENTCOMMANDTRAITS_H +#define LLVM_CLANG_AST_COMMENTCOMMANDTRAITS_H + +#include "clang/Basic/CommentOptions.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/ErrorHandling.h" + +namespace clang { +namespace comments { + +/// \brief Information about a single command. +/// +/// When reordering, adding or removing members please update the corresponding +/// TableGen backend. +struct CommandInfo { + unsigned getID() const { + return ID; + } + + const char *Name; + + /// Name of the command that ends the verbatim block. + const char *EndCommandName; + + /// DRY definition of the number of bits used for a command ID. + enum { NumCommandIDBits = 20 }; + + /// The ID of the command. + unsigned ID : NumCommandIDBits; + + /// Number of word-like arguments for a given block command, except for + /// \\param and \\tparam commands -- these have special argument parsers. + unsigned NumArgs : 4; + + /// True if this command is a inline command (of any kind). + unsigned IsInlineCommand : 1; + + /// True if this command is a block command (of any kind). + unsigned IsBlockCommand : 1; + + /// True if this command is introducing a brief documentation + /// paragraph (\\brief or an alias). + unsigned IsBriefCommand : 1; + + /// True if this command is \\returns or an alias. + unsigned IsReturnsCommand : 1; + + /// True if this command is introducing documentation for a function + /// parameter (\\param or an alias). + unsigned IsParamCommand : 1; + + /// True if this command is introducing documentation for + /// a template parameter (\\tparam or an alias). + unsigned IsTParamCommand : 1; + + /// True if this command is \\throws or an alias. + unsigned IsThrowsCommand : 1; + + /// True if this command is \\deprecated or an alias. + unsigned IsDeprecatedCommand : 1; + + /// \brief True if this is a \\headerfile-like command. + unsigned IsHeaderfileCommand : 1; + + /// True if we don't want to warn about this command being passed an empty + /// paragraph. Meaningful only for block commands. + unsigned IsEmptyParagraphAllowed : 1; + + /// \brief True if this command is a verbatim-like block command. + /// + /// A verbatim-like block command eats every character (except line starting + /// decorations) until matching end command is seen or comment end is hit. + unsigned IsVerbatimBlockCommand : 1; + + /// \brief True if this command is an end command for a verbatim-like block. + unsigned IsVerbatimBlockEndCommand : 1; + + /// \brief True if this command is a verbatim line command. + /// + /// A verbatim-like line command eats everything until a newline is seen or + /// comment end is hit. + unsigned IsVerbatimLineCommand : 1; + + /// \brief True if this command contains a declaration for the entity being + /// documented. + /// + /// For example: + /// \code + /// \fn void f(int a); + /// \endcode + unsigned IsDeclarationCommand : 1; + + /// \brief True if verbatim-like line command is a function declaration. + unsigned IsFunctionDeclarationCommand : 1; + + /// \brief True if block command is further describing a container API; such + /// as \@coclass, \@classdesign, etc. + unsigned IsRecordLikeDetailCommand : 1; + + /// \brief True if block command is a container API; such as \@interface. + unsigned IsRecordLikeDeclarationCommand : 1; + + /// \brief True if this command is unknown. This \c CommandInfo object was + /// created during parsing. + unsigned IsUnknownCommand : 1; +}; + +/// This class provides information about commands that can be used +/// in comments. +class CommandTraits { +public: + enum KnownCommandIDs { +#define COMMENT_COMMAND(NAME) KCI_##NAME, +#include "clang/AST/CommentCommandList.inc" +#undef COMMENT_COMMAND + KCI_Last + }; + + CommandTraits(llvm::BumpPtrAllocator &Allocator, + const CommentOptions &CommentOptions); + + void registerCommentOptions(const CommentOptions &CommentOptions); + + /// \returns a CommandInfo object for a given command name or + /// NULL if no CommandInfo object exists for this command. + const CommandInfo *getCommandInfoOrNULL(StringRef Name) const; + + const CommandInfo *getCommandInfo(StringRef Name) const { + if (const CommandInfo *Info = getCommandInfoOrNULL(Name)) + return Info; + llvm_unreachable("the command should be known"); + } + + const CommandInfo *getTypoCorrectCommandInfo(StringRef Typo) const; + + const CommandInfo *getCommandInfo(unsigned CommandID) const; + + const CommandInfo *registerUnknownCommand(StringRef CommandName); + + const CommandInfo *registerBlockCommand(StringRef CommandName); + + /// \returns a CommandInfo object for a given command name or + /// NULL if \c Name is not a builtin command. + static const CommandInfo *getBuiltinCommandInfo(StringRef Name); + + /// \returns a CommandInfo object for a given command ID or + /// NULL if \c CommandID is not a builtin command. + static const CommandInfo *getBuiltinCommandInfo(unsigned CommandID); + +private: + CommandTraits(const CommandTraits &) = delete; + void operator=(const CommandTraits &) = delete; + + const CommandInfo *getRegisteredCommandInfo(StringRef Name) const; + const CommandInfo *getRegisteredCommandInfo(unsigned CommandID) const; + + CommandInfo *createCommandInfoWithName(StringRef CommandName); + + unsigned NextID; + + /// Allocator for CommandInfo objects. + llvm::BumpPtrAllocator &Allocator; + + SmallVector<CommandInfo *, 4> RegisteredCommands; +}; + +} // end namespace comments +} // end namespace clang + +#endif + diff --git a/contrib/llvm/tools/clang/include/clang/AST/CommentCommands.td b/contrib/llvm/tools/clang/include/clang/AST/CommentCommands.td new file mode 100644 index 0000000..958ee03 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/CommentCommands.td @@ -0,0 +1,241 @@ +//===----------------------------------------------------------------------===// +// Define command classes. +//===----------------------------------------------------------------------===// + +class Command<string name> { + string Name = name; + string EndCommandName = ""; + + int NumArgs = 0; + + bit IsInlineCommand = 0; + + bit IsBlockCommand = 0; + bit IsBriefCommand = 0; + bit IsReturnsCommand = 0; + bit IsParamCommand = 0; + bit IsTParamCommand = 0; + bit IsThrowsCommand = 0; + bit IsDeprecatedCommand = 0; + bit IsHeaderfileCommand = 0; + + bit IsEmptyParagraphAllowed = 0; + + bit IsVerbatimBlockCommand = 0; + bit IsVerbatimBlockEndCommand = 0; + bit IsVerbatimLineCommand = 0; + bit IsDeclarationCommand = 0; + bit IsFunctionDeclarationCommand = 0; + bit IsRecordLikeDetailCommand = 0; + bit IsRecordLikeDeclarationCommand = 0; +} + +class InlineCommand<string name> : Command<name> { + let IsInlineCommand = 1; +} + +class BlockCommand<string name> : Command<name> { + let IsBlockCommand = 1; +} + +class RecordLikeDetailCommand<string name> : BlockCommand<name> { + let IsRecordLikeDetailCommand = 1; +} + +class VerbatimBlockCommand<string name> : Command<name> { + let EndCommandName = name; + let IsVerbatimBlockCommand = 1; +} + +multiclass VerbatimBlockCommand<string name, string endCommandName> { + def Begin : Command<name> { + let EndCommandName = endCommandName; + let IsVerbatimBlockCommand = 1; + } + + def End : Command<endCommandName> { + let IsVerbatimBlockEndCommand = 1; + } +} + +class VerbatimLineCommand<string name> : Command<name> { + let IsVerbatimLineCommand = 1; +} + +class DeclarationVerbatimLineCommand<string name> : + VerbatimLineCommand<name> { + let IsDeclarationCommand = 1; +} + +class FunctionDeclarationVerbatimLineCommand<string name> : + DeclarationVerbatimLineCommand<name> { + let IsFunctionDeclarationCommand = 1; +} + +class RecordLikeDeclarationVerbatimLineCommand<string name> : + DeclarationVerbatimLineCommand<name> { + let IsRecordLikeDeclarationCommand = 1; +} + +//===----------------------------------------------------------------------===// +// InlineCommand +//===----------------------------------------------------------------------===// + +def B : InlineCommand<"b">; +def C : InlineCommand<"c">; +def P : InlineCommand<"p">; +def A : InlineCommand<"a">; +def E : InlineCommand<"e">; +def Em : InlineCommand<"em">; + +//===----------------------------------------------------------------------===// +// BlockCommand +//===----------------------------------------------------------------------===// + +def Brief : BlockCommand<"brief"> { let IsBriefCommand = 1; } +def Short : BlockCommand<"short"> { let IsBriefCommand = 1; } + +// Opposite of \brief, it is the default in our implementation. +def Details : BlockCommand<"details">; + +def Returns : BlockCommand<"returns"> { let IsReturnsCommand = 1; } +def Return : BlockCommand<"return"> { let IsReturnsCommand = 1; } +def Result : BlockCommand<"result"> { let IsReturnsCommand = 1; } + +def Param : BlockCommand<"param"> { let IsParamCommand = 1; } + +// Doxygen command for template parameter documentation. +def Tparam : BlockCommand<"tparam"> { let IsTParamCommand = 1; } + +// HeaderDoc command for template parameter documentation. +def Templatefield : BlockCommand<"templatefield"> { let IsTParamCommand = 1; } + +def Throws : BlockCommand<"throws"> { let IsThrowsCommand = 1; } +def Throw : BlockCommand<"throw"> { let IsThrowsCommand = 1; } +def Exception : BlockCommand<"exception"> { let IsThrowsCommand = 1; } + +def Deprecated : BlockCommand<"deprecated"> { + let IsEmptyParagraphAllowed = 1; + let IsDeprecatedCommand = 1; +} + +def Headerfile : BlockCommand<"headerfile"> { let IsHeaderfileCommand = 1; } + +// We don't do any additional semantic analysis for the following +// BlockCommands. It might be a good idea to do something extra for them, but +// for now we model them as plain BlockCommands. +def Arg : BlockCommand<"arg">; +def Attention : BlockCommand<"attention">; +def Author : BlockCommand<"author">; +def Authors : BlockCommand<"authors">; +def Bug : BlockCommand<"bug">; +def Copyright : BlockCommand<"copyright">; +def Date : BlockCommand<"date">; +def Invariant : BlockCommand<"invariant">; +def Li : BlockCommand<"li">; +def Note : BlockCommand<"note">; +def Par : BlockCommand<"par">; +def Post : BlockCommand<"post">; +def Pre : BlockCommand<"pre">; +def Remark : BlockCommand<"remark">; +def Remarks : BlockCommand<"remarks">; +def Sa : BlockCommand<"sa">; +def See : BlockCommand<"see">; +def Since : BlockCommand<"since">; +def Todo : BlockCommand<"todo">; +def Version : BlockCommand<"version">; +def Warning : BlockCommand<"warning">; +// HeaderDoc commands +def Abstract : BlockCommand<"abstract"> { let IsBriefCommand = 1; } +def ClassDesign : RecordLikeDetailCommand<"classdesign">; +def CoClass : RecordLikeDetailCommand<"coclass">; +def Dependency : RecordLikeDetailCommand<"dependency">; +def Discussion : BlockCommand<"discussion">; +def Helper : RecordLikeDetailCommand<"helper">; +def HelperClass : RecordLikeDetailCommand<"helperclass">; +def Helps : RecordLikeDetailCommand<"helps">; +def InstanceSize : RecordLikeDetailCommand<"instancesize">; +def Ownership : RecordLikeDetailCommand<"ownership">; +def Performance : RecordLikeDetailCommand<"performance">; +def Security : RecordLikeDetailCommand<"security">; +def SeeAlso : BlockCommand<"seealso">; +def SuperClass : RecordLikeDetailCommand<"superclass">; + +//===----------------------------------------------------------------------===// +// VerbatimBlockCommand +//===----------------------------------------------------------------------===// + +defm Code : VerbatimBlockCommand<"code", "endcode">; +defm Verbatim : VerbatimBlockCommand<"verbatim", "endverbatim">; +defm Htmlonly : VerbatimBlockCommand<"htmlonly", "endhtmlonly">; +defm Latexonly : VerbatimBlockCommand<"latexonly", "endlatexonly">; +defm Xmlonly : VerbatimBlockCommand<"xmlonly", "endxmlonly">; +defm Manonly : VerbatimBlockCommand<"manonly", "endmanonly">; +defm Rtfonly : VerbatimBlockCommand<"rtfonly", "endrtfonly">; + +defm Dot : VerbatimBlockCommand<"dot", "enddot">; +defm Msc : VerbatimBlockCommand<"msc", "endmsc">; + +// These three commands have special support in CommentLexer to recognize their +// names. +def FDollar : VerbatimBlockCommand<"f$">; // Inline LaTeX formula +defm FBracket : VerbatimBlockCommand<"f[", "f]">; // Displayed LaTeX formula +defm FBrace : VerbatimBlockCommand<"f{", "f}">; // LaTeX environment + +// HeaderDoc commands +defm Textblock : VerbatimBlockCommand<"textblock", "/textblock">; +defm Link : VerbatimBlockCommand<"link", "/link">; + +//===----------------------------------------------------------------------===// +// VerbatimLineCommand +//===----------------------------------------------------------------------===// + +def Defgroup : VerbatimLineCommand<"defgroup">; +def Ingroup : VerbatimLineCommand<"ingroup">; +def Addtogroup : VerbatimLineCommand<"addtogroup">; +def Weakgroup : VerbatimLineCommand<"weakgroup">; +def Name : VerbatimLineCommand<"name">; + +def Section : VerbatimLineCommand<"section">; +def Subsection : VerbatimLineCommand<"subsection">; +def Subsubsection : VerbatimLineCommand<"subsubsection">; +def Paragraph : VerbatimLineCommand<"paragraph">; + +def Mainpage : VerbatimLineCommand<"mainpage">; +def Subpage : VerbatimLineCommand<"subpage">; +def Ref : VerbatimLineCommand<"ref">; + +def Relates : VerbatimLineCommand<"relates">; +def Related : VerbatimLineCommand<"related">; +def RelatesAlso : VerbatimLineCommand<"relatesalso">; +def RelatedAlso : VerbatimLineCommand<"relatedalso">; + +//===----------------------------------------------------------------------===// +// DeclarationVerbatimLineCommand +//===----------------------------------------------------------------------===// + +// Doxygen commands. +def Def : DeclarationVerbatimLineCommand<"def">; +def Fn : DeclarationVerbatimLineCommand<"fn">; +def Namespace : DeclarationVerbatimLineCommand<"namespace">; +def Overload : DeclarationVerbatimLineCommand<"overload">; +def Property : DeclarationVerbatimLineCommand<"property">; +def Typedef : DeclarationVerbatimLineCommand<"typedef">; +def Var : DeclarationVerbatimLineCommand<"var">; + +// HeaderDoc commands. +def Class : RecordLikeDeclarationVerbatimLineCommand<"class">; +def Interface : RecordLikeDeclarationVerbatimLineCommand<"interface">; +def Protocol : RecordLikeDeclarationVerbatimLineCommand<"protocol">; +def Struct : RecordLikeDeclarationVerbatimLineCommand<"struct">; +def Union : RecordLikeDeclarationVerbatimLineCommand<"union">; +def Category : DeclarationVerbatimLineCommand<"category">; +def Template : DeclarationVerbatimLineCommand<"template">; +def Function : FunctionDeclarationVerbatimLineCommand<"function">; +def FunctionGroup : FunctionDeclarationVerbatimLineCommand<"functiongroup">; +def Method : FunctionDeclarationVerbatimLineCommand<"method">; +def MethodGroup : FunctionDeclarationVerbatimLineCommand<"methodgroup">; +def Callback : FunctionDeclarationVerbatimLineCommand<"callback">; +def Const : DeclarationVerbatimLineCommand<"const">; +def Constant : DeclarationVerbatimLineCommand<"constant">; +def Enum : DeclarationVerbatimLineCommand<"enum">; diff --git a/contrib/llvm/tools/clang/include/clang/AST/CommentDiagnostic.h b/contrib/llvm/tools/clang/include/clang/AST/CommentDiagnostic.h new file mode 100644 index 0000000..f3a209b --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/CommentDiagnostic.h @@ -0,0 +1,29 @@ +//===--- CommentDiagnostic.h - Diagnostics for the AST library --*- 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_AST_COMMENTDIAGNOSTIC_H +#define LLVM_CLANG_AST_COMMENTDIAGNOSTIC_H + +#include "clang/Basic/Diagnostic.h" + +namespace clang { + namespace diag { + enum { +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\ + SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM, +#define COMMENTSTART +#include "clang/Basic/DiagnosticCommentKinds.inc" +#undef DIAG + NUM_BUILTIN_COMMENT_DIAGNOSTICS + }; + } // end namespace diag +} // end namespace clang + +#endif + diff --git a/contrib/llvm/tools/clang/include/clang/AST/CommentHTMLNamedCharacterReferences.td b/contrib/llvm/tools/clang/include/clang/AST/CommentHTMLNamedCharacterReferences.td new file mode 100644 index 0000000..4493108 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/CommentHTMLNamedCharacterReferences.td @@ -0,0 +1,177 @@ +// HTML Named Character Reference +class NCR<string spelling, int codePoint> { + string Spelling = spelling; + int CodePoint = codePoint; +} + +// The list below includes named character references supported by Doxygen: +// http://www.stack.nl/~dimitri/doxygen/manual/htmlcmds.html +// +// It does not include all HTML 5 named character references. +// +// Corresponding code point values can be found here: +// http://www.w3.org/TR/2011/WD-html5-20110113/named-character-references.html + +def : NCR<"copy", 0x000A9>; +def : NCR<"COPY", 0x000A9>; +def : NCR<"trade", 0x02122>; +def : NCR<"TRADE", 0x02122>; +def : NCR<"reg", 0x000AE>; +def : NCR<"REG", 0x000AE>; +def : NCR<"lt", 0x0003C>; +def : NCR<"Lt", 0x0003C>; +def : NCR<"LT", 0x0003C>; +def : NCR<"gt", 0x0003E>; +def : NCR<"Gt", 0x0003E>; +def : NCR<"GT", 0x0003E>; +def : NCR<"amp", 0x00026>; +def : NCR<"AMP", 0x00026>; +def : NCR<"apos", 0x00027>; +def : NCR<"quot", 0x00022>; +def : NCR<"QUOT", 0x00022>; +def : NCR<"lsquo", 0x02018>; +def : NCR<"rsquo", 0x02019>; +def : NCR<"ldquo", 0x0201C>; +def : NCR<"rdquo", 0x0201D>; +def : NCR<"ndash", 0x02013>; +def : NCR<"mdash", 0x02014>; + +def : NCR<"Auml", 0x000C4>; +def : NCR<"Euml", 0x000CB>; +def : NCR<"Iuml", 0x000CF>; +def : NCR<"Ouml", 0x000D6>; +def : NCR<"Uuml", 0x000DC>; +def : NCR<"Yuml", 0x00178>; +def : NCR<"auml", 0x000E4>; +def : NCR<"euml", 0x000EB>; +def : NCR<"iuml", 0x000EF>; +def : NCR<"ouml", 0x000F6>; +def : NCR<"uuml", 0x000FC>; +def : NCR<"yuml", 0x000FF>; + +def : NCR<"Aacute", 0x000C1>; +def : NCR<"Eacute", 0x000C9>; +def : NCR<"Iacute", 0x000CD>; +def : NCR<"Oacute", 0x000D3>; +def : NCR<"Uacute", 0x000DA>; +def : NCR<"Yacute", 0x000DD>; +def : NCR<"aacute", 0x000E1>; +def : NCR<"eacute", 0x000E9>; +def : NCR<"iacute", 0x000ED>; +def : NCR<"oacute", 0x000F3>; +def : NCR<"uacute", 0x000FA>; +def : NCR<"yacute", 0x000FD>; + +def : NCR<"Agrave", 0x000C0>; +def : NCR<"Egrave", 0x000C8>; +def : NCR<"Igrave", 0x000CC>; +def : NCR<"Ograve", 0x000D2>; +def : NCR<"Ugrave", 0x000D9>; +// def : NCR<"Ygrave", 0x01EF2>; // Defined neither in Doxygen, nor in HTML5. +def : NCR<"agrave", 0x000E0>; +def : NCR<"egrave", 0x000E8>; +def : NCR<"igrave", 0x000EC>; +def : NCR<"ograve", 0x000F2>; +def : NCR<"ugrave", 0x000F9>; +def : NCR<"ygrave", 0x01EF3>; // Defined in Doxygen, not defined in HTML5. + +def : NCR<"Acirc", 0x000C2>; +def : NCR<"Ecirc", 0x000CA>; +def : NCR<"Icirc", 0x000CE>; +def : NCR<"Ocirc", 0x000D4>; +def : NCR<"Ucirc", 0x000DB>; +def : NCR<"Ycirc", 0x00176>; // Not defined in Doxygen, defined in HTML5. +def : NCR<"acirc", 0x000E2>; +def : NCR<"ecirc", 0x000EA>; +def : NCR<"icirc", 0x000EE>; +def : NCR<"ocirc", 0x000F4>; +def : NCR<"ucirc", 0x000FB>; +def : NCR<"ycirc", 0x00177>; + +def : NCR<"Atilde", 0x000C3>; +def : NCR<"Ntilde", 0x000D1>; +def : NCR<"Otilde", 0x000D5>; +def : NCR<"atilde", 0x000E3>; +def : NCR<"ntilde", 0x000F1>; +def : NCR<"otilde", 0x000F5>; + +def : NCR<"szlig", 0x000DF>; + +def : NCR<"ccedil", 0x000E7>; +def : NCR<"Ccedil", 0x000C7>; + +def : NCR<"aring", 0x000E5>; +def : NCR<"Aring", 0x000C5>; + +def : NCR<"nbsp", 0x000A0>; + +def : NCR<"Gamma", 0x00393>; +def : NCR<"Delta", 0x00394>; +def : NCR<"Theta", 0x00398>; +def : NCR<"Lambda", 0x0039B>; +def : NCR<"Xi", 0x0039E>; +def : NCR<"Pi", 0x003A0>; +def : NCR<"Sigma", 0x003A3>; +def : NCR<"Upsilon", 0x003A5>; +def : NCR<"Phi", 0x003A6>; +def : NCR<"Psi", 0x003A8>; +def : NCR<"Omega", 0x003A9>; + +def : NCR<"alpha", 0x003B1>; +def : NCR<"beta", 0x003B2>; +def : NCR<"gamma", 0x003B3>; +def : NCR<"delta", 0x003B4>; +def : NCR<"epsilon", 0x003B5>; +def : NCR<"zeta", 0x003B6>; +def : NCR<"eta", 0x003B7>; +def : NCR<"theta", 0x003B8>; +def : NCR<"iota", 0x003B9>; +def : NCR<"kappa", 0x003BA>; +def : NCR<"lambda", 0x003BB>; +def : NCR<"mu", 0x003BC>; +def : NCR<"nu", 0x003BD>; +def : NCR<"xi", 0x003BE>; +def : NCR<"pi", 0x003C0>; +def : NCR<"rho", 0x003C1>; +def : NCR<"sigma", 0x003C3>; +def : NCR<"tau", 0x003C4>; +def : NCR<"upsilon", 0x003C5>; +def : NCR<"phi", 0x003C6>; +def : NCR<"chi", 0x003C7>; +def : NCR<"psi", 0x003C8>; +def : NCR<"omega", 0x003C9>; +def : NCR<"sigmaf", 0x003C2>; + +def : NCR<"sect", 0x000A7>; +def : NCR<"deg", 0x000B0>; +def : NCR<"prime", 0x02032>; +def : NCR<"Prime", 0x02033>; +def : NCR<"infin", 0x0221E>; +def : NCR<"empty", 0x02205>; +def : NCR<"plusmn", 0x000B1>; +def : NCR<"times", 0x000D7>; +def : NCR<"minus", 0x02212>; +def : NCR<"sdot", 0x022C5>; +def : NCR<"part", 0x02202>; +def : NCR<"nabla", 0x02207>; +def : NCR<"radic", 0x0221A>; +def : NCR<"perp", 0x022A5>; +def : NCR<"sum", 0x02211>; +def : NCR<"int", 0x0222B>; +def : NCR<"prod", 0x0220F>; +def : NCR<"sim", 0x0223C>; +def : NCR<"asymp", 0x02248>; +def : NCR<"ne", 0x02260>; +def : NCR<"equiv", 0x02261>; +def : NCR<"prop", 0x0221D>; +def : NCR<"le", 0x02264>; +def : NCR<"ge", 0x02265>; +def : NCR<"larr", 0x02190>; +def : NCR<"rarr", 0x02192>; +def : NCR<"isin", 0x02208>; +def : NCR<"notin", 0x02209>; +def : NCR<"lceil", 0x02308>; +def : NCR<"rceil", 0x02309>; +def : NCR<"lfloor", 0x0230A>; +def : NCR<"rfloor", 0x0230B>; + diff --git a/contrib/llvm/tools/clang/include/clang/AST/CommentHTMLTags.td b/contrib/llvm/tools/clang/include/clang/AST/CommentHTMLTags.td new file mode 100644 index 0000000..2514900 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/CommentHTMLTags.td @@ -0,0 +1,67 @@ +class Tag<string spelling> { + string Spelling = spelling; + bit EndTagOptional = 0; + bit EndTagForbidden = 0; +} + +def Em : Tag<"em">; +def Strong : Tag<"strong">; +def Tt : Tag<"tt">; +def I : Tag<"i">; +def B : Tag<"b">; +def Big : Tag<"big">; +def Small : Tag<"small">; +def Strike : Tag<"strike">; +def S : Tag<"s">; +def U : Tag<"u">; +def Font : Tag<"font">; +def A : Tag<"a">; +def Hr : Tag<"hr"> { let EndTagForbidden = 1; } +def Div : Tag<"div">; +def Span : Tag<"span">; +def H1 : Tag<"h1">; +def H2 : Tag<"h2">; +def H3 : Tag<"h3">; +def H4 : Tag<"h4">; +def H5 : Tag<"h5">; +def H6 : Tag<"h6">; +def Code : Tag<"code">; +def Blockquote : Tag<"blockquote">; +def Sub : Tag<"sub">; +def Sup : Tag<"sup">; +def Img : Tag<"img"> { let EndTagForbidden = 1; } +def P : Tag<"p"> { let EndTagOptional = 1; } +def Br : Tag<"br"> { let EndTagForbidden = 1; } +def Pre : Tag<"pre">; +def Ins : Tag<"ins">; +def Del : Tag<"del">; +def Ul : Tag<"ul">; +def Ol : Tag<"ol">; +def Li : Tag<"li"> { let EndTagOptional = 1; } +def Dl : Tag<"dl">; +def Dt : Tag<"dt"> { let EndTagOptional = 1; } +def Dd : Tag<"dd"> { let EndTagOptional = 1; } +def Table : Tag<"table">; +def Caption : Tag<"caption">; +def Thead : Tag<"thead"> { let EndTagOptional = 1; } +def Tfoot : Tag<"tfoot"> { let EndTagOptional = 1; } +def Tbody : Tag<"tbody"> { let EndTagOptional = 1; } +def Colgroup : Tag<"colgroup"> { let EndTagOptional = 1; } +def Col : Tag<"col"> { let EndTagForbidden = 1; } +def Tr : Tag<"tr"> { let EndTagOptional = 1; } +def Th : Tag<"th"> { let EndTagOptional = 1; } +def Td : Tag<"td"> { let EndTagOptional = 1; } + +// Define a blacklist of attributes that are not safe to pass through to HTML +// output if the input is untrusted. +// +// FIXME: this should be a whitelist. When changing this to a whitelist, don't +// forget to change the default in the TableGen backend. +class Attribute<string spelling> { + string Spelling = spelling; + bit IsSafeToPassThrough = 1; +} +class EventHandlerContentAttribute<string spelling> : Attribute<spelling> { + let IsSafeToPassThrough = 0; +} + diff --git a/contrib/llvm/tools/clang/include/clang/AST/CommentLexer.h b/contrib/llvm/tools/clang/include/clang/AST/CommentLexer.h new file mode 100644 index 0000000..f190b93 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/CommentLexer.h @@ -0,0 +1,362 @@ +//===--- CommentLexer.h - Lexer for structured comments ---------*- 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 lexer for structured comments and supporting token class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_COMMENTLEXER_H +#define LLVM_CLANG_AST_COMMENTLEXER_H + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/raw_ostream.h" + +namespace clang { +namespace comments { + +class Lexer; +class TextTokenRetokenizer; +struct CommandInfo; +class CommandTraits; + +namespace tok { +enum TokenKind { + eof, + newline, + text, + unknown_command, // Command that does not have an ID. + backslash_command, // Command with an ID, that used backslash marker. + at_command, // Command with an ID, that used 'at' marker. + verbatim_block_begin, + verbatim_block_line, + verbatim_block_end, + verbatim_line_name, + verbatim_line_text, + html_start_tag, // <tag + html_ident, // attr + html_equals, // = + html_quoted_string, // "blah\"blah" or 'blah\'blah' + html_greater, // > + html_slash_greater, // /> + html_end_tag // </tag +}; +} // end namespace tok + +/// \brief Comment token. +class Token { + friend class Lexer; + friend class TextTokenRetokenizer; + + /// The location of the token. + SourceLocation Loc; + + /// The actual kind of the token. + tok::TokenKind Kind; + + /// Length of the token spelling in comment. Can be 0 for synthenized + /// tokens. + unsigned Length; + + /// Contains text value associated with a token. + const char *TextPtr; + + /// Integer value associated with a token. + /// + /// If the token is a konwn command, contains command ID and TextPtr is + /// unused (command spelling can be found with CommandTraits). Otherwise, + /// contains the length of the string that starts at TextPtr. + unsigned IntVal; + +public: + SourceLocation getLocation() const LLVM_READONLY { return Loc; } + void setLocation(SourceLocation SL) { Loc = SL; } + + SourceLocation getEndLocation() const LLVM_READONLY { + if (Length == 0 || Length == 1) + return Loc; + return Loc.getLocWithOffset(Length - 1); + } + + tok::TokenKind getKind() const LLVM_READONLY { return Kind; } + void setKind(tok::TokenKind K) { Kind = K; } + + bool is(tok::TokenKind K) const LLVM_READONLY { return Kind == K; } + bool isNot(tok::TokenKind K) const LLVM_READONLY { return Kind != K; } + + unsigned getLength() const LLVM_READONLY { return Length; } + void setLength(unsigned L) { Length = L; } + + StringRef getText() const LLVM_READONLY { + assert(is(tok::text)); + return StringRef(TextPtr, IntVal); + } + + void setText(StringRef Text) { + assert(is(tok::text)); + TextPtr = Text.data(); + IntVal = Text.size(); + } + + StringRef getUnknownCommandName() const LLVM_READONLY { + assert(is(tok::unknown_command)); + return StringRef(TextPtr, IntVal); + } + + void setUnknownCommandName(StringRef Name) { + assert(is(tok::unknown_command)); + TextPtr = Name.data(); + IntVal = Name.size(); + } + + unsigned getCommandID() const LLVM_READONLY { + assert(is(tok::backslash_command) || is(tok::at_command)); + return IntVal; + } + + void setCommandID(unsigned ID) { + assert(is(tok::backslash_command) || is(tok::at_command)); + IntVal = ID; + } + + unsigned getVerbatimBlockID() const LLVM_READONLY { + assert(is(tok::verbatim_block_begin) || is(tok::verbatim_block_end)); + return IntVal; + } + + void setVerbatimBlockID(unsigned ID) { + assert(is(tok::verbatim_block_begin) || is(tok::verbatim_block_end)); + IntVal = ID; + } + + StringRef getVerbatimBlockText() const LLVM_READONLY { + assert(is(tok::verbatim_block_line)); + return StringRef(TextPtr, IntVal); + } + + void setVerbatimBlockText(StringRef Text) { + assert(is(tok::verbatim_block_line)); + TextPtr = Text.data(); + IntVal = Text.size(); + } + + unsigned getVerbatimLineID() const LLVM_READONLY { + assert(is(tok::verbatim_line_name)); + return IntVal; + } + + void setVerbatimLineID(unsigned ID) { + assert(is(tok::verbatim_line_name)); + IntVal = ID; + } + + StringRef getVerbatimLineText() const LLVM_READONLY { + assert(is(tok::verbatim_line_text)); + return StringRef(TextPtr, IntVal); + } + + void setVerbatimLineText(StringRef Text) { + assert(is(tok::verbatim_line_text)); + TextPtr = Text.data(); + IntVal = Text.size(); + } + + StringRef getHTMLTagStartName() const LLVM_READONLY { + assert(is(tok::html_start_tag)); + return StringRef(TextPtr, IntVal); + } + + void setHTMLTagStartName(StringRef Name) { + assert(is(tok::html_start_tag)); + TextPtr = Name.data(); + IntVal = Name.size(); + } + + StringRef getHTMLIdent() const LLVM_READONLY { + assert(is(tok::html_ident)); + return StringRef(TextPtr, IntVal); + } + + void setHTMLIdent(StringRef Name) { + assert(is(tok::html_ident)); + TextPtr = Name.data(); + IntVal = Name.size(); + } + + StringRef getHTMLQuotedString() const LLVM_READONLY { + assert(is(tok::html_quoted_string)); + return StringRef(TextPtr, IntVal); + } + + void setHTMLQuotedString(StringRef Str) { + assert(is(tok::html_quoted_string)); + TextPtr = Str.data(); + IntVal = Str.size(); + } + + StringRef getHTMLTagEndName() const LLVM_READONLY { + assert(is(tok::html_end_tag)); + return StringRef(TextPtr, IntVal); + } + + void setHTMLTagEndName(StringRef Name) { + assert(is(tok::html_end_tag)); + TextPtr = Name.data(); + IntVal = Name.size(); + } + + void dump(const Lexer &L, const SourceManager &SM) const; +}; + +/// \brief Comment lexer. +class Lexer { +private: + Lexer(const Lexer &) = delete; + void operator=(const Lexer &) = delete; + + /// Allocator for strings that are semantic values of tokens and have to be + /// computed (for example, resolved decimal character references). + llvm::BumpPtrAllocator &Allocator; + + DiagnosticsEngine &Diags; + + const CommandTraits &Traits; + + const char *const BufferStart; + const char *const BufferEnd; + SourceLocation FileLoc; + + const char *BufferPtr; + + /// One past end pointer for the current comment. For BCPL comments points + /// to newline or BufferEnd, for C comments points to star in '*/'. + const char *CommentEnd; + + enum LexerCommentState { + LCS_BeforeComment, + LCS_InsideBCPLComment, + LCS_InsideCComment, + LCS_BetweenComments + }; + + /// Low-level lexer state, track if we are inside or outside of comment. + LexerCommentState CommentState; + + enum LexerState { + /// Lexing normal comment text + LS_Normal, + + /// Finished lexing verbatim block beginning command, will lex first body + /// line. + LS_VerbatimBlockFirstLine, + + /// Lexing verbatim block body line-by-line, skipping line-starting + /// decorations. + LS_VerbatimBlockBody, + + /// Finished lexing verbatim line beginning command, will lex text (one + /// line). + LS_VerbatimLineText, + + /// Finished lexing \verbatim <TAG \endverbatim part, lexing tag attributes. + LS_HTMLStartTag, + + /// Finished lexing \verbatim </TAG \endverbatim part, lexing '>'. + LS_HTMLEndTag + }; + + /// Current lexing mode. + LexerState State; + + /// If State is LS_VerbatimBlock, contains the name of verbatim end + /// command, including command marker. + SmallString<16> VerbatimBlockEndCommandName; + + /// Given a character reference name (e.g., "lt"), return the character that + /// it stands for (e.g., "<"). + StringRef resolveHTMLNamedCharacterReference(StringRef Name) const; + + /// Given a Unicode codepoint as base-10 integer, return the character. + StringRef resolveHTMLDecimalCharacterReference(StringRef Name) const; + + /// Given a Unicode codepoint as base-16 integer, return the character. + StringRef resolveHTMLHexCharacterReference(StringRef Name) const; + + void formTokenWithChars(Token &Result, const char *TokEnd, + tok::TokenKind Kind); + + void formTextToken(Token &Result, const char *TokEnd) { + StringRef Text(BufferPtr, TokEnd - BufferPtr); + formTokenWithChars(Result, TokEnd, tok::text); + Result.setText(Text); + } + + SourceLocation getSourceLocation(const char *Loc) const { + assert(Loc >= BufferStart && Loc <= BufferEnd && + "Location out of range for this buffer!"); + + const unsigned CharNo = Loc - BufferStart; + return FileLoc.getLocWithOffset(CharNo); + } + + DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) { + return Diags.Report(Loc, DiagID); + } + + /// Eat string matching regexp \code \s*\* \endcode. + void skipLineStartingDecorations(); + + /// Lex stuff inside comments. CommentEnd should be set correctly. + void lexCommentText(Token &T); + + void setupAndLexVerbatimBlock(Token &T, + const char *TextBegin, + char Marker, const CommandInfo *Info); + + void lexVerbatimBlockFirstLine(Token &T); + + void lexVerbatimBlockBody(Token &T); + + void setupAndLexVerbatimLine(Token &T, const char *TextBegin, + const CommandInfo *Info); + + void lexVerbatimLineText(Token &T); + + void lexHTMLCharacterReference(Token &T); + + void setupAndLexHTMLStartTag(Token &T); + + void lexHTMLStartTag(Token &T); + + void setupAndLexHTMLEndTag(Token &T); + + void lexHTMLEndTag(Token &T); + +public: + Lexer(llvm::BumpPtrAllocator &Allocator, DiagnosticsEngine &Diags, + const CommandTraits &Traits, + SourceLocation FileLoc, + const char *BufferStart, const char *BufferEnd); + + void lex(Token &T); + + StringRef getSpelling(const Token &Tok, + const SourceManager &SourceMgr, + bool *Invalid = nullptr) const; +}; + +} // end namespace comments +} // end namespace clang + +#endif + diff --git a/contrib/llvm/tools/clang/include/clang/AST/CommentParser.h b/contrib/llvm/tools/clang/include/clang/AST/CommentParser.h new file mode 100644 index 0000000..fa88628 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/CommentParser.h @@ -0,0 +1,123 @@ +//===--- CommentParser.h - Doxygen comment parser ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Doxygen comment parser. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_COMMENTPARSER_H +#define LLVM_CLANG_AST_COMMENTPARSER_H + +#include "clang/AST/Comment.h" +#include "clang/AST/CommentLexer.h" +#include "clang/AST/CommentSema.h" +#include "clang/Basic/Diagnostic.h" +#include "llvm/Support/Allocator.h" + +namespace clang { +class SourceManager; + +namespace comments { +class CommandTraits; + +/// Doxygen comment parser. +class Parser { + Parser(const Parser &) = delete; + void operator=(const Parser &) = delete; + + friend class TextTokenRetokenizer; + + Lexer &L; + + Sema &S; + + /// Allocator for anything that goes into AST nodes. + llvm::BumpPtrAllocator &Allocator; + + /// Source manager for the comment being parsed. + const SourceManager &SourceMgr; + + DiagnosticsEngine &Diags; + + DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) { + return Diags.Report(Loc, DiagID); + } + + const CommandTraits &Traits; + + /// Current lookahead token. We can safely assume that all tokens are from + /// a single source file. + Token Tok; + + /// A stack of additional lookahead tokens. + SmallVector<Token, 8> MoreLATokens; + + void consumeToken() { + if (MoreLATokens.empty()) + L.lex(Tok); + else + Tok = MoreLATokens.pop_back_val(); + } + + void putBack(const Token &OldTok) { + MoreLATokens.push_back(Tok); + Tok = OldTok; + } + + void putBack(ArrayRef<Token> Toks) { + if (Toks.empty()) + return; + + MoreLATokens.push_back(Tok); + MoreLATokens.append(Toks.rbegin(), std::prev(Toks.rend())); + + Tok = Toks[0]; + } + + bool isTokBlockCommand() { + return (Tok.is(tok::backslash_command) || Tok.is(tok::at_command)) && + Traits.getCommandInfo(Tok.getCommandID())->IsBlockCommand; + } + +public: + Parser(Lexer &L, Sema &S, llvm::BumpPtrAllocator &Allocator, + const SourceManager &SourceMgr, DiagnosticsEngine &Diags, + const CommandTraits &Traits); + + /// Parse arguments for \\param command. + void parseParamCommandArgs(ParamCommandComment *PC, + TextTokenRetokenizer &Retokenizer); + + /// Parse arguments for \\tparam command. + void parseTParamCommandArgs(TParamCommandComment *TPC, + TextTokenRetokenizer &Retokenizer); + + void parseBlockCommandArgs(BlockCommandComment *BC, + TextTokenRetokenizer &Retokenizer, + unsigned NumArgs); + + BlockCommandComment *parseBlockCommand(); + InlineCommandComment *parseInlineCommand(); + + HTMLStartTagComment *parseHTMLStartTag(); + HTMLEndTagComment *parseHTMLEndTag(); + + BlockContentComment *parseParagraphOrBlockCommand(); + + VerbatimBlockComment *parseVerbatimBlock(); + VerbatimLineComment *parseVerbatimLine(); + BlockContentComment *parseBlockContent(); + FullComment *parseFullComment(); +}; + +} // end namespace comments +} // end namespace clang + +#endif + diff --git a/contrib/llvm/tools/clang/include/clang/AST/CommentSema.h b/contrib/llvm/tools/clang/include/clang/AST/CommentSema.h new file mode 100644 index 0000000..6a80383 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/CommentSema.h @@ -0,0 +1,254 @@ +//===--- CommentSema.h - Doxygen comment semantic analysis ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the semantic analysis class for Doxygen comments. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_COMMENTSEMA_H +#define LLVM_CLANG_AST_COMMENTSEMA_H + +#include "clang/AST/Comment.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Allocator.h" + +namespace clang { +class Decl; +class SourceMgr; +class Preprocessor; + +namespace comments { +class CommandTraits; + +class Sema { + Sema(const Sema &) = delete; + void operator=(const Sema &) = delete; + + /// Allocator for AST nodes. + llvm::BumpPtrAllocator &Allocator; + + /// Source manager for the comment being parsed. + const SourceManager &SourceMgr; + + DiagnosticsEngine &Diags; + + CommandTraits &Traits; + + const Preprocessor *PP; + + /// Information about the declaration this comment is attached to. + DeclInfo *ThisDeclInfo; + + /// Comment AST nodes that correspond to parameter names in + /// \c TemplateParameters. + /// + /// Contains a valid value if \c DeclInfo->IsFilled is true. + llvm::StringMap<TParamCommandComment *> TemplateParameterDocs; + + /// AST node for the \\brief command and its aliases. + const BlockCommandComment *BriefCommand; + + /// AST node for the \\headerfile command. + const BlockCommandComment *HeaderfileCommand; + + DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) { + return Diags.Report(Loc, DiagID); + } + + /// A stack of HTML tags that are currently open (not matched with closing + /// tags). + SmallVector<HTMLStartTagComment *, 8> HTMLOpenTags; + +public: + Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr, + DiagnosticsEngine &Diags, CommandTraits &Traits, + const Preprocessor *PP); + + void setDecl(const Decl *D); + + /// Returns a copy of array, owned by Sema's allocator. + template<typename T> + ArrayRef<T> copyArray(ArrayRef<T> Source) { + if (!Source.empty()) + return Source.copy(Allocator); + return None; + } + + ParagraphComment *actOnParagraphComment( + ArrayRef<InlineContentComment *> Content); + + BlockCommandComment *actOnBlockCommandStart(SourceLocation LocBegin, + SourceLocation LocEnd, + unsigned CommandID, + CommandMarkerKind CommandMarker); + + void actOnBlockCommandArgs(BlockCommandComment *Command, + ArrayRef<BlockCommandComment::Argument> Args); + + void actOnBlockCommandFinish(BlockCommandComment *Command, + ParagraphComment *Paragraph); + + ParamCommandComment *actOnParamCommandStart(SourceLocation LocBegin, + SourceLocation LocEnd, + unsigned CommandID, + CommandMarkerKind CommandMarker); + + void actOnParamCommandDirectionArg(ParamCommandComment *Command, + SourceLocation ArgLocBegin, + SourceLocation ArgLocEnd, + StringRef Arg); + + void actOnParamCommandParamNameArg(ParamCommandComment *Command, + SourceLocation ArgLocBegin, + SourceLocation ArgLocEnd, + StringRef Arg); + + void actOnParamCommandFinish(ParamCommandComment *Command, + ParagraphComment *Paragraph); + + TParamCommandComment *actOnTParamCommandStart(SourceLocation LocBegin, + SourceLocation LocEnd, + unsigned CommandID, + CommandMarkerKind CommandMarker); + + void actOnTParamCommandParamNameArg(TParamCommandComment *Command, + SourceLocation ArgLocBegin, + SourceLocation ArgLocEnd, + StringRef Arg); + + void actOnTParamCommandFinish(TParamCommandComment *Command, + ParagraphComment *Paragraph); + + InlineCommandComment *actOnInlineCommand(SourceLocation CommandLocBegin, + SourceLocation CommandLocEnd, + unsigned CommandID); + + InlineCommandComment *actOnInlineCommand(SourceLocation CommandLocBegin, + SourceLocation CommandLocEnd, + unsigned CommandID, + SourceLocation ArgLocBegin, + SourceLocation ArgLocEnd, + StringRef Arg); + + InlineContentComment *actOnUnknownCommand(SourceLocation LocBegin, + SourceLocation LocEnd, + StringRef CommandName); + + InlineContentComment *actOnUnknownCommand(SourceLocation LocBegin, + SourceLocation LocEnd, + unsigned CommandID); + + TextComment *actOnText(SourceLocation LocBegin, + SourceLocation LocEnd, + StringRef Text); + + VerbatimBlockComment *actOnVerbatimBlockStart(SourceLocation Loc, + unsigned CommandID); + + VerbatimBlockLineComment *actOnVerbatimBlockLine(SourceLocation Loc, + StringRef Text); + + void actOnVerbatimBlockFinish(VerbatimBlockComment *Block, + SourceLocation CloseNameLocBegin, + StringRef CloseName, + ArrayRef<VerbatimBlockLineComment *> Lines); + + VerbatimLineComment *actOnVerbatimLine(SourceLocation LocBegin, + unsigned CommandID, + SourceLocation TextBegin, + StringRef Text); + + HTMLStartTagComment *actOnHTMLStartTagStart(SourceLocation LocBegin, + StringRef TagName); + + void actOnHTMLStartTagFinish(HTMLStartTagComment *Tag, + ArrayRef<HTMLStartTagComment::Attribute> Attrs, + SourceLocation GreaterLoc, + bool IsSelfClosing); + + HTMLEndTagComment *actOnHTMLEndTag(SourceLocation LocBegin, + SourceLocation LocEnd, + StringRef TagName); + + FullComment *actOnFullComment(ArrayRef<BlockContentComment *> Blocks); + + void checkBlockCommandEmptyParagraph(BlockCommandComment *Command); + + void checkReturnsCommand(const BlockCommandComment *Command); + + /// Emit diagnostics about duplicate block commands that should be + /// used only once per comment, e.g., \\brief and \\returns. + void checkBlockCommandDuplicate(const BlockCommandComment *Command); + + void checkDeprecatedCommand(const BlockCommandComment *Comment); + + void checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment); + + void checkContainerDeclVerbatimLine(const BlockCommandComment *Comment); + + void checkContainerDecl(const BlockCommandComment *Comment); + + /// Resolve parameter names to parameter indexes in function declaration. + /// Emit diagnostics about unknown parametrs. + void resolveParamCommandIndexes(const FullComment *FC); + + bool isFunctionDecl(); + bool isAnyFunctionDecl(); + + /// \returns \c true if declaration that this comment is attached to declares + /// a function pointer. + bool isFunctionPointerVarDecl(); + bool isFunctionOrMethodVariadic(); + bool isObjCMethodDecl(); + bool isObjCPropertyDecl(); + bool isTemplateOrSpecialization(); + bool isRecordLikeDecl(); + bool isClassOrStructDecl(); + bool isUnionDecl(); + bool isObjCInterfaceDecl(); + bool isObjCProtocolDecl(); + bool isClassTemplateDecl(); + bool isFunctionTemplateDecl(); + + ArrayRef<const ParmVarDecl *> getParamVars(); + + /// Extract all important semantic information from + /// \c ThisDeclInfo->ThisDecl into \c ThisDeclInfo members. + void inspectThisDecl(); + + /// Returns index of a function parameter with a given name. + unsigned resolveParmVarReference(StringRef Name, + ArrayRef<const ParmVarDecl *> ParamVars); + + /// Returns index of a function parameter with the name closest to a given + /// typo. + unsigned correctTypoInParmVarReference(StringRef Typo, + ArrayRef<const ParmVarDecl *> ParamVars); + + bool resolveTParamReference(StringRef Name, + const TemplateParameterList *TemplateParameters, + SmallVectorImpl<unsigned> *Position); + + StringRef correctTypoInTParamReference( + StringRef Typo, + const TemplateParameterList *TemplateParameters); + + InlineCommandComment::RenderKind + getInlineCommandRenderKind(StringRef Name) const; +}; + +} // end namespace comments +} // end namespace clang + +#endif + diff --git a/contrib/llvm/tools/clang/include/clang/AST/CommentVisitor.h b/contrib/llvm/tools/clang/include/clang/AST/CommentVisitor.h new file mode 100644 index 0000000..21641bf --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/CommentVisitor.h @@ -0,0 +1,70 @@ +//===--- CommentVisitor.h - Visitor for Comment subclasses ------*- 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_AST_COMMENTVISITOR_H +#define LLVM_CLANG_AST_COMMENTVISITOR_H + +#include "clang/AST/Comment.h" +#include "llvm/Support/ErrorHandling.h" + +namespace clang { +namespace comments { + +template <typename T> struct make_ptr { typedef T *type; }; +template <typename T> struct make_const_ptr { typedef const T *type; }; + +template<template <typename> class Ptr, typename ImplClass, typename RetTy=void> +class CommentVisitorBase { +public: +#define PTR(CLASS) typename Ptr<CLASS>::type +#define DISPATCH(NAME, CLASS) \ + return static_cast<ImplClass*>(this)->visit ## NAME(static_cast<PTR(CLASS)>(C)) + + RetTy visit(PTR(Comment) C) { + if (!C) + return RetTy(); + + switch (C->getCommentKind()) { + default: llvm_unreachable("Unknown comment kind!"); +#define ABSTRACT_COMMENT(COMMENT) +#define COMMENT(CLASS, PARENT) \ + case Comment::CLASS##Kind: DISPATCH(CLASS, CLASS); +#include "clang/AST/CommentNodes.inc" +#undef ABSTRACT_COMMENT +#undef COMMENT + } + } + + // If the derived class does not implement a certain Visit* method, fall back + // on Visit* method for the superclass. +#define ABSTRACT_COMMENT(COMMENT) COMMENT +#define COMMENT(CLASS, PARENT) \ + RetTy visit ## CLASS(PTR(CLASS) C) { DISPATCH(PARENT, PARENT); } +#include "clang/AST/CommentNodes.inc" +#undef ABSTRACT_COMMENT +#undef COMMENT + + RetTy visitComment(PTR(Comment) C) { return RetTy(); } + +#undef PTR +#undef DISPATCH +}; + +template<typename ImplClass, typename RetTy=void> +class CommentVisitor : + public CommentVisitorBase<make_ptr, ImplClass, RetTy> {}; + +template<typename ImplClass, typename RetTy=void> +class ConstCommentVisitor : + public CommentVisitorBase<make_const_ptr, ImplClass, RetTy> {}; + +} // end namespace comments +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/Decl.h b/contrib/llvm/tools/clang/include/clang/AST/Decl.h new file mode 100644 index 0000000..046ce70 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/Decl.h @@ -0,0 +1,3801 @@ +//===--- Decl.h - Classes for representing declarations ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Decl subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DECL_H +#define LLVM_CLANG_AST_DECL_H + +#include "clang/AST/APValue.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/ExternalASTSource.h" +#include "clang/AST/Redeclarable.h" +#include "clang/AST/Type.h" +#include "clang/Basic/Linkage.h" +#include "clang/Basic/Module.h" +#include "clang/Basic/OperatorKinds.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/TrailingObjects.h" + +namespace clang { +struct ASTTemplateArgumentListInfo; +class CXXTemporary; +class CompoundStmt; +class DependentFunctionTemplateSpecializationInfo; +class Expr; +class FunctionTemplateDecl; +class FunctionTemplateSpecializationInfo; +class LabelStmt; +class MemberSpecializationInfo; +class NestedNameSpecifier; +class ParmVarDecl; +class Stmt; +class StringLiteral; +class TemplateArgumentList; +class TemplateParameterList; +class TypeAliasTemplateDecl; +class TypeLoc; +class UnresolvedSetImpl; +class VarTemplateDecl; + +/// \brief A container of type source information. +/// +/// A client can read the relevant info using TypeLoc wrappers, e.g: +/// @code +/// TypeLoc TL = TypeSourceInfo->getTypeLoc(); +/// TL.getStartLoc().print(OS, SrcMgr); +/// @endcode +/// +class TypeSourceInfo { + QualType Ty; + // Contains a memory block after the class, used for type source information, + // allocated by ASTContext. + friend class ASTContext; + TypeSourceInfo(QualType ty) : Ty(ty) { } +public: + /// \brief Return the type wrapped by this type source info. + QualType getType() const { return Ty; } + + /// \brief Return the TypeLoc wrapper for the type source info. + TypeLoc getTypeLoc() const; // implemented in TypeLoc.h + + /// \brief Override the type stored in this TypeSourceInfo. Use with caution! + void overrideType(QualType T) { Ty = T; } +}; + +/// TranslationUnitDecl - The top declaration context. +class TranslationUnitDecl : public Decl, public DeclContext { + virtual void anchor(); + ASTContext &Ctx; + + /// The (most recently entered) anonymous namespace for this + /// translation unit, if one has been created. + NamespaceDecl *AnonymousNamespace; + + explicit TranslationUnitDecl(ASTContext &ctx); +public: + ASTContext &getASTContext() const { return Ctx; } + + NamespaceDecl *getAnonymousNamespace() const { return AnonymousNamespace; } + void setAnonymousNamespace(NamespaceDecl *D) { AnonymousNamespace = D; } + + static TranslationUnitDecl *Create(ASTContext &C); + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == TranslationUnit; } + static DeclContext *castToDeclContext(const TranslationUnitDecl *D) { + return static_cast<DeclContext *>(const_cast<TranslationUnitDecl*>(D)); + } + static TranslationUnitDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<TranslationUnitDecl *>(const_cast<DeclContext*>(DC)); + } +}; + +/// \brief Declaration context for names declared as extern "C" in C++. This +/// is neither the semantic nor lexical context for such declarations, but is +/// used to check for conflicts with other extern "C" declarations. Example: +/// +/// \code +/// namespace N { extern "C" void f(); } // #1 +/// void N::f() {} // #2 +/// namespace M { extern "C" void f(); } // #3 +/// \endcode +/// +/// The semantic context of #1 is namespace N and its lexical context is the +/// LinkageSpecDecl; the semantic context of #2 is namespace N and its lexical +/// context is the TU. However, both declarations are also visible in the +/// extern "C" context. +/// +/// The declaration at #3 finds it is a redeclaration of \c N::f through +/// lookup in the extern "C" context. +class ExternCContextDecl : public Decl, public DeclContext { + virtual void anchor(); + + explicit ExternCContextDecl(TranslationUnitDecl *TU) + : Decl(ExternCContext, TU, SourceLocation()), + DeclContext(ExternCContext) {} +public: + static ExternCContextDecl *Create(const ASTContext &C, + TranslationUnitDecl *TU); + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == ExternCContext; } + static DeclContext *castToDeclContext(const ExternCContextDecl *D) { + return static_cast<DeclContext *>(const_cast<ExternCContextDecl*>(D)); + } + static ExternCContextDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<ExternCContextDecl *>(const_cast<DeclContext*>(DC)); + } +}; + +/// NamedDecl - This represents a decl with a name. Many decls have names such +/// as ObjCMethodDecl, but not \@class, etc. +class NamedDecl : public Decl { + virtual void anchor(); + /// Name - The name of this declaration, which is typically a normal + /// identifier but may also be a special kind of name (C++ + /// constructor, Objective-C selector, etc.) + DeclarationName Name; + +private: + NamedDecl *getUnderlyingDeclImpl() LLVM_READONLY; + +protected: + NamedDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName N) + : Decl(DK, DC, L), Name(N) { } + +public: + /// getIdentifier - Get the identifier that names this declaration, + /// if there is one. This will return NULL if this declaration has + /// no name (e.g., for an unnamed class) or if the name is a special + /// name (C++ constructor, Objective-C selector, etc.). + IdentifierInfo *getIdentifier() const { return Name.getAsIdentifierInfo(); } + + /// getName - Get the name of identifier for this declaration as a StringRef. + /// This requires that the declaration have a name and that it be a simple + /// identifier. + StringRef getName() const { + assert(Name.isIdentifier() && "Name is not a simple identifier"); + return getIdentifier() ? getIdentifier()->getName() : ""; + } + + /// getNameAsString - Get a human-readable name for the declaration, even if + /// it is one of the special kinds of names (C++ constructor, Objective-C + /// selector, etc). Creating this name requires expensive string + /// manipulation, so it should be called only when performance doesn't matter. + /// For simple declarations, getNameAsCString() should suffice. + // + // FIXME: This function should be renamed to indicate that it is not just an + // alternate form of getName(), and clients should move as appropriate. + // + // FIXME: Deprecated, move clients to getName(). + std::string getNameAsString() const { return Name.getAsString(); } + + void printName(raw_ostream &os) const { os << Name; } + + /// getDeclName - Get the actual, stored name of the declaration, + /// which may be a special name. + DeclarationName getDeclName() const { return Name; } + + /// \brief Set the name of this declaration. + void setDeclName(DeclarationName N) { Name = N; } + + /// printQualifiedName - Returns human-readable qualified name for + /// declaration, like A::B::i, for i being member of namespace A::B. + /// If declaration is not member of context which can be named (record, + /// namespace), it will return same result as printName(). + /// Creating this name is expensive, so it should be called only when + /// performance doesn't matter. + void printQualifiedName(raw_ostream &OS) const; + void printQualifiedName(raw_ostream &OS, const PrintingPolicy &Policy) const; + + // FIXME: Remove string version. + std::string getQualifiedNameAsString() const; + + /// getNameForDiagnostic - Appends a human-readable name for this + /// declaration into the given stream. + /// + /// This is the method invoked by Sema when displaying a NamedDecl + /// in a diagnostic. It does not necessarily produce the same + /// result as printName(); for example, class template + /// specializations are printed with their template arguments. + virtual void getNameForDiagnostic(raw_ostream &OS, + const PrintingPolicy &Policy, + bool Qualified) const; + + /// \brief Determine whether this declaration, if + /// known to be well-formed within its context, will replace the + /// declaration OldD if introduced into scope. A declaration will + /// replace another declaration if, for example, it is a + /// redeclaration of the same variable or function, but not if it is + /// a declaration of a different kind (function vs. class) or an + /// overloaded function. + /// + /// \param IsKnownNewer \c true if this declaration is known to be newer + /// than \p OldD (for instance, if this declaration is newly-created). + bool declarationReplaces(NamedDecl *OldD, bool IsKnownNewer = true) const; + + /// \brief Determine whether this declaration has linkage. + bool hasLinkage() const; + + using Decl::isModulePrivate; + using Decl::setModulePrivate; + + /// \brief Determine whether this declaration is hidden from name lookup. + bool isHidden() const { return Hidden; } + + /// \brief Set whether this declaration is hidden from name lookup. + void setHidden(bool Hide) { + assert((!Hide || isFromASTFile() || hasLocalOwningModuleStorage()) && + "declaration with no owning module can't be hidden"); + Hidden = Hide; + } + + /// \brief Determine whether this declaration is a C++ class member. + bool isCXXClassMember() const { + const DeclContext *DC = getDeclContext(); + + // C++0x [class.mem]p1: + // The enumerators of an unscoped enumeration defined in + // the class are members of the class. + if (isa<EnumDecl>(DC)) + DC = DC->getRedeclContext(); + + return DC->isRecord(); + } + + /// \brief Determine whether the given declaration is an instance member of + /// a C++ class. + bool isCXXInstanceMember() const; + + /// \brief Determine what kind of linkage this entity has. + /// This is not the linkage as defined by the standard or the codegen notion + /// of linkage. It is just an implementation detail that is used to compute + /// those. + Linkage getLinkageInternal() const; + + /// \brief Get the linkage from a semantic point of view. Entities in + /// anonymous namespaces are external (in c++98). + Linkage getFormalLinkage() const { + return clang::getFormalLinkage(getLinkageInternal()); + } + + /// \brief True if this decl has external linkage. + bool hasExternalFormalLinkage() const { + return isExternalFormalLinkage(getLinkageInternal()); + } + + bool isExternallyVisible() const { + return clang::isExternallyVisible(getLinkageInternal()); + } + + /// \brief Determines the visibility of this entity. + Visibility getVisibility() const { + return getLinkageAndVisibility().getVisibility(); + } + + /// \brief Determines the linkage and visibility of this entity. + LinkageInfo getLinkageAndVisibility() const; + + /// Kinds of explicit visibility. + enum ExplicitVisibilityKind { + VisibilityForType, + VisibilityForValue + }; + + /// \brief If visibility was explicitly specified for this + /// declaration, return that visibility. + Optional<Visibility> + getExplicitVisibility(ExplicitVisibilityKind kind) const; + + /// \brief True if the computed linkage is valid. Used for consistency + /// checking. Should always return true. + bool isLinkageValid() const; + + /// \brief True if something has required us to compute the linkage + /// of this declaration. + /// + /// Language features which can retroactively change linkage (like a + /// typedef name for linkage purposes) may need to consider this, + /// but hopefully only in transitory ways during parsing. + bool hasLinkageBeenComputed() const { + return hasCachedLinkage(); + } + + /// \brief Looks through UsingDecls and ObjCCompatibleAliasDecls for + /// the underlying named decl. + NamedDecl *getUnderlyingDecl() { + // Fast-path the common case. + if (this->getKind() != UsingShadow && + this->getKind() != ObjCCompatibleAlias && + this->getKind() != NamespaceAlias) + return this; + + return getUnderlyingDeclImpl(); + } + const NamedDecl *getUnderlyingDecl() const { + return const_cast<NamedDecl*>(this)->getUnderlyingDecl(); + } + + NamedDecl *getMostRecentDecl() { + return cast<NamedDecl>(static_cast<Decl *>(this)->getMostRecentDecl()); + } + const NamedDecl *getMostRecentDecl() const { + return const_cast<NamedDecl*>(this)->getMostRecentDecl(); + } + + ObjCStringFormatFamily getObjCFStringFormattingFamily() const; + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K >= firstNamed && K <= lastNamed; } +}; + +inline raw_ostream &operator<<(raw_ostream &OS, const NamedDecl &ND) { + ND.printName(OS); + return OS; +} + +/// LabelDecl - Represents the declaration of a label. Labels also have a +/// corresponding LabelStmt, which indicates the position that the label was +/// defined at. For normal labels, the location of the decl is the same as the +/// location of the statement. For GNU local labels (__label__), the decl +/// location is where the __label__ is. +class LabelDecl : public NamedDecl { + void anchor() override; + LabelStmt *TheStmt; + StringRef MSAsmName; + bool MSAsmNameResolved; + /// LocStart - For normal labels, this is the same as the main declaration + /// label, i.e., the location of the identifier; for GNU local labels, + /// this is the location of the __label__ keyword. + SourceLocation LocStart; + + LabelDecl(DeclContext *DC, SourceLocation IdentL, IdentifierInfo *II, + LabelStmt *S, SourceLocation StartL) + : NamedDecl(Label, DC, IdentL, II), + TheStmt(S), + MSAsmNameResolved(false), + LocStart(StartL) {} + +public: + static LabelDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation IdentL, IdentifierInfo *II); + static LabelDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation IdentL, IdentifierInfo *II, + SourceLocation GnuLabelL); + static LabelDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + LabelStmt *getStmt() const { return TheStmt; } + void setStmt(LabelStmt *T) { TheStmt = T; } + + bool isGnuLocal() const { return LocStart != getLocation(); } + void setLocStart(SourceLocation L) { LocStart = L; } + + SourceRange getSourceRange() const override LLVM_READONLY { + return SourceRange(LocStart, getLocation()); + } + + bool isMSAsmLabel() const { return MSAsmName.size() != 0; } + bool isResolvedMSAsmLabel() const { return isMSAsmLabel() && MSAsmNameResolved; } + void setMSAsmLabel(StringRef Name); + StringRef getMSAsmLabel() const { return MSAsmName; } + void setMSAsmLabelResolved() { MSAsmNameResolved = true; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == Label; } +}; + +/// NamespaceDecl - Represent a C++ namespace. +class NamespaceDecl : public NamedDecl, public DeclContext, + public Redeclarable<NamespaceDecl> +{ + /// LocStart - The starting location of the source range, pointing + /// to either the namespace or the inline keyword. + SourceLocation LocStart; + /// RBraceLoc - The ending location of the source range. + SourceLocation RBraceLoc; + + /// \brief A pointer to either the anonymous namespace that lives just inside + /// this namespace or to the first namespace in the chain (the latter case + /// only when this is not the first in the chain), along with a + /// boolean value indicating whether this is an inline namespace. + llvm::PointerIntPair<NamespaceDecl *, 1, bool> AnonOrFirstNamespaceAndInline; + + NamespaceDecl(ASTContext &C, DeclContext *DC, bool Inline, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, NamespaceDecl *PrevDecl); + + typedef Redeclarable<NamespaceDecl> redeclarable_base; + NamespaceDecl *getNextRedeclarationImpl() override; + NamespaceDecl *getPreviousDeclImpl() override; + NamespaceDecl *getMostRecentDeclImpl() override; + +public: + static NamespaceDecl *Create(ASTContext &C, DeclContext *DC, + bool Inline, SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + NamespaceDecl *PrevDecl); + + static NamespaceDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + typedef redeclarable_base::redecl_range redecl_range; + typedef redeclarable_base::redecl_iterator redecl_iterator; + using redeclarable_base::redecls_begin; + using redeclarable_base::redecls_end; + using redeclarable_base::redecls; + using redeclarable_base::getPreviousDecl; + using redeclarable_base::getMostRecentDecl; + using redeclarable_base::isFirstDecl; + + /// \brief Returns true if this is an anonymous namespace declaration. + /// + /// For example: + /// \code + /// namespace { + /// ... + /// }; + /// \endcode + /// q.v. C++ [namespace.unnamed] + bool isAnonymousNamespace() const { + return !getIdentifier(); + } + + /// \brief Returns true if this is an inline namespace declaration. + bool isInline() const { + return AnonOrFirstNamespaceAndInline.getInt(); + } + + /// \brief Set whether this is an inline namespace declaration. + void setInline(bool Inline) { + AnonOrFirstNamespaceAndInline.setInt(Inline); + } + + /// \brief Get the original (first) namespace declaration. + NamespaceDecl *getOriginalNamespace(); + + /// \brief Get the original (first) namespace declaration. + const NamespaceDecl *getOriginalNamespace() const; + + /// \brief Return true if this declaration is an original (first) declaration + /// of the namespace. This is false for non-original (subsequent) namespace + /// declarations and anonymous namespaces. + bool isOriginalNamespace() const; + + /// \brief Retrieve the anonymous namespace nested inside this namespace, + /// if any. + NamespaceDecl *getAnonymousNamespace() const { + return getOriginalNamespace()->AnonOrFirstNamespaceAndInline.getPointer(); + } + + void setAnonymousNamespace(NamespaceDecl *D) { + getOriginalNamespace()->AnonOrFirstNamespaceAndInline.setPointer(D); + } + + /// Retrieves the canonical declaration of this namespace. + NamespaceDecl *getCanonicalDecl() override { + return getOriginalNamespace(); + } + const NamespaceDecl *getCanonicalDecl() const { + return getOriginalNamespace(); + } + + SourceRange getSourceRange() const override LLVM_READONLY { + return SourceRange(LocStart, RBraceLoc); + } + + SourceLocation getLocStart() const LLVM_READONLY { return LocStart; } + SourceLocation getRBraceLoc() const { return RBraceLoc; } + void setLocStart(SourceLocation L) { LocStart = L; } + void setRBraceLoc(SourceLocation L) { RBraceLoc = L; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == Namespace; } + static DeclContext *castToDeclContext(const NamespaceDecl *D) { + return static_cast<DeclContext *>(const_cast<NamespaceDecl*>(D)); + } + static NamespaceDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<NamespaceDecl *>(const_cast<DeclContext*>(DC)); + } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// ValueDecl - Represent the declaration of a variable (in which case it is +/// an lvalue) a function (in which case it is a function designator) or +/// an enum constant. +class ValueDecl : public NamedDecl { + void anchor() override; + QualType DeclType; + +protected: + ValueDecl(Kind DK, DeclContext *DC, SourceLocation L, + DeclarationName N, QualType T) + : NamedDecl(DK, DC, L, N), DeclType(T) {} +public: + QualType getType() const { return DeclType; } + void setType(QualType newType) { DeclType = newType; } + + /// \brief Determine whether this symbol is weakly-imported, + /// or declared with the weak or weak-ref attr. + bool isWeak() const; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K >= firstValue && K <= lastValue; } +}; + +/// QualifierInfo - A struct with extended info about a syntactic +/// name qualifier, to be used for the case of out-of-line declarations. +struct QualifierInfo { + NestedNameSpecifierLoc QualifierLoc; + + /// NumTemplParamLists - The number of "outer" template parameter lists. + /// The count includes all of the template parameter lists that were matched + /// against the template-ids occurring into the NNS and possibly (in the + /// case of an explicit specialization) a final "template <>". + unsigned NumTemplParamLists; + + /// TemplParamLists - A new-allocated array of size NumTemplParamLists, + /// containing pointers to the "outer" template parameter lists. + /// It includes all of the template parameter lists that were matched + /// against the template-ids occurring into the NNS and possibly (in the + /// case of an explicit specialization) a final "template <>". + TemplateParameterList** TemplParamLists; + + /// Default constructor. + QualifierInfo() + : QualifierLoc(), NumTemplParamLists(0), TemplParamLists(nullptr) {} + + /// setTemplateParameterListsInfo - Sets info about "outer" template + /// parameter lists. + void setTemplateParameterListsInfo(ASTContext &Context, + ArrayRef<TemplateParameterList *> TPLists); + +private: + // Copy constructor and copy assignment are disabled. + QualifierInfo(const QualifierInfo&) = delete; + QualifierInfo& operator=(const QualifierInfo&) = delete; +}; + +/// \brief Represents a ValueDecl that came out of a declarator. +/// Contains type source information through TypeSourceInfo. +class DeclaratorDecl : public ValueDecl { + // A struct representing both a TInfo and a syntactic qualifier, + // to be used for the (uncommon) case of out-of-line declarations. + struct ExtInfo : public QualifierInfo { + TypeSourceInfo *TInfo; + }; + + llvm::PointerUnion<TypeSourceInfo*, ExtInfo*> DeclInfo; + + /// InnerLocStart - The start of the source range for this declaration, + /// ignoring outer template declarations. + SourceLocation InnerLocStart; + + bool hasExtInfo() const { return DeclInfo.is<ExtInfo*>(); } + ExtInfo *getExtInfo() { return DeclInfo.get<ExtInfo*>(); } + const ExtInfo *getExtInfo() const { return DeclInfo.get<ExtInfo*>(); } + +protected: + DeclaratorDecl(Kind DK, DeclContext *DC, SourceLocation L, + DeclarationName N, QualType T, TypeSourceInfo *TInfo, + SourceLocation StartL) + : ValueDecl(DK, DC, L, N, T), DeclInfo(TInfo), InnerLocStart(StartL) { + } + +public: + TypeSourceInfo *getTypeSourceInfo() const { + return hasExtInfo() + ? getExtInfo()->TInfo + : DeclInfo.get<TypeSourceInfo*>(); + } + void setTypeSourceInfo(TypeSourceInfo *TI) { + if (hasExtInfo()) + getExtInfo()->TInfo = TI; + else + DeclInfo = TI; + } + + /// getInnerLocStart - Return SourceLocation representing start of source + /// range ignoring outer template declarations. + SourceLocation getInnerLocStart() const { return InnerLocStart; } + void setInnerLocStart(SourceLocation L) { InnerLocStart = L; } + + /// getOuterLocStart - Return SourceLocation representing start of source + /// range taking into account any outer template declarations. + SourceLocation getOuterLocStart() const; + + SourceRange getSourceRange() const override LLVM_READONLY; + SourceLocation getLocStart() const LLVM_READONLY { + return getOuterLocStart(); + } + + /// \brief Retrieve the nested-name-specifier that qualifies the name of this + /// declaration, if it was present in the source. + NestedNameSpecifier *getQualifier() const { + return hasExtInfo() ? getExtInfo()->QualifierLoc.getNestedNameSpecifier() + : nullptr; + } + + /// \brief Retrieve the nested-name-specifier (with source-location + /// information) that qualifies the name of this declaration, if it was + /// present in the source. + NestedNameSpecifierLoc getQualifierLoc() const { + return hasExtInfo() ? getExtInfo()->QualifierLoc + : NestedNameSpecifierLoc(); + } + + void setQualifierInfo(NestedNameSpecifierLoc QualifierLoc); + + unsigned getNumTemplateParameterLists() const { + return hasExtInfo() ? getExtInfo()->NumTemplParamLists : 0; + } + TemplateParameterList *getTemplateParameterList(unsigned index) const { + assert(index < getNumTemplateParameterLists()); + return getExtInfo()->TemplParamLists[index]; + } + void setTemplateParameterListsInfo(ASTContext &Context, + ArrayRef<TemplateParameterList *> TPLists); + + SourceLocation getTypeSpecStartLoc() const; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { + return K >= firstDeclarator && K <= lastDeclarator; + } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// \brief Structure used to store a statement, the constant value to +/// which it was evaluated (if any), and whether or not the statement +/// is an integral constant expression (if known). +struct EvaluatedStmt { + EvaluatedStmt() : WasEvaluated(false), IsEvaluating(false), CheckedICE(false), + CheckingICE(false), IsICE(false) { } + + /// \brief Whether this statement was already evaluated. + bool WasEvaluated : 1; + + /// \brief Whether this statement is being evaluated. + bool IsEvaluating : 1; + + /// \brief Whether we already checked whether this statement was an + /// integral constant expression. + bool CheckedICE : 1; + + /// \brief Whether we are checking whether this statement is an + /// integral constant expression. + bool CheckingICE : 1; + + /// \brief Whether this statement is an integral constant expression, + /// or in C++11, whether the statement is a constant expression. Only + /// valid if CheckedICE is true. + bool IsICE : 1; + + Stmt *Value; + APValue Evaluated; +}; + +/// VarDecl - An instance of this class is created to represent a variable +/// declaration or definition. +class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> { +public: + /// getStorageClassSpecifierString - Return the string used to + /// specify the storage class \p SC. + /// + /// It is illegal to call this function with SC == None. + static const char *getStorageClassSpecifierString(StorageClass SC); + + /// \brief Initialization styles. + enum InitializationStyle { + CInit, ///< C-style initialization with assignment + CallInit, ///< Call-style initialization (C++98) + ListInit ///< Direct list-initialization (C++11) + }; + + /// \brief Kinds of thread-local storage. + enum TLSKind { + TLS_None, ///< Not a TLS variable. + TLS_Static, ///< TLS with a known-constant initializer. + TLS_Dynamic ///< TLS with a dynamic initializer. + }; + +protected: + // A pointer union of Stmt * and EvaluatedStmt *. When an EvaluatedStmt, we + // have allocated the auxilliary struct of information there. + // + // TODO: It is a bit unfortunate to use a PointerUnion inside the VarDecl for + // this as *many* VarDecls are ParmVarDecls that don't have default + // arguments. We could save some space by moving this pointer union to be + // allocated in trailing space when necessary. + typedef llvm::PointerUnion<Stmt *, EvaluatedStmt *> InitType; + + /// \brief The initializer for this variable or, for a ParmVarDecl, the + /// C++ default argument. + mutable InitType Init; + +private: + class VarDeclBitfields { + friend class VarDecl; + friend class ASTDeclReader; + + unsigned SClass : 3; + unsigned TSCSpec : 2; + unsigned InitStyle : 2; + }; + enum { NumVarDeclBits = 7 }; + + friend class ASTDeclReader; + friend class StmtIteratorBase; + friend class ASTNodeImporter; + +protected: + enum { NumParameterIndexBits = 8 }; + + enum DefaultArgKind { + DAK_None, + DAK_Unparsed, + DAK_Uninstantiated, + DAK_Normal + }; + + class ParmVarDeclBitfields { + friend class ParmVarDecl; + friend class ASTDeclReader; + + unsigned : NumVarDeclBits; + + /// Whether this parameter inherits a default argument from a + /// prior declaration. + unsigned HasInheritedDefaultArg : 1; + + /// Describes the kind of default argument for this parameter. By default + /// this is none. If this is normal, then the default argument is stored in + /// the \c VarDecl initalizer expression unless we were unble to parse + /// (even an invalid) expression for the default argument. + unsigned DefaultArgKind : 2; + + /// Whether this parameter undergoes K&R argument promotion. + unsigned IsKNRPromoted : 1; + + /// Whether this parameter is an ObjC method parameter or not. + unsigned IsObjCMethodParam : 1; + + /// If IsObjCMethodParam, a Decl::ObjCDeclQualifier. + /// Otherwise, the number of function parameter scopes enclosing + /// the function parameter scope in which this parameter was + /// declared. + unsigned ScopeDepthOrObjCQuals : 7; + + /// The number of parameters preceding this parameter in the + /// function parameter scope in which it was declared. + unsigned ParameterIndex : NumParameterIndexBits; + }; + + class NonParmVarDeclBitfields { + friend class VarDecl; + friend class ASTDeclReader; + + unsigned : NumVarDeclBits; + + /// \brief Whether this variable is the exception variable in a C++ catch + /// or an Objective-C @catch statement. + unsigned ExceptionVar : 1; + + /// \brief Whether this local variable could be allocated in the return + /// slot of its function, enabling the named return value optimization + /// (NRVO). + unsigned NRVOVariable : 1; + + /// \brief Whether this variable is the for-range-declaration in a C++0x + /// for-range statement. + unsigned CXXForRangeDecl : 1; + + /// \brief Whether this variable is an ARC pseudo-__strong + /// variable; see isARCPseudoStrong() for details. + unsigned ARCPseudoStrong : 1; + + /// \brief Whether this variable is (C++0x) constexpr. + unsigned IsConstexpr : 1; + + /// \brief Whether this variable is a (C++ Concepts TS) concept. + unsigned IsConcept : 1; + + /// \brief Whether this variable is the implicit variable for a lambda + /// init-capture. + unsigned IsInitCapture : 1; + + /// \brief Whether this local extern variable's previous declaration was + /// declared in the same block scope. This controls whether we should merge + /// the type of this declaration with its previous declaration. + unsigned PreviousDeclInSameBlockScope : 1; + }; + + union { + unsigned AllBits; + VarDeclBitfields VarDeclBits; + ParmVarDeclBitfields ParmVarDeclBits; + NonParmVarDeclBitfields NonParmVarDeclBits; + }; + + VarDecl(Kind DK, ASTContext &C, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, QualType T, + TypeSourceInfo *TInfo, StorageClass SC); + + typedef Redeclarable<VarDecl> redeclarable_base; + VarDecl *getNextRedeclarationImpl() override { + return getNextRedeclaration(); + } + VarDecl *getPreviousDeclImpl() override { + return getPreviousDecl(); + } + VarDecl *getMostRecentDeclImpl() override { + return getMostRecentDecl(); + } + +public: + typedef redeclarable_base::redecl_range redecl_range; + typedef redeclarable_base::redecl_iterator redecl_iterator; + using redeclarable_base::redecls_begin; + using redeclarable_base::redecls_end; + using redeclarable_base::redecls; + using redeclarable_base::getPreviousDecl; + using redeclarable_base::getMostRecentDecl; + using redeclarable_base::isFirstDecl; + + static VarDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, + StorageClass S); + + static VarDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + SourceRange getSourceRange() const override LLVM_READONLY; + + /// \brief Returns the storage class as written in the source. For the + /// computed linkage of symbol, see getLinkage. + StorageClass getStorageClass() const { + return (StorageClass) VarDeclBits.SClass; + } + void setStorageClass(StorageClass SC); + + void setTSCSpec(ThreadStorageClassSpecifier TSC) { + VarDeclBits.TSCSpec = TSC; + assert(VarDeclBits.TSCSpec == TSC && "truncation"); + } + ThreadStorageClassSpecifier getTSCSpec() const { + return static_cast<ThreadStorageClassSpecifier>(VarDeclBits.TSCSpec); + } + TLSKind getTLSKind() const; + + /// hasLocalStorage - Returns true if a variable with function scope + /// is a non-static local variable. + bool hasLocalStorage() const { + if (getStorageClass() == SC_None) + // Second check is for C++11 [dcl.stc]p4. + return !isFileVarDecl() && getTSCSpec() == TSCS_unspecified; + + // Global Named Register (GNU extension) + if (getStorageClass() == SC_Register && !isLocalVarDeclOrParm()) + return false; + + // Return true for: Auto, Register. + // Return false for: Extern, Static, PrivateExtern, OpenCLWorkGroupLocal. + + return getStorageClass() >= SC_Auto; + } + + /// isStaticLocal - Returns true if a variable with function scope is a + /// static local variable. + bool isStaticLocal() const { + return (getStorageClass() == SC_Static || + // C++11 [dcl.stc]p4 + (getStorageClass() == SC_None && getTSCSpec() == TSCS_thread_local)) + && !isFileVarDecl(); + } + + /// \brief Returns true if a variable has extern or __private_extern__ + /// storage. + bool hasExternalStorage() const { + return getStorageClass() == SC_Extern || + getStorageClass() == SC_PrivateExtern; + } + + /// \brief Returns true for all variables that do not have local storage. + /// + /// This includes all global variables as well as static variables declared + /// within a function. + bool hasGlobalStorage() const { return !hasLocalStorage(); } + + /// \brief Get the storage duration of this variable, per C++ [basic.stc]. + StorageDuration getStorageDuration() const { + return hasLocalStorage() ? SD_Automatic : + getTSCSpec() ? SD_Thread : SD_Static; + } + + /// \brief Compute the language linkage. + LanguageLinkage getLanguageLinkage() const; + + /// \brief Determines whether this variable is a variable with + /// external, C linkage. + bool isExternC() const; + + /// \brief Determines whether this variable's context is, or is nested within, + /// a C++ extern "C" linkage spec. + bool isInExternCContext() const; + + /// \brief Determines whether this variable's context is, or is nested within, + /// a C++ extern "C++" linkage spec. + bool isInExternCXXContext() const; + + /// isLocalVarDecl - Returns true for local variable declarations + /// other than parameters. Note that this includes static variables + /// inside of functions. It also includes variables inside blocks. + /// + /// void foo() { int x; static int y; extern int z; } + /// + bool isLocalVarDecl() const { + if (getKind() != Decl::Var) + return false; + if (const DeclContext *DC = getLexicalDeclContext()) + return DC->getRedeclContext()->isFunctionOrMethod(); + return false; + } + + /// \brief Similar to isLocalVarDecl but also includes parameters. + bool isLocalVarDeclOrParm() const { + return isLocalVarDecl() || getKind() == Decl::ParmVar; + } + + /// isFunctionOrMethodVarDecl - Similar to isLocalVarDecl, but + /// excludes variables declared in blocks. + bool isFunctionOrMethodVarDecl() const { + if (getKind() != Decl::Var) + return false; + const DeclContext *DC = getLexicalDeclContext()->getRedeclContext(); + return DC->isFunctionOrMethod() && DC->getDeclKind() != Decl::Block; + } + + /// \brief Determines whether this is a static data member. + /// + /// This will only be true in C++, and applies to, e.g., the + /// variable 'x' in: + /// \code + /// struct S { + /// static int x; + /// }; + /// \endcode + bool isStaticDataMember() const { + // If it wasn't static, it would be a FieldDecl. + return getKind() != Decl::ParmVar && getDeclContext()->isRecord(); + } + + VarDecl *getCanonicalDecl() override; + const VarDecl *getCanonicalDecl() const { + return const_cast<VarDecl*>(this)->getCanonicalDecl(); + } + + enum DefinitionKind { + DeclarationOnly, ///< This declaration is only a declaration. + TentativeDefinition, ///< This declaration is a tentative definition. + Definition ///< This declaration is definitely a definition. + }; + + /// \brief Check whether this declaration is a definition. If this could be + /// a tentative definition (in C), don't check whether there's an overriding + /// definition. + DefinitionKind isThisDeclarationADefinition(ASTContext &) const; + DefinitionKind isThisDeclarationADefinition() const { + return isThisDeclarationADefinition(getASTContext()); + } + + /// \brief Check whether this variable is defined in this + /// translation unit. + DefinitionKind hasDefinition(ASTContext &) const; + DefinitionKind hasDefinition() const { + return hasDefinition(getASTContext()); + } + + /// \brief Get the tentative definition that acts as the real definition in + /// a TU. Returns null if there is a proper definition available. + VarDecl *getActingDefinition(); + const VarDecl *getActingDefinition() const { + return const_cast<VarDecl*>(this)->getActingDefinition(); + } + + /// \brief Get the real (not just tentative) definition for this declaration. + VarDecl *getDefinition(ASTContext &); + const VarDecl *getDefinition(ASTContext &C) const { + return const_cast<VarDecl*>(this)->getDefinition(C); + } + VarDecl *getDefinition() { + return getDefinition(getASTContext()); + } + const VarDecl *getDefinition() const { + return const_cast<VarDecl*>(this)->getDefinition(); + } + + /// \brief Determine whether this is or was instantiated from an out-of-line + /// definition of a static data member. + bool isOutOfLine() const override; + + /// \brief If this is a static data member, find its out-of-line definition. + VarDecl *getOutOfLineDefinition(); + + /// isFileVarDecl - Returns true for file scoped variable declaration. + bool isFileVarDecl() const { + Kind K = getKind(); + if (K == ParmVar || K == ImplicitParam) + return false; + + if (getLexicalDeclContext()->getRedeclContext()->isFileContext()) + return true; + + if (isStaticDataMember()) + return true; + + return false; + } + + /// getAnyInitializer - Get the initializer for this variable, no matter which + /// declaration it is attached to. + const Expr *getAnyInitializer() const { + const VarDecl *D; + return getAnyInitializer(D); + } + + /// getAnyInitializer - Get the initializer for this variable, no matter which + /// declaration it is attached to. Also get that declaration. + const Expr *getAnyInitializer(const VarDecl *&D) const; + + bool hasInit() const; + const Expr *getInit() const { + return const_cast<VarDecl *>(this)->getInit(); + } + Expr *getInit(); + + /// \brief Retrieve the address of the initializer expression. + Stmt **getInitAddress(); + + void setInit(Expr *I); + + /// \brief Determine whether this variable's value can be used in a + /// constant expression, according to the relevant language standard. + /// This only checks properties of the declaration, and does not check + /// whether the initializer is in fact a constant expression. + bool isUsableInConstantExpressions(ASTContext &C) const; + + EvaluatedStmt *ensureEvaluatedStmt() const; + + /// \brief Attempt to evaluate the value of the initializer attached to this + /// declaration, and produce notes explaining why it cannot be evaluated or is + /// not a constant expression. Returns a pointer to the value if evaluation + /// succeeded, 0 otherwise. + APValue *evaluateValue() const; + APValue *evaluateValue(SmallVectorImpl<PartialDiagnosticAt> &Notes) const; + + /// \brief Return the already-evaluated value of this variable's + /// initializer, or NULL if the value is not yet known. Returns pointer + /// to untyped APValue if the value could not be evaluated. + APValue *getEvaluatedValue() const; + + /// \brief Determines whether it is already known whether the + /// initializer is an integral constant expression or not. + bool isInitKnownICE() const; + + /// \brief Determines whether the initializer is an integral constant + /// expression, or in C++11, whether the initializer is a constant + /// expression. + /// + /// \pre isInitKnownICE() + bool isInitICE() const; + + /// \brief Determine whether the value of the initializer attached to this + /// declaration is an integral constant expression. + bool checkInitIsICE() const; + + void setInitStyle(InitializationStyle Style) { + VarDeclBits.InitStyle = Style; + } + + /// \brief The style of initialization for this declaration. + /// + /// C-style initialization is "int x = 1;". Call-style initialization is + /// a C++98 direct-initializer, e.g. "int x(1);". The Init expression will be + /// the expression inside the parens or a "ClassType(a,b,c)" class constructor + /// expression for class types. List-style initialization is C++11 syntax, + /// e.g. "int x{1};". Clients can distinguish between different forms of + /// initialization by checking this value. In particular, "int x = {1};" is + /// C-style, "int x({1})" is call-style, and "int x{1};" is list-style; the + /// Init expression in all three cases is an InitListExpr. + InitializationStyle getInitStyle() const { + return static_cast<InitializationStyle>(VarDeclBits.InitStyle); + } + + /// \brief Whether the initializer is a direct-initializer (list or call). + bool isDirectInit() const { + return getInitStyle() != CInit; + } + + /// \brief Determine whether this variable is the exception variable in a + /// C++ catch statememt or an Objective-C \@catch statement. + bool isExceptionVariable() const { + return isa<ParmVarDecl>(this) ? false : NonParmVarDeclBits.ExceptionVar; + } + void setExceptionVariable(bool EV) { + assert(!isa<ParmVarDecl>(this)); + NonParmVarDeclBits.ExceptionVar = EV; + } + + /// \brief Determine whether this local variable can be used with the named + /// return value optimization (NRVO). + /// + /// The named return value optimization (NRVO) works by marking certain + /// non-volatile local variables of class type as NRVO objects. These + /// locals can be allocated within the return slot of their containing + /// function, in which case there is no need to copy the object to the + /// return slot when returning from the function. Within the function body, + /// each return that returns the NRVO object will have this variable as its + /// NRVO candidate. + bool isNRVOVariable() const { + return isa<ParmVarDecl>(this) ? false : NonParmVarDeclBits.NRVOVariable; + } + void setNRVOVariable(bool NRVO) { + assert(!isa<ParmVarDecl>(this)); + NonParmVarDeclBits.NRVOVariable = NRVO; + } + + /// \brief Determine whether this variable is the for-range-declaration in + /// a C++0x for-range statement. + bool isCXXForRangeDecl() const { + return isa<ParmVarDecl>(this) ? false : NonParmVarDeclBits.CXXForRangeDecl; + } + void setCXXForRangeDecl(bool FRD) { + assert(!isa<ParmVarDecl>(this)); + NonParmVarDeclBits.CXXForRangeDecl = FRD; + } + + /// \brief Determine whether this variable is an ARC pseudo-__strong + /// variable. A pseudo-__strong variable has a __strong-qualified + /// type but does not actually retain the object written into it. + /// Generally such variables are also 'const' for safety. + bool isARCPseudoStrong() const { + return isa<ParmVarDecl>(this) ? false : NonParmVarDeclBits.ARCPseudoStrong; + } + void setARCPseudoStrong(bool ps) { + assert(!isa<ParmVarDecl>(this)); + NonParmVarDeclBits.ARCPseudoStrong = ps; + } + + /// Whether this variable is (C++11) constexpr. + bool isConstexpr() const { + return isa<ParmVarDecl>(this) ? false : NonParmVarDeclBits.IsConstexpr; + } + void setConstexpr(bool IC) { + assert(!isa<ParmVarDecl>(this)); + NonParmVarDeclBits.IsConstexpr = IC; + } + + /// Whether this variable is (C++ Concepts TS) concept. + bool isConcept() const { + return isa<ParmVarDecl>(this) ? false : NonParmVarDeclBits.IsConcept; + } + void setConcept(bool IC) { + assert(!isa<ParmVarDecl>(this)); + NonParmVarDeclBits.IsConcept = IC; + } + + /// Whether this variable is the implicit variable for a lambda init-capture. + bool isInitCapture() const { + return isa<ParmVarDecl>(this) ? false : NonParmVarDeclBits.IsInitCapture; + } + void setInitCapture(bool IC) { + assert(!isa<ParmVarDecl>(this)); + NonParmVarDeclBits.IsInitCapture = IC; + } + + /// Whether this local extern variable declaration's previous declaration + /// was declared in the same block scope. Only correct in C++. + bool isPreviousDeclInSameBlockScope() const { + return isa<ParmVarDecl>(this) + ? false + : NonParmVarDeclBits.PreviousDeclInSameBlockScope; + } + void setPreviousDeclInSameBlockScope(bool Same) { + assert(!isa<ParmVarDecl>(this)); + NonParmVarDeclBits.PreviousDeclInSameBlockScope = Same; + } + + /// \brief If this variable is an instantiated static data member of a + /// class template specialization, returns the templated static data member + /// from which it was instantiated. + VarDecl *getInstantiatedFromStaticDataMember() const; + + /// \brief If this variable is an instantiation of a variable template or a + /// static data member of a class template, determine what kind of + /// template specialization or instantiation this is. + TemplateSpecializationKind getTemplateSpecializationKind() const; + + /// \brief If this variable is an instantiation of a variable template or a + /// static data member of a class template, determine its point of + /// instantiation. + SourceLocation getPointOfInstantiation() const; + + /// \brief If this variable is an instantiation of a static data member of a + /// class template specialization, retrieves the member specialization + /// information. + MemberSpecializationInfo *getMemberSpecializationInfo() const; + + /// \brief For a static data member that was instantiated from a static + /// data member of a class template, set the template specialiation kind. + void setTemplateSpecializationKind(TemplateSpecializationKind TSK, + SourceLocation PointOfInstantiation = SourceLocation()); + + /// \brief Specify that this variable is an instantiation of the + /// static data member VD. + void setInstantiationOfStaticDataMember(VarDecl *VD, + TemplateSpecializationKind TSK); + + /// \brief Retrieves the variable template that is described by this + /// variable declaration. + /// + /// Every variable template is represented as a VarTemplateDecl and a + /// VarDecl. The former contains template properties (such as + /// the template parameter lists) while the latter contains the + /// actual description of the template's + /// contents. VarTemplateDecl::getTemplatedDecl() retrieves the + /// VarDecl that from a VarTemplateDecl, while + /// getDescribedVarTemplate() retrieves the VarTemplateDecl from + /// a VarDecl. + VarTemplateDecl *getDescribedVarTemplate() const; + + void setDescribedVarTemplate(VarTemplateDecl *Template); + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K >= firstVar && K <= lastVar; } +}; + +class ImplicitParamDecl : public VarDecl { + void anchor() override; +public: + static ImplicitParamDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation IdLoc, IdentifierInfo *Id, + QualType T); + + static ImplicitParamDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + ImplicitParamDecl(ASTContext &C, DeclContext *DC, SourceLocation IdLoc, + IdentifierInfo *Id, QualType Type) + : VarDecl(ImplicitParam, C, DC, IdLoc, IdLoc, Id, Type, + /*tinfo*/ nullptr, SC_None) { + setImplicit(); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == ImplicitParam; } +}; + +/// ParmVarDecl - Represents a parameter to a function. +class ParmVarDecl : public VarDecl { +public: + enum { MaxFunctionScopeDepth = 255 }; + enum { MaxFunctionScopeIndex = 255 }; + +protected: + ParmVarDecl(Kind DK, ASTContext &C, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, QualType T, + TypeSourceInfo *TInfo, StorageClass S, Expr *DefArg) + : VarDecl(DK, C, DC, StartLoc, IdLoc, Id, T, TInfo, S) { + assert(ParmVarDeclBits.HasInheritedDefaultArg == false); + assert(ParmVarDeclBits.DefaultArgKind == DAK_None); + assert(ParmVarDeclBits.IsKNRPromoted == false); + assert(ParmVarDeclBits.IsObjCMethodParam == false); + setDefaultArg(DefArg); + } + +public: + static ParmVarDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + QualType T, TypeSourceInfo *TInfo, + StorageClass S, Expr *DefArg); + + static ParmVarDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + SourceRange getSourceRange() const override LLVM_READONLY; + + void setObjCMethodScopeInfo(unsigned parameterIndex) { + ParmVarDeclBits.IsObjCMethodParam = true; + setParameterIndex(parameterIndex); + } + + void setScopeInfo(unsigned scopeDepth, unsigned parameterIndex) { + assert(!ParmVarDeclBits.IsObjCMethodParam); + + ParmVarDeclBits.ScopeDepthOrObjCQuals = scopeDepth; + assert(ParmVarDeclBits.ScopeDepthOrObjCQuals == scopeDepth + && "truncation!"); + + setParameterIndex(parameterIndex); + } + + bool isObjCMethodParameter() const { + return ParmVarDeclBits.IsObjCMethodParam; + } + + unsigned getFunctionScopeDepth() const { + if (ParmVarDeclBits.IsObjCMethodParam) return 0; + return ParmVarDeclBits.ScopeDepthOrObjCQuals; + } + + /// Returns the index of this parameter in its prototype or method scope. + unsigned getFunctionScopeIndex() const { + return getParameterIndex(); + } + + ObjCDeclQualifier getObjCDeclQualifier() const { + if (!ParmVarDeclBits.IsObjCMethodParam) return OBJC_TQ_None; + return ObjCDeclQualifier(ParmVarDeclBits.ScopeDepthOrObjCQuals); + } + void setObjCDeclQualifier(ObjCDeclQualifier QTVal) { + assert(ParmVarDeclBits.IsObjCMethodParam); + ParmVarDeclBits.ScopeDepthOrObjCQuals = QTVal; + } + + /// True if the value passed to this parameter must undergo + /// K&R-style default argument promotion: + /// + /// C99 6.5.2.2. + /// If the expression that denotes the called function has a type + /// that does not include a prototype, the integer promotions are + /// performed on each argument, and arguments that have type float + /// are promoted to double. + bool isKNRPromoted() const { + return ParmVarDeclBits.IsKNRPromoted; + } + void setKNRPromoted(bool promoted) { + ParmVarDeclBits.IsKNRPromoted = promoted; + } + + Expr *getDefaultArg(); + const Expr *getDefaultArg() const { + return const_cast<ParmVarDecl *>(this)->getDefaultArg(); + } + + void setDefaultArg(Expr *defarg); + + /// \brief Retrieve the source range that covers the entire default + /// argument. + SourceRange getDefaultArgRange() const; + void setUninstantiatedDefaultArg(Expr *arg); + Expr *getUninstantiatedDefaultArg(); + const Expr *getUninstantiatedDefaultArg() const { + return const_cast<ParmVarDecl *>(this)->getUninstantiatedDefaultArg(); + } + + /// hasDefaultArg - Determines whether this parameter has a default argument, + /// either parsed or not. + bool hasDefaultArg() const; + + /// hasUnparsedDefaultArg - Determines whether this parameter has a + /// default argument that has not yet been parsed. This will occur + /// during the processing of a C++ class whose member functions have + /// default arguments, e.g., + /// @code + /// class X { + /// public: + /// void f(int x = 17); // x has an unparsed default argument now + /// }; // x has a regular default argument now + /// @endcode + bool hasUnparsedDefaultArg() const { + return ParmVarDeclBits.DefaultArgKind == DAK_Unparsed; + } + + bool hasUninstantiatedDefaultArg() const { + return ParmVarDeclBits.DefaultArgKind == DAK_Uninstantiated; + } + + /// setUnparsedDefaultArg - Specify that this parameter has an + /// unparsed default argument. The argument will be replaced with a + /// real default argument via setDefaultArg when the class + /// definition enclosing the function declaration that owns this + /// default argument is completed. + void setUnparsedDefaultArg() { + ParmVarDeclBits.DefaultArgKind = DAK_Unparsed; + } + + bool hasInheritedDefaultArg() const { + return ParmVarDeclBits.HasInheritedDefaultArg; + } + + void setHasInheritedDefaultArg(bool I = true) { + ParmVarDeclBits.HasInheritedDefaultArg = I; + } + + QualType getOriginalType() const; + + /// \brief Determine whether this parameter is actually a function + /// parameter pack. + bool isParameterPack() const; + + /// setOwningFunction - Sets the function declaration that owns this + /// ParmVarDecl. Since ParmVarDecls are often created before the + /// FunctionDecls that own them, this routine is required to update + /// the DeclContext appropriately. + void setOwningFunction(DeclContext *FD) { setDeclContext(FD); } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == ParmVar; } + +private: + enum { ParameterIndexSentinel = (1 << NumParameterIndexBits) - 1 }; + + void setParameterIndex(unsigned parameterIndex) { + if (parameterIndex >= ParameterIndexSentinel) { + setParameterIndexLarge(parameterIndex); + return; + } + + ParmVarDeclBits.ParameterIndex = parameterIndex; + assert(ParmVarDeclBits.ParameterIndex == parameterIndex && "truncation!"); + } + unsigned getParameterIndex() const { + unsigned d = ParmVarDeclBits.ParameterIndex; + return d == ParameterIndexSentinel ? getParameterIndexLarge() : d; + } + + void setParameterIndexLarge(unsigned parameterIndex); + unsigned getParameterIndexLarge() const; +}; + +/// FunctionDecl - An instance of this class is created to represent a +/// function declaration or definition. +/// +/// Since a given function can be declared several times in a program, +/// there may be several FunctionDecls that correspond to that +/// function. Only one of those FunctionDecls will be found when +/// traversing the list of declarations in the context of the +/// FunctionDecl (e.g., the translation unit); this FunctionDecl +/// contains all of the information known about the function. Other, +/// previous declarations of the function are available via the +/// getPreviousDecl() chain. +class FunctionDecl : public DeclaratorDecl, public DeclContext, + public Redeclarable<FunctionDecl> { +public: + /// \brief The kind of templated function a FunctionDecl can be. + enum TemplatedKind { + TK_NonTemplate, + TK_FunctionTemplate, + TK_MemberSpecialization, + TK_FunctionTemplateSpecialization, + TK_DependentFunctionTemplateSpecialization + }; + +private: + /// ParamInfo - new[]'d array of pointers to VarDecls for the formal + /// parameters of this function. This is null if a prototype or if there are + /// no formals. + ParmVarDecl **ParamInfo; + + /// DeclsInPrototypeScope - Array of pointers to NamedDecls for + /// decls defined in the function prototype that are not parameters. E.g. + /// 'enum Y' in 'void f(enum Y {AA} x) {}'. + ArrayRef<NamedDecl *> DeclsInPrototypeScope; + + LazyDeclStmtPtr Body; + + // FIXME: This can be packed into the bitfields in DeclContext. + // NOTE: VC++ packs bitfields poorly if the types differ. + unsigned SClass : 2; + unsigned IsInline : 1; + unsigned IsInlineSpecified : 1; + unsigned IsVirtualAsWritten : 1; + unsigned IsPure : 1; + unsigned HasInheritedPrototype : 1; + unsigned HasWrittenPrototype : 1; + unsigned IsDeleted : 1; + unsigned IsTrivial : 1; // sunk from CXXMethodDecl + unsigned IsDefaulted : 1; // sunk from CXXMethoDecl + unsigned IsExplicitlyDefaulted : 1; //sunk from CXXMethodDecl + unsigned HasImplicitReturnZero : 1; + unsigned IsLateTemplateParsed : 1; + unsigned IsConstexpr : 1; + + /// \brief Indicates if the function uses __try. + unsigned UsesSEHTry : 1; + + /// \brief Indicates if the function was a definition but its body was + /// skipped. + unsigned HasSkippedBody : 1; + + /// \brief End part of this FunctionDecl's source range. + /// + /// We could compute the full range in getSourceRange(). However, when we're + /// dealing with a function definition deserialized from a PCH/AST file, + /// we can only compute the full range once the function body has been + /// de-serialized, so it's far better to have the (sometimes-redundant) + /// EndRangeLoc. + SourceLocation EndRangeLoc; + + /// \brief The template or declaration that this declaration + /// describes or was instantiated from, respectively. + /// + /// For non-templates, this value will be NULL. For function + /// declarations that describe a function template, this will be a + /// pointer to a FunctionTemplateDecl. For member functions + /// of class template specializations, this will be a MemberSpecializationInfo + /// pointer containing information about the specialization. + /// For function template specializations, this will be a + /// FunctionTemplateSpecializationInfo, which contains information about + /// the template being specialized and the template arguments involved in + /// that specialization. + llvm::PointerUnion4<FunctionTemplateDecl *, + MemberSpecializationInfo *, + FunctionTemplateSpecializationInfo *, + DependentFunctionTemplateSpecializationInfo *> + TemplateOrSpecialization; + + /// DNLoc - Provides source/type location info for the + /// declaration name embedded in the DeclaratorDecl base class. + DeclarationNameLoc DNLoc; + + /// \brief Specify that this function declaration is actually a function + /// template specialization. + /// + /// \param C the ASTContext. + /// + /// \param Template the function template that this function template + /// specialization specializes. + /// + /// \param TemplateArgs the template arguments that produced this + /// function template specialization from the template. + /// + /// \param InsertPos If non-NULL, the position in the function template + /// specialization set where the function template specialization data will + /// be inserted. + /// + /// \param TSK the kind of template specialization this is. + /// + /// \param TemplateArgsAsWritten location info of template arguments. + /// + /// \param PointOfInstantiation point at which the function template + /// specialization was first instantiated. + void setFunctionTemplateSpecialization(ASTContext &C, + FunctionTemplateDecl *Template, + const TemplateArgumentList *TemplateArgs, + void *InsertPos, + TemplateSpecializationKind TSK, + const TemplateArgumentListInfo *TemplateArgsAsWritten, + SourceLocation PointOfInstantiation); + + /// \brief Specify that this record is an instantiation of the + /// member function FD. + void setInstantiationOfMemberFunction(ASTContext &C, FunctionDecl *FD, + TemplateSpecializationKind TSK); + + void setParams(ASTContext &C, ArrayRef<ParmVarDecl *> NewParamInfo); + +protected: + FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC, SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, + QualType T, TypeSourceInfo *TInfo, + StorageClass S, bool isInlineSpecified, + bool isConstexprSpecified) + : DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo, + StartLoc), + DeclContext(DK), + redeclarable_base(C), + ParamInfo(nullptr), Body(), + SClass(S), + IsInline(isInlineSpecified), IsInlineSpecified(isInlineSpecified), + IsVirtualAsWritten(false), IsPure(false), HasInheritedPrototype(false), + HasWrittenPrototype(true), IsDeleted(false), IsTrivial(false), + IsDefaulted(false), IsExplicitlyDefaulted(false), + HasImplicitReturnZero(false), IsLateTemplateParsed(false), + IsConstexpr(isConstexprSpecified), UsesSEHTry(false), + HasSkippedBody(false), EndRangeLoc(NameInfo.getEndLoc()), + TemplateOrSpecialization(), + DNLoc(NameInfo.getInfo()) {} + + typedef Redeclarable<FunctionDecl> redeclarable_base; + FunctionDecl *getNextRedeclarationImpl() override { + return getNextRedeclaration(); + } + FunctionDecl *getPreviousDeclImpl() override { + return getPreviousDecl(); + } + FunctionDecl *getMostRecentDeclImpl() override { + return getMostRecentDecl(); + } + +public: + typedef redeclarable_base::redecl_range redecl_range; + typedef redeclarable_base::redecl_iterator redecl_iterator; + using redeclarable_base::redecls_begin; + using redeclarable_base::redecls_end; + using redeclarable_base::redecls; + using redeclarable_base::getPreviousDecl; + using redeclarable_base::getMostRecentDecl; + using redeclarable_base::isFirstDecl; + + static FunctionDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, SourceLocation NLoc, + DeclarationName N, QualType T, + TypeSourceInfo *TInfo, + StorageClass SC, + bool isInlineSpecified = false, + bool hasWrittenPrototype = true, + bool isConstexprSpecified = false) { + DeclarationNameInfo NameInfo(N, NLoc); + return FunctionDecl::Create(C, DC, StartLoc, NameInfo, T, TInfo, + SC, + isInlineSpecified, hasWrittenPrototype, + isConstexprSpecified); + } + + static FunctionDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, + QualType T, TypeSourceInfo *TInfo, + StorageClass SC, + bool isInlineSpecified, + bool hasWrittenPrototype, + bool isConstexprSpecified = false); + + static FunctionDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + DeclarationNameInfo getNameInfo() const { + return DeclarationNameInfo(getDeclName(), getLocation(), DNLoc); + } + + void getNameForDiagnostic(raw_ostream &OS, const PrintingPolicy &Policy, + bool Qualified) const override; + + void setRangeEnd(SourceLocation E) { EndRangeLoc = E; } + + SourceRange getSourceRange() const override LLVM_READONLY; + + /// \brief Returns true if the function has a body (definition). The + /// function body might be in any of the (re-)declarations of this + /// function. The variant that accepts a FunctionDecl pointer will + /// set that function declaration to the actual declaration + /// containing the body (if there is one). + bool hasBody(const FunctionDecl *&Definition) const; + + bool hasBody() const override { + const FunctionDecl* Definition; + return hasBody(Definition); + } + + /// hasTrivialBody - Returns whether the function has a trivial body that does + /// not require any specific codegen. + bool hasTrivialBody() const; + + /// isDefined - Returns true if the function is defined at all, including + /// a deleted definition. Except for the behavior when the function is + /// deleted, behaves like hasBody. + bool isDefined(const FunctionDecl *&Definition) const; + + virtual bool isDefined() const { + const FunctionDecl* Definition; + return isDefined(Definition); + } + + /// getBody - Retrieve the body (definition) of the function. The + /// function body might be in any of the (re-)declarations of this + /// function. The variant that accepts a FunctionDecl pointer will + /// set that function declaration to the actual declaration + /// containing the body (if there is one). + /// NOTE: For checking if there is a body, use hasBody() instead, to avoid + /// unnecessary AST de-serialization of the body. + Stmt *getBody(const FunctionDecl *&Definition) const; + + Stmt *getBody() const override { + const FunctionDecl* Definition; + return getBody(Definition); + } + + /// isThisDeclarationADefinition - Returns whether this specific + /// declaration of the function is also a definition. This does not + /// determine whether the function has been defined (e.g., in a + /// previous definition); for that information, use isDefined. Note + /// that this returns false for a defaulted function unless that function + /// has been implicitly defined (possibly as deleted). + bool isThisDeclarationADefinition() const { + return IsDeleted || Body || IsLateTemplateParsed; + } + + /// doesThisDeclarationHaveABody - Returns whether this specific + /// declaration of the function has a body - that is, if it is a non- + /// deleted definition. + bool doesThisDeclarationHaveABody() const { + return Body || IsLateTemplateParsed; + } + + void setBody(Stmt *B); + void setLazyBody(uint64_t Offset) { Body = Offset; } + + /// Whether this function is variadic. + bool isVariadic() const; + + /// Whether this function is marked as virtual explicitly. + bool isVirtualAsWritten() const { return IsVirtualAsWritten; } + void setVirtualAsWritten(bool V) { IsVirtualAsWritten = V; } + + /// Whether this virtual function is pure, i.e. makes the containing class + /// abstract. + bool isPure() const { return IsPure; } + void setPure(bool P = true); + + /// Whether this templated function will be late parsed. + bool isLateTemplateParsed() const { return IsLateTemplateParsed; } + void setLateTemplateParsed(bool ILT = true) { IsLateTemplateParsed = ILT; } + + /// Whether this function is "trivial" in some specialized C++ senses. + /// Can only be true for default constructors, copy constructors, + /// copy assignment operators, and destructors. Not meaningful until + /// the class has been fully built by Sema. + bool isTrivial() const { return IsTrivial; } + void setTrivial(bool IT) { IsTrivial = IT; } + + /// Whether this function is defaulted per C++0x. Only valid for + /// special member functions. + bool isDefaulted() const { return IsDefaulted; } + void setDefaulted(bool D = true) { IsDefaulted = D; } + + /// Whether this function is explicitly defaulted per C++0x. Only valid + /// for special member functions. + bool isExplicitlyDefaulted() const { return IsExplicitlyDefaulted; } + void setExplicitlyDefaulted(bool ED = true) { IsExplicitlyDefaulted = ED; } + + /// Whether falling off this function implicitly returns null/zero. + /// If a more specific implicit return value is required, front-ends + /// should synthesize the appropriate return statements. + bool hasImplicitReturnZero() const { return HasImplicitReturnZero; } + void setHasImplicitReturnZero(bool IRZ) { HasImplicitReturnZero = IRZ; } + + /// \brief Whether this function has a prototype, either because one + /// was explicitly written or because it was "inherited" by merging + /// a declaration without a prototype with a declaration that has a + /// prototype. + bool hasPrototype() const { + return HasWrittenPrototype || HasInheritedPrototype; + } + + bool hasWrittenPrototype() const { return HasWrittenPrototype; } + + /// \brief Whether this function inherited its prototype from a + /// previous declaration. + bool hasInheritedPrototype() const { return HasInheritedPrototype; } + void setHasInheritedPrototype(bool P = true) { HasInheritedPrototype = P; } + + /// Whether this is a (C++11) constexpr function or constexpr constructor. + bool isConstexpr() const { return IsConstexpr; } + void setConstexpr(bool IC) { IsConstexpr = IC; } + + /// \brief Indicates the function uses __try. + bool usesSEHTry() const { return UsesSEHTry; } + void setUsesSEHTry(bool UST) { UsesSEHTry = UST; } + + /// \brief Whether this function has been deleted. + /// + /// A function that is "deleted" (via the C++0x "= delete" syntax) + /// acts like a normal function, except that it cannot actually be + /// called or have its address taken. Deleted functions are + /// typically used in C++ overload resolution to attract arguments + /// whose type or lvalue/rvalue-ness would permit the use of a + /// different overload that would behave incorrectly. For example, + /// one might use deleted functions to ban implicit conversion from + /// a floating-point number to an Integer type: + /// + /// @code + /// struct Integer { + /// Integer(long); // construct from a long + /// Integer(double) = delete; // no construction from float or double + /// Integer(long double) = delete; // no construction from long double + /// }; + /// @endcode + // If a function is deleted, its first declaration must be. + bool isDeleted() const { return getCanonicalDecl()->IsDeleted; } + bool isDeletedAsWritten() const { return IsDeleted && !IsDefaulted; } + void setDeletedAsWritten(bool D = true) { IsDeleted = D; } + + /// \brief Determines whether this function is "main", which is the + /// entry point into an executable program. + bool isMain() const; + + /// \brief Determines whether this function is a MSVCRT user defined entry + /// point. + bool isMSVCRTEntryPoint() const; + + /// \brief Determines whether this operator new or delete is one + /// of the reserved global placement operators: + /// void *operator new(size_t, void *); + /// void *operator new[](size_t, void *); + /// void operator delete(void *, void *); + /// void operator delete[](void *, void *); + /// These functions have special behavior under [new.delete.placement]: + /// These functions are reserved, a C++ program may not define + /// functions that displace the versions in the Standard C++ library. + /// The provisions of [basic.stc.dynamic] do not apply to these + /// reserved placement forms of operator new and operator delete. + /// + /// This function must be an allocation or deallocation function. + bool isReservedGlobalPlacementOperator() const; + + /// \brief Determines whether this function is one of the replaceable + /// global allocation functions: + /// void *operator new(size_t); + /// void *operator new(size_t, const std::nothrow_t &) noexcept; + /// void *operator new[](size_t); + /// void *operator new[](size_t, const std::nothrow_t &) noexcept; + /// void operator delete(void *) noexcept; + /// void operator delete(void *, std::size_t) noexcept; [C++1y] + /// void operator delete(void *, const std::nothrow_t &) noexcept; + /// void operator delete[](void *) noexcept; + /// void operator delete[](void *, std::size_t) noexcept; [C++1y] + /// void operator delete[](void *, const std::nothrow_t &) noexcept; + /// These functions have special behavior under C++1y [expr.new]: + /// An implementation is allowed to omit a call to a replaceable global + /// allocation function. [...] + bool isReplaceableGlobalAllocationFunction() const; + + /// Compute the language linkage. + LanguageLinkage getLanguageLinkage() const; + + /// \brief Determines whether this function is a function with + /// external, C linkage. + bool isExternC() const; + + /// \brief Determines whether this function's context is, or is nested within, + /// a C++ extern "C" linkage spec. + bool isInExternCContext() const; + + /// \brief Determines whether this function's context is, or is nested within, + /// a C++ extern "C++" linkage spec. + bool isInExternCXXContext() const; + + /// \brief Determines whether this is a global function. + bool isGlobal() const; + + /// \brief Determines whether this function is known to be 'noreturn', through + /// an attribute on its declaration or its type. + bool isNoReturn() const; + + /// \brief True if the function was a definition but its body was skipped. + bool hasSkippedBody() const { return HasSkippedBody; } + void setHasSkippedBody(bool Skipped = true) { HasSkippedBody = Skipped; } + + void setPreviousDeclaration(FunctionDecl * PrevDecl); + + FunctionDecl *getCanonicalDecl() override; + const FunctionDecl *getCanonicalDecl() const { + return const_cast<FunctionDecl*>(this)->getCanonicalDecl(); + } + + unsigned getBuiltinID() const; + + // Iterator access to formal parameters. + unsigned param_size() const { return getNumParams(); } + typedef ParmVarDecl **param_iterator; + typedef ParmVarDecl * const *param_const_iterator; + typedef llvm::iterator_range<param_iterator> param_range; + typedef llvm::iterator_range<param_const_iterator> param_const_range; + + param_iterator param_begin() { return param_iterator(ParamInfo); } + param_iterator param_end() { + return param_iterator(ParamInfo + param_size()); + } + param_range params() { return param_range(param_begin(), param_end()); } + + param_const_iterator param_begin() const { + return param_const_iterator(ParamInfo); + } + param_const_iterator param_end() const { + return param_const_iterator(ParamInfo + param_size()); + } + param_const_range params() const { + return param_const_range(param_begin(), param_end()); + } + + /// getNumParams - Return the number of parameters this function must have + /// based on its FunctionType. This is the length of the ParamInfo array + /// after it has been created. + unsigned getNumParams() const; + + const ParmVarDecl *getParamDecl(unsigned i) const { + assert(i < getNumParams() && "Illegal param #"); + return ParamInfo[i]; + } + ParmVarDecl *getParamDecl(unsigned i) { + assert(i < getNumParams() && "Illegal param #"); + return ParamInfo[i]; + } + void setParams(ArrayRef<ParmVarDecl *> NewParamInfo) { + setParams(getASTContext(), NewParamInfo); + } + + // ArrayRef iterface to parameters. + // FIXME: Should one day replace iterator interface. + ArrayRef<ParmVarDecl*> parameters() const { + return llvm::makeArrayRef(ParamInfo, getNumParams()); + } + + ArrayRef<NamedDecl *> getDeclsInPrototypeScope() const { + return DeclsInPrototypeScope; + } + void setDeclsInPrototypeScope(ArrayRef<NamedDecl *> NewDecls); + + /// getMinRequiredArguments - Returns the minimum number of arguments + /// needed to call this function. This may be fewer than the number of + /// function parameters, if some of the parameters have default + /// arguments (in C++). + unsigned getMinRequiredArguments() const; + + QualType getReturnType() const { + return getType()->getAs<FunctionType>()->getReturnType(); + } + + /// \brief Attempt to compute an informative source range covering the + /// function return type. This may omit qualifiers and other information with + /// limited representation in the AST. + SourceRange getReturnTypeSourceRange() const; + + /// \brief Determine the type of an expression that calls this function. + QualType getCallResultType() const { + return getType()->getAs<FunctionType>()->getCallResultType(getASTContext()); + } + + /// \brief Returns true if this function or its return type has the + /// warn_unused_result attribute. If the return type has the attribute and + /// this function is a method of the return type's class, then false will be + /// returned to avoid spurious warnings on member methods such as assignment + /// operators. + bool hasUnusedResultAttr() const; + + /// \brief Returns the storage class as written in the source. For the + /// computed linkage of symbol, see getLinkage. + StorageClass getStorageClass() const { return StorageClass(SClass); } + + /// \brief Determine whether the "inline" keyword was specified for this + /// function. + bool isInlineSpecified() const { return IsInlineSpecified; } + + /// Set whether the "inline" keyword was specified for this function. + void setInlineSpecified(bool I) { + IsInlineSpecified = I; + IsInline = I; + } + + /// Flag that this function is implicitly inline. + void setImplicitlyInline() { + IsInline = true; + } + + /// \brief Determine whether this function should be inlined, because it is + /// either marked "inline" or "constexpr" or is a member function of a class + /// that was defined in the class body. + bool isInlined() const { return IsInline; } + + bool isInlineDefinitionExternallyVisible() const; + + bool isMSExternInline() const; + + bool doesDeclarationForceExternallyVisibleDefinition() const; + + /// isOverloadedOperator - Whether this function declaration + /// represents an C++ overloaded operator, e.g., "operator+". + bool isOverloadedOperator() const { + return getOverloadedOperator() != OO_None; + } + + OverloadedOperatorKind getOverloadedOperator() const; + + const IdentifierInfo *getLiteralIdentifier() const; + + /// \brief If this function is an instantiation of a member function + /// of a class template specialization, retrieves the function from + /// which it was instantiated. + /// + /// This routine will return non-NULL for (non-templated) member + /// functions of class templates and for instantiations of function + /// templates. For example, given: + /// + /// \code + /// template<typename T> + /// struct X { + /// void f(T); + /// }; + /// \endcode + /// + /// The declaration for X<int>::f is a (non-templated) FunctionDecl + /// whose parent is the class template specialization X<int>. For + /// this declaration, getInstantiatedFromFunction() will return + /// the FunctionDecl X<T>::A. When a complete definition of + /// X<int>::A is required, it will be instantiated from the + /// declaration returned by getInstantiatedFromMemberFunction(). + FunctionDecl *getInstantiatedFromMemberFunction() const; + + /// \brief What kind of templated function this is. + TemplatedKind getTemplatedKind() const; + + /// \brief If this function is an instantiation of a member function of a + /// class template specialization, retrieves the member specialization + /// information. + MemberSpecializationInfo *getMemberSpecializationInfo() const; + + /// \brief Specify that this record is an instantiation of the + /// member function FD. + void setInstantiationOfMemberFunction(FunctionDecl *FD, + TemplateSpecializationKind TSK) { + setInstantiationOfMemberFunction(getASTContext(), FD, TSK); + } + + /// \brief Retrieves the function template that is described by this + /// function declaration. + /// + /// Every function template is represented as a FunctionTemplateDecl + /// and a FunctionDecl (or something derived from FunctionDecl). The + /// former contains template properties (such as the template + /// parameter lists) while the latter contains the actual + /// description of the template's + /// contents. FunctionTemplateDecl::getTemplatedDecl() retrieves the + /// FunctionDecl that describes the function template, + /// getDescribedFunctionTemplate() retrieves the + /// FunctionTemplateDecl from a FunctionDecl. + FunctionTemplateDecl *getDescribedFunctionTemplate() const; + + void setDescribedFunctionTemplate(FunctionTemplateDecl *Template); + + /// \brief Determine whether this function is a function template + /// specialization. + bool isFunctionTemplateSpecialization() const { + return getPrimaryTemplate() != nullptr; + } + + /// \brief Retrieve the class scope template pattern that this function + /// template specialization is instantiated from. + FunctionDecl *getClassScopeSpecializationPattern() const; + + /// \brief If this function is actually a function template specialization, + /// retrieve information about this function template specialization. + /// Otherwise, returns NULL. + FunctionTemplateSpecializationInfo *getTemplateSpecializationInfo() const; + + /// \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 Determines if the given function was instantiated from a + /// function template. + bool isTemplateInstantiation() 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. + /// + /// If this function declaration is not a function template specialization, + /// returns NULL. + FunctionTemplateDecl *getPrimaryTemplate() const; + + /// \brief Retrieve the template arguments used to produce this function + /// template specialization from the primary template. + /// + /// If this function declaration is not a function template specialization, + /// returns NULL. + const TemplateArgumentList *getTemplateSpecializationArgs() const; + + /// \brief Retrieve the template argument list as written in the sources, + /// if any. + /// + /// If this function declaration is not a function template specialization + /// or if it had no explicit template argument list, returns NULL. + /// Note that it an explicit template argument list may be written empty, + /// e.g., template<> void foo<>(char* s); + const ASTTemplateArgumentListInfo* + getTemplateSpecializationArgsAsWritten() const; + + /// \brief Specify that this function declaration is actually a function + /// template specialization. + /// + /// \param Template the function template that this function template + /// specialization specializes. + /// + /// \param TemplateArgs the template arguments that produced this + /// function template specialization from the template. + /// + /// \param InsertPos If non-NULL, the position in the function template + /// specialization set where the function template specialization data will + /// be inserted. + /// + /// \param TSK the kind of template specialization this is. + /// + /// \param TemplateArgsAsWritten location info of template arguments. + /// + /// \param PointOfInstantiation point at which the function template + /// specialization was first instantiated. + void setFunctionTemplateSpecialization(FunctionTemplateDecl *Template, + const TemplateArgumentList *TemplateArgs, + void *InsertPos, + TemplateSpecializationKind TSK = TSK_ImplicitInstantiation, + const TemplateArgumentListInfo *TemplateArgsAsWritten = nullptr, + SourceLocation PointOfInstantiation = SourceLocation()) { + setFunctionTemplateSpecialization(getASTContext(), Template, TemplateArgs, + InsertPos, TSK, TemplateArgsAsWritten, + PointOfInstantiation); + } + + /// \brief Specifies that this function declaration is actually a + /// dependent function template specialization. + void setDependentTemplateSpecialization(ASTContext &Context, + const UnresolvedSetImpl &Templates, + const TemplateArgumentListInfo &TemplateArgs); + + DependentFunctionTemplateSpecializationInfo * + getDependentSpecializationInfo() const; + + /// \brief Determine what kind of template instantiation this function + /// represents. + TemplateSpecializationKind getTemplateSpecializationKind() const; + + /// \brief Determine what kind of template instantiation this function + /// represents. + void setTemplateSpecializationKind(TemplateSpecializationKind TSK, + SourceLocation PointOfInstantiation = SourceLocation()); + + /// \brief Retrieve the (first) point of instantiation of a function template + /// specialization or a member of a class template specialization. + /// + /// \returns the first point of instantiation, if this function was + /// instantiated from a template; otherwise, 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 override; + + /// \brief Identify a memory copying or setting function. + /// If the given function is a memory copy or setting function, returns + /// the corresponding Builtin ID. If the function is not a memory function, + /// returns 0. + unsigned getMemoryFunctionKind() const; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { + return K >= firstFunction && K <= lastFunction; + } + static DeclContext *castToDeclContext(const FunctionDecl *D) { + return static_cast<DeclContext *>(const_cast<FunctionDecl*>(D)); + } + static FunctionDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<FunctionDecl *>(const_cast<DeclContext*>(DC)); + } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + + +/// FieldDecl - An instance of this class is created by Sema::ActOnField to +/// represent a member of a struct/union/class. +class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> { + // FIXME: This can be packed into the bitfields in Decl. + bool Mutable : 1; + mutable unsigned CachedFieldIndex : 31; + + /// The kinds of value we can store in InitializerOrBitWidth. + /// + /// Note that this is compatible with InClassInitStyle except for + /// ISK_CapturedVLAType. + enum InitStorageKind { + /// If the pointer is null, there's nothing special. Otherwise, + /// this is a bitfield and the pointer is the Expr* storing the + /// bit-width. + ISK_BitWidthOrNothing = (unsigned) ICIS_NoInit, + + /// The pointer is an (optional due to delayed parsing) Expr* + /// holding the copy-initializer. + ISK_InClassCopyInit = (unsigned) ICIS_CopyInit, + + /// The pointer is an (optional due to delayed parsing) Expr* + /// holding the list-initializer. + ISK_InClassListInit = (unsigned) ICIS_ListInit, + + /// The pointer is a VariableArrayType* that's been captured; + /// the enclosing context is a lambda or captured statement. + ISK_CapturedVLAType, + }; + + /// \brief Storage for either the bit-width, the in-class + /// initializer, or the captured variable length array bound. + /// + /// We can safely combine these because in-class initializers are + /// not permitted for bit-fields, and both are exclusive with VLA + /// captures. + /// + /// If the storage kind is ISK_InClassCopyInit or + /// ISK_InClassListInit, but the initializer is null, then this + /// field has an in-class initializer which has not yet been parsed + /// and attached. + llvm::PointerIntPair<void *, 2, InitStorageKind> InitStorage; +protected: + FieldDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable, + InClassInitStyle InitStyle) + : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), + Mutable(Mutable), CachedFieldIndex(0), + InitStorage(BW, (InitStorageKind) InitStyle) { + assert((!BW || InitStyle == ICIS_NoInit) && "got initializer for bitfield"); + } + +public: + static FieldDecl *Create(const ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, QualType T, + TypeSourceInfo *TInfo, Expr *BW, bool Mutable, + InClassInitStyle InitStyle); + + static FieldDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + /// getFieldIndex - Returns the index of this field within its record, + /// as appropriate for passing to ASTRecordLayout::getFieldOffset. + unsigned getFieldIndex() const; + + /// isMutable - Determines whether this field is mutable (C++ only). + bool isMutable() const { return Mutable; } + + /// \brief Determines whether this field is a bitfield. + bool isBitField() const { + return InitStorage.getInt() == ISK_BitWidthOrNothing && + InitStorage.getPointer() != nullptr; + } + + /// @brief Determines whether this is an unnamed bitfield. + bool isUnnamedBitfield() const { return isBitField() && !getDeclName(); } + + /// isAnonymousStructOrUnion - Determines whether this field is a + /// representative for an anonymous struct or union. Such fields are + /// unnamed and are implicitly generated by the implementation to + /// store the data for the anonymous union or struct. + bool isAnonymousStructOrUnion() const; + + Expr *getBitWidth() const { + return isBitField() + ? static_cast<Expr *>(InitStorage.getPointer()) + : nullptr; + } + unsigned getBitWidthValue(const ASTContext &Ctx) const; + + /// setBitWidth - Set the bit-field width for this member. + // Note: used by some clients (i.e., do not remove it). + void setBitWidth(Expr *Width) { + assert(InitStorage.getInt() == ISK_BitWidthOrNothing && + InitStorage.getPointer() == nullptr && + "bit width, initializer or captured type already set"); + InitStorage.setPointerAndInt(Width, ISK_BitWidthOrNothing); + } + + /// removeBitWidth - Remove the bit-field width from this member. + // Note: used by some clients (i.e., do not remove it). + void removeBitWidth() { + assert(isBitField() && "no bitfield width to remove"); + InitStorage.setPointerAndInt(nullptr, ISK_BitWidthOrNothing); + } + + /// getInClassInitStyle - Get the kind of (C++11) in-class initializer which + /// this field has. + InClassInitStyle getInClassInitStyle() const { + InitStorageKind storageKind = InitStorage.getInt(); + return (storageKind == ISK_CapturedVLAType + ? ICIS_NoInit : (InClassInitStyle) storageKind); + } + + /// hasInClassInitializer - Determine whether this member has a C++11 in-class + /// initializer. + bool hasInClassInitializer() const { + return getInClassInitStyle() != ICIS_NoInit; + } + + /// getInClassInitializer - Get the C++11 in-class initializer for this + /// member, or null if one has not been set. If a valid declaration has an + /// in-class initializer, but this returns null, then we have not parsed and + /// attached it yet. + Expr *getInClassInitializer() const { + return hasInClassInitializer() + ? static_cast<Expr *>(InitStorage.getPointer()) + : nullptr; + } + + /// setInClassInitializer - Set the C++11 in-class initializer for this + /// member. + void setInClassInitializer(Expr *Init) { + assert(hasInClassInitializer() && + InitStorage.getPointer() == nullptr && + "bit width, initializer or captured type already set"); + InitStorage.setPointer(Init); + } + + /// removeInClassInitializer - Remove the C++11 in-class initializer from this + /// member. + void removeInClassInitializer() { + assert(hasInClassInitializer() && "no initializer to remove"); + InitStorage.setPointerAndInt(nullptr, ISK_BitWidthOrNothing); + } + + /// \brief Determine whether this member captures the variable length array + /// type. + bool hasCapturedVLAType() const { + return InitStorage.getInt() == ISK_CapturedVLAType; + } + + /// \brief Get the captured variable length array type. + const VariableArrayType *getCapturedVLAType() const { + return hasCapturedVLAType() ? static_cast<const VariableArrayType *>( + InitStorage.getPointer()) + : nullptr; + } + /// \brief Set the captured variable length array type for this field. + void setCapturedVLAType(const VariableArrayType *VLAType); + + /// getParent - Returns the parent of this field declaration, which + /// is the struct in which this method is defined. + const RecordDecl *getParent() const { + return cast<RecordDecl>(getDeclContext()); + } + + RecordDecl *getParent() { + return cast<RecordDecl>(getDeclContext()); + } + + SourceRange getSourceRange() const override LLVM_READONLY; + + /// Retrieves the canonical declaration of this field. + FieldDecl *getCanonicalDecl() override { return getFirstDecl(); } + const FieldDecl *getCanonicalDecl() const { return getFirstDecl(); } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K >= firstField && K <= lastField; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// EnumConstantDecl - An instance of this object exists for each enum constant +/// that is defined. For example, in "enum X {a,b}", each of a/b are +/// EnumConstantDecl's, X is an instance of EnumDecl, and the type of a/b is a +/// TagType for the X EnumDecl. +class EnumConstantDecl : public ValueDecl, public Mergeable<EnumConstantDecl> { + Stmt *Init; // an integer constant expression + llvm::APSInt Val; // The value. +protected: + EnumConstantDecl(DeclContext *DC, SourceLocation L, + IdentifierInfo *Id, QualType T, Expr *E, + const llvm::APSInt &V) + : ValueDecl(EnumConstant, DC, L, Id, T), Init((Stmt*)E), Val(V) {} + +public: + + static EnumConstantDecl *Create(ASTContext &C, EnumDecl *DC, + SourceLocation L, IdentifierInfo *Id, + QualType T, Expr *E, + const llvm::APSInt &V); + static EnumConstantDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + const Expr *getInitExpr() const { return (const Expr*) Init; } + Expr *getInitExpr() { return (Expr*) Init; } + const llvm::APSInt &getInitVal() const { return Val; } + + void setInitExpr(Expr *E) { Init = (Stmt*) E; } + void setInitVal(const llvm::APSInt &V) { Val = V; } + + SourceRange getSourceRange() const override LLVM_READONLY; + + /// Retrieves the canonical declaration of this enumerator. + EnumConstantDecl *getCanonicalDecl() override { return getFirstDecl(); } + const EnumConstantDecl *getCanonicalDecl() const { return getFirstDecl(); } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == EnumConstant; } + + friend class StmtIteratorBase; +}; + +/// IndirectFieldDecl - An instance of this class is created to represent a +/// field injected from an anonymous union/struct into the parent scope. +/// IndirectFieldDecl are always implicit. +class IndirectFieldDecl : public ValueDecl, + public Mergeable<IndirectFieldDecl> { + void anchor() override; + NamedDecl **Chaining; + unsigned ChainingSize; + + IndirectFieldDecl(DeclContext *DC, SourceLocation L, + DeclarationName N, QualType T, + NamedDecl **CH, unsigned CHS) + : ValueDecl(IndirectField, DC, L, N, T), Chaining(CH), ChainingSize(CHS) {} + +public: + static IndirectFieldDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + QualType T, NamedDecl **CH, unsigned CHS); + + static IndirectFieldDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + typedef NamedDecl * const *chain_iterator; + typedef llvm::iterator_range<chain_iterator> chain_range; + + chain_range chain() const { return chain_range(chain_begin(), chain_end()); } + chain_iterator chain_begin() const { return chain_iterator(Chaining); } + chain_iterator chain_end() const { + return chain_iterator(Chaining + ChainingSize); + } + + unsigned getChainingSize() const { return ChainingSize; } + + FieldDecl *getAnonField() const { + assert(ChainingSize >= 2); + return cast<FieldDecl>(Chaining[ChainingSize - 1]); + } + + VarDecl *getVarDecl() const { + assert(ChainingSize >= 2); + return dyn_cast<VarDecl>(*chain_begin()); + } + + IndirectFieldDecl *getCanonicalDecl() override { return getFirstDecl(); } + const IndirectFieldDecl *getCanonicalDecl() const { return getFirstDecl(); } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == IndirectField; } + friend class ASTDeclReader; +}; + +/// TypeDecl - Represents a declaration of a type. +/// +class TypeDecl : public NamedDecl { + void anchor() override; + /// TypeForDecl - This indicates the Type object that represents + /// this TypeDecl. It is a cache maintained by + /// ASTContext::getTypedefType, ASTContext::getTagDeclType, and + /// ASTContext::getTemplateTypeParmType, and TemplateTypeParmDecl. + mutable const Type *TypeForDecl; + /// LocStart - The start of the source range for this declaration. + SourceLocation LocStart; + friend class ASTContext; + +protected: + TypeDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, + SourceLocation StartL = SourceLocation()) + : NamedDecl(DK, DC, L, Id), TypeForDecl(nullptr), LocStart(StartL) {} + +public: + // Low-level accessor. If you just want the type defined by this node, + // check out ASTContext::getTypeDeclType or one of + // ASTContext::getTypedefType, ASTContext::getRecordType, etc. if you + // already know the specific kind of node this is. + const Type *getTypeForDecl() const { return TypeForDecl; } + void setTypeForDecl(const Type *TD) { TypeForDecl = TD; } + + SourceLocation getLocStart() const LLVM_READONLY { return LocStart; } + void setLocStart(SourceLocation L) { LocStart = L; } + SourceRange getSourceRange() const override LLVM_READONLY { + if (LocStart.isValid()) + return SourceRange(LocStart, getLocation()); + else + return SourceRange(getLocation()); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K >= firstType && K <= lastType; } +}; + + +/// Base class for declarations which introduce a typedef-name. +class TypedefNameDecl : public TypeDecl, public Redeclarable<TypedefNameDecl> { + void anchor() override; + typedef std::pair<TypeSourceInfo*, QualType> ModedTInfo; + llvm::PointerUnion<TypeSourceInfo*, ModedTInfo*> MaybeModedTInfo; + +protected: + TypedefNameDecl(Kind DK, ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, TypeSourceInfo *TInfo) + : TypeDecl(DK, DC, IdLoc, Id, StartLoc), redeclarable_base(C), + MaybeModedTInfo(TInfo) {} + + typedef Redeclarable<TypedefNameDecl> redeclarable_base; + TypedefNameDecl *getNextRedeclarationImpl() override { + return getNextRedeclaration(); + } + TypedefNameDecl *getPreviousDeclImpl() override { + return getPreviousDecl(); + } + TypedefNameDecl *getMostRecentDeclImpl() override { + return getMostRecentDecl(); + } + +public: + typedef redeclarable_base::redecl_range redecl_range; + typedef redeclarable_base::redecl_iterator redecl_iterator; + using redeclarable_base::redecls_begin; + using redeclarable_base::redecls_end; + using redeclarable_base::redecls; + using redeclarable_base::getPreviousDecl; + using redeclarable_base::getMostRecentDecl; + using redeclarable_base::isFirstDecl; + + bool isModed() const { return MaybeModedTInfo.is<ModedTInfo*>(); } + + TypeSourceInfo *getTypeSourceInfo() const { + return isModed() + ? MaybeModedTInfo.get<ModedTInfo*>()->first + : MaybeModedTInfo.get<TypeSourceInfo*>(); + } + QualType getUnderlyingType() const { + return isModed() + ? MaybeModedTInfo.get<ModedTInfo*>()->second + : MaybeModedTInfo.get<TypeSourceInfo*>()->getType(); + } + void setTypeSourceInfo(TypeSourceInfo *newType) { + MaybeModedTInfo = newType; + } + void setModedTypeSourceInfo(TypeSourceInfo *unmodedTSI, QualType modedTy) { + MaybeModedTInfo = new (getASTContext()) ModedTInfo(unmodedTSI, modedTy); + } + + /// Retrieves the canonical declaration of this typedef-name. + TypedefNameDecl *getCanonicalDecl() override { return getFirstDecl(); } + const TypedefNameDecl *getCanonicalDecl() const { return getFirstDecl(); } + + /// Retrieves the tag declaration for which this is the typedef name for + /// linkage purposes, if any. + /// + /// \param AnyRedecl Look for the tag declaration in any redeclaration of + /// this typedef declaration. + TagDecl *getAnonDeclWithTypedefName(bool AnyRedecl = false) const; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { + return K >= firstTypedefName && K <= lastTypedefName; + } +}; + +/// TypedefDecl - Represents the declaration of a typedef-name via the 'typedef' +/// type specifier. +class TypedefDecl : public TypedefNameDecl { + TypedefDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, TypeSourceInfo *TInfo) + : TypedefNameDecl(Typedef, C, DC, StartLoc, IdLoc, Id, TInfo) {} + +public: + static TypedefDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, TypeSourceInfo *TInfo); + static TypedefDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + SourceRange getSourceRange() const override LLVM_READONLY; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == Typedef; } +}; + +/// TypeAliasDecl - Represents the declaration of a typedef-name via a C++0x +/// alias-declaration. +class TypeAliasDecl : public TypedefNameDecl { + /// The template for which this is the pattern, if any. + TypeAliasTemplateDecl *Template; + + TypeAliasDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, TypeSourceInfo *TInfo) + : TypedefNameDecl(TypeAlias, C, DC, StartLoc, IdLoc, Id, TInfo), + Template(nullptr) {} + +public: + static TypeAliasDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, TypeSourceInfo *TInfo); + static TypeAliasDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + SourceRange getSourceRange() const override LLVM_READONLY; + + TypeAliasTemplateDecl *getDescribedAliasTemplate() const { return Template; } + void setDescribedAliasTemplate(TypeAliasTemplateDecl *TAT) { Template = TAT; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == TypeAlias; } +}; + +/// TagDecl - Represents the declaration of a struct/union/class/enum. +class TagDecl + : public TypeDecl, public DeclContext, public Redeclarable<TagDecl> { +public: + // This is really ugly. + typedef TagTypeKind TagKind; + +private: + // FIXME: This can be packed into the bitfields in Decl. + /// TagDeclKind - The TagKind enum. + unsigned TagDeclKind : 3; + + /// IsCompleteDefinition - True if this is a definition ("struct foo + /// {};"), false if it is a declaration ("struct foo;"). It is not + /// a definition until the definition has been fully processed. + bool IsCompleteDefinition : 1; + +protected: + /// IsBeingDefined - True if this is currently being defined. + bool IsBeingDefined : 1; + +private: + /// IsEmbeddedInDeclarator - True if this tag declaration is + /// "embedded" (i.e., defined or declared for the very first time) + /// in the syntax of a declarator. + bool IsEmbeddedInDeclarator : 1; + + /// \brief True if this tag is free standing, e.g. "struct foo;". + bool IsFreeStanding : 1; + +protected: + // These are used by (and only defined for) EnumDecl. + unsigned NumPositiveBits : 8; + unsigned NumNegativeBits : 8; + + /// IsScoped - True if this tag declaration is a scoped enumeration. Only + /// possible in C++11 mode. + bool IsScoped : 1; + /// IsScopedUsingClassTag - If this tag declaration is a scoped enum, + /// then this is true if the scoped enum was declared using the class + /// tag, false if it was declared with the struct tag. No meaning is + /// associated if this tag declaration is not a scoped enum. + bool IsScopedUsingClassTag : 1; + + /// IsFixed - True if this is an enumeration with fixed underlying type. Only + /// possible in C++11, Microsoft extensions, or Objective C mode. + bool IsFixed : 1; + + /// \brief Indicates whether it is possible for declarations of this kind + /// to have an out-of-date definition. + /// + /// This option is only enabled when modules are enabled. + bool MayHaveOutOfDateDef : 1; + + /// Has the full definition of this type been required by a use somewhere in + /// the TU. + bool IsCompleteDefinitionRequired : 1; +private: + SourceLocation RBraceLoc; + + // A struct representing syntactic qualifier info, + // to be used for the (uncommon) case of out-of-line declarations. + typedef QualifierInfo ExtInfo; + + /// \brief If the (out-of-line) tag declaration name + /// is qualified, it points to the qualifier info (nns and range); + /// otherwise, if the tag declaration is anonymous and it is part of + /// a typedef or alias, it points to the TypedefNameDecl (used for mangling); + /// otherwise, if the tag declaration is anonymous and it is used as a + /// declaration specifier for variables, it points to the first VarDecl (used + /// for mangling); + /// otherwise, it is a null (TypedefNameDecl) pointer. + llvm::PointerUnion<TypedefNameDecl *, ExtInfo *> TypedefNameDeclOrQualifier; + + bool hasExtInfo() const { return TypedefNameDeclOrQualifier.is<ExtInfo *>(); } + ExtInfo *getExtInfo() { return TypedefNameDeclOrQualifier.get<ExtInfo *>(); } + const ExtInfo *getExtInfo() const { + return TypedefNameDeclOrQualifier.get<ExtInfo *>(); + } + +protected: + TagDecl(Kind DK, TagKind TK, const ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, TagDecl *PrevDecl, + SourceLocation StartL) + : TypeDecl(DK, DC, L, Id, StartL), DeclContext(DK), redeclarable_base(C), + TagDeclKind(TK), IsCompleteDefinition(false), IsBeingDefined(false), + IsEmbeddedInDeclarator(false), IsFreeStanding(false), + IsCompleteDefinitionRequired(false), + TypedefNameDeclOrQualifier((TypedefNameDecl *)nullptr) { + assert((DK != Enum || TK == TTK_Enum) && + "EnumDecl not matched with TTK_Enum"); + setPreviousDecl(PrevDecl); + } + + typedef Redeclarable<TagDecl> redeclarable_base; + TagDecl *getNextRedeclarationImpl() override { + return getNextRedeclaration(); + } + TagDecl *getPreviousDeclImpl() override { + return getPreviousDecl(); + } + TagDecl *getMostRecentDeclImpl() override { + return getMostRecentDecl(); + } + + /// @brief Completes the definition of this tag declaration. + /// + /// This is a helper function for derived classes. + void completeDefinition(); + +public: + typedef redeclarable_base::redecl_range redecl_range; + typedef redeclarable_base::redecl_iterator redecl_iterator; + using redeclarable_base::redecls_begin; + using redeclarable_base::redecls_end; + using redeclarable_base::redecls; + using redeclarable_base::getPreviousDecl; + using redeclarable_base::getMostRecentDecl; + using redeclarable_base::isFirstDecl; + + SourceLocation getRBraceLoc() const { return RBraceLoc; } + void setRBraceLoc(SourceLocation L) { RBraceLoc = L; } + + /// getInnerLocStart - Return SourceLocation representing start of source + /// range ignoring outer template declarations. + SourceLocation getInnerLocStart() const { return getLocStart(); } + + /// getOuterLocStart - Return SourceLocation representing start of source + /// range taking into account any outer template declarations. + SourceLocation getOuterLocStart() const; + SourceRange getSourceRange() const override LLVM_READONLY; + + TagDecl *getCanonicalDecl() override; + const TagDecl *getCanonicalDecl() const { + return const_cast<TagDecl*>(this)->getCanonicalDecl(); + } + + /// isThisDeclarationADefinition() - Return true if this declaration + /// is a completion definition of the type. Provided for consistency. + bool isThisDeclarationADefinition() const { + return isCompleteDefinition(); + } + + /// isCompleteDefinition - Return true if this decl has its body + /// fully specified. + bool isCompleteDefinition() const { + return IsCompleteDefinition; + } + + /// \brief Return true if this complete decl is + /// required to be complete for some existing use. + bool isCompleteDefinitionRequired() const { + return IsCompleteDefinitionRequired; + } + + /// isBeingDefined - Return true if this decl is currently being defined. + bool isBeingDefined() const { + return IsBeingDefined; + } + + bool isEmbeddedInDeclarator() const { + return IsEmbeddedInDeclarator; + } + void setEmbeddedInDeclarator(bool isInDeclarator) { + IsEmbeddedInDeclarator = isInDeclarator; + } + + bool isFreeStanding() const { return IsFreeStanding; } + void setFreeStanding(bool isFreeStanding = true) { + IsFreeStanding = isFreeStanding; + } + + /// \brief Whether this declaration declares a type that is + /// dependent, i.e., a type that somehow depends on template + /// parameters. + bool isDependentType() const { return isDependentContext(); } + + /// @brief Starts the definition of this tag declaration. + /// + /// This method should be invoked at the beginning of the definition + /// of this tag declaration. It will set the tag type into a state + /// where it is in the process of being defined. + void startDefinition(); + + /// getDefinition - Returns the TagDecl that actually defines this + /// struct/union/class/enum. When determining whether or not a + /// struct/union/class/enum has a definition, one should use this + /// method as opposed to 'isDefinition'. 'isDefinition' indicates + /// whether or not a specific TagDecl is defining declaration, not + /// whether or not the struct/union/class/enum type is defined. + /// This method returns NULL if there is no TagDecl that defines + /// the struct/union/class/enum. + TagDecl *getDefinition() const; + + void setCompleteDefinition(bool V) { IsCompleteDefinition = V; } + + void setCompleteDefinitionRequired(bool V = true) { + IsCompleteDefinitionRequired = V; + } + + StringRef getKindName() const { + return TypeWithKeyword::getTagTypeKindName(getTagKind()); + } + + TagKind getTagKind() const { + return TagKind(TagDeclKind); + } + + void setTagKind(TagKind TK) { TagDeclKind = TK; } + + bool isStruct() const { return getTagKind() == TTK_Struct; } + bool isInterface() const { return getTagKind() == TTK_Interface; } + bool isClass() const { return getTagKind() == TTK_Class; } + bool isUnion() const { return getTagKind() == TTK_Union; } + bool isEnum() const { return getTagKind() == TTK_Enum; } + + /// Is this tag type named, either directly or via being defined in + /// a typedef of this type? + /// + /// C++11 [basic.link]p8: + /// A type is said to have linkage if and only if: + /// - it is a class or enumeration type that is named (or has a + /// name for linkage purposes) and the name has linkage; ... + /// C++11 [dcl.typedef]p9: + /// If the typedef declaration defines an unnamed class (or enum), + /// the first typedef-name declared by the declaration to be that + /// class type (or enum type) is used to denote the class type (or + /// enum type) for linkage purposes only. + /// + /// C does not have an analogous rule, but the same concept is + /// nonetheless useful in some places. + bool hasNameForLinkage() const { + return (getDeclName() || getTypedefNameForAnonDecl()); + } + + TypedefNameDecl *getTypedefNameForAnonDecl() const { + return hasExtInfo() ? nullptr + : TypedefNameDeclOrQualifier.get<TypedefNameDecl *>(); + } + + void setTypedefNameForAnonDecl(TypedefNameDecl *TDD); + + /// \brief Retrieve the nested-name-specifier that qualifies the name of this + /// declaration, if it was present in the source. + NestedNameSpecifier *getQualifier() const { + return hasExtInfo() ? getExtInfo()->QualifierLoc.getNestedNameSpecifier() + : nullptr; + } + + /// \brief Retrieve the nested-name-specifier (with source-location + /// information) that qualifies the name of this declaration, if it was + /// present in the source. + NestedNameSpecifierLoc getQualifierLoc() const { + return hasExtInfo() ? getExtInfo()->QualifierLoc + : NestedNameSpecifierLoc(); + } + + void setQualifierInfo(NestedNameSpecifierLoc QualifierLoc); + + unsigned getNumTemplateParameterLists() const { + return hasExtInfo() ? getExtInfo()->NumTemplParamLists : 0; + } + TemplateParameterList *getTemplateParameterList(unsigned i) const { + assert(i < getNumTemplateParameterLists()); + return getExtInfo()->TemplParamLists[i]; + } + void setTemplateParameterListsInfo(ASTContext &Context, + ArrayRef<TemplateParameterList *> TPLists); + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K >= firstTag && K <= lastTag; } + + static DeclContext *castToDeclContext(const TagDecl *D) { + return static_cast<DeclContext *>(const_cast<TagDecl*>(D)); + } + static TagDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<TagDecl *>(const_cast<DeclContext*>(DC)); + } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// EnumDecl - Represents an enum. In C++11, enums can be forward-declared +/// with a fixed underlying type, and in C we allow them to be forward-declared +/// with no underlying type as an extension. +class EnumDecl : public TagDecl { + void anchor() override; + /// IntegerType - This represent the integer type that the enum corresponds + /// to for code generation purposes. Note that the enumerator constants may + /// have a different type than this does. + /// + /// If the underlying integer type was explicitly stated in the source + /// code, this is a TypeSourceInfo* for that type. Otherwise this type + /// was automatically deduced somehow, and this is a Type*. + /// + /// Normally if IsFixed(), this would contain a TypeSourceInfo*, but in + /// some cases it won't. + /// + /// The underlying type of an enumeration never has any qualifiers, so + /// we can get away with just storing a raw Type*, and thus save an + /// extra pointer when TypeSourceInfo is needed. + + llvm::PointerUnion<const Type*, TypeSourceInfo*> IntegerType; + + /// PromotionType - The integer type that values of this type should + /// promote to. In C, enumerators are generally of an integer type + /// directly, but gcc-style large enumerators (and all enumerators + /// in C++) are of the enum type instead. + QualType PromotionType; + + /// \brief If this enumeration is an instantiation of a member enumeration + /// of a class template specialization, this is the member specialization + /// information. + MemberSpecializationInfo *SpecializationInfo; + + EnumDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, EnumDecl *PrevDecl, + bool Scoped, bool ScopedUsingClassTag, bool Fixed) + : TagDecl(Enum, TTK_Enum, C, DC, IdLoc, Id, PrevDecl, StartLoc), + SpecializationInfo(nullptr) { + assert(Scoped || !ScopedUsingClassTag); + IntegerType = (const Type *)nullptr; + NumNegativeBits = 0; + NumPositiveBits = 0; + IsScoped = Scoped; + IsScopedUsingClassTag = ScopedUsingClassTag; + IsFixed = Fixed; + } + + void setInstantiationOfMemberEnum(ASTContext &C, EnumDecl *ED, + TemplateSpecializationKind TSK); +public: + EnumDecl *getCanonicalDecl() override { + return cast<EnumDecl>(TagDecl::getCanonicalDecl()); + } + const EnumDecl *getCanonicalDecl() const { + return const_cast<EnumDecl*>(this)->getCanonicalDecl(); + } + + EnumDecl *getPreviousDecl() { + return cast_or_null<EnumDecl>( + static_cast<TagDecl *>(this)->getPreviousDecl()); + } + const EnumDecl *getPreviousDecl() const { + return const_cast<EnumDecl*>(this)->getPreviousDecl(); + } + + EnumDecl *getMostRecentDecl() { + return cast<EnumDecl>(static_cast<TagDecl *>(this)->getMostRecentDecl()); + } + const EnumDecl *getMostRecentDecl() const { + return const_cast<EnumDecl*>(this)->getMostRecentDecl(); + } + + EnumDecl *getDefinition() const { + return cast_or_null<EnumDecl>(TagDecl::getDefinition()); + } + + static EnumDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, EnumDecl *PrevDecl, + bool IsScoped, bool IsScopedUsingClassTag, + bool IsFixed); + static EnumDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + /// completeDefinition - When created, the EnumDecl corresponds to a + /// forward-declared enum. This method is used to mark the + /// declaration as being defined; it's enumerators have already been + /// added (via DeclContext::addDecl). NewType is the new underlying + /// type of the enumeration type. + void completeDefinition(QualType NewType, + QualType PromotionType, + unsigned NumPositiveBits, + unsigned NumNegativeBits); + + // enumerator_iterator - Iterates through the enumerators of this + // enumeration. + typedef specific_decl_iterator<EnumConstantDecl> enumerator_iterator; + typedef llvm::iterator_range<specific_decl_iterator<EnumConstantDecl>> + enumerator_range; + + enumerator_range enumerators() const { + return enumerator_range(enumerator_begin(), enumerator_end()); + } + + enumerator_iterator enumerator_begin() const { + const EnumDecl *E = getDefinition(); + if (!E) + E = this; + return enumerator_iterator(E->decls_begin()); + } + + enumerator_iterator enumerator_end() const { + const EnumDecl *E = getDefinition(); + if (!E) + E = this; + return enumerator_iterator(E->decls_end()); + } + + /// getPromotionType - Return the integer type that enumerators + /// should promote to. + QualType getPromotionType() const { return PromotionType; } + + /// \brief Set the promotion type. + void setPromotionType(QualType T) { PromotionType = T; } + + /// getIntegerType - Return the integer type this enum decl corresponds to. + /// This returns a null QualType for an enum forward definition with no fixed + /// underlying type. + QualType getIntegerType() const { + if (!IntegerType) + return QualType(); + if (const Type *T = IntegerType.dyn_cast<const Type*>()) + return QualType(T, 0); + return IntegerType.get<TypeSourceInfo*>()->getType().getUnqualifiedType(); + } + + /// \brief Set the underlying integer type. + void setIntegerType(QualType T) { IntegerType = T.getTypePtrOrNull(); } + + /// \brief Set the underlying integer type source info. + void setIntegerTypeSourceInfo(TypeSourceInfo *TInfo) { IntegerType = TInfo; } + + /// \brief Return the type source info for the underlying integer type, + /// if no type source info exists, return 0. + TypeSourceInfo *getIntegerTypeSourceInfo() const { + return IntegerType.dyn_cast<TypeSourceInfo*>(); + } + + /// \brief Retrieve the source range that covers the underlying type if + /// specified. + SourceRange getIntegerTypeRange() const LLVM_READONLY; + + /// \brief Returns the width in bits required to store all the + /// non-negative enumerators of this enum. + unsigned getNumPositiveBits() const { + return NumPositiveBits; + } + void setNumPositiveBits(unsigned Num) { + NumPositiveBits = Num; + assert(NumPositiveBits == Num && "can't store this bitcount"); + } + + /// \brief Returns the width in bits required to store all the + /// negative enumerators of this enum. These widths include + /// the rightmost leading 1; that is: + /// + /// MOST NEGATIVE ENUMERATOR PATTERN NUM NEGATIVE BITS + /// ------------------------ ------- ----------------- + /// -1 1111111 1 + /// -10 1110110 5 + /// -101 1001011 8 + unsigned getNumNegativeBits() const { + return NumNegativeBits; + } + void setNumNegativeBits(unsigned Num) { + NumNegativeBits = Num; + } + + /// \brief Returns true if this is a C++11 scoped enumeration. + bool isScoped() const { + return IsScoped; + } + + /// \brief Returns true if this is a C++11 scoped enumeration. + bool isScopedUsingClassTag() const { + return IsScopedUsingClassTag; + } + + /// \brief Returns true if this is an Objective-C, C++11, or + /// Microsoft-style enumeration with a fixed underlying type. + bool isFixed() const { + return IsFixed; + } + + /// \brief Returns true if this can be considered a complete type. + bool isComplete() const { + return isCompleteDefinition() || isFixed(); + } + + /// \brief Returns the enumeration (declared within the template) + /// from which this enumeration type was instantiated, or NULL if + /// this enumeration was not instantiated from any template. + EnumDecl *getInstantiatedFromMemberEnum() const; + + /// \brief If this enumeration is a member of a specialization of a + /// templated class, determine what kind of template specialization + /// or instantiation this is. + TemplateSpecializationKind getTemplateSpecializationKind() const; + + /// \brief For an enumeration member that was instantiated from a member + /// enumeration of a templated class, set the template specialiation kind. + void setTemplateSpecializationKind(TemplateSpecializationKind TSK, + SourceLocation PointOfInstantiation = SourceLocation()); + + /// \brief If this enumeration is an instantiation of a member enumeration of + /// a class template specialization, retrieves the member specialization + /// information. + MemberSpecializationInfo *getMemberSpecializationInfo() const { + return SpecializationInfo; + } + + /// \brief Specify that this enumeration is an instantiation of the + /// member enumeration ED. + void setInstantiationOfMemberEnum(EnumDecl *ED, + TemplateSpecializationKind TSK) { + setInstantiationOfMemberEnum(getASTContext(), ED, TSK); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == Enum; } + + friend class ASTDeclReader; +}; + + +/// RecordDecl - Represents a struct/union/class. For example: +/// struct X; // Forward declaration, no "body". +/// union Y { int A, B; }; // Has body with members A and B (FieldDecls). +/// This decl will be marked invalid if *any* members are invalid. +/// +class RecordDecl : public TagDecl { + // FIXME: This can be packed into the bitfields in Decl. + /// HasFlexibleArrayMember - This is true if this struct ends with a flexible + /// array member (e.g. int X[]) or if this union contains a struct that does. + /// If so, this cannot be contained in arrays or other structs as a member. + bool HasFlexibleArrayMember : 1; + + /// AnonymousStructOrUnion - Whether this is the type of an anonymous struct + /// or union. + bool AnonymousStructOrUnion : 1; + + /// HasObjectMember - This is true if this struct has at least one member + /// containing an Objective-C object pointer type. + bool HasObjectMember : 1; + + /// HasVolatileMember - This is true if struct has at least one member of + /// 'volatile' type. + bool HasVolatileMember : 1; + + /// \brief Whether the field declarations of this record have been loaded + /// from external storage. To avoid unnecessary deserialization of + /// methods/nested types we allow deserialization of just the fields + /// when needed. + mutable bool LoadedFieldsFromExternalStorage : 1; + friend class DeclContext; + +protected: + RecordDecl(Kind DK, TagKind TK, const ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, RecordDecl *PrevDecl); + +public: + static RecordDecl *Create(const ASTContext &C, TagKind TK, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, RecordDecl* PrevDecl = nullptr); + static RecordDecl *CreateDeserialized(const ASTContext &C, unsigned ID); + + RecordDecl *getPreviousDecl() { + return cast_or_null<RecordDecl>( + static_cast<TagDecl *>(this)->getPreviousDecl()); + } + const RecordDecl *getPreviousDecl() const { + return const_cast<RecordDecl*>(this)->getPreviousDecl(); + } + + RecordDecl *getMostRecentDecl() { + return cast<RecordDecl>(static_cast<TagDecl *>(this)->getMostRecentDecl()); + } + const RecordDecl *getMostRecentDecl() const { + return const_cast<RecordDecl*>(this)->getMostRecentDecl(); + } + + bool hasFlexibleArrayMember() const { return HasFlexibleArrayMember; } + void setHasFlexibleArrayMember(bool V) { HasFlexibleArrayMember = V; } + + /// isAnonymousStructOrUnion - Whether this is an anonymous struct + /// or union. To be an anonymous struct or union, it must have been + /// declared without a name and there must be no objects of this + /// type declared, e.g., + /// @code + /// union { int i; float f; }; + /// @endcode + /// is an anonymous union but neither of the following are: + /// @code + /// union X { int i; float f; }; + /// union { int i; float f; } obj; + /// @endcode + bool isAnonymousStructOrUnion() const { return AnonymousStructOrUnion; } + void setAnonymousStructOrUnion(bool Anon) { + AnonymousStructOrUnion = Anon; + } + + bool hasObjectMember() const { return HasObjectMember; } + void setHasObjectMember (bool val) { HasObjectMember = val; } + + bool hasVolatileMember() const { return HasVolatileMember; } + void setHasVolatileMember (bool val) { HasVolatileMember = val; } + + bool hasLoadedFieldsFromExternalStorage() const { + return LoadedFieldsFromExternalStorage; + } + void setHasLoadedFieldsFromExternalStorage(bool val) { + LoadedFieldsFromExternalStorage = val; + } + + /// \brief Determines whether this declaration represents the + /// injected class name. + /// + /// The injected class name in C++ is the name of the class that + /// appears inside the class itself. For example: + /// + /// \code + /// struct C { + /// // C is implicitly declared here as a synonym for the class name. + /// }; + /// + /// C::C c; // same as "C c;" + /// \endcode + bool isInjectedClassName() const; + + /// \brief Determine whether this record is a class describing a lambda + /// function object. + bool isLambda() const; + + /// \brief Determine whether this record is a record for captured variables in + /// CapturedStmt construct. + bool isCapturedRecord() const; + /// \brief Mark the record as a record for captured variables in CapturedStmt + /// construct. + void setCapturedRecord(); + + /// getDefinition - Returns the RecordDecl that actually defines + /// this struct/union/class. When determining whether or not a + /// struct/union/class is completely defined, one should use this + /// method as opposed to 'isCompleteDefinition'. + /// 'isCompleteDefinition' indicates whether or not a specific + /// RecordDecl is a completed definition, not whether or not the + /// record type is defined. This method returns NULL if there is + /// no RecordDecl that defines the struct/union/tag. + RecordDecl *getDefinition() const { + return cast_or_null<RecordDecl>(TagDecl::getDefinition()); + } + + // Iterator access to field members. The field iterator only visits + // the non-static data members of this class, ignoring any static + // data members, functions, constructors, destructors, etc. + typedef specific_decl_iterator<FieldDecl> field_iterator; + typedef llvm::iterator_range<specific_decl_iterator<FieldDecl>> field_range; + + field_range fields() const { return field_range(field_begin(), field_end()); } + field_iterator field_begin() const; + + field_iterator field_end() const { + return field_iterator(decl_iterator()); + } + + // field_empty - Whether there are any fields (non-static data + // members) in this record. + bool field_empty() const { + return field_begin() == field_end(); + } + + /// completeDefinition - Notes that the definition of this type is + /// now complete. + virtual void completeDefinition(); + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { + return K >= firstRecord && K <= lastRecord; + } + + /// isMsStrust - Get whether or not this is an ms_struct which can + /// be turned on with an attribute, pragma, or -mms-bitfields + /// commandline option. + bool isMsStruct(const ASTContext &C) const; + + /// \brief Whether we are allowed to insert extra padding between fields. + /// These padding are added to help AddressSanitizer detect + /// intra-object-overflow bugs. + bool mayInsertExtraPadding(bool EmitRemark = false) const; + + /// Finds the first data member which has a name. + /// nullptr is returned if no named data member exists. + const FieldDecl *findFirstNamedDataMember() const; + +private: + /// \brief Deserialize just the fields. + void LoadFieldsFromExternalStorage() const; +}; + +class FileScopeAsmDecl : public Decl { + virtual void anchor(); + StringLiteral *AsmString; + SourceLocation RParenLoc; + FileScopeAsmDecl(DeclContext *DC, StringLiteral *asmstring, + SourceLocation StartL, SourceLocation EndL) + : Decl(FileScopeAsm, DC, StartL), AsmString(asmstring), RParenLoc(EndL) {} +public: + static FileScopeAsmDecl *Create(ASTContext &C, DeclContext *DC, + StringLiteral *Str, SourceLocation AsmLoc, + SourceLocation RParenLoc); + + static FileScopeAsmDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + SourceLocation getAsmLoc() const { return getLocation(); } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + SourceRange getSourceRange() const override LLVM_READONLY { + return SourceRange(getAsmLoc(), getRParenLoc()); + } + + const StringLiteral *getAsmString() const { return AsmString; } + StringLiteral *getAsmString() { return AsmString; } + void setAsmString(StringLiteral *Asm) { AsmString = Asm; } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == FileScopeAsm; } +}; + +/// BlockDecl - This represents a block literal declaration, which is like an +/// unnamed FunctionDecl. For example: +/// ^{ statement-body } or ^(int arg1, float arg2){ statement-body } +/// +class BlockDecl : public Decl, public DeclContext { +public: + /// A class which contains all the information about a particular + /// captured value. + class Capture { + enum { + flag_isByRef = 0x1, + flag_isNested = 0x2 + }; + + /// The variable being captured. + llvm::PointerIntPair<VarDecl*, 2> VariableAndFlags; + + /// The copy expression, expressed in terms of a DeclRef (or + /// BlockDeclRef) to the captured variable. Only required if the + /// variable has a C++ class type. + Expr *CopyExpr; + + public: + Capture(VarDecl *variable, bool byRef, bool nested, Expr *copy) + : VariableAndFlags(variable, + (byRef ? flag_isByRef : 0) | (nested ? flag_isNested : 0)), + CopyExpr(copy) {} + + /// The variable being captured. + VarDecl *getVariable() const { return VariableAndFlags.getPointer(); } + + /// Whether this is a "by ref" capture, i.e. a capture of a __block + /// variable. + bool isByRef() const { return VariableAndFlags.getInt() & flag_isByRef; } + + /// Whether this is a nested capture, i.e. the variable captured + /// is not from outside the immediately enclosing function/block. + bool isNested() const { return VariableAndFlags.getInt() & flag_isNested; } + + bool hasCopyExpr() const { return CopyExpr != nullptr; } + Expr *getCopyExpr() const { return CopyExpr; } + void setCopyExpr(Expr *e) { CopyExpr = e; } + }; + +private: + // FIXME: This can be packed into the bitfields in Decl. + bool IsVariadic : 1; + bool CapturesCXXThis : 1; + bool BlockMissingReturnType : 1; + bool IsConversionFromLambda : 1; + /// ParamInfo - new[]'d array of pointers to ParmVarDecls for the formal + /// parameters of this function. This is null if a prototype or if there are + /// no formals. + ParmVarDecl **ParamInfo; + unsigned NumParams; + + Stmt *Body; + TypeSourceInfo *SignatureAsWritten; + + const Capture *Captures; + unsigned NumCaptures; + + unsigned ManglingNumber; + Decl *ManglingContextDecl; + +protected: + BlockDecl(DeclContext *DC, SourceLocation CaretLoc) + : Decl(Block, DC, CaretLoc), DeclContext(Block), + IsVariadic(false), CapturesCXXThis(false), + BlockMissingReturnType(true), IsConversionFromLambda(false), + ParamInfo(nullptr), NumParams(0), Body(nullptr), + SignatureAsWritten(nullptr), Captures(nullptr), NumCaptures(0), + ManglingNumber(0), ManglingContextDecl(nullptr) {} + +public: + static BlockDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L); + static BlockDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + SourceLocation getCaretLocation() const { return getLocation(); } + + bool isVariadic() const { return IsVariadic; } + void setIsVariadic(bool value) { IsVariadic = value; } + + CompoundStmt *getCompoundBody() const { return (CompoundStmt*) Body; } + Stmt *getBody() const override { return (Stmt*) Body; } + void setBody(CompoundStmt *B) { Body = (Stmt*) B; } + + void setSignatureAsWritten(TypeSourceInfo *Sig) { SignatureAsWritten = Sig; } + TypeSourceInfo *getSignatureAsWritten() const { return SignatureAsWritten; } + + // Iterator access to formal parameters. + unsigned param_size() const { return getNumParams(); } + typedef ParmVarDecl **param_iterator; + typedef ParmVarDecl * const *param_const_iterator; + typedef llvm::iterator_range<param_iterator> param_range; + typedef llvm::iterator_range<param_const_iterator> param_const_range; + + // ArrayRef access to formal parameters. + // FIXME: Should eventual replace iterator access. + ArrayRef<ParmVarDecl*> parameters() const { + return llvm::makeArrayRef(ParamInfo, param_size()); + } + + bool param_empty() const { return NumParams == 0; } + param_range params() { return param_range(param_begin(), param_end()); } + param_iterator param_begin() { return param_iterator(ParamInfo); } + param_iterator param_end() { + return param_iterator(ParamInfo + param_size()); + } + + param_const_range params() const { + return param_const_range(param_begin(), param_end()); + } + param_const_iterator param_begin() const { + return param_const_iterator(ParamInfo); + } + param_const_iterator param_end() const { + return param_const_iterator(ParamInfo + param_size()); + } + + unsigned getNumParams() const { return NumParams; } + const ParmVarDecl *getParamDecl(unsigned i) const { + assert(i < getNumParams() && "Illegal param #"); + return ParamInfo[i]; + } + ParmVarDecl *getParamDecl(unsigned i) { + assert(i < getNumParams() && "Illegal param #"); + return ParamInfo[i]; + } + void setParams(ArrayRef<ParmVarDecl *> NewParamInfo); + + /// hasCaptures - True if this block (or its nested blocks) captures + /// anything of local storage from its enclosing scopes. + bool hasCaptures() const { return NumCaptures != 0 || CapturesCXXThis; } + + /// getNumCaptures - Returns the number of captured variables. + /// Does not include an entry for 'this'. + unsigned getNumCaptures() const { return NumCaptures; } + + typedef const Capture *capture_iterator; + typedef const Capture *capture_const_iterator; + typedef llvm::iterator_range<capture_iterator> capture_range; + typedef llvm::iterator_range<capture_const_iterator> capture_const_range; + + capture_range captures() { + return capture_range(capture_begin(), capture_end()); + } + capture_const_range captures() const { + return capture_const_range(capture_begin(), capture_end()); + } + + capture_iterator capture_begin() { return Captures; } + capture_iterator capture_end() { return Captures + NumCaptures; } + capture_const_iterator capture_begin() const { return Captures; } + capture_const_iterator capture_end() const { return Captures + NumCaptures; } + + bool capturesCXXThis() const { return CapturesCXXThis; } + bool blockMissingReturnType() const { return BlockMissingReturnType; } + void setBlockMissingReturnType(bool val) { BlockMissingReturnType = val; } + + bool isConversionFromLambda() const { return IsConversionFromLambda; } + void setIsConversionFromLambda(bool val) { IsConversionFromLambda = val; } + + bool capturesVariable(const VarDecl *var) const; + + void setCaptures(ASTContext &Context, ArrayRef<Capture> Captures, + bool CapturesCXXThis); + + unsigned getBlockManglingNumber() const { + return ManglingNumber; + } + Decl *getBlockManglingContextDecl() const { + return ManglingContextDecl; + } + + void setBlockMangling(unsigned Number, Decl *Ctx) { + ManglingNumber = Number; + ManglingContextDecl = Ctx; + } + + SourceRange getSourceRange() const override LLVM_READONLY; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == Block; } + static DeclContext *castToDeclContext(const BlockDecl *D) { + return static_cast<DeclContext *>(const_cast<BlockDecl*>(D)); + } + static BlockDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<BlockDecl *>(const_cast<DeclContext*>(DC)); + } +}; + +/// \brief This represents the body of a CapturedStmt, and serves as its +/// DeclContext. +class CapturedDecl final + : public Decl, + public DeclContext, + private llvm::TrailingObjects<CapturedDecl, ImplicitParamDecl *> { +protected: + size_t numTrailingObjects(OverloadToken<ImplicitParamDecl>) { + return NumParams; + } + +private: + /// \brief The number of parameters to the outlined function. + unsigned NumParams; + /// \brief The position of context parameter in list of parameters. + unsigned ContextParam; + /// \brief The body of the outlined function. + llvm::PointerIntPair<Stmt *, 1, bool> BodyAndNothrow; + + explicit CapturedDecl(DeclContext *DC, unsigned NumParams); + + ImplicitParamDecl *const *getParams() const { + return getTrailingObjects<ImplicitParamDecl *>(); + } + + ImplicitParamDecl **getParams() { + return getTrailingObjects<ImplicitParamDecl *>(); + } + +public: + static CapturedDecl *Create(ASTContext &C, DeclContext *DC, + unsigned NumParams); + static CapturedDecl *CreateDeserialized(ASTContext &C, unsigned ID, + unsigned NumParams); + + Stmt *getBody() const override; + void setBody(Stmt *B); + + bool isNothrow() const; + void setNothrow(bool Nothrow = true); + + unsigned getNumParams() const { return NumParams; } + + ImplicitParamDecl *getParam(unsigned i) const { + assert(i < NumParams); + return getParams()[i]; + } + void setParam(unsigned i, ImplicitParamDecl *P) { + assert(i < NumParams); + getParams()[i] = P; + } + + /// \brief Retrieve the parameter containing captured variables. + ImplicitParamDecl *getContextParam() const { + assert(ContextParam < NumParams); + return getParam(ContextParam); + } + void setContextParam(unsigned i, ImplicitParamDecl *P) { + assert(i < NumParams); + ContextParam = i; + setParam(i, P); + } + unsigned getContextParamPosition() const { return ContextParam; } + + typedef ImplicitParamDecl *const *param_iterator; + typedef llvm::iterator_range<param_iterator> param_range; + + /// \brief Retrieve an iterator pointing to the first parameter decl. + param_iterator param_begin() const { return getParams(); } + /// \brief Retrieve an iterator one past the last parameter decl. + param_iterator param_end() const { return getParams() + NumParams; } + + /// \brief Retrieve an iterator range for the parameter declarations. + param_range params() const { return param_range(param_begin(), param_end()); } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == Captured; } + static DeclContext *castToDeclContext(const CapturedDecl *D) { + return static_cast<DeclContext *>(const_cast<CapturedDecl *>(D)); + } + static CapturedDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<CapturedDecl *>(const_cast<DeclContext *>(DC)); + } + + friend class ASTDeclReader; + friend class ASTDeclWriter; + friend TrailingObjects; +}; + +/// \brief Describes a module import declaration, which makes the contents +/// of the named module visible in the current translation unit. +/// +/// An import declaration imports the named module (or submodule). For example: +/// \code +/// @import std.vector; +/// \endcode +/// +/// Import declarations can also be implicitly generated from +/// \#include/\#import directives. +class ImportDecl final : public Decl, + llvm::TrailingObjects<ImportDecl, SourceLocation> { + /// \brief The imported module, along with a bit that indicates whether + /// we have source-location information for each identifier in the module + /// name. + /// + /// When the bit is false, we only have a single source location for the + /// end of the import declaration. + llvm::PointerIntPair<Module *, 1, bool> ImportedAndComplete; + + /// \brief The next import in the list of imports local to the translation + /// unit being parsed (not loaded from an AST file). + ImportDecl *NextLocalImport; + + friend class ASTReader; + friend class ASTDeclReader; + friend class ASTContext; + friend TrailingObjects; + + ImportDecl(DeclContext *DC, SourceLocation StartLoc, Module *Imported, + ArrayRef<SourceLocation> IdentifierLocs); + + ImportDecl(DeclContext *DC, SourceLocation StartLoc, Module *Imported, + SourceLocation EndLoc); + + ImportDecl(EmptyShell Empty) : Decl(Import, Empty), NextLocalImport() { } + +public: + /// \brief Create a new module import declaration. + static ImportDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, Module *Imported, + ArrayRef<SourceLocation> IdentifierLocs); + + /// \brief Create a new module import declaration for an implicitly-generated + /// import. + static ImportDecl *CreateImplicit(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, Module *Imported, + SourceLocation EndLoc); + + /// \brief Create a new, deserialized module import declaration. + static ImportDecl *CreateDeserialized(ASTContext &C, unsigned ID, + unsigned NumLocations); + + /// \brief Retrieve the module that was imported by the import declaration. + Module *getImportedModule() const { return ImportedAndComplete.getPointer(); } + + /// \brief Retrieves the locations of each of the identifiers that make up + /// the complete module name in the import declaration. + /// + /// This will return an empty array if the locations of the individual + /// identifiers aren't available. + ArrayRef<SourceLocation> getIdentifierLocs() const; + + SourceRange getSourceRange() const override LLVM_READONLY; + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == Import; } +}; + +/// \brief Represents an empty-declaration. +class EmptyDecl : public Decl { + virtual void anchor(); + EmptyDecl(DeclContext *DC, SourceLocation L) + : Decl(Empty, DC, L) { } + +public: + static EmptyDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L); + static EmptyDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == Empty; } +}; + +/// Insertion operator for diagnostics. This allows sending NamedDecl's +/// into a diagnostic with <<. +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const NamedDecl* ND) { + DB.AddTaggedVal(reinterpret_cast<intptr_t>(ND), + DiagnosticsEngine::ak_nameddecl); + return DB; +} +inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + const NamedDecl* ND) { + PD.AddTaggedVal(reinterpret_cast<intptr_t>(ND), + DiagnosticsEngine::ak_nameddecl); + return PD; +} + +template<typename decl_type> +void Redeclarable<decl_type>::setPreviousDecl(decl_type *PrevDecl) { + // Note: This routine is implemented here because we need both NamedDecl + // and Redeclarable to be defined. + assert(RedeclLink.NextIsLatest() && + "setPreviousDecl on a decl already in a redeclaration chain"); + + if (PrevDecl) { + // Point to previous. Make sure that this is actually the most recent + // redeclaration, or we can build invalid chains. If the most recent + // redeclaration is invalid, it won't be PrevDecl, but we want it anyway. + First = PrevDecl->getFirstDecl(); + assert(First->RedeclLink.NextIsLatest() && "Expected first"); + decl_type *MostRecent = First->getNextRedeclaration(); + RedeclLink = PreviousDeclLink(cast<decl_type>(MostRecent)); + + // If the declaration was previously visible, a redeclaration of it remains + // visible even if it wouldn't be visible by itself. + static_cast<decl_type*>(this)->IdentifierNamespace |= + MostRecent->getIdentifierNamespace() & + (Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Type); + } else { + // Make this first. + First = static_cast<decl_type*>(this); + } + + // First one will point to this one as latest. + First->RedeclLink.setLatest(static_cast<decl_type*>(this)); + + assert(!isa<NamedDecl>(static_cast<decl_type*>(this)) || + cast<NamedDecl>(static_cast<decl_type*>(this))->isLinkageValid()); +} + +// Inline function definitions. + +/// \brief Check if the given decl is complete. +/// +/// We use this function to break a cycle between the inline definitions in +/// Type.h and Decl.h. +inline bool IsEnumDeclComplete(EnumDecl *ED) { + return ED->isComplete(); +} + +/// \brief Check if the given decl is scoped. +/// +/// We use this function to break a cycle between the inline definitions in +/// Type.h and Decl.h. +inline bool IsEnumDeclScoped(EnumDecl *ED) { + return ED->isScoped(); +} + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/DeclAccessPair.h b/contrib/llvm/tools/clang/include/clang/AST/DeclAccessPair.h new file mode 100644 index 0000000..3c5056c --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/DeclAccessPair.h @@ -0,0 +1,72 @@ +//===--- DeclAccessPair.h - A decl bundled with its path access -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the DeclAccessPair class, which provides an +// efficient representation of a pair of a NamedDecl* and an +// AccessSpecifier. Generally the access specifier gives the +// natural access of a declaration when named in a class, as +// defined in C++ [class.access.base]p1. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DECLACCESSPAIR_H +#define LLVM_CLANG_AST_DECLACCESSPAIR_H + +#include "clang/Basic/Specifiers.h" +#include "llvm/Support/DataTypes.h" + +namespace clang { + +class NamedDecl; + +/// A POD class for pairing a NamedDecl* with an access specifier. +/// Can be put into unions. +class DeclAccessPair { + uintptr_t Ptr; // we'd use llvm::PointerUnion, but it isn't trivial + + enum { Mask = 0x3 }; + +public: + static DeclAccessPair make(NamedDecl *D, AccessSpecifier AS) { + DeclAccessPair p; + p.set(D, AS); + return p; + } + + NamedDecl *getDecl() const { + return reinterpret_cast<NamedDecl*>(~Mask & Ptr); + } + AccessSpecifier getAccess() const { + return AccessSpecifier(Mask & Ptr); + } + + void setDecl(NamedDecl *D) { + set(D, getAccess()); + } + void setAccess(AccessSpecifier AS) { + set(getDecl(), AS); + } + void set(NamedDecl *D, AccessSpecifier AS) { + Ptr = uintptr_t(AS) | reinterpret_cast<uintptr_t>(D); + } + + operator NamedDecl*() const { return getDecl(); } + NamedDecl *operator->() const { return getDecl(); } +}; +} + +// Take a moment to tell SmallVector that DeclAccessPair is POD. +namespace llvm { +template<typename> struct isPodLike; +template<> struct isPodLike<clang::DeclAccessPair> { + static const bool value = true; +}; +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/DeclBase.h b/contrib/llvm/tools/clang/include/clang/AST/DeclBase.h new file mode 100644 index 0000000..05b2a12 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/DeclBase.h @@ -0,0 +1,1904 @@ +//===-- DeclBase.h - Base Classes for representing declarations -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Decl and DeclContext interfaces. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DECLBASE_H +#define LLVM_CLANG_AST_DECLBASE_H + +#include "clang/AST/AttrIterator.h" +#include "clang/AST/DeclarationName.h" +#include "clang/Basic/Specifiers.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/iterator.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/PrettyStackTrace.h" + +namespace clang { +class ASTMutationListener; +class BlockDecl; +class CXXRecordDecl; +class CompoundStmt; +class DeclContext; +class DeclarationName; +class DependentDiagnostic; +class EnumDecl; +class FunctionDecl; +class FunctionType; +enum Linkage : unsigned char; +class LinkageComputer; +class LinkageSpecDecl; +class Module; +class NamedDecl; +class NamespaceDecl; +class ObjCCategoryDecl; +class ObjCCategoryImplDecl; +class ObjCContainerDecl; +class ObjCImplDecl; +class ObjCImplementationDecl; +class ObjCInterfaceDecl; +class ObjCMethodDecl; +class ObjCProtocolDecl; +struct PrintingPolicy; +class RecordDecl; +class Stmt; +class StoredDeclsMap; +class TranslationUnitDecl; +class UsingDirectiveDecl; +} + +namespace clang { + + /// \brief Captures the result of checking the availability of a + /// declaration. + enum AvailabilityResult { + AR_Available = 0, + AR_NotYetIntroduced, + AR_Deprecated, + AR_Unavailable + }; + +/// Decl - This represents one declaration (or definition), e.g. a variable, +/// typedef, function, struct, etc. +/// +/// Note: There are objects tacked on before the *beginning* of Decl +/// (and its subclasses) in its Decl::operator new(). Proper alignment +/// of all subclasses (not requiring more than DeclObjAlignment) is +/// asserted in DeclBase.cpp. +class Decl { +public: + /// \brief Alignment guaranteed when allocating Decl and any subtypes. + enum { DeclObjAlignment = llvm::AlignOf<uint64_t>::Alignment }; + + /// \brief Lists the kind of concrete classes of Decl. + enum Kind { +#define DECL(DERIVED, BASE) DERIVED, +#define ABSTRACT_DECL(DECL) +#define DECL_RANGE(BASE, START, END) \ + first##BASE = START, last##BASE = END, +#define LAST_DECL_RANGE(BASE, START, END) \ + first##BASE = START, last##BASE = END +#include "clang/AST/DeclNodes.inc" + }; + + /// \brief A placeholder type used to construct an empty shell of a + /// decl-derived type that will be filled in later (e.g., by some + /// deserialization method). + struct EmptyShell { }; + + /// IdentifierNamespace - The different namespaces in which + /// declarations may appear. According to C99 6.2.3, there are + /// four namespaces, labels, tags, members and ordinary + /// identifiers. C++ describes lookup completely differently: + /// certain lookups merely "ignore" certain kinds of declarations, + /// usually based on whether the declaration is of a type, etc. + /// + /// These are meant as bitmasks, so that searches in + /// C++ can look into the "tag" namespace during ordinary lookup. + /// + /// Decl currently provides 15 bits of IDNS bits. + enum IdentifierNamespace { + /// Labels, declared with 'x:' and referenced with 'goto x'. + IDNS_Label = 0x0001, + + /// Tags, declared with 'struct foo;' and referenced with + /// 'struct foo'. All tags are also types. This is what + /// elaborated-type-specifiers look for in C. + IDNS_Tag = 0x0002, + + /// Types, declared with 'struct foo', typedefs, etc. + /// This is what elaborated-type-specifiers look for in C++, + /// but note that it's ill-formed to find a non-tag. + IDNS_Type = 0x0004, + + /// Members, declared with object declarations within tag + /// definitions. In C, these can only be found by "qualified" + /// lookup in member expressions. In C++, they're found by + /// normal lookup. + IDNS_Member = 0x0008, + + /// Namespaces, declared with 'namespace foo {}'. + /// Lookup for nested-name-specifiers find these. + IDNS_Namespace = 0x0010, + + /// Ordinary names. In C, everything that's not a label, tag, + /// or member ends up here. + IDNS_Ordinary = 0x0020, + + /// Objective C \@protocol. + IDNS_ObjCProtocol = 0x0040, + + /// This declaration is a friend function. A friend function + /// declaration is always in this namespace but may also be in + /// IDNS_Ordinary if it was previously declared. + IDNS_OrdinaryFriend = 0x0080, + + /// This declaration is a friend class. A friend class + /// declaration is always in this namespace but may also be in + /// IDNS_Tag|IDNS_Type if it was previously declared. + IDNS_TagFriend = 0x0100, + + /// This declaration is a using declaration. A using declaration + /// *introduces* a number of other declarations into the current + /// scope, and those declarations use the IDNS of their targets, + /// but the actual using declarations go in this namespace. + IDNS_Using = 0x0200, + + /// This declaration is a C++ operator declared in a non-class + /// context. All such operators are also in IDNS_Ordinary. + /// C++ lexical operator lookup looks for these. + IDNS_NonMemberOperator = 0x0400, + + /// This declaration is a function-local extern declaration of a + /// variable or function. This may also be IDNS_Ordinary if it + /// has been declared outside any function. + IDNS_LocalExtern = 0x0800 + }; + + /// ObjCDeclQualifier - 'Qualifiers' written next to the return and + /// parameter types in method declarations. Other than remembering + /// them and mangling them into the method's signature string, these + /// are ignored by the compiler; they are consumed by certain + /// remote-messaging frameworks. + /// + /// in, inout, and out are mutually exclusive and apply only to + /// method parameters. bycopy and byref are mutually exclusive and + /// apply only to method parameters (?). oneway applies only to + /// results. All of these expect their corresponding parameter to + /// have a particular type. None of this is currently enforced by + /// clang. + /// + /// This should be kept in sync with ObjCDeclSpec::ObjCDeclQualifier. + enum ObjCDeclQualifier { + OBJC_TQ_None = 0x0, + OBJC_TQ_In = 0x1, + OBJC_TQ_Inout = 0x2, + OBJC_TQ_Out = 0x4, + OBJC_TQ_Bycopy = 0x8, + OBJC_TQ_Byref = 0x10, + OBJC_TQ_Oneway = 0x20, + + /// The nullability qualifier is set when the nullability of the + /// result or parameter was expressed via a context-sensitive + /// keyword. + OBJC_TQ_CSNullability = 0x40 + }; + +protected: + // Enumeration values used in the bits stored in NextInContextAndBits. + enum { + /// \brief Whether this declaration is a top-level declaration (function, + /// global variable, etc.) that is lexically inside an objc container + /// definition. + TopLevelDeclInObjCContainerFlag = 0x01, + + /// \brief Whether this declaration is private to the module in which it was + /// defined. + ModulePrivateFlag = 0x02 + }; + + /// \brief The next declaration within the same lexical + /// DeclContext. These pointers form the linked list that is + /// traversed via DeclContext's decls_begin()/decls_end(). + /// + /// The extra two bits are used for the TopLevelDeclInObjCContainer and + /// ModulePrivate bits. + llvm::PointerIntPair<Decl *, 2, unsigned> NextInContextAndBits; + +private: + friend class DeclContext; + + struct MultipleDC { + DeclContext *SemanticDC; + DeclContext *LexicalDC; + }; + + + /// DeclCtx - Holds either a DeclContext* or a MultipleDC*. + /// For declarations that don't contain C++ scope specifiers, it contains + /// the DeclContext where the Decl was declared. + /// For declarations with C++ scope specifiers, it contains a MultipleDC* + /// with the context where it semantically belongs (SemanticDC) and the + /// context where it was lexically declared (LexicalDC). + /// e.g.: + /// + /// namespace A { + /// void f(); // SemanticDC == LexicalDC == 'namespace A' + /// } + /// void A::f(); // SemanticDC == namespace 'A' + /// // LexicalDC == global namespace + llvm::PointerUnion<DeclContext*, MultipleDC*> DeclCtx; + + inline bool isInSemaDC() const { return DeclCtx.is<DeclContext*>(); } + inline bool isOutOfSemaDC() const { return DeclCtx.is<MultipleDC*>(); } + inline MultipleDC *getMultipleDC() const { + return DeclCtx.get<MultipleDC*>(); + } + inline DeclContext *getSemanticDC() const { + return DeclCtx.get<DeclContext*>(); + } + + /// Loc - The location of this decl. + SourceLocation Loc; + + /// DeclKind - This indicates which class this is. + unsigned DeclKind : 8; + + /// InvalidDecl - This indicates a semantic error occurred. + unsigned InvalidDecl : 1; + + /// HasAttrs - This indicates whether the decl has attributes or not. + unsigned HasAttrs : 1; + + /// Implicit - Whether this declaration was implicitly generated by + /// the implementation rather than explicitly written by the user. + unsigned Implicit : 1; + + /// \brief Whether this declaration was "used", meaning that a definition is + /// required. + unsigned Used : 1; + + /// \brief Whether this declaration was "referenced". + /// The difference with 'Used' is whether the reference appears in a + /// evaluated context or not, e.g. functions used in uninstantiated templates + /// are regarded as "referenced" but not "used". + unsigned Referenced : 1; + + /// \brief Whether statistic collection is enabled. + static bool StatisticsEnabled; + +protected: + /// Access - Used by C++ decls for the access specifier. + // NOTE: VC++ treats enums as signed, avoid using the AccessSpecifier enum + unsigned Access : 2; + friend class CXXClassMemberWrapper; + + /// \brief Whether this declaration was loaded from an AST file. + unsigned FromASTFile : 1; + + /// \brief Whether this declaration is hidden from normal name lookup, e.g., + /// because it is was loaded from an AST file is either module-private or + /// because its submodule has not been made visible. + unsigned Hidden : 1; + + /// IdentifierNamespace - This specifies what IDNS_* namespace this lives in. + unsigned IdentifierNamespace : 12; + + /// \brief If 0, we have not computed the linkage of this declaration. + /// Otherwise, it is the linkage + 1. + mutable unsigned CacheValidAndLinkage : 3; + + friend class ASTDeclWriter; + friend class ASTDeclReader; + friend class ASTReader; + friend class LinkageComputer; + + template<typename decl_type> friend class Redeclarable; + + /// \brief Allocate memory for a deserialized declaration. + /// + /// This routine must be used to allocate memory for any declaration that is + /// deserialized from a module file. + /// + /// \param Size The size of the allocated object. + /// \param Ctx The context in which we will allocate memory. + /// \param ID The global ID of the deserialized declaration. + /// \param Extra The amount of extra space to allocate after the object. + void *operator new(std::size_t Size, const ASTContext &Ctx, unsigned ID, + std::size_t Extra = 0); + + /// \brief Allocate memory for a non-deserialized declaration. + void *operator new(std::size_t Size, const ASTContext &Ctx, + DeclContext *Parent, std::size_t Extra = 0); + +private: + bool AccessDeclContextSanity() const; + +protected: + + Decl(Kind DK, DeclContext *DC, SourceLocation L) + : NextInContextAndBits(), DeclCtx(DC), + Loc(L), DeclKind(DK), InvalidDecl(0), + HasAttrs(false), Implicit(false), Used(false), Referenced(false), + Access(AS_none), FromASTFile(0), Hidden(DC && cast<Decl>(DC)->Hidden), + IdentifierNamespace(getIdentifierNamespaceForKind(DK)), + CacheValidAndLinkage(0) + { + if (StatisticsEnabled) add(DK); + } + + Decl(Kind DK, EmptyShell Empty) + : NextInContextAndBits(), DeclKind(DK), InvalidDecl(0), + HasAttrs(false), Implicit(false), Used(false), Referenced(false), + Access(AS_none), FromASTFile(0), Hidden(0), + IdentifierNamespace(getIdentifierNamespaceForKind(DK)), + CacheValidAndLinkage(0) + { + if (StatisticsEnabled) add(DK); + } + + virtual ~Decl(); + + /// \brief Update a potentially out-of-date declaration. + void updateOutOfDate(IdentifierInfo &II) const; + + Linkage getCachedLinkage() const { + return Linkage(CacheValidAndLinkage - 1); + } + + void setCachedLinkage(Linkage L) const { + CacheValidAndLinkage = L + 1; + } + + bool hasCachedLinkage() const { + return CacheValidAndLinkage; + } + +public: + + /// \brief Source range that this declaration covers. + virtual SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(getLocation(), getLocation()); + } + SourceLocation getLocStart() const LLVM_READONLY { + return getSourceRange().getBegin(); + } + SourceLocation getLocEnd() const LLVM_READONLY { + return getSourceRange().getEnd(); + } + + SourceLocation getLocation() const { return Loc; } + void setLocation(SourceLocation L) { Loc = L; } + + Kind getKind() const { return static_cast<Kind>(DeclKind); } + const char *getDeclKindName() const; + + Decl *getNextDeclInContext() { return NextInContextAndBits.getPointer(); } + const Decl *getNextDeclInContext() const {return NextInContextAndBits.getPointer();} + + DeclContext *getDeclContext() { + if (isInSemaDC()) + return getSemanticDC(); + return getMultipleDC()->SemanticDC; + } + const DeclContext *getDeclContext() const { + return const_cast<Decl*>(this)->getDeclContext(); + } + + /// Find the innermost non-closure ancestor of this declaration, + /// walking up through blocks, lambdas, etc. If that ancestor is + /// not a code context (!isFunctionOrMethod()), returns null. + /// + /// A declaration may be its own non-closure context. + Decl *getNonClosureContext(); + const Decl *getNonClosureContext() const { + return const_cast<Decl*>(this)->getNonClosureContext(); + } + + TranslationUnitDecl *getTranslationUnitDecl(); + const TranslationUnitDecl *getTranslationUnitDecl() const { + return const_cast<Decl*>(this)->getTranslationUnitDecl(); + } + + bool isInAnonymousNamespace() const; + + bool isInStdNamespace() const; + + ASTContext &getASTContext() const LLVM_READONLY; + + void setAccess(AccessSpecifier AS) { + Access = AS; + assert(AccessDeclContextSanity()); + } + + AccessSpecifier getAccess() const { + assert(AccessDeclContextSanity()); + return AccessSpecifier(Access); + } + + /// \brief Retrieve the access specifier for this declaration, even though + /// it may not yet have been properly set. + AccessSpecifier getAccessUnsafe() const { + return AccessSpecifier(Access); + } + + bool hasAttrs() const { return HasAttrs; } + void setAttrs(const AttrVec& Attrs) { + return setAttrsImpl(Attrs, getASTContext()); + } + AttrVec &getAttrs() { + return const_cast<AttrVec&>(const_cast<const Decl*>(this)->getAttrs()); + } + const AttrVec &getAttrs() const; + void dropAttrs(); + + void addAttr(Attr *A) { + if (hasAttrs()) + getAttrs().push_back(A); + else + setAttrs(AttrVec(1, A)); + } + + typedef AttrVec::const_iterator attr_iterator; + typedef llvm::iterator_range<attr_iterator> attr_range; + + attr_range attrs() const { + return attr_range(attr_begin(), attr_end()); + } + + attr_iterator attr_begin() const { + return hasAttrs() ? getAttrs().begin() : nullptr; + } + attr_iterator attr_end() const { + return hasAttrs() ? getAttrs().end() : nullptr; + } + + template <typename T> + void dropAttr() { + if (!HasAttrs) return; + + AttrVec &Vec = getAttrs(); + Vec.erase(std::remove_if(Vec.begin(), Vec.end(), isa<T, Attr*>), Vec.end()); + + if (Vec.empty()) + HasAttrs = false; + } + + template <typename T> + llvm::iterator_range<specific_attr_iterator<T>> specific_attrs() const { + return llvm::make_range(specific_attr_begin<T>(), specific_attr_end<T>()); + } + + template <typename T> + specific_attr_iterator<T> specific_attr_begin() const { + return specific_attr_iterator<T>(attr_begin()); + } + template <typename T> + specific_attr_iterator<T> specific_attr_end() const { + return specific_attr_iterator<T>(attr_end()); + } + + template<typename T> T *getAttr() const { + return hasAttrs() ? getSpecificAttr<T>(getAttrs()) : nullptr; + } + template<typename T> bool hasAttr() const { + return hasAttrs() && hasSpecificAttr<T>(getAttrs()); + } + + /// getMaxAlignment - return the maximum alignment specified by attributes + /// on this decl, 0 if there are none. + unsigned getMaxAlignment() const; + + /// setInvalidDecl - Indicates the Decl had a semantic error. This + /// allows for graceful error recovery. + void setInvalidDecl(bool Invalid = true); + bool isInvalidDecl() const { return (bool) InvalidDecl; } + + /// isImplicit - Indicates whether the declaration was implicitly + /// generated by the implementation. If false, this declaration + /// was written explicitly in the source code. + bool isImplicit() const { return Implicit; } + void setImplicit(bool I = true) { Implicit = I; } + + /// \brief Whether this declaration was used, meaning that a definition + /// is required. + /// + /// \param CheckUsedAttr When true, also consider the "used" attribute + /// (in addition to the "used" bit set by \c setUsed()) when determining + /// whether the function is used. + bool isUsed(bool CheckUsedAttr = true) const; + + /// \brief Set whether the declaration is used, in the sense of odr-use. + /// + /// This should only be used immediately after creating a declaration. + void setIsUsed() { Used = true; } + + /// \brief Mark the declaration used, in the sense of odr-use. + /// + /// This notifies any mutation listeners in addition to setting a bit + /// indicating the declaration is used. + void markUsed(ASTContext &C); + + /// \brief Whether any declaration of this entity was referenced. + bool isReferenced() const; + + /// \brief Whether this declaration was referenced. This should not be relied + /// upon for anything other than debugging. + bool isThisDeclarationReferenced() const { return Referenced; } + + void setReferenced(bool R = true) { Referenced = R; } + + /// \brief Whether this declaration is a top-level declaration (function, + /// global variable, etc.) that is lexically inside an objc container + /// definition. + bool isTopLevelDeclInObjCContainer() const { + return NextInContextAndBits.getInt() & TopLevelDeclInObjCContainerFlag; + } + + void setTopLevelDeclInObjCContainer(bool V = true) { + unsigned Bits = NextInContextAndBits.getInt(); + if (V) + Bits |= TopLevelDeclInObjCContainerFlag; + else + Bits &= ~TopLevelDeclInObjCContainerFlag; + NextInContextAndBits.setInt(Bits); + } + + /// \brief Whether this declaration was marked as being private to the + /// module in which it was defined. + bool isModulePrivate() const { + return NextInContextAndBits.getInt() & ModulePrivateFlag; + } + +protected: + /// \brief Specify whether this declaration was marked as being private + /// to the module in which it was defined. + void setModulePrivate(bool MP = true) { + unsigned Bits = NextInContextAndBits.getInt(); + if (MP) + Bits |= ModulePrivateFlag; + else + Bits &= ~ModulePrivateFlag; + NextInContextAndBits.setInt(Bits); + } + + /// \brief Set the owning module ID. + void setOwningModuleID(unsigned ID) { + assert(isFromASTFile() && "Only works on a deserialized declaration"); + *((unsigned*)this - 2) = ID; + } + +public: + + /// \brief Determine the availability of the given declaration. + /// + /// This routine will determine the most restrictive availability of + /// the given declaration (e.g., preferring 'unavailable' to + /// 'deprecated'). + /// + /// \param Message If non-NULL and the result is not \c + /// AR_Available, will be set to a (possibly empty) message + /// describing why the declaration has not been introduced, is + /// deprecated, or is unavailable. + AvailabilityResult getAvailability(std::string *Message = nullptr) const; + + /// \brief Determine whether this declaration is marked 'deprecated'. + /// + /// \param Message If non-NULL and the declaration is deprecated, + /// this will be set to the message describing why the declaration + /// was deprecated (which may be empty). + bool isDeprecated(std::string *Message = nullptr) const { + return getAvailability(Message) == AR_Deprecated; + } + + /// \brief Determine whether this declaration is marked 'unavailable'. + /// + /// \param Message If non-NULL and the declaration is unavailable, + /// this will be set to the message describing why the declaration + /// was made unavailable (which may be empty). + bool isUnavailable(std::string *Message = nullptr) const { + return getAvailability(Message) == AR_Unavailable; + } + + /// \brief Determine whether this is a weak-imported symbol. + /// + /// Weak-imported symbols are typically marked with the + /// 'weak_import' attribute, but may also be marked with an + /// 'availability' attribute where we're targing a platform prior to + /// the introduction of this feature. + bool isWeakImported() const; + + /// \brief Determines whether this symbol can be weak-imported, + /// e.g., whether it would be well-formed to add the weak_import + /// attribute. + /// + /// \param IsDefinition Set to \c true to indicate that this + /// declaration cannot be weak-imported because it has a definition. + bool canBeWeakImported(bool &IsDefinition) const; + + /// \brief Determine whether this declaration came from an AST file (such as + /// a precompiled header or module) rather than having been parsed. + bool isFromASTFile() const { return FromASTFile; } + + /// \brief Retrieve the global declaration ID associated with this + /// declaration, which specifies where in the + unsigned getGlobalID() const { + if (isFromASTFile()) + return *((const unsigned*)this - 1); + return 0; + } + + /// \brief Retrieve the global ID of the module that owns this particular + /// declaration. + unsigned getOwningModuleID() const { + if (isFromASTFile()) + return *((const unsigned*)this - 2); + + return 0; + } + +private: + Module *getOwningModuleSlow() const; +protected: + bool hasLocalOwningModuleStorage() const; + +public: + /// \brief Get the imported owning module, if this decl is from an imported + /// (non-local) module. + Module *getImportedOwningModule() const { + if (!isFromASTFile()) + return nullptr; + + return getOwningModuleSlow(); + } + + /// \brief Get the local owning module, if known. Returns nullptr if owner is + /// not yet known or declaration is not from a module. + Module *getLocalOwningModule() const { + if (isFromASTFile() || !Hidden) + return nullptr; + return reinterpret_cast<Module *const *>(this)[-1]; + } + void setLocalOwningModule(Module *M) { + assert(!isFromASTFile() && Hidden && hasLocalOwningModuleStorage() && + "should not have a cached owning module"); + reinterpret_cast<Module **>(this)[-1] = M; + } + + unsigned getIdentifierNamespace() const { + return IdentifierNamespace; + } + bool isInIdentifierNamespace(unsigned NS) const { + return getIdentifierNamespace() & NS; + } + static unsigned getIdentifierNamespaceForKind(Kind DK); + + bool hasTagIdentifierNamespace() const { + return isTagIdentifierNamespace(getIdentifierNamespace()); + } + static bool isTagIdentifierNamespace(unsigned NS) { + // TagDecls have Tag and Type set and may also have TagFriend. + return (NS & ~IDNS_TagFriend) == (IDNS_Tag | IDNS_Type); + } + + /// getLexicalDeclContext - The declaration context where this Decl was + /// lexically declared (LexicalDC). May be different from + /// getDeclContext() (SemanticDC). + /// e.g.: + /// + /// namespace A { + /// void f(); // SemanticDC == LexicalDC == 'namespace A' + /// } + /// void A::f(); // SemanticDC == namespace 'A' + /// // LexicalDC == global namespace + DeclContext *getLexicalDeclContext() { + if (isInSemaDC()) + return getSemanticDC(); + return getMultipleDC()->LexicalDC; + } + const DeclContext *getLexicalDeclContext() const { + return const_cast<Decl*>(this)->getLexicalDeclContext(); + } + + /// Determine whether this declaration is declared out of line (outside its + /// semantic context). + virtual bool isOutOfLine() const; + + /// setDeclContext - Set both the semantic and lexical DeclContext + /// to DC. + void setDeclContext(DeclContext *DC); + + void setLexicalDeclContext(DeclContext *DC); + + /// isDefinedOutsideFunctionOrMethod - This predicate returns true if this + /// scoped decl is defined outside the current function or method. This is + /// roughly global variables and functions, but also handles enums (which + /// could be defined inside or outside a function etc). + bool isDefinedOutsideFunctionOrMethod() const { + return getParentFunctionOrMethod() == nullptr; + } + + /// \brief Returns true if this declaration lexically is inside a function. + /// It recognizes non-defining declarations as well as members of local + /// classes: + /// \code + /// void foo() { void bar(); } + /// void foo2() { class ABC { void bar(); }; } + /// \endcode + bool isLexicallyWithinFunctionOrMethod() const; + + /// \brief If this decl is defined inside a function/method/block it returns + /// the corresponding DeclContext, otherwise it returns null. + const DeclContext *getParentFunctionOrMethod() const; + DeclContext *getParentFunctionOrMethod() { + return const_cast<DeclContext*>( + const_cast<const Decl*>(this)->getParentFunctionOrMethod()); + } + + /// \brief Retrieves the "canonical" declaration of the given declaration. + virtual Decl *getCanonicalDecl() { return this; } + const Decl *getCanonicalDecl() const { + return const_cast<Decl*>(this)->getCanonicalDecl(); + } + + /// \brief Whether this particular Decl is a canonical one. + bool isCanonicalDecl() const { return getCanonicalDecl() == this; } + +protected: + /// \brief Returns the next redeclaration or itself if this is the only decl. + /// + /// Decl subclasses that can be redeclared should override this method so that + /// Decl::redecl_iterator can iterate over them. + virtual Decl *getNextRedeclarationImpl() { return this; } + + /// \brief Implementation of getPreviousDecl(), to be overridden by any + /// subclass that has a redeclaration chain. + virtual Decl *getPreviousDeclImpl() { return nullptr; } + + /// \brief Implementation of getMostRecentDecl(), to be overridden by any + /// subclass that has a redeclaration chain. + virtual Decl *getMostRecentDeclImpl() { return this; } + +public: + /// \brief Iterates through all the redeclarations of the same decl. + class redecl_iterator { + /// Current - The current declaration. + Decl *Current; + Decl *Starter; + + public: + typedef Decl *value_type; + typedef const value_type &reference; + typedef const value_type *pointer; + typedef std::forward_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + + redecl_iterator() : Current(nullptr) { } + explicit redecl_iterator(Decl *C) : Current(C), Starter(C) { } + + reference operator*() const { return Current; } + value_type operator->() const { return Current; } + + redecl_iterator& operator++() { + assert(Current && "Advancing while iterator has reached end"); + // Get either previous decl or latest decl. + Decl *Next = Current->getNextRedeclarationImpl(); + assert(Next && "Should return next redeclaration or itself, never null!"); + Current = (Next != Starter) ? Next : nullptr; + return *this; + } + + redecl_iterator operator++(int) { + redecl_iterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool operator==(redecl_iterator x, redecl_iterator y) { + return x.Current == y.Current; + } + friend bool operator!=(redecl_iterator x, redecl_iterator y) { + return x.Current != y.Current; + } + }; + + typedef llvm::iterator_range<redecl_iterator> redecl_range; + + /// \brief Returns an iterator range for all the redeclarations of the same + /// decl. It will iterate at least once (when this decl is the only one). + redecl_range redecls() const { + return redecl_range(redecls_begin(), redecls_end()); + } + + redecl_iterator redecls_begin() const { + return redecl_iterator(const_cast<Decl *>(this)); + } + redecl_iterator redecls_end() const { return redecl_iterator(); } + + /// \brief Retrieve the previous declaration that declares the same entity + /// as this declaration, or NULL if there is no previous declaration. + Decl *getPreviousDecl() { return getPreviousDeclImpl(); } + + /// \brief Retrieve the most recent declaration that declares the same entity + /// as this declaration, or NULL if there is no previous declaration. + const Decl *getPreviousDecl() const { + return const_cast<Decl *>(this)->getPreviousDeclImpl(); + } + + /// \brief True if this is the first declaration in its redeclaration chain. + bool isFirstDecl() const { + return getPreviousDecl() == nullptr; + } + + /// \brief Retrieve the most recent declaration that declares the same entity + /// as this declaration (which may be this declaration). + Decl *getMostRecentDecl() { return getMostRecentDeclImpl(); } + + /// \brief Retrieve the most recent declaration that declares the same entity + /// as this declaration (which may be this declaration). + const Decl *getMostRecentDecl() const { + return const_cast<Decl *>(this)->getMostRecentDeclImpl(); + } + + /// getBody - If this Decl represents a declaration for a body of code, + /// such as a function or method definition, this method returns the + /// top-level Stmt* of that body. Otherwise this method returns null. + virtual Stmt* getBody() const { return nullptr; } + + /// \brief Returns true if this \c Decl represents a declaration for a body of + /// code, such as a function or method definition. + /// Note that \c hasBody can also return true if any redeclaration of this + /// \c Decl represents a declaration for a body of code. + virtual bool hasBody() const { return getBody() != nullptr; } + + /// getBodyRBrace - Gets the right brace of the body, if a body exists. + /// This works whether the body is a CompoundStmt or a CXXTryStmt. + SourceLocation getBodyRBrace() const; + + // global temp stats (until we have a per-module visitor) + static void add(Kind k); + static void EnableStatistics(); + static void PrintStats(); + + /// isTemplateParameter - Determines whether this declaration is a + /// template parameter. + bool isTemplateParameter() const; + + /// isTemplateParameter - Determines whether this declaration is a + /// template parameter pack. + bool isTemplateParameterPack() const; + + /// \brief Whether this declaration is a parameter pack. + bool isParameterPack() const; + + /// \brief returns true if this declaration is a template + bool isTemplateDecl() const; + + /// \brief Whether this declaration is a function or function template. + bool isFunctionOrFunctionTemplate() const { + return (DeclKind >= Decl::firstFunction && + DeclKind <= Decl::lastFunction) || + DeclKind == FunctionTemplate; + } + + /// \brief Returns the function itself, or the templated function if this is a + /// function template. + FunctionDecl *getAsFunction() LLVM_READONLY; + + const FunctionDecl *getAsFunction() const { + return const_cast<Decl *>(this)->getAsFunction(); + } + + /// \brief Changes the namespace of this declaration to reflect that it's + /// a function-local extern declaration. + /// + /// These declarations appear in the lexical context of the extern + /// declaration, but in the semantic context of the enclosing namespace + /// scope. + void setLocalExternDecl() { + assert((IdentifierNamespace == IDNS_Ordinary || + IdentifierNamespace == IDNS_OrdinaryFriend) && + "namespace is not ordinary"); + + Decl *Prev = getPreviousDecl(); + IdentifierNamespace &= ~IDNS_Ordinary; + + IdentifierNamespace |= IDNS_LocalExtern; + if (Prev && Prev->getIdentifierNamespace() & IDNS_Ordinary) + IdentifierNamespace |= IDNS_Ordinary; + } + + /// \brief Determine whether this is a block-scope declaration with linkage. + /// This will either be a local variable declaration declared 'extern', or a + /// local function declaration. + bool isLocalExternDecl() { + return IdentifierNamespace & IDNS_LocalExtern; + } + + /// \brief Changes the namespace of this declaration to reflect that it's + /// the object of a friend declaration. + /// + /// These declarations appear in the lexical context of the friending + /// class, but in the semantic context of the actual entity. This property + /// applies only to a specific decl object; other redeclarations of the + /// same entity may not (and probably don't) share this property. + void setObjectOfFriendDecl(bool PerformFriendInjection = false) { + unsigned OldNS = IdentifierNamespace; + assert((OldNS & (IDNS_Tag | IDNS_Ordinary | + IDNS_TagFriend | IDNS_OrdinaryFriend | + IDNS_LocalExtern)) && + "namespace includes neither ordinary nor tag"); + assert(!(OldNS & ~(IDNS_Tag | IDNS_Ordinary | IDNS_Type | + IDNS_TagFriend | IDNS_OrdinaryFriend | + IDNS_LocalExtern)) && + "namespace includes other than ordinary or tag"); + + Decl *Prev = getPreviousDecl(); + IdentifierNamespace &= ~(IDNS_Ordinary | IDNS_Tag | IDNS_Type); + + if (OldNS & (IDNS_Tag | IDNS_TagFriend)) { + IdentifierNamespace |= IDNS_TagFriend; + if (PerformFriendInjection || + (Prev && Prev->getIdentifierNamespace() & IDNS_Tag)) + IdentifierNamespace |= IDNS_Tag | IDNS_Type; + } + + if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend | IDNS_LocalExtern)) { + IdentifierNamespace |= IDNS_OrdinaryFriend; + if (PerformFriendInjection || + (Prev && Prev->getIdentifierNamespace() & IDNS_Ordinary)) + IdentifierNamespace |= IDNS_Ordinary; + } + } + + enum FriendObjectKind { + FOK_None, ///< Not a friend object. + FOK_Declared, ///< A friend of a previously-declared entity. + FOK_Undeclared ///< A friend of a previously-undeclared entity. + }; + + /// \brief Determines whether this declaration is the object of a + /// friend declaration and, if so, what kind. + /// + /// There is currently no direct way to find the associated FriendDecl. + FriendObjectKind getFriendObjectKind() const { + unsigned mask = + (IdentifierNamespace & (IDNS_TagFriend | IDNS_OrdinaryFriend)); + if (!mask) return FOK_None; + return (IdentifierNamespace & (IDNS_Tag | IDNS_Ordinary) ? FOK_Declared + : FOK_Undeclared); + } + + /// Specifies that this declaration is a C++ overloaded non-member. + void setNonMemberOperator() { + assert(getKind() == Function || getKind() == FunctionTemplate); + assert((IdentifierNamespace & IDNS_Ordinary) && + "visible non-member operators should be in ordinary namespace"); + IdentifierNamespace |= IDNS_NonMemberOperator; + } + + static bool classofKind(Kind K) { return true; } + static DeclContext *castToDeclContext(const Decl *); + static Decl *castFromDeclContext(const DeclContext *); + + void print(raw_ostream &Out, unsigned Indentation = 0, + bool PrintInstantiation = false) const; + void print(raw_ostream &Out, const PrintingPolicy &Policy, + unsigned Indentation = 0, bool PrintInstantiation = false) const; + static void printGroup(Decl** Begin, unsigned NumDecls, + raw_ostream &Out, const PrintingPolicy &Policy, + unsigned Indentation = 0); + // Debuggers don't usually respect default arguments. + void dump() const; + // Same as dump(), but forces color printing. + void dumpColor() const; + void dump(raw_ostream &Out) const; + + /// \brief Looks through the Decl's underlying type to extract a FunctionType + /// when possible. Will return null if the type underlying the Decl does not + /// have a FunctionType. + const FunctionType *getFunctionType(bool BlocksToo = true) const; + +private: + void setAttrsImpl(const AttrVec& Attrs, ASTContext &Ctx); + void setDeclContextsImpl(DeclContext *SemaDC, DeclContext *LexicalDC, + ASTContext &Ctx); + +protected: + ASTMutationListener *getASTMutationListener() const; +}; + +/// \brief Determine whether two declarations declare the same entity. +inline bool declaresSameEntity(const Decl *D1, const Decl *D2) { + if (!D1 || !D2) + return false; + + if (D1 == D2) + return true; + + return D1->getCanonicalDecl() == D2->getCanonicalDecl(); +} + +/// PrettyStackTraceDecl - If a crash occurs, indicate that it happened when +/// doing something to a specific decl. +class PrettyStackTraceDecl : public llvm::PrettyStackTraceEntry { + const Decl *TheDecl; + SourceLocation Loc; + SourceManager &SM; + const char *Message; +public: + PrettyStackTraceDecl(const Decl *theDecl, SourceLocation L, + SourceManager &sm, const char *Msg) + : TheDecl(theDecl), Loc(L), SM(sm), Message(Msg) {} + + void print(raw_ostream &OS) const override; +}; + +/// \brief The results of name lookup within a DeclContext. This is either a +/// single result (with no stable storage) or a collection of results (with +/// stable storage provided by the lookup table). +class DeclContextLookupResult { + typedef ArrayRef<NamedDecl *> ResultTy; + ResultTy Result; + // If there is only one lookup result, it would be invalidated by + // reallocations of the name table, so store it separately. + NamedDecl *Single; + + static NamedDecl *const SingleElementDummyList; + +public: + DeclContextLookupResult() : Result(), Single() {} + DeclContextLookupResult(ArrayRef<NamedDecl *> Result) + : Result(Result), Single() {} + DeclContextLookupResult(NamedDecl *Single) + : Result(SingleElementDummyList), Single(Single) {} + + class iterator; + typedef llvm::iterator_adaptor_base<iterator, ResultTy::iterator, + std::random_access_iterator_tag, + NamedDecl *const> IteratorBase; + class iterator : public IteratorBase { + value_type SingleElement; + + public: + iterator() : IteratorBase(), SingleElement() {} + explicit iterator(pointer Pos, value_type Single = nullptr) + : IteratorBase(Pos), SingleElement(Single) {} + + reference operator*() const { + return SingleElement ? SingleElement : IteratorBase::operator*(); + } + }; + typedef iterator const_iterator; + typedef iterator::pointer pointer; + typedef iterator::reference reference; + + iterator begin() const { return iterator(Result.begin(), Single); } + iterator end() const { return iterator(Result.end(), Single); } + + bool empty() const { return Result.empty(); } + pointer data() const { return Single ? &Single : Result.data(); } + size_t size() const { return Single ? 1 : Result.size(); } + reference front() const { return Single ? Single : Result.front(); } + reference back() const { return Single ? Single : Result.back(); } + reference operator[](size_t N) const { return Single ? Single : Result[N]; } + + // FIXME: Remove this from the interface + DeclContextLookupResult slice(size_t N) const { + DeclContextLookupResult Sliced = Result.slice(N); + Sliced.Single = Single; + return Sliced; + } +}; + +/// DeclContext - This is used only as base class of specific decl types that +/// can act as declaration contexts. These decls are (only the top classes +/// that directly derive from DeclContext are mentioned, not their subclasses): +/// +/// TranslationUnitDecl +/// NamespaceDecl +/// FunctionDecl +/// TagDecl +/// ObjCMethodDecl +/// ObjCContainerDecl +/// LinkageSpecDecl +/// BlockDecl +/// +class DeclContext { + /// DeclKind - This indicates which class this is. + unsigned DeclKind : 8; + + /// \brief Whether this declaration context also has some external + /// storage that contains additional declarations that are lexically + /// part of this context. + mutable bool ExternalLexicalStorage : 1; + + /// \brief Whether this declaration context also has some external + /// storage that contains additional declarations that are visible + /// in this context. + mutable bool ExternalVisibleStorage : 1; + + /// \brief Whether this declaration context has had external visible + /// storage added since the last lookup. In this case, \c LookupPtr's + /// invariant may not hold and needs to be fixed before we perform + /// another lookup. + mutable bool NeedToReconcileExternalVisibleStorage : 1; + + /// \brief If \c true, this context may have local lexical declarations + /// that are missing from the lookup table. + mutable bool HasLazyLocalLexicalLookups : 1; + + /// \brief If \c true, the external source may have lexical declarations + /// that are missing from the lookup table. + mutable bool HasLazyExternalLexicalLookups : 1; + + /// \brief If \c true, lookups should only return identifier from + /// DeclContext scope (for example TranslationUnit). Used in + /// LookupQualifiedName() + mutable bool UseQualifiedLookup : 1; + + /// \brief Pointer to the data structure used to lookup declarations + /// within this context (or a DependentStoredDeclsMap if this is a + /// dependent context). We maintain the invariant that, if the map + /// contains an entry for a DeclarationName (and we haven't lazily + /// omitted anything), then it contains all relevant entries for that + /// name (modulo the hasExternalDecls() flag). + mutable StoredDeclsMap *LookupPtr; + +protected: + /// FirstDecl - The first declaration stored within this declaration + /// context. + mutable Decl *FirstDecl; + + /// LastDecl - The last declaration stored within this declaration + /// context. FIXME: We could probably cache this value somewhere + /// outside of the DeclContext, to reduce the size of DeclContext by + /// another pointer. + mutable Decl *LastDecl; + + friend class ExternalASTSource; + friend class ASTDeclReader; + friend class ASTWriter; + + /// \brief Build up a chain of declarations. + /// + /// \returns the first/last pair of declarations. + static std::pair<Decl *, Decl *> + BuildDeclChain(ArrayRef<Decl*> Decls, bool FieldsAlreadyLoaded); + + DeclContext(Decl::Kind K) + : DeclKind(K), ExternalLexicalStorage(false), + ExternalVisibleStorage(false), + NeedToReconcileExternalVisibleStorage(false), + HasLazyLocalLexicalLookups(false), HasLazyExternalLexicalLookups(false), + UseQualifiedLookup(false), + LookupPtr(nullptr), FirstDecl(nullptr), LastDecl(nullptr) {} + +public: + ~DeclContext(); + + Decl::Kind getDeclKind() const { + return static_cast<Decl::Kind>(DeclKind); + } + const char *getDeclKindName() const; + + /// getParent - Returns the containing DeclContext. + DeclContext *getParent() { + return cast<Decl>(this)->getDeclContext(); + } + const DeclContext *getParent() const { + return const_cast<DeclContext*>(this)->getParent(); + } + + /// getLexicalParent - Returns the containing lexical DeclContext. May be + /// different from getParent, e.g.: + /// + /// namespace A { + /// struct S; + /// } + /// struct A::S {}; // getParent() == namespace 'A' + /// // getLexicalParent() == translation unit + /// + DeclContext *getLexicalParent() { + return cast<Decl>(this)->getLexicalDeclContext(); + } + const DeclContext *getLexicalParent() const { + return const_cast<DeclContext*>(this)->getLexicalParent(); + } + + DeclContext *getLookupParent(); + + const DeclContext *getLookupParent() const { + return const_cast<DeclContext*>(this)->getLookupParent(); + } + + ASTContext &getParentASTContext() const { + return cast<Decl>(this)->getASTContext(); + } + + bool isClosure() const { + return DeclKind == Decl::Block; + } + + bool isObjCContainer() const { + switch (DeclKind) { + case Decl::ObjCCategory: + case Decl::ObjCCategoryImpl: + case Decl::ObjCImplementation: + case Decl::ObjCInterface: + case Decl::ObjCProtocol: + return true; + } + return false; + } + + bool isFunctionOrMethod() const { + switch (DeclKind) { + case Decl::Block: + case Decl::Captured: + case Decl::ObjCMethod: + return true; + default: + return DeclKind >= Decl::firstFunction && DeclKind <= Decl::lastFunction; + } + } + + /// \brief Test whether the context supports looking up names. + bool isLookupContext() const { + return !isFunctionOrMethod() && DeclKind != Decl::LinkageSpec; + } + + bool isFileContext() const { + return DeclKind == Decl::TranslationUnit || DeclKind == Decl::Namespace; + } + + bool isTranslationUnit() const { + return DeclKind == Decl::TranslationUnit; + } + + bool isRecord() const { + return DeclKind >= Decl::firstRecord && DeclKind <= Decl::lastRecord; + } + + bool isNamespace() const { + return DeclKind == Decl::Namespace; + } + + bool isStdNamespace() const; + + bool isInlineNamespace() const; + + /// \brief Determines whether this context is dependent on a + /// template parameter. + bool isDependentContext() const; + + /// isTransparentContext - Determines whether this context is a + /// "transparent" context, meaning that the members declared in this + /// context are semantically declared in the nearest enclosing + /// non-transparent (opaque) context but are lexically declared in + /// this context. For example, consider the enumerators of an + /// enumeration type: + /// @code + /// enum E { + /// Val1 + /// }; + /// @endcode + /// Here, E is a transparent context, so its enumerator (Val1) will + /// appear (semantically) that it is in the same context of E. + /// Examples of transparent contexts include: enumerations (except for + /// C++0x scoped enums), and C++ linkage specifications. + bool isTransparentContext() const; + + /// \brief Determines whether this context or some of its ancestors is a + /// linkage specification context that specifies C linkage. + bool isExternCContext() const; + + /// \brief Determines whether this context or some of its ancestors is a + /// linkage specification context that specifies C++ linkage. + bool isExternCXXContext() const; + + /// \brief Determine whether this declaration context is equivalent + /// to the declaration context DC. + bool Equals(const DeclContext *DC) const { + return DC && this->getPrimaryContext() == DC->getPrimaryContext(); + } + + /// \brief Determine whether this declaration context encloses the + /// declaration context DC. + bool Encloses(const DeclContext *DC) const; + + /// \brief Find the nearest non-closure ancestor of this context, + /// i.e. the innermost semantic parent of this context which is not + /// a closure. A context may be its own non-closure ancestor. + Decl *getNonClosureAncestor(); + const Decl *getNonClosureAncestor() const { + return const_cast<DeclContext*>(this)->getNonClosureAncestor(); + } + + /// getPrimaryContext - There may be many different + /// declarations of the same entity (including forward declarations + /// of classes, multiple definitions of namespaces, etc.), each with + /// a different set of declarations. This routine returns the + /// "primary" DeclContext structure, which will contain the + /// information needed to perform name lookup into this context. + DeclContext *getPrimaryContext(); + const DeclContext *getPrimaryContext() const { + return const_cast<DeclContext*>(this)->getPrimaryContext(); + } + + /// getRedeclContext - Retrieve the context in which an entity conflicts with + /// other entities of the same name, or where it is a redeclaration if the + /// two entities are compatible. This skips through transparent contexts. + DeclContext *getRedeclContext(); + const DeclContext *getRedeclContext() const { + return const_cast<DeclContext *>(this)->getRedeclContext(); + } + + /// \brief Retrieve the nearest enclosing namespace context. + DeclContext *getEnclosingNamespaceContext(); + const DeclContext *getEnclosingNamespaceContext() const { + return const_cast<DeclContext *>(this)->getEnclosingNamespaceContext(); + } + + /// \brief Retrieve the outermost lexically enclosing record context. + RecordDecl *getOuterLexicalRecordContext(); + const RecordDecl *getOuterLexicalRecordContext() const { + return const_cast<DeclContext *>(this)->getOuterLexicalRecordContext(); + } + + /// \brief Test if this context is part of the enclosing namespace set of + /// the context NS, as defined in C++0x [namespace.def]p9. If either context + /// isn't a namespace, this is equivalent to Equals(). + /// + /// The enclosing namespace set of a namespace is the namespace and, if it is + /// inline, its enclosing namespace, recursively. + bool InEnclosingNamespaceSetOf(const DeclContext *NS) const; + + /// \brief Collects all of the declaration contexts that are semantically + /// connected to this declaration context. + /// + /// For declaration contexts that have multiple semantically connected but + /// syntactically distinct contexts, such as C++ namespaces, this routine + /// retrieves the complete set of such declaration contexts in source order. + /// For example, given: + /// + /// \code + /// namespace N { + /// int x; + /// } + /// namespace N { + /// int y; + /// } + /// \endcode + /// + /// The \c Contexts parameter will contain both definitions of N. + /// + /// \param Contexts Will be cleared and set to the set of declaration + /// contexts that are semanticaly connected to this declaration context, + /// in source order, including this context (which may be the only result, + /// for non-namespace contexts). + void collectAllContexts(SmallVectorImpl<DeclContext *> &Contexts); + + /// decl_iterator - Iterates through the declarations stored + /// within this context. + class decl_iterator { + /// Current - The current declaration. + Decl *Current; + + public: + typedef Decl *value_type; + typedef const value_type &reference; + typedef const value_type *pointer; + typedef std::forward_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + + decl_iterator() : Current(nullptr) { } + explicit decl_iterator(Decl *C) : Current(C) { } + + reference operator*() const { return Current; } + // This doesn't meet the iterator requirements, but it's convenient + value_type operator->() const { return Current; } + + decl_iterator& operator++() { + Current = Current->getNextDeclInContext(); + return *this; + } + + decl_iterator operator++(int) { + decl_iterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool operator==(decl_iterator x, decl_iterator y) { + return x.Current == y.Current; + } + friend bool operator!=(decl_iterator x, decl_iterator y) { + return x.Current != y.Current; + } + }; + + typedef llvm::iterator_range<decl_iterator> decl_range; + + /// decls_begin/decls_end - Iterate over the declarations stored in + /// this context. + decl_range decls() const { return decl_range(decls_begin(), decls_end()); } + decl_iterator decls_begin() const; + decl_iterator decls_end() const { return decl_iterator(); } + bool decls_empty() const; + + /// noload_decls_begin/end - Iterate over the declarations stored in this + /// context that are currently loaded; don't attempt to retrieve anything + /// from an external source. + decl_range noload_decls() const { + return decl_range(noload_decls_begin(), noload_decls_end()); + } + decl_iterator noload_decls_begin() const { return decl_iterator(FirstDecl); } + decl_iterator noload_decls_end() const { return decl_iterator(); } + + /// specific_decl_iterator - Iterates over a subrange of + /// declarations stored in a DeclContext, providing only those that + /// are of type SpecificDecl (or a class derived from it). This + /// iterator is used, for example, to provide iteration over just + /// the fields within a RecordDecl (with SpecificDecl = FieldDecl). + template<typename SpecificDecl> + class specific_decl_iterator { + /// Current - The current, underlying declaration iterator, which + /// will either be NULL or will point to a declaration of + /// type SpecificDecl. + DeclContext::decl_iterator Current; + + /// SkipToNextDecl - Advances the current position up to the next + /// declaration of type SpecificDecl that also meets the criteria + /// required by Acceptable. + void SkipToNextDecl() { + while (*Current && !isa<SpecificDecl>(*Current)) + ++Current; + } + + public: + typedef SpecificDecl *value_type; + // TODO: Add reference and pointer typedefs (with some appropriate proxy + // type) if we ever have a need for them. + typedef void reference; + typedef void pointer; + typedef std::iterator_traits<DeclContext::decl_iterator>::difference_type + difference_type; + typedef std::forward_iterator_tag iterator_category; + + specific_decl_iterator() : Current() { } + + /// specific_decl_iterator - Construct a new iterator over a + /// subset of the declarations the range [C, + /// end-of-declarations). If A is non-NULL, it is a pointer to a + /// member function of SpecificDecl that should return true for + /// all of the SpecificDecl instances that will be in the subset + /// of iterators. For example, if you want Objective-C instance + /// methods, SpecificDecl will be ObjCMethodDecl and A will be + /// &ObjCMethodDecl::isInstanceMethod. + explicit specific_decl_iterator(DeclContext::decl_iterator C) : Current(C) { + SkipToNextDecl(); + } + + value_type operator*() const { return cast<SpecificDecl>(*Current); } + // This doesn't meet the iterator requirements, but it's convenient + value_type operator->() const { return **this; } + + specific_decl_iterator& operator++() { + ++Current; + SkipToNextDecl(); + return *this; + } + + specific_decl_iterator operator++(int) { + specific_decl_iterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool operator==(const specific_decl_iterator& x, + const specific_decl_iterator& y) { + return x.Current == y.Current; + } + + friend bool operator!=(const specific_decl_iterator& x, + const specific_decl_iterator& y) { + return x.Current != y.Current; + } + }; + + /// \brief Iterates over a filtered subrange of declarations stored + /// in a DeclContext. + /// + /// This iterator visits only those declarations that are of type + /// SpecificDecl (or a class derived from it) and that meet some + /// additional run-time criteria. This iterator is used, for + /// example, to provide access to the instance methods within an + /// Objective-C interface (with SpecificDecl = ObjCMethodDecl and + /// Acceptable = ObjCMethodDecl::isInstanceMethod). + template<typename SpecificDecl, bool (SpecificDecl::*Acceptable)() const> + class filtered_decl_iterator { + /// Current - The current, underlying declaration iterator, which + /// will either be NULL or will point to a declaration of + /// type SpecificDecl. + DeclContext::decl_iterator Current; + + /// SkipToNextDecl - Advances the current position up to the next + /// declaration of type SpecificDecl that also meets the criteria + /// required by Acceptable. + void SkipToNextDecl() { + while (*Current && + (!isa<SpecificDecl>(*Current) || + (Acceptable && !(cast<SpecificDecl>(*Current)->*Acceptable)()))) + ++Current; + } + + public: + typedef SpecificDecl *value_type; + // TODO: Add reference and pointer typedefs (with some appropriate proxy + // type) if we ever have a need for them. + typedef void reference; + typedef void pointer; + typedef std::iterator_traits<DeclContext::decl_iterator>::difference_type + difference_type; + typedef std::forward_iterator_tag iterator_category; + + filtered_decl_iterator() : Current() { } + + /// filtered_decl_iterator - Construct a new iterator over a + /// subset of the declarations the range [C, + /// end-of-declarations). If A is non-NULL, it is a pointer to a + /// member function of SpecificDecl that should return true for + /// all of the SpecificDecl instances that will be in the subset + /// of iterators. For example, if you want Objective-C instance + /// methods, SpecificDecl will be ObjCMethodDecl and A will be + /// &ObjCMethodDecl::isInstanceMethod. + explicit filtered_decl_iterator(DeclContext::decl_iterator C) : Current(C) { + SkipToNextDecl(); + } + + value_type operator*() const { return cast<SpecificDecl>(*Current); } + value_type operator->() const { return cast<SpecificDecl>(*Current); } + + filtered_decl_iterator& operator++() { + ++Current; + SkipToNextDecl(); + return *this; + } + + filtered_decl_iterator operator++(int) { + filtered_decl_iterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool operator==(const filtered_decl_iterator& x, + const filtered_decl_iterator& y) { + return x.Current == y.Current; + } + + friend bool operator!=(const filtered_decl_iterator& x, + const filtered_decl_iterator& y) { + return x.Current != y.Current; + } + }; + + /// @brief Add the declaration D into this context. + /// + /// This routine should be invoked when the declaration D has first + /// been declared, to place D into the context where it was + /// (lexically) defined. Every declaration must be added to one + /// (and only one!) context, where it can be visited via + /// [decls_begin(), decls_end()). Once a declaration has been added + /// to its lexical context, the corresponding DeclContext owns the + /// declaration. + /// + /// If D is also a NamedDecl, it will be made visible within its + /// semantic context via makeDeclVisibleInContext. + void addDecl(Decl *D); + + /// @brief Add the declaration D into this context, but suppress + /// searches for external declarations with the same name. + /// + /// Although analogous in function to addDecl, this removes an + /// important check. This is only useful if the Decl is being + /// added in response to an external search; in all other cases, + /// addDecl() is the right function to use. + /// See the ASTImporter for use cases. + void addDeclInternal(Decl *D); + + /// @brief Add the declaration D to this context without modifying + /// any lookup tables. + /// + /// This is useful for some operations in dependent contexts where + /// the semantic context might not be dependent; this basically + /// only happens with friends. + void addHiddenDecl(Decl *D); + + /// @brief Removes a declaration from this context. + void removeDecl(Decl *D); + + /// @brief Checks whether a declaration is in this context. + bool containsDecl(Decl *D) const; + + typedef DeclContextLookupResult lookup_result; + typedef lookup_result::iterator lookup_iterator; + + /// lookup - Find the declarations (if any) with the given Name in + /// this context. Returns a range of iterators that contains all of + /// the declarations with this name, with object, function, member, + /// and enumerator names preceding any tag name. Note that this + /// routine will not look into parent contexts. + lookup_result lookup(DeclarationName Name) const; + + /// \brief Find the declarations with the given name that are visible + /// within this context; don't attempt to retrieve anything from an + /// external source. + lookup_result noload_lookup(DeclarationName Name); + + /// \brief A simplistic name lookup mechanism that performs name lookup + /// into this declaration context without consulting the external source. + /// + /// This function should almost never be used, because it subverts the + /// usual relationship between a DeclContext and the external source. + /// See the ASTImporter for the (few, but important) use cases. + /// + /// FIXME: This is very inefficient; replace uses of it with uses of + /// noload_lookup. + void localUncachedLookup(DeclarationName Name, + SmallVectorImpl<NamedDecl *> &Results); + + /// @brief Makes a declaration visible within this context. + /// + /// This routine makes the declaration D visible to name lookup + /// within this context and, if this is a transparent context, + /// within its parent contexts up to the first enclosing + /// non-transparent context. Making a declaration visible within a + /// context does not transfer ownership of a declaration, and a + /// declaration can be visible in many contexts that aren't its + /// lexical context. + /// + /// If D is a redeclaration of an existing declaration that is + /// visible from this context, as determined by + /// NamedDecl::declarationReplaces, the previous declaration will be + /// replaced with D. + void makeDeclVisibleInContext(NamedDecl *D); + + /// all_lookups_iterator - An iterator that provides a view over the results + /// of looking up every possible name. + class all_lookups_iterator; + + typedef llvm::iterator_range<all_lookups_iterator> lookups_range; + + lookups_range lookups() const; + lookups_range noload_lookups() const; + + /// \brief Iterators over all possible lookups within this context. + all_lookups_iterator lookups_begin() const; + all_lookups_iterator lookups_end() const; + + /// \brief Iterators over all possible lookups within this context that are + /// currently loaded; don't attempt to retrieve anything from an external + /// source. + all_lookups_iterator noload_lookups_begin() const; + all_lookups_iterator noload_lookups_end() const; + + struct udir_iterator; + typedef llvm::iterator_adaptor_base<udir_iterator, lookup_iterator, + std::random_access_iterator_tag, + UsingDirectiveDecl *> udir_iterator_base; + struct udir_iterator : udir_iterator_base { + udir_iterator(lookup_iterator I) : udir_iterator_base(I) {} + UsingDirectiveDecl *operator*() const; + }; + + typedef llvm::iterator_range<udir_iterator> udir_range; + + udir_range using_directives() const; + + // These are all defined in DependentDiagnostic.h. + class ddiag_iterator; + typedef llvm::iterator_range<DeclContext::ddiag_iterator> ddiag_range; + + inline ddiag_range ddiags() const; + + // Low-level accessors + + /// \brief Mark that there are external lexical declarations that we need + /// to include in our lookup table (and that are not available as external + /// visible lookups). These extra lookup results will be found by walking + /// the lexical declarations of this context. This should be used only if + /// setHasExternalLexicalStorage() has been called on any decl context for + /// which this is the primary context. + void setMustBuildLookupTable() { + assert(this == getPrimaryContext() && + "should only be called on primary context"); + HasLazyExternalLexicalLookups = true; + } + + /// \brief Retrieve the internal representation of the lookup structure. + /// This may omit some names if we are lazily building the structure. + StoredDeclsMap *getLookupPtr() const { return LookupPtr; } + + /// \brief Ensure the lookup structure is fully-built and return it. + StoredDeclsMap *buildLookup(); + + /// \brief Whether this DeclContext has external storage containing + /// additional declarations that are lexically in this context. + bool hasExternalLexicalStorage() const { return ExternalLexicalStorage; } + + /// \brief State whether this DeclContext has external storage for + /// declarations lexically in this context. + void setHasExternalLexicalStorage(bool ES = true) { + ExternalLexicalStorage = ES; + } + + /// \brief Whether this DeclContext has external storage containing + /// additional declarations that are visible in this context. + bool hasExternalVisibleStorage() const { return ExternalVisibleStorage; } + + /// \brief State whether this DeclContext has external storage for + /// declarations visible in this context. + void setHasExternalVisibleStorage(bool ES = true) { + ExternalVisibleStorage = ES; + if (ES && LookupPtr) + NeedToReconcileExternalVisibleStorage = true; + } + + /// \brief Determine whether the given declaration is stored in the list of + /// declarations lexically within this context. + bool isDeclInLexicalTraversal(const Decl *D) const { + return D && (D->NextInContextAndBits.getPointer() || D == FirstDecl || + D == LastDecl); + } + + bool setUseQualifiedLookup(bool use = true) { + bool old_value = UseQualifiedLookup; + UseQualifiedLookup = use; + return old_value; + } + + bool shouldUseQualifiedLookup() const { + return UseQualifiedLookup; + } + + static bool classof(const Decl *D); + static bool classof(const DeclContext *D) { return true; } + + void dumpDeclContext() const; + void dumpLookups() const; + void dumpLookups(llvm::raw_ostream &OS, bool DumpDecls = false) const; + +private: + void reconcileExternalVisibleStorage() const; + bool LoadLexicalDeclsFromExternalStorage() const; + + /// @brief Makes a declaration visible within this context, but + /// suppresses searches for external declarations with the same + /// name. + /// + /// Analogous to makeDeclVisibleInContext, but for the exclusive + /// use of addDeclInternal(). + void makeDeclVisibleInContextInternal(NamedDecl *D); + + friend class DependentDiagnostic; + StoredDeclsMap *CreateStoredDeclsMap(ASTContext &C) const; + + void buildLookupImpl(DeclContext *DCtx, bool Internal); + void makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal, + bool Rediscoverable); + void makeDeclVisibleInContextImpl(NamedDecl *D, bool Internal); +}; + +inline bool Decl::isTemplateParameter() const { + return getKind() == TemplateTypeParm || getKind() == NonTypeTemplateParm || + getKind() == TemplateTemplateParm; +} + +// Specialization selected when ToTy is not a known subclass of DeclContext. +template <class ToTy, + bool IsKnownSubtype = ::std::is_base_of<DeclContext, ToTy>::value> +struct cast_convert_decl_context { + static const ToTy *doit(const DeclContext *Val) { + return static_cast<const ToTy*>(Decl::castFromDeclContext(Val)); + } + + static ToTy *doit(DeclContext *Val) { + return static_cast<ToTy*>(Decl::castFromDeclContext(Val)); + } +}; + +// Specialization selected when ToTy is a known subclass of DeclContext. +template <class ToTy> +struct cast_convert_decl_context<ToTy, true> { + static const ToTy *doit(const DeclContext *Val) { + return static_cast<const ToTy*>(Val); + } + + static ToTy *doit(DeclContext *Val) { + return static_cast<ToTy*>(Val); + } +}; + + +} // end clang. + +namespace llvm { + +/// isa<T>(DeclContext*) +template <typename To> +struct isa_impl<To, ::clang::DeclContext> { + static bool doit(const ::clang::DeclContext &Val) { + return To::classofKind(Val.getDeclKind()); + } +}; + +/// cast<T>(DeclContext*) +template<class ToTy> +struct cast_convert_val<ToTy, + const ::clang::DeclContext,const ::clang::DeclContext> { + static const ToTy &doit(const ::clang::DeclContext &Val) { + return *::clang::cast_convert_decl_context<ToTy>::doit(&Val); + } +}; +template<class ToTy> +struct cast_convert_val<ToTy, ::clang::DeclContext, ::clang::DeclContext> { + static ToTy &doit(::clang::DeclContext &Val) { + return *::clang::cast_convert_decl_context<ToTy>::doit(&Val); + } +}; +template<class ToTy> +struct cast_convert_val<ToTy, + const ::clang::DeclContext*, const ::clang::DeclContext*> { + static const ToTy *doit(const ::clang::DeclContext *Val) { + return ::clang::cast_convert_decl_context<ToTy>::doit(Val); + } +}; +template<class ToTy> +struct cast_convert_val<ToTy, ::clang::DeclContext*, ::clang::DeclContext*> { + static ToTy *doit(::clang::DeclContext *Val) { + return ::clang::cast_convert_decl_context<ToTy>::doit(Val); + } +}; + +/// Implement cast_convert_val for Decl -> DeclContext conversions. +template<class FromTy> +struct cast_convert_val< ::clang::DeclContext, FromTy, FromTy> { + static ::clang::DeclContext &doit(const FromTy &Val) { + return *FromTy::castToDeclContext(&Val); + } +}; + +template<class FromTy> +struct cast_convert_val< ::clang::DeclContext, FromTy*, FromTy*> { + static ::clang::DeclContext *doit(const FromTy *Val) { + return FromTy::castToDeclContext(Val); + } +}; + +template<class FromTy> +struct cast_convert_val< const ::clang::DeclContext, FromTy, FromTy> { + static const ::clang::DeclContext &doit(const FromTy &Val) { + return *FromTy::castToDeclContext(&Val); + } +}; + +template<class FromTy> +struct cast_convert_val< const ::clang::DeclContext, FromTy*, FromTy*> { + static const ::clang::DeclContext *doit(const FromTy *Val) { + return FromTy::castToDeclContext(Val); + } +}; + +} // end namespace llvm + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/DeclCXX.h b/contrib/llvm/tools/clang/include/clang/AST/DeclCXX.h new file mode 100644 index 0000000..7c54901 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/DeclCXX.h @@ -0,0 +1,3249 @@ +//===-- DeclCXX.h - Classes for representing C++ declarations -*- C++ -*-=====// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the C++ Decl subclasses, other than those for templates +/// (found in DeclTemplate.h) and friends (in DeclFriend.h). +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DECLCXX_H +#define LLVM_CLANG_AST_DECLCXX_H + +#include "clang/AST/ASTUnresolvedSet.h" +#include "clang/AST/Attr.h" +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "clang/AST/LambdaCapture.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/Support/Compiler.h" + +namespace clang { + +class ClassTemplateDecl; +class ClassTemplateSpecializationDecl; +class CXXBasePath; +class CXXBasePaths; +class CXXConstructorDecl; +class CXXConversionDecl; +class CXXDestructorDecl; +class CXXMethodDecl; +class CXXRecordDecl; +class CXXMemberLookupCriteria; +class CXXFinalOverriderMap; +class CXXIndirectPrimaryBaseSet; +class FriendDecl; +class LambdaExpr; +class UsingDecl; + +/// \brief Represents any kind of function declaration, whether it is a +/// concrete function or a function template. +class AnyFunctionDecl { + NamedDecl *Function; + + AnyFunctionDecl(NamedDecl *ND) : Function(ND) { } + +public: + AnyFunctionDecl(FunctionDecl *FD) : Function(FD) { } + AnyFunctionDecl(FunctionTemplateDecl *FTD); + + /// \brief Implicily converts any function or function template into a + /// named declaration. + operator NamedDecl *() const { return Function; } + + /// \brief Retrieve the underlying function or function template. + NamedDecl *get() const { return Function; } + + static AnyFunctionDecl getFromNamedDecl(NamedDecl *ND) { + return AnyFunctionDecl(ND); + } +}; + +} // end namespace clang + +namespace llvm { + // Provide PointerLikeTypeTraits for non-cvr pointers. + template<> + class PointerLikeTypeTraits< ::clang::AnyFunctionDecl> { + public: + static inline void *getAsVoidPointer(::clang::AnyFunctionDecl F) { + return F.get(); + } + static inline ::clang::AnyFunctionDecl getFromVoidPointer(void *P) { + return ::clang::AnyFunctionDecl::getFromNamedDecl( + static_cast< ::clang::NamedDecl*>(P)); + } + + enum { NumLowBitsAvailable = 2 }; + }; + +} // end namespace llvm + +namespace clang { + +/// \brief Represents an access specifier followed by colon ':'. +/// +/// An objects of this class represents sugar for the syntactic occurrence +/// of an access specifier followed by a colon in the list of member +/// specifiers of a C++ class definition. +/// +/// Note that they do not represent other uses of access specifiers, +/// such as those occurring in a list of base specifiers. +/// Also note that this class has nothing to do with so-called +/// "access declarations" (C++98 11.3 [class.access.dcl]). +class AccessSpecDecl : public Decl { + virtual void anchor(); + /// \brief The location of the ':'. + SourceLocation ColonLoc; + + AccessSpecDecl(AccessSpecifier AS, DeclContext *DC, + SourceLocation ASLoc, SourceLocation ColonLoc) + : Decl(AccessSpec, DC, ASLoc), ColonLoc(ColonLoc) { + setAccess(AS); + } + AccessSpecDecl(EmptyShell Empty) + : Decl(AccessSpec, Empty) { } +public: + /// \brief The location of the access specifier. + SourceLocation getAccessSpecifierLoc() const { return getLocation(); } + /// \brief Sets the location of the access specifier. + void setAccessSpecifierLoc(SourceLocation ASLoc) { setLocation(ASLoc); } + + /// \brief The location of the colon following the access specifier. + SourceLocation getColonLoc() const { return ColonLoc; } + /// \brief Sets the location of the colon. + void setColonLoc(SourceLocation CLoc) { ColonLoc = CLoc; } + + SourceRange getSourceRange() const override LLVM_READONLY { + return SourceRange(getAccessSpecifierLoc(), getColonLoc()); + } + + static AccessSpecDecl *Create(ASTContext &C, AccessSpecifier AS, + DeclContext *DC, SourceLocation ASLoc, + SourceLocation ColonLoc) { + return new (C, DC) AccessSpecDecl(AS, DC, ASLoc, ColonLoc); + } + static AccessSpecDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == AccessSpec; } +}; + + +/// \brief Represents a base class of a C++ class. +/// +/// Each CXXBaseSpecifier represents a single, direct base class (or +/// struct) of a C++ class (or struct). It specifies the type of that +/// base class, whether it is a virtual or non-virtual base, and what +/// level of access (public, protected, private) is used for the +/// derivation. For example: +/// +/// \code +/// class A { }; +/// class B { }; +/// class C : public virtual A, protected B { }; +/// \endcode +/// +/// In this code, C will have two CXXBaseSpecifiers, one for "public +/// virtual A" and the other for "protected B". +class CXXBaseSpecifier { + /// \brief The source code range that covers the full base + /// specifier, including the "virtual" (if present) and access + /// specifier (if present). + SourceRange Range; + + /// \brief The source location of the ellipsis, if this is a pack + /// expansion. + SourceLocation EllipsisLoc; + + /// \brief Whether this is a virtual base class or not. + bool Virtual : 1; + + /// \brief Whether this is the base of a class (true) or of a struct (false). + /// + /// This determines the mapping from the access specifier as written in the + /// source code to the access specifier used for semantic analysis. + bool BaseOfClass : 1; + + /// \brief Access specifier as written in the source code (may be AS_none). + /// + /// The actual type of data stored here is an AccessSpecifier, but we use + /// "unsigned" here to work around a VC++ bug. + unsigned Access : 2; + + /// \brief Whether the class contains a using declaration + /// to inherit the named class's constructors. + bool InheritConstructors : 1; + + /// \brief The type of the base class. + /// + /// This will be a class or struct (or a typedef of such). The source code + /// range does not include the \c virtual or the access specifier. + TypeSourceInfo *BaseTypeInfo; + +public: + CXXBaseSpecifier() { } + + CXXBaseSpecifier(SourceRange R, bool V, bool BC, AccessSpecifier A, + TypeSourceInfo *TInfo, SourceLocation EllipsisLoc) + : Range(R), EllipsisLoc(EllipsisLoc), Virtual(V), BaseOfClass(BC), + Access(A), InheritConstructors(false), BaseTypeInfo(TInfo) { } + + /// \brief Retrieves the source range that contains the entire base specifier. + SourceRange getSourceRange() const LLVM_READONLY { return Range; } + SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } + SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } + + /// \brief Determines whether the base class is a virtual base class (or not). + bool isVirtual() const { return Virtual; } + + /// \brief Determine whether this base class is a base of a class declared + /// with the 'class' keyword (vs. one declared with the 'struct' keyword). + bool isBaseOfClass() const { return BaseOfClass; } + + /// \brief Determine whether this base specifier is a pack expansion. + bool isPackExpansion() const { return EllipsisLoc.isValid(); } + + /// \brief Determine whether this base class's constructors get inherited. + bool getInheritConstructors() const { return InheritConstructors; } + + /// \brief Set that this base class's constructors should be inherited. + void setInheritConstructors(bool Inherit = true) { + InheritConstructors = Inherit; + } + + /// \brief For a pack expansion, determine the location of the ellipsis. + SourceLocation getEllipsisLoc() const { + return EllipsisLoc; + } + + /// \brief Returns the access specifier for this base specifier. + /// + /// This is the actual base specifier as used for semantic analysis, so + /// the result can never be AS_none. To retrieve the access specifier as + /// written in the source code, use getAccessSpecifierAsWritten(). + AccessSpecifier getAccessSpecifier() const { + if ((AccessSpecifier)Access == AS_none) + return BaseOfClass? AS_private : AS_public; + else + return (AccessSpecifier)Access; + } + + /// \brief Retrieves the access specifier as written in the source code + /// (which may mean that no access specifier was explicitly written). + /// + /// Use getAccessSpecifier() to retrieve the access specifier for use in + /// semantic analysis. + AccessSpecifier getAccessSpecifierAsWritten() const { + return (AccessSpecifier)Access; + } + + /// \brief Retrieves the type of the base class. + /// + /// This type will always be an unqualified class type. + QualType getType() const { + return BaseTypeInfo->getType().getUnqualifiedType(); + } + + /// \brief Retrieves the type and source location of the base class. + TypeSourceInfo *getTypeSourceInfo() const { return BaseTypeInfo; } +}; + +/// \brief A lazy pointer to the definition data for a declaration. +/// FIXME: This is a little CXXRecordDecl-specific that the moment. +template<typename Decl, typename T> class LazyDefinitionDataPtr { + llvm::PointerUnion<T *, Decl *> DataOrCanonicalDecl; + + LazyDefinitionDataPtr update() { + if (Decl *Canon = DataOrCanonicalDecl.template dyn_cast<Decl*>()) { + if (Canon->isCanonicalDecl()) + Canon->getMostRecentDecl(); + else + // Declaration isn't canonical any more; + // update it and perform path compression. + *this = Canon->getPreviousDecl()->DefinitionData.update(); + } + return *this; + } + +public: + LazyDefinitionDataPtr(Decl *Canon) : DataOrCanonicalDecl(Canon) {} + LazyDefinitionDataPtr(T *Data) : DataOrCanonicalDecl(Data) {} + T *getNotUpdated() { return DataOrCanonicalDecl.template dyn_cast<T*>(); } + T *get() { return update().getNotUpdated(); } +}; + +/// \brief Represents a C++ struct/union/class. +class CXXRecordDecl : public RecordDecl { + + friend void TagDecl::startDefinition(); + + /// Values used in DefinitionData fields to represent special members. + enum SpecialMemberFlags { + SMF_DefaultConstructor = 0x1, + SMF_CopyConstructor = 0x2, + SMF_MoveConstructor = 0x4, + SMF_CopyAssignment = 0x8, + SMF_MoveAssignment = 0x10, + SMF_Destructor = 0x20, + SMF_All = 0x3f + }; + + struct DefinitionData { + DefinitionData(CXXRecordDecl *D); + + /// \brief True if this class has any user-declared constructors. + bool UserDeclaredConstructor : 1; + + /// \brief The user-declared special members which this class has. + unsigned UserDeclaredSpecialMembers : 6; + + /// \brief True when this class is an aggregate. + bool Aggregate : 1; + + /// \brief True when this class is a POD-type. + bool PlainOldData : 1; + + /// true when this class is empty for traits purposes, + /// i.e. has no data members other than 0-width bit-fields, has no + /// virtual function/base, and doesn't inherit from a non-empty + /// class. Doesn't take union-ness into account. + bool Empty : 1; + + /// \brief True when this class is polymorphic, i.e., has at + /// least one virtual member or derives from a polymorphic class. + bool Polymorphic : 1; + + /// \brief True when this class is abstract, i.e., has at least + /// one pure virtual function, (that can come from a base class). + bool Abstract : 1; + + /// \brief True when this class has standard layout. + /// + /// C++11 [class]p7. A standard-layout class is a class that: + /// * has no non-static data members of type non-standard-layout class (or + /// array of such types) or reference, + /// * has no virtual functions (10.3) and no virtual base classes (10.1), + /// * has the same access control (Clause 11) for all non-static data + /// members + /// * has no non-standard-layout base classes, + /// * either has no non-static data members in the most derived class and at + /// most one base class with non-static data members, or has no base + /// classes with non-static data members, and + /// * has no base classes of the same type as the first non-static data + /// member. + bool IsStandardLayout : 1; + + /// \brief True when there are no non-empty base classes. + /// + /// This is a helper bit of state used to implement IsStandardLayout more + /// efficiently. + bool HasNoNonEmptyBases : 1; + + /// \brief True when there are private non-static data members. + bool HasPrivateFields : 1; + + /// \brief True when there are protected non-static data members. + bool HasProtectedFields : 1; + + /// \brief True when there are private non-static data members. + bool HasPublicFields : 1; + + /// \brief True if this class (or any subobject) has mutable fields. + bool HasMutableFields : 1; + + /// \brief True if this class (or any nested anonymous struct or union) + /// has variant members. + bool HasVariantMembers : 1; + + /// \brief True if there no non-field members declared by the user. + bool HasOnlyCMembers : 1; + + /// \brief True if any field has an in-class initializer, including those + /// within anonymous unions or structs. + bool HasInClassInitializer : 1; + + /// \brief True if any field is of reference type, and does not have an + /// in-class initializer. + /// + /// In this case, value-initialization of this class is illegal in C++98 + /// even if the class has a trivial default constructor. + bool HasUninitializedReferenceMember : 1; + + /// \brief These flags are \c true if a defaulted corresponding special + /// member can't be fully analyzed without performing overload resolution. + /// @{ + bool NeedOverloadResolutionForMoveConstructor : 1; + bool NeedOverloadResolutionForMoveAssignment : 1; + bool NeedOverloadResolutionForDestructor : 1; + /// @} + + /// \brief These flags are \c true if an implicit defaulted corresponding + /// special member would be defined as deleted. + /// @{ + bool DefaultedMoveConstructorIsDeleted : 1; + bool DefaultedMoveAssignmentIsDeleted : 1; + bool DefaultedDestructorIsDeleted : 1; + /// @} + + /// \brief The trivial special members which this class has, per + /// C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25, + /// C++11 [class.dtor]p5, or would have if the member were not suppressed. + /// + /// This excludes any user-declared but not user-provided special members + /// which have been declared but not yet defined. + unsigned HasTrivialSpecialMembers : 6; + + /// \brief The declared special members of this class which are known to be + /// non-trivial. + /// + /// This excludes any user-declared but not user-provided special members + /// which have been declared but not yet defined, and any implicit special + /// members which have not yet been declared. + unsigned DeclaredNonTrivialSpecialMembers : 6; + + /// \brief True when this class has a destructor with no semantic effect. + bool HasIrrelevantDestructor : 1; + + /// \brief True when this class has at least one user-declared constexpr + /// constructor which is neither the copy nor move constructor. + bool HasConstexprNonCopyMoveConstructor : 1; + + /// \brief True if a defaulted default constructor for this class would + /// be constexpr. + bool DefaultedDefaultConstructorIsConstexpr : 1; + + /// \brief True if this class has a constexpr default constructor. + /// + /// This is true for either a user-declared constexpr default constructor + /// or an implicitly declared constexpr default constructor. + bool HasConstexprDefaultConstructor : 1; + + /// \brief True when this class contains at least one non-static data + /// member or base class of non-literal or volatile type. + bool HasNonLiteralTypeFieldsOrBases : 1; + + /// \brief True when visible conversion functions are already computed + /// and are available. + bool ComputedVisibleConversions : 1; + + /// \brief Whether we have a C++11 user-provided default constructor (not + /// explicitly deleted or defaulted). + bool UserProvidedDefaultConstructor : 1; + + /// \brief The special members which have been declared for this class, + /// either by the user or implicitly. + unsigned DeclaredSpecialMembers : 6; + + /// \brief Whether an implicit copy constructor would have a const-qualified + /// parameter. + bool ImplicitCopyConstructorHasConstParam : 1; + + /// \brief Whether an implicit copy assignment operator would have a + /// const-qualified parameter. + bool ImplicitCopyAssignmentHasConstParam : 1; + + /// \brief Whether any declared copy constructor has a const-qualified + /// parameter. + bool HasDeclaredCopyConstructorWithConstParam : 1; + + /// \brief Whether any declared copy assignment operator has either a + /// const-qualified reference parameter or a non-reference parameter. + bool HasDeclaredCopyAssignmentWithConstParam : 1; + + /// \brief Whether this class describes a C++ lambda. + bool IsLambda : 1; + + /// \brief Whether we are currently parsing base specifiers. + bool IsParsingBaseSpecifiers : 1; + + /// \brief The number of base class specifiers in Bases. + unsigned NumBases; + + /// \brief The number of virtual base class specifiers in VBases. + unsigned NumVBases; + + /// \brief Base classes of this class. + /// + /// FIXME: This is wasted space for a union. + LazyCXXBaseSpecifiersPtr Bases; + + /// \brief direct and indirect virtual base classes of this class. + LazyCXXBaseSpecifiersPtr VBases; + + /// \brief The conversion functions of this C++ class (but not its + /// inherited conversion functions). + /// + /// Each of the entries in this overload set is a CXXConversionDecl. + LazyASTUnresolvedSet Conversions; + + /// \brief The conversion functions of this C++ class and all those + /// inherited conversion functions that are visible in this class. + /// + /// Each of the entries in this overload set is a CXXConversionDecl or a + /// FunctionTemplateDecl. + LazyASTUnresolvedSet VisibleConversions; + + /// \brief The declaration which defines this record. + CXXRecordDecl *Definition; + + /// \brief The first friend declaration in this class, or null if there + /// aren't any. + /// + /// This is actually currently stored in reverse order. + LazyDeclPtr FirstFriend; + + /// \brief Retrieve the set of direct base classes. + CXXBaseSpecifier *getBases() const { + if (!Bases.isOffset()) + return Bases.get(nullptr); + return getBasesSlowCase(); + } + + /// \brief Retrieve the set of virtual base classes. + CXXBaseSpecifier *getVBases() const { + if (!VBases.isOffset()) + return VBases.get(nullptr); + return getVBasesSlowCase(); + } + + private: + CXXBaseSpecifier *getBasesSlowCase() const; + CXXBaseSpecifier *getVBasesSlowCase() const; + }; + + typedef LazyDefinitionDataPtr<CXXRecordDecl, struct DefinitionData> + DefinitionDataPtr; + friend class LazyDefinitionDataPtr<CXXRecordDecl, struct DefinitionData>; + + mutable DefinitionDataPtr DefinitionData; + + /// \brief Describes a C++ closure type (generated by a lambda expression). + struct LambdaDefinitionData : public DefinitionData { + typedef LambdaCapture Capture; + + LambdaDefinitionData(CXXRecordDecl *D, TypeSourceInfo *Info, + bool Dependent, bool IsGeneric, + LambdaCaptureDefault CaptureDefault) + : DefinitionData(D), Dependent(Dependent), IsGenericLambda(IsGeneric), + CaptureDefault(CaptureDefault), NumCaptures(0), NumExplicitCaptures(0), + ManglingNumber(0), ContextDecl(nullptr), Captures(nullptr), + MethodTyInfo(Info) { + IsLambda = true; + + // C++11 [expr.prim.lambda]p3: + // This class type is neither an aggregate nor a literal type. + Aggregate = false; + PlainOldData = false; + HasNonLiteralTypeFieldsOrBases = true; + } + + /// \brief Whether this lambda is known to be dependent, even if its + /// context isn't dependent. + /// + /// A lambda with a non-dependent context can be dependent if it occurs + /// within the default argument of a function template, because the + /// lambda will have been created with the enclosing context as its + /// declaration context, rather than function. This is an unfortunate + /// artifact of having to parse the default arguments before. + unsigned Dependent : 1; + + /// \brief Whether this lambda is a generic lambda. + unsigned IsGenericLambda : 1; + + /// \brief The Default Capture. + unsigned CaptureDefault : 2; + + /// \brief The number of captures in this lambda is limited 2^NumCaptures. + unsigned NumCaptures : 15; + + /// \brief The number of explicit captures in this lambda. + unsigned NumExplicitCaptures : 13; + + /// \brief The number used to indicate this lambda expression for name + /// mangling in the Itanium C++ ABI. + unsigned ManglingNumber; + + /// \brief The declaration that provides context for this lambda, if the + /// actual DeclContext does not suffice. This is used for lambdas that + /// occur within default arguments of function parameters within the class + /// or within a data member initializer. + Decl *ContextDecl; + + /// \brief The list of captures, both explicit and implicit, for this + /// lambda. + Capture *Captures; + + /// \brief The type of the call method. + TypeSourceInfo *MethodTyInfo; + + }; + + struct DefinitionData &data() const { + auto *DD = DefinitionData.get(); + assert(DD && "queried property of class with no definition"); + return *DD; + } + + struct LambdaDefinitionData &getLambdaData() const { + // No update required: a merged definition cannot change any lambda + // properties. + auto *DD = DefinitionData.getNotUpdated(); + assert(DD && DD->IsLambda && "queried lambda property of non-lambda class"); + return static_cast<LambdaDefinitionData&>(*DD); + } + + /// \brief The template or declaration that this declaration + /// describes or was instantiated from, respectively. + /// + /// For non-templates, this value will be null. For record + /// declarations that describe a class template, this will be a + /// pointer to a ClassTemplateDecl. For member + /// classes of class template specializations, this will be the + /// MemberSpecializationInfo referring to the member class that was + /// instantiated or specialized. + llvm::PointerUnion<ClassTemplateDecl*, MemberSpecializationInfo*> + TemplateOrInstantiation; + + friend class DeclContext; + friend class LambdaExpr; + + /// \brief Called from setBases and addedMember to notify the class that a + /// direct or virtual base class or a member of class type has been added. + void addedClassSubobject(CXXRecordDecl *Base); + + /// \brief Notify the class that member has been added. + /// + /// This routine helps maintain information about the class based on which + /// members have been added. It will be invoked by DeclContext::addDecl() + /// whenever a member is added to this record. + void addedMember(Decl *D); + + void markedVirtualFunctionPure(); + friend void FunctionDecl::setPure(bool); + + friend class ASTNodeImporter; + + /// \brief Get the head of our list of friend declarations, possibly + /// deserializing the friends from an external AST source. + FriendDecl *getFirstFriend() const; + +protected: + CXXRecordDecl(Kind K, TagKind TK, const ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, CXXRecordDecl *PrevDecl); + +public: + /// \brief Iterator that traverses the base classes of a class. + typedef CXXBaseSpecifier* base_class_iterator; + + /// \brief Iterator that traverses the base classes of a class. + typedef const CXXBaseSpecifier* base_class_const_iterator; + + CXXRecordDecl *getCanonicalDecl() override { + return cast<CXXRecordDecl>(RecordDecl::getCanonicalDecl()); + } + const CXXRecordDecl *getCanonicalDecl() const { + return const_cast<CXXRecordDecl*>(this)->getCanonicalDecl(); + } + + CXXRecordDecl *getPreviousDecl() { + return cast_or_null<CXXRecordDecl>( + static_cast<RecordDecl *>(this)->getPreviousDecl()); + } + const CXXRecordDecl *getPreviousDecl() const { + return const_cast<CXXRecordDecl*>(this)->getPreviousDecl(); + } + + CXXRecordDecl *getMostRecentDecl() { + return cast<CXXRecordDecl>( + static_cast<RecordDecl *>(this)->getMostRecentDecl()); + } + + const CXXRecordDecl *getMostRecentDecl() const { + return const_cast<CXXRecordDecl*>(this)->getMostRecentDecl(); + } + + CXXRecordDecl *getDefinition() const { + auto *DD = DefinitionData.get(); + return DD ? DD->Definition : nullptr; + } + + bool hasDefinition() const { return DefinitionData.get(); } + + static CXXRecordDecl *Create(const ASTContext &C, TagKind TK, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, + CXXRecordDecl *PrevDecl = nullptr, + bool DelayTypeCreation = false); + static CXXRecordDecl *CreateLambda(const ASTContext &C, DeclContext *DC, + TypeSourceInfo *Info, SourceLocation Loc, + bool DependentLambda, bool IsGeneric, + LambdaCaptureDefault CaptureDefault); + static CXXRecordDecl *CreateDeserialized(const ASTContext &C, unsigned ID); + + bool isDynamicClass() const { + return data().Polymorphic || data().NumVBases != 0; + } + + void setIsParsingBaseSpecifiers() { data().IsParsingBaseSpecifiers = true; } + + bool isParsingBaseSpecifiers() const { + return data().IsParsingBaseSpecifiers; + } + + /// \brief Sets the base classes of this struct or class. + void setBases(CXXBaseSpecifier const * const *Bases, unsigned NumBases); + + /// \brief Retrieves the number of base classes of this class. + unsigned getNumBases() const { return data().NumBases; } + + typedef llvm::iterator_range<base_class_iterator> base_class_range; + typedef llvm::iterator_range<base_class_const_iterator> + base_class_const_range; + + base_class_range bases() { + return base_class_range(bases_begin(), bases_end()); + } + base_class_const_range bases() const { + return base_class_const_range(bases_begin(), bases_end()); + } + + base_class_iterator bases_begin() { return data().getBases(); } + base_class_const_iterator bases_begin() const { return data().getBases(); } + base_class_iterator bases_end() { return bases_begin() + data().NumBases; } + base_class_const_iterator bases_end() const { + return bases_begin() + data().NumBases; + } + + /// \brief Retrieves the number of virtual base classes of this class. + unsigned getNumVBases() const { return data().NumVBases; } + + base_class_range vbases() { + return base_class_range(vbases_begin(), vbases_end()); + } + base_class_const_range vbases() const { + return base_class_const_range(vbases_begin(), vbases_end()); + } + + base_class_iterator vbases_begin() { return data().getVBases(); } + base_class_const_iterator vbases_begin() const { return data().getVBases(); } + base_class_iterator vbases_end() { return vbases_begin() + data().NumVBases; } + base_class_const_iterator vbases_end() const { + return vbases_begin() + data().NumVBases; + } + + /// \brief Determine whether this class has any dependent base classes which + /// are not the current instantiation. + bool hasAnyDependentBases() const; + + /// Iterator access to method members. The method iterator visits + /// all method members of the class, including non-instance methods, + /// special methods, etc. + typedef specific_decl_iterator<CXXMethodDecl> method_iterator; + typedef llvm::iterator_range<specific_decl_iterator<CXXMethodDecl>> + method_range; + + method_range methods() const { + return method_range(method_begin(), method_end()); + } + + /// \brief Method begin iterator. Iterates in the order the methods + /// were declared. + method_iterator method_begin() const { + return method_iterator(decls_begin()); + } + /// \brief Method past-the-end iterator. + method_iterator method_end() const { + return method_iterator(decls_end()); + } + + /// Iterator access to constructor members. + typedef specific_decl_iterator<CXXConstructorDecl> ctor_iterator; + typedef llvm::iterator_range<specific_decl_iterator<CXXConstructorDecl>> + ctor_range; + + ctor_range ctors() const { return ctor_range(ctor_begin(), ctor_end()); } + + ctor_iterator ctor_begin() const { + return ctor_iterator(decls_begin()); + } + ctor_iterator ctor_end() const { + return ctor_iterator(decls_end()); + } + + /// An iterator over friend declarations. All of these are defined + /// in DeclFriend.h. + class friend_iterator; + typedef llvm::iterator_range<friend_iterator> friend_range; + + friend_range friends() const; + friend_iterator friend_begin() const; + friend_iterator friend_end() const; + void pushFriendDecl(FriendDecl *FD); + + /// Determines whether this record has any friends. + bool hasFriends() const { + return data().FirstFriend.isValid(); + } + + /// \brief \c true if we know for sure that this class has a single, + /// accessible, unambiguous move constructor that is not deleted. + bool hasSimpleMoveConstructor() const { + return !hasUserDeclaredMoveConstructor() && hasMoveConstructor() && + !data().DefaultedMoveConstructorIsDeleted; + } + /// \brief \c true if we know for sure that this class has a single, + /// accessible, unambiguous move assignment operator that is not deleted. + bool hasSimpleMoveAssignment() const { + return !hasUserDeclaredMoveAssignment() && hasMoveAssignment() && + !data().DefaultedMoveAssignmentIsDeleted; + } + /// \brief \c true if we know for sure that this class has an accessible + /// destructor that is not deleted. + bool hasSimpleDestructor() const { + return !hasUserDeclaredDestructor() && + !data().DefaultedDestructorIsDeleted; + } + + /// \brief Determine whether this class has any default constructors. + bool hasDefaultConstructor() const { + return (data().DeclaredSpecialMembers & SMF_DefaultConstructor) || + needsImplicitDefaultConstructor(); + } + + /// \brief Determine if we need to declare a default constructor for + /// this class. + /// + /// This value is used for lazy creation of default constructors. + bool needsImplicitDefaultConstructor() const { + return !data().UserDeclaredConstructor && + !(data().DeclaredSpecialMembers & SMF_DefaultConstructor) && + // C++14 [expr.prim.lambda]p20: + // The closure type associated with a lambda-expression has no + // default constructor. + !isLambda(); + } + + /// \brief Determine whether this class has any user-declared constructors. + /// + /// When true, a default constructor will not be implicitly declared. + bool hasUserDeclaredConstructor() const { + return data().UserDeclaredConstructor; + } + + /// \brief Whether this class has a user-provided default constructor + /// per C++11. + bool hasUserProvidedDefaultConstructor() const { + return data().UserProvidedDefaultConstructor; + } + + /// \brief Determine whether this class has a user-declared copy constructor. + /// + /// When false, a copy constructor will be implicitly declared. + bool hasUserDeclaredCopyConstructor() const { + return data().UserDeclaredSpecialMembers & SMF_CopyConstructor; + } + + /// \brief Determine whether this class needs an implicit copy + /// constructor to be lazily declared. + bool needsImplicitCopyConstructor() const { + return !(data().DeclaredSpecialMembers & SMF_CopyConstructor); + } + + /// \brief Determine whether we need to eagerly declare a defaulted copy + /// constructor for this class. + bool needsOverloadResolutionForCopyConstructor() const { + return data().HasMutableFields; + } + + /// \brief Determine whether an implicit copy constructor for this type + /// would have a parameter with a const-qualified reference type. + bool implicitCopyConstructorHasConstParam() const { + return data().ImplicitCopyConstructorHasConstParam; + } + + /// \brief Determine whether this class has a copy constructor with + /// a parameter type which is a reference to a const-qualified type. + bool hasCopyConstructorWithConstParam() const { + return data().HasDeclaredCopyConstructorWithConstParam || + (needsImplicitCopyConstructor() && + implicitCopyConstructorHasConstParam()); + } + + /// \brief Whether this class has a user-declared move constructor or + /// assignment operator. + /// + /// When false, a move constructor and assignment operator may be + /// implicitly declared. + bool hasUserDeclaredMoveOperation() const { + return data().UserDeclaredSpecialMembers & + (SMF_MoveConstructor | SMF_MoveAssignment); + } + + /// \brief Determine whether this class has had a move constructor + /// declared by the user. + bool hasUserDeclaredMoveConstructor() const { + return data().UserDeclaredSpecialMembers & SMF_MoveConstructor; + } + + /// \brief Determine whether this class has a move constructor. + bool hasMoveConstructor() const { + return (data().DeclaredSpecialMembers & SMF_MoveConstructor) || + needsImplicitMoveConstructor(); + } + + /// \brief Set that we attempted to declare an implicitly move + /// constructor, but overload resolution failed so we deleted it. + void setImplicitMoveConstructorIsDeleted() { + assert((data().DefaultedMoveConstructorIsDeleted || + needsOverloadResolutionForMoveConstructor()) && + "move constructor should not be deleted"); + data().DefaultedMoveConstructorIsDeleted = true; + } + + /// \brief Determine whether this class should get an implicit move + /// constructor or if any existing special member function inhibits this. + bool needsImplicitMoveConstructor() const { + return !(data().DeclaredSpecialMembers & SMF_MoveConstructor) && + !hasUserDeclaredCopyConstructor() && + !hasUserDeclaredCopyAssignment() && + !hasUserDeclaredMoveAssignment() && + !hasUserDeclaredDestructor(); + } + + /// \brief Determine whether we need to eagerly declare a defaulted move + /// constructor for this class. + bool needsOverloadResolutionForMoveConstructor() const { + return data().NeedOverloadResolutionForMoveConstructor; + } + + /// \brief Determine whether this class has a user-declared copy assignment + /// operator. + /// + /// When false, a copy assigment operator will be implicitly declared. + bool hasUserDeclaredCopyAssignment() const { + return data().UserDeclaredSpecialMembers & SMF_CopyAssignment; + } + + /// \brief Determine whether this class needs an implicit copy + /// assignment operator to be lazily declared. + bool needsImplicitCopyAssignment() const { + return !(data().DeclaredSpecialMembers & SMF_CopyAssignment); + } + + /// \brief Determine whether we need to eagerly declare a defaulted copy + /// assignment operator for this class. + bool needsOverloadResolutionForCopyAssignment() const { + return data().HasMutableFields; + } + + /// \brief Determine whether an implicit copy assignment operator for this + /// type would have a parameter with a const-qualified reference type. + bool implicitCopyAssignmentHasConstParam() const { + return data().ImplicitCopyAssignmentHasConstParam; + } + + /// \brief Determine whether this class has a copy assignment operator with + /// a parameter type which is a reference to a const-qualified type or is not + /// a reference. + bool hasCopyAssignmentWithConstParam() const { + return data().HasDeclaredCopyAssignmentWithConstParam || + (needsImplicitCopyAssignment() && + implicitCopyAssignmentHasConstParam()); + } + + /// \brief Determine whether this class has had a move assignment + /// declared by the user. + bool hasUserDeclaredMoveAssignment() const { + return data().UserDeclaredSpecialMembers & SMF_MoveAssignment; + } + + /// \brief Determine whether this class has a move assignment operator. + bool hasMoveAssignment() const { + return (data().DeclaredSpecialMembers & SMF_MoveAssignment) || + needsImplicitMoveAssignment(); + } + + /// \brief Set that we attempted to declare an implicit move assignment + /// operator, but overload resolution failed so we deleted it. + void setImplicitMoveAssignmentIsDeleted() { + assert((data().DefaultedMoveAssignmentIsDeleted || + needsOverloadResolutionForMoveAssignment()) && + "move assignment should not be deleted"); + data().DefaultedMoveAssignmentIsDeleted = true; + } + + /// \brief Determine whether this class should get an implicit move + /// assignment operator or if any existing special member function inhibits + /// this. + bool needsImplicitMoveAssignment() const { + return !(data().DeclaredSpecialMembers & SMF_MoveAssignment) && + !hasUserDeclaredCopyConstructor() && + !hasUserDeclaredCopyAssignment() && + !hasUserDeclaredMoveConstructor() && + !hasUserDeclaredDestructor(); + } + + /// \brief Determine whether we need to eagerly declare a move assignment + /// operator for this class. + bool needsOverloadResolutionForMoveAssignment() const { + return data().NeedOverloadResolutionForMoveAssignment; + } + + /// \brief Determine whether this class has a user-declared destructor. + /// + /// When false, a destructor will be implicitly declared. + bool hasUserDeclaredDestructor() const { + return data().UserDeclaredSpecialMembers & SMF_Destructor; + } + + /// \brief Determine whether this class needs an implicit destructor to + /// be lazily declared. + bool needsImplicitDestructor() const { + return !(data().DeclaredSpecialMembers & SMF_Destructor); + } + + /// \brief Determine whether we need to eagerly declare a destructor for this + /// class. + bool needsOverloadResolutionForDestructor() const { + return data().NeedOverloadResolutionForDestructor; + } + + /// \brief Determine whether this class describes a lambda function object. + bool isLambda() const { + // An update record can't turn a non-lambda into a lambda. + auto *DD = DefinitionData.getNotUpdated(); + return DD && DD->IsLambda; + } + + /// \brief Determine whether this class describes a generic + /// lambda function object (i.e. function call operator is + /// a template). + bool isGenericLambda() const; + + /// \brief Retrieve the lambda call operator of the closure type + /// if this is a closure type. + CXXMethodDecl *getLambdaCallOperator() const; + + /// \brief Retrieve the lambda static invoker, the address of which + /// is returned by the conversion operator, and the body of which + /// is forwarded to the lambda call operator. + CXXMethodDecl *getLambdaStaticInvoker() const; + + /// \brief Retrieve the generic lambda's template parameter list. + /// Returns null if the class does not represent a lambda or a generic + /// lambda. + TemplateParameterList *getGenericLambdaTemplateParameterList() const; + + LambdaCaptureDefault getLambdaCaptureDefault() const { + assert(isLambda()); + return static_cast<LambdaCaptureDefault>(getLambdaData().CaptureDefault); + } + + /// \brief For a closure type, retrieve the mapping from captured + /// variables and \c this to the non-static data members that store the + /// values or references of the captures. + /// + /// \param Captures Will be populated with the mapping from captured + /// variables to the corresponding fields. + /// + /// \param ThisCapture Will be set to the field declaration for the + /// \c this capture. + /// + /// \note No entries will be added for init-captures, as they do not capture + /// variables. + void getCaptureFields(llvm::DenseMap<const VarDecl *, FieldDecl *> &Captures, + FieldDecl *&ThisCapture) const; + + typedef const LambdaCapture *capture_const_iterator; + typedef llvm::iterator_range<capture_const_iterator> capture_const_range; + + capture_const_range captures() const { + return capture_const_range(captures_begin(), captures_end()); + } + capture_const_iterator captures_begin() const { + return isLambda() ? getLambdaData().Captures : nullptr; + } + capture_const_iterator captures_end() const { + return isLambda() ? captures_begin() + getLambdaData().NumCaptures + : nullptr; + } + + typedef UnresolvedSetIterator conversion_iterator; + conversion_iterator conversion_begin() const { + return data().Conversions.get(getASTContext()).begin(); + } + conversion_iterator conversion_end() const { + return data().Conversions.get(getASTContext()).end(); + } + + /// Removes a conversion function from this class. The conversion + /// function must currently be a member of this class. Furthermore, + /// this class must currently be in the process of being defined. + void removeConversion(const NamedDecl *Old); + + /// \brief Get all conversion functions visible in current class, + /// including conversion function templates. + llvm::iterator_range<conversion_iterator> getVisibleConversionFunctions(); + + /// Determine whether this class is an aggregate (C++ [dcl.init.aggr]), + /// which is a class with no user-declared constructors, no private + /// or protected non-static data members, no base classes, and no virtual + /// functions (C++ [dcl.init.aggr]p1). + bool isAggregate() const { return data().Aggregate; } + + /// \brief Whether this class has any in-class initializers + /// for non-static data members (including those in anonymous unions or + /// structs). + bool hasInClassInitializer() const { return data().HasInClassInitializer; } + + /// \brief Whether this class or any of its subobjects has any members of + /// reference type which would make value-initialization ill-formed. + /// + /// Per C++03 [dcl.init]p5: + /// - if T is a non-union class type without a user-declared constructor, + /// then every non-static data member and base-class component of T is + /// value-initialized [...] A program that calls for [...] + /// value-initialization of an entity of reference type is ill-formed. + bool hasUninitializedReferenceMember() const { + return !isUnion() && !hasUserDeclaredConstructor() && + data().HasUninitializedReferenceMember; + } + + /// \brief Whether this class is a POD-type (C++ [class]p4) + /// + /// For purposes of this function a class is POD if it is an aggregate + /// that has no non-static non-POD data members, no reference data + /// members, no user-defined copy assignment operator and no + /// user-defined destructor. + /// + /// Note that this is the C++ TR1 definition of POD. + bool isPOD() const { return data().PlainOldData; } + + /// \brief True if this class is C-like, without C++-specific features, e.g. + /// it contains only public fields, no bases, tag kind is not 'class', etc. + bool isCLike() const; + + /// \brief Determine whether this is an empty class in the sense of + /// (C++11 [meta.unary.prop]). + /// + /// A non-union class is empty iff it has a virtual function, virtual base, + /// data member (other than 0-width bit-field) or inherits from a non-empty + /// class. + /// + /// \note This does NOT include a check for union-ness. + bool isEmpty() const { return data().Empty; } + + /// Whether this class is polymorphic (C++ [class.virtual]), + /// which means that the class contains or inherits a virtual function. + bool isPolymorphic() const { return data().Polymorphic; } + + /// \brief Determine whether this class has a pure virtual function. + /// + /// The class is is abstract per (C++ [class.abstract]p2) if it declares + /// a pure virtual function or inherits a pure virtual function that is + /// not overridden. + bool isAbstract() const { return data().Abstract; } + + /// \brief Determine whether this class has standard layout per + /// (C++ [class]p7) + bool isStandardLayout() const { return data().IsStandardLayout; } + + /// \brief Determine whether this class, or any of its class subobjects, + /// contains a mutable field. + bool hasMutableFields() const { return data().HasMutableFields; } + + /// \brief Determine whether this class has any variant members. + bool hasVariantMembers() const { return data().HasVariantMembers; } + + /// \brief Determine whether this class has a trivial default constructor + /// (C++11 [class.ctor]p5). + bool hasTrivialDefaultConstructor() const { + return hasDefaultConstructor() && + (data().HasTrivialSpecialMembers & SMF_DefaultConstructor); + } + + /// \brief Determine whether this class has a non-trivial default constructor + /// (C++11 [class.ctor]p5). + bool hasNonTrivialDefaultConstructor() const { + return (data().DeclaredNonTrivialSpecialMembers & SMF_DefaultConstructor) || + (needsImplicitDefaultConstructor() && + !(data().HasTrivialSpecialMembers & SMF_DefaultConstructor)); + } + + /// \brief Determine whether this class has at least one constexpr constructor + /// other than the copy or move constructors. + bool hasConstexprNonCopyMoveConstructor() const { + return data().HasConstexprNonCopyMoveConstructor || + (needsImplicitDefaultConstructor() && + defaultedDefaultConstructorIsConstexpr()); + } + + /// \brief Determine whether a defaulted default constructor for this class + /// would be constexpr. + bool defaultedDefaultConstructorIsConstexpr() const { + return data().DefaultedDefaultConstructorIsConstexpr && + (!isUnion() || hasInClassInitializer() || !hasVariantMembers()); + } + + /// \brief Determine whether this class has a constexpr default constructor. + bool hasConstexprDefaultConstructor() const { + return data().HasConstexprDefaultConstructor || + (needsImplicitDefaultConstructor() && + defaultedDefaultConstructorIsConstexpr()); + } + + /// \brief Determine whether this class has a trivial copy constructor + /// (C++ [class.copy]p6, C++11 [class.copy]p12) + bool hasTrivialCopyConstructor() const { + return data().HasTrivialSpecialMembers & SMF_CopyConstructor; + } + + /// \brief Determine whether this class has a non-trivial copy constructor + /// (C++ [class.copy]p6, C++11 [class.copy]p12) + bool hasNonTrivialCopyConstructor() const { + return data().DeclaredNonTrivialSpecialMembers & SMF_CopyConstructor || + !hasTrivialCopyConstructor(); + } + + /// \brief Determine whether this class has a trivial move constructor + /// (C++11 [class.copy]p12) + bool hasTrivialMoveConstructor() const { + return hasMoveConstructor() && + (data().HasTrivialSpecialMembers & SMF_MoveConstructor); + } + + /// \brief Determine whether this class has a non-trivial move constructor + /// (C++11 [class.copy]p12) + bool hasNonTrivialMoveConstructor() const { + return (data().DeclaredNonTrivialSpecialMembers & SMF_MoveConstructor) || + (needsImplicitMoveConstructor() && + !(data().HasTrivialSpecialMembers & SMF_MoveConstructor)); + } + + /// \brief Determine whether this class has a trivial copy assignment operator + /// (C++ [class.copy]p11, C++11 [class.copy]p25) + bool hasTrivialCopyAssignment() const { + return data().HasTrivialSpecialMembers & SMF_CopyAssignment; + } + + /// \brief Determine whether this class has a non-trivial copy assignment + /// operator (C++ [class.copy]p11, C++11 [class.copy]p25) + bool hasNonTrivialCopyAssignment() const { + return data().DeclaredNonTrivialSpecialMembers & SMF_CopyAssignment || + !hasTrivialCopyAssignment(); + } + + /// \brief Determine whether this class has a trivial move assignment operator + /// (C++11 [class.copy]p25) + bool hasTrivialMoveAssignment() const { + return hasMoveAssignment() && + (data().HasTrivialSpecialMembers & SMF_MoveAssignment); + } + + /// \brief Determine whether this class has a non-trivial move assignment + /// operator (C++11 [class.copy]p25) + bool hasNonTrivialMoveAssignment() const { + return (data().DeclaredNonTrivialSpecialMembers & SMF_MoveAssignment) || + (needsImplicitMoveAssignment() && + !(data().HasTrivialSpecialMembers & SMF_MoveAssignment)); + } + + /// \brief Determine whether this class has a trivial destructor + /// (C++ [class.dtor]p3) + bool hasTrivialDestructor() const { + return data().HasTrivialSpecialMembers & SMF_Destructor; + } + + /// \brief Determine whether this class has a non-trivial destructor + /// (C++ [class.dtor]p3) + bool hasNonTrivialDestructor() const { + return !(data().HasTrivialSpecialMembers & SMF_Destructor); + } + + /// \brief Determine whether this class has a destructor which has no + /// semantic effect. + /// + /// Any such destructor will be trivial, public, defaulted and not deleted, + /// and will call only irrelevant destructors. + bool hasIrrelevantDestructor() const { + return data().HasIrrelevantDestructor; + } + + /// \brief Determine whether this class has a non-literal or/ volatile type + /// non-static data member or base class. + bool hasNonLiteralTypeFieldsOrBases() const { + return data().HasNonLiteralTypeFieldsOrBases; + } + + /// \brief Determine whether this class is considered trivially copyable per + /// (C++11 [class]p6). + bool isTriviallyCopyable() const; + + /// \brief Determine whether this class is considered trivial. + /// + /// C++11 [class]p6: + /// "A trivial class is a class that has a trivial default constructor and + /// is trivially copiable." + bool isTrivial() const { + return isTriviallyCopyable() && hasTrivialDefaultConstructor(); + } + + /// \brief Determine whether this class is a literal type. + /// + /// C++11 [basic.types]p10: + /// A class type that has all the following properties: + /// - it has a trivial destructor + /// - every constructor call and full-expression in the + /// brace-or-equal-intializers for non-static data members (if any) is + /// a constant expression. + /// - it is an aggregate type or has at least one constexpr constructor + /// or constructor template that is not a copy or move constructor, and + /// - all of its non-static data members and base classes are of literal + /// types + /// + /// We resolve DR1361 by ignoring the second bullet. We resolve DR1452 by + /// treating types with trivial default constructors as literal types. + bool isLiteral() const { + return hasTrivialDestructor() && + (isAggregate() || hasConstexprNonCopyMoveConstructor() || + hasTrivialDefaultConstructor()) && + !hasNonLiteralTypeFieldsOrBases(); + } + + /// \brief If this record is an instantiation of a member class, + /// retrieves the member class from which it was instantiated. + /// + /// This routine will return non-null for (non-templated) member + /// classes of class templates. For example, given: + /// + /// \code + /// template<typename T> + /// struct X { + /// struct A { }; + /// }; + /// \endcode + /// + /// The declaration for X<int>::A is a (non-templated) CXXRecordDecl + /// whose parent is the class template specialization X<int>. For + /// this declaration, getInstantiatedFromMemberClass() will return + /// the CXXRecordDecl X<T>::A. When a complete definition of + /// X<int>::A is required, it will be instantiated from the + /// declaration returned by getInstantiatedFromMemberClass(). + CXXRecordDecl *getInstantiatedFromMemberClass() const; + + /// \brief If this class is an instantiation of a member class of a + /// class template specialization, retrieves the member specialization + /// information. + MemberSpecializationInfo *getMemberSpecializationInfo() const; + + /// \brief Specify that this record is an instantiation of the + /// member class \p RD. + void setInstantiationOfMemberClass(CXXRecordDecl *RD, + TemplateSpecializationKind TSK); + + /// \brief Retrieves the class template that is described by this + /// class declaration. + /// + /// Every class template is represented as a ClassTemplateDecl and a + /// CXXRecordDecl. The former contains template properties (such as + /// the template parameter lists) while the latter contains the + /// actual description of the template's + /// contents. ClassTemplateDecl::getTemplatedDecl() retrieves the + /// CXXRecordDecl that from a ClassTemplateDecl, while + /// getDescribedClassTemplate() retrieves the ClassTemplateDecl from + /// a CXXRecordDecl. + ClassTemplateDecl *getDescribedClassTemplate() const; + + void setDescribedClassTemplate(ClassTemplateDecl *Template); + + /// \brief Determine whether this particular class is a specialization or + /// instantiation of a class template or member class of a class template, + /// and how it was instantiated or specialized. + TemplateSpecializationKind getTemplateSpecializationKind() const; + + /// \brief Set the kind of specialization or template instantiation this is. + void setTemplateSpecializationKind(TemplateSpecializationKind TSK); + + /// \brief Retrieve the record declaration from which this record could be + /// instantiated. Returns null if this class is not a template instantiation. + const CXXRecordDecl *getTemplateInstantiationPattern() const; + + CXXRecordDecl *getTemplateInstantiationPattern() { + return const_cast<CXXRecordDecl *>(const_cast<const CXXRecordDecl *>(this) + ->getTemplateInstantiationPattern()); + } + + /// \brief Returns the destructor decl for this class. + CXXDestructorDecl *getDestructor() const; + + /// \brief Returns true if the class destructor, or any implicitly invoked + /// destructors are marked noreturn. + bool isAnyDestructorNoReturn() const; + + /// \brief If the class is a local class [class.local], returns + /// the enclosing function declaration. + const FunctionDecl *isLocalClass() const { + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(getDeclContext())) + return RD->isLocalClass(); + + return dyn_cast<FunctionDecl>(getDeclContext()); + } + + FunctionDecl *isLocalClass() { + return const_cast<FunctionDecl*>( + const_cast<const CXXRecordDecl*>(this)->isLocalClass()); + } + + /// \brief Determine whether this dependent class is a current instantiation, + /// when viewed from within the given context. + bool isCurrentInstantiation(const DeclContext *CurContext) const; + + /// \brief Determine whether this class is derived from the class \p Base. + /// + /// This routine only determines whether this class is derived from \p Base, + /// but does not account for factors that may make a Derived -> Base class + /// ill-formed, such as private/protected inheritance or multiple, ambiguous + /// base class subobjects. + /// + /// \param Base the base class we are searching for. + /// + /// \returns true if this class is derived from Base, false otherwise. + bool isDerivedFrom(const CXXRecordDecl *Base) const; + + /// \brief Determine whether this class is derived from the type \p Base. + /// + /// This routine only determines whether this class is derived from \p Base, + /// but does not account for factors that may make a Derived -> Base class + /// ill-formed, such as private/protected inheritance or multiple, ambiguous + /// base class subobjects. + /// + /// \param Base the base class we are searching for. + /// + /// \param Paths will contain the paths taken from the current class to the + /// given \p Base class. + /// + /// \returns true if this class is derived from \p Base, false otherwise. + /// + /// \todo add a separate parameter to configure IsDerivedFrom, rather than + /// tangling input and output in \p Paths + bool isDerivedFrom(const CXXRecordDecl *Base, CXXBasePaths &Paths) const; + + /// \brief Determine whether this class is virtually derived from + /// the class \p Base. + /// + /// This routine only determines whether this class is virtually + /// derived from \p Base, but does not account for factors that may + /// make a Derived -> Base class ill-formed, such as + /// private/protected inheritance or multiple, ambiguous base class + /// subobjects. + /// + /// \param Base the base class we are searching for. + /// + /// \returns true if this class is virtually derived from Base, + /// false otherwise. + bool isVirtuallyDerivedFrom(const CXXRecordDecl *Base) const; + + /// \brief Determine whether this class is provably not derived from + /// the type \p Base. + bool isProvablyNotDerivedFrom(const CXXRecordDecl *Base) const; + + /// \brief Function type used by forallBases() as a callback. + /// + /// \param BaseDefinition the definition of the base class + /// + /// \returns true if this base matched the search criteria + typedef llvm::function_ref<bool(const CXXRecordDecl *BaseDefinition)> + ForallBasesCallback; + + /// \brief Determines if the given callback holds for all the direct + /// or indirect base classes of this type. + /// + /// The class itself does not count as a base class. This routine + /// returns false if the class has non-computable base classes. + /// + /// \param BaseMatches Callback invoked for each (direct or indirect) base + /// class of this type, or if \p AllowShortCircuit is true then until a call + /// returns false. + /// + /// \param AllowShortCircuit if false, forces the callback to be called + /// for every base class, even if a dependent or non-matching base was + /// found. + bool forallBases(ForallBasesCallback BaseMatches, + bool AllowShortCircuit = true) const; + + /// \brief Function type used by lookupInBases() to determine whether a + /// specific base class subobject matches the lookup criteria. + /// + /// \param Specifier the base-class specifier that describes the inheritance + /// from the base class we are trying to match. + /// + /// \param Path the current path, from the most-derived class down to the + /// base named by the \p Specifier. + /// + /// \returns true if this base matched the search criteria, false otherwise. + typedef llvm::function_ref<bool(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path)> BaseMatchesCallback; + + /// \brief Look for entities within the base classes of this C++ class, + /// transitively searching all base class subobjects. + /// + /// This routine uses the callback function \p BaseMatches to find base + /// classes meeting some search criteria, walking all base class subobjects + /// and populating the given \p Paths structure with the paths through the + /// inheritance hierarchy that resulted in a match. On a successful search, + /// the \p Paths structure can be queried to retrieve the matching paths and + /// to determine if there were any ambiguities. + /// + /// \param BaseMatches callback function used to determine whether a given + /// base matches the user-defined search criteria. + /// + /// \param Paths used to record the paths from this class to its base class + /// subobjects that match the search criteria. + /// + /// \returns true if there exists any path from this class to a base class + /// subobject that matches the search criteria. + bool lookupInBases(BaseMatchesCallback BaseMatches, + CXXBasePaths &Paths) const; + + /// \brief Base-class lookup callback that determines whether the given + /// base class specifier refers to a specific class declaration. + /// + /// This callback can be used with \c lookupInBases() to determine whether + /// a given derived class has is a base class subobject of a particular type. + /// The base record pointer should refer to the canonical CXXRecordDecl of the + /// base class that we are searching for. + static bool FindBaseClass(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path, const CXXRecordDecl *BaseRecord); + + /// \brief Base-class lookup callback that determines whether the + /// given base class specifier refers to a specific class + /// declaration and describes virtual derivation. + /// + /// This callback can be used with \c lookupInBases() to determine + /// whether a given derived class has is a virtual base class + /// subobject of a particular type. The base record pointer should + /// refer to the canonical CXXRecordDecl of the base class that we + /// are searching for. + static bool FindVirtualBaseClass(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path, + const CXXRecordDecl *BaseRecord); + + /// \brief Base-class lookup callback that determines whether there exists + /// a tag with the given name. + /// + /// This callback can be used with \c lookupInBases() to find tag members + /// of the given name within a C++ class hierarchy. + static bool FindTagMember(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path, DeclarationName Name); + + /// \brief Base-class lookup callback that determines whether there exists + /// a member with the given name. + /// + /// This callback can be used with \c lookupInBases() to find members + /// of the given name within a C++ class hierarchy. + static bool FindOrdinaryMember(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path, DeclarationName Name); + + /// \brief Base-class lookup callback that determines whether there exists + /// a member with the given name that can be used in a nested-name-specifier. + /// + /// This callback can be used with \c lookupInBases() to find members of + /// the given name within a C++ class hierarchy that can occur within + /// nested-name-specifiers. + static bool FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path, + DeclarationName Name); + + /// \brief Retrieve the final overriders for each virtual member + /// function in the class hierarchy where this class is the + /// most-derived class in the class hierarchy. + void getFinalOverriders(CXXFinalOverriderMap &FinaOverriders) const; + + /// \brief Get the indirect primary bases for this class. + void getIndirectPrimaryBases(CXXIndirectPrimaryBaseSet& Bases) const; + + /// Renders and displays an inheritance diagram + /// for this C++ class and all of its base classes (transitively) using + /// GraphViz. + void viewInheritance(ASTContext& Context) const; + + /// \brief Calculates the access of a decl that is reached + /// along a path. + static AccessSpecifier MergeAccess(AccessSpecifier PathAccess, + AccessSpecifier DeclAccess) { + assert(DeclAccess != AS_none); + if (DeclAccess == AS_private) return AS_none; + return (PathAccess > DeclAccess ? PathAccess : DeclAccess); + } + + /// \brief Indicates that the declaration of a defaulted or deleted special + /// member function is now complete. + void finishedDefaultedOrDeletedMember(CXXMethodDecl *MD); + + /// \brief Indicates that the definition of this class is now complete. + void completeDefinition() override; + + /// \brief Indicates that the definition of this class is now complete, + /// and provides a final overrider map to help determine + /// + /// \param FinalOverriders The final overrider map for this class, which can + /// be provided as an optimization for abstract-class checking. If NULL, + /// final overriders will be computed if they are needed to complete the + /// definition. + void completeDefinition(CXXFinalOverriderMap *FinalOverriders); + + /// \brief Determine whether this class may end up being abstract, even though + /// it is not yet known to be abstract. + /// + /// \returns true if this class is not known to be abstract but has any + /// base classes that are abstract. In this case, \c completeDefinition() + /// will need to compute final overriders to determine whether the class is + /// actually abstract. + bool mayBeAbstract() const; + + /// \brief If this is the closure type of a lambda expression, retrieve the + /// number to be used for name mangling in the Itanium C++ ABI. + /// + /// Zero indicates that this closure type has internal linkage, so the + /// mangling number does not matter, while a non-zero value indicates which + /// lambda expression this is in this particular context. + unsigned getLambdaManglingNumber() const { + assert(isLambda() && "Not a lambda closure type!"); + return getLambdaData().ManglingNumber; + } + + /// \brief Retrieve the declaration that provides additional context for a + /// lambda, when the normal declaration context is not specific enough. + /// + /// Certain contexts (default arguments of in-class function parameters and + /// the initializers of data members) have separate name mangling rules for + /// lambdas within the Itanium C++ ABI. For these cases, this routine provides + /// the declaration in which the lambda occurs, e.g., the function parameter + /// or the non-static data member. Otherwise, it returns NULL to imply that + /// the declaration context suffices. + Decl *getLambdaContextDecl() const { + assert(isLambda() && "Not a lambda closure type!"); + return getLambdaData().ContextDecl; + } + + /// \brief Set the mangling number and context declaration for a lambda + /// class. + void setLambdaMangling(unsigned ManglingNumber, Decl *ContextDecl) { + getLambdaData().ManglingNumber = ManglingNumber; + getLambdaData().ContextDecl = ContextDecl; + } + + /// \brief Returns the inheritance model used for this record. + MSInheritanceAttr::Spelling getMSInheritanceModel() const; + /// \brief Calculate what the inheritance model would be for this class. + MSInheritanceAttr::Spelling calculateInheritanceModel() const; + + /// In the Microsoft C++ ABI, use zero for the field offset of a null data + /// member pointer if we can guarantee that zero is not a valid field offset, + /// or if the member pointer has multiple fields. Polymorphic classes have a + /// vfptr at offset zero, so we can use zero for null. If there are multiple + /// fields, we can use zero even if it is a valid field offset because + /// null-ness testing will check the other fields. + bool nullFieldOffsetIsZero() const { + return !MSInheritanceAttr::hasOnlyOneField(/*IsMemberFunction=*/false, + getMSInheritanceModel()) || + (hasDefinition() && isPolymorphic()); + } + + /// \brief Controls when vtordisps will be emitted if this record is used as a + /// virtual base. + MSVtorDispAttr::Mode getMSVtorDispMode() const; + + /// \brief Determine whether this lambda expression was known to be dependent + /// at the time it was created, even if its context does not appear to be + /// dependent. + /// + /// This flag is a workaround for an issue with parsing, where default + /// arguments are parsed before their enclosing function declarations have + /// been created. This means that any lambda expressions within those + /// default arguments will have as their DeclContext the context enclosing + /// the function declaration, which may be non-dependent even when the + /// function declaration itself is dependent. This flag indicates when we + /// know that the lambda is dependent despite that. + bool isDependentLambda() const { + return isLambda() && getLambdaData().Dependent; + } + + TypeSourceInfo *getLambdaTypeInfo() const { + return getLambdaData().MethodTyInfo; + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { + return K >= firstCXXRecord && K <= lastCXXRecord; + } + + friend class ASTDeclReader; + friend class ASTDeclWriter; + friend class ASTReader; + friend class ASTWriter; +}; + +/// \brief Represents a static or instance method of a struct/union/class. +/// +/// In the terminology of the C++ Standard, these are the (static and +/// non-static) member functions, whether virtual or not. +class CXXMethodDecl : public FunctionDecl { + void anchor() override; +protected: + CXXMethodDecl(Kind DK, ASTContext &C, CXXRecordDecl *RD, + SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, + QualType T, TypeSourceInfo *TInfo, + StorageClass SC, bool isInline, + bool isConstexpr, SourceLocation EndLocation) + : FunctionDecl(DK, C, RD, StartLoc, NameInfo, T, TInfo, + SC, isInline, isConstexpr) { + if (EndLocation.isValid()) + setRangeEnd(EndLocation); + } + +public: + static CXXMethodDecl *Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, + QualType T, TypeSourceInfo *TInfo, + StorageClass SC, + bool isInline, + bool isConstexpr, + SourceLocation EndLocation); + + static CXXMethodDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + bool isStatic() const; + bool isInstance() const { return !isStatic(); } + + /// Returns true if the given operator is implicitly static in a record + /// context. + static bool isStaticOverloadedOperator(OverloadedOperatorKind OOK) { + // [class.free]p1: + // Any allocation function for a class T is a static member + // (even if not explicitly declared static). + // [class.free]p6 Any deallocation function for a class X is a static member + // (even if not explicitly declared static). + return OOK == OO_New || OOK == OO_Array_New || OOK == OO_Delete || + OOK == OO_Array_Delete; + } + + bool isConst() const { return getType()->castAs<FunctionType>()->isConst(); } + bool isVolatile() const { return getType()->castAs<FunctionType>()->isVolatile(); } + + bool isVirtual() const { + CXXMethodDecl *CD = + cast<CXXMethodDecl>(const_cast<CXXMethodDecl*>(this)->getCanonicalDecl()); + + // Member function is virtual if it is marked explicitly so, or if it is + // declared in __interface -- then it is automatically pure virtual. + if (CD->isVirtualAsWritten() || CD->isPure()) + return true; + + return (CD->begin_overridden_methods() != CD->end_overridden_methods()); + } + + /// \brief Determine whether this is a usual deallocation function + /// (C++ [basic.stc.dynamic.deallocation]p2), which is an overloaded + /// delete or delete[] operator with a particular signature. + bool isUsualDeallocationFunction() const; + + /// \brief Determine whether this is a copy-assignment operator, regardless + /// of whether it was declared implicitly or explicitly. + bool isCopyAssignmentOperator() const; + + /// \brief Determine whether this is a move assignment operator. + bool isMoveAssignmentOperator() const; + + CXXMethodDecl *getCanonicalDecl() override { + return cast<CXXMethodDecl>(FunctionDecl::getCanonicalDecl()); + } + const CXXMethodDecl *getCanonicalDecl() const { + return const_cast<CXXMethodDecl*>(this)->getCanonicalDecl(); + } + + CXXMethodDecl *getMostRecentDecl() { + return cast<CXXMethodDecl>( + static_cast<FunctionDecl *>(this)->getMostRecentDecl()); + } + const CXXMethodDecl *getMostRecentDecl() const { + return const_cast<CXXMethodDecl*>(this)->getMostRecentDecl(); + } + + /// True if this method is user-declared and was not + /// deleted or defaulted on its first declaration. + bool isUserProvided() const { + return !(isDeleted() || getCanonicalDecl()->isDefaulted()); + } + + /// + void addOverriddenMethod(const CXXMethodDecl *MD); + + typedef const CXXMethodDecl *const* method_iterator; + + method_iterator begin_overridden_methods() const; + method_iterator end_overridden_methods() const; + unsigned size_overridden_methods() const; + + /// Returns the parent of this method declaration, which + /// is the class in which this method is defined. + const CXXRecordDecl *getParent() const { + return cast<CXXRecordDecl>(FunctionDecl::getParent()); + } + + /// Returns the parent of this method declaration, which + /// is the class in which this method is defined. + CXXRecordDecl *getParent() { + return const_cast<CXXRecordDecl *>( + cast<CXXRecordDecl>(FunctionDecl::getParent())); + } + + /// \brief Returns the type of the \c this pointer. + /// + /// Should only be called for instance (i.e., non-static) methods. + QualType getThisType(ASTContext &C) const; + + unsigned getTypeQualifiers() const { + return getType()->getAs<FunctionProtoType>()->getTypeQuals(); + } + + /// \brief Retrieve the ref-qualifier associated with this method. + /// + /// In the following example, \c f() has an lvalue ref-qualifier, \c g() + /// has an rvalue ref-qualifier, and \c h() has no ref-qualifier. + /// @code + /// struct X { + /// void f() &; + /// void g() &&; + /// void h(); + /// }; + /// @endcode + RefQualifierKind getRefQualifier() const { + return getType()->getAs<FunctionProtoType>()->getRefQualifier(); + } + + bool hasInlineBody() const; + + /// \brief Determine whether this is a lambda closure type's static member + /// function that is used for the result of the lambda's conversion to + /// function pointer (for a lambda with no captures). + /// + /// The function itself, if used, will have a placeholder body that will be + /// supplied by IR generation to either forward to the function call operator + /// or clone the function call operator. + bool isLambdaStaticInvoker() const; + + /// \brief Find the method in \p RD that corresponds to this one. + /// + /// Find if \p RD or one of the classes it inherits from override this method. + /// If so, return it. \p RD is assumed to be a subclass of the class defining + /// this method (or be the class itself), unless \p MayBeBase is set to true. + CXXMethodDecl * + getCorrespondingMethodInClass(const CXXRecordDecl *RD, + bool MayBeBase = false); + + const CXXMethodDecl * + getCorrespondingMethodInClass(const CXXRecordDecl *RD, + bool MayBeBase = false) const { + return const_cast<CXXMethodDecl *>(this) + ->getCorrespondingMethodInClass(RD, MayBeBase); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { + return K >= firstCXXMethod && K <= lastCXXMethod; + } +}; + +/// \brief Represents a C++ base or member initializer. +/// +/// This is part of a constructor initializer that +/// initializes one non-static member variable or one base class. For +/// example, in the following, both 'A(a)' and 'f(3.14159)' are member +/// initializers: +/// +/// \code +/// class A { }; +/// class B : public A { +/// float f; +/// public: +/// B(A& a) : A(a), f(3.14159) { } +/// }; +/// \endcode +class CXXCtorInitializer final + : private llvm::TrailingObjects<CXXCtorInitializer, VarDecl *> { + /// \brief Either the base class name/delegating constructor type (stored as + /// a TypeSourceInfo*), an normal field (FieldDecl), or an anonymous field + /// (IndirectFieldDecl*) being initialized. + llvm::PointerUnion3<TypeSourceInfo *, FieldDecl *, IndirectFieldDecl *> + Initializee; + + /// \brief The source location for the field name or, for a base initializer + /// pack expansion, the location of the ellipsis. + /// + /// In the case of a delegating + /// constructor, it will still include the type's source location as the + /// Initializee points to the CXXConstructorDecl (to allow loop detection). + SourceLocation MemberOrEllipsisLocation; + + /// \brief The argument used to initialize the base or member, which may + /// end up constructing an object (when multiple arguments are involved). + Stmt *Init; + + /// \brief Location of the left paren of the ctor-initializer. + SourceLocation LParenLoc; + + /// \brief Location of the right paren of the ctor-initializer. + SourceLocation RParenLoc; + + /// \brief If the initializee is a type, whether that type makes this + /// a delegating initialization. + bool IsDelegating : 1; + + /// \brief If the initializer is a base initializer, this keeps track + /// of whether the base is virtual or not. + bool IsVirtual : 1; + + /// \brief Whether or not the initializer is explicitly written + /// in the sources. + bool IsWritten : 1; + + /// If IsWritten is true, then this number keeps track of the textual order + /// of this initializer in the original sources, counting from 0; otherwise, + /// it stores the number of array index variables stored after this object + /// in memory. + unsigned SourceOrderOrNumArrayIndices : 13; + + CXXCtorInitializer(ASTContext &Context, FieldDecl *Member, + SourceLocation MemberLoc, SourceLocation L, Expr *Init, + SourceLocation R, VarDecl **Indices, unsigned NumIndices); + +public: + /// \brief Creates a new base-class initializer. + explicit + CXXCtorInitializer(ASTContext &Context, TypeSourceInfo *TInfo, bool IsVirtual, + SourceLocation L, Expr *Init, SourceLocation R, + SourceLocation EllipsisLoc); + + /// \brief Creates a new member initializer. + explicit + CXXCtorInitializer(ASTContext &Context, FieldDecl *Member, + SourceLocation MemberLoc, SourceLocation L, Expr *Init, + SourceLocation R); + + /// \brief Creates a new anonymous field initializer. + explicit + CXXCtorInitializer(ASTContext &Context, IndirectFieldDecl *Member, + SourceLocation MemberLoc, SourceLocation L, Expr *Init, + SourceLocation R); + + /// \brief Creates a new delegating initializer. + explicit + CXXCtorInitializer(ASTContext &Context, TypeSourceInfo *TInfo, + SourceLocation L, Expr *Init, SourceLocation R); + + /// \brief Creates a new member initializer that optionally contains + /// array indices used to describe an elementwise initialization. + static CXXCtorInitializer *Create(ASTContext &Context, FieldDecl *Member, + SourceLocation MemberLoc, SourceLocation L, + Expr *Init, SourceLocation R, + VarDecl **Indices, unsigned NumIndices); + + /// \brief Determine whether this initializer is initializing a base class. + bool isBaseInitializer() const { + return Initializee.is<TypeSourceInfo*>() && !IsDelegating; + } + + /// \brief Determine whether this initializer is initializing a non-static + /// data member. + bool isMemberInitializer() const { return Initializee.is<FieldDecl*>(); } + + bool isAnyMemberInitializer() const { + return isMemberInitializer() || isIndirectMemberInitializer(); + } + + bool isIndirectMemberInitializer() const { + return Initializee.is<IndirectFieldDecl*>(); + } + + /// \brief Determine whether this initializer is an implicit initializer + /// generated for a field with an initializer defined on the member + /// declaration. + /// + /// In-class member initializers (also known as "non-static data member + /// initializations", NSDMIs) were introduced in C++11. + bool isInClassMemberInitializer() const { + return Init->getStmtClass() == Stmt::CXXDefaultInitExprClass; + } + + /// \brief Determine whether this initializer is creating a delegating + /// constructor. + bool isDelegatingInitializer() const { + return Initializee.is<TypeSourceInfo*>() && IsDelegating; + } + + /// \brief Determine whether this initializer is a pack expansion. + bool isPackExpansion() const { + return isBaseInitializer() && MemberOrEllipsisLocation.isValid(); + } + + // \brief For a pack expansion, returns the location of the ellipsis. + SourceLocation getEllipsisLoc() const { + assert(isPackExpansion() && "Initializer is not a pack expansion"); + return MemberOrEllipsisLocation; + } + + /// If this is a base class initializer, returns the type of the + /// base class with location information. Otherwise, returns an NULL + /// type location. + TypeLoc getBaseClassLoc() const; + + /// If this is a base class initializer, returns the type of the base class. + /// Otherwise, returns null. + const Type *getBaseClass() const; + + /// Returns whether the base is virtual or not. + bool isBaseVirtual() const { + assert(isBaseInitializer() && "Must call this on base initializer!"); + + return IsVirtual; + } + + /// \brief Returns the declarator information for a base class or delegating + /// initializer. + TypeSourceInfo *getTypeSourceInfo() const { + return Initializee.dyn_cast<TypeSourceInfo *>(); + } + + /// \brief If this is a member initializer, returns the declaration of the + /// non-static data member being initialized. Otherwise, returns null. + FieldDecl *getMember() const { + if (isMemberInitializer()) + return Initializee.get<FieldDecl*>(); + return nullptr; + } + FieldDecl *getAnyMember() const { + if (isMemberInitializer()) + return Initializee.get<FieldDecl*>(); + if (isIndirectMemberInitializer()) + return Initializee.get<IndirectFieldDecl*>()->getAnonField(); + return nullptr; + } + + IndirectFieldDecl *getIndirectMember() const { + if (isIndirectMemberInitializer()) + return Initializee.get<IndirectFieldDecl*>(); + return nullptr; + } + + SourceLocation getMemberLocation() const { + return MemberOrEllipsisLocation; + } + + /// \brief Determine the source location of the initializer. + SourceLocation getSourceLocation() const; + + /// \brief Determine the source range covering the entire initializer. + SourceRange getSourceRange() const LLVM_READONLY; + + /// \brief Determine whether this initializer is explicitly written + /// in the source code. + bool isWritten() const { return IsWritten; } + + /// \brief Return the source position of the initializer, counting from 0. + /// If the initializer was implicit, -1 is returned. + int getSourceOrder() const { + return IsWritten ? static_cast<int>(SourceOrderOrNumArrayIndices) : -1; + } + + /// \brief Set the source order of this initializer. + /// + /// This can only be called once for each initializer; it cannot be called + /// on an initializer having a positive number of (implicit) array indices. + /// + /// This assumes that the initializer was written in the source code, and + /// ensures that isWritten() returns true. + void setSourceOrder(int pos) { + assert(!IsWritten && + "calling twice setSourceOrder() on the same initializer"); + assert(SourceOrderOrNumArrayIndices == 0 && + "setSourceOrder() used when there are implicit array indices"); + assert(pos >= 0 && + "setSourceOrder() used to make an initializer implicit"); + IsWritten = true; + SourceOrderOrNumArrayIndices = static_cast<unsigned>(pos); + } + + SourceLocation getLParenLoc() const { return LParenLoc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + + /// \brief Determine the number of implicit array indices used while + /// described an array member initialization. + unsigned getNumArrayIndices() const { + return IsWritten ? 0 : SourceOrderOrNumArrayIndices; + } + + /// \brief Retrieve a particular array index variable used to + /// describe an array member initialization. + VarDecl *getArrayIndex(unsigned I) { + assert(I < getNumArrayIndices() && "Out of bounds member array index"); + return getTrailingObjects<VarDecl *>()[I]; + } + const VarDecl *getArrayIndex(unsigned I) const { + assert(I < getNumArrayIndices() && "Out of bounds member array index"); + return getTrailingObjects<VarDecl *>()[I]; + } + void setArrayIndex(unsigned I, VarDecl *Index) { + assert(I < getNumArrayIndices() && "Out of bounds member array index"); + getTrailingObjects<VarDecl *>()[I] = Index; + } + ArrayRef<VarDecl *> getArrayIndexes() { + assert(getNumArrayIndices() != 0 && "Getting indexes for non-array init"); + return llvm::makeArrayRef(getTrailingObjects<VarDecl *>(), + getNumArrayIndices()); + } + + /// \brief Get the initializer. + Expr *getInit() const { return static_cast<Expr*>(Init); } + + friend TrailingObjects; +}; + +/// \brief Represents a C++ constructor within a class. +/// +/// For example: +/// +/// \code +/// class X { +/// public: +/// explicit X(int); // represented by a CXXConstructorDecl. +/// }; +/// \endcode +class CXXConstructorDecl : public CXXMethodDecl { + void anchor() override; + /// \brief Whether this constructor declaration has the \c explicit keyword + /// specified. + bool IsExplicitSpecified : 1; + + /// \name Support for base and member initializers. + /// \{ + /// \brief The arguments used to initialize the base or member. + LazyCXXCtorInitializersPtr CtorInitializers; + unsigned NumCtorInitializers; + /// \} + + CXXConstructorDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, + QualType T, TypeSourceInfo *TInfo, + bool isExplicitSpecified, bool isInline, + bool isImplicitlyDeclared, bool isConstexpr) + : CXXMethodDecl(CXXConstructor, C, RD, StartLoc, NameInfo, T, TInfo, + SC_None, isInline, isConstexpr, SourceLocation()), + IsExplicitSpecified(isExplicitSpecified), CtorInitializers(nullptr), + NumCtorInitializers(0) { + setImplicit(isImplicitlyDeclared); + } + +public: + static CXXConstructorDecl *CreateDeserialized(ASTContext &C, unsigned ID); + static CXXConstructorDecl *Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, + QualType T, TypeSourceInfo *TInfo, + bool isExplicit, + bool isInline, bool isImplicitlyDeclared, + bool isConstexpr); + + /// \brief Determine whether this constructor declaration has the + /// \c explicit keyword specified. + bool isExplicitSpecified() const { return IsExplicitSpecified; } + + /// \brief Determine whether this constructor was marked "explicit" or not. + bool isExplicit() const { + return cast<CXXConstructorDecl>(getFirstDecl())->isExplicitSpecified(); + } + + /// \brief Iterates through the member/base initializer list. + typedef CXXCtorInitializer **init_iterator; + + /// \brief Iterates through the member/base initializer list. + typedef CXXCtorInitializer *const *init_const_iterator; + + typedef llvm::iterator_range<init_iterator> init_range; + typedef llvm::iterator_range<init_const_iterator> init_const_range; + + init_range inits() { return init_range(init_begin(), init_end()); } + init_const_range inits() const { + return init_const_range(init_begin(), init_end()); + } + + /// \brief Retrieve an iterator to the first initializer. + init_iterator init_begin() { + const auto *ConstThis = this; + return const_cast<init_iterator>(ConstThis->init_begin()); + } + /// \brief Retrieve an iterator to the first initializer. + init_const_iterator init_begin() const; + + /// \brief Retrieve an iterator past the last initializer. + init_iterator init_end() { + return init_begin() + NumCtorInitializers; + } + /// \brief Retrieve an iterator past the last initializer. + init_const_iterator init_end() const { + return init_begin() + NumCtorInitializers; + } + + typedef std::reverse_iterator<init_iterator> init_reverse_iterator; + typedef std::reverse_iterator<init_const_iterator> + init_const_reverse_iterator; + + init_reverse_iterator init_rbegin() { + return init_reverse_iterator(init_end()); + } + init_const_reverse_iterator init_rbegin() const { + return init_const_reverse_iterator(init_end()); + } + + init_reverse_iterator init_rend() { + return init_reverse_iterator(init_begin()); + } + init_const_reverse_iterator init_rend() const { + return init_const_reverse_iterator(init_begin()); + } + + /// \brief Determine the number of arguments used to initialize the member + /// or base. + unsigned getNumCtorInitializers() const { + return NumCtorInitializers; + } + + void setNumCtorInitializers(unsigned numCtorInitializers) { + NumCtorInitializers = numCtorInitializers; + } + + void setCtorInitializers(CXXCtorInitializer **Initializers) { + CtorInitializers = Initializers; + } + + /// \brief Determine whether this constructor is a delegating constructor. + bool isDelegatingConstructor() const { + return (getNumCtorInitializers() == 1) && + init_begin()[0]->isDelegatingInitializer(); + } + + /// \brief When this constructor delegates to another, retrieve the target. + CXXConstructorDecl *getTargetConstructor() const; + + /// Whether this constructor is a default + /// constructor (C++ [class.ctor]p5), which can be used to + /// default-initialize a class of this type. + bool isDefaultConstructor() const; + + /// \brief Whether this constructor is a copy constructor (C++ [class.copy]p2, + /// which can be used to copy the class. + /// + /// \p TypeQuals will be set to the qualifiers on the + /// argument type. For example, \p TypeQuals would be set to \c + /// Qualifiers::Const for the following copy constructor: + /// + /// \code + /// class X { + /// public: + /// X(const X&); + /// }; + /// \endcode + bool isCopyConstructor(unsigned &TypeQuals) const; + + /// Whether this constructor is a copy + /// constructor (C++ [class.copy]p2, which can be used to copy the + /// class. + bool isCopyConstructor() const { + unsigned TypeQuals = 0; + return isCopyConstructor(TypeQuals); + } + + /// \brief Determine whether this constructor is a move constructor + /// (C++11 [class.copy]p3), which can be used to move values of the class. + /// + /// \param TypeQuals If this constructor is a move constructor, will be set + /// to the type qualifiers on the referent of the first parameter's type. + bool isMoveConstructor(unsigned &TypeQuals) const; + + /// \brief Determine whether this constructor is a move constructor + /// (C++11 [class.copy]p3), which can be used to move values of the class. + bool isMoveConstructor() const { + unsigned TypeQuals = 0; + return isMoveConstructor(TypeQuals); + } + + /// \brief Determine whether this is a copy or move constructor. + /// + /// \param TypeQuals Will be set to the type qualifiers on the reference + /// parameter, if in fact this is a copy or move constructor. + bool isCopyOrMoveConstructor(unsigned &TypeQuals) const; + + /// \brief Determine whether this a copy or move constructor. + bool isCopyOrMoveConstructor() const { + unsigned Quals; + return isCopyOrMoveConstructor(Quals); + } + + /// Whether this constructor is a + /// converting constructor (C++ [class.conv.ctor]), which can be + /// used for user-defined conversions. + bool isConvertingConstructor(bool AllowExplicit) const; + + /// \brief Determine whether this is a member template specialization that + /// would copy the object to itself. Such constructors are never used to copy + /// an object. + bool isSpecializationCopyingObject() const; + + /// \brief Get the constructor that this inheriting constructor is based on. + const CXXConstructorDecl *getInheritedConstructor() const; + + /// \brief Set the constructor that this inheriting constructor is based on. + void setInheritedConstructor(const CXXConstructorDecl *BaseCtor); + + CXXConstructorDecl *getCanonicalDecl() override { + return cast<CXXConstructorDecl>(FunctionDecl::getCanonicalDecl()); + } + const CXXConstructorDecl *getCanonicalDecl() const { + return const_cast<CXXConstructorDecl*>(this)->getCanonicalDecl(); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == CXXConstructor; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// \brief Represents a C++ destructor within a class. +/// +/// For example: +/// +/// \code +/// class X { +/// public: +/// ~X(); // represented by a CXXDestructorDecl. +/// }; +/// \endcode +class CXXDestructorDecl : public CXXMethodDecl { + void anchor() override; + + FunctionDecl *OperatorDelete; + + CXXDestructorDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, + QualType T, TypeSourceInfo *TInfo, + bool isInline, bool isImplicitlyDeclared) + : CXXMethodDecl(CXXDestructor, C, RD, StartLoc, NameInfo, T, TInfo, + SC_None, isInline, /*isConstexpr=*/false, SourceLocation()), + OperatorDelete(nullptr) { + setImplicit(isImplicitlyDeclared); + } + +public: + static CXXDestructorDecl *Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, + QualType T, TypeSourceInfo* TInfo, + bool isInline, + bool isImplicitlyDeclared); + static CXXDestructorDecl *CreateDeserialized(ASTContext & C, unsigned ID); + + void setOperatorDelete(FunctionDecl *OD); + const FunctionDecl *getOperatorDelete() const { + return cast<CXXDestructorDecl>(getFirstDecl())->OperatorDelete; + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == CXXDestructor; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// \brief Represents a C++ conversion function within a class. +/// +/// For example: +/// +/// \code +/// class X { +/// public: +/// operator bool(); +/// }; +/// \endcode +class CXXConversionDecl : public CXXMethodDecl { + void anchor() override; + /// Whether this conversion function declaration is marked + /// "explicit", meaning that it can only be applied when the user + /// explicitly wrote a cast. This is a C++11 feature. + bool IsExplicitSpecified : 1; + + CXXConversionDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, + QualType T, TypeSourceInfo *TInfo, + bool isInline, bool isExplicitSpecified, + bool isConstexpr, SourceLocation EndLocation) + : CXXMethodDecl(CXXConversion, C, RD, StartLoc, NameInfo, T, TInfo, + SC_None, isInline, isConstexpr, EndLocation), + IsExplicitSpecified(isExplicitSpecified) { } + +public: + static CXXConversionDecl *Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, + QualType T, TypeSourceInfo *TInfo, + bool isInline, bool isExplicit, + bool isConstexpr, + SourceLocation EndLocation); + static CXXConversionDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + /// Whether this conversion function declaration is marked + /// "explicit", meaning that it can only be used for direct initialization + /// (including explitly written casts). This is a C++11 feature. + bool isExplicitSpecified() const { return IsExplicitSpecified; } + + /// \brief Whether this is an explicit conversion operator (C++11 and later). + /// + /// Explicit conversion operators are only considered for direct + /// initialization, e.g., when the user has explicitly written a cast. + bool isExplicit() const { + return cast<CXXConversionDecl>(getFirstDecl())->isExplicitSpecified(); + } + + /// \brief Returns the type that this conversion function is converting to. + QualType getConversionType() const { + return getType()->getAs<FunctionType>()->getReturnType(); + } + + /// \brief Determine whether this conversion function is a conversion from + /// a lambda closure type to a block pointer. + bool isLambdaToBlockPointerConversion() const; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == CXXConversion; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// \brief Represents a linkage specification. +/// +/// For example: +/// \code +/// extern "C" void foo(); +/// \endcode +class LinkageSpecDecl : public Decl, public DeclContext { + virtual void anchor(); +public: + /// \brief Represents the language in a linkage specification. + /// + /// The values are part of the serialization ABI for + /// ASTs and cannot be changed without altering that ABI. To help + /// ensure a stable ABI for this, we choose the DW_LANG_ encodings + /// from the dwarf standard. + enum LanguageIDs { + lang_c = /* DW_LANG_C */ 0x0002, + lang_cxx = /* DW_LANG_C_plus_plus */ 0x0004 + }; +private: + /// \brief The language for this linkage specification. + unsigned Language : 3; + /// \brief True if this linkage spec has braces. + /// + /// This is needed so that hasBraces() returns the correct result while the + /// linkage spec body is being parsed. Once RBraceLoc has been set this is + /// not used, so it doesn't need to be serialized. + unsigned HasBraces : 1; + /// \brief The source location for the extern keyword. + SourceLocation ExternLoc; + /// \brief The source location for the right brace (if valid). + SourceLocation RBraceLoc; + + LinkageSpecDecl(DeclContext *DC, SourceLocation ExternLoc, + SourceLocation LangLoc, LanguageIDs lang, bool HasBraces) + : Decl(LinkageSpec, DC, LangLoc), DeclContext(LinkageSpec), + Language(lang), HasBraces(HasBraces), ExternLoc(ExternLoc), + RBraceLoc(SourceLocation()) { } + +public: + static LinkageSpecDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation ExternLoc, + SourceLocation LangLoc, LanguageIDs Lang, + bool HasBraces); + static LinkageSpecDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + /// \brief Return the language specified by this linkage specification. + LanguageIDs getLanguage() const { return LanguageIDs(Language); } + /// \brief Set the language specified by this linkage specification. + void setLanguage(LanguageIDs L) { Language = L; } + + /// \brief Determines whether this linkage specification had braces in + /// its syntactic form. + bool hasBraces() const { + assert(!RBraceLoc.isValid() || HasBraces); + return HasBraces; + } + + SourceLocation getExternLoc() const { return ExternLoc; } + SourceLocation getRBraceLoc() const { return RBraceLoc; } + void setExternLoc(SourceLocation L) { ExternLoc = L; } + void setRBraceLoc(SourceLocation L) { + RBraceLoc = L; + HasBraces = RBraceLoc.isValid(); + } + + SourceLocation getLocEnd() const LLVM_READONLY { + if (hasBraces()) + return getRBraceLoc(); + // No braces: get the end location of the (only) declaration in context + // (if present). + return decls_empty() ? getLocation() : decls_begin()->getLocEnd(); + } + + SourceRange getSourceRange() const override LLVM_READONLY { + return SourceRange(ExternLoc, getLocEnd()); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == LinkageSpec; } + static DeclContext *castToDeclContext(const LinkageSpecDecl *D) { + return static_cast<DeclContext *>(const_cast<LinkageSpecDecl*>(D)); + } + static LinkageSpecDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<LinkageSpecDecl *>(const_cast<DeclContext*>(DC)); + } +}; + +/// \brief Represents C++ using-directive. +/// +/// For example: +/// \code +/// using namespace std; +/// \endcode +/// +/// \note UsingDirectiveDecl should be Decl not NamedDecl, but we provide +/// artificial names for all using-directives in order to store +/// them in DeclContext effectively. +class UsingDirectiveDecl : public NamedDecl { + void anchor() override; + /// \brief The location of the \c using keyword. + SourceLocation UsingLoc; + + /// \brief The location of the \c namespace keyword. + SourceLocation NamespaceLoc; + + /// \brief The nested-name-specifier that precedes the namespace. + NestedNameSpecifierLoc QualifierLoc; + + /// \brief The namespace nominated by this using-directive. + NamedDecl *NominatedNamespace; + + /// Enclosing context containing both using-directive and nominated + /// namespace. + DeclContext *CommonAncestor; + + /// \brief Returns special DeclarationName used by using-directives. + /// + /// This is only used by DeclContext for storing UsingDirectiveDecls in + /// its lookup structure. + static DeclarationName getName() { + return DeclarationName::getUsingDirectiveName(); + } + + UsingDirectiveDecl(DeclContext *DC, SourceLocation UsingLoc, + SourceLocation NamespcLoc, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation IdentLoc, + NamedDecl *Nominated, + DeclContext *CommonAncestor) + : NamedDecl(UsingDirective, DC, IdentLoc, getName()), UsingLoc(UsingLoc), + NamespaceLoc(NamespcLoc), QualifierLoc(QualifierLoc), + NominatedNamespace(Nominated), CommonAncestor(CommonAncestor) { } + +public: + /// \brief Retrieve the nested-name-specifier that qualifies the + /// name of the namespace, with source-location information. + NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } + + /// \brief Retrieve the nested-name-specifier that qualifies the + /// name of the namespace. + NestedNameSpecifier *getQualifier() const { + return QualifierLoc.getNestedNameSpecifier(); + } + + NamedDecl *getNominatedNamespaceAsWritten() { return NominatedNamespace; } + const NamedDecl *getNominatedNamespaceAsWritten() const { + return NominatedNamespace; + } + + /// \brief Returns the namespace nominated by this using-directive. + NamespaceDecl *getNominatedNamespace(); + + const NamespaceDecl *getNominatedNamespace() const { + return const_cast<UsingDirectiveDecl*>(this)->getNominatedNamespace(); + } + + /// \brief Returns the common ancestor context of this using-directive and + /// its nominated namespace. + DeclContext *getCommonAncestor() { return CommonAncestor; } + const DeclContext *getCommonAncestor() const { return CommonAncestor; } + + /// \brief Return the location of the \c using keyword. + SourceLocation getUsingLoc() const { return UsingLoc; } + + // FIXME: Could omit 'Key' in name. + /// \brief Returns the location of the \c namespace keyword. + SourceLocation getNamespaceKeyLocation() const { return NamespaceLoc; } + + /// \brief Returns the location of this using declaration's identifier. + SourceLocation getIdentLocation() const { return getLocation(); } + + static UsingDirectiveDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation UsingLoc, + SourceLocation NamespaceLoc, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation IdentLoc, + NamedDecl *Nominated, + DeclContext *CommonAncestor); + static UsingDirectiveDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + SourceRange getSourceRange() const override LLVM_READONLY { + return SourceRange(UsingLoc, getLocation()); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == UsingDirective; } + + // Friend for getUsingDirectiveName. + friend class DeclContext; + + friend class ASTDeclReader; +}; + +/// \brief Represents a C++ namespace alias. +/// +/// For example: +/// +/// \code +/// namespace Foo = Bar; +/// \endcode +class NamespaceAliasDecl : public NamedDecl, + public Redeclarable<NamespaceAliasDecl> { + void anchor() override; + + /// \brief The location of the \c namespace keyword. + SourceLocation NamespaceLoc; + + /// \brief The location of the namespace's identifier. + /// + /// This is accessed by TargetNameLoc. + SourceLocation IdentLoc; + + /// \brief The nested-name-specifier that precedes the namespace. + NestedNameSpecifierLoc QualifierLoc; + + /// \brief The Decl that this alias points to, either a NamespaceDecl or + /// a NamespaceAliasDecl. + NamedDecl *Namespace; + + NamespaceAliasDecl(ASTContext &C, DeclContext *DC, + SourceLocation NamespaceLoc, SourceLocation AliasLoc, + IdentifierInfo *Alias, NestedNameSpecifierLoc QualifierLoc, + SourceLocation IdentLoc, NamedDecl *Namespace) + : NamedDecl(NamespaceAlias, DC, AliasLoc, Alias), redeclarable_base(C), + NamespaceLoc(NamespaceLoc), IdentLoc(IdentLoc), + QualifierLoc(QualifierLoc), Namespace(Namespace) {} + + typedef Redeclarable<NamespaceAliasDecl> redeclarable_base; + NamespaceAliasDecl *getNextRedeclarationImpl() override; + NamespaceAliasDecl *getPreviousDeclImpl() override; + NamespaceAliasDecl *getMostRecentDeclImpl() override; + + friend class ASTDeclReader; + +public: + static NamespaceAliasDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation NamespaceLoc, + SourceLocation AliasLoc, + IdentifierInfo *Alias, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation IdentLoc, + NamedDecl *Namespace); + + static NamespaceAliasDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + typedef redeclarable_base::redecl_range redecl_range; + typedef redeclarable_base::redecl_iterator redecl_iterator; + using redeclarable_base::redecls_begin; + using redeclarable_base::redecls_end; + using redeclarable_base::redecls; + using redeclarable_base::getPreviousDecl; + using redeclarable_base::getMostRecentDecl; + + NamespaceAliasDecl *getCanonicalDecl() override { + return getFirstDecl(); + } + const NamespaceAliasDecl *getCanonicalDecl() const { + return getFirstDecl(); + } + + /// \brief Retrieve the nested-name-specifier that qualifies the + /// name of the namespace, with source-location information. + NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } + + /// \brief Retrieve the nested-name-specifier that qualifies the + /// name of the namespace. + NestedNameSpecifier *getQualifier() const { + return QualifierLoc.getNestedNameSpecifier(); + } + + /// \brief Retrieve the namespace declaration aliased by this directive. + NamespaceDecl *getNamespace() { + if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(Namespace)) + return AD->getNamespace(); + + return cast<NamespaceDecl>(Namespace); + } + + const NamespaceDecl *getNamespace() const { + return const_cast<NamespaceAliasDecl*>(this)->getNamespace(); + } + + /// Returns the location of the alias name, i.e. 'foo' in + /// "namespace foo = ns::bar;". + SourceLocation getAliasLoc() const { return getLocation(); } + + /// Returns the location of the \c namespace keyword. + SourceLocation getNamespaceLoc() const { return NamespaceLoc; } + + /// Returns the location of the identifier in the named namespace. + SourceLocation getTargetNameLoc() const { return IdentLoc; } + + /// \brief Retrieve the namespace that this alias refers to, which + /// may either be a NamespaceDecl or a NamespaceAliasDecl. + NamedDecl *getAliasedNamespace() const { return Namespace; } + + SourceRange getSourceRange() const override LLVM_READONLY { + return SourceRange(NamespaceLoc, IdentLoc); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == NamespaceAlias; } +}; + +/// \brief Represents a shadow declaration introduced into a scope by a +/// (resolved) using declaration. +/// +/// For example, +/// \code +/// namespace A { +/// void foo(); +/// } +/// namespace B { +/// using A::foo; // <- a UsingDecl +/// // Also creates a UsingShadowDecl for A::foo() in B +/// } +/// \endcode +class UsingShadowDecl : public NamedDecl, public Redeclarable<UsingShadowDecl> { + void anchor() override; + + /// The referenced declaration. + NamedDecl *Underlying; + + /// \brief The using declaration which introduced this decl or the next using + /// shadow declaration contained in the aforementioned using declaration. + NamedDecl *UsingOrNextShadow; + friend class UsingDecl; + + UsingShadowDecl(ASTContext &C, DeclContext *DC, SourceLocation Loc, + UsingDecl *Using, NamedDecl *Target) + : NamedDecl(UsingShadow, DC, Loc, DeclarationName()), + redeclarable_base(C), Underlying(Target), + UsingOrNextShadow(reinterpret_cast<NamedDecl *>(Using)) { + if (Target) { + setDeclName(Target->getDeclName()); + IdentifierNamespace = Target->getIdentifierNamespace(); + } + setImplicit(); + } + + typedef Redeclarable<UsingShadowDecl> redeclarable_base; + UsingShadowDecl *getNextRedeclarationImpl() override { + return getNextRedeclaration(); + } + UsingShadowDecl *getPreviousDeclImpl() override { + return getPreviousDecl(); + } + UsingShadowDecl *getMostRecentDeclImpl() override { + return getMostRecentDecl(); + } + +public: + static UsingShadowDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation Loc, UsingDecl *Using, + NamedDecl *Target) { + return new (C, DC) UsingShadowDecl(C, DC, Loc, Using, Target); + } + + static UsingShadowDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + typedef redeclarable_base::redecl_range redecl_range; + typedef redeclarable_base::redecl_iterator redecl_iterator; + using redeclarable_base::redecls_begin; + using redeclarable_base::redecls_end; + using redeclarable_base::redecls; + using redeclarable_base::getPreviousDecl; + using redeclarable_base::getMostRecentDecl; + + UsingShadowDecl *getCanonicalDecl() override { + return getFirstDecl(); + } + const UsingShadowDecl *getCanonicalDecl() const { + return getFirstDecl(); + } + + /// \brief Gets the underlying declaration which has been brought into the + /// local scope. + NamedDecl *getTargetDecl() const { return Underlying; } + + /// \brief Sets the underlying declaration which has been brought into the + /// local scope. + void setTargetDecl(NamedDecl* ND) { + assert(ND && "Target decl is null!"); + Underlying = ND; + IdentifierNamespace = ND->getIdentifierNamespace(); + } + + /// \brief Gets the using declaration to which this declaration is tied. + UsingDecl *getUsingDecl() const; + + /// \brief The next using shadow declaration contained in the shadow decl + /// chain of the using declaration which introduced this decl. + UsingShadowDecl *getNextUsingShadowDecl() const { + return dyn_cast_or_null<UsingShadowDecl>(UsingOrNextShadow); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == Decl::UsingShadow; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// \brief Represents a C++ using-declaration. +/// +/// For example: +/// \code +/// using someNameSpace::someIdentifier; +/// \endcode +class UsingDecl : public NamedDecl, public Mergeable<UsingDecl> { + void anchor() override; + + /// \brief The source location of the 'using' keyword itself. + SourceLocation UsingLocation; + + /// \brief The nested-name-specifier that precedes the name. + NestedNameSpecifierLoc QualifierLoc; + + /// \brief Provides source/type location info for the declaration name + /// embedded in the ValueDecl base class. + DeclarationNameLoc DNLoc; + + /// \brief The first shadow declaration of the shadow decl chain associated + /// with this using declaration. + /// + /// The bool member of the pair store whether this decl has the \c typename + /// keyword. + llvm::PointerIntPair<UsingShadowDecl *, 1, bool> FirstUsingShadow; + + UsingDecl(DeclContext *DC, SourceLocation UL, + NestedNameSpecifierLoc QualifierLoc, + const DeclarationNameInfo &NameInfo, bool HasTypenameKeyword) + : NamedDecl(Using, DC, NameInfo.getLoc(), NameInfo.getName()), + UsingLocation(UL), QualifierLoc(QualifierLoc), + DNLoc(NameInfo.getInfo()), FirstUsingShadow(nullptr, HasTypenameKeyword) { + } + +public: + /// \brief Return the source location of the 'using' keyword. + SourceLocation getUsingLoc() const { return UsingLocation; } + + /// \brief Set the source location of the 'using' keyword. + void setUsingLoc(SourceLocation L) { UsingLocation = L; } + + /// \brief Retrieve the nested-name-specifier that qualifies the name, + /// with source-location information. + NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } + + /// \brief Retrieve the nested-name-specifier that qualifies the name. + NestedNameSpecifier *getQualifier() const { + return QualifierLoc.getNestedNameSpecifier(); + } + + DeclarationNameInfo getNameInfo() const { + return DeclarationNameInfo(getDeclName(), getLocation(), DNLoc); + } + + /// \brief Return true if it is a C++03 access declaration (no 'using'). + bool isAccessDeclaration() const { return UsingLocation.isInvalid(); } + + /// \brief Return true if the using declaration has 'typename'. + bool hasTypename() const { return FirstUsingShadow.getInt(); } + + /// \brief Sets whether the using declaration has 'typename'. + void setTypename(bool TN) { FirstUsingShadow.setInt(TN); } + + /// \brief Iterates through the using shadow declarations associated with + /// this using declaration. + class shadow_iterator { + /// \brief The current using shadow declaration. + UsingShadowDecl *Current; + + public: + typedef UsingShadowDecl* value_type; + typedef UsingShadowDecl* reference; + typedef UsingShadowDecl* pointer; + typedef std::forward_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + + shadow_iterator() : Current(nullptr) { } + explicit shadow_iterator(UsingShadowDecl *C) : Current(C) { } + + reference operator*() const { return Current; } + pointer operator->() const { return Current; } + + shadow_iterator& operator++() { + Current = Current->getNextUsingShadowDecl(); + return *this; + } + + shadow_iterator operator++(int) { + shadow_iterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool operator==(shadow_iterator x, shadow_iterator y) { + return x.Current == y.Current; + } + friend bool operator!=(shadow_iterator x, shadow_iterator y) { + return x.Current != y.Current; + } + }; + + typedef llvm::iterator_range<shadow_iterator> shadow_range; + + shadow_range shadows() const { + return shadow_range(shadow_begin(), shadow_end()); + } + shadow_iterator shadow_begin() const { + return shadow_iterator(FirstUsingShadow.getPointer()); + } + shadow_iterator shadow_end() const { return shadow_iterator(); } + + /// \brief Return the number of shadowed declarations associated with this + /// using declaration. + unsigned shadow_size() const { + return std::distance(shadow_begin(), shadow_end()); + } + + void addShadowDecl(UsingShadowDecl *S); + void removeShadowDecl(UsingShadowDecl *S); + + static UsingDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation UsingL, + NestedNameSpecifierLoc QualifierLoc, + const DeclarationNameInfo &NameInfo, + bool HasTypenameKeyword); + + static UsingDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + SourceRange getSourceRange() const override LLVM_READONLY; + + /// Retrieves the canonical declaration of this declaration. + UsingDecl *getCanonicalDecl() override { return getFirstDecl(); } + const UsingDecl *getCanonicalDecl() const { return getFirstDecl(); } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == Using; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// \brief Represents a dependent using declaration which was not marked with +/// \c typename. +/// +/// Unlike non-dependent using declarations, these *only* bring through +/// non-types; otherwise they would break two-phase lookup. +/// +/// \code +/// template \<class T> class A : public Base<T> { +/// using Base<T>::foo; +/// }; +/// \endcode +class UnresolvedUsingValueDecl : public ValueDecl, + public Mergeable<UnresolvedUsingValueDecl> { + void anchor() override; + + /// \brief The source location of the 'using' keyword + SourceLocation UsingLocation; + + /// \brief The nested-name-specifier that precedes the name. + NestedNameSpecifierLoc QualifierLoc; + + /// \brief Provides source/type location info for the declaration name + /// embedded in the ValueDecl base class. + DeclarationNameLoc DNLoc; + + UnresolvedUsingValueDecl(DeclContext *DC, QualType Ty, + SourceLocation UsingLoc, + NestedNameSpecifierLoc QualifierLoc, + const DeclarationNameInfo &NameInfo) + : ValueDecl(UnresolvedUsingValue, DC, + NameInfo.getLoc(), NameInfo.getName(), Ty), + UsingLocation(UsingLoc), QualifierLoc(QualifierLoc), + DNLoc(NameInfo.getInfo()) + { } + +public: + /// \brief Returns the source location of the 'using' keyword. + SourceLocation getUsingLoc() const { return UsingLocation; } + + /// \brief Set the source location of the 'using' keyword. + void setUsingLoc(SourceLocation L) { UsingLocation = L; } + + /// \brief Return true if it is a C++03 access declaration (no 'using'). + bool isAccessDeclaration() const { return UsingLocation.isInvalid(); } + + /// \brief Retrieve the nested-name-specifier that qualifies the name, + /// with source-location information. + NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } + + /// \brief Retrieve the nested-name-specifier that qualifies the name. + NestedNameSpecifier *getQualifier() const { + return QualifierLoc.getNestedNameSpecifier(); + } + + DeclarationNameInfo getNameInfo() const { + return DeclarationNameInfo(getDeclName(), getLocation(), DNLoc); + } + + static UnresolvedUsingValueDecl * + Create(ASTContext &C, DeclContext *DC, SourceLocation UsingLoc, + NestedNameSpecifierLoc QualifierLoc, + const DeclarationNameInfo &NameInfo); + + static UnresolvedUsingValueDecl * + CreateDeserialized(ASTContext &C, unsigned ID); + + SourceRange getSourceRange() const override LLVM_READONLY; + + /// Retrieves the canonical declaration of this declaration. + UnresolvedUsingValueDecl *getCanonicalDecl() override { + return getFirstDecl(); + } + const UnresolvedUsingValueDecl *getCanonicalDecl() const { + return getFirstDecl(); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == UnresolvedUsingValue; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// \brief Represents a dependent using declaration which was marked with +/// \c typename. +/// +/// \code +/// template \<class T> class A : public Base<T> { +/// using typename Base<T>::foo; +/// }; +/// \endcode +/// +/// The type associated with an unresolved using typename decl is +/// currently always a typename type. +class UnresolvedUsingTypenameDecl + : public TypeDecl, + public Mergeable<UnresolvedUsingTypenameDecl> { + void anchor() override; + + /// \brief The source location of the 'typename' keyword + SourceLocation TypenameLocation; + + /// \brief The nested-name-specifier that precedes the name. + NestedNameSpecifierLoc QualifierLoc; + + UnresolvedUsingTypenameDecl(DeclContext *DC, SourceLocation UsingLoc, + SourceLocation TypenameLoc, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TargetNameLoc, + IdentifierInfo *TargetName) + : TypeDecl(UnresolvedUsingTypename, DC, TargetNameLoc, TargetName, + UsingLoc), + TypenameLocation(TypenameLoc), QualifierLoc(QualifierLoc) { } + + friend class ASTDeclReader; + +public: + /// \brief Returns the source location of the 'using' keyword. + SourceLocation getUsingLoc() const { return getLocStart(); } + + /// \brief Returns the source location of the 'typename' keyword. + SourceLocation getTypenameLoc() const { return TypenameLocation; } + + /// \brief Retrieve the nested-name-specifier that qualifies the name, + /// with source-location information. + NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } + + /// \brief Retrieve the nested-name-specifier that qualifies the name. + NestedNameSpecifier *getQualifier() const { + return QualifierLoc.getNestedNameSpecifier(); + } + + static UnresolvedUsingTypenameDecl * + Create(ASTContext &C, DeclContext *DC, SourceLocation UsingLoc, + SourceLocation TypenameLoc, NestedNameSpecifierLoc QualifierLoc, + SourceLocation TargetNameLoc, DeclarationName TargetName); + + static UnresolvedUsingTypenameDecl * + CreateDeserialized(ASTContext &C, unsigned ID); + + /// Retrieves the canonical declaration of this declaration. + UnresolvedUsingTypenameDecl *getCanonicalDecl() override { + return getFirstDecl(); + } + const UnresolvedUsingTypenameDecl *getCanonicalDecl() const { + return getFirstDecl(); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == UnresolvedUsingTypename; } +}; + +/// \brief Represents a C++11 static_assert declaration. +class StaticAssertDecl : public Decl { + virtual void anchor(); + llvm::PointerIntPair<Expr *, 1, bool> AssertExprAndFailed; + StringLiteral *Message; + SourceLocation RParenLoc; + + StaticAssertDecl(DeclContext *DC, SourceLocation StaticAssertLoc, + Expr *AssertExpr, StringLiteral *Message, + SourceLocation RParenLoc, bool Failed) + : Decl(StaticAssert, DC, StaticAssertLoc), + AssertExprAndFailed(AssertExpr, Failed), Message(Message), + RParenLoc(RParenLoc) { } + +public: + static StaticAssertDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation StaticAssertLoc, + Expr *AssertExpr, StringLiteral *Message, + SourceLocation RParenLoc, bool Failed); + static StaticAssertDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + Expr *getAssertExpr() { return AssertExprAndFailed.getPointer(); } + const Expr *getAssertExpr() const { return AssertExprAndFailed.getPointer(); } + + StringLiteral *getMessage() { return Message; } + const StringLiteral *getMessage() const { return Message; } + + bool isFailed() const { return AssertExprAndFailed.getInt(); } + + SourceLocation getRParenLoc() const { return RParenLoc; } + + SourceRange getSourceRange() const override LLVM_READONLY { + return SourceRange(getLocation(), getRParenLoc()); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == StaticAssert; } + + friend class ASTDeclReader; +}; + +/// An instance of this class represents the declaration of a property +/// member. This is a Microsoft extension to C++, first introduced in +/// Visual Studio .NET 2003 as a parallel to similar features in C# +/// and Managed C++. +/// +/// A property must always be a non-static class member. +/// +/// A property member superficially resembles a non-static data +/// member, except preceded by a property attribute: +/// __declspec(property(get=GetX, put=PutX)) int x; +/// Either (but not both) of the 'get' and 'put' names may be omitted. +/// +/// A reference to a property is always an lvalue. If the lvalue +/// undergoes lvalue-to-rvalue conversion, then a getter name is +/// required, and that member is called with no arguments. +/// If the lvalue is assigned into, then a setter name is required, +/// and that member is called with one argument, the value assigned. +/// Both operations are potentially overloaded. Compound assignments +/// are permitted, as are the increment and decrement operators. +/// +/// The getter and putter methods are permitted to be overloaded, +/// although their return and parameter types are subject to certain +/// restrictions according to the type of the property. +/// +/// A property declared using an incomplete array type may +/// additionally be subscripted, adding extra parameters to the getter +/// and putter methods. +class MSPropertyDecl : public DeclaratorDecl { + IdentifierInfo *GetterId, *SetterId; + + MSPropertyDecl(DeclContext *DC, SourceLocation L, DeclarationName N, + QualType T, TypeSourceInfo *TInfo, SourceLocation StartL, + IdentifierInfo *Getter, IdentifierInfo *Setter) + : DeclaratorDecl(MSProperty, DC, L, N, T, TInfo, StartL), + GetterId(Getter), SetterId(Setter) {} + +public: + static MSPropertyDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, DeclarationName N, QualType T, + TypeSourceInfo *TInfo, SourceLocation StartL, + IdentifierInfo *Getter, IdentifierInfo *Setter); + static MSPropertyDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + static bool classof(const Decl *D) { return D->getKind() == MSProperty; } + + bool hasGetter() const { return GetterId != nullptr; } + IdentifierInfo* getGetterId() const { return GetterId; } + bool hasSetter() const { return SetterId != nullptr; } + IdentifierInfo* getSetterId() const { return SetterId; } + + friend class ASTDeclReader; +}; + +/// Insertion operator for diagnostics. This allows sending an AccessSpecifier +/// into a diagnostic with <<. +const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + AccessSpecifier AS); + +const PartialDiagnostic &operator<<(const PartialDiagnostic &DB, + AccessSpecifier AS); + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/DeclContextInternals.h b/contrib/llvm/tools/clang/include/clang/AST/DeclContextInternals.h new file mode 100644 index 0000000..ff37758 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/DeclContextInternals.h @@ -0,0 +1,264 @@ +//===-- DeclContextInternals.h - DeclContext Representation -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the data structures used in the implementation +// of DeclContext. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_DECLCONTEXTINTERNALS_H +#define LLVM_CLANG_AST_DECLCONTEXTINTERNALS_H + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclarationName.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/SmallVector.h" +#include <algorithm> + +namespace clang { + +class DependentDiagnostic; + +/// \brief An array of decls optimized for the common case of only containing +/// one entry. +struct StoredDeclsList { + + /// \brief When in vector form, this is what the Data pointer points to. + typedef SmallVector<NamedDecl *, 4> DeclsTy; + + /// \brief A collection of declarations, with a flag to indicate if we have + /// further external declarations. + typedef llvm::PointerIntPair<DeclsTy *, 1, bool> DeclsAndHasExternalTy; + + /// \brief The stored data, which will be either a pointer to a NamedDecl, + /// or a pointer to a vector with a flag to indicate if there are further + /// external declarations. + llvm::PointerUnion<NamedDecl*, DeclsAndHasExternalTy> Data; + +public: + StoredDeclsList() {} + + StoredDeclsList(StoredDeclsList &&RHS) : Data(RHS.Data) { + RHS.Data = (NamedDecl *)nullptr; + } + + ~StoredDeclsList() { + // If this is a vector-form, free the vector. + if (DeclsTy *Vector = getAsVector()) + delete Vector; + } + + StoredDeclsList &operator=(StoredDeclsList &&RHS) { + if (DeclsTy *Vector = getAsVector()) + delete Vector; + Data = RHS.Data; + RHS.Data = (NamedDecl *)nullptr; + return *this; + } + + bool isNull() const { return Data.isNull(); } + + NamedDecl *getAsDecl() const { + return Data.dyn_cast<NamedDecl *>(); + } + + DeclsAndHasExternalTy getAsVectorAndHasExternal() const { + return Data.dyn_cast<DeclsAndHasExternalTy>(); + } + + DeclsTy *getAsVector() const { + return getAsVectorAndHasExternal().getPointer(); + } + + bool hasExternalDecls() const { + return getAsVectorAndHasExternal().getInt(); + } + + void setHasExternalDecls() { + if (DeclsTy *Vec = getAsVector()) + Data = DeclsAndHasExternalTy(Vec, true); + else { + DeclsTy *VT = new DeclsTy(); + if (NamedDecl *OldD = getAsDecl()) + VT->push_back(OldD); + Data = DeclsAndHasExternalTy(VT, true); + } + } + + void setOnlyValue(NamedDecl *ND) { + assert(!getAsVector() && "Not inline"); + Data = ND; + // Make sure that Data is a plain NamedDecl* so we can use its address + // at getLookupResult. + assert(*(NamedDecl **)&Data == ND && + "PointerUnion mangles the NamedDecl pointer!"); + } + + void remove(NamedDecl *D) { + assert(!isNull() && "removing from empty list"); + if (NamedDecl *Singleton = getAsDecl()) { + assert(Singleton == D && "list is different singleton"); + (void)Singleton; + Data = (NamedDecl *)nullptr; + return; + } + + DeclsTy &Vec = *getAsVector(); + DeclsTy::iterator I = std::find(Vec.begin(), Vec.end(), D); + assert(I != Vec.end() && "list does not contain decl"); + Vec.erase(I); + + assert(std::find(Vec.begin(), Vec.end(), D) + == Vec.end() && "list still contains decl"); + } + + /// \brief Remove any declarations which were imported from an external + /// AST source. + void removeExternalDecls() { + if (isNull()) { + // Nothing to do. + } else if (NamedDecl *Singleton = getAsDecl()) { + if (Singleton->isFromASTFile()) + *this = StoredDeclsList(); + } else { + DeclsTy &Vec = *getAsVector(); + Vec.erase(std::remove_if(Vec.begin(), Vec.end(), + std::mem_fun(&Decl::isFromASTFile)), + Vec.end()); + // Don't have any external decls any more. + Data = DeclsAndHasExternalTy(&Vec, false); + } + } + + /// getLookupResult - Return an array of all the decls that this list + /// represents. + DeclContext::lookup_result getLookupResult() { + if (isNull()) + return DeclContext::lookup_result(); + + // If we have a single NamedDecl, return it. + if (NamedDecl *ND = getAsDecl()) { + assert(!isNull() && "Empty list isn't allowed"); + + // Data is a raw pointer to a NamedDecl*, return it. + return DeclContext::lookup_result(ND); + } + + assert(getAsVector() && "Must have a vector at this point"); + DeclsTy &Vector = *getAsVector(); + + // Otherwise, we have a range result. + return DeclContext::lookup_result(Vector); + } + + /// HandleRedeclaration - If this is a redeclaration of an existing decl, + /// replace the old one with D and return true. Otherwise return false. + bool HandleRedeclaration(NamedDecl *D, bool IsKnownNewer) { + // Most decls only have one entry in their list, special case it. + if (NamedDecl *OldD = getAsDecl()) { + if (!D->declarationReplaces(OldD, IsKnownNewer)) + return false; + setOnlyValue(D); + return true; + } + + // Determine if this declaration is actually a redeclaration. + DeclsTy &Vec = *getAsVector(); + for (DeclsTy::iterator OD = Vec.begin(), ODEnd = Vec.end(); + OD != ODEnd; ++OD) { + NamedDecl *OldD = *OD; + if (D->declarationReplaces(OldD, IsKnownNewer)) { + *OD = D; + return true; + } + } + + return false; + } + + /// AddSubsequentDecl - This is called on the second and later decl when it is + /// not a redeclaration to merge it into the appropriate place in our list. + /// + void AddSubsequentDecl(NamedDecl *D) { + assert(!isNull() && "don't AddSubsequentDecl when we have no decls"); + + // If this is the second decl added to the list, convert this to vector + // form. + if (NamedDecl *OldD = getAsDecl()) { + DeclsTy *VT = new DeclsTy(); + VT->push_back(OldD); + Data = DeclsAndHasExternalTy(VT, false); + } + + DeclsTy &Vec = *getAsVector(); + + // Using directives end up in a special entry which contains only + // other using directives, so all this logic is wasted for them. + // But avoiding the logic wastes time in the far-more-common case + // that we're *not* adding a new using directive. + + // Tag declarations always go at the end of the list so that an + // iterator which points at the first tag will start a span of + // decls that only contains tags. + if (D->hasTagIdentifierNamespace()) + Vec.push_back(D); + + // Resolved using declarations go at the front of the list so that + // they won't show up in other lookup results. Unresolved using + // declarations (which are always in IDNS_Using | IDNS_Ordinary) + // follow that so that the using declarations will be contiguous. + else if (D->getIdentifierNamespace() & Decl::IDNS_Using) { + DeclsTy::iterator I = Vec.begin(); + if (D->getIdentifierNamespace() != Decl::IDNS_Using) { + while (I != Vec.end() && + (*I)->getIdentifierNamespace() == Decl::IDNS_Using) + ++I; + } + Vec.insert(I, D); + + // All other declarations go at the end of the list, but before any + // tag declarations. But we can be clever about tag declarations + // because there can only ever be one in a scope. + } else if (!Vec.empty() && Vec.back()->hasTagIdentifierNamespace()) { + NamedDecl *TagD = Vec.back(); + Vec.back() = D; + Vec.push_back(TagD); + } else + Vec.push_back(D); + } +}; + +class StoredDeclsMap + : public llvm::SmallDenseMap<DeclarationName, StoredDeclsList, 4> { + +public: + static void DestroyAll(StoredDeclsMap *Map, bool Dependent); + +private: + friend class ASTContext; // walks the chain deleting these + friend class DeclContext; + llvm::PointerIntPair<StoredDeclsMap*, 1> Previous; +}; + +class DependentStoredDeclsMap : public StoredDeclsMap { +public: + DependentStoredDeclsMap() : FirstDiagnostic(nullptr) {} + +private: + friend class DependentDiagnostic; + friend class DeclContext; // iterates over diagnostics + + DependentDiagnostic *FirstDiagnostic; +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/DeclFriend.h b/contrib/llvm/tools/clang/include/clang/AST/DeclFriend.h new file mode 100644 index 0000000..27b0388 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/DeclFriend.h @@ -0,0 +1,243 @@ +//===-- DeclFriend.h - Classes for C++ friend declarations -*- C++ -*------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the section of the AST representing C++ friend +// declarations. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DECLFRIEND_H +#define LLVM_CLANG_AST_DECLFRIEND_H + +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/TypeLoc.h" +#include "llvm/Support/Compiler.h" + +namespace clang { + +/// FriendDecl - Represents the declaration of a friend entity, +/// which can be a function, a type, or a templated function or type. +// For example: +/// +/// @code +/// template <typename T> class A { +/// friend int foo(T); +/// friend class B; +/// friend T; // only in C++0x +/// template <typename U> friend class C; +/// template <typename U> friend A& operator+=(A&, const U&) { ... } +/// }; +/// @endcode +/// +/// The semantic context of a friend decl is its declaring class. +class FriendDecl final + : public Decl, + private llvm::TrailingObjects<FriendDecl, TemplateParameterList *> { + virtual void anchor(); +public: + typedef llvm::PointerUnion<NamedDecl*,TypeSourceInfo*> FriendUnion; + +private: + // The declaration that's a friend of this class. + FriendUnion Friend; + + // A pointer to the next friend in the sequence. + LazyDeclPtr NextFriend; + + // Location of the 'friend' specifier. + SourceLocation FriendLoc; + + /// True if this 'friend' declaration is unsupported. Eventually we + /// will support every possible friend declaration, but for now we + /// silently ignore some and set this flag to authorize all access. + bool UnsupportedFriend : 1; + + // The number of "outer" template parameter lists in non-templatic + // (currently unsupported) friend type declarations, such as + // template <class T> friend class A<T>::B; + unsigned NumTPLists : 31; + + friend class CXXRecordDecl::friend_iterator; + friend class CXXRecordDecl; + + FriendDecl(DeclContext *DC, SourceLocation L, FriendUnion Friend, + SourceLocation FriendL, + ArrayRef<TemplateParameterList*> FriendTypeTPLists) + : Decl(Decl::Friend, DC, L), + Friend(Friend), + NextFriend(), + FriendLoc(FriendL), + UnsupportedFriend(false), + NumTPLists(FriendTypeTPLists.size()) { + for (unsigned i = 0; i < NumTPLists; ++i) + getTrailingObjects<TemplateParameterList *>()[i] = FriendTypeTPLists[i]; + } + + FriendDecl(EmptyShell Empty, unsigned NumFriendTypeTPLists) + : Decl(Decl::Friend, Empty), NextFriend(), + NumTPLists(NumFriendTypeTPLists) { } + + FriendDecl *getNextFriend() { + if (!NextFriend.isOffset()) + return cast_or_null<FriendDecl>(NextFriend.get(nullptr)); + return getNextFriendSlowCase(); + } + FriendDecl *getNextFriendSlowCase(); + +public: + static FriendDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, FriendUnion Friend_, + SourceLocation FriendL, + ArrayRef<TemplateParameterList*> FriendTypeTPLists + = None); + static FriendDecl *CreateDeserialized(ASTContext &C, unsigned ID, + unsigned FriendTypeNumTPLists); + + /// If this friend declaration names an (untemplated but possibly + /// dependent) type, return the type; otherwise return null. This + /// is used for elaborated-type-specifiers and, in C++0x, for + /// arbitrary friend type declarations. + TypeSourceInfo *getFriendType() const { + return Friend.dyn_cast<TypeSourceInfo*>(); + } + unsigned getFriendTypeNumTemplateParameterLists() const { + return NumTPLists; + } + TemplateParameterList *getFriendTypeTemplateParameterList(unsigned N) const { + assert(N < NumTPLists); + return getTrailingObjects<TemplateParameterList *>()[N]; + } + + /// If this friend declaration doesn't name a type, return the inner + /// declaration. + NamedDecl *getFriendDecl() const { + return Friend.dyn_cast<NamedDecl*>(); + } + + /// Retrieves the location of the 'friend' keyword. + SourceLocation getFriendLoc() const { + return FriendLoc; + } + + /// Retrieves the source range for the friend declaration. + SourceRange getSourceRange() const override LLVM_READONLY { + if (NamedDecl *ND = getFriendDecl()) { + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) + return FD->getSourceRange(); + if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(ND)) + return FTD->getSourceRange(); + if (ClassTemplateDecl *CTD = dyn_cast<ClassTemplateDecl>(ND)) + return CTD->getSourceRange(); + if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(ND)) { + if (DD->getOuterLocStart() != DD->getInnerLocStart()) + return DD->getSourceRange(); + } + return SourceRange(getFriendLoc(), ND->getLocEnd()); + } + else if (TypeSourceInfo *TInfo = getFriendType()) { + SourceLocation StartL = + (NumTPLists == 0) ? getFriendLoc() + : getTrailingObjects<TemplateParameterList *>()[0] + ->getTemplateLoc(); + return SourceRange(StartL, TInfo->getTypeLoc().getEndLoc()); + } + else + return SourceRange(getFriendLoc(), getLocation()); + } + + /// Determines if this friend kind is unsupported. + bool isUnsupportedFriend() const { + return UnsupportedFriend; + } + void setUnsupportedFriend(bool Unsupported) { + UnsupportedFriend = Unsupported; + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == Decl::Friend; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; + friend TrailingObjects; +}; + +/// An iterator over the friend declarations of a class. +class CXXRecordDecl::friend_iterator { + FriendDecl *Ptr; + + friend class CXXRecordDecl; + explicit friend_iterator(FriendDecl *Ptr) : Ptr(Ptr) {} +public: + friend_iterator() {} + + typedef FriendDecl *value_type; + typedef FriendDecl *reference; + typedef FriendDecl *pointer; + typedef int difference_type; + typedef std::forward_iterator_tag iterator_category; + + reference operator*() const { return Ptr; } + + friend_iterator &operator++() { + assert(Ptr && "attempt to increment past end of friend list"); + Ptr = Ptr->getNextFriend(); + return *this; + } + + friend_iterator operator++(int) { + friend_iterator tmp = *this; + ++*this; + return tmp; + } + + bool operator==(const friend_iterator &Other) const { + return Ptr == Other.Ptr; + } + + bool operator!=(const friend_iterator &Other) const { + return Ptr != Other.Ptr; + } + + friend_iterator &operator+=(difference_type N) { + assert(N >= 0 && "cannot rewind a CXXRecordDecl::friend_iterator"); + while (N--) + ++*this; + return *this; + } + + friend_iterator operator+(difference_type N) const { + friend_iterator tmp = *this; + tmp += N; + return tmp; + } +}; + +inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_begin() const { + return friend_iterator(getFirstFriend()); +} + +inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_end() const { + return friend_iterator(nullptr); +} + +inline CXXRecordDecl::friend_range CXXRecordDecl::friends() const { + return friend_range(friend_begin(), friend_end()); +} + +inline void CXXRecordDecl::pushFriendDecl(FriendDecl *FD) { + assert(!FD->NextFriend && "friend already has next friend?"); + FD->NextFriend = data().FirstFriend; + data().FirstFriend = FD; +} + +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/DeclGroup.h b/contrib/llvm/tools/clang/include/clang/AST/DeclGroup.h new file mode 100644 index 0000000..c84bb5e --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/DeclGroup.h @@ -0,0 +1,154 @@ +//===--- DeclGroup.h - Classes for representing groups of Decls -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the DeclGroup, DeclGroupRef, and OwningDeclGroup classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DECLGROUP_H +#define LLVM_CLANG_AST_DECLGROUP_H + +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/TrailingObjects.h" +#include <cassert> + +namespace clang { + +class ASTContext; +class Decl; +class DeclGroup; +class DeclGroupIterator; + +class DeclGroup final : private llvm::TrailingObjects<DeclGroup, Decl *> { + // FIXME: Include a TypeSpecifier object. + unsigned NumDecls; + +private: + DeclGroup() : NumDecls(0) {} + DeclGroup(unsigned numdecls, Decl** decls); + +public: + static DeclGroup *Create(ASTContext &C, Decl **Decls, unsigned NumDecls); + + unsigned size() const { return NumDecls; } + + Decl*& operator[](unsigned i) { + assert (i < NumDecls && "Out-of-bounds access."); + return getTrailingObjects<Decl *>()[i]; + } + + Decl* const& operator[](unsigned i) const { + assert (i < NumDecls && "Out-of-bounds access."); + return getTrailingObjects<Decl *>()[i]; + } + + friend TrailingObjects; +}; + +class DeclGroupRef { + // Note this is not a PointerIntPair because we need the address of the + // non-group case to be valid as a Decl** for iteration. + enum Kind { SingleDeclKind=0x0, DeclGroupKind=0x1, Mask=0x1 }; + Decl* D; + + Kind getKind() const { + return (Kind) (reinterpret_cast<uintptr_t>(D) & Mask); + } + +public: + DeclGroupRef() : D(nullptr) {} + + explicit DeclGroupRef(Decl* d) : D(d) {} + explicit DeclGroupRef(DeclGroup* dg) + : D((Decl*) (reinterpret_cast<uintptr_t>(dg) | DeclGroupKind)) {} + + static DeclGroupRef Create(ASTContext &C, Decl **Decls, unsigned NumDecls) { + if (NumDecls == 0) + return DeclGroupRef(); + if (NumDecls == 1) + return DeclGroupRef(Decls[0]); + return DeclGroupRef(DeclGroup::Create(C, Decls, NumDecls)); + } + + typedef Decl** iterator; + typedef Decl* const * const_iterator; + + bool isNull() const { return D == nullptr; } + bool isSingleDecl() const { return getKind() == SingleDeclKind; } + bool isDeclGroup() const { return getKind() == DeclGroupKind; } + + Decl *getSingleDecl() { + assert(isSingleDecl() && "Isn't a declgroup"); + return D; + } + const Decl *getSingleDecl() const { + return const_cast<DeclGroupRef*>(this)->getSingleDecl(); + } + + DeclGroup &getDeclGroup() { + assert(isDeclGroup() && "Isn't a declgroup"); + return *((DeclGroup*)(reinterpret_cast<uintptr_t>(D) & ~Mask)); + } + const DeclGroup &getDeclGroup() const { + return const_cast<DeclGroupRef*>(this)->getDeclGroup(); + } + + iterator begin() { + if (isSingleDecl()) + return D ? &D : nullptr; + return &getDeclGroup()[0]; + } + + iterator end() { + if (isSingleDecl()) + return D ? &D+1 : nullptr; + DeclGroup &G = getDeclGroup(); + return &G[0] + G.size(); + } + + const_iterator begin() const { + if (isSingleDecl()) + return D ? &D : nullptr; + return &getDeclGroup()[0]; + } + + const_iterator end() const { + if (isSingleDecl()) + return D ? &D+1 : nullptr; + const DeclGroup &G = getDeclGroup(); + return &G[0] + G.size(); + } + + void *getAsOpaquePtr() const { return D; } + static DeclGroupRef getFromOpaquePtr(void *Ptr) { + DeclGroupRef X; + X.D = static_cast<Decl*>(Ptr); + return X; + } +}; + +} // end clang namespace + +namespace llvm { + // DeclGroupRef is "like a pointer", implement PointerLikeTypeTraits. + template <typename T> + class PointerLikeTypeTraits; + template <> + class PointerLikeTypeTraits<clang::DeclGroupRef> { + public: + static inline void *getAsVoidPointer(clang::DeclGroupRef P) { + return P.getAsOpaquePtr(); + } + static inline clang::DeclGroupRef getFromVoidPointer(void *P) { + return clang::DeclGroupRef::getFromOpaquePtr(P); + } + enum { NumLowBitsAvailable = 0 }; + }; +} +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/DeclLookups.h b/contrib/llvm/tools/clang/include/clang/AST/DeclLookups.h new file mode 100644 index 0000000..eba2266 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/DeclLookups.h @@ -0,0 +1,115 @@ +//===-- DeclLookups.h - Low-level interface to all names in a DC-*- 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 DeclContext::all_lookups_iterator. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DECLLOOKUPS_H +#define LLVM_CLANG_AST_DECLLOOKUPS_H + +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclContextInternals.h" +#include "clang/AST/DeclarationName.h" + +namespace clang { + +/// all_lookups_iterator - An iterator that provides a view over the results +/// of looking up every possible name. +class DeclContext::all_lookups_iterator { + StoredDeclsMap::iterator It, End; +public: + typedef lookup_result value_type; + typedef lookup_result reference; + typedef lookup_result pointer; + typedef std::forward_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + + all_lookups_iterator() {} + all_lookups_iterator(StoredDeclsMap::iterator It, + StoredDeclsMap::iterator End) + : It(It), End(End) {} + + DeclarationName getLookupName() const { return It->first; } + + reference operator*() const { return It->second.getLookupResult(); } + pointer operator->() const { return It->second.getLookupResult(); } + + all_lookups_iterator& operator++() { + // Filter out using directives. They don't belong as results from name + // lookup anyways, except as an implementation detail. Users of the API + // should not expect to get them (or worse, rely on it). + do { + ++It; + } while (It != End && + It->first == DeclarationName::getUsingDirectiveName()); + + return *this; + } + + all_lookups_iterator operator++(int) { + all_lookups_iterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool operator==(all_lookups_iterator x, all_lookups_iterator y) { + return x.It == y.It; + } + friend bool operator!=(all_lookups_iterator x, all_lookups_iterator y) { + return x.It != y.It; + } +}; + +inline DeclContext::lookups_range DeclContext::lookups() const { + DeclContext *Primary = const_cast<DeclContext*>(this)->getPrimaryContext(); + if (Primary->hasExternalVisibleStorage()) + getParentASTContext().getExternalSource()->completeVisibleDeclsMap(Primary); + if (StoredDeclsMap *Map = Primary->buildLookup()) + return lookups_range(all_lookups_iterator(Map->begin(), Map->end()), + all_lookups_iterator(Map->end(), Map->end())); + + // Synthesize an empty range. This requires that two default constructed + // versions of these iterators form a valid empty range. + return lookups_range(all_lookups_iterator(), all_lookups_iterator()); +} + +inline DeclContext::all_lookups_iterator DeclContext::lookups_begin() const { + return lookups().begin(); +} + +inline DeclContext::all_lookups_iterator DeclContext::lookups_end() const { + return lookups().end(); +} + +inline DeclContext::lookups_range DeclContext::noload_lookups() const { + DeclContext *Primary = const_cast<DeclContext*>(this)->getPrimaryContext(); + if (StoredDeclsMap *Map = Primary->getLookupPtr()) + return lookups_range(all_lookups_iterator(Map->begin(), Map->end()), + all_lookups_iterator(Map->end(), Map->end())); + + // Synthesize an empty range. This requires that two default constructed + // versions of these iterators form a valid empty range. + return lookups_range(all_lookups_iterator(), all_lookups_iterator()); +} + +inline +DeclContext::all_lookups_iterator DeclContext::noload_lookups_begin() const { + return noload_lookups().begin(); +} + +inline +DeclContext::all_lookups_iterator DeclContext::noload_lookups_end() const { + return noload_lookups().end(); +} + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/DeclObjC.h b/contrib/llvm/tools/clang/include/clang/AST/DeclObjC.h new file mode 100644 index 0000000..f46078f --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/DeclObjC.h @@ -0,0 +1,2742 @@ +//===--- DeclObjC.h - Classes for representing declarations -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the DeclObjC interface and subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DECLOBJC_H +#define LLVM_CLANG_AST_DECLOBJC_H + +#include "clang/AST/Decl.h" +#include "clang/AST/SelectorLocationsKind.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +class Expr; +class Stmt; +class FunctionDecl; +class RecordDecl; +class ObjCIvarDecl; +class ObjCMethodDecl; +class ObjCProtocolDecl; +class ObjCCategoryDecl; +class ObjCPropertyDecl; +class ObjCPropertyImplDecl; +class CXXCtorInitializer; + +class ObjCListBase { + ObjCListBase(const ObjCListBase &) = delete; + void operator=(const ObjCListBase &) = delete; +protected: + /// List is an array of pointers to objects that are not owned by this object. + void **List; + unsigned NumElts; + +public: + ObjCListBase() : List(nullptr), NumElts(0) {} + unsigned size() const { return NumElts; } + bool empty() const { return NumElts == 0; } + +protected: + void set(void *const* InList, unsigned Elts, ASTContext &Ctx); +}; + + +/// ObjCList - This is a simple template class used to hold various lists of +/// decls etc, which is heavily used by the ObjC front-end. This only use case +/// this supports is setting the list all at once and then reading elements out +/// of it. +template <typename T> +class ObjCList : public ObjCListBase { +public: + void set(T* const* InList, unsigned Elts, ASTContext &Ctx) { + ObjCListBase::set(reinterpret_cast<void*const*>(InList), Elts, Ctx); + } + + typedef T* const * iterator; + iterator begin() const { return (iterator)List; } + iterator end() const { return (iterator)List+NumElts; } + + T* operator[](unsigned Idx) const { + assert(Idx < NumElts && "Invalid access"); + return (T*)List[Idx]; + } +}; + +/// \brief A list of Objective-C protocols, along with the source +/// locations at which they were referenced. +class ObjCProtocolList : public ObjCList<ObjCProtocolDecl> { + SourceLocation *Locations; + + using ObjCList<ObjCProtocolDecl>::set; + +public: + ObjCProtocolList() : ObjCList<ObjCProtocolDecl>(), Locations(nullptr) { } + + typedef const SourceLocation *loc_iterator; + loc_iterator loc_begin() const { return Locations; } + loc_iterator loc_end() const { return Locations + size(); } + + void set(ObjCProtocolDecl* const* InList, unsigned Elts, + const SourceLocation *Locs, ASTContext &Ctx); +}; + + +/// ObjCMethodDecl - Represents an instance or class method declaration. +/// ObjC methods can be declared within 4 contexts: class interfaces, +/// categories, protocols, and class implementations. While C++ member +/// functions leverage C syntax, Objective-C method syntax is modeled after +/// Smalltalk (using colons to specify argument types/expressions). +/// Here are some brief examples: +/// +/// Setter/getter instance methods: +/// - (void)setMenu:(NSMenu *)menu; +/// - (NSMenu *)menu; +/// +/// Instance method that takes 2 NSView arguments: +/// - (void)replaceSubview:(NSView *)oldView with:(NSView *)newView; +/// +/// Getter class method: +/// + (NSMenu *)defaultMenu; +/// +/// A selector represents a unique name for a method. The selector names for +/// the above methods are setMenu:, menu, replaceSubview:with:, and defaultMenu. +/// +class ObjCMethodDecl : public NamedDecl, public DeclContext { +public: + enum ImplementationControl { None, Required, Optional }; +private: + // The conventional meaning of this method; an ObjCMethodFamily. + // This is not serialized; instead, it is computed on demand and + // cached. + mutable unsigned Family : ObjCMethodFamilyBitWidth; + + /// instance (true) or class (false) method. + unsigned IsInstance : 1; + unsigned IsVariadic : 1; + + /// True if this method is the getter or setter for an explicit property. + unsigned IsPropertyAccessor : 1; + + // Method has a definition. + unsigned IsDefined : 1; + + /// \brief Method redeclaration in the same interface. + unsigned IsRedeclaration : 1; + + /// \brief Is redeclared in the same interface. + mutable unsigned HasRedeclaration : 1; + + // NOTE: VC++ treats enums as signed, avoid using ImplementationControl enum + /// \@required/\@optional + unsigned DeclImplementation : 2; + + // NOTE: VC++ treats enums as signed, avoid using the ObjCDeclQualifier enum + /// in, inout, etc. + unsigned objcDeclQualifier : 7; + + /// \brief Indicates whether this method has a related result type. + unsigned RelatedResultType : 1; + + /// \brief Whether the locations of the selector identifiers are in a + /// "standard" position, a enum SelectorLocationsKind. + unsigned SelLocsKind : 2; + + /// \brief Whether this method overrides any other in the class hierarchy. + /// + /// A method is said to override any method in the class's + /// base classes, its protocols, or its categories' protocols, that has + /// the same selector and is of the same kind (class or instance). + /// A method in an implementation is not considered as overriding the same + /// method in the interface or its categories. + unsigned IsOverriding : 1; + + /// \brief Indicates if the method was a definition but its body was skipped. + unsigned HasSkippedBody : 1; + + // Return type of this method. + QualType MethodDeclType; + + // Type source information for the return type. + TypeSourceInfo *ReturnTInfo; + + /// \brief Array of ParmVarDecls for the formal parameters of this method + /// and optionally followed by selector locations. + void *ParamsAndSelLocs; + unsigned NumParams; + + /// List of attributes for this method declaration. + SourceLocation DeclEndLoc; // the location of the ';' or '{'. + + // The following are only used for method definitions, null otherwise. + LazyDeclStmtPtr Body; + + /// SelfDecl - Decl for the implicit self parameter. This is lazily + /// constructed by createImplicitParams. + ImplicitParamDecl *SelfDecl; + /// CmdDecl - Decl for the implicit _cmd parameter. This is lazily + /// constructed by createImplicitParams. + ImplicitParamDecl *CmdDecl; + + SelectorLocationsKind getSelLocsKind() const { + return (SelectorLocationsKind)SelLocsKind; + } + bool hasStandardSelLocs() const { + return getSelLocsKind() != SelLoc_NonStandard; + } + + /// \brief Get a pointer to the stored selector identifiers locations array. + /// No locations will be stored if HasStandardSelLocs is true. + SourceLocation *getStoredSelLocs() { + return reinterpret_cast<SourceLocation*>(getParams() + NumParams); + } + const SourceLocation *getStoredSelLocs() const { + return reinterpret_cast<const SourceLocation*>(getParams() + NumParams); + } + + /// \brief Get a pointer to the stored selector identifiers locations array. + /// No locations will be stored if HasStandardSelLocs is true. + ParmVarDecl **getParams() { + return reinterpret_cast<ParmVarDecl **>(ParamsAndSelLocs); + } + const ParmVarDecl *const *getParams() const { + return reinterpret_cast<const ParmVarDecl *const *>(ParamsAndSelLocs); + } + + /// \brief Get the number of stored selector identifiers locations. + /// No locations will be stored if HasStandardSelLocs is true. + unsigned getNumStoredSelLocs() const { + if (hasStandardSelLocs()) + return 0; + return getNumSelectorLocs(); + } + + void setParamsAndSelLocs(ASTContext &C, + ArrayRef<ParmVarDecl*> Params, + ArrayRef<SourceLocation> SelLocs); + + ObjCMethodDecl(SourceLocation beginLoc, SourceLocation endLoc, + Selector SelInfo, QualType T, TypeSourceInfo *ReturnTInfo, + DeclContext *contextDecl, bool isInstance = true, + bool isVariadic = false, bool isPropertyAccessor = false, + bool isImplicitlyDeclared = false, bool isDefined = false, + ImplementationControl impControl = None, + bool HasRelatedResultType = false) + : NamedDecl(ObjCMethod, contextDecl, beginLoc, SelInfo), + DeclContext(ObjCMethod), Family(InvalidObjCMethodFamily), + IsInstance(isInstance), IsVariadic(isVariadic), + IsPropertyAccessor(isPropertyAccessor), IsDefined(isDefined), + IsRedeclaration(0), HasRedeclaration(0), DeclImplementation(impControl), + objcDeclQualifier(OBJC_TQ_None), + RelatedResultType(HasRelatedResultType), + SelLocsKind(SelLoc_StandardNoSpace), IsOverriding(0), HasSkippedBody(0), + MethodDeclType(T), ReturnTInfo(ReturnTInfo), ParamsAndSelLocs(nullptr), + NumParams(0), DeclEndLoc(endLoc), Body(), SelfDecl(nullptr), + CmdDecl(nullptr) { + setImplicit(isImplicitlyDeclared); + } + + /// \brief A definition will return its interface declaration. + /// An interface declaration will return its definition. + /// Otherwise it will return itself. + ObjCMethodDecl *getNextRedeclarationImpl() override; + +public: + static ObjCMethodDecl * + Create(ASTContext &C, SourceLocation beginLoc, SourceLocation endLoc, + Selector SelInfo, QualType T, TypeSourceInfo *ReturnTInfo, + DeclContext *contextDecl, bool isInstance = true, + bool isVariadic = false, bool isPropertyAccessor = false, + bool isImplicitlyDeclared = false, bool isDefined = false, + ImplementationControl impControl = None, + bool HasRelatedResultType = false); + + static ObjCMethodDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + ObjCMethodDecl *getCanonicalDecl() override; + const ObjCMethodDecl *getCanonicalDecl() const { + return const_cast<ObjCMethodDecl*>(this)->getCanonicalDecl(); + } + + ObjCDeclQualifier getObjCDeclQualifier() const { + return ObjCDeclQualifier(objcDeclQualifier); + } + void setObjCDeclQualifier(ObjCDeclQualifier QV) { objcDeclQualifier = QV; } + + /// \brief Determine whether this method has a result type that is related + /// to the message receiver's type. + bool hasRelatedResultType() const { return RelatedResultType; } + + /// \brief Note whether this method has a related result type. + void SetRelatedResultType(bool RRT = true) { RelatedResultType = RRT; } + + /// \brief True if this is a method redeclaration in the same interface. + bool isRedeclaration() const { return IsRedeclaration; } + void setAsRedeclaration(const ObjCMethodDecl *PrevMethod); + + /// \brief Returns the location where the declarator ends. It will be + /// the location of ';' for a method declaration and the location of '{' + /// for a method definition. + SourceLocation getDeclaratorEndLoc() const { return DeclEndLoc; } + + // Location information, modeled after the Stmt API. + SourceLocation getLocStart() const LLVM_READONLY { return getLocation(); } + SourceLocation getLocEnd() const LLVM_READONLY; + SourceRange getSourceRange() const override LLVM_READONLY { + return SourceRange(getLocation(), getLocEnd()); + } + + SourceLocation getSelectorStartLoc() const { + if (isImplicit()) + return getLocStart(); + return getSelectorLoc(0); + } + SourceLocation getSelectorLoc(unsigned Index) const { + assert(Index < getNumSelectorLocs() && "Index out of range!"); + if (hasStandardSelLocs()) + return getStandardSelectorLoc(Index, getSelector(), + getSelLocsKind() == SelLoc_StandardWithSpace, + parameters(), + DeclEndLoc); + return getStoredSelLocs()[Index]; + } + + void getSelectorLocs(SmallVectorImpl<SourceLocation> &SelLocs) const; + + unsigned getNumSelectorLocs() const { + if (isImplicit()) + return 0; + Selector Sel = getSelector(); + if (Sel.isUnarySelector()) + return 1; + return Sel.getNumArgs(); + } + + ObjCInterfaceDecl *getClassInterface(); + const ObjCInterfaceDecl *getClassInterface() const { + return const_cast<ObjCMethodDecl*>(this)->getClassInterface(); + } + + Selector getSelector() const { return getDeclName().getObjCSelector(); } + + QualType getReturnType() const { return MethodDeclType; } + void setReturnType(QualType T) { MethodDeclType = T; } + SourceRange getReturnTypeSourceRange() const; + + /// \brief Determine the type of an expression that sends a message to this + /// function. This replaces the type parameters with the types they would + /// get if the receiver was parameterless (e.g. it may replace the type + /// parameter with 'id'). + QualType getSendResultType() const; + + /// Determine the type of an expression that sends a message to this + /// function with the given receiver type. + QualType getSendResultType(QualType receiverType) const; + + TypeSourceInfo *getReturnTypeSourceInfo() const { return ReturnTInfo; } + void setReturnTypeSourceInfo(TypeSourceInfo *TInfo) { ReturnTInfo = TInfo; } + + // Iterator access to formal parameters. + unsigned param_size() const { return NumParams; } + typedef const ParmVarDecl *const *param_const_iterator; + typedef ParmVarDecl *const *param_iterator; + typedef llvm::iterator_range<param_iterator> param_range; + typedef llvm::iterator_range<param_const_iterator> param_const_range; + + param_range params() { return param_range(param_begin(), param_end()); } + param_const_range params() const { + return param_const_range(param_begin(), param_end()); + } + + param_const_iterator param_begin() const { + return param_const_iterator(getParams()); + } + param_const_iterator param_end() const { + return param_const_iterator(getParams() + NumParams); + } + param_iterator param_begin() { return param_iterator(getParams()); } + param_iterator param_end() { return param_iterator(getParams() + NumParams); } + + // This method returns and of the parameters which are part of the selector + // name mangling requirements. + param_const_iterator sel_param_end() const { + return param_begin() + getSelector().getNumArgs(); + } + + // ArrayRef access to formal parameters. This should eventually + // replace the iterator interface above. + ArrayRef<ParmVarDecl*> parameters() const { + return llvm::makeArrayRef(const_cast<ParmVarDecl**>(getParams()), + NumParams); + } + + /// \brief Sets the method's parameters and selector source locations. + /// If the method is implicit (not coming from source) \p SelLocs is + /// ignored. + void setMethodParams(ASTContext &C, + ArrayRef<ParmVarDecl*> Params, + ArrayRef<SourceLocation> SelLocs = llvm::None); + + // Iterator access to parameter types. + typedef std::const_mem_fun_t<QualType, ParmVarDecl> deref_fun; + typedef llvm::mapped_iterator<param_const_iterator, deref_fun> + param_type_iterator; + + param_type_iterator param_type_begin() const { + return llvm::map_iterator(param_begin(), deref_fun(&ParmVarDecl::getType)); + } + param_type_iterator param_type_end() const { + return llvm::map_iterator(param_end(), deref_fun(&ParmVarDecl::getType)); + } + + /// createImplicitParams - Used to lazily create the self and cmd + /// implict parameters. This must be called prior to using getSelfDecl() + /// or getCmdDecl(). The call is ignored if the implicit paramters + /// have already been created. + void createImplicitParams(ASTContext &Context, const ObjCInterfaceDecl *ID); + + /// \return the type for \c self and set \arg selfIsPseudoStrong and + /// \arg selfIsConsumed accordingly. + QualType getSelfType(ASTContext &Context, const ObjCInterfaceDecl *OID, + bool &selfIsPseudoStrong, bool &selfIsConsumed); + + ImplicitParamDecl * getSelfDecl() const { return SelfDecl; } + void setSelfDecl(ImplicitParamDecl *SD) { SelfDecl = SD; } + ImplicitParamDecl * getCmdDecl() const { return CmdDecl; } + void setCmdDecl(ImplicitParamDecl *CD) { CmdDecl = CD; } + + /// Determines the family of this method. + ObjCMethodFamily getMethodFamily() const; + + bool isInstanceMethod() const { return IsInstance; } + void setInstanceMethod(bool isInst) { IsInstance = isInst; } + bool isVariadic() const { return IsVariadic; } + void setVariadic(bool isVar) { IsVariadic = isVar; } + + bool isClassMethod() const { return !IsInstance; } + + bool isPropertyAccessor() const { return IsPropertyAccessor; } + void setPropertyAccessor(bool isAccessor) { IsPropertyAccessor = isAccessor; } + + bool isDefined() const { return IsDefined; } + void setDefined(bool isDefined) { IsDefined = isDefined; } + + /// \brief Whether this method overrides any other in the class hierarchy. + /// + /// A method is said to override any method in the class's + /// base classes, its protocols, or its categories' protocols, that has + /// the same selector and is of the same kind (class or instance). + /// A method in an implementation is not considered as overriding the same + /// method in the interface or its categories. + bool isOverriding() const { return IsOverriding; } + void setOverriding(bool isOverriding) { IsOverriding = isOverriding; } + + /// \brief Return overridden methods for the given \p Method. + /// + /// An ObjC method is considered to override any method in the class's + /// base classes (and base's categories), its protocols, or its categories' + /// protocols, that has + /// the same selector and is of the same kind (class or instance). + /// A method in an implementation is not considered as overriding the same + /// method in the interface or its categories. + void getOverriddenMethods( + SmallVectorImpl<const ObjCMethodDecl *> &Overridden) const; + + /// \brief True if the method was a definition but its body was skipped. + bool hasSkippedBody() const { return HasSkippedBody; } + void setHasSkippedBody(bool Skipped = true) { HasSkippedBody = Skipped; } + + /// \brief Returns the property associated with this method's selector. + /// + /// Note that even if this particular method is not marked as a property + /// accessor, it is still possible for it to match a property declared in a + /// superclass. Pass \c false if you only want to check the current class. + const ObjCPropertyDecl *findPropertyDecl(bool CheckOverrides = true) const; + + // Related to protocols declared in \@protocol + void setDeclImplementation(ImplementationControl ic) { + DeclImplementation = ic; + } + ImplementationControl getImplementationControl() const { + return ImplementationControl(DeclImplementation); + } + + /// Returns true if this specific method declaration is marked with the + /// designated initializer attribute. + bool isThisDeclarationADesignatedInitializer() const; + + /// Returns true if the method selector resolves to a designated initializer + /// in the class's interface. + /// + /// \param InitMethod if non-null and the function returns true, it receives + /// the method declaration that was marked with the designated initializer + /// attribute. + bool isDesignatedInitializerForTheInterface( + const ObjCMethodDecl **InitMethod = nullptr) const; + + /// \brief Determine whether this method has a body. + bool hasBody() const override { return Body.isValid(); } + + /// \brief Retrieve the body of this method, if it has one. + Stmt *getBody() const override; + + void setLazyBody(uint64_t Offset) { Body = Offset; } + + CompoundStmt *getCompoundBody() { return (CompoundStmt*)getBody(); } + void setBody(Stmt *B) { Body = B; } + + /// \brief Returns whether this specific method is a definition. + bool isThisDeclarationADefinition() const { return hasBody(); } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == ObjCMethod; } + static DeclContext *castToDeclContext(const ObjCMethodDecl *D) { + return static_cast<DeclContext *>(const_cast<ObjCMethodDecl*>(D)); + } + static ObjCMethodDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<ObjCMethodDecl *>(const_cast<DeclContext*>(DC)); + } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// Describes the variance of a given generic parameter. +enum class ObjCTypeParamVariance : uint8_t { + /// The parameter is invariant: must match exactly. + Invariant, + /// The parameter is covariant, e.g., X<T> is a subtype of X<U> when + /// the type parameter is covariant and T is a subtype of U. + Covariant, + /// The parameter is contravariant, e.g., X<T> is a subtype of X<U> + /// when the type parameter is covariant and U is a subtype of T. + Contravariant, +}; + +/// Represents the declaration of an Objective-C type parameter. +/// +/// \code +/// @interface NSDictionary<Key : id<NSCopying>, Value> +/// @end +/// \endcode +/// +/// In the example above, both \c Key and \c Value are represented by +/// \c ObjCTypeParamDecl. \c Key has an explicit bound of \c id<NSCopying>, +/// while \c Value gets an implicit bound of \c id. +/// +/// Objective-C type parameters are typedef-names in the grammar, +class ObjCTypeParamDecl : public TypedefNameDecl { + void anchor() override; + + /// Index of this type parameter in the type parameter list. + unsigned Index : 14; + + /// The variance of the type parameter. + unsigned Variance : 2; + + /// The location of the variance, if any. + SourceLocation VarianceLoc; + + /// The location of the ':', which will be valid when the bound was + /// explicitly specified. + SourceLocation ColonLoc; + + ObjCTypeParamDecl(ASTContext &ctx, DeclContext *dc, + ObjCTypeParamVariance variance, SourceLocation varianceLoc, + unsigned index, + SourceLocation nameLoc, IdentifierInfo *name, + SourceLocation colonLoc, TypeSourceInfo *boundInfo) + : TypedefNameDecl(ObjCTypeParam, ctx, dc, nameLoc, nameLoc, name, + boundInfo), + Index(index), Variance(static_cast<unsigned>(variance)), + VarianceLoc(varianceLoc), ColonLoc(colonLoc) { } + +public: + static ObjCTypeParamDecl *Create(ASTContext &ctx, DeclContext *dc, + ObjCTypeParamVariance variance, + SourceLocation varianceLoc, + unsigned index, + SourceLocation nameLoc, + IdentifierInfo *name, + SourceLocation colonLoc, + TypeSourceInfo *boundInfo); + static ObjCTypeParamDecl *CreateDeserialized(ASTContext &ctx, unsigned ID); + + SourceRange getSourceRange() const override LLVM_READONLY; + + /// Determine the variance of this type parameter. + ObjCTypeParamVariance getVariance() const { + return static_cast<ObjCTypeParamVariance>(Variance); + } + + /// Set the variance of this type parameter. + void setVariance(ObjCTypeParamVariance variance) { + Variance = static_cast<unsigned>(variance); + } + + /// Retrieve the location of the variance keyword. + SourceLocation getVarianceLoc() const { return VarianceLoc; } + + /// Retrieve the index into its type parameter list. + unsigned getIndex() const { return Index; } + + /// Whether this type parameter has an explicitly-written type bound, e.g., + /// "T : NSView". + bool hasExplicitBound() const { return ColonLoc.isValid(); } + + /// Retrieve the location of the ':' separating the type parameter name + /// from the explicitly-specified bound. + SourceLocation getColonLoc() const { return ColonLoc; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == ObjCTypeParam; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// Stores a list of Objective-C type parameters for a parameterized class +/// or a category/extension thereof. +/// +/// \code +/// @interface NSArray<T> // stores the <T> +/// @end +/// \endcode +class ObjCTypeParamList final + : private llvm::TrailingObjects<ObjCTypeParamList, ObjCTypeParamDecl *> { + /// Stores the components of a SourceRange as a POD. + struct PODSourceRange { + unsigned Begin; + unsigned End; + }; + + union { + /// Location of the left and right angle brackets. + PODSourceRange Brackets; + + // Used only for alignment. + ObjCTypeParamDecl *AlignmentHack; + }; + + /// The number of parameters in the list, which are tail-allocated. + unsigned NumParams; + + ObjCTypeParamList(SourceLocation lAngleLoc, + ArrayRef<ObjCTypeParamDecl *> typeParams, + SourceLocation rAngleLoc); + +public: + /// Create a new Objective-C type parameter list. + static ObjCTypeParamList *create(ASTContext &ctx, + SourceLocation lAngleLoc, + ArrayRef<ObjCTypeParamDecl *> typeParams, + SourceLocation rAngleLoc); + + /// Iterate through the type parameters in the list. + typedef ObjCTypeParamDecl **iterator; + + iterator begin() { return getTrailingObjects<ObjCTypeParamDecl *>(); } + + iterator end() { return begin() + size(); } + + /// Determine the number of type parameters in this list. + unsigned size() const { return NumParams; } + + // Iterate through the type parameters in the list. + typedef ObjCTypeParamDecl * const *const_iterator; + + const_iterator begin() const { + return getTrailingObjects<ObjCTypeParamDecl *>(); + } + + const_iterator end() const { + return begin() + size(); + } + + ObjCTypeParamDecl *front() const { + assert(size() > 0 && "empty Objective-C type parameter list"); + return *begin(); + } + + ObjCTypeParamDecl *back() const { + assert(size() > 0 && "empty Objective-C type parameter list"); + return *(end() - 1); + } + + SourceLocation getLAngleLoc() const { + return SourceLocation::getFromRawEncoding(Brackets.Begin); + } + SourceLocation getRAngleLoc() const { + return SourceLocation::getFromRawEncoding(Brackets.End); + } + SourceRange getSourceRange() const { + return SourceRange(getLAngleLoc(), getRAngleLoc()); + } + + /// Gather the default set of type arguments to be substituted for + /// these type parameters when dealing with an unspecialized type. + void gatherDefaultTypeArgs(SmallVectorImpl<QualType> &typeArgs) const; + friend TrailingObjects; +}; + +/// ObjCContainerDecl - Represents a container for method declarations. +/// Current sub-classes are ObjCInterfaceDecl, ObjCCategoryDecl, +/// ObjCProtocolDecl, and ObjCImplDecl. +/// +class ObjCContainerDecl : public NamedDecl, public DeclContext { + void anchor() override; + + SourceLocation AtStart; + + // These two locations in the range mark the end of the method container. + // The first points to the '@' token, and the second to the 'end' token. + SourceRange AtEnd; +public: + + ObjCContainerDecl(Kind DK, DeclContext *DC, + IdentifierInfo *Id, SourceLocation nameLoc, + SourceLocation atStartLoc) + : NamedDecl(DK, DC, nameLoc, Id), DeclContext(DK), AtStart(atStartLoc) {} + + // Iterator access to properties. + typedef specific_decl_iterator<ObjCPropertyDecl> prop_iterator; + typedef llvm::iterator_range<specific_decl_iterator<ObjCPropertyDecl>> + prop_range; + + prop_range properties() const { return prop_range(prop_begin(), prop_end()); } + prop_iterator prop_begin() const { + return prop_iterator(decls_begin()); + } + prop_iterator prop_end() const { + return prop_iterator(decls_end()); + } + + // Iterator access to instance/class methods. + typedef specific_decl_iterator<ObjCMethodDecl> method_iterator; + typedef llvm::iterator_range<specific_decl_iterator<ObjCMethodDecl>> + method_range; + + method_range methods() const { + return method_range(meth_begin(), meth_end()); + } + method_iterator meth_begin() const { + return method_iterator(decls_begin()); + } + method_iterator meth_end() const { + return method_iterator(decls_end()); + } + + typedef filtered_decl_iterator<ObjCMethodDecl, + &ObjCMethodDecl::isInstanceMethod> + instmeth_iterator; + typedef llvm::iterator_range<instmeth_iterator> instmeth_range; + + instmeth_range instance_methods() const { + return instmeth_range(instmeth_begin(), instmeth_end()); + } + instmeth_iterator instmeth_begin() const { + return instmeth_iterator(decls_begin()); + } + instmeth_iterator instmeth_end() const { + return instmeth_iterator(decls_end()); + } + + typedef filtered_decl_iterator<ObjCMethodDecl, + &ObjCMethodDecl::isClassMethod> + classmeth_iterator; + typedef llvm::iterator_range<classmeth_iterator> classmeth_range; + + classmeth_range class_methods() const { + return classmeth_range(classmeth_begin(), classmeth_end()); + } + classmeth_iterator classmeth_begin() const { + return classmeth_iterator(decls_begin()); + } + classmeth_iterator classmeth_end() const { + return classmeth_iterator(decls_end()); + } + + // Get the local instance/class method declared in this interface. + ObjCMethodDecl *getMethod(Selector Sel, bool isInstance, + bool AllowHidden = false) const; + ObjCMethodDecl *getInstanceMethod(Selector Sel, + bool AllowHidden = false) const { + return getMethod(Sel, true/*isInstance*/, AllowHidden); + } + ObjCMethodDecl *getClassMethod(Selector Sel, bool AllowHidden = false) const { + return getMethod(Sel, false/*isInstance*/, AllowHidden); + } + bool HasUserDeclaredSetterMethod(const ObjCPropertyDecl *P) const; + ObjCIvarDecl *getIvarDecl(IdentifierInfo *Id) const; + + ObjCPropertyDecl * + FindPropertyDeclaration(const IdentifierInfo *PropertyId) const; + + typedef llvm::DenseMap<IdentifierInfo*, ObjCPropertyDecl*> PropertyMap; + + typedef llvm::DenseMap<const ObjCProtocolDecl *, ObjCPropertyDecl*> + ProtocolPropertyMap; + + typedef llvm::SmallVector<ObjCPropertyDecl*, 8> PropertyDeclOrder; + + /// This routine collects list of properties to be implemented in the class. + /// This includes, class's and its conforming protocols' properties. + /// Note, the superclass's properties are not included in the list. + virtual void collectPropertiesToImplement(PropertyMap &PM, + PropertyDeclOrder &PO) const {} + + SourceLocation getAtStartLoc() const { return AtStart; } + void setAtStartLoc(SourceLocation Loc) { AtStart = Loc; } + + // Marks the end of the container. + SourceRange getAtEndRange() const { + return AtEnd; + } + void setAtEndRange(SourceRange atEnd) { + AtEnd = atEnd; + } + + SourceRange getSourceRange() const override LLVM_READONLY { + return SourceRange(AtStart, getAtEndRange().getEnd()); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { + return K >= firstObjCContainer && + K <= lastObjCContainer; + } + + static DeclContext *castToDeclContext(const ObjCContainerDecl *D) { + return static_cast<DeclContext *>(const_cast<ObjCContainerDecl*>(D)); + } + static ObjCContainerDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<ObjCContainerDecl *>(const_cast<DeclContext*>(DC)); + } +}; + +/// \brief Represents an ObjC class declaration. +/// +/// For example: +/// +/// \code +/// // MostPrimitive declares no super class (not particularly useful). +/// \@interface MostPrimitive +/// // no instance variables or methods. +/// \@end +/// +/// // NSResponder inherits from NSObject & implements NSCoding (a protocol). +/// \@interface NSResponder : NSObject \<NSCoding> +/// { // instance variables are represented by ObjCIvarDecl. +/// id nextResponder; // nextResponder instance variable. +/// } +/// - (NSResponder *)nextResponder; // return a pointer to NSResponder. +/// - (void)mouseMoved:(NSEvent *)theEvent; // return void, takes a pointer +/// \@end // to an NSEvent. +/// \endcode +/// +/// Unlike C/C++, forward class declarations are accomplished with \@class. +/// Unlike C/C++, \@class allows for a list of classes to be forward declared. +/// Unlike C++, ObjC is a single-rooted class model. In Cocoa, classes +/// typically inherit from NSObject (an exception is NSProxy). +/// +class ObjCInterfaceDecl : public ObjCContainerDecl + , public Redeclarable<ObjCInterfaceDecl> { + void anchor() override; + + /// TypeForDecl - This indicates the Type object that represents this + /// TypeDecl. It is a cache maintained by ASTContext::getObjCInterfaceType + mutable const Type *TypeForDecl; + friend class ASTContext; + + struct DefinitionData { + /// \brief The definition of this class, for quick access from any + /// declaration. + ObjCInterfaceDecl *Definition; + + /// When non-null, this is always an ObjCObjectType. + TypeSourceInfo *SuperClassTInfo; + + /// Protocols referenced in the \@interface declaration + ObjCProtocolList ReferencedProtocols; + + /// Protocols reference in both the \@interface and class extensions. + ObjCList<ObjCProtocolDecl> AllReferencedProtocols; + + /// \brief List of categories and class extensions defined for this class. + /// + /// Categories are stored as a linked list in the AST, since the categories + /// and class extensions come long after the initial interface declaration, + /// and we avoid dynamically-resized arrays in the AST wherever possible. + ObjCCategoryDecl *CategoryList; + + /// IvarList - List of all ivars defined by this class; including class + /// extensions and implementation. This list is built lazily. + ObjCIvarDecl *IvarList; + + /// \brief Indicates that the contents of this Objective-C class will be + /// completed by the external AST source when required. + mutable bool ExternallyCompleted : 1; + + /// \brief Indicates that the ivar cache does not yet include ivars + /// declared in the implementation. + mutable bool IvarListMissingImplementation : 1; + + /// Indicates that this interface decl contains at least one initializer + /// marked with the 'objc_designated_initializer' attribute. + bool HasDesignatedInitializers : 1; + + enum InheritedDesignatedInitializersState { + /// We didn't calculate whether the designated initializers should be + /// inherited or not. + IDI_Unknown = 0, + /// Designated initializers are inherited for the super class. + IDI_Inherited = 1, + /// The class does not inherit designated initializers. + IDI_NotInherited = 2 + }; + /// One of the \c InheritedDesignatedInitializersState enumeratos. + mutable unsigned InheritedDesignatedInitializers : 2; + + /// \brief The location of the last location in this declaration, before + /// the properties/methods. For example, this will be the '>', '}', or + /// identifier, + SourceLocation EndLoc; + + DefinitionData() : Definition(), SuperClassTInfo(), CategoryList(), IvarList(), + ExternallyCompleted(), + IvarListMissingImplementation(true), + HasDesignatedInitializers(), + InheritedDesignatedInitializers(IDI_Unknown) { } + }; + + ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC, SourceLocation AtLoc, + IdentifierInfo *Id, ObjCTypeParamList *typeParamList, + SourceLocation CLoc, ObjCInterfaceDecl *PrevDecl, + bool IsInternal); + + void LoadExternalDefinition() const; + + /// The type parameters associated with this class, if any. + ObjCTypeParamList *TypeParamList; + + /// \brief Contains a pointer to the data associated with this class, + /// which will be NULL if this class has not yet been defined. + /// + /// The bit indicates when we don't need to check for out-of-date + /// declarations. It will be set unless modules are enabled. + llvm::PointerIntPair<DefinitionData *, 1, bool> Data; + + DefinitionData &data() const { + assert(Data.getPointer() && "Declaration has no definition!"); + return *Data.getPointer(); + } + + /// \brief Allocate the definition data for this class. + void allocateDefinitionData(); + + typedef Redeclarable<ObjCInterfaceDecl> redeclarable_base; + ObjCInterfaceDecl *getNextRedeclarationImpl() override { + return getNextRedeclaration(); + } + ObjCInterfaceDecl *getPreviousDeclImpl() override { + return getPreviousDecl(); + } + ObjCInterfaceDecl *getMostRecentDeclImpl() override { + return getMostRecentDecl(); + } + +public: + static ObjCInterfaceDecl *Create(const ASTContext &C, DeclContext *DC, + SourceLocation atLoc, + IdentifierInfo *Id, + ObjCTypeParamList *typeParamList, + ObjCInterfaceDecl *PrevDecl, + SourceLocation ClassLoc = SourceLocation(), + bool isInternal = false); + + static ObjCInterfaceDecl *CreateDeserialized(const ASTContext &C, unsigned ID); + + /// Retrieve the type parameters of this class. + /// + /// This function looks for a type parameter list for the given + /// class; if the class has been declared (with \c \@class) but not + /// defined (with \c \@interface), it will search for a declaration that + /// has type parameters, skipping any declarations that do not. + ObjCTypeParamList *getTypeParamList() const; + + /// Set the type parameters of this class. + /// + /// This function is used by the AST importer, which must import the type + /// parameters after creating their DeclContext to avoid loops. + void setTypeParamList(ObjCTypeParamList *TPL); + + /// Retrieve the type parameters written on this particular declaration of + /// the class. + ObjCTypeParamList *getTypeParamListAsWritten() const { + return TypeParamList; + } + + SourceRange getSourceRange() const override LLVM_READONLY { + if (isThisDeclarationADefinition()) + return ObjCContainerDecl::getSourceRange(); + + return SourceRange(getAtStartLoc(), getLocation()); + } + + /// \brief Indicate that this Objective-C class is complete, but that + /// the external AST source will be responsible for filling in its contents + /// when a complete class is required. + void setExternallyCompleted(); + + /// Indicate that this interface decl contains at least one initializer + /// marked with the 'objc_designated_initializer' attribute. + void setHasDesignatedInitializers(); + + /// Returns true if this interface decl contains at least one initializer + /// marked with the 'objc_designated_initializer' attribute. + bool hasDesignatedInitializers() const; + + /// Returns true if this interface decl declares a designated initializer + /// or it inherites one from its super class. + bool declaresOrInheritsDesignatedInitializers() const { + return hasDesignatedInitializers() || inheritsDesignatedInitializers(); + } + + const ObjCProtocolList &getReferencedProtocols() const { + assert(hasDefinition() && "Caller did not check for forward reference!"); + if (data().ExternallyCompleted) + LoadExternalDefinition(); + + return data().ReferencedProtocols; + } + + ObjCImplementationDecl *getImplementation() const; + void setImplementation(ObjCImplementationDecl *ImplD); + + ObjCCategoryDecl *FindCategoryDeclaration(IdentifierInfo *CategoryId) const; + + // Get the local instance/class method declared in a category. + ObjCMethodDecl *getCategoryInstanceMethod(Selector Sel) const; + ObjCMethodDecl *getCategoryClassMethod(Selector Sel) const; + ObjCMethodDecl *getCategoryMethod(Selector Sel, bool isInstance) const { + return isInstance ? getCategoryInstanceMethod(Sel) + : getCategoryClassMethod(Sel); + } + + typedef ObjCProtocolList::iterator protocol_iterator; + typedef llvm::iterator_range<protocol_iterator> protocol_range; + + protocol_range protocols() const { + return protocol_range(protocol_begin(), protocol_end()); + } + protocol_iterator protocol_begin() const { + // FIXME: Should make sure no callers ever do this. + if (!hasDefinition()) + return protocol_iterator(); + + if (data().ExternallyCompleted) + LoadExternalDefinition(); + + return data().ReferencedProtocols.begin(); + } + protocol_iterator protocol_end() const { + // FIXME: Should make sure no callers ever do this. + if (!hasDefinition()) + return protocol_iterator(); + + if (data().ExternallyCompleted) + LoadExternalDefinition(); + + return data().ReferencedProtocols.end(); + } + + typedef ObjCProtocolList::loc_iterator protocol_loc_iterator; + typedef llvm::iterator_range<protocol_loc_iterator> protocol_loc_range; + + protocol_loc_range protocol_locs() const { + return protocol_loc_range(protocol_loc_begin(), protocol_loc_end()); + } + protocol_loc_iterator protocol_loc_begin() const { + // FIXME: Should make sure no callers ever do this. + if (!hasDefinition()) + return protocol_loc_iterator(); + + if (data().ExternallyCompleted) + LoadExternalDefinition(); + + return data().ReferencedProtocols.loc_begin(); + } + + protocol_loc_iterator protocol_loc_end() const { + // FIXME: Should make sure no callers ever do this. + if (!hasDefinition()) + return protocol_loc_iterator(); + + if (data().ExternallyCompleted) + LoadExternalDefinition(); + + return data().ReferencedProtocols.loc_end(); + } + + typedef ObjCList<ObjCProtocolDecl>::iterator all_protocol_iterator; + typedef llvm::iterator_range<all_protocol_iterator> all_protocol_range; + + all_protocol_range all_referenced_protocols() const { + return all_protocol_range(all_referenced_protocol_begin(), + all_referenced_protocol_end()); + } + all_protocol_iterator all_referenced_protocol_begin() const { + // FIXME: Should make sure no callers ever do this. + if (!hasDefinition()) + return all_protocol_iterator(); + + if (data().ExternallyCompleted) + LoadExternalDefinition(); + + return data().AllReferencedProtocols.empty() + ? protocol_begin() + : data().AllReferencedProtocols.begin(); + } + all_protocol_iterator all_referenced_protocol_end() const { + // FIXME: Should make sure no callers ever do this. + if (!hasDefinition()) + return all_protocol_iterator(); + + if (data().ExternallyCompleted) + LoadExternalDefinition(); + + return data().AllReferencedProtocols.empty() + ? protocol_end() + : data().AllReferencedProtocols.end(); + } + + typedef specific_decl_iterator<ObjCIvarDecl> ivar_iterator; + typedef llvm::iterator_range<specific_decl_iterator<ObjCIvarDecl>> ivar_range; + + ivar_range ivars() const { return ivar_range(ivar_begin(), ivar_end()); } + ivar_iterator ivar_begin() const { + if (const ObjCInterfaceDecl *Def = getDefinition()) + return ivar_iterator(Def->decls_begin()); + + // FIXME: Should make sure no callers ever do this. + return ivar_iterator(); + } + ivar_iterator ivar_end() const { + if (const ObjCInterfaceDecl *Def = getDefinition()) + return ivar_iterator(Def->decls_end()); + + // FIXME: Should make sure no callers ever do this. + return ivar_iterator(); + } + + unsigned ivar_size() const { + return std::distance(ivar_begin(), ivar_end()); + } + + bool ivar_empty() const { return ivar_begin() == ivar_end(); } + + ObjCIvarDecl *all_declared_ivar_begin(); + const ObjCIvarDecl *all_declared_ivar_begin() const { + // Even though this modifies IvarList, it's conceptually const: + // the ivar chain is essentially a cached property of ObjCInterfaceDecl. + return const_cast<ObjCInterfaceDecl *>(this)->all_declared_ivar_begin(); + } + void setIvarList(ObjCIvarDecl *ivar) { data().IvarList = ivar; } + + /// setProtocolList - Set the list of protocols that this interface + /// implements. + void setProtocolList(ObjCProtocolDecl *const* List, unsigned Num, + const SourceLocation *Locs, ASTContext &C) { + data().ReferencedProtocols.set(List, Num, Locs, C); + } + + /// mergeClassExtensionProtocolList - Merge class extension's protocol list + /// into the protocol list for this class. + void mergeClassExtensionProtocolList(ObjCProtocolDecl *const* List, + unsigned Num, + ASTContext &C); + + /// Produce a name to be used for class's metadata. It comes either via + /// objc_runtime_name attribute or class name. + StringRef getObjCRuntimeNameAsString() const; + + /// Returns the designated initializers for the interface. + /// + /// If this declaration does not have methods marked as designated + /// initializers then the interface inherits the designated initializers of + /// its super class. + void getDesignatedInitializers( + llvm::SmallVectorImpl<const ObjCMethodDecl *> &Methods) const; + + /// Returns true if the given selector is a designated initializer for the + /// interface. + /// + /// If this declaration does not have methods marked as designated + /// initializers then the interface inherits the designated initializers of + /// its super class. + /// + /// \param InitMethod if non-null and the function returns true, it receives + /// the method that was marked as a designated initializer. + bool + isDesignatedInitializer(Selector Sel, + const ObjCMethodDecl **InitMethod = nullptr) const; + + /// \brief Determine whether this particular declaration of this class is + /// actually also a definition. + bool isThisDeclarationADefinition() const { + return getDefinition() == this; + } + + /// \brief Determine whether this class has been defined. + bool hasDefinition() const { + // If the name of this class is out-of-date, bring it up-to-date, which + // might bring in a definition. + // Note: a null value indicates that we don't have a definition and that + // modules are enabled. + if (!Data.getOpaqueValue()) + getMostRecentDecl(); + + return Data.getPointer(); + } + + /// \brief Retrieve the definition of this class, or NULL if this class + /// has been forward-declared (with \@class) but not yet defined (with + /// \@interface). + ObjCInterfaceDecl *getDefinition() { + return hasDefinition()? Data.getPointer()->Definition : nullptr; + } + + /// \brief Retrieve the definition of this class, or NULL if this class + /// has been forward-declared (with \@class) but not yet defined (with + /// \@interface). + const ObjCInterfaceDecl *getDefinition() const { + return hasDefinition()? Data.getPointer()->Definition : nullptr; + } + + /// \brief Starts the definition of this Objective-C class, taking it from + /// a forward declaration (\@class) to a definition (\@interface). + void startDefinition(); + + /// Retrieve the superclass type. + const ObjCObjectType *getSuperClassType() const { + if (TypeSourceInfo *TInfo = getSuperClassTInfo()) + return TInfo->getType()->castAs<ObjCObjectType>(); + + return nullptr; + } + + // Retrieve the type source information for the superclass. + TypeSourceInfo *getSuperClassTInfo() const { + // FIXME: Should make sure no callers ever do this. + if (!hasDefinition()) + return nullptr; + + if (data().ExternallyCompleted) + LoadExternalDefinition(); + + return data().SuperClassTInfo; + } + + // Retrieve the declaration for the superclass of this class, which + // does not include any type arguments that apply to the superclass. + ObjCInterfaceDecl *getSuperClass() const; + + void setSuperClass(TypeSourceInfo *superClass) { + data().SuperClassTInfo = superClass; + } + + /// \brief Iterator that walks over the list of categories, filtering out + /// those that do not meet specific criteria. + /// + /// This class template is used for the various permutations of category + /// and extension iterators. + template<bool (*Filter)(ObjCCategoryDecl *)> + class filtered_category_iterator { + ObjCCategoryDecl *Current; + + void findAcceptableCategory(); + + public: + typedef ObjCCategoryDecl * value_type; + typedef value_type reference; + typedef value_type pointer; + typedef std::ptrdiff_t difference_type; + typedef std::input_iterator_tag iterator_category; + + filtered_category_iterator() : Current(nullptr) { } + explicit filtered_category_iterator(ObjCCategoryDecl *Current) + : Current(Current) + { + findAcceptableCategory(); + } + + reference operator*() const { return Current; } + pointer operator->() const { return Current; } + + filtered_category_iterator &operator++(); + + filtered_category_iterator operator++(int) { + filtered_category_iterator Tmp = *this; + ++(*this); + return Tmp; + } + + friend bool operator==(filtered_category_iterator X, + filtered_category_iterator Y) { + return X.Current == Y.Current; + } + + friend bool operator!=(filtered_category_iterator X, + filtered_category_iterator Y) { + return X.Current != Y.Current; + } + }; + +private: + /// \brief Test whether the given category is visible. + /// + /// Used in the \c visible_categories_iterator. + static bool isVisibleCategory(ObjCCategoryDecl *Cat); + +public: + /// \brief Iterator that walks over the list of categories and extensions + /// that are visible, i.e., not hidden in a non-imported submodule. + typedef filtered_category_iterator<isVisibleCategory> + visible_categories_iterator; + + typedef llvm::iterator_range<visible_categories_iterator> + visible_categories_range; + + visible_categories_range visible_categories() const { + return visible_categories_range(visible_categories_begin(), + visible_categories_end()); + } + + /// \brief Retrieve an iterator to the beginning of the visible-categories + /// list. + visible_categories_iterator visible_categories_begin() const { + return visible_categories_iterator(getCategoryListRaw()); + } + + /// \brief Retrieve an iterator to the end of the visible-categories list. + visible_categories_iterator visible_categories_end() const { + return visible_categories_iterator(); + } + + /// \brief Determine whether the visible-categories list is empty. + bool visible_categories_empty() const { + return visible_categories_begin() == visible_categories_end(); + } + +private: + /// \brief Test whether the given category... is a category. + /// + /// Used in the \c known_categories_iterator. + static bool isKnownCategory(ObjCCategoryDecl *) { return true; } + +public: + /// \brief Iterator that walks over all of the known categories and + /// extensions, including those that are hidden. + typedef filtered_category_iterator<isKnownCategory> known_categories_iterator; + typedef llvm::iterator_range<known_categories_iterator> + known_categories_range; + + known_categories_range known_categories() const { + return known_categories_range(known_categories_begin(), + known_categories_end()); + } + + /// \brief Retrieve an iterator to the beginning of the known-categories + /// list. + known_categories_iterator known_categories_begin() const { + return known_categories_iterator(getCategoryListRaw()); + } + + /// \brief Retrieve an iterator to the end of the known-categories list. + known_categories_iterator known_categories_end() const { + return known_categories_iterator(); + } + + /// \brief Determine whether the known-categories list is empty. + bool known_categories_empty() const { + return known_categories_begin() == known_categories_end(); + } + +private: + /// \brief Test whether the given category is a visible extension. + /// + /// Used in the \c visible_extensions_iterator. + static bool isVisibleExtension(ObjCCategoryDecl *Cat); + +public: + /// \brief Iterator that walks over all of the visible extensions, skipping + /// any that are known but hidden. + typedef filtered_category_iterator<isVisibleExtension> + visible_extensions_iterator; + + typedef llvm::iterator_range<visible_extensions_iterator> + visible_extensions_range; + + visible_extensions_range visible_extensions() const { + return visible_extensions_range(visible_extensions_begin(), + visible_extensions_end()); + } + + /// \brief Retrieve an iterator to the beginning of the visible-extensions + /// list. + visible_extensions_iterator visible_extensions_begin() const { + return visible_extensions_iterator(getCategoryListRaw()); + } + + /// \brief Retrieve an iterator to the end of the visible-extensions list. + visible_extensions_iterator visible_extensions_end() const { + return visible_extensions_iterator(); + } + + /// \brief Determine whether the visible-extensions list is empty. + bool visible_extensions_empty() const { + return visible_extensions_begin() == visible_extensions_end(); + } + +private: + /// \brief Test whether the given category is an extension. + /// + /// Used in the \c known_extensions_iterator. + static bool isKnownExtension(ObjCCategoryDecl *Cat); + +public: + /// \brief Iterator that walks over all of the known extensions. + typedef filtered_category_iterator<isKnownExtension> + known_extensions_iterator; + typedef llvm::iterator_range<known_extensions_iterator> + known_extensions_range; + + known_extensions_range known_extensions() const { + return known_extensions_range(known_extensions_begin(), + known_extensions_end()); + } + + /// \brief Retrieve an iterator to the beginning of the known-extensions + /// list. + known_extensions_iterator known_extensions_begin() const { + return known_extensions_iterator(getCategoryListRaw()); + } + + /// \brief Retrieve an iterator to the end of the known-extensions list. + known_extensions_iterator known_extensions_end() const { + return known_extensions_iterator(); + } + + /// \brief Determine whether the known-extensions list is empty. + bool known_extensions_empty() const { + return known_extensions_begin() == known_extensions_end(); + } + + /// \brief Retrieve the raw pointer to the start of the category/extension + /// list. + ObjCCategoryDecl* getCategoryListRaw() const { + // FIXME: Should make sure no callers ever do this. + if (!hasDefinition()) + return nullptr; + + if (data().ExternallyCompleted) + LoadExternalDefinition(); + + return data().CategoryList; + } + + /// \brief Set the raw pointer to the start of the category/extension + /// list. + void setCategoryListRaw(ObjCCategoryDecl *category) { + data().CategoryList = category; + } + + ObjCPropertyDecl + *FindPropertyVisibleInPrimaryClass(IdentifierInfo *PropertyId) const; + + void collectPropertiesToImplement(PropertyMap &PM, + PropertyDeclOrder &PO) const override; + + /// isSuperClassOf - Return true if this class is the specified class or is a + /// super class of the specified interface class. + bool isSuperClassOf(const ObjCInterfaceDecl *I) const { + // If RHS is derived from LHS it is OK; else it is not OK. + while (I != nullptr) { + if (declaresSameEntity(this, I)) + return true; + + I = I->getSuperClass(); + } + return false; + } + + /// isArcWeakrefUnavailable - Checks for a class or one of its super classes + /// to be incompatible with __weak references. Returns true if it is. + bool isArcWeakrefUnavailable() const; + + /// isObjCRequiresPropertyDefs - Checks that a class or one of its super + /// classes must not be auto-synthesized. Returns class decl. if it must not + /// be; 0, otherwise. + const ObjCInterfaceDecl *isObjCRequiresPropertyDefs() const; + + ObjCIvarDecl *lookupInstanceVariable(IdentifierInfo *IVarName, + ObjCInterfaceDecl *&ClassDeclared); + ObjCIvarDecl *lookupInstanceVariable(IdentifierInfo *IVarName) { + ObjCInterfaceDecl *ClassDeclared; + return lookupInstanceVariable(IVarName, ClassDeclared); + } + + ObjCProtocolDecl *lookupNestedProtocol(IdentifierInfo *Name); + + // Lookup a method. First, we search locally. If a method isn't + // found, we search referenced protocols and class categories. + ObjCMethodDecl *lookupMethod(Selector Sel, bool isInstance, + bool shallowCategoryLookup = false, + bool followSuper = true, + const ObjCCategoryDecl *C = nullptr) const; + + /// Lookup an instance method for a given selector. + ObjCMethodDecl *lookupInstanceMethod(Selector Sel) const { + return lookupMethod(Sel, true/*isInstance*/); + } + + /// Lookup a class method for a given selector. + ObjCMethodDecl *lookupClassMethod(Selector Sel) const { + return lookupMethod(Sel, false/*isInstance*/); + } + ObjCInterfaceDecl *lookupInheritedClass(const IdentifierInfo *ICName); + + /// \brief Lookup a method in the classes implementation hierarchy. + ObjCMethodDecl *lookupPrivateMethod(const Selector &Sel, + bool Instance=true) const; + + ObjCMethodDecl *lookupPrivateClassMethod(const Selector &Sel) { + return lookupPrivateMethod(Sel, false); + } + + /// \brief Lookup a setter or getter in the class hierarchy, + /// including in all categories except for category passed + /// as argument. + ObjCMethodDecl *lookupPropertyAccessor(const Selector Sel, + const ObjCCategoryDecl *Cat) const { + return lookupMethod(Sel, true/*isInstance*/, + false/*shallowCategoryLookup*/, + true /* followsSuper */, + Cat); + } + + SourceLocation getEndOfDefinitionLoc() const { + if (!hasDefinition()) + return getLocation(); + + return data().EndLoc; + } + + void setEndOfDefinitionLoc(SourceLocation LE) { data().EndLoc = LE; } + + /// Retrieve the starting location of the superclass. + SourceLocation getSuperClassLoc() const; + + /// isImplicitInterfaceDecl - check that this is an implicitly declared + /// ObjCInterfaceDecl node. This is for legacy objective-c \@implementation + /// declaration without an \@interface declaration. + bool isImplicitInterfaceDecl() const { + return hasDefinition() ? data().Definition->isImplicit() : isImplicit(); + } + + /// ClassImplementsProtocol - Checks that 'lProto' protocol + /// has been implemented in IDecl class, its super class or categories (if + /// lookupCategory is true). + bool ClassImplementsProtocol(ObjCProtocolDecl *lProto, + bool lookupCategory, + bool RHSIsQualifiedID = false); + + typedef redeclarable_base::redecl_range redecl_range; + typedef redeclarable_base::redecl_iterator redecl_iterator; + using redeclarable_base::redecls_begin; + using redeclarable_base::redecls_end; + using redeclarable_base::redecls; + using redeclarable_base::getPreviousDecl; + using redeclarable_base::getMostRecentDecl; + using redeclarable_base::isFirstDecl; + + /// Retrieves the canonical declaration of this Objective-C class. + ObjCInterfaceDecl *getCanonicalDecl() override { return getFirstDecl(); } + const ObjCInterfaceDecl *getCanonicalDecl() const { return getFirstDecl(); } + + // Low-level accessor + const Type *getTypeForDecl() const { return TypeForDecl; } + void setTypeForDecl(const Type *TD) const { TypeForDecl = TD; } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == ObjCInterface; } + + friend class ASTReader; + friend class ASTDeclReader; + friend class ASTDeclWriter; + +private: + const ObjCInterfaceDecl *findInterfaceWithDesignatedInitializers() const; + bool inheritsDesignatedInitializers() const; +}; + +/// ObjCIvarDecl - Represents an ObjC instance variable. In general, ObjC +/// instance variables are identical to C. The only exception is Objective-C +/// supports C++ style access control. For example: +/// +/// \@interface IvarExample : NSObject +/// { +/// id defaultToProtected; +/// \@public: +/// id canBePublic; // same as C++. +/// \@protected: +/// id canBeProtected; // same as C++. +/// \@package: +/// id canBePackage; // framework visibility (not available in C++). +/// } +/// +class ObjCIvarDecl : public FieldDecl { + void anchor() override; + +public: + enum AccessControl { + None, Private, Protected, Public, Package + }; + +private: + ObjCIvarDecl(ObjCContainerDecl *DC, SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW, + bool synthesized) + : FieldDecl(ObjCIvar, DC, StartLoc, IdLoc, Id, T, TInfo, BW, + /*Mutable=*/false, /*HasInit=*/ICIS_NoInit), + NextIvar(nullptr), DeclAccess(ac), Synthesized(synthesized) {} + +public: + static ObjCIvarDecl *Create(ASTContext &C, ObjCContainerDecl *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, QualType T, + TypeSourceInfo *TInfo, + AccessControl ac, Expr *BW = nullptr, + bool synthesized=false); + + static ObjCIvarDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + /// \brief Return the class interface that this ivar is logically contained + /// in; this is either the interface where the ivar was declared, or the + /// interface the ivar is conceptually a part of in the case of synthesized + /// ivars. + const ObjCInterfaceDecl *getContainingInterface() const; + + ObjCIvarDecl *getNextIvar() { return NextIvar; } + const ObjCIvarDecl *getNextIvar() const { return NextIvar; } + void setNextIvar(ObjCIvarDecl *ivar) { NextIvar = ivar; } + + void setAccessControl(AccessControl ac) { DeclAccess = ac; } + + AccessControl getAccessControl() const { return AccessControl(DeclAccess); } + + AccessControl getCanonicalAccessControl() const { + return DeclAccess == None ? Protected : AccessControl(DeclAccess); + } + + void setSynthesize(bool synth) { Synthesized = synth; } + bool getSynthesize() const { return Synthesized; } + + /// Retrieve the type of this instance variable when viewed as a member of a + /// specific object type. + QualType getUsageType(QualType objectType) const; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == ObjCIvar; } +private: + /// NextIvar - Next Ivar in the list of ivars declared in class; class's + /// extensions and class's implementation + ObjCIvarDecl *NextIvar; + + // NOTE: VC++ treats enums as signed, avoid using the AccessControl enum + unsigned DeclAccess : 3; + unsigned Synthesized : 1; +}; + + +/// \brief Represents a field declaration created by an \@defs(...). +class ObjCAtDefsFieldDecl : public FieldDecl { + void anchor() override; + ObjCAtDefsFieldDecl(DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + QualType T, Expr *BW) + : FieldDecl(ObjCAtDefsField, DC, StartLoc, IdLoc, Id, T, + /*TInfo=*/nullptr, // FIXME: Do ObjCAtDefs have declarators ? + BW, /*Mutable=*/false, /*HasInit=*/ICIS_NoInit) {} + +public: + static ObjCAtDefsFieldDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + QualType T, Expr *BW); + + static ObjCAtDefsFieldDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == ObjCAtDefsField; } +}; + +/// \brief Represents an Objective-C protocol declaration. +/// +/// Objective-C protocols declare a pure abstract type (i.e., no instance +/// variables are permitted). Protocols originally drew inspiration from +/// C++ pure virtual functions (a C++ feature with nice semantics and lousy +/// syntax:-). Here is an example: +/// +/// \code +/// \@protocol NSDraggingInfo <refproto1, refproto2> +/// - (NSWindow *)draggingDestinationWindow; +/// - (NSImage *)draggedImage; +/// \@end +/// \endcode +/// +/// This says that NSDraggingInfo requires two methods and requires everything +/// that the two "referenced protocols" 'refproto1' and 'refproto2' require as +/// well. +/// +/// \code +/// \@interface ImplementsNSDraggingInfo : NSObject \<NSDraggingInfo> +/// \@end +/// \endcode +/// +/// ObjC protocols inspired Java interfaces. Unlike Java, ObjC classes and +/// protocols are in distinct namespaces. For example, Cocoa defines both +/// an NSObject protocol and class (which isn't allowed in Java). As a result, +/// protocols are referenced using angle brackets as follows: +/// +/// id \<NSDraggingInfo> anyObjectThatImplementsNSDraggingInfo; +/// +class ObjCProtocolDecl : public ObjCContainerDecl, + public Redeclarable<ObjCProtocolDecl> { + void anchor() override; + + struct DefinitionData { + // \brief The declaration that defines this protocol. + ObjCProtocolDecl *Definition; + + /// \brief Referenced protocols + ObjCProtocolList ReferencedProtocols; + }; + + /// \brief Contains a pointer to the data associated with this class, + /// which will be NULL if this class has not yet been defined. + /// + /// The bit indicates when we don't need to check for out-of-date + /// declarations. It will be set unless modules are enabled. + llvm::PointerIntPair<DefinitionData *, 1, bool> Data; + + DefinitionData &data() const { + assert(Data.getPointer() && "Objective-C protocol has no definition!"); + return *Data.getPointer(); + } + + ObjCProtocolDecl(ASTContext &C, DeclContext *DC, IdentifierInfo *Id, + SourceLocation nameLoc, SourceLocation atStartLoc, + ObjCProtocolDecl *PrevDecl); + + void allocateDefinitionData(); + + typedef Redeclarable<ObjCProtocolDecl> redeclarable_base; + ObjCProtocolDecl *getNextRedeclarationImpl() override { + return getNextRedeclaration(); + } + ObjCProtocolDecl *getPreviousDeclImpl() override { + return getPreviousDecl(); + } + ObjCProtocolDecl *getMostRecentDeclImpl() override { + return getMostRecentDecl(); + } + +public: + static ObjCProtocolDecl *Create(ASTContext &C, DeclContext *DC, + IdentifierInfo *Id, + SourceLocation nameLoc, + SourceLocation atStartLoc, + ObjCProtocolDecl *PrevDecl); + + static ObjCProtocolDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + const ObjCProtocolList &getReferencedProtocols() const { + assert(hasDefinition() && "No definition available!"); + return data().ReferencedProtocols; + } + typedef ObjCProtocolList::iterator protocol_iterator; + typedef llvm::iterator_range<protocol_iterator> protocol_range; + + protocol_range protocols() const { + return protocol_range(protocol_begin(), protocol_end()); + } + protocol_iterator protocol_begin() const { + if (!hasDefinition()) + return protocol_iterator(); + + return data().ReferencedProtocols.begin(); + } + protocol_iterator protocol_end() const { + if (!hasDefinition()) + return protocol_iterator(); + + return data().ReferencedProtocols.end(); + } + typedef ObjCProtocolList::loc_iterator protocol_loc_iterator; + typedef llvm::iterator_range<protocol_loc_iterator> protocol_loc_range; + + protocol_loc_range protocol_locs() const { + return protocol_loc_range(protocol_loc_begin(), protocol_loc_end()); + } + protocol_loc_iterator protocol_loc_begin() const { + if (!hasDefinition()) + return protocol_loc_iterator(); + + return data().ReferencedProtocols.loc_begin(); + } + protocol_loc_iterator protocol_loc_end() const { + if (!hasDefinition()) + return protocol_loc_iterator(); + + return data().ReferencedProtocols.loc_end(); + } + unsigned protocol_size() const { + if (!hasDefinition()) + return 0; + + return data().ReferencedProtocols.size(); + } + + /// setProtocolList - Set the list of protocols that this interface + /// implements. + void setProtocolList(ObjCProtocolDecl *const*List, unsigned Num, + const SourceLocation *Locs, ASTContext &C) { + assert(hasDefinition() && "Protocol is not defined"); + data().ReferencedProtocols.set(List, Num, Locs, C); + } + + ObjCProtocolDecl *lookupProtocolNamed(IdentifierInfo *PName); + + // Lookup a method. First, we search locally. If a method isn't + // found, we search referenced protocols and class categories. + ObjCMethodDecl *lookupMethod(Selector Sel, bool isInstance) const; + ObjCMethodDecl *lookupInstanceMethod(Selector Sel) const { + return lookupMethod(Sel, true/*isInstance*/); + } + ObjCMethodDecl *lookupClassMethod(Selector Sel) const { + return lookupMethod(Sel, false/*isInstance*/); + } + + /// \brief Determine whether this protocol has a definition. + bool hasDefinition() const { + // If the name of this protocol is out-of-date, bring it up-to-date, which + // might bring in a definition. + // Note: a null value indicates that we don't have a definition and that + // modules are enabled. + if (!Data.getOpaqueValue()) + getMostRecentDecl(); + + return Data.getPointer(); + } + + /// \brief Retrieve the definition of this protocol, if any. + ObjCProtocolDecl *getDefinition() { + return hasDefinition()? Data.getPointer()->Definition : nullptr; + } + + /// \brief Retrieve the definition of this protocol, if any. + const ObjCProtocolDecl *getDefinition() const { + return hasDefinition()? Data.getPointer()->Definition : nullptr; + } + + /// \brief Determine whether this particular declaration is also the + /// definition. + bool isThisDeclarationADefinition() const { + return getDefinition() == this; + } + + /// \brief Starts the definition of this Objective-C protocol. + void startDefinition(); + + /// Produce a name to be used for protocol's metadata. It comes either via + /// objc_runtime_name attribute or protocol name. + StringRef getObjCRuntimeNameAsString() const; + + SourceRange getSourceRange() const override LLVM_READONLY { + if (isThisDeclarationADefinition()) + return ObjCContainerDecl::getSourceRange(); + + return SourceRange(getAtStartLoc(), getLocation()); + } + + typedef redeclarable_base::redecl_range redecl_range; + typedef redeclarable_base::redecl_iterator redecl_iterator; + using redeclarable_base::redecls_begin; + using redeclarable_base::redecls_end; + using redeclarable_base::redecls; + using redeclarable_base::getPreviousDecl; + using redeclarable_base::getMostRecentDecl; + using redeclarable_base::isFirstDecl; + + /// Retrieves the canonical declaration of this Objective-C protocol. + ObjCProtocolDecl *getCanonicalDecl() override { return getFirstDecl(); } + const ObjCProtocolDecl *getCanonicalDecl() const { return getFirstDecl(); } + + void collectPropertiesToImplement(PropertyMap &PM, + PropertyDeclOrder &PO) const override; + + void collectInheritedProtocolProperties(const ObjCPropertyDecl *Property, + ProtocolPropertyMap &PM) const; + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == ObjCProtocol; } + + friend class ASTReader; + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// ObjCCategoryDecl - Represents a category declaration. A category allows +/// you to add methods to an existing class (without subclassing or modifying +/// the original class interface or implementation:-). Categories don't allow +/// you to add instance data. The following example adds "myMethod" to all +/// NSView's within a process: +/// +/// \@interface NSView (MyViewMethods) +/// - myMethod; +/// \@end +/// +/// Categories also allow you to split the implementation of a class across +/// several files (a feature more naturally supported in C++). +/// +/// Categories were originally inspired by dynamic languages such as Common +/// Lisp and Smalltalk. More traditional class-based languages (C++, Java) +/// don't support this level of dynamism, which is both powerful and dangerous. +/// +class ObjCCategoryDecl : public ObjCContainerDecl { + void anchor() override; + + /// Interface belonging to this category + ObjCInterfaceDecl *ClassInterface; + + /// The type parameters associated with this category, if any. + ObjCTypeParamList *TypeParamList; + + /// referenced protocols in this category. + ObjCProtocolList ReferencedProtocols; + + /// Next category belonging to this class. + /// FIXME: this should not be a singly-linked list. Move storage elsewhere. + ObjCCategoryDecl *NextClassCategory; + + /// \brief The location of the category name in this declaration. + SourceLocation CategoryNameLoc; + + /// class extension may have private ivars. + SourceLocation IvarLBraceLoc; + SourceLocation IvarRBraceLoc; + + ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc, + SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc, + IdentifierInfo *Id, ObjCInterfaceDecl *IDecl, + ObjCTypeParamList *typeParamList, + SourceLocation IvarLBraceLoc=SourceLocation(), + SourceLocation IvarRBraceLoc=SourceLocation()); + +public: + + static ObjCCategoryDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation AtLoc, + SourceLocation ClassNameLoc, + SourceLocation CategoryNameLoc, + IdentifierInfo *Id, + ObjCInterfaceDecl *IDecl, + ObjCTypeParamList *typeParamList, + SourceLocation IvarLBraceLoc=SourceLocation(), + SourceLocation IvarRBraceLoc=SourceLocation()); + static ObjCCategoryDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + ObjCInterfaceDecl *getClassInterface() { return ClassInterface; } + const ObjCInterfaceDecl *getClassInterface() const { return ClassInterface; } + + /// Retrieve the type parameter list associated with this category or + /// extension. + ObjCTypeParamList *getTypeParamList() const { return TypeParamList; } + + /// Set the type parameters of this category. + /// + /// This function is used by the AST importer, which must import the type + /// parameters after creating their DeclContext to avoid loops. + void setTypeParamList(ObjCTypeParamList *TPL); + + + ObjCCategoryImplDecl *getImplementation() const; + void setImplementation(ObjCCategoryImplDecl *ImplD); + + /// setProtocolList - Set the list of protocols that this interface + /// implements. + void setProtocolList(ObjCProtocolDecl *const*List, unsigned Num, + const SourceLocation *Locs, ASTContext &C) { + ReferencedProtocols.set(List, Num, Locs, C); + } + + const ObjCProtocolList &getReferencedProtocols() const { + return ReferencedProtocols; + } + + typedef ObjCProtocolList::iterator protocol_iterator; + typedef llvm::iterator_range<protocol_iterator> protocol_range; + + protocol_range protocols() const { + return protocol_range(protocol_begin(), protocol_end()); + } + protocol_iterator protocol_begin() const { + return ReferencedProtocols.begin(); + } + protocol_iterator protocol_end() const { return ReferencedProtocols.end(); } + unsigned protocol_size() const { return ReferencedProtocols.size(); } + typedef ObjCProtocolList::loc_iterator protocol_loc_iterator; + typedef llvm::iterator_range<protocol_loc_iterator> protocol_loc_range; + + protocol_loc_range protocol_locs() const { + return protocol_loc_range(protocol_loc_begin(), protocol_loc_end()); + } + protocol_loc_iterator protocol_loc_begin() const { + return ReferencedProtocols.loc_begin(); + } + protocol_loc_iterator protocol_loc_end() const { + return ReferencedProtocols.loc_end(); + } + + ObjCCategoryDecl *getNextClassCategory() const { return NextClassCategory; } + + /// \brief Retrieve the pointer to the next stored category (or extension), + /// which may be hidden. + ObjCCategoryDecl *getNextClassCategoryRaw() const { + return NextClassCategory; + } + + bool IsClassExtension() const { return getIdentifier() == nullptr; } + + typedef specific_decl_iterator<ObjCIvarDecl> ivar_iterator; + typedef llvm::iterator_range<specific_decl_iterator<ObjCIvarDecl>> ivar_range; + + ivar_range ivars() const { return ivar_range(ivar_begin(), ivar_end()); } + ivar_iterator ivar_begin() const { + return ivar_iterator(decls_begin()); + } + ivar_iterator ivar_end() const { + return ivar_iterator(decls_end()); + } + unsigned ivar_size() const { + return std::distance(ivar_begin(), ivar_end()); + } + bool ivar_empty() const { + return ivar_begin() == ivar_end(); + } + + SourceLocation getCategoryNameLoc() const { return CategoryNameLoc; } + void setCategoryNameLoc(SourceLocation Loc) { CategoryNameLoc = Loc; } + + void setIvarLBraceLoc(SourceLocation Loc) { IvarLBraceLoc = Loc; } + SourceLocation getIvarLBraceLoc() const { return IvarLBraceLoc; } + void setIvarRBraceLoc(SourceLocation Loc) { IvarRBraceLoc = Loc; } + SourceLocation getIvarRBraceLoc() const { return IvarRBraceLoc; } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == ObjCCategory; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +class ObjCImplDecl : public ObjCContainerDecl { + void anchor() override; + + /// Class interface for this class/category implementation + ObjCInterfaceDecl *ClassInterface; + +protected: + ObjCImplDecl(Kind DK, DeclContext *DC, + ObjCInterfaceDecl *classInterface, + SourceLocation nameLoc, SourceLocation atStartLoc) + : ObjCContainerDecl(DK, DC, + classInterface? classInterface->getIdentifier() + : nullptr, + nameLoc, atStartLoc), + ClassInterface(classInterface) {} + +public: + const ObjCInterfaceDecl *getClassInterface() const { return ClassInterface; } + ObjCInterfaceDecl *getClassInterface() { return ClassInterface; } + void setClassInterface(ObjCInterfaceDecl *IFace); + + void addInstanceMethod(ObjCMethodDecl *method) { + // FIXME: Context should be set correctly before we get here. + method->setLexicalDeclContext(this); + addDecl(method); + } + void addClassMethod(ObjCMethodDecl *method) { + // FIXME: Context should be set correctly before we get here. + method->setLexicalDeclContext(this); + addDecl(method); + } + + void addPropertyImplementation(ObjCPropertyImplDecl *property); + + ObjCPropertyImplDecl *FindPropertyImplDecl(IdentifierInfo *propertyId) const; + ObjCPropertyImplDecl *FindPropertyImplIvarDecl(IdentifierInfo *ivarId) const; + + // Iterator access to properties. + typedef specific_decl_iterator<ObjCPropertyImplDecl> propimpl_iterator; + typedef llvm::iterator_range<specific_decl_iterator<ObjCPropertyImplDecl>> + propimpl_range; + + propimpl_range property_impls() const { + return propimpl_range(propimpl_begin(), propimpl_end()); + } + propimpl_iterator propimpl_begin() const { + return propimpl_iterator(decls_begin()); + } + propimpl_iterator propimpl_end() const { + return propimpl_iterator(decls_end()); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { + return K >= firstObjCImpl && K <= lastObjCImpl; + } +}; + +/// ObjCCategoryImplDecl - An object of this class encapsulates a category +/// \@implementation declaration. If a category class has declaration of a +/// property, its implementation must be specified in the category's +/// \@implementation declaration. Example: +/// \@interface I \@end +/// \@interface I(CATEGORY) +/// \@property int p1, d1; +/// \@end +/// \@implementation I(CATEGORY) +/// \@dynamic p1,d1; +/// \@end +/// +/// ObjCCategoryImplDecl +class ObjCCategoryImplDecl : public ObjCImplDecl { + void anchor() override; + + // Category name + IdentifierInfo *Id; + + // Category name location + SourceLocation CategoryNameLoc; + + ObjCCategoryImplDecl(DeclContext *DC, IdentifierInfo *Id, + ObjCInterfaceDecl *classInterface, + SourceLocation nameLoc, SourceLocation atStartLoc, + SourceLocation CategoryNameLoc) + : ObjCImplDecl(ObjCCategoryImpl, DC, classInterface, nameLoc, atStartLoc), + Id(Id), CategoryNameLoc(CategoryNameLoc) {} +public: + static ObjCCategoryImplDecl *Create(ASTContext &C, DeclContext *DC, + IdentifierInfo *Id, + ObjCInterfaceDecl *classInterface, + SourceLocation nameLoc, + SourceLocation atStartLoc, + SourceLocation CategoryNameLoc); + static ObjCCategoryImplDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + /// getIdentifier - Get the identifier that names the category + /// interface associated with this implementation. + /// FIXME: This is a bad API, we are hiding NamedDecl::getIdentifier() + /// with a different meaning. 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 *getCategoryDecl() const; + + SourceLocation getCategoryNameLoc() const { return CategoryNameLoc; } + + /// getName - Get the name of identifier for the class interface associated + /// with this implementation as a StringRef. + // + // FIXME: This is a bad API, we are hiding NamedDecl::getName with a different + // meaning. + StringRef getName() const { return Id ? Id->getName() : StringRef(); } + + /// @brief Get the name of the class associated with this interface. + // + // FIXME: Deprecated, move clients to getName(). + std::string getNameAsString() const { + return getName(); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == ObjCCategoryImpl;} + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +raw_ostream &operator<<(raw_ostream &OS, const ObjCCategoryImplDecl &CID); + +/// ObjCImplementationDecl - Represents a class definition - this is where +/// method definitions are specified. For example: +/// +/// @code +/// \@implementation MyClass +/// - (void)myMethod { /* do something */ } +/// \@end +/// @endcode +/// +/// In a non-fragile runtime, instance variables can appear in the class +/// interface, class extensions (nameless categories), and in the implementation +/// itself, as well as being synthesized as backing storage for properties. +/// +/// In a fragile runtime, instance variables are specified in the class +/// interface, \em not in the implementation. Nevertheless (for legacy reasons), +/// we allow instance variables to be specified in the implementation. When +/// specified, they need to be \em identical to the interface. +class ObjCImplementationDecl : public ObjCImplDecl { + void anchor() override; + /// Implementation Class's super class. + ObjCInterfaceDecl *SuperClass; + SourceLocation SuperLoc; + + /// \@implementation may have private ivars. + SourceLocation IvarLBraceLoc; + SourceLocation IvarRBraceLoc; + + /// Support for ivar initialization. + /// \brief The arguments used to initialize the ivars + LazyCXXCtorInitializersPtr IvarInitializers; + unsigned NumIvarInitializers; + + /// Do the ivars of this class require initialization other than + /// zero-initialization? + bool HasNonZeroConstructors : 1; + + /// Do the ivars of this class require non-trivial destruction? + bool HasDestructors : 1; + + ObjCImplementationDecl(DeclContext *DC, + ObjCInterfaceDecl *classInterface, + ObjCInterfaceDecl *superDecl, + SourceLocation nameLoc, SourceLocation atStartLoc, + SourceLocation superLoc = SourceLocation(), + SourceLocation IvarLBraceLoc=SourceLocation(), + SourceLocation IvarRBraceLoc=SourceLocation()) + : ObjCImplDecl(ObjCImplementation, DC, classInterface, nameLoc, atStartLoc), + SuperClass(superDecl), SuperLoc(superLoc), IvarLBraceLoc(IvarLBraceLoc), + IvarRBraceLoc(IvarRBraceLoc), + IvarInitializers(nullptr), NumIvarInitializers(0), + HasNonZeroConstructors(false), HasDestructors(false) {} +public: + static ObjCImplementationDecl *Create(ASTContext &C, DeclContext *DC, + ObjCInterfaceDecl *classInterface, + ObjCInterfaceDecl *superDecl, + SourceLocation nameLoc, + SourceLocation atStartLoc, + SourceLocation superLoc = SourceLocation(), + SourceLocation IvarLBraceLoc=SourceLocation(), + SourceLocation IvarRBraceLoc=SourceLocation()); + + static ObjCImplementationDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + /// init_iterator - Iterates through the ivar initializer list. + typedef CXXCtorInitializer **init_iterator; + + /// init_const_iterator - Iterates through the ivar initializer list. + typedef CXXCtorInitializer * const * init_const_iterator; + + typedef llvm::iterator_range<init_iterator> init_range; + typedef llvm::iterator_range<init_const_iterator> init_const_range; + + init_range inits() { return init_range(init_begin(), init_end()); } + init_const_range inits() const { + return init_const_range(init_begin(), init_end()); + } + + /// init_begin() - Retrieve an iterator to the first initializer. + init_iterator init_begin() { + const auto *ConstThis = this; + return const_cast<init_iterator>(ConstThis->init_begin()); + } + /// begin() - Retrieve an iterator to the first initializer. + init_const_iterator init_begin() const; + + /// init_end() - Retrieve an iterator past the last initializer. + init_iterator init_end() { + return init_begin() + NumIvarInitializers; + } + /// end() - Retrieve an iterator past the last initializer. + init_const_iterator init_end() const { + return init_begin() + NumIvarInitializers; + } + /// getNumArgs - Number of ivars which must be initialized. + unsigned getNumIvarInitializers() const { + return NumIvarInitializers; + } + + void setNumIvarInitializers(unsigned numNumIvarInitializers) { + NumIvarInitializers = numNumIvarInitializers; + } + + void setIvarInitializers(ASTContext &C, + CXXCtorInitializer ** initializers, + unsigned numInitializers); + + /// Do any of the ivars of this class (not counting its base classes) + /// require construction other than zero-initialization? + bool hasNonZeroConstructors() const { return HasNonZeroConstructors; } + void setHasNonZeroConstructors(bool val) { HasNonZeroConstructors = val; } + + /// Do any of the ivars of this class (not counting its base classes) + /// require non-trivial destruction? + bool hasDestructors() const { return HasDestructors; } + void setHasDestructors(bool val) { HasDestructors = val; } + + /// getIdentifier - Get the identifier that names the class + /// interface associated with this implementation. + IdentifierInfo *getIdentifier() const { + return getClassInterface()->getIdentifier(); + } + + /// getName - Get the name of identifier for the class interface associated + /// with this implementation as a StringRef. + // + // FIXME: This is a bad API, we are hiding NamedDecl::getName with a different + // meaning. + StringRef getName() const { + assert(getIdentifier() && "Name is not a simple identifier"); + return getIdentifier()->getName(); + } + + /// @brief Get the name of the class associated with this interface. + // + // FIXME: Move to StringRef API. + std::string getNameAsString() const { + return getName(); + } + + /// Produce a name to be used for class's metadata. It comes either via + /// class's objc_runtime_name attribute or class name. + StringRef getObjCRuntimeNameAsString() const; + + const ObjCInterfaceDecl *getSuperClass() const { return SuperClass; } + ObjCInterfaceDecl *getSuperClass() { return SuperClass; } + SourceLocation getSuperClassLoc() const { return SuperLoc; } + + void setSuperClass(ObjCInterfaceDecl * superCls) { SuperClass = superCls; } + + void setIvarLBraceLoc(SourceLocation Loc) { IvarLBraceLoc = Loc; } + SourceLocation getIvarLBraceLoc() const { return IvarLBraceLoc; } + void setIvarRBraceLoc(SourceLocation Loc) { IvarRBraceLoc = Loc; } + SourceLocation getIvarRBraceLoc() const { return IvarRBraceLoc; } + + typedef specific_decl_iterator<ObjCIvarDecl> ivar_iterator; + typedef llvm::iterator_range<specific_decl_iterator<ObjCIvarDecl>> ivar_range; + + ivar_range ivars() const { return ivar_range(ivar_begin(), ivar_end()); } + ivar_iterator ivar_begin() const { + return ivar_iterator(decls_begin()); + } + ivar_iterator ivar_end() const { + return ivar_iterator(decls_end()); + } + unsigned ivar_size() const { + return std::distance(ivar_begin(), ivar_end()); + } + bool ivar_empty() const { + return ivar_begin() == ivar_end(); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == ObjCImplementation; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +raw_ostream &operator<<(raw_ostream &OS, const ObjCImplementationDecl &ID); + +/// ObjCCompatibleAliasDecl - Represents alias of a class. This alias is +/// declared as \@compatibility_alias alias class. +class ObjCCompatibleAliasDecl : public NamedDecl { + void anchor() override; + /// Class that this is an alias of. + ObjCInterfaceDecl *AliasedClass; + + ObjCCompatibleAliasDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, + ObjCInterfaceDecl* aliasedClass) + : NamedDecl(ObjCCompatibleAlias, DC, L, Id), AliasedClass(aliasedClass) {} +public: + static ObjCCompatibleAliasDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + ObjCInterfaceDecl* aliasedClass); + + static ObjCCompatibleAliasDecl *CreateDeserialized(ASTContext &C, + unsigned ID); + + const ObjCInterfaceDecl *getClassInterface() const { return AliasedClass; } + ObjCInterfaceDecl *getClassInterface() { return AliasedClass; } + void setClassInterface(ObjCInterfaceDecl *D) { AliasedClass = D; } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == ObjCCompatibleAlias; } + +}; + +/// \brief Represents one property declaration in an Objective-C interface. +/// +/// For example: +/// \code{.mm} +/// \@property (assign, readwrite) int MyProperty; +/// \endcode +class ObjCPropertyDecl : public NamedDecl { + void anchor() override; +public: + enum PropertyAttributeKind { + OBJC_PR_noattr = 0x00, + OBJC_PR_readonly = 0x01, + OBJC_PR_getter = 0x02, + OBJC_PR_assign = 0x04, + OBJC_PR_readwrite = 0x08, + OBJC_PR_retain = 0x10, + OBJC_PR_copy = 0x20, + OBJC_PR_nonatomic = 0x40, + OBJC_PR_setter = 0x80, + OBJC_PR_atomic = 0x100, + OBJC_PR_weak = 0x200, + OBJC_PR_strong = 0x400, + OBJC_PR_unsafe_unretained = 0x800, + /// Indicates that the nullability of the type was spelled with a + /// property attribute rather than a type qualifier. + OBJC_PR_nullability = 0x1000, + OBJC_PR_null_resettable = 0x2000 + // Adding a property should change NumPropertyAttrsBits + }; + + enum { + /// \brief Number of bits fitting all the property attributes. + NumPropertyAttrsBits = 14 + }; + + enum SetterKind { Assign, Retain, Copy, Weak }; + enum PropertyControl { None, Required, Optional }; +private: + SourceLocation AtLoc; // location of \@property + SourceLocation LParenLoc; // location of '(' starting attribute list or null. + QualType DeclType; + TypeSourceInfo *DeclTypeSourceInfo; + unsigned PropertyAttributes : NumPropertyAttrsBits; + unsigned PropertyAttributesAsWritten : NumPropertyAttrsBits; + // \@required/\@optional + unsigned PropertyImplementation : 2; + + Selector GetterName; // getter name of NULL if no getter + Selector SetterName; // setter name of NULL if no setter + + ObjCMethodDecl *GetterMethodDecl; // Declaration of getter instance method + ObjCMethodDecl *SetterMethodDecl; // Declaration of setter instance method + ObjCIvarDecl *PropertyIvarDecl; // Synthesize ivar for this property + + ObjCPropertyDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, + SourceLocation AtLocation, SourceLocation LParenLocation, + QualType T, TypeSourceInfo *TSI, + PropertyControl propControl) + : NamedDecl(ObjCProperty, DC, L, Id), AtLoc(AtLocation), + LParenLoc(LParenLocation), DeclType(T), DeclTypeSourceInfo(TSI), + PropertyAttributes(OBJC_PR_noattr), + PropertyAttributesAsWritten(OBJC_PR_noattr), + PropertyImplementation(propControl), + GetterName(Selector()), + SetterName(Selector()), + GetterMethodDecl(nullptr), SetterMethodDecl(nullptr), + PropertyIvarDecl(nullptr) {} + +public: + static ObjCPropertyDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + IdentifierInfo *Id, SourceLocation AtLocation, + SourceLocation LParenLocation, + QualType T, + TypeSourceInfo *TSI, + PropertyControl propControl = None); + + static ObjCPropertyDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + SourceLocation getAtLoc() const { return AtLoc; } + void setAtLoc(SourceLocation L) { AtLoc = L; } + + SourceLocation getLParenLoc() const { return LParenLoc; } + void setLParenLoc(SourceLocation L) { LParenLoc = L; } + + TypeSourceInfo *getTypeSourceInfo() const { return DeclTypeSourceInfo; } + + QualType getType() const { return DeclType; } + + void setType(QualType T, TypeSourceInfo *TSI) { + DeclType = T; + DeclTypeSourceInfo = TSI; + } + + /// Retrieve the type when this property is used with a specific base object + /// type. + QualType getUsageType(QualType objectType) const; + + PropertyAttributeKind getPropertyAttributes() const { + return PropertyAttributeKind(PropertyAttributes); + } + void setPropertyAttributes(PropertyAttributeKind PRVal) { + PropertyAttributes |= PRVal; + } + void overwritePropertyAttributes(unsigned PRVal) { + PropertyAttributes = PRVal; + } + + PropertyAttributeKind getPropertyAttributesAsWritten() const { + return PropertyAttributeKind(PropertyAttributesAsWritten); + } + + void setPropertyAttributesAsWritten(PropertyAttributeKind PRVal) { + PropertyAttributesAsWritten = PRVal; + } + + // Helper methods for accessing attributes. + + /// isReadOnly - Return true iff the property has a setter. + bool isReadOnly() const { + return (PropertyAttributes & OBJC_PR_readonly); + } + + /// isAtomic - Return true if the property is atomic. + bool isAtomic() const { + return (PropertyAttributes & OBJC_PR_atomic); + } + + /// isRetaining - Return true if the property retains its value. + bool isRetaining() const { + return (PropertyAttributes & + (OBJC_PR_retain | OBJC_PR_strong | OBJC_PR_copy)); + } + + /// getSetterKind - Return the method used for doing assignment in + /// the property setter. This is only valid if the property has been + /// defined to have a setter. + SetterKind getSetterKind() const { + if (PropertyAttributes & OBJC_PR_strong) + return getType()->isBlockPointerType() ? Copy : Retain; + if (PropertyAttributes & OBJC_PR_retain) + return Retain; + if (PropertyAttributes & OBJC_PR_copy) + return Copy; + if (PropertyAttributes & OBJC_PR_weak) + return Weak; + return Assign; + } + + Selector getGetterName() const { return GetterName; } + void setGetterName(Selector Sel) { GetterName = Sel; } + + Selector getSetterName() const { return SetterName; } + void setSetterName(Selector Sel) { SetterName = Sel; } + + ObjCMethodDecl *getGetterMethodDecl() const { return GetterMethodDecl; } + void setGetterMethodDecl(ObjCMethodDecl *gDecl) { GetterMethodDecl = gDecl; } + + ObjCMethodDecl *getSetterMethodDecl() const { return SetterMethodDecl; } + void setSetterMethodDecl(ObjCMethodDecl *gDecl) { SetterMethodDecl = gDecl; } + + // Related to \@optional/\@required declared in \@protocol + void setPropertyImplementation(PropertyControl pc) { + PropertyImplementation = pc; + } + PropertyControl getPropertyImplementation() const { + return PropertyControl(PropertyImplementation); + } + + void setPropertyIvarDecl(ObjCIvarDecl *Ivar) { + PropertyIvarDecl = Ivar; + } + ObjCIvarDecl *getPropertyIvarDecl() const { + return PropertyIvarDecl; + } + + SourceRange getSourceRange() const override LLVM_READONLY { + return SourceRange(AtLoc, getLocation()); + } + + /// Get the default name of the synthesized ivar. + IdentifierInfo *getDefaultSynthIvarName(ASTContext &Ctx) const; + + /// Lookup a property by name in the specified DeclContext. + static ObjCPropertyDecl *findPropertyDecl(const DeclContext *DC, + const IdentifierInfo *propertyID); + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == ObjCProperty; } +}; + +/// ObjCPropertyImplDecl - Represents implementation declaration of a property +/// in a class or category implementation block. For example: +/// \@synthesize prop1 = ivar1; +/// +class ObjCPropertyImplDecl : public Decl { +public: + enum Kind { + Synthesize, + Dynamic + }; +private: + SourceLocation AtLoc; // location of \@synthesize or \@dynamic + + /// \brief For \@synthesize, the location of the ivar, if it was written in + /// the source code. + /// + /// \code + /// \@synthesize int a = b + /// \endcode + SourceLocation IvarLoc; + + /// Property declaration being implemented + ObjCPropertyDecl *PropertyDecl; + + /// Null for \@dynamic. Required for \@synthesize. + ObjCIvarDecl *PropertyIvarDecl; + + /// Null for \@dynamic. Non-null if property must be copy-constructed in + /// getter. + Expr *GetterCXXConstructor; + + /// Null for \@dynamic. Non-null if property has assignment operator to call + /// in Setter synthesis. + Expr *SetterCXXAssignment; + + ObjCPropertyImplDecl(DeclContext *DC, SourceLocation atLoc, SourceLocation L, + ObjCPropertyDecl *property, + Kind PK, + ObjCIvarDecl *ivarDecl, + SourceLocation ivarLoc) + : Decl(ObjCPropertyImpl, DC, L), AtLoc(atLoc), + IvarLoc(ivarLoc), PropertyDecl(property), PropertyIvarDecl(ivarDecl), + GetterCXXConstructor(nullptr), SetterCXXAssignment(nullptr) { + assert (PK == Dynamic || PropertyIvarDecl); + } + +public: + static ObjCPropertyImplDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation atLoc, SourceLocation L, + ObjCPropertyDecl *property, + Kind PK, + ObjCIvarDecl *ivarDecl, + SourceLocation ivarLoc); + + static ObjCPropertyImplDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + SourceRange getSourceRange() const override LLVM_READONLY; + + SourceLocation getLocStart() const LLVM_READONLY { return AtLoc; } + void setAtLoc(SourceLocation Loc) { AtLoc = Loc; } + + ObjCPropertyDecl *getPropertyDecl() const { + return PropertyDecl; + } + void setPropertyDecl(ObjCPropertyDecl *Prop) { PropertyDecl = Prop; } + + Kind getPropertyImplementation() const { + return PropertyIvarDecl ? Synthesize : Dynamic; + } + + ObjCIvarDecl *getPropertyIvarDecl() const { + return PropertyIvarDecl; + } + SourceLocation getPropertyIvarDeclLoc() const { return IvarLoc; } + + void setPropertyIvarDecl(ObjCIvarDecl *Ivar, + SourceLocation IvarLoc) { + PropertyIvarDecl = Ivar; + this->IvarLoc = IvarLoc; + } + + /// \brief For \@synthesize, returns true if an ivar name was explicitly + /// specified. + /// + /// \code + /// \@synthesize int a = b; // true + /// \@synthesize int a; // false + /// \endcode + bool isIvarNameSpecified() const { + return IvarLoc.isValid() && IvarLoc != getLocation(); + } + + Expr *getGetterCXXConstructor() const { + return GetterCXXConstructor; + } + void setGetterCXXConstructor(Expr *getterCXXConstructor) { + GetterCXXConstructor = getterCXXConstructor; + } + + Expr *getSetterCXXAssignment() const { + return SetterCXXAssignment; + } + void setSetterCXXAssignment(Expr *setterCXXAssignment) { + SetterCXXAssignment = setterCXXAssignment; + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Decl::Kind K) { return K == ObjCPropertyImpl; } + + friend class ASTDeclReader; +}; + +template<bool (*Filter)(ObjCCategoryDecl *)> +void +ObjCInterfaceDecl::filtered_category_iterator<Filter>:: +findAcceptableCategory() { + while (Current && !Filter(Current)) + Current = Current->getNextClassCategoryRaw(); +} + +template<bool (*Filter)(ObjCCategoryDecl *)> +inline ObjCInterfaceDecl::filtered_category_iterator<Filter> & +ObjCInterfaceDecl::filtered_category_iterator<Filter>::operator++() { + Current = Current->getNextClassCategoryRaw(); + findAcceptableCategory(); + return *this; +} + +inline bool ObjCInterfaceDecl::isVisibleCategory(ObjCCategoryDecl *Cat) { + return !Cat->isHidden(); +} + +inline bool ObjCInterfaceDecl::isVisibleExtension(ObjCCategoryDecl *Cat) { + return Cat->IsClassExtension() && !Cat->isHidden(); +} + +inline bool ObjCInterfaceDecl::isKnownExtension(ObjCCategoryDecl *Cat) { + return Cat->IsClassExtension(); +} + +} // end namespace clang +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/DeclOpenMP.h b/contrib/llvm/tools/clang/include/clang/AST/DeclOpenMP.h new file mode 100644 index 0000000..598f418 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/DeclOpenMP.h @@ -0,0 +1,91 @@ +//===- DeclOpenMP.h - Classes for representing OpenMP directives -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file defines OpenMP nodes for declarative directives. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DECLOPENMP_H +#define LLVM_CLANG_AST_DECLOPENMP_H + +#include "clang/AST/DeclBase.h" +#include "llvm/ADT/ArrayRef.h" + +namespace clang { +class Expr; + +/// \brief This represents '#pragma omp threadprivate ...' directive. +/// For example, in the following, both 'a' and 'A::b' are threadprivate: +/// +/// \code +/// int a; +/// #pragma omp threadprivate(a) +/// struct A { +/// static int b; +/// #pragma omp threadprivate(b) +/// }; +/// \endcode +/// +class OMPThreadPrivateDecl final + : public Decl, + private llvm::TrailingObjects<OMPThreadPrivateDecl, Expr *> { + friend class ASTDeclReader; + friend TrailingObjects; + + unsigned NumVars; + + virtual void anchor(); + + OMPThreadPrivateDecl(Kind DK, DeclContext *DC, SourceLocation L) : + Decl(DK, DC, L), NumVars(0) { } + + ArrayRef<const Expr *> getVars() const { + return llvm::makeArrayRef(getTrailingObjects<Expr *>(), NumVars); + } + + MutableArrayRef<Expr *> getVars() { + return MutableArrayRef<Expr *>(getTrailingObjects<Expr *>(), NumVars); + } + + void setVars(ArrayRef<Expr *> VL); + +public: + static OMPThreadPrivateDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + ArrayRef<Expr *> VL); + static OMPThreadPrivateDecl *CreateDeserialized(ASTContext &C, + unsigned ID, unsigned N); + + typedef MutableArrayRef<Expr *>::iterator varlist_iterator; + typedef ArrayRef<const Expr *>::iterator varlist_const_iterator; + typedef llvm::iterator_range<varlist_iterator> varlist_range; + typedef llvm::iterator_range<varlist_const_iterator> varlist_const_range; + + unsigned varlist_size() const { return NumVars; } + bool varlist_empty() const { return NumVars == 0; } + + varlist_range varlists() { + return varlist_range(varlist_begin(), varlist_end()); + } + varlist_const_range varlists() const { + return varlist_const_range(varlist_begin(), varlist_end()); + } + varlist_iterator varlist_begin() { return getVars().begin(); } + varlist_iterator varlist_end() { return getVars().end(); } + varlist_const_iterator varlist_begin() const { return getVars().begin(); } + varlist_const_iterator varlist_end() const { return getVars().end(); } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == OMPThreadPrivate; } +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/DeclTemplate.h b/contrib/llvm/tools/clang/include/clang/AST/DeclTemplate.h new file mode 100644 index 0000000..a9109ef --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/DeclTemplate.h @@ -0,0 +1,2927 @@ +//===-- DeclTemplate.h - Classes for representing C++ templates -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the C++ template declaration subclasses. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DECLTEMPLATE_H +#define LLVM_CLANG_AST_DECLTEMPLATE_H + +#include "clang/AST/DeclCXX.h" +#include "clang/AST/Redeclarable.h" +#include "clang/AST/TemplateBase.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/TrailingObjects.h" +#include <limits> + +namespace clang { + +enum BuiltinTemplateKind : int; +class TemplateParameterList; +class TemplateDecl; +class RedeclarableTemplateDecl; +class FunctionTemplateDecl; +class ClassTemplateDecl; +class ClassTemplatePartialSpecializationDecl; +class TemplateTypeParmDecl; +class NonTypeTemplateParmDecl; +class TemplateTemplateParmDecl; +class TypeAliasTemplateDecl; +class VarTemplateDecl; +class VarTemplatePartialSpecializationDecl; + +/// \brief Stores a template parameter of any kind. +typedef llvm::PointerUnion3<TemplateTypeParmDecl*, NonTypeTemplateParmDecl*, + TemplateTemplateParmDecl*> TemplateParameter; + +/// \brief Stores a list of template parameters for a TemplateDecl and its +/// derived classes. +class TemplateParameterList final + : private llvm::TrailingObjects<TemplateParameterList, NamedDecl *> { + + /// The location of the 'template' keyword. + SourceLocation TemplateLoc; + + /// The locations of the '<' and '>' angle brackets. + SourceLocation LAngleLoc, RAngleLoc; + + /// The number of template parameters in this template + /// parameter list. + unsigned NumParams : 31; + + /// Whether this template parameter list contains an unexpanded parameter + /// pack. + unsigned ContainsUnexpandedParameterPack : 1; + +protected: + size_t numTrailingObjects(OverloadToken<NamedDecl *>) const { + return NumParams; + } + + TemplateParameterList(SourceLocation TemplateLoc, SourceLocation LAngleLoc, + ArrayRef<NamedDecl *> Params, SourceLocation RAngleLoc); + +public: + static TemplateParameterList *Create(const ASTContext &C, + SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + ArrayRef<NamedDecl *> Params, + SourceLocation RAngleLoc); + + /// \brief Iterates through the template parameters in this list. + typedef NamedDecl** iterator; + + /// \brief Iterates through the template parameters in this list. + typedef NamedDecl* const* const_iterator; + + iterator begin() { return getTrailingObjects<NamedDecl *>(); } + const_iterator begin() const { return getTrailingObjects<NamedDecl *>(); } + iterator end() { return begin() + NumParams; } + const_iterator end() const { return begin() + NumParams; } + + unsigned size() const { return NumParams; } + + ArrayRef<NamedDecl*> asArray() { + return llvm::makeArrayRef(begin(), end()); + } + ArrayRef<const NamedDecl*> asArray() const { + return llvm::makeArrayRef(begin(), size()); + } + + NamedDecl* getParam(unsigned Idx) { + assert(Idx < size() && "Template parameter index out-of-range"); + return begin()[Idx]; + } + + const NamedDecl* getParam(unsigned Idx) const { + assert(Idx < size() && "Template parameter index out-of-range"); + return begin()[Idx]; + } + + /// \brief Returns the minimum number of arguments needed to form a + /// template specialization. + /// + /// This may be fewer than the number of template parameters, if some of + /// the parameters have default 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; + + /// \brief Determine whether this template parameter list contains an + /// unexpanded parameter pack. + bool containsUnexpandedParameterPack() const { + return ContainsUnexpandedParameterPack; + } + + SourceLocation getTemplateLoc() const { return TemplateLoc; } + SourceLocation getLAngleLoc() const { return LAngleLoc; } + SourceLocation getRAngleLoc() const { return RAngleLoc; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(TemplateLoc, RAngleLoc); + } + + friend TrailingObjects; + template <size_t N> friend class FixedSizeTemplateParameterListStorage; +}; + +/// \brief Stores a list of template parameters for a TemplateDecl and its +/// derived classes. Suitable for creating on the stack. +template <size_t N> class FixedSizeTemplateParameterListStorage { + // This is kinda ugly: TemplateParameterList usually gets allocated + // in a block of memory with NamedDecls appended to it. Here, to get + // it stack allocated, we include the params as a separate + // variable. After allocation, the TemplateParameterList object + // treats them as part of itself. + TemplateParameterList List; + NamedDecl *Params[N]; + +public: + FixedSizeTemplateParameterListStorage(SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + ArrayRef<NamedDecl *> Params, + SourceLocation RAngleLoc) + : List(TemplateLoc, LAngleLoc, Params, RAngleLoc) { + // Because we're doing an evil layout hack above, have some + // asserts, just to double-check everything is laid out like + // expected. + assert(sizeof(*this) == + TemplateParameterList::totalSizeToAlloc<NamedDecl *>(N) && + "Object layout not as expected"); + assert(this->Params == List.getTrailingObjects<NamedDecl *>() && + "Object layout not as expected"); + } + TemplateParameterList *get() { return &List; } +}; + +/// \brief A template argument list. +class TemplateArgumentList final + : private llvm::TrailingObjects<TemplateArgumentList, TemplateArgument> { + /// \brief The template argument list. + const TemplateArgument *Arguments; + + /// \brief The number of template arguments in this template + /// argument list. + unsigned NumArguments; + + TemplateArgumentList(const TemplateArgumentList &Other) = delete; + void operator=(const TemplateArgumentList &Other) = delete; + + // Constructs an instance with an internal Argument list, containing + // a copy of the Args array. (Called by CreateCopy) + TemplateArgumentList(const TemplateArgument *Args, unsigned NumArgs); + +public: + /// \brief Type used to indicate that the template argument list itself is a + /// stack object. It does not own its template arguments. + enum OnStackType { OnStack }; + + /// \brief Create a new template argument list that copies the given set of + /// template arguments. + static TemplateArgumentList *CreateCopy(ASTContext &Context, + const TemplateArgument *Args, + unsigned NumArgs); + + /// \brief Construct a new, temporary template argument list on the stack. + /// + /// The template argument list does not own the template arguments + /// provided. + explicit TemplateArgumentList(OnStackType, const TemplateArgument *Args, + unsigned NumArgs) + : Arguments(Args), NumArguments(NumArgs) {} + + /// \brief Produces a shallow copy of the given template argument list. + /// + /// This operation assumes that the input argument list outlives it. + /// This takes the list as a pointer to avoid looking like a copy + /// constructor, since this really really isn't safe to use that + /// way. + explicit TemplateArgumentList(const TemplateArgumentList *Other) + : Arguments(Other->data()), NumArguments(Other->size()) {} + + /// \brief Retrieve the template argument at a given index. + const TemplateArgument &get(unsigned Idx) const { + assert(Idx < NumArguments && "Invalid template argument index"); + return data()[Idx]; + } + + /// \brief Retrieve the template argument at a given index. + const TemplateArgument &operator[](unsigned Idx) const { return get(Idx); } + + /// \brief Produce this as an array ref. + ArrayRef<TemplateArgument> asArray() const { + return llvm::makeArrayRef(data(), size()); + } + + /// \brief Retrieve the number of template arguments in this + /// template argument list. + unsigned size() const { return NumArguments; } + + /// \brief Retrieve a pointer to the template argument list. + const TemplateArgument *data() const { return Arguments; } + + friend TrailingObjects; +}; + +void *allocateDefaultArgStorageChain(const ASTContext &C); + +/// Storage for a default argument. This is conceptually either empty, or an +/// argument value, or a pointer to a previous declaration that had a default +/// argument. +/// +/// However, this is complicated by modules: while we require all the default +/// arguments for a template to be equivalent, there may be more than one, and +/// we need to track all the originating parameters to determine if the default +/// argument is visible. +template<typename ParmDecl, typename ArgType> +class DefaultArgStorage { + /// Storage for both the value *and* another parameter from which we inherit + /// the default argument. This is used when multiple default arguments for a + /// parameter are merged together from different modules. + struct Chain { + ParmDecl *PrevDeclWithDefaultArg; + ArgType Value; + }; + static_assert(sizeof(Chain) == sizeof(void *) * 2, + "non-pointer argument type?"); + + llvm::PointerUnion3<ArgType, ParmDecl*, Chain*> ValueOrInherited; + + static ParmDecl *getParmOwningDefaultArg(ParmDecl *Parm) { + const DefaultArgStorage &Storage = Parm->getDefaultArgStorage(); + if (auto *Prev = Storage.ValueOrInherited.template dyn_cast<ParmDecl*>()) + Parm = Prev; + assert(!Parm->getDefaultArgStorage() + .ValueOrInherited.template is<ParmDecl *>() && + "should only be one level of indirection"); + return Parm; + } + +public: + DefaultArgStorage() : ValueOrInherited(ArgType()) {} + + /// Determine whether there is a default argument for this parameter. + bool isSet() const { return !ValueOrInherited.isNull(); } + /// Determine whether the default argument for this parameter was inherited + /// from a previous declaration of the same entity. + bool isInherited() const { return ValueOrInherited.template is<ParmDecl*>(); } + /// Get the default argument's value. This does not consider whether the + /// default argument is visible. + ArgType get() const { + const DefaultArgStorage *Storage = this; + if (auto *Prev = ValueOrInherited.template dyn_cast<ParmDecl*>()) + Storage = &Prev->getDefaultArgStorage(); + if (auto *C = Storage->ValueOrInherited.template dyn_cast<Chain*>()) + return C->Value; + return Storage->ValueOrInherited.template get<ArgType>(); + } + /// Get the parameter from which we inherit the default argument, if any. + /// This is the parameter on which the default argument was actually written. + const ParmDecl *getInheritedFrom() const { + if (auto *D = ValueOrInherited.template dyn_cast<ParmDecl*>()) + return D; + if (auto *C = ValueOrInherited.template dyn_cast<Chain*>()) + return C->PrevDeclWithDefaultArg; + return nullptr; + } + /// Set the default argument. + void set(ArgType Arg) { + assert(!isSet() && "default argument already set"); + ValueOrInherited = Arg; + } + /// Set that the default argument was inherited from another parameter. + void setInherited(const ASTContext &C, ParmDecl *InheritedFrom) { + assert(!isInherited() && "default argument already inherited"); + InheritedFrom = getParmOwningDefaultArg(InheritedFrom); + if (!isSet()) + ValueOrInherited = InheritedFrom; + else + ValueOrInherited = new (allocateDefaultArgStorageChain(C)) + Chain{InheritedFrom, ValueOrInherited.template get<ArgType>()}; + } + /// Remove the default argument, even if it was inherited. + void clear() { + ValueOrInherited = ArgType(); + } +}; + +//===----------------------------------------------------------------------===// +// Kinds of Templates +//===----------------------------------------------------------------------===// + +/// \brief The base class of all kinds of template declarations (e.g., +/// class, function, etc.). +/// +/// The TemplateDecl class stores the list of template parameters and a +/// reference to the templated scoped declaration: the underlying AST node. +class TemplateDecl : public NamedDecl { + void anchor() override; +protected: + // This is probably never used. + TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, + DeclarationName Name) + : NamedDecl(DK, DC, L, Name), TemplatedDecl(nullptr), + TemplateParams(nullptr) {} + + // Construct a template decl with the given name and parameters. + // Used when there is not templated element (tt-params). + TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, + DeclarationName Name, TemplateParameterList *Params) + : NamedDecl(DK, DC, L, Name), TemplatedDecl(nullptr), + TemplateParams(Params) {} + + // Construct a template decl with name, parameters, and templated element. + TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, + DeclarationName Name, TemplateParameterList *Params, + NamedDecl *Decl) + : NamedDecl(DK, DC, L, Name), TemplatedDecl(Decl), + TemplateParams(Params) { } +public: + /// Get the list of template parameters + TemplateParameterList *getTemplateParameters() const { + return TemplateParams; + } + + /// Get the underlying, templated declaration. + NamedDecl *getTemplatedDecl() const { return TemplatedDecl; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { + return K >= firstTemplate && K <= lastTemplate; + } + + SourceRange getSourceRange() const override LLVM_READONLY { + return SourceRange(TemplateParams->getTemplateLoc(), + TemplatedDecl->getSourceRange().getEnd()); + } + +protected: + NamedDecl *TemplatedDecl; + TemplateParameterList* TemplateParams; + +public: + /// \brief Initialize the underlying templated declaration and + /// template parameters. + void init(NamedDecl *templatedDecl, TemplateParameterList* templateParams) { + assert(!TemplatedDecl && "TemplatedDecl already set!"); + assert(!TemplateParams && "TemplateParams already set!"); + TemplatedDecl = templatedDecl; + TemplateParams = templateParams; + } +}; + +/// \brief Provides information about a function template specialization, +/// which is a FunctionDecl that has been explicitly specialization or +/// instantiated from a function template. +class FunctionTemplateSpecializationInfo : public llvm::FoldingSetNode { + FunctionTemplateSpecializationInfo(FunctionDecl *FD, + FunctionTemplateDecl *Template, + TemplateSpecializationKind TSK, + const TemplateArgumentList *TemplateArgs, + const ASTTemplateArgumentListInfo *TemplateArgsAsWritten, + SourceLocation POI) + : Function(FD), + Template(Template, TSK - 1), + TemplateArguments(TemplateArgs), + TemplateArgumentsAsWritten(TemplateArgsAsWritten), + PointOfInstantiation(POI) { } + +public: + static FunctionTemplateSpecializationInfo * + Create(ASTContext &C, FunctionDecl *FD, FunctionTemplateDecl *Template, + TemplateSpecializationKind TSK, + const TemplateArgumentList *TemplateArgs, + const TemplateArgumentListInfo *TemplateArgsAsWritten, + SourceLocation POI); + + /// \brief The function template specialization that this structure + /// describes. + FunctionDecl *Function; + + /// \brief The function template from which this function template + /// specialization was generated. + /// + /// The two bits contain the top 4 values of TemplateSpecializationKind. + llvm::PointerIntPair<FunctionTemplateDecl *, 2> Template; + + /// \brief The template arguments used to produce the function template + /// specialization from the function template. + const TemplateArgumentList *TemplateArguments; + + /// \brief The template arguments as written in the sources, if provided. + const ASTTemplateArgumentListInfo *TemplateArgumentsAsWritten; + + /// \brief The point at which this function template specialization was + /// first instantiated. + SourceLocation PointOfInstantiation; + + /// \brief Retrieve the template from which this function was specialized. + FunctionTemplateDecl *getTemplate() const { return Template.getPointer(); } + + /// \brief Determine what kind of template specialization this is. + TemplateSpecializationKind getTemplateSpecializationKind() const { + return (TemplateSpecializationKind)(Template.getInt() + 1); + } + + bool isExplicitSpecialization() const { + return getTemplateSpecializationKind() == TSK_ExplicitSpecialization; + } + + /// \brief True if this declaration is an explicit specialization, + /// explicit instantiation declaration, or explicit instantiation + /// definition. + bool isExplicitInstantiationOrSpecialization() const { + return isTemplateExplicitInstantiationOrSpecialization( + getTemplateSpecializationKind()); + } + + /// \brief Set the template specialization kind. + void setTemplateSpecializationKind(TemplateSpecializationKind TSK) { + assert(TSK != TSK_Undeclared && + "Cannot encode TSK_Undeclared for a function template specialization"); + Template.setInt(TSK - 1); + } + + /// \brief Retrieve the first point of instantiation of this function + /// template specialization. + /// + /// The point of instantiation may be an invalid source location if this + /// function has yet to be instantiated. + SourceLocation getPointOfInstantiation() const { + return PointOfInstantiation; + } + + /// \brief Set the (first) point of instantiation of this function template + /// specialization. + void setPointOfInstantiation(SourceLocation POI) { + PointOfInstantiation = POI; + } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, TemplateArguments->asArray(), + Function->getASTContext()); + } + + static void + Profile(llvm::FoldingSetNodeID &ID, ArrayRef<TemplateArgument> TemplateArgs, + ASTContext &Context) { + ID.AddInteger(TemplateArgs.size()); + for (unsigned Arg = 0; Arg != TemplateArgs.size(); ++Arg) + TemplateArgs[Arg].Profile(ID, Context); + } +}; + +/// \brief Provides information a specialization of a member of a class +/// template, which may be a member function, static data member, +/// member class or member enumeration. +class MemberSpecializationInfo { + // The member declaration from which this member was instantiated, and the + // manner in which the instantiation occurred (in the lower two bits). + llvm::PointerIntPair<NamedDecl *, 2> MemberAndTSK; + + // The point at which this member was first instantiated. + SourceLocation PointOfInstantiation; + +public: + explicit + MemberSpecializationInfo(NamedDecl *IF, TemplateSpecializationKind TSK, + SourceLocation POI = SourceLocation()) + : MemberAndTSK(IF, TSK - 1), PointOfInstantiation(POI) { + assert(TSK != TSK_Undeclared && + "Cannot encode undeclared template specializations for members"); + } + + /// \brief Retrieve the member declaration from which this member was + /// instantiated. + NamedDecl *getInstantiatedFrom() const { return MemberAndTSK.getPointer(); } + + /// \brief Determine what kind of template specialization this is. + TemplateSpecializationKind getTemplateSpecializationKind() const { + return (TemplateSpecializationKind)(MemberAndTSK.getInt() + 1); + } + + bool isExplicitSpecialization() const { + return getTemplateSpecializationKind() == TSK_ExplicitSpecialization; + } + + /// \brief Set the template specialization kind. + void setTemplateSpecializationKind(TemplateSpecializationKind TSK) { + assert(TSK != TSK_Undeclared && + "Cannot encode undeclared template specializations for members"); + MemberAndTSK.setInt(TSK - 1); + } + + /// \brief Retrieve the first point of instantiation of this member. + /// If the point of instantiation is an invalid location, then this member + /// has not yet been instantiated. + SourceLocation getPointOfInstantiation() const { + return PointOfInstantiation; + } + + /// \brief Set the first point of instantiation. + void setPointOfInstantiation(SourceLocation POI) { + PointOfInstantiation = POI; + } +}; + +/// \brief Provides information about a dependent function-template +/// specialization declaration. +/// +/// Since explicit function template specialization and instantiation +/// declarations can only appear in namespace scope, and you can only +/// specialize a member of a fully-specialized class, the only way to +/// get one of these is in a friend declaration like the following: +/// +/// \code +/// template \<class T> void foo(T); +/// template \<class T> class A { +/// friend void foo<>(T); +/// }; +/// \endcode +class DependentFunctionTemplateSpecializationInfo final + : private llvm::TrailingObjects<DependentFunctionTemplateSpecializationInfo, + TemplateArgumentLoc, + FunctionTemplateDecl *> { + /// The number of potential template candidates. + unsigned NumTemplates; + + /// The number of template arguments. + unsigned NumArgs; + + /// The locations of the left and right angle brackets. + SourceRange AngleLocs; + + size_t numTrailingObjects(OverloadToken<TemplateArgumentLoc>) const { + return NumArgs; + } + size_t numTrailingObjects(OverloadToken<FunctionTemplateDecl *>) const { + return NumTemplates; + } + + DependentFunctionTemplateSpecializationInfo( + const UnresolvedSetImpl &Templates, + const TemplateArgumentListInfo &TemplateArgs); + +public: + static DependentFunctionTemplateSpecializationInfo * + Create(ASTContext &Context, const UnresolvedSetImpl &Templates, + const TemplateArgumentListInfo &TemplateArgs); + + /// \brief Returns the number of function templates that this might + /// be a specialization of. + unsigned getNumTemplates() const { return NumTemplates; } + + /// \brief Returns the i'th template candidate. + FunctionTemplateDecl *getTemplate(unsigned I) const { + assert(I < getNumTemplates() && "template index out of range"); + return getTrailingObjects<FunctionTemplateDecl *>()[I]; + } + + /// \brief Returns the explicit template arguments that were given. + const TemplateArgumentLoc *getTemplateArgs() const { + return getTrailingObjects<TemplateArgumentLoc>(); + } + + /// \brief Returns the number of explicit template arguments that were given. + unsigned getNumTemplateArgs() const { return NumArgs; } + + /// \brief Returns the nth template argument. + const TemplateArgumentLoc &getTemplateArg(unsigned I) const { + assert(I < getNumTemplateArgs() && "template arg index out of range"); + return getTemplateArgs()[I]; + } + + SourceLocation getLAngleLoc() const { + return AngleLocs.getBegin(); + } + + SourceLocation getRAngleLoc() const { + return AngleLocs.getEnd(); + } + + friend TrailingObjects; +}; + +/// Declaration of a redeclarable template. +class RedeclarableTemplateDecl : public TemplateDecl, + public Redeclarable<RedeclarableTemplateDecl> +{ + typedef Redeclarable<RedeclarableTemplateDecl> redeclarable_base; + RedeclarableTemplateDecl *getNextRedeclarationImpl() override { + return getNextRedeclaration(); + } + RedeclarableTemplateDecl *getPreviousDeclImpl() override { + return getPreviousDecl(); + } + RedeclarableTemplateDecl *getMostRecentDeclImpl() override { + return getMostRecentDecl(); + } + +protected: + template <typename EntryType> struct SpecEntryTraits { + typedef EntryType DeclType; + + static DeclType *getDecl(EntryType *D) { + return D; + } + static ArrayRef<TemplateArgument> getTemplateArgs(EntryType *D) { + return D->getTemplateArgs().asArray(); + } + }; + + template <typename EntryType, typename SETraits = SpecEntryTraits<EntryType>, + typename DeclType = typename SETraits::DeclType> + struct SpecIterator + : llvm::iterator_adaptor_base< + SpecIterator<EntryType, SETraits, DeclType>, + typename llvm::FoldingSetVector<EntryType>::iterator, + typename std::iterator_traits<typename llvm::FoldingSetVector< + EntryType>::iterator>::iterator_category, + DeclType *, ptrdiff_t, DeclType *, DeclType *> { + SpecIterator() {} + explicit SpecIterator( + typename llvm::FoldingSetVector<EntryType>::iterator SetIter) + : SpecIterator::iterator_adaptor_base(std::move(SetIter)) {} + + DeclType *operator*() const { + return SETraits::getDecl(&*this->I)->getMostRecentDecl(); + } + DeclType *operator->() const { return **this; } + }; + + template <typename EntryType> + static SpecIterator<EntryType> + makeSpecIterator(llvm::FoldingSetVector<EntryType> &Specs, bool isEnd) { + return SpecIterator<EntryType>(isEnd ? Specs.end() : Specs.begin()); + } + + template <class EntryType> typename SpecEntryTraits<EntryType>::DeclType* + findSpecializationImpl(llvm::FoldingSetVector<EntryType> &Specs, + ArrayRef<TemplateArgument> Args, void *&InsertPos); + + template <class Derived, class EntryType> + void addSpecializationImpl(llvm::FoldingSetVector<EntryType> &Specs, + EntryType *Entry, void *InsertPos); + + struct CommonBase { + CommonBase() : InstantiatedFromMember(nullptr, false) { } + + /// \brief The template from which this was most + /// directly instantiated (or null). + /// + /// The boolean value indicates whether this template + /// was explicitly specialized. + llvm::PointerIntPair<RedeclarableTemplateDecl*, 1, bool> + InstantiatedFromMember; + }; + + /// \brief Pointer to the common data shared by all declarations of this + /// template. + mutable CommonBase *Common; + + /// \brief Retrieves the "common" pointer shared by all (re-)declarations of + /// the same template. Calling this routine may implicitly allocate memory + /// for the common pointer. + CommonBase *getCommonPtr() const; + + virtual CommonBase *newCommon(ASTContext &C) const = 0; + + // Construct a template decl with name, parameters, and templated element. + RedeclarableTemplateDecl(Kind DK, ASTContext &C, DeclContext *DC, + SourceLocation L, DeclarationName Name, + TemplateParameterList *Params, NamedDecl *Decl) + : TemplateDecl(DK, DC, L, Name, Params, Decl), redeclarable_base(C), + Common() {} + +public: + template <class decl_type> friend class RedeclarableTemplate; + + /// \brief Retrieves the canonical declaration of this template. + RedeclarableTemplateDecl *getCanonicalDecl() override { + return getFirstDecl(); + } + const RedeclarableTemplateDecl *getCanonicalDecl() const { + return getFirstDecl(); + } + + /// \brief Determines whether this template was a specialization of a + /// member template. + /// + /// In the following example, the function template \c X<int>::f and the + /// member template \c X<int>::Inner are member specializations. + /// + /// \code + /// template<typename T> + /// struct X { + /// template<typename U> void f(T, U); + /// template<typename U> struct Inner; + /// }; + /// + /// template<> template<typename T> + /// void X<int>::f(int, T); + /// template<> template<typename T> + /// struct X<int>::Inner { /* ... */ }; + /// \endcode + bool isMemberSpecialization() const { + return getCommonPtr()->InstantiatedFromMember.getInt(); + } + + /// \brief Note that this member template is a specialization. + void setMemberSpecialization() { + assert(getCommonPtr()->InstantiatedFromMember.getPointer() && + "Only member templates can be member template specializations"); + getCommonPtr()->InstantiatedFromMember.setInt(true); + } + + /// \brief Retrieve the member template from which this template was + /// instantiated, or NULL if this template was not instantiated from a + /// member template. + /// + /// A template is instantiated from a member template when the member + /// template itself is part of a class template (or member thereof). For + /// example, given + /// + /// \code + /// template<typename T> + /// struct X { + /// template<typename U> void f(T, U); + /// }; + /// + /// void test(X<int> x) { + /// x.f(1, 'a'); + /// }; + /// \endcode + /// + /// \c X<int>::f is a FunctionTemplateDecl that describes the function + /// template + /// + /// \code + /// template<typename U> void X<int>::f(int, U); + /// \endcode + /// + /// which was itself created during the instantiation of \c X<int>. Calling + /// getInstantiatedFromMemberTemplate() on this FunctionTemplateDecl will + /// retrieve the FunctionTemplateDecl for the original template \c f within + /// the class template \c X<T>, i.e., + /// + /// \code + /// template<typename T> + /// template<typename U> + /// void X<T>::f(T, U); + /// \endcode + RedeclarableTemplateDecl *getInstantiatedFromMemberTemplate() const { + return getCommonPtr()->InstantiatedFromMember.getPointer(); + } + + void setInstantiatedFromMemberTemplate(RedeclarableTemplateDecl *TD) { + assert(!getCommonPtr()->InstantiatedFromMember.getPointer()); + getCommonPtr()->InstantiatedFromMember.setPointer(TD); + } + + typedef redeclarable_base::redecl_range redecl_range; + typedef redeclarable_base::redecl_iterator redecl_iterator; + using redeclarable_base::redecls_begin; + using redeclarable_base::redecls_end; + using redeclarable_base::redecls; + using redeclarable_base::getPreviousDecl; + using redeclarable_base::getMostRecentDecl; + using redeclarable_base::isFirstDecl; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { + return K >= firstRedeclarableTemplate && K <= lastRedeclarableTemplate; + } + + friend class ASTReader; + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +template <> struct RedeclarableTemplateDecl:: +SpecEntryTraits<FunctionTemplateSpecializationInfo> { + typedef FunctionDecl DeclType; + + static DeclType *getDecl(FunctionTemplateSpecializationInfo *I) { + return I->Function; + } + static ArrayRef<TemplateArgument> + getTemplateArgs(FunctionTemplateSpecializationInfo *I) { + return I->TemplateArguments->asArray(); + } +}; + +/// Declaration of a template function. +class FunctionTemplateDecl : public RedeclarableTemplateDecl { + static void DeallocateCommon(void *Ptr); + +protected: + /// \brief Data that is common to all of the declarations of a given + /// function template. + struct Common : CommonBase { + Common() : InjectedArgs(), LazySpecializations() { } + + /// \brief The function template specializations for this function + /// template, including explicit specializations and instantiations. + llvm::FoldingSetVector<FunctionTemplateSpecializationInfo> Specializations; + + /// \brief The set of "injected" template arguments used within this + /// function template. + /// + /// This pointer refers to the template arguments (there are as + /// many template arguments as template parameaters) for the function + /// template, and is allocated lazily, since most function templates do not + /// require the use of this information. + TemplateArgument *InjectedArgs; + + /// \brief If non-null, points to an array of specializations known only + /// by their external declaration IDs. + /// + /// The first value in the array is the number of of specializations + /// that follow. + uint32_t *LazySpecializations; + }; + + FunctionTemplateDecl(ASTContext &C, DeclContext *DC, SourceLocation L, + DeclarationName Name, TemplateParameterList *Params, + NamedDecl *Decl) + : RedeclarableTemplateDecl(FunctionTemplate, C, DC, L, Name, Params, + Decl) {} + + CommonBase *newCommon(ASTContext &C) const override; + + Common *getCommonPtr() const { + return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr()); + } + + friend class FunctionDecl; + + /// \brief Retrieve the set of function template specializations of this + /// function template. + llvm::FoldingSetVector<FunctionTemplateSpecializationInfo> & + getSpecializations() const; + + /// \brief Add a specialization of this function template. + /// + /// \param InsertPos Insert position in the FoldingSetVector, must have been + /// retrieved by an earlier call to findSpecialization(). + void addSpecialization(FunctionTemplateSpecializationInfo* Info, + void *InsertPos); + +public: + /// \brief Load any lazily-loaded specializations from the external source. + void LoadLazySpecializations() const; + + /// Get the underlying function declaration of the template. + FunctionDecl *getTemplatedDecl() const { + return static_cast<FunctionDecl*>(TemplatedDecl); + } + + /// Returns whether this template declaration defines the primary + /// pattern. + bool isThisDeclarationADefinition() const { + return getTemplatedDecl()->isThisDeclarationADefinition(); + } + + /// \brief Return the specialization with the provided arguments if it exists, + /// otherwise return the insertion point. + FunctionDecl *findSpecialization(ArrayRef<TemplateArgument> Args, + void *&InsertPos); + + FunctionTemplateDecl *getCanonicalDecl() override { + return cast<FunctionTemplateDecl>( + RedeclarableTemplateDecl::getCanonicalDecl()); + } + const FunctionTemplateDecl *getCanonicalDecl() const { + return cast<FunctionTemplateDecl>( + RedeclarableTemplateDecl::getCanonicalDecl()); + } + + /// \brief Retrieve the previous declaration of this function template, or + /// NULL if no such declaration exists. + FunctionTemplateDecl *getPreviousDecl() { + return cast_or_null<FunctionTemplateDecl>( + static_cast<RedeclarableTemplateDecl *>(this)->getPreviousDecl()); + } + + /// \brief Retrieve the previous declaration of this function template, or + /// NULL if no such declaration exists. + const FunctionTemplateDecl *getPreviousDecl() const { + return cast_or_null<FunctionTemplateDecl>( + static_cast<const RedeclarableTemplateDecl *>(this)->getPreviousDecl()); + } + + FunctionTemplateDecl *getMostRecentDecl() { + return cast<FunctionTemplateDecl>( + static_cast<RedeclarableTemplateDecl *>(this) + ->getMostRecentDecl()); + } + const FunctionTemplateDecl *getMostRecentDecl() const { + return const_cast<FunctionTemplateDecl*>(this)->getMostRecentDecl(); + } + + FunctionTemplateDecl *getInstantiatedFromMemberTemplate() const { + return cast_or_null<FunctionTemplateDecl>( + RedeclarableTemplateDecl::getInstantiatedFromMemberTemplate()); + } + + typedef SpecIterator<FunctionTemplateSpecializationInfo> spec_iterator; + typedef llvm::iterator_range<spec_iterator> spec_range; + + spec_range specializations() const { + return spec_range(spec_begin(), spec_end()); + } + spec_iterator spec_begin() const { + return makeSpecIterator(getSpecializations(), false); + } + + spec_iterator spec_end() const { + return makeSpecIterator(getSpecializations(), true); + } + + /// \brief Retrieve the "injected" template arguments that correspond to the + /// template parameters of this function template. + /// + /// Although the C++ standard has no notion of the "injected" template + /// arguments for a function template, the notion is convenient when + /// we need to perform substitutions inside the definition of a function + /// template. + ArrayRef<TemplateArgument> getInjectedTemplateArgs(); + + /// \brief Create a function template node. + static FunctionTemplateDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + DeclarationName Name, + TemplateParameterList *Params, + NamedDecl *Decl); + + /// \brief Create an empty function template node. + static FunctionTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + // Implement isa/cast/dyncast support + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == FunctionTemplate; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +//===----------------------------------------------------------------------===// +// Kinds of Template Parameters +//===----------------------------------------------------------------------===// + +/// \brief Defines the position of a template parameter within a template +/// parameter list. +/// +/// Because template parameter can be listed +/// sequentially for out-of-line template members, each template parameter is +/// given a Depth - the nesting of template parameter scopes - and a Position - +/// the occurrence within the parameter list. +/// This class is inheritedly privately by different kinds of template +/// parameters and is not part of the Decl hierarchy. Just a facility. +class TemplateParmPosition { + TemplateParmPosition() = delete; + +protected: + TemplateParmPosition(unsigned D, unsigned P) + : Depth(D), Position(P) + { } + + // FIXME: These probably don't need to be ints. int:5 for depth, int:8 for + // position? Maybe? + unsigned Depth; + unsigned Position; + +public: + /// Get the nesting depth of the template parameter. + unsigned getDepth() const { return Depth; } + void setDepth(unsigned D) { Depth = D; } + + /// Get the position of the template parameter within its parameter list. + unsigned getPosition() const { return Position; } + void setPosition(unsigned P) { Position = P; } + + /// Get the index of the template parameter within its parameter list. + unsigned getIndex() const { return Position; } +}; + +/// \brief Declaration of a template type parameter. +/// +/// For example, "T" in +/// \code +/// template<typename T> class vector; +/// \endcode +class TemplateTypeParmDecl : public TypeDecl { + /// \brief Whether this template type parameter was declaration with + /// the 'typename' keyword. + /// + /// If false, it was declared with the 'class' keyword. + bool Typename : 1; + + /// \brief The default template argument, if any. + typedef DefaultArgStorage<TemplateTypeParmDecl, TypeSourceInfo *> + DefArgStorage; + DefArgStorage DefaultArgument; + + TemplateTypeParmDecl(DeclContext *DC, SourceLocation KeyLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + bool Typename) + : TypeDecl(TemplateTypeParm, DC, IdLoc, Id, KeyLoc), Typename(Typename), + DefaultArgument() { } + + /// Sema creates these on the stack during auto type deduction. + friend class Sema; + +public: + static TemplateTypeParmDecl *Create(const ASTContext &C, DeclContext *DC, + SourceLocation KeyLoc, + SourceLocation NameLoc, + unsigned D, unsigned P, + IdentifierInfo *Id, bool Typename, + bool ParameterPack); + static TemplateTypeParmDecl *CreateDeserialized(const ASTContext &C, + unsigned ID); + + /// \brief Whether this template type parameter was declared with + /// the 'typename' keyword. + /// + /// If not, it was declared with the 'class' keyword. + bool wasDeclaredWithTypename() const { return Typename; } + + const DefArgStorage &getDefaultArgStorage() const { return DefaultArgument; } + + /// \brief Determine whether this template parameter has a default + /// argument. + bool hasDefaultArgument() const { return DefaultArgument.isSet(); } + + /// \brief Retrieve the default argument, if any. + QualType getDefaultArgument() const { + return DefaultArgument.get()->getType(); + } + + /// \brief Retrieves the default argument's source information, if any. + TypeSourceInfo *getDefaultArgumentInfo() const { + return DefaultArgument.get(); + } + + /// \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. + bool defaultArgumentWasInherited() const { + return DefaultArgument.isInherited(); + } + + /// \brief Set the default argument for this template parameter. + void setDefaultArgument(TypeSourceInfo *DefArg) { + DefaultArgument.set(DefArg); + } + /// \brief Set that this default argument was inherited from another + /// parameter. + void setInheritedDefaultArgument(const ASTContext &C, + TemplateTypeParmDecl *Prev) { + DefaultArgument.setInherited(C, Prev); + } + + /// \brief Removes the default argument of this template parameter. + void removeDefaultArgument() { + DefaultArgument.clear(); + } + + /// \brief Set whether this template type parameter was declared with + /// the 'typename' or 'class' keyword. + void setDeclaredWithTypename(bool withTypename) { Typename = withTypename; } + + /// \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; + + SourceRange getSourceRange() const override LLVM_READONLY; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == TemplateTypeParm; } +}; + +/// NonTypeTemplateParmDecl - Declares a non-type template parameter, +/// e.g., "Size" in +/// @code +/// template<int Size> class array { }; +/// @endcode +class NonTypeTemplateParmDecl final + : public DeclaratorDecl, + protected TemplateParmPosition, + private llvm::TrailingObjects<NonTypeTemplateParmDecl, + std::pair<QualType, TypeSourceInfo *>> { + /// \brief The default template argument, if any, and whether or not + /// it was inherited. + typedef DefaultArgStorage<NonTypeTemplateParmDecl, Expr*> DefArgStorage; + DefArgStorage DefaultArgument; + + // FIXME: Collapse this into TemplateParamPosition; or, just move depth/index + // down here to save memory. + + /// \brief Whether this non-type template parameter is a parameter pack. + bool ParameterPack; + + /// \brief Whether this non-type template parameter is an "expanded" + /// parameter pack, meaning that its type is a pack expansion and we + /// already know the set of types that expansion expands to. + bool ExpandedParameterPack; + + /// \brief The number of types in an expanded parameter pack. + unsigned NumExpandedTypes; + + size_t numTrailingObjects( + OverloadToken<std::pair<QualType, TypeSourceInfo *>>) const { + return NumExpandedTypes; + } + + NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, unsigned D, unsigned P, + IdentifierInfo *Id, QualType T, + bool ParameterPack, TypeSourceInfo *TInfo) + : DeclaratorDecl(NonTypeTemplateParm, DC, IdLoc, Id, T, TInfo, StartLoc), + TemplateParmPosition(D, P), ParameterPack(ParameterPack), + ExpandedParameterPack(false), NumExpandedTypes(0) + { } + + NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, unsigned D, unsigned P, + IdentifierInfo *Id, QualType T, + TypeSourceInfo *TInfo, + const QualType *ExpandedTypes, + unsigned NumExpandedTypes, + TypeSourceInfo **ExpandedTInfos); + + friend class ASTDeclReader; + friend TrailingObjects; + +public: + static NonTypeTemplateParmDecl * + Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, unsigned D, unsigned P, IdentifierInfo *Id, + QualType T, bool ParameterPack, TypeSourceInfo *TInfo); + + static NonTypeTemplateParmDecl * + Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, unsigned D, unsigned P, IdentifierInfo *Id, + QualType T, TypeSourceInfo *TInfo, + const QualType *ExpandedTypes, unsigned NumExpandedTypes, + TypeSourceInfo **ExpandedTInfos); + + static NonTypeTemplateParmDecl *CreateDeserialized(ASTContext &C, + unsigned ID); + static NonTypeTemplateParmDecl *CreateDeserialized(ASTContext &C, + unsigned ID, + unsigned NumExpandedTypes); + + using TemplateParmPosition::getDepth; + using TemplateParmPosition::setDepth; + using TemplateParmPosition::getPosition; + using TemplateParmPosition::setPosition; + using TemplateParmPosition::getIndex; + + SourceRange getSourceRange() const override LLVM_READONLY; + + const DefArgStorage &getDefaultArgStorage() const { return DefaultArgument; } + + /// \brief Determine whether this template parameter has a default + /// argument. + bool hasDefaultArgument() const { return DefaultArgument.isSet(); } + + /// \brief Retrieve the default argument, if any. + Expr *getDefaultArgument() const { return DefaultArgument.get(); } + + /// \brief Retrieve the location of the default argument, if any. + SourceLocation getDefaultArgumentLoc() const; + + /// \brief Determines whether the default argument was inherited + /// from a previous declaration of this template. + bool defaultArgumentWasInherited() const { + return DefaultArgument.isInherited(); + } + + /// \brief Set the default argument for this template parameter, and + /// whether that default argument was inherited from another + /// declaration. + void setDefaultArgument(Expr *DefArg) { DefaultArgument.set(DefArg); } + void setInheritedDefaultArgument(const ASTContext &C, + NonTypeTemplateParmDecl *Parm) { + DefaultArgument.setInherited(C, Parm); + } + + /// \brief Removes the default argument of this template parameter. + void removeDefaultArgument() { DefaultArgument.clear(); } + + /// \brief Whether this parameter is a non-type template parameter pack. + /// + /// If the parameter is a parameter pack, the type may be a + /// \c PackExpansionType. In the following example, the \c Dims parameter + /// is a parameter pack (whose type is 'unsigned'). + /// + /// \code + /// template<typename T, unsigned ...Dims> struct multi_array; + /// \endcode + bool isParameterPack() const { return ParameterPack; } + + /// \brief Whether this parameter pack is a pack expansion. + /// + /// A non-type template parameter pack is a pack expansion if its type + /// contains an unexpanded parameter pack. In this case, we will have + /// built a PackExpansionType wrapping the type. + bool isPackExpansion() const { + return ParameterPack && getType()->getAs<PackExpansionType>(); + } + + /// \brief Whether this parameter is a non-type template parameter pack + /// that has a known list of different types at different positions. + /// + /// A parameter pack is an expanded parameter pack when the original + /// parameter pack's type was itself a pack expansion, and that expansion + /// has already been expanded. For example, given: + /// + /// \code + /// template<typename ...Types> + /// struct X { + /// template<Types ...Values> + /// struct Y { /* ... */ }; + /// }; + /// \endcode + /// + /// The parameter pack \c Values has a \c PackExpansionType as its type, + /// which expands \c Types. When \c Types is supplied with template arguments + /// by instantiating \c X, the instantiation of \c Values becomes an + /// expanded parameter pack. For example, instantiating + /// \c X<int, unsigned int> results in \c Values being an expanded parameter + /// pack with expansion types \c int and \c unsigned int. + /// + /// The \c getExpansionType() and \c getExpansionTypeSourceInfo() functions + /// return the expansion types. + bool isExpandedParameterPack() const { return ExpandedParameterPack; } + + /// \brief Retrieves the number of expansion types in an expanded parameter + /// pack. + unsigned getNumExpansionTypes() const { + assert(ExpandedParameterPack && "Not an expansion parameter pack"); + return NumExpandedTypes; + } + + /// \brief Retrieve a particular expansion type within an expanded parameter + /// pack. + QualType getExpansionType(unsigned I) const { + assert(I < NumExpandedTypes && "Out-of-range expansion type index"); + auto TypesAndInfos = + getTrailingObjects<std::pair<QualType, TypeSourceInfo *>>(); + return TypesAndInfos[I].first; + } + + /// \brief Retrieve a particular expansion type source info within an + /// expanded parameter pack. + TypeSourceInfo *getExpansionTypeSourceInfo(unsigned I) const { + assert(I < NumExpandedTypes && "Out-of-range expansion type index"); + auto TypesAndInfos = + getTrailingObjects<std::pair<QualType, TypeSourceInfo *>>(); + return TypesAndInfos[I].second; + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == NonTypeTemplateParm; } +}; + +/// TemplateTemplateParmDecl - Declares a template template parameter, +/// e.g., "T" in +/// @code +/// template <template <typename> class T> class container { }; +/// @endcode +/// A template template parameter is a TemplateDecl because it defines the +/// name of a template and the template parameters allowable for substitution. +class TemplateTemplateParmDecl final + : public TemplateDecl, + protected TemplateParmPosition, + private llvm::TrailingObjects<TemplateTemplateParmDecl, + TemplateParameterList *> { + void anchor() override; + + /// \brief The default template argument, if any. + typedef DefaultArgStorage<TemplateTemplateParmDecl, TemplateArgumentLoc *> + DefArgStorage; + DefArgStorage DefaultArgument; + + /// \brief Whether this parameter is a parameter pack. + bool ParameterPack; + + /// \brief Whether this template template parameter is an "expanded" + /// parameter pack, meaning that it is a pack expansion and we + /// already know the set of template parameters that expansion expands to. + bool ExpandedParameterPack; + + /// \brief The number of parameters in an expanded parameter pack. + unsigned NumExpandedParams; + + TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L, + unsigned D, unsigned P, bool ParameterPack, + IdentifierInfo *Id, TemplateParameterList *Params) + : TemplateDecl(TemplateTemplateParm, DC, L, Id, Params), + TemplateParmPosition(D, P), ParameterPack(ParameterPack), + ExpandedParameterPack(false), NumExpandedParams(0) + { } + + TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L, + unsigned D, unsigned P, + IdentifierInfo *Id, TemplateParameterList *Params, + unsigned NumExpansions, + TemplateParameterList * const *Expansions); + +public: + static TemplateTemplateParmDecl *Create(const ASTContext &C, DeclContext *DC, + SourceLocation L, unsigned D, + unsigned P, bool ParameterPack, + IdentifierInfo *Id, + TemplateParameterList *Params); + static TemplateTemplateParmDecl *Create(const ASTContext &C, DeclContext *DC, + SourceLocation L, unsigned D, + unsigned P, + IdentifierInfo *Id, + TemplateParameterList *Params, + ArrayRef<TemplateParameterList *> Expansions); + + static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C, + unsigned ID); + static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C, + unsigned ID, + unsigned NumExpansions); + + using TemplateParmPosition::getDepth; + using TemplateParmPosition::getPosition; + using TemplateParmPosition::getIndex; + + /// \brief Whether this template template parameter is a template + /// parameter pack. + /// + /// \code + /// template<template <class T> ...MetaFunctions> struct Apply; + /// \endcode + bool isParameterPack() const { return ParameterPack; } + + /// \brief Whether this parameter pack is a pack expansion. + /// + /// A template template parameter pack is a pack expansion if its template + /// parameter list contains an unexpanded parameter pack. + bool isPackExpansion() const { + return ParameterPack && + getTemplateParameters()->containsUnexpandedParameterPack(); + } + + /// \brief Whether this parameter is a template template parameter pack that + /// has a known list of different template parameter lists at different + /// positions. + /// + /// A parameter pack is an expanded parameter pack when the original parameter + /// pack's template parameter list was itself a pack expansion, and that + /// expansion has already been expanded. For exampe, given: + /// + /// \code + /// template<typename...Types> struct Outer { + /// template<template<Types> class...Templates> struct Inner; + /// }; + /// \endcode + /// + /// The parameter pack \c Templates is a pack expansion, which expands the + /// pack \c Types. When \c Types is supplied with template arguments by + /// instantiating \c Outer, the instantiation of \c Templates is an expanded + /// parameter pack. + bool isExpandedParameterPack() const { return ExpandedParameterPack; } + + /// \brief Retrieves the number of expansion template parameters in + /// an expanded parameter pack. + unsigned getNumExpansionTemplateParameters() const { + assert(ExpandedParameterPack && "Not an expansion parameter pack"); + return NumExpandedParams; + } + + /// \brief Retrieve a particular expansion type within an expanded parameter + /// pack. + TemplateParameterList *getExpansionTemplateParameters(unsigned I) const { + assert(I < NumExpandedParams && "Out-of-range expansion type index"); + return getTrailingObjects<TemplateParameterList *>()[I]; + } + + const DefArgStorage &getDefaultArgStorage() const { return DefaultArgument; } + + /// \brief Determine whether this template parameter has a default + /// argument. + bool hasDefaultArgument() const { return DefaultArgument.isSet(); } + + /// \brief Retrieve the default argument, if any. + const TemplateArgumentLoc &getDefaultArgument() const { + static const TemplateArgumentLoc None; + return DefaultArgument.isSet() ? *DefaultArgument.get() : None; + } + + /// \brief Retrieve the location of the default argument, if any. + SourceLocation getDefaultArgumentLoc() const; + + /// \brief Determines whether the default argument was inherited + /// from a previous declaration of this template. + bool defaultArgumentWasInherited() const { + return DefaultArgument.isInherited(); + } + + /// \brief Set the default argument for this template parameter, and + /// whether that default argument was inherited from another + /// declaration. + void setDefaultArgument(const ASTContext &C, + const TemplateArgumentLoc &DefArg); + void setInheritedDefaultArgument(const ASTContext &C, + TemplateTemplateParmDecl *Prev) { + DefaultArgument.setInherited(C, Prev); + } + + /// \brief Removes the default argument of this template parameter. + void removeDefaultArgument() { DefaultArgument.clear(); } + + SourceRange getSourceRange() const override LLVM_READONLY { + SourceLocation End = getLocation(); + if (hasDefaultArgument() && !defaultArgumentWasInherited()) + End = getDefaultArgument().getSourceRange().getEnd(); + return SourceRange(getTemplateParameters()->getTemplateLoc(), End); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == TemplateTemplateParm; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; + friend TrailingObjects; +}; + +/// \brief Represents the builtin template declaration which is used to +/// implement __make_integer_seq. It serves no real purpose beyond existing as +/// a place to hold template parameters. +class BuiltinTemplateDecl : public TemplateDecl { + void anchor() override; + + BuiltinTemplateDecl(const ASTContext &C, DeclContext *DC, + DeclarationName Name, BuiltinTemplateKind BTK); + + BuiltinTemplateKind BTK; + +public: + // Implement isa/cast/dyncast support + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == BuiltinTemplate; } + + static BuiltinTemplateDecl *Create(const ASTContext &C, DeclContext *DC, + DeclarationName Name, + BuiltinTemplateKind BTK) { + return new (C, DC) BuiltinTemplateDecl(C, DC, Name, BTK); + } + + SourceRange getSourceRange() const override LLVM_READONLY { + return SourceRange(); + } + + BuiltinTemplateKind getBuiltinTemplateKind() const { return BTK; } +}; + +/// \brief Represents a class template specialization, which refers to +/// a class template with a given set of template arguments. +/// +/// Class template specializations represent both explicit +/// specialization of class templates, as in the example below, and +/// implicit instantiations of class templates. +/// +/// \code +/// template<typename T> class array; +/// +/// template<> +/// class array<bool> { }; // class template specialization array<bool> +/// \endcode +class ClassTemplateSpecializationDecl + : public CXXRecordDecl, public llvm::FoldingSetNode { + + /// \brief Structure that stores information about a class template + /// specialization that was instantiated from a class template partial + /// specialization. + struct SpecializedPartialSpecialization { + /// \brief The class template partial specialization from which this + /// class template specialization was instantiated. + ClassTemplatePartialSpecializationDecl *PartialSpecialization; + + /// \brief The template argument list deduced for the class template + /// partial specialization itself. + const TemplateArgumentList *TemplateArgs; + }; + + /// \brief The template that this specialization specializes + llvm::PointerUnion<ClassTemplateDecl *, SpecializedPartialSpecialization *> + SpecializedTemplate; + + /// \brief Further info for explicit template specialization/instantiation. + struct ExplicitSpecializationInfo { + /// \brief The type-as-written. + TypeSourceInfo *TypeAsWritten; + /// \brief The location of the extern keyword. + SourceLocation ExternLoc; + /// \brief The location of the template keyword. + SourceLocation TemplateKeywordLoc; + + ExplicitSpecializationInfo() + : TypeAsWritten(nullptr), ExternLoc(), TemplateKeywordLoc() {} + }; + + /// \brief Further info for explicit template specialization/instantiation. + /// Does not apply to implicit specializations. + ExplicitSpecializationInfo *ExplicitInfo; + + /// \brief The template arguments used to describe this specialization. + const TemplateArgumentList *TemplateArgs; + + /// \brief The point where this template was instantiated (if any) + SourceLocation PointOfInstantiation; + + /// \brief The kind of specialization this declaration refers to. + /// Really a value of type TemplateSpecializationKind. + unsigned SpecializationKind : 3; + +protected: + ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, TagKind TK, + DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, + ClassTemplateDecl *SpecializedTemplate, + const TemplateArgument *Args, + unsigned NumArgs, + ClassTemplateSpecializationDecl *PrevDecl); + + explicit ClassTemplateSpecializationDecl(ASTContext &C, Kind DK); + +public: + static ClassTemplateSpecializationDecl * + Create(ASTContext &Context, TagKind TK, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + ClassTemplateDecl *SpecializedTemplate, + const TemplateArgument *Args, + unsigned NumArgs, + ClassTemplateSpecializationDecl *PrevDecl); + static ClassTemplateSpecializationDecl * + CreateDeserialized(ASTContext &C, unsigned ID); + + void getNameForDiagnostic(raw_ostream &OS, const PrintingPolicy &Policy, + bool Qualified) const override; + + // FIXME: This is broken. CXXRecordDecl::getMostRecentDecl() returns a + // different "most recent" declaration from this function for the same + // declaration, because we don't override getMostRecentDeclImpl(). But + // it's not clear that we should override that, because the most recent + // declaration as a CXXRecordDecl sometimes is the injected-class-name. + ClassTemplateSpecializationDecl *getMostRecentDecl() { + CXXRecordDecl *Recent = static_cast<CXXRecordDecl *>( + this)->getMostRecentDecl(); + while (!isa<ClassTemplateSpecializationDecl>(Recent)) { + // FIXME: Does injected class name need to be in the redeclarations chain? + assert(Recent->isInjectedClassName() && Recent->getPreviousDecl()); + Recent = Recent->getPreviousDecl(); + } + return cast<ClassTemplateSpecializationDecl>(Recent); + } + + /// \brief Retrieve the template that this specialization specializes. + ClassTemplateDecl *getSpecializedTemplate() const; + + /// \brief Retrieve the template arguments of the class template + /// specialization. + const TemplateArgumentList &getTemplateArgs() const { + return *TemplateArgs; + } + + /// \brief Determine the kind of specialization that this + /// declaration represents. + TemplateSpecializationKind getSpecializationKind() const { + return static_cast<TemplateSpecializationKind>(SpecializationKind); + } + + bool isExplicitSpecialization() const { + return getSpecializationKind() == TSK_ExplicitSpecialization; + } + + /// \brief True if this declaration is an explicit specialization, + /// explicit instantiation declaration, or explicit instantiation + /// definition. + bool isExplicitInstantiationOrSpecialization() const { + return isTemplateExplicitInstantiationOrSpecialization( + getTemplateSpecializationKind()); + } + + void setSpecializationKind(TemplateSpecializationKind TSK) { + SpecializationKind = TSK; + } + + /// \brief Get the point of instantiation (if any), or null if none. + SourceLocation getPointOfInstantiation() const { + return PointOfInstantiation; + } + + void setPointOfInstantiation(SourceLocation Loc) { + assert(Loc.isValid() && "point of instantiation must be valid!"); + PointOfInstantiation = Loc; + } + + /// \brief If this class template specialization is an instantiation of + /// a template (rather than an explicit specialization), return the + /// class template or class template partial specialization from which it + /// was instantiated. + llvm::PointerUnion<ClassTemplateDecl *, + ClassTemplatePartialSpecializationDecl *> + getInstantiatedFrom() const { + if (!isTemplateInstantiation(getSpecializationKind())) + return llvm::PointerUnion<ClassTemplateDecl *, + ClassTemplatePartialSpecializationDecl *>(); + + return getSpecializedTemplateOrPartial(); + } + + /// \brief Retrieve the class template or class template partial + /// specialization which was specialized by this. + llvm::PointerUnion<ClassTemplateDecl *, + ClassTemplatePartialSpecializationDecl *> + getSpecializedTemplateOrPartial() const { + if (SpecializedPartialSpecialization *PartialSpec + = SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization*>()) + return PartialSpec->PartialSpecialization; + + return SpecializedTemplate.get<ClassTemplateDecl*>(); + } + + /// \brief Retrieve the set of template arguments that should be used + /// to instantiate members of the class template or class template partial + /// specialization from which this class template specialization was + /// instantiated. + /// + /// \returns For a class template specialization instantiated from the primary + /// template, this function will return the same template arguments as + /// getTemplateArgs(). For a class template specialization instantiated from + /// a class template partial specialization, this function will return the + /// deduced template arguments for the class template partial specialization + /// itself. + const TemplateArgumentList &getTemplateInstantiationArgs() const { + if (SpecializedPartialSpecialization *PartialSpec + = SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization*>()) + return *PartialSpec->TemplateArgs; + + return getTemplateArgs(); + } + + /// \brief Note that this class template specialization is actually an + /// instantiation of the given class template partial specialization whose + /// template arguments have been deduced. + void setInstantiationOf(ClassTemplatePartialSpecializationDecl *PartialSpec, + const TemplateArgumentList *TemplateArgs) { + assert(!SpecializedTemplate.is<SpecializedPartialSpecialization*>() && + "Already set to a class template partial specialization!"); + SpecializedPartialSpecialization *PS + = new (getASTContext()) SpecializedPartialSpecialization(); + PS->PartialSpecialization = PartialSpec; + PS->TemplateArgs = TemplateArgs; + SpecializedTemplate = PS; + } + + /// \brief Note that this class template specialization is an instantiation + /// of the given class template. + void setInstantiationOf(ClassTemplateDecl *TemplDecl) { + assert(!SpecializedTemplate.is<SpecializedPartialSpecialization*>() && + "Previously set to a class template partial specialization!"); + SpecializedTemplate = TemplDecl; + } + + /// \brief Sets the type of this specialization as it was written by + /// the user. This will be a class template specialization type. + void setTypeAsWritten(TypeSourceInfo *T) { + if (!ExplicitInfo) + ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo; + ExplicitInfo->TypeAsWritten = T; + } + /// \brief Gets the type of this specialization as it was written by + /// the user, if it was so written. + TypeSourceInfo *getTypeAsWritten() const { + return ExplicitInfo ? ExplicitInfo->TypeAsWritten : nullptr; + } + + /// \brief Gets the location of the extern keyword, if present. + SourceLocation getExternLoc() const { + return ExplicitInfo ? ExplicitInfo->ExternLoc : SourceLocation(); + } + /// \brief Sets the location of the extern keyword. + void setExternLoc(SourceLocation Loc) { + if (!ExplicitInfo) + ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo; + ExplicitInfo->ExternLoc = Loc; + } + + /// \brief Sets the location of the template keyword. + void setTemplateKeywordLoc(SourceLocation Loc) { + if (!ExplicitInfo) + ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo; + ExplicitInfo->TemplateKeywordLoc = Loc; + } + /// \brief Gets the location of the template keyword, if present. + SourceLocation getTemplateKeywordLoc() const { + return ExplicitInfo ? ExplicitInfo->TemplateKeywordLoc : SourceLocation(); + } + + SourceRange getSourceRange() const override LLVM_READONLY; + + void Profile(llvm::FoldingSetNodeID &ID) const { + Profile(ID, TemplateArgs->asArray(), getASTContext()); + } + + static void + Profile(llvm::FoldingSetNodeID &ID, ArrayRef<TemplateArgument> TemplateArgs, + ASTContext &Context) { + ID.AddInteger(TemplateArgs.size()); + for (unsigned Arg = 0; Arg != TemplateArgs.size(); ++Arg) + TemplateArgs[Arg].Profile(ID, Context); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { + return K >= firstClassTemplateSpecialization && + K <= lastClassTemplateSpecialization; + } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +class ClassTemplatePartialSpecializationDecl + : public ClassTemplateSpecializationDecl { + void anchor() override; + + /// \brief The list of template parameters + TemplateParameterList* TemplateParams; + + /// \brief The source info for the template arguments as written. + /// FIXME: redundant with TypeAsWritten? + const ASTTemplateArgumentListInfo *ArgsAsWritten; + + /// \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, TagKind TK, + DeclContext *DC, + SourceLocation StartLoc, + SourceLocation IdLoc, + TemplateParameterList *Params, + ClassTemplateDecl *SpecializedTemplate, + const TemplateArgument *Args, + unsigned NumArgs, + const ASTTemplateArgumentListInfo *ArgsAsWritten, + ClassTemplatePartialSpecializationDecl *PrevDecl); + + ClassTemplatePartialSpecializationDecl(ASTContext &C) + : ClassTemplateSpecializationDecl(C, ClassTemplatePartialSpecialization), + TemplateParams(nullptr), ArgsAsWritten(nullptr), + InstantiatedFromMember(nullptr, false) {} + +public: + static ClassTemplatePartialSpecializationDecl * + Create(ASTContext &Context, TagKind TK, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + TemplateParameterList *Params, + ClassTemplateDecl *SpecializedTemplate, + const TemplateArgument *Args, + unsigned NumArgs, + const TemplateArgumentListInfo &ArgInfos, + QualType CanonInjectedType, + ClassTemplatePartialSpecializationDecl *PrevDecl); + + static ClassTemplatePartialSpecializationDecl * + CreateDeserialized(ASTContext &C, unsigned ID); + + ClassTemplatePartialSpecializationDecl *getMostRecentDecl() { + return cast<ClassTemplatePartialSpecializationDecl>( + static_cast<ClassTemplateSpecializationDecl *>( + this)->getMostRecentDecl()); + } + + /// Get the list of template parameters + TemplateParameterList *getTemplateParameters() const { + return TemplateParams; + } + + /// Get the template arguments as written. + const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const { + return ArgsAsWritten; + } + + /// \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() const { + const ClassTemplatePartialSpecializationDecl *First = + cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl()); + return First->InstantiatedFromMember.getPointer(); + } + + void setInstantiatedFromMember( + ClassTemplatePartialSpecializationDecl *PartialSpec) { + ClassTemplatePartialSpecializationDecl *First = + cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl()); + 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>(getFirstDecl()); + return First->InstantiatedFromMember.getInt(); + } + + /// \brief Note that this member template is a specialization. + void setMemberSpecialization() { + ClassTemplatePartialSpecializationDecl *First = + cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl()); + assert(First->InstantiatedFromMember.getPointer() && + "Only member templates can be member template specializations"); + return First->InstantiatedFromMember.setInt(true); + } + + /// Retrieves the injected specialization type for this partial + /// specialization. This is not the same as the type-decl-type for + /// this partial specialization, which is an InjectedClassNameType. + QualType getInjectedSpecializationType() const { + assert(getTypeForDecl() && "partial specialization has no type set!"); + return cast<InjectedClassNameType>(getTypeForDecl()) + ->getInjectedSpecializationType(); + } + + // FIXME: Add Profile support! + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { + return K == ClassTemplatePartialSpecialization; + } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// Declaration of a class template. +class ClassTemplateDecl : public RedeclarableTemplateDecl { + static void DeallocateCommon(void *Ptr); + +protected: + /// \brief Data that is common to all of the declarations of a given + /// class template. + struct Common : CommonBase { + Common() : LazySpecializations() { } + + /// \brief The class template specializations for this class + /// template, including explicit specializations and instantiations. + llvm::FoldingSetVector<ClassTemplateSpecializationDecl> Specializations; + + /// \brief The class template partial specializations for this class + /// template. + llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> + PartialSpecializations; + + /// \brief The injected-class-name type for this class template. + QualType InjectedClassNameType; + + /// \brief If non-null, points to an array of specializations (including + /// partial specializations) known only by their external declaration IDs. + /// + /// The first value in the array is the number of of specializations/ + /// partial specializations that follow. + uint32_t *LazySpecializations; + }; + + /// \brief Retrieve the set of specializations of this class template. + llvm::FoldingSetVector<ClassTemplateSpecializationDecl> & + getSpecializations() const; + + /// \brief Retrieve the set of partial specializations of this class + /// template. + llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> & + getPartialSpecializations(); + + ClassTemplateDecl(ASTContext &C, DeclContext *DC, SourceLocation L, + DeclarationName Name, TemplateParameterList *Params, + NamedDecl *Decl) + : RedeclarableTemplateDecl(ClassTemplate, C, DC, L, Name, Params, Decl) {} + + CommonBase *newCommon(ASTContext &C) const override; + + Common *getCommonPtr() const { + return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr()); + } + +public: + /// \brief Load any lazily-loaded specializations from the external source. + void LoadLazySpecializations() const; + + /// \brief Get the underlying class declarations of the template. + CXXRecordDecl *getTemplatedDecl() const { + return static_cast<CXXRecordDecl *>(TemplatedDecl); + } + + /// \brief Returns whether this template declaration defines the primary + /// class pattern. + bool isThisDeclarationADefinition() const { + return getTemplatedDecl()->isThisDeclarationADefinition(); + } + + /// \brief Create a class template node. + static ClassTemplateDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + DeclarationName Name, + TemplateParameterList *Params, + NamedDecl *Decl, + ClassTemplateDecl *PrevDecl); + + /// \brief Create an empty class template node. + static ClassTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + /// \brief Return the specialization with the provided arguments if it exists, + /// otherwise return the insertion point. + ClassTemplateSpecializationDecl * + findSpecialization(ArrayRef<TemplateArgument> Args, void *&InsertPos); + + /// \brief Insert the specified specialization knowing that it is not already + /// in. InsertPos must be obtained from findSpecialization. + void AddSpecialization(ClassTemplateSpecializationDecl *D, void *InsertPos); + + ClassTemplateDecl *getCanonicalDecl() override { + return cast<ClassTemplateDecl>( + RedeclarableTemplateDecl::getCanonicalDecl()); + } + const ClassTemplateDecl *getCanonicalDecl() const { + return cast<ClassTemplateDecl>( + RedeclarableTemplateDecl::getCanonicalDecl()); + } + + /// \brief Retrieve the previous declaration of this class template, or + /// NULL if no such declaration exists. + ClassTemplateDecl *getPreviousDecl() { + return cast_or_null<ClassTemplateDecl>( + static_cast<RedeclarableTemplateDecl *>(this)->getPreviousDecl()); + } + + /// \brief Retrieve the previous declaration of this class template, or + /// NULL if no such declaration exists. + const ClassTemplateDecl *getPreviousDecl() const { + return cast_or_null<ClassTemplateDecl>( + static_cast<const RedeclarableTemplateDecl *>( + this)->getPreviousDecl()); + } + + ClassTemplateDecl *getMostRecentDecl() { + return cast<ClassTemplateDecl>( + static_cast<RedeclarableTemplateDecl *>(this)->getMostRecentDecl()); + } + const ClassTemplateDecl *getMostRecentDecl() const { + return const_cast<ClassTemplateDecl*>(this)->getMostRecentDecl(); + } + + ClassTemplateDecl *getInstantiatedFromMemberTemplate() const { + return cast_or_null<ClassTemplateDecl>( + RedeclarableTemplateDecl::getInstantiatedFromMemberTemplate()); + } + + /// \brief Return the partial specialization with the provided arguments if it + /// exists, otherwise return the insertion point. + ClassTemplatePartialSpecializationDecl * + findPartialSpecialization(ArrayRef<TemplateArgument> Args, void *&InsertPos); + + /// \brief Insert the specified partial specialization knowing that it is not + /// already in. InsertPos must be obtained from findPartialSpecialization. + void AddPartialSpecialization(ClassTemplatePartialSpecializationDecl *D, + void *InsertPos); + + /// \brief Retrieve the partial specializations as an ordered list. + void getPartialSpecializations( + SmallVectorImpl<ClassTemplatePartialSpecializationDecl *> &PS); + + /// \brief Find a class template partial specialization with the given + /// type T. + /// + /// \param T a dependent type that names a specialization of this class + /// template. + /// + /// \returns the class template partial specialization that exactly matches + /// the type \p T, or NULL if no such partial specialization exists. + ClassTemplatePartialSpecializationDecl *findPartialSpecialization(QualType T); + + /// \brief Find a class template partial specialization which was instantiated + /// from the given member partial specialization. + /// + /// \param D a member class template partial specialization. + /// + /// \returns the class template partial specialization which was instantiated + /// from the given member partial specialization, or NULL if no such partial + /// specialization exists. + ClassTemplatePartialSpecializationDecl * + findPartialSpecInstantiatedFromMember( + ClassTemplatePartialSpecializationDecl *D); + + /// \brief Retrieve the template specialization type of the + /// injected-class-name for this class template. + /// + /// The injected-class-name for a class template \c X is \c + /// X<template-args>, where \c template-args is formed from the + /// template arguments that correspond to the template parameters of + /// \c X. For example: + /// + /// \code + /// template<typename T, int N> + /// struct array { + /// typedef array this_type; // "array" is equivalent to "array<T, N>" + /// }; + /// \endcode + QualType getInjectedClassNameSpecialization(); + + typedef SpecIterator<ClassTemplateSpecializationDecl> spec_iterator; + typedef llvm::iterator_range<spec_iterator> spec_range; + + spec_range specializations() const { + return spec_range(spec_begin(), spec_end()); + } + + spec_iterator spec_begin() const { + return makeSpecIterator(getSpecializations(), false); + } + + spec_iterator spec_end() const { + return makeSpecIterator(getSpecializations(), true); + } + + // Implement isa/cast/dyncast support + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == ClassTemplate; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// \brief Declaration of a friend template. +/// +/// For example: +/// \code +/// template \<typename T> class A { +/// friend class MyVector<T>; // not a friend template +/// template \<typename U> friend class B; // not a friend template +/// template \<typename U> friend class Foo<T>::Nested; // friend template +/// }; +/// \endcode +/// +/// \note This class is not currently in use. All of the above +/// will yield a FriendDecl, not a FriendTemplateDecl. +class FriendTemplateDecl : public Decl { + virtual void anchor(); +public: + typedef llvm::PointerUnion<NamedDecl*,TypeSourceInfo*> FriendUnion; + +private: + // The number of template parameters; always non-zero. + unsigned NumParams; + + // The parameter list. + TemplateParameterList **Params; + + // The declaration that's a friend of this class. + FriendUnion Friend; + + // Location of the 'friend' specifier. + SourceLocation FriendLoc; + + + FriendTemplateDecl(DeclContext *DC, SourceLocation Loc, + unsigned NParams, + TemplateParameterList **Params, + FriendUnion Friend, + SourceLocation FriendLoc) + : Decl(Decl::FriendTemplate, DC, Loc), + NumParams(NParams), + Params(Params), + Friend(Friend), + FriendLoc(FriendLoc) + {} + + FriendTemplateDecl(EmptyShell Empty) + : Decl(Decl::FriendTemplate, Empty), + NumParams(0), + Params(nullptr) + {} + +public: + static FriendTemplateDecl *Create(ASTContext &Context, + DeclContext *DC, SourceLocation Loc, + unsigned NParams, + TemplateParameterList **Params, + FriendUnion Friend, + SourceLocation FriendLoc); + + static FriendTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + /// If this friend declaration names a templated type (or + /// a dependent member type of a templated type), return that + /// type; otherwise return null. + TypeSourceInfo *getFriendType() const { + return Friend.dyn_cast<TypeSourceInfo*>(); + } + + /// If this friend declaration names a templated function (or + /// a member function of a templated type), return that type; + /// otherwise return null. + NamedDecl *getFriendDecl() const { + return Friend.dyn_cast<NamedDecl*>(); + } + + /// \brief Retrieves the location of the 'friend' keyword. + SourceLocation getFriendLoc() const { + return FriendLoc; + } + + TemplateParameterList *getTemplateParameterList(unsigned i) const { + assert(i <= NumParams); + return Params[i]; + } + + unsigned getNumTemplateParameters() const { + return NumParams; + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == Decl::FriendTemplate; } + + friend class ASTDeclReader; +}; + +/// \brief Declaration of an alias template. +/// +/// For example: +/// \code +/// template \<typename T> using V = std::map<T*, int, MyCompare<T>>; +/// \endcode +class TypeAliasTemplateDecl : public RedeclarableTemplateDecl { + static void DeallocateCommon(void *Ptr); + +protected: + typedef CommonBase Common; + + TypeAliasTemplateDecl(ASTContext &C, DeclContext *DC, SourceLocation L, + DeclarationName Name, TemplateParameterList *Params, + NamedDecl *Decl) + : RedeclarableTemplateDecl(TypeAliasTemplate, C, DC, L, Name, Params, + Decl) {} + + CommonBase *newCommon(ASTContext &C) const override; + + Common *getCommonPtr() { + return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr()); + } + +public: + /// Get the underlying function declaration of the template. + TypeAliasDecl *getTemplatedDecl() const { + return static_cast<TypeAliasDecl*>(TemplatedDecl); + } + + + TypeAliasTemplateDecl *getCanonicalDecl() override { + return cast<TypeAliasTemplateDecl>( + RedeclarableTemplateDecl::getCanonicalDecl()); + } + const TypeAliasTemplateDecl *getCanonicalDecl() const { + return cast<TypeAliasTemplateDecl>( + RedeclarableTemplateDecl::getCanonicalDecl()); + } + + /// \brief Retrieve the previous declaration of this function template, or + /// NULL if no such declaration exists. + TypeAliasTemplateDecl *getPreviousDecl() { + return cast_or_null<TypeAliasTemplateDecl>( + static_cast<RedeclarableTemplateDecl *>(this)->getPreviousDecl()); + } + + /// \brief Retrieve the previous declaration of this function template, or + /// NULL if no such declaration exists. + const TypeAliasTemplateDecl *getPreviousDecl() const { + return cast_or_null<TypeAliasTemplateDecl>( + static_cast<const RedeclarableTemplateDecl *>( + this)->getPreviousDecl()); + } + + TypeAliasTemplateDecl *getInstantiatedFromMemberTemplate() const { + return cast_or_null<TypeAliasTemplateDecl>( + RedeclarableTemplateDecl::getInstantiatedFromMemberTemplate()); + } + + + /// \brief Create a function template node. + static TypeAliasTemplateDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + DeclarationName Name, + TemplateParameterList *Params, + NamedDecl *Decl); + + /// \brief Create an empty alias template node. + static TypeAliasTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + // Implement isa/cast/dyncast support + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == TypeAliasTemplate; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// \brief Declaration of a function specialization at template class scope. +/// +/// This is a non-standard extension needed to support MSVC. +/// +/// For example: +/// \code +/// template <class T> +/// class A { +/// template <class U> void foo(U a) { } +/// template<> void foo(int a) { } +/// } +/// \endcode +/// +/// "template<> foo(int a)" will be saved in Specialization as a normal +/// CXXMethodDecl. Then during an instantiation of class A, it will be +/// transformed into an actual function specialization. +class ClassScopeFunctionSpecializationDecl : public Decl { + virtual void anchor(); + + ClassScopeFunctionSpecializationDecl(DeclContext *DC, SourceLocation Loc, + CXXMethodDecl *FD, bool Args, + TemplateArgumentListInfo TemplArgs) + : Decl(Decl::ClassScopeFunctionSpecialization, DC, Loc), + Specialization(FD), HasExplicitTemplateArgs(Args), + TemplateArgs(TemplArgs) {} + + ClassScopeFunctionSpecializationDecl(EmptyShell Empty) + : Decl(Decl::ClassScopeFunctionSpecialization, Empty) {} + + CXXMethodDecl *Specialization; + bool HasExplicitTemplateArgs; + TemplateArgumentListInfo TemplateArgs; + +public: + CXXMethodDecl *getSpecialization() const { return Specialization; } + bool hasExplicitTemplateArgs() const { return HasExplicitTemplateArgs; } + const TemplateArgumentListInfo& templateArgs() const { return TemplateArgs; } + + static ClassScopeFunctionSpecializationDecl *Create(ASTContext &C, + DeclContext *DC, + SourceLocation Loc, + CXXMethodDecl *FD, + bool HasExplicitTemplateArgs, + TemplateArgumentListInfo TemplateArgs) { + return new (C, DC) ClassScopeFunctionSpecializationDecl( + DC, Loc, FD, HasExplicitTemplateArgs, TemplateArgs); + } + + static ClassScopeFunctionSpecializationDecl * + CreateDeserialized(ASTContext &Context, unsigned ID); + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { + return K == Decl::ClassScopeFunctionSpecialization; + } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// Implementation of inline functions that require the template declarations +inline AnyFunctionDecl::AnyFunctionDecl(FunctionTemplateDecl *FTD) + : Function(FTD) { } + +/// \brief Represents a variable template specialization, which refers to +/// a variable template with a given set of template arguments. +/// +/// Variable template specializations represent both explicit +/// specializations of variable templates, as in the example below, and +/// implicit instantiations of variable templates. +/// +/// \code +/// template<typename T> constexpr T pi = T(3.1415926535897932385); +/// +/// template<> +/// constexpr float pi<float>; // variable template specialization pi<float> +/// \endcode +class VarTemplateSpecializationDecl : public VarDecl, + public llvm::FoldingSetNode { + + /// \brief Structure that stores information about a variable template + /// specialization that was instantiated from a variable template partial + /// specialization. + struct SpecializedPartialSpecialization { + /// \brief The variable template partial specialization from which this + /// variable template specialization was instantiated. + VarTemplatePartialSpecializationDecl *PartialSpecialization; + + /// \brief The template argument list deduced for the variable template + /// partial specialization itself. + const TemplateArgumentList *TemplateArgs; + }; + + /// \brief The template that this specialization specializes. + llvm::PointerUnion<VarTemplateDecl *, SpecializedPartialSpecialization *> + SpecializedTemplate; + + /// \brief Further info for explicit template specialization/instantiation. + struct ExplicitSpecializationInfo { + /// \brief The type-as-written. + TypeSourceInfo *TypeAsWritten; + /// \brief The location of the extern keyword. + SourceLocation ExternLoc; + /// \brief The location of the template keyword. + SourceLocation TemplateKeywordLoc; + + ExplicitSpecializationInfo() + : TypeAsWritten(nullptr), ExternLoc(), TemplateKeywordLoc() {} + }; + + /// \brief Further info for explicit template specialization/instantiation. + /// Does not apply to implicit specializations. + ExplicitSpecializationInfo *ExplicitInfo; + + /// \brief The template arguments used to describe this specialization. + const TemplateArgumentList *TemplateArgs; + TemplateArgumentListInfo TemplateArgsInfo; + + /// \brief The point where this template was instantiated (if any). + SourceLocation PointOfInstantiation; + + /// \brief The kind of specialization this declaration refers to. + /// Really a value of type TemplateSpecializationKind. + unsigned SpecializationKind : 3; + +protected: + VarTemplateSpecializationDecl(Kind DK, ASTContext &Context, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + VarTemplateDecl *SpecializedTemplate, + QualType T, TypeSourceInfo *TInfo, + StorageClass S, const TemplateArgument *Args, + unsigned NumArgs); + + explicit VarTemplateSpecializationDecl(Kind DK, ASTContext &Context); + +public: + static VarTemplateSpecializationDecl * + Create(ASTContext &Context, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, VarTemplateDecl *SpecializedTemplate, QualType T, + TypeSourceInfo *TInfo, StorageClass S, const TemplateArgument *Args, + unsigned NumArgs); + static VarTemplateSpecializationDecl *CreateDeserialized(ASTContext &C, + unsigned ID); + + void getNameForDiagnostic(raw_ostream &OS, const PrintingPolicy &Policy, + bool Qualified) const override; + + VarTemplateSpecializationDecl *getMostRecentDecl() { + VarDecl *Recent = static_cast<VarDecl *>(this)->getMostRecentDecl(); + return cast<VarTemplateSpecializationDecl>(Recent); + } + + /// \brief Retrieve the template that this specialization specializes. + VarTemplateDecl *getSpecializedTemplate() const; + + /// \brief Retrieve the template arguments of the variable template + /// specialization. + const TemplateArgumentList &getTemplateArgs() const { return *TemplateArgs; } + + // TODO: Always set this when creating the new specialization? + void setTemplateArgsInfo(const TemplateArgumentListInfo &ArgsInfo); + + const TemplateArgumentListInfo &getTemplateArgsInfo() const { + return TemplateArgsInfo; + } + + /// \brief Determine the kind of specialization that this + /// declaration represents. + TemplateSpecializationKind getSpecializationKind() const { + return static_cast<TemplateSpecializationKind>(SpecializationKind); + } + + bool isExplicitSpecialization() const { + return getSpecializationKind() == TSK_ExplicitSpecialization; + } + + /// \brief True if this declaration is an explicit specialization, + /// explicit instantiation declaration, or explicit instantiation + /// definition. + bool isExplicitInstantiationOrSpecialization() const { + return isTemplateExplicitInstantiationOrSpecialization( + getTemplateSpecializationKind()); + } + + void setSpecializationKind(TemplateSpecializationKind TSK) { + SpecializationKind = TSK; + } + + /// \brief Get the point of instantiation (if any), or null if none. + SourceLocation getPointOfInstantiation() const { + return PointOfInstantiation; + } + + void setPointOfInstantiation(SourceLocation Loc) { + assert(Loc.isValid() && "point of instantiation must be valid!"); + PointOfInstantiation = Loc; + } + + /// \brief If this variable template specialization is an instantiation of + /// a template (rather than an explicit specialization), return the + /// variable template or variable template partial specialization from which + /// it was instantiated. + llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *> + getInstantiatedFrom() const { + if (getSpecializationKind() != TSK_ImplicitInstantiation && + getSpecializationKind() != TSK_ExplicitInstantiationDefinition && + getSpecializationKind() != TSK_ExplicitInstantiationDeclaration) + return llvm::PointerUnion<VarTemplateDecl *, + VarTemplatePartialSpecializationDecl *>(); + + if (SpecializedPartialSpecialization *PartialSpec = + SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>()) + return PartialSpec->PartialSpecialization; + + return SpecializedTemplate.get<VarTemplateDecl *>(); + } + + /// \brief Retrieve the variable template or variable template partial + /// specialization which was specialized by this. + llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *> + getSpecializedTemplateOrPartial() const { + if (SpecializedPartialSpecialization *PartialSpec = + SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>()) + return PartialSpec->PartialSpecialization; + + return SpecializedTemplate.get<VarTemplateDecl *>(); + } + + /// \brief Retrieve the set of template arguments that should be used + /// to instantiate the initializer of the variable template or variable + /// template partial specialization from which this variable template + /// specialization was instantiated. + /// + /// \returns For a variable template specialization instantiated from the + /// primary template, this function will return the same template arguments + /// as getTemplateArgs(). For a variable template specialization instantiated + /// from a variable template partial specialization, this function will the + /// return deduced template arguments for the variable template partial + /// specialization itself. + const TemplateArgumentList &getTemplateInstantiationArgs() const { + if (SpecializedPartialSpecialization *PartialSpec = + SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>()) + return *PartialSpec->TemplateArgs; + + return getTemplateArgs(); + } + + /// \brief Note that this variable template specialization is actually an + /// instantiation of the given variable template partial specialization whose + /// template arguments have been deduced. + void setInstantiationOf(VarTemplatePartialSpecializationDecl *PartialSpec, + const TemplateArgumentList *TemplateArgs) { + assert(!SpecializedTemplate.is<SpecializedPartialSpecialization *>() && + "Already set to a variable template partial specialization!"); + SpecializedPartialSpecialization *PS = + new (getASTContext()) SpecializedPartialSpecialization(); + PS->PartialSpecialization = PartialSpec; + PS->TemplateArgs = TemplateArgs; + SpecializedTemplate = PS; + } + + /// \brief Note that this variable template specialization is an instantiation + /// of the given variable template. + void setInstantiationOf(VarTemplateDecl *TemplDecl) { + assert(!SpecializedTemplate.is<SpecializedPartialSpecialization *>() && + "Previously set to a variable template partial specialization!"); + SpecializedTemplate = TemplDecl; + } + + /// \brief Sets the type of this specialization as it was written by + /// the user. + void setTypeAsWritten(TypeSourceInfo *T) { + if (!ExplicitInfo) + ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo; + ExplicitInfo->TypeAsWritten = T; + } + /// \brief Gets the type of this specialization as it was written by + /// the user, if it was so written. + TypeSourceInfo *getTypeAsWritten() const { + return ExplicitInfo ? ExplicitInfo->TypeAsWritten : nullptr; + } + + /// \brief Gets the location of the extern keyword, if present. + SourceLocation getExternLoc() const { + return ExplicitInfo ? ExplicitInfo->ExternLoc : SourceLocation(); + } + /// \brief Sets the location of the extern keyword. + void setExternLoc(SourceLocation Loc) { + if (!ExplicitInfo) + ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo; + ExplicitInfo->ExternLoc = Loc; + } + + /// \brief Sets the location of the template keyword. + void setTemplateKeywordLoc(SourceLocation Loc) { + if (!ExplicitInfo) + ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo; + ExplicitInfo->TemplateKeywordLoc = Loc; + } + /// \brief Gets the location of the template keyword, if present. + SourceLocation getTemplateKeywordLoc() const { + return ExplicitInfo ? ExplicitInfo->TemplateKeywordLoc : SourceLocation(); + } + + void Profile(llvm::FoldingSetNodeID &ID) const { + Profile(ID, TemplateArgs->asArray(), getASTContext()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, + ArrayRef<TemplateArgument> TemplateArgs, + ASTContext &Context) { + ID.AddInteger(TemplateArgs.size()); + for (unsigned Arg = 0; Arg != TemplateArgs.size(); ++Arg) + TemplateArgs[Arg].Profile(ID, Context); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { + return K >= firstVarTemplateSpecialization && + K <= lastVarTemplateSpecialization; + } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +class VarTemplatePartialSpecializationDecl + : public VarTemplateSpecializationDecl { + void anchor() override; + + /// \brief The list of template parameters + TemplateParameterList *TemplateParams; + + /// \brief The source info for the template arguments as written. + /// FIXME: redundant with TypeAsWritten? + const ASTTemplateArgumentListInfo *ArgsAsWritten; + + /// \brief The variable template partial specialization from which this + /// variable template partial specialization was instantiated. + /// + /// The boolean value will be true to indicate that this variable template + /// partial specialization was specialized at this level. + llvm::PointerIntPair<VarTemplatePartialSpecializationDecl *, 1, bool> + InstantiatedFromMember; + + VarTemplatePartialSpecializationDecl( + ASTContext &Context, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, TemplateParameterList *Params, + VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo, + StorageClass S, const TemplateArgument *Args, unsigned NumArgs, + const ASTTemplateArgumentListInfo *ArgInfos); + + VarTemplatePartialSpecializationDecl(ASTContext &Context) + : VarTemplateSpecializationDecl(VarTemplatePartialSpecialization, Context), + TemplateParams(nullptr), ArgsAsWritten(nullptr), + InstantiatedFromMember(nullptr, false) {} + +public: + static VarTemplatePartialSpecializationDecl * + Create(ASTContext &Context, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, TemplateParameterList *Params, + VarTemplateDecl *SpecializedTemplate, QualType T, + TypeSourceInfo *TInfo, StorageClass S, const TemplateArgument *Args, + unsigned NumArgs, const TemplateArgumentListInfo &ArgInfos); + + static VarTemplatePartialSpecializationDecl *CreateDeserialized(ASTContext &C, + unsigned ID); + + VarTemplatePartialSpecializationDecl *getMostRecentDecl() { + return cast<VarTemplatePartialSpecializationDecl>( + static_cast<VarTemplateSpecializationDecl *>( + this)->getMostRecentDecl()); + } + + /// Get the list of template parameters + TemplateParameterList *getTemplateParameters() const { + return TemplateParams; + } + + /// Get the template arguments as written. + const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const { + return ArgsAsWritten; + } + + /// \brief Retrieve the member variable template partial specialization from + /// which this particular variable template partial specialization was + /// instantiated. + /// + /// \code + /// template<typename T> + /// struct Outer { + /// template<typename U> U Inner; + /// template<typename U> U* Inner<U*> = (U*)(0); // #1 + /// }; + /// + /// template int* Outer<float>::Inner<int*>; + /// \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 + /// variable template partial specialization \c Outer<T>::Inner<U*>. Given + /// \c Outer<float>::Inner<U*>, this function would return + /// \c Outer<T>::Inner<U*>. + VarTemplatePartialSpecializationDecl *getInstantiatedFromMember() const { + const VarTemplatePartialSpecializationDecl *First = + cast<VarTemplatePartialSpecializationDecl>(getFirstDecl()); + return First->InstantiatedFromMember.getPointer(); + } + + void + setInstantiatedFromMember(VarTemplatePartialSpecializationDecl *PartialSpec) { + VarTemplatePartialSpecializationDecl *First = + cast<VarTemplatePartialSpecializationDecl>(getFirstDecl()); + First->InstantiatedFromMember.setPointer(PartialSpec); + } + + /// \brief Determines whether this variable template partial specialization + /// 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> U Inner; + /// template<typename U> U* Inner<U*> = (U*)(0); + /// }; + /// + /// template<> template<typename T> + /// U* X<int>::Inner<T*> = (T*)(0) + 1; + /// \endcode + bool isMemberSpecialization() { + VarTemplatePartialSpecializationDecl *First = + cast<VarTemplatePartialSpecializationDecl>(getFirstDecl()); + return First->InstantiatedFromMember.getInt(); + } + + /// \brief Note that this member template is a specialization. + void setMemberSpecialization() { + VarTemplatePartialSpecializationDecl *First = + cast<VarTemplatePartialSpecializationDecl>(getFirstDecl()); + assert(First->InstantiatedFromMember.getPointer() && + "Only member templates can be member template specializations"); + return First->InstantiatedFromMember.setInt(true); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { + return K == VarTemplatePartialSpecialization; + } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// Declaration of a variable template. +class VarTemplateDecl : public RedeclarableTemplateDecl { + static void DeallocateCommon(void *Ptr); + +protected: + /// \brief Data that is common to all of the declarations of a given + /// variable template. + struct Common : CommonBase { + Common() : LazySpecializations() {} + + /// \brief The variable template specializations for this variable + /// template, including explicit specializations and instantiations. + llvm::FoldingSetVector<VarTemplateSpecializationDecl> Specializations; + + /// \brief The variable template partial specializations for this variable + /// template. + llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> + PartialSpecializations; + + /// \brief If non-null, points to an array of specializations (including + /// partial specializations) known ownly by their external declaration IDs. + /// + /// The first value in the array is the number of of specializations/ + /// partial specializations that follow. + uint32_t *LazySpecializations; + }; + + /// \brief Retrieve the set of specializations of this variable template. + llvm::FoldingSetVector<VarTemplateSpecializationDecl> & + getSpecializations() const; + + /// \brief Retrieve the set of partial specializations of this class + /// template. + llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> & + getPartialSpecializations(); + + VarTemplateDecl(ASTContext &C, DeclContext *DC, SourceLocation L, + DeclarationName Name, TemplateParameterList *Params, + NamedDecl *Decl) + : RedeclarableTemplateDecl(VarTemplate, C, DC, L, Name, Params, Decl) {} + + CommonBase *newCommon(ASTContext &C) const override; + + Common *getCommonPtr() const { + return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr()); + } + +public: + /// \brief Load any lazily-loaded specializations from the external source. + void LoadLazySpecializations() const; + + /// \brief Get the underlying variable declarations of the template. + VarDecl *getTemplatedDecl() const { + return static_cast<VarDecl *>(TemplatedDecl); + } + + /// \brief Returns whether this template declaration defines the primary + /// variable pattern. + bool isThisDeclarationADefinition() const { + return getTemplatedDecl()->isThisDeclarationADefinition(); + } + + VarTemplateDecl *getDefinition(); + + /// \brief Create a variable template node. + static VarTemplateDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, DeclarationName Name, + TemplateParameterList *Params, + VarDecl *Decl); + + /// \brief Create an empty variable template node. + static VarTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + /// \brief Return the specialization with the provided arguments if it exists, + /// otherwise return the insertion point. + VarTemplateSpecializationDecl * + findSpecialization(ArrayRef<TemplateArgument> Args, void *&InsertPos); + + /// \brief Insert the specified specialization knowing that it is not already + /// in. InsertPos must be obtained from findSpecialization. + void AddSpecialization(VarTemplateSpecializationDecl *D, void *InsertPos); + + VarTemplateDecl *getCanonicalDecl() override { + return cast<VarTemplateDecl>(RedeclarableTemplateDecl::getCanonicalDecl()); + } + const VarTemplateDecl *getCanonicalDecl() const { + return cast<VarTemplateDecl>(RedeclarableTemplateDecl::getCanonicalDecl()); + } + + /// \brief Retrieve the previous declaration of this variable template, or + /// NULL if no such declaration exists. + VarTemplateDecl *getPreviousDecl() { + return cast_or_null<VarTemplateDecl>( + static_cast<RedeclarableTemplateDecl *>(this)->getPreviousDecl()); + } + + /// \brief Retrieve the previous declaration of this variable template, or + /// NULL if no such declaration exists. + const VarTemplateDecl *getPreviousDecl() const { + return cast_or_null<VarTemplateDecl>( + static_cast<const RedeclarableTemplateDecl *>( + this)->getPreviousDecl()); + } + + VarTemplateDecl *getMostRecentDecl() { + return cast<VarTemplateDecl>( + static_cast<RedeclarableTemplateDecl *>(this)->getMostRecentDecl()); + } + const VarTemplateDecl *getMostRecentDecl() const { + return const_cast<VarTemplateDecl *>(this)->getMostRecentDecl(); + } + + VarTemplateDecl *getInstantiatedFromMemberTemplate() const { + return cast_or_null<VarTemplateDecl>( + RedeclarableTemplateDecl::getInstantiatedFromMemberTemplate()); + } + + /// \brief Return the partial specialization with the provided arguments if it + /// exists, otherwise return the insertion point. + VarTemplatePartialSpecializationDecl * + findPartialSpecialization(ArrayRef<TemplateArgument> Args, void *&InsertPos); + + /// \brief Insert the specified partial specialization knowing that it is not + /// already in. InsertPos must be obtained from findPartialSpecialization. + void AddPartialSpecialization(VarTemplatePartialSpecializationDecl *D, + void *InsertPos); + + /// \brief Retrieve the partial specializations as an ordered list. + void getPartialSpecializations( + SmallVectorImpl<VarTemplatePartialSpecializationDecl *> &PS); + + /// \brief Find a variable template partial specialization which was + /// instantiated + /// from the given member partial specialization. + /// + /// \param D a member variable template partial specialization. + /// + /// \returns the variable template partial specialization which was + /// instantiated + /// from the given member partial specialization, or NULL if no such partial + /// specialization exists. + VarTemplatePartialSpecializationDecl *findPartialSpecInstantiatedFromMember( + VarTemplatePartialSpecializationDecl *D); + + typedef SpecIterator<VarTemplateSpecializationDecl> spec_iterator; + typedef llvm::iterator_range<spec_iterator> spec_range; + + spec_range specializations() const { + return spec_range(spec_begin(), spec_end()); + } + + spec_iterator spec_begin() const { + return makeSpecIterator(getSpecializations(), false); + } + + spec_iterator spec_end() const { + return makeSpecIterator(getSpecializations(), true); + } + + // Implement isa/cast/dyncast support + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == VarTemplate; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +} /* end of namespace clang */ + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/DeclVisitor.h b/contrib/llvm/tools/clang/include/clang/AST/DeclVisitor.h new file mode 100644 index 0000000..4eaae35 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/DeclVisitor.h @@ -0,0 +1,79 @@ +//===--- DeclVisitor.h - Visitor for Decl subclasses ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the DeclVisitor interface. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_DECLVISITOR_H +#define LLVM_CLANG_AST_DECLVISITOR_H + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclFriend.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclOpenMP.h" +#include "clang/AST/DeclTemplate.h" + +namespace clang { +namespace declvisitor { + +template <typename T> struct make_ptr { typedef T *type; }; +template <typename T> struct make_const_ptr { typedef const T *type; }; + +/// \brief A simple visitor class that helps create declaration visitors. +template<template <typename> class Ptr, typename ImplClass, typename RetTy=void> +class Base { +public: + +#define PTR(CLASS) typename Ptr<CLASS>::type +#define DISPATCH(NAME, CLASS) \ + return static_cast<ImplClass*>(this)->Visit##NAME(static_cast<PTR(CLASS)>(D)) + + RetTy Visit(PTR(Decl) D) { + switch (D->getKind()) { +#define DECL(DERIVED, BASE) \ + case Decl::DERIVED: DISPATCH(DERIVED##Decl, DERIVED##Decl); +#define ABSTRACT_DECL(DECL) +#include "clang/AST/DeclNodes.inc" + } + llvm_unreachable("Decl that isn't part of DeclNodes.inc!"); + } + + // If the implementation chooses not to implement a certain visit + // method, fall back to the parent. +#define DECL(DERIVED, BASE) \ + RetTy Visit##DERIVED##Decl(PTR(DERIVED##Decl) D) { DISPATCH(BASE, BASE); } +#include "clang/AST/DeclNodes.inc" + + RetTy VisitDecl(PTR(Decl) D) { return RetTy(); } + +#undef PTR +#undef DISPATCH +}; + +} // end namespace declvisitor + +/// \brief A simple visitor class that helps create declaration visitors. +/// +/// This class does not preserve constness of Decl pointers (see also +/// ConstDeclVisitor). +template<typename ImplClass, typename RetTy=void> +class DeclVisitor + : public declvisitor::Base<declvisitor::make_ptr, ImplClass, RetTy> {}; + +/// \brief A simple visitor class that helps create declaration visitors. +/// +/// This class preserves constness of Decl pointers (see also DeclVisitor). +template<typename ImplClass, typename RetTy=void> +class ConstDeclVisitor + : public declvisitor::Base<declvisitor::make_const_ptr, ImplClass, RetTy> {}; + +} // end namespace clang + +#endif // LLVM_CLANG_AST_DECLVISITOR_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/DeclarationName.h b/contrib/llvm/tools/clang/include/clang/AST/DeclarationName.h new file mode 100644 index 0000000..9482e83e --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/DeclarationName.h @@ -0,0 +1,598 @@ +//===-- DeclarationName.h - Representation of declaration names -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the DeclarationName and DeclarationNameTable classes. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_DECLARATIONNAME_H +#define LLVM_CLANG_AST_DECLARATIONNAME_H + +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/PartialDiagnostic.h" +#include "llvm/Support/Compiler.h" + +namespace llvm { + template <typename T> struct DenseMapInfo; +} + +namespace clang { + class ASTContext; + class CXXLiteralOperatorIdName; + class CXXOperatorIdName; + class CXXSpecialName; + class DeclarationNameExtra; + class IdentifierInfo; + class MultiKeywordSelector; + enum OverloadedOperatorKind : int; + class QualType; + class Type; + class TypeSourceInfo; + class UsingDirectiveDecl; + + template <typename> class CanQual; + typedef CanQual<Type> CanQualType; + +/// DeclarationName - The name of a declaration. In the common case, +/// this just stores an IdentifierInfo pointer to a normal +/// name. However, it also provides encodings for Objective-C +/// selectors (optimizing zero- and one-argument selectors, which make +/// up 78% percent of all selectors in Cocoa.h) and special C++ names +/// for constructors, destructors, and conversion functions. +class DeclarationName { +public: + /// NameKind - The kind of name this object contains. + enum NameKind { + Identifier, + ObjCZeroArgSelector, + ObjCOneArgSelector, + ObjCMultiArgSelector, + CXXConstructorName, + CXXDestructorName, + CXXConversionFunctionName, + CXXOperatorName, + CXXLiteralOperatorName, + CXXUsingDirective + }; + static const unsigned NumNameKinds = CXXUsingDirective + 1; + +private: + /// StoredNameKind - The kind of name that is actually stored in the + /// upper bits of the Ptr field. This is only used internally. + /// + /// Note: The entries here are synchronized with the entries in Selector, + /// for efficient translation between the two. + enum StoredNameKind { + StoredIdentifier = 0, + StoredObjCZeroArgSelector = 0x01, + StoredObjCOneArgSelector = 0x02, + StoredDeclarationNameExtra = 0x03, + PtrMask = 0x03 + }; + + /// Ptr - The lowest two bits are used to express what kind of name + /// we're actually storing, using the values of NameKind. Depending + /// on the kind of name this is, the upper bits of Ptr may have one + /// of several different meanings: + /// + /// StoredIdentifier - The name is a normal identifier, and Ptr is + /// a normal IdentifierInfo pointer. + /// + /// StoredObjCZeroArgSelector - The name is an Objective-C + /// selector with zero arguments, and Ptr is an IdentifierInfo + /// pointer pointing to the selector name. + /// + /// StoredObjCOneArgSelector - The name is an Objective-C selector + /// with one argument, and Ptr is an IdentifierInfo pointer + /// pointing to the selector name. + /// + /// StoredDeclarationNameExtra - Ptr is actually a pointer to a + /// DeclarationNameExtra structure, whose first value will tell us + /// whether this is an Objective-C selector, C++ operator-id name, + /// or special C++ name. + uintptr_t Ptr; + + /// getStoredNameKind - Return the kind of object that is stored in + /// Ptr. + StoredNameKind getStoredNameKind() const { + return static_cast<StoredNameKind>(Ptr & PtrMask); + } + + /// getExtra - Get the "extra" information associated with this + /// multi-argument selector or C++ special name. + DeclarationNameExtra *getExtra() const { + assert(getStoredNameKind() == StoredDeclarationNameExtra && + "Declaration name does not store an Extra structure"); + return reinterpret_cast<DeclarationNameExtra *>(Ptr & ~PtrMask); + } + + /// getAsCXXSpecialName - If the stored pointer is actually a + /// CXXSpecialName, returns a pointer to it. Otherwise, returns + /// a NULL pointer. + CXXSpecialName *getAsCXXSpecialName() const { + NameKind Kind = getNameKind(); + if (Kind >= CXXConstructorName && Kind <= CXXConversionFunctionName) + return reinterpret_cast<CXXSpecialName *>(Ptr & ~PtrMask); + return nullptr; + } + + /// getAsCXXOperatorIdName + CXXOperatorIdName *getAsCXXOperatorIdName() const { + if (getNameKind() == CXXOperatorName) + return reinterpret_cast<CXXOperatorIdName *>(Ptr & ~PtrMask); + return nullptr; + } + + CXXLiteralOperatorIdName *getAsCXXLiteralOperatorIdName() const { + if (getNameKind() == CXXLiteralOperatorName) + return reinterpret_cast<CXXLiteralOperatorIdName *>(Ptr & ~PtrMask); + return nullptr; + } + + // Construct a declaration name from the name of a C++ constructor, + // destructor, or conversion function. + DeclarationName(CXXSpecialName *Name) + : Ptr(reinterpret_cast<uintptr_t>(Name)) { + assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXSpecialName"); + Ptr |= StoredDeclarationNameExtra; + } + + // Construct a declaration name from the name of a C++ overloaded + // operator. + DeclarationName(CXXOperatorIdName *Name) + : Ptr(reinterpret_cast<uintptr_t>(Name)) { + assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXOperatorId"); + Ptr |= StoredDeclarationNameExtra; + } + + DeclarationName(CXXLiteralOperatorIdName *Name) + : Ptr(reinterpret_cast<uintptr_t>(Name)) { + assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXLiteralOperatorId"); + Ptr |= StoredDeclarationNameExtra; + } + + /// Construct a declaration name from a raw pointer. + DeclarationName(uintptr_t Ptr) : Ptr(Ptr) { } + + friend class DeclarationNameTable; + friend class NamedDecl; + + /// getFETokenInfoAsVoidSlow - Retrieves the front end-specified pointer + /// for this name as a void pointer if it's not an identifier. + void *getFETokenInfoAsVoidSlow() const; + +public: + /// DeclarationName - Used to create an empty selector. + DeclarationName() : Ptr(0) { } + + // Construct a declaration name from an IdentifierInfo *. + DeclarationName(const IdentifierInfo *II) + : Ptr(reinterpret_cast<uintptr_t>(II)) { + assert((Ptr & PtrMask) == 0 && "Improperly aligned IdentifierInfo"); + } + + // Construct a declaration name from an Objective-C selector. + DeclarationName(Selector Sel) : Ptr(Sel.InfoPtr) { } + + /// getUsingDirectiveName - Return name for all using-directives. + static DeclarationName getUsingDirectiveName(); + + // operator bool() - Evaluates true when this declaration name is + // non-empty. + explicit operator bool() const { + return ((Ptr & PtrMask) != 0) || + (reinterpret_cast<IdentifierInfo *>(Ptr & ~PtrMask)); + } + + /// \brief Evaluates true when this declaration name is empty. + bool isEmpty() const { + return !*this; + } + + /// Predicate functions for querying what type of name this is. + bool isIdentifier() const { return getStoredNameKind() == StoredIdentifier; } + bool isObjCZeroArgSelector() const { + return getStoredNameKind() == StoredObjCZeroArgSelector; + } + bool isObjCOneArgSelector() const { + return getStoredNameKind() == StoredObjCOneArgSelector; + } + + /// getNameKind - Determine what kind of name this is. + NameKind getNameKind() const; + + /// \brief Determines whether the name itself is dependent, e.g., because it + /// involves a C++ type that is itself dependent. + /// + /// Note that this does not capture all of the notions of "dependent name", + /// because an identifier can be a dependent name if it is used as the + /// callee in a call expression with dependent arguments. + bool isDependentName() const; + + /// getNameAsString - Retrieve the human-readable string for this name. + std::string getAsString() const; + + /// getAsIdentifierInfo - Retrieve the IdentifierInfo * stored in + /// this declaration name, or NULL if this declaration name isn't a + /// simple identifier. + IdentifierInfo *getAsIdentifierInfo() const { + if (isIdentifier()) + return reinterpret_cast<IdentifierInfo *>(Ptr); + return nullptr; + } + + /// getAsOpaqueInteger - Get the representation of this declaration + /// name as an opaque integer. + uintptr_t getAsOpaqueInteger() const { return Ptr; } + + /// getAsOpaquePtr - Get the representation of this declaration name as + /// an opaque pointer. + void *getAsOpaquePtr() const { return reinterpret_cast<void*>(Ptr); } + + static DeclarationName getFromOpaquePtr(void *P) { + DeclarationName N; + N.Ptr = reinterpret_cast<uintptr_t> (P); + return N; + } + + static DeclarationName getFromOpaqueInteger(uintptr_t P) { + DeclarationName N; + N.Ptr = P; + return N; + } + + /// getCXXNameType - If this name is one of the C++ names (of a + /// constructor, destructor, or conversion function), return the + /// type associated with that name. + QualType getCXXNameType() const; + + /// getCXXOverloadedOperator - If this name is the name of an + /// overloadable operator in C++ (e.g., @c operator+), retrieve the + /// kind of overloaded operator. + OverloadedOperatorKind getCXXOverloadedOperator() const; + + /// getCXXLiteralIdentifier - If this name is the name of a literal + /// operator, retrieve the identifier associated with it. + IdentifierInfo *getCXXLiteralIdentifier() const; + + /// getObjCSelector - Get the Objective-C selector stored in this + /// declaration name. + Selector getObjCSelector() const { + assert((getNameKind() == ObjCZeroArgSelector || + getNameKind() == ObjCOneArgSelector || + getNameKind() == ObjCMultiArgSelector || + Ptr == 0) && "Not a selector!"); + return Selector(Ptr); + } + + /// getFETokenInfo/setFETokenInfo - The language front-end is + /// allowed to associate arbitrary metadata with some kinds of + /// declaration names, including normal identifiers and C++ + /// constructors, destructors, and conversion functions. + template<typename T> + T *getFETokenInfo() const { + if (const IdentifierInfo *Info = getAsIdentifierInfo()) + return Info->getFETokenInfo<T>(); + return static_cast<T*>(getFETokenInfoAsVoidSlow()); + } + + void setFETokenInfo(void *T); + + /// operator== - Determine whether the specified names are identical.. + friend bool operator==(DeclarationName LHS, DeclarationName RHS) { + return LHS.Ptr == RHS.Ptr; + } + + /// operator!= - Determine whether the specified names are different. + friend bool operator!=(DeclarationName LHS, DeclarationName RHS) { + return LHS.Ptr != RHS.Ptr; + } + + static DeclarationName getEmptyMarker() { + return DeclarationName(uintptr_t(-1)); + } + + static DeclarationName getTombstoneMarker() { + return DeclarationName(uintptr_t(-2)); + } + + static int compare(DeclarationName LHS, DeclarationName RHS); + + void dump() const; +}; + +raw_ostream &operator<<(raw_ostream &OS, DeclarationName N); + +/// Ordering on two declaration names. If both names are identifiers, +/// this provides a lexicographical ordering. +inline bool operator<(DeclarationName LHS, DeclarationName RHS) { + return DeclarationName::compare(LHS, RHS) < 0; +} + +/// Ordering on two declaration names. If both names are identifiers, +/// this provides a lexicographical ordering. +inline bool operator>(DeclarationName LHS, DeclarationName RHS) { + return DeclarationName::compare(LHS, RHS) > 0; +} + +/// Ordering on two declaration names. If both names are identifiers, +/// this provides a lexicographical ordering. +inline bool operator<=(DeclarationName LHS, DeclarationName RHS) { + return DeclarationName::compare(LHS, RHS) <= 0; +} + +/// Ordering on two declaration names. If both names are identifiers, +/// this provides a lexicographical ordering. +inline bool operator>=(DeclarationName LHS, DeclarationName RHS) { + return DeclarationName::compare(LHS, RHS) >= 0; +} + +/// DeclarationNameTable - Used to store and retrieve DeclarationName +/// instances for the various kinds of declaration names, e.g., normal +/// identifiers, C++ constructor names, etc. This class contains +/// uniqued versions of each of the C++ special names, which can be +/// retrieved using its member functions (e.g., +/// getCXXConstructorName). +class DeclarationNameTable { + const ASTContext &Ctx; + void *CXXSpecialNamesImpl; // Actually a FoldingSet<CXXSpecialName> * + CXXOperatorIdName *CXXOperatorNames; // Operator names + void *CXXLiteralOperatorNames; // Actually a CXXOperatorIdName* + + DeclarationNameTable(const DeclarationNameTable&) = delete; + void operator=(const DeclarationNameTable&) = delete; + +public: + DeclarationNameTable(const ASTContext &C); + ~DeclarationNameTable(); + + /// getIdentifier - Create a declaration name that is a simple + /// identifier. + DeclarationName getIdentifier(const IdentifierInfo *ID) { + return DeclarationName(ID); + } + + /// getCXXConstructorName - Returns the name of a C++ constructor + /// for the given Type. + DeclarationName getCXXConstructorName(CanQualType Ty); + + /// getCXXDestructorName - Returns the name of a C++ destructor + /// for the given Type. + DeclarationName getCXXDestructorName(CanQualType Ty); + + /// getCXXConversionFunctionName - Returns the name of a C++ + /// conversion function for the given Type. + DeclarationName getCXXConversionFunctionName(CanQualType Ty); + + /// getCXXSpecialName - Returns a declaration name for special kind + /// of C++ name, e.g., for a constructor, destructor, or conversion + /// function. + DeclarationName getCXXSpecialName(DeclarationName::NameKind Kind, + CanQualType Ty); + + /// getCXXOperatorName - Get the name of the overloadable C++ + /// operator corresponding to Op. + DeclarationName getCXXOperatorName(OverloadedOperatorKind Op); + + /// getCXXLiteralOperatorName - Get the name of the literal operator function + /// with II as the identifier. + DeclarationName getCXXLiteralOperatorName(IdentifierInfo *II); +}; + +/// DeclarationNameLoc - Additional source/type location info +/// for a declaration name. Needs a DeclarationName in order +/// to be interpreted correctly. +struct DeclarationNameLoc { + // The source location for identifier stored elsewhere. + // struct {} Identifier; + + // Type info for constructors, destructors and conversion functions. + // Locations (if any) for the tilde (destructor) or operator keyword + // (conversion) are stored elsewhere. + struct NT { + TypeSourceInfo *TInfo; + }; + + // The location (if any) of the operator keyword is stored elsewhere. + struct CXXOpName { + unsigned BeginOpNameLoc; + unsigned EndOpNameLoc; + }; + + // The location (if any) of the operator keyword is stored elsewhere. + struct CXXLitOpName { + unsigned OpNameLoc; + }; + + // struct {} CXXUsingDirective; + // struct {} ObjCZeroArgSelector; + // struct {} ObjCOneArgSelector; + // struct {} ObjCMultiArgSelector; + union { + struct NT NamedType; + struct CXXOpName CXXOperatorName; + struct CXXLitOpName CXXLiteralOperatorName; + }; + + DeclarationNameLoc(DeclarationName Name); + // FIXME: this should go away once all DNLocs are properly initialized. + DeclarationNameLoc() { memset((void*) this, 0, sizeof(*this)); } +}; // struct DeclarationNameLoc + + +/// DeclarationNameInfo - A collector data type for bundling together +/// a DeclarationName and the correspnding source/type location info. +struct DeclarationNameInfo { +private: + /// Name - The declaration name, also encoding name kind. + DeclarationName Name; + /// Loc - The main source location for the declaration name. + SourceLocation NameLoc; + /// Info - Further source/type location info for special kinds of names. + DeclarationNameLoc LocInfo; + +public: + // FIXME: remove it. + DeclarationNameInfo() {} + + DeclarationNameInfo(DeclarationName Name, SourceLocation NameLoc) + : Name(Name), NameLoc(NameLoc), LocInfo(Name) {} + + DeclarationNameInfo(DeclarationName Name, SourceLocation NameLoc, + DeclarationNameLoc LocInfo) + : Name(Name), NameLoc(NameLoc), LocInfo(LocInfo) {} + + /// getName - Returns the embedded declaration name. + DeclarationName getName() const { return Name; } + /// setName - Sets the embedded declaration name. + void setName(DeclarationName N) { Name = N; } + + /// getLoc - Returns the main location of the declaration name. + SourceLocation getLoc() const { return NameLoc; } + /// setLoc - Sets the main location of the declaration name. + void setLoc(SourceLocation L) { NameLoc = L; } + + const DeclarationNameLoc &getInfo() const { return LocInfo; } + DeclarationNameLoc &getInfo() { return LocInfo; } + void setInfo(const DeclarationNameLoc &Info) { LocInfo = Info; } + + /// getNamedTypeInfo - Returns the source type info associated to + /// the name. Assumes it is a constructor, destructor or conversion. + TypeSourceInfo *getNamedTypeInfo() const { + assert(Name.getNameKind() == DeclarationName::CXXConstructorName || + Name.getNameKind() == DeclarationName::CXXDestructorName || + Name.getNameKind() == DeclarationName::CXXConversionFunctionName); + return LocInfo.NamedType.TInfo; + } + /// setNamedTypeInfo - Sets the source type info associated to + /// the name. Assumes it is a constructor, destructor or conversion. + void setNamedTypeInfo(TypeSourceInfo *TInfo) { + assert(Name.getNameKind() == DeclarationName::CXXConstructorName || + Name.getNameKind() == DeclarationName::CXXDestructorName || + Name.getNameKind() == DeclarationName::CXXConversionFunctionName); + LocInfo.NamedType.TInfo = TInfo; + } + + /// getCXXOperatorNameRange - Gets the range of the operator name + /// (without the operator keyword). Assumes it is a (non-literal) operator. + SourceRange getCXXOperatorNameRange() const { + assert(Name.getNameKind() == DeclarationName::CXXOperatorName); + return SourceRange( + SourceLocation::getFromRawEncoding(LocInfo.CXXOperatorName.BeginOpNameLoc), + SourceLocation::getFromRawEncoding(LocInfo.CXXOperatorName.EndOpNameLoc) + ); + } + /// setCXXOperatorNameRange - Sets the range of the operator name + /// (without the operator keyword). Assumes it is a C++ operator. + void setCXXOperatorNameRange(SourceRange R) { + assert(Name.getNameKind() == DeclarationName::CXXOperatorName); + LocInfo.CXXOperatorName.BeginOpNameLoc = R.getBegin().getRawEncoding(); + LocInfo.CXXOperatorName.EndOpNameLoc = R.getEnd().getRawEncoding(); + } + + /// getCXXLiteralOperatorNameLoc - Returns the location of the literal + /// operator name (not the operator keyword). + /// Assumes it is a literal operator. + SourceLocation getCXXLiteralOperatorNameLoc() const { + assert(Name.getNameKind() == DeclarationName::CXXLiteralOperatorName); + return SourceLocation:: + getFromRawEncoding(LocInfo.CXXLiteralOperatorName.OpNameLoc); + } + /// setCXXLiteralOperatorNameLoc - Sets the location of the literal + /// operator name (not the operator keyword). + /// Assumes it is a literal operator. + void setCXXLiteralOperatorNameLoc(SourceLocation Loc) { + assert(Name.getNameKind() == DeclarationName::CXXLiteralOperatorName); + LocInfo.CXXLiteralOperatorName.OpNameLoc = Loc.getRawEncoding(); + } + + /// \brief Determine whether this name involves a template parameter. + bool isInstantiationDependent() const; + + /// \brief Determine whether this name contains an unexpanded + /// parameter pack. + bool containsUnexpandedParameterPack() const; + + /// getAsString - Retrieve the human-readable string for this name. + std::string getAsString() const; + + /// printName - Print the human-readable name to a stream. + void printName(raw_ostream &OS) const; + + /// getBeginLoc - Retrieve the location of the first token. + SourceLocation getBeginLoc() const { return NameLoc; } + /// getEndLoc - Retrieve the location of the last token. + SourceLocation getEndLoc() const; + /// getSourceRange - The range of the declaration name. + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(getLocStart(), getLocEnd()); + } + SourceLocation getLocStart() const LLVM_READONLY { + return getBeginLoc(); + } + SourceLocation getLocEnd() const LLVM_READONLY { + SourceLocation EndLoc = getEndLoc(); + return EndLoc.isValid() ? EndLoc : getLocStart(); + } +}; + +/// Insertion operator for diagnostics. This allows sending DeclarationName's +/// into a diagnostic with <<. +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + DeclarationName N) { + DB.AddTaggedVal(N.getAsOpaqueInteger(), + DiagnosticsEngine::ak_declarationname); + return DB; +} + +/// Insertion operator for partial diagnostics. This allows binding +/// DeclarationName's into a partial diagnostic with <<. +inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + DeclarationName N) { + PD.AddTaggedVal(N.getAsOpaqueInteger(), + DiagnosticsEngine::ak_declarationname); + return PD; +} + +inline raw_ostream &operator<<(raw_ostream &OS, + DeclarationNameInfo DNInfo) { + DNInfo.printName(OS); + return OS; +} + +} // end namespace clang + +namespace llvm { +/// Define DenseMapInfo so that DeclarationNames can be used as keys +/// in DenseMap and DenseSets. +template<> +struct DenseMapInfo<clang::DeclarationName> { + static inline clang::DeclarationName getEmptyKey() { + return clang::DeclarationName::getEmptyMarker(); + } + + static inline clang::DeclarationName getTombstoneKey() { + return clang::DeclarationName::getTombstoneMarker(); + } + + static unsigned getHashValue(clang::DeclarationName Name) { + return DenseMapInfo<void*>::getHashValue(Name.getAsOpaquePtr()); + } + + static inline bool + isEqual(clang::DeclarationName LHS, clang::DeclarationName RHS) { + return LHS == RHS; + } +}; + +template <> +struct isPodLike<clang::DeclarationName> { static const bool value = true; }; + +} // end namespace llvm + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/DependentDiagnostic.h b/contrib/llvm/tools/clang/include/clang/AST/DependentDiagnostic.h new file mode 100644 index 0000000..8e038c8 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/DependentDiagnostic.h @@ -0,0 +1,189 @@ +//===-- DependentDiagnostic.h - Dependently-generated diagnostics -*- 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 interfaces for diagnostics which may or may +// fire based on how a template is instantiated. +// +// At the moment, the only consumer of this interface is access +// control. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DEPENDENTDIAGNOSTIC_H +#define LLVM_CLANG_AST_DEPENDENTDIAGNOSTIC_H + +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclContextInternals.h" +#include "clang/AST/Type.h" +#include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/SourceLocation.h" + +namespace clang { + +class ASTContext; +class CXXRecordDecl; +class NamedDecl; + +/// A dependently-generated diagnostic. +class DependentDiagnostic { +public: + enum AccessNonce { Access = 0 }; + + static DependentDiagnostic *Create(ASTContext &Context, + DeclContext *Parent, + AccessNonce _, + SourceLocation Loc, + bool IsMemberAccess, + AccessSpecifier AS, + NamedDecl *TargetDecl, + CXXRecordDecl *NamingClass, + QualType BaseObjectType, + const PartialDiagnostic &PDiag) { + DependentDiagnostic *DD = Create(Context, Parent, PDiag); + DD->AccessData.Loc = Loc.getRawEncoding(); + DD->AccessData.IsMember = IsMemberAccess; + DD->AccessData.Access = AS; + DD->AccessData.TargetDecl = TargetDecl; + DD->AccessData.NamingClass = NamingClass; + DD->AccessData.BaseObjectType = BaseObjectType.getAsOpaquePtr(); + return DD; + } + + unsigned getKind() const { + return Access; + } + + bool isAccessToMember() const { + assert(getKind() == Access); + return AccessData.IsMember; + } + + AccessSpecifier getAccess() const { + assert(getKind() == Access); + return AccessSpecifier(AccessData.Access); + } + + SourceLocation getAccessLoc() const { + assert(getKind() == Access); + return SourceLocation::getFromRawEncoding(AccessData.Loc); + } + + NamedDecl *getAccessTarget() const { + assert(getKind() == Access); + return AccessData.TargetDecl; + } + + NamedDecl *getAccessNamingClass() const { + assert(getKind() == Access); + return AccessData.NamingClass; + } + + QualType getAccessBaseObjectType() const { + assert(getKind() == Access); + return QualType::getFromOpaquePtr(AccessData.BaseObjectType); + } + + const PartialDiagnostic &getDiagnostic() const { + return Diag; + } + +private: + DependentDiagnostic(const PartialDiagnostic &PDiag, + PartialDiagnostic::Storage *Storage) + : Diag(PDiag, Storage) {} + + static DependentDiagnostic *Create(ASTContext &Context, + DeclContext *Parent, + const PartialDiagnostic &PDiag); + + friend class DependentStoredDeclsMap; + friend class DeclContext::ddiag_iterator; + DependentDiagnostic *NextDiagnostic; + + PartialDiagnostic Diag; + + struct { + unsigned Loc; + unsigned Access : 2; + unsigned IsMember : 1; + NamedDecl *TargetDecl; + CXXRecordDecl *NamingClass; + void *BaseObjectType; + } AccessData; +}; + +/// + +/// An iterator over the dependent diagnostics in a dependent context. +class DeclContext::ddiag_iterator { +public: + ddiag_iterator() : Ptr(nullptr) {} + explicit ddiag_iterator(DependentDiagnostic *Ptr) : Ptr(Ptr) {} + + typedef DependentDiagnostic *value_type; + typedef DependentDiagnostic *reference; + typedef DependentDiagnostic *pointer; + typedef int difference_type; + typedef std::forward_iterator_tag iterator_category; + + reference operator*() const { return Ptr; } + + ddiag_iterator &operator++() { + assert(Ptr && "attempt to increment past end of diag list"); + Ptr = Ptr->NextDiagnostic; + return *this; + } + + ddiag_iterator operator++(int) { + ddiag_iterator tmp = *this; + ++*this; + return tmp; + } + + bool operator==(ddiag_iterator Other) const { + return Ptr == Other.Ptr; + } + + bool operator!=(ddiag_iterator Other) const { + return Ptr != Other.Ptr; + } + + ddiag_iterator &operator+=(difference_type N) { + assert(N >= 0 && "cannot rewind a DeclContext::ddiag_iterator"); + while (N--) + ++*this; + return *this; + } + + ddiag_iterator operator+(difference_type N) const { + ddiag_iterator tmp = *this; + tmp += N; + return tmp; + } + +private: + DependentDiagnostic *Ptr; +}; + +inline DeclContext::ddiag_range DeclContext::ddiags() const { + assert(isDependentContext() + && "cannot iterate dependent diagnostics of non-dependent context"); + const DependentStoredDeclsMap *Map + = static_cast<DependentStoredDeclsMap*>(getPrimaryContext()->getLookupPtr()); + + if (!Map) + // Return an empty range using the always-end default constructor. + return ddiag_range(ddiag_iterator(), ddiag_iterator()); + + return ddiag_range(ddiag_iterator(Map->FirstDiagnostic), ddiag_iterator()); +} + +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/EvaluatedExprVisitor.h b/contrib/llvm/tools/clang/include/clang/AST/EvaluatedExprVisitor.h new file mode 100644 index 0000000..aad7726 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/EvaluatedExprVisitor.h @@ -0,0 +1,129 @@ +//===--- EvaluatedExprVisitor.h - Evaluated expression visitor --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the EvaluatedExprVisitor class template, which visits +// the potentially-evaluated subexpressions of a potentially-evaluated +// expression. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_EVALUATEDEXPRVISITOR_H +#define LLVM_CLANG_AST_EVALUATEDEXPRVISITOR_H + +#include "clang/AST/DeclCXX.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/StmtVisitor.h" + +namespace clang { + +class ASTContext; + +/// \brief Given a potentially-evaluated expression, this visitor visits all +/// of its potentially-evaluated subexpressions, recursively. +template<template <typename> class Ptr, typename ImplClass> +class EvaluatedExprVisitorBase : public StmtVisitorBase<Ptr, ImplClass, void> { +protected: + const ASTContext &Context; + +public: +#define PTR(CLASS) typename Ptr<CLASS>::type + + explicit EvaluatedExprVisitorBase(const ASTContext &Context) : Context(Context) { } + + // Expressions that have no potentially-evaluated subexpressions (but may have + // other sub-expressions). + void VisitDeclRefExpr(PTR(DeclRefExpr) E) { } + void VisitOffsetOfExpr(PTR(OffsetOfExpr) E) { } + void VisitUnaryExprOrTypeTraitExpr(PTR(UnaryExprOrTypeTraitExpr) E) { } + void VisitExpressionTraitExpr(PTR(ExpressionTraitExpr) E) { } + void VisitBlockExpr(PTR(BlockExpr) E) { } + void VisitCXXUuidofExpr(PTR(CXXUuidofExpr) E) { } + void VisitCXXNoexceptExpr(PTR(CXXNoexceptExpr) E) { } + + void VisitMemberExpr(PTR(MemberExpr) E) { + // Only the base matters. + return this->Visit(E->getBase()); + } + + void VisitChooseExpr(PTR(ChooseExpr) E) { + // Don't visit either child expression if the condition is dependent. + if (E->getCond()->isValueDependent()) + return; + // Only the selected subexpression matters; the other one is not evaluated. + return this->Visit(E->getChosenSubExpr()); + } + + void VisitGenericSelectionExpr(PTR(GenericSelectionExpr) E) { + // The controlling expression of a generic selection is not evaluated. + + // Don't visit either child expression if the condition is type-dependent. + if (E->isResultDependent()) + return; + // Only the selected subexpression matters; the other subexpressions and the + // controlling expression are not evaluated. + return this->Visit(E->getResultExpr()); + } + + void VisitDesignatedInitExpr(PTR(DesignatedInitExpr) E) { + // Only the actual initializer matters; the designators are all constant + // expressions. + return this->Visit(E->getInit()); + } + + void VisitCXXTypeidExpr(PTR(CXXTypeidExpr) E) { + if (E->isPotentiallyEvaluated()) + return this->Visit(E->getExprOperand()); + } + + void VisitCallExpr(PTR(CallExpr) CE) { + if (!CE->isUnevaluatedBuiltinCall(Context)) + return static_cast<ImplClass*>(this)->VisitExpr(CE); + } + + void VisitLambdaExpr(PTR(LambdaExpr) LE) { + // Only visit the capture initializers, and not the body. + for (LambdaExpr::const_capture_init_iterator I = LE->capture_init_begin(), + E = LE->capture_init_end(); + I != E; ++I) + if (*I) + this->Visit(*I); + } + + /// \brief The basis case walks all of the children of the statement or + /// expression, assuming they are all potentially evaluated. + void VisitStmt(PTR(Stmt) S) { + for (auto *SubStmt : S->children()) + if (SubStmt) + this->Visit(SubStmt); + } + +#undef PTR +}; + +/// EvaluatedExprVisitor - This class visits 'Expr *'s +template<typename ImplClass> +class EvaluatedExprVisitor + : public EvaluatedExprVisitorBase<make_ptr, ImplClass> { +public: + explicit EvaluatedExprVisitor(const ASTContext &Context) : + EvaluatedExprVisitorBase<make_ptr, ImplClass>(Context) { } +}; + +/// ConstEvaluatedExprVisitor - This class visits 'const Expr *'s. +template<typename ImplClass> +class ConstEvaluatedExprVisitor + : public EvaluatedExprVisitorBase<make_const_ptr, ImplClass> { +public: + explicit ConstEvaluatedExprVisitor(const ASTContext &Context) : + EvaluatedExprVisitorBase<make_const_ptr, ImplClass>(Context) { } +}; + +} + +#endif // LLVM_CLANG_AST_EVALUATEDEXPRVISITOR_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/Expr.h b/contrib/llvm/tools/clang/include/clang/AST/Expr.h new file mode 100644 index 0000000..095dd6a --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/Expr.h @@ -0,0 +1,4941 @@ +//===--- Expr.h - Classes for representing expressions ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Expr interface and subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_EXPR_H +#define LLVM_CLANG_AST_EXPR_H + +#include "clang/AST/APValue.h" +#include "clang/AST/ASTVector.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclAccessPair.h" +#include "clang/AST/OperationKinds.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/Type.h" +#include "clang/Basic/CharInfo.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/TypeTraits.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Compiler.h" + +namespace clang { + class APValue; + class ASTContext; + class BlockDecl; + class CXXBaseSpecifier; + class CXXMemberCallExpr; + class CXXOperatorCallExpr; + class CastExpr; + class Decl; + class IdentifierInfo; + class MaterializeTemporaryExpr; + class NamedDecl; + class ObjCPropertyRefExpr; + class OpaqueValueExpr; + class ParmVarDecl; + class StringLiteral; + class TargetInfo; + class ValueDecl; + +/// \brief A simple array of base specifiers. +typedef SmallVector<CXXBaseSpecifier*, 4> CXXCastPath; + +/// \brief An adjustment to be made to the temporary created when emitting a +/// reference binding, which accesses a particular subobject of that temporary. +struct SubobjectAdjustment { + enum { + DerivedToBaseAdjustment, + FieldAdjustment, + MemberPointerAdjustment + } Kind; + + struct DTB { + const CastExpr *BasePath; + const CXXRecordDecl *DerivedClass; + }; + + struct P { + const MemberPointerType *MPT; + Expr *RHS; + }; + + union { + struct DTB DerivedToBase; + FieldDecl *Field; + struct P Ptr; + }; + + SubobjectAdjustment(const CastExpr *BasePath, + const CXXRecordDecl *DerivedClass) + : Kind(DerivedToBaseAdjustment) { + DerivedToBase.BasePath = BasePath; + DerivedToBase.DerivedClass = DerivedClass; + } + + SubobjectAdjustment(FieldDecl *Field) + : Kind(FieldAdjustment) { + this->Field = Field; + } + + SubobjectAdjustment(const MemberPointerType *MPT, Expr *RHS) + : Kind(MemberPointerAdjustment) { + this->Ptr.MPT = MPT; + this->Ptr.RHS = RHS; + } +}; + +/// 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 +/// is required. +/// +class Expr : public Stmt { + QualType TR; + +protected: + Expr(StmtClass SC, QualType T, ExprValueKind VK, ExprObjectKind OK, + bool TD, bool VD, bool ID, bool ContainsUnexpandedParameterPack) + : Stmt(SC) + { + ExprBits.TypeDependent = TD; + ExprBits.ValueDependent = VD; + ExprBits.InstantiationDependent = ID; + ExprBits.ValueKind = VK; + ExprBits.ObjectKind = OK; + ExprBits.ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack; + setType(T); + } + + /// \brief Construct an empty expression. + explicit Expr(StmtClass SC, EmptyShell) : Stmt(SC) { } + +public: + QualType getType() const { return TR; } + void setType(QualType t) { + // In C++, the type of an expression is always adjusted so that it + // will not have reference type (C++ [expr]p6). Use + // QualType::getNonReferenceType() to retrieve the non-reference + // type. Additionally, inspect Expr::isLvalue to determine whether + // an expression that is adjusted in this manner should be + // considered an lvalue. + assert((t.isNull() || !t->isReferenceType()) && + "Expressions can't have reference type"); + + TR = t; + } + + /// isValueDependent - Determines whether this expression is + /// value-dependent (C++ [temp.dep.constexpr]). For example, the + /// array bound of "Chars" in the following example is + /// value-dependent. + /// @code + /// template<int Size, char (&Chars)[Size]> struct meta_string; + /// @endcode + bool isValueDependent() const { return ExprBits.ValueDependent; } + + /// \brief Set whether this expression is value-dependent or not. + void setValueDependent(bool VD) { + ExprBits.ValueDependent = VD; + } + + /// isTypeDependent - Determines whether this expression is + /// type-dependent (C++ [temp.dep.expr]), which means that its type + /// could change from one template instantiation to the next. For + /// example, the expressions "x" and "x + y" are type-dependent in + /// the following code, but "y" is not type-dependent: + /// @code + /// template<typename T> + /// void add(T x, int y) { + /// x + y; + /// } + /// @endcode + bool isTypeDependent() const { return ExprBits.TypeDependent; } + + /// \brief Set whether this expression is type-dependent or not. + void setTypeDependent(bool TD) { + ExprBits.TypeDependent = TD; + } + + /// \brief Whether this expression is instantiation-dependent, meaning that + /// it depends in some way on a template parameter, even if neither its type + /// nor (constant) value can change due to the template instantiation. + /// + /// In the following example, the expression \c sizeof(sizeof(T() + T())) is + /// instantiation-dependent (since it involves a template parameter \c T), but + /// is neither type- nor value-dependent, since the type of the inner + /// \c sizeof is known (\c std::size_t) and therefore the size of the outer + /// \c sizeof is known. + /// + /// \code + /// template<typename T> + /// void f(T x, T y) { + /// sizeof(sizeof(T() + T()); + /// } + /// \endcode + /// + bool isInstantiationDependent() const { + return ExprBits.InstantiationDependent; + } + + /// \brief Set whether this expression is instantiation-dependent or not. + void setInstantiationDependent(bool ID) { + ExprBits.InstantiationDependent = ID; + } + + /// \brief Whether this expression contains an unexpanded parameter + /// pack (for C++11 variadic templates). + /// + /// Given the following function template: + /// + /// \code + /// template<typename F, typename ...Types> + /// void forward(const F &f, Types &&...args) { + /// f(static_cast<Types&&>(args)...); + /// } + /// \endcode + /// + /// The expressions \c args and \c static_cast<Types&&>(args) both + /// contain parameter packs. + bool containsUnexpandedParameterPack() const { + return ExprBits.ContainsUnexpandedParameterPack; + } + + /// \brief Set the bit that describes whether this expression + /// contains an unexpanded parameter pack. + void setContainsUnexpandedParameterPack(bool PP = true) { + ExprBits.ContainsUnexpandedParameterPack = PP; + } + + /// getExprLoc - Return the preferred location for the arrow when diagnosing + /// a problem with a generic expression. + SourceLocation getExprLoc() const LLVM_READONLY; + + /// isUnusedResultAWarning - Return true if this immediate expression should + /// be warned about if the result is unused. If so, fill in expr, location, + /// and ranges with expr to warn on and source locations/ranges appropriate + /// for a warning. + bool isUnusedResultAWarning(const Expr *&WarnExpr, SourceLocation &Loc, + SourceRange &R1, SourceRange &R2, + ASTContext &Ctx) const; + + /// isLValue - True if this expression is an "l-value" according to + /// the rules of the current language. C and C++ give somewhat + /// different rules for this concept, but in general, the result of + /// an l-value expression identifies a specific object whereas the + /// result of an r-value expression is a value detached from any + /// specific storage. + /// + /// C++11 divides the concept of "r-value" into pure r-values + /// ("pr-values") and so-called expiring values ("x-values"), which + /// identify specific objects that can be safely cannibalized for + /// their resources. This is an unfortunate abuse of terminology on + /// the part of the C++ committee. In Clang, when we say "r-value", + /// we generally mean a pr-value. + bool isLValue() const { return getValueKind() == VK_LValue; } + bool isRValue() const { return getValueKind() == VK_RValue; } + bool isXValue() const { return getValueKind() == VK_XValue; } + bool isGLValue() const { return getValueKind() != VK_RValue; } + + enum LValueClassification { + LV_Valid, + LV_NotObjectType, + LV_IncompleteVoidType, + LV_DuplicateVectorComponents, + LV_InvalidExpression, + LV_InvalidMessageExpression, + LV_MemberFunction, + LV_SubObjCPropertySetting, + LV_ClassTemporary, + LV_ArrayTemporary + }; + /// Reasons why an expression might not be an l-value. + LValueClassification ClassifyLValue(ASTContext &Ctx) const; + + enum isModifiableLvalueResult { + MLV_Valid, + MLV_NotObjectType, + MLV_IncompleteVoidType, + MLV_DuplicateVectorComponents, + MLV_InvalidExpression, + MLV_LValueCast, // Specialized form of MLV_InvalidExpression. + MLV_IncompleteType, + MLV_ConstQualified, + MLV_ConstAddrSpace, + MLV_ArrayType, + MLV_NoSetterProperty, + MLV_MemberFunction, + MLV_SubObjCPropertySetting, + MLV_InvalidMessageExpression, + MLV_ClassTemporary, + MLV_ArrayTemporary + }; + /// isModifiableLvalue - C99 6.3.2.1: an lvalue that does not have array type, + /// does not have an incomplete type, does not have a const-qualified type, + /// and if it is a structure or union, does not have any member (including, + /// recursively, any member or element of all contained aggregates or unions) + /// with a const-qualified type. + /// + /// \param Loc [in,out] - A source location which *may* be filled + /// in with the location of the expression making this a + /// non-modifiable lvalue, if specified. + isModifiableLvalueResult + isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc = nullptr) const; + + /// \brief The return type of classify(). Represents the C++11 expression + /// taxonomy. + class Classification { + public: + /// \brief The various classification results. Most of these mean prvalue. + enum Kinds { + CL_LValue, + CL_XValue, + CL_Function, // Functions cannot be lvalues in C. + CL_Void, // Void cannot be an lvalue in C. + CL_AddressableVoid, // Void expression whose address can be taken in C. + CL_DuplicateVectorComponents, // A vector shuffle with dupes. + CL_MemberFunction, // An expression referring to a member function + CL_SubObjCPropertySetting, + CL_ClassTemporary, // A temporary of class type, or subobject thereof. + CL_ArrayTemporary, // A temporary of array type. + CL_ObjCMessageRValue, // ObjC message is an rvalue + CL_PRValue // A prvalue for any other reason, of any other type + }; + /// \brief The results of modification testing. + enum ModifiableType { + CM_Untested, // testModifiable was false. + CM_Modifiable, + CM_RValue, // Not modifiable because it's an rvalue + CM_Function, // Not modifiable because it's a function; C++ only + CM_LValueCast, // Same as CM_RValue, but indicates GCC cast-as-lvalue ext + CM_NoSetterProperty,// Implicit assignment to ObjC property without setter + CM_ConstQualified, + CM_ConstAddrSpace, + CM_ArrayType, + CM_IncompleteType + }; + + private: + friend class Expr; + + unsigned short Kind; + unsigned short Modifiable; + + explicit Classification(Kinds k, ModifiableType m) + : Kind(k), Modifiable(m) + {} + + public: + Classification() {} + + Kinds getKind() const { return static_cast<Kinds>(Kind); } + ModifiableType getModifiable() const { + assert(Modifiable != CM_Untested && "Did not test for modifiability."); + return static_cast<ModifiableType>(Modifiable); + } + bool isLValue() const { return Kind == CL_LValue; } + bool isXValue() const { return Kind == CL_XValue; } + bool isGLValue() const { return Kind <= CL_XValue; } + bool isPRValue() const { return Kind >= CL_Function; } + bool isRValue() const { return Kind >= CL_XValue; } + bool isModifiable() const { return getModifiable() == CM_Modifiable; } + + /// \brief Create a simple, modifiably lvalue + static Classification makeSimpleLValue() { + return Classification(CL_LValue, CM_Modifiable); + } + + }; + /// \brief Classify - Classify this expression according to the C++11 + /// expression taxonomy. + /// + /// C++11 defines ([basic.lval]) a new taxonomy of expressions to replace the + /// old lvalue vs rvalue. This function determines the type of expression this + /// is. There are three expression types: + /// - lvalues are classical lvalues as in C++03. + /// - prvalues are equivalent to rvalues in C++03. + /// - xvalues are expressions yielding unnamed rvalue references, e.g. a + /// function returning an rvalue reference. + /// lvalues and xvalues are collectively referred to as glvalues, while + /// prvalues and xvalues together form rvalues. + Classification Classify(ASTContext &Ctx) const { + return ClassifyImpl(Ctx, nullptr); + } + + /// \brief ClassifyModifiable - Classify this expression according to the + /// C++11 expression taxonomy, and see if it is valid on the left side + /// of an assignment. + /// + /// This function extends classify in that it also tests whether the + /// expression is modifiable (C99 6.3.2.1p1). + /// \param Loc A source location that might be filled with a relevant location + /// if the expression is not modifiable. + Classification ClassifyModifiable(ASTContext &Ctx, SourceLocation &Loc) const{ + return ClassifyImpl(Ctx, &Loc); + } + + /// getValueKindForType - Given a formal return or parameter type, + /// give its value kind. + static ExprValueKind getValueKindForType(QualType T) { + if (const ReferenceType *RT = T->getAs<ReferenceType>()) + return (isa<LValueReferenceType>(RT) + ? VK_LValue + : (RT->getPointeeType()->isFunctionType() + ? VK_LValue : VK_XValue)); + return VK_RValue; + } + + /// getValueKind - The value kind that this expression produces. + ExprValueKind getValueKind() const { + return static_cast<ExprValueKind>(ExprBits.ValueKind); + } + + /// getObjectKind - The object kind that this expression produces. + /// Object kinds are meaningful only for expressions that yield an + /// l-value or x-value. + ExprObjectKind getObjectKind() const { + return static_cast<ExprObjectKind>(ExprBits.ObjectKind); + } + + bool isOrdinaryOrBitFieldObject() const { + ExprObjectKind OK = getObjectKind(); + return (OK == OK_Ordinary || OK == OK_BitField); + } + + /// setValueKind - Set the value kind produced by this expression. + void setValueKind(ExprValueKind Cat) { ExprBits.ValueKind = Cat; } + + /// setObjectKind - Set the object kind produced by this expression. + void setObjectKind(ExprObjectKind Cat) { ExprBits.ObjectKind = Cat; } + +private: + Classification ClassifyImpl(ASTContext &Ctx, SourceLocation *Loc) const; + +public: + + /// \brief Returns true if this expression is a gl-value that + /// potentially refers to a bit-field. + /// + /// In C++, whether a gl-value refers to a bitfield is essentially + /// an aspect of the value-kind type system. + bool refersToBitField() const { return getObjectKind() == OK_BitField; } + + /// \brief If this expression refers to a bit-field, retrieve the + /// declaration of that bit-field. + /// + /// Note that this returns a non-null pointer in subtly different + /// places than refersToBitField returns true. In particular, this can + /// return a non-null pointer even for r-values loaded from + /// bit-fields, but it will return null for a conditional bit-field. + FieldDecl *getSourceBitField(); + + const FieldDecl *getSourceBitField() const { + return const_cast<Expr*>(this)->getSourceBitField(); + } + + /// \brief If this expression is an l-value for an Objective C + /// property, find the underlying property reference expression. + const ObjCPropertyRefExpr *getObjCProperty() const; + + /// \brief Check if this expression is the ObjC 'self' implicit parameter. + bool isObjCSelfExpr() const; + + /// \brief Returns whether this expression refers to a vector element. + bool refersToVectorElement() const; + + /// \brief Returns whether this expression refers to a global register + /// variable. + bool refersToGlobalRegisterVar() const; + + /// \brief Returns whether this expression has a placeholder type. + bool hasPlaceholderType() const { + return getType()->isPlaceholderType(); + } + + /// \brief Returns whether this expression has a specific placeholder type. + bool hasPlaceholderType(BuiltinType::Kind K) const { + assert(BuiltinType::isPlaceholderTypeKind(K)); + if (const BuiltinType *BT = dyn_cast<BuiltinType>(getType())) + return BT->getKind() == K; + return false; + } + + /// isKnownToHaveBooleanValue - Return true if this is an integer expression + /// that is known to return 0 or 1. This happens for _Bool/bool expressions + /// but also int expressions which are produced by things like comparisons in + /// C. + bool isKnownToHaveBooleanValue() const; + + /// isIntegerConstantExpr - Return true if this expression is a valid integer + /// constant expression, and, if so, return its value in Result. If not a + /// valid i-c-e, return false and fill in Loc (if specified) with the location + /// of the invalid expression. + /// + /// Note: This does not perform the implicit conversions required by C++11 + /// [expr.const]p5. + bool isIntegerConstantExpr(llvm::APSInt &Result, const ASTContext &Ctx, + SourceLocation *Loc = nullptr, + bool isEvaluated = true) const; + bool isIntegerConstantExpr(const ASTContext &Ctx, + SourceLocation *Loc = nullptr) const; + + /// isCXX98IntegralConstantExpr - Return true if this expression is an + /// integral constant expression in C++98. Can only be used in C++. + bool isCXX98IntegralConstantExpr(const ASTContext &Ctx) const; + + /// isCXX11ConstantExpr - Return true if this expression is a constant + /// expression in C++11. Can only be used in C++. + /// + /// Note: This does not perform the implicit conversions required by C++11 + /// [expr.const]p5. + bool isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result = nullptr, + SourceLocation *Loc = nullptr) const; + + /// isPotentialConstantExpr - Return true if this function's definition + /// might be usable in a constant expression in C++11, if it were marked + /// constexpr. Return false if the function can never produce a constant + /// expression, along with diagnostics describing why not. + static bool isPotentialConstantExpr(const FunctionDecl *FD, + SmallVectorImpl< + PartialDiagnosticAt> &Diags); + + /// isPotentialConstantExprUnevaluted - Return true if this expression might + /// be usable in a constant expression in C++11 in an unevaluated context, if + /// it were in function FD marked constexpr. Return false if the function can + /// never produce a constant expression, along with diagnostics describing + /// why not. + static bool isPotentialConstantExprUnevaluated(Expr *E, + const FunctionDecl *FD, + SmallVectorImpl< + PartialDiagnosticAt> &Diags); + + /// isConstantInitializer - Returns true if this expression can be emitted to + /// IR as a constant, and thus can be used as a constant initializer in C. + /// If this expression is not constant and Culprit is non-null, + /// it is used to store the address of first non constant expr. + bool isConstantInitializer(ASTContext &Ctx, bool ForRef, + const Expr **Culprit = nullptr) const; + + /// EvalStatus is a struct with detailed info about an evaluation in progress. + struct EvalStatus { + /// \brief Whether the evaluated expression has side effects. + /// For example, (f() && 0) can be folded, but it still has side effects. + bool HasSideEffects; + + /// \brief Whether the evaluation hit undefined behavior. + /// For example, 1.0 / 0.0 can be folded to Inf, but has undefined behavior. + /// Likewise, INT_MAX + 1 can be folded to INT_MIN, but has UB. + bool HasUndefinedBehavior; + + /// Diag - If this is non-null, it will be filled in with a stack of notes + /// indicating why evaluation failed (or why it failed to produce a constant + /// expression). + /// If the expression is unfoldable, the notes will indicate why it's not + /// foldable. If the expression is foldable, but not a constant expression, + /// the notes will describes why it isn't a constant expression. If the + /// expression *is* a constant expression, no notes will be produced. + SmallVectorImpl<PartialDiagnosticAt> *Diag; + + EvalStatus() + : HasSideEffects(false), HasUndefinedBehavior(false), Diag(nullptr) {} + + // hasSideEffects - Return true if the evaluated expression has + // side effects. + bool hasSideEffects() const { + return HasSideEffects; + } + }; + + /// EvalResult is a struct with detailed info about an evaluated expression. + struct EvalResult : EvalStatus { + /// Val - This is the value the expression can be folded to. + APValue Val; + + // isGlobalLValue - Return true if the evaluated lvalue expression + // is global. + bool isGlobalLValue() const; + }; + + /// EvaluateAsRValue - Return true if this is a constant which we can fold to + /// an rvalue using any crazy technique (that has nothing to do with language + /// standards) that we want to, even if the expression has side-effects. If + /// this function returns true, it returns the folded constant in Result. If + /// the expression is a glvalue, an lvalue-to-rvalue conversion will be + /// applied. + bool EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx) const; + + /// EvaluateAsBooleanCondition - Return true if this is a constant + /// which we we can fold and convert to a boolean condition using + /// any crazy technique that we want to, even if the expression has + /// side-effects. + bool EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx) const; + + enum SideEffectsKind { + SE_NoSideEffects, ///< Strictly evaluate the expression. + SE_AllowUndefinedBehavior, ///< Allow UB that we can give a value, but not + ///< arbitrary unmodeled side effects. + SE_AllowSideEffects ///< Allow any unmodeled side effect. + }; + + /// EvaluateAsInt - Return true if this is a constant which we can fold and + /// convert to an integer, using any crazy technique that we want to. + bool EvaluateAsInt(llvm::APSInt &Result, const ASTContext &Ctx, + SideEffectsKind AllowSideEffects = SE_NoSideEffects) const; + + /// isEvaluatable - Call EvaluateAsRValue to see if this expression can be + /// constant folded without side-effects, but discard the result. + bool isEvaluatable(const ASTContext &Ctx, + SideEffectsKind AllowSideEffects = SE_NoSideEffects) const; + + /// HasSideEffects - This routine returns true for all those expressions + /// which have any effect other than producing a value. Example is a function + /// call, volatile variable read, or throwing an exception. If + /// IncludePossibleEffects is false, this call treats certain expressions with + /// potential side effects (such as function call-like expressions, + /// instantiation-dependent expressions, or invocations from a macro) as not + /// having side effects. + bool HasSideEffects(const ASTContext &Ctx, + bool IncludePossibleEffects = true) const; + + /// \brief Determine whether this expression involves a call to any function + /// that is not trivial. + bool hasNonTrivialCall(const ASTContext &Ctx) const; + + /// EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded + /// integer. This must be called on an expression that constant folds to an + /// integer. + llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx, + SmallVectorImpl<PartialDiagnosticAt> *Diag = nullptr) const; + + void EvaluateForOverflow(const ASTContext &Ctx) const; + + /// EvaluateAsLValue - Evaluate an expression to see if we can fold it to an + /// lvalue with link time known address, with no side-effects. + bool EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const; + + /// EvaluateAsInitializer - Evaluate an expression as if it were the + /// initializer of the given declaration. Returns true if the initializer + /// can be folded to a constant, and produces any relevant notes. In C++11, + /// notes will be produced if the expression is not a constant expression. + bool EvaluateAsInitializer(APValue &Result, const ASTContext &Ctx, + const VarDecl *VD, + SmallVectorImpl<PartialDiagnosticAt> &Notes) const; + + /// EvaluateWithSubstitution - Evaluate an expression as if from the context + /// of a call to the given function with the given arguments, inside an + /// unevaluated context. Returns true if the expression could be folded to a + /// constant. + bool EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx, + const FunctionDecl *Callee, + ArrayRef<const Expr*> Args) const; + + /// \brief If the current Expr is a pointer, this will try to statically + /// determine the number of bytes available where the pointer is pointing. + /// Returns true if all of the above holds and we were able to figure out the + /// size, false otherwise. + /// + /// \param Type - How to evaluate the size of the Expr, as defined by the + /// "type" parameter of __builtin_object_size + bool tryEvaluateObjectSize(uint64_t &Result, ASTContext &Ctx, + unsigned Type) const; + + /// \brief Enumeration used to describe the kind of Null pointer constant + /// returned from \c isNullPointerConstant(). + enum NullPointerConstantKind { + /// \brief Expression is not a Null pointer constant. + NPCK_NotNull = 0, + + /// \brief Expression is a Null pointer constant built from a zero integer + /// expression that is not a simple, possibly parenthesized, zero literal. + /// C++ Core Issue 903 will classify these expressions as "not pointers" + /// once it is adopted. + /// http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#903 + NPCK_ZeroExpression, + + /// \brief Expression is a Null pointer constant built from a literal zero. + NPCK_ZeroLiteral, + + /// \brief Expression is a C++11 nullptr. + NPCK_CXX11_nullptr, + + /// \brief Expression is a GNU-style __null constant. + NPCK_GNUNull + }; + + /// \brief Enumeration used to describe how \c isNullPointerConstant() + /// should cope with value-dependent expressions. + enum NullPointerConstantValueDependence { + /// \brief Specifies that the expression should never be value-dependent. + NPC_NeverValueDependent = 0, + + /// \brief Specifies that a value-dependent expression of integral or + /// dependent type should be considered a null pointer constant. + NPC_ValueDependentIsNull, + + /// \brief Specifies that a value-dependent expression should be considered + /// to never be a null pointer constant. + NPC_ValueDependentIsNotNull + }; + + /// isNullPointerConstant - C99 6.3.2.3p3 - Test if this reduces down to + /// a Null pointer constant. The return value can further distinguish the + /// kind of NULL pointer constant that was detected. + NullPointerConstantKind isNullPointerConstant( + ASTContext &Ctx, + NullPointerConstantValueDependence NPC) const; + + /// isOBJCGCCandidate - Return true if this expression may be used in a read/ + /// write barrier. + bool isOBJCGCCandidate(ASTContext &Ctx) const; + + /// \brief Returns true if this expression is a bound member function. + bool isBoundMemberFunction(ASTContext &Ctx) const; + + /// \brief Given an expression of bound-member type, find the type + /// of the member. Returns null if this is an *overloaded* bound + /// member expression. + static QualType findBoundMemberType(const Expr *expr); + + /// IgnoreImpCasts - Skip past any implicit casts which might + /// surround this expression. Only skips ImplicitCastExprs. + Expr *IgnoreImpCasts() LLVM_READONLY; + + /// IgnoreImplicit - Skip past any implicit AST nodes which might + /// surround this expression. + Expr *IgnoreImplicit() LLVM_READONLY { + return cast<Expr>(Stmt::IgnoreImplicit()); + } + + const Expr *IgnoreImplicit() const LLVM_READONLY { + return const_cast<Expr*>(this)->IgnoreImplicit(); + } + + /// IgnoreParens - Ignore parentheses. If this Expr is a ParenExpr, return + /// its subexpression. If that subexpression is also a ParenExpr, + /// then this method recursively returns its subexpression, and so forth. + /// Otherwise, the method returns the current Expr. + Expr *IgnoreParens() LLVM_READONLY; + + /// IgnoreParenCasts - Ignore parentheses and casts. Strip off any ParenExpr + /// or CastExprs, returning their operand. + Expr *IgnoreParenCasts() LLVM_READONLY; + + /// Ignore casts. Strip off any CastExprs, returning their operand. + Expr *IgnoreCasts() LLVM_READONLY; + + /// IgnoreParenImpCasts - Ignore parentheses and implicit casts. Strip off + /// any ParenExpr or ImplicitCastExprs, returning their operand. + Expr *IgnoreParenImpCasts() LLVM_READONLY; + + /// IgnoreConversionOperator - Ignore conversion operator. If this Expr is a + /// call to a conversion operator, return the argument. + Expr *IgnoreConversionOperator() LLVM_READONLY; + + const Expr *IgnoreConversionOperator() const LLVM_READONLY { + return const_cast<Expr*>(this)->IgnoreConversionOperator(); + } + + const Expr *IgnoreParenImpCasts() const LLVM_READONLY { + return const_cast<Expr*>(this)->IgnoreParenImpCasts(); + } + + /// Ignore parentheses and lvalue casts. Strip off any ParenExpr and + /// CastExprs that represent lvalue casts, returning their operand. + Expr *IgnoreParenLValueCasts() LLVM_READONLY; + + const Expr *IgnoreParenLValueCasts() const LLVM_READONLY { + return const_cast<Expr*>(this)->IgnoreParenLValueCasts(); + } + + /// IgnoreParenNoopCasts - Ignore parentheses and casts that do not change the + /// value (including ptr->int casts of the same size). Strip off any + /// ParenExpr or CastExprs, returning their operand. + Expr *IgnoreParenNoopCasts(ASTContext &Ctx) LLVM_READONLY; + + /// Ignore parentheses and derived-to-base casts. + Expr *ignoreParenBaseCasts() LLVM_READONLY; + + const Expr *ignoreParenBaseCasts() const LLVM_READONLY { + return const_cast<Expr*>(this)->ignoreParenBaseCasts(); + } + + /// \brief Determine whether this expression is a default function argument. + /// + /// Default arguments are implicitly generated in the abstract syntax tree + /// by semantic analysis for function calls, object constructions, etc. in + /// C++. Default arguments are represented by \c CXXDefaultArgExpr nodes; + /// this routine also looks through any implicit casts to determine whether + /// the expression is a default argument. + bool isDefaultArgument() const; + + /// \brief Determine whether the result of this expression is a + /// temporary object of the given class type. + bool isTemporaryObject(ASTContext &Ctx, const CXXRecordDecl *TempTy) const; + + /// \brief Whether this expression is an implicit reference to 'this' in C++. + bool isImplicitCXXThis() const; + + const Expr *IgnoreImpCasts() const LLVM_READONLY { + return const_cast<Expr*>(this)->IgnoreImpCasts(); + } + const Expr *IgnoreParens() const LLVM_READONLY { + return const_cast<Expr*>(this)->IgnoreParens(); + } + const Expr *IgnoreParenCasts() const LLVM_READONLY { + return const_cast<Expr*>(this)->IgnoreParenCasts(); + } + /// Strip off casts, but keep parentheses. + const Expr *IgnoreCasts() const LLVM_READONLY { + return const_cast<Expr*>(this)->IgnoreCasts(); + } + + const Expr *IgnoreParenNoopCasts(ASTContext &Ctx) const LLVM_READONLY { + return const_cast<Expr*>(this)->IgnoreParenNoopCasts(Ctx); + } + + static bool hasAnyTypeDependentArguments(ArrayRef<Expr *> Exprs); + + /// \brief For an expression of class type or pointer to class type, + /// return the most derived class decl the expression is known to refer to. + /// + /// If this expression is a cast, this method looks through it to find the + /// most derived decl that can be inferred from the expression. + /// This is valid because derived-to-base conversions have undefined + /// behavior if the object isn't dynamically of the derived type. + const CXXRecordDecl *getBestDynamicClassType() const; + + /// Walk outwards from an expression we want to bind a reference to and + /// find the expression whose lifetime needs to be extended. Record + /// the LHSs of comma expressions and adjustments needed along the path. + const Expr *skipRValueSubobjectAdjustments( + SmallVectorImpl<const Expr *> &CommaLHS, + SmallVectorImpl<SubobjectAdjustment> &Adjustments) const; + + static bool classof(const Stmt *T) { + return T->getStmtClass() >= firstExprConstant && + T->getStmtClass() <= lastExprConstant; + } +}; + +//===----------------------------------------------------------------------===// +// Primary Expressions. +//===----------------------------------------------------------------------===// + +/// OpaqueValueExpr - An expression referring to an opaque object of a +/// fixed type and value class. These don't correspond to concrete +/// syntax; instead they're used to express operations (usually copy +/// operations) on values whose source is generally obvious from +/// context. +class OpaqueValueExpr : public Expr { + friend class ASTStmtReader; + Expr *SourceExpr; + SourceLocation Loc; + +public: + OpaqueValueExpr(SourceLocation Loc, QualType T, ExprValueKind VK, + ExprObjectKind OK = OK_Ordinary, + Expr *SourceExpr = nullptr) + : Expr(OpaqueValueExprClass, T, VK, OK, + T->isDependentType(), + T->isDependentType() || + (SourceExpr && SourceExpr->isValueDependent()), + T->isInstantiationDependentType(), + false), + SourceExpr(SourceExpr), Loc(Loc) { + } + + /// Given an expression which invokes a copy constructor --- i.e. a + /// CXXConstructExpr, possibly wrapped in an ExprWithCleanups --- + /// find the OpaqueValueExpr that's the source of the construction. + static const OpaqueValueExpr *findInCopyConstruct(const Expr *expr); + + explicit OpaqueValueExpr(EmptyShell Empty) + : Expr(OpaqueValueExprClass, Empty) { } + + /// \brief Retrieve the location of this expression. + SourceLocation getLocation() const { return Loc; } + + SourceLocation getLocStart() const LLVM_READONLY { + return SourceExpr ? SourceExpr->getLocStart() : Loc; + } + SourceLocation getLocEnd() const LLVM_READONLY { + return SourceExpr ? SourceExpr->getLocEnd() : Loc; + } + SourceLocation getExprLoc() const LLVM_READONLY { + if (SourceExpr) return SourceExpr->getExprLoc(); + return Loc; + } + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + + /// The source expression of an opaque value expression is the + /// expression which originally generated the value. This is + /// provided as a convenience for analyses that don't wish to + /// precisely model the execution behavior of the program. + /// + /// The source expression is typically set when building the + /// expression which binds the opaque value expression in the first + /// place. + Expr *getSourceExpr() const { return SourceExpr; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OpaqueValueExprClass; + } +}; + +/// \brief A reference to a declared variable, function, enum, etc. +/// [C99 6.5.1p2] +/// +/// This encodes all the information about how a declaration is referenced +/// within an expression. +/// +/// There are several optional constructs attached to DeclRefExprs only when +/// they apply in order to conserve memory. These are laid out past the end of +/// the object, and flags in the DeclRefExprBitfield track whether they exist: +/// +/// DeclRefExprBits.HasQualifier: +/// Specifies when this declaration reference expression has a C++ +/// nested-name-specifier. +/// DeclRefExprBits.HasFoundDecl: +/// Specifies when this declaration reference expression has a record of +/// a NamedDecl (different from the referenced ValueDecl) which was found +/// during name lookup and/or overload resolution. +/// DeclRefExprBits.HasTemplateKWAndArgsInfo: +/// Specifies when this declaration reference expression has an explicit +/// C++ template keyword and/or template argument list. +/// DeclRefExprBits.RefersToEnclosingVariableOrCapture +/// Specifies when this declaration reference expression (validly) +/// refers to an enclosed local or a captured variable. +class DeclRefExpr final + : public Expr, + private llvm::TrailingObjects<DeclRefExpr, NestedNameSpecifierLoc, + NamedDecl *, ASTTemplateKWAndArgsInfo, + TemplateArgumentLoc> { + /// \brief The declaration that we are referencing. + ValueDecl *D; + + /// \brief The location of the declaration name itself. + SourceLocation Loc; + + /// \brief Provides source/type location info for the declaration name + /// embedded in D. + DeclarationNameLoc DNLoc; + + size_t numTrailingObjects(OverloadToken<NestedNameSpecifierLoc>) const { + return hasQualifier() ? 1 : 0; + } + + size_t numTrailingObjects(OverloadToken<NamedDecl *>) const { + return hasFoundDecl() ? 1 : 0; + } + + size_t numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const { + return hasTemplateKWAndArgsInfo() ? 1 : 0; + } + + /// \brief Test whether there is a distinct FoundDecl attached to the end of + /// this DRE. + bool hasFoundDecl() const { return DeclRefExprBits.HasFoundDecl; } + + DeclRefExpr(const ASTContext &Ctx, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, + ValueDecl *D, bool RefersToEnlosingVariableOrCapture, + const DeclarationNameInfo &NameInfo, + NamedDecl *FoundD, + const TemplateArgumentListInfo *TemplateArgs, + QualType T, ExprValueKind VK); + + /// \brief Construct an empty declaration reference expression. + explicit DeclRefExpr(EmptyShell Empty) + : Expr(DeclRefExprClass, Empty) { } + + /// \brief Computes the type- and value-dependence flags for this + /// declaration reference expression. + void computeDependence(const ASTContext &C); + +public: + DeclRefExpr(ValueDecl *D, bool RefersToEnclosingVariableOrCapture, QualType T, + ExprValueKind VK, SourceLocation L, + const DeclarationNameLoc &LocInfo = DeclarationNameLoc()) + : Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false, false), + D(D), Loc(L), DNLoc(LocInfo) { + DeclRefExprBits.HasQualifier = 0; + DeclRefExprBits.HasTemplateKWAndArgsInfo = 0; + DeclRefExprBits.HasFoundDecl = 0; + DeclRefExprBits.HadMultipleCandidates = 0; + DeclRefExprBits.RefersToEnclosingVariableOrCapture = + RefersToEnclosingVariableOrCapture; + computeDependence(D->getASTContext()); + } + + static DeclRefExpr * + Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, ValueDecl *D, + bool RefersToEnclosingVariableOrCapture, SourceLocation NameLoc, + QualType T, ExprValueKind VK, NamedDecl *FoundD = nullptr, + const TemplateArgumentListInfo *TemplateArgs = nullptr); + + static DeclRefExpr * + Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, ValueDecl *D, + bool RefersToEnclosingVariableOrCapture, + const DeclarationNameInfo &NameInfo, QualType T, ExprValueKind VK, + NamedDecl *FoundD = nullptr, + const TemplateArgumentListInfo *TemplateArgs = nullptr); + + /// \brief Construct an empty declaration reference expression. + static DeclRefExpr *CreateEmpty(const ASTContext &Context, + bool HasQualifier, + bool HasFoundDecl, + bool HasTemplateKWAndArgsInfo, + unsigned NumTemplateArgs); + + ValueDecl *getDecl() { return D; } + const ValueDecl *getDecl() const { return D; } + void setDecl(ValueDecl *NewD) { D = NewD; } + + DeclarationNameInfo getNameInfo() const { + return DeclarationNameInfo(getDecl()->getDeclName(), Loc, DNLoc); + } + + SourceLocation getLocation() const { return Loc; } + void setLocation(SourceLocation L) { Loc = L; } + SourceLocation getLocStart() const LLVM_READONLY; + SourceLocation getLocEnd() const LLVM_READONLY; + + /// \brief Determine whether this declaration reference was preceded by a + /// C++ nested-name-specifier, e.g., \c N::foo. + bool hasQualifier() const { return DeclRefExprBits.HasQualifier; } + + /// \brief If the name was qualified, retrieves the nested-name-specifier + /// that precedes the name, with source-location information. + NestedNameSpecifierLoc getQualifierLoc() const { + if (!hasQualifier()) + return NestedNameSpecifierLoc(); + return *getTrailingObjects<NestedNameSpecifierLoc>(); + } + + /// \brief If the name was qualified, retrieves the nested-name-specifier + /// that precedes the name. Otherwise, returns NULL. + NestedNameSpecifier *getQualifier() const { + return getQualifierLoc().getNestedNameSpecifier(); + } + + /// \brief Get the NamedDecl through which this reference occurred. + /// + /// This Decl may be different from the ValueDecl actually referred to in the + /// presence of using declarations, etc. It always returns non-NULL, and may + /// simple return the ValueDecl when appropriate. + + NamedDecl *getFoundDecl() { + return hasFoundDecl() ? *getTrailingObjects<NamedDecl *>() : D; + } + + /// \brief Get the NamedDecl through which this reference occurred. + /// See non-const variant. + const NamedDecl *getFoundDecl() const { + return hasFoundDecl() ? *getTrailingObjects<NamedDecl *>() : D; + } + + bool hasTemplateKWAndArgsInfo() const { + return DeclRefExprBits.HasTemplateKWAndArgsInfo; + } + + /// \brief Retrieve the location of the template keyword preceding + /// this name, if any. + SourceLocation getTemplateKeywordLoc() const { + if (!hasTemplateKWAndArgsInfo()) return SourceLocation(); + return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->TemplateKWLoc; + } + + /// \brief Retrieve the location of the left angle bracket starting the + /// explicit template argument list following the name, if any. + SourceLocation getLAngleLoc() const { + if (!hasTemplateKWAndArgsInfo()) return SourceLocation(); + return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->LAngleLoc; + } + + /// \brief Retrieve the location of the right angle bracket ending the + /// explicit template argument list following the name, if any. + SourceLocation getRAngleLoc() const { + if (!hasTemplateKWAndArgsInfo()) return SourceLocation(); + return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->RAngleLoc; + } + + /// \brief Determines whether the name in this declaration reference + /// was preceded by the template keyword. + bool hasTemplateKeyword() const { return getTemplateKeywordLoc().isValid(); } + + /// \brief Determines whether this declaration reference was followed by an + /// explicit template argument list. + bool hasExplicitTemplateArgs() const { return getLAngleLoc().isValid(); } + + /// \brief Copies the template arguments (if present) into the given + /// structure. + void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const { + if (hasExplicitTemplateArgs()) + getTrailingObjects<ASTTemplateKWAndArgsInfo>()->copyInto( + getTrailingObjects<TemplateArgumentLoc>(), List); + } + + /// \brief Retrieve the template arguments provided as part of this + /// template-id. + const TemplateArgumentLoc *getTemplateArgs() const { + if (!hasExplicitTemplateArgs()) + return nullptr; + + return getTrailingObjects<TemplateArgumentLoc>(); + } + + /// \brief Retrieve the number of template arguments provided as part of this + /// template-id. + unsigned getNumTemplateArgs() const { + if (!hasExplicitTemplateArgs()) + return 0; + + return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->NumTemplateArgs; + } + + /// \brief Returns true if this expression refers to a function that + /// was resolved from an overloaded set having size greater than 1. + bool hadMultipleCandidates() const { + return DeclRefExprBits.HadMultipleCandidates; + } + /// \brief Sets the flag telling whether this expression refers to + /// a function that was resolved from an overloaded set having size + /// greater than 1. + void setHadMultipleCandidates(bool V = true) { + DeclRefExprBits.HadMultipleCandidates = V; + } + + /// \brief Does this DeclRefExpr refer to an enclosing local or a captured + /// variable? + bool refersToEnclosingVariableOrCapture() const { + return DeclRefExprBits.RefersToEnclosingVariableOrCapture; + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == DeclRefExprClass; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + + friend TrailingObjects; + friend class ASTStmtReader; + friend class ASTStmtWriter; +}; + +/// \brief [C99 6.4.2.2] - A predefined identifier such as __func__. +class PredefinedExpr : public Expr { +public: + enum IdentType { + Func, + Function, + LFunction, // Same as Function, but as wide string. + FuncDName, + FuncSig, + PrettyFunction, + /// \brief The same as PrettyFunction, except that the + /// 'virtual' keyword is omitted for virtual member functions. + PrettyFunctionNoVirtual + }; + +private: + SourceLocation Loc; + IdentType Type; + Stmt *FnName; + +public: + PredefinedExpr(SourceLocation L, QualType FNTy, IdentType IT, + StringLiteral *SL); + + /// \brief Construct an empty predefined expression. + explicit PredefinedExpr(EmptyShell Empty) + : Expr(PredefinedExprClass, Empty), Loc(), Type(Func), FnName(nullptr) {} + + IdentType getIdentType() const { return Type; } + + SourceLocation getLocation() const { return Loc; } + void setLocation(SourceLocation L) { Loc = L; } + + StringLiteral *getFunctionName(); + const StringLiteral *getFunctionName() const { + return const_cast<PredefinedExpr *>(this)->getFunctionName(); + } + + static StringRef getIdentTypeName(IdentType IT); + static std::string ComputeName(IdentType IT, const Decl *CurrentDecl); + + SourceLocation getLocStart() const LLVM_READONLY { return Loc; } + SourceLocation getLocEnd() const LLVM_READONLY { return Loc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == PredefinedExprClass; + } + + // Iterators + child_range children() { return child_range(&FnName, &FnName + 1); } + + friend class ASTStmtReader; +}; + +/// \brief Used by IntegerLiteral/FloatingLiteral to store the numeric without +/// leaking memory. +/// +/// For large floats/integers, APFloat/APInt will allocate memory from the heap +/// to represent these numbers. Unfortunately, when we use a BumpPtrAllocator +/// to allocate IntegerLiteral/FloatingLiteral nodes the memory associated with +/// the APFloat/APInt values will never get freed. APNumericStorage uses +/// ASTContext's allocator for memory allocation. +class APNumericStorage { + union { + uint64_t VAL; ///< Used to store the <= 64 bits integer value. + uint64_t *pVal; ///< Used to store the >64 bits integer value. + }; + unsigned BitWidth; + + bool hasAllocation() const { return llvm::APInt::getNumWords(BitWidth) > 1; } + + APNumericStorage(const APNumericStorage &) = delete; + void operator=(const APNumericStorage &) = delete; + +protected: + APNumericStorage() : VAL(0), BitWidth(0) { } + + llvm::APInt getIntValue() const { + unsigned NumWords = llvm::APInt::getNumWords(BitWidth); + if (NumWords > 1) + return llvm::APInt(BitWidth, NumWords, pVal); + else + return llvm::APInt(BitWidth, VAL); + } + void setIntValue(const ASTContext &C, const llvm::APInt &Val); +}; + +class APIntStorage : private APNumericStorage { +public: + llvm::APInt getValue() const { return getIntValue(); } + void setValue(const ASTContext &C, const llvm::APInt &Val) { + setIntValue(C, Val); + } +}; + +class APFloatStorage : private APNumericStorage { +public: + llvm::APFloat getValue(const llvm::fltSemantics &Semantics) const { + return llvm::APFloat(Semantics, getIntValue()); + } + void setValue(const ASTContext &C, const llvm::APFloat &Val) { + setIntValue(C, Val.bitcastToAPInt()); + } +}; + +class IntegerLiteral : public Expr, public APIntStorage { + SourceLocation Loc; + + /// \brief Construct an empty integer literal. + explicit IntegerLiteral(EmptyShell Empty) + : Expr(IntegerLiteralClass, Empty) { } + +public: + // type should be IntTy, LongTy, LongLongTy, UnsignedIntTy, UnsignedLongTy, + // or UnsignedLongLongTy + IntegerLiteral(const ASTContext &C, const llvm::APInt &V, QualType type, + SourceLocation l); + + /// \brief Returns a new integer literal with value 'V' and type 'type'. + /// \param type - either IntTy, LongTy, LongLongTy, UnsignedIntTy, + /// UnsignedLongTy, or UnsignedLongLongTy which should match the size of V + /// \param V - the value that the returned integer literal contains. + static IntegerLiteral *Create(const ASTContext &C, const llvm::APInt &V, + QualType type, SourceLocation l); + /// \brief Returns a new empty integer literal. + static IntegerLiteral *Create(const ASTContext &C, EmptyShell Empty); + + SourceLocation getLocStart() const LLVM_READONLY { return Loc; } + SourceLocation getLocEnd() const LLVM_READONLY { return Loc; } + + /// \brief Retrieve the location of the literal. + SourceLocation getLocation() const { return Loc; } + + void setLocation(SourceLocation Location) { Loc = Location; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == IntegerLiteralClass; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +class CharacterLiteral : public Expr { +public: + enum CharacterKind { + Ascii, + Wide, + UTF16, + UTF32 + }; + +private: + unsigned Value; + SourceLocation Loc; +public: + // type should be IntTy + CharacterLiteral(unsigned value, CharacterKind kind, QualType type, + SourceLocation l) + : Expr(CharacterLiteralClass, type, VK_RValue, OK_Ordinary, false, false, + false, false), + Value(value), Loc(l) { + CharacterLiteralBits.Kind = kind; + } + + /// \brief Construct an empty character literal. + CharacterLiteral(EmptyShell Empty) : Expr(CharacterLiteralClass, Empty) { } + + SourceLocation getLocation() const { return Loc; } + CharacterKind getKind() const { + return static_cast<CharacterKind>(CharacterLiteralBits.Kind); + } + + SourceLocation getLocStart() const LLVM_READONLY { return Loc; } + SourceLocation getLocEnd() const LLVM_READONLY { return Loc; } + + unsigned getValue() const { return Value; } + + void setLocation(SourceLocation Location) { Loc = Location; } + void setKind(CharacterKind kind) { CharacterLiteralBits.Kind = kind; } + void setValue(unsigned Val) { Value = Val; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CharacterLiteralClass; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +class FloatingLiteral : public Expr, private APFloatStorage { + SourceLocation Loc; + + FloatingLiteral(const ASTContext &C, const llvm::APFloat &V, bool isexact, + QualType Type, SourceLocation L); + + /// \brief Construct an empty floating-point literal. + explicit FloatingLiteral(const ASTContext &C, EmptyShell Empty); + +public: + static FloatingLiteral *Create(const ASTContext &C, const llvm::APFloat &V, + bool isexact, QualType Type, SourceLocation L); + static FloatingLiteral *Create(const ASTContext &C, EmptyShell Empty); + + llvm::APFloat getValue() const { + return APFloatStorage::getValue(getSemantics()); + } + void setValue(const ASTContext &C, const llvm::APFloat &Val) { + assert(&getSemantics() == &Val.getSemantics() && "Inconsistent semantics"); + APFloatStorage::setValue(C, Val); + } + + /// Get a raw enumeration value representing the floating-point semantics of + /// this literal (32-bit IEEE, x87, ...), suitable for serialisation. + APFloatSemantics getRawSemantics() const { + return static_cast<APFloatSemantics>(FloatingLiteralBits.Semantics); + } + + /// Set the raw enumeration value representing the floating-point semantics of + /// this literal (32-bit IEEE, x87, ...), suitable for serialisation. + void setRawSemantics(APFloatSemantics Sem) { + FloatingLiteralBits.Semantics = Sem; + } + + /// Return the APFloat semantics this literal uses. + const llvm::fltSemantics &getSemantics() const; + + /// Set the APFloat semantics this literal uses. + void setSemantics(const llvm::fltSemantics &Sem); + + bool isExact() const { return FloatingLiteralBits.IsExact; } + void setExact(bool E) { FloatingLiteralBits.IsExact = E; } + + /// getValueAsApproximateDouble - This returns the value as an inaccurate + /// double. Note that this may cause loss of precision, but is useful for + /// debugging dumps, etc. + double getValueAsApproximateDouble() const; + + SourceLocation getLocation() const { return Loc; } + void setLocation(SourceLocation L) { Loc = L; } + + SourceLocation getLocStart() const LLVM_READONLY { return Loc; } + SourceLocation getLocEnd() const LLVM_READONLY { return Loc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == FloatingLiteralClass; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +/// ImaginaryLiteral - We support imaginary integer and floating point literals, +/// like "1.0i". We represent these as a wrapper around FloatingLiteral and +/// IntegerLiteral classes. Instances of this class always have a Complex type +/// whose element type matches the subexpression. +/// +class ImaginaryLiteral : public Expr { + Stmt *Val; +public: + ImaginaryLiteral(Expr *val, QualType Ty) + : Expr(ImaginaryLiteralClass, Ty, VK_RValue, OK_Ordinary, false, false, + false, false), + Val(val) {} + + /// \brief Build an empty imaginary literal. + explicit ImaginaryLiteral(EmptyShell Empty) + : Expr(ImaginaryLiteralClass, Empty) { } + + const Expr *getSubExpr() const { return cast<Expr>(Val); } + Expr *getSubExpr() { return cast<Expr>(Val); } + void setSubExpr(Expr *E) { Val = E; } + + SourceLocation getLocStart() const LLVM_READONLY { return Val->getLocStart(); } + SourceLocation getLocEnd() const LLVM_READONLY { return Val->getLocEnd(); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ImaginaryLiteralClass; + } + + // Iterators + child_range children() { return child_range(&Val, &Val+1); } +}; + +/// StringLiteral - This represents a string literal expression, e.g. "foo" +/// or L"bar" (wide strings). The actual string is returned by getBytes() +/// is NOT null-terminated, and the length of the string is determined by +/// calling getByteLength(). The C type for a string is always a +/// ConstantArrayType. In C++, the char type is const qualified, in C it is +/// not. +/// +/// Note that strings in C can be formed by concatenation of multiple string +/// literal pptokens in translation phase #6. This keeps track of the locations +/// of each of these pieces. +/// +/// Strings in C can also be truncated and extended by assigning into arrays, +/// e.g. with constructs like: +/// char X[2] = "foobar"; +/// In this case, getByteLength() will return 6, but the string literal will +/// have type "char[2]". +class StringLiteral : public Expr { +public: + enum StringKind { + Ascii, + Wide, + UTF8, + UTF16, + UTF32 + }; + +private: + friend class ASTStmtReader; + + union { + const char *asChar; + const uint16_t *asUInt16; + const uint32_t *asUInt32; + } StrData; + unsigned Length; + unsigned CharByteWidth : 4; + unsigned Kind : 3; + unsigned IsPascal : 1; + unsigned NumConcatenated; + SourceLocation TokLocs[1]; + + StringLiteral(QualType Ty) : + Expr(StringLiteralClass, Ty, VK_LValue, OK_Ordinary, false, false, false, + false) {} + + static int mapCharByteWidth(TargetInfo const &target,StringKind k); + +public: + /// This is the "fully general" constructor that allows representation of + /// strings formed from multiple concatenated tokens. + static StringLiteral *Create(const ASTContext &C, StringRef Str, + StringKind Kind, bool Pascal, QualType Ty, + const SourceLocation *Loc, unsigned NumStrs); + + /// Simple constructor for string literals made from one token. + static StringLiteral *Create(const ASTContext &C, StringRef Str, + StringKind Kind, bool Pascal, QualType Ty, + SourceLocation Loc) { + return Create(C, Str, Kind, Pascal, Ty, &Loc, 1); + } + + /// \brief Construct an empty string literal. + static StringLiteral *CreateEmpty(const ASTContext &C, unsigned NumStrs); + + StringRef getString() const { + assert(CharByteWidth==1 + && "This function is used in places that assume strings use char"); + return StringRef(StrData.asChar, getByteLength()); + } + + /// Allow access to clients that need the byte representation, such as + /// ASTWriterStmt::VisitStringLiteral(). + StringRef getBytes() const { + // FIXME: StringRef may not be the right type to use as a result for this. + if (CharByteWidth == 1) + return StringRef(StrData.asChar, getByteLength()); + if (CharByteWidth == 4) + return StringRef(reinterpret_cast<const char*>(StrData.asUInt32), + getByteLength()); + assert(CharByteWidth == 2 && "unsupported CharByteWidth"); + return StringRef(reinterpret_cast<const char*>(StrData.asUInt16), + getByteLength()); + } + + void outputString(raw_ostream &OS) const; + + uint32_t getCodeUnit(size_t i) const { + assert(i < Length && "out of bounds access"); + if (CharByteWidth == 1) + return static_cast<unsigned char>(StrData.asChar[i]); + if (CharByteWidth == 4) + return StrData.asUInt32[i]; + assert(CharByteWidth == 2 && "unsupported CharByteWidth"); + return StrData.asUInt16[i]; + } + + unsigned getByteLength() const { return CharByteWidth*Length; } + unsigned getLength() const { return Length; } + unsigned getCharByteWidth() const { return CharByteWidth; } + + /// \brief Sets the string data to the given string data. + void setString(const ASTContext &C, StringRef Str, + StringKind Kind, bool IsPascal); + + StringKind getKind() const { return static_cast<StringKind>(Kind); } + + + bool isAscii() const { return Kind == Ascii; } + bool isWide() const { return Kind == Wide; } + bool isUTF8() const { return Kind == UTF8; } + bool isUTF16() const { return Kind == UTF16; } + bool isUTF32() const { return Kind == UTF32; } + bool isPascal() const { return IsPascal; } + + bool containsNonAsciiOrNull() const { + StringRef Str = getString(); + for (unsigned i = 0, e = Str.size(); i != e; ++i) + if (!isASCII(Str[i]) || !Str[i]) + return true; + return false; + } + + /// getNumConcatenated - Get the number of string literal tokens that were + /// concatenated in translation phase #6 to form this string literal. + unsigned getNumConcatenated() const { return NumConcatenated; } + + SourceLocation getStrTokenLoc(unsigned TokNum) const { + assert(TokNum < NumConcatenated && "Invalid tok number"); + return TokLocs[TokNum]; + } + void setStrTokenLoc(unsigned TokNum, SourceLocation L) { + assert(TokNum < NumConcatenated && "Invalid tok number"); + TokLocs[TokNum] = L; + } + + /// getLocationOfByte - Return a source location that points to the specified + /// byte of this string literal. + /// + /// Strings are amazingly complex. They can be formed from multiple tokens + /// and can have escape sequences in them in addition to the usual trigraph + /// and escaped newline business. This routine handles this complexity. + /// + SourceLocation + getLocationOfByte(unsigned ByteNo, const SourceManager &SM, + const LangOptions &Features, const TargetInfo &Target, + unsigned *StartToken = nullptr, + unsigned *StartTokenByteOffset = nullptr) const; + + typedef const SourceLocation *tokloc_iterator; + tokloc_iterator tokloc_begin() const { return TokLocs; } + tokloc_iterator tokloc_end() const { return TokLocs + NumConcatenated; } + + SourceLocation getLocStart() const LLVM_READONLY { return TokLocs[0]; } + SourceLocation getLocEnd() const LLVM_READONLY { + return TokLocs[NumConcatenated - 1]; + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == StringLiteralClass; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +/// ParenExpr - This represents a parethesized expression, e.g. "(1)". This +/// AST node is only formed if full location information is requested. +class ParenExpr : public Expr { + SourceLocation L, R; + Stmt *Val; +public: + ParenExpr(SourceLocation l, SourceLocation r, Expr *val) + : Expr(ParenExprClass, val->getType(), + val->getValueKind(), val->getObjectKind(), + val->isTypeDependent(), val->isValueDependent(), + val->isInstantiationDependent(), + val->containsUnexpandedParameterPack()), + L(l), R(r), Val(val) {} + + /// \brief Construct an empty parenthesized expression. + explicit ParenExpr(EmptyShell Empty) + : Expr(ParenExprClass, Empty) { } + + const Expr *getSubExpr() const { return cast<Expr>(Val); } + Expr *getSubExpr() { return cast<Expr>(Val); } + void setSubExpr(Expr *E) { Val = E; } + + SourceLocation getLocStart() const LLVM_READONLY { return L; } + SourceLocation getLocEnd() const LLVM_READONLY { return R; } + + /// \brief Get the location of the left parentheses '('. + SourceLocation getLParen() const { return L; } + void setLParen(SourceLocation Loc) { L = Loc; } + + /// \brief Get the location of the right parentheses ')'. + SourceLocation getRParen() const { return R; } + void setRParen(SourceLocation Loc) { R = Loc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ParenExprClass; + } + + // Iterators + child_range children() { return child_range(&Val, &Val+1); } +}; + +/// UnaryOperator - This represents the unary-expression's (except sizeof and +/// alignof), the postinc/postdec operators from postfix-expression, and various +/// extensions. +/// +/// Notes on various nodes: +/// +/// Real/Imag - These return the real/imag part of a complex operand. If +/// applied to a non-complex value, the former returns its operand and the +/// later returns zero in the type of the operand. +/// +class UnaryOperator : public Expr { +public: + typedef UnaryOperatorKind Opcode; + +private: + unsigned Opc : 5; + SourceLocation Loc; + Stmt *Val; +public: + + UnaryOperator(Expr *input, Opcode opc, QualType type, + ExprValueKind VK, ExprObjectKind OK, SourceLocation l) + : Expr(UnaryOperatorClass, type, VK, OK, + input->isTypeDependent() || type->isDependentType(), + input->isValueDependent(), + (input->isInstantiationDependent() || + type->isInstantiationDependentType()), + input->containsUnexpandedParameterPack()), + Opc(opc), Loc(l), Val(input) {} + + /// \brief Build an empty unary operator. + explicit UnaryOperator(EmptyShell Empty) + : Expr(UnaryOperatorClass, Empty), Opc(UO_AddrOf) { } + + Opcode getOpcode() const { return static_cast<Opcode>(Opc); } + void setOpcode(Opcode O) { Opc = O; } + + Expr *getSubExpr() const { return cast<Expr>(Val); } + void setSubExpr(Expr *E) { Val = E; } + + /// getOperatorLoc - Return the location of the operator. + SourceLocation getOperatorLoc() const { return Loc; } + void setOperatorLoc(SourceLocation L) { Loc = L; } + + /// isPostfix - Return true if this is a postfix operation, like x++. + static bool isPostfix(Opcode Op) { + return Op == UO_PostInc || Op == UO_PostDec; + } + + /// isPrefix - Return true if this is a prefix operation, like --x. + static bool isPrefix(Opcode Op) { + return Op == UO_PreInc || Op == UO_PreDec; + } + + bool isPrefix() const { return isPrefix(getOpcode()); } + bool isPostfix() const { return isPostfix(getOpcode()); } + + static bool isIncrementOp(Opcode Op) { + return Op == UO_PreInc || Op == UO_PostInc; + } + bool isIncrementOp() const { + return isIncrementOp(getOpcode()); + } + + static bool isDecrementOp(Opcode Op) { + return Op == UO_PreDec || Op == UO_PostDec; + } + bool isDecrementOp() const { + return isDecrementOp(getOpcode()); + } + + static bool isIncrementDecrementOp(Opcode Op) { return Op <= UO_PreDec; } + bool isIncrementDecrementOp() const { + return isIncrementDecrementOp(getOpcode()); + } + + static bool isArithmeticOp(Opcode Op) { + return Op >= UO_Plus && Op <= UO_LNot; + } + bool isArithmeticOp() const { return isArithmeticOp(getOpcode()); } + + /// getOpcodeStr - Turn an Opcode enum value into the punctuation char it + /// corresponds to, e.g. "sizeof" or "[pre]++" + static StringRef getOpcodeStr(Opcode Op); + + /// \brief Retrieve the unary opcode that corresponds to the given + /// overloaded operator. + static Opcode getOverloadedOpcode(OverloadedOperatorKind OO, bool Postfix); + + /// \brief Retrieve the overloaded operator kind that corresponds to + /// the given unary opcode. + static OverloadedOperatorKind getOverloadedOperator(Opcode Opc); + + SourceLocation getLocStart() const LLVM_READONLY { + return isPostfix() ? Val->getLocStart() : Loc; + } + SourceLocation getLocEnd() const LLVM_READONLY { + return isPostfix() ? Loc : Val->getLocEnd(); + } + SourceLocation getExprLoc() const LLVM_READONLY { return Loc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == UnaryOperatorClass; + } + + // Iterators + child_range children() { return child_range(&Val, &Val+1); } +}; + +/// Helper class for OffsetOfExpr. + +// __builtin_offsetof(type, identifier(.identifier|[expr])*) +class OffsetOfNode { +public: + /// \brief The kind of offsetof node we have. + enum Kind { + /// \brief An index into an array. + Array = 0x00, + /// \brief A field. + Field = 0x01, + /// \brief A field in a dependent type, known only by its name. + Identifier = 0x02, + /// \brief An implicit indirection through a C++ base class, when the + /// field found is in a base class. + Base = 0x03 + }; + +private: + enum { MaskBits = 2, Mask = 0x03 }; + + /// \brief The source range that covers this part of the designator. + SourceRange Range; + + /// \brief The data describing the designator, which comes in three + /// different forms, depending on the lower two bits. + /// - An unsigned index into the array of Expr*'s stored after this node + /// in memory, for [constant-expression] designators. + /// - A FieldDecl*, for references to a known field. + /// - An IdentifierInfo*, for references to a field with a given name + /// when the class type is dependent. + /// - A CXXBaseSpecifier*, for references that look at a field in a + /// base class. + uintptr_t Data; + +public: + /// \brief Create an offsetof node that refers to an array element. + OffsetOfNode(SourceLocation LBracketLoc, unsigned Index, + SourceLocation RBracketLoc) + : Range(LBracketLoc, RBracketLoc), Data((Index << 2) | Array) {} + + /// \brief Create an offsetof node that refers to a field. + OffsetOfNode(SourceLocation DotLoc, FieldDecl *Field, SourceLocation NameLoc) + : Range(DotLoc.isValid() ? DotLoc : NameLoc, NameLoc), + Data(reinterpret_cast<uintptr_t>(Field) | OffsetOfNode::Field) {} + + /// \brief Create an offsetof node that refers to an identifier. + OffsetOfNode(SourceLocation DotLoc, IdentifierInfo *Name, + SourceLocation NameLoc) + : Range(DotLoc.isValid() ? DotLoc : NameLoc, NameLoc), + Data(reinterpret_cast<uintptr_t>(Name) | Identifier) {} + + /// \brief Create an offsetof node that refers into a C++ base class. + explicit OffsetOfNode(const CXXBaseSpecifier *Base) + : Range(), Data(reinterpret_cast<uintptr_t>(Base) | OffsetOfNode::Base) {} + + /// \brief Determine what kind of offsetof node this is. + Kind getKind() const { return static_cast<Kind>(Data & Mask); } + + /// \brief For an array element node, returns the index into the array + /// of expressions. + unsigned getArrayExprIndex() const { + assert(getKind() == Array); + return Data >> 2; + } + + /// \brief For a field offsetof node, returns the field. + FieldDecl *getField() const { + assert(getKind() == Field); + return reinterpret_cast<FieldDecl *>(Data & ~(uintptr_t)Mask); + } + + /// \brief For a field or identifier offsetof node, returns the name of + /// the field. + IdentifierInfo *getFieldName() const; + + /// \brief For a base class node, returns the base specifier. + CXXBaseSpecifier *getBase() const { + assert(getKind() == Base); + return reinterpret_cast<CXXBaseSpecifier *>(Data & ~(uintptr_t)Mask); + } + + /// \brief Retrieve the source range that covers this offsetof node. + /// + /// For an array element node, the source range contains the locations of + /// the square brackets. For a field or identifier node, the source range + /// contains the location of the period (if there is one) and the + /// identifier. + SourceRange getSourceRange() const LLVM_READONLY { return Range; } + SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } + SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } +}; + +/// OffsetOfExpr - [C99 7.17] - This represents an expression of the form +/// offsetof(record-type, member-designator). For example, given: +/// @code +/// struct S { +/// float f; +/// double d; +/// }; +/// struct T { +/// int i; +/// struct S s[10]; +/// }; +/// @endcode +/// we can represent and evaluate the expression @c offsetof(struct T, s[2].d). + +class OffsetOfExpr final + : public Expr, + private llvm::TrailingObjects<OffsetOfExpr, OffsetOfNode, Expr *> { + SourceLocation OperatorLoc, RParenLoc; + // Base type; + TypeSourceInfo *TSInfo; + // Number of sub-components (i.e. instances of OffsetOfNode). + unsigned NumComps; + // Number of sub-expressions (i.e. array subscript expressions). + unsigned NumExprs; + + size_t numTrailingObjects(OverloadToken<OffsetOfNode>) const { + return NumComps; + } + + OffsetOfExpr(const ASTContext &C, QualType type, + SourceLocation OperatorLoc, TypeSourceInfo *tsi, + ArrayRef<OffsetOfNode> comps, ArrayRef<Expr*> exprs, + SourceLocation RParenLoc); + + explicit OffsetOfExpr(unsigned numComps, unsigned numExprs) + : Expr(OffsetOfExprClass, EmptyShell()), + TSInfo(nullptr), NumComps(numComps), NumExprs(numExprs) {} + +public: + + static OffsetOfExpr *Create(const ASTContext &C, QualType type, + SourceLocation OperatorLoc, TypeSourceInfo *tsi, + ArrayRef<OffsetOfNode> comps, + ArrayRef<Expr*> exprs, SourceLocation RParenLoc); + + static OffsetOfExpr *CreateEmpty(const ASTContext &C, + unsigned NumComps, unsigned NumExprs); + + /// getOperatorLoc - Return the location of the operator. + SourceLocation getOperatorLoc() const { return OperatorLoc; } + void setOperatorLoc(SourceLocation L) { OperatorLoc = L; } + + /// \brief Return the location of the right parentheses. + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation R) { RParenLoc = R; } + + TypeSourceInfo *getTypeSourceInfo() const { + return TSInfo; + } + void setTypeSourceInfo(TypeSourceInfo *tsi) { + TSInfo = tsi; + } + + const OffsetOfNode &getComponent(unsigned Idx) const { + assert(Idx < NumComps && "Subscript out of range"); + return getTrailingObjects<OffsetOfNode>()[Idx]; + } + + void setComponent(unsigned Idx, OffsetOfNode ON) { + assert(Idx < NumComps && "Subscript out of range"); + getTrailingObjects<OffsetOfNode>()[Idx] = ON; + } + + unsigned getNumComponents() const { + return NumComps; + } + + Expr* getIndexExpr(unsigned Idx) { + assert(Idx < NumExprs && "Subscript out of range"); + return getTrailingObjects<Expr *>()[Idx]; + } + + const Expr *getIndexExpr(unsigned Idx) const { + assert(Idx < NumExprs && "Subscript out of range"); + return getTrailingObjects<Expr *>()[Idx]; + } + + void setIndexExpr(unsigned Idx, Expr* E) { + assert(Idx < NumComps && "Subscript out of range"); + getTrailingObjects<Expr *>()[Idx] = E; + } + + unsigned getNumExpressions() const { + return NumExprs; + } + + SourceLocation getLocStart() const LLVM_READONLY { return OperatorLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OffsetOfExprClass; + } + + // Iterators + child_range children() { + Stmt **begin = reinterpret_cast<Stmt **>(getTrailingObjects<Expr *>()); + return child_range(begin, begin + NumExprs); + } + friend TrailingObjects; +}; + +/// UnaryExprOrTypeTraitExpr - expression with either a type or (unevaluated) +/// expression operand. Used for sizeof/alignof (C99 6.5.3.4) and +/// vec_step (OpenCL 1.1 6.11.12). +class UnaryExprOrTypeTraitExpr : public Expr { + union { + TypeSourceInfo *Ty; + Stmt *Ex; + } Argument; + SourceLocation OpLoc, RParenLoc; + +public: + UnaryExprOrTypeTraitExpr(UnaryExprOrTypeTrait ExprKind, TypeSourceInfo *TInfo, + QualType resultType, SourceLocation op, + SourceLocation rp) : + Expr(UnaryExprOrTypeTraitExprClass, resultType, VK_RValue, OK_Ordinary, + false, // Never type-dependent (C++ [temp.dep.expr]p3). + // Value-dependent if the argument is type-dependent. + TInfo->getType()->isDependentType(), + TInfo->getType()->isInstantiationDependentType(), + TInfo->getType()->containsUnexpandedParameterPack()), + OpLoc(op), RParenLoc(rp) { + UnaryExprOrTypeTraitExprBits.Kind = ExprKind; + UnaryExprOrTypeTraitExprBits.IsType = true; + Argument.Ty = TInfo; + } + + UnaryExprOrTypeTraitExpr(UnaryExprOrTypeTrait ExprKind, Expr *E, + QualType resultType, SourceLocation op, + SourceLocation rp); + + /// \brief Construct an empty sizeof/alignof expression. + explicit UnaryExprOrTypeTraitExpr(EmptyShell Empty) + : Expr(UnaryExprOrTypeTraitExprClass, Empty) { } + + UnaryExprOrTypeTrait getKind() const { + return static_cast<UnaryExprOrTypeTrait>(UnaryExprOrTypeTraitExprBits.Kind); + } + void setKind(UnaryExprOrTypeTrait K) { UnaryExprOrTypeTraitExprBits.Kind = K;} + + bool isArgumentType() const { return UnaryExprOrTypeTraitExprBits.IsType; } + QualType getArgumentType() const { + return getArgumentTypeInfo()->getType(); + } + TypeSourceInfo *getArgumentTypeInfo() const { + assert(isArgumentType() && "calling getArgumentType() when arg is expr"); + return Argument.Ty; + } + Expr *getArgumentExpr() { + assert(!isArgumentType() && "calling getArgumentExpr() when arg is type"); + return static_cast<Expr*>(Argument.Ex); + } + const Expr *getArgumentExpr() const { + return const_cast<UnaryExprOrTypeTraitExpr*>(this)->getArgumentExpr(); + } + + void setArgument(Expr *E) { + Argument.Ex = E; + UnaryExprOrTypeTraitExprBits.IsType = false; + } + void setArgument(TypeSourceInfo *TInfo) { + Argument.Ty = TInfo; + UnaryExprOrTypeTraitExprBits.IsType = true; + } + + /// Gets the argument type, or the type of the argument expression, whichever + /// is appropriate. + QualType getTypeOfArgument() const { + return isArgumentType() ? getArgumentType() : getArgumentExpr()->getType(); + } + + SourceLocation getOperatorLoc() const { return OpLoc; } + void setOperatorLoc(SourceLocation L) { OpLoc = L; } + + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + SourceLocation getLocStart() const LLVM_READONLY { return OpLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == UnaryExprOrTypeTraitExprClass; + } + + // Iterators + child_range children(); +}; + +//===----------------------------------------------------------------------===// +// Postfix Operators. +//===----------------------------------------------------------------------===// + +/// ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting. +class ArraySubscriptExpr : public Expr { + enum { LHS, RHS, END_EXPR=2 }; + Stmt* SubExprs[END_EXPR]; + SourceLocation RBracketLoc; +public: + ArraySubscriptExpr(Expr *lhs, Expr *rhs, QualType t, + ExprValueKind VK, ExprObjectKind OK, + SourceLocation rbracketloc) + : Expr(ArraySubscriptExprClass, t, VK, OK, + lhs->isTypeDependent() || rhs->isTypeDependent(), + lhs->isValueDependent() || rhs->isValueDependent(), + (lhs->isInstantiationDependent() || + rhs->isInstantiationDependent()), + (lhs->containsUnexpandedParameterPack() || + rhs->containsUnexpandedParameterPack())), + RBracketLoc(rbracketloc) { + SubExprs[LHS] = lhs; + SubExprs[RHS] = rhs; + } + + /// \brief Create an empty array subscript expression. + explicit ArraySubscriptExpr(EmptyShell Shell) + : Expr(ArraySubscriptExprClass, Shell) { } + + /// An array access can be written A[4] or 4[A] (both are equivalent). + /// - getBase() and getIdx() always present the normalized view: A[4]. + /// In this case getBase() returns "A" and getIdx() returns "4". + /// - getLHS() and getRHS() present the syntactic view. e.g. for + /// 4[A] getLHS() returns "4". + /// Note: Because vector element access is also written A[4] we must + /// predicate the format conversion in getBase and getIdx only on the + /// the type of the RHS, as it is possible for the LHS to be a vector of + /// integer type + Expr *getLHS() { return cast<Expr>(SubExprs[LHS]); } + const Expr *getLHS() const { return cast<Expr>(SubExprs[LHS]); } + void setLHS(Expr *E) { SubExprs[LHS] = E; } + + Expr *getRHS() { return cast<Expr>(SubExprs[RHS]); } + const Expr *getRHS() const { return cast<Expr>(SubExprs[RHS]); } + void setRHS(Expr *E) { SubExprs[RHS] = E; } + + Expr *getBase() { + return cast<Expr>(getRHS()->getType()->isIntegerType() ? getLHS():getRHS()); + } + + const Expr *getBase() const { + return cast<Expr>(getRHS()->getType()->isIntegerType() ? getLHS():getRHS()); + } + + Expr *getIdx() { + return cast<Expr>(getRHS()->getType()->isIntegerType() ? getRHS():getLHS()); + } + + const Expr *getIdx() const { + return cast<Expr>(getRHS()->getType()->isIntegerType() ? getRHS():getLHS()); + } + + SourceLocation getLocStart() const LLVM_READONLY { + return getLHS()->getLocStart(); + } + SourceLocation getLocEnd() const LLVM_READONLY { return RBracketLoc; } + + SourceLocation getRBracketLoc() const { return RBracketLoc; } + void setRBracketLoc(SourceLocation L) { RBracketLoc = L; } + + SourceLocation getExprLoc() const LLVM_READONLY { + return getBase()->getExprLoc(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ArraySubscriptExprClass; + } + + // Iterators + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); + } +}; + +/// CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]). +/// CallExpr itself represents a normal function call, e.g., "f(x, 2)", +/// while its subclasses may represent alternative syntax that (semantically) +/// results in a function call. For example, CXXOperatorCallExpr is +/// a subclass for overloaded operator calls that use operator syntax, e.g., +/// "str1 + str2" to resolve to a function call. +class CallExpr : public Expr { + enum { FN=0, PREARGS_START=1 }; + Stmt **SubExprs; + unsigned NumArgs; + SourceLocation RParenLoc; + +protected: + // These versions of the constructor are for derived classes. + CallExpr(const ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs, + ArrayRef<Expr*> args, QualType t, ExprValueKind VK, + SourceLocation rparenloc); + CallExpr(const ASTContext &C, StmtClass SC, unsigned NumPreArgs, + EmptyShell Empty); + + Stmt *getPreArg(unsigned i) { + assert(i < getNumPreArgs() && "Prearg access out of range!"); + return SubExprs[PREARGS_START+i]; + } + const Stmt *getPreArg(unsigned i) const { + assert(i < getNumPreArgs() && "Prearg access out of range!"); + return SubExprs[PREARGS_START+i]; + } + void setPreArg(unsigned i, Stmt *PreArg) { + assert(i < getNumPreArgs() && "Prearg access out of range!"); + SubExprs[PREARGS_START+i] = PreArg; + } + + unsigned getNumPreArgs() const { return CallExprBits.NumPreArgs; } + +public: + CallExpr(const ASTContext& C, Expr *fn, ArrayRef<Expr*> args, QualType t, + ExprValueKind VK, SourceLocation rparenloc); + + /// \brief Build an empty call expression. + CallExpr(const ASTContext &C, StmtClass SC, EmptyShell Empty); + + const Expr *getCallee() const { return cast<Expr>(SubExprs[FN]); } + Expr *getCallee() { return cast<Expr>(SubExprs[FN]); } + void setCallee(Expr *F) { SubExprs[FN] = F; } + + Decl *getCalleeDecl(); + const Decl *getCalleeDecl() const { + return const_cast<CallExpr*>(this)->getCalleeDecl(); + } + + /// \brief If the callee is a FunctionDecl, return it. Otherwise return 0. + FunctionDecl *getDirectCallee(); + const FunctionDecl *getDirectCallee() const { + return const_cast<CallExpr*>(this)->getDirectCallee(); + } + + /// getNumArgs - Return the number of actual arguments to this call. + /// + unsigned getNumArgs() const { return NumArgs; } + + /// \brief Retrieve the call arguments. + Expr **getArgs() { + return reinterpret_cast<Expr **>(SubExprs+getNumPreArgs()+PREARGS_START); + } + const Expr *const *getArgs() const { + return reinterpret_cast<Expr **>(SubExprs + getNumPreArgs() + + PREARGS_START); + } + + /// getArg - Return the specified argument. + Expr *getArg(unsigned Arg) { + assert(Arg < NumArgs && "Arg access out of range!"); + return cast_or_null<Expr>(SubExprs[Arg + getNumPreArgs() + PREARGS_START]); + } + const Expr *getArg(unsigned Arg) const { + assert(Arg < NumArgs && "Arg access out of range!"); + return cast_or_null<Expr>(SubExprs[Arg + getNumPreArgs() + PREARGS_START]); + } + + /// setArg - Set the specified argument. + void setArg(unsigned Arg, Expr *ArgExpr) { + assert(Arg < NumArgs && "Arg access out of range!"); + SubExprs[Arg+getNumPreArgs()+PREARGS_START] = ArgExpr; + } + + /// setNumArgs - This changes the number of arguments present in this call. + /// Any orphaned expressions are deleted by this, and any new operands are set + /// to null. + void setNumArgs(const ASTContext& C, unsigned NumArgs); + + typedef ExprIterator arg_iterator; + typedef ConstExprIterator const_arg_iterator; + typedef llvm::iterator_range<arg_iterator> arg_range; + typedef llvm::iterator_range<const_arg_iterator> arg_const_range; + + arg_range arguments() { return arg_range(arg_begin(), arg_end()); } + arg_const_range arguments() const { + return arg_const_range(arg_begin(), arg_end()); + } + + arg_iterator arg_begin() { return SubExprs+PREARGS_START+getNumPreArgs(); } + arg_iterator arg_end() { + return SubExprs+PREARGS_START+getNumPreArgs()+getNumArgs(); + } + const_arg_iterator arg_begin() const { + return SubExprs+PREARGS_START+getNumPreArgs(); + } + const_arg_iterator arg_end() const { + return SubExprs+PREARGS_START+getNumPreArgs()+getNumArgs(); + } + + /// This method provides fast access to all the subexpressions of + /// a CallExpr without going through the slower virtual child_iterator + /// interface. This provides efficient reverse iteration of the + /// subexpressions. This is currently used for CFG construction. + ArrayRef<Stmt*> getRawSubExprs() { + return llvm::makeArrayRef(SubExprs, + getNumPreArgs() + PREARGS_START + getNumArgs()); + } + + /// getNumCommas - Return the number of commas that must have been present in + /// this function call. + unsigned getNumCommas() const { return NumArgs ? NumArgs - 1 : 0; } + + /// getBuiltinCallee - If this is a call to a builtin, return the builtin ID + /// of the callee. If not, return 0. + unsigned getBuiltinCallee() const; + + /// \brief Returns \c true if this is a call to a builtin which does not + /// evaluate side-effects within its arguments. + bool isUnevaluatedBuiltinCall(const ASTContext &Ctx) const; + + /// getCallReturnType - Get the return type of the call expr. This is not + /// always the type of the expr itself, if the return type is a reference + /// type. + QualType getCallReturnType(const ASTContext &Ctx) const; + + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + SourceLocation getLocStart() const LLVM_READONLY; + SourceLocation getLocEnd() const LLVM_READONLY; + + static bool classof(const Stmt *T) { + return T->getStmtClass() >= firstCallExprConstant && + T->getStmtClass() <= lastCallExprConstant; + } + + // Iterators + child_range children() { + return child_range(&SubExprs[0], + &SubExprs[0]+NumArgs+getNumPreArgs()+PREARGS_START); + } +}; + +/// Extra data stored in some MemberExpr objects. +struct MemberExprNameQualifier { + /// \brief The nested-name-specifier that qualifies the name, including + /// source-location information. + NestedNameSpecifierLoc QualifierLoc; + + /// \brief The DeclAccessPair through which the MemberDecl was found due to + /// name qualifiers. + DeclAccessPair FoundDecl; +}; + +/// MemberExpr - [C99 6.5.2.3] Structure and Union Members. X->F and X.F. +/// +class MemberExpr final + : public Expr, + private llvm::TrailingObjects<MemberExpr, MemberExprNameQualifier, + ASTTemplateKWAndArgsInfo, + TemplateArgumentLoc> { + /// Base - the expression for the base pointer or structure references. In + /// X.F, this is "X". + Stmt *Base; + + /// MemberDecl - This is the decl being referenced by the field/member name. + /// In X.F, this is the decl referenced by F. + ValueDecl *MemberDecl; + + /// MemberDNLoc - Provides source/type location info for the + /// declaration name embedded in MemberDecl. + DeclarationNameLoc MemberDNLoc; + + /// MemberLoc - This is the location of the member name. + SourceLocation MemberLoc; + + /// This is the location of the -> or . in the expression. + SourceLocation OperatorLoc; + + /// IsArrow - True if this is "X->F", false if this is "X.F". + bool IsArrow : 1; + + /// \brief True if this member expression used a nested-name-specifier to + /// refer to the member, e.g., "x->Base::f", or found its member via a using + /// declaration. When true, a MemberExprNameQualifier + /// structure is allocated immediately after the MemberExpr. + bool HasQualifierOrFoundDecl : 1; + + /// \brief True if this member expression specified a template keyword + /// and/or a template argument list explicitly, e.g., x->f<int>, + /// x->template f, x->template f<int>. + /// When true, an ASTTemplateKWAndArgsInfo structure and its + /// TemplateArguments (if any) are present. + bool HasTemplateKWAndArgsInfo : 1; + + /// \brief True if this member expression refers to a method that + /// was resolved from an overloaded set having size greater than 1. + bool HadMultipleCandidates : 1; + + size_t numTrailingObjects(OverloadToken<MemberExprNameQualifier>) const { + return HasQualifierOrFoundDecl ? 1 : 0; + } + + size_t numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const { + return HasTemplateKWAndArgsInfo ? 1 : 0; + } + +public: + MemberExpr(Expr *base, bool isarrow, SourceLocation operatorloc, + ValueDecl *memberdecl, const DeclarationNameInfo &NameInfo, + QualType ty, ExprValueKind VK, ExprObjectKind OK) + : Expr(MemberExprClass, ty, VK, OK, base->isTypeDependent(), + base->isValueDependent(), base->isInstantiationDependent(), + base->containsUnexpandedParameterPack()), + Base(base), MemberDecl(memberdecl), MemberDNLoc(NameInfo.getInfo()), + MemberLoc(NameInfo.getLoc()), OperatorLoc(operatorloc), + IsArrow(isarrow), HasQualifierOrFoundDecl(false), + HasTemplateKWAndArgsInfo(false), HadMultipleCandidates(false) { + assert(memberdecl->getDeclName() == NameInfo.getName()); + } + + // NOTE: this constructor should be used only when it is known that + // the member name can not provide additional syntactic info + // (i.e., source locations for C++ operator names or type source info + // for constructors, destructors and conversion operators). + MemberExpr(Expr *base, bool isarrow, SourceLocation operatorloc, + ValueDecl *memberdecl, SourceLocation l, QualType ty, + ExprValueKind VK, ExprObjectKind OK) + : Expr(MemberExprClass, ty, VK, OK, base->isTypeDependent(), + base->isValueDependent(), base->isInstantiationDependent(), + base->containsUnexpandedParameterPack()), + Base(base), MemberDecl(memberdecl), MemberDNLoc(), MemberLoc(l), + OperatorLoc(operatorloc), IsArrow(isarrow), + HasQualifierOrFoundDecl(false), HasTemplateKWAndArgsInfo(false), + HadMultipleCandidates(false) {} + + static MemberExpr *Create(const ASTContext &C, Expr *base, bool isarrow, + SourceLocation OperatorLoc, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, ValueDecl *memberdecl, + DeclAccessPair founddecl, + DeclarationNameInfo MemberNameInfo, + const TemplateArgumentListInfo *targs, QualType ty, + ExprValueKind VK, ExprObjectKind OK); + + void setBase(Expr *E) { Base = E; } + Expr *getBase() const { return cast<Expr>(Base); } + + /// \brief Retrieve the member declaration to which this expression refers. + /// + /// The returned declaration will either be a FieldDecl or (in C++) + /// a CXXMethodDecl. + ValueDecl *getMemberDecl() const { return MemberDecl; } + void setMemberDecl(ValueDecl *D) { MemberDecl = D; } + + /// \brief Retrieves the declaration found by lookup. + DeclAccessPair getFoundDecl() const { + if (!HasQualifierOrFoundDecl) + return DeclAccessPair::make(getMemberDecl(), + getMemberDecl()->getAccess()); + return getTrailingObjects<MemberExprNameQualifier>()->FoundDecl; + } + + /// \brief Determines whether this member expression actually had + /// a C++ nested-name-specifier prior to the name of the member, e.g., + /// x->Base::foo. + bool hasQualifier() const { return getQualifier() != nullptr; } + + /// \brief If the member name was qualified, retrieves the + /// nested-name-specifier that precedes the member name, with source-location + /// information. + NestedNameSpecifierLoc getQualifierLoc() const { + if (!HasQualifierOrFoundDecl) + return NestedNameSpecifierLoc(); + + return getTrailingObjects<MemberExprNameQualifier>()->QualifierLoc; + } + + /// \brief If the member name was qualified, retrieves the + /// nested-name-specifier that precedes the member name. Otherwise, returns + /// NULL. + NestedNameSpecifier *getQualifier() const { + return getQualifierLoc().getNestedNameSpecifier(); + } + + /// \brief Retrieve the location of the template keyword preceding + /// the member name, if any. + SourceLocation getTemplateKeywordLoc() const { + if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->TemplateKWLoc; + } + + /// \brief Retrieve the location of the left angle bracket starting the + /// explicit template argument list following the member name, if any. + SourceLocation getLAngleLoc() const { + if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->LAngleLoc; + } + + /// \brief Retrieve the location of the right angle bracket ending the + /// explicit template argument list following the member name, if any. + SourceLocation getRAngleLoc() const { + if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->RAngleLoc; + } + + /// Determines whether the member name was preceded by the template keyword. + bool hasTemplateKeyword() const { return getTemplateKeywordLoc().isValid(); } + + /// \brief Determines whether the member name was followed by an + /// explicit template argument list. + bool hasExplicitTemplateArgs() const { return getLAngleLoc().isValid(); } + + /// \brief Copies the template arguments (if present) into the given + /// structure. + void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const { + if (hasExplicitTemplateArgs()) + getTrailingObjects<ASTTemplateKWAndArgsInfo>()->copyInto( + getTrailingObjects<TemplateArgumentLoc>(), List); + } + + /// \brief Retrieve the template arguments provided as part of this + /// template-id. + const TemplateArgumentLoc *getTemplateArgs() const { + if (!hasExplicitTemplateArgs()) + return nullptr; + + return getTrailingObjects<TemplateArgumentLoc>(); + } + + /// \brief Retrieve the number of template arguments provided as part of this + /// template-id. + unsigned getNumTemplateArgs() const { + if (!hasExplicitTemplateArgs()) + return 0; + + return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->NumTemplateArgs; + } + + /// \brief Retrieve the member declaration name info. + DeclarationNameInfo getMemberNameInfo() const { + return DeclarationNameInfo(MemberDecl->getDeclName(), + MemberLoc, MemberDNLoc); + } + + SourceLocation getOperatorLoc() const LLVM_READONLY { return OperatorLoc; } + + bool isArrow() const { return IsArrow; } + void setArrow(bool A) { IsArrow = A; } + + /// getMemberLoc - Return the location of the "member", in X->F, it is the + /// location of 'F'. + SourceLocation getMemberLoc() const { return MemberLoc; } + void setMemberLoc(SourceLocation L) { MemberLoc = L; } + + SourceLocation getLocStart() const LLVM_READONLY; + SourceLocation getLocEnd() const LLVM_READONLY; + + SourceLocation getExprLoc() const LLVM_READONLY { return MemberLoc; } + + /// \brief Determine whether the base of this explicit is implicit. + bool isImplicitAccess() const { + return getBase() && getBase()->isImplicitCXXThis(); + } + + /// \brief Returns true if this member expression refers to a method that + /// was resolved from an overloaded set having size greater than 1. + bool hadMultipleCandidates() const { + return HadMultipleCandidates; + } + /// \brief Sets the flag telling whether this expression refers to + /// a method that was resolved from an overloaded set having size + /// greater than 1. + void setHadMultipleCandidates(bool V = true) { + HadMultipleCandidates = V; + } + + /// \brief Returns true if virtual dispatch is performed. + /// If the member access is fully qualified, (i.e. X::f()), virtual + /// dispatching is not performed. In -fapple-kext mode qualified + /// calls to virtual method will still go through the vtable. + bool performsVirtualDispatch(const LangOptions &LO) const { + return LO.AppleKext || !hasQualifier(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == MemberExprClass; + } + + // Iterators + child_range children() { return child_range(&Base, &Base+1); } + + friend TrailingObjects; + friend class ASTReader; + friend class ASTStmtWriter; +}; + +/// CompoundLiteralExpr - [C99 6.5.2.5] +/// +class CompoundLiteralExpr : public Expr { + /// LParenLoc - If non-null, this is the location of the left paren in a + /// compound literal like "(int){4}". This can be null if this is a + /// synthesized compound expression. + SourceLocation LParenLoc; + + /// The type as written. This can be an incomplete array type, in + /// which case the actual expression type will be different. + /// The int part of the pair stores whether this expr is file scope. + llvm::PointerIntPair<TypeSourceInfo *, 1, bool> TInfoAndScope; + Stmt *Init; +public: + CompoundLiteralExpr(SourceLocation lparenloc, TypeSourceInfo *tinfo, + QualType T, ExprValueKind VK, Expr *init, bool fileScope) + : Expr(CompoundLiteralExprClass, T, VK, OK_Ordinary, + tinfo->getType()->isDependentType(), + init->isValueDependent(), + (init->isInstantiationDependent() || + tinfo->getType()->isInstantiationDependentType()), + init->containsUnexpandedParameterPack()), + LParenLoc(lparenloc), TInfoAndScope(tinfo, fileScope), Init(init) {} + + /// \brief Construct an empty compound literal. + explicit CompoundLiteralExpr(EmptyShell Empty) + : Expr(CompoundLiteralExprClass, Empty) { } + + const Expr *getInitializer() const { return cast<Expr>(Init); } + Expr *getInitializer() { return cast<Expr>(Init); } + void setInitializer(Expr *E) { Init = E; } + + bool isFileScope() const { return TInfoAndScope.getInt(); } + void setFileScope(bool FS) { TInfoAndScope.setInt(FS); } + + SourceLocation getLParenLoc() const { return LParenLoc; } + void setLParenLoc(SourceLocation L) { LParenLoc = L; } + + TypeSourceInfo *getTypeSourceInfo() const { + return TInfoAndScope.getPointer(); + } + void setTypeSourceInfo(TypeSourceInfo *tinfo) { + TInfoAndScope.setPointer(tinfo); + } + + SourceLocation getLocStart() const LLVM_READONLY { + // FIXME: Init should never be null. + if (!Init) + return SourceLocation(); + if (LParenLoc.isInvalid()) + return Init->getLocStart(); + return LParenLoc; + } + SourceLocation getLocEnd() const LLVM_READONLY { + // FIXME: Init should never be null. + if (!Init) + return SourceLocation(); + return Init->getLocEnd(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CompoundLiteralExprClass; + } + + // Iterators + child_range children() { return child_range(&Init, &Init+1); } +}; + +/// CastExpr - Base class for type casts, including both implicit +/// casts (ImplicitCastExpr) and explicit casts that have some +/// representation in the source code (ExplicitCastExpr's derived +/// classes). +class CastExpr : public Expr { +private: + Stmt *Op; + + bool CastConsistency() const; + + const CXXBaseSpecifier * const *path_buffer() const { + return const_cast<CastExpr*>(this)->path_buffer(); + } + CXXBaseSpecifier **path_buffer(); + + void setBasePathSize(unsigned basePathSize) { + CastExprBits.BasePathSize = basePathSize; + assert(CastExprBits.BasePathSize == basePathSize && + "basePathSize doesn't fit in bits of CastExprBits.BasePathSize!"); + } + +protected: + CastExpr(StmtClass SC, QualType ty, ExprValueKind VK, const CastKind kind, + Expr *op, unsigned BasePathSize) + : Expr(SC, ty, VK, OK_Ordinary, + // Cast expressions are type-dependent if the type is + // dependent (C++ [temp.dep.expr]p3). + ty->isDependentType(), + // Cast expressions are value-dependent if the type is + // dependent or if the subexpression is value-dependent. + ty->isDependentType() || (op && op->isValueDependent()), + (ty->isInstantiationDependentType() || + (op && op->isInstantiationDependent())), + // An implicit cast expression doesn't (lexically) contain an + // unexpanded pack, even if its target type does. + ((SC != ImplicitCastExprClass && + ty->containsUnexpandedParameterPack()) || + (op && op->containsUnexpandedParameterPack()))), + Op(op) { + assert(kind != CK_Invalid && "creating cast with invalid cast kind"); + CastExprBits.Kind = kind; + setBasePathSize(BasePathSize); + assert(CastConsistency()); + } + + /// \brief Construct an empty cast. + CastExpr(StmtClass SC, EmptyShell Empty, unsigned BasePathSize) + : Expr(SC, Empty) { + setBasePathSize(BasePathSize); + } + +public: + CastKind getCastKind() const { return (CastKind) CastExprBits.Kind; } + void setCastKind(CastKind K) { CastExprBits.Kind = K; } + const char *getCastKindName() const; + + Expr *getSubExpr() { return cast<Expr>(Op); } + const Expr *getSubExpr() const { return cast<Expr>(Op); } + void setSubExpr(Expr *E) { Op = E; } + + /// \brief Retrieve the cast subexpression as it was written in the source + /// code, looking through any implicit casts or other intermediate nodes + /// introduced by semantic analysis. + Expr *getSubExprAsWritten(); + const Expr *getSubExprAsWritten() const { + return const_cast<CastExpr *>(this)->getSubExprAsWritten(); + } + + typedef CXXBaseSpecifier **path_iterator; + typedef const CXXBaseSpecifier * const *path_const_iterator; + bool path_empty() const { return CastExprBits.BasePathSize == 0; } + unsigned path_size() const { return CastExprBits.BasePathSize; } + path_iterator path_begin() { return path_buffer(); } + path_iterator path_end() { return path_buffer() + path_size(); } + path_const_iterator path_begin() const { return path_buffer(); } + path_const_iterator path_end() const { return path_buffer() + path_size(); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() >= firstCastExprConstant && + T->getStmtClass() <= lastCastExprConstant; + } + + // Iterators + child_range children() { return child_range(&Op, &Op+1); } +}; + +/// ImplicitCastExpr - Allows us to explicitly represent implicit type +/// conversions, which have no direct representation in the original +/// source code. For example: converting T[]->T*, void f()->void +/// (*f)(), float->double, short->int, etc. +/// +/// In C, implicit casts always produce rvalues. However, in C++, an +/// implicit cast whose result is being bound to a reference will be +/// an lvalue or xvalue. For example: +/// +/// @code +/// class Base { }; +/// class Derived : public Base { }; +/// Derived &&ref(); +/// void f(Derived d) { +/// Base& b = d; // initializer is an ImplicitCastExpr +/// // to an lvalue of type Base +/// Base&& r = ref(); // initializer is an ImplicitCastExpr +/// // to an xvalue of type Base +/// } +/// @endcode +class ImplicitCastExpr final + : public CastExpr, + private llvm::TrailingObjects<ImplicitCastExpr, CXXBaseSpecifier *> { +private: + ImplicitCastExpr(QualType ty, CastKind kind, Expr *op, + unsigned BasePathLength, ExprValueKind VK) + : CastExpr(ImplicitCastExprClass, ty, VK, kind, op, BasePathLength) { + } + + /// \brief Construct an empty implicit cast. + explicit ImplicitCastExpr(EmptyShell Shell, unsigned PathSize) + : CastExpr(ImplicitCastExprClass, Shell, PathSize) { } + +public: + enum OnStack_t { OnStack }; + ImplicitCastExpr(OnStack_t _, QualType ty, CastKind kind, Expr *op, + ExprValueKind VK) + : CastExpr(ImplicitCastExprClass, ty, VK, kind, op, 0) { + } + + static ImplicitCastExpr *Create(const ASTContext &Context, QualType T, + CastKind Kind, Expr *Operand, + const CXXCastPath *BasePath, + ExprValueKind Cat); + + static ImplicitCastExpr *CreateEmpty(const ASTContext &Context, + unsigned PathSize); + + SourceLocation getLocStart() const LLVM_READONLY { + return getSubExpr()->getLocStart(); + } + SourceLocation getLocEnd() const LLVM_READONLY { + return getSubExpr()->getLocEnd(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ImplicitCastExprClass; + } + + friend TrailingObjects; + friend class CastExpr; +}; + +inline Expr *Expr::IgnoreImpCasts() { + Expr *e = this; + while (ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(e)) + e = ice->getSubExpr(); + return e; +} + +/// ExplicitCastExpr - An explicit cast written in the source +/// code. +/// +/// This class is effectively an abstract class, because it provides +/// the basic representation of an explicitly-written cast without +/// specifying which kind of cast (C cast, functional cast, static +/// cast, etc.) was written; specific derived classes represent the +/// particular style of cast and its location information. +/// +/// Unlike implicit casts, explicit cast nodes have two different +/// types: the type that was written into the source code, and the +/// actual type of the expression as determined by semantic +/// analysis. These types may differ slightly. For example, in C++ one +/// can cast to a reference type, which indicates that the resulting +/// expression will be an lvalue or xvalue. The reference type, however, +/// will not be used as the type of the expression. +class ExplicitCastExpr : public CastExpr { + /// TInfo - Source type info for the (written) type + /// this expression is casting to. + TypeSourceInfo *TInfo; + +protected: + ExplicitCastExpr(StmtClass SC, QualType exprTy, ExprValueKind VK, + CastKind kind, Expr *op, unsigned PathSize, + TypeSourceInfo *writtenTy) + : CastExpr(SC, exprTy, VK, kind, op, PathSize), TInfo(writtenTy) {} + + /// \brief Construct an empty explicit cast. + ExplicitCastExpr(StmtClass SC, EmptyShell Shell, unsigned PathSize) + : CastExpr(SC, Shell, PathSize) { } + +public: + /// getTypeInfoAsWritten - Returns the type source info for the type + /// that this expression is casting to. + TypeSourceInfo *getTypeInfoAsWritten() const { return TInfo; } + void setTypeInfoAsWritten(TypeSourceInfo *writtenTy) { TInfo = writtenTy; } + + /// getTypeAsWritten - Returns the type that this expression is + /// casting to, as written in the source code. + QualType getTypeAsWritten() const { return TInfo->getType(); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() >= firstExplicitCastExprConstant && + T->getStmtClass() <= lastExplicitCastExprConstant; + } +}; + +/// CStyleCastExpr - An explicit cast in C (C99 6.5.4) or a C-style +/// cast in C++ (C++ [expr.cast]), which uses the syntax +/// (Type)expr. For example: @c (int)f. +class CStyleCastExpr final + : public ExplicitCastExpr, + private llvm::TrailingObjects<CStyleCastExpr, CXXBaseSpecifier *> { + SourceLocation LPLoc; // the location of the left paren + SourceLocation RPLoc; // the location of the right paren + + CStyleCastExpr(QualType exprTy, ExprValueKind vk, CastKind kind, Expr *op, + unsigned PathSize, TypeSourceInfo *writtenTy, + SourceLocation l, SourceLocation r) + : ExplicitCastExpr(CStyleCastExprClass, exprTy, vk, kind, op, PathSize, + writtenTy), LPLoc(l), RPLoc(r) {} + + /// \brief Construct an empty C-style explicit cast. + explicit CStyleCastExpr(EmptyShell Shell, unsigned PathSize) + : ExplicitCastExpr(CStyleCastExprClass, Shell, PathSize) { } + +public: + static CStyleCastExpr *Create(const ASTContext &Context, QualType T, + ExprValueKind VK, CastKind K, + Expr *Op, const CXXCastPath *BasePath, + TypeSourceInfo *WrittenTy, SourceLocation L, + SourceLocation R); + + static CStyleCastExpr *CreateEmpty(const ASTContext &Context, + unsigned PathSize); + + SourceLocation getLParenLoc() const { return LPLoc; } + void setLParenLoc(SourceLocation L) { LPLoc = L; } + + SourceLocation getRParenLoc() const { return RPLoc; } + void setRParenLoc(SourceLocation L) { RPLoc = L; } + + SourceLocation getLocStart() const LLVM_READONLY { return LPLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { + return getSubExpr()->getLocEnd(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CStyleCastExprClass; + } + + friend TrailingObjects; + friend class CastExpr; +}; + +/// \brief A builtin binary operation expression such as "x + y" or "x <= y". +/// +/// This expression node kind describes a builtin binary operation, +/// such as "x + y" for integer values "x" and "y". The operands will +/// already have been converted to appropriate types (e.g., by +/// performing promotions or conversions). +/// +/// In C++, where operators may be overloaded, a different kind of +/// expression node (CXXOperatorCallExpr) is used to express the +/// invocation of an overloaded operator with operator syntax. Within +/// a C++ template, whether BinaryOperator or CXXOperatorCallExpr is +/// used to store an expression "x + y" depends on the subexpressions +/// for x and y. If neither x or y is type-dependent, and the "+" +/// operator resolves to a built-in operation, BinaryOperator will be +/// used to express the computation (x and y may still be +/// value-dependent). If either x or y is type-dependent, or if the +/// "+" resolves to an overloaded operator, CXXOperatorCallExpr will +/// be used to express the computation. +class BinaryOperator : public Expr { +public: + typedef BinaryOperatorKind Opcode; + +private: + unsigned Opc : 6; + + // Records the FP_CONTRACT pragma status at the point that this binary + // operator was parsed. This bit is only meaningful for operations on + // floating point types. For all other types it should default to + // false. + unsigned FPContractable : 1; + SourceLocation OpLoc; + + enum { LHS, RHS, END_EXPR }; + Stmt* SubExprs[END_EXPR]; +public: + + BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, + ExprValueKind VK, ExprObjectKind OK, + SourceLocation opLoc, bool fpContractable) + : Expr(BinaryOperatorClass, ResTy, VK, OK, + lhs->isTypeDependent() || rhs->isTypeDependent(), + lhs->isValueDependent() || rhs->isValueDependent(), + (lhs->isInstantiationDependent() || + rhs->isInstantiationDependent()), + (lhs->containsUnexpandedParameterPack() || + rhs->containsUnexpandedParameterPack())), + Opc(opc), FPContractable(fpContractable), OpLoc(opLoc) { + SubExprs[LHS] = lhs; + SubExprs[RHS] = rhs; + assert(!isCompoundAssignmentOp() && + "Use CompoundAssignOperator for compound assignments"); + } + + /// \brief Construct an empty binary operator. + explicit BinaryOperator(EmptyShell Empty) + : Expr(BinaryOperatorClass, Empty), Opc(BO_Comma) { } + + SourceLocation getExprLoc() const LLVM_READONLY { return OpLoc; } + SourceLocation getOperatorLoc() const { return OpLoc; } + void setOperatorLoc(SourceLocation L) { OpLoc = L; } + + Opcode getOpcode() const { return static_cast<Opcode>(Opc); } + void setOpcode(Opcode O) { Opc = O; } + + Expr *getLHS() const { return cast<Expr>(SubExprs[LHS]); } + void setLHS(Expr *E) { SubExprs[LHS] = E; } + Expr *getRHS() const { return cast<Expr>(SubExprs[RHS]); } + void setRHS(Expr *E) { SubExprs[RHS] = E; } + + SourceLocation getLocStart() const LLVM_READONLY { + return getLHS()->getLocStart(); + } + SourceLocation getLocEnd() const LLVM_READONLY { + return getRHS()->getLocEnd(); + } + + /// getOpcodeStr - Turn an Opcode enum value into the punctuation char it + /// corresponds to, e.g. "<<=". + static StringRef getOpcodeStr(Opcode Op); + + StringRef getOpcodeStr() const { return getOpcodeStr(getOpcode()); } + + /// \brief Retrieve the binary opcode that corresponds to the given + /// overloaded operator. + static Opcode getOverloadedOpcode(OverloadedOperatorKind OO); + + /// \brief Retrieve the overloaded operator kind that corresponds to + /// the given binary opcode. + static OverloadedOperatorKind getOverloadedOperator(Opcode Opc); + + /// predicates to categorize the respective opcodes. + bool isPtrMemOp() const { return Opc == BO_PtrMemD || Opc == BO_PtrMemI; } + static bool isMultiplicativeOp(Opcode Opc) { + return Opc >= BO_Mul && Opc <= BO_Rem; + } + bool isMultiplicativeOp() const { return isMultiplicativeOp(getOpcode()); } + static bool isAdditiveOp(Opcode Opc) { return Opc == BO_Add || Opc==BO_Sub; } + bool isAdditiveOp() const { return isAdditiveOp(getOpcode()); } + static bool isShiftOp(Opcode Opc) { return Opc == BO_Shl || Opc == BO_Shr; } + bool isShiftOp() const { return isShiftOp(getOpcode()); } + + static bool isBitwiseOp(Opcode Opc) { return Opc >= BO_And && Opc <= BO_Or; } + bool isBitwiseOp() const { return isBitwiseOp(getOpcode()); } + + static bool isRelationalOp(Opcode Opc) { return Opc >= BO_LT && Opc<=BO_GE; } + bool isRelationalOp() const { return isRelationalOp(getOpcode()); } + + static bool isEqualityOp(Opcode Opc) { return Opc == BO_EQ || Opc == BO_NE; } + bool isEqualityOp() const { return isEqualityOp(getOpcode()); } + + static bool isComparisonOp(Opcode Opc) { return Opc >= BO_LT && Opc<=BO_NE; } + bool isComparisonOp() const { return isComparisonOp(getOpcode()); } + + static Opcode negateComparisonOp(Opcode Opc) { + switch (Opc) { + default: + llvm_unreachable("Not a comparsion operator."); + case BO_LT: return BO_GE; + case BO_GT: return BO_LE; + case BO_LE: return BO_GT; + case BO_GE: return BO_LT; + case BO_EQ: return BO_NE; + case BO_NE: return BO_EQ; + } + } + + static Opcode reverseComparisonOp(Opcode Opc) { + switch (Opc) { + default: + llvm_unreachable("Not a comparsion operator."); + case BO_LT: return BO_GT; + case BO_GT: return BO_LT; + case BO_LE: return BO_GE; + case BO_GE: return BO_LE; + case BO_EQ: + case BO_NE: + return Opc; + } + } + + static bool isLogicalOp(Opcode Opc) { return Opc == BO_LAnd || Opc==BO_LOr; } + bool isLogicalOp() const { return isLogicalOp(getOpcode()); } + + static bool isAssignmentOp(Opcode Opc) { + return Opc >= BO_Assign && Opc <= BO_OrAssign; + } + bool isAssignmentOp() const { return isAssignmentOp(getOpcode()); } + + static bool isCompoundAssignmentOp(Opcode Opc) { + return Opc > BO_Assign && Opc <= BO_OrAssign; + } + bool isCompoundAssignmentOp() const { + return isCompoundAssignmentOp(getOpcode()); + } + static Opcode getOpForCompoundAssignment(Opcode Opc) { + assert(isCompoundAssignmentOp(Opc)); + if (Opc >= BO_AndAssign) + return Opcode(unsigned(Opc) - BO_AndAssign + BO_And); + else + return Opcode(unsigned(Opc) - BO_MulAssign + BO_Mul); + } + + static bool isShiftAssignOp(Opcode Opc) { + return Opc == BO_ShlAssign || Opc == BO_ShrAssign; + } + bool isShiftAssignOp() const { + return isShiftAssignOp(getOpcode()); + } + + static bool classof(const Stmt *S) { + return S->getStmtClass() >= firstBinaryOperatorConstant && + S->getStmtClass() <= lastBinaryOperatorConstant; + } + + // Iterators + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); + } + + // Set the FP contractability status of this operator. Only meaningful for + // operations on floating point types. + void setFPContractable(bool FPC) { FPContractable = FPC; } + + // Get the FP contractability status of this operator. Only meaningful for + // operations on floating point types. + bool isFPContractable() const { return FPContractable; } + +protected: + BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, + ExprValueKind VK, ExprObjectKind OK, + SourceLocation opLoc, bool fpContractable, bool dead2) + : Expr(CompoundAssignOperatorClass, ResTy, VK, OK, + lhs->isTypeDependent() || rhs->isTypeDependent(), + lhs->isValueDependent() || rhs->isValueDependent(), + (lhs->isInstantiationDependent() || + rhs->isInstantiationDependent()), + (lhs->containsUnexpandedParameterPack() || + rhs->containsUnexpandedParameterPack())), + Opc(opc), FPContractable(fpContractable), OpLoc(opLoc) { + SubExprs[LHS] = lhs; + SubExprs[RHS] = rhs; + } + + BinaryOperator(StmtClass SC, EmptyShell Empty) + : Expr(SC, Empty), Opc(BO_MulAssign) { } +}; + +/// CompoundAssignOperator - For compound assignments (e.g. +=), we keep +/// track of the type the operation is performed in. Due to the semantics of +/// these operators, the operands are promoted, the arithmetic performed, an +/// implicit conversion back to the result type done, then the assignment takes +/// place. This captures the intermediate type which the computation is done +/// in. +class CompoundAssignOperator : public BinaryOperator { + QualType ComputationLHSType; + QualType ComputationResultType; +public: + CompoundAssignOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResType, + ExprValueKind VK, ExprObjectKind OK, + QualType CompLHSType, QualType CompResultType, + SourceLocation OpLoc, bool fpContractable) + : BinaryOperator(lhs, rhs, opc, ResType, VK, OK, OpLoc, fpContractable, + true), + ComputationLHSType(CompLHSType), + ComputationResultType(CompResultType) { + assert(isCompoundAssignmentOp() && + "Only should be used for compound assignments"); + } + + /// \brief Build an empty compound assignment operator expression. + explicit CompoundAssignOperator(EmptyShell Empty) + : BinaryOperator(CompoundAssignOperatorClass, Empty) { } + + // The two computation types are the type the LHS is converted + // to for the computation and the type of the result; the two are + // distinct in a few cases (specifically, int+=ptr and ptr-=ptr). + QualType getComputationLHSType() const { return ComputationLHSType; } + void setComputationLHSType(QualType T) { ComputationLHSType = T; } + + QualType getComputationResultType() const { return ComputationResultType; } + void setComputationResultType(QualType T) { ComputationResultType = T; } + + static bool classof(const Stmt *S) { + return S->getStmtClass() == CompoundAssignOperatorClass; + } +}; + +/// AbstractConditionalOperator - An abstract base class for +/// ConditionalOperator and BinaryConditionalOperator. +class AbstractConditionalOperator : public Expr { + SourceLocation QuestionLoc, ColonLoc; + friend class ASTStmtReader; + +protected: + AbstractConditionalOperator(StmtClass SC, QualType T, + ExprValueKind VK, ExprObjectKind OK, + bool TD, bool VD, bool ID, + bool ContainsUnexpandedParameterPack, + SourceLocation qloc, + SourceLocation cloc) + : Expr(SC, T, VK, OK, TD, VD, ID, ContainsUnexpandedParameterPack), + QuestionLoc(qloc), ColonLoc(cloc) {} + + AbstractConditionalOperator(StmtClass SC, EmptyShell Empty) + : Expr(SC, Empty) { } + +public: + // getCond - Return the expression representing the condition for + // the ?: operator. + Expr *getCond() const; + + // getTrueExpr - Return the subexpression representing the value of + // the expression if the condition evaluates to true. + Expr *getTrueExpr() const; + + // getFalseExpr - Return the subexpression representing the value of + // the expression if the condition evaluates to false. This is + // the same as getRHS. + Expr *getFalseExpr() const; + + SourceLocation getQuestionLoc() const { return QuestionLoc; } + SourceLocation getColonLoc() const { return ColonLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ConditionalOperatorClass || + T->getStmtClass() == BinaryConditionalOperatorClass; + } +}; + +/// ConditionalOperator - The ?: ternary operator. The GNU "missing +/// middle" extension is a BinaryConditionalOperator. +class ConditionalOperator : public AbstractConditionalOperator { + enum { COND, LHS, RHS, END_EXPR }; + Stmt* SubExprs[END_EXPR]; // Left/Middle/Right hand sides. + + friend class ASTStmtReader; +public: + ConditionalOperator(Expr *cond, SourceLocation QLoc, Expr *lhs, + SourceLocation CLoc, Expr *rhs, + QualType t, ExprValueKind VK, ExprObjectKind OK) + : AbstractConditionalOperator(ConditionalOperatorClass, t, VK, OK, + // FIXME: the type of the conditional operator doesn't + // depend on the type of the conditional, but the standard + // seems to imply that it could. File a bug! + (lhs->isTypeDependent() || rhs->isTypeDependent()), + (cond->isValueDependent() || lhs->isValueDependent() || + rhs->isValueDependent()), + (cond->isInstantiationDependent() || + lhs->isInstantiationDependent() || + rhs->isInstantiationDependent()), + (cond->containsUnexpandedParameterPack() || + lhs->containsUnexpandedParameterPack() || + rhs->containsUnexpandedParameterPack()), + QLoc, CLoc) { + SubExprs[COND] = cond; + SubExprs[LHS] = lhs; + SubExprs[RHS] = rhs; + } + + /// \brief Build an empty conditional operator. + explicit ConditionalOperator(EmptyShell Empty) + : AbstractConditionalOperator(ConditionalOperatorClass, Empty) { } + + // getCond - Return the expression representing the condition for + // the ?: operator. + Expr *getCond() const { return cast<Expr>(SubExprs[COND]); } + + // getTrueExpr - Return the subexpression representing the value of + // the expression if the condition evaluates to true. + Expr *getTrueExpr() const { return cast<Expr>(SubExprs[LHS]); } + + // getFalseExpr - Return the subexpression representing the value of + // the expression if the condition evaluates to false. This is + // the same as getRHS. + Expr *getFalseExpr() const { return cast<Expr>(SubExprs[RHS]); } + + Expr *getLHS() const { return cast<Expr>(SubExprs[LHS]); } + Expr *getRHS() const { return cast<Expr>(SubExprs[RHS]); } + + SourceLocation getLocStart() const LLVM_READONLY { + return getCond()->getLocStart(); + } + SourceLocation getLocEnd() const LLVM_READONLY { + return getRHS()->getLocEnd(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ConditionalOperatorClass; + } + + // Iterators + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); + } +}; + +/// BinaryConditionalOperator - The GNU extension to the conditional +/// operator which allows the middle operand to be omitted. +/// +/// This is a different expression kind on the assumption that almost +/// every client ends up needing to know that these are different. +class BinaryConditionalOperator : public AbstractConditionalOperator { + enum { COMMON, COND, LHS, RHS, NUM_SUBEXPRS }; + + /// - the common condition/left-hand-side expression, which will be + /// evaluated as the opaque value + /// - the condition, expressed in terms of the opaque value + /// - the left-hand-side, expressed in terms of the opaque value + /// - the right-hand-side + Stmt *SubExprs[NUM_SUBEXPRS]; + OpaqueValueExpr *OpaqueValue; + + friend class ASTStmtReader; +public: + BinaryConditionalOperator(Expr *common, OpaqueValueExpr *opaqueValue, + Expr *cond, Expr *lhs, Expr *rhs, + SourceLocation qloc, SourceLocation cloc, + QualType t, ExprValueKind VK, ExprObjectKind OK) + : AbstractConditionalOperator(BinaryConditionalOperatorClass, t, VK, OK, + (common->isTypeDependent() || rhs->isTypeDependent()), + (common->isValueDependent() || rhs->isValueDependent()), + (common->isInstantiationDependent() || + rhs->isInstantiationDependent()), + (common->containsUnexpandedParameterPack() || + rhs->containsUnexpandedParameterPack()), + qloc, cloc), + OpaqueValue(opaqueValue) { + SubExprs[COMMON] = common; + SubExprs[COND] = cond; + SubExprs[LHS] = lhs; + SubExprs[RHS] = rhs; + assert(OpaqueValue->getSourceExpr() == common && "Wrong opaque value"); + } + + /// \brief Build an empty conditional operator. + explicit BinaryConditionalOperator(EmptyShell Empty) + : AbstractConditionalOperator(BinaryConditionalOperatorClass, Empty) { } + + /// \brief getCommon - Return the common expression, written to the + /// left of the condition. The opaque value will be bound to the + /// result of this expression. + Expr *getCommon() const { return cast<Expr>(SubExprs[COMMON]); } + + /// \brief getOpaqueValue - Return the opaque value placeholder. + OpaqueValueExpr *getOpaqueValue() const { return OpaqueValue; } + + /// \brief getCond - Return the condition expression; this is defined + /// in terms of the opaque value. + Expr *getCond() const { return cast<Expr>(SubExprs[COND]); } + + /// \brief getTrueExpr - Return the subexpression which will be + /// evaluated if the condition evaluates to true; this is defined + /// in terms of the opaque value. + Expr *getTrueExpr() const { + return cast<Expr>(SubExprs[LHS]); + } + + /// \brief getFalseExpr - Return the subexpression which will be + /// evaluated if the condnition evaluates to false; this is + /// defined in terms of the opaque value. + Expr *getFalseExpr() const { + return cast<Expr>(SubExprs[RHS]); + } + + SourceLocation getLocStart() const LLVM_READONLY { + return getCommon()->getLocStart(); + } + SourceLocation getLocEnd() const LLVM_READONLY { + return getFalseExpr()->getLocEnd(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == BinaryConditionalOperatorClass; + } + + // Iterators + child_range children() { + return child_range(SubExprs, SubExprs + NUM_SUBEXPRS); + } +}; + +inline Expr *AbstractConditionalOperator::getCond() const { + if (const ConditionalOperator *co = dyn_cast<ConditionalOperator>(this)) + return co->getCond(); + return cast<BinaryConditionalOperator>(this)->getCond(); +} + +inline Expr *AbstractConditionalOperator::getTrueExpr() const { + if (const ConditionalOperator *co = dyn_cast<ConditionalOperator>(this)) + return co->getTrueExpr(); + return cast<BinaryConditionalOperator>(this)->getTrueExpr(); +} + +inline Expr *AbstractConditionalOperator::getFalseExpr() const { + if (const ConditionalOperator *co = dyn_cast<ConditionalOperator>(this)) + return co->getFalseExpr(); + return cast<BinaryConditionalOperator>(this)->getFalseExpr(); +} + +/// AddrLabelExpr - The GNU address of label extension, representing &&label. +class AddrLabelExpr : public Expr { + SourceLocation AmpAmpLoc, LabelLoc; + LabelDecl *Label; +public: + AddrLabelExpr(SourceLocation AALoc, SourceLocation LLoc, LabelDecl *L, + QualType t) + : Expr(AddrLabelExprClass, t, VK_RValue, OK_Ordinary, false, false, false, + false), + AmpAmpLoc(AALoc), LabelLoc(LLoc), Label(L) {} + + /// \brief Build an empty address of a label expression. + explicit AddrLabelExpr(EmptyShell Empty) + : Expr(AddrLabelExprClass, Empty) { } + + SourceLocation getAmpAmpLoc() const { return AmpAmpLoc; } + void setAmpAmpLoc(SourceLocation L) { AmpAmpLoc = L; } + SourceLocation getLabelLoc() const { return LabelLoc; } + void setLabelLoc(SourceLocation L) { LabelLoc = L; } + + SourceLocation getLocStart() const LLVM_READONLY { return AmpAmpLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return LabelLoc; } + + LabelDecl *getLabel() const { return Label; } + void setLabel(LabelDecl *L) { Label = L; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == AddrLabelExprClass; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +/// StmtExpr - This is the GNU Statement Expression extension: ({int X=4; X;}). +/// The StmtExpr contains a single CompoundStmt node, which it evaluates and +/// takes the value of the last subexpression. +/// +/// A StmtExpr is always an r-value; values "returned" out of a +/// StmtExpr will be copied. +class StmtExpr : public Expr { + Stmt *SubStmt; + SourceLocation LParenLoc, RParenLoc; +public: + // FIXME: Does type-dependence need to be computed differently? + // FIXME: Do we need to compute instantiation instantiation-dependence for + // statements? (ugh!) + StmtExpr(CompoundStmt *substmt, QualType T, + SourceLocation lp, SourceLocation rp) : + Expr(StmtExprClass, T, VK_RValue, OK_Ordinary, + T->isDependentType(), false, false, false), + SubStmt(substmt), LParenLoc(lp), RParenLoc(rp) { } + + /// \brief Build an empty statement expression. + explicit StmtExpr(EmptyShell Empty) : Expr(StmtExprClass, Empty) { } + + CompoundStmt *getSubStmt() { return cast<CompoundStmt>(SubStmt); } + const CompoundStmt *getSubStmt() const { return cast<CompoundStmt>(SubStmt); } + void setSubStmt(CompoundStmt *S) { SubStmt = S; } + + SourceLocation getLocStart() const LLVM_READONLY { return LParenLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + + SourceLocation getLParenLoc() const { return LParenLoc; } + void setLParenLoc(SourceLocation L) { LParenLoc = L; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == StmtExprClass; + } + + // Iterators + child_range children() { return child_range(&SubStmt, &SubStmt+1); } +}; + +/// ShuffleVectorExpr - clang-specific builtin-in function +/// __builtin_shufflevector. +/// This AST node represents a operator that does a constant +/// shuffle, similar to LLVM's shufflevector instruction. It takes +/// two vectors and a variable number of constant indices, +/// and returns the appropriately shuffled vector. +class ShuffleVectorExpr : public Expr { + SourceLocation BuiltinLoc, RParenLoc; + + // SubExprs - the list of values passed to the __builtin_shufflevector + // function. The first two are vectors, and the rest are constant + // indices. The number of values in this list is always + // 2+the number of indices in the vector type. + Stmt **SubExprs; + unsigned NumExprs; + +public: + ShuffleVectorExpr(const ASTContext &C, ArrayRef<Expr*> args, QualType Type, + SourceLocation BLoc, SourceLocation RP); + + /// \brief Build an empty vector-shuffle expression. + explicit ShuffleVectorExpr(EmptyShell Empty) + : Expr(ShuffleVectorExprClass, Empty), SubExprs(nullptr) { } + + SourceLocation getBuiltinLoc() const { return BuiltinLoc; } + void setBuiltinLoc(SourceLocation L) { BuiltinLoc = L; } + + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + SourceLocation getLocStart() const LLVM_READONLY { return BuiltinLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ShuffleVectorExprClass; + } + + /// getNumSubExprs - Return the size of the SubExprs array. This includes the + /// constant expression, the actual arguments passed in, and the function + /// pointers. + unsigned getNumSubExprs() const { return NumExprs; } + + /// \brief Retrieve the array of expressions. + Expr **getSubExprs() { return reinterpret_cast<Expr **>(SubExprs); } + + /// getExpr - Return the Expr at the specified index. + Expr *getExpr(unsigned Index) { + assert((Index < NumExprs) && "Arg access out of range!"); + return cast<Expr>(SubExprs[Index]); + } + const Expr *getExpr(unsigned Index) const { + assert((Index < NumExprs) && "Arg access out of range!"); + return cast<Expr>(SubExprs[Index]); + } + + void setExprs(const ASTContext &C, ArrayRef<Expr *> Exprs); + + llvm::APSInt getShuffleMaskIdx(const ASTContext &Ctx, unsigned N) const { + assert((N < NumExprs - 2) && "Shuffle idx out of range!"); + return getExpr(N+2)->EvaluateKnownConstInt(Ctx); + } + + // Iterators + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0]+NumExprs); + } +}; + +/// ConvertVectorExpr - Clang builtin function __builtin_convertvector +/// This AST node provides support for converting a vector type to another +/// vector type of the same arity. +class ConvertVectorExpr : public Expr { +private: + Stmt *SrcExpr; + TypeSourceInfo *TInfo; + SourceLocation BuiltinLoc, RParenLoc; + + friend class ASTReader; + friend class ASTStmtReader; + explicit ConvertVectorExpr(EmptyShell Empty) : Expr(ConvertVectorExprClass, Empty) {} + +public: + ConvertVectorExpr(Expr* SrcExpr, TypeSourceInfo *TI, QualType DstType, + ExprValueKind VK, ExprObjectKind OK, + SourceLocation BuiltinLoc, SourceLocation RParenLoc) + : Expr(ConvertVectorExprClass, DstType, VK, OK, + DstType->isDependentType(), + DstType->isDependentType() || SrcExpr->isValueDependent(), + (DstType->isInstantiationDependentType() || + SrcExpr->isInstantiationDependent()), + (DstType->containsUnexpandedParameterPack() || + SrcExpr->containsUnexpandedParameterPack())), + SrcExpr(SrcExpr), TInfo(TI), BuiltinLoc(BuiltinLoc), RParenLoc(RParenLoc) {} + + /// getSrcExpr - Return the Expr to be converted. + Expr *getSrcExpr() const { return cast<Expr>(SrcExpr); } + + /// getTypeSourceInfo - Return the destination type. + TypeSourceInfo *getTypeSourceInfo() const { + return TInfo; + } + void setTypeSourceInfo(TypeSourceInfo *ti) { + TInfo = ti; + } + + /// getBuiltinLoc - Return the location of the __builtin_convertvector token. + SourceLocation getBuiltinLoc() const { return BuiltinLoc; } + + /// getRParenLoc - Return the location of final right parenthesis. + SourceLocation getRParenLoc() const { return RParenLoc; } + + SourceLocation getLocStart() const LLVM_READONLY { return BuiltinLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ConvertVectorExprClass; + } + + // Iterators + child_range children() { return child_range(&SrcExpr, &SrcExpr+1); } +}; + +/// ChooseExpr - GNU builtin-in function __builtin_choose_expr. +/// This AST node is similar to the conditional operator (?:) in C, with +/// the following exceptions: +/// - the test expression must be a integer constant expression. +/// - the expression returned acts like the chosen subexpression in every +/// visible way: the type is the same as that of the chosen subexpression, +/// and all predicates (whether it's an l-value, whether it's an integer +/// constant expression, etc.) return the same result as for the chosen +/// sub-expression. +class ChooseExpr : public Expr { + enum { COND, LHS, RHS, END_EXPR }; + Stmt* SubExprs[END_EXPR]; // Left/Middle/Right hand sides. + SourceLocation BuiltinLoc, RParenLoc; + bool CondIsTrue; +public: + ChooseExpr(SourceLocation BLoc, Expr *cond, Expr *lhs, Expr *rhs, + QualType t, ExprValueKind VK, ExprObjectKind OK, + SourceLocation RP, bool condIsTrue, + bool TypeDependent, bool ValueDependent) + : Expr(ChooseExprClass, t, VK, OK, TypeDependent, ValueDependent, + (cond->isInstantiationDependent() || + lhs->isInstantiationDependent() || + rhs->isInstantiationDependent()), + (cond->containsUnexpandedParameterPack() || + lhs->containsUnexpandedParameterPack() || + rhs->containsUnexpandedParameterPack())), + BuiltinLoc(BLoc), RParenLoc(RP), CondIsTrue(condIsTrue) { + SubExprs[COND] = cond; + SubExprs[LHS] = lhs; + SubExprs[RHS] = rhs; + } + + /// \brief Build an empty __builtin_choose_expr. + explicit ChooseExpr(EmptyShell Empty) : Expr(ChooseExprClass, Empty) { } + + /// isConditionTrue - Return whether the condition is true (i.e. not + /// equal to zero). + bool isConditionTrue() const { + assert(!isConditionDependent() && + "Dependent condition isn't true or false"); + return CondIsTrue; + } + void setIsConditionTrue(bool isTrue) { CondIsTrue = isTrue; } + + bool isConditionDependent() const { + return getCond()->isTypeDependent() || getCond()->isValueDependent(); + } + + /// getChosenSubExpr - Return the subexpression chosen according to the + /// condition. + Expr *getChosenSubExpr() const { + return isConditionTrue() ? getLHS() : getRHS(); + } + + Expr *getCond() const { return cast<Expr>(SubExprs[COND]); } + void setCond(Expr *E) { SubExprs[COND] = E; } + Expr *getLHS() const { return cast<Expr>(SubExprs[LHS]); } + void setLHS(Expr *E) { SubExprs[LHS] = E; } + Expr *getRHS() const { return cast<Expr>(SubExprs[RHS]); } + void setRHS(Expr *E) { SubExprs[RHS] = E; } + + SourceLocation getBuiltinLoc() const { return BuiltinLoc; } + void setBuiltinLoc(SourceLocation L) { BuiltinLoc = L; } + + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + SourceLocation getLocStart() const LLVM_READONLY { return BuiltinLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ChooseExprClass; + } + + // Iterators + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); + } +}; + +/// GNUNullExpr - Implements the GNU __null extension, which is a name +/// for a null pointer constant that has integral type (e.g., int or +/// long) and is the same size and alignment as a pointer. The __null +/// extension is typically only used by system headers, which define +/// NULL as __null in C++ rather than using 0 (which is an integer +/// that may not match the size of a pointer). +class GNUNullExpr : public Expr { + /// TokenLoc - The location of the __null keyword. + SourceLocation TokenLoc; + +public: + GNUNullExpr(QualType Ty, SourceLocation Loc) + : Expr(GNUNullExprClass, Ty, VK_RValue, OK_Ordinary, false, false, false, + false), + TokenLoc(Loc) { } + + /// \brief Build an empty GNU __null expression. + explicit GNUNullExpr(EmptyShell Empty) : Expr(GNUNullExprClass, Empty) { } + + /// getTokenLocation - The location of the __null token. + SourceLocation getTokenLocation() const { return TokenLoc; } + void setTokenLocation(SourceLocation L) { TokenLoc = L; } + + SourceLocation getLocStart() const LLVM_READONLY { return TokenLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return TokenLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == GNUNullExprClass; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +/// Represents a call to the builtin function \c __builtin_va_arg. +class VAArgExpr : public Expr { + Stmt *Val; + llvm::PointerIntPair<TypeSourceInfo *, 1, bool> TInfo; + SourceLocation BuiltinLoc, RParenLoc; +public: + VAArgExpr(SourceLocation BLoc, Expr *e, TypeSourceInfo *TInfo, + SourceLocation RPLoc, QualType t, bool IsMS) + : Expr(VAArgExprClass, t, VK_RValue, OK_Ordinary, t->isDependentType(), + false, (TInfo->getType()->isInstantiationDependentType() || + e->isInstantiationDependent()), + (TInfo->getType()->containsUnexpandedParameterPack() || + e->containsUnexpandedParameterPack())), + Val(e), TInfo(TInfo, IsMS), BuiltinLoc(BLoc), RParenLoc(RPLoc) {} + + /// Create an empty __builtin_va_arg expression. + explicit VAArgExpr(EmptyShell Empty) + : Expr(VAArgExprClass, Empty), Val(nullptr), TInfo(nullptr, false) {} + + const Expr *getSubExpr() const { return cast<Expr>(Val); } + Expr *getSubExpr() { return cast<Expr>(Val); } + void setSubExpr(Expr *E) { Val = E; } + + /// Returns whether this is really a Win64 ABI va_arg expression. + bool isMicrosoftABI() const { return TInfo.getInt(); } + void setIsMicrosoftABI(bool IsMS) { TInfo.setInt(IsMS); } + + TypeSourceInfo *getWrittenTypeInfo() const { return TInfo.getPointer(); } + void setWrittenTypeInfo(TypeSourceInfo *TI) { TInfo.setPointer(TI); } + + SourceLocation getBuiltinLoc() const { return BuiltinLoc; } + void setBuiltinLoc(SourceLocation L) { BuiltinLoc = L; } + + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + SourceLocation getLocStart() const LLVM_READONLY { return BuiltinLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == VAArgExprClass; + } + + // Iterators + child_range children() { return child_range(&Val, &Val+1); } +}; + +/// @brief Describes an C or C++ initializer list. +/// +/// InitListExpr describes an initializer list, which can be used to +/// initialize objects of different types, including +/// struct/class/union types, arrays, and vectors. For example: +/// +/// @code +/// struct foo x = { 1, { 2, 3 } }; +/// @endcode +/// +/// Prior to semantic analysis, an initializer list will represent the +/// initializer list as written by the user, but will have the +/// placeholder type "void". This initializer list is called the +/// syntactic form of the initializer, and may contain C99 designated +/// initializers (represented as DesignatedInitExprs), initializations +/// of subobject members without explicit braces, and so on. Clients +/// interested in the original syntax of the initializer list should +/// use the syntactic form of the initializer list. +/// +/// After semantic analysis, the initializer list will represent the +/// semantic form of the initializer, where the initializations of all +/// subobjects are made explicit with nested InitListExpr nodes and +/// C99 designators have been eliminated by placing the designated +/// initializations into the subobject they initialize. Additionally, +/// any "holes" in the initialization, where no initializer has been +/// specified for a particular subobject, will be replaced with +/// implicitly-generated ImplicitValueInitExpr expressions that +/// value-initialize the subobjects. Note, however, that the +/// initializer lists may still have fewer initializers than there are +/// elements to initialize within the object. +/// +/// After semantic analysis has completed, given an initializer list, +/// method isSemanticForm() returns true if and only if this is the +/// semantic form of the initializer list (note: the same AST node +/// may at the same time be the syntactic form). +/// Given the semantic form of the initializer list, one can retrieve +/// the syntactic form of that initializer list (when different) +/// using method getSyntacticForm(); the method returns null if applied +/// to a initializer list which is already in syntactic form. +/// Similarly, given the syntactic form (i.e., an initializer list such +/// that isSemanticForm() returns false), one can retrieve the semantic +/// form using method getSemanticForm(). +/// Since many initializer lists have the same syntactic and semantic forms, +/// getSyntacticForm() may return NULL, indicating that the current +/// semantic initializer list also serves as its syntactic form. +class InitListExpr : public Expr { + // FIXME: Eliminate this vector in favor of ASTContext allocation + typedef ASTVector<Stmt *> InitExprsTy; + InitExprsTy InitExprs; + SourceLocation LBraceLoc, RBraceLoc; + + /// The alternative form of the initializer list (if it exists). + /// The int part of the pair stores whether this initializer list is + /// in semantic form. If not null, the pointer points to: + /// - the syntactic form, if this is in semantic form; + /// - the semantic form, if this is in syntactic form. + llvm::PointerIntPair<InitListExpr *, 1, bool> AltForm; + + /// \brief Either: + /// If this initializer list initializes an array with more elements than + /// there are initializers in the list, specifies an expression to be used + /// for value initialization of the rest of the elements. + /// Or + /// If this initializer list initializes a union, specifies which + /// field within the union will be initialized. + llvm::PointerUnion<Expr *, FieldDecl *> ArrayFillerOrUnionFieldInit; + +public: + InitListExpr(const ASTContext &C, SourceLocation lbraceloc, + ArrayRef<Expr*> initExprs, SourceLocation rbraceloc); + + /// \brief Build an empty initializer list. + explicit InitListExpr(EmptyShell Empty) + : Expr(InitListExprClass, Empty) { } + + unsigned getNumInits() const { return InitExprs.size(); } + + /// \brief Retrieve the set of initializers. + Expr **getInits() { return reinterpret_cast<Expr **>(InitExprs.data()); } + + ArrayRef<Expr *> inits() { + return llvm::makeArrayRef(getInits(), getNumInits()); + } + + const Expr *getInit(unsigned Init) const { + assert(Init < getNumInits() && "Initializer access out of range!"); + return cast_or_null<Expr>(InitExprs[Init]); + } + + Expr *getInit(unsigned Init) { + assert(Init < getNumInits() && "Initializer access out of range!"); + return cast_or_null<Expr>(InitExprs[Init]); + } + + void setInit(unsigned Init, Expr *expr) { + assert(Init < getNumInits() && "Initializer access out of range!"); + InitExprs[Init] = expr; + + if (expr) { + ExprBits.TypeDependent |= expr->isTypeDependent(); + ExprBits.ValueDependent |= expr->isValueDependent(); + ExprBits.InstantiationDependent |= expr->isInstantiationDependent(); + ExprBits.ContainsUnexpandedParameterPack |= + expr->containsUnexpandedParameterPack(); + } + } + + /// \brief Reserve space for some number of initializers. + void reserveInits(const ASTContext &C, unsigned NumInits); + + /// @brief Specify the number of initializers + /// + /// If there are more than @p NumInits initializers, the remaining + /// initializers will be destroyed. If there are fewer than @p + /// NumInits initializers, NULL expressions will be added for the + /// unknown initializers. + void resizeInits(const ASTContext &Context, unsigned NumInits); + + /// @brief Updates the initializer at index @p Init with the new + /// expression @p expr, and returns the old expression at that + /// location. + /// + /// When @p Init is out of range for this initializer list, the + /// initializer list will be extended with NULL expressions to + /// accommodate the new entry. + Expr *updateInit(const ASTContext &C, unsigned Init, Expr *expr); + + /// \brief If this initializer list initializes an array with more elements + /// than there are initializers in the list, specifies an expression to be + /// used for value initialization of the rest of the elements. + Expr *getArrayFiller() { + return ArrayFillerOrUnionFieldInit.dyn_cast<Expr *>(); + } + const Expr *getArrayFiller() const { + return const_cast<InitListExpr *>(this)->getArrayFiller(); + } + void setArrayFiller(Expr *filler); + + /// \brief Return true if this is an array initializer and its array "filler" + /// has been set. + bool hasArrayFiller() const { return getArrayFiller(); } + + /// \brief If this initializes a union, specifies which field in the + /// union to initialize. + /// + /// Typically, this field is the first named field within the + /// union. However, a designated initializer can specify the + /// initialization of a different field within the union. + FieldDecl *getInitializedFieldInUnion() { + return ArrayFillerOrUnionFieldInit.dyn_cast<FieldDecl *>(); + } + const FieldDecl *getInitializedFieldInUnion() const { + return const_cast<InitListExpr *>(this)->getInitializedFieldInUnion(); + } + void setInitializedFieldInUnion(FieldDecl *FD) { + assert((FD == nullptr + || getInitializedFieldInUnion() == nullptr + || getInitializedFieldInUnion() == FD) + && "Only one field of a union may be initialized at a time!"); + ArrayFillerOrUnionFieldInit = FD; + } + + // Explicit InitListExpr's originate from source code (and have valid source + // locations). Implicit InitListExpr's are created by the semantic analyzer. + bool isExplicit() { + return LBraceLoc.isValid() && RBraceLoc.isValid(); + } + + // Is this an initializer for an array of characters, initialized by a string + // literal or an @encode? + bool isStringLiteralInit() const; + + SourceLocation getLBraceLoc() const { return LBraceLoc; } + void setLBraceLoc(SourceLocation Loc) { LBraceLoc = Loc; } + SourceLocation getRBraceLoc() const { return RBraceLoc; } + void setRBraceLoc(SourceLocation Loc) { RBraceLoc = Loc; } + + bool isSemanticForm() const { return AltForm.getInt(); } + InitListExpr *getSemanticForm() const { + return isSemanticForm() ? nullptr : AltForm.getPointer(); + } + InitListExpr *getSyntacticForm() const { + return isSemanticForm() ? AltForm.getPointer() : nullptr; + } + + void setSyntacticForm(InitListExpr *Init) { + AltForm.setPointer(Init); + AltForm.setInt(true); + Init->AltForm.setPointer(this); + Init->AltForm.setInt(false); + } + + bool hadArrayRangeDesignator() const { + return InitListExprBits.HadArrayRangeDesignator != 0; + } + void sawArrayRangeDesignator(bool ARD = true) { + InitListExprBits.HadArrayRangeDesignator = ARD; + } + + SourceLocation getLocStart() const LLVM_READONLY; + SourceLocation getLocEnd() const LLVM_READONLY; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == InitListExprClass; + } + + // Iterators + child_range children() { + // FIXME: This does not include the array filler expression. + if (InitExprs.empty()) + return child_range(child_iterator(), child_iterator()); + return child_range(&InitExprs[0], &InitExprs[0] + InitExprs.size()); + } + + typedef InitExprsTy::iterator iterator; + typedef InitExprsTy::const_iterator const_iterator; + typedef InitExprsTy::reverse_iterator reverse_iterator; + typedef InitExprsTy::const_reverse_iterator const_reverse_iterator; + + iterator begin() { return InitExprs.begin(); } + const_iterator begin() const { return InitExprs.begin(); } + iterator end() { return InitExprs.end(); } + const_iterator end() const { return InitExprs.end(); } + reverse_iterator rbegin() { return InitExprs.rbegin(); } + const_reverse_iterator rbegin() const { return InitExprs.rbegin(); } + reverse_iterator rend() { return InitExprs.rend(); } + const_reverse_iterator rend() const { return InitExprs.rend(); } + + friend class ASTStmtReader; + friend class ASTStmtWriter; +}; + +/// @brief Represents a C99 designated initializer expression. +/// +/// A designated initializer expression (C99 6.7.8) contains one or +/// more designators (which can be field designators, array +/// designators, or GNU array-range designators) followed by an +/// expression that initializes the field or element(s) that the +/// designators refer to. For example, given: +/// +/// @code +/// struct point { +/// double x; +/// double y; +/// }; +/// struct point ptarray[10] = { [2].y = 1.0, [2].x = 2.0, [0].x = 1.0 }; +/// @endcode +/// +/// The InitListExpr contains three DesignatedInitExprs, the first of +/// which covers @c [2].y=1.0. This DesignatedInitExpr will have two +/// designators, one array designator for @c [2] followed by one field +/// designator for @c .y. The initialization expression will be 1.0. +class DesignatedInitExpr final + : public Expr, + private llvm::TrailingObjects<DesignatedInitExpr, Stmt *> { +public: + /// \brief Forward declaration of the Designator class. + class Designator; + +private: + /// The location of the '=' or ':' prior to the actual initializer + /// expression. + SourceLocation EqualOrColonLoc; + + /// Whether this designated initializer used the GNU deprecated + /// syntax rather than the C99 '=' syntax. + bool GNUSyntax : 1; + + /// The number of designators in this initializer expression. + unsigned NumDesignators : 15; + + /// The number of subexpressions of this initializer expression, + /// which contains both the initializer and any additional + /// expressions used by array and array-range designators. + unsigned NumSubExprs : 16; + + /// \brief The designators in this designated initialization + /// expression. + Designator *Designators; + + + DesignatedInitExpr(const ASTContext &C, QualType Ty, unsigned NumDesignators, + const Designator *Designators, + SourceLocation EqualOrColonLoc, bool GNUSyntax, + ArrayRef<Expr*> IndexExprs, Expr *Init); + + explicit DesignatedInitExpr(unsigned NumSubExprs) + : Expr(DesignatedInitExprClass, EmptyShell()), + NumDesignators(0), NumSubExprs(NumSubExprs), Designators(nullptr) { } + +public: + /// A field designator, e.g., ".x". + struct FieldDesignator { + /// Refers to the field that is being initialized. The low bit + /// of this field determines whether this is actually a pointer + /// to an IdentifierInfo (if 1) or a FieldDecl (if 0). When + /// initially constructed, a field designator will store an + /// IdentifierInfo*. After semantic analysis has resolved that + /// name, the field designator will instead store a FieldDecl*. + uintptr_t NameOrField; + + /// The location of the '.' in the designated initializer. + unsigned DotLoc; + + /// The location of the field name in the designated initializer. + unsigned FieldLoc; + }; + + /// An array or GNU array-range designator, e.g., "[9]" or "[10..15]". + struct ArrayOrRangeDesignator { + /// Location of the first index expression within the designated + /// initializer expression's list of subexpressions. + unsigned Index; + /// The location of the '[' starting the array range designator. + unsigned LBracketLoc; + /// The location of the ellipsis separating the start and end + /// indices. Only valid for GNU array-range designators. + unsigned EllipsisLoc; + /// The location of the ']' terminating the array range designator. + unsigned RBracketLoc; + }; + + /// @brief Represents a single C99 designator. + /// + /// @todo This class is infuriatingly similar to clang::Designator, + /// but minor differences (storing indices vs. storing pointers) + /// keep us from reusing it. Try harder, later, to rectify these + /// differences. + class Designator { + /// @brief The kind of designator this describes. + enum { + FieldDesignator, + ArrayDesignator, + ArrayRangeDesignator + } Kind; + + union { + /// A field designator, e.g., ".x". + struct FieldDesignator Field; + /// An array or GNU array-range designator, e.g., "[9]" or "[10..15]". + struct ArrayOrRangeDesignator ArrayOrRange; + }; + friend class DesignatedInitExpr; + + public: + Designator() {} + + /// @brief Initializes a field designator. + Designator(const IdentifierInfo *FieldName, SourceLocation DotLoc, + SourceLocation FieldLoc) + : Kind(FieldDesignator) { + Field.NameOrField = reinterpret_cast<uintptr_t>(FieldName) | 0x01; + Field.DotLoc = DotLoc.getRawEncoding(); + Field.FieldLoc = FieldLoc.getRawEncoding(); + } + + /// @brief Initializes an array designator. + Designator(unsigned Index, SourceLocation LBracketLoc, + SourceLocation RBracketLoc) + : Kind(ArrayDesignator) { + ArrayOrRange.Index = Index; + ArrayOrRange.LBracketLoc = LBracketLoc.getRawEncoding(); + ArrayOrRange.EllipsisLoc = SourceLocation().getRawEncoding(); + ArrayOrRange.RBracketLoc = RBracketLoc.getRawEncoding(); + } + + /// @brief Initializes a GNU array-range designator. + Designator(unsigned Index, SourceLocation LBracketLoc, + SourceLocation EllipsisLoc, SourceLocation RBracketLoc) + : Kind(ArrayRangeDesignator) { + ArrayOrRange.Index = Index; + ArrayOrRange.LBracketLoc = LBracketLoc.getRawEncoding(); + ArrayOrRange.EllipsisLoc = EllipsisLoc.getRawEncoding(); + ArrayOrRange.RBracketLoc = RBracketLoc.getRawEncoding(); + } + + bool isFieldDesignator() const { return Kind == FieldDesignator; } + bool isArrayDesignator() const { return Kind == ArrayDesignator; } + bool isArrayRangeDesignator() const { return Kind == ArrayRangeDesignator; } + + IdentifierInfo *getFieldName() const; + + FieldDecl *getField() const { + assert(Kind == FieldDesignator && "Only valid on a field designator"); + if (Field.NameOrField & 0x01) + return nullptr; + else + return reinterpret_cast<FieldDecl *>(Field.NameOrField); + } + + void setField(FieldDecl *FD) { + assert(Kind == FieldDesignator && "Only valid on a field designator"); + Field.NameOrField = reinterpret_cast<uintptr_t>(FD); + } + + SourceLocation getDotLoc() const { + assert(Kind == FieldDesignator && "Only valid on a field designator"); + return SourceLocation::getFromRawEncoding(Field.DotLoc); + } + + SourceLocation getFieldLoc() const { + assert(Kind == FieldDesignator && "Only valid on a field designator"); + return SourceLocation::getFromRawEncoding(Field.FieldLoc); + } + + SourceLocation getLBracketLoc() const { + assert((Kind == ArrayDesignator || Kind == ArrayRangeDesignator) && + "Only valid on an array or array-range designator"); + return SourceLocation::getFromRawEncoding(ArrayOrRange.LBracketLoc); + } + + SourceLocation getRBracketLoc() const { + assert((Kind == ArrayDesignator || Kind == ArrayRangeDesignator) && + "Only valid on an array or array-range designator"); + return SourceLocation::getFromRawEncoding(ArrayOrRange.RBracketLoc); + } + + SourceLocation getEllipsisLoc() const { + assert(Kind == ArrayRangeDesignator && + "Only valid on an array-range designator"); + return SourceLocation::getFromRawEncoding(ArrayOrRange.EllipsisLoc); + } + + unsigned getFirstExprIndex() const { + assert((Kind == ArrayDesignator || Kind == ArrayRangeDesignator) && + "Only valid on an array or array-range designator"); + return ArrayOrRange.Index; + } + + SourceLocation getLocStart() const LLVM_READONLY { + if (Kind == FieldDesignator) + return getDotLoc().isInvalid()? getFieldLoc() : getDotLoc(); + else + return getLBracketLoc(); + } + SourceLocation getLocEnd() const LLVM_READONLY { + return Kind == FieldDesignator ? getFieldLoc() : getRBracketLoc(); + } + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(getLocStart(), getLocEnd()); + } + }; + + static DesignatedInitExpr *Create(const ASTContext &C, + Designator *Designators, + unsigned NumDesignators, + ArrayRef<Expr*> IndexExprs, + SourceLocation EqualOrColonLoc, + bool GNUSyntax, Expr *Init); + + static DesignatedInitExpr *CreateEmpty(const ASTContext &C, + unsigned NumIndexExprs); + + /// @brief Returns the number of designators in this initializer. + unsigned size() const { return NumDesignators; } + + // Iterator access to the designators. + typedef Designator *designators_iterator; + designators_iterator designators_begin() { return Designators; } + designators_iterator designators_end() { + return Designators + NumDesignators; + } + + typedef const Designator *const_designators_iterator; + const_designators_iterator designators_begin() const { return Designators; } + const_designators_iterator designators_end() const { + return Designators + NumDesignators; + } + + typedef llvm::iterator_range<designators_iterator> designators_range; + designators_range designators() { + return designators_range(designators_begin(), designators_end()); + } + + typedef llvm::iterator_range<const_designators_iterator> + designators_const_range; + designators_const_range designators() const { + return designators_const_range(designators_begin(), designators_end()); + } + + typedef std::reverse_iterator<designators_iterator> + reverse_designators_iterator; + reverse_designators_iterator designators_rbegin() { + return reverse_designators_iterator(designators_end()); + } + reverse_designators_iterator designators_rend() { + return reverse_designators_iterator(designators_begin()); + } + + typedef std::reverse_iterator<const_designators_iterator> + const_reverse_designators_iterator; + const_reverse_designators_iterator designators_rbegin() const { + return const_reverse_designators_iterator(designators_end()); + } + const_reverse_designators_iterator designators_rend() const { + return const_reverse_designators_iterator(designators_begin()); + } + + Designator *getDesignator(unsigned Idx) { return &designators_begin()[Idx]; } + + void setDesignators(const ASTContext &C, const Designator *Desigs, + unsigned NumDesigs); + + Expr *getArrayIndex(const Designator &D) const; + Expr *getArrayRangeStart(const Designator &D) const; + Expr *getArrayRangeEnd(const Designator &D) const; + + /// @brief Retrieve the location of the '=' that precedes the + /// initializer value itself, if present. + SourceLocation getEqualOrColonLoc() const { return EqualOrColonLoc; } + void setEqualOrColonLoc(SourceLocation L) { EqualOrColonLoc = L; } + + /// @brief Determines whether this designated initializer used the + /// deprecated GNU syntax for designated initializers. + bool usesGNUSyntax() const { return GNUSyntax; } + void setGNUSyntax(bool GNU) { GNUSyntax = GNU; } + + /// @brief Retrieve the initializer value. + Expr *getInit() const { + return cast<Expr>(*const_cast<DesignatedInitExpr*>(this)->child_begin()); + } + + void setInit(Expr *init) { + *child_begin() = init; + } + + /// \brief Retrieve the total number of subexpressions in this + /// designated initializer expression, including the actual + /// initialized value and any expressions that occur within array + /// and array-range designators. + unsigned getNumSubExprs() const { return NumSubExprs; } + + Expr *getSubExpr(unsigned Idx) const { + assert(Idx < NumSubExprs && "Subscript out of range"); + return cast<Expr>(getTrailingObjects<Stmt *>()[Idx]); + } + + void setSubExpr(unsigned Idx, Expr *E) { + assert(Idx < NumSubExprs && "Subscript out of range"); + getTrailingObjects<Stmt *>()[Idx] = E; + } + + /// \brief Replaces the designator at index @p Idx with the series + /// of designators in [First, Last). + void ExpandDesignator(const ASTContext &C, unsigned Idx, + const Designator *First, const Designator *Last); + + SourceRange getDesignatorsSourceRange() const; + + SourceLocation getLocStart() const LLVM_READONLY; + SourceLocation getLocEnd() const LLVM_READONLY; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == DesignatedInitExprClass; + } + + // Iterators + child_range children() { + Stmt **begin = getTrailingObjects<Stmt *>(); + return child_range(begin, begin + NumSubExprs); + } + + friend TrailingObjects; +}; + +/// \brief Represents a place-holder for an object not to be initialized by +/// anything. +/// +/// This only makes sense when it appears as part of an updater of a +/// DesignatedInitUpdateExpr (see below). The base expression of a DIUE +/// initializes a big object, and the NoInitExpr's mark the spots within the +/// big object not to be overwritten by the updater. +/// +/// \see DesignatedInitUpdateExpr +class NoInitExpr : public Expr { +public: + explicit NoInitExpr(QualType ty) + : Expr(NoInitExprClass, ty, VK_RValue, OK_Ordinary, + false, false, ty->isInstantiationDependentType(), false) { } + + explicit NoInitExpr(EmptyShell Empty) + : Expr(NoInitExprClass, Empty) { } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == NoInitExprClass; + } + + SourceLocation getLocStart() const LLVM_READONLY { return SourceLocation(); } + SourceLocation getLocEnd() const LLVM_READONLY { return SourceLocation(); } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +// In cases like: +// struct Q { int a, b, c; }; +// Q *getQ(); +// void foo() { +// struct A { Q q; } a = { *getQ(), .q.b = 3 }; +// } +// +// We will have an InitListExpr for a, with type A, and then a +// DesignatedInitUpdateExpr for "a.q" with type Q. The "base" for this DIUE +// is the call expression *getQ(); the "updater" for the DIUE is ".q.b = 3" +// +class DesignatedInitUpdateExpr : public Expr { + // BaseAndUpdaterExprs[0] is the base expression; + // BaseAndUpdaterExprs[1] is an InitListExpr overwriting part of the base. + Stmt *BaseAndUpdaterExprs[2]; + +public: + DesignatedInitUpdateExpr(const ASTContext &C, SourceLocation lBraceLoc, + Expr *baseExprs, SourceLocation rBraceLoc); + + explicit DesignatedInitUpdateExpr(EmptyShell Empty) + : Expr(DesignatedInitUpdateExprClass, Empty) { } + + SourceLocation getLocStart() const LLVM_READONLY; + SourceLocation getLocEnd() const LLVM_READONLY; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == DesignatedInitUpdateExprClass; + } + + Expr *getBase() const { return cast<Expr>(BaseAndUpdaterExprs[0]); } + void setBase(Expr *Base) { BaseAndUpdaterExprs[0] = Base; } + + InitListExpr *getUpdater() const { + return cast<InitListExpr>(BaseAndUpdaterExprs[1]); + } + void setUpdater(Expr *Updater) { BaseAndUpdaterExprs[1] = Updater; } + + // Iterators + // children = the base and the updater + child_range children() { + return child_range(&BaseAndUpdaterExprs[0], &BaseAndUpdaterExprs[0] + 2); + } +}; + +/// \brief Represents an implicitly-generated value initialization of +/// an object of a given type. +/// +/// Implicit value initializations occur within semantic initializer +/// list expressions (InitListExpr) as placeholders for subobject +/// initializations not explicitly specified by the user. +/// +/// \see InitListExpr +class ImplicitValueInitExpr : public Expr { +public: + explicit ImplicitValueInitExpr(QualType ty) + : Expr(ImplicitValueInitExprClass, ty, VK_RValue, OK_Ordinary, + false, false, ty->isInstantiationDependentType(), false) { } + + /// \brief Construct an empty implicit value initialization. + explicit ImplicitValueInitExpr(EmptyShell Empty) + : Expr(ImplicitValueInitExprClass, Empty) { } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ImplicitValueInitExprClass; + } + + SourceLocation getLocStart() const LLVM_READONLY { return SourceLocation(); } + SourceLocation getLocEnd() const LLVM_READONLY { return SourceLocation(); } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +class ParenListExpr : public Expr { + Stmt **Exprs; + unsigned NumExprs; + SourceLocation LParenLoc, RParenLoc; + +public: + ParenListExpr(const ASTContext& C, SourceLocation lparenloc, + ArrayRef<Expr*> exprs, SourceLocation rparenloc); + + /// \brief Build an empty paren list. + explicit ParenListExpr(EmptyShell Empty) : Expr(ParenListExprClass, Empty) { } + + unsigned getNumExprs() const { return NumExprs; } + + const Expr* getExpr(unsigned Init) const { + assert(Init < getNumExprs() && "Initializer access out of range!"); + return cast_or_null<Expr>(Exprs[Init]); + } + + Expr* getExpr(unsigned Init) { + assert(Init < getNumExprs() && "Initializer access out of range!"); + return cast_or_null<Expr>(Exprs[Init]); + } + + Expr **getExprs() { return reinterpret_cast<Expr **>(Exprs); } + + ArrayRef<Expr *> exprs() { + return llvm::makeArrayRef(getExprs(), getNumExprs()); + } + + SourceLocation getLParenLoc() const { return LParenLoc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + + SourceLocation getLocStart() const LLVM_READONLY { return LParenLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ParenListExprClass; + } + + // Iterators + child_range children() { + return child_range(&Exprs[0], &Exprs[0]+NumExprs); + } + + friend class ASTStmtReader; + friend class ASTStmtWriter; +}; + +/// \brief Represents a C11 generic selection. +/// +/// A generic selection (C11 6.5.1.1) contains an unevaluated controlling +/// expression, followed by one or more generic associations. Each generic +/// association specifies a type name and an expression, or "default" and an +/// expression (in which case it is known as a default generic association). +/// The type and value of the generic selection are identical to those of its +/// result expression, which is defined as the expression in the generic +/// association with a type name that is compatible with the type of the +/// controlling expression, or the expression in the default generic association +/// if no types are compatible. For example: +/// +/// @code +/// _Generic(X, double: 1, float: 2, default: 3) +/// @endcode +/// +/// The above expression evaluates to 1 if 1.0 is substituted for X, 2 if 1.0f +/// or 3 if "hello". +/// +/// As an extension, generic selections are allowed in C++, where the following +/// additional semantics apply: +/// +/// Any generic selection whose controlling expression is type-dependent or +/// which names a dependent type in its association list is result-dependent, +/// which means that the choice of result expression is dependent. +/// Result-dependent generic associations are both type- and value-dependent. +class GenericSelectionExpr : public Expr { + enum { CONTROLLING, END_EXPR }; + TypeSourceInfo **AssocTypes; + Stmt **SubExprs; + unsigned NumAssocs, ResultIndex; + SourceLocation GenericLoc, DefaultLoc, RParenLoc; + +public: + GenericSelectionExpr(const ASTContext &Context, + SourceLocation GenericLoc, Expr *ControllingExpr, + ArrayRef<TypeSourceInfo*> AssocTypes, + ArrayRef<Expr*> AssocExprs, + SourceLocation DefaultLoc, SourceLocation RParenLoc, + bool ContainsUnexpandedParameterPack, + unsigned ResultIndex); + + /// This constructor is used in the result-dependent case. + GenericSelectionExpr(const ASTContext &Context, + SourceLocation GenericLoc, Expr *ControllingExpr, + ArrayRef<TypeSourceInfo*> AssocTypes, + ArrayRef<Expr*> AssocExprs, + SourceLocation DefaultLoc, SourceLocation RParenLoc, + bool ContainsUnexpandedParameterPack); + + explicit GenericSelectionExpr(EmptyShell Empty) + : Expr(GenericSelectionExprClass, Empty) { } + + unsigned getNumAssocs() const { return NumAssocs; } + + SourceLocation getGenericLoc() const { return GenericLoc; } + SourceLocation getDefaultLoc() const { return DefaultLoc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + + const Expr *getAssocExpr(unsigned i) const { + return cast<Expr>(SubExprs[END_EXPR+i]); + } + Expr *getAssocExpr(unsigned i) { return cast<Expr>(SubExprs[END_EXPR+i]); } + + const TypeSourceInfo *getAssocTypeSourceInfo(unsigned i) const { + return AssocTypes[i]; + } + TypeSourceInfo *getAssocTypeSourceInfo(unsigned i) { return AssocTypes[i]; } + + QualType getAssocType(unsigned i) const { + if (const TypeSourceInfo *TS = getAssocTypeSourceInfo(i)) + return TS->getType(); + else + return QualType(); + } + + const Expr *getControllingExpr() const { + return cast<Expr>(SubExprs[CONTROLLING]); + } + Expr *getControllingExpr() { return cast<Expr>(SubExprs[CONTROLLING]); } + + /// Whether this generic selection is result-dependent. + bool isResultDependent() const { return ResultIndex == -1U; } + + /// The zero-based index of the result expression's generic association in + /// the generic selection's association list. Defined only if the + /// generic selection is not result-dependent. + unsigned getResultIndex() const { + assert(!isResultDependent() && "Generic selection is result-dependent"); + return ResultIndex; + } + + /// The generic selection's result expression. Defined only if the + /// generic selection is not result-dependent. + const Expr *getResultExpr() const { return getAssocExpr(getResultIndex()); } + Expr *getResultExpr() { return getAssocExpr(getResultIndex()); } + + SourceLocation getLocStart() const LLVM_READONLY { return GenericLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == GenericSelectionExprClass; + } + + child_range children() { + return child_range(SubExprs, SubExprs+END_EXPR+NumAssocs); + } + + friend class ASTStmtReader; +}; + +//===----------------------------------------------------------------------===// +// Clang Extensions +//===----------------------------------------------------------------------===// + +/// ExtVectorElementExpr - This represents access to specific elements of a +/// vector, and may occur on the left hand side or right hand side. For example +/// the following is legal: "V.xy = V.zw" if V is a 4 element extended vector. +/// +/// Note that the base may have either vector or pointer to vector type, just +/// like a struct field reference. +/// +class ExtVectorElementExpr : public Expr { + Stmt *Base; + IdentifierInfo *Accessor; + SourceLocation AccessorLoc; +public: + ExtVectorElementExpr(QualType ty, ExprValueKind VK, Expr *base, + IdentifierInfo &accessor, SourceLocation loc) + : Expr(ExtVectorElementExprClass, ty, VK, + (VK == VK_RValue ? OK_Ordinary : OK_VectorComponent), + base->isTypeDependent(), base->isValueDependent(), + base->isInstantiationDependent(), + base->containsUnexpandedParameterPack()), + Base(base), Accessor(&accessor), AccessorLoc(loc) {} + + /// \brief Build an empty vector element expression. + explicit ExtVectorElementExpr(EmptyShell Empty) + : Expr(ExtVectorElementExprClass, Empty) { } + + const Expr *getBase() const { return cast<Expr>(Base); } + Expr *getBase() { return cast<Expr>(Base); } + void setBase(Expr *E) { Base = E; } + + IdentifierInfo &getAccessor() const { return *Accessor; } + void setAccessor(IdentifierInfo *II) { Accessor = II; } + + SourceLocation getAccessorLoc() const { return AccessorLoc; } + void setAccessorLoc(SourceLocation L) { AccessorLoc = L; } + + /// getNumElements - Get the number of components being selected. + unsigned getNumElements() const; + + /// containsDuplicateElements - Return true if any element access is + /// repeated. + bool containsDuplicateElements() const; + + /// getEncodedElementAccess - Encode the elements accessed into an llvm + /// aggregate Constant of ConstantInt(s). + void getEncodedElementAccess(SmallVectorImpl<uint32_t> &Elts) const; + + SourceLocation getLocStart() const LLVM_READONLY { + return getBase()->getLocStart(); + } + SourceLocation getLocEnd() const LLVM_READONLY { return AccessorLoc; } + + /// isArrow - Return true if the base expression is a pointer to vector, + /// return false if the base expression is a vector. + bool isArrow() const; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ExtVectorElementExprClass; + } + + // Iterators + child_range children() { return child_range(&Base, &Base+1); } +}; + +/// BlockExpr - Adaptor class for mixing a BlockDecl with expressions. +/// ^{ statement-body } or ^(int arg1, float arg2){ statement-body } +class BlockExpr : public Expr { +protected: + BlockDecl *TheBlock; +public: + BlockExpr(BlockDecl *BD, QualType ty) + : Expr(BlockExprClass, ty, VK_RValue, OK_Ordinary, + ty->isDependentType(), ty->isDependentType(), + ty->isInstantiationDependentType() || BD->isDependentContext(), + false), + TheBlock(BD) {} + + /// \brief Build an empty block expression. + explicit BlockExpr(EmptyShell Empty) : Expr(BlockExprClass, Empty) { } + + const BlockDecl *getBlockDecl() const { return TheBlock; } + BlockDecl *getBlockDecl() { return TheBlock; } + void setBlockDecl(BlockDecl *BD) { TheBlock = BD; } + + // Convenience functions for probing the underlying BlockDecl. + SourceLocation getCaretLocation() const; + const Stmt *getBody() const; + Stmt *getBody(); + + SourceLocation getLocStart() const LLVM_READONLY { return getCaretLocation(); } + SourceLocation getLocEnd() const LLVM_READONLY { return getBody()->getLocEnd(); } + + /// getFunctionType - Return the underlying function type for this block. + const FunctionProtoType *getFunctionType() const; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == BlockExprClass; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +/// AsTypeExpr - Clang builtin function __builtin_astype [OpenCL 6.2.4.2] +/// This AST node provides support for reinterpreting a type to another +/// type of the same size. +class AsTypeExpr : public Expr { +private: + Stmt *SrcExpr; + SourceLocation BuiltinLoc, RParenLoc; + + friend class ASTReader; + friend class ASTStmtReader; + explicit AsTypeExpr(EmptyShell Empty) : Expr(AsTypeExprClass, Empty) {} + +public: + AsTypeExpr(Expr* SrcExpr, QualType DstType, + ExprValueKind VK, ExprObjectKind OK, + SourceLocation BuiltinLoc, SourceLocation RParenLoc) + : Expr(AsTypeExprClass, DstType, VK, OK, + DstType->isDependentType(), + DstType->isDependentType() || SrcExpr->isValueDependent(), + (DstType->isInstantiationDependentType() || + SrcExpr->isInstantiationDependent()), + (DstType->containsUnexpandedParameterPack() || + SrcExpr->containsUnexpandedParameterPack())), + SrcExpr(SrcExpr), BuiltinLoc(BuiltinLoc), RParenLoc(RParenLoc) {} + + /// getSrcExpr - Return the Expr to be converted. + Expr *getSrcExpr() const { return cast<Expr>(SrcExpr); } + + /// getBuiltinLoc - Return the location of the __builtin_astype token. + SourceLocation getBuiltinLoc() const { return BuiltinLoc; } + + /// getRParenLoc - Return the location of final right parenthesis. + SourceLocation getRParenLoc() const { return RParenLoc; } + + SourceLocation getLocStart() const LLVM_READONLY { return BuiltinLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == AsTypeExprClass; + } + + // Iterators + child_range children() { return child_range(&SrcExpr, &SrcExpr+1); } +}; + +/// PseudoObjectExpr - An expression which accesses a pseudo-object +/// l-value. A pseudo-object is an abstract object, accesses to which +/// are translated to calls. The pseudo-object expression has a +/// syntactic form, which shows how the expression was actually +/// written in the source code, and a semantic form, which is a series +/// of expressions to be executed in order which detail how the +/// operation is actually evaluated. Optionally, one of the semantic +/// forms may also provide a result value for the expression. +/// +/// If any of the semantic-form expressions is an OpaqueValueExpr, +/// that OVE is required to have a source expression, and it is bound +/// to the result of that source expression. Such OVEs may appear +/// only in subsequent semantic-form expressions and as +/// sub-expressions of the syntactic form. +/// +/// PseudoObjectExpr should be used only when an operation can be +/// usefully described in terms of fairly simple rewrite rules on +/// objects and functions that are meant to be used by end-developers. +/// For example, under the Itanium ABI, dynamic casts are implemented +/// as a call to a runtime function called __dynamic_cast; using this +/// class to describe that would be inappropriate because that call is +/// not really part of the user-visible semantics, and instead the +/// cast is properly reflected in the AST and IR-generation has been +/// taught to generate the call as necessary. In contrast, an +/// Objective-C property access is semantically defined to be +/// equivalent to a particular message send, and this is very much +/// part of the user model. The name of this class encourages this +/// modelling design. +class PseudoObjectExpr final + : public Expr, + private llvm::TrailingObjects<PseudoObjectExpr, Expr *> { + // PseudoObjectExprBits.NumSubExprs - The number of sub-expressions. + // Always at least two, because the first sub-expression is the + // syntactic form. + + // PseudoObjectExprBits.ResultIndex - The index of the + // sub-expression holding the result. 0 means the result is void, + // which is unambiguous because it's the index of the syntactic + // form. Note that this is therefore 1 higher than the value passed + // in to Create, which is an index within the semantic forms. + // Note also that ASTStmtWriter assumes this encoding. + + Expr **getSubExprsBuffer() { return getTrailingObjects<Expr *>(); } + const Expr * const *getSubExprsBuffer() const { + return getTrailingObjects<Expr *>(); + } + + PseudoObjectExpr(QualType type, ExprValueKind VK, + Expr *syntactic, ArrayRef<Expr*> semantic, + unsigned resultIndex); + + PseudoObjectExpr(EmptyShell shell, unsigned numSemanticExprs); + + unsigned getNumSubExprs() const { + return PseudoObjectExprBits.NumSubExprs; + } + +public: + /// NoResult - A value for the result index indicating that there is + /// no semantic result. + enum : unsigned { NoResult = ~0U }; + + static PseudoObjectExpr *Create(const ASTContext &Context, Expr *syntactic, + ArrayRef<Expr*> semantic, + unsigned resultIndex); + + static PseudoObjectExpr *Create(const ASTContext &Context, EmptyShell shell, + unsigned numSemanticExprs); + + /// Return the syntactic form of this expression, i.e. the + /// expression it actually looks like. Likely to be expressed in + /// terms of OpaqueValueExprs bound in the semantic form. + Expr *getSyntacticForm() { return getSubExprsBuffer()[0]; } + const Expr *getSyntacticForm() const { return getSubExprsBuffer()[0]; } + + /// Return the index of the result-bearing expression into the semantics + /// expressions, or PseudoObjectExpr::NoResult if there is none. + unsigned getResultExprIndex() const { + if (PseudoObjectExprBits.ResultIndex == 0) return NoResult; + return PseudoObjectExprBits.ResultIndex - 1; + } + + /// Return the result-bearing expression, or null if there is none. + Expr *getResultExpr() { + if (PseudoObjectExprBits.ResultIndex == 0) + return nullptr; + return getSubExprsBuffer()[PseudoObjectExprBits.ResultIndex]; + } + const Expr *getResultExpr() const { + return const_cast<PseudoObjectExpr*>(this)->getResultExpr(); + } + + unsigned getNumSemanticExprs() const { return getNumSubExprs() - 1; } + + typedef Expr * const *semantics_iterator; + typedef const Expr * const *const_semantics_iterator; + semantics_iterator semantics_begin() { + return getSubExprsBuffer() + 1; + } + const_semantics_iterator semantics_begin() const { + return getSubExprsBuffer() + 1; + } + semantics_iterator semantics_end() { + return getSubExprsBuffer() + getNumSubExprs(); + } + const_semantics_iterator semantics_end() const { + return getSubExprsBuffer() + getNumSubExprs(); + } + + llvm::iterator_range<semantics_iterator> semantics() { + return llvm::make_range(semantics_begin(), semantics_end()); + } + llvm::iterator_range<const_semantics_iterator> semantics() const { + return llvm::make_range(semantics_begin(), semantics_end()); + } + + Expr *getSemanticExpr(unsigned index) { + assert(index + 1 < getNumSubExprs()); + return getSubExprsBuffer()[index + 1]; + } + const Expr *getSemanticExpr(unsigned index) const { + return const_cast<PseudoObjectExpr*>(this)->getSemanticExpr(index); + } + + SourceLocation getExprLoc() const LLVM_READONLY { + return getSyntacticForm()->getExprLoc(); + } + + SourceLocation getLocStart() const LLVM_READONLY { + return getSyntacticForm()->getLocStart(); + } + SourceLocation getLocEnd() const LLVM_READONLY { + return getSyntacticForm()->getLocEnd(); + } + + child_range children() { + Stmt **cs = reinterpret_cast<Stmt**>(getSubExprsBuffer()); + return child_range(cs, cs + getNumSubExprs()); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == PseudoObjectExprClass; + } + + friend TrailingObjects; + friend class ASTStmtReader; +}; + +/// AtomicExpr - Variadic atomic builtins: __atomic_exchange, __atomic_fetch_*, +/// __atomic_load, __atomic_store, and __atomic_compare_exchange_*, for the +/// similarly-named C++11 instructions, and __c11 variants for <stdatomic.h>. +/// All of these instructions take one primary pointer and at least one memory +/// order. +class AtomicExpr : public Expr { +public: + enum AtomicOp { +#define BUILTIN(ID, TYPE, ATTRS) +#define ATOMIC_BUILTIN(ID, TYPE, ATTRS) AO ## ID, +#include "clang/Basic/Builtins.def" + // Avoid trailing comma + BI_First = 0 + }; + + // The ABI values for various atomic memory orderings. + enum AtomicOrderingKind { + AO_ABI_memory_order_relaxed = 0, + AO_ABI_memory_order_consume = 1, + AO_ABI_memory_order_acquire = 2, + AO_ABI_memory_order_release = 3, + AO_ABI_memory_order_acq_rel = 4, + AO_ABI_memory_order_seq_cst = 5 + }; + +private: + enum { PTR, ORDER, VAL1, ORDER_FAIL, VAL2, WEAK, END_EXPR }; + Stmt* SubExprs[END_EXPR]; + unsigned NumSubExprs; + SourceLocation BuiltinLoc, RParenLoc; + AtomicOp Op; + + friend class ASTStmtReader; + +public: + AtomicExpr(SourceLocation BLoc, ArrayRef<Expr*> args, QualType t, + AtomicOp op, SourceLocation RP); + + /// \brief Determine the number of arguments the specified atomic builtin + /// should have. + static unsigned getNumSubExprs(AtomicOp Op); + + /// \brief Build an empty AtomicExpr. + explicit AtomicExpr(EmptyShell Empty) : Expr(AtomicExprClass, Empty) { } + + Expr *getPtr() const { + return cast<Expr>(SubExprs[PTR]); + } + Expr *getOrder() const { + return cast<Expr>(SubExprs[ORDER]); + } + Expr *getVal1() const { + if (Op == AO__c11_atomic_init) + return cast<Expr>(SubExprs[ORDER]); + assert(NumSubExprs > VAL1); + return cast<Expr>(SubExprs[VAL1]); + } + Expr *getOrderFail() const { + assert(NumSubExprs > ORDER_FAIL); + return cast<Expr>(SubExprs[ORDER_FAIL]); + } + Expr *getVal2() const { + if (Op == AO__atomic_exchange) + return cast<Expr>(SubExprs[ORDER_FAIL]); + assert(NumSubExprs > VAL2); + return cast<Expr>(SubExprs[VAL2]); + } + Expr *getWeak() const { + assert(NumSubExprs > WEAK); + return cast<Expr>(SubExprs[WEAK]); + } + + AtomicOp getOp() const { return Op; } + unsigned getNumSubExprs() { return NumSubExprs; } + + Expr **getSubExprs() { return reinterpret_cast<Expr **>(SubExprs); } + + bool isVolatile() const { + return getPtr()->getType()->getPointeeType().isVolatileQualified(); + } + + bool isCmpXChg() const { + return getOp() == AO__c11_atomic_compare_exchange_strong || + getOp() == AO__c11_atomic_compare_exchange_weak || + getOp() == AO__atomic_compare_exchange || + getOp() == AO__atomic_compare_exchange_n; + } + + SourceLocation getBuiltinLoc() const { return BuiltinLoc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + + SourceLocation getLocStart() const LLVM_READONLY { return BuiltinLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == AtomicExprClass; + } + + // Iterators + child_range children() { + return child_range(SubExprs, SubExprs+NumSubExprs); + } +}; + +/// TypoExpr - Internal placeholder for expressions where typo correction +/// still needs to be performed and/or an error diagnostic emitted. +class TypoExpr : public Expr { +public: + TypoExpr(QualType T) + : Expr(TypoExprClass, T, VK_LValue, OK_Ordinary, + /*isTypeDependent*/ true, + /*isValueDependent*/ true, + /*isInstantiationDependent*/ true, + /*containsUnexpandedParameterPack*/ false) { + assert(T->isDependentType() && "TypoExpr given a non-dependent type"); + } + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + SourceLocation getLocStart() const LLVM_READONLY { return SourceLocation(); } + SourceLocation getLocEnd() const LLVM_READONLY { return SourceLocation(); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == TypoExprClass; + } + +}; +} // end namespace clang + +#endif // LLVM_CLANG_AST_EXPR_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/ExprCXX.h b/contrib/llvm/tools/clang/include/clang/AST/ExprCXX.h new file mode 100644 index 0000000..0608aba --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/ExprCXX.h @@ -0,0 +1,4179 @@ +//===--- ExprCXX.h - Classes for representing expressions -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the clang::Expr interface and subclasses for C++ expressions. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_EXPRCXX_H +#define LLVM_CLANG_AST_EXPRCXX_H + +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "clang/AST/LambdaCapture.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/UnresolvedSet.h" +#include "clang/Basic/ExpressionTraits.h" +#include "clang/Basic/TypeTraits.h" +#include "llvm/Support/Compiler.h" + +namespace clang { + +class CXXConstructorDecl; +class CXXDestructorDecl; +class CXXMethodDecl; +class CXXTemporary; +class MSPropertyDecl; +class TemplateArgumentListInfo; +class UuidAttr; + +//===--------------------------------------------------------------------===// +// C++ Expressions. +//===--------------------------------------------------------------------===// + +/// \brief A call to an overloaded operator written using operator +/// syntax. +/// +/// Represents a call to an overloaded operator written using operator +/// syntax, e.g., "x + y" or "*p". While semantically equivalent to a +/// normal call, this AST node provides better information about the +/// syntactic representation of the call. +/// +/// In a C++ template, this expression node kind will be used whenever +/// any of the arguments are type-dependent. In this case, the +/// function itself will be a (possibly empty) set of functions and +/// function templates that were found by name lookup at template +/// definition time. +class CXXOperatorCallExpr : public CallExpr { + /// \brief The overloaded operator. + OverloadedOperatorKind Operator; + SourceRange Range; + + // Record the FP_CONTRACT state that applies to this operator call. Only + // meaningful for floating point types. For other types this value can be + // set to false. + unsigned FPContractable : 1; + + SourceRange getSourceRangeImpl() const LLVM_READONLY; +public: + CXXOperatorCallExpr(ASTContext& C, OverloadedOperatorKind Op, Expr *fn, + ArrayRef<Expr*> args, QualType t, ExprValueKind VK, + SourceLocation operatorloc, bool fpContractable) + : CallExpr(C, CXXOperatorCallExprClass, fn, 0, args, t, VK, + operatorloc), + Operator(Op), FPContractable(fpContractable) { + Range = getSourceRangeImpl(); + } + explicit CXXOperatorCallExpr(ASTContext& C, EmptyShell Empty) : + CallExpr(C, CXXOperatorCallExprClass, Empty) { } + + + /// \brief Returns the kind of overloaded operator that this + /// expression refers to. + OverloadedOperatorKind getOperator() const { return Operator; } + + /// \brief Returns the location of the operator symbol in the expression. + /// + /// When \c getOperator()==OO_Call, this is the location of the right + /// parentheses; when \c getOperator()==OO_Subscript, this is the location + /// of the right bracket. + SourceLocation getOperatorLoc() const { return getRParenLoc(); } + + SourceLocation getExprLoc() const LLVM_READONLY { + return (Operator < OO_Plus || Operator >= OO_Arrow || + Operator == OO_PlusPlus || Operator == OO_MinusMinus) + ? getLocStart() + : getOperatorLoc(); + } + + SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } + SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } + SourceRange getSourceRange() const { return Range; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXOperatorCallExprClass; + } + + // Set the FP contractability status of this operator. Only meaningful for + // operations on floating point types. + void setFPContractable(bool FPC) { FPContractable = FPC; } + + // Get the FP contractability status of this operator. Only meaningful for + // operations on floating point types. + bool isFPContractable() const { return FPContractable; } + + friend class ASTStmtReader; + friend class ASTStmtWriter; +}; + +/// Represents a call to a member function that +/// may be written either with member call syntax (e.g., "obj.func()" +/// or "objptr->func()") or with normal function-call syntax +/// ("func()") within a member function that ends up calling a member +/// function. The callee in either case is a MemberExpr that contains +/// both the object argument and the member function, while the +/// arguments are the arguments within the parentheses (not including +/// the object argument). +class CXXMemberCallExpr : public CallExpr { +public: + CXXMemberCallExpr(ASTContext &C, Expr *fn, ArrayRef<Expr*> args, + QualType t, ExprValueKind VK, SourceLocation RP) + : CallExpr(C, CXXMemberCallExprClass, fn, 0, args, t, VK, RP) {} + + CXXMemberCallExpr(ASTContext &C, EmptyShell Empty) + : CallExpr(C, CXXMemberCallExprClass, Empty) { } + + /// \brief Retrieves the implicit object argument for the member call. + /// + /// For example, in "x.f(5)", this returns the sub-expression "x". + Expr *getImplicitObjectArgument() const; + + /// \brief Retrieves the declaration of the called method. + CXXMethodDecl *getMethodDecl() const; + + /// \brief Retrieves the CXXRecordDecl for the underlying type of + /// the implicit object argument. + /// + /// Note that this is may not be the same declaration as that of the class + /// context of the CXXMethodDecl which this function is calling. + /// FIXME: Returns 0 for member pointer call exprs. + CXXRecordDecl *getRecordDecl() const; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXMemberCallExprClass; + } +}; + +/// \brief Represents a call to a CUDA kernel function. +class CUDAKernelCallExpr : public CallExpr { +private: + enum { CONFIG, END_PREARG }; + +public: + CUDAKernelCallExpr(ASTContext &C, Expr *fn, CallExpr *Config, + ArrayRef<Expr*> args, QualType t, ExprValueKind VK, + SourceLocation RP) + : CallExpr(C, CUDAKernelCallExprClass, fn, END_PREARG, args, t, VK, RP) { + setConfig(Config); + } + + CUDAKernelCallExpr(ASTContext &C, EmptyShell Empty) + : CallExpr(C, CUDAKernelCallExprClass, END_PREARG, Empty) { } + + const CallExpr *getConfig() const { + return cast_or_null<CallExpr>(getPreArg(CONFIG)); + } + CallExpr *getConfig() { return cast_or_null<CallExpr>(getPreArg(CONFIG)); } + void setConfig(CallExpr *E) { setPreArg(CONFIG, E); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CUDAKernelCallExprClass; + } +}; + +/// \brief Abstract class common to all of the C++ "named"/"keyword" casts. +/// +/// This abstract class is inherited by all of the classes +/// representing "named" casts: CXXStaticCastExpr for \c static_cast, +/// CXXDynamicCastExpr for \c dynamic_cast, CXXReinterpretCastExpr for +/// reinterpret_cast, and CXXConstCastExpr for \c const_cast. +class CXXNamedCastExpr : public ExplicitCastExpr { +private: + SourceLocation Loc; // the location of the casting op + SourceLocation RParenLoc; // the location of the right parenthesis + SourceRange AngleBrackets; // range for '<' '>' + +protected: + CXXNamedCastExpr(StmtClass SC, QualType ty, ExprValueKind VK, + CastKind kind, Expr *op, unsigned PathSize, + TypeSourceInfo *writtenTy, SourceLocation l, + SourceLocation RParenLoc, + SourceRange AngleBrackets) + : ExplicitCastExpr(SC, ty, VK, kind, op, PathSize, writtenTy), Loc(l), + RParenLoc(RParenLoc), AngleBrackets(AngleBrackets) {} + + explicit CXXNamedCastExpr(StmtClass SC, EmptyShell Shell, unsigned PathSize) + : ExplicitCastExpr(SC, Shell, PathSize) { } + + friend class ASTStmtReader; + +public: + const char *getCastName() const; + + /// \brief Retrieve the location of the cast operator keyword, e.g., + /// \c static_cast. + SourceLocation getOperatorLoc() const { return Loc; } + + /// \brief Retrieve the location of the closing parenthesis. + SourceLocation getRParenLoc() const { return RParenLoc; } + + SourceLocation getLocStart() const LLVM_READONLY { return Loc; } + SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + SourceRange getAngleBrackets() const LLVM_READONLY { return AngleBrackets; } + + static bool classof(const Stmt *T) { + switch (T->getStmtClass()) { + case CXXStaticCastExprClass: + case CXXDynamicCastExprClass: + case CXXReinterpretCastExprClass: + case CXXConstCastExprClass: + return true; + default: + return false; + } + } +}; + +/// \brief A C++ \c static_cast expression (C++ [expr.static.cast]). +/// +/// This expression node represents a C++ static cast, e.g., +/// \c static_cast<int>(1.0). +class CXXStaticCastExpr final + : public CXXNamedCastExpr, + private llvm::TrailingObjects<CXXStaticCastExpr, CXXBaseSpecifier *> { + CXXStaticCastExpr(QualType ty, ExprValueKind vk, CastKind kind, Expr *op, + unsigned pathSize, TypeSourceInfo *writtenTy, + SourceLocation l, SourceLocation RParenLoc, + SourceRange AngleBrackets) + : CXXNamedCastExpr(CXXStaticCastExprClass, ty, vk, kind, op, pathSize, + writtenTy, l, RParenLoc, AngleBrackets) {} + + explicit CXXStaticCastExpr(EmptyShell Empty, unsigned PathSize) + : CXXNamedCastExpr(CXXStaticCastExprClass, Empty, PathSize) { } + +public: + static CXXStaticCastExpr *Create(const ASTContext &Context, QualType T, + ExprValueKind VK, CastKind K, Expr *Op, + const CXXCastPath *Path, + TypeSourceInfo *Written, SourceLocation L, + SourceLocation RParenLoc, + SourceRange AngleBrackets); + static CXXStaticCastExpr *CreateEmpty(const ASTContext &Context, + unsigned PathSize); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXStaticCastExprClass; + } + + friend TrailingObjects; + friend class CastExpr; +}; + +/// \brief A C++ @c dynamic_cast expression (C++ [expr.dynamic.cast]). +/// +/// This expression node represents a dynamic cast, e.g., +/// \c dynamic_cast<Derived*>(BasePtr). Such a cast may perform a run-time +/// check to determine how to perform the type conversion. +class CXXDynamicCastExpr final + : public CXXNamedCastExpr, + private llvm::TrailingObjects<CXXDynamicCastExpr, CXXBaseSpecifier *> { + CXXDynamicCastExpr(QualType ty, ExprValueKind VK, CastKind kind, + Expr *op, unsigned pathSize, TypeSourceInfo *writtenTy, + SourceLocation l, SourceLocation RParenLoc, + SourceRange AngleBrackets) + : CXXNamedCastExpr(CXXDynamicCastExprClass, ty, VK, kind, op, pathSize, + writtenTy, l, RParenLoc, AngleBrackets) {} + + explicit CXXDynamicCastExpr(EmptyShell Empty, unsigned pathSize) + : CXXNamedCastExpr(CXXDynamicCastExprClass, Empty, pathSize) { } + +public: + static CXXDynamicCastExpr *Create(const ASTContext &Context, QualType T, + ExprValueKind VK, CastKind Kind, Expr *Op, + const CXXCastPath *Path, + TypeSourceInfo *Written, SourceLocation L, + SourceLocation RParenLoc, + SourceRange AngleBrackets); + + static CXXDynamicCastExpr *CreateEmpty(const ASTContext &Context, + unsigned pathSize); + + bool isAlwaysNull() const; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXDynamicCastExprClass; + } + + friend TrailingObjects; + friend class CastExpr; +}; + +/// \brief A C++ @c reinterpret_cast expression (C++ [expr.reinterpret.cast]). +/// +/// This expression node represents a reinterpret cast, e.g., +/// @c reinterpret_cast<int>(VoidPtr). +/// +/// A reinterpret_cast provides a differently-typed view of a value but +/// (in Clang, as in most C++ implementations) performs no actual work at +/// run time. +class CXXReinterpretCastExpr final + : public CXXNamedCastExpr, + private llvm::TrailingObjects<CXXReinterpretCastExpr, + CXXBaseSpecifier *> { + CXXReinterpretCastExpr(QualType ty, ExprValueKind vk, CastKind kind, + Expr *op, unsigned pathSize, + TypeSourceInfo *writtenTy, SourceLocation l, + SourceLocation RParenLoc, + SourceRange AngleBrackets) + : CXXNamedCastExpr(CXXReinterpretCastExprClass, ty, vk, kind, op, + pathSize, writtenTy, l, RParenLoc, AngleBrackets) {} + + CXXReinterpretCastExpr(EmptyShell Empty, unsigned pathSize) + : CXXNamedCastExpr(CXXReinterpretCastExprClass, Empty, pathSize) { } + +public: + static CXXReinterpretCastExpr *Create(const ASTContext &Context, QualType T, + ExprValueKind VK, CastKind Kind, + Expr *Op, const CXXCastPath *Path, + TypeSourceInfo *WrittenTy, SourceLocation L, + SourceLocation RParenLoc, + SourceRange AngleBrackets); + static CXXReinterpretCastExpr *CreateEmpty(const ASTContext &Context, + unsigned pathSize); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXReinterpretCastExprClass; + } + + friend TrailingObjects; + friend class CastExpr; +}; + +/// \brief A C++ \c const_cast expression (C++ [expr.const.cast]). +/// +/// This expression node represents a const cast, e.g., +/// \c const_cast<char*>(PtrToConstChar). +/// +/// A const_cast can remove type qualifiers but does not change the underlying +/// value. +class CXXConstCastExpr final + : public CXXNamedCastExpr, + private llvm::TrailingObjects<CXXConstCastExpr, CXXBaseSpecifier *> { + CXXConstCastExpr(QualType ty, ExprValueKind VK, Expr *op, + TypeSourceInfo *writtenTy, SourceLocation l, + SourceLocation RParenLoc, SourceRange AngleBrackets) + : CXXNamedCastExpr(CXXConstCastExprClass, ty, VK, CK_NoOp, op, + 0, writtenTy, l, RParenLoc, AngleBrackets) {} + + explicit CXXConstCastExpr(EmptyShell Empty) + : CXXNamedCastExpr(CXXConstCastExprClass, Empty, 0) { } + +public: + static CXXConstCastExpr *Create(const ASTContext &Context, QualType T, + ExprValueKind VK, Expr *Op, + TypeSourceInfo *WrittenTy, SourceLocation L, + SourceLocation RParenLoc, + SourceRange AngleBrackets); + static CXXConstCastExpr *CreateEmpty(const ASTContext &Context); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXConstCastExprClass; + } + + friend TrailingObjects; + friend class CastExpr; +}; + +/// \brief A call to a literal operator (C++11 [over.literal]) +/// written as a user-defined literal (C++11 [lit.ext]). +/// +/// Represents a user-defined literal, e.g. "foo"_bar or 1.23_xyz. While this +/// is semantically equivalent to a normal call, this AST node provides better +/// information about the syntactic representation of the literal. +/// +/// Since literal operators are never found by ADL and can only be declared at +/// namespace scope, a user-defined literal is never dependent. +class UserDefinedLiteral : public CallExpr { + /// \brief The location of a ud-suffix within the literal. + SourceLocation UDSuffixLoc; + +public: + UserDefinedLiteral(const ASTContext &C, Expr *Fn, ArrayRef<Expr*> Args, + QualType T, ExprValueKind VK, SourceLocation LitEndLoc, + SourceLocation SuffixLoc) + : CallExpr(C, UserDefinedLiteralClass, Fn, 0, Args, T, VK, LitEndLoc), + UDSuffixLoc(SuffixLoc) {} + explicit UserDefinedLiteral(const ASTContext &C, EmptyShell Empty) + : CallExpr(C, UserDefinedLiteralClass, Empty) {} + + /// The kind of literal operator which is invoked. + enum LiteralOperatorKind { + LOK_Raw, ///< Raw form: operator "" X (const char *) + LOK_Template, ///< Raw form: operator "" X<cs...> () + LOK_Integer, ///< operator "" X (unsigned long long) + LOK_Floating, ///< operator "" X (long double) + LOK_String, ///< operator "" X (const CharT *, size_t) + LOK_Character ///< operator "" X (CharT) + }; + + /// \brief Returns the kind of literal operator invocation + /// which this expression represents. + LiteralOperatorKind getLiteralOperatorKind() const; + + /// \brief If this is not a raw user-defined literal, get the + /// underlying cooked literal (representing the literal with the suffix + /// removed). + Expr *getCookedLiteral(); + const Expr *getCookedLiteral() const { + return const_cast<UserDefinedLiteral*>(this)->getCookedLiteral(); + } + + SourceLocation getLocStart() const { + if (getLiteralOperatorKind() == LOK_Template) + return getRParenLoc(); + return getArg(0)->getLocStart(); + } + SourceLocation getLocEnd() const { return getRParenLoc(); } + + + /// \brief Returns the location of a ud-suffix in the expression. + /// + /// For a string literal, there may be multiple identical suffixes. This + /// returns the first. + SourceLocation getUDSuffixLoc() const { return UDSuffixLoc; } + + /// \brief Returns the ud-suffix specified for this literal. + const IdentifierInfo *getUDSuffix() const; + + static bool classof(const Stmt *S) { + return S->getStmtClass() == UserDefinedLiteralClass; + } + + friend class ASTStmtReader; + friend class ASTStmtWriter; +}; + +/// \brief A boolean literal, per ([C++ lex.bool] Boolean literals). +/// +class CXXBoolLiteralExpr : public Expr { + bool Value; + SourceLocation Loc; +public: + CXXBoolLiteralExpr(bool val, QualType Ty, SourceLocation l) : + Expr(CXXBoolLiteralExprClass, Ty, VK_RValue, OK_Ordinary, false, false, + false, false), + Value(val), Loc(l) {} + + explicit CXXBoolLiteralExpr(EmptyShell Empty) + : Expr(CXXBoolLiteralExprClass, Empty) { } + + bool getValue() const { return Value; } + void setValue(bool V) { Value = V; } + + SourceLocation getLocStart() const LLVM_READONLY { return Loc; } + SourceLocation getLocEnd() const LLVM_READONLY { return Loc; } + + SourceLocation getLocation() const { return Loc; } + void setLocation(SourceLocation L) { Loc = L; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXBoolLiteralExprClass; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +/// \brief The null pointer literal (C++11 [lex.nullptr]) +/// +/// Introduced in C++11, the only literal of type \c nullptr_t is \c nullptr. +class CXXNullPtrLiteralExpr : public Expr { + SourceLocation Loc; +public: + CXXNullPtrLiteralExpr(QualType Ty, SourceLocation l) : + Expr(CXXNullPtrLiteralExprClass, Ty, VK_RValue, OK_Ordinary, false, false, + false, false), + Loc(l) {} + + explicit CXXNullPtrLiteralExpr(EmptyShell Empty) + : Expr(CXXNullPtrLiteralExprClass, Empty) { } + + SourceLocation getLocStart() const LLVM_READONLY { return Loc; } + SourceLocation getLocEnd() const LLVM_READONLY { return Loc; } + + SourceLocation getLocation() const { return Loc; } + void setLocation(SourceLocation L) { Loc = L; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXNullPtrLiteralExprClass; + } + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +/// \brief Implicit construction of a std::initializer_list<T> object from an +/// array temporary within list-initialization (C++11 [dcl.init.list]p5). +class CXXStdInitializerListExpr : public Expr { + Stmt *SubExpr; + + CXXStdInitializerListExpr(EmptyShell Empty) + : Expr(CXXStdInitializerListExprClass, Empty), SubExpr(nullptr) {} + +public: + CXXStdInitializerListExpr(QualType Ty, Expr *SubExpr) + : Expr(CXXStdInitializerListExprClass, Ty, VK_RValue, OK_Ordinary, + Ty->isDependentType(), SubExpr->isValueDependent(), + SubExpr->isInstantiationDependent(), + SubExpr->containsUnexpandedParameterPack()), + SubExpr(SubExpr) {} + + Expr *getSubExpr() { return static_cast<Expr*>(SubExpr); } + const Expr *getSubExpr() const { return static_cast<const Expr*>(SubExpr); } + + SourceLocation getLocStart() const LLVM_READONLY { + return SubExpr->getLocStart(); + } + SourceLocation getLocEnd() const LLVM_READONLY { + return SubExpr->getLocEnd(); + } + SourceRange getSourceRange() const LLVM_READONLY { + return SubExpr->getSourceRange(); + } + + static bool classof(const Stmt *S) { + return S->getStmtClass() == CXXStdInitializerListExprClass; + } + + child_range children() { return child_range(&SubExpr, &SubExpr + 1); } + + friend class ASTReader; + friend class ASTStmtReader; +}; + +/// A C++ \c typeid expression (C++ [expr.typeid]), which gets +/// the \c type_info that corresponds to the supplied type, or the (possibly +/// dynamic) type of the supplied expression. +/// +/// This represents code like \c typeid(int) or \c typeid(*objPtr) +class CXXTypeidExpr : public Expr { +private: + llvm::PointerUnion<Stmt *, TypeSourceInfo *> Operand; + SourceRange Range; + +public: + CXXTypeidExpr(QualType Ty, TypeSourceInfo *Operand, SourceRange R) + : Expr(CXXTypeidExprClass, Ty, VK_LValue, OK_Ordinary, + // typeid is never type-dependent (C++ [temp.dep.expr]p4) + false, + // typeid is value-dependent if the type or expression are dependent + Operand->getType()->isDependentType(), + Operand->getType()->isInstantiationDependentType(), + Operand->getType()->containsUnexpandedParameterPack()), + Operand(Operand), Range(R) { } + + CXXTypeidExpr(QualType Ty, Expr *Operand, SourceRange R) + : Expr(CXXTypeidExprClass, Ty, VK_LValue, OK_Ordinary, + // typeid is never type-dependent (C++ [temp.dep.expr]p4) + false, + // typeid is value-dependent if the type or expression are dependent + Operand->isTypeDependent() || Operand->isValueDependent(), + Operand->isInstantiationDependent(), + Operand->containsUnexpandedParameterPack()), + Operand(Operand), Range(R) { } + + CXXTypeidExpr(EmptyShell Empty, bool isExpr) + : Expr(CXXTypeidExprClass, Empty) { + if (isExpr) + Operand = (Expr*)nullptr; + else + Operand = (TypeSourceInfo*)nullptr; + } + + /// Determine whether this typeid has a type operand which is potentially + /// evaluated, per C++11 [expr.typeid]p3. + bool isPotentiallyEvaluated() const; + + bool isTypeOperand() const { return Operand.is<TypeSourceInfo *>(); } + + /// \brief Retrieves the type operand of this typeid() expression after + /// various required adjustments (removing reference types, cv-qualifiers). + QualType getTypeOperand(ASTContext &Context) const; + + /// \brief Retrieve source information for the type operand. + TypeSourceInfo *getTypeOperandSourceInfo() const { + assert(isTypeOperand() && "Cannot call getTypeOperand for typeid(expr)"); + return Operand.get<TypeSourceInfo *>(); + } + + void setTypeOperandSourceInfo(TypeSourceInfo *TSI) { + assert(isTypeOperand() && "Cannot call getTypeOperand for typeid(expr)"); + Operand = TSI; + } + + Expr *getExprOperand() const { + assert(!isTypeOperand() && "Cannot call getExprOperand for typeid(type)"); + return static_cast<Expr*>(Operand.get<Stmt *>()); + } + + void setExprOperand(Expr *E) { + assert(!isTypeOperand() && "Cannot call getExprOperand for typeid(type)"); + Operand = E; + } + + SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } + SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } + SourceRange getSourceRange() const LLVM_READONLY { return Range; } + void setSourceRange(SourceRange R) { Range = R; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXTypeidExprClass; + } + + // Iterators + child_range children() { + if (isTypeOperand()) + return child_range(child_iterator(), child_iterator()); + Stmt **begin = reinterpret_cast<Stmt**>(&Operand); + return child_range(begin, begin + 1); + } +}; + +/// \brief A member reference to an MSPropertyDecl. +/// +/// This expression always has pseudo-object type, and therefore it is +/// typically not encountered in a fully-typechecked expression except +/// within the syntactic form of a PseudoObjectExpr. +class MSPropertyRefExpr : public Expr { + Expr *BaseExpr; + MSPropertyDecl *TheDecl; + SourceLocation MemberLoc; + bool IsArrow; + NestedNameSpecifierLoc QualifierLoc; + +public: + MSPropertyRefExpr(Expr *baseExpr, MSPropertyDecl *decl, bool isArrow, + QualType ty, ExprValueKind VK, + NestedNameSpecifierLoc qualifierLoc, + SourceLocation nameLoc) + : Expr(MSPropertyRefExprClass, ty, VK, OK_Ordinary, + /*type-dependent*/ false, baseExpr->isValueDependent(), + baseExpr->isInstantiationDependent(), + baseExpr->containsUnexpandedParameterPack()), + BaseExpr(baseExpr), TheDecl(decl), + MemberLoc(nameLoc), IsArrow(isArrow), + QualifierLoc(qualifierLoc) {} + + MSPropertyRefExpr(EmptyShell Empty) : Expr(MSPropertyRefExprClass, Empty) {} + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(getLocStart(), getLocEnd()); + } + bool isImplicitAccess() const { + return getBaseExpr() && getBaseExpr()->isImplicitCXXThis(); + } + SourceLocation getLocStart() const { + if (!isImplicitAccess()) + return BaseExpr->getLocStart(); + else if (QualifierLoc) + return QualifierLoc.getBeginLoc(); + else + return MemberLoc; + } + SourceLocation getLocEnd() const { return getMemberLoc(); } + + child_range children() { + return child_range((Stmt**)&BaseExpr, (Stmt**)&BaseExpr + 1); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == MSPropertyRefExprClass; + } + + Expr *getBaseExpr() const { return BaseExpr; } + MSPropertyDecl *getPropertyDecl() const { return TheDecl; } + bool isArrow() const { return IsArrow; } + SourceLocation getMemberLoc() const { return MemberLoc; } + NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } + + friend class ASTStmtReader; +}; + +/// MS property subscript expression. +/// MSVC supports 'property' attribute and allows to apply it to the +/// declaration of an empty array in a class or structure definition. +/// For example: +/// \code +/// __declspec(property(get=GetX, put=PutX)) int x[]; +/// \endcode +/// The above statement indicates that x[] can be used with one or more array +/// indices. In this case, i=p->x[a][b] will be turned into i=p->GetX(a, b), and +/// p->x[a][b] = i will be turned into p->PutX(a, b, i). +/// This is a syntactic pseudo-object expression. +class MSPropertySubscriptExpr : public Expr { + friend class ASTStmtReader; + enum { BASE_EXPR, IDX_EXPR, NUM_SUBEXPRS = 2 }; + Stmt *SubExprs[NUM_SUBEXPRS]; + SourceLocation RBracketLoc; + + void setBase(Expr *Base) { SubExprs[BASE_EXPR] = Base; } + void setIdx(Expr *Idx) { SubExprs[IDX_EXPR] = Idx; } + +public: + MSPropertySubscriptExpr(Expr *Base, Expr *Idx, QualType Ty, ExprValueKind VK, + ExprObjectKind OK, SourceLocation RBracketLoc) + : Expr(MSPropertySubscriptExprClass, Ty, VK, OK, Idx->isTypeDependent(), + Idx->isValueDependent(), Idx->isInstantiationDependent(), + Idx->containsUnexpandedParameterPack()), + RBracketLoc(RBracketLoc) { + SubExprs[BASE_EXPR] = Base; + SubExprs[IDX_EXPR] = Idx; + } + + /// \brief Create an empty array subscript expression. + explicit MSPropertySubscriptExpr(EmptyShell Shell) + : Expr(MSPropertySubscriptExprClass, Shell) {} + + Expr *getBase() { return cast<Expr>(SubExprs[BASE_EXPR]); } + const Expr *getBase() const { return cast<Expr>(SubExprs[BASE_EXPR]); } + + Expr *getIdx() { return cast<Expr>(SubExprs[IDX_EXPR]); } + const Expr *getIdx() const { return cast<Expr>(SubExprs[IDX_EXPR]); } + + SourceLocation getLocStart() const LLVM_READONLY { + return getBase()->getLocStart(); + } + SourceLocation getLocEnd() const LLVM_READONLY { return RBracketLoc; } + + SourceLocation getRBracketLoc() const { return RBracketLoc; } + void setRBracketLoc(SourceLocation L) { RBracketLoc = L; } + + SourceLocation getExprLoc() const LLVM_READONLY { + return getBase()->getExprLoc(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == MSPropertySubscriptExprClass; + } + + // Iterators + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0] + NUM_SUBEXPRS); + } +}; + +/// A Microsoft C++ @c __uuidof expression, which gets +/// the _GUID that corresponds to the supplied type or expression. +/// +/// This represents code like @c __uuidof(COMTYPE) or @c __uuidof(*comPtr) +class CXXUuidofExpr : public Expr { +private: + llvm::PointerUnion<Stmt *, TypeSourceInfo *> Operand; + SourceRange Range; + +public: + CXXUuidofExpr(QualType Ty, TypeSourceInfo *Operand, SourceRange R) + : Expr(CXXUuidofExprClass, Ty, VK_LValue, OK_Ordinary, + false, Operand->getType()->isDependentType(), + Operand->getType()->isInstantiationDependentType(), + Operand->getType()->containsUnexpandedParameterPack()), + Operand(Operand), Range(R) { } + + CXXUuidofExpr(QualType Ty, Expr *Operand, SourceRange R) + : Expr(CXXUuidofExprClass, Ty, VK_LValue, OK_Ordinary, + false, Operand->isTypeDependent(), + Operand->isInstantiationDependent(), + Operand->containsUnexpandedParameterPack()), + Operand(Operand), Range(R) { } + + CXXUuidofExpr(EmptyShell Empty, bool isExpr) + : Expr(CXXUuidofExprClass, Empty) { + if (isExpr) + Operand = (Expr*)nullptr; + else + Operand = (TypeSourceInfo*)nullptr; + } + + bool isTypeOperand() const { return Operand.is<TypeSourceInfo *>(); } + + /// \brief Retrieves the type operand of this __uuidof() expression after + /// various required adjustments (removing reference types, cv-qualifiers). + QualType getTypeOperand(ASTContext &Context) const; + + /// \brief Retrieve source information for the type operand. + TypeSourceInfo *getTypeOperandSourceInfo() const { + assert(isTypeOperand() && "Cannot call getTypeOperand for __uuidof(expr)"); + return Operand.get<TypeSourceInfo *>(); + } + + void setTypeOperandSourceInfo(TypeSourceInfo *TSI) { + assert(isTypeOperand() && "Cannot call getTypeOperand for __uuidof(expr)"); + Operand = TSI; + } + + Expr *getExprOperand() const { + assert(!isTypeOperand() && "Cannot call getExprOperand for __uuidof(type)"); + return static_cast<Expr*>(Operand.get<Stmt *>()); + } + + void setExprOperand(Expr *E) { + assert(!isTypeOperand() && "Cannot call getExprOperand for __uuidof(type)"); + Operand = E; + } + + StringRef getUuidAsStringRef(ASTContext &Context) const; + + SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } + SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } + SourceRange getSourceRange() const LLVM_READONLY { return Range; } + void setSourceRange(SourceRange R) { Range = R; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXUuidofExprClass; + } + + /// Grabs __declspec(uuid()) off a type, or returns 0 if we cannot resolve to + /// a single GUID. + static const UuidAttr *GetUuidAttrOfType(QualType QT, + bool *HasMultipleGUIDsPtr = nullptr); + + // Iterators + child_range children() { + if (isTypeOperand()) + return child_range(child_iterator(), child_iterator()); + Stmt **begin = reinterpret_cast<Stmt**>(&Operand); + return child_range(begin, begin + 1); + } +}; + +/// \brief Represents the \c this expression in C++. +/// +/// This is a pointer to the object on which the current member function is +/// executing (C++ [expr.prim]p3). Example: +/// +/// \code +/// class Foo { +/// public: +/// void bar(); +/// void test() { this->bar(); } +/// }; +/// \endcode +class CXXThisExpr : public Expr { + SourceLocation Loc; + bool Implicit : 1; + +public: + CXXThisExpr(SourceLocation L, QualType Type, bool isImplicit) + : Expr(CXXThisExprClass, Type, VK_RValue, OK_Ordinary, + // 'this' is type-dependent if the class type of the enclosing + // member function is dependent (C++ [temp.dep.expr]p2) + Type->isDependentType(), Type->isDependentType(), + Type->isInstantiationDependentType(), + /*ContainsUnexpandedParameterPack=*/false), + Loc(L), Implicit(isImplicit) { } + + CXXThisExpr(EmptyShell Empty) : Expr(CXXThisExprClass, Empty) {} + + SourceLocation getLocation() const { return Loc; } + void setLocation(SourceLocation L) { Loc = L; } + + SourceLocation getLocStart() const LLVM_READONLY { return Loc; } + SourceLocation getLocEnd() const LLVM_READONLY { return Loc; } + + bool isImplicit() const { return Implicit; } + void setImplicit(bool I) { Implicit = I; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXThisExprClass; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +/// \brief A C++ throw-expression (C++ [except.throw]). +/// +/// This handles 'throw' (for re-throwing the current exception) and +/// 'throw' assignment-expression. When assignment-expression isn't +/// present, Op will be null. +class CXXThrowExpr : public Expr { + Stmt *Op; + SourceLocation ThrowLoc; + /// \brief Whether the thrown variable (if any) is in scope. + unsigned IsThrownVariableInScope : 1; + + friend class ASTStmtReader; + +public: + // \p Ty is the void type which is used as the result type of the + // expression. The \p l is the location of the throw keyword. \p expr + // can by null, if the optional expression to throw isn't present. + CXXThrowExpr(Expr *expr, QualType Ty, SourceLocation l, + bool IsThrownVariableInScope) : + Expr(CXXThrowExprClass, Ty, VK_RValue, OK_Ordinary, false, false, + expr && expr->isInstantiationDependent(), + expr && expr->containsUnexpandedParameterPack()), + Op(expr), ThrowLoc(l), IsThrownVariableInScope(IsThrownVariableInScope) {} + CXXThrowExpr(EmptyShell Empty) : Expr(CXXThrowExprClass, Empty) {} + + const Expr *getSubExpr() const { return cast_or_null<Expr>(Op); } + Expr *getSubExpr() { return cast_or_null<Expr>(Op); } + + SourceLocation getThrowLoc() const { return ThrowLoc; } + + /// \brief Determines whether the variable thrown by this expression (if any!) + /// is within the innermost try block. + /// + /// This information is required to determine whether the NRVO can apply to + /// this variable. + bool isThrownVariableInScope() const { return IsThrownVariableInScope; } + + SourceLocation getLocStart() const LLVM_READONLY { return ThrowLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { + if (!getSubExpr()) + return ThrowLoc; + return getSubExpr()->getLocEnd(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXThrowExprClass; + } + + // Iterators + child_range children() { + return child_range(&Op, Op ? &Op+1 : &Op); + } +}; + +/// \brief A default argument (C++ [dcl.fct.default]). +/// +/// This wraps up a function call argument that was created from the +/// corresponding parameter's default argument, when the call did not +/// explicitly supply arguments for all of the parameters. +class CXXDefaultArgExpr final + : public Expr, + private llvm::TrailingObjects<CXXDefaultArgExpr, Expr *> { + /// \brief The parameter whose default is being used. + /// + /// When the bit is set, the subexpression is stored after the + /// CXXDefaultArgExpr itself. When the bit is clear, the parameter's + /// actual default expression is the subexpression. + llvm::PointerIntPair<ParmVarDecl *, 1, bool> Param; + + /// \brief The location where the default argument expression was used. + SourceLocation Loc; + + CXXDefaultArgExpr(StmtClass SC, SourceLocation Loc, ParmVarDecl *param) + : Expr(SC, + param->hasUnparsedDefaultArg() + ? param->getType().getNonReferenceType() + : param->getDefaultArg()->getType(), + param->getDefaultArg()->getValueKind(), + param->getDefaultArg()->getObjectKind(), false, false, false, false), + Param(param, false), Loc(Loc) { } + + CXXDefaultArgExpr(StmtClass SC, SourceLocation Loc, ParmVarDecl *param, + Expr *SubExpr) + : Expr(SC, SubExpr->getType(), + SubExpr->getValueKind(), SubExpr->getObjectKind(), + false, false, false, false), + Param(param, true), Loc(Loc) { + *getTrailingObjects<Expr *>() = SubExpr; + } + +public: + CXXDefaultArgExpr(EmptyShell Empty) : Expr(CXXDefaultArgExprClass, Empty) {} + + // \p Param is the parameter whose default argument is used by this + // expression. + static CXXDefaultArgExpr *Create(const ASTContext &C, SourceLocation Loc, + ParmVarDecl *Param) { + return new (C) CXXDefaultArgExpr(CXXDefaultArgExprClass, Loc, Param); + } + + // \p Param is the parameter whose default argument is used by this + // expression, and \p SubExpr is the expression that will actually be used. + static CXXDefaultArgExpr *Create(const ASTContext &C, SourceLocation Loc, + ParmVarDecl *Param, Expr *SubExpr); + + // Retrieve the parameter that the argument was created from. + const ParmVarDecl *getParam() const { return Param.getPointer(); } + ParmVarDecl *getParam() { return Param.getPointer(); } + + // Retrieve the actual argument to the function call. + const Expr *getExpr() const { + if (Param.getInt()) + return *getTrailingObjects<Expr *>(); + return getParam()->getDefaultArg(); + } + Expr *getExpr() { + if (Param.getInt()) + return *getTrailingObjects<Expr *>(); + return getParam()->getDefaultArg(); + } + + /// \brief Retrieve the location where this default argument was actually + /// used. + SourceLocation getUsedLocation() const { return Loc; } + + /// Default argument expressions have no representation in the + /// source, so they have an empty source range. + SourceLocation getLocStart() const LLVM_READONLY { return SourceLocation(); } + SourceLocation getLocEnd() const LLVM_READONLY { return SourceLocation(); } + + SourceLocation getExprLoc() const LLVM_READONLY { return Loc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXDefaultArgExprClass; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + + friend TrailingObjects; + friend class ASTStmtReader; + friend class ASTStmtWriter; +}; + +/// \brief A use of a default initializer in a constructor or in aggregate +/// initialization. +/// +/// This wraps a use of a C++ default initializer (technically, +/// a brace-or-equal-initializer for a non-static data member) when it +/// is implicitly used in a mem-initializer-list in a constructor +/// (C++11 [class.base.init]p8) or in aggregate initialization +/// (C++1y [dcl.init.aggr]p7). +class CXXDefaultInitExpr : public Expr { + /// \brief The field whose default is being used. + FieldDecl *Field; + + /// \brief The location where the default initializer expression was used. + SourceLocation Loc; + + CXXDefaultInitExpr(const ASTContext &C, SourceLocation Loc, FieldDecl *Field, + QualType T); + + CXXDefaultInitExpr(EmptyShell Empty) : Expr(CXXDefaultInitExprClass, Empty) {} + +public: + /// \p Field is the non-static data member whose default initializer is used + /// by this expression. + static CXXDefaultInitExpr *Create(const ASTContext &C, SourceLocation Loc, + FieldDecl *Field) { + return new (C) CXXDefaultInitExpr(C, Loc, Field, Field->getType()); + } + + /// \brief Get the field whose initializer will be used. + FieldDecl *getField() { return Field; } + const FieldDecl *getField() const { return Field; } + + /// \brief Get the initialization expression that will be used. + const Expr *getExpr() const { + assert(Field->getInClassInitializer() && "initializer hasn't been parsed"); + return Field->getInClassInitializer(); + } + Expr *getExpr() { + assert(Field->getInClassInitializer() && "initializer hasn't been parsed"); + return Field->getInClassInitializer(); + } + + SourceLocation getLocStart() const LLVM_READONLY { return Loc; } + SourceLocation getLocEnd() const LLVM_READONLY { return Loc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXDefaultInitExprClass; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + + friend class ASTReader; + friend class ASTStmtReader; +}; + +/// \brief Represents a C++ temporary. +class CXXTemporary { + /// \brief The destructor that needs to be called. + const CXXDestructorDecl *Destructor; + + explicit CXXTemporary(const CXXDestructorDecl *destructor) + : Destructor(destructor) { } + +public: + static CXXTemporary *Create(const ASTContext &C, + const CXXDestructorDecl *Destructor); + + const CXXDestructorDecl *getDestructor() const { return Destructor; } + void setDestructor(const CXXDestructorDecl *Dtor) { + Destructor = Dtor; + } +}; + +/// \brief Represents binding an expression to a temporary. +/// +/// This ensures the destructor is called for the temporary. It should only be +/// needed for non-POD, non-trivially destructable class types. For example: +/// +/// \code +/// struct S { +/// S() { } // User defined constructor makes S non-POD. +/// ~S() { } // User defined destructor makes it non-trivial. +/// }; +/// void test() { +/// const S &s_ref = S(); // Requires a CXXBindTemporaryExpr. +/// } +/// \endcode +class CXXBindTemporaryExpr : public Expr { + CXXTemporary *Temp; + + Stmt *SubExpr; + + CXXBindTemporaryExpr(CXXTemporary *temp, Expr* SubExpr) + : Expr(CXXBindTemporaryExprClass, SubExpr->getType(), + VK_RValue, OK_Ordinary, SubExpr->isTypeDependent(), + SubExpr->isValueDependent(), + SubExpr->isInstantiationDependent(), + SubExpr->containsUnexpandedParameterPack()), + Temp(temp), SubExpr(SubExpr) { } + +public: + CXXBindTemporaryExpr(EmptyShell Empty) + : Expr(CXXBindTemporaryExprClass, Empty), Temp(nullptr), SubExpr(nullptr) {} + + static CXXBindTemporaryExpr *Create(const ASTContext &C, CXXTemporary *Temp, + Expr* SubExpr); + + CXXTemporary *getTemporary() { return Temp; } + const CXXTemporary *getTemporary() const { return Temp; } + void setTemporary(CXXTemporary *T) { Temp = T; } + + const Expr *getSubExpr() const { return cast<Expr>(SubExpr); } + Expr *getSubExpr() { return cast<Expr>(SubExpr); } + void setSubExpr(Expr *E) { SubExpr = E; } + + SourceLocation getLocStart() const LLVM_READONLY { + return SubExpr->getLocStart(); + } + SourceLocation getLocEnd() const LLVM_READONLY { return SubExpr->getLocEnd();} + + // Implement isa/cast/dyncast/etc. + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXBindTemporaryExprClass; + } + + // Iterators + child_range children() { return child_range(&SubExpr, &SubExpr + 1); } +}; + +/// \brief Represents a call to a C++ constructor. +class CXXConstructExpr : public Expr { +public: + enum ConstructionKind { + CK_Complete, + CK_NonVirtualBase, + CK_VirtualBase, + CK_Delegating + }; + +private: + CXXConstructorDecl *Constructor; + + SourceLocation Loc; + SourceRange ParenOrBraceRange; + unsigned NumArgs : 16; + bool Elidable : 1; + bool HadMultipleCandidates : 1; + bool ListInitialization : 1; + bool StdInitListInitialization : 1; + bool ZeroInitialization : 1; + unsigned ConstructKind : 2; + Stmt **Args; + +protected: + CXXConstructExpr(const ASTContext &C, StmtClass SC, QualType T, + SourceLocation Loc, + CXXConstructorDecl *d, bool elidable, + ArrayRef<Expr *> Args, + bool HadMultipleCandidates, + bool ListInitialization, + bool StdInitListInitialization, + bool ZeroInitialization, + ConstructionKind ConstructKind, + SourceRange ParenOrBraceRange); + + /// \brief Construct an empty C++ construction expression. + CXXConstructExpr(StmtClass SC, EmptyShell Empty) + : Expr(SC, Empty), Constructor(nullptr), NumArgs(0), Elidable(false), + HadMultipleCandidates(false), ListInitialization(false), + ZeroInitialization(false), ConstructKind(0), Args(nullptr) + { } + +public: + /// \brief Construct an empty C++ construction expression. + explicit CXXConstructExpr(EmptyShell Empty) + : Expr(CXXConstructExprClass, Empty), Constructor(nullptr), + NumArgs(0), Elidable(false), HadMultipleCandidates(false), + ListInitialization(false), ZeroInitialization(false), + ConstructKind(0), Args(nullptr) + { } + + static CXXConstructExpr *Create(const ASTContext &C, QualType T, + SourceLocation Loc, + CXXConstructorDecl *D, bool Elidable, + ArrayRef<Expr *> Args, + bool HadMultipleCandidates, + bool ListInitialization, + bool StdInitListInitialization, + bool ZeroInitialization, + ConstructionKind ConstructKind, + SourceRange ParenOrBraceRange); + + CXXConstructorDecl *getConstructor() const { return Constructor; } + void setConstructor(CXXConstructorDecl *C) { Constructor = C; } + + SourceLocation getLocation() const { return Loc; } + void setLocation(SourceLocation Loc) { this->Loc = Loc; } + + /// \brief Whether this construction is elidable. + bool isElidable() const { return Elidable; } + void setElidable(bool E) { Elidable = E; } + + /// \brief Whether the referred constructor was resolved from + /// an overloaded set having size greater than 1. + bool hadMultipleCandidates() const { return HadMultipleCandidates; } + void setHadMultipleCandidates(bool V) { HadMultipleCandidates = V; } + + /// \brief Whether this constructor call was written as list-initialization. + bool isListInitialization() const { return ListInitialization; } + void setListInitialization(bool V) { ListInitialization = V; } + + /// \brief Whether this constructor call was written as list-initialization, + /// but was interpreted as forming a std::initializer_list<T> from the list + /// and passing that as a single constructor argument. + /// See C++11 [over.match.list]p1 bullet 1. + bool isStdInitListInitialization() const { return StdInitListInitialization; } + void setStdInitListInitialization(bool V) { StdInitListInitialization = V; } + + /// \brief Whether this construction first requires + /// zero-initialization before the initializer is called. + bool requiresZeroInitialization() const { return ZeroInitialization; } + void setRequiresZeroInitialization(bool ZeroInit) { + ZeroInitialization = ZeroInit; + } + + /// \brief Determine whether this constructor is actually constructing + /// a base class (rather than a complete object). + ConstructionKind getConstructionKind() const { + return (ConstructionKind)ConstructKind; + } + void setConstructionKind(ConstructionKind CK) { + ConstructKind = CK; + } + + typedef ExprIterator arg_iterator; + typedef ConstExprIterator const_arg_iterator; + typedef llvm::iterator_range<arg_iterator> arg_range; + typedef llvm::iterator_range<const_arg_iterator> arg_const_range; + + arg_range arguments() { return arg_range(arg_begin(), arg_end()); } + arg_const_range arguments() const { + return arg_const_range(arg_begin(), arg_end()); + } + + arg_iterator arg_begin() { return Args; } + arg_iterator arg_end() { return Args + NumArgs; } + const_arg_iterator arg_begin() const { return Args; } + const_arg_iterator arg_end() const { return Args + NumArgs; } + + Expr **getArgs() { return reinterpret_cast<Expr **>(Args); } + const Expr *const *getArgs() const { + return const_cast<CXXConstructExpr *>(this)->getArgs(); + } + unsigned getNumArgs() const { return NumArgs; } + + /// \brief Return the specified argument. + Expr *getArg(unsigned Arg) { + assert(Arg < NumArgs && "Arg access out of range!"); + return cast<Expr>(Args[Arg]); + } + const Expr *getArg(unsigned Arg) const { + assert(Arg < NumArgs && "Arg access out of range!"); + return cast<Expr>(Args[Arg]); + } + + /// \brief Set the specified argument. + void setArg(unsigned Arg, Expr *ArgExpr) { + assert(Arg < NumArgs && "Arg access out of range!"); + Args[Arg] = ArgExpr; + } + + SourceLocation getLocStart() const LLVM_READONLY; + SourceLocation getLocEnd() const LLVM_READONLY; + SourceRange getParenOrBraceRange() const { return ParenOrBraceRange; } + void setParenOrBraceRange(SourceRange Range) { ParenOrBraceRange = Range; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXConstructExprClass || + T->getStmtClass() == CXXTemporaryObjectExprClass; + } + + // Iterators + child_range children() { + return child_range(&Args[0], &Args[0]+NumArgs); + } + + friend class ASTStmtReader; +}; + +/// \brief Represents an explicit C++ type conversion that uses "functional" +/// notation (C++ [expr.type.conv]). +/// +/// Example: +/// \code +/// x = int(0.5); +/// \endcode +class CXXFunctionalCastExpr final + : public ExplicitCastExpr, + private llvm::TrailingObjects<CXXFunctionalCastExpr, CXXBaseSpecifier *> { + SourceLocation LParenLoc; + SourceLocation RParenLoc; + + CXXFunctionalCastExpr(QualType ty, ExprValueKind VK, + TypeSourceInfo *writtenTy, + CastKind kind, Expr *castExpr, unsigned pathSize, + SourceLocation lParenLoc, SourceLocation rParenLoc) + : ExplicitCastExpr(CXXFunctionalCastExprClass, ty, VK, kind, + castExpr, pathSize, writtenTy), + LParenLoc(lParenLoc), RParenLoc(rParenLoc) {} + + explicit CXXFunctionalCastExpr(EmptyShell Shell, unsigned PathSize) + : ExplicitCastExpr(CXXFunctionalCastExprClass, Shell, PathSize) { } + +public: + static CXXFunctionalCastExpr *Create(const ASTContext &Context, QualType T, + ExprValueKind VK, + TypeSourceInfo *Written, + CastKind Kind, Expr *Op, + const CXXCastPath *Path, + SourceLocation LPLoc, + SourceLocation RPLoc); + static CXXFunctionalCastExpr *CreateEmpty(const ASTContext &Context, + unsigned PathSize); + + SourceLocation getLParenLoc() const { return LParenLoc; } + void setLParenLoc(SourceLocation L) { LParenLoc = L; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + SourceLocation getLocStart() const LLVM_READONLY; + SourceLocation getLocEnd() const LLVM_READONLY; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXFunctionalCastExprClass; + } + + friend TrailingObjects; + friend class CastExpr; +}; + +/// @brief Represents a C++ functional cast expression that builds a +/// temporary object. +/// +/// This expression type represents a C++ "functional" cast +/// (C++[expr.type.conv]) with N != 1 arguments that invokes a +/// constructor to build a temporary object. With N == 1 arguments the +/// functional cast expression will be represented by CXXFunctionalCastExpr. +/// Example: +/// \code +/// struct X { X(int, float); } +/// +/// X create_X() { +/// return X(1, 3.14f); // creates a CXXTemporaryObjectExpr +/// }; +/// \endcode +class CXXTemporaryObjectExpr : public CXXConstructExpr { + TypeSourceInfo *Type; + +public: + CXXTemporaryObjectExpr(const ASTContext &C, CXXConstructorDecl *Cons, + TypeSourceInfo *Type, + ArrayRef<Expr *> Args, + SourceRange ParenOrBraceRange, + bool HadMultipleCandidates, + bool ListInitialization, + bool StdInitListInitialization, + bool ZeroInitialization); + explicit CXXTemporaryObjectExpr(EmptyShell Empty) + : CXXConstructExpr(CXXTemporaryObjectExprClass, Empty), Type() { } + + TypeSourceInfo *getTypeSourceInfo() const { return Type; } + + SourceLocation getLocStart() const LLVM_READONLY; + SourceLocation getLocEnd() const LLVM_READONLY; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXTemporaryObjectExprClass; + } + + friend class ASTStmtReader; +}; + +/// \brief A C++ lambda expression, which produces a function object +/// (of unspecified type) that can be invoked later. +/// +/// Example: +/// \code +/// void low_pass_filter(std::vector<double> &values, double cutoff) { +/// values.erase(std::remove_if(values.begin(), values.end(), +/// [=](double value) { return value > cutoff; }); +/// } +/// \endcode +/// +/// C++11 lambda expressions can capture local variables, either by copying +/// the values of those local variables at the time the function +/// object is constructed (not when it is called!) or by holding a +/// reference to the local variable. These captures can occur either +/// implicitly or can be written explicitly between the square +/// brackets ([...]) that start the lambda expression. +/// +/// C++1y introduces a new form of "capture" called an init-capture that +/// includes an initializing expression (rather than capturing a variable), +/// and which can never occur implicitly. +class LambdaExpr final + : public Expr, + private llvm::TrailingObjects<LambdaExpr, Stmt *, unsigned, VarDecl *> { + /// \brief The source range that covers the lambda introducer ([...]). + SourceRange IntroducerRange; + + /// \brief The source location of this lambda's capture-default ('=' or '&'). + SourceLocation CaptureDefaultLoc; + + /// \brief The number of captures. + unsigned NumCaptures : 16; + + /// \brief The default capture kind, which is a value of type + /// LambdaCaptureDefault. + unsigned CaptureDefault : 2; + + /// \brief Whether this lambda had an explicit parameter list vs. an + /// implicit (and empty) parameter list. + unsigned ExplicitParams : 1; + + /// \brief Whether this lambda had the result type explicitly specified. + unsigned ExplicitResultType : 1; + + /// \brief Whether there are any array index variables stored at the end of + /// this lambda expression. + unsigned HasArrayIndexVars : 1; + + /// \brief The location of the closing brace ('}') that completes + /// the lambda. + /// + /// The location of the brace is also available by looking up the + /// function call operator in the lambda class. However, it is + /// stored here to improve the performance of getSourceRange(), and + /// to avoid having to deserialize the function call operator from a + /// module file just to determine the source range. + SourceLocation ClosingBrace; + + size_t numTrailingObjects(OverloadToken<Stmt *>) const { + return NumCaptures + 1; + } + + size_t numTrailingObjects(OverloadToken<unsigned>) const { + return HasArrayIndexVars ? NumCaptures + 1 : 0; + } + + /// \brief Construct a lambda expression. + LambdaExpr(QualType T, SourceRange IntroducerRange, + LambdaCaptureDefault CaptureDefault, + SourceLocation CaptureDefaultLoc, ArrayRef<LambdaCapture> Captures, + bool ExplicitParams, bool ExplicitResultType, + ArrayRef<Expr *> CaptureInits, ArrayRef<VarDecl *> ArrayIndexVars, + ArrayRef<unsigned> ArrayIndexStarts, SourceLocation ClosingBrace, + bool ContainsUnexpandedParameterPack); + + /// \brief Construct an empty lambda expression. + LambdaExpr(EmptyShell Empty, unsigned NumCaptures, bool HasArrayIndexVars) + : Expr(LambdaExprClass, Empty), + NumCaptures(NumCaptures), CaptureDefault(LCD_None), ExplicitParams(false), + ExplicitResultType(false), HasArrayIndexVars(true) { + getStoredStmts()[NumCaptures] = nullptr; + } + + Stmt **getStoredStmts() { return getTrailingObjects<Stmt *>(); } + + Stmt *const *getStoredStmts() const { return getTrailingObjects<Stmt *>(); } + + /// \brief Retrieve the mapping from captures to the first array index + /// variable. + unsigned *getArrayIndexStarts() { return getTrailingObjects<unsigned>(); } + + const unsigned *getArrayIndexStarts() const { + return getTrailingObjects<unsigned>(); + } + + /// \brief Retrieve the complete set of array-index variables. + VarDecl **getArrayIndexVars() { return getTrailingObjects<VarDecl *>(); } + + VarDecl *const *getArrayIndexVars() const { + return getTrailingObjects<VarDecl *>(); + } + +public: + /// \brief Construct a new lambda expression. + static LambdaExpr * + Create(const ASTContext &C, CXXRecordDecl *Class, SourceRange IntroducerRange, + LambdaCaptureDefault CaptureDefault, SourceLocation CaptureDefaultLoc, + ArrayRef<LambdaCapture> Captures, bool ExplicitParams, + bool ExplicitResultType, ArrayRef<Expr *> CaptureInits, + ArrayRef<VarDecl *> ArrayIndexVars, + ArrayRef<unsigned> ArrayIndexStarts, SourceLocation ClosingBrace, + bool ContainsUnexpandedParameterPack); + + /// \brief Construct a new lambda expression that will be deserialized from + /// an external source. + static LambdaExpr *CreateDeserialized(const ASTContext &C, + unsigned NumCaptures, + unsigned NumArrayIndexVars); + + /// \brief Determine the default capture kind for this lambda. + LambdaCaptureDefault getCaptureDefault() const { + return static_cast<LambdaCaptureDefault>(CaptureDefault); + } + + /// \brief Retrieve the location of this lambda's capture-default, if any. + SourceLocation getCaptureDefaultLoc() const { + return CaptureDefaultLoc; + } + + /// \brief Determine whether one of this lambda's captures is an init-capture. + bool isInitCapture(const LambdaCapture *Capture) const; + + /// \brief An iterator that walks over the captures of the lambda, + /// both implicit and explicit. + typedef const LambdaCapture *capture_iterator; + + /// \brief An iterator over a range of lambda captures. + typedef llvm::iterator_range<capture_iterator> capture_range; + + /// \brief Retrieve this lambda's captures. + capture_range captures() const; + + /// \brief Retrieve an iterator pointing to the first lambda capture. + capture_iterator capture_begin() const; + + /// \brief Retrieve an iterator pointing past the end of the + /// sequence of lambda captures. + capture_iterator capture_end() const; + + /// \brief Determine the number of captures in this lambda. + unsigned capture_size() const { return NumCaptures; } + + /// \brief Retrieve this lambda's explicit captures. + capture_range explicit_captures() const; + + /// \brief Retrieve an iterator pointing to the first explicit + /// lambda capture. + capture_iterator explicit_capture_begin() const; + + /// \brief Retrieve an iterator pointing past the end of the sequence of + /// explicit lambda captures. + capture_iterator explicit_capture_end() const; + + /// \brief Retrieve this lambda's implicit captures. + capture_range implicit_captures() const; + + /// \brief Retrieve an iterator pointing to the first implicit + /// lambda capture. + capture_iterator implicit_capture_begin() const; + + /// \brief Retrieve an iterator pointing past the end of the sequence of + /// implicit lambda captures. + capture_iterator implicit_capture_end() const; + + /// \brief Iterator that walks over the capture initialization + /// arguments. + typedef Expr **capture_init_iterator; + + /// \brief Const iterator that walks over the capture initialization + /// arguments. + typedef Expr *const *const_capture_init_iterator; + + /// \brief Retrieve the initialization expressions for this lambda's captures. + llvm::iterator_range<capture_init_iterator> capture_inits() { + return llvm::make_range(capture_init_begin(), capture_init_end()); + } + + /// \brief Retrieve the initialization expressions for this lambda's captures. + llvm::iterator_range<const_capture_init_iterator> capture_inits() const { + return llvm::make_range(capture_init_begin(), capture_init_end()); + } + + /// \brief Retrieve the first initialization argument for this + /// lambda expression (which initializes the first capture field). + capture_init_iterator capture_init_begin() { + return reinterpret_cast<Expr **>(getStoredStmts()); + } + + /// \brief Retrieve the first initialization argument for this + /// lambda expression (which initializes the first capture field). + const_capture_init_iterator capture_init_begin() const { + return reinterpret_cast<Expr *const *>(getStoredStmts()); + } + + /// \brief Retrieve the iterator pointing one past the last + /// initialization argument for this lambda expression. + capture_init_iterator capture_init_end() { + return capture_init_begin() + NumCaptures; + } + + /// \brief Retrieve the iterator pointing one past the last + /// initialization argument for this lambda expression. + const_capture_init_iterator capture_init_end() const { + return capture_init_begin() + NumCaptures; + } + + /// \brief Retrieve the set of index variables used in the capture + /// initializer of an array captured by copy. + /// + /// \param Iter The iterator that points at the capture initializer for + /// which we are extracting the corresponding index variables. + ArrayRef<VarDecl *> + getCaptureInitIndexVars(const_capture_init_iterator Iter) const; + + /// \brief Retrieve the source range covering the lambda introducer, + /// which contains the explicit capture list surrounded by square + /// brackets ([...]). + SourceRange getIntroducerRange() const { return IntroducerRange; } + + /// \brief Retrieve the class that corresponds to the lambda. + /// + /// This is the "closure type" (C++1y [expr.prim.lambda]), and stores the + /// captures in its fields and provides the various operations permitted + /// on a lambda (copying, calling). + CXXRecordDecl *getLambdaClass() const; + + /// \brief Retrieve the function call operator associated with this + /// lambda expression. + CXXMethodDecl *getCallOperator() const; + + /// \brief If this is a generic lambda expression, retrieve the template + /// parameter list associated with it, or else return null. + TemplateParameterList *getTemplateParameterList() const; + + /// \brief Whether this is a generic lambda. + bool isGenericLambda() const { return getTemplateParameterList(); } + + /// \brief Retrieve the body of the lambda. + CompoundStmt *getBody() const; + + /// \brief Determine whether the lambda is mutable, meaning that any + /// captures values can be modified. + bool isMutable() const; + + /// \brief Determine whether this lambda has an explicit parameter + /// list vs. an implicit (empty) parameter list. + bool hasExplicitParameters() const { return ExplicitParams; } + + /// \brief Whether this lambda had its result type explicitly specified. + bool hasExplicitResultType() const { return ExplicitResultType; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == LambdaExprClass; + } + + SourceLocation getLocStart() const LLVM_READONLY { + return IntroducerRange.getBegin(); + } + SourceLocation getLocEnd() const LLVM_READONLY { return ClosingBrace; } + + child_range children() { + // Includes initialization exprs plus body stmt + return child_range(getStoredStmts(), getStoredStmts() + NumCaptures + 1); + } + + friend TrailingObjects; + friend class ASTStmtReader; + friend class ASTStmtWriter; +}; + +/// An expression "T()" which creates a value-initialized rvalue of type +/// T, which is a non-class type. See (C++98 [5.2.3p2]). +class CXXScalarValueInitExpr : public Expr { + SourceLocation RParenLoc; + TypeSourceInfo *TypeInfo; + + friend class ASTStmtReader; + +public: + /// \brief Create an explicitly-written scalar-value initialization + /// expression. + CXXScalarValueInitExpr(QualType Type, TypeSourceInfo *TypeInfo, + SourceLocation rParenLoc) + : Expr(CXXScalarValueInitExprClass, Type, VK_RValue, OK_Ordinary, + false, false, Type->isInstantiationDependentType(), + Type->containsUnexpandedParameterPack()), + RParenLoc(rParenLoc), TypeInfo(TypeInfo) {} + + explicit CXXScalarValueInitExpr(EmptyShell Shell) + : Expr(CXXScalarValueInitExprClass, Shell) { } + + TypeSourceInfo *getTypeSourceInfo() const { + return TypeInfo; + } + + SourceLocation getRParenLoc() const { return RParenLoc; } + + SourceLocation getLocStart() const LLVM_READONLY; + SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXScalarValueInitExprClass; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +/// \brief Represents a new-expression for memory allocation and constructor +/// calls, e.g: "new CXXNewExpr(foo)". +class CXXNewExpr : public Expr { + /// Contains an optional array size expression, an optional initialization + /// expression, and any number of optional placement arguments, in that order. + Stmt **SubExprs; + /// \brief Points to the allocation function used. + FunctionDecl *OperatorNew; + /// \brief Points to the deallocation function used in case of error. May be + /// null. + FunctionDecl *OperatorDelete; + + /// \brief The allocated type-source information, as written in the source. + TypeSourceInfo *AllocatedTypeInfo; + + /// \brief If the allocated type was expressed as a parenthesized type-id, + /// the source range covering the parenthesized type-id. + SourceRange TypeIdParens; + + /// \brief Range of the entire new expression. + SourceRange Range; + + /// \brief Source-range of a paren-delimited initializer. + SourceRange DirectInitRange; + + /// Was the usage ::new, i.e. is the global new to be used? + bool GlobalNew : 1; + /// Do we allocate an array? If so, the first SubExpr is the size expression. + bool Array : 1; + /// If this is an array allocation, does the usual deallocation + /// function for the allocated type want to know the allocated size? + bool UsualArrayDeleteWantsSize : 1; + /// The number of placement new arguments. + unsigned NumPlacementArgs : 13; + /// What kind of initializer do we have? Could be none, parens, or braces. + /// In storage, we distinguish between "none, and no initializer expr", and + /// "none, but an implicit initializer expr". + unsigned StoredInitializationStyle : 2; + + friend class ASTStmtReader; + friend class ASTStmtWriter; +public: + enum InitializationStyle { + NoInit, ///< New-expression has no initializer as written. + CallInit, ///< New-expression has a C++98 paren-delimited initializer. + ListInit ///< New-expression has a C++11 list-initializer. + }; + + CXXNewExpr(const ASTContext &C, bool globalNew, FunctionDecl *operatorNew, + FunctionDecl *operatorDelete, bool usualArrayDeleteWantsSize, + ArrayRef<Expr*> placementArgs, + SourceRange typeIdParens, Expr *arraySize, + InitializationStyle initializationStyle, Expr *initializer, + QualType ty, TypeSourceInfo *AllocatedTypeInfo, + SourceRange Range, SourceRange directInitRange); + explicit CXXNewExpr(EmptyShell Shell) + : Expr(CXXNewExprClass, Shell), SubExprs(nullptr) { } + + void AllocateArgsArray(const ASTContext &C, bool isArray, + unsigned numPlaceArgs, bool hasInitializer); + + QualType getAllocatedType() const { + assert(getType()->isPointerType()); + return getType()->getAs<PointerType>()->getPointeeType(); + } + + TypeSourceInfo *getAllocatedTypeSourceInfo() const { + return AllocatedTypeInfo; + } + + /// \brief True if the allocation result needs to be null-checked. + /// + /// C++11 [expr.new]p13: + /// If the allocation function returns null, initialization shall + /// not be done, the deallocation function shall not be called, + /// and the value of the new-expression shall be null. + /// + /// C++ DR1748: + /// If the allocation function is a reserved placement allocation + /// function that returns null, the behavior is undefined. + /// + /// An allocation function is not allowed to return null unless it + /// has a non-throwing exception-specification. The '03 rule is + /// identical except that the definition of a non-throwing + /// exception specification is just "is it throw()?". + bool shouldNullCheckAllocation(const ASTContext &Ctx) const; + + FunctionDecl *getOperatorNew() const { return OperatorNew; } + void setOperatorNew(FunctionDecl *D) { OperatorNew = D; } + FunctionDecl *getOperatorDelete() const { return OperatorDelete; } + void setOperatorDelete(FunctionDecl *D) { OperatorDelete = D; } + + bool isArray() const { return Array; } + Expr *getArraySize() { + return Array ? cast<Expr>(SubExprs[0]) : nullptr; + } + const Expr *getArraySize() const { + return Array ? cast<Expr>(SubExprs[0]) : nullptr; + } + + unsigned getNumPlacementArgs() const { return NumPlacementArgs; } + Expr **getPlacementArgs() { + return reinterpret_cast<Expr **>(SubExprs + Array + hasInitializer()); + } + + Expr *getPlacementArg(unsigned i) { + assert(i < NumPlacementArgs && "Index out of range"); + return getPlacementArgs()[i]; + } + const Expr *getPlacementArg(unsigned i) const { + assert(i < NumPlacementArgs && "Index out of range"); + return const_cast<CXXNewExpr*>(this)->getPlacementArg(i); + } + + bool isParenTypeId() const { return TypeIdParens.isValid(); } + SourceRange getTypeIdParens() const { return TypeIdParens; } + + bool isGlobalNew() const { return GlobalNew; } + + /// \brief Whether this new-expression has any initializer at all. + bool hasInitializer() const { return StoredInitializationStyle > 0; } + + /// \brief The kind of initializer this new-expression has. + InitializationStyle getInitializationStyle() const { + if (StoredInitializationStyle == 0) + return NoInit; + return static_cast<InitializationStyle>(StoredInitializationStyle-1); + } + + /// \brief The initializer of this new-expression. + Expr *getInitializer() { + return hasInitializer() ? cast<Expr>(SubExprs[Array]) : nullptr; + } + const Expr *getInitializer() const { + return hasInitializer() ? cast<Expr>(SubExprs[Array]) : nullptr; + } + + /// \brief Returns the CXXConstructExpr from this new-expression, or null. + const CXXConstructExpr* getConstructExpr() const { + return dyn_cast_or_null<CXXConstructExpr>(getInitializer()); + } + + /// Answers whether the usual array deallocation function for the + /// allocated type expects the size of the allocation as a + /// parameter. + bool doesUsualArrayDeleteWantSize() const { + return UsualArrayDeleteWantsSize; + } + + typedef ExprIterator arg_iterator; + typedef ConstExprIterator const_arg_iterator; + + llvm::iterator_range<arg_iterator> placement_arguments() { + return llvm::make_range(placement_arg_begin(), placement_arg_end()); + } + + llvm::iterator_range<const_arg_iterator> placement_arguments() const { + return llvm::make_range(placement_arg_begin(), placement_arg_end()); + } + + arg_iterator placement_arg_begin() { + return SubExprs + Array + hasInitializer(); + } + arg_iterator placement_arg_end() { + return SubExprs + Array + hasInitializer() + getNumPlacementArgs(); + } + const_arg_iterator placement_arg_begin() const { + return SubExprs + Array + hasInitializer(); + } + const_arg_iterator placement_arg_end() const { + return SubExprs + Array + hasInitializer() + getNumPlacementArgs(); + } + + typedef Stmt **raw_arg_iterator; + raw_arg_iterator raw_arg_begin() { return SubExprs; } + raw_arg_iterator raw_arg_end() { + return SubExprs + Array + hasInitializer() + getNumPlacementArgs(); + } + const_arg_iterator raw_arg_begin() const { return SubExprs; } + const_arg_iterator raw_arg_end() const { + return SubExprs + Array + hasInitializer() + getNumPlacementArgs(); + } + + SourceLocation getStartLoc() const { return Range.getBegin(); } + SourceLocation getEndLoc() const { return Range.getEnd(); } + + SourceRange getDirectInitRange() const { return DirectInitRange; } + + SourceRange getSourceRange() const LLVM_READONLY { + return Range; + } + SourceLocation getLocStart() const LLVM_READONLY { return getStartLoc(); } + SourceLocation getLocEnd() const LLVM_READONLY { return getEndLoc(); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXNewExprClass; + } + + // Iterators + child_range children() { + return child_range(raw_arg_begin(), raw_arg_end()); + } +}; + +/// \brief Represents a \c delete expression for memory deallocation and +/// destructor calls, e.g. "delete[] pArray". +class CXXDeleteExpr : public Expr { + /// Points to the operator delete overload that is used. Could be a member. + FunctionDecl *OperatorDelete; + /// The pointer expression to be deleted. + Stmt *Argument; + /// Location of the expression. + SourceLocation Loc; + /// Is this a forced global delete, i.e. "::delete"? + bool GlobalDelete : 1; + /// Is this the array form of delete, i.e. "delete[]"? + bool ArrayForm : 1; + /// ArrayFormAsWritten can be different from ArrayForm if 'delete' is applied + /// to pointer-to-array type (ArrayFormAsWritten will be false while ArrayForm + /// will be true). + bool ArrayFormAsWritten : 1; + /// Does the usual deallocation function for the element type require + /// a size_t argument? + bool UsualArrayDeleteWantsSize : 1; +public: + CXXDeleteExpr(QualType ty, bool globalDelete, bool arrayForm, + bool arrayFormAsWritten, bool usualArrayDeleteWantsSize, + FunctionDecl *operatorDelete, Expr *arg, SourceLocation loc) + : Expr(CXXDeleteExprClass, ty, VK_RValue, OK_Ordinary, false, false, + arg->isInstantiationDependent(), + arg->containsUnexpandedParameterPack()), + OperatorDelete(operatorDelete), Argument(arg), Loc(loc), + GlobalDelete(globalDelete), + ArrayForm(arrayForm), ArrayFormAsWritten(arrayFormAsWritten), + UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize) { } + explicit CXXDeleteExpr(EmptyShell Shell) + : Expr(CXXDeleteExprClass, Shell), OperatorDelete(nullptr), + Argument(nullptr) {} + + bool isGlobalDelete() const { return GlobalDelete; } + bool isArrayForm() const { return ArrayForm; } + bool isArrayFormAsWritten() const { return ArrayFormAsWritten; } + + /// Answers whether the usual array deallocation function for the + /// allocated type expects the size of the allocation as a + /// parameter. This can be true even if the actual deallocation + /// function that we're using doesn't want a size. + bool doesUsualArrayDeleteWantSize() const { + return UsualArrayDeleteWantsSize; + } + + FunctionDecl *getOperatorDelete() const { return OperatorDelete; } + + Expr *getArgument() { return cast<Expr>(Argument); } + const Expr *getArgument() const { return cast<Expr>(Argument); } + + /// \brief Retrieve the type being destroyed. + /// + /// If the type being destroyed is a dependent type which may or may not + /// be a pointer, return an invalid type. + QualType getDestroyedType() const; + + SourceLocation getLocStart() const LLVM_READONLY { return Loc; } + SourceLocation getLocEnd() const LLVM_READONLY {return Argument->getLocEnd();} + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXDeleteExprClass; + } + + // Iterators + child_range children() { return child_range(&Argument, &Argument+1); } + + friend class ASTStmtReader; +}; + +/// \brief Stores the type being destroyed by a pseudo-destructor expression. +class PseudoDestructorTypeStorage { + /// \brief Either the type source information or the name of the type, if + /// it couldn't be resolved due to type-dependence. + llvm::PointerUnion<TypeSourceInfo *, IdentifierInfo *> Type; + + /// \brief The starting source location of the pseudo-destructor type. + SourceLocation Location; + +public: + PseudoDestructorTypeStorage() { } + + PseudoDestructorTypeStorage(IdentifierInfo *II, SourceLocation Loc) + : Type(II), Location(Loc) { } + + PseudoDestructorTypeStorage(TypeSourceInfo *Info); + + TypeSourceInfo *getTypeSourceInfo() const { + return Type.dyn_cast<TypeSourceInfo *>(); + } + + IdentifierInfo *getIdentifier() const { + return Type.dyn_cast<IdentifierInfo *>(); + } + + SourceLocation getLocation() const { return Location; } +}; + +/// \brief Represents a C++ pseudo-destructor (C++ [expr.pseudo]). +/// +/// A pseudo-destructor is an expression that looks like a member access to a +/// destructor of a scalar type, except that scalar types don't have +/// destructors. For example: +/// +/// \code +/// typedef int T; +/// void f(int *p) { +/// p->T::~T(); +/// } +/// \endcode +/// +/// Pseudo-destructors typically occur when instantiating templates such as: +/// +/// \code +/// template<typename T> +/// void destroy(T* ptr) { +/// ptr->T::~T(); +/// } +/// \endcode +/// +/// for scalar types. A pseudo-destructor expression has no run-time semantics +/// beyond evaluating the base expression. +class CXXPseudoDestructorExpr : public Expr { + /// \brief The base expression (that is being destroyed). + Stmt *Base; + + /// \brief Whether the operator was an arrow ('->'); otherwise, it was a + /// period ('.'). + bool IsArrow : 1; + + /// \brief The location of the '.' or '->' operator. + SourceLocation OperatorLoc; + + /// \brief The nested-name-specifier that follows the operator, if present. + NestedNameSpecifierLoc QualifierLoc; + + /// \brief The type that precedes the '::' in a qualified pseudo-destructor + /// expression. + TypeSourceInfo *ScopeType; + + /// \brief The location of the '::' in a qualified pseudo-destructor + /// expression. + SourceLocation ColonColonLoc; + + /// \brief The location of the '~'. + SourceLocation TildeLoc; + + /// \brief The type being destroyed, or its name if we were unable to + /// resolve the name. + PseudoDestructorTypeStorage DestroyedType; + + friend class ASTStmtReader; + +public: + CXXPseudoDestructorExpr(const ASTContext &Context, + Expr *Base, bool isArrow, SourceLocation OperatorLoc, + NestedNameSpecifierLoc QualifierLoc, + TypeSourceInfo *ScopeType, + SourceLocation ColonColonLoc, + SourceLocation TildeLoc, + PseudoDestructorTypeStorage DestroyedType); + + explicit CXXPseudoDestructorExpr(EmptyShell Shell) + : Expr(CXXPseudoDestructorExprClass, Shell), + Base(nullptr), IsArrow(false), QualifierLoc(), ScopeType(nullptr) { } + + Expr *getBase() const { return cast<Expr>(Base); } + + /// \brief Determines whether this member expression actually had + /// a C++ nested-name-specifier prior to the name of the member, e.g., + /// x->Base::foo. + bool hasQualifier() const { return QualifierLoc.hasQualifier(); } + + /// \brief Retrieves the nested-name-specifier that qualifies the type name, + /// with source-location information. + NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } + + /// \brief If the member name was qualified, retrieves the + /// nested-name-specifier that precedes the member name. Otherwise, returns + /// null. + NestedNameSpecifier *getQualifier() const { + return QualifierLoc.getNestedNameSpecifier(); + } + + /// \brief Determine whether this pseudo-destructor expression was written + /// using an '->' (otherwise, it used a '.'). + bool isArrow() const { return IsArrow; } + + /// \brief Retrieve the location of the '.' or '->' operator. + SourceLocation getOperatorLoc() const { return OperatorLoc; } + + /// \brief Retrieve the scope type in a qualified pseudo-destructor + /// expression. + /// + /// Pseudo-destructor expressions can have extra qualification within them + /// that is not part of the nested-name-specifier, e.g., \c p->T::~T(). + /// Here, if the object type of the expression is (or may be) a scalar type, + /// \p T may also be a scalar type and, therefore, cannot be part of a + /// nested-name-specifier. It is stored as the "scope type" of the pseudo- + /// destructor expression. + TypeSourceInfo *getScopeTypeInfo() const { return ScopeType; } + + /// \brief Retrieve the location of the '::' in a qualified pseudo-destructor + /// expression. + SourceLocation getColonColonLoc() const { return ColonColonLoc; } + + /// \brief Retrieve the location of the '~'. + SourceLocation getTildeLoc() const { return TildeLoc; } + + /// \brief Retrieve the source location information for the type + /// being destroyed. + /// + /// This type-source information is available for non-dependent + /// pseudo-destructor expressions and some dependent pseudo-destructor + /// expressions. Returns null if we only have the identifier for a + /// dependent pseudo-destructor expression. + TypeSourceInfo *getDestroyedTypeInfo() const { + return DestroyedType.getTypeSourceInfo(); + } + + /// \brief In a dependent pseudo-destructor expression for which we do not + /// have full type information on the destroyed type, provides the name + /// of the destroyed type. + IdentifierInfo *getDestroyedTypeIdentifier() const { + return DestroyedType.getIdentifier(); + } + + /// \brief Retrieve the type being destroyed. + QualType getDestroyedType() const; + + /// \brief Retrieve the starting location of the type being destroyed. + SourceLocation getDestroyedTypeLoc() const { + return DestroyedType.getLocation(); + } + + /// \brief Set the name of destroyed type for a dependent pseudo-destructor + /// expression. + void setDestroyedType(IdentifierInfo *II, SourceLocation Loc) { + DestroyedType = PseudoDestructorTypeStorage(II, Loc); + } + + /// \brief Set the destroyed type. + void setDestroyedType(TypeSourceInfo *Info) { + DestroyedType = PseudoDestructorTypeStorage(Info); + } + + SourceLocation getLocStart() const LLVM_READONLY {return Base->getLocStart();} + SourceLocation getLocEnd() const LLVM_READONLY; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXPseudoDestructorExprClass; + } + + // Iterators + child_range children() { return child_range(&Base, &Base + 1); } +}; + +/// \brief A type trait used in the implementation of various C++11 and +/// Library TR1 trait templates. +/// +/// \code +/// __is_pod(int) == true +/// __is_enum(std::string) == false +/// __is_trivially_constructible(vector<int>, int*, int*) +/// \endcode +class TypeTraitExpr final + : public Expr, + private llvm::TrailingObjects<TypeTraitExpr, TypeSourceInfo *> { + /// \brief The location of the type trait keyword. + SourceLocation Loc; + + /// \brief The location of the closing parenthesis. + SourceLocation RParenLoc; + + // Note: The TypeSourceInfos for the arguments are allocated after the + // TypeTraitExpr. + + TypeTraitExpr(QualType T, SourceLocation Loc, TypeTrait Kind, + ArrayRef<TypeSourceInfo *> Args, + SourceLocation RParenLoc, + bool Value); + + TypeTraitExpr(EmptyShell Empty) : Expr(TypeTraitExprClass, Empty) { } + + size_t numTrailingObjects(OverloadToken<TypeSourceInfo *>) const { + return getNumArgs(); + } + +public: + /// \brief Create a new type trait expression. + static TypeTraitExpr *Create(const ASTContext &C, QualType T, + SourceLocation Loc, TypeTrait Kind, + ArrayRef<TypeSourceInfo *> Args, + SourceLocation RParenLoc, + bool Value); + + static TypeTraitExpr *CreateDeserialized(const ASTContext &C, + unsigned NumArgs); + + /// \brief Determine which type trait this expression uses. + TypeTrait getTrait() const { + return static_cast<TypeTrait>(TypeTraitExprBits.Kind); + } + + bool getValue() const { + assert(!isValueDependent()); + return TypeTraitExprBits.Value; + } + + /// \brief Determine the number of arguments to this type trait. + unsigned getNumArgs() const { return TypeTraitExprBits.NumArgs; } + + /// \brief Retrieve the Ith argument. + TypeSourceInfo *getArg(unsigned I) const { + assert(I < getNumArgs() && "Argument out-of-range"); + return getArgs()[I]; + } + + /// \brief Retrieve the argument types. + ArrayRef<TypeSourceInfo *> getArgs() const { + return llvm::makeArrayRef(getTrailingObjects<TypeSourceInfo *>(), + getNumArgs()); + } + + SourceLocation getLocStart() const LLVM_READONLY { return Loc; } + SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == TypeTraitExprClass; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + + friend TrailingObjects; + friend class ASTStmtReader; + friend class ASTStmtWriter; +}; + +/// \brief An Embarcadero array type trait, as used in the implementation of +/// __array_rank and __array_extent. +/// +/// Example: +/// \code +/// __array_rank(int[10][20]) == 2 +/// __array_extent(int, 1) == 20 +/// \endcode +class ArrayTypeTraitExpr : public Expr { + virtual void anchor(); + + /// \brief The trait. An ArrayTypeTrait enum in MSVC compat unsigned. + unsigned ATT : 2; + + /// \brief The value of the type trait. Unspecified if dependent. + uint64_t Value; + + /// \brief The array dimension being queried, or -1 if not used. + Expr *Dimension; + + /// \brief The location of the type trait keyword. + SourceLocation Loc; + + /// \brief The location of the closing paren. + SourceLocation RParen; + + /// \brief The type being queried. + TypeSourceInfo *QueriedType; + +public: + ArrayTypeTraitExpr(SourceLocation loc, ArrayTypeTrait att, + TypeSourceInfo *queried, uint64_t value, + Expr *dimension, SourceLocation rparen, QualType ty) + : Expr(ArrayTypeTraitExprClass, ty, VK_RValue, OK_Ordinary, + false, queried->getType()->isDependentType(), + (queried->getType()->isInstantiationDependentType() || + (dimension && dimension->isInstantiationDependent())), + queried->getType()->containsUnexpandedParameterPack()), + ATT(att), Value(value), Dimension(dimension), + Loc(loc), RParen(rparen), QueriedType(queried) { } + + + explicit ArrayTypeTraitExpr(EmptyShell Empty) + : Expr(ArrayTypeTraitExprClass, Empty), ATT(0), Value(false), + QueriedType() { } + + virtual ~ArrayTypeTraitExpr() { } + + SourceLocation getLocStart() const LLVM_READONLY { return Loc; } + SourceLocation getLocEnd() const LLVM_READONLY { return RParen; } + + ArrayTypeTrait getTrait() const { return static_cast<ArrayTypeTrait>(ATT); } + + QualType getQueriedType() const { return QueriedType->getType(); } + + TypeSourceInfo *getQueriedTypeSourceInfo() const { return QueriedType; } + + uint64_t getValue() const { assert(!isTypeDependent()); return Value; } + + Expr *getDimensionExpression() const { return Dimension; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ArrayTypeTraitExprClass; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + + friend class ASTStmtReader; +}; + +/// \brief An expression trait intrinsic. +/// +/// Example: +/// \code +/// __is_lvalue_expr(std::cout) == true +/// __is_lvalue_expr(1) == false +/// \endcode +class ExpressionTraitExpr : public Expr { + /// \brief The trait. A ExpressionTrait enum in MSVC compatible unsigned. + unsigned ET : 31; + /// \brief The value of the type trait. Unspecified if dependent. + bool Value : 1; + + /// \brief The location of the type trait keyword. + SourceLocation Loc; + + /// \brief The location of the closing paren. + SourceLocation RParen; + + /// \brief The expression being queried. + Expr* QueriedExpression; +public: + ExpressionTraitExpr(SourceLocation loc, ExpressionTrait et, + Expr *queried, bool value, + SourceLocation rparen, QualType resultType) + : Expr(ExpressionTraitExprClass, resultType, VK_RValue, OK_Ordinary, + false, // Not type-dependent + // Value-dependent if the argument is type-dependent. + queried->isTypeDependent(), + queried->isInstantiationDependent(), + queried->containsUnexpandedParameterPack()), + ET(et), Value(value), Loc(loc), RParen(rparen), + QueriedExpression(queried) { } + + explicit ExpressionTraitExpr(EmptyShell Empty) + : Expr(ExpressionTraitExprClass, Empty), ET(0), Value(false), + QueriedExpression() { } + + SourceLocation getLocStart() const LLVM_READONLY { return Loc; } + SourceLocation getLocEnd() const LLVM_READONLY { return RParen; } + + ExpressionTrait getTrait() const { return static_cast<ExpressionTrait>(ET); } + + Expr *getQueriedExpression() const { return QueriedExpression; } + + bool getValue() const { return Value; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ExpressionTraitExprClass; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + + friend class ASTStmtReader; +}; + + +/// \brief A reference to an overloaded function set, either an +/// \c UnresolvedLookupExpr or an \c UnresolvedMemberExpr. +class OverloadExpr : public Expr { + /// \brief The common name of these declarations. + DeclarationNameInfo NameInfo; + + /// \brief The nested-name-specifier that qualifies the name, if any. + NestedNameSpecifierLoc QualifierLoc; + + /// The results. These are undesugared, which is to say, they may + /// include UsingShadowDecls. Access is relative to the naming + /// class. + // FIXME: Allocate this data after the OverloadExpr subclass. + DeclAccessPair *Results; + unsigned NumResults; + +protected: + /// \brief Whether the name includes info for explicit template + /// keyword and arguments. + bool HasTemplateKWAndArgsInfo; + + /// \brief Return the optional template keyword and arguments info. + ASTTemplateKWAndArgsInfo * + getTrailingASTTemplateKWAndArgsInfo(); // defined far below. + + /// \brief Return the optional template keyword and arguments info. + const ASTTemplateKWAndArgsInfo *getTrailingASTTemplateKWAndArgsInfo() const { + return const_cast<OverloadExpr *>(this) + ->getTrailingASTTemplateKWAndArgsInfo(); + } + + /// Return the optional template arguments. + TemplateArgumentLoc *getTrailingTemplateArgumentLoc(); // defined far below + + OverloadExpr(StmtClass K, const ASTContext &C, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, + const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *TemplateArgs, + UnresolvedSetIterator Begin, UnresolvedSetIterator End, + bool KnownDependent, + bool KnownInstantiationDependent, + bool KnownContainsUnexpandedParameterPack); + + OverloadExpr(StmtClass K, EmptyShell Empty) + : Expr(K, Empty), QualifierLoc(), Results(nullptr), NumResults(0), + HasTemplateKWAndArgsInfo(false) { } + + void initializeResults(const ASTContext &C, + UnresolvedSetIterator Begin, + UnresolvedSetIterator End); + +public: + struct FindResult { + OverloadExpr *Expression; + bool IsAddressOfOperand; + bool HasFormOfMemberPointer; + }; + + /// \brief Finds the overloaded expression in the given expression \p E of + /// OverloadTy. + /// + /// \return the expression (which must be there) and true if it has + /// the particular form of a member pointer expression + static FindResult find(Expr *E) { + assert(E->getType()->isSpecificBuiltinType(BuiltinType::Overload)); + + FindResult Result; + + E = E->IgnoreParens(); + if (isa<UnaryOperator>(E)) { + assert(cast<UnaryOperator>(E)->getOpcode() == UO_AddrOf); + E = cast<UnaryOperator>(E)->getSubExpr(); + OverloadExpr *Ovl = cast<OverloadExpr>(E->IgnoreParens()); + + Result.HasFormOfMemberPointer = (E == Ovl && Ovl->getQualifier()); + Result.IsAddressOfOperand = true; + Result.Expression = Ovl; + } else { + Result.HasFormOfMemberPointer = false; + Result.IsAddressOfOperand = false; + Result.Expression = cast<OverloadExpr>(E); + } + + return Result; + } + + /// \brief Gets the naming class of this lookup, if any. + CXXRecordDecl *getNamingClass() const; + + typedef UnresolvedSetImpl::iterator decls_iterator; + decls_iterator decls_begin() const { return UnresolvedSetIterator(Results); } + decls_iterator decls_end() const { + return UnresolvedSetIterator(Results + NumResults); + } + llvm::iterator_range<decls_iterator> decls() const { + return llvm::make_range(decls_begin(), decls_end()); + } + + /// \brief Gets the number of declarations in the unresolved set. + unsigned getNumDecls() const { return NumResults; } + + /// \brief Gets the full name info. + const DeclarationNameInfo &getNameInfo() const { return NameInfo; } + + /// \brief Gets the name looked up. + DeclarationName getName() const { return NameInfo.getName(); } + + /// \brief Gets the location of the name. + SourceLocation getNameLoc() const { return NameInfo.getLoc(); } + + /// \brief Fetches the nested-name qualifier, if one was given. + NestedNameSpecifier *getQualifier() const { + return QualifierLoc.getNestedNameSpecifier(); + } + + /// \brief Fetches the nested-name qualifier with source-location + /// information, if one was given. + NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } + + /// \brief Retrieve the location of the template keyword preceding + /// this name, if any. + SourceLocation getTemplateKeywordLoc() const { + if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + return getTrailingASTTemplateKWAndArgsInfo()->TemplateKWLoc; + } + + /// \brief Retrieve the location of the left angle bracket starting the + /// explicit template argument list following the name, if any. + SourceLocation getLAngleLoc() const { + if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + return getTrailingASTTemplateKWAndArgsInfo()->LAngleLoc; + } + + /// \brief Retrieve the location of the right angle bracket ending the + /// explicit template argument list following the name, if any. + SourceLocation getRAngleLoc() const { + if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + return getTrailingASTTemplateKWAndArgsInfo()->RAngleLoc; + } + + /// \brief Determines whether the name was preceded by the template keyword. + bool hasTemplateKeyword() const { return getTemplateKeywordLoc().isValid(); } + + /// \brief Determines whether this expression had explicit template arguments. + bool hasExplicitTemplateArgs() const { return getLAngleLoc().isValid(); } + + TemplateArgumentLoc const *getTemplateArgs() const { + if (!hasExplicitTemplateArgs()) + return nullptr; + return const_cast<OverloadExpr *>(this)->getTrailingTemplateArgumentLoc(); + } + + unsigned getNumTemplateArgs() const { + if (!hasExplicitTemplateArgs()) + return 0; + + return getTrailingASTTemplateKWAndArgsInfo()->NumTemplateArgs; + } + + /// \brief Copies the template arguments into the given structure. + void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const { + if (hasExplicitTemplateArgs()) + getTrailingASTTemplateKWAndArgsInfo()->copyInto(getTemplateArgs(), List); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == UnresolvedLookupExprClass || + T->getStmtClass() == UnresolvedMemberExprClass; + } + + friend class ASTStmtReader; + friend class ASTStmtWriter; +}; + +/// \brief A reference to a name which we were able to look up during +/// parsing but could not resolve to a specific declaration. +/// +/// This arises in several ways: +/// * we might be waiting for argument-dependent lookup; +/// * the name might resolve to an overloaded function; +/// and eventually: +/// * the lookup might have included a function template. +/// +/// These never include UnresolvedUsingValueDecls, which are always class +/// members and therefore appear only in UnresolvedMemberLookupExprs. +class UnresolvedLookupExpr final + : public OverloadExpr, + private llvm::TrailingObjects< + UnresolvedLookupExpr, ASTTemplateKWAndArgsInfo, TemplateArgumentLoc> { + /// True if these lookup results should be extended by + /// argument-dependent lookup if this is the operand of a function + /// call. + bool RequiresADL; + + /// True if these lookup results are overloaded. This is pretty + /// trivially rederivable if we urgently need to kill this field. + bool Overloaded; + + /// The naming class (C++ [class.access.base]p5) of the lookup, if + /// any. This can generally be recalculated from the context chain, + /// but that can be fairly expensive for unqualified lookups. If we + /// want to improve memory use here, this could go in a union + /// against the qualified-lookup bits. + CXXRecordDecl *NamingClass; + + size_t numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const { + return HasTemplateKWAndArgsInfo ? 1 : 0; + } + + UnresolvedLookupExpr(const ASTContext &C, + CXXRecordDecl *NamingClass, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, + const DeclarationNameInfo &NameInfo, + bool RequiresADL, bool Overloaded, + const TemplateArgumentListInfo *TemplateArgs, + UnresolvedSetIterator Begin, UnresolvedSetIterator End) + : OverloadExpr(UnresolvedLookupExprClass, C, QualifierLoc, TemplateKWLoc, + NameInfo, TemplateArgs, Begin, End, false, false, false), + RequiresADL(RequiresADL), + Overloaded(Overloaded), NamingClass(NamingClass) + {} + + UnresolvedLookupExpr(EmptyShell Empty) + : OverloadExpr(UnresolvedLookupExprClass, Empty), + RequiresADL(false), Overloaded(false), NamingClass(nullptr) + {} + + friend TrailingObjects; + friend class OverloadExpr; + friend class ASTStmtReader; + +public: + static UnresolvedLookupExpr *Create(const ASTContext &C, + CXXRecordDecl *NamingClass, + NestedNameSpecifierLoc QualifierLoc, + const DeclarationNameInfo &NameInfo, + bool ADL, bool Overloaded, + UnresolvedSetIterator Begin, + UnresolvedSetIterator End) { + return new(C) UnresolvedLookupExpr(C, NamingClass, QualifierLoc, + SourceLocation(), NameInfo, + ADL, Overloaded, nullptr, Begin, End); + } + + static UnresolvedLookupExpr *Create(const ASTContext &C, + CXXRecordDecl *NamingClass, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, + const DeclarationNameInfo &NameInfo, + bool ADL, + const TemplateArgumentListInfo *Args, + UnresolvedSetIterator Begin, + UnresolvedSetIterator End); + + static UnresolvedLookupExpr *CreateEmpty(const ASTContext &C, + bool HasTemplateKWAndArgsInfo, + unsigned NumTemplateArgs); + + /// True if this declaration should be extended by + /// argument-dependent lookup. + bool requiresADL() const { return RequiresADL; } + + /// True if this lookup is overloaded. + bool isOverloaded() const { return Overloaded; } + + /// Gets the 'naming class' (in the sense of C++0x + /// [class.access.base]p5) of the lookup. This is the scope + /// that was looked in to find these results. + CXXRecordDecl *getNamingClass() const { return NamingClass; } + + SourceLocation getLocStart() const LLVM_READONLY { + if (NestedNameSpecifierLoc l = getQualifierLoc()) + return l.getBeginLoc(); + return getNameInfo().getLocStart(); + } + SourceLocation getLocEnd() const LLVM_READONLY { + if (hasExplicitTemplateArgs()) + return getRAngleLoc(); + return getNameInfo().getLocEnd(); + } + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == UnresolvedLookupExprClass; + } +}; + +/// \brief A qualified reference to a name whose declaration cannot +/// yet be resolved. +/// +/// DependentScopeDeclRefExpr is similar to DeclRefExpr in that +/// it expresses a reference to a declaration such as +/// X<T>::value. The difference, however, is that an +/// DependentScopeDeclRefExpr node is used only within C++ templates when +/// the qualification (e.g., X<T>::) refers to a dependent type. In +/// this case, X<T>::value cannot resolve to a declaration because the +/// declaration will differ from one instantiation of X<T> to the +/// next. Therefore, DependentScopeDeclRefExpr keeps track of the +/// qualifier (X<T>::) and the name of the entity being referenced +/// ("value"). Such expressions will instantiate to a DeclRefExpr once the +/// declaration can be found. +class DependentScopeDeclRefExpr final + : public Expr, + private llvm::TrailingObjects<DependentScopeDeclRefExpr, + ASTTemplateKWAndArgsInfo, + TemplateArgumentLoc> { + /// \brief The nested-name-specifier that qualifies this unresolved + /// declaration name. + NestedNameSpecifierLoc QualifierLoc; + + /// \brief The name of the entity we will be referencing. + DeclarationNameInfo NameInfo; + + /// \brief Whether the name includes info for explicit template + /// keyword and arguments. + bool HasTemplateKWAndArgsInfo; + + size_t numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const { + return HasTemplateKWAndArgsInfo ? 1 : 0; + } + + DependentScopeDeclRefExpr(QualType T, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, + const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *Args); + +public: + static DependentScopeDeclRefExpr *Create(const ASTContext &C, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, + const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *TemplateArgs); + + static DependentScopeDeclRefExpr *CreateEmpty(const ASTContext &C, + bool HasTemplateKWAndArgsInfo, + unsigned NumTemplateArgs); + + /// \brief Retrieve the name that this expression refers to. + const DeclarationNameInfo &getNameInfo() const { return NameInfo; } + + /// \brief Retrieve the name that this expression refers to. + DeclarationName getDeclName() const { return NameInfo.getName(); } + + /// \brief Retrieve the location of the name within the expression. + /// + /// For example, in "X<T>::value" this is the location of "value". + SourceLocation getLocation() const { return NameInfo.getLoc(); } + + /// \brief Retrieve the nested-name-specifier that qualifies the + /// name, with source location information. + NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } + + /// \brief Retrieve the nested-name-specifier that qualifies this + /// declaration. + NestedNameSpecifier *getQualifier() const { + return QualifierLoc.getNestedNameSpecifier(); + } + + /// \brief Retrieve the location of the template keyword preceding + /// this name, if any. + SourceLocation getTemplateKeywordLoc() const { + if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->TemplateKWLoc; + } + + /// \brief Retrieve the location of the left angle bracket starting the + /// explicit template argument list following the name, if any. + SourceLocation getLAngleLoc() const { + if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->LAngleLoc; + } + + /// \brief Retrieve the location of the right angle bracket ending the + /// explicit template argument list following the name, if any. + SourceLocation getRAngleLoc() const { + if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->RAngleLoc; + } + + /// Determines whether the name was preceded by the template keyword. + bool hasTemplateKeyword() const { return getTemplateKeywordLoc().isValid(); } + + /// Determines whether this lookup had explicit template arguments. + bool hasExplicitTemplateArgs() const { return getLAngleLoc().isValid(); } + + /// \brief Copies the template arguments (if present) into the given + /// structure. + void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const { + if (hasExplicitTemplateArgs()) + getTrailingObjects<ASTTemplateKWAndArgsInfo>()->copyInto( + getTrailingObjects<TemplateArgumentLoc>(), List); + } + + TemplateArgumentLoc const *getTemplateArgs() const { + if (!hasExplicitTemplateArgs()) + return nullptr; + + return getTrailingObjects<TemplateArgumentLoc>(); + } + + unsigned getNumTemplateArgs() const { + if (!hasExplicitTemplateArgs()) + return 0; + + return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->NumTemplateArgs; + } + + /// Note: getLocStart() is the start of the whole DependentScopeDeclRefExpr, + /// and differs from getLocation().getStart(). + SourceLocation getLocStart() const LLVM_READONLY { + return QualifierLoc.getBeginLoc(); + } + SourceLocation getLocEnd() const LLVM_READONLY { + if (hasExplicitTemplateArgs()) + return getRAngleLoc(); + return getLocation(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == DependentScopeDeclRefExprClass; + } + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + + friend TrailingObjects; + friend class ASTStmtReader; + friend class ASTStmtWriter; +}; + +/// Represents an expression -- generally a full-expression -- that +/// introduces cleanups to be run at the end of the sub-expression's +/// evaluation. The most common source of expression-introduced +/// cleanups is temporary objects in C++, but several other kinds of +/// expressions can create cleanups, including basically every +/// call in ARC that returns an Objective-C pointer. +/// +/// This expression also tracks whether the sub-expression contains a +/// potentially-evaluated block literal. The lifetime of a block +/// literal is the extent of the enclosing scope. +class ExprWithCleanups final + : public Expr, + private llvm::TrailingObjects<ExprWithCleanups, BlockDecl *> { +public: + /// The type of objects that are kept in the cleanup. + /// It's useful to remember the set of blocks; we could also + /// remember the set of temporaries, but there's currently + /// no need. + typedef BlockDecl *CleanupObject; + +private: + Stmt *SubExpr; + + ExprWithCleanups(EmptyShell, unsigned NumObjects); + ExprWithCleanups(Expr *SubExpr, ArrayRef<CleanupObject> Objects); + + friend TrailingObjects; + friend class ASTStmtReader; + +public: + static ExprWithCleanups *Create(const ASTContext &C, EmptyShell empty, + unsigned numObjects); + + static ExprWithCleanups *Create(const ASTContext &C, Expr *subexpr, + ArrayRef<CleanupObject> objects); + + ArrayRef<CleanupObject> getObjects() const { + return llvm::makeArrayRef(getTrailingObjects<CleanupObject>(), + getNumObjects()); + } + + unsigned getNumObjects() const { return ExprWithCleanupsBits.NumObjects; } + + CleanupObject getObject(unsigned i) const { + assert(i < getNumObjects() && "Index out of range"); + return getObjects()[i]; + } + + Expr *getSubExpr() { return cast<Expr>(SubExpr); } + const Expr *getSubExpr() const { return cast<Expr>(SubExpr); } + + /// As with any mutator of the AST, be very careful + /// when modifying an existing AST to preserve its invariants. + void setSubExpr(Expr *E) { SubExpr = E; } + + SourceLocation getLocStart() const LLVM_READONLY { + return SubExpr->getLocStart(); + } + SourceLocation getLocEnd() const LLVM_READONLY { return SubExpr->getLocEnd();} + + // Implement isa/cast/dyncast/etc. + static bool classof(const Stmt *T) { + return T->getStmtClass() == ExprWithCleanupsClass; + } + + // Iterators + child_range children() { return child_range(&SubExpr, &SubExpr + 1); } +}; + +/// \brief Describes an explicit type conversion that uses functional +/// notion but could not be resolved because one or more arguments are +/// type-dependent. +/// +/// The explicit type conversions expressed by +/// CXXUnresolvedConstructExpr have the form <tt>T(a1, a2, ..., aN)</tt>, +/// where \c T is some type and \c a1, \c a2, ..., \c aN are values, and +/// either \c T is a dependent type or one or more of the <tt>a</tt>'s is +/// type-dependent. For example, this would occur in a template such +/// as: +/// +/// \code +/// template<typename T, typename A1> +/// inline T make_a(const A1& a1) { +/// return T(a1); +/// } +/// \endcode +/// +/// When the returned expression is instantiated, it may resolve to a +/// constructor call, conversion function call, or some kind of type +/// conversion. +class CXXUnresolvedConstructExpr final + : public Expr, + private llvm::TrailingObjects<CXXUnresolvedConstructExpr, Expr *> { + /// \brief The type being constructed. + TypeSourceInfo *Type; + + /// \brief The location of the left parentheses ('('). + SourceLocation LParenLoc; + + /// \brief The location of the right parentheses (')'). + SourceLocation RParenLoc; + + /// \brief The number of arguments used to construct the type. + unsigned NumArgs; + + CXXUnresolvedConstructExpr(TypeSourceInfo *Type, + SourceLocation LParenLoc, + ArrayRef<Expr*> Args, + SourceLocation RParenLoc); + + CXXUnresolvedConstructExpr(EmptyShell Empty, unsigned NumArgs) + : Expr(CXXUnresolvedConstructExprClass, Empty), Type(), NumArgs(NumArgs) { } + + friend TrailingObjects; + friend class ASTStmtReader; + +public: + static CXXUnresolvedConstructExpr *Create(const ASTContext &C, + TypeSourceInfo *Type, + SourceLocation LParenLoc, + ArrayRef<Expr*> Args, + SourceLocation RParenLoc); + + static CXXUnresolvedConstructExpr *CreateEmpty(const ASTContext &C, + unsigned NumArgs); + + /// \brief Retrieve the type that is being constructed, as specified + /// in the source code. + QualType getTypeAsWritten() const { return Type->getType(); } + + /// \brief Retrieve the type source information for the type being + /// constructed. + TypeSourceInfo *getTypeSourceInfo() const { return Type; } + + /// \brief Retrieve the location of the left parentheses ('(') that + /// precedes the argument list. + SourceLocation getLParenLoc() const { return LParenLoc; } + void setLParenLoc(SourceLocation L) { LParenLoc = L; } + + /// \brief Retrieve the location of the right parentheses (')') that + /// follows the argument list. + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + /// \brief Retrieve the number of arguments. + unsigned arg_size() const { return NumArgs; } + + typedef Expr** arg_iterator; + arg_iterator arg_begin() { return getTrailingObjects<Expr *>(); } + arg_iterator arg_end() { return arg_begin() + NumArgs; } + + typedef const Expr* const * const_arg_iterator; + const_arg_iterator arg_begin() const { return getTrailingObjects<Expr *>(); } + const_arg_iterator arg_end() const { + return arg_begin() + NumArgs; + } + + Expr *getArg(unsigned I) { + assert(I < NumArgs && "Argument index out-of-range"); + return *(arg_begin() + I); + } + + const Expr *getArg(unsigned I) const { + assert(I < NumArgs && "Argument index out-of-range"); + return *(arg_begin() + I); + } + + void setArg(unsigned I, Expr *E) { + assert(I < NumArgs && "Argument index out-of-range"); + *(arg_begin() + I) = E; + } + + SourceLocation getLocStart() const LLVM_READONLY; + SourceLocation getLocEnd() const LLVM_READONLY { + if (!RParenLoc.isValid() && NumArgs > 0) + return getArg(NumArgs - 1)->getLocEnd(); + return RParenLoc; + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXUnresolvedConstructExprClass; + } + + // Iterators + child_range children() { + Stmt **begin = reinterpret_cast<Stmt **>(arg_begin()); + return child_range(begin, begin + NumArgs); + } +}; + +/// \brief Represents a C++ member access expression where the actual +/// member referenced could not be resolved because the base +/// expression or the member name was dependent. +/// +/// Like UnresolvedMemberExprs, these can be either implicit or +/// explicit accesses. It is only possible to get one of these with +/// an implicit access if a qualifier is provided. +class CXXDependentScopeMemberExpr final + : public Expr, + private llvm::TrailingObjects<CXXDependentScopeMemberExpr, + ASTTemplateKWAndArgsInfo, + TemplateArgumentLoc> { + /// \brief The expression for the base pointer or class reference, + /// e.g., the \c x in x.f. Can be null in implicit accesses. + Stmt *Base; + + /// \brief The type of the base expression. Never null, even for + /// implicit accesses. + QualType BaseType; + + /// \brief Whether this member expression used the '->' operator or + /// the '.' operator. + bool IsArrow : 1; + + /// \brief Whether this member expression has info for explicit template + /// keyword and arguments. + bool HasTemplateKWAndArgsInfo : 1; + + /// \brief The location of the '->' or '.' operator. + SourceLocation OperatorLoc; + + /// \brief The nested-name-specifier that precedes the member name, if any. + NestedNameSpecifierLoc QualifierLoc; + + /// \brief In a qualified member access expression such as t->Base::f, this + /// member stores the resolves of name lookup in the context of the member + /// access expression, to be used at instantiation time. + /// + /// FIXME: This member, along with the QualifierLoc, could + /// be stuck into a structure that is optionally allocated at the end of + /// the CXXDependentScopeMemberExpr, to save space in the common case. + NamedDecl *FirstQualifierFoundInScope; + + /// \brief The member to which this member expression refers, which + /// can be name, overloaded operator, or destructor. + /// + /// FIXME: could also be a template-id + DeclarationNameInfo MemberNameInfo; + + size_t numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const { + return HasTemplateKWAndArgsInfo ? 1 : 0; + } + + CXXDependentScopeMemberExpr(const ASTContext &C, Expr *Base, + QualType BaseType, bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, + NamedDecl *FirstQualifierFoundInScope, + DeclarationNameInfo MemberNameInfo, + const TemplateArgumentListInfo *TemplateArgs); + +public: + CXXDependentScopeMemberExpr(const ASTContext &C, Expr *Base, + QualType BaseType, bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifierLoc QualifierLoc, + NamedDecl *FirstQualifierFoundInScope, + DeclarationNameInfo MemberNameInfo); + + static CXXDependentScopeMemberExpr * + Create(const ASTContext &C, Expr *Base, QualType BaseType, bool IsArrow, + SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierFoundInScope, + DeclarationNameInfo MemberNameInfo, + const TemplateArgumentListInfo *TemplateArgs); + + static CXXDependentScopeMemberExpr * + CreateEmpty(const ASTContext &C, bool HasTemplateKWAndArgsInfo, + unsigned NumTemplateArgs); + + /// \brief True if this is an implicit access, i.e. one in which the + /// member being accessed was not written in the source. The source + /// location of the operator is invalid in this case. + bool isImplicitAccess() const; + + /// \brief Retrieve the base object of this member expressions, + /// e.g., the \c x in \c x.m. + Expr *getBase() const { + assert(!isImplicitAccess()); + return cast<Expr>(Base); + } + + QualType getBaseType() const { return BaseType; } + + /// \brief Determine whether this member expression used the '->' + /// operator; otherwise, it used the '.' operator. + bool isArrow() const { return IsArrow; } + + /// \brief Retrieve the location of the '->' or '.' operator. + SourceLocation getOperatorLoc() const { return OperatorLoc; } + + /// \brief Retrieve the nested-name-specifier that qualifies the member + /// name. + NestedNameSpecifier *getQualifier() const { + return QualifierLoc.getNestedNameSpecifier(); + } + + /// \brief Retrieve the nested-name-specifier that qualifies the member + /// name, with source location information. + NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } + + + /// \brief Retrieve the first part of the nested-name-specifier that was + /// found in the scope of the member access expression when the member access + /// was initially parsed. + /// + /// This function only returns a useful result when member access expression + /// uses a qualified member name, e.g., "x.Base::f". Here, the declaration + /// returned by this function describes what was found by unqualified name + /// lookup for the identifier "Base" within the scope of the member access + /// expression itself. At template instantiation time, this information is + /// combined with the results of name lookup into the type of the object + /// expression itself (the class type of x). + NamedDecl *getFirstQualifierFoundInScope() const { + return FirstQualifierFoundInScope; + } + + /// \brief Retrieve the name of the member that this expression + /// refers to. + const DeclarationNameInfo &getMemberNameInfo() const { + return MemberNameInfo; + } + + /// \brief Retrieve the name of the member that this expression + /// refers to. + DeclarationName getMember() const { return MemberNameInfo.getName(); } + + // \brief Retrieve the location of the name of the member that this + // expression refers to. + SourceLocation getMemberLoc() const { return MemberNameInfo.getLoc(); } + + /// \brief Retrieve the location of the template keyword preceding the + /// member name, if any. + SourceLocation getTemplateKeywordLoc() const { + if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->TemplateKWLoc; + } + + /// \brief Retrieve the location of the left angle bracket starting the + /// explicit template argument list following the member name, if any. + SourceLocation getLAngleLoc() const { + if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->LAngleLoc; + } + + /// \brief Retrieve the location of the right angle bracket ending the + /// explicit template argument list following the member name, if any. + SourceLocation getRAngleLoc() const { + if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->RAngleLoc; + } + + /// Determines whether the member name was preceded by the template keyword. + bool hasTemplateKeyword() const { return getTemplateKeywordLoc().isValid(); } + + /// \brief Determines whether this member expression actually had a C++ + /// template argument list explicitly specified, e.g., x.f<int>. + bool hasExplicitTemplateArgs() const { return getLAngleLoc().isValid(); } + + /// \brief Copies the template arguments (if present) into the given + /// structure. + void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const { + if (hasExplicitTemplateArgs()) + getTrailingObjects<ASTTemplateKWAndArgsInfo>()->copyInto( + getTrailingObjects<TemplateArgumentLoc>(), List); + } + + /// \brief Retrieve the template arguments provided as part of this + /// template-id. + const TemplateArgumentLoc *getTemplateArgs() const { + if (!hasExplicitTemplateArgs()) + return nullptr; + + return getTrailingObjects<TemplateArgumentLoc>(); + } + + /// \brief Retrieve the number of template arguments provided as part of this + /// template-id. + unsigned getNumTemplateArgs() const { + if (!hasExplicitTemplateArgs()) + return 0; + + return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->NumTemplateArgs; + } + + SourceLocation getLocStart() const LLVM_READONLY { + if (!isImplicitAccess()) + return Base->getLocStart(); + if (getQualifier()) + return getQualifierLoc().getBeginLoc(); + return MemberNameInfo.getBeginLoc(); + } + + SourceLocation getLocEnd() const LLVM_READONLY { + if (hasExplicitTemplateArgs()) + return getRAngleLoc(); + return MemberNameInfo.getEndLoc(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXDependentScopeMemberExprClass; + } + + // Iterators + child_range children() { + if (isImplicitAccess()) + return child_range(child_iterator(), child_iterator()); + return child_range(&Base, &Base + 1); + } + + friend TrailingObjects; + friend class ASTStmtReader; + friend class ASTStmtWriter; +}; + +/// \brief Represents a C++ member access expression for which lookup +/// produced a set of overloaded functions. +/// +/// The member access may be explicit or implicit: +/// \code +/// struct A { +/// int a, b; +/// int explicitAccess() { return this->a + this->A::b; } +/// int implicitAccess() { return a + A::b; } +/// }; +/// \endcode +/// +/// In the final AST, an explicit access always becomes a MemberExpr. +/// An implicit access may become either a MemberExpr or a +/// DeclRefExpr, depending on whether the member is static. +class UnresolvedMemberExpr final + : public OverloadExpr, + private llvm::TrailingObjects< + UnresolvedMemberExpr, ASTTemplateKWAndArgsInfo, TemplateArgumentLoc> { + /// \brief Whether this member expression used the '->' operator or + /// the '.' operator. + bool IsArrow : 1; + + /// \brief Whether the lookup results contain an unresolved using + /// declaration. + bool HasUnresolvedUsing : 1; + + /// \brief The expression for the base pointer or class reference, + /// e.g., the \c x in x.f. + /// + /// This can be null if this is an 'unbased' member expression. + Stmt *Base; + + /// \brief The type of the base expression; never null. + QualType BaseType; + + /// \brief The location of the '->' or '.' operator. + SourceLocation OperatorLoc; + + size_t numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const { + return HasTemplateKWAndArgsInfo ? 1 : 0; + } + + UnresolvedMemberExpr(const ASTContext &C, bool HasUnresolvedUsing, + Expr *Base, QualType BaseType, bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, + const DeclarationNameInfo &MemberNameInfo, + const TemplateArgumentListInfo *TemplateArgs, + UnresolvedSetIterator Begin, UnresolvedSetIterator End); + + UnresolvedMemberExpr(EmptyShell Empty) + : OverloadExpr(UnresolvedMemberExprClass, Empty), IsArrow(false), + HasUnresolvedUsing(false), Base(nullptr) { } + + friend TrailingObjects; + friend class OverloadExpr; + friend class ASTStmtReader; + +public: + static UnresolvedMemberExpr * + Create(const ASTContext &C, bool HasUnresolvedUsing, + Expr *Base, QualType BaseType, bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, + const DeclarationNameInfo &MemberNameInfo, + const TemplateArgumentListInfo *TemplateArgs, + UnresolvedSetIterator Begin, UnresolvedSetIterator End); + + static UnresolvedMemberExpr * + CreateEmpty(const ASTContext &C, bool HasTemplateKWAndArgsInfo, + unsigned NumTemplateArgs); + + /// \brief True if this is an implicit access, i.e., one in which the + /// member being accessed was not written in the source. + /// + /// The source location of the operator is invalid in this case. + bool isImplicitAccess() const; + + /// \brief Retrieve the base object of this member expressions, + /// e.g., the \c x in \c x.m. + Expr *getBase() { + assert(!isImplicitAccess()); + return cast<Expr>(Base); + } + const Expr *getBase() const { + assert(!isImplicitAccess()); + return cast<Expr>(Base); + } + + QualType getBaseType() const { return BaseType; } + + /// \brief Determine whether the lookup results contain an unresolved using + /// declaration. + bool hasUnresolvedUsing() const { return HasUnresolvedUsing; } + + /// \brief Determine whether this member expression used the '->' + /// operator; otherwise, it used the '.' operator. + bool isArrow() const { return IsArrow; } + + /// \brief Retrieve the location of the '->' or '.' operator. + SourceLocation getOperatorLoc() const { return OperatorLoc; } + + /// \brief Retrieve the naming class of this lookup. + CXXRecordDecl *getNamingClass() const; + + /// \brief Retrieve the full name info for the member that this expression + /// refers to. + const DeclarationNameInfo &getMemberNameInfo() const { return getNameInfo(); } + + /// \brief Retrieve the name of the member that this expression + /// refers to. + DeclarationName getMemberName() const { return getName(); } + + // \brief Retrieve the location of the name of the member that this + // expression refers to. + SourceLocation getMemberLoc() const { return getNameLoc(); } + + // \brief Return the preferred location (the member name) for the arrow when + // diagnosing a problem with this expression. + SourceLocation getExprLoc() const LLVM_READONLY { return getMemberLoc(); } + + SourceLocation getLocStart() const LLVM_READONLY { + if (!isImplicitAccess()) + return Base->getLocStart(); + if (NestedNameSpecifierLoc l = getQualifierLoc()) + return l.getBeginLoc(); + return getMemberNameInfo().getLocStart(); + } + SourceLocation getLocEnd() const LLVM_READONLY { + if (hasExplicitTemplateArgs()) + return getRAngleLoc(); + return getMemberNameInfo().getLocEnd(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == UnresolvedMemberExprClass; + } + + // Iterators + child_range children() { + if (isImplicitAccess()) + return child_range(child_iterator(), child_iterator()); + return child_range(&Base, &Base + 1); + } +}; + +inline ASTTemplateKWAndArgsInfo * +OverloadExpr::getTrailingASTTemplateKWAndArgsInfo() { + if (!HasTemplateKWAndArgsInfo) + return nullptr; + + if (isa<UnresolvedLookupExpr>(this)) + return cast<UnresolvedLookupExpr>(this) + ->getTrailingObjects<ASTTemplateKWAndArgsInfo>(); + else + return cast<UnresolvedMemberExpr>(this) + ->getTrailingObjects<ASTTemplateKWAndArgsInfo>(); +} + +inline TemplateArgumentLoc *OverloadExpr::getTrailingTemplateArgumentLoc() { + if (isa<UnresolvedLookupExpr>(this)) + return cast<UnresolvedLookupExpr>(this) + ->getTrailingObjects<TemplateArgumentLoc>(); + else + return cast<UnresolvedMemberExpr>(this) + ->getTrailingObjects<TemplateArgumentLoc>(); +} + +/// \brief Represents a C++11 noexcept expression (C++ [expr.unary.noexcept]). +/// +/// The noexcept expression tests whether a given expression might throw. Its +/// result is a boolean constant. +class CXXNoexceptExpr : public Expr { + bool Value : 1; + Stmt *Operand; + SourceRange Range; + + friend class ASTStmtReader; + +public: + CXXNoexceptExpr(QualType Ty, Expr *Operand, CanThrowResult Val, + SourceLocation Keyword, SourceLocation RParen) + : Expr(CXXNoexceptExprClass, Ty, VK_RValue, OK_Ordinary, + /*TypeDependent*/false, + /*ValueDependent*/Val == CT_Dependent, + Val == CT_Dependent || Operand->isInstantiationDependent(), + Operand->containsUnexpandedParameterPack()), + Value(Val == CT_Cannot), Operand(Operand), Range(Keyword, RParen) + { } + + CXXNoexceptExpr(EmptyShell Empty) + : Expr(CXXNoexceptExprClass, Empty) + { } + + Expr *getOperand() const { return static_cast<Expr*>(Operand); } + + SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } + SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } + SourceRange getSourceRange() const LLVM_READONLY { return Range; } + + bool getValue() const { return Value; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXNoexceptExprClass; + } + + // Iterators + child_range children() { return child_range(&Operand, &Operand + 1); } +}; + +/// \brief Represents a C++11 pack expansion that produces a sequence of +/// expressions. +/// +/// A pack expansion expression contains a pattern (which itself is an +/// expression) followed by an ellipsis. For example: +/// +/// \code +/// template<typename F, typename ...Types> +/// void forward(F f, Types &&...args) { +/// f(static_cast<Types&&>(args)...); +/// } +/// \endcode +/// +/// Here, the argument to the function object \c f is a pack expansion whose +/// pattern is \c static_cast<Types&&>(args). When the \c forward function +/// template is instantiated, the pack expansion will instantiate to zero or +/// or more function arguments to the function object \c f. +class PackExpansionExpr : public Expr { + SourceLocation EllipsisLoc; + + /// \brief The number of expansions that will be produced by this pack + /// expansion expression, if known. + /// + /// When zero, the number of expansions is not known. Otherwise, this value + /// is the number of expansions + 1. + unsigned NumExpansions; + + Stmt *Pattern; + + friend class ASTStmtReader; + friend class ASTStmtWriter; + +public: + PackExpansionExpr(QualType T, Expr *Pattern, SourceLocation EllipsisLoc, + Optional<unsigned> NumExpansions) + : Expr(PackExpansionExprClass, T, Pattern->getValueKind(), + Pattern->getObjectKind(), /*TypeDependent=*/true, + /*ValueDependent=*/true, /*InstantiationDependent=*/true, + /*ContainsUnexpandedParameterPack=*/false), + EllipsisLoc(EllipsisLoc), + NumExpansions(NumExpansions? *NumExpansions + 1 : 0), + Pattern(Pattern) { } + + PackExpansionExpr(EmptyShell Empty) : Expr(PackExpansionExprClass, Empty) { } + + /// \brief Retrieve the pattern of the pack expansion. + Expr *getPattern() { return reinterpret_cast<Expr *>(Pattern); } + + /// \brief Retrieve the pattern of the pack expansion. + const Expr *getPattern() const { return reinterpret_cast<Expr *>(Pattern); } + + /// \brief Retrieve the location of the ellipsis that describes this pack + /// expansion. + SourceLocation getEllipsisLoc() const { return EllipsisLoc; } + + /// \brief Determine the number of expansions that will be produced when + /// this pack expansion is instantiated, if already known. + Optional<unsigned> getNumExpansions() const { + if (NumExpansions) + return NumExpansions - 1; + + return None; + } + + SourceLocation getLocStart() const LLVM_READONLY { + return Pattern->getLocStart(); + } + SourceLocation getLocEnd() const LLVM_READONLY { return EllipsisLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == PackExpansionExprClass; + } + + // Iterators + child_range children() { + return child_range(&Pattern, &Pattern + 1); + } +}; + + +/// \brief Represents an expression that computes the length of a parameter +/// pack. +/// +/// \code +/// template<typename ...Types> +/// struct count { +/// static const unsigned value = sizeof...(Types); +/// }; +/// \endcode +class SizeOfPackExpr final + : public Expr, + private llvm::TrailingObjects<SizeOfPackExpr, TemplateArgument> { + /// \brief The location of the \c sizeof keyword. + SourceLocation OperatorLoc; + + /// \brief The location of the name of the parameter pack. + SourceLocation PackLoc; + + /// \brief The location of the closing parenthesis. + SourceLocation RParenLoc; + + /// \brief The length of the parameter pack, if known. + /// + /// When this expression is not value-dependent, this is the length of + /// the pack. When the expression was parsed rather than instantiated + /// (and thus is value-dependent), this is zero. + /// + /// After partial substitution into a sizeof...(X) expression (for instance, + /// within an alias template or during function template argument deduction), + /// we store a trailing array of partially-substituted TemplateArguments, + /// and this is the length of that array. + unsigned Length; + + /// \brief The parameter pack. + NamedDecl *Pack; + + friend TrailingObjects; + friend class ASTStmtReader; + friend class ASTStmtWriter; + + /// \brief Create an expression that computes the length of + /// the given parameter pack. + SizeOfPackExpr(QualType SizeType, SourceLocation OperatorLoc, NamedDecl *Pack, + SourceLocation PackLoc, SourceLocation RParenLoc, + Optional<unsigned> Length, ArrayRef<TemplateArgument> PartialArgs) + : Expr(SizeOfPackExprClass, SizeType, VK_RValue, OK_Ordinary, + /*TypeDependent=*/false, /*ValueDependent=*/!Length, + /*InstantiationDependent=*/!Length, + /*ContainsUnexpandedParameterPack=*/false), + OperatorLoc(OperatorLoc), PackLoc(PackLoc), RParenLoc(RParenLoc), + Length(Length ? *Length : PartialArgs.size()), Pack(Pack) { + assert((!Length || PartialArgs.empty()) && + "have partial args for non-dependent sizeof... expression"); + TemplateArgument *Args = getTrailingObjects<TemplateArgument>(); + std::uninitialized_copy(PartialArgs.begin(), PartialArgs.end(), Args); + } + + /// \brief Create an empty expression. + SizeOfPackExpr(EmptyShell Empty, unsigned NumPartialArgs) + : Expr(SizeOfPackExprClass, Empty), Length(NumPartialArgs), Pack() {} + +public: + static SizeOfPackExpr *Create(ASTContext &Context, SourceLocation OperatorLoc, + NamedDecl *Pack, SourceLocation PackLoc, + SourceLocation RParenLoc, + Optional<unsigned> Length = None, + ArrayRef<TemplateArgument> PartialArgs = None); + static SizeOfPackExpr *CreateDeserialized(ASTContext &Context, + unsigned NumPartialArgs); + + /// \brief Determine the location of the 'sizeof' keyword. + SourceLocation getOperatorLoc() const { return OperatorLoc; } + + /// \brief Determine the location of the parameter pack. + SourceLocation getPackLoc() const { return PackLoc; } + + /// \brief Determine the location of the right parenthesis. + SourceLocation getRParenLoc() const { return RParenLoc; } + + /// \brief Retrieve the parameter pack. + NamedDecl *getPack() const { return Pack; } + + /// \brief Retrieve the length of the parameter pack. + /// + /// This routine may only be invoked when the expression is not + /// value-dependent. + unsigned getPackLength() const { + assert(!isValueDependent() && + "Cannot get the length of a value-dependent pack size expression"); + return Length; + } + + /// \brief Determine whether this represents a partially-substituted sizeof... + /// expression, such as is produced for: + /// + /// template<typename ...Ts> using X = int[sizeof...(Ts)]; + /// template<typename ...Us> void f(X<Us..., 1, 2, 3, Us...>); + bool isPartiallySubstituted() const { + return isValueDependent() && Length; + } + + /// \brief Get + ArrayRef<TemplateArgument> getPartialArguments() const { + assert(isPartiallySubstituted()); + const TemplateArgument *Args = getTrailingObjects<TemplateArgument>(); + return llvm::makeArrayRef(Args, Args + Length); + } + + SourceLocation getLocStart() const LLVM_READONLY { return OperatorLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == SizeOfPackExprClass; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +/// \brief Represents a reference to a non-type template parameter +/// that has been substituted with a template argument. +class SubstNonTypeTemplateParmExpr : public Expr { + /// \brief The replaced parameter. + NonTypeTemplateParmDecl *Param; + + /// \brief The replacement expression. + Stmt *Replacement; + + /// \brief The location of the non-type template parameter reference. + SourceLocation NameLoc; + + friend class ASTReader; + friend class ASTStmtReader; + explicit SubstNonTypeTemplateParmExpr(EmptyShell Empty) + : Expr(SubstNonTypeTemplateParmExprClass, Empty) { } + +public: + SubstNonTypeTemplateParmExpr(QualType type, + ExprValueKind valueKind, + SourceLocation loc, + NonTypeTemplateParmDecl *param, + Expr *replacement) + : Expr(SubstNonTypeTemplateParmExprClass, type, valueKind, OK_Ordinary, + replacement->isTypeDependent(), replacement->isValueDependent(), + replacement->isInstantiationDependent(), + replacement->containsUnexpandedParameterPack()), + Param(param), Replacement(replacement), NameLoc(loc) {} + + SourceLocation getNameLoc() const { return NameLoc; } + SourceLocation getLocStart() const LLVM_READONLY { return NameLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return NameLoc; } + + Expr *getReplacement() const { return cast<Expr>(Replacement); } + + NonTypeTemplateParmDecl *getParameter() const { return Param; } + + static bool classof(const Stmt *s) { + return s->getStmtClass() == SubstNonTypeTemplateParmExprClass; + } + + // Iterators + child_range children() { return child_range(&Replacement, &Replacement+1); } +}; + +/// \brief Represents a reference to a non-type template parameter pack that +/// has been substituted with a non-template argument pack. +/// +/// When a pack expansion in the source code contains multiple parameter packs +/// and those parameter packs correspond to different levels of template +/// parameter lists, this node is used to represent a non-type template +/// parameter pack from an outer level, which has already had its argument pack +/// substituted but that still lives within a pack expansion that itself +/// could not be instantiated. When actually performing a substitution into +/// that pack expansion (e.g., when all template parameters have corresponding +/// arguments), this type will be replaced with the appropriate underlying +/// expression at the current pack substitution index. +class SubstNonTypeTemplateParmPackExpr : public Expr { + /// \brief The non-type template parameter pack itself. + NonTypeTemplateParmDecl *Param; + + /// \brief A pointer to the set of template arguments that this + /// parameter pack is instantiated with. + const TemplateArgument *Arguments; + + /// \brief The number of template arguments in \c Arguments. + unsigned NumArguments; + + /// \brief The location of the non-type template parameter pack reference. + SourceLocation NameLoc; + + friend class ASTReader; + friend class ASTStmtReader; + explicit SubstNonTypeTemplateParmPackExpr(EmptyShell Empty) + : Expr(SubstNonTypeTemplateParmPackExprClass, Empty) { } + +public: + SubstNonTypeTemplateParmPackExpr(QualType T, + NonTypeTemplateParmDecl *Param, + SourceLocation NameLoc, + const TemplateArgument &ArgPack); + + /// \brief Retrieve the non-type template parameter pack being substituted. + NonTypeTemplateParmDecl *getParameterPack() const { return Param; } + + /// \brief Retrieve the location of the parameter pack name. + SourceLocation getParameterPackLocation() const { return NameLoc; } + + /// \brief Retrieve the template argument pack containing the substituted + /// template arguments. + TemplateArgument getArgumentPack() const; + + SourceLocation getLocStart() const LLVM_READONLY { return NameLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return NameLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == SubstNonTypeTemplateParmPackExprClass; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +/// \brief Represents a reference to a function parameter pack that has been +/// substituted but not yet expanded. +/// +/// When a pack expansion contains multiple parameter packs at different levels, +/// this node is used to represent a function parameter pack at an outer level +/// which we have already substituted to refer to expanded parameters, but where +/// the containing pack expansion cannot yet be expanded. +/// +/// \code +/// template<typename...Ts> struct S { +/// template<typename...Us> auto f(Ts ...ts) -> decltype(g(Us(ts)...)); +/// }; +/// template struct S<int, int>; +/// \endcode +class FunctionParmPackExpr final + : public Expr, + private llvm::TrailingObjects<FunctionParmPackExpr, ParmVarDecl *> { + /// \brief The function parameter pack which was referenced. + ParmVarDecl *ParamPack; + + /// \brief The location of the function parameter pack reference. + SourceLocation NameLoc; + + /// \brief The number of expansions of this pack. + unsigned NumParameters; + + FunctionParmPackExpr(QualType T, ParmVarDecl *ParamPack, + SourceLocation NameLoc, unsigned NumParams, + ParmVarDecl *const *Params); + + friend TrailingObjects; + friend class ASTReader; + friend class ASTStmtReader; + +public: + static FunctionParmPackExpr *Create(const ASTContext &Context, QualType T, + ParmVarDecl *ParamPack, + SourceLocation NameLoc, + ArrayRef<ParmVarDecl *> Params); + static FunctionParmPackExpr *CreateEmpty(const ASTContext &Context, + unsigned NumParams); + + /// \brief Get the parameter pack which this expression refers to. + ParmVarDecl *getParameterPack() const { return ParamPack; } + + /// \brief Get the location of the parameter pack. + SourceLocation getParameterPackLocation() const { return NameLoc; } + + /// \brief Iterators over the parameters which the parameter pack expanded + /// into. + typedef ParmVarDecl * const *iterator; + iterator begin() const { return getTrailingObjects<ParmVarDecl *>(); } + iterator end() const { return begin() + NumParameters; } + + /// \brief Get the number of parameters in this parameter pack. + unsigned getNumExpansions() const { return NumParameters; } + + /// \brief Get an expansion of the parameter pack by index. + ParmVarDecl *getExpansion(unsigned I) const { return begin()[I]; } + + SourceLocation getLocStart() const LLVM_READONLY { return NameLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return NameLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == FunctionParmPackExprClass; + } + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +/// \brief Represents a prvalue temporary that is written into memory so that +/// a reference can bind to it. +/// +/// Prvalue expressions are materialized when they need to have an address +/// in memory for a reference to bind to. This happens when binding a +/// reference to the result of a conversion, e.g., +/// +/// \code +/// const int &r = 1.0; +/// \endcode +/// +/// Here, 1.0 is implicitly converted to an \c int. That resulting \c int is +/// then materialized via a \c MaterializeTemporaryExpr, and the reference +/// binds to the temporary. \c MaterializeTemporaryExprs are always glvalues +/// (either an lvalue or an xvalue, depending on the kind of reference binding +/// to it), maintaining the invariant that references always bind to glvalues. +/// +/// Reference binding and copy-elision can both extend the lifetime of a +/// temporary. When either happens, the expression will also track the +/// declaration which is responsible for the lifetime extension. +class MaterializeTemporaryExpr : public Expr { +private: + struct ExtraState { + /// \brief The temporary-generating expression whose value will be + /// materialized. + Stmt *Temporary; + + /// \brief The declaration which lifetime-extended this reference, if any. + /// Either a VarDecl, or (for a ctor-initializer) a FieldDecl. + const ValueDecl *ExtendingDecl; + + unsigned ManglingNumber; + }; + llvm::PointerUnion<Stmt *, ExtraState *> State; + + friend class ASTStmtReader; + friend class ASTStmtWriter; + + void initializeExtraState(const ValueDecl *ExtendedBy, + unsigned ManglingNumber); + +public: + MaterializeTemporaryExpr(QualType T, Expr *Temporary, + bool BoundToLvalueReference) + : Expr(MaterializeTemporaryExprClass, T, + BoundToLvalueReference? VK_LValue : VK_XValue, OK_Ordinary, + Temporary->isTypeDependent(), Temporary->isValueDependent(), + Temporary->isInstantiationDependent(), + Temporary->containsUnexpandedParameterPack()), + State(Temporary) {} + + MaterializeTemporaryExpr(EmptyShell Empty) + : Expr(MaterializeTemporaryExprClass, Empty) { } + + Stmt *getTemporary() const { + return State.is<Stmt *>() ? State.get<Stmt *>() + : State.get<ExtraState *>()->Temporary; + } + + /// \brief Retrieve the temporary-generating subexpression whose value will + /// be materialized into a glvalue. + Expr *GetTemporaryExpr() const { return static_cast<Expr *>(getTemporary()); } + + /// \brief Retrieve the storage duration for the materialized temporary. + StorageDuration getStorageDuration() const { + const ValueDecl *ExtendingDecl = getExtendingDecl(); + if (!ExtendingDecl) + return SD_FullExpression; + // FIXME: This is not necessarily correct for a temporary materialized + // within a default initializer. + if (isa<FieldDecl>(ExtendingDecl)) + return SD_Automatic; + return cast<VarDecl>(ExtendingDecl)->getStorageDuration(); + } + + /// \brief Get the declaration which triggered the lifetime-extension of this + /// temporary, if any. + const ValueDecl *getExtendingDecl() const { + return State.is<Stmt *>() ? nullptr + : State.get<ExtraState *>()->ExtendingDecl; + } + + void setExtendingDecl(const ValueDecl *ExtendedBy, unsigned ManglingNumber); + + unsigned getManglingNumber() const { + return State.is<Stmt *>() ? 0 : State.get<ExtraState *>()->ManglingNumber; + } + + /// \brief Determine whether this materialized temporary is bound to an + /// lvalue reference; otherwise, it's bound to an rvalue reference. + bool isBoundToLvalueReference() const { + return getValueKind() == VK_LValue; + } + + SourceLocation getLocStart() const LLVM_READONLY { + return getTemporary()->getLocStart(); + } + SourceLocation getLocEnd() const LLVM_READONLY { + return getTemporary()->getLocEnd(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == MaterializeTemporaryExprClass; + } + + // Iterators + child_range children() { + if (State.is<Stmt *>()) + return child_range(State.getAddrOfPtr1(), State.getAddrOfPtr1() + 1); + + auto ES = State.get<ExtraState *>(); + return child_range(&ES->Temporary, &ES->Temporary + 1); + } +}; + +/// \brief Represents a folding of a pack over an operator. +/// +/// This expression is always dependent and represents a pack expansion of the +/// forms: +/// +/// ( expr op ... ) +/// ( ... op expr ) +/// ( expr op ... op expr ) +class CXXFoldExpr : public Expr { + SourceLocation LParenLoc; + SourceLocation EllipsisLoc; + SourceLocation RParenLoc; + Stmt *SubExprs[2]; + BinaryOperatorKind Opcode; + + friend class ASTStmtReader; + friend class ASTStmtWriter; +public: + CXXFoldExpr(QualType T, SourceLocation LParenLoc, Expr *LHS, + BinaryOperatorKind Opcode, SourceLocation EllipsisLoc, Expr *RHS, + SourceLocation RParenLoc) + : Expr(CXXFoldExprClass, T, VK_RValue, OK_Ordinary, + /*Dependent*/ true, true, true, + /*ContainsUnexpandedParameterPack*/ false), + LParenLoc(LParenLoc), EllipsisLoc(EllipsisLoc), RParenLoc(RParenLoc), + Opcode(Opcode) { + SubExprs[0] = LHS; + SubExprs[1] = RHS; + } + CXXFoldExpr(EmptyShell Empty) : Expr(CXXFoldExprClass, Empty) {} + + Expr *getLHS() const { return static_cast<Expr*>(SubExprs[0]); } + Expr *getRHS() const { return static_cast<Expr*>(SubExprs[1]); } + + /// Does this produce a right-associated sequence of operators? + bool isRightFold() const { + return getLHS() && getLHS()->containsUnexpandedParameterPack(); + } + /// Does this produce a left-associated sequence of operators? + bool isLeftFold() const { return !isRightFold(); } + /// Get the pattern, that is, the operand that contains an unexpanded pack. + Expr *getPattern() const { return isLeftFold() ? getRHS() : getLHS(); } + /// Get the operand that doesn't contain a pack, for a binary fold. + Expr *getInit() const { return isLeftFold() ? getLHS() : getRHS(); } + + SourceLocation getEllipsisLoc() const { return EllipsisLoc; } + BinaryOperatorKind getOperator() const { return Opcode; } + + SourceLocation getLocStart() const LLVM_READONLY { + return LParenLoc; + } + SourceLocation getLocEnd() const LLVM_READONLY { + return RParenLoc; + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXFoldExprClass; + } + + // Iterators + child_range children() { return child_range(SubExprs, SubExprs + 2); } +}; + +/// \brief Represents an expression that might suspend coroutine execution; +/// either a co_await or co_yield expression. +/// +/// Evaluation of this expression first evaluates its 'ready' expression. If +/// that returns 'false': +/// -- execution of the coroutine is suspended +/// -- the 'suspend' expression is evaluated +/// -- if the 'suspend' expression returns 'false', the coroutine is +/// resumed +/// -- otherwise, control passes back to the resumer. +/// If the coroutine is not suspended, or when it is resumed, the 'resume' +/// expression is evaluated, and its result is the result of the overall +/// expression. +class CoroutineSuspendExpr : public Expr { + SourceLocation KeywordLoc; + + enum SubExpr { Common, Ready, Suspend, Resume, Count }; + Stmt *SubExprs[SubExpr::Count]; + + friend class ASTStmtReader; +public: + CoroutineSuspendExpr(StmtClass SC, SourceLocation KeywordLoc, Expr *Common, + Expr *Ready, Expr *Suspend, Expr *Resume) + : Expr(SC, Resume->getType(), Resume->getValueKind(), + Resume->getObjectKind(), Resume->isTypeDependent(), + Resume->isValueDependent(), Common->isInstantiationDependent(), + Common->containsUnexpandedParameterPack()), + KeywordLoc(KeywordLoc) { + SubExprs[SubExpr::Common] = Common; + SubExprs[SubExpr::Ready] = Ready; + SubExprs[SubExpr::Suspend] = Suspend; + SubExprs[SubExpr::Resume] = Resume; + } + CoroutineSuspendExpr(StmtClass SC, SourceLocation KeywordLoc, QualType Ty, + Expr *Common) + : Expr(SC, Ty, VK_RValue, OK_Ordinary, true, true, true, + Common->containsUnexpandedParameterPack()), + KeywordLoc(KeywordLoc) { + assert(Common->isTypeDependent() && Ty->isDependentType() && + "wrong constructor for non-dependent co_await/co_yield expression"); + SubExprs[SubExpr::Common] = Common; + SubExprs[SubExpr::Ready] = nullptr; + SubExprs[SubExpr::Suspend] = nullptr; + SubExprs[SubExpr::Resume] = nullptr; + } + CoroutineSuspendExpr(StmtClass SC, EmptyShell Empty) : Expr(SC, Empty) { + SubExprs[SubExpr::Common] = nullptr; + SubExprs[SubExpr::Ready] = nullptr; + SubExprs[SubExpr::Suspend] = nullptr; + SubExprs[SubExpr::Resume] = nullptr; + } + + SourceLocation getKeywordLoc() const { return KeywordLoc; } + Expr *getCommonExpr() const { + return static_cast<Expr*>(SubExprs[SubExpr::Common]); + } + + Expr *getReadyExpr() const { + return static_cast<Expr*>(SubExprs[SubExpr::Ready]); + } + Expr *getSuspendExpr() const { + return static_cast<Expr*>(SubExprs[SubExpr::Suspend]); + } + Expr *getResumeExpr() const { + return static_cast<Expr*>(SubExprs[SubExpr::Resume]); + } + + SourceLocation getLocStart() const LLVM_READONLY { + return KeywordLoc; + } + SourceLocation getLocEnd() const LLVM_READONLY { + return getCommonExpr()->getLocEnd(); + } + + child_range children() { + return child_range(SubExprs, SubExprs + SubExpr::Count); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CoawaitExprClass || + T->getStmtClass() == CoyieldExprClass; + } +}; + +/// \brief Represents a 'co_await' expression. +class CoawaitExpr : public CoroutineSuspendExpr { + friend class ASTStmtReader; +public: + CoawaitExpr(SourceLocation CoawaitLoc, Expr *Operand, Expr *Ready, + Expr *Suspend, Expr *Resume) + : CoroutineSuspendExpr(CoawaitExprClass, CoawaitLoc, Operand, Ready, + Suspend, Resume) {} + CoawaitExpr(SourceLocation CoawaitLoc, QualType Ty, Expr *Operand) + : CoroutineSuspendExpr(CoawaitExprClass, CoawaitLoc, Ty, Operand) {} + CoawaitExpr(EmptyShell Empty) + : CoroutineSuspendExpr(CoawaitExprClass, Empty) {} + + Expr *getOperand() const { + // FIXME: Dig out the actual operand or store it. + return getCommonExpr(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CoawaitExprClass; + } +}; + +/// \brief Represents a 'co_yield' expression. +class CoyieldExpr : public CoroutineSuspendExpr { + friend class ASTStmtReader; +public: + CoyieldExpr(SourceLocation CoyieldLoc, Expr *Operand, Expr *Ready, + Expr *Suspend, Expr *Resume) + : CoroutineSuspendExpr(CoyieldExprClass, CoyieldLoc, Operand, Ready, + Suspend, Resume) {} + CoyieldExpr(SourceLocation CoyieldLoc, QualType Ty, Expr *Operand) + : CoroutineSuspendExpr(CoyieldExprClass, CoyieldLoc, Ty, Operand) {} + CoyieldExpr(EmptyShell Empty) + : CoroutineSuspendExpr(CoyieldExprClass, Empty) {} + + Expr *getOperand() const { + // FIXME: Dig out the actual operand or store it. + return getCommonExpr(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CoyieldExprClass; + } +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/ExprObjC.h b/contrib/llvm/tools/clang/include/clang/AST/ExprObjC.h new file mode 100644 index 0000000..61e6383 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/ExprObjC.h @@ -0,0 +1,1568 @@ +//===--- ExprObjC.h - Classes for representing ObjC expressions -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ExprObjC interface and subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_EXPROBJC_H +#define LLVM_CLANG_AST_EXPROBJC_H + +#include "clang/AST/DeclObjC.h" +#include "clang/AST/Expr.h" +#include "clang/AST/SelectorLocationsKind.h" +#include "clang/Basic/IdentifierTable.h" +#include "llvm/Support/Compiler.h" + +namespace clang { + class IdentifierInfo; + class ASTContext; + +/// ObjCStringLiteral, used for Objective-C string literals +/// i.e. @"foo". +class ObjCStringLiteral : public Expr { + Stmt *String; + SourceLocation AtLoc; +public: + ObjCStringLiteral(StringLiteral *SL, QualType T, SourceLocation L) + : Expr(ObjCStringLiteralClass, T, VK_RValue, OK_Ordinary, false, false, + false, false), + String(SL), AtLoc(L) {} + explicit ObjCStringLiteral(EmptyShell Empty) + : Expr(ObjCStringLiteralClass, Empty) {} + + StringLiteral *getString() { return cast<StringLiteral>(String); } + const StringLiteral *getString() const { return cast<StringLiteral>(String); } + void setString(StringLiteral *S) { String = S; } + + SourceLocation getAtLoc() const { return AtLoc; } + void setAtLoc(SourceLocation L) { AtLoc = L; } + + SourceLocation getLocStart() const LLVM_READONLY { return AtLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return String->getLocEnd(); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCStringLiteralClass; + } + + // Iterators + child_range children() { return child_range(&String, &String+1); } +}; + +/// ObjCBoolLiteralExpr - Objective-C Boolean Literal. +/// +class ObjCBoolLiteralExpr : public Expr { + bool Value; + SourceLocation Loc; +public: + ObjCBoolLiteralExpr(bool val, QualType Ty, SourceLocation l) : + Expr(ObjCBoolLiteralExprClass, Ty, VK_RValue, OK_Ordinary, false, false, + false, false), Value(val), Loc(l) {} + + explicit ObjCBoolLiteralExpr(EmptyShell Empty) + : Expr(ObjCBoolLiteralExprClass, Empty) { } + + bool getValue() const { return Value; } + void setValue(bool V) { Value = V; } + + SourceLocation getLocStart() const LLVM_READONLY { return Loc; } + SourceLocation getLocEnd() const LLVM_READONLY { return Loc; } + + SourceLocation getLocation() const { return Loc; } + void setLocation(SourceLocation L) { Loc = L; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCBoolLiteralExprClass; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +/// ObjCBoxedExpr - used for generalized expression boxing. +/// as in: @(strdup("hello world")), @(random()) or @(view.frame) +/// Also used for boxing non-parenthesized numeric literals; +/// as in: @42 or \@true (c++/objc++) or \@__yes (c/objc). +class ObjCBoxedExpr : public Expr { + Stmt *SubExpr; + ObjCMethodDecl *BoxingMethod; + SourceRange Range; +public: + ObjCBoxedExpr(Expr *E, QualType T, ObjCMethodDecl *method, + SourceRange R) + : Expr(ObjCBoxedExprClass, T, VK_RValue, OK_Ordinary, + E->isTypeDependent(), E->isValueDependent(), + E->isInstantiationDependent(), E->containsUnexpandedParameterPack()), + SubExpr(E), BoxingMethod(method), Range(R) {} + explicit ObjCBoxedExpr(EmptyShell Empty) + : Expr(ObjCBoxedExprClass, Empty) {} + + Expr *getSubExpr() { return cast<Expr>(SubExpr); } + const Expr *getSubExpr() const { return cast<Expr>(SubExpr); } + + ObjCMethodDecl *getBoxingMethod() const { + return BoxingMethod; + } + + SourceLocation getAtLoc() const { return Range.getBegin(); } + + SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } + SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } + SourceRange getSourceRange() const LLVM_READONLY { + return Range; + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCBoxedExprClass; + } + + // Iterators + child_range children() { return child_range(&SubExpr, &SubExpr+1); } + + typedef ConstExprIterator const_arg_iterator; + + const_arg_iterator arg_begin() const { + return reinterpret_cast<Stmt const * const*>(&SubExpr); + } + const_arg_iterator arg_end() const { + return reinterpret_cast<Stmt const * const*>(&SubExpr + 1); + } + + friend class ASTStmtReader; +}; + +/// ObjCArrayLiteral - used for objective-c array containers; as in: +/// @[@"Hello", NSApp, [NSNumber numberWithInt:42]]; +class ObjCArrayLiteral final + : public Expr, + private llvm::TrailingObjects<ObjCArrayLiteral, Expr *> { + unsigned NumElements; + SourceRange Range; + ObjCMethodDecl *ArrayWithObjectsMethod; + + ObjCArrayLiteral(ArrayRef<Expr *> Elements, + QualType T, ObjCMethodDecl * Method, + SourceRange SR); + + explicit ObjCArrayLiteral(EmptyShell Empty, unsigned NumElements) + : Expr(ObjCArrayLiteralClass, Empty), NumElements(NumElements) {} + +public: + static ObjCArrayLiteral *Create(const ASTContext &C, + ArrayRef<Expr *> Elements, + QualType T, ObjCMethodDecl * Method, + SourceRange SR); + + static ObjCArrayLiteral *CreateEmpty(const ASTContext &C, + unsigned NumElements); + + SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } + SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } + SourceRange getSourceRange() const LLVM_READONLY { return Range; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCArrayLiteralClass; + } + + /// \brief Retrieve elements of array of literals. + Expr **getElements() { return getTrailingObjects<Expr *>(); } + + /// \brief Retrieve elements of array of literals. + const Expr * const *getElements() const { + return getTrailingObjects<Expr *>(); + } + + /// getNumElements - Return number of elements of objective-c array literal. + unsigned getNumElements() const { return NumElements; } + + /// getExpr - Return the Expr at the specified index. + Expr *getElement(unsigned Index) { + assert((Index < NumElements) && "Arg access out of range!"); + return cast<Expr>(getElements()[Index]); + } + const Expr *getElement(unsigned Index) const { + assert((Index < NumElements) && "Arg access out of range!"); + return cast<Expr>(getElements()[Index]); + } + + ObjCMethodDecl *getArrayWithObjectsMethod() const { + return ArrayWithObjectsMethod; + } + + // Iterators + child_range children() { + return child_range(reinterpret_cast<Stmt **>(getElements()), + reinterpret_cast<Stmt **>(getElements()) + NumElements); + } + + friend TrailingObjects; + friend class ASTStmtReader; +}; + +/// \brief An element in an Objective-C dictionary literal. +/// +struct ObjCDictionaryElement { + /// \brief The key for the dictionary element. + Expr *Key; + + /// \brief The value of the dictionary element. + Expr *Value; + + /// \brief The location of the ellipsis, if this is a pack expansion. + SourceLocation EllipsisLoc; + + /// \brief The number of elements this pack expansion will expand to, if + /// this is a pack expansion and is known. + Optional<unsigned> NumExpansions; + + /// \brief Determines whether this dictionary element is a pack expansion. + bool isPackExpansion() const { return EllipsisLoc.isValid(); } +}; +} // end namespace clang + +namespace llvm { +template <> struct isPodLike<clang::ObjCDictionaryElement> : std::true_type {}; +} + +namespace clang { +/// \brief Internal struct for storing Key/value pair. +struct ObjCDictionaryLiteral_KeyValuePair { + Expr *Key; + Expr *Value; +}; + +/// \brief Internal struct to describes an element that is a pack +/// expansion, used if any of the elements in the dictionary literal +/// are pack expansions. +struct ObjCDictionaryLiteral_ExpansionData { + /// \brief The location of the ellipsis, if this element is a pack + /// expansion. + SourceLocation EllipsisLoc; + + /// \brief If non-zero, the number of elements that this pack + /// expansion will expand to (+1). + unsigned NumExpansionsPlusOne; +}; + +/// ObjCDictionaryLiteral - AST node to represent objective-c dictionary +/// literals; as in: @{@"name" : NSUserName(), @"date" : [NSDate date] }; +class ObjCDictionaryLiteral final + : public Expr, + private llvm::TrailingObjects<ObjCDictionaryLiteral, + ObjCDictionaryLiteral_KeyValuePair, + ObjCDictionaryLiteral_ExpansionData> { + /// \brief The number of elements in this dictionary literal. + unsigned NumElements : 31; + + /// \brief Determine whether this dictionary literal has any pack expansions. + /// + /// If the dictionary literal has pack expansions, then there will + /// be an array of pack expansion data following the array of + /// key/value pairs, which provide the locations of the ellipses (if + /// any) and number of elements in the expansion (if known). If + /// there are no pack expansions, we optimize away this storage. + unsigned HasPackExpansions : 1; + + SourceRange Range; + ObjCMethodDecl *DictWithObjectsMethod; + + typedef ObjCDictionaryLiteral_KeyValuePair KeyValuePair; + typedef ObjCDictionaryLiteral_ExpansionData ExpansionData; + + size_t numTrailingObjects(OverloadToken<KeyValuePair>) const { + return NumElements; + } + + ObjCDictionaryLiteral(ArrayRef<ObjCDictionaryElement> VK, + bool HasPackExpansions, + QualType T, ObjCMethodDecl *method, + SourceRange SR); + + explicit ObjCDictionaryLiteral(EmptyShell Empty, unsigned NumElements, + bool HasPackExpansions) + : Expr(ObjCDictionaryLiteralClass, Empty), NumElements(NumElements), + HasPackExpansions(HasPackExpansions) {} + +public: + static ObjCDictionaryLiteral *Create(const ASTContext &C, + ArrayRef<ObjCDictionaryElement> VK, + bool HasPackExpansions, + QualType T, ObjCMethodDecl *method, + SourceRange SR); + + static ObjCDictionaryLiteral *CreateEmpty(const ASTContext &C, + unsigned NumElements, + bool HasPackExpansions); + + /// getNumElements - Return number of elements of objective-c dictionary + /// literal. + unsigned getNumElements() const { return NumElements; } + + ObjCDictionaryElement getKeyValueElement(unsigned Index) const { + assert((Index < NumElements) && "Arg access out of range!"); + const KeyValuePair &KV = getTrailingObjects<KeyValuePair>()[Index]; + ObjCDictionaryElement Result = { KV.Key, KV.Value, SourceLocation(), None }; + if (HasPackExpansions) { + const ExpansionData &Expansion = + getTrailingObjects<ExpansionData>()[Index]; + Result.EllipsisLoc = Expansion.EllipsisLoc; + if (Expansion.NumExpansionsPlusOne > 0) + Result.NumExpansions = Expansion.NumExpansionsPlusOne - 1; + } + return Result; + } + + ObjCMethodDecl *getDictWithObjectsMethod() const + { return DictWithObjectsMethod; } + + SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } + SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } + SourceRange getSourceRange() const LLVM_READONLY { return Range; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCDictionaryLiteralClass; + } + + // Iterators + child_range children() { + // Note: we're taking advantage of the layout of the KeyValuePair struct + // here. If that struct changes, this code will need to change as well. + static_assert(sizeof(KeyValuePair) == sizeof(Stmt *) * 2, + "KeyValuePair is expected size"); + return child_range( + reinterpret_cast<Stmt **>(getTrailingObjects<KeyValuePair>()), + reinterpret_cast<Stmt **>(getTrailingObjects<KeyValuePair>()) + + NumElements * 2); + } + + friend class ASTStmtReader; + friend class ASTStmtWriter; + friend TrailingObjects; +}; + + +/// ObjCEncodeExpr, used for \@encode in Objective-C. \@encode has the same +/// type and behavior as StringLiteral except that the string initializer is +/// obtained from ASTContext with the encoding type as an argument. +class ObjCEncodeExpr : public Expr { + TypeSourceInfo *EncodedType; + SourceLocation AtLoc, RParenLoc; +public: + ObjCEncodeExpr(QualType T, TypeSourceInfo *EncodedType, + SourceLocation at, SourceLocation rp) + : Expr(ObjCEncodeExprClass, T, VK_LValue, OK_Ordinary, + EncodedType->getType()->isDependentType(), + EncodedType->getType()->isDependentType(), + EncodedType->getType()->isInstantiationDependentType(), + EncodedType->getType()->containsUnexpandedParameterPack()), + EncodedType(EncodedType), AtLoc(at), RParenLoc(rp) {} + + explicit ObjCEncodeExpr(EmptyShell Empty) : Expr(ObjCEncodeExprClass, Empty){} + + + SourceLocation getAtLoc() const { return AtLoc; } + void setAtLoc(SourceLocation L) { AtLoc = L; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + QualType getEncodedType() const { return EncodedType->getType(); } + + TypeSourceInfo *getEncodedTypeSourceInfo() const { return EncodedType; } + void setEncodedTypeSourceInfo(TypeSourceInfo *EncType) { + EncodedType = EncType; + } + + SourceLocation getLocStart() const LLVM_READONLY { return AtLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCEncodeExprClass; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +/// ObjCSelectorExpr used for \@selector in Objective-C. +class ObjCSelectorExpr : public Expr { + Selector SelName; + SourceLocation AtLoc, RParenLoc; +public: + ObjCSelectorExpr(QualType T, Selector selInfo, + SourceLocation at, SourceLocation rp) + : Expr(ObjCSelectorExprClass, T, VK_RValue, OK_Ordinary, false, false, + false, false), + SelName(selInfo), AtLoc(at), RParenLoc(rp){} + explicit ObjCSelectorExpr(EmptyShell Empty) + : Expr(ObjCSelectorExprClass, Empty) {} + + Selector getSelector() const { return SelName; } + void setSelector(Selector S) { SelName = S; } + + SourceLocation getAtLoc() const { return AtLoc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setAtLoc(SourceLocation L) { AtLoc = L; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + SourceLocation getLocStart() const LLVM_READONLY { return AtLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + + /// getNumArgs - Return the number of actual arguments to this call. + unsigned getNumArgs() const { return SelName.getNumArgs(); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCSelectorExprClass; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +/// ObjCProtocolExpr used for protocol expression in Objective-C. +/// +/// This is used as: \@protocol(foo), as in: +/// \code +/// [obj conformsToProtocol:@protocol(foo)] +/// \endcode +/// +/// The return type is "Protocol*". +class ObjCProtocolExpr : public Expr { + ObjCProtocolDecl *TheProtocol; + SourceLocation AtLoc, ProtoLoc, RParenLoc; +public: + ObjCProtocolExpr(QualType T, ObjCProtocolDecl *protocol, + SourceLocation at, SourceLocation protoLoc, SourceLocation rp) + : Expr(ObjCProtocolExprClass, T, VK_RValue, OK_Ordinary, false, false, + false, false), + TheProtocol(protocol), AtLoc(at), ProtoLoc(protoLoc), RParenLoc(rp) {} + explicit ObjCProtocolExpr(EmptyShell Empty) + : Expr(ObjCProtocolExprClass, Empty) {} + + ObjCProtocolDecl *getProtocol() const { return TheProtocol; } + void setProtocol(ObjCProtocolDecl *P) { TheProtocol = P; } + + SourceLocation getProtocolIdLoc() const { return ProtoLoc; } + SourceLocation getAtLoc() const { return AtLoc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setAtLoc(SourceLocation L) { AtLoc = L; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + SourceLocation getLocStart() const LLVM_READONLY { return AtLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCProtocolExprClass; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + + friend class ASTStmtReader; + friend class ASTStmtWriter; +}; + +/// ObjCIvarRefExpr - A reference to an ObjC instance variable. +class ObjCIvarRefExpr : public Expr { + ObjCIvarDecl *D; + Stmt *Base; + SourceLocation Loc; + /// OpLoc - This is the location of '.' or '->' + SourceLocation OpLoc; + + bool IsArrow:1; // True if this is "X->F", false if this is "X.F". + bool IsFreeIvar:1; // True if ivar reference has no base (self assumed). + +public: + ObjCIvarRefExpr(ObjCIvarDecl *d, QualType t, + SourceLocation l, SourceLocation oploc, + Expr *base, + bool arrow = false, bool freeIvar = false) : + Expr(ObjCIvarRefExprClass, t, VK_LValue, + d->isBitField() ? OK_BitField : OK_Ordinary, + /*TypeDependent=*/false, base->isValueDependent(), + base->isInstantiationDependent(), + base->containsUnexpandedParameterPack()), + D(d), Base(base), Loc(l), OpLoc(oploc), + IsArrow(arrow), IsFreeIvar(freeIvar) {} + + explicit ObjCIvarRefExpr(EmptyShell Empty) + : Expr(ObjCIvarRefExprClass, Empty) {} + + ObjCIvarDecl *getDecl() { return D; } + const ObjCIvarDecl *getDecl() const { return D; } + void setDecl(ObjCIvarDecl *d) { D = d; } + + const Expr *getBase() const { return cast<Expr>(Base); } + Expr *getBase() { return cast<Expr>(Base); } + void setBase(Expr * base) { Base = base; } + + bool isArrow() const { return IsArrow; } + bool isFreeIvar() const { return IsFreeIvar; } + void setIsArrow(bool A) { IsArrow = A; } + void setIsFreeIvar(bool A) { IsFreeIvar = A; } + + SourceLocation getLocation() const { return Loc; } + void setLocation(SourceLocation L) { Loc = L; } + + SourceLocation getLocStart() const LLVM_READONLY { + return isFreeIvar() ? Loc : getBase()->getLocStart(); + } + SourceLocation getLocEnd() const LLVM_READONLY { return Loc; } + + SourceLocation getOpLoc() const { return OpLoc; } + void setOpLoc(SourceLocation L) { OpLoc = L; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCIvarRefExprClass; + } + + // Iterators + child_range children() { return child_range(&Base, &Base+1); } +}; + +/// ObjCPropertyRefExpr - A dot-syntax expression to access an ObjC +/// property. +class ObjCPropertyRefExpr : public Expr { +private: + /// If the bool is true, this is an implicit property reference; the + /// pointer is an (optional) ObjCMethodDecl and Setter may be set. + /// if the bool is false, this is an explicit property reference; + /// the pointer is an ObjCPropertyDecl and Setter is always null. + llvm::PointerIntPair<NamedDecl*, 1, bool> PropertyOrGetter; + + /// \brief Indicates whether the property reference will result in a message + /// to the getter, the setter, or both. + /// This applies to both implicit and explicit property references. + enum MethodRefFlags { + MethodRef_None = 0, + MethodRef_Getter = 0x1, + MethodRef_Setter = 0x2 + }; + + /// \brief Contains the Setter method pointer and MethodRefFlags bit flags. + llvm::PointerIntPair<ObjCMethodDecl *, 2, unsigned> SetterAndMethodRefFlags; + + // FIXME: Maybe we should store the property identifier here, + // because it's not rederivable from the other data when there's an + // implicit property with no getter (because the 'foo' -> 'setFoo:' + // transformation is lossy on the first character). + + SourceLocation IdLoc; + + /// \brief When the receiver in property access is 'super', this is + /// the location of the 'super' keyword. When it's an interface, + /// this is that interface. + SourceLocation ReceiverLoc; + llvm::PointerUnion3<Stmt*, const Type*, ObjCInterfaceDecl*> Receiver; + +public: + ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t, + ExprValueKind VK, ExprObjectKind OK, + SourceLocation l, Expr *base) + : Expr(ObjCPropertyRefExprClass, t, VK, OK, + /*TypeDependent=*/false, base->isValueDependent(), + base->isInstantiationDependent(), + base->containsUnexpandedParameterPack()), + PropertyOrGetter(PD, false), SetterAndMethodRefFlags(), + IdLoc(l), ReceiverLoc(), Receiver(base) { + assert(t->isSpecificPlaceholderType(BuiltinType::PseudoObject)); + } + + ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t, + ExprValueKind VK, ExprObjectKind OK, + SourceLocation l, SourceLocation sl, QualType st) + : Expr(ObjCPropertyRefExprClass, t, VK, OK, + /*TypeDependent=*/false, false, st->isInstantiationDependentType(), + st->containsUnexpandedParameterPack()), + PropertyOrGetter(PD, false), SetterAndMethodRefFlags(), + IdLoc(l), ReceiverLoc(sl), Receiver(st.getTypePtr()) { + assert(t->isSpecificPlaceholderType(BuiltinType::PseudoObject)); + } + + ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter, + QualType T, ExprValueKind VK, ExprObjectKind OK, + SourceLocation IdLoc, Expr *Base) + : Expr(ObjCPropertyRefExprClass, T, VK, OK, false, + Base->isValueDependent(), Base->isInstantiationDependent(), + Base->containsUnexpandedParameterPack()), + PropertyOrGetter(Getter, true), SetterAndMethodRefFlags(Setter, 0), + IdLoc(IdLoc), ReceiverLoc(), Receiver(Base) { + assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject)); + } + + ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter, + QualType T, ExprValueKind VK, ExprObjectKind OK, + SourceLocation IdLoc, + SourceLocation SuperLoc, QualType SuperTy) + : Expr(ObjCPropertyRefExprClass, T, VK, OK, false, false, false, false), + PropertyOrGetter(Getter, true), SetterAndMethodRefFlags(Setter, 0), + IdLoc(IdLoc), ReceiverLoc(SuperLoc), Receiver(SuperTy.getTypePtr()) { + assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject)); + } + + ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter, + QualType T, ExprValueKind VK, ExprObjectKind OK, + SourceLocation IdLoc, + SourceLocation ReceiverLoc, ObjCInterfaceDecl *Receiver) + : Expr(ObjCPropertyRefExprClass, T, VK, OK, false, false, false, false), + PropertyOrGetter(Getter, true), SetterAndMethodRefFlags(Setter, 0), + IdLoc(IdLoc), ReceiverLoc(ReceiverLoc), Receiver(Receiver) { + assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject)); + } + + explicit ObjCPropertyRefExpr(EmptyShell Empty) + : Expr(ObjCPropertyRefExprClass, Empty) {} + + bool isImplicitProperty() const { return PropertyOrGetter.getInt(); } + bool isExplicitProperty() const { return !PropertyOrGetter.getInt(); } + + ObjCPropertyDecl *getExplicitProperty() const { + assert(!isImplicitProperty()); + return cast<ObjCPropertyDecl>(PropertyOrGetter.getPointer()); + } + + ObjCMethodDecl *getImplicitPropertyGetter() const { + assert(isImplicitProperty()); + return cast_or_null<ObjCMethodDecl>(PropertyOrGetter.getPointer()); + } + + ObjCMethodDecl *getImplicitPropertySetter() const { + assert(isImplicitProperty()); + return SetterAndMethodRefFlags.getPointer(); + } + + Selector getGetterSelector() const { + if (isImplicitProperty()) + return getImplicitPropertyGetter()->getSelector(); + return getExplicitProperty()->getGetterName(); + } + + Selector getSetterSelector() const { + if (isImplicitProperty()) + return getImplicitPropertySetter()->getSelector(); + return getExplicitProperty()->getSetterName(); + } + + /// \brief True if the property reference will result in a message to the + /// getter. + /// This applies to both implicit and explicit property references. + bool isMessagingGetter() const { + return SetterAndMethodRefFlags.getInt() & MethodRef_Getter; + } + + /// \brief True if the property reference will result in a message to the + /// setter. + /// This applies to both implicit and explicit property references. + bool isMessagingSetter() const { + return SetterAndMethodRefFlags.getInt() & MethodRef_Setter; + } + + void setIsMessagingGetter(bool val = true) { + setMethodRefFlag(MethodRef_Getter, val); + } + + void setIsMessagingSetter(bool val = true) { + setMethodRefFlag(MethodRef_Setter, val); + } + + const Expr *getBase() const { + return cast<Expr>(Receiver.get<Stmt*>()); + } + Expr *getBase() { + return cast<Expr>(Receiver.get<Stmt*>()); + } + + SourceLocation getLocation() const { return IdLoc; } + + SourceLocation getReceiverLocation() const { return ReceiverLoc; } + QualType getSuperReceiverType() const { + return QualType(Receiver.get<const Type*>(), 0); + } + + ObjCInterfaceDecl *getClassReceiver() const { + return Receiver.get<ObjCInterfaceDecl*>(); + } + bool isObjectReceiver() const { return Receiver.is<Stmt*>(); } + bool isSuperReceiver() const { return Receiver.is<const Type*>(); } + bool isClassReceiver() const { return Receiver.is<ObjCInterfaceDecl*>(); } + + /// Determine the type of the base, regardless of the kind of receiver. + QualType getReceiverType(const ASTContext &ctx) const; + + SourceLocation getLocStart() const LLVM_READONLY { + return isObjectReceiver() ? getBase()->getLocStart() :getReceiverLocation(); + } + SourceLocation getLocEnd() const LLVM_READONLY { return IdLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCPropertyRefExprClass; + } + + // Iterators + child_range children() { + if (Receiver.is<Stmt*>()) { + Stmt **begin = reinterpret_cast<Stmt**>(&Receiver); // hack! + return child_range(begin, begin+1); + } + return child_range(child_iterator(), child_iterator()); + } + +private: + friend class ASTStmtReader; + friend class ASTStmtWriter; + void setExplicitProperty(ObjCPropertyDecl *D, unsigned methRefFlags) { + PropertyOrGetter.setPointer(D); + PropertyOrGetter.setInt(false); + SetterAndMethodRefFlags.setPointer(nullptr); + SetterAndMethodRefFlags.setInt(methRefFlags); + } + void setImplicitProperty(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter, + unsigned methRefFlags) { + PropertyOrGetter.setPointer(Getter); + PropertyOrGetter.setInt(true); + SetterAndMethodRefFlags.setPointer(Setter); + SetterAndMethodRefFlags.setInt(methRefFlags); + } + void setBase(Expr *Base) { Receiver = Base; } + void setSuperReceiver(QualType T) { Receiver = T.getTypePtr(); } + void setClassReceiver(ObjCInterfaceDecl *D) { Receiver = D; } + + void setLocation(SourceLocation L) { IdLoc = L; } + void setReceiverLocation(SourceLocation Loc) { ReceiverLoc = Loc; } + + void setMethodRefFlag(MethodRefFlags flag, bool val) { + unsigned f = SetterAndMethodRefFlags.getInt(); + if (val) + f |= flag; + else + f &= ~flag; + SetterAndMethodRefFlags.setInt(f); + } +}; + +/// ObjCSubscriptRefExpr - used for array and dictionary subscripting. +/// array[4] = array[3]; dictionary[key] = dictionary[alt_key]; +/// +class ObjCSubscriptRefExpr : public Expr { + // Location of ']' in an indexing expression. + SourceLocation RBracket; + // array/dictionary base expression. + // for arrays, this is a numeric expression. For dictionaries, this is + // an objective-c object pointer expression. + enum { BASE, KEY, END_EXPR }; + Stmt* SubExprs[END_EXPR]; + + ObjCMethodDecl *GetAtIndexMethodDecl; + + // For immutable objects this is null. When ObjCSubscriptRefExpr is to read + // an indexed object this is null too. + ObjCMethodDecl *SetAtIndexMethodDecl; + +public: + + ObjCSubscriptRefExpr(Expr *base, Expr *key, QualType T, + ExprValueKind VK, ExprObjectKind OK, + ObjCMethodDecl *getMethod, + ObjCMethodDecl *setMethod, SourceLocation RB) + : Expr(ObjCSubscriptRefExprClass, T, VK, OK, + base->isTypeDependent() || key->isTypeDependent(), + base->isValueDependent() || key->isValueDependent(), + base->isInstantiationDependent() || key->isInstantiationDependent(), + (base->containsUnexpandedParameterPack() || + key->containsUnexpandedParameterPack())), + RBracket(RB), + GetAtIndexMethodDecl(getMethod), + SetAtIndexMethodDecl(setMethod) + {SubExprs[BASE] = base; SubExprs[KEY] = key;} + + explicit ObjCSubscriptRefExpr(EmptyShell Empty) + : Expr(ObjCSubscriptRefExprClass, Empty) {} + + SourceLocation getRBracket() const { return RBracket; } + void setRBracket(SourceLocation RB) { RBracket = RB; } + + SourceLocation getLocStart() const LLVM_READONLY { + return SubExprs[BASE]->getLocStart(); + } + SourceLocation getLocEnd() const LLVM_READONLY { return RBracket; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCSubscriptRefExprClass; + } + + Expr *getBaseExpr() const { return cast<Expr>(SubExprs[BASE]); } + void setBaseExpr(Stmt *S) { SubExprs[BASE] = S; } + + Expr *getKeyExpr() const { return cast<Expr>(SubExprs[KEY]); } + void setKeyExpr(Stmt *S) { SubExprs[KEY] = S; } + + ObjCMethodDecl *getAtIndexMethodDecl() const { + return GetAtIndexMethodDecl; + } + + ObjCMethodDecl *setAtIndexMethodDecl() const { + return SetAtIndexMethodDecl; + } + + bool isArraySubscriptRefExpr() const { + return getKeyExpr()->getType()->isIntegralOrEnumerationType(); + } + + child_range children() { + return child_range(SubExprs, SubExprs+END_EXPR); + } +private: + friend class ASTStmtReader; +}; + + +/// \brief An expression that sends a message to the given Objective-C +/// object or class. +/// +/// The following contains two message send expressions: +/// +/// \code +/// [[NSString alloc] initWithString:@"Hello"] +/// \endcode +/// +/// The innermost message send invokes the "alloc" class method on the +/// NSString class, while the outermost message send invokes the +/// "initWithString" instance method on the object returned from +/// NSString's "alloc". In all, an Objective-C message send can take +/// on four different (although related) forms: +/// +/// 1. Send to an object instance. +/// 2. Send to a class. +/// 3. Send to the superclass instance of the current class. +/// 4. Send to the superclass of the current class. +/// +/// All four kinds of message sends are modeled by the ObjCMessageExpr +/// class, and can be distinguished via \c getReceiverKind(). Example: +/// +/// The "void *" trailing objects are actually ONE void * (the +/// receiver pointer), and NumArgs Expr *. But due to the +/// implementation of children(), these must be together contiguously. + +class ObjCMessageExpr final + : public Expr, + private llvm::TrailingObjects<ObjCMessageExpr, void *, SourceLocation> { + /// \brief Stores either the selector that this message is sending + /// to (when \c HasMethod is zero) or an \c ObjCMethodDecl pointer + /// referring to the method that we type-checked against. + uintptr_t SelectorOrMethod; + + enum { NumArgsBitWidth = 16 }; + + /// \brief The number of arguments in the message send, not + /// including the receiver. + unsigned NumArgs : NumArgsBitWidth; + + /// \brief The kind of message send this is, which is one of the + /// ReceiverKind values. + /// + /// We pad this out to a byte to avoid excessive masking and shifting. + unsigned Kind : 8; + + /// \brief Whether we have an actual method prototype in \c + /// SelectorOrMethod. + /// + /// When non-zero, we have a method declaration; otherwise, we just + /// have a selector. + unsigned HasMethod : 1; + + /// \brief Whether this message send is a "delegate init call", + /// i.e. a call of an init method on self from within an init method. + unsigned IsDelegateInitCall : 1; + + /// \brief Whether this message send was implicitly generated by + /// the implementation rather than explicitly written by the user. + unsigned IsImplicit : 1; + + /// \brief Whether the locations of the selector identifiers are in a + /// "standard" position, a enum SelectorLocationsKind. + unsigned SelLocsKind : 2; + + /// \brief When the message expression is a send to 'super', this is + /// the location of the 'super' keyword. + SourceLocation SuperLoc; + + /// \brief The source locations of the open and close square + /// brackets ('[' and ']', respectively). + SourceLocation LBracLoc, RBracLoc; + + size_t numTrailingObjects(OverloadToken<void *>) const { return NumArgs + 1; } + + void setNumArgs(unsigned Num) { + assert((Num >> NumArgsBitWidth) == 0 && "Num of args is out of range!"); + NumArgs = Num; + } + + ObjCMessageExpr(EmptyShell Empty, unsigned NumArgs) + : Expr(ObjCMessageExprClass, Empty), SelectorOrMethod(0), Kind(0), + HasMethod(0), IsDelegateInitCall(0), IsImplicit(0), SelLocsKind(0) { + setNumArgs(NumArgs); + } + + ObjCMessageExpr(QualType T, ExprValueKind VK, + SourceLocation LBracLoc, + SourceLocation SuperLoc, + bool IsInstanceSuper, + QualType SuperType, + Selector Sel, + ArrayRef<SourceLocation> SelLocs, + SelectorLocationsKind SelLocsK, + ObjCMethodDecl *Method, + ArrayRef<Expr *> Args, + SourceLocation RBracLoc, + bool isImplicit); + ObjCMessageExpr(QualType T, ExprValueKind VK, + SourceLocation LBracLoc, + TypeSourceInfo *Receiver, + Selector Sel, + ArrayRef<SourceLocation> SelLocs, + SelectorLocationsKind SelLocsK, + ObjCMethodDecl *Method, + ArrayRef<Expr *> Args, + SourceLocation RBracLoc, + bool isImplicit); + ObjCMessageExpr(QualType T, ExprValueKind VK, + SourceLocation LBracLoc, + Expr *Receiver, + Selector Sel, + ArrayRef<SourceLocation> SelLocs, + SelectorLocationsKind SelLocsK, + ObjCMethodDecl *Method, + ArrayRef<Expr *> Args, + SourceLocation RBracLoc, + bool isImplicit); + + void initArgsAndSelLocs(ArrayRef<Expr *> Args, + ArrayRef<SourceLocation> SelLocs, + SelectorLocationsKind SelLocsK); + + /// \brief Retrieve the pointer value of the message receiver. + void *getReceiverPointer() const { return *getTrailingObjects<void *>(); } + + /// \brief Set the pointer value of the message receiver. + void setReceiverPointer(void *Value) { + *getTrailingObjects<void *>() = Value; + } + + SelectorLocationsKind getSelLocsKind() const { + return (SelectorLocationsKind)SelLocsKind; + } + bool hasStandardSelLocs() const { + return getSelLocsKind() != SelLoc_NonStandard; + } + + /// \brief Get a pointer to the stored selector identifiers locations array. + /// No locations will be stored if HasStandardSelLocs is true. + SourceLocation *getStoredSelLocs() { + return getTrailingObjects<SourceLocation>(); + } + const SourceLocation *getStoredSelLocs() const { + return getTrailingObjects<SourceLocation>(); + } + + /// \brief Get the number of stored selector identifiers locations. + /// No locations will be stored if HasStandardSelLocs is true. + unsigned getNumStoredSelLocs() const { + if (hasStandardSelLocs()) + return 0; + return getNumSelectorLocs(); + } + + static ObjCMessageExpr *alloc(const ASTContext &C, + ArrayRef<Expr *> Args, + SourceLocation RBraceLoc, + ArrayRef<SourceLocation> SelLocs, + Selector Sel, + SelectorLocationsKind &SelLocsK); + static ObjCMessageExpr *alloc(const ASTContext &C, + unsigned NumArgs, + unsigned NumStoredSelLocs); + +public: + /// \brief The kind of receiver this message is sending to. + enum ReceiverKind { + /// \brief The receiver is a class. + Class = 0, + /// \brief The receiver is an object instance. + Instance, + /// \brief The receiver is a superclass. + SuperClass, + /// \brief The receiver is the instance of the superclass object. + SuperInstance + }; + + /// \brief Create a message send to super. + /// + /// \param Context The ASTContext in which this expression will be created. + /// + /// \param T The result type of this message. + /// + /// \param VK The value kind of this message. A message returning + /// a l-value or r-value reference will be an l-value or x-value, + /// respectively. + /// + /// \param LBracLoc The location of the open square bracket '['. + /// + /// \param SuperLoc The location of the "super" keyword. + /// + /// \param IsInstanceSuper Whether this is an instance "super" + /// message (otherwise, it's a class "super" message). + /// + /// \param Sel The selector used to determine which method gets called. + /// + /// \param Method The Objective-C method against which this message + /// send was type-checked. May be NULL. + /// + /// \param Args The message send arguments. + /// + /// \param RBracLoc The location of the closing square bracket ']'. + static ObjCMessageExpr *Create(const ASTContext &Context, QualType T, + ExprValueKind VK, + SourceLocation LBracLoc, + SourceLocation SuperLoc, + bool IsInstanceSuper, + QualType SuperType, + Selector Sel, + ArrayRef<SourceLocation> SelLocs, + ObjCMethodDecl *Method, + ArrayRef<Expr *> Args, + SourceLocation RBracLoc, + bool isImplicit); + + /// \brief Create a class message send. + /// + /// \param Context The ASTContext in which this expression will be created. + /// + /// \param T The result type of this message. + /// + /// \param VK The value kind of this message. A message returning + /// a l-value or r-value reference will be an l-value or x-value, + /// respectively. + /// + /// \param LBracLoc The location of the open square bracket '['. + /// + /// \param Receiver The type of the receiver, including + /// source-location information. + /// + /// \param Sel The selector used to determine which method gets called. + /// + /// \param Method The Objective-C method against which this message + /// send was type-checked. May be NULL. + /// + /// \param Args The message send arguments. + /// + /// \param RBracLoc The location of the closing square bracket ']'. + static ObjCMessageExpr *Create(const ASTContext &Context, QualType T, + ExprValueKind VK, + SourceLocation LBracLoc, + TypeSourceInfo *Receiver, + Selector Sel, + ArrayRef<SourceLocation> SelLocs, + ObjCMethodDecl *Method, + ArrayRef<Expr *> Args, + SourceLocation RBracLoc, + bool isImplicit); + + /// \brief Create an instance message send. + /// + /// \param Context The ASTContext in which this expression will be created. + /// + /// \param T The result type of this message. + /// + /// \param VK The value kind of this message. A message returning + /// a l-value or r-value reference will be an l-value or x-value, + /// respectively. + /// + /// \param LBracLoc The location of the open square bracket '['. + /// + /// \param Receiver The expression used to produce the object that + /// will receive this message. + /// + /// \param Sel The selector used to determine which method gets called. + /// + /// \param Method The Objective-C method against which this message + /// send was type-checked. May be NULL. + /// + /// \param Args The message send arguments. + /// + /// \param RBracLoc The location of the closing square bracket ']'. + static ObjCMessageExpr *Create(const ASTContext &Context, QualType T, + ExprValueKind VK, + SourceLocation LBracLoc, + Expr *Receiver, + Selector Sel, + ArrayRef<SourceLocation> SeLocs, + ObjCMethodDecl *Method, + ArrayRef<Expr *> Args, + SourceLocation RBracLoc, + bool isImplicit); + + /// \brief Create an empty Objective-C message expression, to be + /// filled in by subsequent calls. + /// + /// \param Context The context in which the message send will be created. + /// + /// \param NumArgs The number of message arguments, not including + /// the receiver. + static ObjCMessageExpr *CreateEmpty(const ASTContext &Context, + unsigned NumArgs, + unsigned NumStoredSelLocs); + + /// \brief Indicates whether the message send was implicitly + /// generated by the implementation. If false, it was written explicitly + /// in the source code. + bool isImplicit() const { return IsImplicit; } + + /// \brief Determine the kind of receiver that this message is being + /// sent to. + ReceiverKind getReceiverKind() const { return (ReceiverKind)Kind; } + + /// \brief Source range of the receiver. + SourceRange getReceiverRange() const; + + /// \brief Determine whether this is an instance message to either a + /// computed object or to super. + bool isInstanceMessage() const { + return getReceiverKind() == Instance || getReceiverKind() == SuperInstance; + } + + /// \brief Determine whether this is an class message to either a + /// specified class or to super. + bool isClassMessage() const { + return getReceiverKind() == Class || getReceiverKind() == SuperClass; + } + + /// \brief Returns the object expression (receiver) for an instance message, + /// or null for a message that is not an instance message. + Expr *getInstanceReceiver() { + if (getReceiverKind() == Instance) + return static_cast<Expr *>(getReceiverPointer()); + + return nullptr; + } + const Expr *getInstanceReceiver() const { + return const_cast<ObjCMessageExpr*>(this)->getInstanceReceiver(); + } + + /// \brief Turn this message send into an instance message that + /// computes the receiver object with the given expression. + void setInstanceReceiver(Expr *rec) { + Kind = Instance; + setReceiverPointer(rec); + } + + /// \brief Returns the type of a class message send, or NULL if the + /// message is not a class message. + QualType getClassReceiver() const { + if (TypeSourceInfo *TSInfo = getClassReceiverTypeInfo()) + return TSInfo->getType(); + + return QualType(); + } + + /// \brief Returns a type-source information of a class message + /// send, or NULL if the message is not a class message. + TypeSourceInfo *getClassReceiverTypeInfo() const { + if (getReceiverKind() == Class) + return reinterpret_cast<TypeSourceInfo *>(getReceiverPointer()); + return nullptr; + } + + void setClassReceiver(TypeSourceInfo *TSInfo) { + Kind = Class; + setReceiverPointer(TSInfo); + } + + /// \brief Retrieve the location of the 'super' keyword for a class + /// or instance message to 'super', otherwise an invalid source location. + SourceLocation getSuperLoc() const { + if (getReceiverKind() == SuperInstance || getReceiverKind() == SuperClass) + return SuperLoc; + + return SourceLocation(); + } + + /// \brief Retrieve the receiver type to which this message is being directed. + /// + /// This routine cross-cuts all of the different kinds of message + /// sends to determine what the underlying (statically known) type + /// of the receiver will be; use \c getReceiverKind() to determine + /// whether the message is a class or an instance method, whether it + /// is a send to super or not, etc. + /// + /// \returns The type of the receiver. + QualType getReceiverType() const; + + /// \brief Retrieve the Objective-C interface to which this message + /// is being directed, if known. + /// + /// This routine cross-cuts all of the different kinds of message + /// sends to determine what the underlying (statically known) type + /// of the receiver will be; use \c getReceiverKind() to determine + /// whether the message is a class or an instance method, whether it + /// is a send to super or not, etc. + /// + /// \returns The Objective-C interface if known, otherwise NULL. + ObjCInterfaceDecl *getReceiverInterface() const; + + /// \brief Retrieve the type referred to by 'super'. + /// + /// The returned type will either be an ObjCInterfaceType (for an + /// class message to super) or an ObjCObjectPointerType that refers + /// to a class (for an instance message to super); + QualType getSuperType() const { + if (getReceiverKind() == SuperInstance || getReceiverKind() == SuperClass) + return QualType::getFromOpaquePtr(getReceiverPointer()); + + return QualType(); + } + + void setSuper(SourceLocation Loc, QualType T, bool IsInstanceSuper) { + Kind = IsInstanceSuper? SuperInstance : SuperClass; + SuperLoc = Loc; + setReceiverPointer(T.getAsOpaquePtr()); + } + + Selector getSelector() const; + + void setSelector(Selector S) { + HasMethod = false; + SelectorOrMethod = reinterpret_cast<uintptr_t>(S.getAsOpaquePtr()); + } + + const ObjCMethodDecl *getMethodDecl() const { + if (HasMethod) + return reinterpret_cast<const ObjCMethodDecl *>(SelectorOrMethod); + + return nullptr; + } + + ObjCMethodDecl *getMethodDecl() { + if (HasMethod) + return reinterpret_cast<ObjCMethodDecl *>(SelectorOrMethod); + + return nullptr; + } + + void setMethodDecl(ObjCMethodDecl *MD) { + HasMethod = true; + SelectorOrMethod = reinterpret_cast<uintptr_t>(MD); + } + + ObjCMethodFamily getMethodFamily() const { + if (HasMethod) return getMethodDecl()->getMethodFamily(); + return getSelector().getMethodFamily(); + } + + /// \brief Return the number of actual arguments in this message, + /// not counting the receiver. + unsigned getNumArgs() const { return NumArgs; } + + /// \brief Retrieve the arguments to this message, not including the + /// receiver. + Expr **getArgs() { + return reinterpret_cast<Expr **>(getTrailingObjects<void *>() + 1); + } + const Expr * const *getArgs() const { + return reinterpret_cast<const Expr *const *>(getTrailingObjects<void *>() + + 1); + } + + /// getArg - Return the specified argument. + Expr *getArg(unsigned Arg) { + assert(Arg < NumArgs && "Arg access out of range!"); + return getArgs()[Arg]; + } + const Expr *getArg(unsigned Arg) const { + assert(Arg < NumArgs && "Arg access out of range!"); + return getArgs()[Arg]; + } + /// setArg - Set the specified argument. + void setArg(unsigned Arg, Expr *ArgExpr) { + assert(Arg < NumArgs && "Arg access out of range!"); + getArgs()[Arg] = ArgExpr; + } + + /// isDelegateInitCall - Answers whether this message send has been + /// tagged as a "delegate init call", i.e. a call to a method in the + /// -init family on self from within an -init method implementation. + bool isDelegateInitCall() const { return IsDelegateInitCall; } + void setDelegateInitCall(bool isDelegate) { IsDelegateInitCall = isDelegate; } + + SourceLocation getLeftLoc() const { return LBracLoc; } + SourceLocation getRightLoc() const { return RBracLoc; } + + SourceLocation getSelectorStartLoc() const { + if (isImplicit()) + return getLocStart(); + return getSelectorLoc(0); + } + SourceLocation getSelectorLoc(unsigned Index) const { + assert(Index < getNumSelectorLocs() && "Index out of range!"); + if (hasStandardSelLocs()) + return getStandardSelectorLoc(Index, getSelector(), + getSelLocsKind() == SelLoc_StandardWithSpace, + llvm::makeArrayRef(const_cast<Expr**>(getArgs()), + getNumArgs()), + RBracLoc); + return getStoredSelLocs()[Index]; + } + + void getSelectorLocs(SmallVectorImpl<SourceLocation> &SelLocs) const; + + unsigned getNumSelectorLocs() const { + if (isImplicit()) + return 0; + Selector Sel = getSelector(); + if (Sel.isUnarySelector()) + return 1; + return Sel.getNumArgs(); + } + + void setSourceRange(SourceRange R) { + LBracLoc = R.getBegin(); + RBracLoc = R.getEnd(); + } + SourceLocation getLocStart() const LLVM_READONLY { return LBracLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return RBracLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCMessageExprClass; + } + + // Iterators + child_range children(); + + typedef ExprIterator arg_iterator; + typedef ConstExprIterator const_arg_iterator; + + llvm::iterator_range<arg_iterator> arguments() { + return llvm::make_range(arg_begin(), arg_end()); + } + + llvm::iterator_range<const_arg_iterator> arguments() const { + return llvm::make_range(arg_begin(), arg_end()); + } + + arg_iterator arg_begin() { return reinterpret_cast<Stmt **>(getArgs()); } + arg_iterator arg_end() { + return reinterpret_cast<Stmt **>(getArgs() + NumArgs); + } + const_arg_iterator arg_begin() const { + return reinterpret_cast<Stmt const * const*>(getArgs()); + } + const_arg_iterator arg_end() const { + return reinterpret_cast<Stmt const * const*>(getArgs() + NumArgs); + } + + friend TrailingObjects; + friend class ASTStmtReader; + friend class ASTStmtWriter; +}; + +/// ObjCIsaExpr - Represent X->isa and X.isa when X is an ObjC 'id' type. +/// (similar in spirit to MemberExpr). +class ObjCIsaExpr : public Expr { + /// Base - the expression for the base object pointer. + Stmt *Base; + + /// IsaMemberLoc - This is the location of the 'isa'. + SourceLocation IsaMemberLoc; + + /// OpLoc - This is the location of '.' or '->' + SourceLocation OpLoc; + + /// IsArrow - True if this is "X->F", false if this is "X.F". + bool IsArrow; +public: + ObjCIsaExpr(Expr *base, bool isarrow, SourceLocation l, SourceLocation oploc, + QualType ty) + : Expr(ObjCIsaExprClass, ty, VK_LValue, OK_Ordinary, + /*TypeDependent=*/false, base->isValueDependent(), + base->isInstantiationDependent(), + /*ContainsUnexpandedParameterPack=*/false), + Base(base), IsaMemberLoc(l), OpLoc(oploc), IsArrow(isarrow) {} + + /// \brief Build an empty expression. + explicit ObjCIsaExpr(EmptyShell Empty) : Expr(ObjCIsaExprClass, Empty) { } + + void setBase(Expr *E) { Base = E; } + Expr *getBase() const { return cast<Expr>(Base); } + + bool isArrow() const { return IsArrow; } + void setArrow(bool A) { IsArrow = A; } + + /// getMemberLoc - Return the location of the "member", in X->F, it is the + /// location of 'F'. + SourceLocation getIsaMemberLoc() const { return IsaMemberLoc; } + void setIsaMemberLoc(SourceLocation L) { IsaMemberLoc = L; } + + SourceLocation getOpLoc() const { return OpLoc; } + void setOpLoc(SourceLocation L) { OpLoc = L; } + + SourceLocation getLocStart() const LLVM_READONLY { + return getBase()->getLocStart(); + } + + SourceLocation getBaseLocEnd() const LLVM_READONLY { + return getBase()->getLocEnd(); + } + + SourceLocation getLocEnd() const LLVM_READONLY { return IsaMemberLoc; } + + SourceLocation getExprLoc() const LLVM_READONLY { return IsaMemberLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCIsaExprClass; + } + + // Iterators + child_range children() { return child_range(&Base, &Base+1); } +}; + + +/// ObjCIndirectCopyRestoreExpr - Represents the passing of a function +/// argument by indirect copy-restore in ARC. This is used to support +/// passing indirect arguments with the wrong lifetime, e.g. when +/// passing the address of a __strong local variable to an 'out' +/// parameter. This expression kind is only valid in an "argument" +/// position to some sort of call expression. +/// +/// The parameter must have type 'pointer to T', and the argument must +/// have type 'pointer to U', where T and U agree except possibly in +/// qualification. If the argument value is null, then a null pointer +/// is passed; otherwise it points to an object A, and: +/// 1. A temporary object B of type T is initialized, either by +/// zero-initialization (used when initializing an 'out' parameter) +/// or copy-initialization (used when initializing an 'inout' +/// parameter). +/// 2. The address of the temporary is passed to the function. +/// 3. If the call completes normally, A is move-assigned from B. +/// 4. Finally, A is destroyed immediately. +/// +/// Currently 'T' must be a retainable object lifetime and must be +/// __autoreleasing; this qualifier is ignored when initializing +/// the value. +class ObjCIndirectCopyRestoreExpr : public Expr { + Stmt *Operand; + + // unsigned ObjCIndirectCopyRestoreBits.ShouldCopy : 1; + + friend class ASTReader; + friend class ASTStmtReader; + + void setShouldCopy(bool shouldCopy) { + ObjCIndirectCopyRestoreExprBits.ShouldCopy = shouldCopy; + } + + explicit ObjCIndirectCopyRestoreExpr(EmptyShell Empty) + : Expr(ObjCIndirectCopyRestoreExprClass, Empty) { } + +public: + ObjCIndirectCopyRestoreExpr(Expr *operand, QualType type, bool shouldCopy) + : Expr(ObjCIndirectCopyRestoreExprClass, type, VK_LValue, OK_Ordinary, + operand->isTypeDependent(), operand->isValueDependent(), + operand->isInstantiationDependent(), + operand->containsUnexpandedParameterPack()), + Operand(operand) { + setShouldCopy(shouldCopy); + } + + Expr *getSubExpr() { return cast<Expr>(Operand); } + const Expr *getSubExpr() const { return cast<Expr>(Operand); } + + /// shouldCopy - True if we should do the 'copy' part of the + /// copy-restore. If false, the temporary will be zero-initialized. + bool shouldCopy() const { return ObjCIndirectCopyRestoreExprBits.ShouldCopy; } + + child_range children() { return child_range(&Operand, &Operand+1); } + + // Source locations are determined by the subexpression. + SourceLocation getLocStart() const LLVM_READONLY { + return Operand->getLocStart(); + } + SourceLocation getLocEnd() const LLVM_READONLY { return Operand->getLocEnd();} + + SourceLocation getExprLoc() const LLVM_READONLY { + return getSubExpr()->getExprLoc(); + } + + static bool classof(const Stmt *s) { + return s->getStmtClass() == ObjCIndirectCopyRestoreExprClass; + } +}; + +/// \brief An Objective-C "bridged" cast expression, which casts between +/// Objective-C pointers and C pointers, transferring ownership in the process. +/// +/// \code +/// NSString *str = (__bridge_transfer NSString *)CFCreateString(); +/// \endcode +class ObjCBridgedCastExpr final + : public ExplicitCastExpr, + private llvm::TrailingObjects<ObjCBridgedCastExpr, CXXBaseSpecifier *> { + SourceLocation LParenLoc; + SourceLocation BridgeKeywordLoc; + unsigned Kind : 2; + + friend TrailingObjects; + friend class CastExpr; + friend class ASTStmtReader; + friend class ASTStmtWriter; + +public: + ObjCBridgedCastExpr(SourceLocation LParenLoc, ObjCBridgeCastKind Kind, + CastKind CK, SourceLocation BridgeKeywordLoc, + TypeSourceInfo *TSInfo, Expr *Operand) + : ExplicitCastExpr(ObjCBridgedCastExprClass, TSInfo->getType(), VK_RValue, + CK, Operand, 0, TSInfo), + LParenLoc(LParenLoc), BridgeKeywordLoc(BridgeKeywordLoc), Kind(Kind) { } + + /// \brief Construct an empty Objective-C bridged cast. + explicit ObjCBridgedCastExpr(EmptyShell Shell) + : ExplicitCastExpr(ObjCBridgedCastExprClass, Shell, 0) { } + + SourceLocation getLParenLoc() const { return LParenLoc; } + + /// \brief Determine which kind of bridge is being performed via this cast. + ObjCBridgeCastKind getBridgeKind() const { + return static_cast<ObjCBridgeCastKind>(Kind); + } + + /// \brief Retrieve the kind of bridge being performed as a string. + StringRef getBridgeKindName() const; + + /// \brief The location of the bridge keyword. + SourceLocation getBridgeKeywordLoc() const { return BridgeKeywordLoc; } + + SourceLocation getLocStart() const LLVM_READONLY { return LParenLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { + return getSubExpr()->getLocEnd(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCBridgedCastExprClass; + } +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/ExprOpenMP.h b/contrib/llvm/tools/clang/include/clang/AST/ExprOpenMP.h new file mode 100644 index 0000000..2d71a3a --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/ExprOpenMP.h @@ -0,0 +1,129 @@ +//===--- ExprOpenMP.h - Classes for representing expressions ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Expr interface and subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_EXPROPENMP_H +#define LLVM_CLANG_AST_EXPROPENMP_H + +#include "clang/AST/Expr.h" + +namespace clang { +/// \brief OpenMP 4.0 [2.4, Array Sections]. +/// To specify an array section in an OpenMP construct, array subscript +/// expressions are extended with the following syntax: +/// \code +/// [ lower-bound : length ] +/// [ lower-bound : ] +/// [ : length ] +/// [ : ] +/// \endcode +/// The array section must be a subset of the original array. +/// Array sections are allowed on multidimensional arrays. Base language array +/// subscript expressions can be used to specify length-one dimensions of +/// multidimensional array sections. +/// The lower-bound and length are integral type expressions. When evaluated +/// they represent a set of integer values as follows: +/// \code +/// { lower-bound, lower-bound + 1, lower-bound + 2,... , lower-bound + length - +/// 1 } +/// \endcode +/// The lower-bound and length must evaluate to non-negative integers. +/// When the size of the array dimension is not known, the length must be +/// specified explicitly. +/// When the length is absent, it defaults to the size of the array dimension +/// minus the lower-bound. +/// When the lower-bound is absent it defaults to 0. +class OMPArraySectionExpr : public Expr { + enum { BASE, LOWER_BOUND, LENGTH, END_EXPR }; + Stmt *SubExprs[END_EXPR]; + SourceLocation ColonLoc; + SourceLocation RBracketLoc; + +public: + OMPArraySectionExpr(Expr *Base, Expr *LowerBound, Expr *Length, QualType Type, + ExprValueKind VK, ExprObjectKind OK, + SourceLocation ColonLoc, SourceLocation RBracketLoc) + : Expr( + OMPArraySectionExprClass, Type, VK, OK, + Base->isTypeDependent() || + (LowerBound && LowerBound->isTypeDependent()) || + (Length && Length->isTypeDependent()), + Base->isValueDependent() || + (LowerBound && LowerBound->isValueDependent()) || + (Length && Length->isValueDependent()), + Base->isInstantiationDependent() || + (LowerBound && LowerBound->isInstantiationDependent()) || + (Length && Length->isInstantiationDependent()), + Base->containsUnexpandedParameterPack() || + (LowerBound && LowerBound->containsUnexpandedParameterPack()) || + (Length && Length->containsUnexpandedParameterPack())), + ColonLoc(ColonLoc), RBracketLoc(RBracketLoc) { + SubExprs[BASE] = Base; + SubExprs[LOWER_BOUND] = LowerBound; + SubExprs[LENGTH] = Length; + } + + /// \brief Create an empty array section expression. + explicit OMPArraySectionExpr(EmptyShell Shell) + : Expr(OMPArraySectionExprClass, Shell) {} + + /// An array section can be written only as Base[LowerBound:Length]. + + /// \brief Get base of the array section. + Expr *getBase() { return cast<Expr>(SubExprs[BASE]); } + const Expr *getBase() const { return cast<Expr>(SubExprs[BASE]); } + /// \brief Set base of the array section. + void setBase(Expr *E) { SubExprs[BASE] = E; } + + /// \brief Return original type of the base expression for array section. + static QualType getBaseOriginalType(Expr *Base); + + /// \brief Get lower bound of array section. + Expr *getLowerBound() { return cast_or_null<Expr>(SubExprs[LOWER_BOUND]); } + const Expr *getLowerBound() const { + return cast_or_null<Expr>(SubExprs[LOWER_BOUND]); + } + /// \brief Set lower bound of the array section. + void setLowerBound(Expr *E) { SubExprs[LOWER_BOUND] = E; } + + /// \brief Get length of array section. + Expr *getLength() { return cast_or_null<Expr>(SubExprs[LENGTH]); } + const Expr *getLength() const { return cast_or_null<Expr>(SubExprs[LENGTH]); } + /// \brief Set length of the array section. + void setLength(Expr *E) { SubExprs[LENGTH] = E; } + + SourceLocation getLocStart() const LLVM_READONLY { + return getBase()->getLocStart(); + } + SourceLocation getLocEnd() const LLVM_READONLY { return RBracketLoc; } + + SourceLocation getColonLoc() const { return ColonLoc; } + void setColonLoc(SourceLocation L) { ColonLoc = L; } + + SourceLocation getRBracketLoc() const { return RBracketLoc; } + void setRBracketLoc(SourceLocation L) { RBracketLoc = L; } + + SourceLocation getExprLoc() const LLVM_READONLY { + return getBase()->getExprLoc(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPArraySectionExprClass; + } + + child_range children() { + return child_range(&SubExprs[BASE], &SubExprs[END_EXPR]); + } +}; +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/ExternalASTSource.h b/contrib/llvm/tools/clang/include/clang/AST/ExternalASTSource.h new file mode 100644 index 0000000..81cf631 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/ExternalASTSource.h @@ -0,0 +1,578 @@ +//===--- ExternalASTSource.h - Abstract External AST Interface --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ExternalASTSource interface, which enables +// construction of AST nodes from some external source. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_EXTERNALASTSOURCE_H +#define LLVM_CLANG_AST_EXTERNALASTSOURCE_H + +#include "clang/AST/CharUnits.h" +#include "clang/AST/DeclBase.h" +#include "llvm/ADT/DenseMap.h" + +namespace clang { + +class ASTConsumer; +class CXXBaseSpecifier; +class CXXCtorInitializer; +class DeclarationName; +class ExternalSemaSource; // layering violation required for downcasting +class FieldDecl; +class Module; +class NamedDecl; +class RecordDecl; +class Selector; +class Stmt; +class TagDecl; + +/// \brief Abstract interface for external sources of AST nodes. +/// +/// External AST sources provide AST nodes constructed from some +/// external source, such as a precompiled header. External AST +/// sources can resolve types and declarations from abstract IDs into +/// actual type and declaration nodes, and read parts of declaration +/// contexts. +class ExternalASTSource : public RefCountedBase<ExternalASTSource> { + /// Generation number for this external AST source. Must be increased + /// whenever we might have added new redeclarations for existing decls. + uint32_t CurrentGeneration; + + /// \brief Whether this AST source also provides information for + /// semantic analysis. + bool SemaSource; + + friend class ExternalSemaSource; + +public: + ExternalASTSource() : CurrentGeneration(0), SemaSource(false) { } + + virtual ~ExternalASTSource(); + + /// \brief RAII class for safely pairing a StartedDeserializing call + /// with FinishedDeserializing. + class Deserializing { + ExternalASTSource *Source; + public: + explicit Deserializing(ExternalASTSource *source) : Source(source) { + assert(Source); + Source->StartedDeserializing(); + } + ~Deserializing() { + Source->FinishedDeserializing(); + } + }; + + /// \brief Get the current generation of this AST source. This number + /// is incremented each time the AST source lazily extends an existing + /// entity. + uint32_t getGeneration() const { return CurrentGeneration; } + + /// \brief Resolve a declaration ID into a declaration, potentially + /// building a new declaration. + /// + /// This method only needs to be implemented if the AST source ever + /// passes back decl sets as VisibleDeclaration objects. + /// + /// The default implementation of this method is a no-op. + virtual Decl *GetExternalDecl(uint32_t ID); + + /// \brief Resolve a selector ID into a selector. + /// + /// This operation only needs to be implemented if the AST source + /// returns non-zero for GetNumKnownSelectors(). + /// + /// The default implementation of this method is a no-op. + virtual Selector GetExternalSelector(uint32_t ID); + + /// \brief Returns the number of selectors known to the external AST + /// source. + /// + /// The default implementation of this method is a no-op. + virtual uint32_t GetNumExternalSelectors(); + + /// \brief Resolve the offset of a statement in the decl stream into + /// a statement. + /// + /// This operation is meant to be used via a LazyOffsetPtr. It only + /// needs to be implemented if the AST source uses methods like + /// FunctionDecl::setLazyBody when building decls. + /// + /// The default implementation of this method is a no-op. + virtual Stmt *GetExternalDeclStmt(uint64_t Offset); + + /// \brief Resolve the offset of a set of C++ constructor initializers in + /// the decl stream into an array of initializers. + /// + /// The default implementation of this method is a no-op. + virtual CXXCtorInitializer **GetExternalCXXCtorInitializers(uint64_t Offset); + + /// \brief Resolve the offset of a set of C++ base specifiers in the decl + /// stream into an array of specifiers. + /// + /// The default implementation of this method is a no-op. + virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset); + + /// \brief Update an out-of-date identifier. + virtual void updateOutOfDateIdentifier(IdentifierInfo &II) { } + + /// \brief Find all declarations with the given name in the given context, + /// and add them to the context by calling SetExternalVisibleDeclsForName + /// or SetNoExternalVisibleDeclsForName. + /// \return \c true if any declarations might have been found, \c false if + /// we definitely have no declarations with tbis name. + /// + /// The default implementation of this method is a no-op returning \c false. + virtual bool + FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name); + + /// \brief Ensures that the table of all visible declarations inside this + /// context is up to date. + /// + /// The default implementation of this function is a no-op. + virtual void completeVisibleDeclsMap(const DeclContext *DC); + + /// \brief Retrieve the module that corresponds to the given module ID. + virtual Module *getModule(unsigned ID) { return nullptr; } + + /// Abstracts clang modules and precompiled header files and holds + /// everything needed to generate debug info for an imported module + /// or PCH. + class ASTSourceDescriptor { + StringRef PCHModuleName; + StringRef Path; + StringRef ASTFile; + uint64_t Signature = 0; + const Module *ClangModule = nullptr; + + public: + ASTSourceDescriptor(){}; + ASTSourceDescriptor(StringRef Name, StringRef Path, StringRef ASTFile, + uint64_t Signature) + : PCHModuleName(std::move(Name)), Path(std::move(Path)), + ASTFile(std::move(ASTFile)), Signature(Signature){}; + ASTSourceDescriptor(const Module &M); + std::string getModuleName() const; + StringRef getPath() const { return Path; } + StringRef getASTFile() const { return ASTFile; } + uint64_t getSignature() const { return Signature; } + const Module *getModuleOrNull() const { return ClangModule; } + }; + + /// Return a descriptor for the corresponding module, if one exists. + virtual llvm::Optional<ASTSourceDescriptor> getSourceDescriptor(unsigned ID); + + /// \brief Finds all declarations lexically contained within the given + /// DeclContext, after applying an optional filter predicate. + /// + /// \param IsKindWeWant a predicate function that returns true if the passed + /// declaration kind is one we are looking for. + /// + /// The default implementation of this method is a no-op. + virtual void + FindExternalLexicalDecls(const DeclContext *DC, + llvm::function_ref<bool(Decl::Kind)> IsKindWeWant, + SmallVectorImpl<Decl *> &Result); + + /// \brief Finds all declarations lexically contained within the given + /// DeclContext. + void FindExternalLexicalDecls(const DeclContext *DC, + SmallVectorImpl<Decl *> &Result) { + FindExternalLexicalDecls(DC, [](Decl::Kind) { return true; }, Result); + } + + /// \brief Get the decls that are contained in a file in the Offset/Length + /// range. \p Length can be 0 to indicate a point at \p Offset instead of + /// a range. + virtual void FindFileRegionDecls(FileID File, unsigned Offset, + unsigned Length, + SmallVectorImpl<Decl *> &Decls); + + /// \brief Gives the external AST source an opportunity to complete + /// the redeclaration chain for a declaration. Called each time we + /// need the most recent declaration of a declaration after the + /// generation count is incremented. + virtual void CompleteRedeclChain(const Decl *D); + + /// \brief Gives the external AST source an opportunity to complete + /// an incomplete type. + virtual void CompleteType(TagDecl *Tag); + + /// \brief Gives the external AST source an opportunity to complete an + /// incomplete Objective-C class. + /// + /// This routine will only be invoked if the "externally completed" bit is + /// set on the ObjCInterfaceDecl via the function + /// \c ObjCInterfaceDecl::setExternallyCompleted(). + virtual void CompleteType(ObjCInterfaceDecl *Class); + + /// \brief Loads comment ranges. + virtual void ReadComments(); + + /// \brief Notify ExternalASTSource that we started deserialization of + /// a decl or type so until FinishedDeserializing is called there may be + /// decls that are initializing. Must be paired with FinishedDeserializing. + /// + /// The default implementation of this method is a no-op. + virtual void StartedDeserializing(); + + /// \brief Notify ExternalASTSource that we finished the deserialization of + /// a decl or type. Must be paired with StartedDeserializing. + /// + /// The default implementation of this method is a no-op. + virtual void FinishedDeserializing(); + + /// \brief Function that will be invoked when we begin parsing a new + /// translation unit involving this external AST source. + /// + /// The default implementation of this method is a no-op. + virtual void StartTranslationUnit(ASTConsumer *Consumer); + + /// \brief Print any statistics that have been gathered regarding + /// the external AST source. + /// + /// The default implementation of this method is a no-op. + virtual void PrintStats(); + + + /// \brief Perform layout on the given record. + /// + /// This routine allows the external AST source to provide an specific + /// layout for a record, overriding the layout that would normally be + /// constructed. It is intended for clients who receive specific layout + /// details rather than source code (such as LLDB). The client is expected + /// to fill in the field offsets, base offsets, virtual base offsets, and + /// complete object size. + /// + /// \param Record The record whose layout is being requested. + /// + /// \param Size The final size of the record, in bits. + /// + /// \param Alignment The final alignment of the record, in bits. + /// + /// \param FieldOffsets The offset of each of the fields within the record, + /// expressed in bits. All of the fields must be provided with offsets. + /// + /// \param BaseOffsets The offset of each of the direct, non-virtual base + /// classes. If any bases are not given offsets, the bases will be laid + /// out according to the ABI. + /// + /// \param VirtualBaseOffsets The offset of each of the virtual base classes + /// (either direct or not). If any bases are not given offsets, the bases will be laid + /// out according to the ABI. + /// + /// \returns true if the record layout was provided, false otherwise. + virtual bool layoutRecordType( + const RecordDecl *Record, uint64_t &Size, uint64_t &Alignment, + llvm::DenseMap<const FieldDecl *, uint64_t> &FieldOffsets, + llvm::DenseMap<const CXXRecordDecl *, CharUnits> &BaseOffsets, + llvm::DenseMap<const CXXRecordDecl *, CharUnits> &VirtualBaseOffsets); + + //===--------------------------------------------------------------------===// + // Queries for performance analysis. + //===--------------------------------------------------------------------===// + + struct MemoryBufferSizes { + size_t malloc_bytes; + size_t mmap_bytes; + + MemoryBufferSizes(size_t malloc_bytes, size_t mmap_bytes) + : malloc_bytes(malloc_bytes), mmap_bytes(mmap_bytes) {} + }; + + /// Return the amount of memory used by memory buffers, breaking down + /// by heap-backed versus mmap'ed memory. + MemoryBufferSizes getMemoryBufferSizes() const { + MemoryBufferSizes sizes(0, 0); + getMemoryBufferSizes(sizes); + return sizes; + } + + virtual void getMemoryBufferSizes(MemoryBufferSizes &sizes) const; + +protected: + static DeclContextLookupResult + SetExternalVisibleDeclsForName(const DeclContext *DC, + DeclarationName Name, + ArrayRef<NamedDecl*> Decls); + + static DeclContextLookupResult + SetNoExternalVisibleDeclsForName(const DeclContext *DC, + DeclarationName Name); + + /// \brief Increment the current generation. + uint32_t incrementGeneration(ASTContext &C); +}; + +/// \brief A lazy pointer to an AST node (of base type T) that resides +/// within an external AST source. +/// +/// The AST node is identified within the external AST source by a +/// 63-bit offset, and can be retrieved via an operation on the +/// external AST source itself. +template<typename T, typename OffsT, T* (ExternalASTSource::*Get)(OffsT Offset)> +struct LazyOffsetPtr { + /// \brief Either a pointer to an AST node or the offset within the + /// external AST source where the AST node can be found. + /// + /// If the low bit is clear, a pointer to the AST node. If the low + /// bit is set, the upper 63 bits are the offset. + mutable uint64_t Ptr; + +public: + LazyOffsetPtr() : Ptr(0) { } + + explicit LazyOffsetPtr(T *Ptr) : Ptr(reinterpret_cast<uint64_t>(Ptr)) { } + explicit LazyOffsetPtr(uint64_t Offset) : Ptr((Offset << 1) | 0x01) { + assert((Offset << 1 >> 1) == Offset && "Offsets must require < 63 bits"); + if (Offset == 0) + Ptr = 0; + } + + LazyOffsetPtr &operator=(T *Ptr) { + this->Ptr = reinterpret_cast<uint64_t>(Ptr); + return *this; + } + + LazyOffsetPtr &operator=(uint64_t Offset) { + assert((Offset << 1 >> 1) == Offset && "Offsets must require < 63 bits"); + if (Offset == 0) + Ptr = 0; + else + Ptr = (Offset << 1) | 0x01; + + return *this; + } + + /// \brief Whether this pointer is non-NULL. + /// + /// This operation does not require the AST node to be deserialized. + explicit operator bool() const { return Ptr != 0; } + + /// \brief Whether this pointer is non-NULL. + /// + /// This operation does not require the AST node to be deserialized. + bool isValid() const { return Ptr != 0; } + + /// \brief Whether this pointer is currently stored as an offset. + bool isOffset() const { return Ptr & 0x01; } + + /// \brief Retrieve the pointer to the AST node that this lazy pointer + /// + /// \param Source the external AST source. + /// + /// \returns a pointer to the AST node. + T* get(ExternalASTSource *Source) const { + if (isOffset()) { + assert(Source && + "Cannot deserialize a lazy pointer without an AST source"); + Ptr = reinterpret_cast<uint64_t>((Source->*Get)(Ptr >> 1)); + } + return reinterpret_cast<T*>(Ptr); + } +}; + +/// \brief A lazy value (of type T) that is within an AST node of type Owner, +/// where the value might change in later generations of the external AST +/// source. +template<typename Owner, typename T, void (ExternalASTSource::*Update)(Owner)> +struct LazyGenerationalUpdatePtr { + /// A cache of the value of this pointer, in the most recent generation in + /// which we queried it. + struct LazyData { + LazyData(ExternalASTSource *Source, T Value) + : ExternalSource(Source), LastGeneration(0), LastValue(Value) {} + ExternalASTSource *ExternalSource; + uint32_t LastGeneration; + T LastValue; + }; + + // Our value is represented as simply T if there is no external AST source. + typedef llvm::PointerUnion<T, LazyData*> ValueType; + ValueType Value; + + LazyGenerationalUpdatePtr(ValueType V) : Value(V) {} + + // Defined in ASTContext.h + static ValueType makeValue(const ASTContext &Ctx, T Value); + +public: + explicit LazyGenerationalUpdatePtr(const ASTContext &Ctx, T Value = T()) + : Value(makeValue(Ctx, Value)) {} + + /// Create a pointer that is not potentially updated by later generations of + /// the external AST source. + enum NotUpdatedTag { NotUpdated }; + LazyGenerationalUpdatePtr(NotUpdatedTag, T Value = T()) + : Value(Value) {} + + /// Forcibly set this pointer (which must be lazy) as needing updates. + void markIncomplete() { + Value.template get<LazyData *>()->LastGeneration = 0; + } + + /// Set the value of this pointer, in the current generation. + void set(T NewValue) { + if (LazyData *LazyVal = Value.template dyn_cast<LazyData*>()) { + LazyVal->LastValue = NewValue; + return; + } + Value = NewValue; + } + + /// Set the value of this pointer, for this and all future generations. + void setNotUpdated(T NewValue) { Value = NewValue; } + + /// Get the value of this pointer, updating its owner if necessary. + T get(Owner O) { + if (LazyData *LazyVal = Value.template dyn_cast<LazyData*>()) { + if (LazyVal->LastGeneration != LazyVal->ExternalSource->getGeneration()) { + LazyVal->LastGeneration = LazyVal->ExternalSource->getGeneration(); + (LazyVal->ExternalSource->*Update)(O); + } + return LazyVal->LastValue; + } + return Value.template get<T>(); + } + + /// Get the most recently computed value of this pointer without updating it. + T getNotUpdated() const { + if (LazyData *LazyVal = Value.template dyn_cast<LazyData*>()) + return LazyVal->LastValue; + return Value.template get<T>(); + } + + void *getOpaqueValue() { return Value.getOpaqueValue(); } + static LazyGenerationalUpdatePtr getFromOpaqueValue(void *Ptr) { + return LazyGenerationalUpdatePtr(ValueType::getFromOpaqueValue(Ptr)); + } +}; +} // end namespace clang + +/// Specialize PointerLikeTypeTraits to allow LazyGenerationalUpdatePtr to be +/// placed into a PointerUnion. +namespace llvm { +template<typename Owner, typename T, + void (clang::ExternalASTSource::*Update)(Owner)> +struct PointerLikeTypeTraits< + clang::LazyGenerationalUpdatePtr<Owner, T, Update>> { + typedef clang::LazyGenerationalUpdatePtr<Owner, T, Update> Ptr; + static void *getAsVoidPointer(Ptr P) { return P.getOpaqueValue(); } + static Ptr getFromVoidPointer(void *P) { return Ptr::getFromOpaqueValue(P); } + enum { + NumLowBitsAvailable = PointerLikeTypeTraits<T>::NumLowBitsAvailable - 1 + }; +}; +} + +namespace clang { +/// \brief Represents a lazily-loaded vector of data. +/// +/// The lazily-loaded vector of data contains data that is partially loaded +/// from an external source and partially added by local translation. The +/// items loaded from the external source are loaded lazily, when needed for +/// iteration over the complete vector. +template<typename T, typename Source, + void (Source::*Loader)(SmallVectorImpl<T>&), + unsigned LoadedStorage = 2, unsigned LocalStorage = 4> +class LazyVector { + SmallVector<T, LoadedStorage> Loaded; + SmallVector<T, LocalStorage> Local; + +public: + /// Iteration over the elements in the vector. + /// + /// In a complete iteration, the iterator walks the range [-M, N), + /// where negative values are used to indicate elements + /// loaded from the external source while non-negative values are used to + /// indicate elements added via \c push_back(). + /// However, to provide iteration in source order (for, e.g., chained + /// precompiled headers), dereferencing the iterator flips the negative + /// values (corresponding to loaded entities), so that position -M + /// corresponds to element 0 in the loaded entities vector, position -M+1 + /// corresponds to element 1 in the loaded entities vector, etc. This + /// gives us a reasonably efficient, source-order walk. + /// + /// We define this as a wrapping iterator around an int. The + /// iterator_adaptor_base class forwards the iterator methods to basic integer + /// arithmetic. + class iterator : public llvm::iterator_adaptor_base< + iterator, int, std::random_access_iterator_tag, T, int> { + LazyVector *Self; + + iterator(LazyVector *Self, int Position) + : iterator::iterator_adaptor_base(Position), Self(Self) {} + + bool isLoaded() const { return this->I < 0; } + friend class LazyVector; + + public: + iterator() : iterator(nullptr, 0) {} + + typename iterator::reference operator*() const { + if (isLoaded()) + return Self->Loaded.end()[this->I]; + return Self->Local.begin()[this->I]; + } + }; + + iterator begin(Source *source, bool LocalOnly = false) { + if (LocalOnly) + return iterator(this, 0); + + if (source) + (source->*Loader)(Loaded); + return iterator(this, -(int)Loaded.size()); + } + + iterator end() { + return iterator(this, Local.size()); + } + + void push_back(const T& LocalValue) { + Local.push_back(LocalValue); + } + + void erase(iterator From, iterator To) { + if (From.isLoaded() && To.isLoaded()) { + Loaded.erase(&*From, &*To); + return; + } + + if (From.isLoaded()) { + Loaded.erase(&*From, Loaded.end()); + From = begin(nullptr, true); + } + + Local.erase(&*From, &*To); + } +}; + +/// \brief A lazy pointer to a statement. +typedef LazyOffsetPtr<Stmt, uint64_t, &ExternalASTSource::GetExternalDeclStmt> + LazyDeclStmtPtr; + +/// \brief A lazy pointer to a declaration. +typedef LazyOffsetPtr<Decl, uint32_t, &ExternalASTSource::GetExternalDecl> + LazyDeclPtr; + +/// \brief A lazy pointer to a set of CXXCtorInitializers. +typedef LazyOffsetPtr<CXXCtorInitializer *, uint64_t, + &ExternalASTSource::GetExternalCXXCtorInitializers> + LazyCXXCtorInitializersPtr; + +/// \brief A lazy pointer to a set of CXXBaseSpecifiers. +typedef LazyOffsetPtr<CXXBaseSpecifier, uint64_t, + &ExternalASTSource::GetExternalCXXBaseSpecifiers> + LazyCXXBaseSpecifiersPtr; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/GlobalDecl.h b/contrib/llvm/tools/clang/include/clang/AST/GlobalDecl.h new file mode 100644 index 0000000..54c9d88 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/GlobalDecl.h @@ -0,0 +1,125 @@ +//===--- GlobalDecl.h - Global declaration holder ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// A GlobalDecl can hold either a regular variable/function or a C++ ctor/dtor +// together with its type. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_GLOBALDECL_H +#define LLVM_CLANG_AST_GLOBALDECL_H + +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/ABI.h" + +namespace clang { + +/// GlobalDecl - represents a global declaration. This can either be a +/// CXXConstructorDecl and the constructor type (Base, Complete). +/// a CXXDestructorDecl and the destructor type (Base, Complete) or +/// a VarDecl, a FunctionDecl or a BlockDecl. +class GlobalDecl { + llvm::PointerIntPair<const Decl*, 2> Value; + + void Init(const Decl *D) { + assert(!isa<CXXConstructorDecl>(D) && "Use other ctor with ctor decls!"); + assert(!isa<CXXDestructorDecl>(D) && "Use other ctor with dtor decls!"); + + Value.setPointer(D); + } + +public: + GlobalDecl() {} + + GlobalDecl(const VarDecl *D) { Init(D);} + GlobalDecl(const FunctionDecl *D) { Init(D); } + GlobalDecl(const BlockDecl *D) { Init(D); } + GlobalDecl(const CapturedDecl *D) { Init(D); } + GlobalDecl(const ObjCMethodDecl *D) { Init(D); } + + GlobalDecl(const CXXConstructorDecl *D, CXXCtorType Type) + : Value(D, Type) {} + GlobalDecl(const CXXDestructorDecl *D, CXXDtorType Type) + : Value(D, Type) {} + + GlobalDecl getCanonicalDecl() const { + GlobalDecl CanonGD; + CanonGD.Value.setPointer(Value.getPointer()->getCanonicalDecl()); + CanonGD.Value.setInt(Value.getInt()); + + return CanonGD; + } + + const Decl *getDecl() const { return Value.getPointer(); } + + CXXCtorType getCtorType() const { + assert(isa<CXXConstructorDecl>(getDecl()) && "Decl is not a ctor!"); + return static_cast<CXXCtorType>(Value.getInt()); + } + + CXXDtorType getDtorType() const { + assert(isa<CXXDestructorDecl>(getDecl()) && "Decl is not a dtor!"); + return static_cast<CXXDtorType>(Value.getInt()); + } + + friend bool operator==(const GlobalDecl &LHS, const GlobalDecl &RHS) { + return LHS.Value == RHS.Value; + } + + void *getAsOpaquePtr() const { return Value.getOpaqueValue(); } + + static GlobalDecl getFromOpaquePtr(void *P) { + GlobalDecl GD; + GD.Value.setFromOpaqueValue(P); + return GD; + } + + GlobalDecl getWithDecl(const Decl *D) { + GlobalDecl Result(*this); + Result.Value.setPointer(D); + return Result; + } +}; + +} // end namespace clang + +namespace llvm { + template<class> struct DenseMapInfo; + + template<> struct DenseMapInfo<clang::GlobalDecl> { + static inline clang::GlobalDecl getEmptyKey() { + return clang::GlobalDecl(); + } + + static inline clang::GlobalDecl getTombstoneKey() { + return clang::GlobalDecl:: + getFromOpaquePtr(reinterpret_cast<void*>(-1)); + } + + static unsigned getHashValue(clang::GlobalDecl GD) { + return DenseMapInfo<void*>::getHashValue(GD.getAsOpaquePtr()); + } + + static bool isEqual(clang::GlobalDecl LHS, + clang::GlobalDecl RHS) { + return LHS == RHS; + } + + }; + + // GlobalDecl isn't *technically* a POD type. However, its copy constructor, + // copy assignment operator, and destructor are all trivial. + template <> + struct isPodLike<clang::GlobalDecl> { + static const bool value = true; + }; +} // end namespace llvm + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/LambdaCapture.h b/contrib/llvm/tools/clang/include/clang/AST/LambdaCapture.h new file mode 100644 index 0000000..ddefa88 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/LambdaCapture.h @@ -0,0 +1,128 @@ +//===--- LambdaCapture.h - Types for C++ Lambda Captures --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the LambdaCapture class. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_LAMBDACAPTURE_H +#define LLVM_CLANG_AST_LAMBDACAPTURE_H + +#include "clang/AST/Decl.h" +#include "clang/Basic/Lambda.h" +#include "llvm/ADT/PointerIntPair.h" + +namespace clang { + +/// \brief Describes the capture of a variable or of \c this, or of a +/// C++1y init-capture. +class LambdaCapture { + enum { + /// \brief Flag used by the Capture class to indicate that the given + /// capture was implicit. + Capture_Implicit = 0x01, + + /// \brief Flag used by the Capture class to indicate that the + /// given capture was by-copy. + /// + /// This includes the case of a non-reference init-capture. + Capture_ByCopy = 0x02 + }; + + llvm::PointerIntPair<Decl *, 2> DeclAndBits; + SourceLocation Loc; + SourceLocation EllipsisLoc; + + friend class ASTStmtReader; + friend class ASTStmtWriter; + +public: + /// \brief Create a new capture of a variable or of \c this. + /// + /// \param Loc The source location associated with this capture. + /// + /// \param Kind The kind of capture (this, byref, bycopy), which must + /// not be init-capture. + /// + /// \param Implicit Whether the capture was implicit or explicit. + /// + /// \param Var The local variable being captured, or null if capturing + /// \c this. + /// + /// \param EllipsisLoc The location of the ellipsis (...) for a + /// capture that is a pack expansion, or an invalid source + /// location to indicate that this is not a pack expansion. + LambdaCapture(SourceLocation Loc, bool Implicit, LambdaCaptureKind Kind, + VarDecl *Var = nullptr, + SourceLocation EllipsisLoc = SourceLocation()); + + /// \brief Determine the kind of capture. + LambdaCaptureKind getCaptureKind() const; + + /// \brief Determine whether this capture handles the C++ \c this + /// pointer. + bool capturesThis() const { + return (DeclAndBits.getPointer() == nullptr) && + !(DeclAndBits.getInt() & Capture_ByCopy); + } + + /// \brief Determine whether this capture handles a variable. + bool capturesVariable() const { + return dyn_cast_or_null<VarDecl>(DeclAndBits.getPointer()); + } + + /// \brief Determine whether this captures a variable length array bound + /// expression. + bool capturesVLAType() const { + return (DeclAndBits.getPointer() == nullptr) && + (DeclAndBits.getInt() & Capture_ByCopy); + } + + /// \brief Retrieve the declaration of the local variable being + /// captured. + /// + /// This operation is only valid if this capture is a variable capture + /// (other than a capture of \c this). + VarDecl *getCapturedVar() const { + assert(capturesVariable() && "No variable available for 'this' capture"); + return cast<VarDecl>(DeclAndBits.getPointer()); + } + + /// \brief Determine whether this was an implicit capture (not + /// written between the square brackets introducing the lambda). + bool isImplicit() const { return DeclAndBits.getInt() & Capture_Implicit; } + + /// \brief Determine whether this was an explicit capture (written + /// between the square brackets introducing the lambda). + bool isExplicit() const { return !isImplicit(); } + + /// \brief Retrieve the source location of the capture. + /// + /// For an explicit capture, this returns the location of the + /// explicit capture in the source. For an implicit capture, this + /// returns the location at which the variable or \c this was first + /// used. + SourceLocation getLocation() const { return Loc; } + + /// \brief Determine whether this capture is a pack expansion, + /// which captures a function parameter pack. + bool isPackExpansion() const { return EllipsisLoc.isValid(); } + + /// \brief Retrieve the location of the ellipsis for a capture + /// that is a pack expansion. + SourceLocation getEllipsisLoc() const { + assert(isPackExpansion() && "No ellipsis location for a non-expansion"); + return EllipsisLoc; + } +}; + +} // end namespace clang + +#endif // LLVM_CLANG_AST_LAMBDACAPTURE_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/Mangle.h b/contrib/llvm/tools/clang/include/clang/AST/Mangle.h new file mode 100644 index 0000000..4872738 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/Mangle.h @@ -0,0 +1,243 @@ +//===--- Mangle.h - Mangle C++ Names ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Defines the C++ name mangling interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_MANGLE_H +#define LLVM_CLANG_AST_MANGLE_H + +#include "clang/AST/Type.h" +#include "clang/Basic/ABI.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/raw_ostream.h" + +namespace clang { + class ASTContext; + class BlockDecl; + class CXXConstructorDecl; + class CXXDestructorDecl; + class CXXMethodDecl; + class FunctionDecl; + class NamedDecl; + class ObjCMethodDecl; + class StringLiteral; + struct ThisAdjustment; + struct ThunkInfo; + class VarDecl; + +/// MangleContext - Context for tracking state which persists across multiple +/// calls to the C++ name mangler. +class MangleContext { +public: + enum ManglerKind { + MK_Itanium, + MK_Microsoft + }; + +private: + virtual void anchor(); + + ASTContext &Context; + DiagnosticsEngine &Diags; + const ManglerKind Kind; + + llvm::DenseMap<const BlockDecl*, unsigned> GlobalBlockIds; + llvm::DenseMap<const BlockDecl*, unsigned> LocalBlockIds; + llvm::DenseMap<const TagDecl*, uint64_t> AnonStructIds; + +public: + ManglerKind getKind() const { return Kind; } + + explicit MangleContext(ASTContext &Context, + DiagnosticsEngine &Diags, + ManglerKind Kind) + : Context(Context), Diags(Diags), Kind(Kind) {} + + virtual ~MangleContext() { } + + ASTContext &getASTContext() const { return Context; } + + DiagnosticsEngine &getDiags() const { return Diags; } + + virtual void startNewFunction() { LocalBlockIds.clear(); } + + unsigned getBlockId(const BlockDecl *BD, bool Local) { + llvm::DenseMap<const BlockDecl *, unsigned> &BlockIds + = Local? LocalBlockIds : GlobalBlockIds; + std::pair<llvm::DenseMap<const BlockDecl *, unsigned>::iterator, bool> + Result = BlockIds.insert(std::make_pair(BD, BlockIds.size())); + return Result.first->second; + } + + uint64_t getAnonymousStructId(const TagDecl *TD) { + std::pair<llvm::DenseMap<const TagDecl *, uint64_t>::iterator, bool> + Result = AnonStructIds.insert(std::make_pair(TD, AnonStructIds.size())); + return Result.first->second; + } + + /// @name Mangler Entry Points + /// @{ + + bool shouldMangleDeclName(const NamedDecl *D); + virtual bool shouldMangleCXXName(const NamedDecl *D) = 0; + virtual bool shouldMangleStringLiteral(const StringLiteral *SL) = 0; + + // FIXME: consider replacing raw_ostream & with something like SmallString &. + void mangleName(const NamedDecl *D, raw_ostream &); + virtual void mangleCXXName(const NamedDecl *D, raw_ostream &) = 0; + virtual void mangleThunk(const CXXMethodDecl *MD, + const ThunkInfo &Thunk, + raw_ostream &) = 0; + virtual void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type, + const ThisAdjustment &ThisAdjustment, + raw_ostream &) = 0; + virtual void mangleReferenceTemporary(const VarDecl *D, + unsigned ManglingNumber, + raw_ostream &) = 0; + virtual void mangleCXXRTTI(QualType T, raw_ostream &) = 0; + virtual void mangleCXXRTTIName(QualType T, raw_ostream &) = 0; + virtual void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type, + raw_ostream &) = 0; + virtual void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, + raw_ostream &) = 0; + virtual void mangleStringLiteral(const StringLiteral *SL, raw_ostream &) = 0; + + void mangleGlobalBlock(const BlockDecl *BD, + const NamedDecl *ID, + raw_ostream &Out); + void mangleCtorBlock(const CXXConstructorDecl *CD, CXXCtorType CT, + const BlockDecl *BD, raw_ostream &Out); + void mangleDtorBlock(const CXXDestructorDecl *CD, CXXDtorType DT, + const BlockDecl *BD, raw_ostream &Out); + void mangleBlock(const DeclContext *DC, const BlockDecl *BD, + raw_ostream &Out); + + void mangleObjCMethodName(const ObjCMethodDecl *MD, raw_ostream &); + + virtual void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &) = 0; + + virtual void mangleDynamicInitializer(const VarDecl *D, raw_ostream &) = 0; + + virtual void mangleDynamicAtExitDestructor(const VarDecl *D, + raw_ostream &) = 0; + + virtual void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl, + raw_ostream &Out) = 0; + + virtual void mangleSEHFinallyBlock(const NamedDecl *EnclosingDecl, + raw_ostream &Out) = 0; + + /// Generates a unique string for an externally visible type for use with TBAA + /// or type uniquing. + /// TODO: Extend this to internal types by generating names that are unique + /// across translation units so it can be used with LTO. + virtual void mangleTypeName(QualType T, raw_ostream &) = 0; + + /// @} +}; + +class ItaniumMangleContext : public MangleContext { +public: + explicit ItaniumMangleContext(ASTContext &C, DiagnosticsEngine &D) + : MangleContext(C, D, MK_Itanium) {} + + virtual void mangleCXXVTable(const CXXRecordDecl *RD, raw_ostream &) = 0; + virtual void mangleCXXVTT(const CXXRecordDecl *RD, raw_ostream &) = 0; + virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset, + const CXXRecordDecl *Type, + raw_ostream &) = 0; + virtual void mangleItaniumThreadLocalInit(const VarDecl *D, + raw_ostream &) = 0; + virtual void mangleItaniumThreadLocalWrapper(const VarDecl *D, + raw_ostream &) = 0; + + virtual void mangleCXXCtorComdat(const CXXConstructorDecl *D, + raw_ostream &) = 0; + virtual void mangleCXXDtorComdat(const CXXDestructorDecl *D, + raw_ostream &) = 0; + + static bool classof(const MangleContext *C) { + return C->getKind() == MK_Itanium; + } + + static ItaniumMangleContext *create(ASTContext &Context, + DiagnosticsEngine &Diags); +}; + +class MicrosoftMangleContext : public MangleContext { +public: + explicit MicrosoftMangleContext(ASTContext &C, DiagnosticsEngine &D) + : MangleContext(C, D, MK_Microsoft) {} + + /// \brief Mangle vftable symbols. Only a subset of the bases along the path + /// to the vftable are included in the name. It's up to the caller to pick + /// them correctly. + virtual void mangleCXXVFTable(const CXXRecordDecl *Derived, + ArrayRef<const CXXRecordDecl *> BasePath, + raw_ostream &Out) = 0; + + /// \brief Mangle vbtable symbols. Only a subset of the bases along the path + /// to the vbtable are included in the name. It's up to the caller to pick + /// them correctly. + virtual void mangleCXXVBTable(const CXXRecordDecl *Derived, + ArrayRef<const CXXRecordDecl *> BasePath, + raw_ostream &Out) = 0; + + virtual void mangleThreadSafeStaticGuardVariable(const VarDecl *VD, + unsigned GuardNum, + raw_ostream &Out) = 0; + + virtual void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD, + raw_ostream &) = 0; + + virtual void mangleCXXVirtualDisplacementMap(const CXXRecordDecl *SrcRD, + const CXXRecordDecl *DstRD, + raw_ostream &Out) = 0; + + virtual void mangleCXXThrowInfo(QualType T, bool IsConst, bool IsVolatile, + uint32_t NumEntries, raw_ostream &Out) = 0; + + virtual void mangleCXXCatchableTypeArray(QualType T, uint32_t NumEntries, + raw_ostream &Out) = 0; + + virtual void mangleCXXCatchableType(QualType T, const CXXConstructorDecl *CD, + CXXCtorType CT, uint32_t Size, + uint32_t NVOffset, int32_t VBPtrOffset, + uint32_t VBIndex, raw_ostream &Out) = 0; + + virtual void mangleCXXRTTIBaseClassDescriptor( + const CXXRecordDecl *Derived, uint32_t NVOffset, int32_t VBPtrOffset, + uint32_t VBTableOffset, uint32_t Flags, raw_ostream &Out) = 0; + + virtual void mangleCXXRTTIBaseClassArray(const CXXRecordDecl *Derived, + raw_ostream &Out) = 0; + virtual void + mangleCXXRTTIClassHierarchyDescriptor(const CXXRecordDecl *Derived, + raw_ostream &Out) = 0; + + virtual void + mangleCXXRTTICompleteObjectLocator(const CXXRecordDecl *Derived, + ArrayRef<const CXXRecordDecl *> BasePath, + raw_ostream &Out) = 0; + + static bool classof(const MangleContext *C) { + return C->getKind() == MK_Microsoft; + } + + static MicrosoftMangleContext *create(ASTContext &Context, + DiagnosticsEngine &Diags); +}; +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/MangleNumberingContext.h b/contrib/llvm/tools/clang/include/clang/AST/MangleNumberingContext.h new file mode 100644 index 0000000..7a81855 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/MangleNumberingContext.h @@ -0,0 +1,60 @@ +//=== MangleNumberingContext.h - Context for mangling numbers ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the LambdaBlockMangleContext interface, which keeps track +// of the Itanium C++ ABI mangling numbers for lambda expressions and block +// literals. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_MANGLENUMBERINGCONTEXT_H +#define LLVM_CLANG_AST_MANGLENUMBERINGCONTEXT_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" + +namespace clang { + +class BlockDecl; +class CXXMethodDecl; +class IdentifierInfo; +class TagDecl; +class Type; +class VarDecl; + +/// \brief Keeps track of the mangled names of lambda expressions and block +/// literals within a particular context. +class MangleNumberingContext : public RefCountedBase<MangleNumberingContext> { +public: + virtual ~MangleNumberingContext() {} + + /// \brief Retrieve the mangling number of a new lambda expression with the + /// given call operator within this context. + virtual unsigned getManglingNumber(const CXXMethodDecl *CallOperator) = 0; + + /// \brief Retrieve the mangling number of a new block literal within this + /// context. + virtual unsigned getManglingNumber(const BlockDecl *BD) = 0; + + /// Static locals are numbered by source order. + virtual unsigned getStaticLocalNumber(const VarDecl *VD) = 0; + + /// \brief Retrieve the mangling number of a static local variable within + /// this context. + virtual unsigned getManglingNumber(const VarDecl *VD, + unsigned MSLocalManglingNumber) = 0; + + /// \brief Retrieve the mangling number of a static local variable within + /// this context. + virtual unsigned getManglingNumber(const TagDecl *TD, + unsigned MSLocalManglingNumber) = 0; +}; + +} // end namespace clang +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/NSAPI.h b/contrib/llvm/tools/clang/include/clang/AST/NSAPI.h new file mode 100644 index 0000000..583f9d9 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/NSAPI.h @@ -0,0 +1,262 @@ +//===--- NSAPI.h - NSFoundation APIs ----------------------------*- 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_AST_NSAPI_H +#define LLVM_CLANG_AST_NSAPI_H + +#include "clang/Basic/IdentifierTable.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" + +namespace clang { + class ASTContext; + class ObjCInterfaceDecl; + class QualType; + class Expr; + +// \brief Provides info and caches identifiers/selectors for NSFoundation API. +class NSAPI { +public: + explicit NSAPI(ASTContext &Ctx); + + ASTContext &getASTContext() const { return Ctx; } + + enum NSClassIdKindKind { + ClassId_NSObject, + ClassId_NSString, + ClassId_NSArray, + ClassId_NSMutableArray, + ClassId_NSDictionary, + ClassId_NSMutableDictionary, + ClassId_NSNumber, + ClassId_NSMutableSet, + ClassId_NSMutableOrderedSet, + ClassId_NSValue + }; + static const unsigned NumClassIds = 10; + + enum NSStringMethodKind { + NSStr_stringWithString, + NSStr_stringWithUTF8String, + NSStr_stringWithCStringEncoding, + NSStr_stringWithCString, + NSStr_initWithString, + NSStr_initWithUTF8String + }; + static const unsigned NumNSStringMethods = 5; + + IdentifierInfo *getNSClassId(NSClassIdKindKind K) const; + + /// \brief The Objective-C NSString selectors. + Selector getNSStringSelector(NSStringMethodKind MK) const; + + /// \brief Return NSStringMethodKind if \param Sel is such a selector. + Optional<NSStringMethodKind> getNSStringMethodKind(Selector Sel) const; + + /// \brief Returns true if the expression \param E is a reference of + /// "NSUTF8StringEncoding" enum constant. + bool isNSUTF8StringEncodingConstant(const Expr *E) const { + return isObjCEnumerator(E, "NSUTF8StringEncoding", NSUTF8StringEncodingId); + } + + /// \brief Returns true if the expression \param E is a reference of + /// "NSASCIIStringEncoding" enum constant. + bool isNSASCIIStringEncodingConstant(const Expr *E) const { + return isObjCEnumerator(E, "NSASCIIStringEncoding",NSASCIIStringEncodingId); + } + + /// \brief Enumerates the NSArray/NSMutableArray methods used to generate + /// literals and to apply some checks. + enum NSArrayMethodKind { + NSArr_array, + NSArr_arrayWithArray, + NSArr_arrayWithObject, + NSArr_arrayWithObjects, + NSArr_arrayWithObjectsCount, + NSArr_initWithArray, + NSArr_initWithObjects, + NSArr_objectAtIndex, + NSMutableArr_replaceObjectAtIndex, + NSMutableArr_addObject, + NSMutableArr_insertObjectAtIndex, + NSMutableArr_setObjectAtIndexedSubscript + }; + static const unsigned NumNSArrayMethods = 12; + + /// \brief The Objective-C NSArray selectors. + Selector getNSArraySelector(NSArrayMethodKind MK) const; + + /// \brief Return NSArrayMethodKind if \p Sel is such a selector. + Optional<NSArrayMethodKind> getNSArrayMethodKind(Selector Sel); + + /// \brief Enumerates the NSDictionary/NSMutableDictionary methods used + /// to generate literals and to apply some checks. + enum NSDictionaryMethodKind { + NSDict_dictionary, + NSDict_dictionaryWithDictionary, + NSDict_dictionaryWithObjectForKey, + NSDict_dictionaryWithObjectsForKeys, + NSDict_dictionaryWithObjectsForKeysCount, + NSDict_dictionaryWithObjectsAndKeys, + NSDict_initWithDictionary, + NSDict_initWithObjectsAndKeys, + NSDict_initWithObjectsForKeys, + NSDict_objectForKey, + NSMutableDict_setObjectForKey, + NSMutableDict_setObjectForKeyedSubscript, + NSMutableDict_setValueForKey + }; + static const unsigned NumNSDictionaryMethods = 14; + + /// \brief The Objective-C NSDictionary selectors. + Selector getNSDictionarySelector(NSDictionaryMethodKind MK) const; + + /// \brief Return NSDictionaryMethodKind if \p Sel is such a selector. + Optional<NSDictionaryMethodKind> getNSDictionaryMethodKind(Selector Sel); + + /// \brief Enumerates the NSMutableSet/NSOrderedSet methods used + /// to apply some checks. + enum NSSetMethodKind { + NSMutableSet_addObject, + NSOrderedSet_insertObjectAtIndex, + NSOrderedSet_setObjectAtIndex, + NSOrderedSet_setObjectAtIndexedSubscript, + NSOrderedSet_replaceObjectAtIndexWithObject + }; + static const unsigned NumNSSetMethods = 5; + + /// \brief The Objective-C NSSet selectors. + Selector getNSSetSelector(NSSetMethodKind MK) const; + + /// \brief Return NSSetMethodKind if \p Sel is such a selector. + Optional<NSSetMethodKind> getNSSetMethodKind(Selector Sel); + + /// \brief Returns selector for "objectForKeyedSubscript:". + Selector getObjectForKeyedSubscriptSelector() const { + return getOrInitSelector(StringRef("objectForKeyedSubscript"), + objectForKeyedSubscriptSel); + } + + /// \brief Returns selector for "objectAtIndexedSubscript:". + Selector getObjectAtIndexedSubscriptSelector() const { + return getOrInitSelector(StringRef("objectAtIndexedSubscript"), + objectAtIndexedSubscriptSel); + } + + /// \brief Returns selector for "setObject:forKeyedSubscript". + Selector getSetObjectForKeyedSubscriptSelector() const { + StringRef Ids[] = { "setObject", "forKeyedSubscript" }; + return getOrInitSelector(Ids, setObjectForKeyedSubscriptSel); + } + + /// \brief Returns selector for "setObject:atIndexedSubscript". + Selector getSetObjectAtIndexedSubscriptSelector() const { + StringRef Ids[] = { "setObject", "atIndexedSubscript" }; + return getOrInitSelector(Ids, setObjectAtIndexedSubscriptSel); + } + + /// \brief Returns selector for "isEqual:". + Selector getIsEqualSelector() const { + return getOrInitSelector(StringRef("isEqual"), isEqualSel); + } + + /// \brief Enumerates the NSNumber methods used to generate literals. + enum NSNumberLiteralMethodKind { + NSNumberWithChar, + NSNumberWithUnsignedChar, + NSNumberWithShort, + NSNumberWithUnsignedShort, + NSNumberWithInt, + NSNumberWithUnsignedInt, + NSNumberWithLong, + NSNumberWithUnsignedLong, + NSNumberWithLongLong, + NSNumberWithUnsignedLongLong, + NSNumberWithFloat, + NSNumberWithDouble, + NSNumberWithBool, + NSNumberWithInteger, + NSNumberWithUnsignedInteger + }; + static const unsigned NumNSNumberLiteralMethods = 15; + + /// \brief The Objective-C NSNumber selectors used to create NSNumber literals. + /// \param Instance if true it will return the selector for the init* method + /// otherwise it will return the selector for the number* method. + Selector getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK, + bool Instance) const; + + bool isNSNumberLiteralSelector(NSNumberLiteralMethodKind MK, + Selector Sel) const { + return Sel == getNSNumberLiteralSelector(MK, false) || + Sel == getNSNumberLiteralSelector(MK, true); + } + + /// \brief Return NSNumberLiteralMethodKind if \p Sel is such a selector. + Optional<NSNumberLiteralMethodKind> + getNSNumberLiteralMethodKind(Selector Sel) const; + + /// \brief Determine the appropriate NSNumber factory method kind for a + /// literal of the given type. + Optional<NSNumberLiteralMethodKind> + getNSNumberFactoryMethodKind(QualType T) const; + + /// \brief Returns true if \param T is a typedef of "BOOL" in objective-c. + bool isObjCBOOLType(QualType T) const; + /// \brief Returns true if \param T is a typedef of "NSInteger" in objective-c. + bool isObjCNSIntegerType(QualType T) const; + /// \brief Returns true if \param T is a typedef of "NSUInteger" in objective-c. + bool isObjCNSUIntegerType(QualType T) const; + /// \brief Returns one of NSIntegral typedef names if \param T is a typedef + /// of that name in objective-c. + StringRef GetNSIntegralKind(QualType T) const; + + /// \brief Returns \c true if \p Id is currently defined as a macro. + bool isMacroDefined(StringRef Id) const; + + /// \brief Returns \c true if \p InterfaceDecl is subclass of \p NSClassKind + bool isSubclassOfNSClass(ObjCInterfaceDecl *InterfaceDecl, + NSClassIdKindKind NSClassKind) const; + +private: + bool isObjCTypedef(QualType T, StringRef name, IdentifierInfo *&II) const; + bool isObjCEnumerator(const Expr *E, + StringRef name, IdentifierInfo *&II) const; + Selector getOrInitSelector(ArrayRef<StringRef> Ids, Selector &Sel) const; + + ASTContext &Ctx; + + mutable IdentifierInfo *ClassIds[NumClassIds]; + + mutable Selector NSStringSelectors[NumNSStringMethods]; + + /// \brief The selectors for Objective-C NSArray methods. + mutable Selector NSArraySelectors[NumNSArrayMethods]; + + /// \brief The selectors for Objective-C NSDictionary methods. + mutable Selector NSDictionarySelectors[NumNSDictionaryMethods]; + + /// \brief The selectors for Objective-C NSSet methods. + mutable Selector NSSetSelectors[NumNSSetMethods]; + + /// \brief The Objective-C NSNumber selectors used to create NSNumber literals. + mutable Selector NSNumberClassSelectors[NumNSNumberLiteralMethods]; + mutable Selector NSNumberInstanceSelectors[NumNSNumberLiteralMethods]; + + mutable Selector objectForKeyedSubscriptSel, objectAtIndexedSubscriptSel, + setObjectForKeyedSubscriptSel,setObjectAtIndexedSubscriptSel, + isEqualSel; + + mutable IdentifierInfo *BOOLId, *NSIntegerId, *NSUIntegerId; + mutable IdentifierInfo *NSASCIIStringEncodingId, *NSUTF8StringEncodingId; +}; + +} // end namespace clang + +#endif // LLVM_CLANG_AST_NSAPI_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/NestedNameSpecifier.h b/contrib/llvm/tools/clang/include/clang/AST/NestedNameSpecifier.h new file mode 100644 index 0000000..b1ff9bd --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/NestedNameSpecifier.h @@ -0,0 +1,516 @@ +//===--- NestedNameSpecifier.h - C++ nested name specifiers -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the NestedNameSpecifier class, which represents +// a C++ nested-name-specifier. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H +#define LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H + +#include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/Support/Compiler.h" + +namespace clang { + +class ASTContext; +class CXXRecordDecl; +class NamespaceAliasDecl; +class NamespaceDecl; +class IdentifierInfo; +struct PrintingPolicy; +class Type; +class TypeLoc; +class LangOptions; + +/// \brief Represents a C++ nested name specifier, such as +/// "\::std::vector<int>::". +/// +/// C++ nested name specifiers are the prefixes to qualified +/// namespaces. For example, "foo::" in "foo::x" is a nested name +/// specifier. Nested name specifiers are made up of a sequence of +/// specifiers, each of which can be a namespace, type, identifier +/// (for dependent names), decltype specifier, or the global specifier ('::'). +/// The last two specifiers can only appear at the start of a +/// nested-namespace-specifier. +class NestedNameSpecifier : public llvm::FoldingSetNode { + + /// \brief Enumeration describing + enum StoredSpecifierKind { + StoredIdentifier = 0, + StoredDecl = 1, + StoredTypeSpec = 2, + StoredTypeSpecWithTemplate = 3 + }; + + /// \brief The nested name specifier that precedes this nested name + /// specifier. + /// + /// The pointer is the nested-name-specifier that precedes this + /// one. The integer stores one of the first four values of type + /// SpecifierKind. + llvm::PointerIntPair<NestedNameSpecifier *, 2, StoredSpecifierKind> Prefix; + + /// \brief The last component in the nested name specifier, which + /// can be an identifier, a declaration, or a type. + /// + /// When the pointer is NULL, this specifier represents the global + /// specifier '::'. Otherwise, the pointer is one of + /// IdentifierInfo*, Namespace*, or Type*, depending on the kind of + /// specifier as encoded within the prefix. + void* Specifier; + +public: + /// \brief The kind of specifier that completes this nested name + /// specifier. + enum SpecifierKind { + /// \brief An identifier, stored as an IdentifierInfo*. + Identifier, + /// \brief A namespace, stored as a NamespaceDecl*. + Namespace, + /// \brief A namespace alias, stored as a NamespaceAliasDecl*. + NamespaceAlias, + /// \brief A type, stored as a Type*. + TypeSpec, + /// \brief A type that was preceded by the 'template' keyword, + /// stored as a Type*. + TypeSpecWithTemplate, + /// \brief The global specifier '::'. There is no stored value. + Global, + /// \brief Microsoft's '__super' specifier, stored as a CXXRecordDecl* of + /// the class it appeared in. + Super + }; + +private: + /// \brief Builds the global specifier. + NestedNameSpecifier() + : Prefix(nullptr, StoredIdentifier), Specifier(nullptr) {} + + /// \brief Copy constructor used internally to clone nested name + /// specifiers. + NestedNameSpecifier(const NestedNameSpecifier &Other) + : llvm::FoldingSetNode(Other), Prefix(Other.Prefix), + Specifier(Other.Specifier) { + } + + void operator=(const NestedNameSpecifier &) = delete; + + /// \brief Either find or insert the given nested name specifier + /// mockup in the given context. + static NestedNameSpecifier *FindOrInsert(const ASTContext &Context, + const NestedNameSpecifier &Mockup); + +public: + /// \brief Builds a specifier combining a prefix and an identifier. + /// + /// The prefix must be dependent, since nested name specifiers + /// referencing an identifier are only permitted when the identifier + /// cannot be resolved. + static NestedNameSpecifier *Create(const ASTContext &Context, + NestedNameSpecifier *Prefix, + IdentifierInfo *II); + + /// \brief Builds a nested name specifier that names a namespace. + static NestedNameSpecifier *Create(const ASTContext &Context, + NestedNameSpecifier *Prefix, + const NamespaceDecl *NS); + + /// \brief Builds a nested name specifier that names a namespace alias. + static NestedNameSpecifier *Create(const ASTContext &Context, + NestedNameSpecifier *Prefix, + NamespaceAliasDecl *Alias); + + /// \brief Builds a nested name specifier that names a type. + static NestedNameSpecifier *Create(const ASTContext &Context, + NestedNameSpecifier *Prefix, + bool Template, const Type *T); + + /// \brief Builds a specifier that consists of just an identifier. + /// + /// The nested-name-specifier is assumed to be dependent, but has no + /// prefix because the prefix is implied by something outside of the + /// nested name specifier, e.g., in "x->Base::f", the "x" has a dependent + /// type. + static NestedNameSpecifier *Create(const ASTContext &Context, + IdentifierInfo *II); + + /// \brief Returns the nested name specifier representing the global + /// scope. + static NestedNameSpecifier *GlobalSpecifier(const ASTContext &Context); + + /// \brief Returns the nested name specifier representing the __super scope + /// for the given CXXRecordDecl. + static NestedNameSpecifier *SuperSpecifier(const ASTContext &Context, + CXXRecordDecl *RD); + + /// \brief Return the prefix of this nested name specifier. + /// + /// The prefix contains all of the parts of the nested name + /// specifier that preced this current specifier. For example, for a + /// nested name specifier that represents "foo::bar::", the current + /// specifier will contain "bar::" and the prefix will contain + /// "foo::". + NestedNameSpecifier *getPrefix() const { return Prefix.getPointer(); } + + /// \brief Determine what kind of nested name specifier is stored. + SpecifierKind getKind() const; + + /// \brief Retrieve the identifier stored in this nested name + /// specifier. + IdentifierInfo *getAsIdentifier() const { + if (Prefix.getInt() == StoredIdentifier) + return (IdentifierInfo *)Specifier; + + return nullptr; + } + + /// \brief Retrieve the namespace stored in this nested name + /// specifier. + NamespaceDecl *getAsNamespace() const; + + /// \brief Retrieve the namespace alias stored in this nested name + /// specifier. + NamespaceAliasDecl *getAsNamespaceAlias() const; + + /// \brief Retrieve the record declaration stored in this nested name + /// specifier. + CXXRecordDecl *getAsRecordDecl() const; + + /// \brief Retrieve the type stored in this nested name specifier. + const Type *getAsType() const { + if (Prefix.getInt() == StoredTypeSpec || + Prefix.getInt() == StoredTypeSpecWithTemplate) + return (const Type *)Specifier; + + return nullptr; + } + + /// \brief Whether this nested name specifier refers to a dependent + /// type or not. + bool isDependent() const; + + /// \brief Whether this nested name specifier involves a template + /// parameter. + bool isInstantiationDependent() const; + + /// \brief Whether this nested-name-specifier contains an unexpanded + /// parameter pack (for C++11 variadic templates). + bool containsUnexpandedParameterPack() const; + + /// \brief Print this nested name specifier to the given output + /// stream. + void print(raw_ostream &OS, const PrintingPolicy &Policy) const; + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddPointer(Prefix.getOpaqueValue()); + ID.AddPointer(Specifier); + } + + /// \brief Dump the nested name specifier to standard output to aid + /// in debugging. + void dump(const LangOptions &LO) const; + void dump() const; +}; + +/// \brief A C++ nested-name-specifier augmented with source location +/// information. +class NestedNameSpecifierLoc { + NestedNameSpecifier *Qualifier; + void *Data; + + /// \brief Determines the data length for the last component in the + /// given nested-name-specifier. + static unsigned getLocalDataLength(NestedNameSpecifier *Qualifier); + + /// \brief Determines the data length for the entire + /// nested-name-specifier. + static unsigned getDataLength(NestedNameSpecifier *Qualifier); + +public: + /// \brief Construct an empty nested-name-specifier. + NestedNameSpecifierLoc() : Qualifier(nullptr), Data(nullptr) { } + + /// \brief Construct a nested-name-specifier with source location information + /// from + NestedNameSpecifierLoc(NestedNameSpecifier *Qualifier, void *Data) + : Qualifier(Qualifier), Data(Data) { } + + /// \brief Evalutes true when this nested-name-specifier location is + /// non-empty. + explicit operator bool() const { return Qualifier; } + + /// \brief Evalutes true when this nested-name-specifier location is + /// empty. + bool hasQualifier() const { return Qualifier; } + + /// \brief Retrieve the nested-name-specifier to which this instance + /// refers. + NestedNameSpecifier *getNestedNameSpecifier() const { + return Qualifier; + } + + /// \brief Retrieve the opaque pointer that refers to source-location data. + void *getOpaqueData() const { return Data; } + + /// \brief Retrieve the source range covering the entirety of this + /// nested-name-specifier. + /// + /// For example, if this instance refers to a nested-name-specifier + /// \c \::std::vector<int>::, the returned source range would cover + /// from the initial '::' to the last '::'. + SourceRange getSourceRange() const LLVM_READONLY; + + /// \brief Retrieve the source range covering just the last part of + /// this nested-name-specifier, not including the prefix. + /// + /// For example, if this instance refers to a nested-name-specifier + /// \c \::std::vector<int>::, the returned source range would cover + /// from "vector" to the last '::'. + SourceRange getLocalSourceRange() const; + + /// \brief Retrieve the location of the beginning of this + /// nested-name-specifier. + SourceLocation getBeginLoc() const { + return getSourceRange().getBegin(); + } + + /// \brief Retrieve the location of the end of this + /// nested-name-specifier. + SourceLocation getEndLoc() const { + return getSourceRange().getEnd(); + } + + /// \brief Retrieve the location of the beginning of this + /// component of the nested-name-specifier. + SourceLocation getLocalBeginLoc() const { + return getLocalSourceRange().getBegin(); + } + + /// \brief Retrieve the location of the end of this component of the + /// nested-name-specifier. + SourceLocation getLocalEndLoc() const { + return getLocalSourceRange().getEnd(); + } + + /// \brief Return the prefix of this nested-name-specifier. + /// + /// For example, if this instance refers to a nested-name-specifier + /// \c \::std::vector<int>::, the prefix is \c \::std::. Note that the + /// returned prefix may be empty, if this is the first component of + /// the nested-name-specifier. + NestedNameSpecifierLoc getPrefix() const { + if (!Qualifier) + return *this; + + return NestedNameSpecifierLoc(Qualifier->getPrefix(), Data); + } + + /// \brief For a nested-name-specifier that refers to a type, + /// retrieve the type with source-location information. + TypeLoc getTypeLoc() const; + + /// \brief Determines the data length for the entire + /// nested-name-specifier. + unsigned getDataLength() const { return getDataLength(Qualifier); } + + friend bool operator==(NestedNameSpecifierLoc X, + NestedNameSpecifierLoc Y) { + return X.Qualifier == Y.Qualifier && X.Data == Y.Data; + } + + friend bool operator!=(NestedNameSpecifierLoc X, + NestedNameSpecifierLoc Y) { + return !(X == Y); + } +}; + +/// \brief Class that aids in the construction of nested-name-specifiers along +/// with source-location information for all of the components of the +/// nested-name-specifier. +class NestedNameSpecifierLocBuilder { + /// \brief The current representation of the nested-name-specifier we're + /// building. + NestedNameSpecifier *Representation; + + /// \brief Buffer used to store source-location information for the + /// nested-name-specifier. + /// + /// Note that we explicitly manage the buffer (rather than using a + /// SmallVector) because \c Declarator expects it to be possible to memcpy() + /// a \c CXXScopeSpec, and CXXScopeSpec uses a NestedNameSpecifierLocBuilder. + char *Buffer; + + /// \brief The size of the buffer used to store source-location information + /// for the nested-name-specifier. + unsigned BufferSize; + + /// \brief The capacity of the buffer used to store source-location + /// information for the nested-name-specifier. + unsigned BufferCapacity; + +public: + NestedNameSpecifierLocBuilder() + : Representation(nullptr), Buffer(nullptr), BufferSize(0), + BufferCapacity(0) {} + + NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other); + + NestedNameSpecifierLocBuilder & + operator=(const NestedNameSpecifierLocBuilder &Other); + + ~NestedNameSpecifierLocBuilder() { + if (BufferCapacity) + free(Buffer); + } + + /// \brief Retrieve the representation of the nested-name-specifier. + NestedNameSpecifier *getRepresentation() const { return Representation; } + + /// \brief Extend the current nested-name-specifier by another + /// nested-name-specifier component of the form 'type::'. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param TemplateKWLoc The location of the 'template' keyword, if present. + /// + /// \param TL The TypeLoc that describes the type preceding the '::'. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void Extend(ASTContext &Context, SourceLocation TemplateKWLoc, TypeLoc TL, + SourceLocation ColonColonLoc); + + /// \brief Extend the current nested-name-specifier by another + /// nested-name-specifier component of the form 'identifier::'. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param Identifier The identifier. + /// + /// \param IdentifierLoc The location of the identifier. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void Extend(ASTContext &Context, IdentifierInfo *Identifier, + SourceLocation IdentifierLoc, SourceLocation ColonColonLoc); + + /// \brief Extend the current nested-name-specifier by another + /// nested-name-specifier component of the form 'namespace::'. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param Namespace The namespace. + /// + /// \param NamespaceLoc The location of the namespace name. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void Extend(ASTContext &Context, NamespaceDecl *Namespace, + SourceLocation NamespaceLoc, SourceLocation ColonColonLoc); + + /// \brief Extend the current nested-name-specifier by another + /// nested-name-specifier component of the form 'namespace-alias::'. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param Alias The namespace alias. + /// + /// \param AliasLoc The location of the namespace alias + /// name. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void Extend(ASTContext &Context, NamespaceAliasDecl *Alias, + SourceLocation AliasLoc, SourceLocation ColonColonLoc); + + /// \brief Turn this (empty) nested-name-specifier into the global + /// nested-name-specifier '::'. + void MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc); + + /// \brief Turns this (empty) nested-name-specifier into '__super' + /// nested-name-specifier. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param RD The declaration of the class in which nested-name-specifier + /// appeared. + /// + /// \param SuperLoc The location of the '__super' keyword. + /// name. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void MakeSuper(ASTContext &Context, CXXRecordDecl *RD, + SourceLocation SuperLoc, SourceLocation ColonColonLoc); + /// \brief Make a new nested-name-specifier from incomplete source-location + /// information. + /// + /// This routine should be used very, very rarely, in cases where we + /// need to synthesize a nested-name-specifier. Most code should instead use + /// \c Adopt() with a proper \c NestedNameSpecifierLoc. + void MakeTrivial(ASTContext &Context, NestedNameSpecifier *Qualifier, + SourceRange R); + + /// \brief Adopt an existing nested-name-specifier (with source-range + /// information). + void Adopt(NestedNameSpecifierLoc Other); + + /// \brief Retrieve the source range covered by this nested-name-specifier. + SourceRange getSourceRange() const LLVM_READONLY { + return NestedNameSpecifierLoc(Representation, Buffer).getSourceRange(); + } + + /// \brief Retrieve a nested-name-specifier with location information, + /// copied into the given AST context. + /// + /// \param Context The context into which this nested-name-specifier will be + /// copied. + NestedNameSpecifierLoc getWithLocInContext(ASTContext &Context) const; + + /// \brief Retrieve a nested-name-specifier with location + /// information based on the information in this builder. + /// + /// This loc will contain references to the builder's internal data and may + /// be invalidated by any change to the builder. + NestedNameSpecifierLoc getTemporary() const { + return NestedNameSpecifierLoc(Representation, Buffer); + } + + /// \brief Clear out this builder, and prepare it to build another + /// nested-name-specifier with source-location information. + void Clear() { + Representation = nullptr; + BufferSize = 0; + } + + /// \brief Retrieve the underlying buffer. + /// + /// \returns A pair containing a pointer to the buffer of source-location + /// data and the size of the source-location data that resides in that + /// buffer. + std::pair<char *, unsigned> getBuffer() const { + return std::make_pair(Buffer, BufferSize); + } +}; + +/// Insertion operator for diagnostics. This allows sending +/// NestedNameSpecifiers into a diagnostic with <<. +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + NestedNameSpecifier *NNS) { + DB.AddTaggedVal(reinterpret_cast<intptr_t>(NNS), + DiagnosticsEngine::ak_nestednamespec); + return DB; +} + +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/OpenMPClause.h b/contrib/llvm/tools/clang/include/clang/AST/OpenMPClause.h new file mode 100644 index 0000000..7632a4b --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/OpenMPClause.h @@ -0,0 +1,3198 @@ +//===- OpenMPClause.h - Classes for OpenMP clauses --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// \brief This file defines OpenMP AST classes for clauses. +/// There are clauses for executable directives, clauses for declarative +/// directives and clauses which can be used in both kinds of directives. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_OPENMPCLAUSE_H +#define LLVM_CLANG_AST_OPENMPCLAUSE_H + +#include "clang/AST/Expr.h" +#include "clang/AST/Stmt.h" +#include "clang/Basic/OpenMPKinds.h" +#include "clang/Basic/SourceLocation.h" + +namespace clang { + +//===----------------------------------------------------------------------===// +// AST classes for clauses. +//===----------------------------------------------------------------------===// + +/// \brief This is a basic class for representing single OpenMP clause. +/// +class OMPClause { + /// \brief Starting location of the clause (the clause keyword). + SourceLocation StartLoc; + /// \brief Ending location of the clause. + SourceLocation EndLoc; + /// \brief Kind of the clause. + OpenMPClauseKind Kind; + +protected: + OMPClause(OpenMPClauseKind K, SourceLocation StartLoc, SourceLocation EndLoc) + : StartLoc(StartLoc), EndLoc(EndLoc), Kind(K) {} + +public: + /// \brief Returns the starting location of the clause. + SourceLocation getLocStart() const { return StartLoc; } + /// \brief Returns the ending location of the clause. + SourceLocation getLocEnd() const { return EndLoc; } + + /// \brief Sets the starting location of the clause. + void setLocStart(SourceLocation Loc) { StartLoc = Loc; } + /// \brief Sets the ending location of the clause. + void setLocEnd(SourceLocation Loc) { EndLoc = Loc; } + + /// \brief Returns kind of OpenMP clause (private, shared, reduction, etc.). + OpenMPClauseKind getClauseKind() const { return Kind; } + + bool isImplicit() const { return StartLoc.isInvalid(); } + + typedef StmtIterator child_iterator; + typedef ConstStmtIterator const_child_iterator; + typedef llvm::iterator_range<child_iterator> child_range; + typedef llvm::iterator_range<const_child_iterator> const_child_range; + + child_range children(); + const_child_range children() const { + auto Children = const_cast<OMPClause *>(this)->children(); + return const_child_range(Children.begin(), Children.end()); + } + static bool classof(const OMPClause *) { return true; } +}; + +/// \brief This represents clauses with the list of variables like 'private', +/// 'firstprivate', 'copyin', 'shared', or 'reduction' clauses in the +/// '#pragma omp ...' directives. +template <class T> class OMPVarListClause : public OMPClause { + friend class OMPClauseReader; + /// \brief Location of '('. + SourceLocation LParenLoc; + /// \brief Number of variables in the list. + unsigned NumVars; + +protected: + /// \brief Fetches list of variables associated with this clause. + MutableArrayRef<Expr *> getVarRefs() { + return MutableArrayRef<Expr *>( + static_cast<T *>(this)->template getTrailingObjects<Expr *>(), NumVars); + } + + /// \brief Sets the list of variables for this clause. + void setVarRefs(ArrayRef<Expr *> VL) { + assert(VL.size() == NumVars && + "Number of variables is not the same as the preallocated buffer"); + std::copy(VL.begin(), VL.end(), + static_cast<T *>(this)->template getTrailingObjects<Expr *>()); + } + + /// \brief Build a clause with \a N variables + /// + /// \param K Kind of the clause. + /// \param StartLoc Starting location of the clause (the clause keyword). + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + /// + OMPVarListClause(OpenMPClauseKind K, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc, unsigned N) + : OMPClause(K, StartLoc, EndLoc), LParenLoc(LParenLoc), NumVars(N) {} + +public: + typedef MutableArrayRef<Expr *>::iterator varlist_iterator; + typedef ArrayRef<const Expr *>::iterator varlist_const_iterator; + typedef llvm::iterator_range<varlist_iterator> varlist_range; + typedef llvm::iterator_range<varlist_const_iterator> varlist_const_range; + + unsigned varlist_size() const { return NumVars; } + bool varlist_empty() const { return NumVars == 0; } + + varlist_range varlists() { + return varlist_range(varlist_begin(), varlist_end()); + } + varlist_const_range varlists() const { + return varlist_const_range(varlist_begin(), varlist_end()); + } + + varlist_iterator varlist_begin() { return getVarRefs().begin(); } + varlist_iterator varlist_end() { return getVarRefs().end(); } + varlist_const_iterator varlist_begin() const { return getVarRefs().begin(); } + varlist_const_iterator varlist_end() const { return getVarRefs().end(); } + + /// \brief Sets the location of '('. + void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. + SourceLocation getLParenLoc() const { return LParenLoc; } + + /// \brief Fetches list of all variables in the clause. + ArrayRef<const Expr *> getVarRefs() const { + return llvm::makeArrayRef( + static_cast<const T *>(this)->template getTrailingObjects<Expr *>(), + NumVars); + } +}; + +/// \brief This represents 'if' clause in the '#pragma omp ...' directive. +/// +/// \code +/// #pragma omp parallel if(parallel:a > 5) +/// \endcode +/// In this example directive '#pragma omp parallel' has simple 'if' clause with +/// condition 'a > 5' and directive name modifier 'parallel'. +/// +class OMPIfClause : public OMPClause { + friend class OMPClauseReader; + /// \brief Location of '('. + SourceLocation LParenLoc; + /// \brief Condition of the 'if' clause. + Stmt *Condition; + /// \brief Location of ':' (if any). + SourceLocation ColonLoc; + /// \brief Directive name modifier for the clause. + OpenMPDirectiveKind NameModifier; + /// \brief Name modifier location. + SourceLocation NameModifierLoc; + + /// \brief Set condition. + /// + void setCondition(Expr *Cond) { Condition = Cond; } + /// \brief Set directive name modifier for the clause. + /// + void setNameModifier(OpenMPDirectiveKind NM) { NameModifier = NM; } + /// \brief Set location of directive name modifier for the clause. + /// + void setNameModifierLoc(SourceLocation Loc) { NameModifierLoc = Loc; } + /// \brief Set location of ':'. + /// + void setColonLoc(SourceLocation Loc) { ColonLoc = Loc; } + +public: + /// \brief Build 'if' clause with condition \a Cond. + /// + /// \param NameModifier [OpenMP 4.1] Directive name modifier of clause. + /// \param Cond Condition of the clause. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param NameModifierLoc Location of directive name modifier. + /// \param ColonLoc [OpenMP 4.1] Location of ':'. + /// \param EndLoc Ending location of the clause. + /// + OMPIfClause(OpenMPDirectiveKind NameModifier, Expr *Cond, + SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation NameModifierLoc, SourceLocation ColonLoc, + SourceLocation EndLoc) + : OMPClause(OMPC_if, StartLoc, EndLoc), LParenLoc(LParenLoc), + Condition(Cond), ColonLoc(ColonLoc), NameModifier(NameModifier), + NameModifierLoc(NameModifierLoc) {} + + /// \brief Build an empty clause. + /// + OMPIfClause() + : OMPClause(OMPC_if, SourceLocation(), SourceLocation()), LParenLoc(), + Condition(nullptr), ColonLoc(), NameModifier(OMPD_unknown), + NameModifierLoc() {} + + /// \brief Sets the location of '('. + void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. + SourceLocation getLParenLoc() const { return LParenLoc; } + + /// \brief Return the location of ':'. + SourceLocation getColonLoc() const { return ColonLoc; } + + /// \brief Returns condition. + Expr *getCondition() const { return cast_or_null<Expr>(Condition); } + /// \brief Return directive name modifier associated with the clause. + OpenMPDirectiveKind getNameModifier() const { return NameModifier; } + + /// \brief Return the location of directive name modifier. + SourceLocation getNameModifierLoc() const { return NameModifierLoc; } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_if; + } + + child_range children() { return child_range(&Condition, &Condition + 1); } +}; + +/// \brief This represents 'final' clause in the '#pragma omp ...' directive. +/// +/// \code +/// #pragma omp task final(a > 5) +/// \endcode +/// In this example directive '#pragma omp task' has simple 'final' +/// clause with condition 'a > 5'. +/// +class OMPFinalClause : public OMPClause { + friend class OMPClauseReader; + /// \brief Location of '('. + SourceLocation LParenLoc; + /// \brief Condition of the 'if' clause. + Stmt *Condition; + + /// \brief Set condition. + /// + void setCondition(Expr *Cond) { Condition = Cond; } + +public: + /// \brief Build 'final' clause with condition \a Cond. + /// + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param Cond Condition of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPFinalClause(Expr *Cond, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc) + : OMPClause(OMPC_final, StartLoc, EndLoc), LParenLoc(LParenLoc), + Condition(Cond) {} + + /// \brief Build an empty clause. + /// + OMPFinalClause() + : OMPClause(OMPC_final, SourceLocation(), SourceLocation()), + LParenLoc(SourceLocation()), Condition(nullptr) {} + + /// \brief Sets the location of '('. + void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. + SourceLocation getLParenLoc() const { return LParenLoc; } + + /// \brief Returns condition. + Expr *getCondition() const { return cast_or_null<Expr>(Condition); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_final; + } + + child_range children() { return child_range(&Condition, &Condition + 1); } +}; + +/// \brief This represents 'num_threads' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp parallel num_threads(6) +/// \endcode +/// In this example directive '#pragma omp parallel' has simple 'num_threads' +/// clause with number of threads '6'. +/// +class OMPNumThreadsClause : public OMPClause { + friend class OMPClauseReader; + /// \brief Location of '('. + SourceLocation LParenLoc; + /// \brief Condition of the 'num_threads' clause. + Stmt *NumThreads; + + /// \brief Set condition. + /// + void setNumThreads(Expr *NThreads) { NumThreads = NThreads; } + +public: + /// \brief Build 'num_threads' clause with condition \a NumThreads. + /// + /// \param NumThreads Number of threads for the construct. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// + OMPNumThreadsClause(Expr *NumThreads, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc) + : OMPClause(OMPC_num_threads, StartLoc, EndLoc), LParenLoc(LParenLoc), + NumThreads(NumThreads) {} + + /// \brief Build an empty clause. + /// + OMPNumThreadsClause() + : OMPClause(OMPC_num_threads, SourceLocation(), SourceLocation()), + LParenLoc(SourceLocation()), NumThreads(nullptr) {} + + /// \brief Sets the location of '('. + void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. + SourceLocation getLParenLoc() const { return LParenLoc; } + + /// \brief Returns number of threads. + Expr *getNumThreads() const { return cast_or_null<Expr>(NumThreads); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_num_threads; + } + + child_range children() { return child_range(&NumThreads, &NumThreads + 1); } +}; + +/// \brief This represents 'safelen' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp simd safelen(4) +/// \endcode +/// In this example directive '#pragma omp simd' has clause 'safelen' +/// with single expression '4'. +/// If the safelen clause is used then no two iterations executed +/// concurrently with SIMD instructions can have a greater distance +/// in the logical iteration space than its value. The parameter of +/// the safelen clause must be a constant positive integer expression. +/// +class OMPSafelenClause : public OMPClause { + friend class OMPClauseReader; + /// \brief Location of '('. + SourceLocation LParenLoc; + /// \brief Safe iteration space distance. + Stmt *Safelen; + + /// \brief Set safelen. + void setSafelen(Expr *Len) { Safelen = Len; } + +public: + /// \brief Build 'safelen' clause. + /// + /// \param Len Expression associated with this clause. + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPSafelenClause(Expr *Len, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc) + : OMPClause(OMPC_safelen, StartLoc, EndLoc), LParenLoc(LParenLoc), + Safelen(Len) {} + + /// \brief Build an empty clause. + /// + explicit OMPSafelenClause() + : OMPClause(OMPC_safelen, SourceLocation(), SourceLocation()), + LParenLoc(SourceLocation()), Safelen(nullptr) {} + + /// \brief Sets the location of '('. + void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. + SourceLocation getLParenLoc() const { return LParenLoc; } + + /// \brief Return safe iteration space distance. + Expr *getSafelen() const { return cast_or_null<Expr>(Safelen); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_safelen; + } + + child_range children() { return child_range(&Safelen, &Safelen + 1); } +}; + +/// \brief This represents 'simdlen' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp simd simdlen(4) +/// \endcode +/// In this example directive '#pragma omp simd' has clause 'simdlen' +/// with single expression '4'. +/// If the 'simdlen' clause is used then it specifies the preferred number of +/// iterations to be executed concurrently. The parameter of the 'simdlen' +/// clause must be a constant positive integer expression. +/// +class OMPSimdlenClause : public OMPClause { + friend class OMPClauseReader; + /// \brief Location of '('. + SourceLocation LParenLoc; + /// \brief Safe iteration space distance. + Stmt *Simdlen; + + /// \brief Set simdlen. + void setSimdlen(Expr *Len) { Simdlen = Len; } + +public: + /// \brief Build 'simdlen' clause. + /// + /// \param Len Expression associated with this clause. + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPSimdlenClause(Expr *Len, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc) + : OMPClause(OMPC_simdlen, StartLoc, EndLoc), LParenLoc(LParenLoc), + Simdlen(Len) {} + + /// \brief Build an empty clause. + /// + explicit OMPSimdlenClause() + : OMPClause(OMPC_simdlen, SourceLocation(), SourceLocation()), + LParenLoc(SourceLocation()), Simdlen(nullptr) {} + + /// \brief Sets the location of '('. + void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. + SourceLocation getLParenLoc() const { return LParenLoc; } + + /// \brief Return safe iteration space distance. + Expr *getSimdlen() const { return cast_or_null<Expr>(Simdlen); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_simdlen; + } + + child_range children() { return child_range(&Simdlen, &Simdlen + 1); } +}; + +/// \brief This represents 'collapse' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp simd collapse(3) +/// \endcode +/// In this example directive '#pragma omp simd' has clause 'collapse' +/// with single expression '3'. +/// The parameter must be a constant positive integer expression, it specifies +/// the number of nested loops that should be collapsed into a single iteration +/// space. +/// +class OMPCollapseClause : public OMPClause { + friend class OMPClauseReader; + /// \brief Location of '('. + SourceLocation LParenLoc; + /// \brief Number of for-loops. + Stmt *NumForLoops; + + /// \brief Set the number of associated for-loops. + void setNumForLoops(Expr *Num) { NumForLoops = Num; } + +public: + /// \brief Build 'collapse' clause. + /// + /// \param Num Expression associated with this clause. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// + OMPCollapseClause(Expr *Num, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc) + : OMPClause(OMPC_collapse, StartLoc, EndLoc), LParenLoc(LParenLoc), + NumForLoops(Num) {} + + /// \brief Build an empty clause. + /// + explicit OMPCollapseClause() + : OMPClause(OMPC_collapse, SourceLocation(), SourceLocation()), + LParenLoc(SourceLocation()), NumForLoops(nullptr) {} + + /// \brief Sets the location of '('. + void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. + SourceLocation getLParenLoc() const { return LParenLoc; } + + /// \brief Return the number of associated for-loops. + Expr *getNumForLoops() const { return cast_or_null<Expr>(NumForLoops); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_collapse; + } + + child_range children() { return child_range(&NumForLoops, &NumForLoops + 1); } +}; + +/// \brief This represents 'default' clause in the '#pragma omp ...' directive. +/// +/// \code +/// #pragma omp parallel default(shared) +/// \endcode +/// In this example directive '#pragma omp parallel' has simple 'default' +/// clause with kind 'shared'. +/// +class OMPDefaultClause : public OMPClause { + friend class OMPClauseReader; + /// \brief Location of '('. + SourceLocation LParenLoc; + /// \brief A kind of the 'default' clause. + OpenMPDefaultClauseKind Kind; + /// \brief Start location of the kind in source code. + SourceLocation KindKwLoc; + + /// \brief Set kind of the clauses. + /// + /// \param K Argument of clause. + /// + void setDefaultKind(OpenMPDefaultClauseKind K) { Kind = K; } + + /// \brief Set argument location. + /// + /// \param KLoc Argument location. + /// + void setDefaultKindKwLoc(SourceLocation KLoc) { KindKwLoc = KLoc; } + +public: + /// \brief Build 'default' clause with argument \a A ('none' or 'shared'). + /// + /// \param A Argument of the clause ('none' or 'shared'). + /// \param ALoc Starting location of the argument. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// + OMPDefaultClause(OpenMPDefaultClauseKind A, SourceLocation ALoc, + SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc) + : OMPClause(OMPC_default, StartLoc, EndLoc), LParenLoc(LParenLoc), + Kind(A), KindKwLoc(ALoc) {} + + /// \brief Build an empty clause. + /// + OMPDefaultClause() + : OMPClause(OMPC_default, SourceLocation(), SourceLocation()), + LParenLoc(SourceLocation()), Kind(OMPC_DEFAULT_unknown), + KindKwLoc(SourceLocation()) {} + + /// \brief Sets the location of '('. + void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. + SourceLocation getLParenLoc() const { return LParenLoc; } + + /// \brief Returns kind of the clause. + OpenMPDefaultClauseKind getDefaultKind() const { return Kind; } + + /// \brief Returns location of clause kind. + SourceLocation getDefaultKindKwLoc() const { return KindKwLoc; } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_default; + } + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +/// \brief This represents 'proc_bind' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp parallel proc_bind(master) +/// \endcode +/// In this example directive '#pragma omp parallel' has simple 'proc_bind' +/// clause with kind 'master'. +/// +class OMPProcBindClause : public OMPClause { + friend class OMPClauseReader; + /// \brief Location of '('. + SourceLocation LParenLoc; + /// \brief A kind of the 'proc_bind' clause. + OpenMPProcBindClauseKind Kind; + /// \brief Start location of the kind in source code. + SourceLocation KindKwLoc; + + /// \brief Set kind of the clause. + /// + /// \param K Kind of clause. + /// + void setProcBindKind(OpenMPProcBindClauseKind K) { Kind = K; } + + /// \brief Set clause kind location. + /// + /// \param KLoc Kind location. + /// + void setProcBindKindKwLoc(SourceLocation KLoc) { KindKwLoc = KLoc; } + +public: + /// \brief Build 'proc_bind' clause with argument \a A ('master', 'close' or + /// 'spread'). + /// + /// \param A Argument of the clause ('master', 'close' or 'spread'). + /// \param ALoc Starting location of the argument. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// + OMPProcBindClause(OpenMPProcBindClauseKind A, SourceLocation ALoc, + SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc) + : OMPClause(OMPC_proc_bind, StartLoc, EndLoc), LParenLoc(LParenLoc), + Kind(A), KindKwLoc(ALoc) {} + + /// \brief Build an empty clause. + /// + OMPProcBindClause() + : OMPClause(OMPC_proc_bind, SourceLocation(), SourceLocation()), + LParenLoc(SourceLocation()), Kind(OMPC_PROC_BIND_unknown), + KindKwLoc(SourceLocation()) {} + + /// \brief Sets the location of '('. + void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. + SourceLocation getLParenLoc() const { return LParenLoc; } + + /// \brief Returns kind of the clause. + OpenMPProcBindClauseKind getProcBindKind() const { return Kind; } + + /// \brief Returns location of clause kind. + SourceLocation getProcBindKindKwLoc() const { return KindKwLoc; } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_proc_bind; + } + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +/// \brief This represents 'schedule' clause in the '#pragma omp ...' directive. +/// +/// \code +/// #pragma omp for schedule(static, 3) +/// \endcode +/// In this example directive '#pragma omp for' has 'schedule' clause with +/// arguments 'static' and '3'. +/// +class OMPScheduleClause : public OMPClause { + friend class OMPClauseReader; + /// \brief Location of '('. + SourceLocation LParenLoc; + /// \brief A kind of the 'schedule' clause. + OpenMPScheduleClauseKind Kind; + /// \brief Modifiers for 'schedule' clause. + enum {FIRST, SECOND, NUM_MODIFIERS}; + OpenMPScheduleClauseModifier Modifiers[NUM_MODIFIERS]; + /// \brief Locations of modifiers. + SourceLocation ModifiersLoc[NUM_MODIFIERS]; + /// \brief Start location of the schedule ind in source code. + SourceLocation KindLoc; + /// \brief Location of ',' (if any). + SourceLocation CommaLoc; + /// \brief Chunk size and a reference to pseudo variable for combined + /// directives. + enum { CHUNK_SIZE, HELPER_CHUNK_SIZE, NUM_EXPRS }; + Stmt *ChunkSizes[NUM_EXPRS]; + + /// \brief Set schedule kind. + /// + /// \param K Schedule kind. + /// + void setScheduleKind(OpenMPScheduleClauseKind K) { Kind = K; } + /// \brief Set the first schedule modifier. + /// + /// \param M Schedule modifier. + /// + void setFirstScheduleModifier(OpenMPScheduleClauseModifier M) { + Modifiers[FIRST] = M; + } + /// \brief Set the second schedule modifier. + /// + /// \param M Schedule modifier. + /// + void setSecondScheduleModifier(OpenMPScheduleClauseModifier M) { + Modifiers[SECOND] = M; + } + /// \brief Set location of the first schedule modifier. + /// + void setFirstScheduleModifierLoc(SourceLocation Loc) { + ModifiersLoc[FIRST] = Loc; + } + /// \brief Set location of the second schedule modifier. + /// + void setSecondScheduleModifierLoc(SourceLocation Loc) { + ModifiersLoc[SECOND] = Loc; + } + /// \brief Set schedule modifier location. + /// + /// \param M Schedule modifier location. + /// + void setScheduleModifer(OpenMPScheduleClauseModifier M) { + if (Modifiers[FIRST] == OMPC_SCHEDULE_MODIFIER_unknown) + Modifiers[FIRST] = M; + else { + assert(Modifiers[SECOND] == OMPC_SCHEDULE_MODIFIER_unknown); + Modifiers[SECOND] = M; + } + } + /// \brief Sets the location of '('. + /// + /// \param Loc Location of '('. + /// + void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Set schedule kind start location. + /// + /// \param KLoc Schedule kind location. + /// + void setScheduleKindLoc(SourceLocation KLoc) { KindLoc = KLoc; } + /// \brief Set location of ','. + /// + /// \param Loc Location of ','. + /// + void setCommaLoc(SourceLocation Loc) { CommaLoc = Loc; } + /// \brief Set chunk size. + /// + /// \param E Chunk size. + /// + void setChunkSize(Expr *E) { ChunkSizes[CHUNK_SIZE] = E; } + /// \brief Set helper chunk size. + /// + /// \param E Helper chunk size. + /// + void setHelperChunkSize(Expr *E) { ChunkSizes[HELPER_CHUNK_SIZE] = E; } + +public: + /// \brief Build 'schedule' clause with schedule kind \a Kind and chunk size + /// expression \a ChunkSize. + /// + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param KLoc Starting location of the argument. + /// \param CommaLoc Location of ','. + /// \param EndLoc Ending location of the clause. + /// \param Kind Schedule kind. + /// \param ChunkSize Chunk size. + /// \param HelperChunkSize Helper chunk size for combined directives. + /// \param M1 The first modifier applied to 'schedule' clause. + /// \param M1Loc Location of the first modifier + /// \param M2 The second modifier applied to 'schedule' clause. + /// \param M2Loc Location of the second modifier + /// + OMPScheduleClause(SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation KLoc, SourceLocation CommaLoc, + SourceLocation EndLoc, OpenMPScheduleClauseKind Kind, + Expr *ChunkSize, Expr *HelperChunkSize, + OpenMPScheduleClauseModifier M1, SourceLocation M1Loc, + OpenMPScheduleClauseModifier M2, SourceLocation M2Loc) + : OMPClause(OMPC_schedule, StartLoc, EndLoc), LParenLoc(LParenLoc), + Kind(Kind), KindLoc(KLoc), CommaLoc(CommaLoc) { + ChunkSizes[CHUNK_SIZE] = ChunkSize; + ChunkSizes[HELPER_CHUNK_SIZE] = HelperChunkSize; + Modifiers[FIRST] = M1; + Modifiers[SECOND] = M2; + ModifiersLoc[FIRST] = M1Loc; + ModifiersLoc[SECOND] = M2Loc; + } + + /// \brief Build an empty clause. + /// + explicit OMPScheduleClause() + : OMPClause(OMPC_schedule, SourceLocation(), SourceLocation()), + Kind(OMPC_SCHEDULE_unknown) { + ChunkSizes[CHUNK_SIZE] = nullptr; + ChunkSizes[HELPER_CHUNK_SIZE] = nullptr; + Modifiers[FIRST] = OMPC_SCHEDULE_MODIFIER_unknown; + Modifiers[SECOND] = OMPC_SCHEDULE_MODIFIER_unknown; + } + + /// \brief Get kind of the clause. + /// + OpenMPScheduleClauseKind getScheduleKind() const { return Kind; } + /// \brief Get the first modifier of the clause. + /// + OpenMPScheduleClauseModifier getFirstScheduleModifier() const { + return Modifiers[FIRST]; + } + /// \brief Get the second modifier of the clause. + /// + OpenMPScheduleClauseModifier getSecondScheduleModifier() const { + return Modifiers[SECOND]; + } + /// \brief Get location of '('. + /// + SourceLocation getLParenLoc() { return LParenLoc; } + /// \brief Get kind location. + /// + SourceLocation getScheduleKindLoc() { return KindLoc; } + /// \brief Get the first modifier location. + /// + SourceLocation getFirstScheduleModifierLoc() const { + return ModifiersLoc[FIRST]; + } + /// \brief Get the second modifier location. + /// + SourceLocation getSecondScheduleModifierLoc() const { + return ModifiersLoc[SECOND]; + } + /// \brief Get location of ','. + /// + SourceLocation getCommaLoc() { return CommaLoc; } + /// \brief Get chunk size. + /// + Expr *getChunkSize() { return dyn_cast_or_null<Expr>(ChunkSizes[CHUNK_SIZE]); } + /// \brief Get chunk size. + /// + Expr *getChunkSize() const { + return dyn_cast_or_null<Expr>(ChunkSizes[CHUNK_SIZE]); + } + /// \brief Get helper chunk size. + /// + Expr *getHelperChunkSize() { + return dyn_cast_or_null<Expr>(ChunkSizes[HELPER_CHUNK_SIZE]); + } + /// \brief Get helper chunk size. + /// + Expr *getHelperChunkSize() const { + return dyn_cast_or_null<Expr>(ChunkSizes[HELPER_CHUNK_SIZE]); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_schedule; + } + + child_range children() { + return child_range(&ChunkSizes[CHUNK_SIZE], &ChunkSizes[CHUNK_SIZE] + 1); + } +}; + +/// \brief This represents 'ordered' clause in the '#pragma omp ...' directive. +/// +/// \code +/// #pragma omp for ordered (2) +/// \endcode +/// In this example directive '#pragma omp for' has 'ordered' clause with +/// parameter 2. +/// +class OMPOrderedClause : public OMPClause { + friend class OMPClauseReader; + /// \brief Location of '('. + SourceLocation LParenLoc; + /// \brief Number of for-loops. + Stmt *NumForLoops; + + /// \brief Set the number of associated for-loops. + void setNumForLoops(Expr *Num) { NumForLoops = Num; } + +public: + /// \brief Build 'ordered' clause. + /// + /// \param Num Expression, possibly associated with this clause. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// + OMPOrderedClause(Expr *Num, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc) + : OMPClause(OMPC_ordered, StartLoc, EndLoc), LParenLoc(LParenLoc), + NumForLoops(Num) {} + + /// \brief Build an empty clause. + /// + explicit OMPOrderedClause() + : OMPClause(OMPC_ordered, SourceLocation(), SourceLocation()), + LParenLoc(SourceLocation()), NumForLoops(nullptr) {} + + /// \brief Sets the location of '('. + void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. + SourceLocation getLParenLoc() const { return LParenLoc; } + + /// \brief Return the number of associated for-loops. + Expr *getNumForLoops() const { return cast_or_null<Expr>(NumForLoops); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_ordered; + } + + child_range children() { return child_range(&NumForLoops, &NumForLoops + 1); } +}; + +/// \brief This represents 'nowait' clause in the '#pragma omp ...' directive. +/// +/// \code +/// #pragma omp for nowait +/// \endcode +/// In this example directive '#pragma omp for' has 'nowait' clause. +/// +class OMPNowaitClause : public OMPClause { +public: + /// \brief Build 'nowait' clause. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPNowaitClause(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_nowait, StartLoc, EndLoc) {} + + /// \brief Build an empty clause. + /// + OMPNowaitClause() + : OMPClause(OMPC_nowait, SourceLocation(), SourceLocation()) {} + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_nowait; + } + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +/// \brief This represents 'untied' clause in the '#pragma omp ...' directive. +/// +/// \code +/// #pragma omp task untied +/// \endcode +/// In this example directive '#pragma omp task' has 'untied' clause. +/// +class OMPUntiedClause : public OMPClause { +public: + /// \brief Build 'untied' clause. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPUntiedClause(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_untied, StartLoc, EndLoc) {} + + /// \brief Build an empty clause. + /// + OMPUntiedClause() + : OMPClause(OMPC_untied, SourceLocation(), SourceLocation()) {} + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_untied; + } + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +/// \brief This represents 'mergeable' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp task mergeable +/// \endcode +/// In this example directive '#pragma omp task' has 'mergeable' clause. +/// +class OMPMergeableClause : public OMPClause { +public: + /// \brief Build 'mergeable' clause. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPMergeableClause(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_mergeable, StartLoc, EndLoc) {} + + /// \brief Build an empty clause. + /// + OMPMergeableClause() + : OMPClause(OMPC_mergeable, SourceLocation(), SourceLocation()) {} + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_mergeable; + } + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +/// \brief This represents 'read' clause in the '#pragma omp atomic' directive. +/// +/// \code +/// #pragma omp atomic read +/// \endcode +/// In this example directive '#pragma omp atomic' has 'read' clause. +/// +class OMPReadClause : public OMPClause { +public: + /// \brief Build 'read' clause. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPReadClause(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_read, StartLoc, EndLoc) {} + + /// \brief Build an empty clause. + /// + OMPReadClause() : OMPClause(OMPC_read, SourceLocation(), SourceLocation()) {} + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_read; + } + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +/// \brief This represents 'write' clause in the '#pragma omp atomic' directive. +/// +/// \code +/// #pragma omp atomic write +/// \endcode +/// In this example directive '#pragma omp atomic' has 'write' clause. +/// +class OMPWriteClause : public OMPClause { +public: + /// \brief Build 'write' clause. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPWriteClause(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_write, StartLoc, EndLoc) {} + + /// \brief Build an empty clause. + /// + OMPWriteClause() + : OMPClause(OMPC_write, SourceLocation(), SourceLocation()) {} + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_write; + } + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +/// \brief This represents 'update' clause in the '#pragma omp atomic' +/// directive. +/// +/// \code +/// #pragma omp atomic update +/// \endcode +/// In this example directive '#pragma omp atomic' has 'update' clause. +/// +class OMPUpdateClause : public OMPClause { +public: + /// \brief Build 'update' clause. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPUpdateClause(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_update, StartLoc, EndLoc) {} + + /// \brief Build an empty clause. + /// + OMPUpdateClause() + : OMPClause(OMPC_update, SourceLocation(), SourceLocation()) {} + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_update; + } + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +/// \brief This represents 'capture' clause in the '#pragma omp atomic' +/// directive. +/// +/// \code +/// #pragma omp atomic capture +/// \endcode +/// In this example directive '#pragma omp atomic' has 'capture' clause. +/// +class OMPCaptureClause : public OMPClause { +public: + /// \brief Build 'capture' clause. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPCaptureClause(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_capture, StartLoc, EndLoc) {} + + /// \brief Build an empty clause. + /// + OMPCaptureClause() + : OMPClause(OMPC_capture, SourceLocation(), SourceLocation()) {} + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_capture; + } + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +/// \brief This represents 'seq_cst' clause in the '#pragma omp atomic' +/// directive. +/// +/// \code +/// #pragma omp atomic seq_cst +/// \endcode +/// In this example directive '#pragma omp atomic' has 'seq_cst' clause. +/// +class OMPSeqCstClause : public OMPClause { +public: + /// \brief Build 'seq_cst' clause. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPSeqCstClause(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_seq_cst, StartLoc, EndLoc) {} + + /// \brief Build an empty clause. + /// + OMPSeqCstClause() + : OMPClause(OMPC_seq_cst, SourceLocation(), SourceLocation()) {} + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_seq_cst; + } + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +/// \brief This represents clause 'private' in the '#pragma omp ...' directives. +/// +/// \code +/// #pragma omp parallel private(a,b) +/// \endcode +/// In this example directive '#pragma omp parallel' has clause 'private' +/// with the variables 'a' and 'b'. +/// +class OMPPrivateClause final + : public OMPVarListClause<OMPPrivateClause>, + private llvm::TrailingObjects<OMPPrivateClause, Expr *> { + friend TrailingObjects; + friend OMPVarListClause; + friend class OMPClauseReader; + /// \brief Build clause with number of variables \a N. + /// + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + /// + OMPPrivateClause(SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc, unsigned N) + : OMPVarListClause<OMPPrivateClause>(OMPC_private, StartLoc, LParenLoc, + EndLoc, N) {} + + /// \brief Build an empty clause. + /// + /// \param N Number of variables. + /// + explicit OMPPrivateClause(unsigned N) + : OMPVarListClause<OMPPrivateClause>(OMPC_private, SourceLocation(), + SourceLocation(), SourceLocation(), + N) {} + + /// \brief Sets the list of references to private copies with initializers for + /// new private variables. + /// \param VL List of references. + void setPrivateCopies(ArrayRef<Expr *> VL); + + /// \brief Gets the list of references to private copies with initializers for + /// new private variables. + MutableArrayRef<Expr *> getPrivateCopies() { + return MutableArrayRef<Expr *>(varlist_end(), varlist_size()); + } + ArrayRef<const Expr *> getPrivateCopies() const { + return llvm::makeArrayRef(varlist_end(), varlist_size()); + } + +public: + /// \brief Creates clause with a list of variables \a VL. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param VL List of references to the variables. + /// \param PrivateVL List of references to private copies with initializers. + /// + static OMPPrivateClause *Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc, ArrayRef<Expr *> VL, + ArrayRef<Expr *> PrivateVL); + /// \brief Creates an empty clause with the place for \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + /// + static OMPPrivateClause *CreateEmpty(const ASTContext &C, unsigned N); + + typedef MutableArrayRef<Expr *>::iterator private_copies_iterator; + typedef ArrayRef<const Expr *>::iterator private_copies_const_iterator; + typedef llvm::iterator_range<private_copies_iterator> private_copies_range; + typedef llvm::iterator_range<private_copies_const_iterator> + private_copies_const_range; + + private_copies_range private_copies() { + return private_copies_range(getPrivateCopies().begin(), + getPrivateCopies().end()); + } + private_copies_const_range private_copies() const { + return private_copies_const_range(getPrivateCopies().begin(), + getPrivateCopies().end()); + } + + child_range children() { + return child_range(reinterpret_cast<Stmt **>(varlist_begin()), + reinterpret_cast<Stmt **>(varlist_end())); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_private; + } +}; + +/// \brief This represents clause 'firstprivate' in the '#pragma omp ...' +/// directives. +/// +/// \code +/// #pragma omp parallel firstprivate(a,b) +/// \endcode +/// In this example directive '#pragma omp parallel' has clause 'firstprivate' +/// with the variables 'a' and 'b'. +/// +class OMPFirstprivateClause final + : public OMPVarListClause<OMPFirstprivateClause>, + private llvm::TrailingObjects<OMPFirstprivateClause, Expr *> { + friend TrailingObjects; + friend OMPVarListClause; + friend class OMPClauseReader; + + /// \brief Build clause with number of variables \a N. + /// + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + /// + OMPFirstprivateClause(SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc, unsigned N) + : OMPVarListClause<OMPFirstprivateClause>(OMPC_firstprivate, StartLoc, + LParenLoc, EndLoc, N) {} + + /// \brief Build an empty clause. + /// + /// \param N Number of variables. + /// + explicit OMPFirstprivateClause(unsigned N) + : OMPVarListClause<OMPFirstprivateClause>( + OMPC_firstprivate, SourceLocation(), SourceLocation(), + SourceLocation(), N) {} + /// \brief Sets the list of references to private copies with initializers for + /// new private variables. + /// \param VL List of references. + void setPrivateCopies(ArrayRef<Expr *> VL); + + /// \brief Gets the list of references to private copies with initializers for + /// new private variables. + MutableArrayRef<Expr *> getPrivateCopies() { + return MutableArrayRef<Expr *>(varlist_end(), varlist_size()); + } + ArrayRef<const Expr *> getPrivateCopies() const { + return llvm::makeArrayRef(varlist_end(), varlist_size()); + } + + /// \brief Sets the list of references to initializer variables for new + /// private variables. + /// \param VL List of references. + void setInits(ArrayRef<Expr *> VL); + + /// \brief Gets the list of references to initializer variables for new + /// private variables. + MutableArrayRef<Expr *> getInits() { + return MutableArrayRef<Expr *>(getPrivateCopies().end(), varlist_size()); + } + ArrayRef<const Expr *> getInits() const { + return llvm::makeArrayRef(getPrivateCopies().end(), varlist_size()); + } + +public: + /// \brief Creates clause with a list of variables \a VL. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param VL List of references to the original variables. + /// \param PrivateVL List of references to private copies with initializers. + /// \param InitVL List of references to auto generated variables used for + /// initialization of a single array element. Used if firstprivate variable is + /// of array type. + /// + static OMPFirstprivateClause * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> PrivateVL, + ArrayRef<Expr *> InitVL); + /// \brief Creates an empty clause with the place for \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + /// + static OMPFirstprivateClause *CreateEmpty(const ASTContext &C, unsigned N); + + typedef MutableArrayRef<Expr *>::iterator private_copies_iterator; + typedef ArrayRef<const Expr *>::iterator private_copies_const_iterator; + typedef llvm::iterator_range<private_copies_iterator> private_copies_range; + typedef llvm::iterator_range<private_copies_const_iterator> + private_copies_const_range; + + private_copies_range private_copies() { + return private_copies_range(getPrivateCopies().begin(), + getPrivateCopies().end()); + } + private_copies_const_range private_copies() const { + return private_copies_const_range(getPrivateCopies().begin(), + getPrivateCopies().end()); + } + + typedef MutableArrayRef<Expr *>::iterator inits_iterator; + typedef ArrayRef<const Expr *>::iterator inits_const_iterator; + typedef llvm::iterator_range<inits_iterator> inits_range; + typedef llvm::iterator_range<inits_const_iterator> inits_const_range; + + inits_range inits() { + return inits_range(getInits().begin(), getInits().end()); + } + inits_const_range inits() const { + return inits_const_range(getInits().begin(), getInits().end()); + } + + child_range children() { + return child_range(reinterpret_cast<Stmt **>(varlist_begin()), + reinterpret_cast<Stmt **>(varlist_end())); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_firstprivate; + } +}; + +/// \brief This represents clause 'lastprivate' in the '#pragma omp ...' +/// directives. +/// +/// \code +/// #pragma omp simd lastprivate(a,b) +/// \endcode +/// In this example directive '#pragma omp simd' has clause 'lastprivate' +/// with the variables 'a' and 'b'. +class OMPLastprivateClause final + : public OMPVarListClause<OMPLastprivateClause>, + private llvm::TrailingObjects<OMPLastprivateClause, Expr *> { + // There are 4 additional tail-allocated arrays at the end of the class: + // 1. Contains list of pseudo variables with the default initialization for + // each non-firstprivate variables. Used in codegen for initialization of + // lastprivate copies. + // 2. List of helper expressions for proper generation of assignment operation + // required for lastprivate clause. This list represents private variables + // (for arrays, single array element). + // 3. List of helper expressions for proper generation of assignment operation + // required for lastprivate clause. This list represents original variables + // (for arrays, single array element). + // 4. List of helper expressions that represents assignment operation: + // \code + // DstExprs = SrcExprs; + // \endcode + // Required for proper codegen of final assignment performed by the + // lastprivate clause. + // + friend TrailingObjects; + friend OMPVarListClause; + friend class OMPClauseReader; + + /// \brief Build clause with number of variables \a N. + /// + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + /// + OMPLastprivateClause(SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc, unsigned N) + : OMPVarListClause<OMPLastprivateClause>(OMPC_lastprivate, StartLoc, + LParenLoc, EndLoc, N) {} + + /// \brief Build an empty clause. + /// + /// \param N Number of variables. + /// + explicit OMPLastprivateClause(unsigned N) + : OMPVarListClause<OMPLastprivateClause>( + OMPC_lastprivate, SourceLocation(), SourceLocation(), + SourceLocation(), N) {} + + /// \brief Get the list of helper expressions for initialization of private + /// copies for lastprivate variables. + MutableArrayRef<Expr *> getPrivateCopies() { + return MutableArrayRef<Expr *>(varlist_end(), varlist_size()); + } + ArrayRef<const Expr *> getPrivateCopies() const { + return llvm::makeArrayRef(varlist_end(), varlist_size()); + } + + /// \brief Set list of helper expressions, required for proper codegen of the + /// clause. These expressions represent private variables (for arrays, single + /// array element) in the final assignment statement performed by the + /// lastprivate clause. + void setSourceExprs(ArrayRef<Expr *> SrcExprs); + + /// \brief Get the list of helper source expressions. + MutableArrayRef<Expr *> getSourceExprs() { + return MutableArrayRef<Expr *>(getPrivateCopies().end(), varlist_size()); + } + ArrayRef<const Expr *> getSourceExprs() const { + return llvm::makeArrayRef(getPrivateCopies().end(), varlist_size()); + } + + /// \brief Set list of helper expressions, required for proper codegen of the + /// clause. These expressions represent original variables (for arrays, single + /// array element) in the final assignment statement performed by the + /// lastprivate clause. + void setDestinationExprs(ArrayRef<Expr *> DstExprs); + + /// \brief Get the list of helper destination expressions. + MutableArrayRef<Expr *> getDestinationExprs() { + return MutableArrayRef<Expr *>(getSourceExprs().end(), varlist_size()); + } + ArrayRef<const Expr *> getDestinationExprs() const { + return llvm::makeArrayRef(getSourceExprs().end(), varlist_size()); + } + + /// \brief Set list of helper assignment expressions, required for proper + /// codegen of the clause. These expressions are assignment expressions that + /// assign private copy of the variable to original variable. + void setAssignmentOps(ArrayRef<Expr *> AssignmentOps); + + /// \brief Get the list of helper assignment expressions. + MutableArrayRef<Expr *> getAssignmentOps() { + return MutableArrayRef<Expr *>(getDestinationExprs().end(), varlist_size()); + } + ArrayRef<const Expr *> getAssignmentOps() const { + return llvm::makeArrayRef(getDestinationExprs().end(), varlist_size()); + } + +public: + /// \brief Creates clause with a list of variables \a VL. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param VL List of references to the variables. + /// \param SrcExprs List of helper expressions for proper generation of + /// assignment operation required for lastprivate clause. This list represents + /// private variables (for arrays, single array element). + /// \param DstExprs List of helper expressions for proper generation of + /// assignment operation required for lastprivate clause. This list represents + /// original variables (for arrays, single array element). + /// \param AssignmentOps List of helper expressions that represents assignment + /// operation: + /// \code + /// DstExprs = SrcExprs; + /// \endcode + /// Required for proper codegen of final assignment performed by the + /// lastprivate clause. + /// + /// + static OMPLastprivateClause * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> SrcExprs, + ArrayRef<Expr *> DstExprs, ArrayRef<Expr *> AssignmentOps); + /// \brief Creates an empty clause with the place for \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + /// + static OMPLastprivateClause *CreateEmpty(const ASTContext &C, unsigned N); + + typedef MutableArrayRef<Expr *>::iterator helper_expr_iterator; + typedef ArrayRef<const Expr *>::iterator helper_expr_const_iterator; + typedef llvm::iterator_range<helper_expr_iterator> helper_expr_range; + typedef llvm::iterator_range<helper_expr_const_iterator> + helper_expr_const_range; + + /// \brief Set list of helper expressions, required for generation of private + /// copies of original lastprivate variables. + void setPrivateCopies(ArrayRef<Expr *> PrivateCopies); + + helper_expr_const_range private_copies() const { + return helper_expr_const_range(getPrivateCopies().begin(), + getPrivateCopies().end()); + } + helper_expr_range private_copies() { + return helper_expr_range(getPrivateCopies().begin(), + getPrivateCopies().end()); + } + helper_expr_const_range source_exprs() const { + return helper_expr_const_range(getSourceExprs().begin(), + getSourceExprs().end()); + } + helper_expr_range source_exprs() { + return helper_expr_range(getSourceExprs().begin(), getSourceExprs().end()); + } + helper_expr_const_range destination_exprs() const { + return helper_expr_const_range(getDestinationExprs().begin(), + getDestinationExprs().end()); + } + helper_expr_range destination_exprs() { + return helper_expr_range(getDestinationExprs().begin(), + getDestinationExprs().end()); + } + helper_expr_const_range assignment_ops() const { + return helper_expr_const_range(getAssignmentOps().begin(), + getAssignmentOps().end()); + } + helper_expr_range assignment_ops() { + return helper_expr_range(getAssignmentOps().begin(), + getAssignmentOps().end()); + } + + child_range children() { + return child_range(reinterpret_cast<Stmt **>(varlist_begin()), + reinterpret_cast<Stmt **>(varlist_end())); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_lastprivate; + } +}; + +/// \brief This represents clause 'shared' in the '#pragma omp ...' directives. +/// +/// \code +/// #pragma omp parallel shared(a,b) +/// \endcode +/// In this example directive '#pragma omp parallel' has clause 'shared' +/// with the variables 'a' and 'b'. +/// +class OMPSharedClause final + : public OMPVarListClause<OMPSharedClause>, + private llvm::TrailingObjects<OMPSharedClause, Expr *> { + friend TrailingObjects; + friend OMPVarListClause; + /// \brief Build clause with number of variables \a N. + /// + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + /// + OMPSharedClause(SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc, unsigned N) + : OMPVarListClause<OMPSharedClause>(OMPC_shared, StartLoc, LParenLoc, + EndLoc, N) {} + + /// \brief Build an empty clause. + /// + /// \param N Number of variables. + /// + explicit OMPSharedClause(unsigned N) + : OMPVarListClause<OMPSharedClause>(OMPC_shared, SourceLocation(), + SourceLocation(), SourceLocation(), + N) {} + +public: + /// \brief Creates clause with a list of variables \a VL. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param VL List of references to the variables. + /// + static OMPSharedClause *Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc, ArrayRef<Expr *> VL); + /// \brief Creates an empty clause with \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + /// + static OMPSharedClause *CreateEmpty(const ASTContext &C, unsigned N); + + child_range children() { + return child_range(reinterpret_cast<Stmt **>(varlist_begin()), + reinterpret_cast<Stmt **>(varlist_end())); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_shared; + } +}; + +/// \brief This represents clause 'reduction' in the '#pragma omp ...' +/// directives. +/// +/// \code +/// #pragma omp parallel reduction(+:a,b) +/// \endcode +/// In this example directive '#pragma omp parallel' has clause 'reduction' +/// with operator '+' and the variables 'a' and 'b'. +/// +class OMPReductionClause final + : public OMPVarListClause<OMPReductionClause>, + private llvm::TrailingObjects<OMPReductionClause, Expr *> { + friend TrailingObjects; + friend OMPVarListClause; + friend class OMPClauseReader; + /// \brief Location of ':'. + SourceLocation ColonLoc; + /// \brief Nested name specifier for C++. + NestedNameSpecifierLoc QualifierLoc; + /// \brief Name of custom operator. + DeclarationNameInfo NameInfo; + + /// \brief Build clause with number of variables \a N. + /// + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param ColonLoc Location of ':'. + /// \param N Number of the variables in the clause. + /// \param QualifierLoc The nested-name qualifier with location information + /// \param NameInfo The full name info for reduction identifier. + /// + OMPReductionClause(SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ColonLoc, SourceLocation EndLoc, unsigned N, + NestedNameSpecifierLoc QualifierLoc, + const DeclarationNameInfo &NameInfo) + : OMPVarListClause<OMPReductionClause>(OMPC_reduction, StartLoc, + LParenLoc, EndLoc, N), + ColonLoc(ColonLoc), QualifierLoc(QualifierLoc), NameInfo(NameInfo) {} + + /// \brief Build an empty clause. + /// + /// \param N Number of variables. + /// + explicit OMPReductionClause(unsigned N) + : OMPVarListClause<OMPReductionClause>(OMPC_reduction, SourceLocation(), + SourceLocation(), SourceLocation(), + N), + ColonLoc(), QualifierLoc(), NameInfo() {} + + /// \brief Sets location of ':' symbol in clause. + void setColonLoc(SourceLocation CL) { ColonLoc = CL; } + /// \brief Sets the name info for specified reduction identifier. + void setNameInfo(DeclarationNameInfo DNI) { NameInfo = DNI; } + /// \brief Sets the nested name specifier. + void setQualifierLoc(NestedNameSpecifierLoc NSL) { QualifierLoc = NSL; } + + /// \brief Set list of helper expressions, required for proper codegen of the + /// clause. These expressions represent private copy of the reduction + /// variable. + void setPrivates(ArrayRef<Expr *> Privates); + + /// \brief Get the list of helper privates. + MutableArrayRef<Expr *> getPrivates() { + return MutableArrayRef<Expr *>(varlist_end(), varlist_size()); + } + ArrayRef<const Expr *> getPrivates() const { + return llvm::makeArrayRef(varlist_end(), varlist_size()); + } + + /// \brief Set list of helper expressions, required for proper codegen of the + /// clause. These expressions represent LHS expression in the final + /// reduction expression performed by the reduction clause. + void setLHSExprs(ArrayRef<Expr *> LHSExprs); + + /// \brief Get the list of helper LHS expressions. + MutableArrayRef<Expr *> getLHSExprs() { + return MutableArrayRef<Expr *>(getPrivates().end(), varlist_size()); + } + ArrayRef<const Expr *> getLHSExprs() const { + return llvm::makeArrayRef(getPrivates().end(), varlist_size()); + } + + /// \brief Set list of helper expressions, required for proper codegen of the + /// clause. These expressions represent RHS expression in the final + /// reduction expression performed by the reduction clause. + /// Also, variables in these expressions are used for proper initialization of + /// reduction copies. + void setRHSExprs(ArrayRef<Expr *> RHSExprs); + + /// \brief Get the list of helper destination expressions. + MutableArrayRef<Expr *> getRHSExprs() { + return MutableArrayRef<Expr *>(getLHSExprs().end(), varlist_size()); + } + ArrayRef<const Expr *> getRHSExprs() const { + return llvm::makeArrayRef(getLHSExprs().end(), varlist_size()); + } + + /// \brief Set list of helper reduction expressions, required for proper + /// codegen of the clause. These expressions are binary expressions or + /// operator/custom reduction call that calculates new value from source + /// helper expressions to destination helper expressions. + void setReductionOps(ArrayRef<Expr *> ReductionOps); + + /// \brief Get the list of helper reduction expressions. + MutableArrayRef<Expr *> getReductionOps() { + return MutableArrayRef<Expr *>(getRHSExprs().end(), varlist_size()); + } + ArrayRef<const Expr *> getReductionOps() const { + return llvm::makeArrayRef(getRHSExprs().end(), varlist_size()); + } + +public: + /// \brief Creates clause with a list of variables \a VL. + /// + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param ColonLoc Location of ':'. + /// \param EndLoc Ending location of the clause. + /// \param VL The variables in the clause. + /// \param QualifierLoc The nested-name qualifier with location information + /// \param NameInfo The full name info for reduction identifier. + /// \param Privates List of helper expressions for proper generation of + /// private copies. + /// \param LHSExprs List of helper expressions for proper generation of + /// assignment operation required for copyprivate clause. This list represents + /// LHSs of the reduction expressions. + /// \param RHSExprs List of helper expressions for proper generation of + /// assignment operation required for copyprivate clause. This list represents + /// RHSs of the reduction expressions. + /// Also, variables in these expressions are used for proper initialization of + /// reduction copies. + /// \param ReductionOps List of helper expressions that represents reduction + /// expressions: + /// \code + /// LHSExprs binop RHSExprs; + /// operator binop(LHSExpr, RHSExpr); + /// <CutomReduction>(LHSExpr, RHSExpr); + /// \endcode + /// Required for proper codegen of final reduction operation performed by the + /// reduction clause. + /// + static OMPReductionClause * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ColonLoc, SourceLocation EndLoc, ArrayRef<Expr *> VL, + NestedNameSpecifierLoc QualifierLoc, + const DeclarationNameInfo &NameInfo, ArrayRef<Expr *> Privates, + ArrayRef<Expr *> LHSExprs, ArrayRef<Expr *> RHSExprs, + ArrayRef<Expr *> ReductionOps); + /// \brief Creates an empty clause with the place for \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + /// + static OMPReductionClause *CreateEmpty(const ASTContext &C, unsigned N); + + /// \brief Gets location of ':' symbol in clause. + SourceLocation getColonLoc() const { return ColonLoc; } + /// \brief Gets the name info for specified reduction identifier. + const DeclarationNameInfo &getNameInfo() const { return NameInfo; } + /// \brief Gets the nested name specifier. + NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } + + typedef MutableArrayRef<Expr *>::iterator helper_expr_iterator; + typedef ArrayRef<const Expr *>::iterator helper_expr_const_iterator; + typedef llvm::iterator_range<helper_expr_iterator> helper_expr_range; + typedef llvm::iterator_range<helper_expr_const_iterator> + helper_expr_const_range; + + helper_expr_const_range privates() const { + return helper_expr_const_range(getPrivates().begin(), getPrivates().end()); + } + helper_expr_range privates() { + return helper_expr_range(getPrivates().begin(), getPrivates().end()); + } + helper_expr_const_range lhs_exprs() const { + return helper_expr_const_range(getLHSExprs().begin(), getLHSExprs().end()); + } + helper_expr_range lhs_exprs() { + return helper_expr_range(getLHSExprs().begin(), getLHSExprs().end()); + } + helper_expr_const_range rhs_exprs() const { + return helper_expr_const_range(getRHSExprs().begin(), getRHSExprs().end()); + } + helper_expr_range rhs_exprs() { + return helper_expr_range(getRHSExprs().begin(), getRHSExprs().end()); + } + helper_expr_const_range reduction_ops() const { + return helper_expr_const_range(getReductionOps().begin(), + getReductionOps().end()); + } + helper_expr_range reduction_ops() { + return helper_expr_range(getReductionOps().begin(), + getReductionOps().end()); + } + + child_range children() { + return child_range(reinterpret_cast<Stmt **>(varlist_begin()), + reinterpret_cast<Stmt **>(varlist_end())); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_reduction; + } +}; + +/// \brief This represents clause 'linear' in the '#pragma omp ...' +/// directives. +/// +/// \code +/// #pragma omp simd linear(a,b : 2) +/// \endcode +/// In this example directive '#pragma omp simd' has clause 'linear' +/// with variables 'a', 'b' and linear step '2'. +/// +class OMPLinearClause final + : public OMPVarListClause<OMPLinearClause>, + private llvm::TrailingObjects<OMPLinearClause, Expr *> { + friend TrailingObjects; + friend OMPVarListClause; + friend class OMPClauseReader; + /// \brief Modifier of 'linear' clause. + OpenMPLinearClauseKind Modifier; + /// \brief Location of linear modifier if any. + SourceLocation ModifierLoc; + /// \brief Location of ':'. + SourceLocation ColonLoc; + + /// \brief Sets the linear step for clause. + void setStep(Expr *Step) { *(getFinals().end()) = Step; } + + /// \brief Sets the expression to calculate linear step for clause. + void setCalcStep(Expr *CalcStep) { *(getFinals().end() + 1) = CalcStep; } + + /// \brief Build 'linear' clause with given number of variables \a NumVars. + /// + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param ColonLoc Location of ':'. + /// \param EndLoc Ending location of the clause. + /// \param NumVars Number of variables. + /// + OMPLinearClause(SourceLocation StartLoc, SourceLocation LParenLoc, + OpenMPLinearClauseKind Modifier, SourceLocation ModifierLoc, + SourceLocation ColonLoc, SourceLocation EndLoc, + unsigned NumVars) + : OMPVarListClause<OMPLinearClause>(OMPC_linear, StartLoc, LParenLoc, + EndLoc, NumVars), + Modifier(Modifier), ModifierLoc(ModifierLoc), ColonLoc(ColonLoc) {} + + /// \brief Build an empty clause. + /// + /// \param NumVars Number of variables. + /// + explicit OMPLinearClause(unsigned NumVars) + : OMPVarListClause<OMPLinearClause>(OMPC_linear, SourceLocation(), + SourceLocation(), SourceLocation(), + NumVars), + Modifier(OMPC_LINEAR_val), ModifierLoc(), ColonLoc() {} + + /// \brief Gets the list of initial values for linear variables. + /// + /// There are NumVars expressions with initial values allocated after the + /// varlist, they are followed by NumVars update expressions (used to update + /// the linear variable's value on current iteration) and they are followed by + /// NumVars final expressions (used to calculate the linear variable's + /// value after the loop body). After these lists, there are 2 helper + /// expressions - linear step and a helper to calculate it before the + /// loop body (used when the linear step is not constant): + /// + /// { Vars[] /* in OMPVarListClause */; Privates[]; Inits[]; Updates[]; + /// Finals[]; Step; CalcStep; } + /// + MutableArrayRef<Expr *> getPrivates() { + return MutableArrayRef<Expr *>(varlist_end(), varlist_size()); + } + ArrayRef<const Expr *> getPrivates() const { + return llvm::makeArrayRef(varlist_end(), varlist_size()); + } + + MutableArrayRef<Expr *> getInits() { + return MutableArrayRef<Expr *>(getPrivates().end(), varlist_size()); + } + ArrayRef<const Expr *> getInits() const { + return llvm::makeArrayRef(getPrivates().end(), varlist_size()); + } + + /// \brief Sets the list of update expressions for linear variables. + MutableArrayRef<Expr *> getUpdates() { + return MutableArrayRef<Expr *>(getInits().end(), varlist_size()); + } + ArrayRef<const Expr *> getUpdates() const { + return llvm::makeArrayRef(getInits().end(), varlist_size()); + } + + /// \brief Sets the list of final update expressions for linear variables. + MutableArrayRef<Expr *> getFinals() { + return MutableArrayRef<Expr *>(getUpdates().end(), varlist_size()); + } + ArrayRef<const Expr *> getFinals() const { + return llvm::makeArrayRef(getUpdates().end(), varlist_size()); + } + + /// \brief Sets the list of the copies of original linear variables. + /// \param PL List of expressions. + void setPrivates(ArrayRef<Expr *> PL); + + /// \brief Sets the list of the initial values for linear variables. + /// \param IL List of expressions. + void setInits(ArrayRef<Expr *> IL); + +public: + /// \brief Creates clause with a list of variables \a VL and a linear step + /// \a Step. + /// + /// \param C AST Context. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param Modifier Modifier of 'linear' clause. + /// \param ModifierLoc Modifier location. + /// \param ColonLoc Location of ':'. + /// \param EndLoc Ending location of the clause. + /// \param VL List of references to the variables. + /// \param PL List of private copies of original variables. + /// \param IL List of initial values for the variables. + /// \param Step Linear step. + /// \param CalcStep Calculation of the linear step. + static OMPLinearClause * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, + OpenMPLinearClauseKind Modifier, SourceLocation ModifierLoc, + SourceLocation ColonLoc, SourceLocation EndLoc, ArrayRef<Expr *> VL, + ArrayRef<Expr *> PL, ArrayRef<Expr *> IL, Expr *Step, Expr *CalcStep); + + /// \brief Creates an empty clause with the place for \a NumVars variables. + /// + /// \param C AST context. + /// \param NumVars Number of variables. + /// + static OMPLinearClause *CreateEmpty(const ASTContext &C, unsigned NumVars); + + /// \brief Set modifier. + void setModifier(OpenMPLinearClauseKind Kind) { Modifier = Kind; } + /// \brief Return modifier. + OpenMPLinearClauseKind getModifier() const { return Modifier; } + + /// \brief Set modifier location. + void setModifierLoc(SourceLocation Loc) { ModifierLoc = Loc; } + /// \brief Return modifier location. + SourceLocation getModifierLoc() const { return ModifierLoc; } + + /// \brief Sets the location of ':'. + void setColonLoc(SourceLocation Loc) { ColonLoc = Loc; } + /// \brief Returns the location of ':'. + SourceLocation getColonLoc() const { return ColonLoc; } + + /// \brief Returns linear step. + Expr *getStep() { return *(getFinals().end()); } + /// \brief Returns linear step. + const Expr *getStep() const { return *(getFinals().end()); } + /// \brief Returns expression to calculate linear step. + Expr *getCalcStep() { return *(getFinals().end() + 1); } + /// \brief Returns expression to calculate linear step. + const Expr *getCalcStep() const { return *(getFinals().end() + 1); } + + /// \brief Sets the list of update expressions for linear variables. + /// \param UL List of expressions. + void setUpdates(ArrayRef<Expr *> UL); + + /// \brief Sets the list of final update expressions for linear variables. + /// \param FL List of expressions. + void setFinals(ArrayRef<Expr *> FL); + + typedef MutableArrayRef<Expr *>::iterator privates_iterator; + typedef ArrayRef<const Expr *>::iterator privates_const_iterator; + typedef llvm::iterator_range<privates_iterator> privates_range; + typedef llvm::iterator_range<privates_const_iterator> privates_const_range; + + privates_range privates() { + return privates_range(getPrivates().begin(), getPrivates().end()); + } + privates_const_range privates() const { + return privates_const_range(getPrivates().begin(), getPrivates().end()); + } + + typedef MutableArrayRef<Expr *>::iterator inits_iterator; + typedef ArrayRef<const Expr *>::iterator inits_const_iterator; + typedef llvm::iterator_range<inits_iterator> inits_range; + typedef llvm::iterator_range<inits_const_iterator> inits_const_range; + + inits_range inits() { + return inits_range(getInits().begin(), getInits().end()); + } + inits_const_range inits() const { + return inits_const_range(getInits().begin(), getInits().end()); + } + + typedef MutableArrayRef<Expr *>::iterator updates_iterator; + typedef ArrayRef<const Expr *>::iterator updates_const_iterator; + typedef llvm::iterator_range<updates_iterator> updates_range; + typedef llvm::iterator_range<updates_const_iterator> updates_const_range; + + updates_range updates() { + return updates_range(getUpdates().begin(), getUpdates().end()); + } + updates_const_range updates() const { + return updates_const_range(getUpdates().begin(), getUpdates().end()); + } + + typedef MutableArrayRef<Expr *>::iterator finals_iterator; + typedef ArrayRef<const Expr *>::iterator finals_const_iterator; + typedef llvm::iterator_range<finals_iterator> finals_range; + typedef llvm::iterator_range<finals_const_iterator> finals_const_range; + + finals_range finals() { + return finals_range(getFinals().begin(), getFinals().end()); + } + finals_const_range finals() const { + return finals_const_range(getFinals().begin(), getFinals().end()); + } + + child_range children() { + return child_range(reinterpret_cast<Stmt **>(varlist_begin()), + reinterpret_cast<Stmt **>(varlist_end())); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_linear; + } +}; + +/// \brief This represents clause 'aligned' in the '#pragma omp ...' +/// directives. +/// +/// \code +/// #pragma omp simd aligned(a,b : 8) +/// \endcode +/// In this example directive '#pragma omp simd' has clause 'aligned' +/// with variables 'a', 'b' and alignment '8'. +/// +class OMPAlignedClause final + : public OMPVarListClause<OMPAlignedClause>, + private llvm::TrailingObjects<OMPAlignedClause, Expr *> { + friend TrailingObjects; + friend OMPVarListClause; + friend class OMPClauseReader; + /// \brief Location of ':'. + SourceLocation ColonLoc; + + /// \brief Sets the alignment for clause. + void setAlignment(Expr *A) { *varlist_end() = A; } + + /// \brief Build 'aligned' clause with given number of variables \a NumVars. + /// + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param ColonLoc Location of ':'. + /// \param EndLoc Ending location of the clause. + /// \param NumVars Number of variables. + /// + OMPAlignedClause(SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ColonLoc, SourceLocation EndLoc, + unsigned NumVars) + : OMPVarListClause<OMPAlignedClause>(OMPC_aligned, StartLoc, LParenLoc, + EndLoc, NumVars), + ColonLoc(ColonLoc) {} + + /// \brief Build an empty clause. + /// + /// \param NumVars Number of variables. + /// + explicit OMPAlignedClause(unsigned NumVars) + : OMPVarListClause<OMPAlignedClause>(OMPC_aligned, SourceLocation(), + SourceLocation(), SourceLocation(), + NumVars), + ColonLoc(SourceLocation()) {} + +public: + /// \brief Creates clause with a list of variables \a VL and alignment \a A. + /// + /// \param C AST Context. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param ColonLoc Location of ':'. + /// \param EndLoc Ending location of the clause. + /// \param VL List of references to the variables. + /// \param A Alignment. + static OMPAlignedClause *Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation ColonLoc, + SourceLocation EndLoc, ArrayRef<Expr *> VL, + Expr *A); + + /// \brief Creates an empty clause with the place for \a NumVars variables. + /// + /// \param C AST context. + /// \param NumVars Number of variables. + /// + static OMPAlignedClause *CreateEmpty(const ASTContext &C, unsigned NumVars); + + /// \brief Sets the location of ':'. + void setColonLoc(SourceLocation Loc) { ColonLoc = Loc; } + /// \brief Returns the location of ':'. + SourceLocation getColonLoc() const { return ColonLoc; } + + /// \brief Returns alignment. + Expr *getAlignment() { return *varlist_end(); } + /// \brief Returns alignment. + const Expr *getAlignment() const { return *varlist_end(); } + + child_range children() { + return child_range(reinterpret_cast<Stmt **>(varlist_begin()), + reinterpret_cast<Stmt **>(varlist_end())); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_aligned; + } +}; + +/// \brief This represents clause 'copyin' in the '#pragma omp ...' directives. +/// +/// \code +/// #pragma omp parallel copyin(a,b) +/// \endcode +/// In this example directive '#pragma omp parallel' has clause 'copyin' +/// with the variables 'a' and 'b'. +/// +class OMPCopyinClause final + : public OMPVarListClause<OMPCopyinClause>, + private llvm::TrailingObjects<OMPCopyinClause, Expr *> { + // Class has 3 additional tail allocated arrays: + // 1. List of helper expressions for proper generation of assignment operation + // required for copyin clause. This list represents sources. + // 2. List of helper expressions for proper generation of assignment operation + // required for copyin clause. This list represents destinations. + // 3. List of helper expressions that represents assignment operation: + // \code + // DstExprs = SrcExprs; + // \endcode + // Required for proper codegen of propagation of master's thread values of + // threadprivate variables to local instances of that variables in other + // implicit threads. + + friend TrailingObjects; + friend OMPVarListClause; + friend class OMPClauseReader; + /// \brief Build clause with number of variables \a N. + /// + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + /// + OMPCopyinClause(SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc, unsigned N) + : OMPVarListClause<OMPCopyinClause>(OMPC_copyin, StartLoc, LParenLoc, + EndLoc, N) {} + + /// \brief Build an empty clause. + /// + /// \param N Number of variables. + /// + explicit OMPCopyinClause(unsigned N) + : OMPVarListClause<OMPCopyinClause>(OMPC_copyin, SourceLocation(), + SourceLocation(), SourceLocation(), + N) {} + + /// \brief Set list of helper expressions, required for proper codegen of the + /// clause. These expressions represent source expression in the final + /// assignment statement performed by the copyin clause. + void setSourceExprs(ArrayRef<Expr *> SrcExprs); + + /// \brief Get the list of helper source expressions. + MutableArrayRef<Expr *> getSourceExprs() { + return MutableArrayRef<Expr *>(varlist_end(), varlist_size()); + } + ArrayRef<const Expr *> getSourceExprs() const { + return llvm::makeArrayRef(varlist_end(), varlist_size()); + } + + /// \brief Set list of helper expressions, required for proper codegen of the + /// clause. These expressions represent destination expression in the final + /// assignment statement performed by the copyin clause. + void setDestinationExprs(ArrayRef<Expr *> DstExprs); + + /// \brief Get the list of helper destination expressions. + MutableArrayRef<Expr *> getDestinationExprs() { + return MutableArrayRef<Expr *>(getSourceExprs().end(), varlist_size()); + } + ArrayRef<const Expr *> getDestinationExprs() const { + return llvm::makeArrayRef(getSourceExprs().end(), varlist_size()); + } + + /// \brief Set list of helper assignment expressions, required for proper + /// codegen of the clause. These expressions are assignment expressions that + /// assign source helper expressions to destination helper expressions + /// correspondingly. + void setAssignmentOps(ArrayRef<Expr *> AssignmentOps); + + /// \brief Get the list of helper assignment expressions. + MutableArrayRef<Expr *> getAssignmentOps() { + return MutableArrayRef<Expr *>(getDestinationExprs().end(), varlist_size()); + } + ArrayRef<const Expr *> getAssignmentOps() const { + return llvm::makeArrayRef(getDestinationExprs().end(), varlist_size()); + } + +public: + /// \brief Creates clause with a list of variables \a VL. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param VL List of references to the variables. + /// \param SrcExprs List of helper expressions for proper generation of + /// assignment operation required for copyin clause. This list represents + /// sources. + /// \param DstExprs List of helper expressions for proper generation of + /// assignment operation required for copyin clause. This list represents + /// destinations. + /// \param AssignmentOps List of helper expressions that represents assignment + /// operation: + /// \code + /// DstExprs = SrcExprs; + /// \endcode + /// Required for proper codegen of propagation of master's thread values of + /// threadprivate variables to local instances of that variables in other + /// implicit threads. + /// + static OMPCopyinClause * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> SrcExprs, + ArrayRef<Expr *> DstExprs, ArrayRef<Expr *> AssignmentOps); + /// \brief Creates an empty clause with \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + /// + static OMPCopyinClause *CreateEmpty(const ASTContext &C, unsigned N); + + typedef MutableArrayRef<Expr *>::iterator helper_expr_iterator; + typedef ArrayRef<const Expr *>::iterator helper_expr_const_iterator; + typedef llvm::iterator_range<helper_expr_iterator> helper_expr_range; + typedef llvm::iterator_range<helper_expr_const_iterator> + helper_expr_const_range; + + helper_expr_const_range source_exprs() const { + return helper_expr_const_range(getSourceExprs().begin(), + getSourceExprs().end()); + } + helper_expr_range source_exprs() { + return helper_expr_range(getSourceExprs().begin(), getSourceExprs().end()); + } + helper_expr_const_range destination_exprs() const { + return helper_expr_const_range(getDestinationExprs().begin(), + getDestinationExprs().end()); + } + helper_expr_range destination_exprs() { + return helper_expr_range(getDestinationExprs().begin(), + getDestinationExprs().end()); + } + helper_expr_const_range assignment_ops() const { + return helper_expr_const_range(getAssignmentOps().begin(), + getAssignmentOps().end()); + } + helper_expr_range assignment_ops() { + return helper_expr_range(getAssignmentOps().begin(), + getAssignmentOps().end()); + } + + child_range children() { + return child_range(reinterpret_cast<Stmt **>(varlist_begin()), + reinterpret_cast<Stmt **>(varlist_end())); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_copyin; + } +}; + +/// \brief This represents clause 'copyprivate' in the '#pragma omp ...' +/// directives. +/// +/// \code +/// #pragma omp single copyprivate(a,b) +/// \endcode +/// In this example directive '#pragma omp single' has clause 'copyprivate' +/// with the variables 'a' and 'b'. +/// +class OMPCopyprivateClause final + : public OMPVarListClause<OMPCopyprivateClause>, + private llvm::TrailingObjects<OMPCopyprivateClause, Expr *> { + friend TrailingObjects; + friend OMPVarListClause; + friend class OMPClauseReader; + /// \brief Build clause with number of variables \a N. + /// + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + /// + OMPCopyprivateClause(SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc, unsigned N) + : OMPVarListClause<OMPCopyprivateClause>(OMPC_copyprivate, StartLoc, + LParenLoc, EndLoc, N) {} + + /// \brief Build an empty clause. + /// + /// \param N Number of variables. + /// + explicit OMPCopyprivateClause(unsigned N) + : OMPVarListClause<OMPCopyprivateClause>( + OMPC_copyprivate, SourceLocation(), SourceLocation(), + SourceLocation(), N) {} + + /// \brief Set list of helper expressions, required for proper codegen of the + /// clause. These expressions represent source expression in the final + /// assignment statement performed by the copyprivate clause. + void setSourceExprs(ArrayRef<Expr *> SrcExprs); + + /// \brief Get the list of helper source expressions. + MutableArrayRef<Expr *> getSourceExprs() { + return MutableArrayRef<Expr *>(varlist_end(), varlist_size()); + } + ArrayRef<const Expr *> getSourceExprs() const { + return llvm::makeArrayRef(varlist_end(), varlist_size()); + } + + /// \brief Set list of helper expressions, required for proper codegen of the + /// clause. These expressions represent destination expression in the final + /// assignment statement performed by the copyprivate clause. + void setDestinationExprs(ArrayRef<Expr *> DstExprs); + + /// \brief Get the list of helper destination expressions. + MutableArrayRef<Expr *> getDestinationExprs() { + return MutableArrayRef<Expr *>(getSourceExprs().end(), varlist_size()); + } + ArrayRef<const Expr *> getDestinationExprs() const { + return llvm::makeArrayRef(getSourceExprs().end(), varlist_size()); + } + + /// \brief Set list of helper assignment expressions, required for proper + /// codegen of the clause. These expressions are assignment expressions that + /// assign source helper expressions to destination helper expressions + /// correspondingly. + void setAssignmentOps(ArrayRef<Expr *> AssignmentOps); + + /// \brief Get the list of helper assignment expressions. + MutableArrayRef<Expr *> getAssignmentOps() { + return MutableArrayRef<Expr *>(getDestinationExprs().end(), varlist_size()); + } + ArrayRef<const Expr *> getAssignmentOps() const { + return llvm::makeArrayRef(getDestinationExprs().end(), varlist_size()); + } + +public: + /// \brief Creates clause with a list of variables \a VL. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param VL List of references to the variables. + /// \param SrcExprs List of helper expressions for proper generation of + /// assignment operation required for copyprivate clause. This list represents + /// sources. + /// \param DstExprs List of helper expressions for proper generation of + /// assignment operation required for copyprivate clause. This list represents + /// destinations. + /// \param AssignmentOps List of helper expressions that represents assignment + /// operation: + /// \code + /// DstExprs = SrcExprs; + /// \endcode + /// Required for proper codegen of final assignment performed by the + /// copyprivate clause. + /// + static OMPCopyprivateClause * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> SrcExprs, + ArrayRef<Expr *> DstExprs, ArrayRef<Expr *> AssignmentOps); + /// \brief Creates an empty clause with \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + /// + static OMPCopyprivateClause *CreateEmpty(const ASTContext &C, unsigned N); + + typedef MutableArrayRef<Expr *>::iterator helper_expr_iterator; + typedef ArrayRef<const Expr *>::iterator helper_expr_const_iterator; + typedef llvm::iterator_range<helper_expr_iterator> helper_expr_range; + typedef llvm::iterator_range<helper_expr_const_iterator> + helper_expr_const_range; + + helper_expr_const_range source_exprs() const { + return helper_expr_const_range(getSourceExprs().begin(), + getSourceExprs().end()); + } + helper_expr_range source_exprs() { + return helper_expr_range(getSourceExprs().begin(), getSourceExprs().end()); + } + helper_expr_const_range destination_exprs() const { + return helper_expr_const_range(getDestinationExprs().begin(), + getDestinationExprs().end()); + } + helper_expr_range destination_exprs() { + return helper_expr_range(getDestinationExprs().begin(), + getDestinationExprs().end()); + } + helper_expr_const_range assignment_ops() const { + return helper_expr_const_range(getAssignmentOps().begin(), + getAssignmentOps().end()); + } + helper_expr_range assignment_ops() { + return helper_expr_range(getAssignmentOps().begin(), + getAssignmentOps().end()); + } + + child_range children() { + return child_range(reinterpret_cast<Stmt **>(varlist_begin()), + reinterpret_cast<Stmt **>(varlist_end())); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_copyprivate; + } +}; + +/// \brief This represents implicit clause 'flush' for the '#pragma omp flush' +/// directive. +/// This clause does not exist by itself, it can be only as a part of 'omp +/// flush' directive. This clause is introduced to keep the original structure +/// of \a OMPExecutableDirective class and its derivatives and to use the +/// existing infrastructure of clauses with the list of variables. +/// +/// \code +/// #pragma omp flush(a,b) +/// \endcode +/// In this example directive '#pragma omp flush' has implicit clause 'flush' +/// with the variables 'a' and 'b'. +/// +class OMPFlushClause final + : public OMPVarListClause<OMPFlushClause>, + private llvm::TrailingObjects<OMPFlushClause, Expr *> { + friend TrailingObjects; + friend OMPVarListClause; + /// \brief Build clause with number of variables \a N. + /// + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + /// + OMPFlushClause(SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc, unsigned N) + : OMPVarListClause<OMPFlushClause>(OMPC_flush, StartLoc, LParenLoc, + EndLoc, N) {} + + /// \brief Build an empty clause. + /// + /// \param N Number of variables. + /// + explicit OMPFlushClause(unsigned N) + : OMPVarListClause<OMPFlushClause>(OMPC_flush, SourceLocation(), + SourceLocation(), SourceLocation(), + N) {} + +public: + /// \brief Creates clause with a list of variables \a VL. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param VL List of references to the variables. + /// + static OMPFlushClause *Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc, + ArrayRef<Expr *> VL); + /// \brief Creates an empty clause with \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + /// + static OMPFlushClause *CreateEmpty(const ASTContext &C, unsigned N); + + child_range children() { + return child_range(reinterpret_cast<Stmt **>(varlist_begin()), + reinterpret_cast<Stmt **>(varlist_end())); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_flush; + } +}; + +/// \brief This represents implicit clause 'depend' for the '#pragma omp task' +/// directive. +/// +/// \code +/// #pragma omp task depend(in:a,b) +/// \endcode +/// In this example directive '#pragma omp task' with clause 'depend' with the +/// variables 'a' and 'b' with dependency 'in'. +/// +class OMPDependClause final + : public OMPVarListClause<OMPDependClause>, + private llvm::TrailingObjects<OMPDependClause, Expr *> { + friend TrailingObjects; + friend OMPVarListClause; + friend class OMPClauseReader; + /// \brief Dependency type (one of in, out, inout). + OpenMPDependClauseKind DepKind; + /// \brief Dependency type location. + SourceLocation DepLoc; + /// \brief Colon location. + SourceLocation ColonLoc; + /// \brief Build clause with number of variables \a N. + /// + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + /// + OMPDependClause(SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc, unsigned N) + : OMPVarListClause<OMPDependClause>(OMPC_depend, StartLoc, LParenLoc, + EndLoc, N), + DepKind(OMPC_DEPEND_unknown) {} + + /// \brief Build an empty clause. + /// + /// \param N Number of variables. + /// + explicit OMPDependClause(unsigned N) + : OMPVarListClause<OMPDependClause>(OMPC_depend, SourceLocation(), + SourceLocation(), SourceLocation(), + N), + DepKind(OMPC_DEPEND_unknown) {} + /// \brief Set dependency kind. + void setDependencyKind(OpenMPDependClauseKind K) { DepKind = K; } + + /// \brief Set dependency kind and its location. + void setDependencyLoc(SourceLocation Loc) { DepLoc = Loc; } + + /// \brief Set colon location. + void setColonLoc(SourceLocation Loc) { ColonLoc = Loc; } + +public: + /// \brief Creates clause with a list of variables \a VL. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param DepKind Dependency type. + /// \param DepLoc Location of the dependency type. + /// \param ColonLoc Colon location. + /// \param VL List of references to the variables. + /// + static OMPDependClause * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc, OpenMPDependClauseKind DepKind, + SourceLocation DepLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VL); + /// \brief Creates an empty clause with \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + /// + static OMPDependClause *CreateEmpty(const ASTContext &C, unsigned N); + + /// \brief Get dependency type. + OpenMPDependClauseKind getDependencyKind() const { return DepKind; } + /// \brief Get dependency type location. + SourceLocation getDependencyLoc() const { return DepLoc; } + /// \brief Get colon location. + SourceLocation getColonLoc() const { return ColonLoc; } + + child_range children() { + return child_range(reinterpret_cast<Stmt **>(varlist_begin()), + reinterpret_cast<Stmt **>(varlist_end())); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_depend; + } +}; + +/// \brief This represents 'device' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp target device(a) +/// \endcode +/// In this example directive '#pragma omp target' has clause 'device' +/// with single expression 'a'. +/// +class OMPDeviceClause : public OMPClause { + friend class OMPClauseReader; + /// \brief Location of '('. + SourceLocation LParenLoc; + /// \brief Device number. + Stmt *Device; + /// \brief Set the device number. + /// + /// \param E Device number. + /// + void setDevice(Expr *E) { Device = E; } + +public: + /// \brief Build 'device' clause. + /// + /// \param E Expression associated with this clause. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// + OMPDeviceClause(Expr *E, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc) + : OMPClause(OMPC_device, StartLoc, EndLoc), LParenLoc(LParenLoc), + Device(E) {} + + /// \brief Build an empty clause. + /// + OMPDeviceClause() + : OMPClause(OMPC_device, SourceLocation(), SourceLocation()), + LParenLoc(SourceLocation()), Device(nullptr) {} + /// \brief Sets the location of '('. + void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. + SourceLocation getLParenLoc() const { return LParenLoc; } + /// \brief Return device number. + Expr *getDevice() { return cast<Expr>(Device); } + /// \brief Return device number. + Expr *getDevice() const { return cast<Expr>(Device); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_device; + } + + child_range children() { return child_range(&Device, &Device + 1); } +}; + +/// \brief This represents 'threads' clause in the '#pragma omp ...' directive. +/// +/// \code +/// #pragma omp ordered threads +/// \endcode +/// In this example directive '#pragma omp ordered' has simple 'threads' clause. +/// +class OMPThreadsClause : public OMPClause { +public: + /// \brief Build 'threads' clause. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPThreadsClause(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_threads, StartLoc, EndLoc) {} + + /// \brief Build an empty clause. + /// + OMPThreadsClause() + : OMPClause(OMPC_threads, SourceLocation(), SourceLocation()) {} + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_threads; + } + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +/// \brief This represents 'simd' clause in the '#pragma omp ...' directive. +/// +/// \code +/// #pragma omp ordered simd +/// \endcode +/// In this example directive '#pragma omp ordered' has simple 'simd' clause. +/// +class OMPSIMDClause : public OMPClause { +public: + /// \brief Build 'simd' clause. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPSIMDClause(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_simd, StartLoc, EndLoc) {} + + /// \brief Build an empty clause. + /// + OMPSIMDClause() : OMPClause(OMPC_simd, SourceLocation(), SourceLocation()) {} + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_simd; + } + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +/// \brief This represents clause 'map' in the '#pragma omp ...' +/// directives. +/// +/// \code +/// #pragma omp target map(a,b) +/// \endcode +/// In this example directive '#pragma omp target' has clause 'map' +/// with the variables 'a' and 'b'. +/// +class OMPMapClause final : public OMPVarListClause<OMPMapClause>, + private llvm::TrailingObjects<OMPMapClause, Expr *> { + friend TrailingObjects; + friend OMPVarListClause; + friend class OMPClauseReader; + + /// \brief Map type modifier for the 'map' clause. + OpenMPMapClauseKind MapTypeModifier; + /// \brief Map type for the 'map' clause. + OpenMPMapClauseKind MapType; + /// \brief Location of the map type. + SourceLocation MapLoc; + /// \brief Colon location. + SourceLocation ColonLoc; + + /// \brief Set type modifier for the clause. + /// + /// \param T Type Modifier for the clause. + /// + void setMapTypeModifier(OpenMPMapClauseKind T) { MapTypeModifier = T; } + + /// \brief Set type for the clause. + /// + /// \param T Type for the clause. + /// + void setMapType(OpenMPMapClauseKind T) { MapType = T; } + + /// \brief Set type location. + /// + /// \param TLoc Type location. + /// + void setMapLoc(SourceLocation TLoc) { MapLoc = TLoc; } + + /// \brief Set colon location. + void setColonLoc(SourceLocation Loc) { ColonLoc = Loc; } + + /// \brief Build clause with number of variables \a N. + /// + /// \param MapTypeModifier Map type modifier. + /// \param MapType Map type. + /// \param MapLoc Location of the map type. + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + /// + explicit OMPMapClause(OpenMPMapClauseKind MapTypeModifier, + OpenMPMapClauseKind MapType, SourceLocation MapLoc, + SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc, unsigned N) + : OMPVarListClause<OMPMapClause>(OMPC_map, StartLoc, LParenLoc, EndLoc, N), + MapTypeModifier(MapTypeModifier), MapType(MapType), MapLoc(MapLoc) {} + + /// \brief Build an empty clause. + /// + /// \param N Number of variables. + /// + explicit OMPMapClause(unsigned N) + : OMPVarListClause<OMPMapClause>(OMPC_map, SourceLocation(), + SourceLocation(), SourceLocation(), N), + MapTypeModifier(OMPC_MAP_unknown), MapType(OMPC_MAP_unknown), MapLoc() {} + +public: + /// \brief Creates clause with a list of variables \a VL. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// \param VL List of references to the variables. + /// \param TypeModifier Map type modifier. + /// \param Type Map type. + /// \param TypeLoc Location of the map type. + /// + static OMPMapClause *Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc, ArrayRef<Expr *> VL, + OpenMPMapClauseKind TypeModifier, + OpenMPMapClauseKind Type, SourceLocation TypeLoc); + /// \brief Creates an empty clause with the place for \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + /// + static OMPMapClause *CreateEmpty(const ASTContext &C, unsigned N); + + /// \brief Fetches mapping kind for the clause. + OpenMPMapClauseKind getMapType() const LLVM_READONLY { return MapType; } + + /// \brief Fetches the map type modifier for the clause. + OpenMPMapClauseKind getMapTypeModifier() const LLVM_READONLY { + return MapTypeModifier; + } + + /// \brief Fetches location of clause mapping kind. + SourceLocation getMapLoc() const LLVM_READONLY { return MapLoc; } + + /// \brief Get colon location. + SourceLocation getColonLoc() const { return ColonLoc; } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_map; + } + + child_range children() { + return child_range( + reinterpret_cast<Stmt **>(varlist_begin()), + reinterpret_cast<Stmt **>(varlist_end())); + } +}; + +/// \brief This represents 'num_teams' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp teams num_teams(n) +/// \endcode +/// In this example directive '#pragma omp teams' has clause 'num_teams' +/// with single expression 'n'. +/// +class OMPNumTeamsClause : public OMPClause { + friend class OMPClauseReader; + /// \brief Location of '('. + SourceLocation LParenLoc; + /// \brief NumTeams number. + Stmt *NumTeams; + /// \brief Set the NumTeams number. + /// + /// \param E NumTeams number. + /// + void setNumTeams(Expr *E) { NumTeams = E; } + +public: + /// \brief Build 'num_teams' clause. + /// + /// \param E Expression associated with this clause. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// + OMPNumTeamsClause(Expr *E, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc) + : OMPClause(OMPC_num_teams, StartLoc, EndLoc), LParenLoc(LParenLoc), + NumTeams(E) {} + + /// \brief Build an empty clause. + /// + OMPNumTeamsClause() + : OMPClause(OMPC_num_teams, SourceLocation(), SourceLocation()), + LParenLoc(SourceLocation()), NumTeams(nullptr) {} + /// \brief Sets the location of '('. + void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. + SourceLocation getLParenLoc() const { return LParenLoc; } + /// \brief Return NumTeams number. + Expr *getNumTeams() { return cast<Expr>(NumTeams); } + /// \brief Return NumTeams number. + Expr *getNumTeams() const { return cast<Expr>(NumTeams); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_num_teams; + } + + child_range children() { return child_range(&NumTeams, &NumTeams + 1); } +}; + +/// \brief This represents 'thread_limit' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp teams thread_limit(n) +/// \endcode +/// In this example directive '#pragma omp teams' has clause 'thread_limit' +/// with single expression 'n'. +/// +class OMPThreadLimitClause : public OMPClause { + friend class OMPClauseReader; + /// \brief Location of '('. + SourceLocation LParenLoc; + /// \brief ThreadLimit number. + Stmt *ThreadLimit; + /// \brief Set the ThreadLimit number. + /// + /// \param E ThreadLimit number. + /// + void setThreadLimit(Expr *E) { ThreadLimit = E; } + +public: + /// \brief Build 'thread_limit' clause. + /// + /// \param E Expression associated with this clause. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// + OMPThreadLimitClause(Expr *E, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc) + : OMPClause(OMPC_thread_limit, StartLoc, EndLoc), LParenLoc(LParenLoc), + ThreadLimit(E) {} + + /// \brief Build an empty clause. + /// + OMPThreadLimitClause() + : OMPClause(OMPC_thread_limit, SourceLocation(), SourceLocation()), + LParenLoc(SourceLocation()), ThreadLimit(nullptr) {} + /// \brief Sets the location of '('. + void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. + SourceLocation getLParenLoc() const { return LParenLoc; } + /// \brief Return ThreadLimit number. + Expr *getThreadLimit() { return cast<Expr>(ThreadLimit); } + /// \brief Return ThreadLimit number. + Expr *getThreadLimit() const { return cast<Expr>(ThreadLimit); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_thread_limit; + } + + child_range children() { return child_range(&ThreadLimit, &ThreadLimit + 1); } +}; + +/// \brief This represents 'priority' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp task priority(n) +/// \endcode +/// In this example directive '#pragma omp teams' has clause 'priority' with +/// single expression 'n'. +/// +class OMPPriorityClause : public OMPClause { + friend class OMPClauseReader; + /// \brief Location of '('. + SourceLocation LParenLoc; + /// \brief Priority number. + Stmt *Priority; + /// \brief Set the Priority number. + /// + /// \param E Priority number. + /// + void setPriority(Expr *E) { Priority = E; } + +public: + /// \brief Build 'priority' clause. + /// + /// \param E Expression associated with this clause. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// + OMPPriorityClause(Expr *E, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc) + : OMPClause(OMPC_priority, StartLoc, EndLoc), LParenLoc(LParenLoc), + Priority(E) {} + + /// \brief Build an empty clause. + /// + OMPPriorityClause() + : OMPClause(OMPC_priority, SourceLocation(), SourceLocation()), + LParenLoc(SourceLocation()), Priority(nullptr) {} + /// \brief Sets the location of '('. + void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. + SourceLocation getLParenLoc() const { return LParenLoc; } + /// \brief Return Priority number. + Expr *getPriority() { return cast<Expr>(Priority); } + /// \brief Return Priority number. + Expr *getPriority() const { return cast<Expr>(Priority); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_priority; + } + + child_range children() { return child_range(&Priority, &Priority + 1); } +}; + +/// \brief This represents 'grainsize' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp taskloop grainsize(4) +/// \endcode +/// In this example directive '#pragma omp taskloop' has clause 'grainsize' +/// with single expression '4'. +/// +class OMPGrainsizeClause : public OMPClause { + friend class OMPClauseReader; + /// \brief Location of '('. + SourceLocation LParenLoc; + /// \brief Safe iteration space distance. + Stmt *Grainsize; + + /// \brief Set safelen. + void setGrainsize(Expr *Size) { Grainsize = Size; } + +public: + /// \brief Build 'grainsize' clause. + /// + /// \param Size Expression associated with this clause. + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPGrainsizeClause(Expr *Size, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc) + : OMPClause(OMPC_grainsize, StartLoc, EndLoc), LParenLoc(LParenLoc), + Grainsize(Size) {} + + /// \brief Build an empty clause. + /// + explicit OMPGrainsizeClause() + : OMPClause(OMPC_grainsize, SourceLocation(), SourceLocation()), + LParenLoc(SourceLocation()), Grainsize(nullptr) {} + + /// \brief Sets the location of '('. + void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. + SourceLocation getLParenLoc() const { return LParenLoc; } + + /// \brief Return safe iteration space distance. + Expr *getGrainsize() const { return cast_or_null<Expr>(Grainsize); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_grainsize; + } + + child_range children() { return child_range(&Grainsize, &Grainsize + 1); } +}; + +/// \brief This represents 'nogroup' clause in the '#pragma omp ...' directive. +/// +/// \code +/// #pragma omp taskloop nogroup +/// \endcode +/// In this example directive '#pragma omp taskloop' has 'nogroup' clause. +/// +class OMPNogroupClause : public OMPClause { +public: + /// \brief Build 'nogroup' clause. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPNogroupClause(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_nogroup, StartLoc, EndLoc) {} + + /// \brief Build an empty clause. + /// + OMPNogroupClause() + : OMPClause(OMPC_nogroup, SourceLocation(), SourceLocation()) {} + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_nogroup; + } + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +/// \brief This represents 'num_tasks' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp taskloop num_tasks(4) +/// \endcode +/// In this example directive '#pragma omp taskloop' has clause 'num_tasks' +/// with single expression '4'. +/// +class OMPNumTasksClause : public OMPClause { + friend class OMPClauseReader; + /// \brief Location of '('. + SourceLocation LParenLoc; + /// \brief Safe iteration space distance. + Stmt *NumTasks; + + /// \brief Set safelen. + void setNumTasks(Expr *Size) { NumTasks = Size; } + +public: + /// \brief Build 'num_tasks' clause. + /// + /// \param Size Expression associated with this clause. + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPNumTasksClause(Expr *Size, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc) + : OMPClause(OMPC_num_tasks, StartLoc, EndLoc), LParenLoc(LParenLoc), + NumTasks(Size) {} + + /// \brief Build an empty clause. + /// + explicit OMPNumTasksClause() + : OMPClause(OMPC_num_tasks, SourceLocation(), SourceLocation()), + LParenLoc(SourceLocation()), NumTasks(nullptr) {} + + /// \brief Sets the location of '('. + void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. + SourceLocation getLParenLoc() const { return LParenLoc; } + + /// \brief Return safe iteration space distance. + Expr *getNumTasks() const { return cast_or_null<Expr>(NumTasks); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_num_tasks; + } + + child_range children() { return child_range(&NumTasks, &NumTasks + 1); } +}; + +/// \brief This represents 'hint' clause in the '#pragma omp ...' directive. +/// +/// \code +/// #pragma omp critical (name) hint(6) +/// \endcode +/// In this example directive '#pragma omp critical' has name 'name' and clause +/// 'hint' with argument '6'. +/// +class OMPHintClause : public OMPClause { + friend class OMPClauseReader; + /// \brief Location of '('. + SourceLocation LParenLoc; + /// \brief Hint expression of the 'hint' clause. + Stmt *Hint; + + /// \brief Set hint expression. + /// + void setHint(Expr *H) { Hint = H; } + +public: + /// \brief Build 'hint' clause with expression \a Hint. + /// + /// \param Hint Hint expression. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// + OMPHintClause(Expr *Hint, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc) + : OMPClause(OMPC_hint, StartLoc, EndLoc), LParenLoc(LParenLoc), + Hint(Hint) {} + + /// \brief Build an empty clause. + /// + OMPHintClause() + : OMPClause(OMPC_hint, SourceLocation(), SourceLocation()), + LParenLoc(SourceLocation()), Hint(nullptr) {} + + /// \brief Sets the location of '('. + void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. + SourceLocation getLParenLoc() const { return LParenLoc; } + + /// \brief Returns number of threads. + Expr *getHint() const { return cast_or_null<Expr>(Hint); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_hint; + } + + child_range children() { return child_range(&Hint, &Hint + 1); } +}; + +} // end namespace clang + +#endif // LLVM_CLANG_AST_OPENMPCLAUSE_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/OperationKinds.h b/contrib/llvm/tools/clang/include/clang/AST/OperationKinds.h new file mode 100644 index 0000000..2235c10 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/OperationKinds.h @@ -0,0 +1,356 @@ +//===- OperationKinds.h - Operation enums -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file enumerates the different kinds of operations that can be +// performed by various expressions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_OPERATIONKINDS_H +#define LLVM_CLANG_AST_OPERATIONKINDS_H + +namespace clang { + +/// CastKind - The kind of operation required for a conversion. +enum CastKind { + /// CK_Dependent - A conversion which cannot yet be analyzed because + /// either the expression or target type is dependent. These are + /// created only for explicit casts; dependent ASTs aren't required + /// to even approximately type-check. + /// (T*) malloc(sizeof(T)) + /// reinterpret_cast<intptr_t>(A<T>::alloc()); + CK_Dependent, + + /// CK_BitCast - A conversion which causes a bit pattern of one type + /// to be reinterpreted as a bit pattern of another type. Generally + /// the operands must have equivalent size and unrelated types. + /// + /// The pointer conversion char* -> int* is a bitcast. A conversion + /// from any pointer type to a C pointer type is a bitcast unless + /// it's actually BaseToDerived or DerivedToBase. A conversion to a + /// block pointer or ObjC pointer type is a bitcast only if the + /// operand has the same type kind; otherwise, it's one of the + /// specialized casts below. + /// + /// Vector coercions are bitcasts. + CK_BitCast, + + /// CK_LValueBitCast - A conversion which reinterprets the address of + /// an l-value as an l-value of a different kind. Used for + /// reinterpret_casts of l-value expressions to reference types. + /// bool b; reinterpret_cast<char&>(b) = 'a'; + CK_LValueBitCast, + + /// CK_LValueToRValue - A conversion which causes the extraction of + /// an r-value from the operand gl-value. The result of an r-value + /// conversion is always unqualified. + CK_LValueToRValue, + + /// CK_NoOp - A conversion which does not affect the type other than + /// (possibly) adding qualifiers. + /// int -> int + /// char** -> const char * const * + CK_NoOp, + + /// CK_BaseToDerived - A conversion from a C++ class pointer/reference + /// to a derived class pointer/reference. + /// B *b = static_cast<B*>(a); + CK_BaseToDerived, + + /// CK_DerivedToBase - A conversion from a C++ class pointer + /// to a base class pointer. + /// A *a = new B(); + CK_DerivedToBase, + + /// CK_UncheckedDerivedToBase - A conversion from a C++ class + /// pointer/reference to a base class that can assume that the + /// derived pointer is not null. + /// const A &a = B(); + /// b->method_from_a(); + CK_UncheckedDerivedToBase, + + /// CK_Dynamic - A C++ dynamic_cast. + CK_Dynamic, + + /// CK_ToUnion - The GCC cast-to-union extension. + /// int -> union { int x; float y; } + /// float -> union { int x; float y; } + CK_ToUnion, + + /// CK_ArrayToPointerDecay - Array to pointer decay. + /// int[10] -> int* + /// char[5][6] -> char(*)[6] + CK_ArrayToPointerDecay, + + /// CK_FunctionToPointerDecay - Function to pointer decay. + /// void(int) -> void(*)(int) + CK_FunctionToPointerDecay, + + /// CK_NullToPointer - Null pointer constant to pointer, ObjC + /// pointer, or block pointer. + /// (void*) 0 + /// void (^block)() = 0; + CK_NullToPointer, + + /// CK_NullToMemberPointer - Null pointer constant to member pointer. + /// int A::*mptr = 0; + /// int (A::*fptr)(int) = nullptr; + CK_NullToMemberPointer, + + /// CK_BaseToDerivedMemberPointer - Member pointer in base class to + /// member pointer in derived class. + /// int B::*mptr = &A::member; + CK_BaseToDerivedMemberPointer, + + /// CK_DerivedToBaseMemberPointer - Member pointer in derived class to + /// member pointer in base class. + /// int A::*mptr = static_cast<int A::*>(&B::member); + CK_DerivedToBaseMemberPointer, + + /// CK_MemberPointerToBoolean - Member pointer to boolean. A check + /// against the null member pointer. + CK_MemberPointerToBoolean, + + /// CK_ReinterpretMemberPointer - Reinterpret a member pointer as a + /// different kind of member pointer. C++ forbids this from + /// crossing between function and object types, but otherwise does + /// not restrict it. However, the only operation that is permitted + /// on a "punned" member pointer is casting it back to the original + /// type, which is required to be a lossless operation (although + /// many ABIs do not guarantee this on all possible intermediate types). + CK_ReinterpretMemberPointer, + + /// CK_UserDefinedConversion - Conversion using a user defined type + /// conversion function. + /// struct A { operator int(); }; int i = int(A()); + CK_UserDefinedConversion, + + /// CK_ConstructorConversion - Conversion by constructor. + /// struct A { A(int); }; A a = A(10); + CK_ConstructorConversion, + + /// CK_IntegralToPointer - Integral to pointer. A special kind of + /// reinterpreting conversion. Applies to normal, ObjC, and block + /// pointers. + /// (char*) 0x1001aab0 + /// reinterpret_cast<int*>(0) + CK_IntegralToPointer, + + /// CK_PointerToIntegral - Pointer to integral. A special kind of + /// reinterpreting conversion. Applies to normal, ObjC, and block + /// pointers. + /// (intptr_t) "help!" + CK_PointerToIntegral, + + /// CK_PointerToBoolean - Pointer to boolean conversion. A check + /// against null. Applies to normal, ObjC, and block pointers. + CK_PointerToBoolean, + + /// CK_ToVoid - Cast to void, discarding the computed value. + /// (void) malloc(2048) + CK_ToVoid, + + /// CK_VectorSplat - A conversion from an arithmetic type to a + /// vector of that element type. Fills all elements ("splats") with + /// the source value. + /// __attribute__((ext_vector_type(4))) int v = 5; + CK_VectorSplat, + + /// CK_IntegralCast - A cast between integral types (other than to + /// boolean). Variously a bitcast, a truncation, a sign-extension, + /// or a zero-extension. + /// long l = 5; + /// (unsigned) i + CK_IntegralCast, + + /// CK_IntegralToBoolean - Integral to boolean. A check against zero. + /// (bool) i + CK_IntegralToBoolean, + + /// CK_IntegralToFloating - Integral to floating point. + /// float f = i; + CK_IntegralToFloating, + + /// CK_FloatingToIntegral - Floating point to integral. Rounds + /// towards zero, discarding any fractional component. + /// (int) f + CK_FloatingToIntegral, + + /// CK_FloatingToBoolean - Floating point to boolean. + /// (bool) f + CK_FloatingToBoolean, + + /// CK_FloatingCast - Casting between floating types of different size. + /// (double) f + /// (float) ld + CK_FloatingCast, + + /// CK_CPointerToObjCPointerCast - Casting a C pointer kind to an + /// Objective-C pointer. + CK_CPointerToObjCPointerCast, + + /// CK_BlockPointerToObjCPointerCast - Casting a block pointer to an + /// ObjC pointer. + CK_BlockPointerToObjCPointerCast, + + /// CK_AnyPointerToBlockPointerCast - Casting any non-block pointer + /// to a block pointer. Block-to-block casts are bitcasts. + CK_AnyPointerToBlockPointerCast, + + /// \brief Converting between two Objective-C object types, which + /// can occur when performing reference binding to an Objective-C + /// object. + CK_ObjCObjectLValueCast, + + /// \brief A conversion of a floating point real to a floating point + /// complex of the original type. Injects the value as the real + /// component with a zero imaginary component. + /// float -> _Complex float + CK_FloatingRealToComplex, + + /// \brief Converts a floating point complex to floating point real + /// of the source's element type. Just discards the imaginary + /// component. + /// _Complex long double -> long double + CK_FloatingComplexToReal, + + /// \brief Converts a floating point complex to bool by comparing + /// against 0+0i. + CK_FloatingComplexToBoolean, + + /// \brief Converts between different floating point complex types. + /// _Complex float -> _Complex double + CK_FloatingComplexCast, + + /// \brief Converts from a floating complex to an integral complex. + /// _Complex float -> _Complex int + CK_FloatingComplexToIntegralComplex, + + /// \brief Converts from an integral real to an integral complex + /// whose element type matches the source. Injects the value as + /// the real component with a zero imaginary component. + /// long -> _Complex long + CK_IntegralRealToComplex, + + /// \brief Converts an integral complex to an integral real of the + /// source's element type by discarding the imaginary component. + /// _Complex short -> short + CK_IntegralComplexToReal, + + /// \brief Converts an integral complex to bool by comparing against + /// 0+0i. + CK_IntegralComplexToBoolean, + + /// \brief Converts between different integral complex types. + /// _Complex char -> _Complex long long + /// _Complex unsigned int -> _Complex signed int + CK_IntegralComplexCast, + + /// \brief Converts from an integral complex to a floating complex. + /// _Complex unsigned -> _Complex float + CK_IntegralComplexToFloatingComplex, + + /// \brief [ARC] Produces a retainable object pointer so that it may + /// be consumed, e.g. by being passed to a consuming parameter. + /// Calls objc_retain. + CK_ARCProduceObject, + + /// \brief [ARC] Consumes a retainable object pointer that has just + /// been produced, e.g. as the return value of a retaining call. + /// Enters a cleanup to call objc_release at some indefinite time. + CK_ARCConsumeObject, + + /// \brief [ARC] Reclaim a retainable object pointer object that may + /// have been produced and autoreleased as part of a function return + /// sequence. + CK_ARCReclaimReturnedObject, + + /// \brief [ARC] Causes a value of block type to be copied to the + /// heap, if it is not already there. A number of other operations + /// in ARC cause blocks to be copied; this is for cases where that + /// would not otherwise be guaranteed, such as when casting to a + /// non-block pointer type. + CK_ARCExtendBlockObject, + + /// \brief Converts from _Atomic(T) to T. + CK_AtomicToNonAtomic, + /// \brief Converts from T to _Atomic(T). + CK_NonAtomicToAtomic, + + /// \brief Causes a block literal to by copied to the heap and then + /// autoreleased. + /// + /// This particular cast kind is used for the conversion from a C++11 + /// lambda expression to a block pointer. + CK_CopyAndAutoreleaseBlockObject, + + // Convert a builtin function to a function pointer; only allowed in the + // callee of a call expression. + CK_BuiltinFnToFnPtr, + + // Convert a zero value for OpenCL event_t initialization. + CK_ZeroToOCLEvent, + + // Convert a pointer to a different address space. + CK_AddressSpaceConversion +}; + +static const CastKind CK_Invalid = static_cast<CastKind>(-1); + +enum BinaryOperatorKind { + // Operators listed in order of precedence. + // Note that additions to this should also update the StmtVisitor class. + BO_PtrMemD, BO_PtrMemI, // [C++ 5.5] Pointer-to-member operators. + BO_Mul, BO_Div, BO_Rem, // [C99 6.5.5] Multiplicative operators. + BO_Add, BO_Sub, // [C99 6.5.6] Additive operators. + BO_Shl, BO_Shr, // [C99 6.5.7] Bitwise shift operators. + BO_LT, BO_GT, BO_LE, BO_GE, // [C99 6.5.8] Relational operators. + BO_EQ, BO_NE, // [C99 6.5.9] Equality operators. + BO_And, // [C99 6.5.10] Bitwise AND operator. + BO_Xor, // [C99 6.5.11] Bitwise XOR operator. + BO_Or, // [C99 6.5.12] Bitwise OR operator. + BO_LAnd, // [C99 6.5.13] Logical AND operator. + BO_LOr, // [C99 6.5.14] Logical OR operator. + BO_Assign, BO_MulAssign, // [C99 6.5.16] Assignment operators. + BO_DivAssign, BO_RemAssign, + BO_AddAssign, BO_SubAssign, + BO_ShlAssign, BO_ShrAssign, + BO_AndAssign, BO_XorAssign, + BO_OrAssign, + BO_Comma // [C99 6.5.17] Comma operator. +}; + +enum UnaryOperatorKind { + // Note that additions to this should also update the StmtVisitor class. + UO_PostInc, UO_PostDec, // [C99 6.5.2.4] Postfix increment and decrement + UO_PreInc, UO_PreDec, // [C99 6.5.3.1] Prefix increment and decrement + UO_AddrOf, UO_Deref, // [C99 6.5.3.2] Address and indirection + UO_Plus, UO_Minus, // [C99 6.5.3.3] Unary arithmetic + UO_Not, UO_LNot, // [C99 6.5.3.3] Unary arithmetic + UO_Real, UO_Imag, // "__real expr"/"__imag expr" Extension. + UO_Extension, // __extension__ marker. + UO_Coawait // [C++ Coroutines] co_await operator +}; + +/// \brief The kind of bridging performed by the Objective-C bridge cast. +enum ObjCBridgeCastKind { + /// \brief Bridging via __bridge, which does nothing but reinterpret + /// the bits. + OBC_Bridge, + /// \brief Bridging via __bridge_transfer, which transfers ownership of an + /// Objective-C pointer into ARC. + OBC_BridgeTransfer, + /// \brief Bridging via __bridge_retain, which makes an ARC object available + /// as a +1 C pointer. + OBC_BridgeRetained +}; + +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/ParentMap.h b/contrib/llvm/tools/clang/include/clang/AST/ParentMap.h new file mode 100644 index 0000000..8945c41 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/ParentMap.h @@ -0,0 +1,67 @@ +//===--- ParentMap.h - Mappings from Stmts to their Parents -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ParentMap class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_PARENTMAP_H +#define LLVM_CLANG_AST_PARENTMAP_H + +namespace clang { +class Stmt; +class Expr; + +class ParentMap { + void* Impl; +public: + ParentMap(Stmt* ASTRoot); + ~ParentMap(); + + /// \brief Adds and/or updates the parent/child-relations of the complete + /// stmt tree of S. All children of S including indirect descendants are + /// visited and updated or inserted but not the parents of S. + void addStmt(Stmt* S); + + /// Manually sets the parent of \p S to \p Parent. + /// + /// If \p S is already in the map, this method will update the mapping. + void setParent(const Stmt *S, const Stmt *Parent); + + Stmt *getParent(Stmt*) const; + Stmt *getParentIgnoreParens(Stmt *) const; + Stmt *getParentIgnoreParenCasts(Stmt *) const; + Stmt *getParentIgnoreParenImpCasts(Stmt *) const; + Stmt *getOuterParenParent(Stmt *) const; + + const Stmt *getParent(const Stmt* S) const { + return getParent(const_cast<Stmt*>(S)); + } + + const Stmt *getParentIgnoreParens(const Stmt *S) const { + return getParentIgnoreParens(const_cast<Stmt*>(S)); + } + + const Stmt *getParentIgnoreParenCasts(const Stmt *S) const { + return getParentIgnoreParenCasts(const_cast<Stmt*>(S)); + } + + bool hasParent(Stmt* S) const { + return getParent(S) != nullptr; + } + + bool isConsumedExpr(Expr *E) const; + + bool isConsumedExpr(const Expr *E) const { + return isConsumedExpr(const_cast<Expr*>(E)); + } +}; + +} // end clang namespace +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/PrettyPrinter.h b/contrib/llvm/tools/clang/include/clang/AST/PrettyPrinter.h new file mode 100644 index 0000000..8ab3f617 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/PrettyPrinter.h @@ -0,0 +1,175 @@ +//===--- PrettyPrinter.h - Classes for aiding with AST printing -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the PrinterHelper interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_PRETTYPRINTER_H +#define LLVM_CLANG_AST_PRETTYPRINTER_H + +#include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" + +namespace clang { + +class LangOptions; +class SourceManager; +class Stmt; +class TagDecl; + +class PrinterHelper { +public: + virtual ~PrinterHelper(); + virtual bool handledStmt(Stmt* E, raw_ostream& OS) = 0; +}; + +/// \brief Describes how types, statements, expressions, and +/// declarations should be printed. +struct PrintingPolicy { + /// \brief Create a default printing policy for C. + PrintingPolicy(const LangOptions &LO) + : LangOpts(LO), Indentation(2), SuppressSpecifiers(false), + SuppressTagKeyword(false), SuppressTag(false), SuppressScope(false), + SuppressUnwrittenScope(false), SuppressInitializers(false), + ConstantArraySizeAsWritten(false), AnonymousTagLocations(true), + SuppressStrongLifetime(false), SuppressLifetimeQualifiers(false), + Bool(LO.Bool), TerseOutput(false), PolishForDeclaration(false), + Half(LO.Half), MSWChar(LO.MicrosoftExt && !LO.WChar), + IncludeNewlines(true), MSVCFormatting(false) { } + + /// \brief What language we're printing. + LangOptions LangOpts; + + /// \brief The number of spaces to use to indent each line. + unsigned Indentation : 8; + + /// \brief Whether we should suppress printing of the actual specifiers for + /// the given type or declaration. + /// + /// This flag is only used when we are printing declarators beyond + /// the first declarator within a declaration group. For example, given: + /// + /// \code + /// const int *x, *y; + /// \endcode + /// + /// SuppressSpecifiers will be false when printing the + /// declaration for "x", so that we will print "int *x"; it will be + /// \c true when we print "y", so that we suppress printing the + /// "const int" type specifier and instead only print the "*y". + bool SuppressSpecifiers : 1; + + /// \brief Whether type printing should skip printing the tag keyword. + /// + /// This is used when printing the inner type of elaborated types, + /// (as the tag keyword is part of the elaborated type): + /// + /// \code + /// struct Geometry::Point; + /// \endcode + bool SuppressTagKeyword : 1; + + /// \brief Whether type printing should skip printing the actual tag type. + /// + /// This is used when the caller needs to print a tag definition in front + /// of the type, as in constructs like the following: + /// + /// \code + /// typedef struct { int x, y; } Point; + /// \endcode + bool SuppressTag : 1; + + /// \brief Suppresses printing of scope specifiers. + bool SuppressScope : 1; + + /// \brief Suppress printing parts of scope specifiers that don't need + /// to be written, e.g., for inline or anonymous namespaces. + bool SuppressUnwrittenScope : 1; + + /// \brief Suppress printing of variable initializers. + /// + /// This flag is used when printing the loop variable in a for-range + /// statement. For example, given: + /// + /// \code + /// for (auto x : coll) + /// \endcode + /// + /// SuppressInitializers will be true when printing "auto x", so that the + /// internal initializer constructed for x will not be printed. + bool SuppressInitializers : 1; + + /// \brief Whether we should print the sizes of constant array expressions + /// as written in the sources. + /// + /// This flag determines whether array types declared as + /// + /// \code + /// int a[4+10*10]; + /// char a[] = "A string"; + /// \endcode + /// + /// will be printed as written or as follows: + /// + /// \code + /// int a[104]; + /// char a[9] = "A string"; + /// \endcode + bool ConstantArraySizeAsWritten : 1; + + /// \brief When printing an anonymous tag name, also print the location of + /// that entity (e.g., "enum <anonymous at t.h:10:5>"). Otherwise, just + /// prints "(anonymous)" for the name. + bool AnonymousTagLocations : 1; + + /// \brief When true, suppress printing of the __strong lifetime qualifier in + /// ARC. + unsigned SuppressStrongLifetime : 1; + + /// \brief When true, suppress printing of lifetime qualifier in + /// ARC. + unsigned SuppressLifetimeQualifiers : 1; + + /// \brief Whether we can use 'bool' rather than '_Bool', even if the language + /// doesn't actually have 'bool' (because, e.g., it is defined as a macro). + unsigned Bool : 1; + + /// \brief Provide a 'terse' output. + /// + /// For example, in this mode we don't print function bodies, class members, + /// declarations inside namespaces etc. Effectively, this should print + /// only the requested declaration. + unsigned TerseOutput : 1; + + /// \brief When true, do certain refinement needed for producing proper + /// declaration tag; such as, do not print attributes attached to the declaration. + /// + unsigned PolishForDeclaration : 1; + + /// \brief When true, print the half-precision floating-point type as 'half' + /// instead of '__fp16' + unsigned Half : 1; + + /// \brief When true, print the built-in wchar_t type as __wchar_t. For use in + /// Microsoft mode when wchar_t is not available. + unsigned MSWChar : 1; + + /// \brief When true, include newlines after statements like "break", etc. + unsigned IncludeNewlines : 1; + + /// \brief Use whitespace and punctuation like MSVC does. In particular, this + /// prints anonymous namespaces as `anonymous namespace' and does not insert + /// spaces after template arguments. + bool MSVCFormatting : 1; +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/RawCommentList.h b/contrib/llvm/tools/clang/include/clang/AST/RawCommentList.h new file mode 100644 index 0000000..2e005dd --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/RawCommentList.h @@ -0,0 +1,203 @@ +//===--- RawCommentList.h - Classes for processing raw comments -*- 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_AST_RAWCOMMENTLIST_H +#define LLVM_CLANG_AST_RAWCOMMENTLIST_H + +#include "clang/Basic/CommentOptions.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/ADT/ArrayRef.h" + +namespace clang { + +class ASTContext; +class ASTReader; +class Decl; +class Preprocessor; + +namespace comments { + class FullComment; +} // end namespace comments + +class RawComment { +public: + enum CommentKind { + RCK_Invalid, ///< Invalid comment + RCK_OrdinaryBCPL, ///< Any normal BCPL comments + RCK_OrdinaryC, ///< Any normal C comment + RCK_BCPLSlash, ///< \code /// stuff \endcode + RCK_BCPLExcl, ///< \code //! stuff \endcode + RCK_JavaDoc, ///< \code /** stuff */ \endcode + RCK_Qt, ///< \code /*! stuff */ \endcode, also used by HeaderDoc + RCK_Merged ///< Two or more documentation comments merged together + }; + + RawComment() : Kind(RCK_Invalid), IsAlmostTrailingComment(false) { } + + RawComment(const SourceManager &SourceMgr, SourceRange SR, + bool Merged, bool ParseAllComments); + + CommentKind getKind() const LLVM_READONLY { + return (CommentKind) Kind; + } + + bool isInvalid() const LLVM_READONLY { + return Kind == RCK_Invalid; + } + + bool isMerged() const LLVM_READONLY { + return Kind == RCK_Merged; + } + + /// Is this comment attached to any declaration? + bool isAttached() const LLVM_READONLY { + return IsAttached; + } + + void setAttached() { + IsAttached = true; + } + + /// Returns true if it is a comment that should be put after a member: + /// \code ///< stuff \endcode + /// \code //!< stuff \endcode + /// \code /**< stuff */ \endcode + /// \code /*!< stuff */ \endcode + bool isTrailingComment() const LLVM_READONLY { + assert(isDocumentation()); + return IsTrailingComment; + } + + /// Returns true if it is a probable typo: + /// \code //< stuff \endcode + /// \code /*< stuff */ \endcode + bool isAlmostTrailingComment() const LLVM_READONLY { + return IsAlmostTrailingComment; + } + + /// Returns true if this comment is not a documentation comment. + bool isOrdinary() const LLVM_READONLY { + return ((Kind == RCK_OrdinaryBCPL) || (Kind == RCK_OrdinaryC)) && + !ParseAllComments; + } + + /// Returns true if this comment any kind of a documentation comment. + bool isDocumentation() const LLVM_READONLY { + return !isInvalid() && !isOrdinary(); + } + + /// Returns whether we are parsing all comments. + bool isParseAllComments() const LLVM_READONLY { + return ParseAllComments; + } + + /// Returns raw comment text with comment markers. + StringRef getRawText(const SourceManager &SourceMgr) const { + if (RawTextValid) + return RawText; + + RawText = getRawTextSlow(SourceMgr); + RawTextValid = true; + return RawText; + } + + SourceRange getSourceRange() const LLVM_READONLY { return Range; } + SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } + SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } + + const char *getBriefText(const ASTContext &Context) const { + if (BriefTextValid) + return BriefText; + + return extractBriefText(Context); + } + + /// Parse the comment, assuming it is attached to decl \c D. + comments::FullComment *parse(const ASTContext &Context, + const Preprocessor *PP, const Decl *D) const; + +private: + SourceRange Range; + + mutable StringRef RawText; + mutable const char *BriefText; + + mutable bool RawTextValid : 1; ///< True if RawText is valid + mutable bool BriefTextValid : 1; ///< True if BriefText is valid + + unsigned Kind : 3; + + /// True if comment is attached to a declaration in ASTContext. + bool IsAttached : 1; + + bool IsTrailingComment : 1; + bool IsAlmostTrailingComment : 1; + + /// When true, ordinary comments starting with "//" and "/*" will be + /// considered as documentation comments. + bool ParseAllComments : 1; + + /// \brief Constructor for AST deserialization. + RawComment(SourceRange SR, CommentKind K, bool IsTrailingComment, + bool IsAlmostTrailingComment, + bool ParseAllComments) : + Range(SR), RawTextValid(false), BriefTextValid(false), Kind(K), + IsAttached(false), IsTrailingComment(IsTrailingComment), + IsAlmostTrailingComment(IsAlmostTrailingComment), + ParseAllComments(ParseAllComments) + { } + + StringRef getRawTextSlow(const SourceManager &SourceMgr) const; + + const char *extractBriefText(const ASTContext &Context) const; + + friend class ASTReader; +}; + +/// \brief Compare comments' source locations. +template<> +class BeforeThanCompare<RawComment> { + const SourceManager &SM; + +public: + explicit BeforeThanCompare(const SourceManager &SM) : SM(SM) { } + + bool operator()(const RawComment &LHS, const RawComment &RHS) { + return SM.isBeforeInTranslationUnit(LHS.getLocStart(), RHS.getLocStart()); + } + + bool operator()(const RawComment *LHS, const RawComment *RHS) { + return operator()(*LHS, *RHS); + } +}; + +/// \brief This class represents all comments included in the translation unit, +/// sorted in order of appearance in the translation unit. +class RawCommentList { +public: + RawCommentList(SourceManager &SourceMgr) : SourceMgr(SourceMgr) {} + + void addComment(const RawComment &RC, llvm::BumpPtrAllocator &Allocator); + + ArrayRef<RawComment *> getComments() const { + return Comments; + } + +private: + SourceManager &SourceMgr; + std::vector<RawComment *> Comments; + + void addDeserializedComments(ArrayRef<RawComment *> DeserializedComments); + + friend class ASTReader; +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/RecordLayout.h b/contrib/llvm/tools/clang/include/clang/AST/RecordLayout.h new file mode 100644 index 0000000..667f235 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/RecordLayout.h @@ -0,0 +1,315 @@ +//===--- RecordLayout.h - Layout information for a struct/union -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the RecordLayout interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_RECORDLAYOUT_H +#define LLVM_CLANG_AST_RECORDLAYOUT_H + +#include "clang/AST/CharUnits.h" +#include "clang/AST/DeclCXX.h" +#include "llvm/ADT/DenseMap.h" + +namespace clang { + class ASTContext; + class FieldDecl; + class RecordDecl; + class CXXRecordDecl; + +/// ASTRecordLayout - +/// This class contains layout information for one RecordDecl, +/// which is a struct/union/class. The decl represented must be a definition, +/// not a forward declaration. +/// This class is also used to contain layout information for one +/// ObjCInterfaceDecl. FIXME - Find appropriate name. +/// These objects are managed by ASTContext. +class ASTRecordLayout { +public: + struct VBaseInfo { + /// The offset to this virtual base in the complete-object layout + /// of this class. + CharUnits VBaseOffset; + + private: + /// Whether this virtual base requires a vtordisp field in the + /// Microsoft ABI. These fields are required for certain operations + /// in constructors and destructors. + bool HasVtorDisp; + + public: + bool hasVtorDisp() const { return HasVtorDisp; } + + VBaseInfo() : HasVtorDisp(false) {} + + VBaseInfo(CharUnits VBaseOffset, bool hasVtorDisp) : + VBaseOffset(VBaseOffset), HasVtorDisp(hasVtorDisp) {} + }; + + typedef llvm::DenseMap<const CXXRecordDecl *, VBaseInfo> + VBaseOffsetsMapTy; + +private: + /// Size - Size of record in characters. + CharUnits Size; + + /// DataSize - Size of record in characters without tail padding. + CharUnits DataSize; + + // Alignment - Alignment of record in characters. + CharUnits Alignment; + + /// RequiredAlignment - The required alignment of the object. In the MS-ABI + /// the __declspec(align()) trumps #pramga pack and must always be obeyed. + CharUnits RequiredAlignment; + + /// FieldOffsets - Array of field offsets in bits. + uint64_t *FieldOffsets; + + // FieldCount - Number of fields. + unsigned FieldCount; + + /// CXXRecordLayoutInfo - Contains C++ specific layout information. + struct CXXRecordLayoutInfo { + /// NonVirtualSize - The non-virtual size (in chars) of an object, which is + /// the size of the object without virtual bases. + CharUnits NonVirtualSize; + + /// NonVirtualAlignment - The non-virtual alignment (in chars) of an object, + /// which is the alignment of the object without virtual bases. + CharUnits NonVirtualAlignment; + + /// SizeOfLargestEmptySubobject - The size of the largest empty subobject + /// (either a base or a member). Will be zero if the class doesn't contain + /// any empty subobjects. + CharUnits SizeOfLargestEmptySubobject; + + /// VBPtrOffset - Virtual base table offset (Microsoft-only). + CharUnits VBPtrOffset; + + /// HasOwnVFPtr - Does this class provide a virtual function table + /// (vtable in Itanium, vftbl in Microsoft) that is independent from + /// its base classes? + bool HasOwnVFPtr : 1; + + /// HasVFPtr - Does this class have a vftable that could be extended by + /// a derived class. The class may have inherited this pointer from + /// a primary base class. + bool HasExtendableVFPtr : 1; + + /// HasZeroSizedSubObject - True if this class contains a zero sized member + /// or base or a base with a zero sized member or base. Only used for + /// MS-ABI. + bool HasZeroSizedSubObject : 1; + + /// \brief True if this class is zero sized or first base is zero sized or + /// has this property. Only used for MS-ABI. + bool LeadsWithZeroSizedBase : 1; + + /// PrimaryBase - The primary base info for this record. + llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> PrimaryBase; + + /// BaseSharingVBPtr - The base we share vbptr with. + const CXXRecordDecl *BaseSharingVBPtr; + + /// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :) + typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy; + + /// BaseOffsets - Contains a map from base classes to their offset. + BaseOffsetsMapTy BaseOffsets; + + /// VBaseOffsets - Contains a map from vbase classes to their offset. + VBaseOffsetsMapTy VBaseOffsets; + }; + + /// CXXInfo - If the record layout is for a C++ record, this will have + /// C++ specific information about the record. + CXXRecordLayoutInfo *CXXInfo; + + friend class ASTContext; + + ASTRecordLayout(const ASTContext &Ctx, CharUnits size, CharUnits alignment, + CharUnits requiredAlignment, + CharUnits datasize, const uint64_t *fieldoffsets, + unsigned fieldcount); + + // Constructor for C++ records. + typedef CXXRecordLayoutInfo::BaseOffsetsMapTy BaseOffsetsMapTy; + ASTRecordLayout(const ASTContext &Ctx, + CharUnits size, CharUnits alignment, + CharUnits requiredAlignment, + bool hasOwnVFPtr, bool hasExtendableVFPtr, + CharUnits vbptroffset, + CharUnits datasize, + const uint64_t *fieldoffsets, unsigned fieldcount, + CharUnits nonvirtualsize, CharUnits nonvirtualalignment, + CharUnits SizeOfLargestEmptySubobject, + const CXXRecordDecl *PrimaryBase, + bool IsPrimaryBaseVirtual, + const CXXRecordDecl *BaseSharingVBPtr, + bool HasZeroSizedSubObject, + bool LeadsWithZeroSizedBase, + const BaseOffsetsMapTy& BaseOffsets, + const VBaseOffsetsMapTy& VBaseOffsets); + + ~ASTRecordLayout() = default; + + void Destroy(ASTContext &Ctx); + + ASTRecordLayout(const ASTRecordLayout &) = delete; + void operator=(const ASTRecordLayout &) = delete; +public: + + /// getAlignment - Get the record alignment in characters. + CharUnits getAlignment() const { return Alignment; } + + /// getSize - Get the record size in characters. + CharUnits getSize() const { return Size; } + + /// getFieldCount - Get the number of fields in the layout. + unsigned getFieldCount() const { return FieldCount; } + + /// getFieldOffset - Get the offset of the given field index, in + /// bits. + uint64_t getFieldOffset(unsigned FieldNo) const { + assert (FieldNo < FieldCount && "Invalid Field No"); + return FieldOffsets[FieldNo]; + } + + /// getDataSize() - Get the record data size, which is the record size + /// without tail padding, in characters. + CharUnits getDataSize() const { + return DataSize; + } + + /// getNonVirtualSize - Get the non-virtual size (in chars) of an object, + /// which is the size of the object without virtual bases. + CharUnits getNonVirtualSize() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + + return CXXInfo->NonVirtualSize; + } + + /// getNonVirtualSize - Get the non-virtual alignment (in chars) of an object, + /// which is the alignment of the object without virtual bases. + CharUnits getNonVirtualAlignment() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + + return CXXInfo->NonVirtualAlignment; + } + + /// getPrimaryBase - Get the primary base for this record. + const CXXRecordDecl *getPrimaryBase() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + + return CXXInfo->PrimaryBase.getPointer(); + } + + /// isPrimaryBaseVirtual - Get whether the primary base for this record + /// is virtual or not. + bool isPrimaryBaseVirtual() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + + return CXXInfo->PrimaryBase.getInt(); + } + + /// getBaseClassOffset - Get the offset, in chars, for the given base class. + CharUnits getBaseClassOffset(const CXXRecordDecl *Base) const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + assert(CXXInfo->BaseOffsets.count(Base) && "Did not find base!"); + + return CXXInfo->BaseOffsets[Base]; + } + + /// getVBaseClassOffset - Get the offset, in chars, for the given base class. + CharUnits getVBaseClassOffset(const CXXRecordDecl *VBase) const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + assert(CXXInfo->VBaseOffsets.count(VBase) && "Did not find base!"); + + return CXXInfo->VBaseOffsets[VBase].VBaseOffset; + } + + CharUnits getSizeOfLargestEmptySubobject() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + return CXXInfo->SizeOfLargestEmptySubobject; + } + + /// hasOwnVFPtr - Does this class provide its own virtual-function + /// table pointer, rather than inheriting one from a primary base + /// class? If so, it is at offset zero. + /// + /// This implies that the ABI has no primary base class, meaning + /// that it has no base classes that are suitable under the conditions + /// of the ABI. + bool hasOwnVFPtr() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + return CXXInfo->HasOwnVFPtr; + } + + /// hasVFPtr - Does this class have a virtual function table pointer + /// that can be extended by a derived class? This is synonymous with + /// this class having a VFPtr at offset zero. + bool hasExtendableVFPtr() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + return CXXInfo->HasExtendableVFPtr; + } + + /// hasOwnVBPtr - Does this class provide its own virtual-base + /// table pointer, rather than inheriting one from a primary base + /// class? + /// + /// This implies that the ABI has no primary base class, meaning + /// that it has no base classes that are suitable under the conditions + /// of the ABI. + bool hasOwnVBPtr() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + return hasVBPtr() && !CXXInfo->BaseSharingVBPtr; + } + + /// hasVBPtr - Does this class have a virtual function table pointer. + bool hasVBPtr() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + return !CXXInfo->VBPtrOffset.isNegative(); + } + + CharUnits getRequiredAlignment() const { + return RequiredAlignment; + } + + bool hasZeroSizedSubObject() const { + return CXXInfo && CXXInfo->HasZeroSizedSubObject; + } + + bool leadsWithZeroSizedBase() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + return CXXInfo->LeadsWithZeroSizedBase; + } + + /// getVBPtrOffset - Get the offset for virtual base table pointer. + /// This is only meaningful with the Microsoft ABI. + CharUnits getVBPtrOffset() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + return CXXInfo->VBPtrOffset; + } + + const CXXRecordDecl *getBaseSharingVBPtr() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + return CXXInfo->BaseSharingVBPtr; + } + + const VBaseOffsetsMapTy &getVBaseOffsetsMap() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + return CXXInfo->VBaseOffsets; + } +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/RecursiveASTVisitor.h b/contrib/llvm/tools/clang/include/clang/AST/RecursiveASTVisitor.h new file mode 100644 index 0000000..e6f7583 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/RecursiveASTVisitor.h @@ -0,0 +1,2805 @@ +//===--- RecursiveASTVisitor.h - Recursive AST Visitor ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the RecursiveASTVisitor interface, which recursively +// traverses the entire AST. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_RECURSIVEASTVISITOR_H +#define LLVM_CLANG_AST_RECURSIVEASTVISITOR_H + +#include <type_traits> + +#include "clang/AST/Attr.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclFriend.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclOpenMP.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/ExprOpenMP.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/StmtCXX.h" +#include "clang/AST/StmtObjC.h" +#include "clang/AST/StmtOpenMP.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/TemplateName.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" + +// The following three macros are used for meta programming. The code +// using them is responsible for defining macro OPERATOR(). + +// All unary operators. +#define UNARYOP_LIST() \ + OPERATOR(PostInc) OPERATOR(PostDec) OPERATOR(PreInc) OPERATOR(PreDec) \ + OPERATOR(AddrOf) OPERATOR(Deref) OPERATOR(Plus) OPERATOR(Minus) \ + OPERATOR(Not) OPERATOR(LNot) OPERATOR(Real) OPERATOR(Imag) \ + OPERATOR(Extension) OPERATOR(Coawait) + +// All binary operators (excluding compound assign operators). +#define BINOP_LIST() \ + OPERATOR(PtrMemD) OPERATOR(PtrMemI) OPERATOR(Mul) OPERATOR(Div) \ + OPERATOR(Rem) OPERATOR(Add) OPERATOR(Sub) OPERATOR(Shl) OPERATOR(Shr) \ + OPERATOR(LT) OPERATOR(GT) OPERATOR(LE) OPERATOR(GE) OPERATOR(EQ) \ + OPERATOR(NE) OPERATOR(And) OPERATOR(Xor) OPERATOR(Or) OPERATOR(LAnd) \ + OPERATOR(LOr) OPERATOR(Assign) OPERATOR(Comma) + +// All compound assign operators. +#define CAO_LIST() \ + OPERATOR(Mul) OPERATOR(Div) OPERATOR(Rem) OPERATOR(Add) OPERATOR(Sub) \ + OPERATOR(Shl) OPERATOR(Shr) OPERATOR(And) OPERATOR(Or) OPERATOR(Xor) + +namespace clang { + +// A helper macro to implement short-circuiting when recursing. It +// invokes CALL_EXPR, which must be a method call, on the derived +// object (s.t. a user of RecursiveASTVisitor can override the method +// in CALL_EXPR). +#define TRY_TO(CALL_EXPR) \ + do { \ + if (!getDerived().CALL_EXPR) \ + return false; \ + } while (0) + +/// \brief A class that does preorder depth-first traversal on the +/// entire Clang AST and visits each node. +/// +/// This class performs three distinct tasks: +/// 1. traverse the AST (i.e. go to each node); +/// 2. at a given node, walk up the class hierarchy, starting from +/// the node's dynamic type, until the top-most class (e.g. Stmt, +/// Decl, or Type) is reached. +/// 3. given a (node, class) combination, where 'class' is some base +/// class of the dynamic type of 'node', call a user-overridable +/// function to actually visit the node. +/// +/// These tasks are done by three groups of methods, respectively: +/// 1. TraverseDecl(Decl *x) does task #1. It is the entry point +/// for traversing an AST rooted at x. This method simply +/// dispatches (i.e. forwards) to TraverseFoo(Foo *x) where Foo +/// is the dynamic type of *x, which calls WalkUpFromFoo(x) and +/// then recursively visits the child nodes of x. +/// TraverseStmt(Stmt *x) and TraverseType(QualType x) work +/// similarly. +/// 2. WalkUpFromFoo(Foo *x) does task #2. It does not try to visit +/// any child node of x. Instead, it first calls WalkUpFromBar(x) +/// where Bar is the direct parent class of Foo (unless Foo has +/// no parent), and then calls VisitFoo(x) (see the next list item). +/// 3. VisitFoo(Foo *x) does task #3. +/// +/// These three method groups are tiered (Traverse* > WalkUpFrom* > +/// Visit*). A method (e.g. Traverse*) may call methods from the same +/// tier (e.g. other Traverse*) or one tier lower (e.g. WalkUpFrom*). +/// It may not call methods from a higher tier. +/// +/// Note that since WalkUpFromFoo() calls WalkUpFromBar() (where Bar +/// is Foo's super class) before calling VisitFoo(), the result is +/// that the Visit*() methods for a given node are called in the +/// top-down order (e.g. for a node of type NamespaceDecl, the order will +/// be VisitDecl(), VisitNamedDecl(), and then VisitNamespaceDecl()). +/// +/// This scheme guarantees that all Visit*() calls for the same AST +/// node are grouped together. In other words, Visit*() methods for +/// different nodes are never interleaved. +/// +/// Clients of this visitor should subclass the visitor (providing +/// themselves as the template argument, using the curiously recurring +/// template pattern) and override any of the Traverse*, WalkUpFrom*, +/// and Visit* methods for declarations, types, statements, +/// expressions, or other AST nodes where the visitor should customize +/// behavior. Most users only need to override Visit*. Advanced +/// users may override Traverse* and WalkUpFrom* to implement custom +/// traversal strategies. Returning false from one of these overridden +/// functions will abort the entire traversal. +/// +/// By default, this visitor tries to visit every part of the explicit +/// source code exactly once. The default policy towards templates +/// is to descend into the 'pattern' class or function body, not any +/// explicit or implicit instantiations. Explicit specializations +/// are still visited, and the patterns of partial specializations +/// are visited separately. This behavior can be changed by +/// overriding shouldVisitTemplateInstantiations() in the derived class +/// to return true, in which case all known implicit and explicit +/// instantiations will be visited at the same time as the pattern +/// from which they were produced. +template <typename Derived> class RecursiveASTVisitor { +public: + /// A queue used for performing data recursion over statements. + /// Parameters involving this type are used to implement data + /// recursion over Stmts and Exprs within this class, and should + /// typically not be explicitly specified by derived classes. + typedef SmallVectorImpl<Stmt *> DataRecursionQueue; + + /// \brief Return a reference to the derived class. + Derived &getDerived() { return *static_cast<Derived *>(this); } + + /// \brief Return whether this visitor should recurse into + /// template instantiations. + bool shouldVisitTemplateInstantiations() const { return false; } + + /// \brief Return whether this visitor should recurse into the types of + /// TypeLocs. + bool shouldWalkTypesOfTypeLocs() const { return true; } + + /// \brief Return whether this visitor should recurse into implicit + /// code, e.g., implicit constructors and destructors. + bool shouldVisitImplicitCode() const { return false; } + + /// \brief Recursively visit a statement or expression, by + /// dispatching to Traverse*() based on the argument's dynamic type. + /// + /// \returns false if the visitation was terminated early, true + /// otherwise (including when the argument is nullptr). + bool TraverseStmt(Stmt *S, DataRecursionQueue *Queue = nullptr); + + /// \brief Recursively visit a type, by dispatching to + /// Traverse*Type() based on the argument's getTypeClass() property. + /// + /// \returns false if the visitation was terminated early, true + /// otherwise (including when the argument is a Null type). + bool TraverseType(QualType T); + + /// \brief Recursively visit a type with location, by dispatching to + /// Traverse*TypeLoc() based on the argument type's getTypeClass() property. + /// + /// \returns false if the visitation was terminated early, true + /// otherwise (including when the argument is a Null type location). + bool TraverseTypeLoc(TypeLoc TL); + + /// \brief Recursively visit an attribute, by dispatching to + /// Traverse*Attr() based on the argument's dynamic type. + /// + /// \returns false if the visitation was terminated early, true + /// otherwise (including when the argument is a Null type location). + bool TraverseAttr(Attr *At); + + /// \brief Recursively visit a declaration, by dispatching to + /// Traverse*Decl() based on the argument's dynamic type. + /// + /// \returns false if the visitation was terminated early, true + /// otherwise (including when the argument is NULL). + bool TraverseDecl(Decl *D); + + /// \brief Recursively visit a C++ nested-name-specifier. + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS); + + /// \brief Recursively visit a C++ nested-name-specifier with location + /// information. + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS); + + /// \brief Recursively visit a name with its location information. + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo); + + /// \brief Recursively visit a template name and dispatch to the + /// appropriate method. + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool TraverseTemplateName(TemplateName Template); + + /// \brief Recursively visit a template argument and dispatch to the + /// appropriate method for the argument type. + /// + /// \returns false if the visitation was terminated early, true otherwise. + // FIXME: migrate callers to TemplateArgumentLoc instead. + bool TraverseTemplateArgument(const TemplateArgument &Arg); + + /// \brief Recursively visit a template argument location and dispatch to the + /// appropriate method for the argument type. + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc); + + /// \brief Recursively visit a set of template arguments. + /// This can be overridden by a subclass, but it's not expected that + /// will be needed -- this visitor always dispatches to another. + /// + /// \returns false if the visitation was terminated early, true otherwise. + // FIXME: take a TemplateArgumentLoc* (or TemplateArgumentListInfo) instead. + bool TraverseTemplateArguments(const TemplateArgument *Args, + unsigned NumArgs); + + /// \brief Recursively visit a constructor initializer. This + /// automatically dispatches to another visitor for the initializer + /// expression, but not for the name of the initializer, so may + /// be overridden for clients that need access to the name. + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool TraverseConstructorInitializer(CXXCtorInitializer *Init); + + /// \brief Recursively visit a lambda capture. + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C); + + /// \brief Recursively visit the body of a lambda expression. + /// + /// This provides a hook for visitors that need more context when visiting + /// \c LE->getBody(). + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool TraverseLambdaBody(LambdaExpr *LE, DataRecursionQueue *Queue = nullptr); + + /// \brief Recursively visit the syntactic or semantic form of an + /// initialization list. + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool TraverseSynOrSemInitListExpr(InitListExpr *S, + DataRecursionQueue *Queue = nullptr); + + // ---- Methods on Attrs ---- + + // \brief Visit an attribute. + bool VisitAttr(Attr *A) { return true; } + +// Declare Traverse* and empty Visit* for all Attr classes. +#define ATTR_VISITOR_DECLS_ONLY +#include "clang/AST/AttrVisitor.inc" +#undef ATTR_VISITOR_DECLS_ONLY + +// ---- Methods on Stmts ---- + +private: + template<typename T, typename U> + struct has_same_member_pointer_type : std::false_type {}; + template<typename T, typename U, typename R, typename... P> + struct has_same_member_pointer_type<R (T::*)(P...), R (U::*)(P...)> + : std::true_type {}; + + // Traverse the given statement. If the most-derived traverse function takes a + // data recursion queue, pass it on; otherwise, discard it. Note that the + // first branch of this conditional must compile whether or not the derived + // class can take a queue, so if we're taking the second arm, make the first + // arm call our function rather than the derived class version. +#define TRAVERSE_STMT_BASE(NAME, CLASS, VAR, QUEUE) \ + (has_same_member_pointer_type<decltype( \ + &RecursiveASTVisitor::Traverse##NAME), \ + decltype(&Derived::Traverse##NAME)>::value \ + ? static_cast<typename std::conditional< \ + has_same_member_pointer_type< \ + decltype(&RecursiveASTVisitor::Traverse##NAME), \ + decltype(&Derived::Traverse##NAME)>::value, \ + Derived &, RecursiveASTVisitor &>::type>(*this) \ + .Traverse##NAME(static_cast<CLASS *>(VAR), QUEUE) \ + : getDerived().Traverse##NAME(static_cast<CLASS *>(VAR))) + +// Try to traverse the given statement, or enqueue it if we're performing data +// recursion in the middle of traversing another statement. Can only be called +// from within a DEF_TRAVERSE_STMT body or similar context. +#define TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S) \ + do { \ + if (!TRAVERSE_STMT_BASE(Stmt, Stmt, S, Queue)) \ + return false; \ + } while (0) + +public: +// Declare Traverse*() for all concrete Stmt classes. +#define ABSTRACT_STMT(STMT) +#define STMT(CLASS, PARENT) \ + bool Traverse##CLASS(CLASS *S, DataRecursionQueue *Queue = nullptr); +#include "clang/AST/StmtNodes.inc" + // The above header #undefs ABSTRACT_STMT and STMT upon exit. + + // Define WalkUpFrom*() and empty Visit*() for all Stmt classes. + bool WalkUpFromStmt(Stmt *S) { return getDerived().VisitStmt(S); } + bool VisitStmt(Stmt *S) { return true; } +#define STMT(CLASS, PARENT) \ + bool WalkUpFrom##CLASS(CLASS *S) { \ + TRY_TO(WalkUpFrom##PARENT(S)); \ + TRY_TO(Visit##CLASS(S)); \ + return true; \ + } \ + bool Visit##CLASS(CLASS *S) { return true; } +#include "clang/AST/StmtNodes.inc" + +// Define Traverse*(), WalkUpFrom*(), and Visit*() for unary +// operator methods. Unary operators are not classes in themselves +// (they're all opcodes in UnaryOperator) but do have visitors. +#define OPERATOR(NAME) \ + bool TraverseUnary##NAME(UnaryOperator *S, \ + DataRecursionQueue *Queue = nullptr) { \ + TRY_TO(WalkUpFromUnary##NAME(S)); \ + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getSubExpr()); \ + return true; \ + } \ + bool WalkUpFromUnary##NAME(UnaryOperator *S) { \ + TRY_TO(WalkUpFromUnaryOperator(S)); \ + TRY_TO(VisitUnary##NAME(S)); \ + return true; \ + } \ + bool VisitUnary##NAME(UnaryOperator *S) { return true; } + + UNARYOP_LIST() +#undef OPERATOR + +// Define Traverse*(), WalkUpFrom*(), and Visit*() for binary +// operator methods. Binary operators are not classes in themselves +// (they're all opcodes in BinaryOperator) but do have visitors. +#define GENERAL_BINOP_FALLBACK(NAME, BINOP_TYPE) \ + bool TraverseBin##NAME(BINOP_TYPE *S, DataRecursionQueue *Queue = nullptr) { \ + TRY_TO(WalkUpFromBin##NAME(S)); \ + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getLHS()); \ + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getRHS()); \ + return true; \ + } \ + bool WalkUpFromBin##NAME(BINOP_TYPE *S) { \ + TRY_TO(WalkUpFrom##BINOP_TYPE(S)); \ + TRY_TO(VisitBin##NAME(S)); \ + return true; \ + } \ + bool VisitBin##NAME(BINOP_TYPE *S) { return true; } + +#define OPERATOR(NAME) GENERAL_BINOP_FALLBACK(NAME, BinaryOperator) + BINOP_LIST() +#undef OPERATOR + +// Define Traverse*(), WalkUpFrom*(), and Visit*() for compound +// assignment methods. Compound assignment operators are not +// classes in themselves (they're all opcodes in +// CompoundAssignOperator) but do have visitors. +#define OPERATOR(NAME) \ + GENERAL_BINOP_FALLBACK(NAME##Assign, CompoundAssignOperator) + + CAO_LIST() +#undef OPERATOR +#undef GENERAL_BINOP_FALLBACK + +// ---- Methods on Types ---- +// FIXME: revamp to take TypeLoc's rather than Types. + +// Declare Traverse*() for all concrete Type classes. +#define ABSTRACT_TYPE(CLASS, BASE) +#define TYPE(CLASS, BASE) bool Traverse##CLASS##Type(CLASS##Type *T); +#include "clang/AST/TypeNodes.def" + // The above header #undefs ABSTRACT_TYPE and TYPE upon exit. + + // Define WalkUpFrom*() and empty Visit*() for all Type classes. + bool WalkUpFromType(Type *T) { return getDerived().VisitType(T); } + bool VisitType(Type *T) { return true; } +#define TYPE(CLASS, BASE) \ + bool WalkUpFrom##CLASS##Type(CLASS##Type *T) { \ + TRY_TO(WalkUpFrom##BASE(T)); \ + TRY_TO(Visit##CLASS##Type(T)); \ + return true; \ + } \ + bool Visit##CLASS##Type(CLASS##Type *T) { return true; } +#include "clang/AST/TypeNodes.def" + +// ---- Methods on TypeLocs ---- +// FIXME: this currently just calls the matching Type methods + +// Declare Traverse*() for all concrete TypeLoc classes. +#define ABSTRACT_TYPELOC(CLASS, BASE) +#define TYPELOC(CLASS, BASE) bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL); +#include "clang/AST/TypeLocNodes.def" + // The above header #undefs ABSTRACT_TYPELOC and TYPELOC upon exit. + + // Define WalkUpFrom*() and empty Visit*() for all TypeLoc classes. + bool WalkUpFromTypeLoc(TypeLoc TL) { return getDerived().VisitTypeLoc(TL); } + bool VisitTypeLoc(TypeLoc TL) { return true; } + + // QualifiedTypeLoc and UnqualTypeLoc are not declared in + // TypeNodes.def and thus need to be handled specially. + bool WalkUpFromQualifiedTypeLoc(QualifiedTypeLoc TL) { + return getDerived().VisitUnqualTypeLoc(TL.getUnqualifiedLoc()); + } + bool VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { return true; } + bool WalkUpFromUnqualTypeLoc(UnqualTypeLoc TL) { + return getDerived().VisitUnqualTypeLoc(TL.getUnqualifiedLoc()); + } + bool VisitUnqualTypeLoc(UnqualTypeLoc TL) { return true; } + +// Note that BASE includes trailing 'Type' which CLASS doesn't. +#define TYPE(CLASS, BASE) \ + bool WalkUpFrom##CLASS##TypeLoc(CLASS##TypeLoc TL) { \ + TRY_TO(WalkUpFrom##BASE##Loc(TL)); \ + TRY_TO(Visit##CLASS##TypeLoc(TL)); \ + return true; \ + } \ + bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TL) { return true; } +#include "clang/AST/TypeNodes.def" + +// ---- Methods on Decls ---- + +// Declare Traverse*() for all concrete Decl classes. +#define ABSTRACT_DECL(DECL) +#define DECL(CLASS, BASE) bool Traverse##CLASS##Decl(CLASS##Decl *D); +#include "clang/AST/DeclNodes.inc" + // The above header #undefs ABSTRACT_DECL and DECL upon exit. + + // Define WalkUpFrom*() and empty Visit*() for all Decl classes. + bool WalkUpFromDecl(Decl *D) { return getDerived().VisitDecl(D); } + bool VisitDecl(Decl *D) { return true; } +#define DECL(CLASS, BASE) \ + bool WalkUpFrom##CLASS##Decl(CLASS##Decl *D) { \ + TRY_TO(WalkUpFrom##BASE(D)); \ + TRY_TO(Visit##CLASS##Decl(D)); \ + return true; \ + } \ + bool Visit##CLASS##Decl(CLASS##Decl *D) { return true; } +#include "clang/AST/DeclNodes.inc" + +private: + // These are helper methods used by more than one Traverse* method. + bool TraverseTemplateParameterListHelper(TemplateParameterList *TPL); +#define DEF_TRAVERSE_TMPL_INST(TMPLDECLKIND) \ + bool TraverseTemplateInstantiations(TMPLDECLKIND##TemplateDecl *D); + DEF_TRAVERSE_TMPL_INST(Class) + DEF_TRAVERSE_TMPL_INST(Var) + DEF_TRAVERSE_TMPL_INST(Function) +#undef DEF_TRAVERSE_TMPL_INST + bool TraverseTemplateArgumentLocsHelper(const TemplateArgumentLoc *TAL, + unsigned Count); + bool TraverseArrayTypeLocHelper(ArrayTypeLoc TL); + bool TraverseRecordHelper(RecordDecl *D); + bool TraverseCXXRecordHelper(CXXRecordDecl *D); + bool TraverseDeclaratorHelper(DeclaratorDecl *D); + bool TraverseDeclContextHelper(DeclContext *DC); + bool TraverseFunctionHelper(FunctionDecl *D); + bool TraverseVarHelper(VarDecl *D); + bool TraverseOMPExecutableDirective(OMPExecutableDirective *S); + bool TraverseOMPLoopDirective(OMPLoopDirective *S); + bool TraverseOMPClause(OMPClause *C); +#define OPENMP_CLAUSE(Name, Class) bool Visit##Class(Class *C); +#include "clang/Basic/OpenMPKinds.def" + /// \brief Process clauses with list of variables. + template <typename T> bool VisitOMPClauseList(T *Node); + + bool dataTraverseNode(Stmt *S, DataRecursionQueue *Queue); +}; + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::dataTraverseNode(Stmt *S, + DataRecursionQueue *Queue) { +#define DISPATCH_STMT(NAME, CLASS, VAR) \ + return TRAVERSE_STMT_BASE(NAME, CLASS, VAR, Queue); + + // If we have a binary expr, dispatch to the subcode of the binop. A smart + // optimizer (e.g. LLVM) will fold this comparison into the switch stmt + // below. + if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(S)) { + switch (BinOp->getOpcode()) { +#define OPERATOR(NAME) \ + case BO_##NAME: \ + DISPATCH_STMT(Bin##NAME, BinaryOperator, S); + + BINOP_LIST() +#undef OPERATOR +#undef BINOP_LIST + +#define OPERATOR(NAME) \ + case BO_##NAME##Assign: \ + DISPATCH_STMT(Bin##NAME##Assign, CompoundAssignOperator, S); + + CAO_LIST() +#undef OPERATOR +#undef CAO_LIST + } + } else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(S)) { + switch (UnOp->getOpcode()) { +#define OPERATOR(NAME) \ + case UO_##NAME: \ + DISPATCH_STMT(Unary##NAME, UnaryOperator, S); + + UNARYOP_LIST() +#undef OPERATOR +#undef UNARYOP_LIST + } + } + + // Top switch stmt: dispatch to TraverseFooStmt for each concrete FooStmt. + switch (S->getStmtClass()) { + case Stmt::NoStmtClass: + break; +#define ABSTRACT_STMT(STMT) +#define STMT(CLASS, PARENT) \ + case Stmt::CLASS##Class: \ + DISPATCH_STMT(CLASS, CLASS, S); +#include "clang/AST/StmtNodes.inc" + } + + return true; +} + +#undef DISPATCH_STMT + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseStmt(Stmt *S, + DataRecursionQueue *Queue) { + if (!S) + return true; + + if (Queue) { + Queue->push_back(S); + return true; + } + + SmallVector<Stmt *, 8> LocalQueue; + LocalQueue.push_back(S); + + while (!LocalQueue.empty()) { + Stmt *CurrS = LocalQueue.pop_back_val(); + + size_t N = LocalQueue.size(); + TRY_TO(dataTraverseNode(CurrS, &LocalQueue)); + // Process new children in the order they were added. + std::reverse(LocalQueue.begin() + N, LocalQueue.end()); + } + + return true; +} + +#define DISPATCH(NAME, CLASS, VAR) \ + return getDerived().Traverse##NAME(static_cast<CLASS *>(VAR)) + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseType(QualType T) { + if (T.isNull()) + return true; + + switch (T->getTypeClass()) { +#define ABSTRACT_TYPE(CLASS, BASE) +#define TYPE(CLASS, BASE) \ + case Type::CLASS: \ + DISPATCH(CLASS##Type, CLASS##Type, const_cast<Type *>(T.getTypePtr())); +#include "clang/AST/TypeNodes.def" + } + + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseTypeLoc(TypeLoc TL) { + if (TL.isNull()) + return true; + + switch (TL.getTypeLocClass()) { +#define ABSTRACT_TYPELOC(CLASS, BASE) +#define TYPELOC(CLASS, BASE) \ + case TypeLoc::CLASS: \ + return getDerived().Traverse##CLASS##TypeLoc(TL.castAs<CLASS##TypeLoc>()); +#include "clang/AST/TypeLocNodes.def" + } + + return true; +} + +// Define the Traverse*Attr(Attr* A) methods +#define VISITORCLASS RecursiveASTVisitor +#include "clang/AST/AttrVisitor.inc" +#undef VISITORCLASS + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseDecl(Decl *D) { + if (!D) + return true; + + // As a syntax visitor, by default we want to ignore declarations for + // implicit declarations (ones not typed explicitly by the user). + if (!getDerived().shouldVisitImplicitCode() && D->isImplicit()) + return true; + + switch (D->getKind()) { +#define ABSTRACT_DECL(DECL) +#define DECL(CLASS, BASE) \ + case Decl::CLASS: \ + if (!getDerived().Traverse##CLASS##Decl(static_cast<CLASS##Decl *>(D))) \ + return false; \ + break; +#include "clang/AST/DeclNodes.inc" + } + + // Visit any attributes attached to this declaration. + for (auto *I : D->attrs()) { + if (!getDerived().TraverseAttr(I)) + return false; + } + return true; +} + +#undef DISPATCH + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseNestedNameSpecifier( + NestedNameSpecifier *NNS) { + if (!NNS) + return true; + + if (NNS->getPrefix()) + TRY_TO(TraverseNestedNameSpecifier(NNS->getPrefix())); + + switch (NNS->getKind()) { + case NestedNameSpecifier::Identifier: + case NestedNameSpecifier::Namespace: + case NestedNameSpecifier::NamespaceAlias: + case NestedNameSpecifier::Global: + case NestedNameSpecifier::Super: + return true; + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + TRY_TO(TraverseType(QualType(NNS->getAsType(), 0))); + } + + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseNestedNameSpecifierLoc( + NestedNameSpecifierLoc NNS) { + if (!NNS) + return true; + + if (NestedNameSpecifierLoc Prefix = NNS.getPrefix()) + TRY_TO(TraverseNestedNameSpecifierLoc(Prefix)); + + switch (NNS.getNestedNameSpecifier()->getKind()) { + case NestedNameSpecifier::Identifier: + case NestedNameSpecifier::Namespace: + case NestedNameSpecifier::NamespaceAlias: + case NestedNameSpecifier::Global: + case NestedNameSpecifier::Super: + return true; + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + TRY_TO(TraverseTypeLoc(NNS.getTypeLoc())); + break; + } + + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseDeclarationNameInfo( + DeclarationNameInfo NameInfo) { + switch (NameInfo.getName().getNameKind()) { + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + if (TypeSourceInfo *TSInfo = NameInfo.getNamedTypeInfo()) + TRY_TO(TraverseTypeLoc(TSInfo->getTypeLoc())); + + break; + + case DeclarationName::Identifier: + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + case DeclarationName::CXXOperatorName: + case DeclarationName::CXXLiteralOperatorName: + case DeclarationName::CXXUsingDirective: + break; + } + + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseTemplateName(TemplateName Template) { + if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) + TRY_TO(TraverseNestedNameSpecifier(DTN->getQualifier())); + else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) + TRY_TO(TraverseNestedNameSpecifier(QTN->getQualifier())); + + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseTemplateArgument( + const TemplateArgument &Arg) { + switch (Arg.getKind()) { + case TemplateArgument::Null: + case TemplateArgument::Declaration: + case TemplateArgument::Integral: + case TemplateArgument::NullPtr: + return true; + + case TemplateArgument::Type: + return getDerived().TraverseType(Arg.getAsType()); + + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: + return getDerived().TraverseTemplateName( + Arg.getAsTemplateOrTemplatePattern()); + + case TemplateArgument::Expression: + return getDerived().TraverseStmt(Arg.getAsExpr()); + + case TemplateArgument::Pack: + return getDerived().TraverseTemplateArguments(Arg.pack_begin(), + Arg.pack_size()); + } + + return true; +} + +// FIXME: no template name location? +// FIXME: no source locations for a template argument pack? +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLoc( + const TemplateArgumentLoc &ArgLoc) { + const TemplateArgument &Arg = ArgLoc.getArgument(); + + switch (Arg.getKind()) { + case TemplateArgument::Null: + case TemplateArgument::Declaration: + case TemplateArgument::Integral: + case TemplateArgument::NullPtr: + return true; + + case TemplateArgument::Type: { + // FIXME: how can TSI ever be NULL? + if (TypeSourceInfo *TSI = ArgLoc.getTypeSourceInfo()) + return getDerived().TraverseTypeLoc(TSI->getTypeLoc()); + else + return getDerived().TraverseType(Arg.getAsType()); + } + + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: + if (ArgLoc.getTemplateQualifierLoc()) + TRY_TO(getDerived().TraverseNestedNameSpecifierLoc( + ArgLoc.getTemplateQualifierLoc())); + return getDerived().TraverseTemplateName( + Arg.getAsTemplateOrTemplatePattern()); + + case TemplateArgument::Expression: + return getDerived().TraverseStmt(ArgLoc.getSourceExpression()); + + case TemplateArgument::Pack: + return getDerived().TraverseTemplateArguments(Arg.pack_begin(), + Arg.pack_size()); + } + + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseTemplateArguments( + const TemplateArgument *Args, unsigned NumArgs) { + for (unsigned I = 0; I != NumArgs; ++I) { + TRY_TO(TraverseTemplateArgument(Args[I])); + } + + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseConstructorInitializer( + CXXCtorInitializer *Init) { + if (TypeSourceInfo *TInfo = Init->getTypeSourceInfo()) + TRY_TO(TraverseTypeLoc(TInfo->getTypeLoc())); + + if (Init->isWritten() || getDerived().shouldVisitImplicitCode()) + TRY_TO(TraverseStmt(Init->getInit())); + return true; +} + +template <typename Derived> +bool +RecursiveASTVisitor<Derived>::TraverseLambdaCapture(LambdaExpr *LE, + const LambdaCapture *C) { + if (LE->isInitCapture(C)) + TRY_TO(TraverseDecl(C->getCapturedVar())); + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseLambdaBody( + LambdaExpr *LE, DataRecursionQueue *Queue) { + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(LE->getBody()); + return true; +} + +// ----------------- Type traversal ----------------- + +// This macro makes available a variable T, the passed-in type. +#define DEF_TRAVERSE_TYPE(TYPE, CODE) \ + template <typename Derived> \ + bool RecursiveASTVisitor<Derived>::Traverse##TYPE(TYPE *T) { \ + TRY_TO(WalkUpFrom##TYPE(T)); \ + { CODE; } \ + return true; \ + } + +DEF_TRAVERSE_TYPE(BuiltinType, {}) + +DEF_TRAVERSE_TYPE(ComplexType, { TRY_TO(TraverseType(T->getElementType())); }) + +DEF_TRAVERSE_TYPE(PointerType, { TRY_TO(TraverseType(T->getPointeeType())); }) + +DEF_TRAVERSE_TYPE(BlockPointerType, + { TRY_TO(TraverseType(T->getPointeeType())); }) + +DEF_TRAVERSE_TYPE(LValueReferenceType, + { TRY_TO(TraverseType(T->getPointeeType())); }) + +DEF_TRAVERSE_TYPE(RValueReferenceType, + { TRY_TO(TraverseType(T->getPointeeType())); }) + +DEF_TRAVERSE_TYPE(MemberPointerType, { + TRY_TO(TraverseType(QualType(T->getClass(), 0))); + TRY_TO(TraverseType(T->getPointeeType())); +}) + +DEF_TRAVERSE_TYPE(AdjustedType, { TRY_TO(TraverseType(T->getOriginalType())); }) + +DEF_TRAVERSE_TYPE(DecayedType, { TRY_TO(TraverseType(T->getOriginalType())); }) + +DEF_TRAVERSE_TYPE(ConstantArrayType, + { TRY_TO(TraverseType(T->getElementType())); }) + +DEF_TRAVERSE_TYPE(IncompleteArrayType, + { TRY_TO(TraverseType(T->getElementType())); }) + +DEF_TRAVERSE_TYPE(VariableArrayType, { + TRY_TO(TraverseType(T->getElementType())); + TRY_TO(TraverseStmt(T->getSizeExpr())); +}) + +DEF_TRAVERSE_TYPE(DependentSizedArrayType, { + TRY_TO(TraverseType(T->getElementType())); + if (T->getSizeExpr()) + TRY_TO(TraverseStmt(T->getSizeExpr())); +}) + +DEF_TRAVERSE_TYPE(DependentSizedExtVectorType, { + if (T->getSizeExpr()) + TRY_TO(TraverseStmt(T->getSizeExpr())); + TRY_TO(TraverseType(T->getElementType())); +}) + +DEF_TRAVERSE_TYPE(VectorType, { TRY_TO(TraverseType(T->getElementType())); }) + +DEF_TRAVERSE_TYPE(ExtVectorType, { TRY_TO(TraverseType(T->getElementType())); }) + +DEF_TRAVERSE_TYPE(FunctionNoProtoType, + { TRY_TO(TraverseType(T->getReturnType())); }) + +DEF_TRAVERSE_TYPE(FunctionProtoType, { + TRY_TO(TraverseType(T->getReturnType())); + + for (const auto &A : T->param_types()) { + TRY_TO(TraverseType(A)); + } + + for (const auto &E : T->exceptions()) { + TRY_TO(TraverseType(E)); + } + + if (Expr *NE = T->getNoexceptExpr()) + TRY_TO(TraverseStmt(NE)); +}) + +DEF_TRAVERSE_TYPE(UnresolvedUsingType, {}) +DEF_TRAVERSE_TYPE(TypedefType, {}) + +DEF_TRAVERSE_TYPE(TypeOfExprType, + { TRY_TO(TraverseStmt(T->getUnderlyingExpr())); }) + +DEF_TRAVERSE_TYPE(TypeOfType, { TRY_TO(TraverseType(T->getUnderlyingType())); }) + +DEF_TRAVERSE_TYPE(DecltypeType, + { TRY_TO(TraverseStmt(T->getUnderlyingExpr())); }) + +DEF_TRAVERSE_TYPE(UnaryTransformType, { + TRY_TO(TraverseType(T->getBaseType())); + TRY_TO(TraverseType(T->getUnderlyingType())); +}) + +DEF_TRAVERSE_TYPE(AutoType, { TRY_TO(TraverseType(T->getDeducedType())); }) + +DEF_TRAVERSE_TYPE(RecordType, {}) +DEF_TRAVERSE_TYPE(EnumType, {}) +DEF_TRAVERSE_TYPE(TemplateTypeParmType, {}) +DEF_TRAVERSE_TYPE(SubstTemplateTypeParmType, {}) +DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType, {}) + +DEF_TRAVERSE_TYPE(TemplateSpecializationType, { + TRY_TO(TraverseTemplateName(T->getTemplateName())); + TRY_TO(TraverseTemplateArguments(T->getArgs(), T->getNumArgs())); +}) + +DEF_TRAVERSE_TYPE(InjectedClassNameType, {}) + +DEF_TRAVERSE_TYPE(AttributedType, + { TRY_TO(TraverseType(T->getModifiedType())); }) + +DEF_TRAVERSE_TYPE(ParenType, { TRY_TO(TraverseType(T->getInnerType())); }) + +DEF_TRAVERSE_TYPE(ElaboratedType, { + if (T->getQualifier()) { + TRY_TO(TraverseNestedNameSpecifier(T->getQualifier())); + } + TRY_TO(TraverseType(T->getNamedType())); +}) + +DEF_TRAVERSE_TYPE(DependentNameType, + { TRY_TO(TraverseNestedNameSpecifier(T->getQualifier())); }) + +DEF_TRAVERSE_TYPE(DependentTemplateSpecializationType, { + TRY_TO(TraverseNestedNameSpecifier(T->getQualifier())); + TRY_TO(TraverseTemplateArguments(T->getArgs(), T->getNumArgs())); +}) + +DEF_TRAVERSE_TYPE(PackExpansionType, { TRY_TO(TraverseType(T->getPattern())); }) + +DEF_TRAVERSE_TYPE(ObjCInterfaceType, {}) + +DEF_TRAVERSE_TYPE(ObjCObjectType, { + // We have to watch out here because an ObjCInterfaceType's base + // type is itself. + if (T->getBaseType().getTypePtr() != T) + TRY_TO(TraverseType(T->getBaseType())); + for (auto typeArg : T->getTypeArgsAsWritten()) { + TRY_TO(TraverseType(typeArg)); + } +}) + +DEF_TRAVERSE_TYPE(ObjCObjectPointerType, + { TRY_TO(TraverseType(T->getPointeeType())); }) + +DEF_TRAVERSE_TYPE(AtomicType, { TRY_TO(TraverseType(T->getValueType())); }) + +#undef DEF_TRAVERSE_TYPE + +// ----------------- TypeLoc traversal ----------------- + +// This macro makes available a variable TL, the passed-in TypeLoc. +// If requested, it calls WalkUpFrom* for the Type in the given TypeLoc, +// in addition to WalkUpFrom* for the TypeLoc itself, such that existing +// clients that override the WalkUpFrom*Type() and/or Visit*Type() methods +// continue to work. +#define DEF_TRAVERSE_TYPELOC(TYPE, CODE) \ + template <typename Derived> \ + bool RecursiveASTVisitor<Derived>::Traverse##TYPE##Loc(TYPE##Loc TL) { \ + if (getDerived().shouldWalkTypesOfTypeLocs()) \ + TRY_TO(WalkUpFrom##TYPE(const_cast<TYPE *>(TL.getTypePtr()))); \ + TRY_TO(WalkUpFrom##TYPE##Loc(TL)); \ + { CODE; } \ + return true; \ + } + +template <typename Derived> +bool +RecursiveASTVisitor<Derived>::TraverseQualifiedTypeLoc(QualifiedTypeLoc TL) { + // Move this over to the 'main' typeloc tree. Note that this is a + // move -- we pretend that we were really looking at the unqualified + // typeloc all along -- rather than a recursion, so we don't follow + // the normal CRTP plan of going through + // getDerived().TraverseTypeLoc. If we did, we'd be traversing + // twice for the same type (once as a QualifiedTypeLoc version of + // the type, once as an UnqualifiedTypeLoc version of the type), + // which in effect means we'd call VisitTypeLoc twice with the + // 'same' type. This solves that problem, at the cost of never + // seeing the qualified version of the type (unless the client + // subclasses TraverseQualifiedTypeLoc themselves). It's not a + // perfect solution. A perfect solution probably requires making + // QualifiedTypeLoc a wrapper around TypeLoc -- like QualType is a + // wrapper around Type* -- rather than being its own class in the + // type hierarchy. + return TraverseTypeLoc(TL.getUnqualifiedLoc()); +} + +DEF_TRAVERSE_TYPELOC(BuiltinType, {}) + +// FIXME: ComplexTypeLoc is unfinished +DEF_TRAVERSE_TYPELOC(ComplexType, { + TRY_TO(TraverseType(TL.getTypePtr()->getElementType())); +}) + +DEF_TRAVERSE_TYPELOC(PointerType, + { TRY_TO(TraverseTypeLoc(TL.getPointeeLoc())); }) + +DEF_TRAVERSE_TYPELOC(BlockPointerType, + { TRY_TO(TraverseTypeLoc(TL.getPointeeLoc())); }) + +DEF_TRAVERSE_TYPELOC(LValueReferenceType, + { TRY_TO(TraverseTypeLoc(TL.getPointeeLoc())); }) + +DEF_TRAVERSE_TYPELOC(RValueReferenceType, + { TRY_TO(TraverseTypeLoc(TL.getPointeeLoc())); }) + +// FIXME: location of base class? +// We traverse this in the type case as well, but how is it not reached through +// the pointee type? +DEF_TRAVERSE_TYPELOC(MemberPointerType, { + TRY_TO(TraverseType(QualType(TL.getTypePtr()->getClass(), 0))); + TRY_TO(TraverseTypeLoc(TL.getPointeeLoc())); +}) + +DEF_TRAVERSE_TYPELOC(AdjustedType, + { TRY_TO(TraverseTypeLoc(TL.getOriginalLoc())); }) + +DEF_TRAVERSE_TYPELOC(DecayedType, + { TRY_TO(TraverseTypeLoc(TL.getOriginalLoc())); }) + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseArrayTypeLocHelper(ArrayTypeLoc TL) { + // This isn't available for ArrayType, but is for the ArrayTypeLoc. + TRY_TO(TraverseStmt(TL.getSizeExpr())); + return true; +} + +DEF_TRAVERSE_TYPELOC(ConstantArrayType, { + TRY_TO(TraverseTypeLoc(TL.getElementLoc())); + return TraverseArrayTypeLocHelper(TL); +}) + +DEF_TRAVERSE_TYPELOC(IncompleteArrayType, { + TRY_TO(TraverseTypeLoc(TL.getElementLoc())); + return TraverseArrayTypeLocHelper(TL); +}) + +DEF_TRAVERSE_TYPELOC(VariableArrayType, { + TRY_TO(TraverseTypeLoc(TL.getElementLoc())); + return TraverseArrayTypeLocHelper(TL); +}) + +DEF_TRAVERSE_TYPELOC(DependentSizedArrayType, { + TRY_TO(TraverseTypeLoc(TL.getElementLoc())); + return TraverseArrayTypeLocHelper(TL); +}) + +// FIXME: order? why not size expr first? +// FIXME: base VectorTypeLoc is unfinished +DEF_TRAVERSE_TYPELOC(DependentSizedExtVectorType, { + if (TL.getTypePtr()->getSizeExpr()) + TRY_TO(TraverseStmt(TL.getTypePtr()->getSizeExpr())); + TRY_TO(TraverseType(TL.getTypePtr()->getElementType())); +}) + +// FIXME: VectorTypeLoc is unfinished +DEF_TRAVERSE_TYPELOC(VectorType, { + TRY_TO(TraverseType(TL.getTypePtr()->getElementType())); +}) + +// FIXME: size and attributes +// FIXME: base VectorTypeLoc is unfinished +DEF_TRAVERSE_TYPELOC(ExtVectorType, { + TRY_TO(TraverseType(TL.getTypePtr()->getElementType())); +}) + +DEF_TRAVERSE_TYPELOC(FunctionNoProtoType, + { TRY_TO(TraverseTypeLoc(TL.getReturnLoc())); }) + +// FIXME: location of exception specifications (attributes?) +DEF_TRAVERSE_TYPELOC(FunctionProtoType, { + TRY_TO(TraverseTypeLoc(TL.getReturnLoc())); + + const FunctionProtoType *T = TL.getTypePtr(); + + for (unsigned I = 0, E = TL.getNumParams(); I != E; ++I) { + if (TL.getParam(I)) { + TRY_TO(TraverseDecl(TL.getParam(I))); + } else if (I < T->getNumParams()) { + TRY_TO(TraverseType(T->getParamType(I))); + } + } + + for (const auto &E : T->exceptions()) { + TRY_TO(TraverseType(E)); + } + + if (Expr *NE = T->getNoexceptExpr()) + TRY_TO(TraverseStmt(NE)); +}) + +DEF_TRAVERSE_TYPELOC(UnresolvedUsingType, {}) +DEF_TRAVERSE_TYPELOC(TypedefType, {}) + +DEF_TRAVERSE_TYPELOC(TypeOfExprType, + { TRY_TO(TraverseStmt(TL.getUnderlyingExpr())); }) + +DEF_TRAVERSE_TYPELOC(TypeOfType, { + TRY_TO(TraverseTypeLoc(TL.getUnderlyingTInfo()->getTypeLoc())); +}) + +// FIXME: location of underlying expr +DEF_TRAVERSE_TYPELOC(DecltypeType, { + TRY_TO(TraverseStmt(TL.getTypePtr()->getUnderlyingExpr())); +}) + +DEF_TRAVERSE_TYPELOC(UnaryTransformType, { + TRY_TO(TraverseTypeLoc(TL.getUnderlyingTInfo()->getTypeLoc())); +}) + +DEF_TRAVERSE_TYPELOC(AutoType, { + TRY_TO(TraverseType(TL.getTypePtr()->getDeducedType())); +}) + +DEF_TRAVERSE_TYPELOC(RecordType, {}) +DEF_TRAVERSE_TYPELOC(EnumType, {}) +DEF_TRAVERSE_TYPELOC(TemplateTypeParmType, {}) +DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmType, {}) +DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmPackType, {}) + +// FIXME: use the loc for the template name? +DEF_TRAVERSE_TYPELOC(TemplateSpecializationType, { + TRY_TO(TraverseTemplateName(TL.getTypePtr()->getTemplateName())); + for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) { + TRY_TO(TraverseTemplateArgumentLoc(TL.getArgLoc(I))); + } +}) + +DEF_TRAVERSE_TYPELOC(InjectedClassNameType, {}) + +DEF_TRAVERSE_TYPELOC(ParenType, { TRY_TO(TraverseTypeLoc(TL.getInnerLoc())); }) + +DEF_TRAVERSE_TYPELOC(AttributedType, + { TRY_TO(TraverseTypeLoc(TL.getModifiedLoc())); }) + +DEF_TRAVERSE_TYPELOC(ElaboratedType, { + if (TL.getQualifierLoc()) { + TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc())); + } + TRY_TO(TraverseTypeLoc(TL.getNamedTypeLoc())); +}) + +DEF_TRAVERSE_TYPELOC(DependentNameType, { + TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc())); +}) + +DEF_TRAVERSE_TYPELOC(DependentTemplateSpecializationType, { + if (TL.getQualifierLoc()) { + TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc())); + } + + for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) { + TRY_TO(TraverseTemplateArgumentLoc(TL.getArgLoc(I))); + } +}) + +DEF_TRAVERSE_TYPELOC(PackExpansionType, + { TRY_TO(TraverseTypeLoc(TL.getPatternLoc())); }) + +DEF_TRAVERSE_TYPELOC(ObjCInterfaceType, {}) + +DEF_TRAVERSE_TYPELOC(ObjCObjectType, { + // We have to watch out here because an ObjCInterfaceType's base + // type is itself. + if (TL.getTypePtr()->getBaseType().getTypePtr() != TL.getTypePtr()) + TRY_TO(TraverseTypeLoc(TL.getBaseLoc())); + for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i) + TRY_TO(TraverseTypeLoc(TL.getTypeArgTInfo(i)->getTypeLoc())); +}) + +DEF_TRAVERSE_TYPELOC(ObjCObjectPointerType, + { TRY_TO(TraverseTypeLoc(TL.getPointeeLoc())); }) + +DEF_TRAVERSE_TYPELOC(AtomicType, { TRY_TO(TraverseTypeLoc(TL.getValueLoc())); }) + +#undef DEF_TRAVERSE_TYPELOC + +// ----------------- Decl traversal ----------------- +// +// For a Decl, we automate (in the DEF_TRAVERSE_DECL macro) traversing +// the children that come from the DeclContext associated with it. +// Therefore each Traverse* only needs to worry about children other +// than those. + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseDeclContextHelper(DeclContext *DC) { + if (!DC) + return true; + + for (auto *Child : DC->decls()) { + // BlockDecls and CapturedDecls are traversed through BlockExprs and + // CapturedStmts respectively. + if (!isa<BlockDecl>(Child) && !isa<CapturedDecl>(Child)) + TRY_TO(TraverseDecl(Child)); + } + + return true; +} + +// This macro makes available a variable D, the passed-in decl. +#define DEF_TRAVERSE_DECL(DECL, CODE) \ + template <typename Derived> \ + bool RecursiveASTVisitor<Derived>::Traverse##DECL(DECL *D) { \ + TRY_TO(WalkUpFrom##DECL(D)); \ + { CODE; } \ + TRY_TO(TraverseDeclContextHelper(dyn_cast<DeclContext>(D))); \ + return true; \ + } + +DEF_TRAVERSE_DECL(AccessSpecDecl, {}) + +DEF_TRAVERSE_DECL(BlockDecl, { + if (TypeSourceInfo *TInfo = D->getSignatureAsWritten()) + TRY_TO(TraverseTypeLoc(TInfo->getTypeLoc())); + TRY_TO(TraverseStmt(D->getBody())); + for (const auto &I : D->captures()) { + if (I.hasCopyExpr()) { + TRY_TO(TraverseStmt(I.getCopyExpr())); + } + } + // This return statement makes sure the traversal of nodes in + // decls_begin()/decls_end() (done in the DEF_TRAVERSE_DECL macro) + // is skipped - don't remove it. + return true; +}) + +DEF_TRAVERSE_DECL(CapturedDecl, { + TRY_TO(TraverseStmt(D->getBody())); + // This return statement makes sure the traversal of nodes in + // decls_begin()/decls_end() (done in the DEF_TRAVERSE_DECL macro) + // is skipped - don't remove it. + return true; +}) + +DEF_TRAVERSE_DECL(EmptyDecl, {}) + +DEF_TRAVERSE_DECL(FileScopeAsmDecl, + { TRY_TO(TraverseStmt(D->getAsmString())); }) + +DEF_TRAVERSE_DECL(ImportDecl, {}) + +DEF_TRAVERSE_DECL(FriendDecl, { + // Friend is either decl or a type. + if (D->getFriendType()) + TRY_TO(TraverseTypeLoc(D->getFriendType()->getTypeLoc())); + else + TRY_TO(TraverseDecl(D->getFriendDecl())); +}) + +DEF_TRAVERSE_DECL(FriendTemplateDecl, { + if (D->getFriendType()) + TRY_TO(TraverseTypeLoc(D->getFriendType()->getTypeLoc())); + else + TRY_TO(TraverseDecl(D->getFriendDecl())); + for (unsigned I = 0, E = D->getNumTemplateParameters(); I < E; ++I) { + TemplateParameterList *TPL = D->getTemplateParameterList(I); + for (TemplateParameterList::iterator ITPL = TPL->begin(), ETPL = TPL->end(); + ITPL != ETPL; ++ITPL) { + TRY_TO(TraverseDecl(*ITPL)); + } + } +}) + +DEF_TRAVERSE_DECL(ClassScopeFunctionSpecializationDecl, { + TRY_TO(TraverseDecl(D->getSpecialization())); + + if (D->hasExplicitTemplateArgs()) { + const TemplateArgumentListInfo &args = D->templateArgs(); + TRY_TO(TraverseTemplateArgumentLocsHelper(args.getArgumentArray(), + args.size())); + } +}) + +DEF_TRAVERSE_DECL(LinkageSpecDecl, {}) + +DEF_TRAVERSE_DECL(ObjCPropertyImplDecl, {// FIXME: implement this + }) + +DEF_TRAVERSE_DECL(StaticAssertDecl, { + TRY_TO(TraverseStmt(D->getAssertExpr())); + TRY_TO(TraverseStmt(D->getMessage())); +}) + +DEF_TRAVERSE_DECL( + TranslationUnitDecl, + {// Code in an unnamed namespace shows up automatically in + // decls_begin()/decls_end(). Thus we don't need to recurse on + // D->getAnonymousNamespace(). + }) + +DEF_TRAVERSE_DECL(ExternCContextDecl, {}) + +DEF_TRAVERSE_DECL(NamespaceAliasDecl, { + TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); + + // We shouldn't traverse an aliased namespace, since it will be + // defined (and, therefore, traversed) somewhere else. + // + // This return statement makes sure the traversal of nodes in + // decls_begin()/decls_end() (done in the DEF_TRAVERSE_DECL macro) + // is skipped - don't remove it. + return true; +}) + +DEF_TRAVERSE_DECL(LabelDecl, {// There is no code in a LabelDecl. + }) + +DEF_TRAVERSE_DECL( + NamespaceDecl, + {// Code in an unnamed namespace shows up automatically in + // decls_begin()/decls_end(). Thus we don't need to recurse on + // D->getAnonymousNamespace(). + }) + +DEF_TRAVERSE_DECL(ObjCCompatibleAliasDecl, {// FIXME: implement + }) + +DEF_TRAVERSE_DECL(ObjCCategoryDecl, {// FIXME: implement + if (ObjCTypeParamList *typeParamList = D->getTypeParamList()) { + for (auto typeParam : *typeParamList) { + TRY_TO(TraverseObjCTypeParamDecl(typeParam)); + } + } +}) + +DEF_TRAVERSE_DECL(ObjCCategoryImplDecl, {// FIXME: implement + }) + +DEF_TRAVERSE_DECL(ObjCImplementationDecl, {// FIXME: implement + }) + +DEF_TRAVERSE_DECL(ObjCInterfaceDecl, {// FIXME: implement + if (ObjCTypeParamList *typeParamList = D->getTypeParamListAsWritten()) { + for (auto typeParam : *typeParamList) { + TRY_TO(TraverseObjCTypeParamDecl(typeParam)); + } + } + + if (TypeSourceInfo *superTInfo = D->getSuperClassTInfo()) { + TRY_TO(TraverseTypeLoc(superTInfo->getTypeLoc())); + } +}) + +DEF_TRAVERSE_DECL(ObjCProtocolDecl, {// FIXME: implement + }) + +DEF_TRAVERSE_DECL(ObjCMethodDecl, { + if (D->getReturnTypeSourceInfo()) { + TRY_TO(TraverseTypeLoc(D->getReturnTypeSourceInfo()->getTypeLoc())); + } + for (ObjCMethodDecl::param_iterator I = D->param_begin(), E = D->param_end(); + I != E; ++I) { + TRY_TO(TraverseDecl(*I)); + } + if (D->isThisDeclarationADefinition()) { + TRY_TO(TraverseStmt(D->getBody())); + } + return true; +}) + +DEF_TRAVERSE_DECL(ObjCTypeParamDecl, { + if (D->hasExplicitBound()) { + TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc())); + // We shouldn't traverse D->getTypeForDecl(); it's a result of + // declaring the type alias, not something that was written in the + // source. + } +}) + +DEF_TRAVERSE_DECL(ObjCPropertyDecl, { + if (D->getTypeSourceInfo()) + TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc())); + else + TRY_TO(TraverseType(D->getType())); + return true; +}) + +DEF_TRAVERSE_DECL(UsingDecl, { + TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); + TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo())); +}) + +DEF_TRAVERSE_DECL(UsingDirectiveDecl, { + TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); +}) + +DEF_TRAVERSE_DECL(UsingShadowDecl, {}) + +DEF_TRAVERSE_DECL(OMPThreadPrivateDecl, { + for (auto *I : D->varlists()) { + TRY_TO(TraverseStmt(I)); + } +}) + +// A helper method for TemplateDecl's children. +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseTemplateParameterListHelper( + TemplateParameterList *TPL) { + if (TPL) { + for (TemplateParameterList::iterator I = TPL->begin(), E = TPL->end(); + I != E; ++I) { + TRY_TO(TraverseDecl(*I)); + } + } + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations( + ClassTemplateDecl *D) { + for (auto *SD : D->specializations()) { + for (auto *RD : SD->redecls()) { + // We don't want to visit injected-class-names in this traversal. + if (cast<CXXRecordDecl>(RD)->isInjectedClassName()) + continue; + + switch ( + cast<ClassTemplateSpecializationDecl>(RD)->getSpecializationKind()) { + // Visit the implicit instantiations with the requested pattern. + case TSK_Undeclared: + case TSK_ImplicitInstantiation: + TRY_TO(TraverseDecl(RD)); + break; + + // We don't need to do anything on an explicit instantiation + // or explicit specialization because there will be an explicit + // node for it elsewhere. + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + case TSK_ExplicitSpecialization: + break; + } + } + } + + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations( + VarTemplateDecl *D) { + for (auto *SD : D->specializations()) { + for (auto *RD : SD->redecls()) { + switch ( + cast<VarTemplateSpecializationDecl>(RD)->getSpecializationKind()) { + case TSK_Undeclared: + case TSK_ImplicitInstantiation: + TRY_TO(TraverseDecl(RD)); + break; + + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + case TSK_ExplicitSpecialization: + break; + } + } + } + + return true; +} + +// A helper method for traversing the instantiations of a +// function while skipping its specializations. +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations( + FunctionTemplateDecl *D) { + for (auto *FD : D->specializations()) { + for (auto *RD : FD->redecls()) { + switch (RD->getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ImplicitInstantiation: + // We don't know what kind of FunctionDecl this is. + TRY_TO(TraverseDecl(RD)); + break; + + // FIXME: For now traverse explicit instantiations here. Change that + // once they are represented as dedicated nodes in the AST. + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + TRY_TO(TraverseDecl(RD)); + break; + + case TSK_ExplicitSpecialization: + break; + } + } + } + + return true; +} + +// This macro unifies the traversal of class, variable and function +// template declarations. +#define DEF_TRAVERSE_TMPL_DECL(TMPLDECLKIND) \ + DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplateDecl, { \ + TRY_TO(TraverseDecl(D->getTemplatedDecl())); \ + TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters())); \ + \ + /* By default, we do not traverse the instantiations of \ + class templates since they do not appear in the user code. The \ + following code optionally traverses them. \ + \ + We only traverse the class instantiations when we see the canonical \ + declaration of the template, to ensure we only visit them once. */ \ + if (getDerived().shouldVisitTemplateInstantiations() && \ + D == D->getCanonicalDecl()) \ + TRY_TO(TraverseTemplateInstantiations(D)); \ + \ + /* Note that getInstantiatedFromMemberTemplate() is just a link \ + from a template instantiation back to the template from which \ + it was instantiated, and thus should not be traversed. */ \ + }) + +DEF_TRAVERSE_TMPL_DECL(Class) +DEF_TRAVERSE_TMPL_DECL(Var) +DEF_TRAVERSE_TMPL_DECL(Function) + +DEF_TRAVERSE_DECL(TemplateTemplateParmDecl, { + // D is the "T" in something like + // template <template <typename> class T> class container { }; + TRY_TO(TraverseDecl(D->getTemplatedDecl())); + if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) { + TRY_TO(TraverseTemplateArgumentLoc(D->getDefaultArgument())); + } + TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters())); +}) + +DEF_TRAVERSE_DECL(BuiltinTemplateDecl, { + TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters())); +}) + +DEF_TRAVERSE_DECL(TemplateTypeParmDecl, { + // D is the "T" in something like "template<typename T> class vector;" + if (D->getTypeForDecl()) + TRY_TO(TraverseType(QualType(D->getTypeForDecl(), 0))); + if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) + TRY_TO(TraverseTypeLoc(D->getDefaultArgumentInfo()->getTypeLoc())); +}) + +DEF_TRAVERSE_DECL(TypedefDecl, { + TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc())); + // We shouldn't traverse D->getTypeForDecl(); it's a result of + // declaring the typedef, not something that was written in the + // source. +}) + +DEF_TRAVERSE_DECL(TypeAliasDecl, { + TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc())); + // We shouldn't traverse D->getTypeForDecl(); it's a result of + // declaring the type alias, not something that was written in the + // source. +}) + +DEF_TRAVERSE_DECL(TypeAliasTemplateDecl, { + TRY_TO(TraverseDecl(D->getTemplatedDecl())); + TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters())); +}) + +DEF_TRAVERSE_DECL(UnresolvedUsingTypenameDecl, { + // A dependent using declaration which was marked with 'typename'. + // template<class T> class A : public B<T> { using typename B<T>::foo; }; + TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); + // We shouldn't traverse D->getTypeForDecl(); it's a result of + // declaring the type, not something that was written in the + // source. +}) + +DEF_TRAVERSE_DECL(EnumDecl, { + if (D->getTypeForDecl()) + TRY_TO(TraverseType(QualType(D->getTypeForDecl(), 0))); + + TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); + // The enumerators are already traversed by + // decls_begin()/decls_end(). +}) + +// Helper methods for RecordDecl and its children. +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseRecordHelper(RecordDecl *D) { + // We shouldn't traverse D->getTypeForDecl(); it's a result of + // declaring the type, not something that was written in the source. + + TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseCXXRecordHelper(CXXRecordDecl *D) { + if (!TraverseRecordHelper(D)) + return false; + if (D->isCompleteDefinition()) { + for (const auto &I : D->bases()) { + TRY_TO(TraverseTypeLoc(I.getTypeSourceInfo()->getTypeLoc())); + } + // We don't traverse the friends or the conversions, as they are + // already in decls_begin()/decls_end(). + } + return true; +} + +DEF_TRAVERSE_DECL(RecordDecl, { TRY_TO(TraverseRecordHelper(D)); }) + +DEF_TRAVERSE_DECL(CXXRecordDecl, { TRY_TO(TraverseCXXRecordHelper(D)); }) + +#define DEF_TRAVERSE_TMPL_SPEC_DECL(TMPLDECLKIND) \ + DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplateSpecializationDecl, { \ + /* For implicit instantiations ("set<int> x;"), we don't want to \ + recurse at all, since the instatiated template isn't written in \ + the source code anywhere. (Note the instatiated *type* -- \ + set<int> -- is written, and will still get a callback of \ + TemplateSpecializationType). For explicit instantiations \ + ("template set<int>;"), we do need a callback, since this \ + is the only callback that's made for this instantiation. \ + We use getTypeAsWritten() to distinguish. */ \ + if (TypeSourceInfo *TSI = D->getTypeAsWritten()) \ + TRY_TO(TraverseTypeLoc(TSI->getTypeLoc())); \ + \ + if (!getDerived().shouldVisitTemplateInstantiations() && \ + D->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) \ + /* Returning from here skips traversing the \ + declaration context of the *TemplateSpecializationDecl \ + (embedded in the DEF_TRAVERSE_DECL() macro) \ + which contains the instantiated members of the template. */ \ + return true; \ + }) + +DEF_TRAVERSE_TMPL_SPEC_DECL(Class) +DEF_TRAVERSE_TMPL_SPEC_DECL(Var) + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLocsHelper( + const TemplateArgumentLoc *TAL, unsigned Count) { + for (unsigned I = 0; I < Count; ++I) { + TRY_TO(TraverseTemplateArgumentLoc(TAL[I])); + } + return true; +} + +#define DEF_TRAVERSE_TMPL_PART_SPEC_DECL(TMPLDECLKIND, DECLKIND) \ + DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplatePartialSpecializationDecl, { \ + /* The partial specialization. */ \ + if (TemplateParameterList *TPL = D->getTemplateParameters()) { \ + for (TemplateParameterList::iterator I = TPL->begin(), E = TPL->end(); \ + I != E; ++I) { \ + TRY_TO(TraverseDecl(*I)); \ + } \ + } \ + /* The args that remains unspecialized. */ \ + TRY_TO(TraverseTemplateArgumentLocsHelper( \ + D->getTemplateArgsAsWritten()->getTemplateArgs(), \ + D->getTemplateArgsAsWritten()->NumTemplateArgs)); \ + \ + /* Don't need the *TemplatePartialSpecializationHelper, even \ + though that's our parent class -- we already visit all the \ + template args here. */ \ + TRY_TO(Traverse##DECLKIND##Helper(D)); \ + \ + /* Instantiations will have been visited with the primary template. */ \ + }) + +DEF_TRAVERSE_TMPL_PART_SPEC_DECL(Class, CXXRecord) +DEF_TRAVERSE_TMPL_PART_SPEC_DECL(Var, Var) + +DEF_TRAVERSE_DECL(EnumConstantDecl, { TRY_TO(TraverseStmt(D->getInitExpr())); }) + +DEF_TRAVERSE_DECL(UnresolvedUsingValueDecl, { + // Like UnresolvedUsingTypenameDecl, but without the 'typename': + // template <class T> Class A : public Base<T> { using Base<T>::foo; }; + TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); + TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo())); +}) + +DEF_TRAVERSE_DECL(IndirectFieldDecl, {}) + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseDeclaratorHelper(DeclaratorDecl *D) { + TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); + if (D->getTypeSourceInfo()) + TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc())); + else + TRY_TO(TraverseType(D->getType())); + return true; +} + +DEF_TRAVERSE_DECL(MSPropertyDecl, { TRY_TO(TraverseDeclaratorHelper(D)); }) + +DEF_TRAVERSE_DECL(FieldDecl, { + TRY_TO(TraverseDeclaratorHelper(D)); + if (D->isBitField()) + TRY_TO(TraverseStmt(D->getBitWidth())); + else if (D->hasInClassInitializer()) + TRY_TO(TraverseStmt(D->getInClassInitializer())); +}) + +DEF_TRAVERSE_DECL(ObjCAtDefsFieldDecl, { + TRY_TO(TraverseDeclaratorHelper(D)); + if (D->isBitField()) + TRY_TO(TraverseStmt(D->getBitWidth())); + // FIXME: implement the rest. +}) + +DEF_TRAVERSE_DECL(ObjCIvarDecl, { + TRY_TO(TraverseDeclaratorHelper(D)); + if (D->isBitField()) + TRY_TO(TraverseStmt(D->getBitWidth())); + // FIXME: implement the rest. +}) + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) { + TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); + TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo())); + + // If we're an explicit template specialization, iterate over the + // template args that were explicitly specified. If we were doing + // this in typing order, we'd do it between the return type and + // the function args, but both are handled by the FunctionTypeLoc + // above, so we have to choose one side. I've decided to do before. + if (const FunctionTemplateSpecializationInfo *FTSI = + D->getTemplateSpecializationInfo()) { + if (FTSI->getTemplateSpecializationKind() != TSK_Undeclared && + FTSI->getTemplateSpecializationKind() != TSK_ImplicitInstantiation) { + // A specialization might not have explicit template arguments if it has + // a templated return type and concrete arguments. + if (const ASTTemplateArgumentListInfo *TALI = + FTSI->TemplateArgumentsAsWritten) { + TRY_TO(TraverseTemplateArgumentLocsHelper(TALI->getTemplateArgs(), + TALI->NumTemplateArgs)); + } + } + } + + // Visit the function type itself, which can be either + // FunctionNoProtoType or FunctionProtoType, or a typedef. This + // also covers the return type and the function parameters, + // including exception specifications. + if (TypeSourceInfo *TSI = D->getTypeSourceInfo()) { + TRY_TO(TraverseTypeLoc(TSI->getTypeLoc())); + } else if (getDerived().shouldVisitImplicitCode()) { + // Visit parameter variable declarations of the implicit function + // if the traverser is visiting implicit code. Parameter variable + // declarations do not have valid TypeSourceInfo, so to visit them + // we need to traverse the declarations explicitly. + for (FunctionDecl::param_const_iterator I = D->param_begin(), + E = D->param_end(); + I != E; ++I) + TRY_TO(TraverseDecl(*I)); + } + + if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) { + // Constructor initializers. + for (auto *I : Ctor->inits()) { + TRY_TO(TraverseConstructorInitializer(I)); + } + } + + if (D->isThisDeclarationADefinition()) { + TRY_TO(TraverseStmt(D->getBody())); // Function body. + } + return true; +} + +DEF_TRAVERSE_DECL(FunctionDecl, { + // We skip decls_begin/decls_end, which are already covered by + // TraverseFunctionHelper(). + return TraverseFunctionHelper(D); +}) + +DEF_TRAVERSE_DECL(CXXMethodDecl, { + // We skip decls_begin/decls_end, which are already covered by + // TraverseFunctionHelper(). + return TraverseFunctionHelper(D); +}) + +DEF_TRAVERSE_DECL(CXXConstructorDecl, { + // We skip decls_begin/decls_end, which are already covered by + // TraverseFunctionHelper(). + return TraverseFunctionHelper(D); +}) + +// CXXConversionDecl is the declaration of a type conversion operator. +// It's not a cast expression. +DEF_TRAVERSE_DECL(CXXConversionDecl, { + // We skip decls_begin/decls_end, which are already covered by + // TraverseFunctionHelper(). + return TraverseFunctionHelper(D); +}) + +DEF_TRAVERSE_DECL(CXXDestructorDecl, { + // We skip decls_begin/decls_end, which are already covered by + // TraverseFunctionHelper(). + return TraverseFunctionHelper(D); +}) + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseVarHelper(VarDecl *D) { + TRY_TO(TraverseDeclaratorHelper(D)); + // Default params are taken care of when we traverse the ParmVarDecl. + if (!isa<ParmVarDecl>(D) && + (!D->isCXXForRangeDecl() || getDerived().shouldVisitImplicitCode())) + TRY_TO(TraverseStmt(D->getInit())); + return true; +} + +DEF_TRAVERSE_DECL(VarDecl, { TRY_TO(TraverseVarHelper(D)); }) + +DEF_TRAVERSE_DECL(ImplicitParamDecl, { TRY_TO(TraverseVarHelper(D)); }) + +DEF_TRAVERSE_DECL(NonTypeTemplateParmDecl, { + // A non-type template parameter, e.g. "S" in template<int S> class Foo ... + TRY_TO(TraverseDeclaratorHelper(D)); + if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) + TRY_TO(TraverseStmt(D->getDefaultArgument())); +}) + +DEF_TRAVERSE_DECL(ParmVarDecl, { + TRY_TO(TraverseVarHelper(D)); + + if (D->hasDefaultArg() && D->hasUninstantiatedDefaultArg() && + !D->hasUnparsedDefaultArg()) + TRY_TO(TraverseStmt(D->getUninstantiatedDefaultArg())); + + if (D->hasDefaultArg() && !D->hasUninstantiatedDefaultArg() && + !D->hasUnparsedDefaultArg()) + TRY_TO(TraverseStmt(D->getDefaultArg())); +}) + +#undef DEF_TRAVERSE_DECL + +// ----------------- Stmt traversal ----------------- +// +// For stmts, we automate (in the DEF_TRAVERSE_STMT macro) iterating +// over the children defined in children() (every stmt defines these, +// though sometimes the range is empty). Each individual Traverse* +// method only needs to worry about children other than those. To see +// what children() does for a given class, see, e.g., +// http://clang.llvm.org/doxygen/Stmt_8cpp_source.html + +// This macro makes available a variable S, the passed-in stmt. +#define DEF_TRAVERSE_STMT(STMT, CODE) \ + template <typename Derived> \ + bool RecursiveASTVisitor<Derived>::Traverse##STMT( \ + STMT *S, DataRecursionQueue *Queue) { \ + TRY_TO(WalkUpFrom##STMT(S)); \ + { CODE; } \ + for (Stmt *SubStmt : S->children()) { \ + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(SubStmt); \ + } \ + return true; \ + } + +DEF_TRAVERSE_STMT(GCCAsmStmt, { + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getAsmString()); + for (unsigned I = 0, E = S->getNumInputs(); I < E; ++I) { + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getInputConstraintLiteral(I)); + } + for (unsigned I = 0, E = S->getNumOutputs(); I < E; ++I) { + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getOutputConstraintLiteral(I)); + } + for (unsigned I = 0, E = S->getNumClobbers(); I < E; ++I) { + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getClobberStringLiteral(I)); + } + // children() iterates over inputExpr and outputExpr. +}) + +DEF_TRAVERSE_STMT( + MSAsmStmt, + {// FIXME: MS Asm doesn't currently parse Constraints, Clobbers, etc. Once + // added this needs to be implemented. + }) + +DEF_TRAVERSE_STMT(CXXCatchStmt, { + TRY_TO(TraverseDecl(S->getExceptionDecl())); + // children() iterates over the handler block. +}) + +DEF_TRAVERSE_STMT(DeclStmt, { + for (auto *I : S->decls()) { + TRY_TO(TraverseDecl(I)); + } + // Suppress the default iteration over children() by + // returning. Here's why: A DeclStmt looks like 'type var [= + // initializer]'. The decls above already traverse over the + // initializers, so we don't have to do it again (which + // children() would do). + return true; +}) + +// These non-expr stmts (most of them), do not need any action except +// iterating over the children. +DEF_TRAVERSE_STMT(BreakStmt, {}) +DEF_TRAVERSE_STMT(CXXTryStmt, {}) +DEF_TRAVERSE_STMT(CaseStmt, {}) +DEF_TRAVERSE_STMT(CompoundStmt, {}) +DEF_TRAVERSE_STMT(ContinueStmt, {}) +DEF_TRAVERSE_STMT(DefaultStmt, {}) +DEF_TRAVERSE_STMT(DoStmt, {}) +DEF_TRAVERSE_STMT(ForStmt, {}) +DEF_TRAVERSE_STMT(GotoStmt, {}) +DEF_TRAVERSE_STMT(IfStmt, {}) +DEF_TRAVERSE_STMT(IndirectGotoStmt, {}) +DEF_TRAVERSE_STMT(LabelStmt, {}) +DEF_TRAVERSE_STMT(AttributedStmt, {}) +DEF_TRAVERSE_STMT(NullStmt, {}) +DEF_TRAVERSE_STMT(ObjCAtCatchStmt, {}) +DEF_TRAVERSE_STMT(ObjCAtFinallyStmt, {}) +DEF_TRAVERSE_STMT(ObjCAtSynchronizedStmt, {}) +DEF_TRAVERSE_STMT(ObjCAtThrowStmt, {}) +DEF_TRAVERSE_STMT(ObjCAtTryStmt, {}) +DEF_TRAVERSE_STMT(ObjCForCollectionStmt, {}) +DEF_TRAVERSE_STMT(ObjCAutoreleasePoolStmt, {}) +DEF_TRAVERSE_STMT(CXXForRangeStmt, { + if (!getDerived().shouldVisitImplicitCode()) { + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getLoopVarStmt()); + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getRangeInit()); + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getBody()); + // Visit everything else only if shouldVisitImplicitCode(). + return true; + } +}) +DEF_TRAVERSE_STMT(MSDependentExistsStmt, { + TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc())); + TRY_TO(TraverseDeclarationNameInfo(S->getNameInfo())); +}) +DEF_TRAVERSE_STMT(ReturnStmt, {}) +DEF_TRAVERSE_STMT(SwitchStmt, {}) +DEF_TRAVERSE_STMT(WhileStmt, {}) + +DEF_TRAVERSE_STMT(CXXDependentScopeMemberExpr, { + TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc())); + TRY_TO(TraverseDeclarationNameInfo(S->getMemberNameInfo())); + if (S->hasExplicitTemplateArgs()) { + TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(), + S->getNumTemplateArgs())); + } +}) + +DEF_TRAVERSE_STMT(DeclRefExpr, { + TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc())); + TRY_TO(TraverseDeclarationNameInfo(S->getNameInfo())); + TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(), + S->getNumTemplateArgs())); +}) + +DEF_TRAVERSE_STMT(DependentScopeDeclRefExpr, { + TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc())); + TRY_TO(TraverseDeclarationNameInfo(S->getNameInfo())); + if (S->hasExplicitTemplateArgs()) { + TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(), + S->getNumTemplateArgs())); + } +}) + +DEF_TRAVERSE_STMT(MemberExpr, { + TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc())); + TRY_TO(TraverseDeclarationNameInfo(S->getMemberNameInfo())); + TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(), + S->getNumTemplateArgs())); +}) + +DEF_TRAVERSE_STMT( + ImplicitCastExpr, + {// We don't traverse the cast type, as it's not written in the + // source code. + }) + +DEF_TRAVERSE_STMT(CStyleCastExpr, { + TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc())); +}) + +DEF_TRAVERSE_STMT(CXXFunctionalCastExpr, { + TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc())); +}) + +DEF_TRAVERSE_STMT(CXXConstCastExpr, { + TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc())); +}) + +DEF_TRAVERSE_STMT(CXXDynamicCastExpr, { + TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc())); +}) + +DEF_TRAVERSE_STMT(CXXReinterpretCastExpr, { + TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc())); +}) + +DEF_TRAVERSE_STMT(CXXStaticCastExpr, { + TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc())); +}) + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseSynOrSemInitListExpr( + InitListExpr *S, DataRecursionQueue *Queue) { + if (S) { + TRY_TO(WalkUpFromInitListExpr(S)); + // All we need are the default actions. FIXME: use a helper function. + for (Stmt *SubStmt : S->children()) { + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(SubStmt); + } + } + return true; +} + +// This method is called once for each pair of syntactic and semantic +// InitListExpr, and it traverses the subtrees defined by the two forms. This +// may cause some of the children to be visited twice, if they appear both in +// the syntactic and the semantic form. +// +// There is no guarantee about which form \p S takes when this method is called. +DEF_TRAVERSE_STMT(InitListExpr, { + TRY_TO(TraverseSynOrSemInitListExpr( + S->isSemanticForm() ? S->getSyntacticForm() : S, Queue)); + TRY_TO(TraverseSynOrSemInitListExpr( + S->isSemanticForm() ? S : S->getSemanticForm(), Queue)); + return true; +}) + +// GenericSelectionExpr is a special case because the types and expressions +// are interleaved. We also need to watch out for null types (default +// generic associations). +DEF_TRAVERSE_STMT(GenericSelectionExpr, { + TRY_TO(TraverseStmt(S->getControllingExpr())); + for (unsigned i = 0; i != S->getNumAssocs(); ++i) { + if (TypeSourceInfo *TS = S->getAssocTypeSourceInfo(i)) + TRY_TO(TraverseTypeLoc(TS->getTypeLoc())); + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getAssocExpr(i)); + } + return true; +}) + +// PseudoObjectExpr is a special case because of the weirdness with +// syntactic expressions and opaque values. +DEF_TRAVERSE_STMT(PseudoObjectExpr, { + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getSyntacticForm()); + for (PseudoObjectExpr::semantics_iterator i = S->semantics_begin(), + e = S->semantics_end(); + i != e; ++i) { + Expr *sub = *i; + if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(sub)) + sub = OVE->getSourceExpr(); + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(sub); + } + return true; +}) + +DEF_TRAVERSE_STMT(CXXScalarValueInitExpr, { + // This is called for code like 'return T()' where T is a built-in + // (i.e. non-class) type. + TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc())); +}) + +DEF_TRAVERSE_STMT(CXXNewExpr, { + // The child-iterator will pick up the other arguments. + TRY_TO(TraverseTypeLoc(S->getAllocatedTypeSourceInfo()->getTypeLoc())); +}) + +DEF_TRAVERSE_STMT(OffsetOfExpr, { + // The child-iterator will pick up the expression representing + // the field. + // FIMXE: for code like offsetof(Foo, a.b.c), should we get + // making a MemberExpr callbacks for Foo.a, Foo.a.b, and Foo.a.b.c? + TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc())); +}) + +DEF_TRAVERSE_STMT(UnaryExprOrTypeTraitExpr, { + // The child-iterator will pick up the arg if it's an expression, + // but not if it's a type. + if (S->isArgumentType()) + TRY_TO(TraverseTypeLoc(S->getArgumentTypeInfo()->getTypeLoc())); +}) + +DEF_TRAVERSE_STMT(CXXTypeidExpr, { + // The child-iterator will pick up the arg if it's an expression, + // but not if it's a type. + if (S->isTypeOperand()) + TRY_TO(TraverseTypeLoc(S->getTypeOperandSourceInfo()->getTypeLoc())); +}) + +DEF_TRAVERSE_STMT(MSPropertyRefExpr, { + TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc())); +}) + +DEF_TRAVERSE_STMT(MSPropertySubscriptExpr, {}) + +DEF_TRAVERSE_STMT(CXXUuidofExpr, { + // The child-iterator will pick up the arg if it's an expression, + // but not if it's a type. + if (S->isTypeOperand()) + TRY_TO(TraverseTypeLoc(S->getTypeOperandSourceInfo()->getTypeLoc())); +}) + +DEF_TRAVERSE_STMT(TypeTraitExpr, { + for (unsigned I = 0, N = S->getNumArgs(); I != N; ++I) + TRY_TO(TraverseTypeLoc(S->getArg(I)->getTypeLoc())); +}) + +DEF_TRAVERSE_STMT(ArrayTypeTraitExpr, { + TRY_TO(TraverseTypeLoc(S->getQueriedTypeSourceInfo()->getTypeLoc())); +}) + +DEF_TRAVERSE_STMT(ExpressionTraitExpr, + { TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getQueriedExpression()); }) + +DEF_TRAVERSE_STMT(VAArgExpr, { + // The child-iterator will pick up the expression argument. + TRY_TO(TraverseTypeLoc(S->getWrittenTypeInfo()->getTypeLoc())); +}) + +DEF_TRAVERSE_STMT(CXXTemporaryObjectExpr, { + // This is called for code like 'return T()' where T is a class type. + TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc())); +}) + +// Walk only the visible parts of lambda expressions. +DEF_TRAVERSE_STMT(LambdaExpr, { + for (LambdaExpr::capture_iterator C = S->explicit_capture_begin(), + CEnd = S->explicit_capture_end(); + C != CEnd; ++C) { + TRY_TO(TraverseLambdaCapture(S, C)); + } + + TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc(); + FunctionProtoTypeLoc Proto = TL.castAs<FunctionProtoTypeLoc>(); + + if (S->hasExplicitParameters() && S->hasExplicitResultType()) { + // Visit the whole type. + TRY_TO(TraverseTypeLoc(TL)); + } else { + if (S->hasExplicitParameters()) { + // Visit parameters. + for (unsigned I = 0, N = Proto.getNumParams(); I != N; ++I) { + TRY_TO(TraverseDecl(Proto.getParam(I))); + } + } else if (S->hasExplicitResultType()) { + TRY_TO(TraverseTypeLoc(Proto.getReturnLoc())); + } + + auto *T = Proto.getTypePtr(); + for (const auto &E : T->exceptions()) { + TRY_TO(TraverseType(E)); + } + + if (Expr *NE = T->getNoexceptExpr()) + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(NE); + } + + return TRAVERSE_STMT_BASE(LambdaBody, LambdaExpr, S, Queue); +}) + +DEF_TRAVERSE_STMT(CXXUnresolvedConstructExpr, { + // This is called for code like 'T()', where T is a template argument. + TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc())); +}) + +// These expressions all might take explicit template arguments. +// We traverse those if so. FIXME: implement these. +DEF_TRAVERSE_STMT(CXXConstructExpr, {}) +DEF_TRAVERSE_STMT(CallExpr, {}) +DEF_TRAVERSE_STMT(CXXMemberCallExpr, {}) + +// These exprs (most of them), do not need any action except iterating +// over the children. +DEF_TRAVERSE_STMT(AddrLabelExpr, {}) +DEF_TRAVERSE_STMT(ArraySubscriptExpr, {}) +DEF_TRAVERSE_STMT(OMPArraySectionExpr, {}) +DEF_TRAVERSE_STMT(BlockExpr, { + TRY_TO(TraverseDecl(S->getBlockDecl())); + return true; // no child statements to loop through. +}) +DEF_TRAVERSE_STMT(ChooseExpr, {}) +DEF_TRAVERSE_STMT(CompoundLiteralExpr, { + TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc())); +}) +DEF_TRAVERSE_STMT(CXXBindTemporaryExpr, {}) +DEF_TRAVERSE_STMT(CXXBoolLiteralExpr, {}) +DEF_TRAVERSE_STMT(CXXDefaultArgExpr, {}) +DEF_TRAVERSE_STMT(CXXDefaultInitExpr, {}) +DEF_TRAVERSE_STMT(CXXDeleteExpr, {}) +DEF_TRAVERSE_STMT(ExprWithCleanups, {}) +DEF_TRAVERSE_STMT(CXXNullPtrLiteralExpr, {}) +DEF_TRAVERSE_STMT(CXXStdInitializerListExpr, {}) +DEF_TRAVERSE_STMT(CXXPseudoDestructorExpr, { + TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc())); + if (TypeSourceInfo *ScopeInfo = S->getScopeTypeInfo()) + TRY_TO(TraverseTypeLoc(ScopeInfo->getTypeLoc())); + if (TypeSourceInfo *DestroyedTypeInfo = S->getDestroyedTypeInfo()) + TRY_TO(TraverseTypeLoc(DestroyedTypeInfo->getTypeLoc())); +}) +DEF_TRAVERSE_STMT(CXXThisExpr, {}) +DEF_TRAVERSE_STMT(CXXThrowExpr, {}) +DEF_TRAVERSE_STMT(UserDefinedLiteral, {}) +DEF_TRAVERSE_STMT(DesignatedInitExpr, {}) +DEF_TRAVERSE_STMT(DesignatedInitUpdateExpr, {}) +DEF_TRAVERSE_STMT(ExtVectorElementExpr, {}) +DEF_TRAVERSE_STMT(GNUNullExpr, {}) +DEF_TRAVERSE_STMT(ImplicitValueInitExpr, {}) +DEF_TRAVERSE_STMT(NoInitExpr, {}) +DEF_TRAVERSE_STMT(ObjCBoolLiteralExpr, {}) +DEF_TRAVERSE_STMT(ObjCEncodeExpr, { + if (TypeSourceInfo *TInfo = S->getEncodedTypeSourceInfo()) + TRY_TO(TraverseTypeLoc(TInfo->getTypeLoc())); +}) +DEF_TRAVERSE_STMT(ObjCIsaExpr, {}) +DEF_TRAVERSE_STMT(ObjCIvarRefExpr, {}) +DEF_TRAVERSE_STMT(ObjCMessageExpr, { + if (TypeSourceInfo *TInfo = S->getClassReceiverTypeInfo()) + TRY_TO(TraverseTypeLoc(TInfo->getTypeLoc())); +}) +DEF_TRAVERSE_STMT(ObjCPropertyRefExpr, {}) +DEF_TRAVERSE_STMT(ObjCSubscriptRefExpr, {}) +DEF_TRAVERSE_STMT(ObjCProtocolExpr, {}) +DEF_TRAVERSE_STMT(ObjCSelectorExpr, {}) +DEF_TRAVERSE_STMT(ObjCIndirectCopyRestoreExpr, {}) +DEF_TRAVERSE_STMT(ObjCBridgedCastExpr, { + TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc())); +}) +DEF_TRAVERSE_STMT(ParenExpr, {}) +DEF_TRAVERSE_STMT(ParenListExpr, {}) +DEF_TRAVERSE_STMT(PredefinedExpr, {}) +DEF_TRAVERSE_STMT(ShuffleVectorExpr, {}) +DEF_TRAVERSE_STMT(ConvertVectorExpr, {}) +DEF_TRAVERSE_STMT(StmtExpr, {}) +DEF_TRAVERSE_STMT(UnresolvedLookupExpr, { + TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc())); + if (S->hasExplicitTemplateArgs()) { + TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(), + S->getNumTemplateArgs())); + } +}) + +DEF_TRAVERSE_STMT(UnresolvedMemberExpr, { + TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc())); + if (S->hasExplicitTemplateArgs()) { + TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(), + S->getNumTemplateArgs())); + } +}) + +DEF_TRAVERSE_STMT(SEHTryStmt, {}) +DEF_TRAVERSE_STMT(SEHExceptStmt, {}) +DEF_TRAVERSE_STMT(SEHFinallyStmt, {}) +DEF_TRAVERSE_STMT(SEHLeaveStmt, {}) +DEF_TRAVERSE_STMT(CapturedStmt, { TRY_TO(TraverseDecl(S->getCapturedDecl())); }) + +DEF_TRAVERSE_STMT(CXXOperatorCallExpr, {}) +DEF_TRAVERSE_STMT(OpaqueValueExpr, {}) +DEF_TRAVERSE_STMT(TypoExpr, {}) +DEF_TRAVERSE_STMT(CUDAKernelCallExpr, {}) + +// These operators (all of them) do not need any action except +// iterating over the children. +DEF_TRAVERSE_STMT(BinaryConditionalOperator, {}) +DEF_TRAVERSE_STMT(ConditionalOperator, {}) +DEF_TRAVERSE_STMT(UnaryOperator, {}) +DEF_TRAVERSE_STMT(BinaryOperator, {}) +DEF_TRAVERSE_STMT(CompoundAssignOperator, {}) +DEF_TRAVERSE_STMT(CXXNoexceptExpr, {}) +DEF_TRAVERSE_STMT(PackExpansionExpr, {}) +DEF_TRAVERSE_STMT(SizeOfPackExpr, {}) +DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, {}) +DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmExpr, {}) +DEF_TRAVERSE_STMT(FunctionParmPackExpr, {}) +DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, {}) +DEF_TRAVERSE_STMT(CXXFoldExpr, {}) +DEF_TRAVERSE_STMT(AtomicExpr, {}) + +// For coroutines expressions, traverse either the operand +// as written or the implied calls, depending on what the +// derived class requests. +DEF_TRAVERSE_STMT(CoroutineBodyStmt, { + if (!getDerived().shouldVisitImplicitCode()) { + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getBody()); + return true; + } +}) +DEF_TRAVERSE_STMT(CoreturnStmt, { + if (!getDerived().shouldVisitImplicitCode()) { + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getOperand()); + return true; + } +}) +DEF_TRAVERSE_STMT(CoawaitExpr, { + if (!getDerived().shouldVisitImplicitCode()) { + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getOperand()); + return true; + } +}) +DEF_TRAVERSE_STMT(CoyieldExpr, { + if (!getDerived().shouldVisitImplicitCode()) { + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getOperand()); + return true; + } +}) + +// These literals (all of them) do not need any action. +DEF_TRAVERSE_STMT(IntegerLiteral, {}) +DEF_TRAVERSE_STMT(CharacterLiteral, {}) +DEF_TRAVERSE_STMT(FloatingLiteral, {}) +DEF_TRAVERSE_STMT(ImaginaryLiteral, {}) +DEF_TRAVERSE_STMT(StringLiteral, {}) +DEF_TRAVERSE_STMT(ObjCStringLiteral, {}) +DEF_TRAVERSE_STMT(ObjCBoxedExpr, {}) +DEF_TRAVERSE_STMT(ObjCArrayLiteral, {}) +DEF_TRAVERSE_STMT(ObjCDictionaryLiteral, {}) + +// Traverse OpenCL: AsType, Convert. +DEF_TRAVERSE_STMT(AsTypeExpr, {}) + +// OpenMP directives. +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseOMPExecutableDirective( + OMPExecutableDirective *S) { + for (auto *C : S->clauses()) { + TRY_TO(TraverseOMPClause(C)); + } + return true; +} + +template <typename Derived> +bool +RecursiveASTVisitor<Derived>::TraverseOMPLoopDirective(OMPLoopDirective *S) { + return TraverseOMPExecutableDirective(S); +} + +DEF_TRAVERSE_STMT(OMPParallelDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPSimdDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPForDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPForSimdDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPSectionsDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPSectionDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPSingleDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPMasterDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPCriticalDirective, { + TRY_TO(TraverseDeclarationNameInfo(S->getDirectiveName())); + TRY_TO(TraverseOMPExecutableDirective(S)); +}) + +DEF_TRAVERSE_STMT(OMPParallelForDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPParallelForSimdDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPParallelSectionsDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPTaskDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPTaskyieldDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPBarrierDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPTaskwaitDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPTaskgroupDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPCancellationPointDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPCancelDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPFlushDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPOrderedDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPAtomicDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPTargetDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPTargetDataDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPTeamsDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPTaskLoopDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPTaskLoopSimdDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPDistributeDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +// OpenMP clauses. +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseOMPClause(OMPClause *C) { + if (!C) + return true; + switch (C->getClauseKind()) { +#define OPENMP_CLAUSE(Name, Class) \ + case OMPC_##Name: \ + TRY_TO(Visit##Class(static_cast<Class *>(C))); \ + break; +#include "clang/Basic/OpenMPKinds.def" + case OMPC_threadprivate: + case OMPC_unknown: + break; + } + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPIfClause(OMPIfClause *C) { + TRY_TO(TraverseStmt(C->getCondition())); + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPFinalClause(OMPFinalClause *C) { + TRY_TO(TraverseStmt(C->getCondition())); + return true; +} + +template <typename Derived> +bool +RecursiveASTVisitor<Derived>::VisitOMPNumThreadsClause(OMPNumThreadsClause *C) { + TRY_TO(TraverseStmt(C->getNumThreads())); + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPSafelenClause(OMPSafelenClause *C) { + TRY_TO(TraverseStmt(C->getSafelen())); + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPSimdlenClause(OMPSimdlenClause *C) { + TRY_TO(TraverseStmt(C->getSimdlen())); + return true; +} + +template <typename Derived> +bool +RecursiveASTVisitor<Derived>::VisitOMPCollapseClause(OMPCollapseClause *C) { + TRY_TO(TraverseStmt(C->getNumForLoops())); + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPDefaultClause(OMPDefaultClause *) { + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPProcBindClause(OMPProcBindClause *) { + return true; +} + +template <typename Derived> +bool +RecursiveASTVisitor<Derived>::VisitOMPScheduleClause(OMPScheduleClause *C) { + TRY_TO(TraverseStmt(C->getChunkSize())); + TRY_TO(TraverseStmt(C->getHelperChunkSize())); + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPOrderedClause(OMPOrderedClause *C) { + TRY_TO(TraverseStmt(C->getNumForLoops())); + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPNowaitClause(OMPNowaitClause *) { + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPUntiedClause(OMPUntiedClause *) { + return true; +} + +template <typename Derived> +bool +RecursiveASTVisitor<Derived>::VisitOMPMergeableClause(OMPMergeableClause *) { + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPReadClause(OMPReadClause *) { + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPWriteClause(OMPWriteClause *) { + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPUpdateClause(OMPUpdateClause *) { + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPCaptureClause(OMPCaptureClause *) { + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPSeqCstClause(OMPSeqCstClause *) { + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPThreadsClause(OMPThreadsClause *) { + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPSIMDClause(OMPSIMDClause *) { + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPNogroupClause(OMPNogroupClause *) { + return true; +} + +template <typename Derived> +template <typename T> +bool RecursiveASTVisitor<Derived>::VisitOMPClauseList(T *Node) { + for (auto *E : Node->varlists()) { + TRY_TO(TraverseStmt(E)); + } + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPPrivateClause(OMPPrivateClause *C) { + TRY_TO(VisitOMPClauseList(C)); + for (auto *E : C->private_copies()) { + TRY_TO(TraverseStmt(E)); + } + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPFirstprivateClause( + OMPFirstprivateClause *C) { + TRY_TO(VisitOMPClauseList(C)); + for (auto *E : C->private_copies()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->inits()) { + TRY_TO(TraverseStmt(E)); + } + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPLastprivateClause( + OMPLastprivateClause *C) { + TRY_TO(VisitOMPClauseList(C)); + for (auto *E : C->private_copies()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->source_exprs()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->destination_exprs()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->assignment_ops()) { + TRY_TO(TraverseStmt(E)); + } + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPSharedClause(OMPSharedClause *C) { + TRY_TO(VisitOMPClauseList(C)); + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPLinearClause(OMPLinearClause *C) { + TRY_TO(TraverseStmt(C->getStep())); + TRY_TO(TraverseStmt(C->getCalcStep())); + TRY_TO(VisitOMPClauseList(C)); + for (auto *E : C->privates()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->inits()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->updates()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->finals()) { + TRY_TO(TraverseStmt(E)); + } + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPAlignedClause(OMPAlignedClause *C) { + TRY_TO(TraverseStmt(C->getAlignment())); + TRY_TO(VisitOMPClauseList(C)); + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPCopyinClause(OMPCopyinClause *C) { + TRY_TO(VisitOMPClauseList(C)); + for (auto *E : C->source_exprs()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->destination_exprs()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->assignment_ops()) { + TRY_TO(TraverseStmt(E)); + } + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPCopyprivateClause( + OMPCopyprivateClause *C) { + TRY_TO(VisitOMPClauseList(C)); + for (auto *E : C->source_exprs()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->destination_exprs()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->assignment_ops()) { + TRY_TO(TraverseStmt(E)); + } + return true; +} + +template <typename Derived> +bool +RecursiveASTVisitor<Derived>::VisitOMPReductionClause(OMPReductionClause *C) { + TRY_TO(TraverseNestedNameSpecifierLoc(C->getQualifierLoc())); + TRY_TO(TraverseDeclarationNameInfo(C->getNameInfo())); + TRY_TO(VisitOMPClauseList(C)); + for (auto *E : C->privates()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->lhs_exprs()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->rhs_exprs()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->reduction_ops()) { + TRY_TO(TraverseStmt(E)); + } + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPFlushClause(OMPFlushClause *C) { + TRY_TO(VisitOMPClauseList(C)); + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPDependClause(OMPDependClause *C) { + TRY_TO(VisitOMPClauseList(C)); + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPDeviceClause(OMPDeviceClause *C) { + TRY_TO(TraverseStmt(C->getDevice())); + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPMapClause(OMPMapClause *C) { + TRY_TO(VisitOMPClauseList(C)); + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPNumTeamsClause( + OMPNumTeamsClause *C) { + TRY_TO(TraverseStmt(C->getNumTeams())); + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPThreadLimitClause( + OMPThreadLimitClause *C) { + TRY_TO(TraverseStmt(C->getThreadLimit())); + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPPriorityClause( + OMPPriorityClause *C) { + TRY_TO(TraverseStmt(C->getPriority())); + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPGrainsizeClause( + OMPGrainsizeClause *C) { + TRY_TO(TraverseStmt(C->getGrainsize())); + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPNumTasksClause( + OMPNumTasksClause *C) { + TRY_TO(TraverseStmt(C->getNumTasks())); + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPHintClause(OMPHintClause *C) { + TRY_TO(TraverseStmt(C->getHint())); + return true; +} + +// FIXME: look at the following tricky-seeming exprs to see if we +// need to recurse on anything. These are ones that have methods +// returning decls or qualtypes or nestednamespecifier -- though I'm +// not sure if they own them -- or just seemed very complicated, or +// had lots of sub-types to explore. +// +// VisitOverloadExpr and its children: recurse on template args? etc? + +// FIXME: go through all the stmts and exprs again, and see which of them +// create new types, and recurse on the types (TypeLocs?) of those. +// Candidates: +// +// http://clang.llvm.org/doxygen/classclang_1_1CXXTypeidExpr.html +// http://clang.llvm.org/doxygen/classclang_1_1UnaryExprOrTypeTraitExpr.html +// http://clang.llvm.org/doxygen/classclang_1_1TypesCompatibleExpr.html +// Every class that has getQualifier. + +#undef DEF_TRAVERSE_STMT +#undef TRAVERSE_STMT +#undef TRAVERSE_STMT_BASE + +#undef TRY_TO + +} // end namespace clang + +#endif // LLVM_CLANG_AST_RECURSIVEASTVISITOR_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/Redeclarable.h b/contrib/llvm/tools/clang/include/clang/AST/Redeclarable.h new file mode 100644 index 0000000..eaa22f8 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/Redeclarable.h @@ -0,0 +1,285 @@ +//===-- Redeclarable.h - Base for Decls that can be redeclared -*- C++ -*-====// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Redeclarable interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_REDECLARABLE_H +#define LLVM_CLANG_AST_REDECLARABLE_H + +#include "clang/AST/ExternalASTSource.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/Support/Casting.h" +#include <iterator> + +namespace clang { +class ASTContext; + +/// \brief Provides common interface for the Decls that can be redeclared. +template<typename decl_type> +class Redeclarable { +protected: + class DeclLink { + /// A pointer to a known latest declaration, either statically known or + /// generationally updated as decls are added by an external source. + typedef LazyGenerationalUpdatePtr<const Decl*, Decl*, + &ExternalASTSource::CompleteRedeclChain> + KnownLatest; + + /// We store a pointer to the ASTContext in the UninitializedLatest + /// pointer, but to avoid circular type dependencies when we steal the low + /// bits of this pointer, we use a raw void* here. + typedef const void *UninitializedLatest; + + typedef Decl *Previous; + + /// A pointer to either an uninitialized latest declaration (where either + /// we've not yet set the previous decl or there isn't one), or to a known + /// previous declaration. + typedef llvm::PointerUnion<Previous, UninitializedLatest> NotKnownLatest; + + mutable llvm::PointerUnion<NotKnownLatest, KnownLatest> Next; + + public: + enum PreviousTag { PreviousLink }; + enum LatestTag { LatestLink }; + + DeclLink(LatestTag, const ASTContext &Ctx) + : Next(NotKnownLatest(reinterpret_cast<UninitializedLatest>(&Ctx))) {} + DeclLink(PreviousTag, decl_type *D) + : Next(NotKnownLatest(Previous(D))) {} + + bool NextIsPrevious() const { + return Next.is<NotKnownLatest>() && + // FIXME: 'template' is required on the next line due to an + // apparent clang bug. + Next.get<NotKnownLatest>().template is<Previous>(); + } + + bool NextIsLatest() const { return !NextIsPrevious(); } + + decl_type *getNext(const decl_type *D) const { + if (Next.is<NotKnownLatest>()) { + NotKnownLatest NKL = Next.get<NotKnownLatest>(); + if (NKL.is<Previous>()) + return static_cast<decl_type*>(NKL.get<Previous>()); + + // Allocate the generational 'most recent' cache now, if needed. + Next = KnownLatest(*reinterpret_cast<const ASTContext *>( + NKL.get<UninitializedLatest>()), + const_cast<decl_type *>(D)); + } + + return static_cast<decl_type*>(Next.get<KnownLatest>().get(D)); + } + + void setPrevious(decl_type *D) { + assert(NextIsPrevious() && "decl became non-canonical unexpectedly"); + Next = Previous(D); + } + + void setLatest(decl_type *D) { + assert(NextIsLatest() && "decl became canonical unexpectedly"); + if (Next.is<NotKnownLatest>()) { + NotKnownLatest NKL = Next.get<NotKnownLatest>(); + Next = KnownLatest(*reinterpret_cast<const ASTContext *>( + NKL.get<UninitializedLatest>()), + D); + } else { + auto Latest = Next.get<KnownLatest>(); + Latest.set(D); + Next = Latest; + } + } + + void markIncomplete() { Next.get<KnownLatest>().markIncomplete(); } + + Decl *getLatestNotUpdated() const { + assert(NextIsLatest() && "expected a canonical decl"); + if (Next.is<NotKnownLatest>()) + return nullptr; + return Next.get<KnownLatest>().getNotUpdated(); + } + }; + + static DeclLink PreviousDeclLink(decl_type *D) { + return DeclLink(DeclLink::PreviousLink, D); + } + + static DeclLink LatestDeclLink(const ASTContext &Ctx) { + return DeclLink(DeclLink::LatestLink, Ctx); + } + + /// \brief Points to the next redeclaration in the chain. + /// + /// If NextIsPrevious() is true, this is a link to the previous declaration + /// of this same Decl. If NextIsLatest() is true, this is the first + /// declaration and Link points to the latest declaration. For example: + /// + /// #1 int f(int x, int y = 1); // <pointer to #3, true> + /// #2 int f(int x = 0, int y); // <pointer to #1, false> + /// #3 int f(int x, int y) { return x + y; } // <pointer to #2, false> + /// + /// If there is only one declaration, it is <pointer to self, true> + DeclLink RedeclLink; + decl_type *First; + + decl_type *getNextRedeclaration() const { + return RedeclLink.getNext(static_cast<const decl_type *>(this)); + } + +public: + Redeclarable(const ASTContext &Ctx) + : RedeclLink(LatestDeclLink(Ctx)), First(static_cast<decl_type *>(this)) {} + + /// \brief Return the previous declaration of this declaration or NULL if this + /// is the first declaration. + decl_type *getPreviousDecl() { + if (RedeclLink.NextIsPrevious()) + return getNextRedeclaration(); + return nullptr; + } + const decl_type *getPreviousDecl() const { + return const_cast<decl_type *>( + static_cast<const decl_type*>(this))->getPreviousDecl(); + } + + /// \brief Return the first declaration of this declaration or itself if this + /// is the only declaration. + decl_type *getFirstDecl() { return First; } + + /// \brief Return the first declaration of this declaration or itself if this + /// is the only declaration. + const decl_type *getFirstDecl() const { return First; } + + /// \brief True if this is the first declaration in its redeclaration chain. + bool isFirstDecl() const { return RedeclLink.NextIsLatest(); } + + /// \brief Returns the most recent (re)declaration of this declaration. + decl_type *getMostRecentDecl() { + return getFirstDecl()->getNextRedeclaration(); + } + + /// \brief Returns the most recent (re)declaration of this declaration. + const decl_type *getMostRecentDecl() const { + return getFirstDecl()->getNextRedeclaration(); + } + + /// \brief Set the previous declaration. If PrevDecl is NULL, set this as the + /// first and only declaration. + void setPreviousDecl(decl_type *PrevDecl); + + /// \brief Iterates through all the redeclarations of the same decl. + class redecl_iterator { + /// Current - The current declaration. + decl_type *Current; + decl_type *Starter; + bool PassedFirst; + + public: + typedef decl_type* value_type; + typedef decl_type* reference; + typedef decl_type* pointer; + typedef std::forward_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + + redecl_iterator() : Current(nullptr) { } + explicit redecl_iterator(decl_type *C) + : Current(C), Starter(C), PassedFirst(false) { } + + reference operator*() const { return Current; } + pointer operator->() const { return Current; } + + redecl_iterator& operator++() { + assert(Current && "Advancing while iterator has reached end"); + // Sanity check to avoid infinite loop on invalid redecl chain. + if (Current->isFirstDecl()) { + if (PassedFirst) { + assert(0 && "Passed first decl twice, invalid redecl chain!"); + Current = nullptr; + return *this; + } + PassedFirst = true; + } + + // Get either previous decl or latest decl. + decl_type *Next = Current->getNextRedeclaration(); + Current = (Next != Starter) ? Next : nullptr; + return *this; + } + + redecl_iterator operator++(int) { + redecl_iterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool operator==(redecl_iterator x, redecl_iterator y) { + return x.Current == y.Current; + } + friend bool operator!=(redecl_iterator x, redecl_iterator y) { + return x.Current != y.Current; + } + }; + + typedef llvm::iterator_range<redecl_iterator> redecl_range; + + /// \brief Returns an iterator range for all the redeclarations of the same + /// decl. It will iterate at least once (when this decl is the only one). + redecl_range redecls() const { + return redecl_range(redecl_iterator(const_cast<decl_type *>( + static_cast<const decl_type *>(this))), + redecl_iterator()); + } + + redecl_iterator redecls_begin() const { return redecls().begin(); } + redecl_iterator redecls_end() const { return redecls().end(); } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// \brief Get the primary declaration for a declaration from an AST file. That +/// will be the first-loaded declaration. +Decl *getPrimaryMergedDecl(Decl *D); + +/// \brief Provides common interface for the Decls that cannot be redeclared, +/// but can be merged if the same declaration is brought in from multiple +/// modules. +template<typename decl_type> +class Mergeable { +public: + Mergeable() {} + + /// \brief Return the first declaration of this declaration or itself if this + /// is the only declaration. + decl_type *getFirstDecl() { + decl_type *D = static_cast<decl_type*>(this); + if (!D->isFromASTFile()) + return D; + return cast<decl_type>(getPrimaryMergedDecl(const_cast<decl_type*>(D))); + } + + /// \brief Return the first declaration of this declaration or itself if this + /// is the only declaration. + const decl_type *getFirstDecl() const { + const decl_type *D = static_cast<const decl_type*>(this); + if (!D->isFromASTFile()) + return D; + return cast<decl_type>(getPrimaryMergedDecl(const_cast<decl_type*>(D))); + } + + /// \brief Returns true if this is the first declaration. + bool isFirstDecl() const { return getFirstDecl() == this; } +}; + +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/SelectorLocationsKind.h b/contrib/llvm/tools/clang/include/clang/AST/SelectorLocationsKind.h new file mode 100644 index 0000000..6d903f8 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/SelectorLocationsKind.h @@ -0,0 +1,83 @@ +//===--- SelectorLocationsKind.h - Kind of selector locations ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Describes whether the identifier locations for a selector are "standard" +// or not. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_SELECTORLOCATIONSKIND_H +#define LLVM_CLANG_AST_SELECTORLOCATIONSKIND_H + +#include "clang/Basic/LLVM.h" + +namespace clang { + class Selector; + class SourceLocation; + class Expr; + class ParmVarDecl; + +/// \brief Whether all locations of the selector identifiers are in a +/// "standard" position. +enum SelectorLocationsKind { + /// \brief Non-standard. + SelLoc_NonStandard = 0, + + /// \brief For nullary selectors, immediately before the end: + /// "[foo release]" / "-(void)release;" + /// Or immediately before the arguments: + /// "[foo first:1 second:2]" / "-(id)first:(int)x second:(int)y; + SelLoc_StandardNoSpace = 1, + + /// \brief For nullary selectors, immediately before the end: + /// "[foo release]" / "-(void)release;" + /// Or with a space between the arguments: + /// "[foo first: 1 second: 2]" / "-(id)first: (int)x second: (int)y; + SelLoc_StandardWithSpace = 2 +}; + +/// \brief Returns true if all \p SelLocs are in a "standard" location. +SelectorLocationsKind hasStandardSelectorLocs(Selector Sel, + ArrayRef<SourceLocation> SelLocs, + ArrayRef<Expr *> Args, + SourceLocation EndLoc); + +/// \brief Get the "standard" location of a selector identifier, e.g: +/// For nullary selectors, immediately before ']': "[foo release]" +/// +/// \param WithArgSpace if true the standard location is with a space apart +/// before arguments: "[foo first: 1 second: 2]" +/// If false: "[foo first:1 second:2]" +SourceLocation getStandardSelectorLoc(unsigned Index, + Selector Sel, + bool WithArgSpace, + ArrayRef<Expr *> Args, + SourceLocation EndLoc); + +/// \brief Returns true if all \p SelLocs are in a "standard" location. +SelectorLocationsKind hasStandardSelectorLocs(Selector Sel, + ArrayRef<SourceLocation> SelLocs, + ArrayRef<ParmVarDecl *> Args, + SourceLocation EndLoc); + +/// \brief Get the "standard" location of a selector identifier, e.g: +/// For nullary selectors, immediately before ']': "[foo release]" +/// +/// \param WithArgSpace if true the standard location is with a space apart +/// before arguments: "-(id)first: (int)x second: (int)y;" +/// If false: "-(id)first:(int)x second:(int)y;" +SourceLocation getStandardSelectorLoc(unsigned Index, + Selector Sel, + bool WithArgSpace, + ArrayRef<ParmVarDecl *> Args, + SourceLocation EndLoc); + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/Stmt.h b/contrib/llvm/tools/clang/include/clang/AST/Stmt.h new file mode 100644 index 0000000..e48b7dc --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/Stmt.h @@ -0,0 +1,2196 @@ +//===--- Stmt.h - Classes for representing statements -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Stmt interface and subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_STMT_H +#define LLVM_CLANG_AST_STMT_H + +#include "clang/AST/DeclGroup.h" +#include "clang/AST/StmtIterator.h" +#include "clang/Basic/CapturedStmt.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/iterator.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" +#include <string> + +namespace llvm { + class FoldingSetNodeID; +} + +namespace clang { + class ASTContext; + class Attr; + class CapturedDecl; + class Decl; + class Expr; + class IdentifierInfo; + class LabelDecl; + class ParmVarDecl; + class PrinterHelper; + struct PrintingPolicy; + class QualType; + class RecordDecl; + class SourceManager; + class StringLiteral; + class SwitchStmt; + class Token; + class VarDecl; + +//===----------------------------------------------------------------------===// +// AST classes for statements. +//===----------------------------------------------------------------------===// + +/// Stmt - This represents one statement. +/// +class LLVM_ALIGNAS(LLVM_PTR_SIZE) Stmt { +public: + enum StmtClass { + NoStmtClass = 0, +#define STMT(CLASS, PARENT) CLASS##Class, +#define STMT_RANGE(BASE, FIRST, LAST) \ + first##BASE##Constant=FIRST##Class, last##BASE##Constant=LAST##Class, +#define LAST_STMT_RANGE(BASE, FIRST, LAST) \ + first##BASE##Constant=FIRST##Class, last##BASE##Constant=LAST##Class +#define ABSTRACT_STMT(STMT) +#include "clang/AST/StmtNodes.inc" + }; + + // Make vanilla 'new' and 'delete' illegal for Stmts. +protected: + void *operator new(size_t bytes) LLVM_NOEXCEPT { + llvm_unreachable("Stmts cannot be allocated with regular 'new'."); + } + void operator delete(void *data) LLVM_NOEXCEPT { + llvm_unreachable("Stmts cannot be released with regular 'delete'."); + } + + class StmtBitfields { + friend class Stmt; + + /// \brief The statement class. + unsigned sClass : 8; + }; + enum { NumStmtBits = 8 }; + + class CompoundStmtBitfields { + friend class CompoundStmt; + unsigned : NumStmtBits; + + unsigned NumStmts : 32 - NumStmtBits; + }; + + class ExprBitfields { + friend class Expr; + friend class DeclRefExpr; // computeDependence + friend class InitListExpr; // ctor + friend class DesignatedInitExpr; // ctor + friend class BlockDeclRefExpr; // ctor + friend class ASTStmtReader; // deserialization + friend class CXXNewExpr; // ctor + friend class DependentScopeDeclRefExpr; // ctor + friend class CXXConstructExpr; // ctor + friend class CallExpr; // ctor + friend class OffsetOfExpr; // ctor + friend class ObjCMessageExpr; // ctor + friend class ObjCArrayLiteral; // ctor + friend class ObjCDictionaryLiteral; // ctor + friend class ShuffleVectorExpr; // ctor + friend class ParenListExpr; // ctor + friend class CXXUnresolvedConstructExpr; // ctor + friend class CXXDependentScopeMemberExpr; // ctor + friend class OverloadExpr; // ctor + friend class PseudoObjectExpr; // ctor + friend class AtomicExpr; // ctor + unsigned : NumStmtBits; + + unsigned ValueKind : 2; + unsigned ObjectKind : 2; + unsigned TypeDependent : 1; + unsigned ValueDependent : 1; + unsigned InstantiationDependent : 1; + unsigned ContainsUnexpandedParameterPack : 1; + }; + enum { NumExprBits = 16 }; + + class CharacterLiteralBitfields { + friend class CharacterLiteral; + unsigned : NumExprBits; + + unsigned Kind : 2; + }; + + enum APFloatSemantics { + IEEEhalf, + IEEEsingle, + IEEEdouble, + x87DoubleExtended, + IEEEquad, + PPCDoubleDouble + }; + + class FloatingLiteralBitfields { + friend class FloatingLiteral; + unsigned : NumExprBits; + + unsigned Semantics : 3; // Provides semantics for APFloat construction + unsigned IsExact : 1; + }; + + class UnaryExprOrTypeTraitExprBitfields { + friend class UnaryExprOrTypeTraitExpr; + unsigned : NumExprBits; + + unsigned Kind : 2; + unsigned IsType : 1; // true if operand is a type, false if an expression. + }; + + class DeclRefExprBitfields { + friend class DeclRefExpr; + friend class ASTStmtReader; // deserialization + unsigned : NumExprBits; + + unsigned HasQualifier : 1; + unsigned HasTemplateKWAndArgsInfo : 1; + unsigned HasFoundDecl : 1; + unsigned HadMultipleCandidates : 1; + unsigned RefersToEnclosingVariableOrCapture : 1; + }; + + class CastExprBitfields { + friend class CastExpr; + unsigned : NumExprBits; + + unsigned Kind : 6; + unsigned BasePathSize : 32 - 6 - NumExprBits; + }; + + class CallExprBitfields { + friend class CallExpr; + unsigned : NumExprBits; + + unsigned NumPreArgs : 1; + }; + + class ExprWithCleanupsBitfields { + friend class ExprWithCleanups; + friend class ASTStmtReader; // deserialization + + unsigned : NumExprBits; + + unsigned NumObjects : 32 - NumExprBits; + }; + + class PseudoObjectExprBitfields { + friend class PseudoObjectExpr; + friend class ASTStmtReader; // deserialization + + unsigned : NumExprBits; + + // These don't need to be particularly wide, because they're + // strictly limited by the forms of expressions we permit. + unsigned NumSubExprs : 8; + unsigned ResultIndex : 32 - 8 - NumExprBits; + }; + + class ObjCIndirectCopyRestoreExprBitfields { + friend class ObjCIndirectCopyRestoreExpr; + unsigned : NumExprBits; + + unsigned ShouldCopy : 1; + }; + + class InitListExprBitfields { + friend class InitListExpr; + + unsigned : NumExprBits; + + /// Whether this initializer list originally had a GNU array-range + /// designator in it. This is a temporary marker used by CodeGen. + unsigned HadArrayRangeDesignator : 1; + }; + + class TypeTraitExprBitfields { + friend class TypeTraitExpr; + friend class ASTStmtReader; + friend class ASTStmtWriter; + + unsigned : NumExprBits; + + /// \brief The kind of type trait, which is a value of a TypeTrait enumerator. + unsigned Kind : 8; + + /// \brief If this expression is not value-dependent, this indicates whether + /// the trait evaluated true or false. + unsigned Value : 1; + + /// \brief The number of arguments to this type trait. + unsigned NumArgs : 32 - 8 - 1 - NumExprBits; + }; + + union { + StmtBitfields StmtBits; + CompoundStmtBitfields CompoundStmtBits; + ExprBitfields ExprBits; + CharacterLiteralBitfields CharacterLiteralBits; + FloatingLiteralBitfields FloatingLiteralBits; + UnaryExprOrTypeTraitExprBitfields UnaryExprOrTypeTraitExprBits; + DeclRefExprBitfields DeclRefExprBits; + CastExprBitfields CastExprBits; + CallExprBitfields CallExprBits; + ExprWithCleanupsBitfields ExprWithCleanupsBits; + PseudoObjectExprBitfields PseudoObjectExprBits; + ObjCIndirectCopyRestoreExprBitfields ObjCIndirectCopyRestoreExprBits; + InitListExprBitfields InitListExprBits; + TypeTraitExprBitfields TypeTraitExprBits; + }; + + friend class ASTStmtReader; + friend class ASTStmtWriter; + +public: + // Only allow allocation of Stmts using the allocator in ASTContext + // or by doing a placement new. + void* operator new(size_t bytes, const ASTContext& C, + unsigned alignment = 8); + + void* operator new(size_t bytes, const ASTContext* C, + unsigned alignment = 8) { + return operator new(bytes, *C, alignment); + } + + void *operator new(size_t bytes, void *mem) LLVM_NOEXCEPT { return mem; } + + void operator delete(void *, const ASTContext &, unsigned) LLVM_NOEXCEPT {} + void operator delete(void *, const ASTContext *, unsigned) LLVM_NOEXCEPT {} + void operator delete(void *, size_t) LLVM_NOEXCEPT {} + void operator delete(void *, void *) LLVM_NOEXCEPT {} + +public: + /// \brief A placeholder type used to construct an empty shell of a + /// type, that will be filled in later (e.g., by some + /// de-serialization). + struct EmptyShell { }; + +protected: + /// Iterator for iterating over Stmt * arrays that contain only Expr * + /// + /// This is needed because AST nodes use Stmt* arrays to store + /// references to children (to be compatible with StmtIterator). + struct ExprIterator + : llvm::iterator_adaptor_base<ExprIterator, Stmt **, + std::random_access_iterator_tag, Expr *> { + ExprIterator() : iterator_adaptor_base(nullptr) {} + ExprIterator(Stmt **I) : iterator_adaptor_base(I) {} + + reference operator*() const { + assert((*I)->getStmtClass() >= firstExprConstant && + (*I)->getStmtClass() <= lastExprConstant); + return *reinterpret_cast<Expr **>(I); + } + }; + + /// Const iterator for iterating over Stmt * arrays that contain only Expr * + struct ConstExprIterator + : llvm::iterator_adaptor_base<ConstExprIterator, const Stmt *const *, + std::random_access_iterator_tag, + const Expr *const> { + ConstExprIterator() : iterator_adaptor_base(nullptr) {} + ConstExprIterator(const Stmt *const *I) : iterator_adaptor_base(I) {} + + reference operator*() const { + assert((*I)->getStmtClass() >= firstExprConstant && + (*I)->getStmtClass() <= lastExprConstant); + return *reinterpret_cast<const Expr *const *>(I); + } + }; + +private: + /// \brief Whether statistic collection is enabled. + static bool StatisticsEnabled; + +protected: + /// \brief Construct an empty statement. + explicit Stmt(StmtClass SC, EmptyShell) : Stmt(SC) {} + +public: + Stmt(StmtClass SC) { + static_assert(sizeof(*this) % llvm::AlignOf<void *>::Alignment == 0, + "Insufficient alignment!"); + StmtBits.sClass = SC; + if (StatisticsEnabled) Stmt::addStmtClass(SC); + } + + StmtClass getStmtClass() const { + return static_cast<StmtClass>(StmtBits.sClass); + } + const char *getStmtClassName() const; + + /// SourceLocation tokens are not useful in isolation - they are low level + /// value objects created/interpreted by SourceManager. We assume AST + /// clients will have a pointer to the respective SourceManager. + SourceRange getSourceRange() const LLVM_READONLY; + SourceLocation getLocStart() const LLVM_READONLY; + SourceLocation getLocEnd() const LLVM_READONLY; + + // global temp stats (until we have a per-module visitor) + static void addStmtClass(const StmtClass s); + static void EnableStatistics(); + static void PrintStats(); + + /// \brief Dumps the specified AST fragment and all subtrees to + /// \c llvm::errs(). + void dump() const; + void dump(SourceManager &SM) const; + void dump(raw_ostream &OS, SourceManager &SM) const; + void dump(raw_ostream &OS) const; + + /// dumpColor - same as dump(), but forces color highlighting. + void dumpColor() const; + + /// dumpPretty/printPretty - These two methods do a "pretty print" of the AST + /// back to its original source language syntax. + void dumpPretty(const ASTContext &Context) const; + void printPretty(raw_ostream &OS, PrinterHelper *Helper, + const PrintingPolicy &Policy, + unsigned Indentation = 0) const; + + /// viewAST - Visualize an AST rooted at this Stmt* using GraphViz. Only + /// works on systems with GraphViz (Mac OS X) or dot+gv installed. + void viewAST() const; + + /// Skip past any implicit AST nodes which might surround this + /// statement, such as ExprWithCleanups or ImplicitCastExpr nodes. + Stmt *IgnoreImplicit(); + + /// \brief Skip no-op (attributed, compound) container stmts and skip captured + /// stmt at the top, if \a IgnoreCaptured is true. + Stmt *IgnoreContainers(bool IgnoreCaptured = false); + + const Stmt *stripLabelLikeStatements() const; + Stmt *stripLabelLikeStatements() { + return const_cast<Stmt*>( + const_cast<const Stmt*>(this)->stripLabelLikeStatements()); + } + + /// Child Iterators: All subclasses must implement 'children' + /// to permit easy iteration over the substatements/subexpessions of an + /// AST node. This permits easy iteration over all nodes in the AST. + typedef StmtIterator child_iterator; + typedef ConstStmtIterator const_child_iterator; + + typedef llvm::iterator_range<child_iterator> child_range; + typedef llvm::iterator_range<const_child_iterator> const_child_range; + + child_range children(); + const_child_range children() const { + auto Children = const_cast<Stmt *>(this)->children(); + return const_child_range(Children.begin(), Children.end()); + } + + child_iterator child_begin() { return children().begin(); } + child_iterator child_end() { return children().end(); } + + const_child_iterator child_begin() const { return children().begin(); } + const_child_iterator child_end() const { return children().end(); } + + /// \brief Produce a unique representation of the given statement. + /// + /// \param ID once the profiling operation is complete, will contain + /// the unique representation of the given statement. + /// + /// \param Context the AST context in which the statement resides + /// + /// \param Canonical whether the profile should be based on the canonical + /// representation of this statement (e.g., where non-type template + /// parameters are identified by index/level rather than their + /// declaration pointers) or the exact representation of the statement as + /// written in the source. + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, + bool Canonical) const; +}; + +/// DeclStmt - Adaptor class for mixing declarations with statements and +/// expressions. For example, CompoundStmt mixes statements, expressions +/// and declarations (variables, types). Another example is ForStmt, where +/// the first statement can be an expression or a declaration. +/// +class DeclStmt : public Stmt { + DeclGroupRef DG; + SourceLocation StartLoc, EndLoc; + +public: + DeclStmt(DeclGroupRef dg, SourceLocation startLoc, + SourceLocation endLoc) : Stmt(DeclStmtClass), DG(dg), + StartLoc(startLoc), EndLoc(endLoc) {} + + /// \brief Build an empty declaration statement. + explicit DeclStmt(EmptyShell Empty) : Stmt(DeclStmtClass, Empty) { } + + /// isSingleDecl - This method returns true if this DeclStmt refers + /// to a single Decl. + bool isSingleDecl() const { + return DG.isSingleDecl(); + } + + const Decl *getSingleDecl() const { return DG.getSingleDecl(); } + Decl *getSingleDecl() { return DG.getSingleDecl(); } + + const DeclGroupRef getDeclGroup() const { return DG; } + DeclGroupRef getDeclGroup() { return DG; } + void setDeclGroup(DeclGroupRef DGR) { DG = DGR; } + + SourceLocation getStartLoc() const { return StartLoc; } + void setStartLoc(SourceLocation L) { StartLoc = L; } + SourceLocation getEndLoc() const { return EndLoc; } + void setEndLoc(SourceLocation L) { EndLoc = L; } + + SourceLocation getLocStart() const LLVM_READONLY { return StartLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return EndLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == DeclStmtClass; + } + + // Iterators over subexpressions. + child_range children() { + return child_range(child_iterator(DG.begin(), DG.end()), + child_iterator(DG.end(), DG.end())); + } + + typedef DeclGroupRef::iterator decl_iterator; + typedef DeclGroupRef::const_iterator const_decl_iterator; + typedef llvm::iterator_range<decl_iterator> decl_range; + typedef llvm::iterator_range<const_decl_iterator> decl_const_range; + + decl_range decls() { return decl_range(decl_begin(), decl_end()); } + decl_const_range decls() const { + return decl_const_range(decl_begin(), decl_end()); + } + decl_iterator decl_begin() { return DG.begin(); } + decl_iterator decl_end() { return DG.end(); } + const_decl_iterator decl_begin() const { return DG.begin(); } + const_decl_iterator decl_end() const { return DG.end(); } + + typedef std::reverse_iterator<decl_iterator> reverse_decl_iterator; + reverse_decl_iterator decl_rbegin() { + return reverse_decl_iterator(decl_end()); + } + reverse_decl_iterator decl_rend() { + return reverse_decl_iterator(decl_begin()); + } +}; + +/// NullStmt - This is the null statement ";": C99 6.8.3p3. +/// +class NullStmt : public Stmt { + SourceLocation SemiLoc; + + /// \brief True if the null statement was preceded by an empty macro, e.g: + /// @code + /// #define CALL(x) + /// CALL(0); + /// @endcode + bool HasLeadingEmptyMacro; +public: + NullStmt(SourceLocation L, bool hasLeadingEmptyMacro = false) + : Stmt(NullStmtClass), SemiLoc(L), + HasLeadingEmptyMacro(hasLeadingEmptyMacro) {} + + /// \brief Build an empty null statement. + explicit NullStmt(EmptyShell Empty) : Stmt(NullStmtClass, Empty), + HasLeadingEmptyMacro(false) { } + + SourceLocation getSemiLoc() const { return SemiLoc; } + void setSemiLoc(SourceLocation L) { SemiLoc = L; } + + bool hasLeadingEmptyMacro() const { return HasLeadingEmptyMacro; } + + SourceLocation getLocStart() const LLVM_READONLY { return SemiLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return SemiLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == NullStmtClass; + } + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + + friend class ASTStmtReader; + friend class ASTStmtWriter; +}; + +/// CompoundStmt - This represents a group of statements like { stmt stmt }. +/// +class CompoundStmt : public Stmt { + Stmt** Body; + SourceLocation LBraceLoc, RBraceLoc; + + friend class ASTStmtReader; + +public: + CompoundStmt(const ASTContext &C, ArrayRef<Stmt*> Stmts, + SourceLocation LB, SourceLocation RB); + + // \brief Build an empty compound statement with a location. + explicit CompoundStmt(SourceLocation Loc) + : Stmt(CompoundStmtClass), Body(nullptr), LBraceLoc(Loc), RBraceLoc(Loc) { + CompoundStmtBits.NumStmts = 0; + } + + // \brief Build an empty compound statement. + explicit CompoundStmt(EmptyShell Empty) + : Stmt(CompoundStmtClass, Empty), Body(nullptr) { + CompoundStmtBits.NumStmts = 0; + } + + void setStmts(const ASTContext &C, ArrayRef<Stmt *> Stmts); + + bool body_empty() const { return CompoundStmtBits.NumStmts == 0; } + unsigned size() const { return CompoundStmtBits.NumStmts; } + + typedef Stmt** body_iterator; + typedef llvm::iterator_range<body_iterator> body_range; + + body_range body() { return body_range(body_begin(), body_end()); } + body_iterator body_begin() { return Body; } + body_iterator body_end() { return Body + size(); } + Stmt *body_front() { return !body_empty() ? Body[0] : nullptr; } + Stmt *body_back() { return !body_empty() ? Body[size()-1] : nullptr; } + + void setLastStmt(Stmt *S) { + assert(!body_empty() && "setLastStmt"); + Body[size()-1] = S; + } + + typedef Stmt* const * const_body_iterator; + typedef llvm::iterator_range<const_body_iterator> body_const_range; + + body_const_range body() const { + return body_const_range(body_begin(), body_end()); + } + const_body_iterator body_begin() const { return Body; } + const_body_iterator body_end() const { return Body + size(); } + const Stmt *body_front() const { + return !body_empty() ? Body[0] : nullptr; + } + const Stmt *body_back() const { + return !body_empty() ? Body[size() - 1] : nullptr; + } + + typedef std::reverse_iterator<body_iterator> reverse_body_iterator; + reverse_body_iterator body_rbegin() { + return reverse_body_iterator(body_end()); + } + reverse_body_iterator body_rend() { + return reverse_body_iterator(body_begin()); + } + + typedef std::reverse_iterator<const_body_iterator> + const_reverse_body_iterator; + + const_reverse_body_iterator body_rbegin() const { + return const_reverse_body_iterator(body_end()); + } + + const_reverse_body_iterator body_rend() const { + return const_reverse_body_iterator(body_begin()); + } + + SourceLocation getLocStart() const LLVM_READONLY { return LBraceLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return RBraceLoc; } + + SourceLocation getLBracLoc() const { return LBraceLoc; } + SourceLocation getRBracLoc() const { return RBraceLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CompoundStmtClass; + } + + // Iterators + child_range children() { + return child_range(Body, Body + CompoundStmtBits.NumStmts); + } + + const_child_range children() const { + return const_child_range(child_iterator(Body), + child_iterator(Body + CompoundStmtBits.NumStmts)); + } +}; + +// SwitchCase is the base class for CaseStmt and DefaultStmt, +class SwitchCase : public Stmt { +protected: + // A pointer to the following CaseStmt or DefaultStmt class, + // used by SwitchStmt. + SwitchCase *NextSwitchCase; + SourceLocation KeywordLoc; + SourceLocation ColonLoc; + + SwitchCase(StmtClass SC, SourceLocation KWLoc, SourceLocation ColonLoc) + : Stmt(SC), NextSwitchCase(nullptr), KeywordLoc(KWLoc), ColonLoc(ColonLoc) { + } + + SwitchCase(StmtClass SC, EmptyShell) + : Stmt(SC), NextSwitchCase(nullptr) {} + +public: + const SwitchCase *getNextSwitchCase() const { return NextSwitchCase; } + + SwitchCase *getNextSwitchCase() { return NextSwitchCase; } + + void setNextSwitchCase(SwitchCase *SC) { NextSwitchCase = SC; } + + SourceLocation getKeywordLoc() const { return KeywordLoc; } + void setKeywordLoc(SourceLocation L) { KeywordLoc = L; } + SourceLocation getColonLoc() const { return ColonLoc; } + void setColonLoc(SourceLocation L) { ColonLoc = L; } + + Stmt *getSubStmt(); + const Stmt *getSubStmt() const { + return const_cast<SwitchCase*>(this)->getSubStmt(); + } + + SourceLocation getLocStart() const LLVM_READONLY { return KeywordLoc; } + SourceLocation getLocEnd() const LLVM_READONLY; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CaseStmtClass || + T->getStmtClass() == DefaultStmtClass; + } +}; + +class CaseStmt : public SwitchCase { + SourceLocation EllipsisLoc; + enum { LHS, RHS, SUBSTMT, END_EXPR }; + Stmt* SubExprs[END_EXPR]; // The expression for the RHS is Non-null for + // GNU "case 1 ... 4" extension +public: + CaseStmt(Expr *lhs, Expr *rhs, SourceLocation caseLoc, + SourceLocation ellipsisLoc, SourceLocation colonLoc) + : SwitchCase(CaseStmtClass, caseLoc, colonLoc) { + SubExprs[SUBSTMT] = nullptr; + SubExprs[LHS] = reinterpret_cast<Stmt*>(lhs); + SubExprs[RHS] = reinterpret_cast<Stmt*>(rhs); + EllipsisLoc = ellipsisLoc; + } + + /// \brief Build an empty switch case statement. + explicit CaseStmt(EmptyShell Empty) : SwitchCase(CaseStmtClass, Empty) { } + + SourceLocation getCaseLoc() const { return KeywordLoc; } + void setCaseLoc(SourceLocation L) { KeywordLoc = L; } + SourceLocation getEllipsisLoc() const { return EllipsisLoc; } + void setEllipsisLoc(SourceLocation L) { EllipsisLoc = L; } + SourceLocation getColonLoc() const { return ColonLoc; } + void setColonLoc(SourceLocation L) { ColonLoc = L; } + + Expr *getLHS() { return reinterpret_cast<Expr*>(SubExprs[LHS]); } + Expr *getRHS() { return reinterpret_cast<Expr*>(SubExprs[RHS]); } + Stmt *getSubStmt() { return SubExprs[SUBSTMT]; } + + const Expr *getLHS() const { + return reinterpret_cast<const Expr*>(SubExprs[LHS]); + } + const Expr *getRHS() const { + return reinterpret_cast<const Expr*>(SubExprs[RHS]); + } + const Stmt *getSubStmt() const { return SubExprs[SUBSTMT]; } + + void setSubStmt(Stmt *S) { SubExprs[SUBSTMT] = S; } + void setLHS(Expr *Val) { SubExprs[LHS] = reinterpret_cast<Stmt*>(Val); } + void setRHS(Expr *Val) { SubExprs[RHS] = reinterpret_cast<Stmt*>(Val); } + + SourceLocation getLocStart() const LLVM_READONLY { return KeywordLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { + // Handle deeply nested case statements with iteration instead of recursion. + const CaseStmt *CS = this; + while (const CaseStmt *CS2 = dyn_cast<CaseStmt>(CS->getSubStmt())) + CS = CS2; + + return CS->getSubStmt()->getLocEnd(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CaseStmtClass; + } + + // Iterators + child_range children() { + return child_range(&SubExprs[0], &SubExprs[END_EXPR]); + } +}; + +class DefaultStmt : public SwitchCase { + Stmt* SubStmt; +public: + DefaultStmt(SourceLocation DL, SourceLocation CL, Stmt *substmt) : + SwitchCase(DefaultStmtClass, DL, CL), SubStmt(substmt) {} + + /// \brief Build an empty default statement. + explicit DefaultStmt(EmptyShell Empty) + : SwitchCase(DefaultStmtClass, Empty) { } + + Stmt *getSubStmt() { return SubStmt; } + const Stmt *getSubStmt() const { return SubStmt; } + void setSubStmt(Stmt *S) { SubStmt = S; } + + SourceLocation getDefaultLoc() const { return KeywordLoc; } + void setDefaultLoc(SourceLocation L) { KeywordLoc = L; } + SourceLocation getColonLoc() const { return ColonLoc; } + void setColonLoc(SourceLocation L) { ColonLoc = L; } + + SourceLocation getLocStart() const LLVM_READONLY { return KeywordLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return SubStmt->getLocEnd();} + + static bool classof(const Stmt *T) { + return T->getStmtClass() == DefaultStmtClass; + } + + // Iterators + child_range children() { return child_range(&SubStmt, &SubStmt+1); } +}; + +inline SourceLocation SwitchCase::getLocEnd() const { + if (const CaseStmt *CS = dyn_cast<CaseStmt>(this)) + return CS->getLocEnd(); + return cast<DefaultStmt>(this)->getLocEnd(); +} + +/// LabelStmt - Represents a label, which has a substatement. For example: +/// foo: return; +/// +class LabelStmt : public Stmt { + SourceLocation IdentLoc; + LabelDecl *TheDecl; + Stmt *SubStmt; + +public: + LabelStmt(SourceLocation IL, LabelDecl *D, Stmt *substmt) + : Stmt(LabelStmtClass), IdentLoc(IL), TheDecl(D), SubStmt(substmt) { + static_assert(sizeof(LabelStmt) == + 2 * sizeof(SourceLocation) + 2 * sizeof(void *), + "LabelStmt too big"); + } + + // \brief Build an empty label statement. + explicit LabelStmt(EmptyShell Empty) : Stmt(LabelStmtClass, Empty) { } + + SourceLocation getIdentLoc() const { return IdentLoc; } + LabelDecl *getDecl() const { return TheDecl; } + void setDecl(LabelDecl *D) { TheDecl = D; } + const char *getName() const; + Stmt *getSubStmt() { return SubStmt; } + const Stmt *getSubStmt() const { return SubStmt; } + void setIdentLoc(SourceLocation L) { IdentLoc = L; } + void setSubStmt(Stmt *SS) { SubStmt = SS; } + + SourceLocation getLocStart() const LLVM_READONLY { return IdentLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return SubStmt->getLocEnd();} + + child_range children() { return child_range(&SubStmt, &SubStmt+1); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == LabelStmtClass; + } +}; + + +/// \brief Represents an attribute applied to a statement. +/// +/// Represents an attribute applied to a statement. For example: +/// [[omp::for(...)]] for (...) { ... } +/// +class AttributedStmt : public Stmt { + Stmt *SubStmt; + SourceLocation AttrLoc; + unsigned NumAttrs; + + friend class ASTStmtReader; + + AttributedStmt(SourceLocation Loc, ArrayRef<const Attr*> Attrs, Stmt *SubStmt) + : Stmt(AttributedStmtClass), SubStmt(SubStmt), AttrLoc(Loc), + NumAttrs(Attrs.size()) { + std::copy(Attrs.begin(), Attrs.end(), getAttrArrayPtr()); + } + + explicit AttributedStmt(EmptyShell Empty, unsigned NumAttrs) + : Stmt(AttributedStmtClass, Empty), NumAttrs(NumAttrs) { + std::fill_n(getAttrArrayPtr(), NumAttrs, nullptr); + } + + const Attr *const *getAttrArrayPtr() const { + return reinterpret_cast<const Attr *const *>(this + 1); + } + const Attr **getAttrArrayPtr() { + return reinterpret_cast<const Attr **>(this + 1); + } + +public: + static AttributedStmt *Create(const ASTContext &C, SourceLocation Loc, + ArrayRef<const Attr*> Attrs, Stmt *SubStmt); + // \brief Build an empty attributed statement. + static AttributedStmt *CreateEmpty(const ASTContext &C, unsigned NumAttrs); + + SourceLocation getAttrLoc() const { return AttrLoc; } + ArrayRef<const Attr*> getAttrs() const { + return llvm::makeArrayRef(getAttrArrayPtr(), NumAttrs); + } + Stmt *getSubStmt() { return SubStmt; } + const Stmt *getSubStmt() const { return SubStmt; } + + SourceLocation getLocStart() const LLVM_READONLY { return AttrLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return SubStmt->getLocEnd();} + + child_range children() { return child_range(&SubStmt, &SubStmt + 1); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == AttributedStmtClass; + } +}; + + +/// IfStmt - This represents an if/then/else. +/// +class IfStmt : public Stmt { + enum { VAR, COND, THEN, ELSE, END_EXPR }; + Stmt* SubExprs[END_EXPR]; + + SourceLocation IfLoc; + SourceLocation ElseLoc; + +public: + IfStmt(const ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond, + Stmt *then, SourceLocation EL = SourceLocation(), + Stmt *elsev = nullptr); + + /// \brief Build an empty if/then/else statement + explicit IfStmt(EmptyShell Empty) : Stmt(IfStmtClass, Empty) { } + + /// \brief Retrieve the variable declared in this "if" statement, if any. + /// + /// In the following example, "x" is the condition variable. + /// \code + /// if (int x = foo()) { + /// printf("x is %d", x); + /// } + /// \endcode + VarDecl *getConditionVariable() const; + void setConditionVariable(const ASTContext &C, VarDecl *V); + + /// If this IfStmt has a condition variable, return the faux DeclStmt + /// associated with the creation of that condition variable. + const DeclStmt *getConditionVariableDeclStmt() const { + return reinterpret_cast<DeclStmt*>(SubExprs[VAR]); + } + + const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);} + void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt *>(E); } + const Stmt *getThen() const { return SubExprs[THEN]; } + void setThen(Stmt *S) { SubExprs[THEN] = S; } + const Stmt *getElse() const { return SubExprs[ELSE]; } + void setElse(Stmt *S) { SubExprs[ELSE] = S; } + + Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); } + Stmt *getThen() { return SubExprs[THEN]; } + Stmt *getElse() { return SubExprs[ELSE]; } + + SourceLocation getIfLoc() const { return IfLoc; } + void setIfLoc(SourceLocation L) { IfLoc = L; } + SourceLocation getElseLoc() const { return ElseLoc; } + void setElseLoc(SourceLocation L) { ElseLoc = L; } + + SourceLocation getLocStart() const LLVM_READONLY { return IfLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { + if (SubExprs[ELSE]) + return SubExprs[ELSE]->getLocEnd(); + else + return SubExprs[THEN]->getLocEnd(); + } + + // Iterators over subexpressions. The iterators will include iterating + // over the initialization expression referenced by the condition variable. + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == IfStmtClass; + } +}; + +/// SwitchStmt - This represents a 'switch' stmt. +/// +class SwitchStmt : public Stmt { + SourceLocation SwitchLoc; + enum { VAR, COND, BODY, END_EXPR }; + Stmt* SubExprs[END_EXPR]; + // This points to a linked list of case and default statements and, if the + // SwitchStmt is a switch on an enum value, records whether all the enum + // values were covered by CaseStmts. The coverage information value is meant + // to be a hint for possible clients. + llvm::PointerIntPair<SwitchCase *, 1, bool> FirstCase; + +public: + SwitchStmt(const ASTContext &C, VarDecl *Var, Expr *cond); + + /// \brief Build a empty switch statement. + explicit SwitchStmt(EmptyShell Empty) : Stmt(SwitchStmtClass, Empty) { } + + /// \brief Retrieve the variable declared in this "switch" statement, if any. + /// + /// In the following example, "x" is the condition variable. + /// \code + /// switch (int x = foo()) { + /// case 0: break; + /// // ... + /// } + /// \endcode + VarDecl *getConditionVariable() const; + void setConditionVariable(const ASTContext &C, VarDecl *V); + + /// If this SwitchStmt has a condition variable, return the faux DeclStmt + /// associated with the creation of that condition variable. + const DeclStmt *getConditionVariableDeclStmt() const { + return reinterpret_cast<DeclStmt*>(SubExprs[VAR]); + } + + const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);} + const Stmt *getBody() const { return SubExprs[BODY]; } + const SwitchCase *getSwitchCaseList() const { return FirstCase.getPointer(); } + + Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]);} + void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt *>(E); } + Stmt *getBody() { return SubExprs[BODY]; } + void setBody(Stmt *S) { SubExprs[BODY] = S; } + SwitchCase *getSwitchCaseList() { return FirstCase.getPointer(); } + + /// \brief Set the case list for this switch statement. + void setSwitchCaseList(SwitchCase *SC) { FirstCase.setPointer(SC); } + + SourceLocation getSwitchLoc() const { return SwitchLoc; } + void setSwitchLoc(SourceLocation L) { SwitchLoc = L; } + + void setBody(Stmt *S, SourceLocation SL) { + SubExprs[BODY] = S; + SwitchLoc = SL; + } + void addSwitchCase(SwitchCase *SC) { + assert(!SC->getNextSwitchCase() + && "case/default already added to a switch"); + SC->setNextSwitchCase(FirstCase.getPointer()); + FirstCase.setPointer(SC); + } + + /// Set a flag in the SwitchStmt indicating that if the 'switch (X)' is a + /// switch over an enum value then all cases have been explicitly covered. + void setAllEnumCasesCovered() { FirstCase.setInt(true); } + + /// Returns true if the SwitchStmt is a switch of an enum value and all cases + /// have been explicitly covered. + bool isAllEnumCasesCovered() const { return FirstCase.getInt(); } + + SourceLocation getLocStart() const LLVM_READONLY { return SwitchLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { + return SubExprs[BODY] ? SubExprs[BODY]->getLocEnd() : SubExprs[COND]->getLocEnd(); + } + + // Iterators + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == SwitchStmtClass; + } +}; + + +/// WhileStmt - This represents a 'while' stmt. +/// +class WhileStmt : public Stmt { + SourceLocation WhileLoc; + enum { VAR, COND, BODY, END_EXPR }; + Stmt* SubExprs[END_EXPR]; +public: + WhileStmt(const ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body, + SourceLocation WL); + + /// \brief Build an empty while statement. + explicit WhileStmt(EmptyShell Empty) : Stmt(WhileStmtClass, Empty) { } + + /// \brief Retrieve the variable declared in this "while" statement, if any. + /// + /// In the following example, "x" is the condition variable. + /// \code + /// while (int x = random()) { + /// // ... + /// } + /// \endcode + VarDecl *getConditionVariable() const; + void setConditionVariable(const ASTContext &C, VarDecl *V); + + /// If this WhileStmt has a condition variable, return the faux DeclStmt + /// associated with the creation of that condition variable. + const DeclStmt *getConditionVariableDeclStmt() const { + return reinterpret_cast<DeclStmt*>(SubExprs[VAR]); + } + + Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); } + const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);} + void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(E); } + Stmt *getBody() { return SubExprs[BODY]; } + const Stmt *getBody() const { return SubExprs[BODY]; } + void setBody(Stmt *S) { SubExprs[BODY] = S; } + + SourceLocation getWhileLoc() const { return WhileLoc; } + void setWhileLoc(SourceLocation L) { WhileLoc = L; } + + SourceLocation getLocStart() const LLVM_READONLY { return WhileLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { + return SubExprs[BODY]->getLocEnd(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == WhileStmtClass; + } + + // Iterators + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); + } +}; + +/// DoStmt - This represents a 'do/while' stmt. +/// +class DoStmt : public Stmt { + SourceLocation DoLoc; + enum { BODY, COND, END_EXPR }; + Stmt* SubExprs[END_EXPR]; + SourceLocation WhileLoc; + SourceLocation RParenLoc; // Location of final ')' in do stmt condition. + +public: + DoStmt(Stmt *body, Expr *cond, SourceLocation DL, SourceLocation WL, + SourceLocation RP) + : Stmt(DoStmtClass), DoLoc(DL), WhileLoc(WL), RParenLoc(RP) { + SubExprs[COND] = reinterpret_cast<Stmt*>(cond); + SubExprs[BODY] = body; + } + + /// \brief Build an empty do-while statement. + explicit DoStmt(EmptyShell Empty) : Stmt(DoStmtClass, Empty) { } + + Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); } + const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);} + void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(E); } + Stmt *getBody() { return SubExprs[BODY]; } + const Stmt *getBody() const { return SubExprs[BODY]; } + void setBody(Stmt *S) { SubExprs[BODY] = S; } + + SourceLocation getDoLoc() const { return DoLoc; } + void setDoLoc(SourceLocation L) { DoLoc = L; } + SourceLocation getWhileLoc() const { return WhileLoc; } + void setWhileLoc(SourceLocation L) { WhileLoc = L; } + + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + SourceLocation getLocStart() const LLVM_READONLY { return DoLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == DoStmtClass; + } + + // Iterators + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); + } +}; + + +/// ForStmt - This represents a 'for (init;cond;inc)' stmt. Note that any of +/// the init/cond/inc parts of the ForStmt will be null if they were not +/// specified in the source. +/// +class ForStmt : public Stmt { + SourceLocation ForLoc; + enum { INIT, CONDVAR, COND, INC, BODY, END_EXPR }; + Stmt* SubExprs[END_EXPR]; // SubExprs[INIT] is an expression or declstmt. + SourceLocation LParenLoc, RParenLoc; + +public: + ForStmt(const ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar, + Expr *Inc, Stmt *Body, SourceLocation FL, SourceLocation LP, + SourceLocation RP); + + /// \brief Build an empty for statement. + explicit ForStmt(EmptyShell Empty) : Stmt(ForStmtClass, Empty) { } + + Stmt *getInit() { return SubExprs[INIT]; } + + /// \brief Retrieve the variable declared in this "for" statement, if any. + /// + /// In the following example, "y" is the condition variable. + /// \code + /// for (int x = random(); int y = mangle(x); ++x) { + /// // ... + /// } + /// \endcode + VarDecl *getConditionVariable() const; + void setConditionVariable(const ASTContext &C, VarDecl *V); + + /// If this ForStmt has a condition variable, return the faux DeclStmt + /// associated with the creation of that condition variable. + const DeclStmt *getConditionVariableDeclStmt() const { + return reinterpret_cast<DeclStmt*>(SubExprs[CONDVAR]); + } + + Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); } + Expr *getInc() { return reinterpret_cast<Expr*>(SubExprs[INC]); } + Stmt *getBody() { return SubExprs[BODY]; } + + const Stmt *getInit() const { return SubExprs[INIT]; } + const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);} + const Expr *getInc() const { return reinterpret_cast<Expr*>(SubExprs[INC]); } + const Stmt *getBody() const { return SubExprs[BODY]; } + + void setInit(Stmt *S) { SubExprs[INIT] = S; } + void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(E); } + void setInc(Expr *E) { SubExprs[INC] = reinterpret_cast<Stmt*>(E); } + void setBody(Stmt *S) { SubExprs[BODY] = S; } + + SourceLocation getForLoc() const { return ForLoc; } + void setForLoc(SourceLocation L) { ForLoc = L; } + SourceLocation getLParenLoc() const { return LParenLoc; } + void setLParenLoc(SourceLocation L) { LParenLoc = L; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + SourceLocation getLocStart() const LLVM_READONLY { return ForLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { + return SubExprs[BODY]->getLocEnd(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ForStmtClass; + } + + // Iterators + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); + } +}; + +/// GotoStmt - This represents a direct goto. +/// +class GotoStmt : public Stmt { + LabelDecl *Label; + SourceLocation GotoLoc; + SourceLocation LabelLoc; +public: + GotoStmt(LabelDecl *label, SourceLocation GL, SourceLocation LL) + : Stmt(GotoStmtClass), Label(label), GotoLoc(GL), LabelLoc(LL) {} + + /// \brief Build an empty goto statement. + explicit GotoStmt(EmptyShell Empty) : Stmt(GotoStmtClass, Empty) { } + + LabelDecl *getLabel() const { return Label; } + void setLabel(LabelDecl *D) { Label = D; } + + SourceLocation getGotoLoc() const { return GotoLoc; } + void setGotoLoc(SourceLocation L) { GotoLoc = L; } + SourceLocation getLabelLoc() const { return LabelLoc; } + void setLabelLoc(SourceLocation L) { LabelLoc = L; } + + SourceLocation getLocStart() const LLVM_READONLY { return GotoLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return LabelLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == GotoStmtClass; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +/// IndirectGotoStmt - This represents an indirect goto. +/// +class IndirectGotoStmt : public Stmt { + SourceLocation GotoLoc; + SourceLocation StarLoc; + Stmt *Target; +public: + IndirectGotoStmt(SourceLocation gotoLoc, SourceLocation starLoc, + Expr *target) + : Stmt(IndirectGotoStmtClass), GotoLoc(gotoLoc), StarLoc(starLoc), + Target((Stmt*)target) {} + + /// \brief Build an empty indirect goto statement. + explicit IndirectGotoStmt(EmptyShell Empty) + : Stmt(IndirectGotoStmtClass, Empty) { } + + void setGotoLoc(SourceLocation L) { GotoLoc = L; } + SourceLocation getGotoLoc() const { return GotoLoc; } + void setStarLoc(SourceLocation L) { StarLoc = L; } + SourceLocation getStarLoc() const { return StarLoc; } + + Expr *getTarget() { return reinterpret_cast<Expr*>(Target); } + const Expr *getTarget() const {return reinterpret_cast<const Expr*>(Target);} + void setTarget(Expr *E) { Target = reinterpret_cast<Stmt*>(E); } + + /// getConstantTarget - Returns the fixed target of this indirect + /// goto, if one exists. + LabelDecl *getConstantTarget(); + const LabelDecl *getConstantTarget() const { + return const_cast<IndirectGotoStmt*>(this)->getConstantTarget(); + } + + SourceLocation getLocStart() const LLVM_READONLY { return GotoLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return Target->getLocEnd(); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == IndirectGotoStmtClass; + } + + // Iterators + child_range children() { return child_range(&Target, &Target+1); } +}; + + +/// ContinueStmt - This represents a continue. +/// +class ContinueStmt : public Stmt { + SourceLocation ContinueLoc; +public: + ContinueStmt(SourceLocation CL) : Stmt(ContinueStmtClass), ContinueLoc(CL) {} + + /// \brief Build an empty continue statement. + explicit ContinueStmt(EmptyShell Empty) : Stmt(ContinueStmtClass, Empty) { } + + SourceLocation getContinueLoc() const { return ContinueLoc; } + void setContinueLoc(SourceLocation L) { ContinueLoc = L; } + + SourceLocation getLocStart() const LLVM_READONLY { return ContinueLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return ContinueLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ContinueStmtClass; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +/// BreakStmt - This represents a break. +/// +class BreakStmt : public Stmt { + SourceLocation BreakLoc; + +public: + BreakStmt(SourceLocation BL) : Stmt(BreakStmtClass), BreakLoc(BL) { + static_assert(sizeof(BreakStmt) == 2 * sizeof(SourceLocation), + "BreakStmt too large"); + } + + /// \brief Build an empty break statement. + explicit BreakStmt(EmptyShell Empty) : Stmt(BreakStmtClass, Empty) { } + + SourceLocation getBreakLoc() const { return BreakLoc; } + void setBreakLoc(SourceLocation L) { BreakLoc = L; } + + SourceLocation getLocStart() const LLVM_READONLY { return BreakLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return BreakLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == BreakStmtClass; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + + +/// ReturnStmt - This represents a return, optionally of an expression: +/// return; +/// return 4; +/// +/// Note that GCC allows return with no argument in a function declared to +/// return a value, and it allows returning a value in functions declared to +/// return void. We explicitly model this in the AST, which means you can't +/// depend on the return type of the function and the presence of an argument. +/// +class ReturnStmt : public Stmt { + SourceLocation RetLoc; + Stmt *RetExpr; + const VarDecl *NRVOCandidate; + +public: + explicit ReturnStmt(SourceLocation RL) : ReturnStmt(RL, nullptr, nullptr) {} + + ReturnStmt(SourceLocation RL, Expr *E, const VarDecl *NRVOCandidate) + : Stmt(ReturnStmtClass), RetLoc(RL), RetExpr((Stmt *)E), + NRVOCandidate(NRVOCandidate) {} + + /// \brief Build an empty return expression. + explicit ReturnStmt(EmptyShell Empty) : Stmt(ReturnStmtClass, Empty) { } + + const Expr *getRetValue() const; + Expr *getRetValue(); + void setRetValue(Expr *E) { RetExpr = reinterpret_cast<Stmt*>(E); } + + SourceLocation getReturnLoc() const { return RetLoc; } + void setReturnLoc(SourceLocation L) { RetLoc = L; } + + /// \brief Retrieve the variable that might be used for the named return + /// value optimization. + /// + /// The optimization itself can only be performed if the variable is + /// also marked as an NRVO object. + const VarDecl *getNRVOCandidate() const { return NRVOCandidate; } + void setNRVOCandidate(const VarDecl *Var) { NRVOCandidate = Var; } + + SourceLocation getLocStart() const LLVM_READONLY { return RetLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { + return RetExpr ? RetExpr->getLocEnd() : RetLoc; + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ReturnStmtClass; + } + + // Iterators + child_range children() { + if (RetExpr) return child_range(&RetExpr, &RetExpr+1); + return child_range(child_iterator(), child_iterator()); + } +}; + +/// AsmStmt is the base class for GCCAsmStmt and MSAsmStmt. +/// +class AsmStmt : public Stmt { +protected: + SourceLocation AsmLoc; + /// \brief True if the assembly statement does not have any input or output + /// operands. + bool IsSimple; + + /// \brief If true, treat this inline assembly as having side effects. + /// This assembly statement should not be optimized, deleted or moved. + bool IsVolatile; + + unsigned NumOutputs; + unsigned NumInputs; + unsigned NumClobbers; + + Stmt **Exprs; + + AsmStmt(StmtClass SC, SourceLocation asmloc, bool issimple, bool isvolatile, + unsigned numoutputs, unsigned numinputs, unsigned numclobbers) : + Stmt (SC), AsmLoc(asmloc), IsSimple(issimple), IsVolatile(isvolatile), + NumOutputs(numoutputs), NumInputs(numinputs), NumClobbers(numclobbers) { } + + friend class ASTStmtReader; + +public: + /// \brief Build an empty inline-assembly statement. + explicit AsmStmt(StmtClass SC, EmptyShell Empty) : + Stmt(SC, Empty), Exprs(nullptr) { } + + SourceLocation getAsmLoc() const { return AsmLoc; } + void setAsmLoc(SourceLocation L) { AsmLoc = L; } + + bool isSimple() const { return IsSimple; } + void setSimple(bool V) { IsSimple = V; } + + bool isVolatile() const { return IsVolatile; } + void setVolatile(bool V) { IsVolatile = V; } + + SourceLocation getLocStart() const LLVM_READONLY { return SourceLocation(); } + SourceLocation getLocEnd() const LLVM_READONLY { return SourceLocation(); } + + //===--- Asm String Analysis ---===// + + /// Assemble final IR asm string. + std::string generateAsmString(const ASTContext &C) const; + + //===--- Output operands ---===// + + unsigned getNumOutputs() const { return NumOutputs; } + + /// getOutputConstraint - Return the constraint string for the specified + /// output operand. All output constraints are known to be non-empty (either + /// '=' or '+'). + StringRef getOutputConstraint(unsigned i) const; + + /// isOutputPlusConstraint - Return true if the specified output constraint + /// is a "+" constraint (which is both an input and an output) or false if it + /// is an "=" constraint (just an output). + bool isOutputPlusConstraint(unsigned i) const { + return getOutputConstraint(i)[0] == '+'; + } + + const Expr *getOutputExpr(unsigned i) const; + + /// getNumPlusOperands - Return the number of output operands that have a "+" + /// constraint. + unsigned getNumPlusOperands() const; + + //===--- Input operands ---===// + + unsigned getNumInputs() const { return NumInputs; } + + /// getInputConstraint - Return the specified input constraint. Unlike output + /// constraints, these can be empty. + StringRef getInputConstraint(unsigned i) const; + + const Expr *getInputExpr(unsigned i) const; + + //===--- Other ---===// + + unsigned getNumClobbers() const { return NumClobbers; } + StringRef getClobber(unsigned i) const; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == GCCAsmStmtClass || + T->getStmtClass() == MSAsmStmtClass; + } + + // Input expr iterators. + + typedef ExprIterator inputs_iterator; + typedef ConstExprIterator const_inputs_iterator; + typedef llvm::iterator_range<inputs_iterator> inputs_range; + typedef llvm::iterator_range<const_inputs_iterator> inputs_const_range; + + inputs_iterator begin_inputs() { + return &Exprs[0] + NumOutputs; + } + + inputs_iterator end_inputs() { + return &Exprs[0] + NumOutputs + NumInputs; + } + + inputs_range inputs() { return inputs_range(begin_inputs(), end_inputs()); } + + const_inputs_iterator begin_inputs() const { + return &Exprs[0] + NumOutputs; + } + + const_inputs_iterator end_inputs() const { + return &Exprs[0] + NumOutputs + NumInputs; + } + + inputs_const_range inputs() const { + return inputs_const_range(begin_inputs(), end_inputs()); + } + + // Output expr iterators. + + typedef ExprIterator outputs_iterator; + typedef ConstExprIterator const_outputs_iterator; + typedef llvm::iterator_range<outputs_iterator> outputs_range; + typedef llvm::iterator_range<const_outputs_iterator> outputs_const_range; + + outputs_iterator begin_outputs() { + return &Exprs[0]; + } + outputs_iterator end_outputs() { + return &Exprs[0] + NumOutputs; + } + outputs_range outputs() { + return outputs_range(begin_outputs(), end_outputs()); + } + + const_outputs_iterator begin_outputs() const { + return &Exprs[0]; + } + const_outputs_iterator end_outputs() const { + return &Exprs[0] + NumOutputs; + } + outputs_const_range outputs() const { + return outputs_const_range(begin_outputs(), end_outputs()); + } + + child_range children() { + return child_range(&Exprs[0], &Exprs[0] + NumOutputs + NumInputs); + } +}; + +/// This represents a GCC inline-assembly statement extension. +/// +class GCCAsmStmt : public AsmStmt { + SourceLocation RParenLoc; + StringLiteral *AsmStr; + + // FIXME: If we wanted to, we could allocate all of these in one big array. + StringLiteral **Constraints; + StringLiteral **Clobbers; + IdentifierInfo **Names; + + friend class ASTStmtReader; + +public: + GCCAsmStmt(const ASTContext &C, SourceLocation asmloc, bool issimple, + bool isvolatile, unsigned numoutputs, unsigned numinputs, + IdentifierInfo **names, StringLiteral **constraints, Expr **exprs, + StringLiteral *asmstr, unsigned numclobbers, + StringLiteral **clobbers, SourceLocation rparenloc); + + /// \brief Build an empty inline-assembly statement. + explicit GCCAsmStmt(EmptyShell Empty) : AsmStmt(GCCAsmStmtClass, Empty), + Constraints(nullptr), Clobbers(nullptr), Names(nullptr) { } + + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + //===--- Asm String Analysis ---===// + + const StringLiteral *getAsmString() const { return AsmStr; } + StringLiteral *getAsmString() { return AsmStr; } + void setAsmString(StringLiteral *E) { AsmStr = E; } + + /// AsmStringPiece - this is part of a decomposed asm string specification + /// (for use with the AnalyzeAsmString function below). An asm string is + /// considered to be a concatenation of these parts. + class AsmStringPiece { + public: + enum Kind { + String, // String in .ll asm string form, "$" -> "$$" and "%%" -> "%". + Operand // Operand reference, with optional modifier %c4. + }; + private: + Kind MyKind; + std::string Str; + unsigned OperandNo; + + // Source range for operand references. + CharSourceRange Range; + public: + AsmStringPiece(const std::string &S) : MyKind(String), Str(S) {} + AsmStringPiece(unsigned OpNo, const std::string &S, SourceLocation Begin, + SourceLocation End) + : MyKind(Operand), Str(S), OperandNo(OpNo), + Range(CharSourceRange::getCharRange(Begin, End)) { + } + + bool isString() const { return MyKind == String; } + bool isOperand() const { return MyKind == Operand; } + + const std::string &getString() const { + return Str; + } + + unsigned getOperandNo() const { + assert(isOperand()); + return OperandNo; + } + + CharSourceRange getRange() const { + assert(isOperand() && "Range is currently used only for Operands."); + return Range; + } + + /// getModifier - Get the modifier for this operand, if present. This + /// returns '\0' if there was no modifier. + char getModifier() const; + }; + + /// AnalyzeAsmString - Analyze the asm string of the current asm, decomposing + /// it into pieces. If the asm string is erroneous, emit errors and return + /// true, otherwise return false. This handles canonicalization and + /// translation of strings from GCC syntax to LLVM IR syntax, and handles + //// flattening of named references like %[foo] to Operand AsmStringPiece's. + unsigned AnalyzeAsmString(SmallVectorImpl<AsmStringPiece> &Pieces, + const ASTContext &C, unsigned &DiagOffs) const; + + /// Assemble final IR asm string. + std::string generateAsmString(const ASTContext &C) const; + + //===--- Output operands ---===// + + IdentifierInfo *getOutputIdentifier(unsigned i) const { + return Names[i]; + } + + StringRef getOutputName(unsigned i) const { + if (IdentifierInfo *II = getOutputIdentifier(i)) + return II->getName(); + + return StringRef(); + } + + StringRef getOutputConstraint(unsigned i) const; + + const StringLiteral *getOutputConstraintLiteral(unsigned i) const { + return Constraints[i]; + } + StringLiteral *getOutputConstraintLiteral(unsigned i) { + return Constraints[i]; + } + + Expr *getOutputExpr(unsigned i); + + const Expr *getOutputExpr(unsigned i) const { + return const_cast<GCCAsmStmt*>(this)->getOutputExpr(i); + } + + //===--- Input operands ---===// + + IdentifierInfo *getInputIdentifier(unsigned i) const { + return Names[i + NumOutputs]; + } + + StringRef getInputName(unsigned i) const { + if (IdentifierInfo *II = getInputIdentifier(i)) + return II->getName(); + + return StringRef(); + } + + StringRef getInputConstraint(unsigned i) const; + + const StringLiteral *getInputConstraintLiteral(unsigned i) const { + return Constraints[i + NumOutputs]; + } + StringLiteral *getInputConstraintLiteral(unsigned i) { + return Constraints[i + NumOutputs]; + } + + Expr *getInputExpr(unsigned i); + void setInputExpr(unsigned i, Expr *E); + + const Expr *getInputExpr(unsigned i) const { + return const_cast<GCCAsmStmt*>(this)->getInputExpr(i); + } + +private: + void setOutputsAndInputsAndClobbers(const ASTContext &C, + IdentifierInfo **Names, + StringLiteral **Constraints, + Stmt **Exprs, + unsigned NumOutputs, + unsigned NumInputs, + StringLiteral **Clobbers, + unsigned NumClobbers); +public: + + //===--- Other ---===// + + /// getNamedOperand - Given a symbolic operand reference like %[foo], + /// translate this into a numeric value needed to reference the same operand. + /// This returns -1 if the operand name is invalid. + int getNamedOperand(StringRef SymbolicName) const; + + StringRef getClobber(unsigned i) const; + StringLiteral *getClobberStringLiteral(unsigned i) { return Clobbers[i]; } + const StringLiteral *getClobberStringLiteral(unsigned i) const { + return Clobbers[i]; + } + + SourceLocation getLocStart() const LLVM_READONLY { return AsmLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == GCCAsmStmtClass; + } +}; + +/// This represents a Microsoft inline-assembly statement extension. +/// +class MSAsmStmt : public AsmStmt { + SourceLocation LBraceLoc, EndLoc; + StringRef AsmStr; + + unsigned NumAsmToks; + + Token *AsmToks; + StringRef *Constraints; + StringRef *Clobbers; + + friend class ASTStmtReader; + +public: + MSAsmStmt(const ASTContext &C, SourceLocation asmloc, + SourceLocation lbraceloc, bool issimple, bool isvolatile, + ArrayRef<Token> asmtoks, unsigned numoutputs, unsigned numinputs, + ArrayRef<StringRef> constraints, + ArrayRef<Expr*> exprs, StringRef asmstr, + ArrayRef<StringRef> clobbers, SourceLocation endloc); + + /// \brief Build an empty MS-style inline-assembly statement. + explicit MSAsmStmt(EmptyShell Empty) : AsmStmt(MSAsmStmtClass, Empty), + NumAsmToks(0), AsmToks(nullptr), Constraints(nullptr), Clobbers(nullptr) { } + + SourceLocation getLBraceLoc() const { return LBraceLoc; } + void setLBraceLoc(SourceLocation L) { LBraceLoc = L; } + SourceLocation getEndLoc() const { return EndLoc; } + void setEndLoc(SourceLocation L) { EndLoc = L; } + + bool hasBraces() const { return LBraceLoc.isValid(); } + + unsigned getNumAsmToks() { return NumAsmToks; } + Token *getAsmToks() { return AsmToks; } + + //===--- Asm String Analysis ---===// + StringRef getAsmString() const { return AsmStr; } + + /// Assemble final IR asm string. + std::string generateAsmString(const ASTContext &C) const; + + //===--- Output operands ---===// + + StringRef getOutputConstraint(unsigned i) const { + assert(i < NumOutputs); + return Constraints[i]; + } + + Expr *getOutputExpr(unsigned i); + + const Expr *getOutputExpr(unsigned i) const { + return const_cast<MSAsmStmt*>(this)->getOutputExpr(i); + } + + //===--- Input operands ---===// + + StringRef getInputConstraint(unsigned i) const { + assert(i < NumInputs); + return Constraints[i + NumOutputs]; + } + + Expr *getInputExpr(unsigned i); + void setInputExpr(unsigned i, Expr *E); + + const Expr *getInputExpr(unsigned i) const { + return const_cast<MSAsmStmt*>(this)->getInputExpr(i); + } + + //===--- Other ---===// + + ArrayRef<StringRef> getAllConstraints() const { + return llvm::makeArrayRef(Constraints, NumInputs + NumOutputs); + } + ArrayRef<StringRef> getClobbers() const { + return llvm::makeArrayRef(Clobbers, NumClobbers); + } + ArrayRef<Expr*> getAllExprs() const { + return llvm::makeArrayRef(reinterpret_cast<Expr**>(Exprs), + NumInputs + NumOutputs); + } + + StringRef getClobber(unsigned i) const { return getClobbers()[i]; } + +private: + void initialize(const ASTContext &C, StringRef AsmString, + ArrayRef<Token> AsmToks, ArrayRef<StringRef> Constraints, + ArrayRef<Expr*> Exprs, ArrayRef<StringRef> Clobbers); +public: + + SourceLocation getLocStart() const LLVM_READONLY { return AsmLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return EndLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == MSAsmStmtClass; + } + + child_range children() { + return child_range(&Exprs[0], &Exprs[NumInputs + NumOutputs]); + } +}; + +class SEHExceptStmt : public Stmt { + SourceLocation Loc; + Stmt *Children[2]; + + enum { FILTER_EXPR, BLOCK }; + + SEHExceptStmt(SourceLocation Loc, + Expr *FilterExpr, + Stmt *Block); + + friend class ASTReader; + friend class ASTStmtReader; + explicit SEHExceptStmt(EmptyShell E) : Stmt(SEHExceptStmtClass, E) { } + +public: + static SEHExceptStmt* Create(const ASTContext &C, + SourceLocation ExceptLoc, + Expr *FilterExpr, + Stmt *Block); + + SourceLocation getLocStart() const LLVM_READONLY { return getExceptLoc(); } + SourceLocation getLocEnd() const LLVM_READONLY { return getEndLoc(); } + + SourceLocation getExceptLoc() const { return Loc; } + SourceLocation getEndLoc() const { return getBlock()->getLocEnd(); } + + Expr *getFilterExpr() const { + return reinterpret_cast<Expr*>(Children[FILTER_EXPR]); + } + + CompoundStmt *getBlock() const { + return cast<CompoundStmt>(Children[BLOCK]); + } + + child_range children() { + return child_range(Children,Children+2); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == SEHExceptStmtClass; + } + +}; + +class SEHFinallyStmt : public Stmt { + SourceLocation Loc; + Stmt *Block; + + SEHFinallyStmt(SourceLocation Loc, + Stmt *Block); + + friend class ASTReader; + friend class ASTStmtReader; + explicit SEHFinallyStmt(EmptyShell E) : Stmt(SEHFinallyStmtClass, E) { } + +public: + static SEHFinallyStmt* Create(const ASTContext &C, + SourceLocation FinallyLoc, + Stmt *Block); + + SourceLocation getLocStart() const LLVM_READONLY { return getFinallyLoc(); } + SourceLocation getLocEnd() const LLVM_READONLY { return getEndLoc(); } + + SourceLocation getFinallyLoc() const { return Loc; } + SourceLocation getEndLoc() const { return Block->getLocEnd(); } + + CompoundStmt *getBlock() const { return cast<CompoundStmt>(Block); } + + child_range children() { + return child_range(&Block,&Block+1); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == SEHFinallyStmtClass; + } + +}; + +class SEHTryStmt : public Stmt { + bool IsCXXTry; + SourceLocation TryLoc; + Stmt *Children[2]; + + enum { TRY = 0, HANDLER = 1 }; + + SEHTryStmt(bool isCXXTry, // true if 'try' otherwise '__try' + SourceLocation TryLoc, + Stmt *TryBlock, + Stmt *Handler); + + friend class ASTReader; + friend class ASTStmtReader; + explicit SEHTryStmt(EmptyShell E) : Stmt(SEHTryStmtClass, E) { } + +public: + static SEHTryStmt* Create(const ASTContext &C, bool isCXXTry, + SourceLocation TryLoc, Stmt *TryBlock, + Stmt *Handler); + + SourceLocation getLocStart() const LLVM_READONLY { return getTryLoc(); } + SourceLocation getLocEnd() const LLVM_READONLY { return getEndLoc(); } + + SourceLocation getTryLoc() const { return TryLoc; } + SourceLocation getEndLoc() const { return Children[HANDLER]->getLocEnd(); } + + bool getIsCXXTry() const { return IsCXXTry; } + + CompoundStmt* getTryBlock() const { + return cast<CompoundStmt>(Children[TRY]); + } + + Stmt *getHandler() const { return Children[HANDLER]; } + + /// Returns 0 if not defined + SEHExceptStmt *getExceptHandler() const; + SEHFinallyStmt *getFinallyHandler() const; + + child_range children() { + return child_range(Children,Children+2); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == SEHTryStmtClass; + } +}; + +/// Represents a __leave statement. +/// +class SEHLeaveStmt : public Stmt { + SourceLocation LeaveLoc; +public: + explicit SEHLeaveStmt(SourceLocation LL) + : Stmt(SEHLeaveStmtClass), LeaveLoc(LL) {} + + /// \brief Build an empty __leave statement. + explicit SEHLeaveStmt(EmptyShell Empty) : Stmt(SEHLeaveStmtClass, Empty) { } + + SourceLocation getLeaveLoc() const { return LeaveLoc; } + void setLeaveLoc(SourceLocation L) { LeaveLoc = L; } + + SourceLocation getLocStart() const LLVM_READONLY { return LeaveLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return LeaveLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == SEHLeaveStmtClass; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + +/// \brief This captures a statement into a function. For example, the following +/// pragma annotated compound statement can be represented as a CapturedStmt, +/// and this compound statement is the body of an anonymous outlined function. +/// @code +/// #pragma omp parallel +/// { +/// compute(); +/// } +/// @endcode +class CapturedStmt : public Stmt { +public: + /// \brief The different capture forms: by 'this', by reference, capture for + /// variable-length array type etc. + enum VariableCaptureKind { + VCK_This, + VCK_ByRef, + VCK_ByCopy, + VCK_VLAType, + }; + + /// \brief Describes the capture of either a variable, or 'this', or + /// variable-length array type. + class Capture { + llvm::PointerIntPair<VarDecl *, 2, VariableCaptureKind> VarAndKind; + SourceLocation Loc; + + public: + /// \brief Create a new capture. + /// + /// \param Loc The source location associated with this capture. + /// + /// \param Kind The kind of capture (this, ByRef, ...). + /// + /// \param Var The variable being captured, or null if capturing this. + /// + Capture(SourceLocation Loc, VariableCaptureKind Kind, + VarDecl *Var = nullptr); + + /// \brief Determine the kind of capture. + VariableCaptureKind getCaptureKind() const; + + /// \brief Retrieve the source location at which the variable or 'this' was + /// first used. + SourceLocation getLocation() const { return Loc; } + + /// \brief Determine whether this capture handles the C++ 'this' pointer. + bool capturesThis() const { return getCaptureKind() == VCK_This; } + + /// \brief Determine whether this capture handles a variable (by reference). + bool capturesVariable() const { return getCaptureKind() == VCK_ByRef; } + + /// \brief Determine whether this capture handles a variable by copy. + bool capturesVariableByCopy() const { + return getCaptureKind() == VCK_ByCopy; + } + + /// \brief Determine whether this capture handles a variable-length array + /// type. + bool capturesVariableArrayType() const { + return getCaptureKind() == VCK_VLAType; + } + + /// \brief Retrieve the declaration of the variable being captured. + /// + /// This operation is only valid if this capture captures a variable. + VarDecl *getCapturedVar() const; + + friend class ASTStmtReader; + }; + +private: + /// \brief The number of variable captured, including 'this'. + unsigned NumCaptures; + + /// \brief The pointer part is the implicit the outlined function and the + /// int part is the captured region kind, 'CR_Default' etc. + llvm::PointerIntPair<CapturedDecl *, 1, CapturedRegionKind> CapDeclAndKind; + + /// \brief The record for captured variables, a RecordDecl or CXXRecordDecl. + RecordDecl *TheRecordDecl; + + /// \brief Construct a captured statement. + CapturedStmt(Stmt *S, CapturedRegionKind Kind, ArrayRef<Capture> Captures, + ArrayRef<Expr *> CaptureInits, CapturedDecl *CD, RecordDecl *RD); + + /// \brief Construct an empty captured statement. + CapturedStmt(EmptyShell Empty, unsigned NumCaptures); + + Stmt **getStoredStmts() { return reinterpret_cast<Stmt **>(this + 1); } + + Stmt *const *getStoredStmts() const { + return reinterpret_cast<Stmt *const *>(this + 1); + } + + Capture *getStoredCaptures() const; + + void setCapturedStmt(Stmt *S) { getStoredStmts()[NumCaptures] = S; } + +public: + static CapturedStmt *Create(const ASTContext &Context, Stmt *S, + CapturedRegionKind Kind, + ArrayRef<Capture> Captures, + ArrayRef<Expr *> CaptureInits, + CapturedDecl *CD, RecordDecl *RD); + + static CapturedStmt *CreateDeserialized(const ASTContext &Context, + unsigned NumCaptures); + + /// \brief Retrieve the statement being captured. + Stmt *getCapturedStmt() { return getStoredStmts()[NumCaptures]; } + const Stmt *getCapturedStmt() const { return getStoredStmts()[NumCaptures]; } + + /// \brief Retrieve the outlined function declaration. + CapturedDecl *getCapturedDecl(); + const CapturedDecl *getCapturedDecl() const; + + /// \brief Set the outlined function declaration. + void setCapturedDecl(CapturedDecl *D); + + /// \brief Retrieve the captured region kind. + CapturedRegionKind getCapturedRegionKind() const; + + /// \brief Set the captured region kind. + void setCapturedRegionKind(CapturedRegionKind Kind); + + /// \brief Retrieve the record declaration for captured variables. + const RecordDecl *getCapturedRecordDecl() const { return TheRecordDecl; } + + /// \brief Set the record declaration for captured variables. + void setCapturedRecordDecl(RecordDecl *D) { + assert(D && "null RecordDecl"); + TheRecordDecl = D; + } + + /// \brief True if this variable has been captured. + bool capturesVariable(const VarDecl *Var) const; + + /// \brief An iterator that walks over the captures. + typedef Capture *capture_iterator; + typedef const Capture *const_capture_iterator; + typedef llvm::iterator_range<capture_iterator> capture_range; + typedef llvm::iterator_range<const_capture_iterator> capture_const_range; + + capture_range captures() { + return capture_range(capture_begin(), capture_end()); + } + capture_const_range captures() const { + return capture_const_range(capture_begin(), capture_end()); + } + + /// \brief Retrieve an iterator pointing to the first capture. + capture_iterator capture_begin() { return getStoredCaptures(); } + const_capture_iterator capture_begin() const { return getStoredCaptures(); } + + /// \brief Retrieve an iterator pointing past the end of the sequence of + /// captures. + capture_iterator capture_end() const { + return getStoredCaptures() + NumCaptures; + } + + /// \brief Retrieve the number of captures, including 'this'. + unsigned capture_size() const { return NumCaptures; } + + /// \brief Iterator that walks over the capture initialization arguments. + typedef Expr **capture_init_iterator; + typedef llvm::iterator_range<capture_init_iterator> capture_init_range; + + /// \brief Const iterator that walks over the capture initialization + /// arguments. + typedef Expr *const *const_capture_init_iterator; + typedef llvm::iterator_range<const_capture_init_iterator> + const_capture_init_range; + + capture_init_range capture_inits() { + return capture_init_range(capture_init_begin(), capture_init_end()); + } + + const_capture_init_range capture_inits() const { + return const_capture_init_range(capture_init_begin(), capture_init_end()); + } + + /// \brief Retrieve the first initialization argument. + capture_init_iterator capture_init_begin() { + return reinterpret_cast<Expr **>(getStoredStmts()); + } + + const_capture_init_iterator capture_init_begin() const { + return reinterpret_cast<Expr *const *>(getStoredStmts()); + } + + /// \brief Retrieve the iterator pointing one past the last initialization + /// argument. + capture_init_iterator capture_init_end() { + return capture_init_begin() + NumCaptures; + } + + const_capture_init_iterator capture_init_end() const { + return capture_init_begin() + NumCaptures; + } + + SourceLocation getLocStart() const LLVM_READONLY { + return getCapturedStmt()->getLocStart(); + } + SourceLocation getLocEnd() const LLVM_READONLY { + return getCapturedStmt()->getLocEnd(); + } + SourceRange getSourceRange() const LLVM_READONLY { + return getCapturedStmt()->getSourceRange(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CapturedStmtClass; + } + + child_range children(); + + friend class ASTStmtReader; +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/StmtCXX.h b/contrib/llvm/tools/clang/include/clang/AST/StmtCXX.h new file mode 100644 index 0000000..1ca73e2 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/StmtCXX.h @@ -0,0 +1,417 @@ +//===--- StmtCXX.h - Classes for representing C++ statements ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the C++ statement AST node classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_STMTCXX_H +#define LLVM_CLANG_AST_STMTCXX_H + +#include "clang/AST/DeclarationName.h" +#include "clang/AST/Expr.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/Stmt.h" +#include "llvm/Support/Compiler.h" + +namespace clang { + +class VarDecl; + +/// CXXCatchStmt - This represents a C++ catch block. +/// +class CXXCatchStmt : public Stmt { + SourceLocation CatchLoc; + /// The exception-declaration of the type. + VarDecl *ExceptionDecl; + /// The handler block. + Stmt *HandlerBlock; + +public: + CXXCatchStmt(SourceLocation catchLoc, VarDecl *exDecl, Stmt *handlerBlock) + : Stmt(CXXCatchStmtClass), CatchLoc(catchLoc), ExceptionDecl(exDecl), + HandlerBlock(handlerBlock) {} + + CXXCatchStmt(EmptyShell Empty) + : Stmt(CXXCatchStmtClass), ExceptionDecl(nullptr), HandlerBlock(nullptr) {} + + SourceLocation getLocStart() const LLVM_READONLY { return CatchLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { + return HandlerBlock->getLocEnd(); + } + + SourceLocation getCatchLoc() const { return CatchLoc; } + VarDecl *getExceptionDecl() const { return ExceptionDecl; } + QualType getCaughtType() const; + Stmt *getHandlerBlock() const { return HandlerBlock; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXCatchStmtClass; + } + + child_range children() { return child_range(&HandlerBlock, &HandlerBlock+1); } + + friend class ASTStmtReader; +}; + +/// CXXTryStmt - A C++ try block, including all handlers. +/// +class CXXTryStmt : public Stmt { + SourceLocation TryLoc; + unsigned NumHandlers; + + CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock, ArrayRef<Stmt*> handlers); + + CXXTryStmt(EmptyShell Empty, unsigned numHandlers) + : Stmt(CXXTryStmtClass), NumHandlers(numHandlers) { } + + Stmt const * const *getStmts() const { + return reinterpret_cast<Stmt const * const*>(this + 1); + } + Stmt **getStmts() { + return reinterpret_cast<Stmt **>(this + 1); + } + +public: + static CXXTryStmt *Create(const ASTContext &C, SourceLocation tryLoc, + Stmt *tryBlock, ArrayRef<Stmt*> handlers); + + static CXXTryStmt *Create(const ASTContext &C, EmptyShell Empty, + unsigned numHandlers); + + SourceLocation getLocStart() const LLVM_READONLY { return getTryLoc(); } + SourceLocation getLocEnd() const LLVM_READONLY { return getEndLoc(); } + + SourceLocation getTryLoc() const { return TryLoc; } + SourceLocation getEndLoc() const { + return getStmts()[NumHandlers]->getLocEnd(); + } + + CompoundStmt *getTryBlock() { + return cast<CompoundStmt>(getStmts()[0]); + } + const CompoundStmt *getTryBlock() const { + return cast<CompoundStmt>(getStmts()[0]); + } + + unsigned getNumHandlers() const { return NumHandlers; } + CXXCatchStmt *getHandler(unsigned i) { + return cast<CXXCatchStmt>(getStmts()[i + 1]); + } + const CXXCatchStmt *getHandler(unsigned i) const { + return cast<CXXCatchStmt>(getStmts()[i + 1]); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXTryStmtClass; + } + + child_range children() { + return child_range(getStmts(), getStmts() + getNumHandlers() + 1); + } + + friend class ASTStmtReader; +}; + +/// CXXForRangeStmt - This represents C++0x [stmt.ranged]'s ranged for +/// statement, represented as 'for (range-declarator : range-expression)'. +/// +/// This is stored in a partially-desugared form to allow full semantic +/// analysis of the constituent components. The original syntactic components +/// can be extracted using getLoopVariable and getRangeInit. +class CXXForRangeStmt : public Stmt { + SourceLocation ForLoc; + enum { RANGE, BEGINEND, COND, INC, LOOPVAR, BODY, END }; + // SubExprs[RANGE] is an expression or declstmt. + // SubExprs[COND] and SubExprs[INC] are expressions. + Stmt *SubExprs[END]; + SourceLocation CoawaitLoc; + SourceLocation ColonLoc; + SourceLocation RParenLoc; + + friend class ASTStmtReader; +public: + CXXForRangeStmt(DeclStmt *Range, DeclStmt *BeginEnd, + Expr *Cond, Expr *Inc, DeclStmt *LoopVar, Stmt *Body, + SourceLocation FL, SourceLocation CAL, SourceLocation CL, + SourceLocation RPL); + CXXForRangeStmt(EmptyShell Empty) : Stmt(CXXForRangeStmtClass, Empty) { } + + + VarDecl *getLoopVariable(); + Expr *getRangeInit(); + + const VarDecl *getLoopVariable() const; + const Expr *getRangeInit() const; + + + DeclStmt *getRangeStmt() { return cast<DeclStmt>(SubExprs[RANGE]); } + DeclStmt *getBeginEndStmt() { + return cast_or_null<DeclStmt>(SubExprs[BEGINEND]); + } + Expr *getCond() { return cast_or_null<Expr>(SubExprs[COND]); } + Expr *getInc() { return cast_or_null<Expr>(SubExprs[INC]); } + DeclStmt *getLoopVarStmt() { return cast<DeclStmt>(SubExprs[LOOPVAR]); } + Stmt *getBody() { return SubExprs[BODY]; } + + const DeclStmt *getRangeStmt() const { + return cast<DeclStmt>(SubExprs[RANGE]); + } + const DeclStmt *getBeginEndStmt() const { + return cast_or_null<DeclStmt>(SubExprs[BEGINEND]); + } + const Expr *getCond() const { + return cast_or_null<Expr>(SubExprs[COND]); + } + const Expr *getInc() const { + return cast_or_null<Expr>(SubExprs[INC]); + } + const DeclStmt *getLoopVarStmt() const { + return cast<DeclStmt>(SubExprs[LOOPVAR]); + } + const Stmt *getBody() const { return SubExprs[BODY]; } + + void setRangeInit(Expr *E) { SubExprs[RANGE] = reinterpret_cast<Stmt*>(E); } + void setRangeStmt(Stmt *S) { SubExprs[RANGE] = S; } + void setBeginEndStmt(Stmt *S) { SubExprs[BEGINEND] = S; } + void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(E); } + void setInc(Expr *E) { SubExprs[INC] = reinterpret_cast<Stmt*>(E); } + void setLoopVarStmt(Stmt *S) { SubExprs[LOOPVAR] = S; } + void setBody(Stmt *S) { SubExprs[BODY] = S; } + + SourceLocation getForLoc() const { return ForLoc; } + SourceLocation getCoawaitLoc() const { return CoawaitLoc; } + SourceLocation getColonLoc() const { return ColonLoc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + + SourceLocation getLocStart() const LLVM_READONLY { return ForLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { + return SubExprs[BODY]->getLocEnd(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXForRangeStmtClass; + } + + // Iterators + child_range children() { + return child_range(&SubExprs[0], &SubExprs[END]); + } +}; + +/// \brief Representation of a Microsoft __if_exists or __if_not_exists +/// statement with a dependent name. +/// +/// The __if_exists statement can be used to include a sequence of statements +/// in the program only when a particular dependent name does not exist. For +/// example: +/// +/// \code +/// template<typename T> +/// void call_foo(T &t) { +/// __if_exists (T::foo) { +/// t.foo(); // okay: only called when T::foo exists. +/// } +/// } +/// \endcode +/// +/// Similarly, the __if_not_exists statement can be used to include the +/// statements when a particular name does not exist. +/// +/// Note that this statement only captures __if_exists and __if_not_exists +/// statements whose name is dependent. All non-dependent cases are handled +/// directly in the parser, so that they don't introduce a new scope. Clang +/// introduces scopes in the dependent case to keep names inside the compound +/// statement from leaking out into the surround statements, which would +/// compromise the template instantiation model. This behavior differs from +/// Visual C++ (which never introduces a scope), but is a fairly reasonable +/// approximation of the VC++ behavior. +class MSDependentExistsStmt : public Stmt { + SourceLocation KeywordLoc; + bool IsIfExists; + NestedNameSpecifierLoc QualifierLoc; + DeclarationNameInfo NameInfo; + Stmt *SubStmt; + + friend class ASTReader; + friend class ASTStmtReader; + +public: + MSDependentExistsStmt(SourceLocation KeywordLoc, bool IsIfExists, + NestedNameSpecifierLoc QualifierLoc, + DeclarationNameInfo NameInfo, + CompoundStmt *SubStmt) + : Stmt(MSDependentExistsStmtClass), + KeywordLoc(KeywordLoc), IsIfExists(IsIfExists), + QualifierLoc(QualifierLoc), NameInfo(NameInfo), + SubStmt(reinterpret_cast<Stmt *>(SubStmt)) { } + + /// \brief Retrieve the location of the __if_exists or __if_not_exists + /// keyword. + SourceLocation getKeywordLoc() const { return KeywordLoc; } + + /// \brief Determine whether this is an __if_exists statement. + bool isIfExists() const { return IsIfExists; } + + /// \brief Determine whether this is an __if_exists statement. + bool isIfNotExists() const { return !IsIfExists; } + + /// \brief Retrieve the nested-name-specifier that qualifies this name, if + /// any. + NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } + + /// \brief Retrieve the name of the entity we're testing for, along with + /// location information + DeclarationNameInfo getNameInfo() const { return NameInfo; } + + /// \brief Retrieve the compound statement that will be included in the + /// program only if the existence of the symbol matches the initial keyword. + CompoundStmt *getSubStmt() const { + return reinterpret_cast<CompoundStmt *>(SubStmt); + } + + SourceLocation getLocStart() const LLVM_READONLY { return KeywordLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return SubStmt->getLocEnd();} + + child_range children() { + return child_range(&SubStmt, &SubStmt+1); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == MSDependentExistsStmtClass; + } +}; + +/// \brief Represents the body of a coroutine. This wraps the normal function +/// body and holds the additional semantic context required to set up and tear +/// down the coroutine frame. +class CoroutineBodyStmt : public Stmt { + enum SubStmt { + Body, ///< The body of the coroutine. + Promise, ///< The promise statement. + InitSuspend, ///< The initial suspend statement, run before the body. + FinalSuspend, ///< The final suspend statement, run after the body. + OnException, ///< Handler for exceptions thrown in the body. + OnFallthrough, ///< Handler for control flow falling off the body. + ReturnValue, ///< Return value for thunk function. + FirstParamMove ///< First offset for move construction of parameter copies. + }; + Stmt *SubStmts[SubStmt::FirstParamMove]; + + friend class ASTStmtReader; +public: + CoroutineBodyStmt(Stmt *Body, Stmt *Promise, Stmt *InitSuspend, + Stmt *FinalSuspend, Stmt *OnException, Stmt *OnFallthrough, + Expr *ReturnValue, ArrayRef<Expr *> ParamMoves) + : Stmt(CoroutineBodyStmtClass) { + SubStmts[CoroutineBodyStmt::Body] = Body; + SubStmts[CoroutineBodyStmt::Promise] = Promise; + SubStmts[CoroutineBodyStmt::InitSuspend] = InitSuspend; + SubStmts[CoroutineBodyStmt::FinalSuspend] = FinalSuspend; + SubStmts[CoroutineBodyStmt::OnException] = OnException; + SubStmts[CoroutineBodyStmt::OnFallthrough] = OnFallthrough; + SubStmts[CoroutineBodyStmt::ReturnValue] = ReturnValue; + // FIXME: Tail-allocate space for parameter move expressions and store them. + assert(ParamMoves.empty() && "not implemented yet"); + } + + /// \brief Retrieve the body of the coroutine as written. This will be either + /// a CompoundStmt or a TryStmt. + Stmt *getBody() const { + return SubStmts[SubStmt::Body]; + } + + Stmt *getPromiseDeclStmt() const { return SubStmts[SubStmt::Promise]; } + VarDecl *getPromiseDecl() const { + return cast<VarDecl>(cast<DeclStmt>(getPromiseDeclStmt())->getSingleDecl()); + } + + Stmt *getInitSuspendStmt() const { return SubStmts[SubStmt::InitSuspend]; } + Stmt *getFinalSuspendStmt() const { return SubStmts[SubStmt::FinalSuspend]; } + + Stmt *getExceptionHandler() const { return SubStmts[SubStmt::OnException]; } + Stmt *getFallthroughHandler() const { + return SubStmts[SubStmt::OnFallthrough]; + } + + Expr *getReturnValueInit() const { + return cast<Expr>(SubStmts[SubStmt::ReturnValue]); + } + + SourceLocation getLocStart() const LLVM_READONLY { + return getBody()->getLocStart(); + } + SourceLocation getLocEnd() const LLVM_READONLY { + return getBody()->getLocEnd(); + } + + child_range children() { + return child_range(SubStmts, SubStmts + SubStmt::FirstParamMove); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CoroutineBodyStmtClass; + } +}; + +/// \brief Represents a 'co_return' statement in the C++ Coroutines TS. +/// +/// This statament models the initialization of the coroutine promise +/// (encapsulating the eventual notional return value) from an expression +/// (or braced-init-list), followed by termination of the coroutine. +/// +/// This initialization is modeled by the evaluation of the operand +/// followed by a call to one of: +/// <promise>.return_value(<operand>) +/// <promise>.return_void() +/// which we name the "promise call". +class CoreturnStmt : public Stmt { + SourceLocation CoreturnLoc; + + enum SubStmt { Operand, PromiseCall, Count }; + Stmt *SubStmts[SubStmt::Count]; + + friend class ASTStmtReader; +public: + CoreturnStmt(SourceLocation CoreturnLoc, Stmt *Operand, Stmt *PromiseCall) + : Stmt(CoreturnStmtClass), CoreturnLoc(CoreturnLoc) { + SubStmts[SubStmt::Operand] = Operand; + SubStmts[SubStmt::PromiseCall] = PromiseCall; + } + + SourceLocation getKeywordLoc() const { return CoreturnLoc; } + + /// \brief Retrieve the operand of the 'co_return' statement. Will be nullptr + /// if none was specified. + Expr *getOperand() const { return static_cast<Expr*>(SubStmts[Operand]); } + + /// \brief Retrieve the promise call that results from this 'co_return' + /// statement. Will be nullptr if either the coroutine has not yet been + /// finalized or the coroutine has no eventual return type. + Expr *getPromiseCall() const { + return static_cast<Expr*>(SubStmts[PromiseCall]); + } + + SourceLocation getLocStart() const LLVM_READONLY { return CoreturnLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { + return getOperand()->getLocEnd(); + } + + child_range children() { + return child_range(SubStmts, SubStmts + SubStmt::Count); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CoreturnStmtClass; + } +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/StmtGraphTraits.h b/contrib/llvm/tools/clang/include/clang/AST/StmtGraphTraits.h new file mode 100644 index 0000000..ab636a5 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/StmtGraphTraits.h @@ -0,0 +1,83 @@ +//===--- StmtGraphTraits.h - Graph Traits for the class Stmt ----*- 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 template specialization of llvm::GraphTraits to +// treat ASTs (Stmt*) as graphs +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_STMTGRAPHTRAITS_H +#define LLVM_CLANG_AST_STMTGRAPHTRAITS_H + +#include "clang/AST/Stmt.h" +#include "llvm/ADT/DepthFirstIterator.h" +#include "llvm/ADT/GraphTraits.h" + +namespace llvm { + +//template <typename T> struct GraphTraits; + + +template <> struct GraphTraits<clang::Stmt*> { + typedef clang::Stmt NodeType; + typedef clang::Stmt::child_iterator ChildIteratorType; + typedef llvm::df_iterator<clang::Stmt*> nodes_iterator; + + static NodeType* getEntryNode(clang::Stmt* S) { return S; } + + static inline ChildIteratorType child_begin(NodeType* N) { + if (N) return N->child_begin(); + else return ChildIteratorType(); + } + + static inline ChildIteratorType child_end(NodeType* N) { + if (N) return N->child_end(); + else return ChildIteratorType(); + } + + static nodes_iterator nodes_begin(clang::Stmt* S) { + return df_begin(S); + } + + static nodes_iterator nodes_end(clang::Stmt* S) { + return df_end(S); + } +}; + + +template <> struct GraphTraits<const clang::Stmt*> { + typedef const clang::Stmt NodeType; + typedef clang::Stmt::const_child_iterator ChildIteratorType; + typedef llvm::df_iterator<const clang::Stmt*> nodes_iterator; + + static NodeType* getEntryNode(const clang::Stmt* S) { return S; } + + static inline ChildIteratorType child_begin(NodeType* N) { + if (N) return N->child_begin(); + else return ChildIteratorType(); + } + + static inline ChildIteratorType child_end(NodeType* N) { + if (N) return N->child_end(); + else return ChildIteratorType(); + } + + static nodes_iterator nodes_begin(const clang::Stmt* S) { + return df_begin(S); + } + + static nodes_iterator nodes_end(const clang::Stmt* S) { + return df_end(S); + } +}; + + +} // end namespace llvm + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/StmtIterator.h b/contrib/llvm/tools/clang/include/clang/AST/StmtIterator.h new file mode 100644 index 0000000..81f8ad43 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/StmtIterator.h @@ -0,0 +1,144 @@ +//===--- StmtIterator.h - Iterators for Statements --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the StmtIterator and ConstStmtIterator classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_STMTITERATOR_H +#define LLVM_CLANG_AST_STMTITERATOR_H + +#include "llvm/Support/Compiler.h" +#include "llvm/Support/DataTypes.h" +#include <cassert> +#include <cstddef> +#include <iterator> +#include <utility> + +namespace clang { + +class Stmt; +class Decl; +class VariableArrayType; + +class StmtIteratorBase { +protected: + enum { StmtMode = 0x0, SizeOfTypeVAMode = 0x1, DeclGroupMode = 0x2, + Flags = 0x3 }; + + union { + Stmt **stmt; + Decl **DGI; + }; + uintptr_t RawVAPtr; + Decl **DGE; + + bool inDeclGroup() const { + return (RawVAPtr & Flags) == DeclGroupMode; + } + + bool inSizeOfTypeVA() const { + return (RawVAPtr & Flags) == SizeOfTypeVAMode; + } + + bool inStmt() const { + return (RawVAPtr & Flags) == StmtMode; + } + + const VariableArrayType *getVAPtr() const { + return reinterpret_cast<const VariableArrayType*>(RawVAPtr & ~Flags); + } + + void setVAPtr(const VariableArrayType *P) { + assert (inDeclGroup() || inSizeOfTypeVA()); + RawVAPtr = reinterpret_cast<uintptr_t>(P) | (RawVAPtr & Flags); + } + + void NextDecl(bool ImmediateAdvance = true); + bool HandleDecl(Decl* D); + void NextVA(); + + Stmt*& GetDeclExpr() const; + + StmtIteratorBase(Stmt **s) : stmt(s), RawVAPtr(0) {} + StmtIteratorBase(const VariableArrayType *t); + StmtIteratorBase(Decl **dgi, Decl **dge); + StmtIteratorBase() : stmt(nullptr), RawVAPtr(0) {} +}; + + +template <typename DERIVED, typename REFERENCE> +class StmtIteratorImpl : public StmtIteratorBase, + public std::iterator<std::forward_iterator_tag, + REFERENCE, ptrdiff_t, + REFERENCE, REFERENCE> { +protected: + StmtIteratorImpl(const StmtIteratorBase& RHS) : StmtIteratorBase(RHS) {} +public: + StmtIteratorImpl() {} + StmtIteratorImpl(Stmt **s) : StmtIteratorBase(s) {} + StmtIteratorImpl(Decl **dgi, Decl **dge) : StmtIteratorBase(dgi, dge) {} + StmtIteratorImpl(const VariableArrayType *t) : StmtIteratorBase(t) {} + + DERIVED& operator++() { + if (inStmt()) + ++stmt; + else if (getVAPtr()) + NextVA(); + else + NextDecl(); + + return static_cast<DERIVED&>(*this); + } + + DERIVED operator++(int) { + DERIVED tmp = static_cast<DERIVED&>(*this); + operator++(); + return tmp; + } + + bool operator==(const DERIVED& RHS) const { + return stmt == RHS.stmt && DGI == RHS.DGI && RawVAPtr == RHS.RawVAPtr; + } + + bool operator!=(const DERIVED& RHS) const { + return stmt != RHS.stmt || DGI != RHS.DGI || RawVAPtr != RHS.RawVAPtr; + } + + REFERENCE operator*() const { + return inStmt() ? *stmt : GetDeclExpr(); + } + + REFERENCE operator->() const { return operator*(); } +}; + +struct StmtIterator : public StmtIteratorImpl<StmtIterator,Stmt*&> { + explicit StmtIterator() : StmtIteratorImpl<StmtIterator,Stmt*&>() {} + + StmtIterator(Stmt** S) : StmtIteratorImpl<StmtIterator,Stmt*&>(S) {} + + StmtIterator(Decl** dgi, Decl** dge) + : StmtIteratorImpl<StmtIterator,Stmt*&>(dgi, dge) {} + + StmtIterator(const VariableArrayType *t) + : StmtIteratorImpl<StmtIterator,Stmt*&>(t) {} +}; + +struct ConstStmtIterator : public StmtIteratorImpl<ConstStmtIterator, + const Stmt*> { + explicit ConstStmtIterator() : + StmtIteratorImpl<ConstStmtIterator,const Stmt*>() {} + + ConstStmtIterator(const StmtIterator& RHS) : + StmtIteratorImpl<ConstStmtIterator,const Stmt*>(RHS) {} +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/StmtObjC.h b/contrib/llvm/tools/clang/include/clang/AST/StmtObjC.h new file mode 100644 index 0000000..68fe3ef --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/StmtObjC.h @@ -0,0 +1,375 @@ +//===--- StmtObjC.h - Classes for representing ObjC statements --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +/// \file +/// \brief Defines the Objective-C statement AST node classes. + +#ifndef LLVM_CLANG_AST_STMTOBJC_H +#define LLVM_CLANG_AST_STMTOBJC_H + +#include "clang/AST/Stmt.h" +#include "llvm/Support/Compiler.h" + +namespace clang { + +/// \brief Represents Objective-C's collection statement. +/// +/// This is represented as 'for (element 'in' collection-expression)' stmt. +class ObjCForCollectionStmt : public Stmt { + enum { ELEM, COLLECTION, BODY, END_EXPR }; + Stmt* SubExprs[END_EXPR]; // SubExprs[ELEM] is an expression or declstmt. + SourceLocation ForLoc; + SourceLocation RParenLoc; +public: + ObjCForCollectionStmt(Stmt *Elem, Expr *Collect, Stmt *Body, + SourceLocation FCL, SourceLocation RPL); + explicit ObjCForCollectionStmt(EmptyShell Empty) : + Stmt(ObjCForCollectionStmtClass, Empty) { } + + Stmt *getElement() { return SubExprs[ELEM]; } + Expr *getCollection() { + return reinterpret_cast<Expr*>(SubExprs[COLLECTION]); + } + Stmt *getBody() { return SubExprs[BODY]; } + + const Stmt *getElement() const { return SubExprs[ELEM]; } + const Expr *getCollection() const { + return reinterpret_cast<Expr*>(SubExprs[COLLECTION]); + } + const Stmt *getBody() const { return SubExprs[BODY]; } + + void setElement(Stmt *S) { SubExprs[ELEM] = S; } + void setCollection(Expr *E) { + SubExprs[COLLECTION] = reinterpret_cast<Stmt*>(E); + } + void setBody(Stmt *S) { SubExprs[BODY] = S; } + + SourceLocation getForLoc() const { return ForLoc; } + void setForLoc(SourceLocation Loc) { ForLoc = Loc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; } + + SourceLocation getLocStart() const LLVM_READONLY { return ForLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { + return SubExprs[BODY]->getLocEnd(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCForCollectionStmtClass; + } + + // Iterators + child_range children() { + return child_range(&SubExprs[0], &SubExprs[END_EXPR]); + } +}; + +/// \brief Represents Objective-C's \@catch statement. +class ObjCAtCatchStmt : public Stmt { +private: + VarDecl *ExceptionDecl; + Stmt *Body; + SourceLocation AtCatchLoc, RParenLoc; + +public: + ObjCAtCatchStmt(SourceLocation atCatchLoc, SourceLocation rparenloc, + VarDecl *catchVarDecl, + Stmt *atCatchStmt) + : Stmt(ObjCAtCatchStmtClass), ExceptionDecl(catchVarDecl), + Body(atCatchStmt), AtCatchLoc(atCatchLoc), RParenLoc(rparenloc) { } + + explicit ObjCAtCatchStmt(EmptyShell Empty) : + Stmt(ObjCAtCatchStmtClass, Empty) { } + + const Stmt *getCatchBody() const { return Body; } + Stmt *getCatchBody() { return Body; } + void setCatchBody(Stmt *S) { Body = S; } + + const VarDecl *getCatchParamDecl() const { + return ExceptionDecl; + } + VarDecl *getCatchParamDecl() { + return ExceptionDecl; + } + void setCatchParamDecl(VarDecl *D) { ExceptionDecl = D; } + + SourceLocation getAtCatchLoc() const { return AtCatchLoc; } + void setAtCatchLoc(SourceLocation Loc) { AtCatchLoc = Loc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; } + + SourceLocation getLocStart() const LLVM_READONLY { return AtCatchLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return Body->getLocEnd(); } + + bool hasEllipsis() const { return getCatchParamDecl() == nullptr; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCAtCatchStmtClass; + } + + child_range children() { return child_range(&Body, &Body + 1); } +}; + +/// \brief Represents Objective-C's \@finally statement +class ObjCAtFinallyStmt : public Stmt { + SourceLocation AtFinallyLoc; + Stmt *AtFinallyStmt; + +public: + ObjCAtFinallyStmt(SourceLocation atFinallyLoc, Stmt *atFinallyStmt) + : Stmt(ObjCAtFinallyStmtClass), AtFinallyLoc(atFinallyLoc), + AtFinallyStmt(atFinallyStmt) {} + + explicit ObjCAtFinallyStmt(EmptyShell Empty) : + Stmt(ObjCAtFinallyStmtClass, Empty) { } + + const Stmt *getFinallyBody() const { return AtFinallyStmt; } + Stmt *getFinallyBody() { return AtFinallyStmt; } + void setFinallyBody(Stmt *S) { AtFinallyStmt = S; } + + SourceLocation getLocStart() const LLVM_READONLY { return AtFinallyLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { + return AtFinallyStmt->getLocEnd(); + } + + SourceLocation getAtFinallyLoc() const { return AtFinallyLoc; } + void setAtFinallyLoc(SourceLocation Loc) { AtFinallyLoc = Loc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCAtFinallyStmtClass; + } + + child_range children() { + return child_range(&AtFinallyStmt, &AtFinallyStmt+1); + } +}; + +/// \brief Represents Objective-C's \@try ... \@catch ... \@finally statement. +class ObjCAtTryStmt : public Stmt { +private: + // The location of the @ in the \@try. + SourceLocation AtTryLoc; + + // The number of catch blocks in this statement. + unsigned NumCatchStmts : 16; + + // Whether this statement has a \@finally statement. + bool HasFinally : 1; + + /// \brief Retrieve the statements that are stored after this \@try statement. + /// + /// The order of the statements in memory follows the order in the source, + /// with the \@try body first, followed by the \@catch statements (if any) + /// and, finally, the \@finally (if it exists). + Stmt **getStmts() { return reinterpret_cast<Stmt **> (this + 1); } + const Stmt* const *getStmts() const { + return reinterpret_cast<const Stmt * const*> (this + 1); + } + + ObjCAtTryStmt(SourceLocation atTryLoc, Stmt *atTryStmt, + Stmt **CatchStmts, unsigned NumCatchStmts, + Stmt *atFinallyStmt); + + explicit ObjCAtTryStmt(EmptyShell Empty, unsigned NumCatchStmts, + bool HasFinally) + : Stmt(ObjCAtTryStmtClass, Empty), NumCatchStmts(NumCatchStmts), + HasFinally(HasFinally) { } + +public: + static ObjCAtTryStmt *Create(const ASTContext &Context, + SourceLocation atTryLoc, Stmt *atTryStmt, + Stmt **CatchStmts, unsigned NumCatchStmts, + Stmt *atFinallyStmt); + static ObjCAtTryStmt *CreateEmpty(const ASTContext &Context, + unsigned NumCatchStmts, bool HasFinally); + + /// \brief Retrieve the location of the @ in the \@try. + SourceLocation getAtTryLoc() const { return AtTryLoc; } + void setAtTryLoc(SourceLocation Loc) { AtTryLoc = Loc; } + + /// \brief Retrieve the \@try body. + const Stmt *getTryBody() const { return getStmts()[0]; } + Stmt *getTryBody() { return getStmts()[0]; } + void setTryBody(Stmt *S) { getStmts()[0] = S; } + + /// \brief Retrieve the number of \@catch statements in this try-catch-finally + /// block. + unsigned getNumCatchStmts() const { return NumCatchStmts; } + + /// \brief Retrieve a \@catch statement. + const ObjCAtCatchStmt *getCatchStmt(unsigned I) const { + assert(I < NumCatchStmts && "Out-of-bounds @catch index"); + return cast_or_null<ObjCAtCatchStmt>(getStmts()[I + 1]); + } + + /// \brief Retrieve a \@catch statement. + ObjCAtCatchStmt *getCatchStmt(unsigned I) { + assert(I < NumCatchStmts && "Out-of-bounds @catch index"); + return cast_or_null<ObjCAtCatchStmt>(getStmts()[I + 1]); + } + + /// \brief Set a particular catch statement. + void setCatchStmt(unsigned I, ObjCAtCatchStmt *S) { + assert(I < NumCatchStmts && "Out-of-bounds @catch index"); + getStmts()[I + 1] = S; + } + + /// \brief Retrieve the \@finally statement, if any. + const ObjCAtFinallyStmt *getFinallyStmt() const { + if (!HasFinally) + return nullptr; + + return cast_or_null<ObjCAtFinallyStmt>(getStmts()[1 + NumCatchStmts]); + } + ObjCAtFinallyStmt *getFinallyStmt() { + if (!HasFinally) + return nullptr; + + return cast_or_null<ObjCAtFinallyStmt>(getStmts()[1 + NumCatchStmts]); + } + void setFinallyStmt(Stmt *S) { + assert(HasFinally && "@try does not have a @finally slot!"); + getStmts()[1 + NumCatchStmts] = S; + } + + SourceLocation getLocStart() const LLVM_READONLY { return AtTryLoc; } + SourceLocation getLocEnd() const LLVM_READONLY; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCAtTryStmtClass; + } + + child_range children() { + return child_range(getStmts(), + getStmts() + 1 + NumCatchStmts + HasFinally); + } +}; + +/// \brief Represents Objective-C's \@synchronized statement. +/// +/// Example: +/// \code +/// @synchronized (sem) { +/// do-something; +/// } +/// \endcode +class ObjCAtSynchronizedStmt : public Stmt { +private: + SourceLocation AtSynchronizedLoc; + enum { SYNC_EXPR, SYNC_BODY, END_EXPR }; + Stmt* SubStmts[END_EXPR]; + +public: + ObjCAtSynchronizedStmt(SourceLocation atSynchronizedLoc, Stmt *synchExpr, + Stmt *synchBody) + : Stmt(ObjCAtSynchronizedStmtClass) { + SubStmts[SYNC_EXPR] = synchExpr; + SubStmts[SYNC_BODY] = synchBody; + AtSynchronizedLoc = atSynchronizedLoc; + } + explicit ObjCAtSynchronizedStmt(EmptyShell Empty) : + Stmt(ObjCAtSynchronizedStmtClass, Empty) { } + + SourceLocation getAtSynchronizedLoc() const { return AtSynchronizedLoc; } + void setAtSynchronizedLoc(SourceLocation Loc) { AtSynchronizedLoc = Loc; } + + const CompoundStmt *getSynchBody() const { + return reinterpret_cast<CompoundStmt*>(SubStmts[SYNC_BODY]); + } + CompoundStmt *getSynchBody() { + return reinterpret_cast<CompoundStmt*>(SubStmts[SYNC_BODY]); + } + void setSynchBody(Stmt *S) { SubStmts[SYNC_BODY] = S; } + + const Expr *getSynchExpr() const { + return reinterpret_cast<Expr*>(SubStmts[SYNC_EXPR]); + } + Expr *getSynchExpr() { + return reinterpret_cast<Expr*>(SubStmts[SYNC_EXPR]); + } + void setSynchExpr(Stmt *S) { SubStmts[SYNC_EXPR] = S; } + + SourceLocation getLocStart() const LLVM_READONLY { return AtSynchronizedLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { + return getSynchBody()->getLocEnd(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCAtSynchronizedStmtClass; + } + + child_range children() { + return child_range(&SubStmts[0], &SubStmts[0]+END_EXPR); + } +}; + +/// \brief Represents Objective-C's \@throw statement. +class ObjCAtThrowStmt : public Stmt { + SourceLocation AtThrowLoc; + Stmt *Throw; + +public: + ObjCAtThrowStmt(SourceLocation atThrowLoc, Stmt *throwExpr) + : Stmt(ObjCAtThrowStmtClass), Throw(throwExpr) { + AtThrowLoc = atThrowLoc; + } + explicit ObjCAtThrowStmt(EmptyShell Empty) : + Stmt(ObjCAtThrowStmtClass, Empty) { } + + const Expr *getThrowExpr() const { return reinterpret_cast<Expr*>(Throw); } + Expr *getThrowExpr() { return reinterpret_cast<Expr*>(Throw); } + void setThrowExpr(Stmt *S) { Throw = S; } + + SourceLocation getThrowLoc() { return AtThrowLoc; } + void setThrowLoc(SourceLocation Loc) { AtThrowLoc = Loc; } + + SourceLocation getLocStart() const LLVM_READONLY { return AtThrowLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { + return Throw ? Throw->getLocEnd() : AtThrowLoc; + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCAtThrowStmtClass; + } + + child_range children() { return child_range(&Throw, &Throw+1); } +}; + +/// \brief Represents Objective-C's \@autoreleasepool Statement +class ObjCAutoreleasePoolStmt : public Stmt { + SourceLocation AtLoc; + Stmt *SubStmt; + +public: + ObjCAutoreleasePoolStmt(SourceLocation atLoc, Stmt *subStmt) + : Stmt(ObjCAutoreleasePoolStmtClass), AtLoc(atLoc), SubStmt(subStmt) {} + + explicit ObjCAutoreleasePoolStmt(EmptyShell Empty) : + Stmt(ObjCAutoreleasePoolStmtClass, Empty) { } + + const Stmt *getSubStmt() const { return SubStmt; } + Stmt *getSubStmt() { return SubStmt; } + void setSubStmt(Stmt *S) { SubStmt = S; } + + SourceLocation getLocStart() const LLVM_READONLY { return AtLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return SubStmt->getLocEnd();} + + SourceLocation getAtLoc() const { return AtLoc; } + void setAtLoc(SourceLocation Loc) { AtLoc = Loc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCAutoreleasePoolStmtClass; + } + + child_range children() { return child_range(&SubStmt, &SubStmt + 1); } +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/StmtOpenMP.h b/contrib/llvm/tools/clang/include/clang/AST/StmtOpenMP.h new file mode 100644 index 0000000..1ba859c --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/StmtOpenMP.h @@ -0,0 +1,2422 @@ +//===- StmtOpenMP.h - Classes for OpenMP directives ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// \brief This file defines OpenMP AST classes for executable directives and +/// clauses. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_STMTOPENMP_H +#define LLVM_CLANG_AST_STMTOPENMP_H + +#include "clang/AST/Expr.h" +#include "clang/AST/OpenMPClause.h" +#include "clang/AST/Stmt.h" +#include "clang/Basic/OpenMPKinds.h" +#include "clang/Basic/SourceLocation.h" + +namespace clang { + +//===----------------------------------------------------------------------===// +// AST classes for directives. +//===----------------------------------------------------------------------===// + +/// \brief This is a basic class for representing single OpenMP executable +/// directive. +/// +class OMPExecutableDirective : public Stmt { + friend class ASTStmtReader; + /// \brief Kind of the directive. + OpenMPDirectiveKind Kind; + /// \brief Starting location of the directive (directive keyword). + SourceLocation StartLoc; + /// \brief Ending location of the directive. + SourceLocation EndLoc; + /// \brief Numbers of clauses. + const unsigned NumClauses; + /// \brief Number of child expressions/stmts. + const unsigned NumChildren; + /// \brief Offset from this to the start of clauses. + /// There are NumClauses pointers to clauses, they are followed by + /// NumChildren pointers to child stmts/exprs (if the directive type + /// requires an associated stmt, then it has to be the first of them). + const unsigned ClausesOffset; + + /// \brief Get the clauses storage. + MutableArrayRef<OMPClause *> getClauses() { + OMPClause **ClauseStorage = reinterpret_cast<OMPClause **>( + reinterpret_cast<char *>(this) + ClausesOffset); + return MutableArrayRef<OMPClause *>(ClauseStorage, NumClauses); + } + +protected: + /// \brief Build instance of directive of class \a K. + /// + /// \param SC Statement class. + /// \param K Kind of OpenMP directive. + /// \param StartLoc Starting location of the directive (directive keyword). + /// \param EndLoc Ending location of the directive. + /// + template <typename T> + OMPExecutableDirective(const T *, StmtClass SC, OpenMPDirectiveKind K, + SourceLocation StartLoc, SourceLocation EndLoc, + unsigned NumClauses, unsigned NumChildren) + : Stmt(SC), Kind(K), StartLoc(std::move(StartLoc)), + EndLoc(std::move(EndLoc)), NumClauses(NumClauses), + NumChildren(NumChildren), + ClausesOffset(llvm::RoundUpToAlignment(sizeof(T), + llvm::alignOf<OMPClause *>())) {} + + /// \brief Sets the list of variables for this clause. + /// + /// \param Clauses The list of clauses for the directive. + /// + void setClauses(ArrayRef<OMPClause *> Clauses); + + /// \brief Set the associated statement for the directive. + /// + /// /param S Associated statement. + /// + void setAssociatedStmt(Stmt *S) { + assert(hasAssociatedStmt() && "no associated statement."); + *child_begin() = S; + } + +public: + /// \brief Iterates over a filtered subrange of clauses applied to a + /// directive. + /// + /// This iterator visits only clauses of type SpecificClause. + template <typename SpecificClause> + class specific_clause_iterator + : public llvm::iterator_adaptor_base< + specific_clause_iterator<SpecificClause>, + ArrayRef<OMPClause *>::const_iterator, std::forward_iterator_tag, + const SpecificClause *, ptrdiff_t, const SpecificClause *, + const SpecificClause *> { + ArrayRef<OMPClause *>::const_iterator End; + + void SkipToNextClause() { + while (this->I != End && !isa<SpecificClause>(*this->I)) + ++this->I; + } + + public: + explicit specific_clause_iterator(ArrayRef<OMPClause *> Clauses) + : specific_clause_iterator::iterator_adaptor_base(Clauses.begin()), + End(Clauses.end()) { + SkipToNextClause(); + } + + const SpecificClause *operator*() const { + return cast<SpecificClause>(*this->I); + } + const SpecificClause *operator->() const { return **this; } + + specific_clause_iterator &operator++() { + ++this->I; + SkipToNextClause(); + return *this; + } + }; + + template <typename SpecificClause> + static llvm::iterator_range<specific_clause_iterator<SpecificClause>> + getClausesOfKind(ArrayRef<OMPClause *> Clauses) { + return {specific_clause_iterator<SpecificClause>(Clauses), + specific_clause_iterator<SpecificClause>( + llvm::makeArrayRef(Clauses.end(), 0))}; + } + + template <typename SpecificClause> + llvm::iterator_range<specific_clause_iterator<SpecificClause>> + getClausesOfKind() const { + return getClausesOfKind<SpecificClause>(clauses()); + } + + /// Gets a single clause of the specified kind associated with the + /// current directive iff there is only one clause of this kind (and assertion + /// is fired if there is more than one clause is associated with the + /// directive). Returns nullptr if no clause of this kind is associated with + /// the directive. + template <typename SpecificClause> + const SpecificClause *getSingleClause() const { + auto Clauses = getClausesOfKind<SpecificClause>(); + + if (Clauses.begin() != Clauses.end()) { + assert(std::next(Clauses.begin()) == Clauses.end() && + "There are at least 2 clauses of the specified kind"); + return *Clauses.begin(); + } + return nullptr; + } + + /// Returns true if the current directive has one or more clauses of a + /// specific kind. + template <typename SpecificClause> + bool hasClausesOfKind() const { + auto Clauses = getClausesOfKind<SpecificClause>(); + return Clauses.begin() != Clauses.end(); + } + + /// \brief Returns starting location of directive kind. + SourceLocation getLocStart() const { return StartLoc; } + /// \brief Returns ending location of directive. + SourceLocation getLocEnd() const { return EndLoc; } + + /// \brief Set starting location of directive kind. + /// + /// \param Loc New starting location of directive. + /// + void setLocStart(SourceLocation Loc) { StartLoc = Loc; } + /// \brief Set ending location of directive. + /// + /// \param Loc New ending location of directive. + /// + void setLocEnd(SourceLocation Loc) { EndLoc = Loc; } + + /// \brief Get number of clauses. + unsigned getNumClauses() const { return NumClauses; } + + /// \brief Returns specified clause. + /// + /// \param i Number of clause. + /// + OMPClause *getClause(unsigned i) const { return clauses()[i]; } + + /// \brief Returns true if directive has associated statement. + bool hasAssociatedStmt() const { return NumChildren > 0; } + + /// \brief Returns statement associated with the directive. + Stmt *getAssociatedStmt() const { + assert(hasAssociatedStmt() && "no associated statement."); + return const_cast<Stmt *>(*child_begin()); + } + + OpenMPDirectiveKind getDirectiveKind() const { return Kind; } + + static bool classof(const Stmt *S) { + return S->getStmtClass() >= firstOMPExecutableDirectiveConstant && + S->getStmtClass() <= lastOMPExecutableDirectiveConstant; + } + + child_range children() { + if (!hasAssociatedStmt()) + return child_range(child_iterator(), child_iterator()); + Stmt **ChildStorage = reinterpret_cast<Stmt **>(getClauses().end()); + return child_range(ChildStorage, ChildStorage + NumChildren); + } + + ArrayRef<OMPClause *> clauses() { return getClauses(); } + + ArrayRef<OMPClause *> clauses() const { + return const_cast<OMPExecutableDirective *>(this)->getClauses(); + } +}; + +/// \brief This represents '#pragma omp parallel' directive. +/// +/// \code +/// #pragma omp parallel private(a,b) reduction(+: c,d) +/// \endcode +/// In this example directive '#pragma omp parallel' has clauses 'private' +/// with the variables 'a' and 'b' and 'reduction' with operator '+' and +/// variables 'c' and 'd'. +/// +class OMPParallelDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + /// \brief true if the construct has inner cancel directive. + bool HasCancel; + + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive (directive keyword). + /// \param EndLoc Ending Location of the directive. + /// + OMPParallelDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned NumClauses) + : OMPExecutableDirective(this, OMPParallelDirectiveClass, OMPD_parallel, + StartLoc, EndLoc, NumClauses, 1), + HasCancel(false) {} + + /// \brief Build an empty directive. + /// + /// \param NumClauses Number of clauses. + /// + explicit OMPParallelDirective(unsigned NumClauses) + : OMPExecutableDirective(this, OMPParallelDirectiveClass, OMPD_parallel, + SourceLocation(), SourceLocation(), NumClauses, + 1), + HasCancel(false) {} + + /// \brief Set cancel state. + void setHasCancel(bool Has) { HasCancel = Has; } + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement associated with the directive. + /// \param HasCancel true if this directive has inner cancel directive. + /// + static OMPParallelDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, bool HasCancel); + + /// \brief Creates an empty directive with the place for \a N clauses. + /// + /// \param C AST context. + /// \param NumClauses Number of clauses. + /// + static OMPParallelDirective *CreateEmpty(const ASTContext &C, + unsigned NumClauses, EmptyShell); + + /// \brief Return true if current directive has inner cancel directive. + bool hasCancel() const { return HasCancel; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPParallelDirectiveClass; + } +}; + +/// \brief This is a common base class for loop directives ('omp simd', 'omp +/// for', 'omp for simd' etc.). It is responsible for the loop code generation. +/// +class OMPLoopDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + /// \brief Number of collapsed loops as specified by 'collapse' clause. + unsigned CollapsedNum; + + /// \brief Offsets to the stored exprs. + /// This enumeration contains offsets to all the pointers to children + /// expressions stored in OMPLoopDirective. + /// The first 9 children are nesessary for all the loop directives, and + /// the next 7 are specific to the worksharing ones. + /// After the fixed children, three arrays of length CollapsedNum are + /// allocated: loop counters, their updates and final values. + /// + enum { + AssociatedStmtOffset = 0, + IterationVariableOffset = 1, + LastIterationOffset = 2, + CalcLastIterationOffset = 3, + PreConditionOffset = 4, + CondOffset = 5, + InitOffset = 6, + IncOffset = 7, + // The '...End' enumerators do not correspond to child expressions - they + // specify the offset to the end (and start of the following counters/ + // updates/finals arrays). + DefaultEnd = 8, + // The following 7 exprs are used by worksharing loops only. + IsLastIterVariableOffset = 8, + LowerBoundVariableOffset = 9, + UpperBoundVariableOffset = 10, + StrideVariableOffset = 11, + EnsureUpperBoundOffset = 12, + NextLowerBoundOffset = 13, + NextUpperBoundOffset = 14, + // Offset to the end (and start of the following counters/updates/finals + // arrays) for worksharing loop directives. + WorksharingEnd = 15, + }; + + /// \brief Get the counters storage. + MutableArrayRef<Expr *> getCounters() { + Expr **Storage = reinterpret_cast<Expr **>( + &(*(std::next(child_begin(), getArraysOffset(getDirectiveKind()))))); + return MutableArrayRef<Expr *>(Storage, CollapsedNum); + } + + /// \brief Get the private counters storage. + MutableArrayRef<Expr *> getPrivateCounters() { + Expr **Storage = reinterpret_cast<Expr **>(&*std::next( + child_begin(), getArraysOffset(getDirectiveKind()) + CollapsedNum)); + return MutableArrayRef<Expr *>(Storage, CollapsedNum); + } + + /// \brief Get the updates storage. + MutableArrayRef<Expr *> getInits() { + Expr **Storage = reinterpret_cast<Expr **>( + &*std::next(child_begin(), + getArraysOffset(getDirectiveKind()) + 2 * CollapsedNum)); + return MutableArrayRef<Expr *>(Storage, CollapsedNum); + } + + /// \brief Get the updates storage. + MutableArrayRef<Expr *> getUpdates() { + Expr **Storage = reinterpret_cast<Expr **>( + &*std::next(child_begin(), + getArraysOffset(getDirectiveKind()) + 3 * CollapsedNum)); + return MutableArrayRef<Expr *>(Storage, CollapsedNum); + } + + /// \brief Get the final counter updates storage. + MutableArrayRef<Expr *> getFinals() { + Expr **Storage = reinterpret_cast<Expr **>( + &*std::next(child_begin(), + getArraysOffset(getDirectiveKind()) + 4 * CollapsedNum)); + return MutableArrayRef<Expr *>(Storage, CollapsedNum); + } + +protected: + /// \brief Build instance of loop directive of class \a Kind. + /// + /// \param SC Statement class. + /// \param Kind Kind of OpenMP directive. + /// \param StartLoc Starting location of the directive (directive keyword). + /// \param EndLoc Ending location of the directive. + /// \param CollapsedNum Number of collapsed loops from 'collapse' clause. + /// \param NumClauses Number of clauses. + /// \param NumSpecialChildren Number of additional directive-specific stmts. + /// + template <typename T> + OMPLoopDirective(const T *That, StmtClass SC, OpenMPDirectiveKind Kind, + SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, unsigned NumClauses, + unsigned NumSpecialChildren = 0) + : OMPExecutableDirective(That, SC, Kind, StartLoc, EndLoc, NumClauses, + numLoopChildren(CollapsedNum, Kind) + + NumSpecialChildren), + CollapsedNum(CollapsedNum) {} + + /// \brief Offset to the start of children expression arrays. + static unsigned getArraysOffset(OpenMPDirectiveKind Kind) { + return (isOpenMPWorksharingDirective(Kind) || + isOpenMPTaskLoopDirective(Kind) || + isOpenMPDistributeDirective(Kind)) + ? WorksharingEnd + : DefaultEnd; + } + + /// \brief Children number. + static unsigned numLoopChildren(unsigned CollapsedNum, + OpenMPDirectiveKind Kind) { + return getArraysOffset(Kind) + 5 * CollapsedNum; // Counters, + // PrivateCounters, Inits, + // Updates and Finals + } + + void setIterationVariable(Expr *IV) { + *std::next(child_begin(), IterationVariableOffset) = IV; + } + void setLastIteration(Expr *LI) { + *std::next(child_begin(), LastIterationOffset) = LI; + } + void setCalcLastIteration(Expr *CLI) { + *std::next(child_begin(), CalcLastIterationOffset) = CLI; + } + void setPreCond(Expr *PC) { + *std::next(child_begin(), PreConditionOffset) = PC; + } + void setCond(Expr *Cond) { + *std::next(child_begin(), CondOffset) = Cond; + } + void setInit(Expr *Init) { *std::next(child_begin(), InitOffset) = Init; } + void setInc(Expr *Inc) { *std::next(child_begin(), IncOffset) = Inc; } + void setIsLastIterVariable(Expr *IL) { + assert((isOpenMPWorksharingDirective(getDirectiveKind()) || + isOpenMPTaskLoopDirective(getDirectiveKind()) || + isOpenMPDistributeDirective(getDirectiveKind())) && + "expected worksharing loop directive"); + *std::next(child_begin(), IsLastIterVariableOffset) = IL; + } + void setLowerBoundVariable(Expr *LB) { + assert((isOpenMPWorksharingDirective(getDirectiveKind()) || + isOpenMPTaskLoopDirective(getDirectiveKind()) || + isOpenMPDistributeDirective(getDirectiveKind())) && + "expected worksharing loop directive"); + *std::next(child_begin(), LowerBoundVariableOffset) = LB; + } + void setUpperBoundVariable(Expr *UB) { + assert((isOpenMPWorksharingDirective(getDirectiveKind()) || + isOpenMPTaskLoopDirective(getDirectiveKind()) || + isOpenMPDistributeDirective(getDirectiveKind())) && + "expected worksharing loop directive"); + *std::next(child_begin(), UpperBoundVariableOffset) = UB; + } + void setStrideVariable(Expr *ST) { + assert((isOpenMPWorksharingDirective(getDirectiveKind()) || + isOpenMPTaskLoopDirective(getDirectiveKind()) || + isOpenMPDistributeDirective(getDirectiveKind())) && + "expected worksharing loop directive"); + *std::next(child_begin(), StrideVariableOffset) = ST; + } + void setEnsureUpperBound(Expr *EUB) { + assert((isOpenMPWorksharingDirective(getDirectiveKind()) || + isOpenMPTaskLoopDirective(getDirectiveKind()) || + isOpenMPDistributeDirective(getDirectiveKind())) && + "expected worksharing loop directive"); + *std::next(child_begin(), EnsureUpperBoundOffset) = EUB; + } + void setNextLowerBound(Expr *NLB) { + assert((isOpenMPWorksharingDirective(getDirectiveKind()) || + isOpenMPTaskLoopDirective(getDirectiveKind()) || + isOpenMPDistributeDirective(getDirectiveKind())) && + "expected worksharing loop directive"); + *std::next(child_begin(), NextLowerBoundOffset) = NLB; + } + void setNextUpperBound(Expr *NUB) { + assert((isOpenMPWorksharingDirective(getDirectiveKind()) || + isOpenMPTaskLoopDirective(getDirectiveKind()) || + isOpenMPDistributeDirective(getDirectiveKind())) && + "expected worksharing loop directive"); + *std::next(child_begin(), NextUpperBoundOffset) = NUB; + } + void setCounters(ArrayRef<Expr *> A); + void setPrivateCounters(ArrayRef<Expr *> A); + void setInits(ArrayRef<Expr *> A); + void setUpdates(ArrayRef<Expr *> A); + void setFinals(ArrayRef<Expr *> A); + +public: + /// \brief The expressions built for the OpenMP loop CodeGen for the + /// whole collapsed loop nest. + struct HelperExprs { + /// \brief Loop iteration variable. + Expr *IterationVarRef; + /// \brief Loop last iteration number. + Expr *LastIteration; + /// \brief Loop number of iterations. + Expr *NumIterations; + /// \brief Calculation of last iteration. + Expr *CalcLastIteration; + /// \brief Loop pre-condition. + Expr *PreCond; + /// \brief Loop condition. + Expr *Cond; + /// \brief Loop iteration variable init. + Expr *Init; + /// \brief Loop increment. + Expr *Inc; + /// \brief IsLastIteration - local flag variable passed to runtime. + Expr *IL; + /// \brief LowerBound - local variable passed to runtime. + Expr *LB; + /// \brief UpperBound - local variable passed to runtime. + Expr *UB; + /// \brief Stride - local variable passed to runtime. + Expr *ST; + /// \brief EnsureUpperBound -- expression LB = min(LB, NumIterations). + Expr *EUB; + /// \brief Update of LowerBound for statically sheduled 'omp for' loops. + Expr *NLB; + /// \brief Update of UpperBound for statically sheduled 'omp for' loops. + Expr *NUB; + /// \brief Counters Loop counters. + SmallVector<Expr *, 4> Counters; + /// \brief PrivateCounters Loop counters. + SmallVector<Expr *, 4> PrivateCounters; + /// \brief Expressions for loop counters inits for CodeGen. + SmallVector<Expr *, 4> Inits; + /// \brief Expressions for loop counters update for CodeGen. + SmallVector<Expr *, 4> Updates; + /// \brief Final loop counter values for GodeGen. + SmallVector<Expr *, 4> Finals; + + /// \brief Check if all the expressions are built (does not check the + /// worksharing ones). + bool builtAll() { + return IterationVarRef != nullptr && LastIteration != nullptr && + NumIterations != nullptr && PreCond != nullptr && + Cond != nullptr && Init != nullptr && Inc != nullptr; + } + + /// \brief Initialize all the fields to null. + /// \param Size Number of elements in the counters/finals/updates arrays. + void clear(unsigned Size) { + IterationVarRef = nullptr; + LastIteration = nullptr; + CalcLastIteration = nullptr; + PreCond = nullptr; + Cond = nullptr; + Init = nullptr; + Inc = nullptr; + IL = nullptr; + LB = nullptr; + UB = nullptr; + ST = nullptr; + EUB = nullptr; + NLB = nullptr; + NUB = nullptr; + Counters.resize(Size); + PrivateCounters.resize(Size); + Inits.resize(Size); + Updates.resize(Size); + Finals.resize(Size); + for (unsigned i = 0; i < Size; ++i) { + Counters[i] = nullptr; + PrivateCounters[i] = nullptr; + Inits[i] = nullptr; + Updates[i] = nullptr; + Finals[i] = nullptr; + } + } + }; + + /// \brief Get number of collapsed loops. + unsigned getCollapsedNumber() const { return CollapsedNum; } + + Expr *getIterationVariable() const { + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), IterationVariableOffset))); + } + Expr *getLastIteration() const { + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), LastIterationOffset))); + } + Expr *getCalcLastIteration() const { + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), CalcLastIterationOffset))); + } + Expr *getPreCond() const { + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), PreConditionOffset))); + } + Expr *getCond() const { + return const_cast<Expr *>( + reinterpret_cast<const Expr *>(*std::next(child_begin(), CondOffset))); + } + Expr *getInit() const { + return const_cast<Expr *>( + reinterpret_cast<const Expr *>(*std::next(child_begin(), InitOffset))); + } + Expr *getInc() const { + return const_cast<Expr *>( + reinterpret_cast<const Expr *>(*std::next(child_begin(), IncOffset))); + } + Expr *getIsLastIterVariable() const { + assert((isOpenMPWorksharingDirective(getDirectiveKind()) || + isOpenMPTaskLoopDirective(getDirectiveKind())) && + "expected worksharing loop directive"); + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), IsLastIterVariableOffset))); + } + Expr *getLowerBoundVariable() const { + assert((isOpenMPWorksharingDirective(getDirectiveKind()) || + isOpenMPTaskLoopDirective(getDirectiveKind())) && + "expected worksharing loop directive"); + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), LowerBoundVariableOffset))); + } + Expr *getUpperBoundVariable() const { + assert((isOpenMPWorksharingDirective(getDirectiveKind()) || + isOpenMPTaskLoopDirective(getDirectiveKind())) && + "expected worksharing loop directive"); + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), UpperBoundVariableOffset))); + } + Expr *getStrideVariable() const { + assert((isOpenMPWorksharingDirective(getDirectiveKind()) || + isOpenMPTaskLoopDirective(getDirectiveKind())) && + "expected worksharing loop directive"); + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), StrideVariableOffset))); + } + Expr *getEnsureUpperBound() const { + assert((isOpenMPWorksharingDirective(getDirectiveKind()) || + isOpenMPTaskLoopDirective(getDirectiveKind())) && + "expected worksharing loop directive"); + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), EnsureUpperBoundOffset))); + } + Expr *getNextLowerBound() const { + assert((isOpenMPWorksharingDirective(getDirectiveKind()) || + isOpenMPTaskLoopDirective(getDirectiveKind())) && + "expected worksharing loop directive"); + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), NextLowerBoundOffset))); + } + Expr *getNextUpperBound() const { + assert((isOpenMPWorksharingDirective(getDirectiveKind()) || + isOpenMPTaskLoopDirective(getDirectiveKind())) && + "expected worksharing loop directive"); + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), NextUpperBoundOffset))); + } + const Stmt *getBody() const { + // This relies on the loop form is already checked by Sema. + Stmt *Body = getAssociatedStmt()->IgnoreContainers(true); + Body = cast<ForStmt>(Body)->getBody(); + for (unsigned Cnt = 1; Cnt < CollapsedNum; ++Cnt) { + Body = Body->IgnoreContainers(); + Body = cast<ForStmt>(Body)->getBody(); + } + return Body; + } + + ArrayRef<Expr *> counters() { return getCounters(); } + + ArrayRef<Expr *> counters() const { + return const_cast<OMPLoopDirective *>(this)->getCounters(); + } + + ArrayRef<Expr *> private_counters() { return getPrivateCounters(); } + + ArrayRef<Expr *> private_counters() const { + return const_cast<OMPLoopDirective *>(this)->getPrivateCounters(); + } + + ArrayRef<Expr *> inits() { return getInits(); } + + ArrayRef<Expr *> inits() const { + return const_cast<OMPLoopDirective *>(this)->getInits(); + } + + ArrayRef<Expr *> updates() { return getUpdates(); } + + ArrayRef<Expr *> updates() const { + return const_cast<OMPLoopDirective *>(this)->getUpdates(); + } + + ArrayRef<Expr *> finals() { return getFinals(); } + + ArrayRef<Expr *> finals() const { + return const_cast<OMPLoopDirective *>(this)->getFinals(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPSimdDirectiveClass || + T->getStmtClass() == OMPForDirectiveClass || + T->getStmtClass() == OMPForSimdDirectiveClass || + T->getStmtClass() == OMPParallelForDirectiveClass || + T->getStmtClass() == OMPParallelForSimdDirectiveClass || + T->getStmtClass() == OMPTaskLoopDirectiveClass || + T->getStmtClass() == OMPTaskLoopSimdDirectiveClass || + T->getStmtClass() == OMPDistributeDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp simd' directive. +/// +/// \code +/// #pragma omp simd private(a,b) linear(i,j:s) reduction(+:c,d) +/// \endcode +/// In this example directive '#pragma omp simd' has clauses 'private' +/// with the variables 'a' and 'b', 'linear' with variables 'i', 'j' and +/// linear step 's', 'reduction' with operator '+' and variables 'c' and 'd'. +/// +class OMPSimdDirective : public OMPLoopDirective { + friend class ASTStmtReader; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// \param CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + OMPSimdDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, unsigned NumClauses) + : OMPLoopDirective(this, OMPSimdDirectiveClass, OMPD_simd, StartLoc, + EndLoc, CollapsedNum, NumClauses) {} + + /// \brief Build an empty directive. + /// + /// \param CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + explicit OMPSimdDirective(unsigned CollapsedNum, unsigned NumClauses) + : OMPLoopDirective(this, OMPSimdDirectiveClass, OMPD_simd, + SourceLocation(), SourceLocation(), CollapsedNum, + NumClauses) {} + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param CollapsedNum Number of collapsed loops. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// \param Exprs Helper expressions for CodeGen. + /// + static OMPSimdDirective *Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation EndLoc, unsigned CollapsedNum, + ArrayRef<OMPClause *> Clauses, + Stmt *AssociatedStmt, + const HelperExprs &Exprs); + + /// \brief Creates an empty directive with the place + /// for \a NumClauses clauses. + /// + /// \param C AST context. + /// \param CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + static OMPSimdDirective *CreateEmpty(const ASTContext &C, unsigned NumClauses, + unsigned CollapsedNum, EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPSimdDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp for' directive. +/// +/// \code +/// #pragma omp for private(a,b) reduction(+:c,d) +/// \endcode +/// In this example directive '#pragma omp for' has clauses 'private' with the +/// variables 'a' and 'b' and 'reduction' with operator '+' and variables 'c' +/// and 'd'. +/// +class OMPForDirective : public OMPLoopDirective { + friend class ASTStmtReader; + + /// \brief true if current directive has inner cancel directive. + bool HasCancel; + + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// \param CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + OMPForDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, unsigned NumClauses) + : OMPLoopDirective(this, OMPForDirectiveClass, OMPD_for, StartLoc, EndLoc, + CollapsedNum, NumClauses), + HasCancel(false) {} + + /// \brief Build an empty directive. + /// + /// \param CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + explicit OMPForDirective(unsigned CollapsedNum, unsigned NumClauses) + : OMPLoopDirective(this, OMPForDirectiveClass, OMPD_for, SourceLocation(), + SourceLocation(), CollapsedNum, NumClauses), + HasCancel(false) {} + + /// \brief Set cancel state. + void setHasCancel(bool Has) { HasCancel = Has; } + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param CollapsedNum Number of collapsed loops. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// \param Exprs Helper expressions for CodeGen. + /// \param HasCancel true if current directive has inner cancel directive. + /// + static OMPForDirective *Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation EndLoc, unsigned CollapsedNum, + ArrayRef<OMPClause *> Clauses, + Stmt *AssociatedStmt, const HelperExprs &Exprs, + bool HasCancel); + + /// \brief Creates an empty directive with the place + /// for \a NumClauses clauses. + /// + /// \param C AST context. + /// \param CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + static OMPForDirective *CreateEmpty(const ASTContext &C, unsigned NumClauses, + unsigned CollapsedNum, EmptyShell); + + /// \brief Return true if current directive has inner cancel directive. + bool hasCancel() const { return HasCancel; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPForDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp for simd' directive. +/// +/// \code +/// #pragma omp for simd private(a,b) linear(i,j:s) reduction(+:c,d) +/// \endcode +/// In this example directive '#pragma omp for simd' has clauses 'private' +/// with the variables 'a' and 'b', 'linear' with variables 'i', 'j' and +/// linear step 's', 'reduction' with operator '+' and variables 'c' and 'd'. +/// +class OMPForSimdDirective : public OMPLoopDirective { + friend class ASTStmtReader; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// \param CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + OMPForSimdDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, unsigned NumClauses) + : OMPLoopDirective(this, OMPForSimdDirectiveClass, OMPD_for_simd, + StartLoc, EndLoc, CollapsedNum, NumClauses) {} + + /// \brief Build an empty directive. + /// + /// \param CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + explicit OMPForSimdDirective(unsigned CollapsedNum, unsigned NumClauses) + : OMPLoopDirective(this, OMPForSimdDirectiveClass, OMPD_for_simd, + SourceLocation(), SourceLocation(), CollapsedNum, + NumClauses) {} + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param CollapsedNum Number of collapsed loops. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// \param Exprs Helper expressions for CodeGen. + /// + static OMPForSimdDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, + Stmt *AssociatedStmt, const HelperExprs &Exprs); + + /// \brief Creates an empty directive with the place + /// for \a NumClauses clauses. + /// + /// \param C AST context. + /// \param CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + static OMPForSimdDirective *CreateEmpty(const ASTContext &C, + unsigned NumClauses, + unsigned CollapsedNum, EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPForSimdDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp sections' directive. +/// +/// \code +/// #pragma omp sections private(a,b) reduction(+:c,d) +/// \endcode +/// In this example directive '#pragma omp sections' has clauses 'private' with +/// the variables 'a' and 'b' and 'reduction' with operator '+' and variables +/// 'c' and 'd'. +/// +class OMPSectionsDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + + /// \brief true if current directive has inner cancel directive. + bool HasCancel; + + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// \param NumClauses Number of clauses. + /// + OMPSectionsDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned NumClauses) + : OMPExecutableDirective(this, OMPSectionsDirectiveClass, OMPD_sections, + StartLoc, EndLoc, NumClauses, 1), + HasCancel(false) {} + + /// \brief Build an empty directive. + /// + /// \param NumClauses Number of clauses. + /// + explicit OMPSectionsDirective(unsigned NumClauses) + : OMPExecutableDirective(this, OMPSectionsDirectiveClass, OMPD_sections, + SourceLocation(), SourceLocation(), NumClauses, + 1), + HasCancel(false) {} + + /// \brief Set cancel state. + void setHasCancel(bool Has) { HasCancel = Has; } + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// \param HasCancel true if current directive has inner directive. + /// + static OMPSectionsDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, bool HasCancel); + + /// \brief Creates an empty directive with the place for \a NumClauses + /// clauses. + /// + /// \param C AST context. + /// \param NumClauses Number of clauses. + /// + static OMPSectionsDirective *CreateEmpty(const ASTContext &C, + unsigned NumClauses, EmptyShell); + + /// \brief Return true if current directive has inner cancel directive. + bool hasCancel() const { return HasCancel; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPSectionsDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp section' directive. +/// +/// \code +/// #pragma omp section +/// \endcode +/// +class OMPSectionDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + + /// \brief true if current directive has inner cancel directive. + bool HasCancel; + + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// + OMPSectionDirective(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPExecutableDirective(this, OMPSectionDirectiveClass, OMPD_section, + StartLoc, EndLoc, 0, 1), + HasCancel(false) {} + + /// \brief Build an empty directive. + /// + explicit OMPSectionDirective() + : OMPExecutableDirective(this, OMPSectionDirectiveClass, OMPD_section, + SourceLocation(), SourceLocation(), 0, 1), + HasCancel(false) {} + +public: + /// \brief Creates directive. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param AssociatedStmt Statement, associated with the directive. + /// \param HasCancel true if current directive has inner directive. + /// + static OMPSectionDirective *Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + Stmt *AssociatedStmt, bool HasCancel); + + /// \brief Creates an empty directive. + /// + /// \param C AST context. + /// + static OMPSectionDirective *CreateEmpty(const ASTContext &C, EmptyShell); + + /// \brief Set cancel state. + void setHasCancel(bool Has) { HasCancel = Has; } + + /// \brief Return true if current directive has inner cancel directive. + bool hasCancel() const { return HasCancel; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPSectionDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp single' directive. +/// +/// \code +/// #pragma omp single private(a,b) copyprivate(c,d) +/// \endcode +/// In this example directive '#pragma omp single' has clauses 'private' with +/// the variables 'a' and 'b' and 'copyprivate' with variables 'c' and 'd'. +/// +class OMPSingleDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// \param NumClauses Number of clauses. + /// + OMPSingleDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned NumClauses) + : OMPExecutableDirective(this, OMPSingleDirectiveClass, OMPD_single, + StartLoc, EndLoc, NumClauses, 1) {} + + /// \brief Build an empty directive. + /// + /// \param NumClauses Number of clauses. + /// + explicit OMPSingleDirective(unsigned NumClauses) + : OMPExecutableDirective(this, OMPSingleDirectiveClass, OMPD_single, + SourceLocation(), SourceLocation(), NumClauses, + 1) {} + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// + static OMPSingleDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt); + + /// \brief Creates an empty directive with the place for \a NumClauses + /// clauses. + /// + /// \param C AST context. + /// \param NumClauses Number of clauses. + /// + static OMPSingleDirective *CreateEmpty(const ASTContext &C, + unsigned NumClauses, EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPSingleDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp master' directive. +/// +/// \code +/// #pragma omp master +/// \endcode +/// +class OMPMasterDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// + OMPMasterDirective(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPExecutableDirective(this, OMPMasterDirectiveClass, OMPD_master, + StartLoc, EndLoc, 0, 1) {} + + /// \brief Build an empty directive. + /// + explicit OMPMasterDirective() + : OMPExecutableDirective(this, OMPMasterDirectiveClass, OMPD_master, + SourceLocation(), SourceLocation(), 0, 1) {} + +public: + /// \brief Creates directive. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param AssociatedStmt Statement, associated with the directive. + /// + static OMPMasterDirective *Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + Stmt *AssociatedStmt); + + /// \brief Creates an empty directive. + /// + /// \param C AST context. + /// + static OMPMasterDirective *CreateEmpty(const ASTContext &C, EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPMasterDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp critical' directive. +/// +/// \code +/// #pragma omp critical +/// \endcode +/// +class OMPCriticalDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + /// \brief Name of the directive. + DeclarationNameInfo DirName; + /// \brief Build directive with the given start and end location. + /// + /// \param Name Name of the directive. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// \param NumClauses Number of clauses. + /// + OMPCriticalDirective(const DeclarationNameInfo &Name, SourceLocation StartLoc, + SourceLocation EndLoc, unsigned NumClauses) + : OMPExecutableDirective(this, OMPCriticalDirectiveClass, OMPD_critical, + StartLoc, EndLoc, NumClauses, 1), + DirName(Name) {} + + /// \brief Build an empty directive. + /// + /// \param NumClauses Number of clauses. + /// + explicit OMPCriticalDirective(unsigned NumClauses) + : OMPExecutableDirective(this, OMPCriticalDirectiveClass, OMPD_critical, + SourceLocation(), SourceLocation(), NumClauses, + 1), + DirName() {} + + /// \brief Set name of the directive. + /// + /// \param Name Name of the directive. + /// + void setDirectiveName(const DeclarationNameInfo &Name) { DirName = Name; } + +public: + /// \brief Creates directive. + /// + /// \param C AST context. + /// \param Name Name of the directive. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// + static OMPCriticalDirective * + Create(const ASTContext &C, const DeclarationNameInfo &Name, + SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt); + + /// \brief Creates an empty directive. + /// + /// \param C AST context. + /// \param NumClauses Number of clauses. + /// + static OMPCriticalDirective *CreateEmpty(const ASTContext &C, + unsigned NumClauses, EmptyShell); + + /// \brief Return name of the directive. + /// + DeclarationNameInfo getDirectiveName() const { return DirName; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPCriticalDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp parallel for' directive. +/// +/// \code +/// #pragma omp parallel for private(a,b) reduction(+:c,d) +/// \endcode +/// In this example directive '#pragma omp parallel for' has clauses 'private' +/// with the variables 'a' and 'b' and 'reduction' with operator '+' and +/// variables 'c' and 'd'. +/// +class OMPParallelForDirective : public OMPLoopDirective { + friend class ASTStmtReader; + + /// \brief true if current region has inner cancel directive. + bool HasCancel; + + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// \param CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + OMPParallelForDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, unsigned NumClauses) + : OMPLoopDirective(this, OMPParallelForDirectiveClass, OMPD_parallel_for, + StartLoc, EndLoc, CollapsedNum, NumClauses), + HasCancel(false) {} + + /// \brief Build an empty directive. + /// + /// \param CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + explicit OMPParallelForDirective(unsigned CollapsedNum, unsigned NumClauses) + : OMPLoopDirective(this, OMPParallelForDirectiveClass, OMPD_parallel_for, + SourceLocation(), SourceLocation(), CollapsedNum, + NumClauses), + HasCancel(false) {} + + /// \brief Set cancel state. + void setHasCancel(bool Has) { HasCancel = Has; } + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param CollapsedNum Number of collapsed loops. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// \param Exprs Helper expressions for CodeGen. + /// \param HasCancel true if current directive has inner cancel directive. + /// + static OMPParallelForDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, + Stmt *AssociatedStmt, const HelperExprs &Exprs, bool HasCancel); + + /// \brief Creates an empty directive with the place + /// for \a NumClauses clauses. + /// + /// \param C AST context. + /// \param CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + static OMPParallelForDirective *CreateEmpty(const ASTContext &C, + unsigned NumClauses, + unsigned CollapsedNum, + EmptyShell); + + /// \brief Return true if current directive has inner cancel directive. + bool hasCancel() const { return HasCancel; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPParallelForDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp parallel for simd' directive. +/// +/// \code +/// #pragma omp parallel for simd private(a,b) linear(i,j:s) reduction(+:c,d) +/// \endcode +/// In this example directive '#pragma omp parallel for simd' has clauses +/// 'private' with the variables 'a' and 'b', 'linear' with variables 'i', 'j' +/// and linear step 's', 'reduction' with operator '+' and variables 'c' and +/// 'd'. +/// +class OMPParallelForSimdDirective : public OMPLoopDirective { + friend class ASTStmtReader; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// \param CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + OMPParallelForSimdDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, unsigned NumClauses) + : OMPLoopDirective(this, OMPParallelForSimdDirectiveClass, + OMPD_parallel_for_simd, StartLoc, EndLoc, CollapsedNum, + NumClauses) {} + + /// \brief Build an empty directive. + /// + /// \param CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + explicit OMPParallelForSimdDirective(unsigned CollapsedNum, + unsigned NumClauses) + : OMPLoopDirective(this, OMPParallelForSimdDirectiveClass, + OMPD_parallel_for_simd, SourceLocation(), + SourceLocation(), CollapsedNum, NumClauses) {} + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param CollapsedNum Number of collapsed loops. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// \param Exprs Helper expressions for CodeGen. + /// + static OMPParallelForSimdDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, + Stmt *AssociatedStmt, const HelperExprs &Exprs); + + /// \brief Creates an empty directive with the place + /// for \a NumClauses clauses. + /// + /// \param C AST context. + /// \param CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + static OMPParallelForSimdDirective *CreateEmpty(const ASTContext &C, + unsigned NumClauses, + unsigned CollapsedNum, + EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPParallelForSimdDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp parallel sections' directive. +/// +/// \code +/// #pragma omp parallel sections private(a,b) reduction(+:c,d) +/// \endcode +/// In this example directive '#pragma omp parallel sections' has clauses +/// 'private' with the variables 'a' and 'b' and 'reduction' with operator '+' +/// and variables 'c' and 'd'. +/// +class OMPParallelSectionsDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + + /// \brief true if current directive has inner cancel directive. + bool HasCancel; + + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// \param NumClauses Number of clauses. + /// + OMPParallelSectionsDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned NumClauses) + : OMPExecutableDirective(this, OMPParallelSectionsDirectiveClass, + OMPD_parallel_sections, StartLoc, EndLoc, + NumClauses, 1), + HasCancel(false) {} + + /// \brief Build an empty directive. + /// + /// \param NumClauses Number of clauses. + /// + explicit OMPParallelSectionsDirective(unsigned NumClauses) + : OMPExecutableDirective(this, OMPParallelSectionsDirectiveClass, + OMPD_parallel_sections, SourceLocation(), + SourceLocation(), NumClauses, 1), + HasCancel(false) {} + + /// \brief Set cancel state. + void setHasCancel(bool Has) { HasCancel = Has; } + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// \param HasCancel true if current directive has inner cancel directive. + /// + static OMPParallelSectionsDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, bool HasCancel); + + /// \brief Creates an empty directive with the place for \a NumClauses + /// clauses. + /// + /// \param C AST context. + /// \param NumClauses Number of clauses. + /// + static OMPParallelSectionsDirective * + CreateEmpty(const ASTContext &C, unsigned NumClauses, EmptyShell); + + /// \brief Return true if current directive has inner cancel directive. + bool hasCancel() const { return HasCancel; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPParallelSectionsDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp task' directive. +/// +/// \code +/// #pragma omp task private(a,b) final(d) +/// \endcode +/// In this example directive '#pragma omp task' has clauses 'private' with the +/// variables 'a' and 'b' and 'final' with condition 'd'. +/// +class OMPTaskDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + /// \brief true if this directive has inner cancel directive. + bool HasCancel; + + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// \param NumClauses Number of clauses. + /// + OMPTaskDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned NumClauses) + : OMPExecutableDirective(this, OMPTaskDirectiveClass, OMPD_task, StartLoc, + EndLoc, NumClauses, 1), + HasCancel(false) {} + + /// \brief Build an empty directive. + /// + /// \param NumClauses Number of clauses. + /// + explicit OMPTaskDirective(unsigned NumClauses) + : OMPExecutableDirective(this, OMPTaskDirectiveClass, OMPD_task, + SourceLocation(), SourceLocation(), NumClauses, + 1), + HasCancel(false) {} + + /// \brief Set cancel state. + void setHasCancel(bool Has) { HasCancel = Has; } + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// \param HasCancel true, if current directive has inner cancel directive. + /// + static OMPTaskDirective *Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation EndLoc, + ArrayRef<OMPClause *> Clauses, + Stmt *AssociatedStmt, bool HasCancel); + + /// \brief Creates an empty directive with the place for \a NumClauses + /// clauses. + /// + /// \param C AST context. + /// \param NumClauses Number of clauses. + /// + static OMPTaskDirective *CreateEmpty(const ASTContext &C, unsigned NumClauses, + EmptyShell); + + /// \brief Return true if current directive has inner cancel directive. + bool hasCancel() const { return HasCancel; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPTaskDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp taskyield' directive. +/// +/// \code +/// #pragma omp taskyield +/// \endcode +/// +class OMPTaskyieldDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// + OMPTaskyieldDirective(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPExecutableDirective(this, OMPTaskyieldDirectiveClass, OMPD_taskyield, + StartLoc, EndLoc, 0, 0) {} + + /// \brief Build an empty directive. + /// + explicit OMPTaskyieldDirective() + : OMPExecutableDirective(this, OMPTaskyieldDirectiveClass, OMPD_taskyield, + SourceLocation(), SourceLocation(), 0, 0) {} + +public: + /// \brief Creates directive. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// + static OMPTaskyieldDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc); + + /// \brief Creates an empty directive. + /// + /// \param C AST context. + /// + static OMPTaskyieldDirective *CreateEmpty(const ASTContext &C, EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPTaskyieldDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp barrier' directive. +/// +/// \code +/// #pragma omp barrier +/// \endcode +/// +class OMPBarrierDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// + OMPBarrierDirective(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPExecutableDirective(this, OMPBarrierDirectiveClass, OMPD_barrier, + StartLoc, EndLoc, 0, 0) {} + + /// \brief Build an empty directive. + /// + explicit OMPBarrierDirective() + : OMPExecutableDirective(this, OMPBarrierDirectiveClass, OMPD_barrier, + SourceLocation(), SourceLocation(), 0, 0) {} + +public: + /// \brief Creates directive. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// + static OMPBarrierDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc); + + /// \brief Creates an empty directive. + /// + /// \param C AST context. + /// + static OMPBarrierDirective *CreateEmpty(const ASTContext &C, EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPBarrierDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp taskwait' directive. +/// +/// \code +/// #pragma omp taskwait +/// \endcode +/// +class OMPTaskwaitDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// + OMPTaskwaitDirective(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPExecutableDirective(this, OMPTaskwaitDirectiveClass, OMPD_taskwait, + StartLoc, EndLoc, 0, 0) {} + + /// \brief Build an empty directive. + /// + explicit OMPTaskwaitDirective() + : OMPExecutableDirective(this, OMPTaskwaitDirectiveClass, OMPD_taskwait, + SourceLocation(), SourceLocation(), 0, 0) {} + +public: + /// \brief Creates directive. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// + static OMPTaskwaitDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc); + + /// \brief Creates an empty directive. + /// + /// \param C AST context. + /// + static OMPTaskwaitDirective *CreateEmpty(const ASTContext &C, EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPTaskwaitDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp taskgroup' directive. +/// +/// \code +/// #pragma omp taskgroup +/// \endcode +/// +class OMPTaskgroupDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// + OMPTaskgroupDirective(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPExecutableDirective(this, OMPTaskgroupDirectiveClass, OMPD_taskgroup, + StartLoc, EndLoc, 0, 1) {} + + /// \brief Build an empty directive. + /// + explicit OMPTaskgroupDirective() + : OMPExecutableDirective(this, OMPTaskgroupDirectiveClass, OMPD_taskgroup, + SourceLocation(), SourceLocation(), 0, 1) {} + +public: + /// \brief Creates directive. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param AssociatedStmt Statement, associated with the directive. + /// + static OMPTaskgroupDirective *Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + Stmt *AssociatedStmt); + + /// \brief Creates an empty directive. + /// + /// \param C AST context. + /// + static OMPTaskgroupDirective *CreateEmpty(const ASTContext &C, EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPTaskgroupDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp flush' directive. +/// +/// \code +/// #pragma omp flush(a,b) +/// \endcode +/// In this example directive '#pragma omp flush' has 2 arguments- variables 'a' +/// and 'b'. +/// 'omp flush' directive does not have clauses but have an optional list of +/// variables to flush. This list of variables is stored within some fake clause +/// FlushClause. +class OMPFlushDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// \param NumClauses Number of clauses. + /// + OMPFlushDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned NumClauses) + : OMPExecutableDirective(this, OMPFlushDirectiveClass, OMPD_flush, + StartLoc, EndLoc, NumClauses, 0) {} + + /// \brief Build an empty directive. + /// + /// \param NumClauses Number of clauses. + /// + explicit OMPFlushDirective(unsigned NumClauses) + : OMPExecutableDirective(this, OMPFlushDirectiveClass, OMPD_flush, + SourceLocation(), SourceLocation(), NumClauses, + 0) {} + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses (only single OMPFlushClause clause is + /// allowed). + /// + static OMPFlushDirective *Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation EndLoc, + ArrayRef<OMPClause *> Clauses); + + /// \brief Creates an empty directive with the place for \a NumClauses + /// clauses. + /// + /// \param C AST context. + /// \param NumClauses Number of clauses. + /// + static OMPFlushDirective *CreateEmpty(const ASTContext &C, + unsigned NumClauses, EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPFlushDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp ordered' directive. +/// +/// \code +/// #pragma omp ordered +/// \endcode +/// +class OMPOrderedDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// \param NumClauses Number of clauses. + /// + OMPOrderedDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned NumClauses) + : OMPExecutableDirective(this, OMPOrderedDirectiveClass, OMPD_ordered, + StartLoc, EndLoc, NumClauses, 1) {} + + /// \brief Build an empty directive. + /// + /// \param NumClauses Number of clauses. + /// + explicit OMPOrderedDirective(unsigned NumClauses) + : OMPExecutableDirective(this, OMPOrderedDirectiveClass, OMPD_ordered, + SourceLocation(), SourceLocation(), NumClauses, + 1) {} + +public: + /// \brief Creates directive. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// + static OMPOrderedDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt); + + /// \brief Creates an empty directive. + /// + /// \param C AST context. + /// \param NumClauses Number of clauses. + /// + static OMPOrderedDirective *CreateEmpty(const ASTContext &C, + unsigned NumClauses, EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPOrderedDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp atomic' directive. +/// +/// \code +/// #pragma omp atomic capture +/// \endcode +/// In this example directive '#pragma omp atomic' has clause 'capture'. +/// +class OMPAtomicDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + /// \brief Used for 'atomic update' or 'atomic capture' constructs. They may + /// have atomic expressions of forms + /// \code + /// x = x binop expr; + /// x = expr binop x; + /// \endcode + /// This field is true for the first form of the expression and false for the + /// second. Required for correct codegen of non-associative operations (like + /// << or >>). + bool IsXLHSInRHSPart; + /// \brief Used for 'atomic update' or 'atomic capture' constructs. They may + /// have atomic expressions of forms + /// \code + /// v = x; <update x>; + /// <update x>; v = x; + /// \endcode + /// This field is true for the first(postfix) form of the expression and false + /// otherwise. + bool IsPostfixUpdate; + + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// \param NumClauses Number of clauses. + /// + OMPAtomicDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned NumClauses) + : OMPExecutableDirective(this, OMPAtomicDirectiveClass, OMPD_atomic, + StartLoc, EndLoc, NumClauses, 5), + IsXLHSInRHSPart(false), IsPostfixUpdate(false) {} + + /// \brief Build an empty directive. + /// + /// \param NumClauses Number of clauses. + /// + explicit OMPAtomicDirective(unsigned NumClauses) + : OMPExecutableDirective(this, OMPAtomicDirectiveClass, OMPD_atomic, + SourceLocation(), SourceLocation(), NumClauses, + 5), + IsXLHSInRHSPart(false), IsPostfixUpdate(false) {} + + /// \brief Set 'x' part of the associated expression/statement. + void setX(Expr *X) { *std::next(child_begin()) = X; } + /// \brief Set helper expression of the form + /// 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' or + /// 'OpaqueValueExpr(expr) binop OpaqueValueExpr(x)'. + void setUpdateExpr(Expr *UE) { *std::next(child_begin(), 2) = UE; } + /// \brief Set 'v' part of the associated expression/statement. + void setV(Expr *V) { *std::next(child_begin(), 3) = V; } + /// \brief Set 'expr' part of the associated expression/statement. + void setExpr(Expr *E) { *std::next(child_begin(), 4) = E; } + +public: + /// \brief Creates directive with a list of \a Clauses and 'x', 'v' and 'expr' + /// parts of the atomic construct (see Section 2.12.6, atomic Construct, for + /// detailed description of 'x', 'v' and 'expr'). + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// \param X 'x' part of the associated expression/statement. + /// \param V 'v' part of the associated expression/statement. + /// \param E 'expr' part of the associated expression/statement. + /// \param UE Helper expression of the form + /// 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' or + /// 'OpaqueValueExpr(expr) binop OpaqueValueExpr(x)'. + /// \param IsXLHSInRHSPart true if \a UE has the first form and false if the + /// second. + /// \param IsPostfixUpdate true if original value of 'x' must be stored in + /// 'v', not an updated one. + static OMPAtomicDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, Expr *X, Expr *V, + Expr *E, Expr *UE, bool IsXLHSInRHSPart, bool IsPostfixUpdate); + + /// \brief Creates an empty directive with the place for \a NumClauses + /// clauses. + /// + /// \param C AST context. + /// \param NumClauses Number of clauses. + /// + static OMPAtomicDirective *CreateEmpty(const ASTContext &C, + unsigned NumClauses, EmptyShell); + + /// \brief Get 'x' part of the associated expression/statement. + Expr *getX() { return cast_or_null<Expr>(*std::next(child_begin())); } + const Expr *getX() const { + return cast_or_null<Expr>(*std::next(child_begin())); + } + /// \brief Get helper expression of the form + /// 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' or + /// 'OpaqueValueExpr(expr) binop OpaqueValueExpr(x)'. + Expr *getUpdateExpr() { + return cast_or_null<Expr>(*std::next(child_begin(), 2)); + } + const Expr *getUpdateExpr() const { + return cast_or_null<Expr>(*std::next(child_begin(), 2)); + } + /// \brief Return true if helper update expression has form + /// 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' and false if it has form + /// 'OpaqueValueExpr(expr) binop OpaqueValueExpr(x)'. + bool isXLHSInRHSPart() const { return IsXLHSInRHSPart; } + /// \brief Return true if 'v' expression must be updated to original value of + /// 'x', false if 'v' must be updated to the new value of 'x'. + bool isPostfixUpdate() const { return IsPostfixUpdate; } + /// \brief Get 'v' part of the associated expression/statement. + Expr *getV() { return cast_or_null<Expr>(*std::next(child_begin(), 3)); } + const Expr *getV() const { + return cast_or_null<Expr>(*std::next(child_begin(), 3)); + } + /// \brief Get 'expr' part of the associated expression/statement. + Expr *getExpr() { return cast_or_null<Expr>(*std::next(child_begin(), 4)); } + const Expr *getExpr() const { + return cast_or_null<Expr>(*std::next(child_begin(), 4)); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPAtomicDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp target' directive. +/// +/// \code +/// #pragma omp target if(a) +/// \endcode +/// In this example directive '#pragma omp target' has clause 'if' with +/// condition 'a'. +/// +class OMPTargetDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// \param NumClauses Number of clauses. + /// + OMPTargetDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned NumClauses) + : OMPExecutableDirective(this, OMPTargetDirectiveClass, OMPD_target, + StartLoc, EndLoc, NumClauses, 1) {} + + /// \brief Build an empty directive. + /// + /// \param NumClauses Number of clauses. + /// + explicit OMPTargetDirective(unsigned NumClauses) + : OMPExecutableDirective(this, OMPTargetDirectiveClass, OMPD_target, + SourceLocation(), SourceLocation(), NumClauses, + 1) {} + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// + static OMPTargetDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt); + + /// \brief Creates an empty directive with the place for \a NumClauses + /// clauses. + /// + /// \param C AST context. + /// \param NumClauses Number of clauses. + /// + static OMPTargetDirective *CreateEmpty(const ASTContext &C, + unsigned NumClauses, EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPTargetDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp target data' directive. +/// +/// \code +/// #pragma omp target data device(0) if(a) map(b[:]) +/// \endcode +/// In this example directive '#pragma omp target data' has clauses 'device' +/// with the value '0', 'if' with condition 'a' and 'map' with array +/// section 'b[:]'. +/// +class OMPTargetDataDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param NumClauses The number of clauses. + /// + OMPTargetDataDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned NumClauses) + : OMPExecutableDirective(this, OMPTargetDataDirectiveClass, + OMPD_target_data, StartLoc, EndLoc, NumClauses, + 1) {} + + /// \brief Build an empty directive. + /// + /// \param NumClauses Number of clauses. + /// + explicit OMPTargetDataDirective(unsigned NumClauses) + : OMPExecutableDirective(this, OMPTargetDataDirectiveClass, + OMPD_target_data, SourceLocation(), + SourceLocation(), NumClauses, 1) {} + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// + static OMPTargetDataDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt); + + /// \brief Creates an empty directive with the place for \a N clauses. + /// + /// \param C AST context. + /// \param N The number of clauses. + /// + static OMPTargetDataDirective *CreateEmpty(const ASTContext &C, unsigned N, + EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPTargetDataDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp teams' directive. +/// +/// \code +/// #pragma omp teams if(a) +/// \endcode +/// In this example directive '#pragma omp teams' has clause 'if' with +/// condition 'a'. +/// +class OMPTeamsDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// \param NumClauses Number of clauses. + /// + OMPTeamsDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned NumClauses) + : OMPExecutableDirective(this, OMPTeamsDirectiveClass, OMPD_teams, + StartLoc, EndLoc, NumClauses, 1) {} + + /// \brief Build an empty directive. + /// + /// \param NumClauses Number of clauses. + /// + explicit OMPTeamsDirective(unsigned NumClauses) + : OMPExecutableDirective(this, OMPTeamsDirectiveClass, OMPD_teams, + SourceLocation(), SourceLocation(), NumClauses, + 1) {} + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// + static OMPTeamsDirective *Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation EndLoc, + ArrayRef<OMPClause *> Clauses, + Stmt *AssociatedStmt); + + /// \brief Creates an empty directive with the place for \a NumClauses + /// clauses. + /// + /// \param C AST context. + /// \param NumClauses Number of clauses. + /// + static OMPTeamsDirective *CreateEmpty(const ASTContext &C, + unsigned NumClauses, EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPTeamsDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp cancellation point' directive. +/// +/// \code +/// #pragma omp cancellation point for +/// \endcode +/// +/// In this example a cancellation point is created for innermost 'for' region. +class OMPCancellationPointDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + OpenMPDirectiveKind CancelRegion; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// + OMPCancellationPointDirective(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPExecutableDirective(this, OMPCancellationPointDirectiveClass, + OMPD_cancellation_point, StartLoc, EndLoc, 0, 0), + CancelRegion(OMPD_unknown) {} + + /// \brief Build an empty directive. + /// + explicit OMPCancellationPointDirective() + : OMPExecutableDirective(this, OMPCancellationPointDirectiveClass, + OMPD_cancellation_point, SourceLocation(), + SourceLocation(), 0, 0), + CancelRegion(OMPD_unknown) {} + + /// \brief Set cancel region for current cancellation point. + /// \param CR Cancellation region. + void setCancelRegion(OpenMPDirectiveKind CR) { CancelRegion = CR; } + +public: + /// \brief Creates directive. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// + static OMPCancellationPointDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + OpenMPDirectiveKind CancelRegion); + + /// \brief Creates an empty directive. + /// + /// \param C AST context. + /// + static OMPCancellationPointDirective *CreateEmpty(const ASTContext &C, + EmptyShell); + + /// \brief Get cancellation region for the current cancellation point. + OpenMPDirectiveKind getCancelRegion() const { return CancelRegion; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPCancellationPointDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp cancel' directive. +/// +/// \code +/// #pragma omp cancel for +/// \endcode +/// +/// In this example a cancel is created for innermost 'for' region. +class OMPCancelDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + OpenMPDirectiveKind CancelRegion; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// \param NumClauses Number of clauses. + /// + OMPCancelDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned NumClauses) + : OMPExecutableDirective(this, OMPCancelDirectiveClass, OMPD_cancel, + StartLoc, EndLoc, NumClauses, 0), + CancelRegion(OMPD_unknown) {} + + /// \brief Build an empty directive. + /// + /// \param NumClauses Number of clauses. + explicit OMPCancelDirective(unsigned NumClauses) + : OMPExecutableDirective(this, OMPCancelDirectiveClass, OMPD_cancel, + SourceLocation(), SourceLocation(), NumClauses, + 0), + CancelRegion(OMPD_unknown) {} + + /// \brief Set cancel region for current cancellation point. + /// \param CR Cancellation region. + void setCancelRegion(OpenMPDirectiveKind CR) { CancelRegion = CR; } + +public: + /// \brief Creates directive. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// + static OMPCancelDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef<OMPClause *> Clauses, OpenMPDirectiveKind CancelRegion); + + /// \brief Creates an empty directive. + /// + /// \param C AST context. + /// \param NumClauses Number of clauses. + /// + static OMPCancelDirective *CreateEmpty(const ASTContext &C, + unsigned NumClauses, EmptyShell); + + /// \brief Get cancellation region for the current cancellation point. + OpenMPDirectiveKind getCancelRegion() const { return CancelRegion; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPCancelDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp taskloop' directive. +/// +/// \code +/// #pragma omp taskloop private(a,b) grainsize(val) num_tasks(num) +/// \endcode +/// In this example directive '#pragma omp taskloop' has clauses 'private' +/// with the variables 'a' and 'b', 'grainsize' with expression 'val' and +/// 'num_tasks' with expression 'num'. +/// +class OMPTaskLoopDirective : public OMPLoopDirective { + friend class ASTStmtReader; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// \param CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + OMPTaskLoopDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, unsigned NumClauses) + : OMPLoopDirective(this, OMPTaskLoopDirectiveClass, OMPD_taskloop, + StartLoc, EndLoc, CollapsedNum, NumClauses) {} + + /// \brief Build an empty directive. + /// + /// \param CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + explicit OMPTaskLoopDirective(unsigned CollapsedNum, unsigned NumClauses) + : OMPLoopDirective(this, OMPTaskLoopDirectiveClass, OMPD_taskloop, + SourceLocation(), SourceLocation(), CollapsedNum, + NumClauses) {} + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param CollapsedNum Number of collapsed loops. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// \param Exprs Helper expressions for CodeGen. + /// + static OMPTaskLoopDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, + Stmt *AssociatedStmt, const HelperExprs &Exprs); + + /// \brief Creates an empty directive with the place + /// for \a NumClauses clauses. + /// + /// \param C AST context. + /// \param CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + static OMPTaskLoopDirective *CreateEmpty(const ASTContext &C, + unsigned NumClauses, + unsigned CollapsedNum, EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPTaskLoopDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp taskloop simd' directive. +/// +/// \code +/// #pragma omp taskloop simd private(a,b) grainsize(val) num_tasks(num) +/// \endcode +/// In this example directive '#pragma omp taskloop simd' has clauses 'private' +/// with the variables 'a' and 'b', 'grainsize' with expression 'val' and +/// 'num_tasks' with expression 'num'. +/// +class OMPTaskLoopSimdDirective : public OMPLoopDirective { + friend class ASTStmtReader; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// \param CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + OMPTaskLoopSimdDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, unsigned NumClauses) + : OMPLoopDirective(this, OMPTaskLoopSimdDirectiveClass, + OMPD_taskloop_simd, StartLoc, EndLoc, CollapsedNum, + NumClauses) {} + + /// \brief Build an empty directive. + /// + /// \param CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + explicit OMPTaskLoopSimdDirective(unsigned CollapsedNum, unsigned NumClauses) + : OMPLoopDirective(this, OMPTaskLoopSimdDirectiveClass, + OMPD_taskloop_simd, SourceLocation(), SourceLocation(), + CollapsedNum, NumClauses) {} + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param CollapsedNum Number of collapsed loops. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// \param Exprs Helper expressions for CodeGen. + /// + static OMPTaskLoopSimdDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, + Stmt *AssociatedStmt, const HelperExprs &Exprs); + + /// \brief Creates an empty directive with the place + /// for \a NumClauses clauses. + /// + /// \param C AST context. + /// \param CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + static OMPTaskLoopSimdDirective *CreateEmpty(const ASTContext &C, + unsigned NumClauses, + unsigned CollapsedNum, + EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPTaskLoopSimdDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp distribute' directive. +/// +/// \code +/// #pragma omp distribute private(a,b) +/// \endcode +/// In this example directive '#pragma omp distribute' has clauses 'private' +/// with the variables 'a' and 'b' +/// +class OMPDistributeDirective : public OMPLoopDirective { + friend class ASTStmtReader; + + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// \param CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + OMPDistributeDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, unsigned NumClauses) + : OMPLoopDirective(this, OMPDistributeDirectiveClass, OMPD_distribute, + StartLoc, EndLoc, CollapsedNum, NumClauses) + {} + + /// \brief Build an empty directive. + /// + /// \param CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + explicit OMPDistributeDirective(unsigned CollapsedNum, unsigned NumClauses) + : OMPLoopDirective(this, OMPDistributeDirectiveClass, OMPD_distribute, + SourceLocation(), SourceLocation(), CollapsedNum, + NumClauses) + {} + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param CollapsedNum Number of collapsed loops. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// \param Exprs Helper expressions for CodeGen. + /// + static OMPDistributeDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, + Stmt *AssociatedStmt, const HelperExprs &Exprs); + + /// \brief Creates an empty directive with the place + /// for \a NumClauses clauses. + /// + /// \param C AST context. + /// \param CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + static OMPDistributeDirective *CreateEmpty(const ASTContext &C, + unsigned NumClauses, + unsigned CollapsedNum, EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPDistributeDirectiveClass; + } +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/StmtVisitor.h b/contrib/llvm/tools/clang/include/clang/AST/StmtVisitor.h new file mode 100644 index 0000000..df4a2d8 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/StmtVisitor.h @@ -0,0 +1,227 @@ +//===--- StmtVisitor.h - Visitor for Stmt subclasses ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the StmtVisitor and ConstStmtVisitor interfaces. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_STMTVISITOR_H +#define LLVM_CLANG_AST_STMTVISITOR_H + +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/ExprOpenMP.h" +#include "clang/AST/StmtCXX.h" +#include "clang/AST/StmtObjC.h" +#include "clang/AST/StmtOpenMP.h" + +namespace clang { + +template <typename T> struct make_ptr { typedef T *type; }; +template <typename T> struct make_const_ptr { typedef const T *type; }; + +/// StmtVisitorBase - This class implements a simple visitor for Stmt +/// subclasses. Since Expr derives from Stmt, this also includes support for +/// visiting Exprs. +template<template <typename> class Ptr, typename ImplClass, typename RetTy=void> +class StmtVisitorBase { +public: + +#define PTR(CLASS) typename Ptr<CLASS>::type +#define DISPATCH(NAME, CLASS) \ + return static_cast<ImplClass*>(this)->Visit ## NAME(static_cast<PTR(CLASS)>(S)) + + RetTy Visit(PTR(Stmt) S) { + + // If we have a binary expr, dispatch to the subcode of the binop. A smart + // optimizer (e.g. LLVM) will fold this comparison into the switch stmt + // below. + if (PTR(BinaryOperator) BinOp = dyn_cast<BinaryOperator>(S)) { + switch (BinOp->getOpcode()) { + case BO_PtrMemD: DISPATCH(BinPtrMemD, BinaryOperator); + case BO_PtrMemI: DISPATCH(BinPtrMemI, BinaryOperator); + case BO_Mul: DISPATCH(BinMul, BinaryOperator); + case BO_Div: DISPATCH(BinDiv, BinaryOperator); + case BO_Rem: DISPATCH(BinRem, BinaryOperator); + case BO_Add: DISPATCH(BinAdd, BinaryOperator); + case BO_Sub: DISPATCH(BinSub, BinaryOperator); + case BO_Shl: DISPATCH(BinShl, BinaryOperator); + case BO_Shr: DISPATCH(BinShr, BinaryOperator); + + case BO_LT: DISPATCH(BinLT, BinaryOperator); + case BO_GT: DISPATCH(BinGT, BinaryOperator); + case BO_LE: DISPATCH(BinLE, BinaryOperator); + case BO_GE: DISPATCH(BinGE, BinaryOperator); + case BO_EQ: DISPATCH(BinEQ, BinaryOperator); + case BO_NE: DISPATCH(BinNE, BinaryOperator); + + case BO_And: DISPATCH(BinAnd, BinaryOperator); + case BO_Xor: DISPATCH(BinXor, BinaryOperator); + case BO_Or : DISPATCH(BinOr, BinaryOperator); + case BO_LAnd: DISPATCH(BinLAnd, BinaryOperator); + case BO_LOr : DISPATCH(BinLOr, BinaryOperator); + case BO_Assign: DISPATCH(BinAssign, BinaryOperator); + case BO_MulAssign: DISPATCH(BinMulAssign, CompoundAssignOperator); + case BO_DivAssign: DISPATCH(BinDivAssign, CompoundAssignOperator); + case BO_RemAssign: DISPATCH(BinRemAssign, CompoundAssignOperator); + case BO_AddAssign: DISPATCH(BinAddAssign, CompoundAssignOperator); + case BO_SubAssign: DISPATCH(BinSubAssign, CompoundAssignOperator); + case BO_ShlAssign: DISPATCH(BinShlAssign, CompoundAssignOperator); + case BO_ShrAssign: DISPATCH(BinShrAssign, CompoundAssignOperator); + case BO_AndAssign: DISPATCH(BinAndAssign, CompoundAssignOperator); + case BO_OrAssign: DISPATCH(BinOrAssign, CompoundAssignOperator); + case BO_XorAssign: DISPATCH(BinXorAssign, CompoundAssignOperator); + case BO_Comma: DISPATCH(BinComma, BinaryOperator); + } + } else if (PTR(UnaryOperator) UnOp = dyn_cast<UnaryOperator>(S)) { + switch (UnOp->getOpcode()) { + case UO_PostInc: DISPATCH(UnaryPostInc, UnaryOperator); + case UO_PostDec: DISPATCH(UnaryPostDec, UnaryOperator); + case UO_PreInc: DISPATCH(UnaryPreInc, UnaryOperator); + case UO_PreDec: DISPATCH(UnaryPreDec, UnaryOperator); + case UO_AddrOf: DISPATCH(UnaryAddrOf, UnaryOperator); + case UO_Deref: DISPATCH(UnaryDeref, UnaryOperator); + case UO_Plus: DISPATCH(UnaryPlus, UnaryOperator); + case UO_Minus: DISPATCH(UnaryMinus, UnaryOperator); + case UO_Not: DISPATCH(UnaryNot, UnaryOperator); + case UO_LNot: DISPATCH(UnaryLNot, UnaryOperator); + case UO_Real: DISPATCH(UnaryReal, UnaryOperator); + case UO_Imag: DISPATCH(UnaryImag, UnaryOperator); + case UO_Extension: DISPATCH(UnaryExtension, UnaryOperator); + case UO_Coawait: DISPATCH(UnaryCoawait, UnaryOperator); + } + } + + // Top switch stmt: dispatch to VisitFooStmt for each FooStmt. + switch (S->getStmtClass()) { + default: llvm_unreachable("Unknown stmt kind!"); +#define ABSTRACT_STMT(STMT) +#define STMT(CLASS, PARENT) \ + case Stmt::CLASS ## Class: DISPATCH(CLASS, CLASS); +#include "clang/AST/StmtNodes.inc" + } + } + + // If the implementation chooses not to implement a certain visit method, fall + // back on VisitExpr or whatever else is the superclass. +#define STMT(CLASS, PARENT) \ + RetTy Visit ## CLASS(PTR(CLASS) S) { DISPATCH(PARENT, PARENT); } +#include "clang/AST/StmtNodes.inc" + + // If the implementation doesn't implement binary operator methods, fall back + // on VisitBinaryOperator. +#define BINOP_FALLBACK(NAME) \ + RetTy VisitBin ## NAME(PTR(BinaryOperator) S) { \ + DISPATCH(BinaryOperator, BinaryOperator); \ + } + BINOP_FALLBACK(PtrMemD) BINOP_FALLBACK(PtrMemI) + BINOP_FALLBACK(Mul) BINOP_FALLBACK(Div) BINOP_FALLBACK(Rem) + BINOP_FALLBACK(Add) BINOP_FALLBACK(Sub) BINOP_FALLBACK(Shl) + BINOP_FALLBACK(Shr) + + BINOP_FALLBACK(LT) BINOP_FALLBACK(GT) BINOP_FALLBACK(LE) + BINOP_FALLBACK(GE) BINOP_FALLBACK(EQ) BINOP_FALLBACK(NE) + BINOP_FALLBACK(And) BINOP_FALLBACK(Xor) BINOP_FALLBACK(Or) + BINOP_FALLBACK(LAnd) BINOP_FALLBACK(LOr) + + BINOP_FALLBACK(Assign) + BINOP_FALLBACK(Comma) +#undef BINOP_FALLBACK + + // If the implementation doesn't implement compound assignment operator + // methods, fall back on VisitCompoundAssignOperator. +#define CAO_FALLBACK(NAME) \ + RetTy VisitBin ## NAME(PTR(CompoundAssignOperator) S) { \ + DISPATCH(CompoundAssignOperator, CompoundAssignOperator); \ + } + CAO_FALLBACK(MulAssign) CAO_FALLBACK(DivAssign) CAO_FALLBACK(RemAssign) + CAO_FALLBACK(AddAssign) CAO_FALLBACK(SubAssign) CAO_FALLBACK(ShlAssign) + CAO_FALLBACK(ShrAssign) CAO_FALLBACK(AndAssign) CAO_FALLBACK(OrAssign) + CAO_FALLBACK(XorAssign) +#undef CAO_FALLBACK + + // If the implementation doesn't implement unary operator methods, fall back + // on VisitUnaryOperator. +#define UNARYOP_FALLBACK(NAME) \ + RetTy VisitUnary ## NAME(PTR(UnaryOperator) S) { \ + DISPATCH(UnaryOperator, UnaryOperator); \ + } + UNARYOP_FALLBACK(PostInc) UNARYOP_FALLBACK(PostDec) + UNARYOP_FALLBACK(PreInc) UNARYOP_FALLBACK(PreDec) + UNARYOP_FALLBACK(AddrOf) UNARYOP_FALLBACK(Deref) + + UNARYOP_FALLBACK(Plus) UNARYOP_FALLBACK(Minus) + UNARYOP_FALLBACK(Not) UNARYOP_FALLBACK(LNot) + UNARYOP_FALLBACK(Real) UNARYOP_FALLBACK(Imag) + UNARYOP_FALLBACK(Extension) UNARYOP_FALLBACK(Coawait) +#undef UNARYOP_FALLBACK + + // Base case, ignore it. :) + RetTy VisitStmt(PTR(Stmt) Node) { return RetTy(); } + +#undef PTR +#undef DISPATCH +}; + +/// StmtVisitor - This class implements a simple visitor for Stmt subclasses. +/// Since Expr derives from Stmt, this also includes support for visiting Exprs. +/// +/// This class does not preserve constness of Stmt pointers (see also +/// ConstStmtVisitor). +template<typename ImplClass, typename RetTy=void> +class StmtVisitor + : public StmtVisitorBase<make_ptr, ImplClass, RetTy> {}; + +/// ConstStmtVisitor - This class implements a simple visitor for Stmt +/// subclasses. Since Expr derives from Stmt, this also includes support for +/// visiting Exprs. +/// +/// This class preserves constness of Stmt pointers (see also StmtVisitor). +template<typename ImplClass, typename RetTy=void> +class ConstStmtVisitor + : public StmtVisitorBase<make_const_ptr, ImplClass, RetTy> {}; + +/// \brief This class implements a simple visitor for OMPClause +/// subclasses. +template<class ImplClass, template <typename> class Ptr, typename RetTy> +class OMPClauseVisitorBase { +public: +#define PTR(CLASS) typename Ptr<CLASS>::type +#define DISPATCH(CLASS) \ + return static_cast<ImplClass*>(this)->Visit##CLASS(static_cast<PTR(CLASS)>(S)) + +#define OPENMP_CLAUSE(Name, Class) \ + RetTy Visit ## Class (PTR(Class) S) { DISPATCH(Class); } +#include "clang/Basic/OpenMPKinds.def" + + RetTy Visit(PTR(OMPClause) S) { + // Top switch clause: visit each OMPClause. + switch (S->getClauseKind()) { + default: llvm_unreachable("Unknown clause kind!"); +#define OPENMP_CLAUSE(Name, Class) \ + case OMPC_ ## Name : return Visit ## Class(static_cast<PTR(Class)>(S)); +#include "clang/Basic/OpenMPKinds.def" + } + } + // Base case, ignore it. :) + RetTy VisitOMPClause(PTR(OMPClause) Node) { return RetTy(); } +#undef PTR +#undef DISPATCH +}; + +template<class ImplClass, typename RetTy = void> +class OMPClauseVisitor : + public OMPClauseVisitorBase <ImplClass, make_ptr, RetTy> {}; +template<class ImplClass, typename RetTy = void> +class ConstOMPClauseVisitor : + public OMPClauseVisitorBase <ImplClass, make_const_ptr, RetTy> {}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/TemplateBase.h b/contrib/llvm/tools/clang/include/clang/AST/TemplateBase.h new file mode 100644 index 0000000..f87171a --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/TemplateBase.h @@ -0,0 +1,661 @@ +//===-- 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 "clang/AST/TemplateName.h" +#include "clang/AST/Type.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TrailingObjects.h" + +namespace llvm { + class FoldingSetNodeID; +} + +namespace clang { + +class DiagnosticBuilder; +class Expr; +struct PrintingPolicy; +class TypeSourceInfo; +class ValueDecl; + +/// \brief Represents a template argument. +class TemplateArgument { +public: + /// \brief The kind of template argument we're storing. + enum ArgKind { + /// \brief Represents an empty template argument, e.g., one that has not + /// been deduced. + Null = 0, + /// The template argument is a type. + Type, + /// The template argument is a declaration that was provided for a pointer, + /// reference, or pointer to member non-type template parameter. + Declaration, + /// The template argument is a null pointer or null pointer to member that + /// was provided for a non-type template parameter. + NullPtr, + /// The template argument is an integral value stored in an llvm::APSInt + /// that was provided for an integral non-type template parameter. + Integral, + /// The template argument is a template name that was provided for a + /// template template parameter. + Template, + /// The template argument is a pack expansion of a template name that was + /// provided for a template template parameter. + TemplateExpansion, + /// The template argument is an expression, and we've not resolved it to one + /// of the other forms yet, either because it's dependent or because we're + /// representing a non-canonical template argument (for instance, in a + /// TemplateSpecializationType). Also used to represent a non-dependent + /// __uuidof expression (a Microsoft extension). + Expression, + /// The template argument is actually a parameter pack. Arguments are stored + /// in the Args struct. + Pack + }; + +private: + /// \brief The kind of template argument we're storing. + + struct DA { + unsigned Kind; + void *QT; + ValueDecl *D; + }; + struct I { + unsigned Kind; + // We store a decomposed APSInt with the data allocated by ASTContext if + // BitWidth > 64. The memory may be shared between multiple + // TemplateArgument instances. + unsigned BitWidth : 31; + unsigned IsUnsigned : 1; + union { + uint64_t VAL; ///< Used to store the <= 64 bits integer value. + const uint64_t *pVal; ///< Used to store the >64 bits integer value. + }; + void *Type; + }; + struct A { + unsigned Kind; + unsigned NumArgs; + const TemplateArgument *Args; + }; + struct TA { + unsigned Kind; + unsigned NumExpansions; + void *Name; + }; + struct TV { + unsigned Kind; + uintptr_t V; + }; + union { + struct DA DeclArg; + struct I Integer; + struct A Args; + struct TA TemplateArg; + struct TV TypeOrValue; + }; + + TemplateArgument(TemplateName, bool) = delete; + +public: + /// \brief Construct an empty, invalid template argument. + TemplateArgument() { + TypeOrValue.Kind = Null; + TypeOrValue.V = 0; + } + + /// \brief Construct a template type argument. + TemplateArgument(QualType T, bool isNullPtr = false) { + TypeOrValue.Kind = isNullPtr ? NullPtr : Type; + TypeOrValue.V = 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(ValueDecl *D, QualType QT) { + assert(D && "Expected decl"); + DeclArg.Kind = Declaration; + DeclArg.QT = QT.getAsOpaquePtr(); + DeclArg.D = D; + } + + /// \brief Construct an integral constant template argument. The memory to + /// store the value is allocated with Ctx. + TemplateArgument(ASTContext &Ctx, const llvm::APSInt &Value, QualType Type); + + /// \brief Construct an integral constant template argument with the same + /// value as Other but a different type. + TemplateArgument(const TemplateArgument &Other, QualType Type) { + Integer = Other.Integer; + Integer.Type = Type.getAsOpaquePtr(); + } + + /// \brief Construct a template argument that is a template. + /// + /// This form of template argument is generally used for template template + /// parameters. However, the template name could be a dependent template + /// name that ends up being instantiated to a function template whose address + /// is taken. + /// + /// \param Name The template name. + TemplateArgument(TemplateName Name) { + TemplateArg.Kind = Template; + TemplateArg.Name = Name.getAsVoidPointer(); + TemplateArg.NumExpansions = 0; + } + + /// \brief Construct a template argument that is a template pack expansion. + /// + /// This form of template argument is generally used for template template + /// parameters. However, the template name could be a dependent template + /// name that ends up being instantiated to a function template whose address + /// is taken. + /// + /// \param Name The template name. + /// + /// \param NumExpansions The number of expansions that will be generated by + /// instantiating + TemplateArgument(TemplateName Name, Optional<unsigned> NumExpansions) { + TemplateArg.Kind = TemplateExpansion; + TemplateArg.Name = Name.getAsVoidPointer(); + if (NumExpansions) + TemplateArg.NumExpansions = *NumExpansions + 1; + else + TemplateArg.NumExpansions = 0; + } + + /// \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) { + TypeOrValue.Kind = Expression; + TypeOrValue.V = reinterpret_cast<uintptr_t>(E); + } + + /// \brief Construct a template argument that is a template argument pack. + /// + /// We assume that storage for the template arguments provided + /// outlives the TemplateArgument itself. + explicit TemplateArgument(ArrayRef<TemplateArgument> Args) { + this->Args.Kind = Pack; + this->Args.Args = Args.data(); + this->Args.NumArgs = Args.size(); + } + + static TemplateArgument getEmptyPack() { return TemplateArgument(None); } + + /// \brief Create a new template argument pack by copying the given set of + /// template arguments. + static TemplateArgument CreatePackCopy(ASTContext &Context, + ArrayRef<TemplateArgument> Args); + + /// \brief Return the kind of stored template argument. + ArgKind getKind() const { return (ArgKind)TypeOrValue.Kind; } + + /// \brief Determine whether this template argument has no value. + bool isNull() const { return getKind() == Null; } + + /// \brief Whether this template argument is dependent on a template + /// parameter such that its result can change from one instantiation to + /// another. + bool isDependent() const; + + /// \brief Whether this template argument is dependent on a template + /// parameter. + bool isInstantiationDependent() const; + + /// \brief Whether this template argument contains an unexpanded + /// parameter pack. + bool containsUnexpandedParameterPack() const; + + /// \brief Determine whether this template argument is a pack expansion. + bool isPackExpansion() const; + + /// \brief Retrieve the type for a type template argument. + QualType getAsType() const { + assert(getKind() == Type && "Unexpected kind"); + return QualType::getFromOpaquePtr(reinterpret_cast<void*>(TypeOrValue.V)); + } + + /// \brief Retrieve the declaration for a declaration non-type + /// template argument. + ValueDecl *getAsDecl() const { + assert(getKind() == Declaration && "Unexpected kind"); + return DeclArg.D; + } + + QualType getParamTypeForDecl() const { + assert(getKind() == Declaration && "Unexpected kind"); + return QualType::getFromOpaquePtr(DeclArg.QT); + } + + /// \brief Retrieve the type for null non-type template argument. + QualType getNullPtrType() const { + assert(getKind() == NullPtr && "Unexpected kind"); + return QualType::getFromOpaquePtr(reinterpret_cast<void*>(TypeOrValue.V)); + } + + /// \brief Retrieve the template name for a template name argument. + TemplateName getAsTemplate() const { + assert(getKind() == Template && "Unexpected kind"); + return TemplateName::getFromVoidPointer(TemplateArg.Name); + } + + /// \brief Retrieve the template argument as a template name; if the argument + /// is a pack expansion, return the pattern as a template name. + TemplateName getAsTemplateOrTemplatePattern() const { + assert((getKind() == Template || getKind() == TemplateExpansion) && + "Unexpected kind"); + + return TemplateName::getFromVoidPointer(TemplateArg.Name); + } + + /// \brief Retrieve the number of expansions that a template template argument + /// expansion will produce, if known. + Optional<unsigned> getNumTemplateExpansions() const; + + /// \brief Retrieve the template argument as an integral value. + // FIXME: Provide a way to read the integral data without copying the value. + llvm::APSInt getAsIntegral() const { + assert(getKind() == Integral && "Unexpected kind"); + using namespace llvm; + if (Integer.BitWidth <= 64) + return APSInt(APInt(Integer.BitWidth, Integer.VAL), Integer.IsUnsigned); + + unsigned NumWords = APInt::getNumWords(Integer.BitWidth); + return APSInt(APInt(Integer.BitWidth, makeArrayRef(Integer.pVal, NumWords)), + Integer.IsUnsigned); + } + + /// \brief Retrieve the type of the integral value. + QualType getIntegralType() const { + assert(getKind() == Integral && "Unexpected kind"); + return QualType::getFromOpaquePtr(Integer.Type); + } + + void setIntegralType(QualType T) { + assert(getKind() == Integral && "Unexpected kind"); + Integer.Type = T.getAsOpaquePtr(); + } + + /// \brief Retrieve the template argument as an expression. + Expr *getAsExpr() const { + assert(getKind() == Expression && "Unexpected kind"); + return reinterpret_cast<Expr *>(TypeOrValue.V); + } + + /// \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(getKind() == Pack); + return Args.Args; + } + + /// \brief Iterator referencing one past the last argument of a template + /// argument pack. + pack_iterator pack_end() const { + assert(getKind() == Pack); + return Args.Args + Args.NumArgs; + } + + /// \brief Iterator range referencing all of the elements of a template + /// argument pack. + llvm::iterator_range<pack_iterator> pack_elements() const { + return llvm::make_range(pack_begin(), pack_end()); + } + + /// \brief The number of template arguments in the given template argument + /// pack. + unsigned pack_size() const { + assert(getKind() == Pack); + return Args.NumArgs; + } + + /// \brief Return the array of arguments in this template argument pack. + ArrayRef<TemplateArgument> getPackAsArray() const { + assert(getKind() == Pack); + return llvm::makeArrayRef(Args.Args, Args.NumArgs); + } + + /// \brief Determines whether two template arguments are superficially the + /// same. + bool structurallyEquals(const TemplateArgument &Other) const; + + /// \brief When the template argument is a pack expansion, returns + /// the pattern of the pack expansion. + TemplateArgument getPackExpansionPattern() const; + + /// \brief Print this template argument to the given output stream. + void print(const PrintingPolicy &Policy, raw_ostream &Out) const; + + /// \brief Used to insert TemplateArguments into FoldingSets. + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) const; +}; + +/// Location information for a TemplateArgument. +struct TemplateArgumentLocInfo { +private: + + struct T { + // FIXME: We'd like to just use the qualifier in the TemplateName, + // but template arguments get canonicalized too quickly. + NestedNameSpecifier *Qualifier; + void *QualifierLocData; + unsigned TemplateNameLoc; + unsigned EllipsisLoc; + }; + + union { + struct T Template; + Expr *Expression; + TypeSourceInfo *Declarator; + }; + +public: + TemplateArgumentLocInfo(); + + TemplateArgumentLocInfo(TypeSourceInfo *TInfo) : Declarator(TInfo) {} + + TemplateArgumentLocInfo(Expr *E) : Expression(E) {} + + TemplateArgumentLocInfo(NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateNameLoc, + SourceLocation EllipsisLoc) + { + Template.Qualifier = QualifierLoc.getNestedNameSpecifier(); + Template.QualifierLocData = QualifierLoc.getOpaqueData(); + Template.TemplateNameLoc = TemplateNameLoc.getRawEncoding(); + Template.EllipsisLoc = EllipsisLoc.getRawEncoding(); + } + + TypeSourceInfo *getAsTypeSourceInfo() const { + return Declarator; + } + + Expr *getAsExpr() const { + return Expression; + } + + NestedNameSpecifierLoc getTemplateQualifierLoc() const { + return NestedNameSpecifierLoc(Template.Qualifier, + Template.QualifierLocData); + } + + SourceLocation getTemplateNameLoc() const { + return SourceLocation::getFromRawEncoding(Template.TemplateNameLoc); + } + + SourceLocation getTemplateEllipsisLoc() const { + return SourceLocation::getFromRawEncoding(Template.EllipsisLoc); + } +}; + +/// 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, TypeSourceInfo *TInfo) + : Argument(Argument), LocInfo(TInfo) { + assert(Argument.getKind() == TemplateArgument::Type); + } + + TemplateArgumentLoc(const TemplateArgument &Argument, Expr *E) + : Argument(Argument), LocInfo(E) { + assert(Argument.getKind() == TemplateArgument::Expression); + } + + TemplateArgumentLoc(const TemplateArgument &Argument, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateNameLoc, + SourceLocation EllipsisLoc = SourceLocation()) + : Argument(Argument), LocInfo(QualifierLoc, TemplateNameLoc, EllipsisLoc) { + assert(Argument.getKind() == TemplateArgument::Template || + Argument.getKind() == TemplateArgument::TemplateExpansion); + } + + /// \brief - Fetches the primary location of the argument. + SourceLocation getLocation() const { + if (Argument.getKind() == TemplateArgument::Template || + Argument.getKind() == TemplateArgument::TemplateExpansion) + return getTemplateNameLoc(); + + return getSourceRange().getBegin(); + } + + /// \brief - Fetches the full source range of the argument. + SourceRange getSourceRange() const LLVM_READONLY; + + const TemplateArgument &getArgument() const { + return Argument; + } + + TemplateArgumentLocInfo getLocInfo() const { + return LocInfo; + } + + TypeSourceInfo *getTypeSourceInfo() const { + assert(Argument.getKind() == TemplateArgument::Type); + return LocInfo.getAsTypeSourceInfo(); + } + + Expr *getSourceExpression() const { + assert(Argument.getKind() == TemplateArgument::Expression); + return LocInfo.getAsExpr(); + } + + Expr *getSourceDeclExpression() const { + assert(Argument.getKind() == TemplateArgument::Declaration); + return LocInfo.getAsExpr(); + } + + Expr *getSourceNullPtrExpression() const { + assert(Argument.getKind() == TemplateArgument::NullPtr); + return LocInfo.getAsExpr(); + } + + Expr *getSourceIntegralExpression() const { + assert(Argument.getKind() == TemplateArgument::Integral); + return LocInfo.getAsExpr(); + } + + NestedNameSpecifierLoc getTemplateQualifierLoc() const { + assert(Argument.getKind() == TemplateArgument::Template || + Argument.getKind() == TemplateArgument::TemplateExpansion); + return LocInfo.getTemplateQualifierLoc(); + } + + SourceLocation getTemplateNameLoc() const { + assert(Argument.getKind() == TemplateArgument::Template || + Argument.getKind() == TemplateArgument::TemplateExpansion); + return LocInfo.getTemplateNameLoc(); + } + + SourceLocation getTemplateEllipsisLoc() const { + assert(Argument.getKind() == TemplateArgument::TemplateExpansion); + return LocInfo.getTemplateEllipsisLoc(); + } +}; + +/// A convenient class for passing around template argument +/// information. Designed to be passed by reference. +class TemplateArgumentListInfo { + SmallVector<TemplateArgumentLoc, 8> Arguments; + SourceLocation LAngleLoc; + SourceLocation RAngleLoc; + + // This can leak if used in an AST node, use ASTTemplateArgumentListInfo + // instead. + void *operator new(size_t bytes, ASTContext &C) = delete; + +public: + TemplateArgumentListInfo() {} + + TemplateArgumentListInfo(SourceLocation LAngleLoc, + SourceLocation RAngleLoc) + : LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc) {} + + SourceLocation getLAngleLoc() const { return LAngleLoc; } + SourceLocation getRAngleLoc() const { return RAngleLoc; } + + void setLAngleLoc(SourceLocation Loc) { LAngleLoc = Loc; } + void setRAngleLoc(SourceLocation Loc) { RAngleLoc = Loc; } + + unsigned size() const { return Arguments.size(); } + + const TemplateArgumentLoc *getArgumentArray() const { + return Arguments.data(); + } + + llvm::ArrayRef<TemplateArgumentLoc> arguments() const { + return Arguments; + } + + const TemplateArgumentLoc &operator[](unsigned I) const { + return Arguments[I]; + } + + TemplateArgumentLoc &operator[](unsigned I) { + return Arguments[I]; + } + + void addArgument(const TemplateArgumentLoc &Loc) { + Arguments.push_back(Loc); + } +}; + +/// \brief Represents an explicit template argument list in C++, e.g., +/// the "<int>" in "sort<int>". +/// This is safe to be used inside an AST node, in contrast with +/// TemplateArgumentListInfo. +struct ASTTemplateArgumentListInfo final + : private llvm::TrailingObjects<ASTTemplateArgumentListInfo, + TemplateArgumentLoc> { +private: + friend TrailingObjects; + + ASTTemplateArgumentListInfo(const TemplateArgumentListInfo &List); + +public: + /// \brief The source location of the left angle bracket ('<'). + SourceLocation LAngleLoc; + + /// \brief The source location of the right angle bracket ('>'). + SourceLocation RAngleLoc; + + /// \brief The number of template arguments in TemplateArgs. + unsigned NumTemplateArgs; + + /// \brief Retrieve the template arguments + const TemplateArgumentLoc *getTemplateArgs() const { + return getTrailingObjects<TemplateArgumentLoc>(); + } + + const TemplateArgumentLoc &operator[](unsigned I) const { + return getTemplateArgs()[I]; + } + + static const ASTTemplateArgumentListInfo * + Create(ASTContext &C, const TemplateArgumentListInfo &List); +}; + +/// \brief Represents an explicit template argument list in C++, e.g., +/// the "<int>" in "sort<int>". +/// +/// It is intended to be used as a trailing object on AST nodes, and +/// as such, doesn't contain the array of TemplateArgumentLoc itself, +/// but expects the containing object to also provide storage for +/// that. +struct LLVM_ALIGNAS(LLVM_PTR_SIZE) ASTTemplateKWAndArgsInfo { + /// \brief The source location of the left angle bracket ('<'). + SourceLocation LAngleLoc; + + /// \brief The source location of the right angle bracket ('>'). + SourceLocation RAngleLoc; + + /// \brief The source location of the template keyword; this is used + /// as part of the representation of qualified identifiers, such as + /// S<T>::template apply<T>. Will be empty if this expression does + /// not have a template keyword. + SourceLocation TemplateKWLoc; + + /// \brief The number of template arguments in TemplateArgs. + unsigned NumTemplateArgs; + + void initializeFrom(SourceLocation TemplateKWLoc, + const TemplateArgumentListInfo &List, + TemplateArgumentLoc *OutArgArray); + void initializeFrom(SourceLocation TemplateKWLoc, + const TemplateArgumentListInfo &List, + TemplateArgumentLoc *OutArgArray, bool &Dependent, + bool &InstantiationDependent, + bool &ContainsUnexpandedParameterPack); + void initializeFrom(SourceLocation TemplateKWLoc); + + void copyInto(const TemplateArgumentLoc *ArgArray, + TemplateArgumentListInfo &List) const; +}; + +const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const TemplateArgument &Arg); + +inline TemplateSpecializationType::iterator + TemplateSpecializationType::end() const { + return getArgs() + getNumArgs(); +} + +inline DependentTemplateSpecializationType::iterator + DependentTemplateSpecializationType::end() const { + return getArgs() + getNumArgs(); +} + +inline const TemplateArgument & + TemplateSpecializationType::getArg(unsigned Idx) const { + assert(Idx < getNumArgs() && "Template argument out of range"); + return getArgs()[Idx]; +} + +inline const TemplateArgument & + DependentTemplateSpecializationType::getArg(unsigned Idx) const { + assert(Idx < getNumArgs() && "Template argument out of range"); + return getArgs()[Idx]; +} + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/TemplateName.h b/contrib/llvm/tools/clang/include/clang/AST/TemplateName.h new file mode 100644 index 0000000..3e10d2f --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/TemplateName.h @@ -0,0 +1,533 @@ +//===--- TemplateName.h - C++ Template Name Representation-------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TemplateName interface and subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_TEMPLATENAME_H +#define LLVM_CLANG_AST_TEMPLATENAME_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/PointerUnion.h" + +namespace clang { + +class ASTContext; +class DependentTemplateName; +class DiagnosticBuilder; +class IdentifierInfo; +class NamedDecl; +class NestedNameSpecifier; +enum OverloadedOperatorKind : int; +class OverloadedTemplateStorage; +struct PrintingPolicy; +class QualifiedTemplateName; +class SubstTemplateTemplateParmPackStorage; +class SubstTemplateTemplateParmStorage; +class TemplateArgument; +class TemplateDecl; +class TemplateTemplateParmDecl; + +/// \brief Implementation class used to describe either a set of overloaded +/// template names or an already-substituted template template parameter pack. +class UncommonTemplateNameStorage { +protected: + enum Kind { + Overloaded, + SubstTemplateTemplateParm, + SubstTemplateTemplateParmPack + }; + + struct BitsTag { + /// \brief A Kind. + unsigned Kind : 2; + + /// \brief The number of stored templates or template arguments, + /// depending on which subclass we have. + unsigned Size : 30; + }; + + union { + struct BitsTag Bits; + void *PointerAlignment; + }; + + UncommonTemplateNameStorage(Kind kind, unsigned size) { + Bits.Kind = kind; + Bits.Size = size; + } + +public: + unsigned size() const { return Bits.Size; } + + OverloadedTemplateStorage *getAsOverloadedStorage() { + return Bits.Kind == Overloaded + ? reinterpret_cast<OverloadedTemplateStorage *>(this) + : nullptr; + } + + SubstTemplateTemplateParmStorage *getAsSubstTemplateTemplateParm() { + return Bits.Kind == SubstTemplateTemplateParm + ? reinterpret_cast<SubstTemplateTemplateParmStorage *>(this) + : nullptr; + } + + SubstTemplateTemplateParmPackStorage *getAsSubstTemplateTemplateParmPack() { + return Bits.Kind == SubstTemplateTemplateParmPack + ? reinterpret_cast<SubstTemplateTemplateParmPackStorage *>(this) + : nullptr; + } +}; + +/// \brief A structure for storing the information associated with an +/// overloaded template name. +class OverloadedTemplateStorage : public UncommonTemplateNameStorage { + friend class ASTContext; + + OverloadedTemplateStorage(unsigned size) + : UncommonTemplateNameStorage(Overloaded, size) { } + + NamedDecl **getStorage() { + return reinterpret_cast<NamedDecl **>(this + 1); + } + NamedDecl * const *getStorage() const { + return reinterpret_cast<NamedDecl *const *>(this + 1); + } + +public: + typedef NamedDecl *const *iterator; + + iterator begin() const { return getStorage(); } + iterator end() const { return getStorage() + size(); } +}; + +/// \brief A structure for storing an already-substituted template template +/// parameter pack. +/// +/// This kind of template names occurs when the parameter pack has been +/// provided with a template template argument pack in a context where its +/// enclosing pack expansion could not be fully expanded. +class SubstTemplateTemplateParmPackStorage + : public UncommonTemplateNameStorage, public llvm::FoldingSetNode +{ + TemplateTemplateParmDecl *Parameter; + const TemplateArgument *Arguments; + +public: + SubstTemplateTemplateParmPackStorage(TemplateTemplateParmDecl *Parameter, + unsigned Size, + const TemplateArgument *Arguments) + : UncommonTemplateNameStorage(SubstTemplateTemplateParmPack, Size), + Parameter(Parameter), Arguments(Arguments) { } + + /// \brief Retrieve the template template parameter pack being substituted. + TemplateTemplateParmDecl *getParameterPack() const { + return Parameter; + } + + /// \brief Retrieve the template template argument pack with which this + /// parameter was substituted. + TemplateArgument getArgumentPack() const; + + void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context); + + static void Profile(llvm::FoldingSetNodeID &ID, + ASTContext &Context, + TemplateTemplateParmDecl *Parameter, + const TemplateArgument &ArgPack); +}; + +/// \brief Represents a C++ template name within the type system. +/// +/// A C++ template name refers to a template within the C++ type +/// system. In most cases, a template name is simply a reference to a +/// class template, e.g. +/// +/// \code +/// template<typename T> class X { }; +/// +/// X<int> xi; +/// \endcode +/// +/// Here, the 'X' in \c X<int> is a template name that refers to the +/// declaration of the class template X, above. Template names can +/// also refer to function templates, C++0x template aliases, etc. +/// +/// Some template names are dependent. For example, consider: +/// +/// \code +/// template<typename MetaFun, typename T1, typename T2> struct apply2 { +/// typedef typename MetaFun::template apply<T1, T2>::type type; +/// }; +/// \endcode +/// +/// Here, "apply" is treated as a template name within the typename +/// specifier in the typedef. "apply" is a nested template, and can +/// only be understood in the context of +class TemplateName { + typedef llvm::PointerUnion4<TemplateDecl *, + UncommonTemplateNameStorage *, + QualifiedTemplateName *, + DependentTemplateName *> StorageType; + + StorageType Storage; + + explicit TemplateName(void *Ptr); + +public: + // \brief Kind of name that is actually stored. + enum NameKind { + /// \brief A single template declaration. + Template, + /// \brief A set of overloaded template declarations. + OverloadedTemplate, + /// \brief A qualified template name, where the qualification is kept + /// to describe the source code as written. + QualifiedTemplate, + /// \brief A dependent template name that has not been resolved to a + /// template (or set of templates). + DependentTemplate, + /// \brief A template template parameter that has been substituted + /// for some other template name. + SubstTemplateTemplateParm, + /// \brief A template template parameter pack that has been substituted for + /// a template template argument pack, but has not yet been expanded into + /// individual arguments. + SubstTemplateTemplateParmPack + }; + + TemplateName() : Storage() { } + explicit TemplateName(TemplateDecl *Template); + explicit TemplateName(OverloadedTemplateStorage *Storage); + explicit TemplateName(SubstTemplateTemplateParmStorage *Storage); + explicit TemplateName(SubstTemplateTemplateParmPackStorage *Storage); + explicit TemplateName(QualifiedTemplateName *Qual); + explicit TemplateName(DependentTemplateName *Dep); + + /// \brief Determine whether this template name is NULL. + bool isNull() const; + + // \brief Get the kind of name that is actually stored. + NameKind getKind() const; + + /// \brief Retrieve the underlying template declaration that + /// this template name refers to, if known. + /// + /// \returns The template declaration that this template name refers + /// to, if any. If the template name does not refer to a specific + /// declaration because it is a dependent name, or if it refers to a + /// set of function templates, returns NULL. + TemplateDecl *getAsTemplateDecl() const; + + /// \brief Retrieve the underlying, overloaded function template + // declarations that this template name refers to, if known. + /// + /// \returns The set of overloaded function templates that this template + /// name refers to, if known. If the template name does not refer to a + /// specific set of function templates because it is a dependent name or + /// refers to a single template, returns NULL. + OverloadedTemplateStorage *getAsOverloadedTemplate() const; + + /// \brief Retrieve the substituted template template parameter, if + /// known. + /// + /// \returns The storage for the substituted template template parameter, + /// if known. Otherwise, returns NULL. + SubstTemplateTemplateParmStorage *getAsSubstTemplateTemplateParm() const; + + /// \brief Retrieve the substituted template template parameter pack, if + /// known. + /// + /// \returns The storage for the substituted template template parameter pack, + /// if known. Otherwise, returns NULL. + SubstTemplateTemplateParmPackStorage * + getAsSubstTemplateTemplateParmPack() const; + + /// \brief Retrieve the underlying qualified template name + /// structure, if any. + QualifiedTemplateName *getAsQualifiedTemplateName() const; + + /// \brief Retrieve the underlying dependent template name + /// structure, if any. + DependentTemplateName *getAsDependentTemplateName() const; + + TemplateName getUnderlying() const; + + /// \brief Determines whether this is a dependent template name. + bool isDependent() const; + + /// \brief Determines whether this is a template name that somehow + /// depends on a template parameter. + bool isInstantiationDependent() const; + + /// \brief Determines whether this template name contains an + /// unexpanded parameter pack (for C++0x variadic templates). + bool containsUnexpandedParameterPack() const; + + /// \brief Print the template name. + /// + /// \param OS the output stream to which the template name will be + /// printed. + /// + /// \param SuppressNNS if true, don't print the + /// nested-name-specifier that precedes the template name (if it has + /// one). + void print(raw_ostream &OS, const PrintingPolicy &Policy, + bool SuppressNNS = false) const; + + /// \brief Debugging aid that dumps the template name. + void dump(raw_ostream &OS) const; + + /// \brief Debugging aid that dumps the template name to standard + /// error. + void dump() const; + + void Profile(llvm::FoldingSetNodeID &ID) { + ID.AddPointer(Storage.getOpaqueValue()); + } + + /// \brief Retrieve the template name as a void pointer. + void *getAsVoidPointer() const { return Storage.getOpaqueValue(); } + + /// \brief Build a template name from a void pointer. + static TemplateName getFromVoidPointer(void *Ptr) { + return TemplateName(Ptr); + } +}; + +/// Insertion operator for diagnostics. This allows sending TemplateName's +/// into a diagnostic with <<. +const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + TemplateName N); + +/// \brief A structure for storing the information associated with a +/// substituted template template parameter. +class SubstTemplateTemplateParmStorage + : public UncommonTemplateNameStorage, public llvm::FoldingSetNode { + friend class ASTContext; + + TemplateTemplateParmDecl *Parameter; + TemplateName Replacement; + + SubstTemplateTemplateParmStorage(TemplateTemplateParmDecl *parameter, + TemplateName replacement) + : UncommonTemplateNameStorage(SubstTemplateTemplateParm, 0), + Parameter(parameter), Replacement(replacement) {} + +public: + TemplateTemplateParmDecl *getParameter() const { return Parameter; } + TemplateName getReplacement() const { return Replacement; } + + void Profile(llvm::FoldingSetNodeID &ID); + + static void Profile(llvm::FoldingSetNodeID &ID, + TemplateTemplateParmDecl *parameter, + TemplateName replacement); +}; + +inline TemplateName TemplateName::getUnderlying() const { + if (SubstTemplateTemplateParmStorage *subst + = getAsSubstTemplateTemplateParm()) + return subst->getReplacement().getUnderlying(); + return *this; +} + +/// \brief Represents a template name that was expressed as a +/// qualified name. +/// +/// This kind of template name refers to a template name that was +/// preceded by a nested name specifier, e.g., \c std::vector. Here, +/// the nested name specifier is "std::" and the template name is the +/// declaration for "vector". The QualifiedTemplateName class is only +/// used to provide "sugar" for template names that were expressed +/// with a qualified name, and has no semantic meaning. In this +/// manner, it is to TemplateName what ElaboratedType is to Type, +/// providing extra syntactic sugar for downstream clients. +class QualifiedTemplateName : public llvm::FoldingSetNode { + /// \brief The nested name specifier that qualifies the template name. + /// + /// The bit is used to indicate whether the "template" keyword was + /// present before the template name itself. Note that the + /// "template" keyword is always redundant in this case (otherwise, + /// the template name would be a dependent name and we would express + /// this name with DependentTemplateName). + llvm::PointerIntPair<NestedNameSpecifier *, 1> Qualifier; + + /// \brief The template declaration or set of overloaded function templates + /// that this qualified name refers to. + TemplateDecl *Template; + + friend class ASTContext; + + QualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword, + TemplateDecl *Template) + : Qualifier(NNS, TemplateKeyword? 1 : 0), + Template(Template) { } + +public: + /// \brief Return the nested name specifier that qualifies this name. + NestedNameSpecifier *getQualifier() const { return Qualifier.getPointer(); } + + /// \brief Whether the template name was prefixed by the "template" + /// keyword. + bool hasTemplateKeyword() const { return Qualifier.getInt(); } + + /// \brief The template declaration that this qualified name refers + /// to. + TemplateDecl *getDecl() const { return Template; } + + /// \brief The template declaration to which this qualified name + /// refers. + TemplateDecl *getTemplateDecl() const { return Template; } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getQualifier(), hasTemplateKeyword(), getTemplateDecl()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS, + bool TemplateKeyword, TemplateDecl *Template) { + ID.AddPointer(NNS); + ID.AddBoolean(TemplateKeyword); + ID.AddPointer(Template); + } +}; + +/// \brief Represents a dependent template name that cannot be +/// resolved prior to template instantiation. +/// +/// This kind of template name refers to a dependent template name, +/// including its nested name specifier (if any). For example, +/// DependentTemplateName can refer to "MetaFun::template apply", +/// where "MetaFun::" is the nested name specifier and "apply" is the +/// template name referenced. The "template" keyword is implied. +class DependentTemplateName : public llvm::FoldingSetNode { + /// \brief The nested name specifier that qualifies the template + /// name. + /// + /// 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. + 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. + /// + /// The canonical template name for a dependent template name is + /// another dependent template name whose nested name specifier is + /// canonical. + TemplateName CanonicalTemplateName; + + friend class ASTContext; + + DependentTemplateName(NestedNameSpecifier *Qualifier, + const IdentifierInfo *Identifier) + : Qualifier(Qualifier, false), Identifier(Identifier), + CanonicalTemplateName(this) { } + + DependentTemplateName(NestedNameSpecifier *Qualifier, + const IdentifierInfo *Identifier, + TemplateName 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.getPointer(); } + + /// \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) { + 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, + OverloadedOperatorKind Operator) { + ID.AddPointer(NNS); + ID.AddBoolean(true); + ID.AddInteger(Operator); + } +}; + +} // end namespace clang. + +namespace llvm { + +/// \brief The clang::TemplateName class is effectively a pointer. +template<> +class PointerLikeTypeTraits<clang::TemplateName> { +public: + static inline void *getAsVoidPointer(clang::TemplateName TN) { + return TN.getAsVoidPointer(); + } + + static inline clang::TemplateName getFromVoidPointer(void *Ptr) { + return clang::TemplateName::getFromVoidPointer(Ptr); + } + + // No bits are available! + enum { NumLowBitsAvailable = 0 }; +}; + +} // end namespace llvm. + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/Type.h b/contrib/llvm/tools/clang/include/clang/AST/Type.h new file mode 100644 index 0000000..0c08130 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/Type.h @@ -0,0 +1,5683 @@ +//===--- Type.h - C Language Family Type Representation ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// \brief C Language Family Type Representation +/// +/// This file defines the clang::Type interface and subclasses, used to +/// represent types for languages in the C family. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_TYPE_H +#define LLVM_CLANG_AST_TYPE_H + +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/TemplateName.h" +#include "clang/Basic/AddressSpaces.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/ExceptionSpecificationType.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/Linkage.h" +#include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/Specifiers.h" +#include "clang/Basic/Visibility.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/Twine.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/ErrorHandling.h" + +namespace clang { + enum { + TypeAlignmentInBits = 4, + TypeAlignment = 1 << TypeAlignmentInBits + }; + class Type; + class ExtQuals; + class QualType; +} + +namespace llvm { + template <typename T> + class PointerLikeTypeTraits; + template<> + class PointerLikeTypeTraits< ::clang::Type*> { + public: + static inline void *getAsVoidPointer(::clang::Type *P) { return P; } + static inline ::clang::Type *getFromVoidPointer(void *P) { + return static_cast< ::clang::Type*>(P); + } + enum { NumLowBitsAvailable = clang::TypeAlignmentInBits }; + }; + template<> + class PointerLikeTypeTraits< ::clang::ExtQuals*> { + public: + static inline void *getAsVoidPointer(::clang::ExtQuals *P) { return P; } + static inline ::clang::ExtQuals *getFromVoidPointer(void *P) { + return static_cast< ::clang::ExtQuals*>(P); + } + enum { NumLowBitsAvailable = clang::TypeAlignmentInBits }; + }; + + template <> + struct isPodLike<clang::QualType> { static const bool value = true; }; +} + +namespace clang { + class ASTContext; + class TypedefNameDecl; + class TemplateDecl; + class TemplateTypeParmDecl; + class NonTypeTemplateParmDecl; + class TemplateTemplateParmDecl; + class TagDecl; + class RecordDecl; + class CXXRecordDecl; + class EnumDecl; + class FieldDecl; + class FunctionDecl; + class ObjCInterfaceDecl; + class ObjCProtocolDecl; + class ObjCMethodDecl; + class UnresolvedUsingTypenameDecl; + class Expr; + class Stmt; + class SourceLocation; + class StmtIteratorBase; + class TemplateArgument; + class TemplateArgumentLoc; + class TemplateArgumentListInfo; + class ElaboratedType; + class ExtQuals; + class ExtQualsTypeCommonBase; + struct PrintingPolicy; + + template <typename> class CanQual; + typedef CanQual<Type> CanQualType; + + // Provide forward declarations for all of the *Type classes +#define TYPE(Class, Base) class Class##Type; +#include "clang/AST/TypeNodes.def" + +/// The collection of all-type qualifiers we support. +/// Clang supports five independent qualifiers: +/// * C99: const, volatile, and restrict +/// * Embedded C (TR18037): address spaces +/// * Objective C: the GC attributes (none, weak, or strong) +class Qualifiers { +public: + enum TQ { // NOTE: These flags must be kept in sync with DeclSpec::TQ. + Const = 0x1, + Restrict = 0x2, + Volatile = 0x4, + CVRMask = Const | Volatile | Restrict + }; + + enum GC { + GCNone = 0, + Weak, + Strong + }; + + enum ObjCLifetime { + /// There is no lifetime qualification on this type. + OCL_None, + + /// This object can be modified without requiring retains or + /// releases. + OCL_ExplicitNone, + + /// Assigning into this object requires the old value to be + /// released and the new value to be retained. The timing of the + /// release of the old value is inexact: it may be moved to + /// immediately after the last known point where the value is + /// live. + OCL_Strong, + + /// Reading or writing from this object requires a barrier call. + OCL_Weak, + + /// Assigning into this object requires a lifetime extension. + OCL_Autoreleasing + }; + + enum { + /// The maximum supported address space number. + /// 24 bits should be enough for anyone. + MaxAddressSpace = 0xffffffu, + + /// The width of the "fast" qualifier mask. + FastWidth = 3, + + /// The fast qualifier mask. + FastMask = (1 << FastWidth) - 1 + }; + + Qualifiers() : Mask(0) {} + + /// Returns the common set of qualifiers while removing them from + /// the given sets. + static Qualifiers removeCommonQualifiers(Qualifiers &L, Qualifiers &R) { + // If both are only CVR-qualified, bit operations are sufficient. + if (!(L.Mask & ~CVRMask) && !(R.Mask & ~CVRMask)) { + Qualifiers Q; + Q.Mask = L.Mask & R.Mask; + L.Mask &= ~Q.Mask; + R.Mask &= ~Q.Mask; + return Q; + } + + Qualifiers Q; + unsigned CommonCRV = L.getCVRQualifiers() & R.getCVRQualifiers(); + Q.addCVRQualifiers(CommonCRV); + L.removeCVRQualifiers(CommonCRV); + R.removeCVRQualifiers(CommonCRV); + + if (L.getObjCGCAttr() == R.getObjCGCAttr()) { + Q.setObjCGCAttr(L.getObjCGCAttr()); + L.removeObjCGCAttr(); + R.removeObjCGCAttr(); + } + + if (L.getObjCLifetime() == R.getObjCLifetime()) { + Q.setObjCLifetime(L.getObjCLifetime()); + L.removeObjCLifetime(); + R.removeObjCLifetime(); + } + + if (L.getAddressSpace() == R.getAddressSpace()) { + Q.setAddressSpace(L.getAddressSpace()); + L.removeAddressSpace(); + R.removeAddressSpace(); + } + return Q; + } + + static Qualifiers fromFastMask(unsigned Mask) { + Qualifiers Qs; + Qs.addFastQualifiers(Mask); + return Qs; + } + + static Qualifiers fromCVRMask(unsigned CVR) { + Qualifiers Qs; + Qs.addCVRQualifiers(CVR); + return Qs; + } + + // Deserialize qualifiers from an opaque representation. + static Qualifiers fromOpaqueValue(unsigned opaque) { + Qualifiers Qs; + Qs.Mask = opaque; + return Qs; + } + + // Serialize these qualifiers into an opaque representation. + unsigned getAsOpaqueValue() const { + return Mask; + } + + bool hasConst() const { return Mask & Const; } + void setConst(bool flag) { + Mask = (Mask & ~Const) | (flag ? Const : 0); + } + void removeConst() { Mask &= ~Const; } + void addConst() { Mask |= Const; } + + bool hasVolatile() const { return Mask & Volatile; } + void setVolatile(bool flag) { + Mask = (Mask & ~Volatile) | (flag ? Volatile : 0); + } + void removeVolatile() { Mask &= ~Volatile; } + void addVolatile() { Mask |= Volatile; } + + bool hasRestrict() const { return Mask & Restrict; } + void setRestrict(bool flag) { + Mask = (Mask & ~Restrict) | (flag ? Restrict : 0); + } + void removeRestrict() { Mask &= ~Restrict; } + void addRestrict() { Mask |= Restrict; } + + bool hasCVRQualifiers() const { return getCVRQualifiers(); } + unsigned getCVRQualifiers() const { return Mask & CVRMask; } + void setCVRQualifiers(unsigned mask) { + assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits"); + Mask = (Mask & ~CVRMask) | mask; + } + void removeCVRQualifiers(unsigned mask) { + assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits"); + Mask &= ~mask; + } + void removeCVRQualifiers() { + removeCVRQualifiers(CVRMask); + } + void addCVRQualifiers(unsigned mask) { + assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits"); + Mask |= mask; + } + + bool hasObjCGCAttr() const { return Mask & GCAttrMask; } + GC getObjCGCAttr() const { return GC((Mask & GCAttrMask) >> GCAttrShift); } + void setObjCGCAttr(GC type) { + Mask = (Mask & ~GCAttrMask) | (type << GCAttrShift); + } + void removeObjCGCAttr() { setObjCGCAttr(GCNone); } + void addObjCGCAttr(GC type) { + assert(type); + setObjCGCAttr(type); + } + Qualifiers withoutObjCGCAttr() const { + Qualifiers qs = *this; + qs.removeObjCGCAttr(); + return qs; + } + Qualifiers withoutObjCLifetime() const { + Qualifiers qs = *this; + qs.removeObjCLifetime(); + return qs; + } + + bool hasObjCLifetime() const { return Mask & LifetimeMask; } + ObjCLifetime getObjCLifetime() const { + return ObjCLifetime((Mask & LifetimeMask) >> LifetimeShift); + } + void setObjCLifetime(ObjCLifetime type) { + Mask = (Mask & ~LifetimeMask) | (type << LifetimeShift); + } + void removeObjCLifetime() { setObjCLifetime(OCL_None); } + void addObjCLifetime(ObjCLifetime type) { + assert(type); + assert(!hasObjCLifetime()); + Mask |= (type << LifetimeShift); + } + + /// True if the lifetime is neither None or ExplicitNone. + bool hasNonTrivialObjCLifetime() const { + ObjCLifetime lifetime = getObjCLifetime(); + return (lifetime > OCL_ExplicitNone); + } + + /// True if the lifetime is either strong or weak. + bool hasStrongOrWeakObjCLifetime() const { + ObjCLifetime lifetime = getObjCLifetime(); + return (lifetime == OCL_Strong || lifetime == OCL_Weak); + } + + bool hasAddressSpace() const { return Mask & AddressSpaceMask; } + unsigned getAddressSpace() const { return Mask >> AddressSpaceShift; } + void setAddressSpace(unsigned space) { + assert(space <= MaxAddressSpace); + Mask = (Mask & ~AddressSpaceMask) + | (((uint32_t) space) << AddressSpaceShift); + } + void removeAddressSpace() { setAddressSpace(0); } + void addAddressSpace(unsigned space) { + assert(space); + setAddressSpace(space); + } + + // Fast qualifiers are those that can be allocated directly + // on a QualType object. + bool hasFastQualifiers() const { return getFastQualifiers(); } + unsigned getFastQualifiers() const { return Mask & FastMask; } + void setFastQualifiers(unsigned mask) { + assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits"); + Mask = (Mask & ~FastMask) | mask; + } + void removeFastQualifiers(unsigned mask) { + assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits"); + Mask &= ~mask; + } + void removeFastQualifiers() { + removeFastQualifiers(FastMask); + } + void addFastQualifiers(unsigned mask) { + assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits"); + Mask |= mask; + } + + /// Return true if the set contains any qualifiers which require an ExtQuals + /// node to be allocated. + bool hasNonFastQualifiers() const { return Mask & ~FastMask; } + Qualifiers getNonFastQualifiers() const { + Qualifiers Quals = *this; + Quals.setFastQualifiers(0); + return Quals; + } + + /// Return true if the set contains any qualifiers. + bool hasQualifiers() const { return Mask; } + bool empty() const { return !Mask; } + + /// Add the qualifiers from the given set to this set. + void addQualifiers(Qualifiers Q) { + // If the other set doesn't have any non-boolean qualifiers, just + // bit-or it in. + if (!(Q.Mask & ~CVRMask)) + Mask |= Q.Mask; + else { + Mask |= (Q.Mask & CVRMask); + if (Q.hasAddressSpace()) + addAddressSpace(Q.getAddressSpace()); + if (Q.hasObjCGCAttr()) + addObjCGCAttr(Q.getObjCGCAttr()); + if (Q.hasObjCLifetime()) + addObjCLifetime(Q.getObjCLifetime()); + } + } + + /// \brief Remove the qualifiers from the given set from this set. + void removeQualifiers(Qualifiers Q) { + // If the other set doesn't have any non-boolean qualifiers, just + // bit-and the inverse in. + if (!(Q.Mask & ~CVRMask)) + Mask &= ~Q.Mask; + else { + Mask &= ~(Q.Mask & CVRMask); + if (getObjCGCAttr() == Q.getObjCGCAttr()) + removeObjCGCAttr(); + if (getObjCLifetime() == Q.getObjCLifetime()) + removeObjCLifetime(); + if (getAddressSpace() == Q.getAddressSpace()) + removeAddressSpace(); + } + } + + /// Add the qualifiers from the given set to this set, given that + /// they don't conflict. + void addConsistentQualifiers(Qualifiers qs) { + assert(getAddressSpace() == qs.getAddressSpace() || + !hasAddressSpace() || !qs.hasAddressSpace()); + assert(getObjCGCAttr() == qs.getObjCGCAttr() || + !hasObjCGCAttr() || !qs.hasObjCGCAttr()); + assert(getObjCLifetime() == qs.getObjCLifetime() || + !hasObjCLifetime() || !qs.hasObjCLifetime()); + Mask |= qs.Mask; + } + + /// Returns true if this address space is a superset of the other one. + /// OpenCL v2.0 defines conversion rules (OpenCLC v2.0 s6.5.5) and notion of + /// overlapping address spaces. + /// CL1.1 or CL1.2: + /// every address space is a superset of itself. + /// CL2.0 adds: + /// __generic is a superset of any address space except for __constant. + bool isAddressSpaceSupersetOf(Qualifiers other) const { + return + // Address spaces must match exactly. + getAddressSpace() == other.getAddressSpace() || + // Otherwise in OpenCLC v2.0 s6.5.5: every address space except + // for __constant can be used as __generic. + (getAddressSpace() == LangAS::opencl_generic && + other.getAddressSpace() != LangAS::opencl_constant); + } + + /// Determines if these qualifiers compatibly include another set. + /// Generally this answers the question of whether an object with the other + /// qualifiers can be safely used as an object with these qualifiers. + bool compatiblyIncludes(Qualifiers other) const { + return isAddressSpaceSupersetOf(other) && + // ObjC GC qualifiers can match, be added, or be removed, but can't + // be changed. + (getObjCGCAttr() == other.getObjCGCAttr() || !hasObjCGCAttr() || + !other.hasObjCGCAttr()) && + // ObjC lifetime qualifiers must match exactly. + getObjCLifetime() == other.getObjCLifetime() && + // CVR qualifiers may subset. + (((Mask & CVRMask) | (other.Mask & CVRMask)) == (Mask & CVRMask)); + } + + /// \brief Determines if these qualifiers compatibly include another set of + /// qualifiers from the narrow perspective of Objective-C ARC lifetime. + /// + /// One set of Objective-C lifetime qualifiers compatibly includes the other + /// if the lifetime qualifiers match, or if both are non-__weak and the + /// including set also contains the 'const' qualifier, or both are non-__weak + /// and one is None (which can only happen in non-ARC modes). + bool compatiblyIncludesObjCLifetime(Qualifiers other) const { + if (getObjCLifetime() == other.getObjCLifetime()) + return true; + + if (getObjCLifetime() == OCL_Weak || other.getObjCLifetime() == OCL_Weak) + return false; + + if (getObjCLifetime() == OCL_None || other.getObjCLifetime() == OCL_None) + return true; + + return hasConst(); + } + + /// \brief Determine whether this set of qualifiers is a strict superset of + /// another set of qualifiers, not considering qualifier compatibility. + bool isStrictSupersetOf(Qualifiers Other) const; + + bool operator==(Qualifiers Other) const { return Mask == Other.Mask; } + bool operator!=(Qualifiers Other) const { return Mask != Other.Mask; } + + explicit operator bool() const { return hasQualifiers(); } + + Qualifiers &operator+=(Qualifiers R) { + addQualifiers(R); + return *this; + } + + // Union two qualifier sets. If an enumerated qualifier appears + // in both sets, use the one from the right. + friend Qualifiers operator+(Qualifiers L, Qualifiers R) { + L += R; + return L; + } + + Qualifiers &operator-=(Qualifiers R) { + removeQualifiers(R); + return *this; + } + + /// \brief Compute the difference between two qualifier sets. + friend Qualifiers operator-(Qualifiers L, Qualifiers R) { + L -= R; + return L; + } + + std::string getAsString() const; + std::string getAsString(const PrintingPolicy &Policy) const; + + bool isEmptyWhenPrinted(const PrintingPolicy &Policy) const; + void print(raw_ostream &OS, const PrintingPolicy &Policy, + bool appendSpaceIfNonEmpty = false) const; + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddInteger(Mask); + } + +private: + + // bits: |0 1 2|3 .. 4|5 .. 7|8 ... 31| + // |C R V|GCAttr|Lifetime|AddressSpace| + uint32_t Mask; + + static const uint32_t GCAttrMask = 0x18; + static const uint32_t GCAttrShift = 3; + static const uint32_t LifetimeMask = 0xE0; + static const uint32_t LifetimeShift = 5; + static const uint32_t AddressSpaceMask = ~(CVRMask|GCAttrMask|LifetimeMask); + static const uint32_t AddressSpaceShift = 8; +}; + +/// A std::pair-like structure for storing a qualified type split +/// into its local qualifiers and its locally-unqualified type. +struct SplitQualType { + /// The locally-unqualified type. + const Type *Ty; + + /// The local qualifiers. + Qualifiers Quals; + + SplitQualType() : Ty(nullptr), Quals() {} + SplitQualType(const Type *ty, Qualifiers qs) : Ty(ty), Quals(qs) {} + + SplitQualType getSingleStepDesugaredType() const; // end of this file + + // Make std::tie work. + std::pair<const Type *,Qualifiers> asPair() const { + return std::pair<const Type *, Qualifiers>(Ty, Quals); + } + + friend bool operator==(SplitQualType a, SplitQualType b) { + return a.Ty == b.Ty && a.Quals == b.Quals; + } + friend bool operator!=(SplitQualType a, SplitQualType b) { + return a.Ty != b.Ty || a.Quals != b.Quals; + } +}; + +/// The kind of type we are substituting Objective-C type arguments into. +/// +/// The kind of substitution affects the replacement of type parameters when +/// no concrete type information is provided, e.g., when dealing with an +/// unspecialized type. +enum class ObjCSubstitutionContext { + /// An ordinary type. + Ordinary, + /// The result type of a method or function. + Result, + /// The parameter type of a method or function. + Parameter, + /// The type of a property. + Property, + /// The superclass of a type. + Superclass, +}; + +/// A (possibly-)qualified type. +/// +/// For efficiency, we don't store CV-qualified types as nodes on their +/// own: instead each reference to a type stores the qualifiers. This +/// greatly reduces the number of nodes we need to allocate for types (for +/// example we only need one for 'int', 'const int', 'volatile int', +/// 'const volatile int', etc). +/// +/// As an added efficiency bonus, instead of making this a pair, we +/// just store the two bits we care about in the low bits of the +/// pointer. To handle the packing/unpacking, we make QualType be a +/// simple wrapper class that acts like a smart pointer. A third bit +/// indicates whether there are extended qualifiers present, in which +/// case the pointer points to a special structure. +class QualType { + // Thankfully, these are efficiently composable. + llvm::PointerIntPair<llvm::PointerUnion<const Type*,const ExtQuals*>, + Qualifiers::FastWidth> Value; + + const ExtQuals *getExtQualsUnsafe() const { + return Value.getPointer().get<const ExtQuals*>(); + } + + const Type *getTypePtrUnsafe() const { + return Value.getPointer().get<const Type*>(); + } + + const ExtQualsTypeCommonBase *getCommonPtr() const { + assert(!isNull() && "Cannot retrieve a NULL type pointer"); + uintptr_t CommonPtrVal + = reinterpret_cast<uintptr_t>(Value.getOpaqueValue()); + CommonPtrVal &= ~(uintptr_t)((1 << TypeAlignmentInBits) - 1); + return reinterpret_cast<ExtQualsTypeCommonBase*>(CommonPtrVal); + } + + friend class QualifierCollector; +public: + QualType() {} + + QualType(const Type *Ptr, unsigned Quals) + : Value(Ptr, Quals) {} + QualType(const ExtQuals *Ptr, unsigned Quals) + : Value(Ptr, Quals) {} + + unsigned getLocalFastQualifiers() const { return Value.getInt(); } + void setLocalFastQualifiers(unsigned Quals) { Value.setInt(Quals); } + + /// Retrieves a pointer to the underlying (unqualified) type. + /// + /// This function requires that the type not be NULL. If the type might be + /// NULL, use the (slightly less efficient) \c getTypePtrOrNull(). + const Type *getTypePtr() const; + + const Type *getTypePtrOrNull() const; + + /// Retrieves a pointer to the name of the base type. + const IdentifierInfo *getBaseTypeIdentifier() const; + + /// Divides a QualType into its unqualified type and a set of local + /// qualifiers. + SplitQualType split() const; + + void *getAsOpaquePtr() const { return Value.getOpaqueValue(); } + static QualType getFromOpaquePtr(const void *Ptr) { + QualType T; + T.Value.setFromOpaqueValue(const_cast<void*>(Ptr)); + return T; + } + + const Type &operator*() const { + return *getTypePtr(); + } + + const Type *operator->() const { + return getTypePtr(); + } + + bool isCanonical() const; + bool isCanonicalAsParam() const; + + /// Return true if this QualType doesn't point to a type yet. + bool isNull() const { + return Value.getPointer().isNull(); + } + + /// \brief Determine whether this particular QualType instance has the + /// "const" qualifier set, without looking through typedefs that may have + /// added "const" at a different level. + bool isLocalConstQualified() const { + return (getLocalFastQualifiers() & Qualifiers::Const); + } + + /// \brief Determine whether this type is const-qualified. + bool isConstQualified() const; + + /// \brief Determine whether this particular QualType instance has the + /// "restrict" qualifier set, without looking through typedefs that may have + /// added "restrict" at a different level. + bool isLocalRestrictQualified() const { + return (getLocalFastQualifiers() & Qualifiers::Restrict); + } + + /// \brief Determine whether this type is restrict-qualified. + bool isRestrictQualified() const; + + /// \brief Determine whether this particular QualType instance has the + /// "volatile" qualifier set, without looking through typedefs that may have + /// added "volatile" at a different level. + bool isLocalVolatileQualified() const { + return (getLocalFastQualifiers() & Qualifiers::Volatile); + } + + /// \brief Determine whether this type is volatile-qualified. + bool isVolatileQualified() const; + + /// \brief Determine whether this particular QualType instance has any + /// qualifiers, without looking through any typedefs that might add + /// qualifiers at a different level. + bool hasLocalQualifiers() const { + return getLocalFastQualifiers() || hasLocalNonFastQualifiers(); + } + + /// \brief Determine whether this type has any qualifiers. + bool hasQualifiers() const; + + /// \brief Determine whether this particular QualType instance has any + /// "non-fast" qualifiers, e.g., those that are stored in an ExtQualType + /// instance. + bool hasLocalNonFastQualifiers() const { + return Value.getPointer().is<const ExtQuals*>(); + } + + /// \brief Retrieve the set of qualifiers local to this particular QualType + /// instance, not including any qualifiers acquired through typedefs or + /// other sugar. + Qualifiers getLocalQualifiers() const; + + /// \brief Retrieve the set of qualifiers applied to this type. + Qualifiers getQualifiers() const; + + /// \brief Retrieve the set of CVR (const-volatile-restrict) qualifiers + /// local to this particular QualType instance, not including any qualifiers + /// acquired through typedefs or other sugar. + unsigned getLocalCVRQualifiers() const { + return getLocalFastQualifiers(); + } + + /// \brief Retrieve the set of CVR (const-volatile-restrict) qualifiers + /// applied to this type. + unsigned getCVRQualifiers() const; + + bool isConstant(ASTContext& Ctx) const { + return QualType::isConstant(*this, Ctx); + } + + /// \brief Determine whether this is a Plain Old Data (POD) type (C++ 3.9p10). + bool isPODType(ASTContext &Context) const; + + /// Return true if this is a POD type according to the rules of the C++98 + /// standard, regardless of the current compilation's language. + bool isCXX98PODType(ASTContext &Context) const; + + /// Return true if this is a POD type according to the more relaxed rules + /// of the C++11 standard, regardless of the current compilation's language. + /// (C++0x [basic.types]p9) + bool isCXX11PODType(ASTContext &Context) const; + + /// Return true if this is a trivial type per (C++0x [basic.types]p9) + bool isTrivialType(ASTContext &Context) const; + + /// Return true if this is a trivially copyable type (C++0x [basic.types]p9) + bool isTriviallyCopyableType(ASTContext &Context) const; + + // Don't promise in the API that anything besides 'const' can be + // easily added. + + /// Add the `const` type qualifier to this QualType. + void addConst() { + addFastQualifiers(Qualifiers::Const); + } + QualType withConst() const { + return withFastQualifiers(Qualifiers::Const); + } + + /// Add the `volatile` type qualifier to this QualType. + void addVolatile() { + addFastQualifiers(Qualifiers::Volatile); + } + QualType withVolatile() const { + return withFastQualifiers(Qualifiers::Volatile); + } + + /// Add the `restrict` qualifier to this QualType. + void addRestrict() { + addFastQualifiers(Qualifiers::Restrict); + } + QualType withRestrict() const { + return withFastQualifiers(Qualifiers::Restrict); + } + + QualType withCVRQualifiers(unsigned CVR) const { + return withFastQualifiers(CVR); + } + + void addFastQualifiers(unsigned TQs) { + assert(!(TQs & ~Qualifiers::FastMask) + && "non-fast qualifier bits set in mask!"); + Value.setInt(Value.getInt() | TQs); + } + + void removeLocalConst(); + void removeLocalVolatile(); + void removeLocalRestrict(); + void removeLocalCVRQualifiers(unsigned Mask); + + void removeLocalFastQualifiers() { Value.setInt(0); } + void removeLocalFastQualifiers(unsigned Mask) { + assert(!(Mask & ~Qualifiers::FastMask) && "mask has non-fast qualifiers"); + Value.setInt(Value.getInt() & ~Mask); + } + + // Creates a type with the given qualifiers in addition to any + // qualifiers already on this type. + QualType withFastQualifiers(unsigned TQs) const { + QualType T = *this; + T.addFastQualifiers(TQs); + return T; + } + + // Creates a type with exactly the given fast qualifiers, removing + // any existing fast qualifiers. + QualType withExactLocalFastQualifiers(unsigned TQs) const { + return withoutLocalFastQualifiers().withFastQualifiers(TQs); + } + + // Removes fast qualifiers, but leaves any extended qualifiers in place. + QualType withoutLocalFastQualifiers() const { + QualType T = *this; + T.removeLocalFastQualifiers(); + return T; + } + + QualType getCanonicalType() const; + + /// \brief Return this type with all of the instance-specific qualifiers + /// removed, but without removing any qualifiers that may have been applied + /// through typedefs. + QualType getLocalUnqualifiedType() const { return QualType(getTypePtr(), 0); } + + /// \brief Retrieve the unqualified variant of the given type, + /// removing as little sugar as possible. + /// + /// This routine looks through various kinds of sugar to find the + /// least-desugared type that is unqualified. For example, given: + /// + /// \code + /// typedef int Integer; + /// typedef const Integer CInteger; + /// typedef CInteger DifferenceType; + /// \endcode + /// + /// Executing \c getUnqualifiedType() on the type \c DifferenceType will + /// desugar until we hit the type \c Integer, which has no qualifiers on it. + /// + /// The resulting type might still be qualified if it's sugar for an array + /// type. To strip qualifiers even from within a sugared array type, use + /// ASTContext::getUnqualifiedArrayType. + inline QualType getUnqualifiedType() const; + + /// Retrieve the unqualified variant of the given type, removing as little + /// sugar as possible. + /// + /// Like getUnqualifiedType(), but also returns the set of + /// qualifiers that were built up. + /// + /// The resulting type might still be qualified if it's sugar for an array + /// type. To strip qualifiers even from within a sugared array type, use + /// ASTContext::getUnqualifiedArrayType. + inline SplitQualType getSplitUnqualifiedType() const; + + /// \brief Determine whether this type is more qualified than the other + /// given type, requiring exact equality for non-CVR qualifiers. + bool isMoreQualifiedThan(QualType Other) const; + + /// \brief Determine whether this type is at least as qualified as the other + /// given type, requiring exact equality for non-CVR qualifiers. + bool isAtLeastAsQualifiedAs(QualType Other) const; + + QualType getNonReferenceType() const; + + /// \brief Determine the type of a (typically non-lvalue) expression with the + /// specified result type. + /// + /// This routine should be used for expressions for which the return type is + /// explicitly specified (e.g., in a cast or call) and isn't necessarily + /// an lvalue. It removes a top-level reference (since there are no + /// expressions of reference type) and deletes top-level cvr-qualifiers + /// from non-class types (in C++) or all types (in C). + QualType getNonLValueExprType(const ASTContext &Context) const; + + /// Return the specified type with any "sugar" removed from + /// the type. This takes off typedefs, typeof's etc. If the outer level of + /// the type is already concrete, it returns it unmodified. This is similar + /// to getting the canonical type, but it doesn't remove *all* typedefs. For + /// example, it returns "T*" as "T*", (not as "int*"), because the pointer is + /// concrete. + /// + /// Qualifiers are left in place. + QualType getDesugaredType(const ASTContext &Context) const { + return getDesugaredType(*this, Context); + } + + SplitQualType getSplitDesugaredType() const { + return getSplitDesugaredType(*this); + } + + /// \brief Return the specified type with one level of "sugar" removed from + /// the type. + /// + /// This routine takes off the first typedef, typeof, etc. If the outer level + /// of the type is already concrete, it returns it unmodified. + QualType getSingleStepDesugaredType(const ASTContext &Context) const { + return getSingleStepDesugaredTypeImpl(*this, Context); + } + + /// Returns the specified type after dropping any + /// outer-level parentheses. + QualType IgnoreParens() const { + if (isa<ParenType>(*this)) + return QualType::IgnoreParens(*this); + return *this; + } + + /// Indicate whether the specified types and qualifiers are identical. + friend bool operator==(const QualType &LHS, const QualType &RHS) { + return LHS.Value == RHS.Value; + } + friend bool operator!=(const QualType &LHS, const QualType &RHS) { + return LHS.Value != RHS.Value; + } + std::string getAsString() const { + return getAsString(split()); + } + static std::string getAsString(SplitQualType split) { + return getAsString(split.Ty, split.Quals); + } + static std::string getAsString(const Type *ty, Qualifiers qs); + + std::string getAsString(const PrintingPolicy &Policy) const; + + void print(raw_ostream &OS, const PrintingPolicy &Policy, + const Twine &PlaceHolder = Twine()) const { + print(split(), OS, Policy, PlaceHolder); + } + static void print(SplitQualType split, raw_ostream &OS, + const PrintingPolicy &policy, const Twine &PlaceHolder) { + return print(split.Ty, split.Quals, OS, policy, PlaceHolder); + } + static void print(const Type *ty, Qualifiers qs, + raw_ostream &OS, const PrintingPolicy &policy, + const Twine &PlaceHolder); + + void getAsStringInternal(std::string &Str, + const PrintingPolicy &Policy) const { + return getAsStringInternal(split(), Str, Policy); + } + static void getAsStringInternal(SplitQualType split, std::string &out, + const PrintingPolicy &policy) { + return getAsStringInternal(split.Ty, split.Quals, out, policy); + } + static void getAsStringInternal(const Type *ty, Qualifiers qs, + std::string &out, + const PrintingPolicy &policy); + + class StreamedQualTypeHelper { + const QualType &T; + const PrintingPolicy &Policy; + const Twine &PlaceHolder; + public: + StreamedQualTypeHelper(const QualType &T, const PrintingPolicy &Policy, + const Twine &PlaceHolder) + : T(T), Policy(Policy), PlaceHolder(PlaceHolder) { } + + friend raw_ostream &operator<<(raw_ostream &OS, + const StreamedQualTypeHelper &SQT) { + SQT.T.print(OS, SQT.Policy, SQT.PlaceHolder); + return OS; + } + }; + + StreamedQualTypeHelper stream(const PrintingPolicy &Policy, + const Twine &PlaceHolder = Twine()) const { + return StreamedQualTypeHelper(*this, Policy, PlaceHolder); + } + + void dump(const char *s) const; + void dump() const; + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddPointer(getAsOpaquePtr()); + } + + /// Return the address space of this type. + inline unsigned getAddressSpace() const; + + /// Returns gc attribute of this type. + inline Qualifiers::GC getObjCGCAttr() const; + + /// true when Type is objc's weak. + bool isObjCGCWeak() const { + return getObjCGCAttr() == Qualifiers::Weak; + } + + /// true when Type is objc's strong. + bool isObjCGCStrong() const { + return getObjCGCAttr() == Qualifiers::Strong; + } + + /// Returns lifetime attribute of this type. + Qualifiers::ObjCLifetime getObjCLifetime() const { + return getQualifiers().getObjCLifetime(); + } + + bool hasNonTrivialObjCLifetime() const { + return getQualifiers().hasNonTrivialObjCLifetime(); + } + + bool hasStrongOrWeakObjCLifetime() const { + return getQualifiers().hasStrongOrWeakObjCLifetime(); + } + + enum DestructionKind { + DK_none, + DK_cxx_destructor, + DK_objc_strong_lifetime, + DK_objc_weak_lifetime + }; + + /// Returns a nonzero value if objects of this type require + /// non-trivial work to clean up after. Non-zero because it's + /// conceivable that qualifiers (objc_gc(weak)?) could make + /// something require destruction. + DestructionKind isDestructedType() const { + return isDestructedTypeImpl(*this); + } + + /// Determine whether expressions of the given type are forbidden + /// from being lvalues in C. + /// + /// The expression types that are forbidden to be lvalues are: + /// - 'void', but not qualified void + /// - function types + /// + /// The exact rule here is C99 6.3.2.1: + /// An lvalue is an expression with an object type or an incomplete + /// type other than void. + bool isCForbiddenLValueType() const; + + /// Substitute type arguments for the Objective-C type parameters used in the + /// subject type. + /// + /// \param ctx ASTContext in which the type exists. + /// + /// \param typeArgs The type arguments that will be substituted for the + /// Objective-C type parameters in the subject type, which are generally + /// computed via \c Type::getObjCSubstitutions. If empty, the type + /// parameters will be replaced with their bounds or id/Class, as appropriate + /// for the context. + /// + /// \param context The context in which the subject type was written. + /// + /// \returns the resulting type. + QualType substObjCTypeArgs(ASTContext &ctx, + ArrayRef<QualType> typeArgs, + ObjCSubstitutionContext context) const; + + /// Substitute type arguments from an object type for the Objective-C type + /// parameters used in the subject type. + /// + /// This operation combines the computation of type arguments for + /// substitution (\c Type::getObjCSubstitutions) with the actual process of + /// substitution (\c QualType::substObjCTypeArgs) for the convenience of + /// callers that need to perform a single substitution in isolation. + /// + /// \param objectType The type of the object whose member type we're + /// substituting into. For example, this might be the receiver of a message + /// or the base of a property access. + /// + /// \param dc The declaration context from which the subject type was + /// retrieved, which indicates (for example) which type parameters should + /// be substituted. + /// + /// \param context The context in which the subject type was written. + /// + /// \returns the subject type after replacing all of the Objective-C type + /// parameters with their corresponding arguments. + QualType substObjCMemberType(QualType objectType, + const DeclContext *dc, + ObjCSubstitutionContext context) const; + + /// Strip Objective-C "__kindof" types from the given type. + QualType stripObjCKindOfType(const ASTContext &ctx) const; + +private: + // These methods are implemented in a separate translation unit; + // "static"-ize them to avoid creating temporary QualTypes in the + // caller. + static bool isConstant(QualType T, ASTContext& Ctx); + static QualType getDesugaredType(QualType T, const ASTContext &Context); + static SplitQualType getSplitDesugaredType(QualType T); + static SplitQualType getSplitUnqualifiedTypeImpl(QualType type); + static QualType getSingleStepDesugaredTypeImpl(QualType type, + const ASTContext &C); + static QualType IgnoreParens(QualType T); + static DestructionKind isDestructedTypeImpl(QualType type); +}; + +} // end clang. + +namespace llvm { +/// Implement simplify_type for QualType, so that we can dyn_cast from QualType +/// to a specific Type class. +template<> struct simplify_type< ::clang::QualType> { + typedef const ::clang::Type *SimpleType; + static SimpleType getSimplifiedValue(::clang::QualType Val) { + return Val.getTypePtr(); + } +}; + +// Teach SmallPtrSet that QualType is "basically a pointer". +template<> +class PointerLikeTypeTraits<clang::QualType> { +public: + static inline void *getAsVoidPointer(clang::QualType P) { + return P.getAsOpaquePtr(); + } + static inline clang::QualType getFromVoidPointer(void *P) { + return clang::QualType::getFromOpaquePtr(P); + } + // Various qualifiers go in low bits. + enum { NumLowBitsAvailable = 0 }; +}; + +} // end namespace llvm + +namespace clang { + +/// \brief Base class that is common to both the \c ExtQuals and \c Type +/// classes, which allows \c QualType to access the common fields between the +/// two. +/// +class ExtQualsTypeCommonBase { + ExtQualsTypeCommonBase(const Type *baseType, QualType canon) + : BaseType(baseType), CanonicalType(canon) {} + + /// \brief The "base" type of an extended qualifiers type (\c ExtQuals) or + /// a self-referential pointer (for \c Type). + /// + /// This pointer allows an efficient mapping from a QualType to its + /// underlying type pointer. + const Type *const BaseType; + + /// \brief The canonical type of this type. A QualType. + QualType CanonicalType; + + friend class QualType; + friend class Type; + friend class ExtQuals; +}; + +/// We can encode up to four bits in the low bits of a +/// type pointer, but there are many more type qualifiers that we want +/// to be able to apply to an arbitrary type. Therefore we have this +/// struct, intended to be heap-allocated and used by QualType to +/// store qualifiers. +/// +/// The current design tags the 'const', 'restrict', and 'volatile' qualifiers +/// in three low bits on the QualType pointer; a fourth bit records whether +/// the pointer is an ExtQuals node. The extended qualifiers (address spaces, +/// Objective-C GC attributes) are much more rare. +class ExtQuals : public ExtQualsTypeCommonBase, public llvm::FoldingSetNode { + // NOTE: changing the fast qualifiers should be straightforward as + // long as you don't make 'const' non-fast. + // 1. Qualifiers: + // a) Modify the bitmasks (Qualifiers::TQ and DeclSpec::TQ). + // Fast qualifiers must occupy the low-order bits. + // b) Update Qualifiers::FastWidth and FastMask. + // 2. QualType: + // a) Update is{Volatile,Restrict}Qualified(), defined inline. + // b) Update remove{Volatile,Restrict}, defined near the end of + // this header. + // 3. ASTContext: + // a) Update get{Volatile,Restrict}Type. + + /// The immutable set of qualifiers applied by this node. Always contains + /// extended qualifiers. + Qualifiers Quals; + + ExtQuals *this_() { return this; } + +public: + ExtQuals(const Type *baseType, QualType canon, Qualifiers quals) + : ExtQualsTypeCommonBase(baseType, + canon.isNull() ? QualType(this_(), 0) : canon), + Quals(quals) + { + assert(Quals.hasNonFastQualifiers() + && "ExtQuals created with no fast qualifiers"); + assert(!Quals.hasFastQualifiers() + && "ExtQuals created with fast qualifiers"); + } + + Qualifiers getQualifiers() const { return Quals; } + + bool hasObjCGCAttr() const { return Quals.hasObjCGCAttr(); } + Qualifiers::GC getObjCGCAttr() const { return Quals.getObjCGCAttr(); } + + bool hasObjCLifetime() const { return Quals.hasObjCLifetime(); } + Qualifiers::ObjCLifetime getObjCLifetime() const { + return Quals.getObjCLifetime(); + } + + bool hasAddressSpace() const { return Quals.hasAddressSpace(); } + unsigned getAddressSpace() const { return Quals.getAddressSpace(); } + + const Type *getBaseType() const { return BaseType; } + +public: + void Profile(llvm::FoldingSetNodeID &ID) const { + Profile(ID, getBaseType(), Quals); + } + static void Profile(llvm::FoldingSetNodeID &ID, + const Type *BaseType, + Qualifiers Quals) { + assert(!Quals.hasFastQualifiers() && "fast qualifiers in ExtQuals hash!"); + ID.AddPointer(BaseType); + Quals.Profile(ID); + } +}; + +/// The kind of C++11 ref-qualifier associated with a function type. +/// This determines whether a member function's "this" object can be an +/// lvalue, rvalue, or neither. +enum RefQualifierKind { + /// \brief No ref-qualifier was provided. + RQ_None = 0, + /// \brief An lvalue ref-qualifier was provided (\c &). + RQ_LValue, + /// \brief An rvalue ref-qualifier was provided (\c &&). + RQ_RValue +}; + +/// Which keyword(s) were used to create an AutoType. +enum class AutoTypeKeyword { + /// \brief auto + Auto, + /// \brief decltype(auto) + DecltypeAuto, + /// \brief __auto_type (GNU extension) + GNUAutoType +}; + +/// The base class of the type hierarchy. +/// +/// A central concept with types is that each type always has a canonical +/// type. A canonical type is the type with any typedef names stripped out +/// of it or the types it references. For example, consider: +/// +/// typedef int foo; +/// typedef foo* bar; +/// 'int *' 'foo *' 'bar' +/// +/// There will be a Type object created for 'int'. Since int is canonical, its +/// CanonicalType pointer points to itself. There is also a Type for 'foo' (a +/// TypedefType). Its CanonicalType pointer points to the 'int' Type. Next +/// there is a PointerType that represents 'int*', which, like 'int', is +/// canonical. Finally, there is a PointerType type for 'foo*' whose canonical +/// type is 'int*', and there is a TypedefType for 'bar', whose canonical type +/// is also 'int*'. +/// +/// Non-canonical types are useful for emitting diagnostics, without losing +/// information about typedefs being used. Canonical types are useful for type +/// comparisons (they allow by-pointer equality tests) and useful for reasoning +/// about whether something has a particular form (e.g. is a function type), +/// because they implicitly, recursively, strip all typedefs out of a type. +/// +/// Types, once created, are immutable. +/// +class Type : public ExtQualsTypeCommonBase { +public: + enum TypeClass { +#define TYPE(Class, Base) Class, +#define LAST_TYPE(Class) TypeLast = Class, +#define ABSTRACT_TYPE(Class, Base) +#include "clang/AST/TypeNodes.def" + TagFirst = Record, TagLast = Enum + }; + +private: + Type(const Type &) = delete; + void operator=(const Type &) = delete; + + /// Bitfields required by the Type class. + class TypeBitfields { + friend class Type; + template <class T> friend class TypePropertyCache; + + /// TypeClass bitfield - Enum that specifies what subclass this belongs to. + unsigned TC : 8; + + /// Whether this type is a dependent type (C++ [temp.dep.type]). + unsigned Dependent : 1; + + /// Whether this type somehow involves a template parameter, even + /// if the resolution of the type does not depend on a template parameter. + unsigned InstantiationDependent : 1; + + /// Whether this type is a variably-modified type (C99 6.7.5). + unsigned VariablyModified : 1; + + /// \brief Whether this type contains an unexpanded parameter pack + /// (for C++11 variadic templates). + unsigned ContainsUnexpandedParameterPack : 1; + + /// \brief True if the cache (i.e. the bitfields here starting with + /// 'Cache') is valid. + mutable unsigned CacheValid : 1; + + /// \brief Linkage of this type. + mutable unsigned CachedLinkage : 3; + + /// \brief Whether this type involves and local or unnamed types. + mutable unsigned CachedLocalOrUnnamed : 1; + + /// \brief Whether this type comes from an AST file. + mutable unsigned FromAST : 1; + + bool isCacheValid() const { + return CacheValid; + } + Linkage getLinkage() const { + assert(isCacheValid() && "getting linkage from invalid cache"); + return static_cast<Linkage>(CachedLinkage); + } + bool hasLocalOrUnnamedType() const { + assert(isCacheValid() && "getting linkage from invalid cache"); + return CachedLocalOrUnnamed; + } + }; + enum { NumTypeBits = 18 }; + +protected: + // These classes allow subclasses to somewhat cleanly pack bitfields + // into Type. + + class ArrayTypeBitfields { + friend class ArrayType; + + unsigned : NumTypeBits; + + /// CVR qualifiers from declarations like + /// 'int X[static restrict 4]'. For function parameters only. + unsigned IndexTypeQuals : 3; + + /// Storage class qualifiers from declarations like + /// 'int X[static restrict 4]'. For function parameters only. + /// Actually an ArrayType::ArraySizeModifier. + unsigned SizeModifier : 3; + }; + + class BuiltinTypeBitfields { + friend class BuiltinType; + + unsigned : NumTypeBits; + + /// The kind (BuiltinType::Kind) of builtin type this is. + unsigned Kind : 8; + }; + + class FunctionTypeBitfields { + friend class FunctionType; + friend class FunctionProtoType; + + unsigned : NumTypeBits; + + /// Extra information which affects how the function is called, like + /// regparm and the calling convention. + unsigned ExtInfo : 9; + + /// Used only by FunctionProtoType, put here to pack with the + /// other bitfields. + /// The qualifiers are part of FunctionProtoType because... + /// + /// C++ 8.3.5p4: The return type, the parameter type list and the + /// cv-qualifier-seq, [...], are part of the function type. + unsigned TypeQuals : 3; + + /// \brief The ref-qualifier associated with a \c FunctionProtoType. + /// + /// This is a value of type \c RefQualifierKind. + unsigned RefQualifier : 2; + }; + + class ObjCObjectTypeBitfields { + friend class ObjCObjectType; + + unsigned : NumTypeBits; + + /// The number of type arguments stored directly on this object type. + unsigned NumTypeArgs : 7; + + /// The number of protocols stored directly on this object type. + unsigned NumProtocols : 6; + + /// Whether this is a "kindof" type. + unsigned IsKindOf : 1; + }; + static_assert(NumTypeBits + 7 + 6 + 1 <= 32, "Does not fit in an unsigned"); + + class ReferenceTypeBitfields { + friend class ReferenceType; + + unsigned : NumTypeBits; + + /// True if the type was originally spelled with an lvalue sigil. + /// This is never true of rvalue references but can also be false + /// on lvalue references because of C++0x [dcl.typedef]p9, + /// as follows: + /// + /// typedef int &ref; // lvalue, spelled lvalue + /// typedef int &&rvref; // rvalue + /// ref &a; // lvalue, inner ref, spelled lvalue + /// ref &&a; // lvalue, inner ref + /// rvref &a; // lvalue, inner ref, spelled lvalue + /// rvref &&a; // rvalue, inner ref + unsigned SpelledAsLValue : 1; + + /// True if the inner type is a reference type. This only happens + /// in non-canonical forms. + unsigned InnerRef : 1; + }; + + class TypeWithKeywordBitfields { + friend class TypeWithKeyword; + + unsigned : NumTypeBits; + + /// An ElaboratedTypeKeyword. 8 bits for efficient access. + unsigned Keyword : 8; + }; + + class VectorTypeBitfields { + friend class VectorType; + + unsigned : NumTypeBits; + + /// The kind of vector, either a generic vector type or some + /// target-specific vector type such as for AltiVec or Neon. + unsigned VecKind : 3; + + /// The number of elements in the vector. + unsigned NumElements : 29 - NumTypeBits; + + enum { MaxNumElements = (1 << (29 - NumTypeBits)) - 1 }; + }; + + class AttributedTypeBitfields { + friend class AttributedType; + + unsigned : NumTypeBits; + + /// An AttributedType::Kind + unsigned AttrKind : 32 - NumTypeBits; + }; + + class AutoTypeBitfields { + friend class AutoType; + + unsigned : NumTypeBits; + + /// Was this placeholder type spelled as 'auto', 'decltype(auto)', + /// or '__auto_type'? AutoTypeKeyword value. + unsigned Keyword : 2; + }; + + union { + TypeBitfields TypeBits; + ArrayTypeBitfields ArrayTypeBits; + AttributedTypeBitfields AttributedTypeBits; + AutoTypeBitfields AutoTypeBits; + BuiltinTypeBitfields BuiltinTypeBits; + FunctionTypeBitfields FunctionTypeBits; + ObjCObjectTypeBitfields ObjCObjectTypeBits; + ReferenceTypeBitfields ReferenceTypeBits; + TypeWithKeywordBitfields TypeWithKeywordBits; + VectorTypeBitfields VectorTypeBits; + }; + +private: + /// \brief Set whether this type comes from an AST file. + void setFromAST(bool V = true) const { + TypeBits.FromAST = V; + } + + template <class T> friend class TypePropertyCache; + +protected: + // silence VC++ warning C4355: 'this' : used in base member initializer list + Type *this_() { return this; } + Type(TypeClass tc, QualType canon, bool Dependent, + bool InstantiationDependent, bool VariablyModified, + bool ContainsUnexpandedParameterPack) + : ExtQualsTypeCommonBase(this, + canon.isNull() ? QualType(this_(), 0) : canon) { + TypeBits.TC = tc; + TypeBits.Dependent = Dependent; + TypeBits.InstantiationDependent = Dependent || InstantiationDependent; + TypeBits.VariablyModified = VariablyModified; + TypeBits.ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack; + TypeBits.CacheValid = false; + TypeBits.CachedLocalOrUnnamed = false; + TypeBits.CachedLinkage = NoLinkage; + TypeBits.FromAST = false; + } + friend class ASTContext; + + void setDependent(bool D = true) { + TypeBits.Dependent = D; + if (D) + TypeBits.InstantiationDependent = true; + } + void setInstantiationDependent(bool D = true) { + TypeBits.InstantiationDependent = D; } + void setVariablyModified(bool VM = true) { TypeBits.VariablyModified = VM; + } + void setContainsUnexpandedParameterPack(bool PP = true) { + TypeBits.ContainsUnexpandedParameterPack = PP; + } + +public: + TypeClass getTypeClass() const { return static_cast<TypeClass>(TypeBits.TC); } + + /// \brief Whether this type comes from an AST file. + bool isFromAST() const { return TypeBits.FromAST; } + + /// \brief Whether this type is or contains an unexpanded parameter + /// pack, used to support C++0x variadic templates. + /// + /// A type that contains a parameter pack shall be expanded by the + /// ellipsis operator at some point. For example, the typedef in the + /// following example contains an unexpanded parameter pack 'T': + /// + /// \code + /// template<typename ...T> + /// struct X { + /// typedef T* pointer_types; // ill-formed; T is a parameter pack. + /// }; + /// \endcode + /// + /// Note that this routine does not specify which + bool containsUnexpandedParameterPack() const { + return TypeBits.ContainsUnexpandedParameterPack; + } + + /// Determines if this type would be canonical if it had no further + /// qualification. + bool isCanonicalUnqualified() const { + return CanonicalType == QualType(this, 0); + } + + /// Pull a single level of sugar off of this locally-unqualified type. + /// Users should generally prefer SplitQualType::getSingleStepDesugaredType() + /// or QualType::getSingleStepDesugaredType(const ASTContext&). + QualType getLocallyUnqualifiedSingleStepDesugaredType() const; + + /// Types are partitioned into 3 broad categories (C99 6.2.5p1): + /// object types, function types, and incomplete types. + + /// Return true if this is an incomplete type. + /// A type that can describe objects, but which lacks information needed to + /// determine its size (e.g. void, or a fwd declared struct). Clients of this + /// routine will need to determine if the size is actually required. + /// + /// \brief Def If non-null, and the type refers to some kind of declaration + /// that can be completed (such as a C struct, C++ class, or Objective-C + /// class), will be set to the declaration. + bool isIncompleteType(NamedDecl **Def = nullptr) const; + + /// Return true if this is an incomplete or object + /// type, in other words, not a function type. + bool isIncompleteOrObjectType() const { + return !isFunctionType(); + } + + /// \brief Determine whether this type is an object type. + bool isObjectType() const { + // C++ [basic.types]p8: + // An object type is a (possibly cv-qualified) type that is not a + // function type, not a reference type, and not a void type. + return !isReferenceType() && !isFunctionType() && !isVoidType(); + } + + /// Return true if this is a literal type + /// (C++11 [basic.types]p10) + bool isLiteralType(const ASTContext &Ctx) const; + + /// Test if this type is a standard-layout type. + /// (C++0x [basic.type]p9) + bool isStandardLayoutType() const; + + /// Helper methods to distinguish type categories. All type predicates + /// operate on the canonical type, ignoring typedefs and qualifiers. + + /// Returns true if the type is a builtin type. + bool isBuiltinType() const; + + /// Test for a particular builtin type. + bool isSpecificBuiltinType(unsigned K) const; + + /// Test for a type which does not represent an actual type-system type but + /// is instead used as a placeholder for various convenient purposes within + /// Clang. All such types are BuiltinTypes. + bool isPlaceholderType() const; + const BuiltinType *getAsPlaceholderType() const; + + /// Test for a specific placeholder type. + bool isSpecificPlaceholderType(unsigned K) const; + + /// Test for a placeholder type other than Overload; see + /// BuiltinType::isNonOverloadPlaceholderType. + bool isNonOverloadPlaceholderType() const; + + /// isIntegerType() does *not* include complex integers (a GCC extension). + /// isComplexIntegerType() can be used to test for complex integers. + bool isIntegerType() const; // C99 6.2.5p17 (int, char, bool, enum) + bool isEnumeralType() const; + bool isBooleanType() const; + bool isCharType() const; + bool isWideCharType() const; + bool isChar16Type() const; + bool isChar32Type() const; + bool isAnyCharacterType() const; + bool isIntegralType(ASTContext &Ctx) const; + + /// Determine whether this type is an integral or enumeration type. + bool isIntegralOrEnumerationType() const; + /// Determine whether this type is an integral or unscoped enumeration type. + bool isIntegralOrUnscopedEnumerationType() const; + + /// Floating point categories. + bool isRealFloatingType() const; // C99 6.2.5p10 (float, double, long double) + /// isComplexType() does *not* include complex integers (a GCC extension). + /// isComplexIntegerType() can be used to test for complex integers. + bool isComplexType() const; // C99 6.2.5p11 (complex) + bool isAnyComplexType() const; // C99 6.2.5p11 (complex) + Complex Int. + bool isFloatingType() const; // C99 6.2.5p11 (real floating + complex) + bool isHalfType() const; // OpenCL 6.1.1.1, NEON (IEEE 754-2008 half) + bool isRealType() const; // C99 6.2.5p17 (real floating + integer) + bool isArithmeticType() const; // C99 6.2.5p18 (integer + floating) + bool isVoidType() const; // C99 6.2.5p19 + bool isScalarType() const; // C99 6.2.5p21 (arithmetic + pointers) + bool isAggregateType() const; + bool isFundamentalType() const; + bool isCompoundType() const; + + // Type Predicates: Check to see if this type is structurally the specified + // type, ignoring typedefs and qualifiers. + bool isFunctionType() const; + bool isFunctionNoProtoType() const { return getAs<FunctionNoProtoType>(); } + bool isFunctionProtoType() const { return getAs<FunctionProtoType>(); } + bool isPointerType() const; + bool isAnyPointerType() const; // Any C pointer or ObjC object pointer + bool isBlockPointerType() const; + bool isVoidPointerType() const; + bool isReferenceType() const; + bool isLValueReferenceType() const; + bool isRValueReferenceType() const; + bool isFunctionPointerType() const; + bool isMemberPointerType() const; + bool isMemberFunctionPointerType() const; + bool isMemberDataPointerType() const; + bool isArrayType() const; + bool isConstantArrayType() const; + bool isIncompleteArrayType() const; + bool isVariableArrayType() const; + bool isDependentSizedArrayType() const; + bool isRecordType() const; + bool isClassType() const; + bool isStructureType() const; + bool isObjCBoxableRecordType() const; + bool isInterfaceType() const; + bool isStructureOrClassType() const; + bool isUnionType() const; + bool isComplexIntegerType() const; // GCC _Complex integer type. + bool isVectorType() const; // GCC vector type. + bool isExtVectorType() const; // Extended vector type. + bool isObjCObjectPointerType() const; // pointer to ObjC object + bool isObjCRetainableType() const; // ObjC object or block pointer + bool isObjCLifetimeType() const; // (array of)* retainable type + bool isObjCIndirectLifetimeType() const; // (pointer to)* lifetime type + bool isObjCNSObjectType() const; // __attribute__((NSObject)) + bool isObjCIndependentClassType() const; // __attribute__((objc_independent_class)) + // FIXME: change this to 'raw' interface type, so we can used 'interface' type + // for the common case. + bool isObjCObjectType() const; // NSString or typeof(*(id)0) + bool isObjCQualifiedInterfaceType() const; // NSString<foo> + bool isObjCQualifiedIdType() const; // id<foo> + bool isObjCQualifiedClassType() const; // Class<foo> + bool isObjCObjectOrInterfaceType() const; + bool isObjCIdType() const; // id + bool isObjCInertUnsafeUnretainedType() const; + + /// Whether the type is Objective-C 'id' or a __kindof type of an + /// object type, e.g., __kindof NSView * or __kindof id + /// <NSCopying>. + /// + /// \param bound Will be set to the bound on non-id subtype types, + /// which will be (possibly specialized) Objective-C class type, or + /// null for 'id. + bool isObjCIdOrObjectKindOfType(const ASTContext &ctx, + const ObjCObjectType *&bound) const; + + bool isObjCClassType() const; // Class + + /// Whether the type is Objective-C 'Class' or a __kindof type of an + /// Class type, e.g., __kindof Class <NSCopying>. + /// + /// Unlike \c isObjCIdOrObjectKindOfType, there is no relevant bound + /// here because Objective-C's type system cannot express "a class + /// object for a subclass of NSFoo". + bool isObjCClassOrClassKindOfType() const; + + bool isBlockCompatibleObjCPointerType(ASTContext &ctx) const; + bool isObjCSelType() const; // Class + bool isObjCBuiltinType() const; // 'id' or 'Class' + bool isObjCARCBridgableType() const; + bool isCARCBridgableType() const; + bool isTemplateTypeParmType() const; // C++ template type parameter + bool isNullPtrType() const; // C++0x nullptr_t + bool isAtomicType() const; // C11 _Atomic() + + bool isImage1dT() const; // OpenCL image1d_t + bool isImage1dArrayT() const; // OpenCL image1d_array_t + bool isImage1dBufferT() const; // OpenCL image1d_buffer_t + bool isImage2dT() const; // OpenCL image2d_t + bool isImage2dArrayT() const; // OpenCL image2d_array_t + bool isImage2dDepthT() const; // OpenCL image_2d_depth_t + bool isImage2dArrayDepthT() const; // OpenCL image_2d_array_depth_t + bool isImage2dMSAAT() const; // OpenCL image_2d_msaa_t + bool isImage2dArrayMSAAT() const; // OpenCL image_2d_array_msaa_t + bool isImage2dMSAATDepth() const; // OpenCL image_2d_msaa_depth_t + bool isImage2dArrayMSAATDepth() const; // OpenCL image_2d_array_msaa_depth_t + bool isImage3dT() const; // OpenCL image3d_t + + bool isImageType() const; // Any OpenCL image type + + bool isSamplerT() const; // OpenCL sampler_t + bool isEventT() const; // OpenCL event_t + bool isClkEventT() const; // OpenCL clk_event_t + bool isQueueT() const; // OpenCL queue_t + bool isNDRangeT() const; // OpenCL ndrange_t + bool isReserveIDT() const; // OpenCL reserve_id_t + + bool isOpenCLSpecificType() const; // Any OpenCL specific type + + /// Determines if this type, which must satisfy + /// isObjCLifetimeType(), is implicitly __unsafe_unretained rather + /// than implicitly __strong. + bool isObjCARCImplicitlyUnretainedType() const; + + /// Return the implicit lifetime for this type, which must not be dependent. + Qualifiers::ObjCLifetime getObjCARCImplicitLifetime() const; + + enum ScalarTypeKind { + STK_CPointer, + STK_BlockPointer, + STK_ObjCObjectPointer, + STK_MemberPointer, + STK_Bool, + STK_Integral, + STK_Floating, + STK_IntegralComplex, + STK_FloatingComplex + }; + /// Given that this is a scalar type, classify it. + ScalarTypeKind getScalarTypeKind() const; + + /// Whether this type is a dependent type, meaning that its definition + /// somehow depends on a template parameter (C++ [temp.dep.type]). + bool isDependentType() const { return TypeBits.Dependent; } + + /// \brief Determine whether this type is an instantiation-dependent type, + /// meaning that the type involves a template parameter (even if the + /// definition does not actually depend on the type substituted for that + /// template parameter). + bool isInstantiationDependentType() const { + return TypeBits.InstantiationDependent; + } + + /// \brief Determine whether this type is an undeduced type, meaning that + /// it somehow involves a C++11 'auto' type which has not yet been deduced. + bool isUndeducedType() const; + + /// \brief Whether this type is a variably-modified type (C99 6.7.5). + bool isVariablyModifiedType() const { return TypeBits.VariablyModified; } + + /// \brief Whether this type involves a variable-length array type + /// with a definite size. + bool hasSizedVLAType() const; + + /// \brief Whether this type is or contains a local or unnamed type. + bool hasUnnamedOrLocalType() const; + + bool isOverloadableType() const; + + /// \brief Determine wither this type is a C++ elaborated-type-specifier. + bool isElaboratedTypeSpecifier() const; + + bool canDecayToPointerType() const; + + /// Whether this type is represented natively as a pointer. This includes + /// pointers, references, block pointers, and Objective-C interface, + /// qualified id, and qualified interface types, as well as nullptr_t. + bool hasPointerRepresentation() const; + + /// Whether this type can represent an objective pointer type for the + /// purpose of GC'ability + bool hasObjCPointerRepresentation() const; + + /// \brief Determine whether this type has an integer representation + /// of some sort, e.g., it is an integer type or a vector. + bool hasIntegerRepresentation() const; + + /// \brief Determine whether this type has an signed integer representation + /// of some sort, e.g., it is an signed integer type or a vector. + bool hasSignedIntegerRepresentation() const; + + /// \brief Determine whether this type has an unsigned integer representation + /// of some sort, e.g., it is an unsigned integer type or a vector. + bool hasUnsignedIntegerRepresentation() const; + + /// \brief Determine whether this type has a floating-point representation + /// of some sort, e.g., it is a floating-point type or a vector thereof. + bool hasFloatingRepresentation() const; + + // Type Checking Functions: Check to see if this type is structurally the + // specified type, ignoring typedefs and qualifiers, and return a pointer to + // the best type we can. + const RecordType *getAsStructureType() const; + /// NOTE: getAs*ArrayType are methods on ASTContext. + const RecordType *getAsUnionType() const; + const ComplexType *getAsComplexIntegerType() const; // GCC complex int type. + const ObjCObjectType *getAsObjCInterfaceType() const; + // The following is a convenience method that returns an ObjCObjectPointerType + // for object declared using an interface. + const ObjCObjectPointerType *getAsObjCInterfacePointerType() const; + const ObjCObjectPointerType *getAsObjCQualifiedIdType() const; + const ObjCObjectPointerType *getAsObjCQualifiedClassType() const; + const ObjCObjectType *getAsObjCQualifiedInterfaceType() const; + + /// \brief Retrieves the CXXRecordDecl that this type refers to, either + /// because the type is a RecordType or because it is the injected-class-name + /// type of a class template or class template partial specialization. + CXXRecordDecl *getAsCXXRecordDecl() const; + + /// \brief Retrieves the TagDecl that this type refers to, either + /// because the type is a TagType or because it is the injected-class-name + /// type of a class template or class template partial specialization. + TagDecl *getAsTagDecl() const; + + /// If this is a pointer or reference to a RecordType, return the + /// CXXRecordDecl that that type refers to. + /// + /// If this is not a pointer or reference, or the type being pointed to does + /// not refer to a CXXRecordDecl, returns NULL. + const CXXRecordDecl *getPointeeCXXRecordDecl() const; + + /// Get the AutoType whose type will be deduced for a variable with + /// an initializer of this type. This looks through declarators like pointer + /// types, but not through decltype or typedefs. + AutoType *getContainedAutoType() const; + + /// Member-template getAs<specific type>'. Look through sugar for + /// an instance of \<specific type>. This scheme will eventually + /// replace the specific getAsXXXX methods above. + /// + /// There are some specializations of this member template listed + /// immediately following this class. + template <typename T> const T *getAs() const; + + /// A variant of getAs<> for array types which silently discards + /// qualifiers from the outermost type. + const ArrayType *getAsArrayTypeUnsafe() const; + + /// Member-template castAs<specific type>. Look through sugar for + /// the underlying instance of \<specific type>. + /// + /// This method has the same relationship to getAs<T> as cast<T> has + /// to dyn_cast<T>; which is to say, the underlying type *must* + /// have the intended type, and this method will never return null. + template <typename T> const T *castAs() const; + + /// A variant of castAs<> for array type which silently discards + /// qualifiers from the outermost type. + const ArrayType *castAsArrayTypeUnsafe() const; + + /// Get the base element type of this type, potentially discarding type + /// qualifiers. This should never be used when type qualifiers + /// are meaningful. + const Type *getBaseElementTypeUnsafe() const; + + /// If this is an array type, return the element type of the array, + /// potentially with type qualifiers missing. + /// This should never be used when type qualifiers are meaningful. + const Type *getArrayElementTypeNoTypeQual() const; + + /// If this is a pointer, ObjC object pointer, or block + /// pointer, this returns the respective pointee. + QualType getPointeeType() const; + + /// Return the specified type with any "sugar" removed from the type, + /// removing any typedefs, typeofs, etc., as well as any qualifiers. + const Type *getUnqualifiedDesugaredType() const; + + /// More type predicates useful for type checking/promotion + bool isPromotableIntegerType() const; // C99 6.3.1.1p2 + + /// Return true if this is an integer type that is + /// signed, according to C99 6.2.5p4 [char, signed char, short, int, long..], + /// or an enum decl which has a signed representation. + bool isSignedIntegerType() const; + + /// Return true if this is an integer type that is + /// unsigned, according to C99 6.2.5p6 [which returns true for _Bool], + /// or an enum decl which has an unsigned representation. + bool isUnsignedIntegerType() const; + + /// Determines whether this is an integer type that is signed or an + /// enumeration types whose underlying type is a signed integer type. + bool isSignedIntegerOrEnumerationType() const; + + /// Determines whether this is an integer type that is unsigned or an + /// enumeration types whose underlying type is a unsigned integer type. + bool isUnsignedIntegerOrEnumerationType() const; + + /// Return true if this is not a variable sized type, + /// according to the rules of C99 6.7.5p3. It is not legal to call this on + /// incomplete types. + bool isConstantSizeType() const; + + /// Returns true if this type can be represented by some + /// set of type specifiers. + bool isSpecifierType() const; + + /// Determine the linkage of this type. + Linkage getLinkage() const; + + /// Determine the visibility of this type. + Visibility getVisibility() const { + return getLinkageAndVisibility().getVisibility(); + } + + /// Return true if the visibility was explicitly set is the code. + bool isVisibilityExplicit() const { + return getLinkageAndVisibility().isVisibilityExplicit(); + } + + /// Determine the linkage and visibility of this type. + LinkageInfo getLinkageAndVisibility() const; + + /// True if the computed linkage is valid. Used for consistency + /// checking. Should always return true. + bool isLinkageValid() const; + + /// Determine the nullability of the given type. + /// + /// Note that nullability is only captured as sugar within the type + /// system, not as part of the canonical type, so nullability will + /// be lost by canonicalization and desugaring. + Optional<NullabilityKind> getNullability(const ASTContext &context) const; + + /// Determine whether the given type can have a nullability + /// specifier applied to it, i.e., if it is any kind of pointer type + /// or a dependent type that could instantiate to any kind of + /// pointer type. + bool canHaveNullability() const; + + /// Retrieve the set of substitutions required when accessing a member + /// of the Objective-C receiver type that is declared in the given context. + /// + /// \c *this is the type of the object we're operating on, e.g., the + /// receiver for a message send or the base of a property access, and is + /// expected to be of some object or object pointer type. + /// + /// \param dc The declaration context for which we are building up a + /// substitution mapping, which should be an Objective-C class, extension, + /// category, or method within. + /// + /// \returns an array of type arguments that can be substituted for + /// the type parameters of the given declaration context in any type described + /// within that context, or an empty optional to indicate that no + /// substitution is required. + Optional<ArrayRef<QualType>> + getObjCSubstitutions(const DeclContext *dc) const; + + /// Determines if this is an ObjC interface type that may accept type + /// parameters. + bool acceptsObjCTypeParams() const; + + const char *getTypeClassName() const; + + QualType getCanonicalTypeInternal() const { + return CanonicalType; + } + CanQualType getCanonicalTypeUnqualified() const; // in CanonicalType.h + void dump() const; + + friend class ASTReader; + friend class ASTWriter; +}; + +/// \brief This will check for a TypedefType by removing any existing sugar +/// until it reaches a TypedefType or a non-sugared type. +template <> const TypedefType *Type::getAs() const; + +/// \brief This will check for a TemplateSpecializationType by removing any +/// existing sugar until it reaches a TemplateSpecializationType or a +/// non-sugared type. +template <> const TemplateSpecializationType *Type::getAs() const; + +/// \brief This will check for an AttributedType by removing any existing sugar +/// until it reaches an AttributedType or a non-sugared type. +template <> const AttributedType *Type::getAs() const; + +// We can do canonical leaf types faster, because we don't have to +// worry about preserving child type decoration. +#define TYPE(Class, Base) +#define LEAF_TYPE(Class) \ +template <> inline const Class##Type *Type::getAs() const { \ + return dyn_cast<Class##Type>(CanonicalType); \ +} \ +template <> inline const Class##Type *Type::castAs() const { \ + return cast<Class##Type>(CanonicalType); \ +} +#include "clang/AST/TypeNodes.def" + + +/// This class is used for builtin types like 'int'. Builtin +/// types are always canonical and have a literal name field. +class BuiltinType : public Type { +public: + enum Kind { +#define BUILTIN_TYPE(Id, SingletonId) Id, +#define LAST_BUILTIN_TYPE(Id) LastKind = Id +#include "clang/AST/BuiltinTypes.def" + }; + +public: + BuiltinType(Kind K) + : Type(Builtin, QualType(), /*Dependent=*/(K == Dependent), + /*InstantiationDependent=*/(K == Dependent), + /*VariablyModified=*/false, + /*Unexpanded paramter pack=*/false) { + BuiltinTypeBits.Kind = K; + } + + Kind getKind() const { return static_cast<Kind>(BuiltinTypeBits.Kind); } + StringRef getName(const PrintingPolicy &Policy) const; + const char *getNameAsCString(const PrintingPolicy &Policy) const { + // The StringRef is null-terminated. + StringRef str = getName(Policy); + assert(!str.empty() && str.data()[str.size()] == '\0'); + return str.data(); + } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + bool isInteger() const { + return getKind() >= Bool && getKind() <= Int128; + } + + bool isSignedInteger() const { + return getKind() >= Char_S && getKind() <= Int128; + } + + bool isUnsignedInteger() const { + return getKind() >= Bool && getKind() <= UInt128; + } + + bool isFloatingPoint() const { + return getKind() >= Half && getKind() <= LongDouble; + } + + /// Determines whether the given kind corresponds to a placeholder type. + static bool isPlaceholderTypeKind(Kind K) { + return K >= Overload; + } + + /// Determines whether this type is a placeholder type, i.e. a type + /// which cannot appear in arbitrary positions in a fully-formed + /// expression. + bool isPlaceholderType() const { + return isPlaceholderTypeKind(getKind()); + } + + /// Determines whether this type is a placeholder type other than + /// Overload. Most placeholder types require only syntactic + /// information about their context in order to be resolved (e.g. + /// whether it is a call expression), which means they can (and + /// should) be resolved in an earlier "phase" of analysis. + /// Overload expressions sometimes pick up further information + /// from their context, like whether the context expects a + /// specific function-pointer type, and so frequently need + /// special treatment. + bool isNonOverloadPlaceholderType() const { + return getKind() > Overload; + } + + static bool classof(const Type *T) { return T->getTypeClass() == Builtin; } +}; + +/// Complex values, per C99 6.2.5p11. This supports the C99 complex +/// types (_Complex float etc) as well as the GCC integer complex extensions. +/// +class ComplexType : public Type, public llvm::FoldingSetNode { + QualType ElementType; + ComplexType(QualType Element, QualType CanonicalPtr) : + Type(Complex, CanonicalPtr, Element->isDependentType(), + Element->isInstantiationDependentType(), + Element->isVariablyModifiedType(), + Element->containsUnexpandedParameterPack()), + ElementType(Element) { + } + friend class ASTContext; // ASTContext creates these. + +public: + QualType getElementType() const { return ElementType; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getElementType()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType Element) { + ID.AddPointer(Element.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { return T->getTypeClass() == Complex; } +}; + +/// Sugar for parentheses used when specifying types. +/// +class ParenType : public Type, public llvm::FoldingSetNode { + QualType Inner; + + ParenType(QualType InnerType, QualType CanonType) : + Type(Paren, CanonType, InnerType->isDependentType(), + InnerType->isInstantiationDependentType(), + InnerType->isVariablyModifiedType(), + InnerType->containsUnexpandedParameterPack()), + Inner(InnerType) { + } + friend class ASTContext; // ASTContext creates these. + +public: + + QualType getInnerType() const { return Inner; } + + bool isSugared() const { return true; } + QualType desugar() const { return getInnerType(); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getInnerType()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType Inner) { + Inner.Profile(ID); + } + + static bool classof(const Type *T) { return T->getTypeClass() == Paren; } +}; + +/// PointerType - C99 6.7.5.1 - Pointer Declarators. +/// +class PointerType : public Type, public llvm::FoldingSetNode { + QualType PointeeType; + + PointerType(QualType Pointee, QualType CanonicalPtr) : + Type(Pointer, CanonicalPtr, Pointee->isDependentType(), + Pointee->isInstantiationDependentType(), + Pointee->isVariablyModifiedType(), + Pointee->containsUnexpandedParameterPack()), + PointeeType(Pointee) { + } + friend class ASTContext; // ASTContext creates these. + +public: + + QualType getPointeeType() const { return PointeeType; } + + /// Returns true if address spaces of pointers overlap. + /// OpenCL v2.0 defines conversion rules for pointers to different + /// address spaces (OpenCLC v2.0 s6.5.5) and notion of overlapping + /// address spaces. + /// CL1.1 or CL1.2: + /// address spaces overlap iff they are they same. + /// CL2.0 adds: + /// __generic overlaps with any address space except for __constant. + bool isAddressSpaceOverlapping(const PointerType &other) const { + Qualifiers thisQuals = PointeeType.getQualifiers(); + Qualifiers otherQuals = other.getPointeeType().getQualifiers(); + // Address spaces overlap if at least one of them is a superset of another + return thisQuals.isAddressSpaceSupersetOf(otherQuals) || + otherQuals.isAddressSpaceSupersetOf(thisQuals); + } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getPointeeType()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee) { + ID.AddPointer(Pointee.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { return T->getTypeClass() == Pointer; } +}; + +/// Represents a type which was implicitly adjusted by the semantic +/// engine for arbitrary reasons. For example, array and function types can +/// decay, and function types can have their calling conventions adjusted. +class AdjustedType : public Type, public llvm::FoldingSetNode { + QualType OriginalTy; + QualType AdjustedTy; + +protected: + AdjustedType(TypeClass TC, QualType OriginalTy, QualType AdjustedTy, + QualType CanonicalPtr) + : Type(TC, CanonicalPtr, OriginalTy->isDependentType(), + OriginalTy->isInstantiationDependentType(), + OriginalTy->isVariablyModifiedType(), + OriginalTy->containsUnexpandedParameterPack()), + OriginalTy(OriginalTy), AdjustedTy(AdjustedTy) {} + + friend class ASTContext; // ASTContext creates these. + +public: + QualType getOriginalType() const { return OriginalTy; } + QualType getAdjustedType() const { return AdjustedTy; } + + bool isSugared() const { return true; } + QualType desugar() const { return AdjustedTy; } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, OriginalTy, AdjustedTy); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType Orig, QualType New) { + ID.AddPointer(Orig.getAsOpaquePtr()); + ID.AddPointer(New.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == Adjusted || T->getTypeClass() == Decayed; + } +}; + +/// Represents a pointer type decayed from an array or function type. +class DecayedType : public AdjustedType { + + DecayedType(QualType OriginalType, QualType DecayedPtr, QualType CanonicalPtr) + : AdjustedType(Decayed, OriginalType, DecayedPtr, CanonicalPtr) { + assert(isa<PointerType>(getAdjustedType())); + } + + friend class ASTContext; // ASTContext creates these. + +public: + QualType getDecayedType() const { return getAdjustedType(); } + + QualType getPointeeType() const { + return cast<PointerType>(getDecayedType())->getPointeeType(); + } + + static bool classof(const Type *T) { return T->getTypeClass() == Decayed; } +}; + +/// Pointer to a block type. +/// This type is to represent types syntactically represented as +/// "void (^)(int)", etc. Pointee is required to always be a function type. +/// +class BlockPointerType : public Type, public llvm::FoldingSetNode { + QualType PointeeType; // Block is some kind of pointer type + BlockPointerType(QualType Pointee, QualType CanonicalCls) : + Type(BlockPointer, CanonicalCls, Pointee->isDependentType(), + Pointee->isInstantiationDependentType(), + Pointee->isVariablyModifiedType(), + Pointee->containsUnexpandedParameterPack()), + PointeeType(Pointee) { + } + friend class ASTContext; // ASTContext creates these. + +public: + + // Get the pointee type. Pointee is required to always be a function type. + QualType getPointeeType() const { return PointeeType; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getPointeeType()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee) { + ID.AddPointer(Pointee.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == BlockPointer; + } +}; + +/// Base for LValueReferenceType and RValueReferenceType +/// +class ReferenceType : public Type, public llvm::FoldingSetNode { + QualType PointeeType; + +protected: + ReferenceType(TypeClass tc, QualType Referencee, QualType CanonicalRef, + bool SpelledAsLValue) : + Type(tc, CanonicalRef, Referencee->isDependentType(), + Referencee->isInstantiationDependentType(), + Referencee->isVariablyModifiedType(), + Referencee->containsUnexpandedParameterPack()), + PointeeType(Referencee) + { + ReferenceTypeBits.SpelledAsLValue = SpelledAsLValue; + ReferenceTypeBits.InnerRef = Referencee->isReferenceType(); + } + +public: + bool isSpelledAsLValue() const { return ReferenceTypeBits.SpelledAsLValue; } + bool isInnerRef() const { return ReferenceTypeBits.InnerRef; } + + QualType getPointeeTypeAsWritten() const { return PointeeType; } + QualType getPointeeType() const { + // FIXME: this might strip inner qualifiers; okay? + const ReferenceType *T = this; + while (T->isInnerRef()) + T = T->PointeeType->castAs<ReferenceType>(); + return T->PointeeType; + } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, PointeeType, isSpelledAsLValue()); + } + static void Profile(llvm::FoldingSetNodeID &ID, + QualType Referencee, + bool SpelledAsLValue) { + ID.AddPointer(Referencee.getAsOpaquePtr()); + ID.AddBoolean(SpelledAsLValue); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == LValueReference || + T->getTypeClass() == RValueReference; + } +}; + +/// An lvalue reference type, per C++11 [dcl.ref]. +/// +class LValueReferenceType : public ReferenceType { + LValueReferenceType(QualType Referencee, QualType CanonicalRef, + bool SpelledAsLValue) : + ReferenceType(LValueReference, Referencee, CanonicalRef, SpelledAsLValue) + {} + friend class ASTContext; // ASTContext creates these +public: + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == LValueReference; + } +}; + +/// An rvalue reference type, per C++11 [dcl.ref]. +/// +class RValueReferenceType : public ReferenceType { + RValueReferenceType(QualType Referencee, QualType CanonicalRef) : + ReferenceType(RValueReference, Referencee, CanonicalRef, false) { + } + friend class ASTContext; // ASTContext creates these +public: + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == RValueReference; + } +}; + +/// A pointer to member type per C++ 8.3.3 - Pointers to members. +/// +/// This includes both pointers to data members and pointer to member functions. +/// +class MemberPointerType : public Type, public llvm::FoldingSetNode { + QualType PointeeType; + /// The class of which the pointee is a member. Must ultimately be a + /// RecordType, but could be a typedef or a template parameter too. + const Type *Class; + + MemberPointerType(QualType Pointee, const Type *Cls, QualType CanonicalPtr) : + Type(MemberPointer, CanonicalPtr, + Cls->isDependentType() || Pointee->isDependentType(), + (Cls->isInstantiationDependentType() || + Pointee->isInstantiationDependentType()), + Pointee->isVariablyModifiedType(), + (Cls->containsUnexpandedParameterPack() || + Pointee->containsUnexpandedParameterPack())), + PointeeType(Pointee), Class(Cls) { + } + friend class ASTContext; // ASTContext creates these. + +public: + QualType getPointeeType() const { return PointeeType; } + + /// Returns true if the member type (i.e. the pointee type) is a + /// function type rather than a data-member type. + bool isMemberFunctionPointer() const { + return PointeeType->isFunctionProtoType(); + } + + /// Returns true if the member type (i.e. the pointee type) is a + /// data type rather than a function type. + bool isMemberDataPointer() const { + return !PointeeType->isFunctionProtoType(); + } + + const Type *getClass() const { return Class; } + CXXRecordDecl *getMostRecentCXXRecordDecl() const; + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getPointeeType(), getClass()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee, + const Type *Class) { + ID.AddPointer(Pointee.getAsOpaquePtr()); + ID.AddPointer(Class); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == MemberPointer; + } +}; + +/// Represents an array type, per C99 6.7.5.2 - Array Declarators. +/// +class ArrayType : public Type, public llvm::FoldingSetNode { +public: + /// Capture whether this is a normal array (e.g. int X[4]) + /// an array with a static size (e.g. int X[static 4]), or an array + /// with a star size (e.g. int X[*]). + /// 'static' is only allowed on function parameters. + enum ArraySizeModifier { + Normal, Static, Star + }; +private: + /// The element type of the array. + QualType ElementType; + +protected: + // C++ [temp.dep.type]p1: + // A type is dependent if it is... + // - an array type constructed from any dependent type or whose + // size is specified by a constant expression that is + // value-dependent, + ArrayType(TypeClass tc, QualType et, QualType can, + ArraySizeModifier sm, unsigned tq, + bool ContainsUnexpandedParameterPack) + : Type(tc, can, et->isDependentType() || tc == DependentSizedArray, + et->isInstantiationDependentType() || tc == DependentSizedArray, + (tc == VariableArray || et->isVariablyModifiedType()), + ContainsUnexpandedParameterPack), + ElementType(et) { + ArrayTypeBits.IndexTypeQuals = tq; + ArrayTypeBits.SizeModifier = sm; + } + + friend class ASTContext; // ASTContext creates these. + +public: + QualType getElementType() const { return ElementType; } + ArraySizeModifier getSizeModifier() const { + return ArraySizeModifier(ArrayTypeBits.SizeModifier); + } + Qualifiers getIndexTypeQualifiers() const { + return Qualifiers::fromCVRMask(getIndexTypeCVRQualifiers()); + } + unsigned getIndexTypeCVRQualifiers() const { + return ArrayTypeBits.IndexTypeQuals; + } + + static bool classof(const Type *T) { + return T->getTypeClass() == ConstantArray || + T->getTypeClass() == VariableArray || + T->getTypeClass() == IncompleteArray || + T->getTypeClass() == DependentSizedArray; + } +}; + +/// Represents the canonical version of C arrays with a specified constant size. +/// For example, the canonical type for 'int A[4 + 4*100]' is a +/// ConstantArrayType where the element type is 'int' and the size is 404. +class ConstantArrayType : public ArrayType { + llvm::APInt Size; // Allows us to unique the type. + + ConstantArrayType(QualType et, QualType can, const llvm::APInt &size, + ArraySizeModifier sm, unsigned tq) + : ArrayType(ConstantArray, et, can, sm, tq, + et->containsUnexpandedParameterPack()), + Size(size) {} +protected: + ConstantArrayType(TypeClass tc, QualType et, QualType can, + const llvm::APInt &size, ArraySizeModifier sm, unsigned tq) + : ArrayType(tc, et, can, sm, tq, et->containsUnexpandedParameterPack()), + Size(size) {} + friend class ASTContext; // ASTContext creates these. +public: + const llvm::APInt &getSize() const { return Size; } + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + + /// \brief Determine the number of bits required to address a member of + // an array with the given element type and number of elements. + static unsigned getNumAddressingBits(ASTContext &Context, + QualType ElementType, + const llvm::APInt &NumElements); + + /// \brief Determine the maximum number of active bits that an array's size + /// can require, which limits the maximum size of the array. + static unsigned getMaxSizeBits(ASTContext &Context); + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getElementType(), getSize(), + getSizeModifier(), getIndexTypeCVRQualifiers()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType ET, + const llvm::APInt &ArraySize, ArraySizeModifier SizeMod, + unsigned TypeQuals) { + ID.AddPointer(ET.getAsOpaquePtr()); + ID.AddInteger(ArraySize.getZExtValue()); + ID.AddInteger(SizeMod); + ID.AddInteger(TypeQuals); + } + static bool classof(const Type *T) { + return T->getTypeClass() == ConstantArray; + } +}; + +/// Represents a C array with an unspecified size. For example 'int A[]' has +/// an IncompleteArrayType where the element type is 'int' and the size is +/// unspecified. +class IncompleteArrayType : public ArrayType { + + IncompleteArrayType(QualType et, QualType can, + ArraySizeModifier sm, unsigned tq) + : ArrayType(IncompleteArray, et, can, sm, tq, + et->containsUnexpandedParameterPack()) {} + friend class ASTContext; // ASTContext creates these. +public: + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == IncompleteArray; + } + + friend class StmtIteratorBase; + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getElementType(), getSizeModifier(), + getIndexTypeCVRQualifiers()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, QualType ET, + ArraySizeModifier SizeMod, unsigned TypeQuals) { + ID.AddPointer(ET.getAsOpaquePtr()); + ID.AddInteger(SizeMod); + ID.AddInteger(TypeQuals); + } +}; + +/// Represents a C array with a specified size that is not an +/// integer-constant-expression. For example, 'int s[x+foo()]'. +/// Since the size expression is an arbitrary expression, we store it as such. +/// +/// Note: VariableArrayType's aren't uniqued (since the expressions aren't) and +/// should not be: two lexically equivalent variable array types could mean +/// different things, for example, these variables do not have the same type +/// dynamically: +/// +/// void foo(int x) { +/// int Y[x]; +/// ++x; +/// int Z[x]; +/// } +/// +class VariableArrayType : public ArrayType { + /// An assignment-expression. VLA's are only permitted within + /// a function block. + Stmt *SizeExpr; + /// The range spanned by the left and right array brackets. + SourceRange Brackets; + + VariableArrayType(QualType et, QualType can, Expr *e, + ArraySizeModifier sm, unsigned tq, + SourceRange brackets) + : ArrayType(VariableArray, et, can, sm, tq, + et->containsUnexpandedParameterPack()), + SizeExpr((Stmt*) e), Brackets(brackets) {} + friend class ASTContext; // ASTContext creates these. + +public: + Expr *getSizeExpr() const { + // We use C-style casts instead of cast<> here because we do not wish + // to have a dependency of Type.h on Stmt.h/Expr.h. + return (Expr*) SizeExpr; + } + SourceRange getBracketsRange() const { return Brackets; } + SourceLocation getLBracketLoc() const { return Brackets.getBegin(); } + SourceLocation getRBracketLoc() const { return Brackets.getEnd(); } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == VariableArray; + } + + friend class StmtIteratorBase; + + void Profile(llvm::FoldingSetNodeID &ID) { + llvm_unreachable("Cannot unique VariableArrayTypes."); + } +}; + +/// Represents an array type in C++ whose size is a value-dependent expression. +/// +/// For example: +/// \code +/// template<typename T, int Size> +/// class array { +/// T data[Size]; +/// }; +/// \endcode +/// +/// For these types, we won't actually know what the array bound is +/// until template instantiation occurs, at which point this will +/// become either a ConstantArrayType or a VariableArrayType. +class DependentSizedArrayType : public ArrayType { + const ASTContext &Context; + + /// \brief An assignment expression that will instantiate to the + /// size of the array. + /// + /// The expression itself might be null, in which case the array + /// type will have its size deduced from an initializer. + Stmt *SizeExpr; + + /// The range spanned by the left and right array brackets. + SourceRange Brackets; + + DependentSizedArrayType(const ASTContext &Context, QualType et, QualType can, + Expr *e, ArraySizeModifier sm, unsigned tq, + SourceRange brackets); + + friend class ASTContext; // ASTContext creates these. + +public: + Expr *getSizeExpr() const { + // We use C-style casts instead of cast<> here because we do not wish + // to have a dependency of Type.h on Stmt.h/Expr.h. + return (Expr*) SizeExpr; + } + SourceRange getBracketsRange() const { return Brackets; } + SourceLocation getLBracketLoc() const { return Brackets.getBegin(); } + SourceLocation getRBracketLoc() const { return Brackets.getEnd(); } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == DependentSizedArray; + } + + friend class StmtIteratorBase; + + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, Context, getElementType(), + getSizeModifier(), getIndexTypeCVRQualifiers(), getSizeExpr()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, + QualType ET, ArraySizeModifier SizeMod, + unsigned TypeQuals, Expr *E); +}; + +/// Represents an extended vector type where either the type or size is +/// dependent. +/// +/// For example: +/// \code +/// template<typename T, int Size> +/// class vector { +/// typedef T __attribute__((ext_vector_type(Size))) type; +/// } +/// \endcode +class DependentSizedExtVectorType : public Type, public llvm::FoldingSetNode { + const ASTContext &Context; + Expr *SizeExpr; + /// The element type of the array. + QualType ElementType; + SourceLocation loc; + + DependentSizedExtVectorType(const ASTContext &Context, QualType ElementType, + QualType can, Expr *SizeExpr, SourceLocation loc); + + friend class ASTContext; + +public: + Expr *getSizeExpr() const { return SizeExpr; } + QualType getElementType() const { return ElementType; } + SourceLocation getAttributeLoc() const { return loc; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == DependentSizedExtVector; + } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, Context, getElementType(), getSizeExpr()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, + QualType ElementType, Expr *SizeExpr); +}; + + +/// Represents a GCC generic vector type. This type is created using +/// __attribute__((vector_size(n)), where "n" specifies the vector size in +/// bytes; or from an Altivec __vector or vector declaration. +/// Since the constructor takes the number of vector elements, the +/// client is responsible for converting the size into the number of elements. +class VectorType : public Type, public llvm::FoldingSetNode { +public: + enum VectorKind { + GenericVector, ///< not a target-specific vector type + AltiVecVector, ///< is AltiVec vector + AltiVecPixel, ///< is AltiVec 'vector Pixel' + AltiVecBool, ///< is AltiVec 'vector bool ...' + NeonVector, ///< is ARM Neon vector + NeonPolyVector ///< is ARM Neon polynomial vector + }; +protected: + /// The element type of the vector. + QualType ElementType; + + VectorType(QualType vecType, unsigned nElements, QualType canonType, + VectorKind vecKind); + + VectorType(TypeClass tc, QualType vecType, unsigned nElements, + QualType canonType, VectorKind vecKind); + + friend class ASTContext; // ASTContext creates these. + +public: + + QualType getElementType() const { return ElementType; } + unsigned getNumElements() const { return VectorTypeBits.NumElements; } + static bool isVectorSizeTooLarge(unsigned NumElements) { + return NumElements > VectorTypeBitfields::MaxNumElements; + } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + VectorKind getVectorKind() const { + return VectorKind(VectorTypeBits.VecKind); + } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getElementType(), getNumElements(), + getTypeClass(), getVectorKind()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType ElementType, + unsigned NumElements, TypeClass TypeClass, + VectorKind VecKind) { + ID.AddPointer(ElementType.getAsOpaquePtr()); + ID.AddInteger(NumElements); + ID.AddInteger(TypeClass); + ID.AddInteger(VecKind); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == Vector || T->getTypeClass() == ExtVector; + } +}; + +/// ExtVectorType - Extended vector type. This type is created using +/// __attribute__((ext_vector_type(n)), where "n" is the number of elements. +/// Unlike vector_size, ext_vector_type is only allowed on typedef's. This +/// class enables syntactic extensions, like Vector Components for accessing +/// points, colors, and textures (modeled after OpenGL Shading Language). +class ExtVectorType : public VectorType { + ExtVectorType(QualType vecType, unsigned nElements, QualType canonType) : + VectorType(ExtVector, vecType, nElements, canonType, GenericVector) {} + friend class ASTContext; // ASTContext creates these. +public: + static int getPointAccessorIdx(char c) { + switch (c) { + default: return -1; + case 'x': return 0; + case 'y': return 1; + case 'z': return 2; + case 'w': return 3; + } + } + static int getNumericAccessorIdx(char c) { + switch (c) { + default: return -1; + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 9; + case 'A': + case 'a': return 10; + case 'B': + case 'b': return 11; + case 'C': + case 'c': return 12; + case 'D': + case 'd': return 13; + case 'E': + case 'e': return 14; + case 'F': + case 'f': return 15; + } + } + + static int getAccessorIdx(char c) { + if (int idx = getPointAccessorIdx(c)+1) return idx-1; + return getNumericAccessorIdx(c); + } + + bool isAccessorWithinNumElements(char c) const { + if (int idx = getAccessorIdx(c)+1) + return unsigned(idx-1) < getNumElements(); + return false; + } + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == ExtVector; + } +}; + +/// FunctionType - C99 6.7.5.3 - Function Declarators. This is the common base +/// class of FunctionNoProtoType and FunctionProtoType. +/// +class FunctionType : public Type { + // The type returned by the function. + QualType ResultType; + + public: + /// A class which abstracts out some details necessary for + /// making a call. + /// + /// It is not actually used directly for storing this information in + /// a FunctionType, although FunctionType does currently use the + /// same bit-pattern. + /// + // If you add a field (say Foo), other than the obvious places (both, + // constructors, compile failures), what you need to update is + // * Operator== + // * getFoo + // * withFoo + // * functionType. Add Foo, getFoo. + // * ASTContext::getFooType + // * ASTContext::mergeFunctionTypes + // * FunctionNoProtoType::Profile + // * FunctionProtoType::Profile + // * TypePrinter::PrintFunctionProto + // * AST read and write + // * Codegen + class ExtInfo { + // Feel free to rearrange or add bits, but if you go over 9, + // you'll need to adjust both the Bits field below and + // Type::FunctionTypeBitfields. + + // | CC |noreturn|produces|regparm| + // |0 .. 3| 4 | 5 | 6 .. 8| + // + // regparm is either 0 (no regparm attribute) or the regparm value+1. + enum { CallConvMask = 0xF }; + enum { NoReturnMask = 0x10 }; + enum { ProducesResultMask = 0x20 }; + enum { RegParmMask = ~(CallConvMask | NoReturnMask | ProducesResultMask), + RegParmOffset = 6 }; // Assumed to be the last field + + uint16_t Bits; + + ExtInfo(unsigned Bits) : Bits(static_cast<uint16_t>(Bits)) {} + + friend class FunctionType; + + public: + // Constructor with no defaults. Use this when you know that you + // have all the elements (when reading an AST file for example). + ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc, + bool producesResult) { + assert((!hasRegParm || regParm < 7) && "Invalid regparm value"); + Bits = ((unsigned) cc) | + (noReturn ? NoReturnMask : 0) | + (producesResult ? ProducesResultMask : 0) | + (hasRegParm ? ((regParm + 1) << RegParmOffset) : 0); + } + + // Constructor with all defaults. Use when for example creating a + // function known to use defaults. + ExtInfo() : Bits(CC_C) { } + + // Constructor with just the calling convention, which is an important part + // of the canonical type. + ExtInfo(CallingConv CC) : Bits(CC) { } + + bool getNoReturn() const { return Bits & NoReturnMask; } + bool getProducesResult() const { return Bits & ProducesResultMask; } + bool getHasRegParm() const { return (Bits >> RegParmOffset) != 0; } + unsigned getRegParm() const { + unsigned RegParm = Bits >> RegParmOffset; + if (RegParm > 0) + --RegParm; + return RegParm; + } + CallingConv getCC() const { return CallingConv(Bits & CallConvMask); } + + bool operator==(ExtInfo Other) const { + return Bits == Other.Bits; + } + bool operator!=(ExtInfo Other) const { + return Bits != Other.Bits; + } + + // Note that we don't have setters. That is by design, use + // the following with methods instead of mutating these objects. + + ExtInfo withNoReturn(bool noReturn) const { + if (noReturn) + return ExtInfo(Bits | NoReturnMask); + else + return ExtInfo(Bits & ~NoReturnMask); + } + + ExtInfo withProducesResult(bool producesResult) const { + if (producesResult) + return ExtInfo(Bits | ProducesResultMask); + else + return ExtInfo(Bits & ~ProducesResultMask); + } + + ExtInfo withRegParm(unsigned RegParm) const { + assert(RegParm < 7 && "Invalid regparm value"); + return ExtInfo((Bits & ~RegParmMask) | + ((RegParm + 1) << RegParmOffset)); + } + + ExtInfo withCallingConv(CallingConv cc) const { + return ExtInfo((Bits & ~CallConvMask) | (unsigned) cc); + } + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddInteger(Bits); + } + }; + +protected: + FunctionType(TypeClass tc, QualType res, + QualType Canonical, bool Dependent, + bool InstantiationDependent, + bool VariablyModified, bool ContainsUnexpandedParameterPack, + ExtInfo Info) + : Type(tc, Canonical, Dependent, InstantiationDependent, VariablyModified, + ContainsUnexpandedParameterPack), + ResultType(res) { + FunctionTypeBits.ExtInfo = Info.Bits; + } + unsigned getTypeQuals() const { return FunctionTypeBits.TypeQuals; } + +public: + QualType getReturnType() const { return ResultType; } + + bool getHasRegParm() const { return getExtInfo().getHasRegParm(); } + unsigned getRegParmType() const { return getExtInfo().getRegParm(); } + /// Determine whether this function type includes the GNU noreturn + /// attribute. The C++11 [[noreturn]] attribute does not affect the function + /// type. + bool getNoReturnAttr() const { return getExtInfo().getNoReturn(); } + CallingConv getCallConv() const { return getExtInfo().getCC(); } + ExtInfo getExtInfo() const { return ExtInfo(FunctionTypeBits.ExtInfo); } + bool isConst() const { return getTypeQuals() & Qualifiers::Const; } + bool isVolatile() const { return getTypeQuals() & Qualifiers::Volatile; } + bool isRestrict() const { return getTypeQuals() & Qualifiers::Restrict; } + + /// \brief Determine the type of an expression that calls a function of + /// this type. + QualType getCallResultType(ASTContext &Context) const { + return getReturnType().getNonLValueExprType(Context); + } + + static StringRef getNameForCallConv(CallingConv CC); + + static bool classof(const Type *T) { + return T->getTypeClass() == FunctionNoProto || + T->getTypeClass() == FunctionProto; + } +}; + +/// Represents a K&R-style 'int foo()' function, which has +/// no information available about its arguments. +class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode { + FunctionNoProtoType(QualType Result, QualType Canonical, ExtInfo Info) + : FunctionType(FunctionNoProto, Result, Canonical, + /*Dependent=*/false, /*InstantiationDependent=*/false, + Result->isVariablyModifiedType(), + /*ContainsUnexpandedParameterPack=*/false, Info) {} + + friend class ASTContext; // ASTContext creates these. + +public: + // No additional state past what FunctionType provides. + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getReturnType(), getExtInfo()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType ResultType, + ExtInfo Info) { + Info.Profile(ID); + ID.AddPointer(ResultType.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == FunctionNoProto; + } +}; + +/// Represents a prototype with parameter type info, e.g. +/// 'int foo(int)' or 'int foo(void)'. 'void' is represented as having no +/// parameters, not as having a single void parameter. Such a type can have an +/// exception specification, but this specification is not part of the canonical +/// type. +class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode { +public: + struct ExceptionSpecInfo { + ExceptionSpecInfo() + : Type(EST_None), NoexceptExpr(nullptr), + SourceDecl(nullptr), SourceTemplate(nullptr) {} + + ExceptionSpecInfo(ExceptionSpecificationType EST) + : Type(EST), NoexceptExpr(nullptr), SourceDecl(nullptr), + SourceTemplate(nullptr) {} + + /// The kind of exception specification this is. + ExceptionSpecificationType Type; + /// Explicitly-specified list of exception types. + ArrayRef<QualType> Exceptions; + /// Noexcept expression, if this is EST_ComputedNoexcept. + Expr *NoexceptExpr; + /// The function whose exception specification this is, for + /// EST_Unevaluated and EST_Uninstantiated. + FunctionDecl *SourceDecl; + /// The function template whose exception specification this is instantiated + /// from, for EST_Uninstantiated. + FunctionDecl *SourceTemplate; + }; + + /// Extra information about a function prototype. + struct ExtProtoInfo { + ExtProtoInfo() + : Variadic(false), HasTrailingReturn(false), TypeQuals(0), + RefQualifier(RQ_None), ConsumedParameters(nullptr) {} + + ExtProtoInfo(CallingConv CC) + : ExtInfo(CC), Variadic(false), HasTrailingReturn(false), TypeQuals(0), + RefQualifier(RQ_None), ConsumedParameters(nullptr) {} + + ExtProtoInfo withExceptionSpec(const ExceptionSpecInfo &O) { + ExtProtoInfo Result(*this); + Result.ExceptionSpec = O; + return Result; + } + + FunctionType::ExtInfo ExtInfo; + bool Variadic : 1; + bool HasTrailingReturn : 1; + unsigned char TypeQuals; + RefQualifierKind RefQualifier; + ExceptionSpecInfo ExceptionSpec; + const bool *ConsumedParameters; + }; + +private: + /// \brief Determine whether there are any argument types that + /// contain an unexpanded parameter pack. + static bool containsAnyUnexpandedParameterPack(const QualType *ArgArray, + unsigned numArgs) { + for (unsigned Idx = 0; Idx < numArgs; ++Idx) + if (ArgArray[Idx]->containsUnexpandedParameterPack()) + return true; + + return false; + } + + FunctionProtoType(QualType result, ArrayRef<QualType> params, + QualType canonical, const ExtProtoInfo &epi); + + /// The number of parameters this function has, not counting '...'. + unsigned NumParams : 15; + + /// The number of types in the exception spec, if any. + unsigned NumExceptions : 9; + + /// The type of exception specification this function has. + unsigned ExceptionSpecType : 4; + + /// Whether this function has any consumed parameters. + unsigned HasAnyConsumedParams : 1; + + /// Whether the function is variadic. + unsigned Variadic : 1; + + /// Whether this function has a trailing return type. + unsigned HasTrailingReturn : 1; + + // ParamInfo - There is an variable size array after the class in memory that + // holds the parameter types. + + // Exceptions - There is another variable size array after ArgInfo that + // holds the exception types. + + // NoexceptExpr - Instead of Exceptions, there may be a single Expr* pointing + // to the expression in the noexcept() specifier. + + // ExceptionSpecDecl, ExceptionSpecTemplate - Instead of Exceptions, there may + // be a pair of FunctionDecl* pointing to the function which should be used to + // instantiate this function type's exception specification, and the function + // from which it should be instantiated. + + // ConsumedParameters - A variable size array, following Exceptions + // and of length NumParams, holding flags indicating which parameters + // are consumed. This only appears if HasAnyConsumedParams is true. + + friend class ASTContext; // ASTContext creates these. + + const bool *getConsumedParamsBuffer() const { + assert(hasAnyConsumedParams()); + + // Find the end of the exceptions. + Expr *const *eh_end = reinterpret_cast<Expr *const *>(exception_end()); + if (getExceptionSpecType() == EST_ComputedNoexcept) + eh_end += 1; // NoexceptExpr + // The memory layout of these types isn't handled here, so + // hopefully this is never called for them? + assert(getExceptionSpecType() != EST_Uninstantiated && + getExceptionSpecType() != EST_Unevaluated); + + return reinterpret_cast<const bool*>(eh_end); + } + +public: + unsigned getNumParams() const { return NumParams; } + QualType getParamType(unsigned i) const { + assert(i < NumParams && "invalid parameter index"); + return param_type_begin()[i]; + } + ArrayRef<QualType> getParamTypes() const { + return llvm::makeArrayRef(param_type_begin(), param_type_end()); + } + + ExtProtoInfo getExtProtoInfo() const { + ExtProtoInfo EPI; + EPI.ExtInfo = getExtInfo(); + EPI.Variadic = isVariadic(); + EPI.HasTrailingReturn = hasTrailingReturn(); + EPI.ExceptionSpec.Type = getExceptionSpecType(); + EPI.TypeQuals = static_cast<unsigned char>(getTypeQuals()); + EPI.RefQualifier = getRefQualifier(); + if (EPI.ExceptionSpec.Type == EST_Dynamic) { + EPI.ExceptionSpec.Exceptions = exceptions(); + } else if (EPI.ExceptionSpec.Type == EST_ComputedNoexcept) { + EPI.ExceptionSpec.NoexceptExpr = getNoexceptExpr(); + } else if (EPI.ExceptionSpec.Type == EST_Uninstantiated) { + EPI.ExceptionSpec.SourceDecl = getExceptionSpecDecl(); + EPI.ExceptionSpec.SourceTemplate = getExceptionSpecTemplate(); + } else if (EPI.ExceptionSpec.Type == EST_Unevaluated) { + EPI.ExceptionSpec.SourceDecl = getExceptionSpecDecl(); + } + if (hasAnyConsumedParams()) + EPI.ConsumedParameters = getConsumedParamsBuffer(); + return EPI; + } + + /// Get the kind of exception specification on this function. + ExceptionSpecificationType getExceptionSpecType() const { + return static_cast<ExceptionSpecificationType>(ExceptionSpecType); + } + /// Return whether this function has any kind of exception spec. + bool hasExceptionSpec() const { + return getExceptionSpecType() != EST_None; + } + /// Return whether this function has a dynamic (throw) exception spec. + bool hasDynamicExceptionSpec() const { + return isDynamicExceptionSpec(getExceptionSpecType()); + } + /// Return whether this function has a noexcept exception spec. + bool hasNoexceptExceptionSpec() const { + return isNoexceptExceptionSpec(getExceptionSpecType()); + } + /// Return whether this function has a dependent exception spec. + bool hasDependentExceptionSpec() const; + /// Result type of getNoexceptSpec(). + enum NoexceptResult { + NR_NoNoexcept, ///< There is no noexcept specifier. + NR_BadNoexcept, ///< The noexcept specifier has a bad expression. + NR_Dependent, ///< The noexcept specifier is dependent. + NR_Throw, ///< The noexcept specifier evaluates to false. + NR_Nothrow ///< The noexcept specifier evaluates to true. + }; + /// Get the meaning of the noexcept spec on this function, if any. + NoexceptResult getNoexceptSpec(const ASTContext &Ctx) const; + unsigned getNumExceptions() const { return NumExceptions; } + QualType getExceptionType(unsigned i) const { + assert(i < NumExceptions && "Invalid exception number!"); + return exception_begin()[i]; + } + Expr *getNoexceptExpr() const { + if (getExceptionSpecType() != EST_ComputedNoexcept) + return nullptr; + // NoexceptExpr sits where the arguments end. + return *reinterpret_cast<Expr *const *>(param_type_end()); + } + /// \brief If this function type has an exception specification which hasn't + /// been determined yet (either because it has not been evaluated or because + /// it has not been instantiated), this is the function whose exception + /// specification is represented by this type. + FunctionDecl *getExceptionSpecDecl() const { + if (getExceptionSpecType() != EST_Uninstantiated && + getExceptionSpecType() != EST_Unevaluated) + return nullptr; + return reinterpret_cast<FunctionDecl *const *>(param_type_end())[0]; + } + /// \brief If this function type has an uninstantiated exception + /// specification, this is the function whose exception specification + /// should be instantiated to find the exception specification for + /// this type. + FunctionDecl *getExceptionSpecTemplate() const { + if (getExceptionSpecType() != EST_Uninstantiated) + return nullptr; + return reinterpret_cast<FunctionDecl *const *>(param_type_end())[1]; + } + /// Determine whether this function type has a non-throwing exception + /// specification. If this depends on template arguments, returns + /// \c ResultIfDependent. + bool isNothrow(const ASTContext &Ctx, bool ResultIfDependent = false) const; + + bool isVariadic() const { return Variadic; } + + /// Determines whether this function prototype contains a + /// parameter pack at the end. + /// + /// A function template whose last parameter is a parameter pack can be + /// called with an arbitrary number of arguments, much like a variadic + /// function. + bool isTemplateVariadic() const; + + bool hasTrailingReturn() const { return HasTrailingReturn; } + + unsigned getTypeQuals() const { return FunctionType::getTypeQuals(); } + + + /// Retrieve the ref-qualifier associated with this function type. + RefQualifierKind getRefQualifier() const { + return static_cast<RefQualifierKind>(FunctionTypeBits.RefQualifier); + } + + typedef const QualType *param_type_iterator; + typedef llvm::iterator_range<param_type_iterator> param_type_range; + + param_type_range param_types() const { + return param_type_range(param_type_begin(), param_type_end()); + } + param_type_iterator param_type_begin() const { + return reinterpret_cast<const QualType *>(this+1); + } + param_type_iterator param_type_end() const { + return param_type_begin() + NumParams; + } + + typedef const QualType *exception_iterator; + + ArrayRef<QualType> exceptions() const { + return llvm::makeArrayRef(exception_begin(), exception_end()); + } + exception_iterator exception_begin() const { + // exceptions begin where arguments end + return param_type_end(); + } + exception_iterator exception_end() const { + if (getExceptionSpecType() != EST_Dynamic) + return exception_begin(); + return exception_begin() + NumExceptions; + } + + bool hasAnyConsumedParams() const { return HasAnyConsumedParams; } + bool isParamConsumed(unsigned I) const { + assert(I < getNumParams() && "parameter index out of range"); + if (hasAnyConsumedParams()) + return getConsumedParamsBuffer()[I]; + return false; + } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void printExceptionSpecification(raw_ostream &OS, + const PrintingPolicy &Policy) const; + + static bool classof(const Type *T) { + return T->getTypeClass() == FunctionProto; + } + + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx); + static void Profile(llvm::FoldingSetNodeID &ID, QualType Result, + param_type_iterator ArgTys, unsigned NumArgs, + const ExtProtoInfo &EPI, const ASTContext &Context); +}; + +/// \brief Represents the dependent type named by a dependently-scoped +/// typename using declaration, e.g. +/// using typename Base<T>::foo; +/// +/// Template instantiation turns these into the underlying type. +class UnresolvedUsingType : public Type { + UnresolvedUsingTypenameDecl *Decl; + + UnresolvedUsingType(const UnresolvedUsingTypenameDecl *D) + : Type(UnresolvedUsing, QualType(), true, true, false, + /*ContainsUnexpandedParameterPack=*/false), + Decl(const_cast<UnresolvedUsingTypenameDecl*>(D)) {} + friend class ASTContext; // ASTContext creates these. +public: + + UnresolvedUsingTypenameDecl *getDecl() const { return Decl; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == UnresolvedUsing; + } + + void Profile(llvm::FoldingSetNodeID &ID) { + return Profile(ID, Decl); + } + static void Profile(llvm::FoldingSetNodeID &ID, + UnresolvedUsingTypenameDecl *D) { + ID.AddPointer(D); + } +}; + + +class TypedefType : public Type { + TypedefNameDecl *Decl; +protected: + TypedefType(TypeClass tc, const TypedefNameDecl *D, QualType can) + : Type(tc, can, can->isDependentType(), + can->isInstantiationDependentType(), + can->isVariablyModifiedType(), + /*ContainsUnexpandedParameterPack=*/false), + Decl(const_cast<TypedefNameDecl*>(D)) { + assert(!isa<TypedefType>(can) && "Invalid canonical type"); + } + friend class ASTContext; // ASTContext creates these. +public: + + TypedefNameDecl *getDecl() const { return Decl; } + + bool isSugared() const { return true; } + QualType desugar() const; + + static bool classof(const Type *T) { return T->getTypeClass() == Typedef; } +}; + +/// Represents a `typeof` (or __typeof__) expression (a GCC extension). +class TypeOfExprType : public Type { + Expr *TOExpr; + +protected: + TypeOfExprType(Expr *E, QualType can = QualType()); + friend class ASTContext; // ASTContext creates these. +public: + Expr *getUnderlyingExpr() const { return TOExpr; } + + /// \brief Remove a single level of sugar. + QualType desugar() const; + + /// \brief Returns whether this type directly provides sugar. + bool isSugared() const; + + static bool classof(const Type *T) { return T->getTypeClass() == TypeOfExpr; } +}; + +/// \brief Internal representation of canonical, dependent +/// `typeof(expr)` types. +/// +/// This class is used internally by the ASTContext to manage +/// canonical, dependent types, only. Clients will only see instances +/// of this class via TypeOfExprType nodes. +class DependentTypeOfExprType + : public TypeOfExprType, public llvm::FoldingSetNode { + const ASTContext &Context; + +public: + DependentTypeOfExprType(const ASTContext &Context, Expr *E) + : TypeOfExprType(E), Context(Context) { } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, Context, getUnderlyingExpr()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, + Expr *E); +}; + +/// Represents `typeof(type)`, a GCC extension. +class TypeOfType : public Type { + QualType TOType; + TypeOfType(QualType T, QualType can) + : Type(TypeOf, can, T->isDependentType(), + T->isInstantiationDependentType(), + T->isVariablyModifiedType(), + T->containsUnexpandedParameterPack()), + TOType(T) { + assert(!isa<TypedefType>(can) && "Invalid canonical type"); + } + friend class ASTContext; // ASTContext creates these. +public: + QualType getUnderlyingType() const { return TOType; } + + /// \brief Remove a single level of sugar. + QualType desugar() const { return getUnderlyingType(); } + + /// \brief Returns whether this type directly provides sugar. + bool isSugared() const { return true; } + + static bool classof(const Type *T) { return T->getTypeClass() == TypeOf; } +}; + +/// Represents the type `decltype(expr)` (C++11). +class DecltypeType : public Type { + Expr *E; + QualType UnderlyingType; + +protected: + DecltypeType(Expr *E, QualType underlyingType, QualType can = QualType()); + friend class ASTContext; // ASTContext creates these. +public: + Expr *getUnderlyingExpr() const { return E; } + QualType getUnderlyingType() const { return UnderlyingType; } + + /// \brief Remove a single level of sugar. + QualType desugar() const; + + /// \brief Returns whether this type directly provides sugar. + bool isSugared() const; + + static bool classof(const Type *T) { return T->getTypeClass() == Decltype; } +}; + +/// \brief Internal representation of canonical, dependent +/// decltype(expr) types. +/// +/// This class is used internally by the ASTContext to manage +/// canonical, dependent types, only. Clients will only see instances +/// of this class via DecltypeType nodes. +class DependentDecltypeType : public DecltypeType, public llvm::FoldingSetNode { + const ASTContext &Context; + +public: + DependentDecltypeType(const ASTContext &Context, Expr *E); + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, Context, getUnderlyingExpr()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, + Expr *E); +}; + +/// A unary type transform, which is a type constructed from another. +class UnaryTransformType : public Type { +public: + enum UTTKind { + EnumUnderlyingType + }; + +private: + /// The untransformed type. + QualType BaseType; + /// The transformed type if not dependent, otherwise the same as BaseType. + QualType UnderlyingType; + + UTTKind UKind; +protected: + UnaryTransformType(QualType BaseTy, QualType UnderlyingTy, UTTKind UKind, + QualType CanonicalTy); + friend class ASTContext; +public: + bool isSugared() const { return !isDependentType(); } + QualType desugar() const { return UnderlyingType; } + + QualType getUnderlyingType() const { return UnderlyingType; } + QualType getBaseType() const { return BaseType; } + + UTTKind getUTTKind() const { return UKind; } + + static bool classof(const Type *T) { + return T->getTypeClass() == UnaryTransform; + } +}; + +class TagType : public Type { + /// Stores the TagDecl associated with this type. The decl may point to any + /// TagDecl that declares the entity. + TagDecl * decl; + + friend class ASTReader; + +protected: + TagType(TypeClass TC, const TagDecl *D, QualType can); + +public: + TagDecl *getDecl() const; + + /// Determines whether this type is in the process of being defined. + bool isBeingDefined() const; + + static bool classof(const Type *T) { + return T->getTypeClass() >= TagFirst && T->getTypeClass() <= TagLast; + } +}; + +/// A helper class that allows the use of isa/cast/dyncast +/// to detect TagType objects of structs/unions/classes. +class RecordType : public TagType { +protected: + explicit RecordType(const RecordDecl *D) + : TagType(Record, reinterpret_cast<const TagDecl*>(D), QualType()) { } + explicit RecordType(TypeClass TC, RecordDecl *D) + : TagType(TC, reinterpret_cast<const TagDecl*>(D), QualType()) { } + friend class ASTContext; // ASTContext creates these. +public: + + RecordDecl *getDecl() const { + return reinterpret_cast<RecordDecl*>(TagType::getDecl()); + } + + // FIXME: This predicate is a helper to QualType/Type. It needs to + // recursively check all fields for const-ness. If any field is declared + // const, it needs to return false. + bool hasConstFields() const { return false; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { return T->getTypeClass() == Record; } +}; + +/// A helper class that allows the use of isa/cast/dyncast +/// to detect TagType objects of enums. +class EnumType : public TagType { + explicit EnumType(const EnumDecl *D) + : TagType(Enum, reinterpret_cast<const TagDecl*>(D), QualType()) { } + friend class ASTContext; // ASTContext creates these. +public: + + EnumDecl *getDecl() const { + return reinterpret_cast<EnumDecl*>(TagType::getDecl()); + } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { return T->getTypeClass() == Enum; } +}; + +/// An attributed type is a type to which a type attribute has been applied. +/// +/// The "modified type" is the fully-sugared type to which the attributed +/// type was applied; generally it is not canonically equivalent to the +/// attributed type. The "equivalent type" is the minimally-desugared type +/// which the type is canonically equivalent to. +/// +/// For example, in the following attributed type: +/// int32_t __attribute__((vector_size(16))) +/// - the modified type is the TypedefType for int32_t +/// - the equivalent type is VectorType(16, int32_t) +/// - the canonical type is VectorType(16, int) +class AttributedType : public Type, public llvm::FoldingSetNode { +public: + // It is really silly to have yet another attribute-kind enum, but + // clang::attr::Kind doesn't currently cover the pure type attrs. + enum Kind { + // Expression operand. + attr_address_space, + attr_regparm, + attr_vector_size, + attr_neon_vector_type, + attr_neon_polyvector_type, + + FirstExprOperandKind = attr_address_space, + LastExprOperandKind = attr_neon_polyvector_type, + + // Enumerated operand (string or keyword). + attr_objc_gc, + attr_objc_ownership, + attr_pcs, + attr_pcs_vfp, + + FirstEnumOperandKind = attr_objc_gc, + LastEnumOperandKind = attr_pcs_vfp, + + // No operand. + attr_noreturn, + attr_cdecl, + attr_fastcall, + attr_stdcall, + attr_thiscall, + attr_pascal, + attr_vectorcall, + attr_inteloclbicc, + attr_ms_abi, + attr_sysv_abi, + attr_ptr32, + attr_ptr64, + attr_sptr, + attr_uptr, + attr_nonnull, + attr_nullable, + attr_null_unspecified, + attr_objc_kindof, + attr_objc_inert_unsafe_unretained, + }; + +private: + QualType ModifiedType; + QualType EquivalentType; + + friend class ASTContext; // creates these + + AttributedType(QualType canon, Kind attrKind, + QualType modified, QualType equivalent) + : Type(Attributed, canon, canon->isDependentType(), + canon->isInstantiationDependentType(), + canon->isVariablyModifiedType(), + canon->containsUnexpandedParameterPack()), + ModifiedType(modified), EquivalentType(equivalent) { + AttributedTypeBits.AttrKind = attrKind; + } + +public: + Kind getAttrKind() const { + return static_cast<Kind>(AttributedTypeBits.AttrKind); + } + + QualType getModifiedType() const { return ModifiedType; } + QualType getEquivalentType() const { return EquivalentType; } + + bool isSugared() const { return true; } + QualType desugar() const { return getEquivalentType(); } + + /// Does this attribute behave like a type qualifier? + /// + /// A type qualifier adjusts a type to provide specialized rules for + /// a specific object, like the standard const and volatile qualifiers. + /// This includes attributes controlling things like nullability, + /// address spaces, and ARC ownership. The value of the object is still + /// largely described by the modified type. + /// + /// In contrast, many type attributes "rewrite" their modified type to + /// produce a fundamentally different type, not necessarily related in any + /// formalizable way to the original type. For example, calling convention + /// and vector attributes are not simple type qualifiers. + /// + /// Type qualifiers are often, but not always, reflected in the canonical + /// type. + bool isQualifier() const; + + bool isMSTypeSpec() const; + + bool isCallingConv() const; + + llvm::Optional<NullabilityKind> getImmediateNullability() const; + + /// Retrieve the attribute kind corresponding to the given + /// nullability kind. + static Kind getNullabilityAttrKind(NullabilityKind kind) { + switch (kind) { + case NullabilityKind::NonNull: + return attr_nonnull; + + case NullabilityKind::Nullable: + return attr_nullable; + + case NullabilityKind::Unspecified: + return attr_null_unspecified; + } + llvm_unreachable("Unknown nullability kind."); + } + + /// Strip off the top-level nullability annotation on the given + /// type, if it's there. + /// + /// \param T The type to strip. If the type is exactly an + /// AttributedType specifying nullability (without looking through + /// type sugar), the nullability is returned and this type changed + /// to the underlying modified type. + /// + /// \returns the top-level nullability, if present. + static Optional<NullabilityKind> stripOuterNullability(QualType &T); + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getAttrKind(), ModifiedType, EquivalentType); + } + + static void Profile(llvm::FoldingSetNodeID &ID, Kind attrKind, + QualType modified, QualType equivalent) { + ID.AddInteger(attrKind); + ID.AddPointer(modified.getAsOpaquePtr()); + ID.AddPointer(equivalent.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == Attributed; + } +}; + +class TemplateTypeParmType : public Type, public llvm::FoldingSetNode { + // Helper data collector for canonical types. + struct CanonicalTTPTInfo { + unsigned Depth : 15; + unsigned ParameterPack : 1; + unsigned Index : 16; + }; + + union { + // Info for the canonical type. + CanonicalTTPTInfo CanTTPTInfo; + // Info for the non-canonical type. + TemplateTypeParmDecl *TTPDecl; + }; + + /// Build a non-canonical type. + TemplateTypeParmType(TemplateTypeParmDecl *TTPDecl, QualType Canon) + : Type(TemplateTypeParm, Canon, /*Dependent=*/true, + /*InstantiationDependent=*/true, + /*VariablyModified=*/false, + Canon->containsUnexpandedParameterPack()), + TTPDecl(TTPDecl) { } + + /// Build the canonical type. + TemplateTypeParmType(unsigned D, unsigned I, bool PP) + : Type(TemplateTypeParm, QualType(this, 0), + /*Dependent=*/true, + /*InstantiationDependent=*/true, + /*VariablyModified=*/false, PP) { + CanTTPTInfo.Depth = D; + CanTTPTInfo.Index = I; + CanTTPTInfo.ParameterPack = PP; + } + + friend class ASTContext; // ASTContext creates these + + const CanonicalTTPTInfo& getCanTTPTInfo() const { + QualType Can = getCanonicalTypeInternal(); + return Can->castAs<TemplateTypeParmType>()->CanTTPTInfo; + } + +public: + unsigned getDepth() const { return getCanTTPTInfo().Depth; } + unsigned getIndex() const { return getCanTTPTInfo().Index; } + bool isParameterPack() const { return getCanTTPTInfo().ParameterPack; } + + TemplateTypeParmDecl *getDecl() const { + return isCanonicalUnqualified() ? nullptr : TTPDecl; + } + + IdentifierInfo *getIdentifier() const; + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getDepth(), getIndex(), isParameterPack(), getDecl()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, unsigned Depth, + unsigned Index, bool ParameterPack, + TemplateTypeParmDecl *TTPDecl) { + ID.AddInteger(Depth); + ID.AddInteger(Index); + ID.AddBoolean(ParameterPack); + ID.AddPointer(TTPDecl); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == TemplateTypeParm; + } +}; + +/// \brief Represents the result of substituting a type for a template +/// type parameter. +/// +/// Within an instantiated template, all template type parameters have +/// been replaced with these. They are used solely to record that a +/// type was originally written as a template type parameter; +/// therefore they are never canonical. +class SubstTemplateTypeParmType : public Type, public llvm::FoldingSetNode { + // The original type parameter. + const TemplateTypeParmType *Replaced; + + SubstTemplateTypeParmType(const TemplateTypeParmType *Param, QualType Canon) + : Type(SubstTemplateTypeParm, Canon, Canon->isDependentType(), + Canon->isInstantiationDependentType(), + Canon->isVariablyModifiedType(), + Canon->containsUnexpandedParameterPack()), + Replaced(Param) { } + + friend class ASTContext; + +public: + /// Gets the template parameter that was substituted for. + const TemplateTypeParmType *getReplacedParameter() const { + return Replaced; + } + + /// Gets the type that was substituted for the template + /// parameter. + QualType getReplacementType() const { + return getCanonicalTypeInternal(); + } + + bool isSugared() const { return true; } + QualType desugar() const { return getReplacementType(); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getReplacedParameter(), getReplacementType()); + } + static void Profile(llvm::FoldingSetNodeID &ID, + const TemplateTypeParmType *Replaced, + QualType Replacement) { + ID.AddPointer(Replaced); + ID.AddPointer(Replacement.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == SubstTemplateTypeParm; + } +}; + +/// \brief Represents the result of substituting a set of types for a template +/// type parameter pack. +/// +/// When a pack expansion in the source code contains multiple parameter packs +/// and those parameter packs correspond to different levels of template +/// parameter lists, this type node is used to represent a template type +/// parameter pack from an outer level, which has already had its argument pack +/// substituted but that still lives within a pack expansion that itself +/// could not be instantiated. When actually performing a substitution into +/// that pack expansion (e.g., when all template parameters have corresponding +/// arguments), this type will be replaced with the \c SubstTemplateTypeParmType +/// at the current pack substitution index. +class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode { + /// \brief The original type parameter. + const TemplateTypeParmType *Replaced; + + /// \brief A pointer to the set of template arguments that this + /// parameter pack is instantiated with. + const TemplateArgument *Arguments; + + /// \brief The number of template arguments in \c Arguments. + unsigned NumArguments; + + SubstTemplateTypeParmPackType(const TemplateTypeParmType *Param, + QualType Canon, + const TemplateArgument &ArgPack); + + friend class ASTContext; + +public: + IdentifierInfo *getIdentifier() const { return Replaced->getIdentifier(); } + + /// Gets the template parameter that was substituted for. + const TemplateTypeParmType *getReplacedParameter() const { + return Replaced; + } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + TemplateArgument getArgumentPack() const; + + void Profile(llvm::FoldingSetNodeID &ID); + static void Profile(llvm::FoldingSetNodeID &ID, + const TemplateTypeParmType *Replaced, + const TemplateArgument &ArgPack); + + static bool classof(const Type *T) { + return T->getTypeClass() == SubstTemplateTypeParmPack; + } +}; + +/// \brief Represents a C++11 auto or C++14 decltype(auto) type. +/// +/// These types are usually a placeholder for a deduced type. However, before +/// the initializer is attached, or if the initializer is type-dependent, there +/// is no deduced type and an auto type is canonical. In the latter case, it is +/// also a dependent type. +class AutoType : public Type, public llvm::FoldingSetNode { + AutoType(QualType DeducedType, AutoTypeKeyword Keyword, bool IsDependent) + : Type(Auto, DeducedType.isNull() ? QualType(this, 0) : DeducedType, + /*Dependent=*/IsDependent, /*InstantiationDependent=*/IsDependent, + /*VariablyModified=*/false, + /*ContainsParameterPack=*/DeducedType.isNull() + ? false : DeducedType->containsUnexpandedParameterPack()) { + assert((DeducedType.isNull() || !IsDependent) && + "auto deduced to dependent type"); + AutoTypeBits.Keyword = (unsigned)Keyword; + } + + friend class ASTContext; // ASTContext creates these + +public: + bool isDecltypeAuto() const { + return getKeyword() == AutoTypeKeyword::DecltypeAuto; + } + AutoTypeKeyword getKeyword() const { + return (AutoTypeKeyword)AutoTypeBits.Keyword; + } + + bool isSugared() const { return !isCanonicalUnqualified(); } + QualType desugar() const { return getCanonicalTypeInternal(); } + + /// \brief Get the type deduced for this auto type, or null if it's either + /// not been deduced or was deduced to a dependent type. + QualType getDeducedType() const { + return !isCanonicalUnqualified() ? getCanonicalTypeInternal() : QualType(); + } + bool isDeduced() const { + return !isCanonicalUnqualified() || isDependentType(); + } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getDeducedType(), getKeyword(), isDependentType()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, QualType Deduced, + AutoTypeKeyword Keyword, bool IsDependent) { + ID.AddPointer(Deduced.getAsOpaquePtr()); + ID.AddInteger((unsigned)Keyword); + ID.AddBoolean(IsDependent); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == Auto; + } +}; + +/// \brief Represents a type template specialization; the template +/// must be a class template, a type alias template, or a template +/// template parameter. A template which cannot be resolved to one of +/// these, e.g. because it is written with a dependent scope +/// specifier, is instead represented as a +/// @c DependentTemplateSpecializationType. +/// +/// A non-dependent template specialization type is always "sugar", +/// typically for a \c RecordType. For example, a class template +/// specialization type of \c vector<int> will refer to a tag type for +/// the instantiation \c std::vector<int, std::allocator<int>> +/// +/// Template specializations are dependent if either the template or +/// any of the template arguments are dependent, in which case the +/// type may also be canonical. +/// +/// Instances of this type are allocated with a trailing array of +/// TemplateArguments, followed by a QualType representing the +/// non-canonical aliased type when the template is a type alias +/// template. +class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) TemplateSpecializationType + : public Type, + public llvm::FoldingSetNode { + /// The name of the template being specialized. This is + /// either a TemplateName::Template (in which case it is a + /// ClassTemplateDecl*, a TemplateTemplateParmDecl*, or a + /// TypeAliasTemplateDecl*), a + /// TemplateName::SubstTemplateTemplateParmPack, or a + /// TemplateName::SubstTemplateTemplateParm (in which case the + /// replacement must, recursively, be one of these). + TemplateName Template; + + /// The number of template arguments named in this class template + /// specialization. + unsigned NumArgs : 31; + + /// Whether this template specialization type is a substituted type alias. + bool TypeAlias : 1; + + TemplateSpecializationType(TemplateName T, + const TemplateArgument *Args, + unsigned NumArgs, QualType Canon, + QualType Aliased); + + friend class ASTContext; // ASTContext creates these + +public: + /// Determine whether any of the given template arguments are dependent. + static bool anyDependentTemplateArguments(const TemplateArgumentLoc *Args, + unsigned NumArgs, + bool &InstantiationDependent); + + static bool anyDependentTemplateArguments(const TemplateArgumentListInfo &, + bool &InstantiationDependent); + + /// \brief Print a template argument list, including the '<' and '>' + /// enclosing the template arguments. + static void PrintTemplateArgumentList(raw_ostream &OS, + const TemplateArgument *Args, + unsigned NumArgs, + const PrintingPolicy &Policy, + bool SkipBrackets = false); + + static void PrintTemplateArgumentList(raw_ostream &OS, + const TemplateArgumentLoc *Args, + unsigned NumArgs, + const PrintingPolicy &Policy); + + static void PrintTemplateArgumentList(raw_ostream &OS, + const TemplateArgumentListInfo &, + const PrintingPolicy &Policy); + + /// True if this template specialization type matches a current + /// instantiation in the context in which it is found. + bool isCurrentInstantiation() const { + return isa<InjectedClassNameType>(getCanonicalTypeInternal()); + } + + /// \brief Determine if this template specialization type is for a type alias + /// template that has been substituted. + /// + /// Nearly every template specialization type whose template is an alias + /// template will be substituted. However, this is not the case when + /// the specialization contains a pack expansion but the template alias + /// does not have a corresponding parameter pack, e.g., + /// + /// \code + /// template<typename T, typename U, typename V> struct S; + /// template<typename T, typename U> using A = S<T, int, U>; + /// template<typename... Ts> struct X { + /// typedef A<Ts...> type; // not a type alias + /// }; + /// \endcode + bool isTypeAlias() const { return TypeAlias; } + + /// Get the aliased type, if this is a specialization of a type alias + /// template. + QualType getAliasedType() const { + assert(isTypeAlias() && "not a type alias template specialization"); + return *reinterpret_cast<const QualType*>(end()); + } + + typedef const TemplateArgument * iterator; + + iterator begin() const { return getArgs(); } + iterator end() const; // defined inline in TemplateBase.h + + /// Retrieve the name of the template that we are specializing. + TemplateName getTemplateName() const { return Template; } + + /// Retrieve the template arguments. + const TemplateArgument *getArgs() const { + return reinterpret_cast<const TemplateArgument *>(this + 1); + } + + /// Retrieve the number of template arguments. + unsigned getNumArgs() const { return NumArgs; } + + /// Retrieve a specific template argument as a type. + /// \pre \c isArgType(Arg) + const TemplateArgument &getArg(unsigned Idx) const; // in TemplateBase.h + + bool isSugared() const { + return !isDependentType() || isCurrentInstantiation() || isTypeAlias(); + } + QualType desugar() const { return getCanonicalTypeInternal(); } + + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) { + Profile(ID, Template, getArgs(), NumArgs, Ctx); + if (isTypeAlias()) + getAliasedType().Profile(ID); + } + + static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T, + const TemplateArgument *Args, + unsigned NumArgs, + const ASTContext &Context); + + static bool classof(const Type *T) { + return T->getTypeClass() == TemplateSpecialization; + } +}; + +/// The injected class name of a C++ class template or class +/// template partial specialization. Used to record that a type was +/// spelled with a bare identifier rather than as a template-id; the +/// equivalent for non-templated classes is just RecordType. +/// +/// Injected class name types are always dependent. Template +/// instantiation turns these into RecordTypes. +/// +/// Injected class name types are always canonical. This works +/// because it is impossible to compare an injected class name type +/// with the corresponding non-injected template type, for the same +/// reason that it is impossible to directly compare template +/// parameters from different dependent contexts: injected class name +/// types can only occur within the scope of a particular templated +/// declaration, and within that scope every template specialization +/// will canonicalize to the injected class name (when appropriate +/// according to the rules of the language). +class InjectedClassNameType : public Type { + CXXRecordDecl *Decl; + + /// The template specialization which this type represents. + /// For example, in + /// template <class T> class A { ... }; + /// this is A<T>, whereas in + /// template <class X, class Y> class A<B<X,Y> > { ... }; + /// this is A<B<X,Y> >. + /// + /// It is always unqualified, always a template specialization type, + /// and always dependent. + QualType InjectedType; + + friend class ASTContext; // ASTContext creates these. + friend class ASTReader; // FIXME: ASTContext::getInjectedClassNameType is not + // currently suitable for AST reading, too much + // interdependencies. + InjectedClassNameType(CXXRecordDecl *D, QualType TST) + : Type(InjectedClassName, QualType(), /*Dependent=*/true, + /*InstantiationDependent=*/true, + /*VariablyModified=*/false, + /*ContainsUnexpandedParameterPack=*/false), + Decl(D), InjectedType(TST) { + assert(isa<TemplateSpecializationType>(TST)); + assert(!TST.hasQualifiers()); + assert(TST->isDependentType()); + } + +public: + QualType getInjectedSpecializationType() const { return InjectedType; } + const TemplateSpecializationType *getInjectedTST() const { + return cast<TemplateSpecializationType>(InjectedType.getTypePtr()); + } + + CXXRecordDecl *getDecl() const; + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == InjectedClassName; + } +}; + +/// \brief The kind of a tag type. +enum TagTypeKind { + /// \brief The "struct" keyword. + TTK_Struct, + /// \brief The "__interface" keyword. + TTK_Interface, + /// \brief The "union" keyword. + TTK_Union, + /// \brief The "class" keyword. + TTK_Class, + /// \brief The "enum" keyword. + TTK_Enum +}; + +/// \brief The elaboration keyword that precedes a qualified type name or +/// introduces an elaborated-type-specifier. +enum ElaboratedTypeKeyword { + /// \brief The "struct" keyword introduces the elaborated-type-specifier. + ETK_Struct, + /// \brief The "__interface" keyword introduces the elaborated-type-specifier. + ETK_Interface, + /// \brief The "union" keyword introduces the elaborated-type-specifier. + ETK_Union, + /// \brief The "class" keyword introduces the elaborated-type-specifier. + ETK_Class, + /// \brief The "enum" keyword introduces the elaborated-type-specifier. + ETK_Enum, + /// \brief The "typename" keyword precedes the qualified type name, e.g., + /// \c typename T::type. + ETK_Typename, + /// \brief No keyword precedes the qualified type name. + ETK_None +}; + +/// A helper class for Type nodes having an ElaboratedTypeKeyword. +/// The keyword in stored in the free bits of the base class. +/// Also provides a few static helpers for converting and printing +/// elaborated type keyword and tag type kind enumerations. +class TypeWithKeyword : public Type { +protected: + TypeWithKeyword(ElaboratedTypeKeyword Keyword, TypeClass tc, + QualType Canonical, bool Dependent, + bool InstantiationDependent, bool VariablyModified, + bool ContainsUnexpandedParameterPack) + : Type(tc, Canonical, Dependent, InstantiationDependent, VariablyModified, + ContainsUnexpandedParameterPack) { + TypeWithKeywordBits.Keyword = Keyword; + } + +public: + ElaboratedTypeKeyword getKeyword() const { + return static_cast<ElaboratedTypeKeyword>(TypeWithKeywordBits.Keyword); + } + + /// Converts a type specifier (DeclSpec::TST) into an elaborated type keyword. + static ElaboratedTypeKeyword getKeywordForTypeSpec(unsigned TypeSpec); + + /// Converts a type specifier (DeclSpec::TST) into a tag type kind. + /// It is an error to provide a type specifier which *isn't* a tag kind here. + static TagTypeKind getTagTypeKindForTypeSpec(unsigned TypeSpec); + + /// Converts a TagTypeKind into an elaborated type keyword. + static ElaboratedTypeKeyword getKeywordForTagTypeKind(TagTypeKind Tag); + + /// Converts an elaborated type keyword into a TagTypeKind. + /// It is an error to provide an elaborated type keyword + /// which *isn't* a tag kind here. + static TagTypeKind getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword); + + static bool KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword); + + static StringRef getKeywordName(ElaboratedTypeKeyword Keyword); + + static StringRef getTagTypeKindName(TagTypeKind Kind) { + return getKeywordName(getKeywordForTagTypeKind(Kind)); + } + + class CannotCastToThisType {}; + static CannotCastToThisType classof(const Type *); +}; + +/// \brief Represents a type that was referred to using an elaborated type +/// keyword, e.g., struct S, or via a qualified name, e.g., N::M::type, +/// or both. +/// +/// This type is used to keep track of a type name as written in the +/// source code, including tag keywords and any nested-name-specifiers. +/// The type itself is always "sugar", used to express what was written +/// in the source code but containing no additional semantic information. +class ElaboratedType : public TypeWithKeyword, public llvm::FoldingSetNode { + + /// The nested name specifier containing the qualifier. + NestedNameSpecifier *NNS; + + /// The type that this qualified name refers to. + QualType NamedType; + + ElaboratedType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, + QualType NamedType, QualType CanonType) + : TypeWithKeyword(Keyword, Elaborated, CanonType, + NamedType->isDependentType(), + NamedType->isInstantiationDependentType(), + NamedType->isVariablyModifiedType(), + NamedType->containsUnexpandedParameterPack()), + NNS(NNS), NamedType(NamedType) { + assert(!(Keyword == ETK_None && NNS == nullptr) && + "ElaboratedType cannot have elaborated type keyword " + "and name qualifier both null."); + } + + friend class ASTContext; // ASTContext creates these + +public: + ~ElaboratedType(); + + /// Retrieve the qualification on this type. + NestedNameSpecifier *getQualifier() const { return NNS; } + + /// Retrieve the type named by the qualified-id. + QualType getNamedType() const { return NamedType; } + + /// Remove a single level of sugar. + QualType desugar() const { return getNamedType(); } + + /// Returns whether this type directly provides sugar. + bool isSugared() const { return true; } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getKeyword(), NNS, NamedType); + } + + static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, QualType NamedType) { + ID.AddInteger(Keyword); + ID.AddPointer(NNS); + NamedType.Profile(ID); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == Elaborated; + } +}; + +/// \brief Represents a qualified type name for which the type name is +/// dependent. +/// +/// DependentNameType represents a class of dependent types that involve a +/// possibly dependent nested-name-specifier (e.g., "T::") followed by a +/// name of a type. The DependentNameType may start with a "typename" (for a +/// typename-specifier), "class", "struct", "union", or "enum" (for a +/// dependent elaborated-type-specifier), or nothing (in contexts where we +/// know that we must be referring to a type, e.g., in a base class specifier). +/// Typically the nested-name-specifier is dependent, but in MSVC compatibility +/// mode, this type is used with non-dependent names to delay name lookup until +/// instantiation. +class DependentNameType : public TypeWithKeyword, public llvm::FoldingSetNode { + + /// \brief The nested name specifier containing the qualifier. + NestedNameSpecifier *NNS; + + /// \brief The type that this typename specifier refers to. + const IdentifierInfo *Name; + + DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, + const IdentifierInfo *Name, QualType CanonType) + : TypeWithKeyword(Keyword, DependentName, CanonType, /*Dependent=*/true, + /*InstantiationDependent=*/true, + /*VariablyModified=*/false, + NNS->containsUnexpandedParameterPack()), + NNS(NNS), Name(Name) {} + + friend class ASTContext; // ASTContext creates these + +public: + /// Retrieve the qualification on this type. + NestedNameSpecifier *getQualifier() const { return NNS; } + + /// Retrieve the type named by the typename specifier as an identifier. + /// + /// This routine will return a non-NULL identifier pointer when the + /// form of the original typename was terminated by an identifier, + /// e.g., "typename T::type". + const IdentifierInfo *getIdentifier() const { + return Name; + } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getKeyword(), NNS, Name); + } + + static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, const IdentifierInfo *Name) { + ID.AddInteger(Keyword); + ID.AddPointer(NNS); + ID.AddPointer(Name); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == DependentName; + } +}; + +/// Represents a template specialization type whose template cannot be +/// resolved, e.g. +/// A<T>::template B<T> +class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) DependentTemplateSpecializationType + : public TypeWithKeyword, + public llvm::FoldingSetNode { + + /// The nested name specifier containing the qualifier. + NestedNameSpecifier *NNS; + + /// The identifier of the template. + const IdentifierInfo *Name; + + /// \brief The number of template arguments named in this class template + /// specialization. + unsigned NumArgs; + + const TemplateArgument *getArgBuffer() const { + return reinterpret_cast<const TemplateArgument*>(this+1); + } + TemplateArgument *getArgBuffer() { + return reinterpret_cast<TemplateArgument*>(this+1); + } + + DependentTemplateSpecializationType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, + const IdentifierInfo *Name, + unsigned NumArgs, + const TemplateArgument *Args, + QualType Canon); + + friend class ASTContext; // ASTContext creates these + +public: + NestedNameSpecifier *getQualifier() const { return NNS; } + const IdentifierInfo *getIdentifier() const { return Name; } + + /// \brief Retrieve the template arguments. + const TemplateArgument *getArgs() const { + return getArgBuffer(); + } + + /// \brief Retrieve the number of template arguments. + unsigned getNumArgs() const { return NumArgs; } + + const TemplateArgument &getArg(unsigned Idx) const; // in TemplateBase.h + + typedef const TemplateArgument * iterator; + iterator begin() const { return getArgs(); } + iterator end() const; // inline in TemplateBase.h + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { + Profile(ID, Context, getKeyword(), NNS, Name, NumArgs, getArgs()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, + const ASTContext &Context, + ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *Qualifier, + const IdentifierInfo *Name, + unsigned NumArgs, + const TemplateArgument *Args); + + static bool classof(const Type *T) { + return T->getTypeClass() == DependentTemplateSpecialization; + } +}; + +/// \brief Represents a pack expansion of types. +/// +/// Pack expansions are part of C++11 variadic templates. A pack +/// expansion contains a pattern, which itself contains one or more +/// "unexpanded" parameter packs. When instantiated, a pack expansion +/// produces a series of types, each instantiated from the pattern of +/// the expansion, where the Ith instantiation of the pattern uses the +/// Ith arguments bound to each of the unexpanded parameter packs. The +/// pack expansion is considered to "expand" these unexpanded +/// parameter packs. +/// +/// \code +/// template<typename ...Types> struct tuple; +/// +/// template<typename ...Types> +/// struct tuple_of_references { +/// typedef tuple<Types&...> type; +/// }; +/// \endcode +/// +/// Here, the pack expansion \c Types&... is represented via a +/// PackExpansionType whose pattern is Types&. +class PackExpansionType : public Type, public llvm::FoldingSetNode { + /// \brief The pattern of the pack expansion. + QualType Pattern; + + /// \brief The number of expansions that this pack expansion will + /// generate when substituted (+1), or indicates that + /// + /// This field will only have a non-zero value when some of the parameter + /// packs that occur within the pattern have been substituted but others have + /// not. + unsigned NumExpansions; + + PackExpansionType(QualType Pattern, QualType Canon, + Optional<unsigned> NumExpansions) + : Type(PackExpansion, Canon, /*Dependent=*/Pattern->isDependentType(), + /*InstantiationDependent=*/true, + /*VariablyModified=*/Pattern->isVariablyModifiedType(), + /*ContainsUnexpandedParameterPack=*/false), + Pattern(Pattern), + NumExpansions(NumExpansions? *NumExpansions + 1: 0) { } + + friend class ASTContext; // ASTContext creates these + +public: + /// \brief Retrieve the pattern of this pack expansion, which is the + /// type that will be repeatedly instantiated when instantiating the + /// pack expansion itself. + QualType getPattern() const { return Pattern; } + + /// \brief Retrieve the number of expansions that this pack expansion will + /// generate, if known. + Optional<unsigned> getNumExpansions() const { + if (NumExpansions) + return NumExpansions - 1; + + return None; + } + + bool isSugared() const { return !Pattern->isDependentType(); } + QualType desugar() const { return isSugared() ? Pattern : QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getPattern(), getNumExpansions()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, QualType Pattern, + Optional<unsigned> NumExpansions) { + ID.AddPointer(Pattern.getAsOpaquePtr()); + ID.AddBoolean(NumExpansions.hasValue()); + if (NumExpansions) + ID.AddInteger(*NumExpansions); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == PackExpansion; + } +}; + +/// Represents a class type in Objective C. +/// +/// Every Objective C type is a combination of a base type, a set of +/// type arguments (optional, for parameterized classes) and a list of +/// protocols. +/// +/// Given the following declarations: +/// \code +/// \@class C<T>; +/// \@protocol P; +/// \endcode +/// +/// 'C' is an ObjCInterfaceType C. It is sugar for an ObjCObjectType +/// with base C and no protocols. +/// +/// 'C<P>' is an unspecialized ObjCObjectType with base C and protocol list [P]. +/// 'C<C*>' is a specialized ObjCObjectType with type arguments 'C*' and no +/// protocol list. +/// 'C<C*><P>' is a specialized ObjCObjectType with base C, type arguments 'C*', +/// and protocol list [P]. +/// +/// 'id' is a TypedefType which is sugar for an ObjCObjectPointerType whose +/// pointee is an ObjCObjectType with base BuiltinType::ObjCIdType +/// and no protocols. +/// +/// 'id<P>' is an ObjCObjectPointerType whose pointee is an ObjCObjectType +/// with base BuiltinType::ObjCIdType and protocol list [P]. Eventually +/// this should get its own sugar class to better represent the source. +class ObjCObjectType : public Type { + // ObjCObjectType.NumTypeArgs - the number of type arguments stored + // after the ObjCObjectPointerType node. + // ObjCObjectType.NumProtocols - the number of protocols stored + // after the type arguments of ObjCObjectPointerType node. + // + // These protocols are those written directly on the type. If + // protocol qualifiers ever become additive, the iterators will need + // to get kindof complicated. + // + // In the canonical object type, these are sorted alphabetically + // and uniqued. + + /// Either a BuiltinType or an InterfaceType or sugar for either. + QualType BaseType; + + /// Cached superclass type. + mutable llvm::PointerIntPair<const ObjCObjectType *, 1, bool> + CachedSuperClassType; + + ObjCProtocolDecl * const *getProtocolStorage() const { + return const_cast<ObjCObjectType*>(this)->getProtocolStorage(); + } + + QualType *getTypeArgStorage(); + const QualType *getTypeArgStorage() const { + return const_cast<ObjCObjectType *>(this)->getTypeArgStorage(); + } + + ObjCProtocolDecl **getProtocolStorage(); + +protected: + ObjCObjectType(QualType Canonical, QualType Base, + ArrayRef<QualType> typeArgs, + ArrayRef<ObjCProtocolDecl *> protocols, + bool isKindOf); + + enum Nonce_ObjCInterface { Nonce_ObjCInterface }; + ObjCObjectType(enum Nonce_ObjCInterface) + : Type(ObjCInterface, QualType(), false, false, false, false), + BaseType(QualType(this_(), 0)) { + ObjCObjectTypeBits.NumProtocols = 0; + ObjCObjectTypeBits.NumTypeArgs = 0; + ObjCObjectTypeBits.IsKindOf = 0; + } + + void computeSuperClassTypeSlow() const; + +public: + /// Gets the base type of this object type. This is always (possibly + /// sugar for) one of: + /// - the 'id' builtin type (as opposed to the 'id' type visible to the + /// user, which is a typedef for an ObjCObjectPointerType) + /// - the 'Class' builtin type (same caveat) + /// - an ObjCObjectType (currently always an ObjCInterfaceType) + QualType getBaseType() const { return BaseType; } + + bool isObjCId() const { + return getBaseType()->isSpecificBuiltinType(BuiltinType::ObjCId); + } + bool isObjCClass() const { + return getBaseType()->isSpecificBuiltinType(BuiltinType::ObjCClass); + } + bool isObjCUnqualifiedId() const { return qual_empty() && isObjCId(); } + bool isObjCUnqualifiedClass() const { return qual_empty() && isObjCClass(); } + bool isObjCUnqualifiedIdOrClass() const { + if (!qual_empty()) return false; + if (const BuiltinType *T = getBaseType()->getAs<BuiltinType>()) + return T->getKind() == BuiltinType::ObjCId || + T->getKind() == BuiltinType::ObjCClass; + return false; + } + bool isObjCQualifiedId() const { return !qual_empty() && isObjCId(); } + bool isObjCQualifiedClass() const { return !qual_empty() && isObjCClass(); } + + /// Gets the interface declaration for this object type, if the base type + /// really is an interface. + ObjCInterfaceDecl *getInterface() const; + + /// Determine whether this object type is "specialized", meaning + /// that it has type arguments. + bool isSpecialized() const; + + /// Determine whether this object type was written with type arguments. + bool isSpecializedAsWritten() const { + return ObjCObjectTypeBits.NumTypeArgs > 0; + } + + /// Determine whether this object type is "unspecialized", meaning + /// that it has no type arguments. + bool isUnspecialized() const { return !isSpecialized(); } + + /// Determine whether this object type is "unspecialized" as + /// written, meaning that it has no type arguments. + bool isUnspecializedAsWritten() const { return !isSpecializedAsWritten(); } + + /// Retrieve the type arguments of this object type (semantically). + ArrayRef<QualType> getTypeArgs() const; + + /// Retrieve the type arguments of this object type as they were + /// written. + ArrayRef<QualType> getTypeArgsAsWritten() const { + return llvm::makeArrayRef(getTypeArgStorage(), + ObjCObjectTypeBits.NumTypeArgs); + } + + typedef ObjCProtocolDecl * const *qual_iterator; + typedef llvm::iterator_range<qual_iterator> qual_range; + + qual_range quals() const { return qual_range(qual_begin(), qual_end()); } + qual_iterator qual_begin() const { return getProtocolStorage(); } + qual_iterator qual_end() const { return qual_begin() + getNumProtocols(); } + + bool qual_empty() const { return getNumProtocols() == 0; } + + /// Return the number of qualifying protocols in this interface type, + /// or 0 if there are none. + unsigned getNumProtocols() const { return ObjCObjectTypeBits.NumProtocols; } + + /// Fetch a protocol by index. + ObjCProtocolDecl *getProtocol(unsigned I) const { + assert(I < getNumProtocols() && "Out-of-range protocol access"); + return qual_begin()[I]; + } + + /// Retrieve all of the protocol qualifiers. + ArrayRef<ObjCProtocolDecl *> getProtocols() const { + return ArrayRef<ObjCProtocolDecl *>(qual_begin(), getNumProtocols()); + } + + /// Whether this is a "__kindof" type as written. + bool isKindOfTypeAsWritten() const { return ObjCObjectTypeBits.IsKindOf; } + + /// Whether this ia a "__kindof" type (semantically). + bool isKindOfType() const; + + /// Retrieve the type of the superclass of this object type. + /// + /// This operation substitutes any type arguments into the + /// superclass of the current class type, potentially producing a + /// specialization of the superclass type. Produces a null type if + /// there is no superclass. + QualType getSuperClassType() const { + if (!CachedSuperClassType.getInt()) + computeSuperClassTypeSlow(); + + assert(CachedSuperClassType.getInt() && "Superclass not set?"); + return QualType(CachedSuperClassType.getPointer(), 0); + } + + /// Strip off the Objective-C "kindof" type and (with it) any + /// protocol qualifiers. + QualType stripObjCKindOfTypeAndQuals(const ASTContext &ctx) const; + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == ObjCObject || + T->getTypeClass() == ObjCInterface; + } +}; + +/// A class providing a concrete implementation +/// of ObjCObjectType, so as to not increase the footprint of +/// ObjCInterfaceType. Code outside of ASTContext and the core type +/// system should not reference this type. +class ObjCObjectTypeImpl : public ObjCObjectType, public llvm::FoldingSetNode { + friend class ASTContext; + + // If anyone adds fields here, ObjCObjectType::getProtocolStorage() + // will need to be modified. + + ObjCObjectTypeImpl(QualType Canonical, QualType Base, + ArrayRef<QualType> typeArgs, + ArrayRef<ObjCProtocolDecl *> protocols, + bool isKindOf) + : ObjCObjectType(Canonical, Base, typeArgs, protocols, isKindOf) {} + +public: + void Profile(llvm::FoldingSetNodeID &ID); + static void Profile(llvm::FoldingSetNodeID &ID, + QualType Base, + ArrayRef<QualType> typeArgs, + ArrayRef<ObjCProtocolDecl *> protocols, + bool isKindOf); +}; + +inline QualType *ObjCObjectType::getTypeArgStorage() { + return reinterpret_cast<QualType *>(static_cast<ObjCObjectTypeImpl*>(this)+1); +} + +inline ObjCProtocolDecl **ObjCObjectType::getProtocolStorage() { + return reinterpret_cast<ObjCProtocolDecl**>( + getTypeArgStorage() + ObjCObjectTypeBits.NumTypeArgs); +} + +/// Interfaces are the core concept in Objective-C for object oriented design. +/// They basically correspond to C++ classes. There are two kinds of interface +/// types: normal interfaces like `NSString`, and qualified interfaces, which +/// are qualified with a protocol list like `NSString<NSCopyable, NSAmazing>`. +/// +/// ObjCInterfaceType guarantees the following properties when considered +/// as a subtype of its superclass, ObjCObjectType: +/// - There are no protocol qualifiers. To reinforce this, code which +/// tries to invoke the protocol methods via an ObjCInterfaceType will +/// fail to compile. +/// - It is its own base type. That is, if T is an ObjCInterfaceType*, +/// T->getBaseType() == QualType(T, 0). +class ObjCInterfaceType : public ObjCObjectType { + mutable ObjCInterfaceDecl *Decl; + + ObjCInterfaceType(const ObjCInterfaceDecl *D) + : ObjCObjectType(Nonce_ObjCInterface), + Decl(const_cast<ObjCInterfaceDecl*>(D)) {} + friend class ASTContext; // ASTContext creates these. + friend class ASTReader; + friend class ObjCInterfaceDecl; + +public: + /// Get the declaration of this interface. + ObjCInterfaceDecl *getDecl() const { return Decl; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == ObjCInterface; + } + + // Nonsense to "hide" certain members of ObjCObjectType within this + // class. People asking for protocols on an ObjCInterfaceType are + // not going to get what they want: ObjCInterfaceTypes are + // guaranteed to have no protocols. + enum { + qual_iterator, + qual_begin, + qual_end, + getNumProtocols, + getProtocol + }; +}; + +inline ObjCInterfaceDecl *ObjCObjectType::getInterface() const { + QualType baseType = getBaseType(); + while (const ObjCObjectType *ObjT = baseType->getAs<ObjCObjectType>()) { + if (const ObjCInterfaceType *T = dyn_cast<ObjCInterfaceType>(ObjT)) + return T->getDecl(); + + baseType = ObjT->getBaseType(); + } + + return nullptr; +} + +/// Represents a pointer to an Objective C object. +/// +/// These are constructed from pointer declarators when the pointee type is +/// an ObjCObjectType (or sugar for one). In addition, the 'id' and 'Class' +/// types are typedefs for these, and the protocol-qualified types 'id<P>' +/// and 'Class<P>' are translated into these. +/// +/// Pointers to pointers to Objective C objects are still PointerTypes; +/// only the first level of pointer gets it own type implementation. +class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode { + QualType PointeeType; + + ObjCObjectPointerType(QualType Canonical, QualType Pointee) + : Type(ObjCObjectPointer, Canonical, + Pointee->isDependentType(), + Pointee->isInstantiationDependentType(), + Pointee->isVariablyModifiedType(), + Pointee->containsUnexpandedParameterPack()), + PointeeType(Pointee) {} + friend class ASTContext; // ASTContext creates these. + +public: + /// Gets the type pointed to by this ObjC pointer. + /// The result will always be an ObjCObjectType or sugar thereof. + QualType getPointeeType() const { return PointeeType; } + + /// Gets the type pointed to by this ObjC pointer. Always returns non-null. + /// + /// This method is equivalent to getPointeeType() except that + /// it discards any typedefs (or other sugar) between this + /// type and the "outermost" object type. So for: + /// \code + /// \@class A; \@protocol P; \@protocol Q; + /// typedef A<P> AP; + /// typedef A A1; + /// typedef A1<P> A1P; + /// typedef A1P<Q> A1PQ; + /// \endcode + /// For 'A*', getObjectType() will return 'A'. + /// For 'A<P>*', getObjectType() will return 'A<P>'. + /// For 'AP*', getObjectType() will return 'A<P>'. + /// For 'A1*', getObjectType() will return 'A'. + /// For 'A1<P>*', getObjectType() will return 'A1<P>'. + /// For 'A1P*', getObjectType() will return 'A1<P>'. + /// For 'A1PQ*', getObjectType() will return 'A1<Q>', because + /// adding protocols to a protocol-qualified base discards the + /// old qualifiers (for now). But if it didn't, getObjectType() + /// would return 'A1P<Q>' (and we'd have to make iterating over + /// qualifiers more complicated). + const ObjCObjectType *getObjectType() const { + return PointeeType->castAs<ObjCObjectType>(); + } + + /// If this pointer points to an Objective C + /// \@interface type, gets the type for that interface. Any protocol + /// qualifiers on the interface are ignored. + /// + /// \return null if the base type for this pointer is 'id' or 'Class' + const ObjCInterfaceType *getInterfaceType() const; + + /// If this pointer points to an Objective \@interface + /// type, gets the declaration for that interface. + /// + /// \return null if the base type for this pointer is 'id' or 'Class' + ObjCInterfaceDecl *getInterfaceDecl() const { + return getObjectType()->getInterface(); + } + + /// True if this is equivalent to the 'id' type, i.e. if + /// its object type is the primitive 'id' type with no protocols. + bool isObjCIdType() const { + return getObjectType()->isObjCUnqualifiedId(); + } + + /// True if this is equivalent to the 'Class' type, + /// i.e. if its object tive is the primitive 'Class' type with no protocols. + bool isObjCClassType() const { + return getObjectType()->isObjCUnqualifiedClass(); + } + + /// True if this is equivalent to the 'id' or 'Class' type, + bool isObjCIdOrClassType() const { + return getObjectType()->isObjCUnqualifiedIdOrClass(); + } + + /// True if this is equivalent to 'id<P>' for some non-empty set of + /// protocols. + bool isObjCQualifiedIdType() const { + return getObjectType()->isObjCQualifiedId(); + } + + /// True if this is equivalent to 'Class<P>' for some non-empty set of + /// protocols. + bool isObjCQualifiedClassType() const { + return getObjectType()->isObjCQualifiedClass(); + } + + /// Whether this is a "__kindof" type. + bool isKindOfType() const { return getObjectType()->isKindOfType(); } + + /// Whether this type is specialized, meaning that it has type arguments. + bool isSpecialized() const { return getObjectType()->isSpecialized(); } + + /// Whether this type is specialized, meaning that it has type arguments. + bool isSpecializedAsWritten() const { + return getObjectType()->isSpecializedAsWritten(); + } + + /// Whether this type is unspecialized, meaning that is has no type arguments. + bool isUnspecialized() const { return getObjectType()->isUnspecialized(); } + + /// Determine whether this object type is "unspecialized" as + /// written, meaning that it has no type arguments. + bool isUnspecializedAsWritten() const { return !isSpecializedAsWritten(); } + + /// Retrieve the type arguments for this type. + ArrayRef<QualType> getTypeArgs() const { + return getObjectType()->getTypeArgs(); + } + + /// Retrieve the type arguments for this type. + ArrayRef<QualType> getTypeArgsAsWritten() const { + return getObjectType()->getTypeArgsAsWritten(); + } + + /// An iterator over the qualifiers on the object type. Provided + /// for convenience. This will always iterate over the full set of + /// protocols on a type, not just those provided directly. + typedef ObjCObjectType::qual_iterator qual_iterator; + typedef llvm::iterator_range<qual_iterator> qual_range; + + qual_range quals() const { return qual_range(qual_begin(), qual_end()); } + qual_iterator qual_begin() const { + return getObjectType()->qual_begin(); + } + qual_iterator qual_end() const { + return getObjectType()->qual_end(); + } + bool qual_empty() const { return getObjectType()->qual_empty(); } + + /// Return the number of qualifying protocols on the object type. + unsigned getNumProtocols() const { + return getObjectType()->getNumProtocols(); + } + + /// Retrieve a qualifying protocol by index on the object type. + ObjCProtocolDecl *getProtocol(unsigned I) const { + return getObjectType()->getProtocol(I); + } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + /// Retrieve the type of the superclass of this object pointer type. + /// + /// This operation substitutes any type arguments into the + /// superclass of the current class type, potentially producing a + /// pointer to a specialization of the superclass type. Produces a + /// null type if there is no superclass. + QualType getSuperClassType() const; + + /// Strip off the Objective-C "kindof" type and (with it) any + /// protocol qualifiers. + const ObjCObjectPointerType *stripObjCKindOfTypeAndQuals( + const ASTContext &ctx) const; + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getPointeeType()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType T) { + ID.AddPointer(T.getAsOpaquePtr()); + } + static bool classof(const Type *T) { + return T->getTypeClass() == ObjCObjectPointer; + } +}; + +class AtomicType : public Type, public llvm::FoldingSetNode { + QualType ValueType; + + AtomicType(QualType ValTy, QualType Canonical) + : Type(Atomic, Canonical, ValTy->isDependentType(), + ValTy->isInstantiationDependentType(), + ValTy->isVariablyModifiedType(), + ValTy->containsUnexpandedParameterPack()), + ValueType(ValTy) {} + friend class ASTContext; // ASTContext creates these. + + public: + /// Gets the type contained by this atomic type, i.e. + /// the type returned by performing an atomic load of this atomic type. + QualType getValueType() const { return ValueType; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getValueType()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType T) { + ID.AddPointer(T.getAsOpaquePtr()); + } + static bool classof(const Type *T) { + return T->getTypeClass() == Atomic; + } +}; + +/// A qualifier set is used to build a set of qualifiers. +class QualifierCollector : public Qualifiers { +public: + QualifierCollector(Qualifiers Qs = Qualifiers()) : Qualifiers(Qs) {} + + /// Collect any qualifiers on the given type and return an + /// unqualified type. The qualifiers are assumed to be consistent + /// with those already in the type. + const Type *strip(QualType type) { + addFastQualifiers(type.getLocalFastQualifiers()); + if (!type.hasLocalNonFastQualifiers()) + return type.getTypePtrUnsafe(); + + const ExtQuals *extQuals = type.getExtQualsUnsafe(); + addConsistentQualifiers(extQuals->getQualifiers()); + return extQuals->getBaseType(); + } + + /// Apply the collected qualifiers to the given type. + QualType apply(const ASTContext &Context, QualType QT) const; + + /// Apply the collected qualifiers to the given type. + QualType apply(const ASTContext &Context, const Type* T) const; +}; + + +// Inline function definitions. + +inline SplitQualType SplitQualType::getSingleStepDesugaredType() const { + SplitQualType desugar = + Ty->getLocallyUnqualifiedSingleStepDesugaredType().split(); + desugar.Quals.addConsistentQualifiers(Quals); + return desugar; +} + +inline const Type *QualType::getTypePtr() const { + return getCommonPtr()->BaseType; +} + +inline const Type *QualType::getTypePtrOrNull() const { + return (isNull() ? nullptr : getCommonPtr()->BaseType); +} + +inline SplitQualType QualType::split() const { + if (!hasLocalNonFastQualifiers()) + return SplitQualType(getTypePtrUnsafe(), + Qualifiers::fromFastMask(getLocalFastQualifiers())); + + const ExtQuals *eq = getExtQualsUnsafe(); + Qualifiers qs = eq->getQualifiers(); + qs.addFastQualifiers(getLocalFastQualifiers()); + return SplitQualType(eq->getBaseType(), qs); +} + +inline Qualifiers QualType::getLocalQualifiers() const { + Qualifiers Quals; + if (hasLocalNonFastQualifiers()) + Quals = getExtQualsUnsafe()->getQualifiers(); + Quals.addFastQualifiers(getLocalFastQualifiers()); + return Quals; +} + +inline Qualifiers QualType::getQualifiers() const { + Qualifiers quals = getCommonPtr()->CanonicalType.getLocalQualifiers(); + quals.addFastQualifiers(getLocalFastQualifiers()); + return quals; +} + +inline unsigned QualType::getCVRQualifiers() const { + unsigned cvr = getCommonPtr()->CanonicalType.getLocalCVRQualifiers(); + cvr |= getLocalCVRQualifiers(); + return cvr; +} + +inline QualType QualType::getCanonicalType() const { + QualType canon = getCommonPtr()->CanonicalType; + return canon.withFastQualifiers(getLocalFastQualifiers()); +} + +inline bool QualType::isCanonical() const { + return getTypePtr()->isCanonicalUnqualified(); +} + +inline bool QualType::isCanonicalAsParam() const { + if (!isCanonical()) return false; + if (hasLocalQualifiers()) return false; + + const Type *T = getTypePtr(); + if (T->isVariablyModifiedType() && T->hasSizedVLAType()) + return false; + + return !isa<FunctionType>(T) && !isa<ArrayType>(T); +} + +inline bool QualType::isConstQualified() const { + return isLocalConstQualified() || + getCommonPtr()->CanonicalType.isLocalConstQualified(); +} + +inline bool QualType::isRestrictQualified() const { + return isLocalRestrictQualified() || + getCommonPtr()->CanonicalType.isLocalRestrictQualified(); +} + + +inline bool QualType::isVolatileQualified() const { + return isLocalVolatileQualified() || + getCommonPtr()->CanonicalType.isLocalVolatileQualified(); +} + +inline bool QualType::hasQualifiers() const { + return hasLocalQualifiers() || + getCommonPtr()->CanonicalType.hasLocalQualifiers(); +} + +inline QualType QualType::getUnqualifiedType() const { + if (!getTypePtr()->getCanonicalTypeInternal().hasLocalQualifiers()) + return QualType(getTypePtr(), 0); + + return QualType(getSplitUnqualifiedTypeImpl(*this).Ty, 0); +} + +inline SplitQualType QualType::getSplitUnqualifiedType() const { + if (!getTypePtr()->getCanonicalTypeInternal().hasLocalQualifiers()) + return split(); + + return getSplitUnqualifiedTypeImpl(*this); +} + +inline void QualType::removeLocalConst() { + removeLocalFastQualifiers(Qualifiers::Const); +} + +inline void QualType::removeLocalRestrict() { + removeLocalFastQualifiers(Qualifiers::Restrict); +} + +inline void QualType::removeLocalVolatile() { + removeLocalFastQualifiers(Qualifiers::Volatile); +} + +inline void QualType::removeLocalCVRQualifiers(unsigned Mask) { + assert(!(Mask & ~Qualifiers::CVRMask) && "mask has non-CVR bits"); + assert((int)Qualifiers::CVRMask == (int)Qualifiers::FastMask); + + // Fast path: we don't need to touch the slow qualifiers. + removeLocalFastQualifiers(Mask); +} + +/// Return the address space of this type. +inline unsigned QualType::getAddressSpace() const { + return getQualifiers().getAddressSpace(); +} + +/// Return the gc attribute of this type. +inline Qualifiers::GC QualType::getObjCGCAttr() const { + return getQualifiers().getObjCGCAttr(); +} + +inline FunctionType::ExtInfo getFunctionExtInfo(const Type &t) { + if (const PointerType *PT = t.getAs<PointerType>()) { + if (const FunctionType *FT = PT->getPointeeType()->getAs<FunctionType>()) + return FT->getExtInfo(); + } else if (const FunctionType *FT = t.getAs<FunctionType>()) + return FT->getExtInfo(); + + return FunctionType::ExtInfo(); +} + +inline FunctionType::ExtInfo getFunctionExtInfo(QualType t) { + return getFunctionExtInfo(*t); +} + +/// Determine whether this type is more +/// qualified than the Other type. For example, "const volatile int" +/// is more qualified than "const int", "volatile int", and +/// "int". However, it is not more qualified than "const volatile +/// int". +inline bool QualType::isMoreQualifiedThan(QualType other) const { + Qualifiers myQuals = getQualifiers(); + Qualifiers otherQuals = other.getQualifiers(); + return (myQuals != otherQuals && myQuals.compatiblyIncludes(otherQuals)); +} + +/// Determine whether this type is at last +/// as qualified as the Other type. For example, "const volatile +/// int" is at least as qualified as "const int", "volatile int", +/// "int", and "const volatile int". +inline bool QualType::isAtLeastAsQualifiedAs(QualType other) const { + return getQualifiers().compatiblyIncludes(other.getQualifiers()); +} + +/// If Type is a reference type (e.g., const +/// int&), returns the type that the reference refers to ("const +/// int"). Otherwise, returns the type itself. This routine is used +/// throughout Sema to implement C++ 5p6: +/// +/// If an expression initially has the type "reference to T" (8.3.2, +/// 8.5.3), the type is adjusted to "T" prior to any further +/// analysis, the expression designates the object or function +/// denoted by the reference, and the expression is an lvalue. +inline QualType QualType::getNonReferenceType() const { + if (const ReferenceType *RefType = (*this)->getAs<ReferenceType>()) + return RefType->getPointeeType(); + else + return *this; +} + +inline bool QualType::isCForbiddenLValueType() const { + return ((getTypePtr()->isVoidType() && !hasQualifiers()) || + getTypePtr()->isFunctionType()); +} + +/// Tests whether the type is categorized as a fundamental type. +/// +/// \returns True for types specified in C++0x [basic.fundamental]. +inline bool Type::isFundamentalType() const { + return isVoidType() || + // FIXME: It's really annoying that we don't have an + // 'isArithmeticType()' which agrees with the standard definition. + (isArithmeticType() && !isEnumeralType()); +} + +/// Tests whether the type is categorized as a compound type. +/// +/// \returns True for types specified in C++0x [basic.compound]. +inline bool Type::isCompoundType() const { + // C++0x [basic.compound]p1: + // Compound types can be constructed in the following ways: + // -- arrays of objects of a given type [...]; + return isArrayType() || + // -- functions, which have parameters of given types [...]; + isFunctionType() || + // -- pointers to void or objects or functions [...]; + isPointerType() || + // -- references to objects or functions of a given type. [...] + isReferenceType() || + // -- classes containing a sequence of objects of various types, [...]; + isRecordType() || + // -- unions, which are classes capable of containing objects of different + // types at different times; + isUnionType() || + // -- enumerations, which comprise a set of named constant values. [...]; + isEnumeralType() || + // -- pointers to non-static class members, [...]. + isMemberPointerType(); +} + +inline bool Type::isFunctionType() const { + return isa<FunctionType>(CanonicalType); +} +inline bool Type::isPointerType() const { + return isa<PointerType>(CanonicalType); +} +inline bool Type::isAnyPointerType() const { + return isPointerType() || isObjCObjectPointerType(); +} +inline bool Type::isBlockPointerType() const { + return isa<BlockPointerType>(CanonicalType); +} +inline bool Type::isReferenceType() const { + return isa<ReferenceType>(CanonicalType); +} +inline bool Type::isLValueReferenceType() const { + return isa<LValueReferenceType>(CanonicalType); +} +inline bool Type::isRValueReferenceType() const { + return isa<RValueReferenceType>(CanonicalType); +} +inline bool Type::isFunctionPointerType() const { + if (const PointerType *T = getAs<PointerType>()) + return T->getPointeeType()->isFunctionType(); + else + return false; +} +inline bool Type::isMemberPointerType() const { + return isa<MemberPointerType>(CanonicalType); +} +inline bool Type::isMemberFunctionPointerType() const { + if (const MemberPointerType* T = getAs<MemberPointerType>()) + return T->isMemberFunctionPointer(); + else + return false; +} +inline bool Type::isMemberDataPointerType() const { + if (const MemberPointerType* T = getAs<MemberPointerType>()) + return T->isMemberDataPointer(); + else + return false; +} +inline bool Type::isArrayType() const { + return isa<ArrayType>(CanonicalType); +} +inline bool Type::isConstantArrayType() const { + return isa<ConstantArrayType>(CanonicalType); +} +inline bool Type::isIncompleteArrayType() const { + return isa<IncompleteArrayType>(CanonicalType); +} +inline bool Type::isVariableArrayType() const { + return isa<VariableArrayType>(CanonicalType); +} +inline bool Type::isDependentSizedArrayType() const { + return isa<DependentSizedArrayType>(CanonicalType); +} +inline bool Type::isBuiltinType() const { + return isa<BuiltinType>(CanonicalType); +} +inline bool Type::isRecordType() const { + return isa<RecordType>(CanonicalType); +} +inline bool Type::isEnumeralType() const { + return isa<EnumType>(CanonicalType); +} +inline bool Type::isAnyComplexType() const { + return isa<ComplexType>(CanonicalType); +} +inline bool Type::isVectorType() const { + return isa<VectorType>(CanonicalType); +} +inline bool Type::isExtVectorType() const { + return isa<ExtVectorType>(CanonicalType); +} +inline bool Type::isObjCObjectPointerType() const { + return isa<ObjCObjectPointerType>(CanonicalType); +} +inline bool Type::isObjCObjectType() const { + return isa<ObjCObjectType>(CanonicalType); +} +inline bool Type::isObjCObjectOrInterfaceType() const { + return isa<ObjCInterfaceType>(CanonicalType) || + isa<ObjCObjectType>(CanonicalType); +} +inline bool Type::isAtomicType() const { + return isa<AtomicType>(CanonicalType); +} + +inline bool Type::isObjCQualifiedIdType() const { + if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) + return OPT->isObjCQualifiedIdType(); + return false; +} +inline bool Type::isObjCQualifiedClassType() const { + if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) + return OPT->isObjCQualifiedClassType(); + return false; +} +inline bool Type::isObjCIdType() const { + if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) + return OPT->isObjCIdType(); + return false; +} +inline bool Type::isObjCClassType() const { + if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) + return OPT->isObjCClassType(); + return false; +} +inline bool Type::isObjCSelType() const { + if (const PointerType *OPT = getAs<PointerType>()) + return OPT->getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCSel); + return false; +} +inline bool Type::isObjCBuiltinType() const { + return isObjCIdType() || isObjCClassType() || isObjCSelType(); +} + +inline bool Type::isImage1dT() const { + return isSpecificBuiltinType(BuiltinType::OCLImage1d); +} + +inline bool Type::isImage1dArrayT() const { + return isSpecificBuiltinType(BuiltinType::OCLImage1dArray); +} + +inline bool Type::isImage1dBufferT() const { + return isSpecificBuiltinType(BuiltinType::OCLImage1dBuffer); +} + +inline bool Type::isImage2dT() const { + return isSpecificBuiltinType(BuiltinType::OCLImage2d); +} + +inline bool Type::isImage2dArrayT() const { + return isSpecificBuiltinType(BuiltinType::OCLImage2dArray); +} + +inline bool Type::isImage2dDepthT() const { + return isSpecificBuiltinType(BuiltinType::OCLImage2dDepth); +} + +inline bool Type::isImage2dArrayDepthT() const { + return isSpecificBuiltinType(BuiltinType::OCLImage2dArrayDepth); +} + +inline bool Type::isImage2dMSAAT() const { + return isSpecificBuiltinType(BuiltinType::OCLImage2dMSAA); +} + +inline bool Type::isImage2dArrayMSAAT() const { + return isSpecificBuiltinType(BuiltinType::OCLImage2dArrayMSAA); +} + +inline bool Type::isImage2dMSAATDepth() const { + return isSpecificBuiltinType(BuiltinType::OCLImage2dMSAADepth); +} + +inline bool Type::isImage2dArrayMSAATDepth() const { + return isSpecificBuiltinType(BuiltinType::OCLImage2dArrayMSAADepth); +} + +inline bool Type::isImage3dT() const { + return isSpecificBuiltinType(BuiltinType::OCLImage3d); +} + +inline bool Type::isSamplerT() const { + return isSpecificBuiltinType(BuiltinType::OCLSampler); +} + +inline bool Type::isEventT() const { + return isSpecificBuiltinType(BuiltinType::OCLEvent); +} + +inline bool Type::isClkEventT() const { + return isSpecificBuiltinType(BuiltinType::OCLClkEvent); +} + +inline bool Type::isQueueT() const { + return isSpecificBuiltinType(BuiltinType::OCLQueue); +} + +inline bool Type::isNDRangeT() const { + return isSpecificBuiltinType(BuiltinType::OCLNDRange); +} + +inline bool Type::isReserveIDT() const { + return isSpecificBuiltinType(BuiltinType::OCLReserveID); +} + +inline bool Type::isImageType() const { + return isImage3dT() || isImage2dT() || isImage2dArrayT() || + isImage2dDepthT() || isImage2dArrayDepthT() || isImage2dMSAAT() || + isImage2dArrayMSAAT() || isImage2dMSAATDepth() || + isImage2dArrayMSAATDepth() || isImage1dT() || isImage1dArrayT() || + isImage1dBufferT(); +} + +inline bool Type::isOpenCLSpecificType() const { + return isSamplerT() || isEventT() || isImageType() || isClkEventT() || + isQueueT() || isNDRangeT() || isReserveIDT(); +} + +inline bool Type::isTemplateTypeParmType() const { + return isa<TemplateTypeParmType>(CanonicalType); +} + +inline bool Type::isSpecificBuiltinType(unsigned K) const { + if (const BuiltinType *BT = getAs<BuiltinType>()) + if (BT->getKind() == (BuiltinType::Kind) K) + return true; + return false; +} + +inline bool Type::isPlaceholderType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(this)) + return BT->isPlaceholderType(); + return false; +} + +inline const BuiltinType *Type::getAsPlaceholderType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(this)) + if (BT->isPlaceholderType()) + return BT; + return nullptr; +} + +inline bool Type::isSpecificPlaceholderType(unsigned K) const { + assert(BuiltinType::isPlaceholderTypeKind((BuiltinType::Kind) K)); + if (const BuiltinType *BT = dyn_cast<BuiltinType>(this)) + return (BT->getKind() == (BuiltinType::Kind) K); + return false; +} + +inline bool Type::isNonOverloadPlaceholderType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(this)) + return BT->isNonOverloadPlaceholderType(); + return false; +} + +inline bool Type::isVoidType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() == BuiltinType::Void; + return false; +} + +inline bool Type::isHalfType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() == BuiltinType::Half; + // FIXME: Should we allow complex __fp16? Probably not. + return false; +} + +inline bool Type::isNullPtrType() const { + if (const BuiltinType *BT = getAs<BuiltinType>()) + return BT->getKind() == BuiltinType::NullPtr; + return false; +} + +extern bool IsEnumDeclComplete(EnumDecl *); +extern bool IsEnumDeclScoped(EnumDecl *); + +inline bool Type::isIntegerType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() >= BuiltinType::Bool && + BT->getKind() <= BuiltinType::Int128; + if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) { + // Incomplete enum types are not treated as integer types. + // FIXME: In C++, enum types are never integer types. + return IsEnumDeclComplete(ET->getDecl()) && + !IsEnumDeclScoped(ET->getDecl()); + } + return false; +} + +inline bool Type::isScalarType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() > BuiltinType::Void && + BT->getKind() <= BuiltinType::NullPtr; + if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) + // Enums are scalar types, but only if they are defined. Incomplete enums + // are not treated as scalar types. + return IsEnumDeclComplete(ET->getDecl()); + return isa<PointerType>(CanonicalType) || + isa<BlockPointerType>(CanonicalType) || + isa<MemberPointerType>(CanonicalType) || + isa<ComplexType>(CanonicalType) || + isa<ObjCObjectPointerType>(CanonicalType); +} + +inline bool Type::isIntegralOrEnumerationType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() >= BuiltinType::Bool && + BT->getKind() <= BuiltinType::Int128; + + // Check for a complete enum type; incomplete enum types are not properly an + // enumeration type in the sense required here. + if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) + return IsEnumDeclComplete(ET->getDecl()); + + return false; +} + +inline bool Type::isBooleanType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() == BuiltinType::Bool; + return false; +} + +inline bool Type::isUndeducedType() const { + const AutoType *AT = getContainedAutoType(); + return AT && !AT->isDeduced(); +} + +/// \brief Determines whether this is a type for which one can define +/// an overloaded operator. +inline bool Type::isOverloadableType() const { + return isDependentType() || isRecordType() || isEnumeralType(); +} + +/// \brief Determines whether this type can decay to a pointer type. +inline bool Type::canDecayToPointerType() const { + return isFunctionType() || isArrayType(); +} + +inline bool Type::hasPointerRepresentation() const { + return (isPointerType() || isReferenceType() || isBlockPointerType() || + isObjCObjectPointerType() || isNullPtrType()); +} + +inline bool Type::hasObjCPointerRepresentation() const { + return isObjCObjectPointerType(); +} + +inline const Type *Type::getBaseElementTypeUnsafe() const { + const Type *type = this; + while (const ArrayType *arrayType = type->getAsArrayTypeUnsafe()) + type = arrayType->getElementType().getTypePtr(); + return type; +} + +/// Insertion operator for diagnostics. This allows sending QualType's into a +/// diagnostic with <<. +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + QualType T) { + DB.AddTaggedVal(reinterpret_cast<intptr_t>(T.getAsOpaquePtr()), + DiagnosticsEngine::ak_qualtype); + return DB; +} + +/// Insertion operator for partial diagnostics. This allows sending QualType's +/// into a diagnostic with <<. +inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + QualType T) { + PD.AddTaggedVal(reinterpret_cast<intptr_t>(T.getAsOpaquePtr()), + DiagnosticsEngine::ak_qualtype); + return PD; +} + +// Helper class template that is used by Type::getAs to ensure that one does +// not try to look through a qualified type to get to an array type. +template <typename T, bool isArrayType = (std::is_same<T, ArrayType>::value || + std::is_base_of<ArrayType, T>::value)> +struct ArrayType_cannot_be_used_with_getAs {}; + +template<typename T> +struct ArrayType_cannot_be_used_with_getAs<T, true>; + +// Member-template getAs<specific type>'. +template <typename T> const T *Type::getAs() const { + ArrayType_cannot_be_used_with_getAs<T> at; + (void)at; + + // If this is directly a T type, return it. + if (const T *Ty = dyn_cast<T>(this)) + return Ty; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa<T>(CanonicalType)) + return nullptr; + + // If this is a typedef for the type, strip the typedef off without + // losing all typedef information. + return cast<T>(getUnqualifiedDesugaredType()); +} + +inline const ArrayType *Type::getAsArrayTypeUnsafe() const { + // If this is directly an array type, return it. + if (const ArrayType *arr = dyn_cast<ArrayType>(this)) + return arr; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa<ArrayType>(CanonicalType)) + return nullptr; + + // If this is a typedef for the type, strip the typedef off without + // losing all typedef information. + return cast<ArrayType>(getUnqualifiedDesugaredType()); +} + +template <typename T> const T *Type::castAs() const { + ArrayType_cannot_be_used_with_getAs<T> at; + (void) at; + + if (const T *ty = dyn_cast<T>(this)) return ty; + assert(isa<T>(CanonicalType)); + return cast<T>(getUnqualifiedDesugaredType()); +} + +inline const ArrayType *Type::castAsArrayTypeUnsafe() const { + assert(isa<ArrayType>(CanonicalType)); + if (const ArrayType *arr = dyn_cast<ArrayType>(this)) return arr; + return cast<ArrayType>(getUnqualifiedDesugaredType()); +} + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/TypeLoc.h b/contrib/llvm/tools/clang/include/clang/AST/TypeLoc.h new file mode 100644 index 0000000..26feda5 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/TypeLoc.h @@ -0,0 +1,2039 @@ +//===--- TypeLoc.h - Type Source Info Wrapper -------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the clang::TypeLoc interface and its subclasses. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_TYPELOC_H +#define LLVM_CLANG_AST_TYPELOC_H + +#include "clang/AST/Decl.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/Type.h" +#include "clang/Basic/Specifiers.h" +#include "llvm/Support/Compiler.h" + +namespace clang { + class ASTContext; + class ParmVarDecl; + class TypeSourceInfo; + class UnqualTypeLoc; + +// Predeclare all the type nodes. +#define ABSTRACT_TYPELOC(Class, Base) +#define TYPELOC(Class, Base) \ + class Class##TypeLoc; +#include "clang/AST/TypeLocNodes.def" + +/// \brief Base wrapper for a particular "section" of type source info. +/// +/// A client should use the TypeLoc subclasses through castAs()/getAs() +/// in order to get at the actual information. +class TypeLoc { +protected: + // The correctness of this relies on the property that, for Type *Ty, + // QualType(Ty, 0).getAsOpaquePtr() == (void*) Ty + const void *Ty; + void *Data; + +public: + /// \brief Convert to the specified TypeLoc type, asserting that this TypeLoc + /// is of the desired type. + /// + /// \pre T::isKind(*this) + template<typename T> + T castAs() const { + assert(T::isKind(*this)); + T t; + TypeLoc& tl = t; + tl = *this; + return t; + } + + /// \brief Convert to the specified TypeLoc type, returning a null TypeLoc if + /// this TypeLoc is not of the desired type. + template<typename T> + T getAs() const { + if (!T::isKind(*this)) + return T(); + T t; + TypeLoc& tl = t; + tl = *this; + return t; + } + + /// The kinds of TypeLocs. Equivalent to the Type::TypeClass enum, + /// except it also defines a Qualified enum that corresponds to the + /// QualifiedLoc class. + enum TypeLocClass { +#define ABSTRACT_TYPE(Class, Base) +#define TYPE(Class, Base) \ + Class = Type::Class, +#include "clang/AST/TypeNodes.def" + Qualified + }; + + TypeLoc() : Ty(nullptr), Data(nullptr) { } + TypeLoc(QualType ty, void *opaqueData) + : Ty(ty.getAsOpaquePtr()), Data(opaqueData) { } + TypeLoc(const Type *ty, void *opaqueData) + : Ty(ty), Data(opaqueData) { } + + TypeLocClass getTypeLocClass() const { + if (getType().hasLocalQualifiers()) return Qualified; + return (TypeLocClass) getType()->getTypeClass(); + } + + bool isNull() const { return !Ty; } + explicit operator bool() const { return Ty; } + + /// \brief Returns the size of type source info data block for the given type. + static unsigned getFullDataSizeForType(QualType Ty); + + /// \brief Returns the alignment of type source info data block for + /// the given type. + static unsigned getLocalAlignmentForType(QualType Ty); + + /// \brief Get the type for which this source info wrapper provides + /// information. + QualType getType() const { + return QualType::getFromOpaquePtr(Ty); + } + + const Type *getTypePtr() const { + return QualType::getFromOpaquePtr(Ty).getTypePtr(); + } + + /// \brief Get the pointer where source information is stored. + void *getOpaqueData() const { + return Data; + } + + /// \brief Get the begin source location. + SourceLocation getBeginLoc() const; + + /// \brief Get the end source location. + SourceLocation getEndLoc() const; + + /// \brief Get the full source range. + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(getBeginLoc(), getEndLoc()); + } + SourceLocation getLocStart() const LLVM_READONLY { return getBeginLoc(); } + SourceLocation getLocEnd() const LLVM_READONLY { return getEndLoc(); } + + /// \brief Get the local source range. + SourceRange getLocalSourceRange() const { + return getLocalSourceRangeImpl(*this); + } + + /// \brief Returns the size of the type source info data block. + unsigned getFullDataSize() const { + return getFullDataSizeForType(getType()); + } + + /// \brief Get the next TypeLoc pointed by this TypeLoc, e.g for "int*" the + /// TypeLoc is a PointerLoc and next TypeLoc is for "int". + TypeLoc getNextTypeLoc() const { + return getNextTypeLocImpl(*this); + } + + /// \brief Skips past any qualifiers, if this is qualified. + UnqualTypeLoc getUnqualifiedLoc() const; // implemented in this header + + TypeLoc IgnoreParens() const; + + /// \brief Find a type with the location of an explicit type qualifier. + /// + /// The result, if non-null, will be one of: + /// QualifiedTypeLoc + /// AtomicTypeLoc + /// AttributedTypeLoc, for those type attributes that behave as qualifiers + TypeLoc findExplicitQualifierLoc() const; + + /// \brief Initializes this to state that every location in this + /// type is the given location. + /// + /// This method exists to provide a simple transition for code that + /// relies on location-less types. + void initialize(ASTContext &Context, SourceLocation Loc) const { + initializeImpl(Context, *this, Loc); + } + + /// \brief Initializes this by copying its information from another + /// TypeLoc of the same type. + void initializeFullCopy(TypeLoc Other) { + assert(getType() == Other.getType()); + copy(Other); + } + + /// \brief Initializes this by copying its information from another + /// TypeLoc of the same type. The given size must be the full data + /// size. + void initializeFullCopy(TypeLoc Other, unsigned Size) { + assert(getType() == Other.getType()); + assert(getFullDataSize() == Size); + copy(Other); + } + + /// Copies the other type loc into this one. + void copy(TypeLoc other); + + friend bool operator==(const TypeLoc &LHS, const TypeLoc &RHS) { + return LHS.Ty == RHS.Ty && LHS.Data == RHS.Data; + } + + friend bool operator!=(const TypeLoc &LHS, const TypeLoc &RHS) { + return !(LHS == RHS); + } + + /// Find the location of the nullability specifier (__nonnull, + /// __nullable, or __null_unspecifier), if there is one. + SourceLocation findNullabilityLoc() const; + +private: + static bool isKind(const TypeLoc&) { + return true; + } + + static void initializeImpl(ASTContext &Context, TypeLoc TL, + SourceLocation Loc); + static TypeLoc getNextTypeLocImpl(TypeLoc TL); + static TypeLoc IgnoreParensImpl(TypeLoc TL); + static SourceRange getLocalSourceRangeImpl(TypeLoc TL); +}; + +/// \brief Return the TypeLoc for a type source info. +inline TypeLoc TypeSourceInfo::getTypeLoc() const { + // TODO: is this alignment already sufficient? + return TypeLoc(Ty, const_cast<void*>(static_cast<const void*>(this + 1))); +} + +/// \brief Wrapper of type source information for a type with +/// no direct qualifiers. +class UnqualTypeLoc : public TypeLoc { +public: + UnqualTypeLoc() {} + UnqualTypeLoc(const Type *Ty, void *Data) : TypeLoc(Ty, Data) {} + + const Type *getTypePtr() const { + return reinterpret_cast<const Type*>(Ty); + } + + TypeLocClass getTypeLocClass() const { + return (TypeLocClass) getTypePtr()->getTypeClass(); + } + +private: + friend class TypeLoc; + static bool isKind(const TypeLoc &TL) { + return !TL.getType().hasLocalQualifiers(); + } +}; + +/// \brief Wrapper of type source information for a type with +/// non-trivial direct qualifiers. +/// +/// Currently, we intentionally do not provide source location for +/// type qualifiers. +class QualifiedTypeLoc : public TypeLoc { +public: + SourceRange getLocalSourceRange() const { + return SourceRange(); + } + + UnqualTypeLoc getUnqualifiedLoc() const { + unsigned align = + TypeLoc::getLocalAlignmentForType(QualType(getTypePtr(), 0)); + uintptr_t dataInt = reinterpret_cast<uintptr_t>(Data); + dataInt = llvm::RoundUpToAlignment(dataInt, align); + return UnqualTypeLoc(getTypePtr(), reinterpret_cast<void*>(dataInt)); + } + + /// Initializes the local data of this type source info block to + /// provide no information. + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + // do nothing + } + + void copyLocal(TypeLoc other) { + // do nothing + } + + TypeLoc getNextTypeLoc() const { + return getUnqualifiedLoc(); + } + + /// \brief Returns the size of the type source info data block that is + /// specific to this type. + unsigned getLocalDataSize() const { + // In fact, we don't currently preserve any location information + // for qualifiers. + return 0; + } + + /// \brief Returns the alignment of the type source info data block that is + /// specific to this type. + unsigned getLocalDataAlignment() const { + // We don't preserve any location information. + return 1; + } + +private: + friend class TypeLoc; + static bool isKind(const TypeLoc &TL) { + return TL.getType().hasLocalQualifiers(); + } +}; + +inline UnqualTypeLoc TypeLoc::getUnqualifiedLoc() const { + if (QualifiedTypeLoc Loc = getAs<QualifiedTypeLoc>()) + return Loc.getUnqualifiedLoc(); + return castAs<UnqualTypeLoc>(); +} + +/// A metaprogramming base class for TypeLoc classes which correspond +/// to a particular Type subclass. It is accepted for a single +/// TypeLoc class to correspond to multiple Type classes. +/// +/// \tparam Base a class from which to derive +/// \tparam Derived the class deriving from this one +/// \tparam TypeClass the concrete Type subclass associated with this +/// location type +/// \tparam LocalData the structure type of local location data for +/// this type +/// +/// TypeLocs with non-constant amounts of local data should override +/// getExtraLocalDataSize(); getExtraLocalData() will then point to +/// this extra memory. +/// +/// TypeLocs with an inner type should define +/// QualType getInnerType() const +/// and getInnerTypeLoc() will then point to this inner type's +/// location data. +/// +/// A word about hierarchies: this template is not designed to be +/// derived from multiple times in a hierarchy. It is also not +/// designed to be used for classes where subtypes might provide +/// different amounts of source information. It should be subclassed +/// only at the deepest portion of the hierarchy where all children +/// have identical source information; if that's an abstract type, +/// then further descendents should inherit from +/// InheritingConcreteTypeLoc instead. +template <class Base, class Derived, class TypeClass, class LocalData> +class ConcreteTypeLoc : public Base { + + const Derived *asDerived() const { + return static_cast<const Derived*>(this); + } + + friend class TypeLoc; + static bool isKind(const TypeLoc &TL) { + return !TL.getType().hasLocalQualifiers() && + Derived::classofType(TL.getTypePtr()); + } + + static bool classofType(const Type *Ty) { + return TypeClass::classof(Ty); + } + +public: + unsigned getLocalDataAlignment() const { + return std::max(llvm::alignOf<LocalData>(), + asDerived()->getExtraLocalDataAlignment()); + } + unsigned getLocalDataSize() const { + unsigned size = sizeof(LocalData); + unsigned extraAlign = asDerived()->getExtraLocalDataAlignment(); + size = llvm::RoundUpToAlignment(size, extraAlign); + size += asDerived()->getExtraLocalDataSize(); + return size; + } + + void copyLocal(Derived other) { + // Some subclasses have no data to copy. + if (asDerived()->getLocalDataSize() == 0) return; + + // Copy the fixed-sized local data. + memcpy(getLocalData(), other.getLocalData(), sizeof(LocalData)); + + // Copy the variable-sized local data. We need to do this + // separately because the padding in the source and the padding in + // the destination might be different. + memcpy(getExtraLocalData(), other.getExtraLocalData(), + asDerived()->getExtraLocalDataSize()); + } + + TypeLoc getNextTypeLoc() const { + return getNextTypeLoc(asDerived()->getInnerType()); + } + + const TypeClass *getTypePtr() const { + return cast<TypeClass>(Base::getTypePtr()); + } + +protected: + unsigned getExtraLocalDataSize() const { + return 0; + } + + unsigned getExtraLocalDataAlignment() const { + return 1; + } + + LocalData *getLocalData() const { + return static_cast<LocalData*>(Base::Data); + } + + /// Gets a pointer past the Info structure; useful for classes with + /// local data that can't be captured in the Info (e.g. because it's + /// of variable size). + void *getExtraLocalData() const { + unsigned size = sizeof(LocalData); + unsigned extraAlign = asDerived()->getExtraLocalDataAlignment(); + size = llvm::RoundUpToAlignment(size, extraAlign); + return reinterpret_cast<char*>(Base::Data) + size; + } + + void *getNonLocalData() const { + uintptr_t data = reinterpret_cast<uintptr_t>(Base::Data); + data += asDerived()->getLocalDataSize(); + data = llvm::RoundUpToAlignment(data, getNextTypeAlign()); + return reinterpret_cast<void*>(data); + } + + struct HasNoInnerType {}; + HasNoInnerType getInnerType() const { return HasNoInnerType(); } + + TypeLoc getInnerTypeLoc() const { + return TypeLoc(asDerived()->getInnerType(), getNonLocalData()); + } + +private: + unsigned getInnerTypeSize() const { + return getInnerTypeSize(asDerived()->getInnerType()); + } + + unsigned getInnerTypeSize(HasNoInnerType _) const { + return 0; + } + + unsigned getInnerTypeSize(QualType _) const { + return getInnerTypeLoc().getFullDataSize(); + } + + unsigned getNextTypeAlign() const { + return getNextTypeAlign(asDerived()->getInnerType()); + } + + unsigned getNextTypeAlign(HasNoInnerType _) const { + return 1; + } + + unsigned getNextTypeAlign(QualType T) const { + return TypeLoc::getLocalAlignmentForType(T); + } + + TypeLoc getNextTypeLoc(HasNoInnerType _) const { + return TypeLoc(); + } + + TypeLoc getNextTypeLoc(QualType T) const { + return TypeLoc(T, getNonLocalData()); + } +}; + +/// A metaprogramming class designed for concrete subtypes of abstract +/// types where all subtypes share equivalently-structured source +/// information. See the note on ConcreteTypeLoc. +template <class Base, class Derived, class TypeClass> +class InheritingConcreteTypeLoc : public Base { + friend class TypeLoc; + static bool classofType(const Type *Ty) { + return TypeClass::classof(Ty); + } + + static bool isKind(const TypeLoc &TL) { + return !TL.getType().hasLocalQualifiers() && + Derived::classofType(TL.getTypePtr()); + } + static bool isKind(const UnqualTypeLoc &TL) { + return Derived::classofType(TL.getTypePtr()); + } + +public: + const TypeClass *getTypePtr() const { + return cast<TypeClass>(Base::getTypePtr()); + } +}; + + +struct TypeSpecLocInfo { + SourceLocation NameLoc; +}; + +/// \brief A reasonable base class for TypeLocs that correspond to +/// types that are written as a type-specifier. +class TypeSpecTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, + TypeSpecTypeLoc, + Type, + TypeSpecLocInfo> { +public: + enum { LocalDataSize = sizeof(TypeSpecLocInfo), + LocalDataAlignment = llvm::AlignOf<TypeSpecLocInfo>::Alignment }; + + SourceLocation getNameLoc() const { + return this->getLocalData()->NameLoc; + } + void setNameLoc(SourceLocation Loc) { + this->getLocalData()->NameLoc = Loc; + } + SourceRange getLocalSourceRange() const { + return SourceRange(getNameLoc(), getNameLoc()); + } + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setNameLoc(Loc); + } + +private: + friend class TypeLoc; + static bool isKind(const TypeLoc &TL); +}; + + +struct BuiltinLocInfo { + SourceLocation BuiltinLoc; +}; + +/// \brief Wrapper for source info for builtin types. +class BuiltinTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, + BuiltinTypeLoc, + BuiltinType, + BuiltinLocInfo> { +public: + SourceLocation getBuiltinLoc() const { + return getLocalData()->BuiltinLoc; + } + void setBuiltinLoc(SourceLocation Loc) { + getLocalData()->BuiltinLoc = Loc; + } + + SourceLocation getNameLoc() const { return getBuiltinLoc(); } + + WrittenBuiltinSpecs& getWrittenBuiltinSpecs() { + return *(static_cast<WrittenBuiltinSpecs*>(getExtraLocalData())); + } + const WrittenBuiltinSpecs& getWrittenBuiltinSpecs() const { + return *(static_cast<WrittenBuiltinSpecs*>(getExtraLocalData())); + } + + bool needsExtraLocalData() const { + BuiltinType::Kind bk = getTypePtr()->getKind(); + return (bk >= BuiltinType::UShort && bk <= BuiltinType::UInt128) + || (bk >= BuiltinType::Short && bk <= BuiltinType::LongDouble) + || bk == BuiltinType::UChar + || bk == BuiltinType::SChar; + } + + unsigned getExtraLocalDataSize() const { + return needsExtraLocalData() ? sizeof(WrittenBuiltinSpecs) : 0; + } + + unsigned getExtraLocalDataAlignment() const { + return needsExtraLocalData() ? llvm::alignOf<WrittenBuiltinSpecs>() : 1; + } + + SourceRange getLocalSourceRange() const { + return SourceRange(getBuiltinLoc(), getBuiltinLoc()); + } + + TypeSpecifierSign getWrittenSignSpec() const { + if (needsExtraLocalData()) + return static_cast<TypeSpecifierSign>(getWrittenBuiltinSpecs().Sign); + else + return TSS_unspecified; + } + bool hasWrittenSignSpec() const { + return getWrittenSignSpec() != TSS_unspecified; + } + void setWrittenSignSpec(TypeSpecifierSign written) { + if (needsExtraLocalData()) + getWrittenBuiltinSpecs().Sign = written; + } + + TypeSpecifierWidth getWrittenWidthSpec() const { + if (needsExtraLocalData()) + return static_cast<TypeSpecifierWidth>(getWrittenBuiltinSpecs().Width); + else + return TSW_unspecified; + } + bool hasWrittenWidthSpec() const { + return getWrittenWidthSpec() != TSW_unspecified; + } + void setWrittenWidthSpec(TypeSpecifierWidth written) { + if (needsExtraLocalData()) + getWrittenBuiltinSpecs().Width = written; + } + + TypeSpecifierType getWrittenTypeSpec() const; + bool hasWrittenTypeSpec() const { + return getWrittenTypeSpec() != TST_unspecified; + } + void setWrittenTypeSpec(TypeSpecifierType written) { + if (needsExtraLocalData()) + getWrittenBuiltinSpecs().Type = written; + } + + bool hasModeAttr() const { + if (needsExtraLocalData()) + return getWrittenBuiltinSpecs().ModeAttr; + else + return false; + } + void setModeAttr(bool written) { + if (needsExtraLocalData()) + getWrittenBuiltinSpecs().ModeAttr = written; + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setBuiltinLoc(Loc); + if (needsExtraLocalData()) { + WrittenBuiltinSpecs &wbs = getWrittenBuiltinSpecs(); + wbs.Sign = TSS_unspecified; + wbs.Width = TSW_unspecified; + wbs.Type = TST_unspecified; + wbs.ModeAttr = false; + } + } +}; + + +/// \brief Wrapper for source info for typedefs. +class TypedefTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, + TypedefTypeLoc, + TypedefType> { +public: + TypedefNameDecl *getTypedefNameDecl() const { + return getTypePtr()->getDecl(); + } +}; + +/// \brief Wrapper for source info for injected class names of class +/// templates. +class InjectedClassNameTypeLoc : + public InheritingConcreteTypeLoc<TypeSpecTypeLoc, + InjectedClassNameTypeLoc, + InjectedClassNameType> { +public: + CXXRecordDecl *getDecl() const { + return getTypePtr()->getDecl(); + } +}; + +/// \brief Wrapper for source info for unresolved typename using decls. +class UnresolvedUsingTypeLoc : + public InheritingConcreteTypeLoc<TypeSpecTypeLoc, + UnresolvedUsingTypeLoc, + UnresolvedUsingType> { +public: + UnresolvedUsingTypenameDecl *getDecl() const { + return getTypePtr()->getDecl(); + } +}; + +/// \brief Wrapper for source info for tag types. Note that this only +/// records source info for the name itself; a type written 'struct foo' +/// should be represented as an ElaboratedTypeLoc. We currently +/// only do that when C++ is enabled because of the expense of +/// creating an ElaboratedType node for so many type references in C. +class TagTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, + TagTypeLoc, + TagType> { +public: + TagDecl *getDecl() const { return getTypePtr()->getDecl(); } + + /// \brief True if the tag was defined in this type specifier. + bool isDefinition() const { + TagDecl *D = getDecl(); + return D->isCompleteDefinition() && + (D->getIdentifier() == nullptr || D->getLocation() == getNameLoc()); + } +}; + +/// \brief Wrapper for source info for record types. +class RecordTypeLoc : public InheritingConcreteTypeLoc<TagTypeLoc, + RecordTypeLoc, + RecordType> { +public: + RecordDecl *getDecl() const { return getTypePtr()->getDecl(); } +}; + +/// \brief Wrapper for source info for enum types. +class EnumTypeLoc : public InheritingConcreteTypeLoc<TagTypeLoc, + EnumTypeLoc, + EnumType> { +public: + EnumDecl *getDecl() const { return getTypePtr()->getDecl(); } +}; + +/// \brief Wrapper for template type parameters. +class TemplateTypeParmTypeLoc : + public InheritingConcreteTypeLoc<TypeSpecTypeLoc, + TemplateTypeParmTypeLoc, + TemplateTypeParmType> { +public: + TemplateTypeParmDecl *getDecl() const { return getTypePtr()->getDecl(); } +}; + +/// \brief Wrapper for substituted template type parameters. +class SubstTemplateTypeParmTypeLoc : + public InheritingConcreteTypeLoc<TypeSpecTypeLoc, + SubstTemplateTypeParmTypeLoc, + SubstTemplateTypeParmType> { +}; + + /// \brief Wrapper for substituted template type parameters. +class SubstTemplateTypeParmPackTypeLoc : + public InheritingConcreteTypeLoc<TypeSpecTypeLoc, + SubstTemplateTypeParmPackTypeLoc, + SubstTemplateTypeParmPackType> { +}; + +struct AttributedLocInfo { + union { + Expr *ExprOperand; + + /// A raw SourceLocation. + unsigned EnumOperandLoc; + }; + + SourceRange OperandParens; + + SourceLocation AttrLoc; +}; + +/// \brief Type source information for an attributed type. +class AttributedTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, + AttributedTypeLoc, + AttributedType, + AttributedLocInfo> { +public: + AttributedType::Kind getAttrKind() const { + return getTypePtr()->getAttrKind(); + } + + bool hasAttrExprOperand() const { + return (getAttrKind() >= AttributedType::FirstExprOperandKind && + getAttrKind() <= AttributedType::LastExprOperandKind); + } + + bool hasAttrEnumOperand() const { + return (getAttrKind() >= AttributedType::FirstEnumOperandKind && + getAttrKind() <= AttributedType::LastEnumOperandKind); + } + + bool hasAttrOperand() const { + return hasAttrExprOperand() || hasAttrEnumOperand(); + } + + bool isQualifier() const { + return getTypePtr()->isQualifier(); + } + + /// The modified type, which is generally canonically different from + /// the attribute type. + /// int main(int, char**) __attribute__((noreturn)) + /// ~~~ ~~~~~~~~~~~~~ + TypeLoc getModifiedLoc() const { + return getInnerTypeLoc(); + } + + /// The location of the attribute name, i.e. + /// __attribute__((regparm(1000))) + /// ^~~~~~~ + SourceLocation getAttrNameLoc() const { + return getLocalData()->AttrLoc; + } + void setAttrNameLoc(SourceLocation loc) { + getLocalData()->AttrLoc = loc; + } + + /// The attribute's expression operand, if it has one. + /// void *cur_thread __attribute__((address_space(21))) + /// ^~ + Expr *getAttrExprOperand() const { + assert(hasAttrExprOperand()); + return getLocalData()->ExprOperand; + } + void setAttrExprOperand(Expr *e) { + assert(hasAttrExprOperand()); + getLocalData()->ExprOperand = e; + } + + /// The location of the attribute's enumerated operand, if it has one. + /// void * __attribute__((objc_gc(weak))) + /// ^~~~ + SourceLocation getAttrEnumOperandLoc() const { + assert(hasAttrEnumOperand()); + return SourceLocation::getFromRawEncoding(getLocalData()->EnumOperandLoc); + } + void setAttrEnumOperandLoc(SourceLocation loc) { + assert(hasAttrEnumOperand()); + getLocalData()->EnumOperandLoc = loc.getRawEncoding(); + } + + /// The location of the parentheses around the operand, if there is + /// an operand. + /// void * __attribute__((objc_gc(weak))) + /// ^ ^ + SourceRange getAttrOperandParensRange() const { + assert(hasAttrOperand()); + return getLocalData()->OperandParens; + } + void setAttrOperandParensRange(SourceRange range) { + assert(hasAttrOperand()); + getLocalData()->OperandParens = range; + } + + SourceRange getLocalSourceRange() const { + // Note that this does *not* include the range of the attribute + // enclosure, e.g.: + // __attribute__((foo(bar))) + // ^~~~~~~~~~~~~~~ ~~ + // or + // [[foo(bar)]] + // ^~ ~~ + // That enclosure doesn't necessarily belong to a single attribute + // anyway. + SourceRange range(getAttrNameLoc()); + if (hasAttrOperand()) + range.setEnd(getAttrOperandParensRange().getEnd()); + return range; + } + + void initializeLocal(ASTContext &Context, SourceLocation loc) { + setAttrNameLoc(loc); + if (hasAttrExprOperand()) { + setAttrOperandParensRange(SourceRange(loc)); + setAttrExprOperand(nullptr); + } else if (hasAttrEnumOperand()) { + setAttrOperandParensRange(SourceRange(loc)); + setAttrEnumOperandLoc(loc); + } + } + + QualType getInnerType() const { + return getTypePtr()->getModifiedType(); + } +}; + + +struct ObjCObjectTypeLocInfo { + SourceLocation TypeArgsLAngleLoc; + SourceLocation TypeArgsRAngleLoc; + SourceLocation ProtocolLAngleLoc; + SourceLocation ProtocolRAngleLoc; + bool HasBaseTypeAsWritten; +}; + +// A helper class for defining ObjC TypeLocs that can qualified with +// protocols. +// +// TypeClass basically has to be either ObjCInterfaceType or +// ObjCObjectPointerType. +class ObjCObjectTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, + ObjCObjectTypeLoc, + ObjCObjectType, + ObjCObjectTypeLocInfo> { + // TypeSourceInfo*'s are stored after Info, one for each type argument. + TypeSourceInfo **getTypeArgLocArray() const { + return (TypeSourceInfo**)this->getExtraLocalData(); + } + + // SourceLocations are stored after the type argument information, one for + // each Protocol. + SourceLocation *getProtocolLocArray() const { + return (SourceLocation*)(getTypeArgLocArray() + getNumTypeArgs()); + } + +public: + SourceLocation getTypeArgsLAngleLoc() const { + return this->getLocalData()->TypeArgsLAngleLoc; + } + void setTypeArgsLAngleLoc(SourceLocation Loc) { + this->getLocalData()->TypeArgsLAngleLoc = Loc; + } + + SourceLocation getTypeArgsRAngleLoc() const { + return this->getLocalData()->TypeArgsRAngleLoc; + } + void setTypeArgsRAngleLoc(SourceLocation Loc) { + this->getLocalData()->TypeArgsRAngleLoc = Loc; + } + + unsigned getNumTypeArgs() const { + return this->getTypePtr()->getTypeArgsAsWritten().size(); + } + + TypeSourceInfo *getTypeArgTInfo(unsigned i) const { + assert(i < getNumTypeArgs() && "Index is out of bounds!"); + return getTypeArgLocArray()[i]; + } + + void setTypeArgTInfo(unsigned i, TypeSourceInfo *TInfo) { + assert(i < getNumTypeArgs() && "Index is out of bounds!"); + getTypeArgLocArray()[i] = TInfo; + } + + SourceLocation getProtocolLAngleLoc() const { + return this->getLocalData()->ProtocolLAngleLoc; + } + void setProtocolLAngleLoc(SourceLocation Loc) { + this->getLocalData()->ProtocolLAngleLoc = Loc; + } + + SourceLocation getProtocolRAngleLoc() const { + return this->getLocalData()->ProtocolRAngleLoc; + } + void setProtocolRAngleLoc(SourceLocation Loc) { + this->getLocalData()->ProtocolRAngleLoc = Loc; + } + + unsigned getNumProtocols() const { + return this->getTypePtr()->getNumProtocols(); + } + + SourceLocation getProtocolLoc(unsigned i) const { + assert(i < getNumProtocols() && "Index is out of bounds!"); + return getProtocolLocArray()[i]; + } + void setProtocolLoc(unsigned i, SourceLocation Loc) { + assert(i < getNumProtocols() && "Index is out of bounds!"); + getProtocolLocArray()[i] = Loc; + } + + ObjCProtocolDecl *getProtocol(unsigned i) const { + assert(i < getNumProtocols() && "Index is out of bounds!"); + return *(this->getTypePtr()->qual_begin() + i); + } + + + ArrayRef<SourceLocation> getProtocolLocs() const { + return llvm::makeArrayRef(getProtocolLocArray(), getNumProtocols()); + } + + bool hasBaseTypeAsWritten() const { + return getLocalData()->HasBaseTypeAsWritten; + } + + void setHasBaseTypeAsWritten(bool HasBaseType) { + getLocalData()->HasBaseTypeAsWritten = HasBaseType; + } + + TypeLoc getBaseLoc() const { + return getInnerTypeLoc(); + } + + SourceRange getLocalSourceRange() const { + SourceLocation start = getTypeArgsLAngleLoc(); + if (start.isInvalid()) + start = getProtocolLAngleLoc(); + SourceLocation end = getProtocolRAngleLoc(); + if (end.isInvalid()) + end = getTypeArgsRAngleLoc(); + return SourceRange(start, end); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc); + + unsigned getExtraLocalDataSize() const { + return this->getNumTypeArgs() * sizeof(TypeSourceInfo *) + + this->getNumProtocols() * sizeof(SourceLocation); + } + + unsigned getExtraLocalDataAlignment() const { + assert(llvm::alignOf<ObjCObjectTypeLoc>() + >= llvm::alignOf<TypeSourceInfo *>() && + "not enough alignment for tail-allocated data"); + return llvm::alignOf<TypeSourceInfo *>(); + } + + QualType getInnerType() const { + return getTypePtr()->getBaseType(); + } +}; + + +struct ObjCInterfaceLocInfo { + SourceLocation NameLoc; + SourceLocation NameEndLoc; +}; + +/// \brief Wrapper for source info for ObjC interfaces. +class ObjCInterfaceTypeLoc : public ConcreteTypeLoc<ObjCObjectTypeLoc, + ObjCInterfaceTypeLoc, + ObjCInterfaceType, + ObjCInterfaceLocInfo> { +public: + ObjCInterfaceDecl *getIFaceDecl() const { + return getTypePtr()->getDecl(); + } + + SourceLocation getNameLoc() const { + return getLocalData()->NameLoc; + } + + void setNameLoc(SourceLocation Loc) { + getLocalData()->NameLoc = Loc; + } + + SourceRange getLocalSourceRange() const { + return SourceRange(getNameLoc(), getNameEndLoc()); + } + + SourceLocation getNameEndLoc() const { + return getLocalData()->NameEndLoc; + } + + void setNameEndLoc(SourceLocation Loc) { + getLocalData()->NameEndLoc = Loc; + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setNameLoc(Loc); + setNameEndLoc(Loc); + } +}; + +struct ParenLocInfo { + SourceLocation LParenLoc; + SourceLocation RParenLoc; +}; + +class ParenTypeLoc + : public ConcreteTypeLoc<UnqualTypeLoc, ParenTypeLoc, ParenType, + ParenLocInfo> { +public: + SourceLocation getLParenLoc() const { + return this->getLocalData()->LParenLoc; + } + SourceLocation getRParenLoc() const { + return this->getLocalData()->RParenLoc; + } + void setLParenLoc(SourceLocation Loc) { + this->getLocalData()->LParenLoc = Loc; + } + void setRParenLoc(SourceLocation Loc) { + this->getLocalData()->RParenLoc = Loc; + } + + SourceRange getLocalSourceRange() const { + return SourceRange(getLParenLoc(), getRParenLoc()); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setLParenLoc(Loc); + setRParenLoc(Loc); + } + + TypeLoc getInnerLoc() const { + return getInnerTypeLoc(); + } + + QualType getInnerType() const { + return this->getTypePtr()->getInnerType(); + } +}; + +inline TypeLoc TypeLoc::IgnoreParens() const { + if (ParenTypeLoc::isKind(*this)) + return IgnoreParensImpl(*this); + return *this; +} + + +struct AdjustedLocInfo { }; // Nothing. + +class AdjustedTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, AdjustedTypeLoc, + AdjustedType, AdjustedLocInfo> { +public: + TypeLoc getOriginalLoc() const { + return getInnerTypeLoc(); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + // do nothing + } + + QualType getInnerType() const { + // The inner type is the undecayed type, since that's what we have source + // location information for. + return getTypePtr()->getOriginalType(); + } + + SourceRange getLocalSourceRange() const { + return SourceRange(); + } + + unsigned getLocalDataSize() const { + // sizeof(AdjustedLocInfo) is 1, but we don't need its address to be unique + // anyway. TypeLocBuilder can't handle data sizes of 1. + return 0; // No data. + } +}; + +/// \brief Wrapper for source info for pointers decayed from arrays and +/// functions. +class DecayedTypeLoc : public InheritingConcreteTypeLoc< + AdjustedTypeLoc, DecayedTypeLoc, DecayedType> { +}; + +struct PointerLikeLocInfo { + SourceLocation StarLoc; +}; + +/// A base class for +template <class Derived, class TypeClass, class LocalData = PointerLikeLocInfo> +class PointerLikeTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, Derived, + TypeClass, LocalData> { +public: + SourceLocation getSigilLoc() const { + return this->getLocalData()->StarLoc; + } + void setSigilLoc(SourceLocation Loc) { + this->getLocalData()->StarLoc = Loc; + } + + TypeLoc getPointeeLoc() const { + return this->getInnerTypeLoc(); + } + + SourceRange getLocalSourceRange() const { + return SourceRange(getSigilLoc(), getSigilLoc()); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setSigilLoc(Loc); + } + + QualType getInnerType() const { + return this->getTypePtr()->getPointeeType(); + } +}; + + +/// \brief Wrapper for source info for pointers. +class PointerTypeLoc : public PointerLikeTypeLoc<PointerTypeLoc, + PointerType> { +public: + SourceLocation getStarLoc() const { + return getSigilLoc(); + } + void setStarLoc(SourceLocation Loc) { + setSigilLoc(Loc); + } +}; + + +/// \brief Wrapper for source info for block pointers. +class BlockPointerTypeLoc : public PointerLikeTypeLoc<BlockPointerTypeLoc, + BlockPointerType> { +public: + SourceLocation getCaretLoc() const { + return getSigilLoc(); + } + void setCaretLoc(SourceLocation Loc) { + setSigilLoc(Loc); + } +}; + +struct MemberPointerLocInfo : public PointerLikeLocInfo { + TypeSourceInfo *ClassTInfo; +}; + +/// \brief Wrapper for source info for member pointers. +class MemberPointerTypeLoc : public PointerLikeTypeLoc<MemberPointerTypeLoc, + MemberPointerType, + MemberPointerLocInfo> { +public: + SourceLocation getStarLoc() const { + return getSigilLoc(); + } + void setStarLoc(SourceLocation Loc) { + setSigilLoc(Loc); + } + + const Type *getClass() const { + return getTypePtr()->getClass(); + } + TypeSourceInfo *getClassTInfo() const { + return getLocalData()->ClassTInfo; + } + void setClassTInfo(TypeSourceInfo* TI) { + getLocalData()->ClassTInfo = TI; + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setSigilLoc(Loc); + setClassTInfo(nullptr); + } + + SourceRange getLocalSourceRange() const { + if (TypeSourceInfo *TI = getClassTInfo()) + return SourceRange(TI->getTypeLoc().getBeginLoc(), getStarLoc()); + else + return SourceRange(getStarLoc()); + } +}; + +/// Wraps an ObjCPointerType with source location information. +class ObjCObjectPointerTypeLoc : + public PointerLikeTypeLoc<ObjCObjectPointerTypeLoc, + ObjCObjectPointerType> { +public: + SourceLocation getStarLoc() const { + return getSigilLoc(); + } + + void setStarLoc(SourceLocation Loc) { + setSigilLoc(Loc); + } +}; + + +class ReferenceTypeLoc : public PointerLikeTypeLoc<ReferenceTypeLoc, + ReferenceType> { +public: + QualType getInnerType() const { + return getTypePtr()->getPointeeTypeAsWritten(); + } +}; + +class LValueReferenceTypeLoc : + public InheritingConcreteTypeLoc<ReferenceTypeLoc, + LValueReferenceTypeLoc, + LValueReferenceType> { +public: + SourceLocation getAmpLoc() const { + return getSigilLoc(); + } + void setAmpLoc(SourceLocation Loc) { + setSigilLoc(Loc); + } +}; + +class RValueReferenceTypeLoc : + public InheritingConcreteTypeLoc<ReferenceTypeLoc, + RValueReferenceTypeLoc, + RValueReferenceType> { +public: + SourceLocation getAmpAmpLoc() const { + return getSigilLoc(); + } + void setAmpAmpLoc(SourceLocation Loc) { + setSigilLoc(Loc); + } +}; + + +struct FunctionLocInfo { + SourceLocation LocalRangeBegin; + SourceLocation LParenLoc; + SourceLocation RParenLoc; + SourceLocation LocalRangeEnd; +}; + +/// \brief Wrapper for source info for functions. +class FunctionTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, + FunctionTypeLoc, + FunctionType, + FunctionLocInfo> { +public: + SourceLocation getLocalRangeBegin() const { + return getLocalData()->LocalRangeBegin; + } + void setLocalRangeBegin(SourceLocation L) { + getLocalData()->LocalRangeBegin = L; + } + + SourceLocation getLocalRangeEnd() const { + return getLocalData()->LocalRangeEnd; + } + void setLocalRangeEnd(SourceLocation L) { + getLocalData()->LocalRangeEnd = L; + } + + SourceLocation getLParenLoc() const { + return this->getLocalData()->LParenLoc; + } + void setLParenLoc(SourceLocation Loc) { + this->getLocalData()->LParenLoc = Loc; + } + + SourceLocation getRParenLoc() const { + return this->getLocalData()->RParenLoc; + } + void setRParenLoc(SourceLocation Loc) { + this->getLocalData()->RParenLoc = Loc; + } + + SourceRange getParensRange() const { + return SourceRange(getLParenLoc(), getRParenLoc()); + } + + ArrayRef<ParmVarDecl *> getParams() const { + return llvm::makeArrayRef(getParmArray(), getNumParams()); + } + + // ParmVarDecls* are stored after Info, one for each parameter. + ParmVarDecl **getParmArray() const { + return (ParmVarDecl**) getExtraLocalData(); + } + + unsigned getNumParams() const { + if (isa<FunctionNoProtoType>(getTypePtr())) + return 0; + return cast<FunctionProtoType>(getTypePtr())->getNumParams(); + } + ParmVarDecl *getParam(unsigned i) const { return getParmArray()[i]; } + void setParam(unsigned i, ParmVarDecl *VD) { getParmArray()[i] = VD; } + + TypeLoc getReturnLoc() const { + return getInnerTypeLoc(); + } + + SourceRange getLocalSourceRange() const { + return SourceRange(getLocalRangeBegin(), getLocalRangeEnd()); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setLocalRangeBegin(Loc); + setLParenLoc(Loc); + setRParenLoc(Loc); + setLocalRangeEnd(Loc); + for (unsigned i = 0, e = getNumParams(); i != e; ++i) + setParam(i, nullptr); + } + + /// \brief Returns the size of the type source info data block that is + /// specific to this type. + unsigned getExtraLocalDataSize() const { + return getNumParams() * sizeof(ParmVarDecl *); + } + + unsigned getExtraLocalDataAlignment() const { + return llvm::alignOf<ParmVarDecl*>(); + } + + QualType getInnerType() const { return getTypePtr()->getReturnType(); } +}; + +class FunctionProtoTypeLoc : + public InheritingConcreteTypeLoc<FunctionTypeLoc, + FunctionProtoTypeLoc, + FunctionProtoType> { +}; + +class FunctionNoProtoTypeLoc : + public InheritingConcreteTypeLoc<FunctionTypeLoc, + FunctionNoProtoTypeLoc, + FunctionNoProtoType> { +}; + + +struct ArrayLocInfo { + SourceLocation LBracketLoc, RBracketLoc; + Expr *Size; +}; + +/// \brief Wrapper for source info for arrays. +class ArrayTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, + ArrayTypeLoc, + ArrayType, + ArrayLocInfo> { +public: + SourceLocation getLBracketLoc() const { + return getLocalData()->LBracketLoc; + } + void setLBracketLoc(SourceLocation Loc) { + getLocalData()->LBracketLoc = Loc; + } + + SourceLocation getRBracketLoc() const { + return getLocalData()->RBracketLoc; + } + void setRBracketLoc(SourceLocation Loc) { + getLocalData()->RBracketLoc = Loc; + } + + SourceRange getBracketsRange() const { + return SourceRange(getLBracketLoc(), getRBracketLoc()); + } + + Expr *getSizeExpr() const { + return getLocalData()->Size; + } + void setSizeExpr(Expr *Size) { + getLocalData()->Size = Size; + } + + TypeLoc getElementLoc() const { + return getInnerTypeLoc(); + } + + SourceRange getLocalSourceRange() const { + return SourceRange(getLBracketLoc(), getRBracketLoc()); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setLBracketLoc(Loc); + setRBracketLoc(Loc); + setSizeExpr(nullptr); + } + + QualType getInnerType() const { return getTypePtr()->getElementType(); } +}; + +class ConstantArrayTypeLoc : + public InheritingConcreteTypeLoc<ArrayTypeLoc, + ConstantArrayTypeLoc, + ConstantArrayType> { +}; + +class IncompleteArrayTypeLoc : + public InheritingConcreteTypeLoc<ArrayTypeLoc, + IncompleteArrayTypeLoc, + IncompleteArrayType> { +}; + +class DependentSizedArrayTypeLoc : + public InheritingConcreteTypeLoc<ArrayTypeLoc, + DependentSizedArrayTypeLoc, + DependentSizedArrayType> { + +}; + +class VariableArrayTypeLoc : + public InheritingConcreteTypeLoc<ArrayTypeLoc, + VariableArrayTypeLoc, + VariableArrayType> { +}; + + +// Location information for a TemplateName. Rudimentary for now. +struct TemplateNameLocInfo { + SourceLocation NameLoc; +}; + +struct TemplateSpecializationLocInfo : TemplateNameLocInfo { + SourceLocation TemplateKWLoc; + SourceLocation LAngleLoc; + SourceLocation RAngleLoc; +}; + +class TemplateSpecializationTypeLoc : + public ConcreteTypeLoc<UnqualTypeLoc, + TemplateSpecializationTypeLoc, + TemplateSpecializationType, + TemplateSpecializationLocInfo> { +public: + SourceLocation getTemplateKeywordLoc() const { + return getLocalData()->TemplateKWLoc; + } + void setTemplateKeywordLoc(SourceLocation Loc) { + getLocalData()->TemplateKWLoc = Loc; + } + + 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) { + 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 TypeSourceInfos 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 getLocalSourceRange() const { + if (getTemplateKeywordLoc().isValid()) + return SourceRange(getTemplateKeywordLoc(), getRAngleLoc()); + else + return SourceRange(getTemplateNameLoc(), getRAngleLoc()); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setTemplateKeywordLoc(Loc); + setTemplateNameLoc(Loc); + setLAngleLoc(Loc); + setRAngleLoc(Loc); + initializeArgLocs(Context, getNumArgs(), getTypePtr()->getArgs(), + getArgInfos(), Loc); + } + + static void initializeArgLocs(ASTContext &Context, unsigned NumArgs, + const TemplateArgument *Args, + TemplateArgumentLocInfo *ArgInfos, + SourceLocation Loc); + + unsigned getExtraLocalDataSize() const { + return getNumArgs() * sizeof(TemplateArgumentLocInfo); + } + + unsigned getExtraLocalDataAlignment() const { + return llvm::alignOf<TemplateArgumentLocInfo>(); + } + +private: + TemplateArgumentLocInfo *getArgInfos() const { + return static_cast<TemplateArgumentLocInfo*>(getExtraLocalData()); + } +}; + +//===----------------------------------------------------------------------===// +// +// All of these need proper implementations. +// +//===----------------------------------------------------------------------===// + +// FIXME: size expression and attribute locations (or keyword if we +// ever fully support altivec syntax). +class VectorTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, + VectorTypeLoc, + VectorType> { +}; + +// FIXME: size expression and attribute locations. +class ExtVectorTypeLoc : public InheritingConcreteTypeLoc<VectorTypeLoc, + ExtVectorTypeLoc, + ExtVectorType> { +}; + +// FIXME: attribute locations. +// For some reason, this isn't a subtype of VectorType. +class DependentSizedExtVectorTypeLoc : + public InheritingConcreteTypeLoc<TypeSpecTypeLoc, + DependentSizedExtVectorTypeLoc, + DependentSizedExtVectorType> { +}; + +// FIXME: location of the '_Complex' keyword. +class ComplexTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, + ComplexTypeLoc, + ComplexType> { +}; + +struct TypeofLocInfo { + SourceLocation TypeofLoc; + SourceLocation LParenLoc; + SourceLocation RParenLoc; +}; + +struct TypeOfExprTypeLocInfo : public TypeofLocInfo { +}; + +struct TypeOfTypeLocInfo : public TypeofLocInfo { + TypeSourceInfo* UnderlyingTInfo; +}; + +template <class Derived, class TypeClass, class LocalData = TypeofLocInfo> +class TypeofLikeTypeLoc + : public ConcreteTypeLoc<UnqualTypeLoc, Derived, TypeClass, LocalData> { +public: + SourceLocation getTypeofLoc() const { + return this->getLocalData()->TypeofLoc; + } + void setTypeofLoc(SourceLocation Loc) { + this->getLocalData()->TypeofLoc = Loc; + } + + SourceLocation getLParenLoc() const { + return this->getLocalData()->LParenLoc; + } + void setLParenLoc(SourceLocation Loc) { + this->getLocalData()->LParenLoc = Loc; + } + + SourceLocation getRParenLoc() const { + return this->getLocalData()->RParenLoc; + } + void setRParenLoc(SourceLocation Loc) { + this->getLocalData()->RParenLoc = Loc; + } + + SourceRange getParensRange() const { + return SourceRange(getLParenLoc(), getRParenLoc()); + } + void setParensRange(SourceRange range) { + setLParenLoc(range.getBegin()); + setRParenLoc(range.getEnd()); + } + + SourceRange getLocalSourceRange() const { + return SourceRange(getTypeofLoc(), getRParenLoc()); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setTypeofLoc(Loc); + setLParenLoc(Loc); + setRParenLoc(Loc); + } +}; + +class TypeOfExprTypeLoc : public TypeofLikeTypeLoc<TypeOfExprTypeLoc, + TypeOfExprType, + TypeOfExprTypeLocInfo> { +public: + Expr* getUnderlyingExpr() const { + return getTypePtr()->getUnderlyingExpr(); + } + // Reimplemented to account for GNU/C++ extension + // typeof unary-expression + // where there are no parentheses. + SourceRange getLocalSourceRange() const; +}; + +class TypeOfTypeLoc + : public TypeofLikeTypeLoc<TypeOfTypeLoc, TypeOfType, TypeOfTypeLocInfo> { +public: + QualType getUnderlyingType() const { + return this->getTypePtr()->getUnderlyingType(); + } + TypeSourceInfo* getUnderlyingTInfo() const { + return this->getLocalData()->UnderlyingTInfo; + } + void setUnderlyingTInfo(TypeSourceInfo* TI) const { + this->getLocalData()->UnderlyingTInfo = TI; + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc); +}; + +// FIXME: location of the 'decltype' and parens. +class DecltypeTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, + DecltypeTypeLoc, + DecltypeType> { +public: + Expr *getUnderlyingExpr() const { return getTypePtr()->getUnderlyingExpr(); } +}; + +struct UnaryTransformTypeLocInfo { + // FIXME: While there's only one unary transform right now, future ones may + // need different representations + SourceLocation KWLoc, LParenLoc, RParenLoc; + TypeSourceInfo *UnderlyingTInfo; +}; + +class UnaryTransformTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, + UnaryTransformTypeLoc, + UnaryTransformType, + UnaryTransformTypeLocInfo> { +public: + SourceLocation getKWLoc() const { return getLocalData()->KWLoc; } + void setKWLoc(SourceLocation Loc) { getLocalData()->KWLoc = Loc; } + + SourceLocation getLParenLoc() const { return getLocalData()->LParenLoc; } + void setLParenLoc(SourceLocation Loc) { getLocalData()->LParenLoc = Loc; } + + SourceLocation getRParenLoc() const { return getLocalData()->RParenLoc; } + void setRParenLoc(SourceLocation Loc) { getLocalData()->RParenLoc = Loc; } + + TypeSourceInfo* getUnderlyingTInfo() const { + return getLocalData()->UnderlyingTInfo; + } + void setUnderlyingTInfo(TypeSourceInfo *TInfo) { + getLocalData()->UnderlyingTInfo = TInfo; + } + + SourceRange getLocalSourceRange() const { + return SourceRange(getKWLoc(), getRParenLoc()); + } + + SourceRange getParensRange() const { + return SourceRange(getLParenLoc(), getRParenLoc()); + } + void setParensRange(SourceRange Range) { + setLParenLoc(Range.getBegin()); + setRParenLoc(Range.getEnd()); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setKWLoc(Loc); + setRParenLoc(Loc); + setLParenLoc(Loc); + } +}; + +class AutoTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, + AutoTypeLoc, + AutoType> { +}; + +struct ElaboratedLocInfo { + SourceLocation ElaboratedKWLoc; + /// \brief Data associated with the nested-name-specifier location. + void *QualifierData; +}; + +class ElaboratedTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, + ElaboratedTypeLoc, + ElaboratedType, + ElaboratedLocInfo> { +public: + SourceLocation getElaboratedKeywordLoc() const { + return this->getLocalData()->ElaboratedKWLoc; + } + void setElaboratedKeywordLoc(SourceLocation Loc) { + this->getLocalData()->ElaboratedKWLoc = Loc; + } + + NestedNameSpecifierLoc getQualifierLoc() const { + return NestedNameSpecifierLoc(getTypePtr()->getQualifier(), + getLocalData()->QualifierData); + } + + void setQualifierLoc(NestedNameSpecifierLoc QualifierLoc) { + assert(QualifierLoc.getNestedNameSpecifier() + == getTypePtr()->getQualifier() && + "Inconsistent nested-name-specifier pointer"); + getLocalData()->QualifierData = QualifierLoc.getOpaqueData(); + } + + SourceRange getLocalSourceRange() const { + if (getElaboratedKeywordLoc().isValid()) + if (getQualifierLoc()) + return SourceRange(getElaboratedKeywordLoc(), + getQualifierLoc().getEndLoc()); + else + return SourceRange(getElaboratedKeywordLoc()); + else + return getQualifierLoc().getSourceRange(); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc); + + TypeLoc getNamedTypeLoc() const { + return getInnerTypeLoc(); + } + + QualType getInnerType() const { + return getTypePtr()->getNamedType(); + } + + void copy(ElaboratedTypeLoc Loc) { + unsigned size = getFullDataSize(); + assert(size == Loc.getFullDataSize()); + memcpy(Data, Loc.Data, size); + } +}; + +// This is exactly the structure of an ElaboratedTypeLoc whose inner +// type is some sort of TypeDeclTypeLoc. +struct DependentNameLocInfo : ElaboratedLocInfo { + SourceLocation NameLoc; +}; + +class DependentNameTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, + DependentNameTypeLoc, + DependentNameType, + DependentNameLocInfo> { +public: + SourceLocation getElaboratedKeywordLoc() const { + return this->getLocalData()->ElaboratedKWLoc; + } + void setElaboratedKeywordLoc(SourceLocation Loc) { + this->getLocalData()->ElaboratedKWLoc = Loc; + } + + NestedNameSpecifierLoc getQualifierLoc() const { + return NestedNameSpecifierLoc(getTypePtr()->getQualifier(), + getLocalData()->QualifierData); + } + + void setQualifierLoc(NestedNameSpecifierLoc QualifierLoc) { + assert(QualifierLoc.getNestedNameSpecifier() + == getTypePtr()->getQualifier() && + "Inconsistent nested-name-specifier pointer"); + getLocalData()->QualifierData = QualifierLoc.getOpaqueData(); + } + + SourceLocation getNameLoc() const { + return this->getLocalData()->NameLoc; + } + void setNameLoc(SourceLocation Loc) { + this->getLocalData()->NameLoc = Loc; + } + + SourceRange getLocalSourceRange() const { + if (getElaboratedKeywordLoc().isValid()) + return SourceRange(getElaboratedKeywordLoc(), getNameLoc()); + else + return SourceRange(getQualifierLoc().getBeginLoc(), getNameLoc()); + } + + void copy(DependentNameTypeLoc Loc) { + unsigned size = getFullDataSize(); + assert(size == Loc.getFullDataSize()); + memcpy(Data, Loc.Data, size); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc); +}; + +struct DependentTemplateSpecializationLocInfo : DependentNameLocInfo { + SourceLocation TemplateKWLoc; + SourceLocation LAngleLoc; + SourceLocation RAngleLoc; + // followed by a TemplateArgumentLocInfo[] +}; + +class DependentTemplateSpecializationTypeLoc : + public ConcreteTypeLoc<UnqualTypeLoc, + DependentTemplateSpecializationTypeLoc, + DependentTemplateSpecializationType, + DependentTemplateSpecializationLocInfo> { +public: + SourceLocation getElaboratedKeywordLoc() const { + return this->getLocalData()->ElaboratedKWLoc; + } + void setElaboratedKeywordLoc(SourceLocation Loc) { + this->getLocalData()->ElaboratedKWLoc = Loc; + } + + NestedNameSpecifierLoc getQualifierLoc() const { + if (!getLocalData()->QualifierData) + return NestedNameSpecifierLoc(); + + return NestedNameSpecifierLoc(getTypePtr()->getQualifier(), + getLocalData()->QualifierData); + } + + void setQualifierLoc(NestedNameSpecifierLoc QualifierLoc) { + if (!QualifierLoc) { + // Even if we have a nested-name-specifier in the dependent + // template specialization type, we won't record the nested-name-specifier + // location information when this type-source location information is + // part of a nested-name-specifier. + getLocalData()->QualifierData = nullptr; + return; + } + + assert(QualifierLoc.getNestedNameSpecifier() + == getTypePtr()->getQualifier() && + "Inconsistent nested-name-specifier pointer"); + getLocalData()->QualifierData = QualifierLoc.getOpaqueData(); + } + + SourceLocation getTemplateKeywordLoc() const { + return getLocalData()->TemplateKWLoc; + } + void setTemplateKeywordLoc(SourceLocation Loc) { + getLocalData()->TemplateKWLoc = Loc; + } + + SourceLocation getTemplateNameLoc() const { + return this->getLocalData()->NameLoc; + } + void setTemplateNameLoc(SourceLocation Loc) { + this->getLocalData()->NameLoc = Loc; + } + + SourceLocation getLAngleLoc() const { + return this->getLocalData()->LAngleLoc; + } + void setLAngleLoc(SourceLocation Loc) { + this->getLocalData()->LAngleLoc = Loc; + } + + SourceLocation getRAngleLoc() const { + return this->getLocalData()->RAngleLoc; + } + void setRAngleLoc(SourceLocation Loc) { + this->getLocalData()->RAngleLoc = Loc; + } + + unsigned getNumArgs() const { + return getTypePtr()->getNumArgs(); + } + + void setArgLocInfo(unsigned i, TemplateArgumentLocInfo AI) { + getArgInfos()[i] = AI; + } + TemplateArgumentLocInfo getArgLocInfo(unsigned i) const { + return getArgInfos()[i]; + } + + TemplateArgumentLoc getArgLoc(unsigned i) const { + return TemplateArgumentLoc(getTypePtr()->getArg(i), getArgLocInfo(i)); + } + + SourceRange getLocalSourceRange() const { + if (getElaboratedKeywordLoc().isValid()) + return SourceRange(getElaboratedKeywordLoc(), getRAngleLoc()); + else if (getQualifierLoc()) + return SourceRange(getQualifierLoc().getBeginLoc(), getRAngleLoc()); + else if (getTemplateKeywordLoc().isValid()) + return SourceRange(getTemplateKeywordLoc(), getRAngleLoc()); + else + return SourceRange(getTemplateNameLoc(), getRAngleLoc()); + } + + void copy(DependentTemplateSpecializationTypeLoc Loc) { + unsigned size = getFullDataSize(); + assert(size == Loc.getFullDataSize()); + memcpy(Data, Loc.Data, size); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc); + + unsigned getExtraLocalDataSize() const { + return getNumArgs() * sizeof(TemplateArgumentLocInfo); + } + + unsigned getExtraLocalDataAlignment() const { + return llvm::alignOf<TemplateArgumentLocInfo>(); + } + +private: + TemplateArgumentLocInfo *getArgInfos() const { + return static_cast<TemplateArgumentLocInfo*>(getExtraLocalData()); + } +}; + + +struct PackExpansionTypeLocInfo { + SourceLocation EllipsisLoc; +}; + +class PackExpansionTypeLoc + : public ConcreteTypeLoc<UnqualTypeLoc, PackExpansionTypeLoc, + PackExpansionType, PackExpansionTypeLocInfo> { +public: + SourceLocation getEllipsisLoc() const { + return this->getLocalData()->EllipsisLoc; + } + + void setEllipsisLoc(SourceLocation Loc) { + this->getLocalData()->EllipsisLoc = Loc; + } + + SourceRange getLocalSourceRange() const { + return SourceRange(getEllipsisLoc(), getEllipsisLoc()); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setEllipsisLoc(Loc); + } + + TypeLoc getPatternLoc() const { + return getInnerTypeLoc(); + } + + QualType getInnerType() const { + return this->getTypePtr()->getPattern(); + } +}; + +struct AtomicTypeLocInfo { + SourceLocation KWLoc, LParenLoc, RParenLoc; +}; + +class AtomicTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, AtomicTypeLoc, + AtomicType, AtomicTypeLocInfo> { +public: + TypeLoc getValueLoc() const { + return this->getInnerTypeLoc(); + } + + SourceRange getLocalSourceRange() const { + return SourceRange(getKWLoc(), getRParenLoc()); + } + + SourceLocation getKWLoc() const { + return this->getLocalData()->KWLoc; + } + void setKWLoc(SourceLocation Loc) { + this->getLocalData()->KWLoc = Loc; + } + + SourceLocation getLParenLoc() const { + return this->getLocalData()->LParenLoc; + } + void setLParenLoc(SourceLocation Loc) { + this->getLocalData()->LParenLoc = Loc; + } + + SourceLocation getRParenLoc() const { + return this->getLocalData()->RParenLoc; + } + void setRParenLoc(SourceLocation Loc) { + this->getLocalData()->RParenLoc = Loc; + } + + SourceRange getParensRange() const { + return SourceRange(getLParenLoc(), getRParenLoc()); + } + void setParensRange(SourceRange Range) { + setLParenLoc(Range.getBegin()); + setRParenLoc(Range.getEnd()); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setKWLoc(Loc); + setLParenLoc(Loc); + setRParenLoc(Loc); + } + + QualType getInnerType() const { + return this->getTypePtr()->getValueType(); + } +}; + + +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/TypeLocNodes.def b/contrib/llvm/tools/clang/include/clang/AST/TypeLocNodes.def new file mode 100644 index 0000000..4590e48 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/TypeLocNodes.def @@ -0,0 +1,41 @@ +//===-- TypeLocNodes.def - Metadata about TypeLoc wrappers ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TypeLoc info database. Each node is +// enumerated by providing its core name (e.g., "Pointer" for "PointerTypeLoc") +// and base class (e.g., "DeclaratorLoc"). All nodes except QualifiedTypeLoc +// are associated +// +// TYPELOC(Class, Base) - A TypeLoc subclass. If UNQUAL_TYPELOC is +// provided, there will be exactly one of these, Qualified. +// +// UNQUAL_TYPELOC(Class, Base, Type) - An UnqualTypeLoc subclass. +// +// ABSTRACT_TYPELOC(Class) - Refers to TypeSpecLoc and DeclaratorLoc. +// +//===----------------------------------------------------------------------===// + +#ifndef UNQUAL_TYPELOC +# define UNQUAL_TYPELOC(Class, Base) TYPELOC(Class, Base) +#endif + +#ifndef ABSTRACT_TYPELOC +# define ABSTRACT_TYPELOC(Class, Base) UNQUAL_TYPELOC(Class, Base) +#endif + +TYPELOC(Qualified, TypeLoc) +#define TYPE(Class, Base) UNQUAL_TYPELOC(Class, Base##Loc) +#define ABSTRACT_TYPE(Class, Base) ABSTRACT_TYPELOC(Class, Base##Loc) +#include "clang/AST/TypeNodes.def" + +#undef DECLARATOR_TYPELOC +#undef TYPESPEC_TYPELOC +#undef ABSTRACT_TYPELOC +#undef UNQUAL_TYPELOC +#undef TYPELOC diff --git a/contrib/llvm/tools/clang/include/clang/AST/TypeLocVisitor.h b/contrib/llvm/tools/clang/include/clang/AST/TypeLocVisitor.h new file mode 100644 index 0000000..db5775a --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/TypeLocVisitor.h @@ -0,0 +1,62 @@ +//===--- TypeLocVisitor.h - Visitor for TypeLoc subclasses ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TypeLocVisitor interface. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_TYPELOCVISITOR_H +#define LLVM_CLANG_AST_TYPELOCVISITOR_H + +#include "clang/AST/TypeLoc.h" +#include "clang/AST/TypeVisitor.h" +#include "llvm/Support/ErrorHandling.h" + +namespace clang { + +#define DISPATCH(CLASSNAME) \ + return static_cast<ImplClass*>(this)-> \ + Visit##CLASSNAME(TyLoc.castAs<CLASSNAME>()) + +template<typename ImplClass, typename RetTy=void> +class TypeLocVisitor { +public: + RetTy Visit(TypeLoc TyLoc) { + switch (TyLoc.getTypeLocClass()) { +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + case TypeLoc::CLASS: DISPATCH(CLASS##TypeLoc); +#include "clang/AST/TypeLocNodes.def" + } + llvm_unreachable("unexpected type loc class!"); + } + + RetTy Visit(UnqualTypeLoc TyLoc) { + switch (TyLoc.getTypeLocClass()) { +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + case TypeLoc::CLASS: DISPATCH(CLASS##TypeLoc); +#include "clang/AST/TypeLocNodes.def" + } + llvm_unreachable("unexpected type loc class!"); + } + +#define TYPELOC(CLASS, PARENT) \ + RetTy Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ + DISPATCH(PARENT); \ + } +#include "clang/AST/TypeLocNodes.def" + + RetTy VisitTypeLoc(TypeLoc TyLoc) { return RetTy(); } +}; + +#undef DISPATCH + +} // end namespace clang + +#endif // LLVM_CLANG_AST_TYPELOCVISITOR_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/TypeNodes.def b/contrib/llvm/tools/clang/include/clang/AST/TypeNodes.def new file mode 100644 index 0000000..2549f0b --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/TypeNodes.def @@ -0,0 +1,129 @@ +//===-- TypeNodes.def - Metadata about Type AST nodes -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the AST type info database. Each type node is +// enumerated by providing its name (e.g., "Builtin" or "Enum") and +// base class (e.g., "Type" or "TagType"). Depending on where in the +// abstract syntax tree the type will show up, the enumeration uses +// one of five different macros: +// +// TYPE(Class, Base) - A type that can show up anywhere in the AST, +// and might be dependent, canonical, or non-canonical. All clients +// will need to understand these types. +// +// ABSTRACT_TYPE(Class, Base) - An abstract class that shows up in +// the type hierarchy but has no concrete instances. +// +// NON_CANONICAL_TYPE(Class, Base) - A type that can show up +// anywhere in the AST but will never be a part of a canonical +// type. Clients that only need to deal with canonical types +// (ignoring, e.g., typedefs and other type alises used for +// pretty-printing) can ignore these types. +// +// DEPENDENT_TYPE(Class, Base) - A type that will only show up +// within a C++ template that has not been instantiated, e.g., a +// type that is always dependent. Clients that do not need to deal +// with uninstantiated C++ templates can ignore these types. +// +// NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) - A type that +// is non-canonical unless it is dependent. Defaults to TYPE because +// it is neither reliably dependent nor reliably non-canonical. +// +// There is a sixth macro, independent of the others. Most clients +// will not need to use it. +// +// LEAF_TYPE(Class) - A type that never has inner types. Clients +// which can operate on such types more efficiently may wish to do so. +// +//===----------------------------------------------------------------------===// + +#ifndef ABSTRACT_TYPE +# define ABSTRACT_TYPE(Class, Base) TYPE(Class, Base) +#endif + +#ifndef NON_CANONICAL_TYPE +# define NON_CANONICAL_TYPE(Class, Base) TYPE(Class, Base) +#endif + +#ifndef DEPENDENT_TYPE +# define DEPENDENT_TYPE(Class, Base) TYPE(Class, Base) +#endif + +#ifndef NON_CANONICAL_UNLESS_DEPENDENT_TYPE +# define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) TYPE(Class, Base) +#endif + +TYPE(Builtin, Type) +TYPE(Complex, Type) +TYPE(Pointer, Type) +TYPE(BlockPointer, Type) +ABSTRACT_TYPE(Reference, Type) +TYPE(LValueReference, ReferenceType) +TYPE(RValueReference, ReferenceType) +TYPE(MemberPointer, Type) +ABSTRACT_TYPE(Array, Type) +TYPE(ConstantArray, ArrayType) +TYPE(IncompleteArray, ArrayType) +TYPE(VariableArray, ArrayType) +DEPENDENT_TYPE(DependentSizedArray, ArrayType) +DEPENDENT_TYPE(DependentSizedExtVector, Type) +TYPE(Vector, Type) +TYPE(ExtVector, VectorType) +ABSTRACT_TYPE(Function, Type) +TYPE(FunctionProto, FunctionType) +TYPE(FunctionNoProto, FunctionType) +DEPENDENT_TYPE(UnresolvedUsing, Type) +NON_CANONICAL_TYPE(Paren, Type) +NON_CANONICAL_TYPE(Typedef, Type) +NON_CANONICAL_TYPE(Adjusted, Type) +NON_CANONICAL_TYPE(Decayed, AdjustedType) +NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TypeOfExpr, Type) +NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TypeOf, Type) +NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Decltype, Type) +NON_CANONICAL_UNLESS_DEPENDENT_TYPE(UnaryTransform, Type) +ABSTRACT_TYPE(Tag, Type) +TYPE(Record, TagType) +TYPE(Enum, TagType) +NON_CANONICAL_TYPE(Elaborated, Type) +NON_CANONICAL_TYPE(Attributed, Type) +DEPENDENT_TYPE(TemplateTypeParm, Type) +NON_CANONICAL_TYPE(SubstTemplateTypeParm, Type) +DEPENDENT_TYPE(SubstTemplateTypeParmPack, Type) +NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TemplateSpecialization, Type) +TYPE(Auto, Type) +DEPENDENT_TYPE(InjectedClassName, Type) +DEPENDENT_TYPE(DependentName, Type) +DEPENDENT_TYPE(DependentTemplateSpecialization, Type) +NON_CANONICAL_UNLESS_DEPENDENT_TYPE(PackExpansion, Type) +TYPE(ObjCObject, Type) +TYPE(ObjCInterface, ObjCObjectType) +TYPE(ObjCObjectPointer, Type) +TYPE(Atomic, Type) + +#ifdef LAST_TYPE +LAST_TYPE(Atomic) +#undef LAST_TYPE +#endif + +// These types are always leaves in the type hierarchy. +#ifdef LEAF_TYPE +LEAF_TYPE(Enum) +LEAF_TYPE(Builtin) +LEAF_TYPE(Record) +LEAF_TYPE(InjectedClassName) +LEAF_TYPE(ObjCInterface) +LEAF_TYPE(TemplateTypeParm) +#undef LEAF_TYPE +#endif + +#undef NON_CANONICAL_UNLESS_DEPENDENT_TYPE +#undef DEPENDENT_TYPE +#undef NON_CANONICAL_TYPE +#undef ABSTRACT_TYPE +#undef TYPE diff --git a/contrib/llvm/tools/clang/include/clang/AST/TypeOrdering.h b/contrib/llvm/tools/clang/include/clang/AST/TypeOrdering.h new file mode 100644 index 0000000..392e544 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/TypeOrdering.h @@ -0,0 +1,79 @@ +//===-------------- TypeOrdering.h - Total ordering for types -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Allows QualTypes to be sorted and hence used in maps and sets. +/// +/// Defines clang::QualTypeOrdering, a total ordering on clang::QualType, +/// and hence enables QualType values to be sorted and to be used in +/// std::maps, std::sets, llvm::DenseMaps, and llvm::DenseSets. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_TYPEORDERING_H +#define LLVM_CLANG_AST_TYPEORDERING_H + +#include "clang/AST/CanonicalType.h" +#include "clang/AST/Type.h" +#include <functional> + +namespace clang { + +/// \brief Function object that provides a total ordering on QualType values. +struct QualTypeOrdering : std::binary_function<QualType, QualType, bool> { + bool operator()(QualType T1, QualType T2) const { + return std::less<void*>()(T1.getAsOpaquePtr(), T2.getAsOpaquePtr()); + } +}; + +} + +namespace llvm { + template<class> struct DenseMapInfo; + + template<> struct DenseMapInfo<clang::QualType> { + static inline clang::QualType getEmptyKey() { return clang::QualType(); } + + static inline clang::QualType getTombstoneKey() { + using clang::QualType; + return QualType::getFromOpaquePtr(reinterpret_cast<clang::Type *>(-1)); + } + + static unsigned getHashValue(clang::QualType Val) { + return (unsigned)((uintptr_t)Val.getAsOpaquePtr()) ^ + ((unsigned)((uintptr_t)Val.getAsOpaquePtr() >> 9)); + } + + static bool isEqual(clang::QualType LHS, clang::QualType RHS) { + return LHS == RHS; + } + }; + + template<> struct DenseMapInfo<clang::CanQualType> { + static inline clang::CanQualType getEmptyKey() { + return clang::CanQualType(); + } + + static inline clang::CanQualType getTombstoneKey() { + using clang::CanQualType; + return CanQualType::getFromOpaquePtr(reinterpret_cast<clang::Type *>(-1)); + } + + static unsigned getHashValue(clang::CanQualType Val) { + return (unsigned)((uintptr_t)Val.getAsOpaquePtr()) ^ + ((unsigned)((uintptr_t)Val.getAsOpaquePtr() >> 9)); + } + + static bool isEqual(clang::CanQualType LHS, clang::CanQualType RHS) { + return LHS == RHS; + } + }; +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/TypeVisitor.h b/contrib/llvm/tools/clang/include/clang/AST/TypeVisitor.h new file mode 100644 index 0000000..11e5a47 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/TypeVisitor.h @@ -0,0 +1,95 @@ +//===--- TypeVisitor.h - Visitor for Type subclasses ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TypeVisitor interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_TYPEVISITOR_H +#define LLVM_CLANG_AST_TYPEVISITOR_H + +#include "clang/AST/Type.h" + +namespace clang { + +#define DISPATCH(CLASS) \ + return static_cast<ImplClass*>(this)-> \ + Visit##CLASS(static_cast<const CLASS*>(T)) + +/// \brief An operation on a type. +/// +/// \tparam ImplClass Class implementing the operation. Must be inherited from +/// TypeVisitor. +/// \tparam RetTy %Type of result produced by the operation. +/// +/// The class implements polymorphic operation on an object of type derived +/// from Type. The operation is performed by calling method Visit. It then +/// dispatches the call to function \c VisitFooType, if actual argument type +/// is \c FooType. +/// +/// The class implements static polymorphism using Curiously Recurring +/// Template Pattern. It is designed to be a base class for some concrete +/// class: +/// +/// \code +/// class SomeVisitor : public TypeVisitor<SomeVisitor,sometype> { ... }; +/// ... +/// Type *atype = ... +/// ... +/// SomeVisitor avisitor; +/// sometype result = avisitor.Visit(atype); +/// \endcode +/// +/// Actual treatment is made by methods of the derived class, TypeVisitor only +/// dispatches call to the appropriate method. If the implementation class +/// \c ImplClass provides specific action for some type, say +/// \c ConstantArrayType, it should define method +/// <tt>VisitConstantArrayType(const ConstantArrayType*)</tt>. Otherwise +/// \c TypeVisitor dispatches call to the method that handles parent type. In +/// this example handlers are tried in the sequence: +/// +/// \li <tt>ImplClass::VisitConstantArrayType(const ConstantArrayType*)</tt> +/// \li <tt>ImplClass::VisitArrayType(const ArrayType*)</tt> +/// \li <tt>ImplClass::VisitType(const Type*)</tt> +/// \li <tt>TypeVisitor::VisitType(const Type*)</tt> +/// +/// The first function of this sequence that is defined will handle object of +/// type \c ConstantArrayType. +template<typename ImplClass, typename RetTy=void> +class TypeVisitor { +public: + + /// \brief Performs the operation associated with this visitor object. + RetTy Visit(const Type *T) { + // Top switch stmt: dispatch to VisitFooType for each FooType. + switch (T->getTypeClass()) { +#define ABSTRACT_TYPE(CLASS, PARENT) +#define TYPE(CLASS, PARENT) case Type::CLASS: DISPATCH(CLASS##Type); +#include "clang/AST/TypeNodes.def" + } + llvm_unreachable("Unknown type class!"); + } + + // If the implementation chooses not to implement a certain visit method, fall + // back on superclass. +#define TYPE(CLASS, PARENT) RetTy Visit##CLASS##Type(const CLASS##Type *T) { \ + DISPATCH(PARENT); \ +} +#include "clang/AST/TypeNodes.def" + + /// \brief Method called if \c ImpClass doesn't provide specific handler + /// for some type class. + RetTy VisitType(const Type*) { return RetTy(); } +}; + +#undef DISPATCH + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/UnresolvedSet.h b/contrib/llvm/tools/clang/include/clang/AST/UnresolvedSet.h new file mode 100644 index 0000000..26ee1cf --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/UnresolvedSet.h @@ -0,0 +1,140 @@ +//===-- UnresolvedSet.h - Unresolved sets of declarations ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the UnresolvedSet class, which is used to store +// collections of declarations in the AST. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_UNRESOLVEDSET_H +#define LLVM_CLANG_AST_UNRESOLVEDSET_H + +#include "clang/AST/DeclAccessPair.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/iterator.h" + +namespace clang { + +/// The iterator over UnresolvedSets. Serves as both the const and +/// non-const iterator. +class UnresolvedSetIterator : public llvm::iterator_adaptor_base< + UnresolvedSetIterator, DeclAccessPair *, + std::random_access_iterator_tag, NamedDecl *, + std::ptrdiff_t, NamedDecl *, NamedDecl *> { + friend class UnresolvedSetImpl; + friend class ASTUnresolvedSet; + friend class OverloadExpr; + + explicit UnresolvedSetIterator(DeclAccessPair *Iter) + : iterator_adaptor_base(Iter) {} + explicit UnresolvedSetIterator(const DeclAccessPair *Iter) + : iterator_adaptor_base(const_cast<DeclAccessPair *>(Iter)) {} + +public: + UnresolvedSetIterator() {} + + NamedDecl *getDecl() const { return I->getDecl(); } + void setDecl(NamedDecl *ND) const { return I->setDecl(ND); } + AccessSpecifier getAccess() const { return I->getAccess(); } + void setAccess(AccessSpecifier AS) { I->setAccess(AS); } + const DeclAccessPair &getPair() const { return *I; } + + NamedDecl *operator*() const { return getDecl(); } + NamedDecl *operator->() const { return **this; } +}; + +/// \brief A set of unresolved declarations. +class UnresolvedSetImpl { + typedef SmallVectorImpl<DeclAccessPair> DeclsTy; + + // Don't allow direct construction, and only permit subclassing by + // UnresolvedSet. +private: + template <unsigned N> friend class UnresolvedSet; + UnresolvedSetImpl() {} + UnresolvedSetImpl(const UnresolvedSetImpl &) {} + +public: + // We don't currently support assignment through this iterator, so we might + // as well use the same implementation twice. + typedef UnresolvedSetIterator iterator; + typedef UnresolvedSetIterator const_iterator; + + iterator begin() { return iterator(decls().begin()); } + iterator end() { return iterator(decls().end()); } + + const_iterator begin() const { return const_iterator(decls().begin()); } + const_iterator end() const { return const_iterator(decls().end()); } + + void addDecl(NamedDecl *D) { + addDecl(D, AS_none); + } + + void addDecl(NamedDecl *D, AccessSpecifier AS) { + decls().push_back(DeclAccessPair::make(D, AS)); + } + + /// Replaces the given declaration with the new one, once. + /// + /// \return true if the set changed + bool replace(const NamedDecl* Old, NamedDecl *New) { + for (DeclsTy::iterator I = decls().begin(), E = decls().end(); I != E; ++I) + if (I->getDecl() == Old) + return (I->setDecl(New), true); + return false; + } + + /// Replaces the declaration at the given iterator with the new one, + /// preserving the original access bits. + void replace(iterator I, NamedDecl *New) { I.I->setDecl(New); } + + void replace(iterator I, NamedDecl *New, AccessSpecifier AS) { + I.I->set(New, AS); + } + + void erase(unsigned I) { decls()[I] = decls().pop_back_val(); } + + void erase(iterator I) { *I.I = decls().pop_back_val(); } + + void setAccess(iterator I, AccessSpecifier AS) { I.I->setAccess(AS); } + + void clear() { decls().clear(); } + void set_size(unsigned N) { decls().set_size(N); } + + bool empty() const { return decls().empty(); } + unsigned size() const { return decls().size(); } + + void append(iterator I, iterator E) { decls().append(I.I, E.I); } + + DeclAccessPair &operator[](unsigned I) { return decls()[I]; } + const DeclAccessPair &operator[](unsigned I) const { return decls()[I]; } + +private: + // These work because the only permitted subclass is UnresolvedSetImpl + + DeclsTy &decls() { + return *reinterpret_cast<DeclsTy*>(this); + } + const DeclsTy &decls() const { + return *reinterpret_cast<const DeclsTy*>(this); + } +}; + +/// \brief A set of unresolved declarations. +template <unsigned InlineCapacity> class UnresolvedSet : + public UnresolvedSetImpl { + SmallVector<DeclAccessPair, InlineCapacity> Decls; +}; + + +} // namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/VTTBuilder.h b/contrib/llvm/tools/clang/include/clang/AST/VTTBuilder.h new file mode 100644 index 0000000..727bf51 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/VTTBuilder.h @@ -0,0 +1,162 @@ +//===--- VTTBuilder.h - C++ VTT layout builder --------------------*- C++ -*-=// +// +// 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 generation of the layout of virtual table +// tables (VTT). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_VTTBUILDER_H +#define LLVM_CLANG_AST_VTTBUILDER_H + +#include "clang/AST/BaseSubobject.h" +#include "clang/AST/CXXInheritance.h" +#include "clang/AST/GlobalDecl.h" +#include "clang/AST/RecordLayout.h" +#include "clang/Basic/ABI.h" +#include "llvm/ADT/SetVector.h" +#include <utility> + +namespace clang { + +class VTTVTable { + llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> BaseAndIsVirtual; + CharUnits BaseOffset; + +public: + VTTVTable() {} + VTTVTable(const CXXRecordDecl *Base, CharUnits BaseOffset, bool BaseIsVirtual) + : BaseAndIsVirtual(Base, BaseIsVirtual), BaseOffset(BaseOffset) {} + VTTVTable(BaseSubobject Base, bool BaseIsVirtual) + : BaseAndIsVirtual(Base.getBase(), BaseIsVirtual), + BaseOffset(Base.getBaseOffset()) {} + + const CXXRecordDecl *getBase() const { + return BaseAndIsVirtual.getPointer(); + } + + CharUnits getBaseOffset() const { + return BaseOffset; + } + + bool isVirtual() const { + return BaseAndIsVirtual.getInt(); + } + + BaseSubobject getBaseSubobject() const { + return BaseSubobject(getBase(), getBaseOffset()); + } +}; + +struct VTTComponent { + uint64_t VTableIndex; + BaseSubobject VTableBase; + + VTTComponent() {} + VTTComponent(uint64_t VTableIndex, BaseSubobject VTableBase) + : VTableIndex(VTableIndex), VTableBase(VTableBase) {} +}; + +/// \brief Class for building VTT layout information. +class VTTBuilder { + + ASTContext &Ctx; + + /// \brief The most derived class for which we're building this vtable. + const CXXRecordDecl *MostDerivedClass; + + typedef SmallVector<VTTVTable, 64> VTTVTablesVectorTy; + + /// \brief The VTT vtables. + VTTVTablesVectorTy VTTVTables; + + typedef SmallVector<VTTComponent, 64> VTTComponentsVectorTy; + + /// \brief The VTT components. + VTTComponentsVectorTy VTTComponents; + + /// \brief The AST record layout of the most derived class. + const ASTRecordLayout &MostDerivedClassLayout; + + typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy; + + typedef llvm::DenseMap<BaseSubobject, uint64_t> AddressPointsMapTy; + + /// \brief The sub-VTT indices for the bases of the most derived class. + llvm::DenseMap<BaseSubobject, uint64_t> SubVTTIndicies; + + /// \brief The secondary virtual pointer indices of all subobjects of + /// the most derived class. + llvm::DenseMap<BaseSubobject, uint64_t> SecondaryVirtualPointerIndices; + + /// \brief Whether the VTT builder should generate LLVM IR for the VTT. + bool GenerateDefinition; + + /// \brief Add a vtable pointer to the VTT currently being built. + void AddVTablePointer(BaseSubobject Base, uint64_t VTableIndex, + const CXXRecordDecl *VTableClass); + + /// \brief Lay out the secondary VTTs of the given base subobject. + void LayoutSecondaryVTTs(BaseSubobject Base); + + /// \brief Lay out the secondary virtual pointers for the given base + /// subobject. + /// + /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base + /// or a direct or indirect base of a virtual base. + void LayoutSecondaryVirtualPointers(BaseSubobject Base, + bool BaseIsMorallyVirtual, + uint64_t VTableIndex, + const CXXRecordDecl *VTableClass, + VisitedVirtualBasesSetTy &VBases); + + /// \brief Lay out the secondary virtual pointers for the given base + /// subobject. + void LayoutSecondaryVirtualPointers(BaseSubobject Base, + uint64_t VTableIndex); + + /// \brief Lay out the VTTs for the virtual base classes of the given + /// record declaration. + void LayoutVirtualVTTs(const CXXRecordDecl *RD, + VisitedVirtualBasesSetTy &VBases); + + /// \brief Lay out the VTT for the given subobject, including any + /// secondary VTTs, secondary virtual pointers and virtual VTTs. + void LayoutVTT(BaseSubobject Base, bool BaseIsVirtual); + +public: + VTTBuilder(ASTContext &Ctx, const CXXRecordDecl *MostDerivedClass, + bool GenerateDefinition); + + // \brief Returns a reference to the VTT components. + const VTTComponentsVectorTy &getVTTComponents() const { + return VTTComponents; + } + + // \brief Returns a reference to the VTT vtables. + const VTTVTablesVectorTy &getVTTVTables() const { + return VTTVTables; + } + + /// \brief Returns a reference to the sub-VTT indices. + const llvm::DenseMap<BaseSubobject, uint64_t> &getSubVTTIndicies() const { + return SubVTTIndicies; + } + + /// \brief Returns a reference to the secondary virtual pointer indices. + const llvm::DenseMap<BaseSubobject, uint64_t> & + getSecondaryVirtualPointerIndices() const { + return SecondaryVirtualPointerIndices; + } + +}; + +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/AST/VTableBuilder.h b/contrib/llvm/tools/clang/include/clang/AST/VTableBuilder.h new file mode 100644 index 0000000..481fd11 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/VTableBuilder.h @@ -0,0 +1,566 @@ +//===--- VTableBuilder.h - C++ vtable layout builder --------------*- C++ -*-=// +// +// 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 generation of the layout of virtual tables. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_VTABLEBUILDER_H +#define LLVM_CLANG_AST_VTABLEBUILDER_H + +#include "clang/AST/BaseSubobject.h" +#include "clang/AST/CXXInheritance.h" +#include "clang/AST/GlobalDecl.h" +#include "clang/AST/RecordLayout.h" +#include "clang/Basic/ABI.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SetVector.h" +#include <memory> +#include <utility> + +namespace clang { + class CXXRecordDecl; + +/// \brief Represents a single component in a vtable. +class VTableComponent { +public: + enum Kind { + CK_VCallOffset, + CK_VBaseOffset, + CK_OffsetToTop, + CK_RTTI, + CK_FunctionPointer, + + /// \brief A pointer to the complete destructor. + CK_CompleteDtorPointer, + + /// \brief A pointer to the deleting destructor. + CK_DeletingDtorPointer, + + /// \brief An entry that is never used. + /// + /// In some cases, a vtable function pointer will end up never being + /// called. Such vtable function pointers are represented as a + /// CK_UnusedFunctionPointer. + CK_UnusedFunctionPointer + }; + + VTableComponent() = default; + + static VTableComponent MakeVCallOffset(CharUnits Offset) { + return VTableComponent(CK_VCallOffset, Offset); + } + + static VTableComponent MakeVBaseOffset(CharUnits Offset) { + return VTableComponent(CK_VBaseOffset, Offset); + } + + static VTableComponent MakeOffsetToTop(CharUnits Offset) { + return VTableComponent(CK_OffsetToTop, Offset); + } + + static VTableComponent MakeRTTI(const CXXRecordDecl *RD) { + return VTableComponent(CK_RTTI, reinterpret_cast<uintptr_t>(RD)); + } + + static VTableComponent MakeFunction(const CXXMethodDecl *MD) { + assert(!isa<CXXDestructorDecl>(MD) && + "Don't use MakeFunction with destructors!"); + + return VTableComponent(CK_FunctionPointer, + reinterpret_cast<uintptr_t>(MD)); + } + + static VTableComponent MakeCompleteDtor(const CXXDestructorDecl *DD) { + return VTableComponent(CK_CompleteDtorPointer, + reinterpret_cast<uintptr_t>(DD)); + } + + static VTableComponent MakeDeletingDtor(const CXXDestructorDecl *DD) { + return VTableComponent(CK_DeletingDtorPointer, + reinterpret_cast<uintptr_t>(DD)); + } + + static VTableComponent MakeUnusedFunction(const CXXMethodDecl *MD) { + assert(!isa<CXXDestructorDecl>(MD) && + "Don't use MakeUnusedFunction with destructors!"); + return VTableComponent(CK_UnusedFunctionPointer, + reinterpret_cast<uintptr_t>(MD)); + } + + static VTableComponent getFromOpaqueInteger(uint64_t I) { + return VTableComponent(I); + } + + /// \brief Get the kind of this vtable component. + Kind getKind() const { + return (Kind)(Value & 0x7); + } + + CharUnits getVCallOffset() const { + assert(getKind() == CK_VCallOffset && "Invalid component kind!"); + + return getOffset(); + } + + CharUnits getVBaseOffset() const { + assert(getKind() == CK_VBaseOffset && "Invalid component kind!"); + + return getOffset(); + } + + CharUnits getOffsetToTop() const { + assert(getKind() == CK_OffsetToTop && "Invalid component kind!"); + + return getOffset(); + } + + const CXXRecordDecl *getRTTIDecl() const { + assert(isRTTIKind() && "Invalid component kind!"); + return reinterpret_cast<CXXRecordDecl *>(getPointer()); + } + + const CXXMethodDecl *getFunctionDecl() const { + assert(isFunctionPointerKind() && "Invalid component kind!"); + if (isDestructorKind()) + return getDestructorDecl(); + return reinterpret_cast<CXXMethodDecl *>(getPointer()); + } + + const CXXDestructorDecl *getDestructorDecl() const { + assert(isDestructorKind() && "Invalid component kind!"); + return reinterpret_cast<CXXDestructorDecl *>(getPointer()); + } + + const CXXMethodDecl *getUnusedFunctionDecl() const { + assert(getKind() == CK_UnusedFunctionPointer && "Invalid component kind!"); + return reinterpret_cast<CXXMethodDecl *>(getPointer()); + } + + bool isDestructorKind() const { return isDestructorKind(getKind()); } + + bool isUsedFunctionPointerKind() const { + return isUsedFunctionPointerKind(getKind()); + } + + bool isFunctionPointerKind() const { + return isFunctionPointerKind(getKind()); + } + + bool isRTTIKind() const { return isRTTIKind(getKind()); } + +private: + static bool isFunctionPointerKind(Kind ComponentKind) { + return isUsedFunctionPointerKind(ComponentKind) || + ComponentKind == CK_UnusedFunctionPointer; + } + static bool isUsedFunctionPointerKind(Kind ComponentKind) { + return ComponentKind == CK_FunctionPointer || + isDestructorKind(ComponentKind); + } + static bool isDestructorKind(Kind ComponentKind) { + return ComponentKind == CK_CompleteDtorPointer || + ComponentKind == CK_DeletingDtorPointer; + } + static bool isRTTIKind(Kind ComponentKind) { + return ComponentKind == CK_RTTI; + } + + VTableComponent(Kind ComponentKind, CharUnits Offset) { + assert((ComponentKind == CK_VCallOffset || + ComponentKind == CK_VBaseOffset || + ComponentKind == CK_OffsetToTop) && "Invalid component kind!"); + assert(Offset.getQuantity() < (1LL << 56) && "Offset is too big!"); + assert(Offset.getQuantity() >= -(1LL << 56) && "Offset is too small!"); + + Value = (uint64_t(Offset.getQuantity()) << 3) | ComponentKind; + } + + VTableComponent(Kind ComponentKind, uintptr_t Ptr) { + assert((isRTTIKind(ComponentKind) || isFunctionPointerKind(ComponentKind)) && + "Invalid component kind!"); + + assert((Ptr & 7) == 0 && "Pointer not sufficiently aligned!"); + + Value = Ptr | ComponentKind; + } + + CharUnits getOffset() const { + assert((getKind() == CK_VCallOffset || getKind() == CK_VBaseOffset || + getKind() == CK_OffsetToTop) && "Invalid component kind!"); + + return CharUnits::fromQuantity(Value >> 3); + } + + uintptr_t getPointer() const { + assert((getKind() == CK_RTTI || isFunctionPointerKind()) && + "Invalid component kind!"); + + return static_cast<uintptr_t>(Value & ~7ULL); + } + + explicit VTableComponent(uint64_t Value) + : Value(Value) { } + + /// The kind is stored in the lower 3 bits of the value. For offsets, we + /// make use of the facts that classes can't be larger than 2^55 bytes, + /// so we store the offset in the lower part of the 61 bits that remain. + /// (The reason that we're not simply using a PointerIntPair here is that we + /// need the offsets to be 64-bit, even when on a 32-bit machine). + int64_t Value; +}; + +class VTableLayout { +public: + typedef std::pair<uint64_t, ThunkInfo> VTableThunkTy; + + typedef const VTableComponent *vtable_component_iterator; + typedef const VTableThunkTy *vtable_thunk_iterator; + typedef llvm::iterator_range<vtable_component_iterator> + vtable_component_range; + + typedef llvm::DenseMap<BaseSubobject, uint64_t> AddressPointsMapTy; + +private: + uint64_t NumVTableComponents; + std::unique_ptr<VTableComponent[]> VTableComponents; + + /// \brief Contains thunks needed by vtables, sorted by indices. + uint64_t NumVTableThunks; + std::unique_ptr<VTableThunkTy[]> VTableThunks; + + /// \brief Address points for all vtables. + AddressPointsMapTy AddressPoints; + + bool IsMicrosoftABI; + +public: + VTableLayout(uint64_t NumVTableComponents, + const VTableComponent *VTableComponents, + uint64_t NumVTableThunks, + const VTableThunkTy *VTableThunks, + const AddressPointsMapTy &AddressPoints, + bool IsMicrosoftABI); + ~VTableLayout(); + + uint64_t getNumVTableComponents() const { + return NumVTableComponents; + } + + vtable_component_range vtable_components() const { + return vtable_component_range(vtable_component_begin(), + vtable_component_end()); + } + + vtable_component_iterator vtable_component_begin() const { + return VTableComponents.get(); + } + + vtable_component_iterator vtable_component_end() const { + return VTableComponents.get() + NumVTableComponents; + } + + uint64_t getNumVTableThunks() const { return NumVTableThunks; } + + vtable_thunk_iterator vtable_thunk_begin() const { + return VTableThunks.get(); + } + + vtable_thunk_iterator vtable_thunk_end() const { + return VTableThunks.get() + NumVTableThunks; + } + + uint64_t getAddressPoint(BaseSubobject Base) const { + assert(AddressPoints.count(Base) && + "Did not find address point!"); + + uint64_t AddressPoint = AddressPoints.lookup(Base); + assert(AddressPoint != 0 || IsMicrosoftABI); + (void)IsMicrosoftABI; + + return AddressPoint; + } + + const AddressPointsMapTy &getAddressPoints() const { + return AddressPoints; + } +}; + +class VTableContextBase { +public: + typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy; + + bool isMicrosoft() const { return IsMicrosoftABI; } + + virtual ~VTableContextBase() {} + +protected: + typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy; + + /// \brief Contains all thunks that a given method decl will need. + ThunksMapTy Thunks; + + /// Compute and store all vtable related information (vtable layout, vbase + /// offset offsets, thunks etc) for the given record decl. + virtual void computeVTableRelatedInformation(const CXXRecordDecl *RD) = 0; + + VTableContextBase(bool MS) : IsMicrosoftABI(MS) {} + +public: + virtual const ThunkInfoVectorTy *getThunkInfo(GlobalDecl GD) { + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()->getCanonicalDecl()); + computeVTableRelatedInformation(MD->getParent()); + + // This assumes that all the destructors present in the vtable + // use exactly the same set of thunks. + ThunksMapTy::const_iterator I = Thunks.find(MD); + if (I == Thunks.end()) { + // We did not find a thunk for this method. + return nullptr; + } + + return &I->second; + } + + bool IsMicrosoftABI; +}; + +class ItaniumVTableContext : public VTableContextBase { +private: + + /// \brief Contains the index (relative to the vtable address point) + /// where the function pointer for a virtual function is stored. + typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVTableIndicesTy; + MethodVTableIndicesTy MethodVTableIndices; + + typedef llvm::DenseMap<const CXXRecordDecl *, const VTableLayout *> + VTableLayoutMapTy; + VTableLayoutMapTy VTableLayouts; + + typedef std::pair<const CXXRecordDecl *, + const CXXRecordDecl *> ClassPairTy; + + /// \brief vtable offsets for offsets of virtual bases of a class. + /// + /// Contains the vtable offset (relative to the address point) in chars + /// where the offsets for virtual bases of a class are stored. + typedef llvm::DenseMap<ClassPairTy, CharUnits> + VirtualBaseClassOffsetOffsetsMapTy; + VirtualBaseClassOffsetOffsetsMapTy VirtualBaseClassOffsetOffsets; + + void computeVTableRelatedInformation(const CXXRecordDecl *RD) override; + +public: + ItaniumVTableContext(ASTContext &Context); + ~ItaniumVTableContext() override; + + const VTableLayout &getVTableLayout(const CXXRecordDecl *RD) { + computeVTableRelatedInformation(RD); + assert(VTableLayouts.count(RD) && "No layout for this record decl!"); + + return *VTableLayouts[RD]; + } + + VTableLayout * + createConstructionVTableLayout(const CXXRecordDecl *MostDerivedClass, + CharUnits MostDerivedClassOffset, + bool MostDerivedClassIsVirtual, + const CXXRecordDecl *LayoutClass); + + /// \brief Locate a virtual function in the vtable. + /// + /// Return the index (relative to the vtable address point) where the + /// function pointer for the given virtual function is stored. + uint64_t getMethodVTableIndex(GlobalDecl GD); + + /// Return the offset in chars (relative to the vtable address point) where + /// the offset of the virtual base that contains the given base is stored, + /// otherwise, if no virtual base contains the given class, return 0. + /// + /// Base must be a virtual base class or an unambiguous base. + CharUnits getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, + const CXXRecordDecl *VBase); + + static bool classof(const VTableContextBase *VT) { + return !VT->isMicrosoft(); + } +}; + +/// Holds information about the inheritance path to a virtual base or function +/// table pointer. A record may contain as many vfptrs or vbptrs as there are +/// base subobjects. +struct VPtrInfo { + typedef SmallVector<const CXXRecordDecl *, 1> BasePath; + + VPtrInfo(const CXXRecordDecl *RD) + : ReusingBase(RD), BaseWithVPtr(RD), NextBaseToMangle(RD) {} + + /// The vtable will hold all of the virtual bases or virtual methods of + /// ReusingBase. This may or may not be the same class as VPtrSubobject.Base. + /// A derived class will reuse the vptr of the first non-virtual base + /// subobject that has one. + const CXXRecordDecl *ReusingBase; + + /// BaseWithVPtr is at this offset from its containing complete object or + /// virtual base. + CharUnits NonVirtualOffset; + + /// The vptr is stored inside this subobject. + const CXXRecordDecl *BaseWithVPtr; + + /// The bases from the inheritance path that got used to mangle the vbtable + /// name. This is not really a full path like a CXXBasePath. It holds the + /// subset of records that need to be mangled into the vbtable symbol name in + /// order to get a unique name. + BasePath MangledPath; + + /// The next base to push onto the mangled path if this path is ambiguous in a + /// derived class. If it's null, then it's already been pushed onto the path. + const CXXRecordDecl *NextBaseToMangle; + + /// The set of possibly indirect vbases that contain this vbtable. When a + /// derived class indirectly inherits from the same vbase twice, we only keep + /// vtables and their paths from the first instance. + BasePath ContainingVBases; + + /// This holds the base classes path from the complete type to the first base + /// with the given vfptr offset, in the base-to-derived order. Only used for + /// vftables. + BasePath PathToBaseWithVPtr; + + /// Static offset from the top of the most derived class to this vfptr, + /// including any virtual base offset. Only used for vftables. + CharUnits FullOffsetInMDC; + + /// The vptr is stored inside the non-virtual component of this virtual base. + const CXXRecordDecl *getVBaseWithVPtr() const { + return ContainingVBases.empty() ? nullptr : ContainingVBases.front(); + } +}; + +typedef SmallVector<VPtrInfo *, 2> VPtrInfoVector; + +/// All virtual base related information about a given record decl. Includes +/// information on all virtual base tables and the path components that are used +/// to mangle them. +struct VirtualBaseInfo { + ~VirtualBaseInfo() { llvm::DeleteContainerPointers(VBPtrPaths); } + + /// A map from virtual base to vbtable index for doing a conversion from the + /// the derived class to the a base. + llvm::DenseMap<const CXXRecordDecl *, unsigned> VBTableIndices; + + /// Information on all virtual base tables used when this record is the most + /// derived class. + VPtrInfoVector VBPtrPaths; +}; + +class MicrosoftVTableContext : public VTableContextBase { +public: + struct MethodVFTableLocation { + /// If nonzero, holds the vbtable index of the virtual base with the vfptr. + uint64_t VBTableIndex; + + /// If nonnull, holds the last vbase which contains the vfptr that the + /// method definition is adjusted to. + const CXXRecordDecl *VBase; + + /// This is the offset of the vfptr from the start of the last vbase, or the + /// complete type if there are no virtual bases. + CharUnits VFPtrOffset; + + /// Method's index in the vftable. + uint64_t Index; + + MethodVFTableLocation() + : VBTableIndex(0), VBase(nullptr), VFPtrOffset(CharUnits::Zero()), + Index(0) {} + + MethodVFTableLocation(uint64_t VBTableIndex, const CXXRecordDecl *VBase, + CharUnits VFPtrOffset, uint64_t Index) + : VBTableIndex(VBTableIndex), VBase(VBase), + VFPtrOffset(VFPtrOffset), Index(Index) {} + + bool operator<(const MethodVFTableLocation &other) const { + if (VBTableIndex != other.VBTableIndex) { + assert(VBase != other.VBase); + return VBTableIndex < other.VBTableIndex; + } + return std::tie(VFPtrOffset, Index) < + std::tie(other.VFPtrOffset, other.Index); + } + }; + +private: + ASTContext &Context; + + typedef llvm::DenseMap<GlobalDecl, MethodVFTableLocation> + MethodVFTableLocationsTy; + MethodVFTableLocationsTy MethodVFTableLocations; + + typedef llvm::DenseMap<const CXXRecordDecl *, VPtrInfoVector *> + VFPtrLocationsMapTy; + VFPtrLocationsMapTy VFPtrLocations; + + typedef std::pair<const CXXRecordDecl *, CharUnits> VFTableIdTy; + typedef llvm::DenseMap<VFTableIdTy, const VTableLayout *> VFTableLayoutMapTy; + VFTableLayoutMapTy VFTableLayouts; + + llvm::DenseMap<const CXXRecordDecl *, VirtualBaseInfo *> VBaseInfo; + + void enumerateVFPtrs(const CXXRecordDecl *ForClass, VPtrInfoVector &Result); + + void computeVTableRelatedInformation(const CXXRecordDecl *RD) override; + + void dumpMethodLocations(const CXXRecordDecl *RD, + const MethodVFTableLocationsTy &NewMethods, + raw_ostream &); + + const VirtualBaseInfo * + computeVBTableRelatedInformation(const CXXRecordDecl *RD); + + void computeVTablePaths(bool ForVBTables, const CXXRecordDecl *RD, + VPtrInfoVector &Paths); + +public: + MicrosoftVTableContext(ASTContext &Context) + : VTableContextBase(/*MS=*/true), Context(Context) {} + + ~MicrosoftVTableContext() override; + + const VPtrInfoVector &getVFPtrOffsets(const CXXRecordDecl *RD); + + const VTableLayout &getVFTableLayout(const CXXRecordDecl *RD, + CharUnits VFPtrOffset); + + const MethodVFTableLocation &getMethodVFTableLocation(GlobalDecl GD); + + const ThunkInfoVectorTy *getThunkInfo(GlobalDecl GD) override { + // Complete destructors don't have a slot in a vftable, so no thunks needed. + if (isa<CXXDestructorDecl>(GD.getDecl()) && + GD.getDtorType() == Dtor_Complete) + return nullptr; + return VTableContextBase::getThunkInfo(GD); + } + + /// \brief Returns the index of VBase in the vbtable of Derived. + /// VBase must be a morally virtual base of Derived. + /// The vbtable is an array of i32 offsets. The first entry is a self entry, + /// and the rest are offsets from the vbptr to virtual bases. + unsigned getVBTableIndex(const CXXRecordDecl *Derived, + const CXXRecordDecl *VBase); + + const VPtrInfoVector &enumerateVBTables(const CXXRecordDecl *RD); + + static bool classof(const VTableContextBase *VT) { return VT->isMicrosoft(); } +}; + +} // namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/ASTMatchers/ASTMatchFinder.h b/contrib/llvm/tools/clang/include/clang/ASTMatchers/ASTMatchFinder.h new file mode 100644 index 0000000..92ec92c --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/ASTMatchers/ASTMatchFinder.h @@ -0,0 +1,294 @@ +//===--- ASTMatchFinder.h - Structural query framework ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Provides a way to construct an ASTConsumer that runs given matchers +// over the AST and invokes a given callback on every match. +// +// The general idea is to construct a matcher expression that describes a +// subtree match on the AST. Next, a callback that is executed every time the +// expression matches is registered, and the matcher is run over the AST of +// some code. Matched subexpressions can be bound to string IDs and easily +// be accessed from the registered callback. The callback can than use the +// AST nodes that the subexpressions matched on to output information about +// the match or construct changes that can be applied to the code. +// +// Example: +// class HandleMatch : public MatchFinder::MatchCallback { +// public: +// virtual void Run(const MatchFinder::MatchResult &Result) { +// const CXXRecordDecl *Class = +// Result.Nodes.GetDeclAs<CXXRecordDecl>("id"); +// ... +// } +// }; +// +// int main(int argc, char **argv) { +// ClangTool Tool(argc, argv); +// MatchFinder finder; +// finder.AddMatcher(Id("id", record(hasName("::a_namespace::AClass"))), +// new HandleMatch); +// return Tool.Run(newFrontendActionFactory(&finder)); +// } +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ASTMATCHERS_ASTMATCHFINDER_H +#define LLVM_CLANG_ASTMATCHERS_ASTMATCHFINDER_H + +#include "clang/ASTMatchers/ASTMatchers.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/Timer.h" + +namespace clang { + +namespace ast_matchers { + +/// \brief A class to allow finding matches over the Clang AST. +/// +/// After creation, you can add multiple matchers to the MatchFinder via +/// calls to addMatcher(...). +/// +/// Once all matchers are added, newASTConsumer() returns an ASTConsumer +/// that will trigger the callbacks specified via addMatcher(...) when a match +/// is found. +/// +/// The order of matches is guaranteed to be equivalent to doing a pre-order +/// traversal on the AST, and applying the matchers in the order in which they +/// were added to the MatchFinder. +/// +/// See ASTMatchers.h for more information about how to create matchers. +/// +/// Not intended to be subclassed. +class MatchFinder { +public: + /// \brief Contains all information for a given match. + /// + /// Every time a match is found, the MatchFinder will invoke the registered + /// MatchCallback with a MatchResult containing information about the match. + struct MatchResult { + MatchResult(const BoundNodes &Nodes, clang::ASTContext *Context); + + /// \brief Contains the nodes bound on the current match. + /// + /// This allows user code to easily extract matched AST nodes. + const BoundNodes Nodes; + + /// \brief Utilities for interpreting the matched AST structures. + /// @{ + clang::ASTContext * const Context; + clang::SourceManager * const SourceManager; + /// @} + }; + + /// \brief Called when the Match registered for it was successfully found + /// in the AST. + class MatchCallback { + public: + virtual ~MatchCallback(); + + /// \brief Called on every match by the \c MatchFinder. + virtual void run(const MatchResult &Result) = 0; + + /// \brief Called at the start of each translation unit. + /// + /// Optionally override to do per translation unit tasks. + virtual void onStartOfTranslationUnit() {} + + /// \brief Called at the end of each translation unit. + /// + /// Optionally override to do per translation unit tasks. + virtual void onEndOfTranslationUnit() {} + + /// \brief An id used to group the matchers. + /// + /// This id is used, for example, for the profiling output. + /// It defaults to "<unknown>". + virtual StringRef getID() const; + }; + + /// \brief Called when parsing is finished. Intended for testing only. + class ParsingDoneTestCallback { + public: + virtual ~ParsingDoneTestCallback(); + virtual void run() = 0; + }; + + struct MatchFinderOptions { + struct Profiling { + Profiling(llvm::StringMap<llvm::TimeRecord> &Records) + : Records(Records) {} + + /// \brief Per bucket timing information. + llvm::StringMap<llvm::TimeRecord> &Records; + }; + + /// \brief Enables per-check timers. + /// + /// It prints a report after match. + llvm::Optional<Profiling> CheckProfiling; + }; + + MatchFinder(MatchFinderOptions Options = MatchFinderOptions()); + ~MatchFinder(); + + /// \brief Adds a matcher to execute when running over the AST. + /// + /// Calls 'Action' with the BoundNodes on every match. + /// Adding more than one 'NodeMatch' allows finding different matches in a + /// single pass over the AST. + /// + /// Does not take ownership of 'Action'. + /// @{ + void addMatcher(const DeclarationMatcher &NodeMatch, + MatchCallback *Action); + void addMatcher(const TypeMatcher &NodeMatch, + MatchCallback *Action); + void addMatcher(const StatementMatcher &NodeMatch, + MatchCallback *Action); + void addMatcher(const NestedNameSpecifierMatcher &NodeMatch, + MatchCallback *Action); + void addMatcher(const NestedNameSpecifierLocMatcher &NodeMatch, + MatchCallback *Action); + void addMatcher(const TypeLocMatcher &NodeMatch, + MatchCallback *Action); + /// @} + + /// \brief Adds a matcher to execute when running over the AST. + /// + /// This is similar to \c addMatcher(), but it uses the dynamic interface. It + /// is more flexible, but the lost type information enables a caller to pass + /// a matcher that cannot match anything. + /// + /// \returns \c true if the matcher is a valid top-level matcher, \c false + /// otherwise. + bool addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch, + MatchCallback *Action); + + /// \brief Creates a clang ASTConsumer that finds all matches. + std::unique_ptr<clang::ASTConsumer> newASTConsumer(); + + /// \brief Calls the registered callbacks on all matches on the given \p Node. + /// + /// Note that there can be multiple matches on a single node, for + /// example when using decl(forEachDescendant(stmt())). + /// + /// @{ + template <typename T> void match(const T &Node, ASTContext &Context) { + match(clang::ast_type_traits::DynTypedNode::create(Node), Context); + } + void match(const clang::ast_type_traits::DynTypedNode &Node, + ASTContext &Context); + /// @} + + /// \brief Finds all matches in the given AST. + void matchAST(ASTContext &Context); + + /// \brief Registers a callback to notify the end of parsing. + /// + /// The provided closure is called after parsing is done, before the AST is + /// traversed. Useful for benchmarking. + /// Each call to FindAll(...) will call the closure once. + void registerTestCallbackAfterParsing(ParsingDoneTestCallback *ParsingDone); + + /// \brief For each \c Matcher<> a \c MatchCallback that will be called + /// when it matches. + struct MatchersByType { + std::vector<std::pair<internal::DynTypedMatcher, MatchCallback *>> + DeclOrStmt; + std::vector<std::pair<TypeMatcher, MatchCallback *>> Type; + std::vector<std::pair<NestedNameSpecifierMatcher, MatchCallback *>> + NestedNameSpecifier; + std::vector<std::pair<NestedNameSpecifierLocMatcher, MatchCallback *>> + NestedNameSpecifierLoc; + std::vector<std::pair<TypeLocMatcher, MatchCallback *>> TypeLoc; + /// \brief All the callbacks in one container to simplify iteration. + llvm::SmallPtrSet<MatchCallback *, 16> AllCallbacks; + }; + +private: + MatchersByType Matchers; + + MatchFinderOptions Options; + + /// \brief Called when parsing is done. + ParsingDoneTestCallback *ParsingDone; +}; + +/// \brief Returns the results of matching \p Matcher on \p Node. +/// +/// Collects the \c BoundNodes of all callback invocations when matching +/// \p Matcher on \p Node and returns the collected results. +/// +/// Multiple results occur when using matchers like \c forEachDescendant, +/// which generate a result for each sub-match. +/// +/// \see selectFirst +/// @{ +template <typename MatcherT, typename NodeT> +SmallVector<BoundNodes, 1> +match(MatcherT Matcher, const NodeT &Node, ASTContext &Context); + +template <typename MatcherT> +SmallVector<BoundNodes, 1> +match(MatcherT Matcher, const ast_type_traits::DynTypedNode &Node, + ASTContext &Context); +/// @} + +/// \brief Returns the first result of type \c NodeT bound to \p BoundTo. +/// +/// Returns \c NULL if there is no match, or if the matching node cannot be +/// casted to \c NodeT. +/// +/// This is useful in combanation with \c match(): +/// \code +/// const Decl *D = selectFirst<Decl>("id", match(Matcher.bind("id"), +/// Node, Context)); +/// \endcode +template <typename NodeT> +const NodeT * +selectFirst(StringRef BoundTo, const SmallVectorImpl<BoundNodes> &Results) { + for (const BoundNodes &N : Results) { + if (const NodeT *Node = N.getNodeAs<NodeT>(BoundTo)) + return Node; + } + return nullptr; +} + +namespace internal { +class CollectMatchesCallback : public MatchFinder::MatchCallback { +public: + void run(const MatchFinder::MatchResult &Result) override { + Nodes.push_back(Result.Nodes); + } + SmallVector<BoundNodes, 1> Nodes; +}; +} + +template <typename MatcherT> +SmallVector<BoundNodes, 1> +match(MatcherT Matcher, const ast_type_traits::DynTypedNode &Node, + ASTContext &Context) { + internal::CollectMatchesCallback Callback; + MatchFinder Finder; + Finder.addMatcher(Matcher, &Callback); + Finder.match(Node, Context); + return std::move(Callback.Nodes); +} + +template <typename MatcherT, typename NodeT> +SmallVector<BoundNodes, 1> +match(MatcherT Matcher, const NodeT &Node, ASTContext &Context) { + return match(Matcher, ast_type_traits::DynTypedNode::create(Node), Context); +} + +} // end namespace ast_matchers +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/ASTMatchers/ASTMatchers.h b/contrib/llvm/tools/clang/include/clang/ASTMatchers/ASTMatchers.h new file mode 100644 index 0000000..e6ba877 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -0,0 +1,4671 @@ +//===--- ASTMatchers.h - Structural query framework -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements matchers to be used together with the MatchFinder to +// match AST nodes. +// +// Matchers are created by generator functions, which can be combined in +// a functional in-language DSL to express queries over the C++ AST. +// +// For example, to match a class with a certain name, one would call: +// cxxRecordDecl(hasName("MyClass")) +// which returns a matcher that can be used to find all AST nodes that declare +// a class named 'MyClass'. +// +// For more complicated match expressions we're often interested in accessing +// multiple parts of the matched AST nodes once a match is found. In that case, +// use the id(...) matcher around the match expressions that match the nodes +// you want to access. +// +// For example, when we're interested in child classes of a certain class, we +// would write: +// cxxRecordDecl(hasName("MyClass"), hasChild(id("child", recordDecl()))) +// When the match is found via the MatchFinder, a user provided callback will +// be called with a BoundNodes instance that contains a mapping from the +// strings that we provided for the id(...) calls to the nodes that were +// matched. +// In the given example, each time our matcher finds a match we get a callback +// where "child" is bound to the RecordDecl node of the matching child +// class declaration. +// +// See ASTMatchersInternal.h for a more in-depth explanation of the +// implementation details of the matcher framework. +// +// See ASTMatchFinder.h for how to use the generated matchers to run over +// an AST. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ASTMATCHERS_ASTMATCHERS_H +#define LLVM_CLANG_ASTMATCHERS_ASTMATCHERS_H + +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclFriend.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/ASTMatchers/ASTMatchersInternal.h" +#include "clang/ASTMatchers/ASTMatchersMacros.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/Regex.h" +#include <iterator> + +namespace clang { +namespace ast_matchers { + +/// \brief Maps string IDs to AST nodes matched by parts of a matcher. +/// +/// The bound nodes are generated by calling \c bind("id") on the node matchers +/// of the nodes we want to access later. +/// +/// The instances of BoundNodes are created by \c MatchFinder when the user's +/// callbacks are executed every time a match is found. +class BoundNodes { +public: + /// \brief Returns the AST node bound to \c ID. + /// + /// Returns NULL if there was no node bound to \c ID or if there is a node but + /// it cannot be converted to the specified type. + template <typename T> + const T *getNodeAs(StringRef ID) const { + return MyBoundNodes.getNodeAs<T>(ID); + } + + /// \brief Deprecated. Please use \c getNodeAs instead. + /// @{ + template <typename T> + const T *getDeclAs(StringRef ID) const { + return getNodeAs<T>(ID); + } + template <typename T> + const T *getStmtAs(StringRef ID) const { + return getNodeAs<T>(ID); + } + /// @} + + /// \brief Type of mapping from binding identifiers to bound nodes. This type + /// is an associative container with a key type of \c std::string and a value + /// type of \c clang::ast_type_traits::DynTypedNode + typedef internal::BoundNodesMap::IDToNodeMap IDToNodeMap; + + /// \brief Retrieve mapping from binding identifiers to bound nodes. + const IDToNodeMap &getMap() const { + return MyBoundNodes.getMap(); + } + +private: + /// \brief Create BoundNodes from a pre-filled map of bindings. + BoundNodes(internal::BoundNodesMap &MyBoundNodes) + : MyBoundNodes(MyBoundNodes) {} + + internal::BoundNodesMap MyBoundNodes; + + friend class internal::BoundNodesTreeBuilder; +}; + +/// \brief If the provided matcher matches a node, binds the node to \c ID. +/// +/// FIXME: Do we want to support this now that we have bind()? +template <typename T> +internal::Matcher<T> id(StringRef ID, + const internal::BindableMatcher<T> &InnerMatcher) { + return InnerMatcher.bind(ID); +} + +/// \brief Types of matchers for the top-level classes in the AST class +/// hierarchy. +/// @{ +typedef internal::Matcher<Decl> DeclarationMatcher; +typedef internal::Matcher<Stmt> StatementMatcher; +typedef internal::Matcher<QualType> TypeMatcher; +typedef internal::Matcher<TypeLoc> TypeLocMatcher; +typedef internal::Matcher<NestedNameSpecifier> NestedNameSpecifierMatcher; +typedef internal::Matcher<NestedNameSpecifierLoc> NestedNameSpecifierLocMatcher; +/// @} + +/// \brief Matches any node. +/// +/// Useful when another matcher requires a child matcher, but there's no +/// additional constraint. This will often be used with an explicit conversion +/// to an \c internal::Matcher<> type such as \c TypeMatcher. +/// +/// Example: \c DeclarationMatcher(anything()) matches all declarations, e.g., +/// \code +/// "int* p" and "void f()" in +/// int* p; +/// void f(); +/// \endcode +/// +/// Usable as: Any Matcher +inline internal::TrueMatcher anything() { return internal::TrueMatcher(); } + +/// \brief Matches the top declaration context. +/// +/// Given +/// \code +/// int X; +/// namespace NS { +/// int Y; +/// } // namespace NS +/// \endcode +/// decl(hasDeclContext(translationUnitDecl())) +/// matches "int X", but not "int Y". +const internal::VariadicDynCastAllOfMatcher<Decl, TranslationUnitDecl> + translationUnitDecl; + +/// \brief Matches typedef declarations. +/// +/// Given +/// \code +/// typedef int X; +/// \endcode +/// typedefDecl() +/// matches "typedef int X" +const internal::VariadicDynCastAllOfMatcher<Decl, TypedefDecl> typedefDecl; + +/// \brief Matches AST nodes that were expanded within the main-file. +/// +/// Example matches X but not Y +/// (matcher = cxxRecordDecl(isExpansionInMainFile()) +/// \code +/// #include <Y.h> +/// class X {}; +/// \endcode +/// Y.h: +/// \code +/// class Y {}; +/// \endcode +/// +/// Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc> +AST_POLYMORPHIC_MATCHER(isExpansionInMainFile, + AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt, TypeLoc)) { + auto &SourceManager = Finder->getASTContext().getSourceManager(); + return SourceManager.isInMainFile( + SourceManager.getExpansionLoc(Node.getLocStart())); +} + +/// \brief Matches AST nodes that were expanded within system-header-files. +/// +/// Example matches Y but not X +/// (matcher = cxxRecordDecl(isExpansionInSystemHeader()) +/// \code +/// #include <SystemHeader.h> +/// class X {}; +/// \endcode +/// SystemHeader.h: +/// \code +/// class Y {}; +/// \endcode +/// +/// Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc> +AST_POLYMORPHIC_MATCHER(isExpansionInSystemHeader, + AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt, TypeLoc)) { + auto &SourceManager = Finder->getASTContext().getSourceManager(); + auto ExpansionLoc = SourceManager.getExpansionLoc(Node.getLocStart()); + if (ExpansionLoc.isInvalid()) { + return false; + } + return SourceManager.isInSystemHeader(ExpansionLoc); +} + +/// \brief Matches AST nodes that were expanded within files whose name is +/// partially matching a given regex. +/// +/// Example matches Y but not X +/// (matcher = cxxRecordDecl(isExpansionInFileMatching("AST.*")) +/// \code +/// #include "ASTMatcher.h" +/// class X {}; +/// \endcode +/// ASTMatcher.h: +/// \code +/// class Y {}; +/// \endcode +/// +/// Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc> +AST_POLYMORPHIC_MATCHER_P(isExpansionInFileMatching, + AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt, TypeLoc), + std::string, RegExp) { + auto &SourceManager = Finder->getASTContext().getSourceManager(); + auto ExpansionLoc = SourceManager.getExpansionLoc(Node.getLocStart()); + if (ExpansionLoc.isInvalid()) { + return false; + } + auto FileEntry = + SourceManager.getFileEntryForID(SourceManager.getFileID(ExpansionLoc)); + if (!FileEntry) { + return false; + } + + auto Filename = FileEntry->getName(); + llvm::Regex RE(RegExp); + return RE.match(Filename); +} + +/// \brief Matches declarations. +/// +/// Examples matches \c X, \c C, and the friend declaration inside \c C; +/// \code +/// void X(); +/// class C { +/// friend X; +/// }; +/// \endcode +const internal::VariadicAllOfMatcher<Decl> decl; + +/// \brief Matches a declaration of a linkage specification. +/// +/// Given +/// \code +/// extern "C" {} +/// \endcode +/// linkageSpecDecl() +/// matches "extern "C" {}" +const internal::VariadicDynCastAllOfMatcher<Decl, LinkageSpecDecl> + linkageSpecDecl; + +/// \brief Matches a declaration of anything that could have a name. +/// +/// Example matches \c X, \c S, the anonymous union type, \c i, and \c U; +/// \code +/// typedef int X; +/// struct S { +/// union { +/// int i; +/// } U; +/// }; +/// \endcode +const internal::VariadicDynCastAllOfMatcher<Decl, NamedDecl> namedDecl; + +/// \brief Matches a declaration of a namespace. +/// +/// Given +/// \code +/// namespace {} +/// namespace test {} +/// \endcode +/// namespaceDecl() +/// matches "namespace {}" and "namespace test {}" +const internal::VariadicDynCastAllOfMatcher<Decl, NamespaceDecl> namespaceDecl; + +/// \brief Matches a declaration of a namespace alias. +/// +/// Given +/// \code +/// namespace test {} +/// namespace alias = ::test; +/// \endcode +/// namespaceAliasDecl() +/// matches "namespace alias" but not "namespace test" +const internal::VariadicDynCastAllOfMatcher<Decl, NamespaceAliasDecl> + namespaceAliasDecl; + +/// \brief Matches class, struct, and union declarations. +/// +/// Example matches \c X, \c Z, \c U, and \c S +/// \code +/// class X; +/// template<class T> class Z {}; +/// struct S {}; +/// union U {}; +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Decl, + RecordDecl> recordDecl; + +/// \brief Matches C++ class declarations. +/// +/// Example matches \c X, \c Z +/// \code +/// class X; +/// template<class T> class Z {}; +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Decl, + CXXRecordDecl> cxxRecordDecl; + +/// \brief Matches C++ class template declarations. +/// +/// Example matches \c Z +/// \code +/// template<class T> class Z {}; +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Decl, + ClassTemplateDecl> classTemplateDecl; + +/// \brief Matches C++ class template specializations. +/// +/// Given +/// \code +/// template<typename T> class A {}; +/// template<> class A<double> {}; +/// A<int> a; +/// \endcode +/// classTemplateSpecializationDecl() +/// matches the specializations \c A<int> and \c A<double> +const internal::VariadicDynCastAllOfMatcher< + Decl, + ClassTemplateSpecializationDecl> classTemplateSpecializationDecl; + +/// \brief Matches declarator declarations (field, variable, function +/// and non-type template parameter declarations). +/// +/// Given +/// \code +/// class X { int y; }; +/// \endcode +/// declaratorDecl() +/// matches \c int y. +const internal::VariadicDynCastAllOfMatcher<Decl, DeclaratorDecl> + declaratorDecl; + +/// \brief Matches parameter variable declarations. +/// +/// Given +/// \code +/// void f(int x); +/// \endcode +/// parmVarDecl() +/// matches \c int x. +const internal::VariadicDynCastAllOfMatcher<Decl, ParmVarDecl> parmVarDecl; + +/// \brief Matches C++ access specifier declarations. +/// +/// Given +/// \code +/// class C { +/// public: +/// int a; +/// }; +/// \endcode +/// accessSpecDecl() +/// matches 'public:' +const internal::VariadicDynCastAllOfMatcher< + Decl, + AccessSpecDecl> accessSpecDecl; + +/// \brief Matches constructor initializers. +/// +/// Examples matches \c i(42). +/// \code +/// class C { +/// C() : i(42) {} +/// int i; +/// }; +/// \endcode +const internal::VariadicAllOfMatcher<CXXCtorInitializer> cxxCtorInitializer; + +/// \brief Matches template arguments. +/// +/// Given +/// \code +/// template <typename T> struct C {}; +/// C<int> c; +/// \endcode +/// templateArgument() +/// matches 'int' in C<int>. +const internal::VariadicAllOfMatcher<TemplateArgument> templateArgument; + +/// \brief Matches non-type template parameter declarations. +/// +/// Given +/// \code +/// template <typename T, int N> struct C {}; +/// \endcode +/// nonTypeTemplateParmDecl() +/// matches 'N', but not 'T'. +const internal::VariadicDynCastAllOfMatcher< + Decl, + NonTypeTemplateParmDecl> nonTypeTemplateParmDecl; + +/// \brief Matches template type parameter declarations. +/// +/// Given +/// \code +/// template <typename T, int N> struct C {}; +/// \endcode +/// templateTypeParmDecl() +/// matches 'T', but not 'N'. +const internal::VariadicDynCastAllOfMatcher< + Decl, + TemplateTypeParmDecl> templateTypeParmDecl; + +/// \brief Matches public C++ declarations. +/// +/// Given +/// \code +/// class C { +/// public: int a; +/// protected: int b; +/// private: int c; +/// }; +/// \endcode +/// fieldDecl(isPublic()) +/// matches 'int a;' +AST_MATCHER(Decl, isPublic) { + return Node.getAccess() == AS_public; +} + +/// \brief Matches protected C++ declarations. +/// +/// Given +/// \code +/// class C { +/// public: int a; +/// protected: int b; +/// private: int c; +/// }; +/// \endcode +/// fieldDecl(isProtected()) +/// matches 'int b;' +AST_MATCHER(Decl, isProtected) { + return Node.getAccess() == AS_protected; +} + +/// \brief Matches private C++ declarations. +/// +/// Given +/// \code +/// class C { +/// public: int a; +/// protected: int b; +/// private: int c; +/// }; +/// \endcode +/// fieldDecl(isPrivate()) +/// matches 'int c;' +AST_MATCHER(Decl, isPrivate) { + return Node.getAccess() == AS_private; +} + +/// \brief Matches a declaration that has been implicitly added +/// by the compiler (eg. implicit default/copy constructors). +AST_MATCHER(Decl, isImplicit) { + return Node.isImplicit(); +} + +/// \brief Matches classTemplateSpecializations that have at least one +/// TemplateArgument matching the given InnerMatcher. +/// +/// Given +/// \code +/// template<typename T> class A {}; +/// template<> class A<double> {}; +/// A<int> a; +/// \endcode +/// classTemplateSpecializationDecl(hasAnyTemplateArgument( +/// refersToType(asString("int")))) +/// matches the specialization \c A<int> +AST_POLYMORPHIC_MATCHER_P( + hasAnyTemplateArgument, + AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl, + TemplateSpecializationType), + internal::Matcher<TemplateArgument>, InnerMatcher) { + ArrayRef<TemplateArgument> List = + internal::getTemplateSpecializationArgs(Node); + return matchesFirstInRange(InnerMatcher, List.begin(), List.end(), Finder, + Builder); +} + +/// \brief Matches expressions that match InnerMatcher after any implicit casts +/// are stripped off. +/// +/// Parentheses and explicit casts are not discarded. +/// Given +/// \code +/// int arr[5]; +/// int a = 0; +/// char b = 0; +/// const int c = a; +/// int *d = arr; +/// long e = (long) 0l; +/// \endcode +/// The matchers +/// \code +/// varDecl(hasInitializer(ignoringImpCasts(integerLiteral()))) +/// varDecl(hasInitializer(ignoringImpCasts(declRefExpr()))) +/// \endcode +/// would match the declarations for a, b, c, and d, but not e. +/// While +/// \code +/// varDecl(hasInitializer(integerLiteral())) +/// varDecl(hasInitializer(declRefExpr())) +/// \endcode +/// only match the declarations for b, c, and d. +AST_MATCHER_P(Expr, ignoringImpCasts, + internal::Matcher<Expr>, InnerMatcher) { + return InnerMatcher.matches(*Node.IgnoreImpCasts(), Finder, Builder); +} + +/// \brief Matches expressions that match InnerMatcher after parentheses and +/// casts are stripped off. +/// +/// Implicit and non-C Style casts are also discarded. +/// Given +/// \code +/// int a = 0; +/// char b = (0); +/// void* c = reinterpret_cast<char*>(0); +/// char d = char(0); +/// \endcode +/// The matcher +/// varDecl(hasInitializer(ignoringParenCasts(integerLiteral()))) +/// would match the declarations for a, b, c, and d. +/// while +/// varDecl(hasInitializer(integerLiteral())) +/// only match the declaration for a. +AST_MATCHER_P(Expr, ignoringParenCasts, internal::Matcher<Expr>, InnerMatcher) { + return InnerMatcher.matches(*Node.IgnoreParenCasts(), Finder, Builder); +} + +/// \brief Matches expressions that match InnerMatcher after implicit casts and +/// parentheses are stripped off. +/// +/// Explicit casts are not discarded. +/// Given +/// \code +/// int arr[5]; +/// int a = 0; +/// char b = (0); +/// const int c = a; +/// int *d = (arr); +/// long e = ((long) 0l); +/// \endcode +/// The matchers +/// varDecl(hasInitializer(ignoringParenImpCasts(integerLiteral()))) +/// varDecl(hasInitializer(ignoringParenImpCasts(declRefExpr()))) +/// would match the declarations for a, b, c, and d, but not e. +/// while +/// varDecl(hasInitializer(integerLiteral())) +/// varDecl(hasInitializer(declRefExpr())) +/// would only match the declaration for a. +AST_MATCHER_P(Expr, ignoringParenImpCasts, + internal::Matcher<Expr>, InnerMatcher) { + return InnerMatcher.matches(*Node.IgnoreParenImpCasts(), Finder, Builder); +} + +/// \brief Matches classTemplateSpecializations where the n'th TemplateArgument +/// matches the given InnerMatcher. +/// +/// Given +/// \code +/// template<typename T, typename U> class A {}; +/// A<bool, int> b; +/// A<int, bool> c; +/// \endcode +/// classTemplateSpecializationDecl(hasTemplateArgument( +/// 1, refersToType(asString("int")))) +/// matches the specialization \c A<bool, int> +AST_POLYMORPHIC_MATCHER_P2( + hasTemplateArgument, + AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl, + TemplateSpecializationType), + unsigned, N, internal::Matcher<TemplateArgument>, InnerMatcher) { + ArrayRef<TemplateArgument> List = + internal::getTemplateSpecializationArgs(Node); + if (List.size() <= N) + return false; + return InnerMatcher.matches(List[N], Finder, Builder); +} + +/// \brief Matches if the number of template arguments equals \p N. +/// +/// Given +/// \code +/// template<typename T> struct C {}; +/// C<int> c; +/// \endcode +/// classTemplateSpecializationDecl(templateArgumentCountIs(1)) +/// matches C<int>. +AST_POLYMORPHIC_MATCHER_P( + templateArgumentCountIs, + AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl, + TemplateSpecializationType), + unsigned, N) { + return internal::getTemplateSpecializationArgs(Node).size() == N; +} + +/// \brief Matches a TemplateArgument that refers to a certain type. +/// +/// Given +/// \code +/// struct X {}; +/// template<typename T> struct A {}; +/// A<X> a; +/// \endcode +/// classTemplateSpecializationDecl(hasAnyTemplateArgument( +/// refersToType(class(hasName("X"))))) +/// matches the specialization \c A<X> +AST_MATCHER_P(TemplateArgument, refersToType, + internal::Matcher<QualType>, InnerMatcher) { + if (Node.getKind() != TemplateArgument::Type) + return false; + return InnerMatcher.matches(Node.getAsType(), Finder, Builder); +} + +/// \brief Matches a canonical TemplateArgument that refers to a certain +/// declaration. +/// +/// Given +/// \code +/// template<typename T> struct A {}; +/// struct B { B* next; }; +/// A<&B::next> a; +/// \endcode +/// classTemplateSpecializationDecl(hasAnyTemplateArgument( +/// refersToDeclaration(fieldDecl(hasName("next")))) +/// matches the specialization \c A<&B::next> with \c fieldDecl(...) matching +/// \c B::next +AST_MATCHER_P(TemplateArgument, refersToDeclaration, + internal::Matcher<Decl>, InnerMatcher) { + if (Node.getKind() == TemplateArgument::Declaration) + return InnerMatcher.matches(*Node.getAsDecl(), Finder, Builder); + return false; +} + +/// \brief Matches a sugar TemplateArgument that refers to a certain expression. +/// +/// Given +/// \code +/// template<typename T> struct A {}; +/// struct B { B* next; }; +/// A<&B::next> a; +/// \endcode +/// templateSpecializationType(hasAnyTemplateArgument( +/// isExpr(hasDescendant(declRefExpr(to(fieldDecl(hasName("next")))))))) +/// matches the specialization \c A<&B::next> with \c fieldDecl(...) matching +/// \c B::next +AST_MATCHER_P(TemplateArgument, isExpr, internal::Matcher<Expr>, InnerMatcher) { + if (Node.getKind() == TemplateArgument::Expression) + return InnerMatcher.matches(*Node.getAsExpr(), Finder, Builder); + return false; +} + +/// \brief Matches a TemplateArgument that is an integral value. +/// +/// Given +/// \code +/// template<int T> struct A {}; +/// C<42> c; +/// \endcode +/// classTemplateSpecializationDecl( +/// hasAnyTemplateArgument(isIntegral())) +/// matches the implicit instantiation of C in C<42> +/// with isIntegral() matching 42. +AST_MATCHER(TemplateArgument, isIntegral) { + return Node.getKind() == TemplateArgument::Integral; +} + +/// \brief Matches a TemplateArgument that referes to an integral type. +/// +/// Given +/// \code +/// template<int T> struct A {}; +/// C<42> c; +/// \endcode +/// classTemplateSpecializationDecl( +/// hasAnyTemplateArgument(refersToIntegralType(asString("int")))) +/// matches the implicit instantiation of C in C<42>. +AST_MATCHER_P(TemplateArgument, refersToIntegralType, + internal::Matcher<QualType>, InnerMatcher) { + if (Node.getKind() != TemplateArgument::Integral) + return false; + return InnerMatcher.matches(Node.getIntegralType(), Finder, Builder); +} + +/// \brief Matches a TemplateArgument of integral type with a given value. +/// +/// Note that 'Value' is a string as the template argument's value is +/// an arbitrary precision integer. 'Value' must be euqal to the canonical +/// representation of that integral value in base 10. +/// +/// Given +/// \code +/// template<int T> struct A {}; +/// C<42> c; +/// \endcode +/// classTemplateSpecializationDecl( +/// hasAnyTemplateArgument(equalsIntegralValue("42"))) +/// matches the implicit instantiation of C in C<42>. +AST_MATCHER_P(TemplateArgument, equalsIntegralValue, + std::string, Value) { + if (Node.getKind() != TemplateArgument::Integral) + return false; + return Node.getAsIntegral().toString(10) == Value; +} + +/// \brief Matches any value declaration. +/// +/// Example matches A, B, C and F +/// \code +/// enum X { A, B, C }; +/// void F(); +/// \endcode +const internal::VariadicDynCastAllOfMatcher<Decl, ValueDecl> valueDecl; + +/// \brief Matches C++ constructor declarations. +/// +/// Example matches Foo::Foo() and Foo::Foo(int) +/// \code +/// class Foo { +/// public: +/// Foo(); +/// Foo(int); +/// int DoSomething(); +/// }; +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Decl, + CXXConstructorDecl> cxxConstructorDecl; + +/// \brief Matches explicit C++ destructor declarations. +/// +/// Example matches Foo::~Foo() +/// \code +/// class Foo { +/// public: +/// virtual ~Foo(); +/// }; +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Decl, + CXXDestructorDecl> cxxDestructorDecl; + +/// \brief Matches enum declarations. +/// +/// Example matches X +/// \code +/// enum X { +/// A, B, C +/// }; +/// \endcode +const internal::VariadicDynCastAllOfMatcher<Decl, EnumDecl> enumDecl; + +/// \brief Matches enum constants. +/// +/// Example matches A, B, C +/// \code +/// enum X { +/// A, B, C +/// }; +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Decl, + EnumConstantDecl> enumConstantDecl; + +/// \brief Matches method declarations. +/// +/// Example matches y +/// \code +/// class X { void y(); }; +/// \endcode +const internal::VariadicDynCastAllOfMatcher<Decl, CXXMethodDecl> cxxMethodDecl; + +/// \brief Matches conversion operator declarations. +/// +/// Example matches the operator. +/// \code +/// class X { operator int() const; }; +/// \endcode +const internal::VariadicDynCastAllOfMatcher<Decl, CXXConversionDecl> + cxxConversionDecl; + +/// \brief Matches variable declarations. +/// +/// Note: this does not match declarations of member variables, which are +/// "field" declarations in Clang parlance. +/// +/// Example matches a +/// \code +/// int a; +/// \endcode +const internal::VariadicDynCastAllOfMatcher<Decl, VarDecl> varDecl; + +/// \brief Matches field declarations. +/// +/// Given +/// \code +/// class X { int m; }; +/// \endcode +/// fieldDecl() +/// matches 'm'. +const internal::VariadicDynCastAllOfMatcher<Decl, FieldDecl> fieldDecl; + +/// \brief Matches function declarations. +/// +/// Example matches f +/// \code +/// void f(); +/// \endcode +const internal::VariadicDynCastAllOfMatcher<Decl, FunctionDecl> functionDecl; + +/// \brief Matches C++ function template declarations. +/// +/// Example matches f +/// \code +/// template<class T> void f(T t) {} +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Decl, + FunctionTemplateDecl> functionTemplateDecl; + +/// \brief Matches friend declarations. +/// +/// Given +/// \code +/// class X { friend void foo(); }; +/// \endcode +/// friendDecl() +/// matches 'friend void foo()'. +const internal::VariadicDynCastAllOfMatcher<Decl, FriendDecl> friendDecl; + +/// \brief Matches statements. +/// +/// Given +/// \code +/// { ++a; } +/// \endcode +/// stmt() +/// matches both the compound statement '{ ++a; }' and '++a'. +const internal::VariadicAllOfMatcher<Stmt> stmt; + +/// \brief Matches declaration statements. +/// +/// Given +/// \code +/// int a; +/// \endcode +/// declStmt() +/// matches 'int a'. +const internal::VariadicDynCastAllOfMatcher< + Stmt, + DeclStmt> declStmt; + +/// \brief Matches member expressions. +/// +/// Given +/// \code +/// class Y { +/// void x() { this->x(); x(); Y y; y.x(); a; this->b; Y::b; } +/// int a; static int b; +/// }; +/// \endcode +/// memberExpr() +/// matches this->x, x, y.x, a, this->b +const internal::VariadicDynCastAllOfMatcher<Stmt, MemberExpr> memberExpr; + +/// \brief Matches call expressions. +/// +/// Example matches x.y() and y() +/// \code +/// X x; +/// x.y(); +/// y(); +/// \endcode +const internal::VariadicDynCastAllOfMatcher<Stmt, CallExpr> callExpr; + +/// \brief Matches lambda expressions. +/// +/// Example matches [&](){return 5;} +/// \code +/// [&](){return 5;} +/// \endcode +const internal::VariadicDynCastAllOfMatcher<Stmt, LambdaExpr> lambdaExpr; + +/// \brief Matches member call expressions. +/// +/// Example matches x.y() +/// \code +/// X x; +/// x.y(); +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Stmt, + CXXMemberCallExpr> cxxMemberCallExpr; + +/// \brief Matches ObjectiveC Message invocation expressions. +/// +/// The innermost message send invokes the "alloc" class method on the +/// NSString class, while the outermost message send invokes the +/// "initWithString" instance method on the object returned from +/// NSString's "alloc". This matcher should match both message sends. +/// \code +/// [[NSString alloc] initWithString:@"Hello"] +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Stmt, + ObjCMessageExpr> objcMessageExpr; + +/// \brief Matches Objective-C interface declarations. +/// +/// Example matches Foo +/// \code +/// @interface Foo +/// @end +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Decl, + ObjCInterfaceDecl> objcInterfaceDecl; + +/// \brief Matches expressions that introduce cleanups to be run at the end +/// of the sub-expression's evaluation. +/// +/// Example matches std::string() +/// \code +/// const std::string str = std::string(); +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Stmt, + ExprWithCleanups> exprWithCleanups; + +/// \brief Matches init list expressions. +/// +/// Given +/// \code +/// int a[] = { 1, 2 }; +/// struct B { int x, y; }; +/// B b = { 5, 6 }; +/// \endcode +/// initListExpr() +/// matches "{ 1, 2 }" and "{ 5, 6 }" +const internal::VariadicDynCastAllOfMatcher<Stmt, InitListExpr> initListExpr; + +/// \brief Matches substitutions of non-type template parameters. +/// +/// Given +/// \code +/// template <int N> +/// struct A { static const int n = N; }; +/// struct B : public A<42> {}; +/// \endcode +/// substNonTypeTemplateParmExpr() +/// matches "N" in the right-hand side of "static const int n = N;" +const internal::VariadicDynCastAllOfMatcher< + Stmt, + SubstNonTypeTemplateParmExpr> substNonTypeTemplateParmExpr; + +/// \brief Matches using declarations. +/// +/// Given +/// \code +/// namespace X { int x; } +/// using X::x; +/// \endcode +/// usingDecl() +/// matches \code using X::x \endcode +const internal::VariadicDynCastAllOfMatcher<Decl, UsingDecl> usingDecl; + +/// \brief Matches using namespace declarations. +/// +/// Given +/// \code +/// namespace X { int x; } +/// using namespace X; +/// \endcode +/// usingDirectiveDecl() +/// matches \code using namespace X \endcode +const internal::VariadicDynCastAllOfMatcher< + Decl, + UsingDirectiveDecl> usingDirectiveDecl; + +/// \brief Matches unresolved using value declarations. +/// +/// Given +/// \code +/// template<typename X> +/// class C : private X { +/// using X::x; +/// }; +/// \endcode +/// unresolvedUsingValueDecl() +/// matches \code using X::x \endcode +const internal::VariadicDynCastAllOfMatcher< + Decl, + UnresolvedUsingValueDecl> unresolvedUsingValueDecl; + +/// \brief Matches unresolved using value declarations that involve the +/// typename. +/// +/// Given +/// \code +/// template <typename T> +/// struct Base { typedef T Foo; }; +/// +/// template<typename T> +/// struct S : private Base<T> { +/// using typename Base<T>::Foo; +/// }; +/// \endcode +/// unresolvedUsingTypenameDecl() +/// matches \code using Base<T>::Foo \endcode +const internal::VariadicDynCastAllOfMatcher< + Decl, + UnresolvedUsingTypenameDecl> unresolvedUsingTypenameDecl; + +/// \brief Matches constructor call expressions (including implicit ones). +/// +/// Example matches string(ptr, n) and ptr within arguments of f +/// (matcher = cxxConstructExpr()) +/// \code +/// void f(const string &a, const string &b); +/// char *ptr; +/// int n; +/// f(string(ptr, n), ptr); +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Stmt, + CXXConstructExpr> cxxConstructExpr; + +/// \brief Matches unresolved constructor call expressions. +/// +/// Example matches T(t) in return statement of f +/// (matcher = cxxUnresolvedConstructExpr()) +/// \code +/// template <typename T> +/// void f(const T& t) { return T(t); } +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Stmt, + CXXUnresolvedConstructExpr> cxxUnresolvedConstructExpr; + +/// \brief Matches implicit and explicit this expressions. +/// +/// Example matches the implicit this expression in "return i". +/// (matcher = cxxThisExpr()) +/// \code +/// struct foo { +/// int i; +/// int f() { return i; } +/// }; +/// \endcode +const internal::VariadicDynCastAllOfMatcher<Stmt, CXXThisExpr> cxxThisExpr; + +/// \brief Matches nodes where temporaries are created. +/// +/// Example matches FunctionTakesString(GetStringByValue()) +/// (matcher = cxxBindTemporaryExpr()) +/// \code +/// FunctionTakesString(GetStringByValue()); +/// FunctionTakesStringByPointer(GetStringPointer()); +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Stmt, + CXXBindTemporaryExpr> cxxBindTemporaryExpr; + +/// \brief Matches nodes where temporaries are materialized. +/// +/// Example: Given +/// \code +/// struct T {void func()}; +/// T f(); +/// void g(T); +/// \endcode +/// materializeTemporaryExpr() matches 'f()' in these statements +/// \code +/// T u(f()); +/// g(f()); +/// \endcode +/// but does not match +/// \code +/// f(); +/// f().func(); +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Stmt, + MaterializeTemporaryExpr> materializeTemporaryExpr; + +/// \brief Matches new expressions. +/// +/// Given +/// \code +/// new X; +/// \endcode +/// cxxNewExpr() +/// matches 'new X'. +const internal::VariadicDynCastAllOfMatcher<Stmt, CXXNewExpr> cxxNewExpr; + +/// \brief Matches delete expressions. +/// +/// Given +/// \code +/// delete X; +/// \endcode +/// cxxDeleteExpr() +/// matches 'delete X'. +const internal::VariadicDynCastAllOfMatcher<Stmt, CXXDeleteExpr> cxxDeleteExpr; + +/// \brief Matches array subscript expressions. +/// +/// Given +/// \code +/// int i = a[1]; +/// \endcode +/// arraySubscriptExpr() +/// matches "a[1]" +const internal::VariadicDynCastAllOfMatcher< + Stmt, + ArraySubscriptExpr> arraySubscriptExpr; + +/// \brief Matches the value of a default argument at the call site. +/// +/// Example matches the CXXDefaultArgExpr placeholder inserted for the +/// default value of the second parameter in the call expression f(42) +/// (matcher = cxxDefaultArgExpr()) +/// \code +/// void f(int x, int y = 0); +/// f(42); +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Stmt, + CXXDefaultArgExpr> cxxDefaultArgExpr; + +/// \brief Matches overloaded operator calls. +/// +/// Note that if an operator isn't overloaded, it won't match. Instead, use +/// binaryOperator matcher. +/// Currently it does not match operators such as new delete. +/// FIXME: figure out why these do not match? +/// +/// Example matches both operator<<((o << b), c) and operator<<(o, b) +/// (matcher = cxxOperatorCallExpr()) +/// \code +/// ostream &operator<< (ostream &out, int i) { }; +/// ostream &o; int b = 1, c = 1; +/// o << b << c; +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Stmt, + CXXOperatorCallExpr> cxxOperatorCallExpr; + +/// \brief Matches expressions. +/// +/// Example matches x() +/// \code +/// void f() { x(); } +/// \endcode +const internal::VariadicDynCastAllOfMatcher<Stmt, Expr> expr; + +/// \brief Matches expressions that refer to declarations. +/// +/// Example matches x in if (x) +/// \code +/// bool x; +/// if (x) {} +/// \endcode +const internal::VariadicDynCastAllOfMatcher<Stmt, DeclRefExpr> declRefExpr; + +/// \brief Matches if statements. +/// +/// Example matches 'if (x) {}' +/// \code +/// if (x) {} +/// \endcode +const internal::VariadicDynCastAllOfMatcher<Stmt, IfStmt> ifStmt; + +/// \brief Matches for statements. +/// +/// Example matches 'for (;;) {}' +/// \code +/// for (;;) {} +/// int i[] = {1, 2, 3}; for (auto a : i); +/// \endcode +const internal::VariadicDynCastAllOfMatcher<Stmt, ForStmt> forStmt; + +/// \brief Matches the increment statement of a for loop. +/// +/// Example: +/// forStmt(hasIncrement(unaryOperator(hasOperatorName("++")))) +/// matches '++x' in +/// \code +/// for (x; x < N; ++x) { } +/// \endcode +AST_MATCHER_P(ForStmt, hasIncrement, internal::Matcher<Stmt>, + InnerMatcher) { + const Stmt *const Increment = Node.getInc(); + return (Increment != nullptr && + InnerMatcher.matches(*Increment, Finder, Builder)); +} + +/// \brief Matches the initialization statement of a for loop. +/// +/// Example: +/// forStmt(hasLoopInit(declStmt())) +/// matches 'int x = 0' in +/// \code +/// for (int x = 0; x < N; ++x) { } +/// \endcode +AST_MATCHER_P(ForStmt, hasLoopInit, internal::Matcher<Stmt>, + InnerMatcher) { + const Stmt *const Init = Node.getInit(); + return (Init != nullptr && InnerMatcher.matches(*Init, Finder, Builder)); +} + +/// \brief Matches range-based for statements. +/// +/// cxxForRangeStmt() matches 'for (auto a : i)' +/// \code +/// int i[] = {1, 2, 3}; for (auto a : i); +/// for(int j = 0; j < 5; ++j); +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Stmt, + CXXForRangeStmt> cxxForRangeStmt; + +/// \brief Matches the initialization statement of a for loop. +/// +/// Example: +/// forStmt(hasLoopVariable(anything())) +/// matches 'int x' in +/// \code +/// for (int x : a) { } +/// \endcode +AST_MATCHER_P(CXXForRangeStmt, hasLoopVariable, internal::Matcher<VarDecl>, + InnerMatcher) { + const VarDecl *const Var = Node.getLoopVariable(); + return (Var != nullptr && InnerMatcher.matches(*Var, Finder, Builder)); +} + +/// \brief Matches the range initialization statement of a for loop. +/// +/// Example: +/// forStmt(hasRangeInit(anything())) +/// matches 'a' in +/// \code +/// for (int x : a) { } +/// \endcode +AST_MATCHER_P(CXXForRangeStmt, hasRangeInit, internal::Matcher<Expr>, + InnerMatcher) { + const Expr *const Init = Node.getRangeInit(); + return (Init != nullptr && InnerMatcher.matches(*Init, Finder, Builder)); +} + +/// \brief Matches while statements. +/// +/// Given +/// \code +/// while (true) {} +/// \endcode +/// whileStmt() +/// matches 'while (true) {}'. +const internal::VariadicDynCastAllOfMatcher<Stmt, WhileStmt> whileStmt; + +/// \brief Matches do statements. +/// +/// Given +/// \code +/// do {} while (true); +/// \endcode +/// doStmt() +/// matches 'do {} while(true)' +const internal::VariadicDynCastAllOfMatcher<Stmt, DoStmt> doStmt; + +/// \brief Matches break statements. +/// +/// Given +/// \code +/// while (true) { break; } +/// \endcode +/// breakStmt() +/// matches 'break' +const internal::VariadicDynCastAllOfMatcher<Stmt, BreakStmt> breakStmt; + +/// \brief Matches continue statements. +/// +/// Given +/// \code +/// while (true) { continue; } +/// \endcode +/// continueStmt() +/// matches 'continue' +const internal::VariadicDynCastAllOfMatcher<Stmt, ContinueStmt> continueStmt; + +/// \brief Matches return statements. +/// +/// Given +/// \code +/// return 1; +/// \endcode +/// returnStmt() +/// matches 'return 1' +const internal::VariadicDynCastAllOfMatcher<Stmt, ReturnStmt> returnStmt; + +/// \brief Matches goto statements. +/// +/// Given +/// \code +/// goto FOO; +/// FOO: bar(); +/// \endcode +/// gotoStmt() +/// matches 'goto FOO' +const internal::VariadicDynCastAllOfMatcher<Stmt, GotoStmt> gotoStmt; + +/// \brief Matches label statements. +/// +/// Given +/// \code +/// goto FOO; +/// FOO: bar(); +/// \endcode +/// labelStmt() +/// matches 'FOO:' +const internal::VariadicDynCastAllOfMatcher<Stmt, LabelStmt> labelStmt; + +/// \brief Matches switch statements. +/// +/// Given +/// \code +/// switch(a) { case 42: break; default: break; } +/// \endcode +/// switchStmt() +/// matches 'switch(a)'. +const internal::VariadicDynCastAllOfMatcher<Stmt, SwitchStmt> switchStmt; + +/// \brief Matches case and default statements inside switch statements. +/// +/// Given +/// \code +/// switch(a) { case 42: break; default: break; } +/// \endcode +/// switchCase() +/// matches 'case 42: break;' and 'default: break;'. +const internal::VariadicDynCastAllOfMatcher<Stmt, SwitchCase> switchCase; + +/// \brief Matches case statements inside switch statements. +/// +/// Given +/// \code +/// switch(a) { case 42: break; default: break; } +/// \endcode +/// caseStmt() +/// matches 'case 42: break;'. +const internal::VariadicDynCastAllOfMatcher<Stmt, CaseStmt> caseStmt; + +/// \brief Matches default statements inside switch statements. +/// +/// Given +/// \code +/// switch(a) { case 42: break; default: break; } +/// \endcode +/// defaultStmt() +/// matches 'default: break;'. +const internal::VariadicDynCastAllOfMatcher<Stmt, DefaultStmt> defaultStmt; + +/// \brief Matches compound statements. +/// +/// Example matches '{}' and '{{}}'in 'for (;;) {{}}' +/// \code +/// for (;;) {{}} +/// \endcode +const internal::VariadicDynCastAllOfMatcher<Stmt, CompoundStmt> compoundStmt; + +/// \brief Matches catch statements. +/// +/// \code +/// try {} catch(int i) {} +/// \endcode +/// cxxCatchStmt() +/// matches 'catch(int i)' +const internal::VariadicDynCastAllOfMatcher<Stmt, CXXCatchStmt> cxxCatchStmt; + +/// \brief Matches try statements. +/// +/// \code +/// try {} catch(int i) {} +/// \endcode +/// cxxTryStmt() +/// matches 'try {}' +const internal::VariadicDynCastAllOfMatcher<Stmt, CXXTryStmt> cxxTryStmt; + +/// \brief Matches throw expressions. +/// +/// \code +/// try { throw 5; } catch(int i) {} +/// \endcode +/// cxxThrowExpr() +/// matches 'throw 5' +const internal::VariadicDynCastAllOfMatcher<Stmt, CXXThrowExpr> cxxThrowExpr; + +/// \brief Matches null statements. +/// +/// \code +/// foo();; +/// \endcode +/// nullStmt() +/// matches the second ';' +const internal::VariadicDynCastAllOfMatcher<Stmt, NullStmt> nullStmt; + +/// \brief Matches asm statements. +/// +/// \code +/// int i = 100; +/// __asm("mov al, 2"); +/// \endcode +/// asmStmt() +/// matches '__asm("mov al, 2")' +const internal::VariadicDynCastAllOfMatcher<Stmt, AsmStmt> asmStmt; + +/// \brief Matches bool literals. +/// +/// Example matches true +/// \code +/// true +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Stmt, + CXXBoolLiteralExpr> cxxBoolLiteral; + +/// \brief Matches string literals (also matches wide string literals). +/// +/// Example matches "abcd", L"abcd" +/// \code +/// char *s = "abcd"; wchar_t *ws = L"abcd" +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Stmt, + StringLiteral> stringLiteral; + +/// \brief Matches character literals (also matches wchar_t). +/// +/// Not matching Hex-encoded chars (e.g. 0x1234, which is a IntegerLiteral), +/// though. +/// +/// Example matches 'a', L'a' +/// \code +/// char ch = 'a'; wchar_t chw = L'a'; +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Stmt, + CharacterLiteral> characterLiteral; + +/// \brief Matches integer literals of all sizes / encodings, e.g. +/// 1, 1L, 0x1 and 1U. +/// +/// Does not match character-encoded integers such as L'a'. +const internal::VariadicDynCastAllOfMatcher< + Stmt, + IntegerLiteral> integerLiteral; + +/// \brief Matches float literals of all sizes / encodings, e.g. +/// 1.0, 1.0f, 1.0L and 1e10. +/// +/// Does not match implicit conversions such as +/// \code +/// float a = 10; +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Stmt, + FloatingLiteral> floatLiteral; + +/// \brief Matches user defined literal operator call. +/// +/// Example match: "foo"_suffix +const internal::VariadicDynCastAllOfMatcher< + Stmt, + UserDefinedLiteral> userDefinedLiteral; + +/// \brief Matches compound (i.e. non-scalar) literals +/// +/// Example match: {1}, (1, 2) +/// \code +/// int array[4] = {1}; vector int myvec = (vector int)(1, 2); +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Stmt, + CompoundLiteralExpr> compoundLiteralExpr; + +/// \brief Matches nullptr literal. +const internal::VariadicDynCastAllOfMatcher< + Stmt, + CXXNullPtrLiteralExpr> cxxNullPtrLiteralExpr; + +/// \brief Matches GNU __null expression. +const internal::VariadicDynCastAllOfMatcher< + Stmt, + GNUNullExpr> gnuNullExpr; + +/// \brief Matches binary operator expressions. +/// +/// Example matches a || b +/// \code +/// !(a || b) +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Stmt, + BinaryOperator> binaryOperator; + +/// \brief Matches unary operator expressions. +/// +/// Example matches !a +/// \code +/// !a || b +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Stmt, + UnaryOperator> unaryOperator; + +/// \brief Matches conditional operator expressions. +/// +/// Example matches a ? b : c +/// \code +/// (a ? b : c) + 42 +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Stmt, + ConditionalOperator> conditionalOperator; + +/// \brief Matches a C++ static_assert declaration. +/// +/// Example: +/// staticAssertExpr() +/// matches +/// static_assert(sizeof(S) == sizeof(int)) +/// in +/// \code +/// struct S { +/// int x; +/// }; +/// static_assert(sizeof(S) == sizeof(int)); +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Decl, + StaticAssertDecl> staticAssertDecl; + +/// \brief Matches a reinterpret_cast expression. +/// +/// Either the source expression or the destination type can be matched +/// using has(), but hasDestinationType() is more specific and can be +/// more readable. +/// +/// Example matches reinterpret_cast<char*>(&p) in +/// \code +/// void* p = reinterpret_cast<char*>(&p); +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Stmt, + CXXReinterpretCastExpr> cxxReinterpretCastExpr; + +/// \brief Matches a C++ static_cast expression. +/// +/// \see hasDestinationType +/// \see reinterpretCast +/// +/// Example: +/// cxxStaticCastExpr() +/// matches +/// static_cast<long>(8) +/// in +/// \code +/// long eight(static_cast<long>(8)); +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Stmt, + CXXStaticCastExpr> cxxStaticCastExpr; + +/// \brief Matches a dynamic_cast expression. +/// +/// Example: +/// cxxDynamicCastExpr() +/// matches +/// dynamic_cast<D*>(&b); +/// in +/// \code +/// struct B { virtual ~B() {} }; struct D : B {}; +/// B b; +/// D* p = dynamic_cast<D*>(&b); +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Stmt, + CXXDynamicCastExpr> cxxDynamicCastExpr; + +/// \brief Matches a const_cast expression. +/// +/// Example: Matches const_cast<int*>(&r) in +/// \code +/// int n = 42; +/// const int &r(n); +/// int* p = const_cast<int*>(&r); +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Stmt, + CXXConstCastExpr> cxxConstCastExpr; + +/// \brief Matches a C-style cast expression. +/// +/// Example: Matches (int*) 2.2f in +/// \code +/// int i = (int) 2.2f; +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Stmt, + CStyleCastExpr> cStyleCastExpr; + +/// \brief Matches explicit cast expressions. +/// +/// Matches any cast expression written in user code, whether it be a +/// C-style cast, a functional-style cast, or a keyword cast. +/// +/// Does not match implicit conversions. +/// +/// Note: the name "explicitCast" is chosen to match Clang's terminology, as +/// Clang uses the term "cast" to apply to implicit conversions as well as to +/// actual cast expressions. +/// +/// \see hasDestinationType. +/// +/// Example: matches all five of the casts in +/// \code +/// int((int)(reinterpret_cast<int>(static_cast<int>(const_cast<int>(42))))) +/// \endcode +/// but does not match the implicit conversion in +/// \code +/// long ell = 42; +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Stmt, + ExplicitCastExpr> explicitCastExpr; + +/// \brief Matches the implicit cast nodes of Clang's AST. +/// +/// This matches many different places, including function call return value +/// eliding, as well as any type conversions. +const internal::VariadicDynCastAllOfMatcher< + Stmt, + ImplicitCastExpr> implicitCastExpr; + +/// \brief Matches any cast nodes of Clang's AST. +/// +/// Example: castExpr() matches each of the following: +/// \code +/// (int) 3; +/// const_cast<Expr *>(SubExpr); +/// char c = 0; +/// \endcode +/// but does not match +/// \code +/// int i = (0); +/// int k = 0; +/// \endcode +const internal::VariadicDynCastAllOfMatcher<Stmt, CastExpr> castExpr; + +/// \brief Matches functional cast expressions +/// +/// Example: Matches Foo(bar); +/// \code +/// Foo f = bar; +/// Foo g = (Foo) bar; +/// Foo h = Foo(bar); +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Stmt, + CXXFunctionalCastExpr> cxxFunctionalCastExpr; + +/// \brief Matches functional cast expressions having N != 1 arguments +/// +/// Example: Matches Foo(bar, bar) +/// \code +/// Foo h = Foo(bar, bar); +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Stmt, + CXXTemporaryObjectExpr> cxxTemporaryObjectExpr; + +/// \brief Matches \c QualTypes in the clang AST. +const internal::VariadicAllOfMatcher<QualType> qualType; + +/// \brief Matches \c Types in the clang AST. +const internal::VariadicAllOfMatcher<Type> type; + +/// \brief Matches \c TypeLocs in the clang AST. +const internal::VariadicAllOfMatcher<TypeLoc> typeLoc; + +/// \brief Matches if any of the given matchers matches. +/// +/// Unlike \c anyOf, \c eachOf will generate a match result for each +/// matching submatcher. +/// +/// For example, in: +/// \code +/// class A { int a; int b; }; +/// \endcode +/// The matcher: +/// \code +/// cxxRecordDecl(eachOf(has(fieldDecl(hasName("a")).bind("v")), +/// has(fieldDecl(hasName("b")).bind("v")))) +/// \endcode +/// will generate two results binding "v", the first of which binds +/// the field declaration of \c a, the second the field declaration of +/// \c b. +/// +/// Usable as: Any Matcher +const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> eachOf = { + internal::DynTypedMatcher::VO_EachOf +}; + +/// \brief Matches if any of the given matchers matches. +/// +/// Usable as: Any Matcher +const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> anyOf = { + internal::DynTypedMatcher::VO_AnyOf +}; + +/// \brief Matches if all given matchers match. +/// +/// Usable as: Any Matcher +const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> allOf = { + internal::DynTypedMatcher::VO_AllOf +}; + +/// \brief Matches sizeof (C99), alignof (C++11) and vec_step (OpenCL) +/// +/// Given +/// \code +/// Foo x = bar; +/// int y = sizeof(x) + alignof(x); +/// \endcode +/// unaryExprOrTypeTraitExpr() +/// matches \c sizeof(x) and \c alignof(x) +const internal::VariadicDynCastAllOfMatcher< + Stmt, + UnaryExprOrTypeTraitExpr> unaryExprOrTypeTraitExpr; + +/// \brief Matches unary expressions that have a specific type of argument. +/// +/// Given +/// \code +/// int a, c; float b; int s = sizeof(a) + sizeof(b) + alignof(c); +/// \endcode +/// unaryExprOrTypeTraitExpr(hasArgumentOfType(asString("int")) +/// matches \c sizeof(a) and \c alignof(c) +AST_MATCHER_P(UnaryExprOrTypeTraitExpr, hasArgumentOfType, + internal::Matcher<QualType>, InnerMatcher) { + const QualType ArgumentType = Node.getTypeOfArgument(); + return InnerMatcher.matches(ArgumentType, Finder, Builder); +} + +/// \brief Matches unary expressions of a certain kind. +/// +/// Given +/// \code +/// int x; +/// int s = sizeof(x) + alignof(x) +/// \endcode +/// unaryExprOrTypeTraitExpr(ofKind(UETT_SizeOf)) +/// matches \c sizeof(x) +AST_MATCHER_P(UnaryExprOrTypeTraitExpr, ofKind, UnaryExprOrTypeTrait, Kind) { + return Node.getKind() == Kind; +} + +/// \brief Same as unaryExprOrTypeTraitExpr, but only matching +/// alignof. +inline internal::Matcher<Stmt> alignOfExpr( + const internal::Matcher<UnaryExprOrTypeTraitExpr> &InnerMatcher) { + return stmt(unaryExprOrTypeTraitExpr(allOf( + ofKind(UETT_AlignOf), InnerMatcher))); +} + +/// \brief Same as unaryExprOrTypeTraitExpr, but only matching +/// sizeof. +inline internal::Matcher<Stmt> sizeOfExpr( + const internal::Matcher<UnaryExprOrTypeTraitExpr> &InnerMatcher) { + return stmt(unaryExprOrTypeTraitExpr( + allOf(ofKind(UETT_SizeOf), InnerMatcher))); +} + +/// \brief Matches NamedDecl nodes that have the specified name. +/// +/// Supports specifying enclosing namespaces or classes by prefixing the name +/// with '<enclosing>::'. +/// Does not match typedefs of an underlying type with the given name. +/// +/// Example matches X (Name == "X") +/// \code +/// class X; +/// \endcode +/// +/// Example matches X (Name is one of "::a::b::X", "a::b::X", "b::X", "X") +/// \code +/// namespace a { namespace b { class X; } } +/// \endcode +inline internal::Matcher<NamedDecl> hasName(const std::string &Name) { + return internal::Matcher<NamedDecl>(new internal::HasNameMatcher(Name)); +} + +/// \brief Matches NamedDecl nodes whose fully qualified names contain +/// a substring matched by the given RegExp. +/// +/// Supports specifying enclosing namespaces or classes by +/// prefixing the name with '<enclosing>::'. Does not match typedefs +/// of an underlying type with the given name. +/// +/// Example matches X (regexp == "::X") +/// \code +/// class X; +/// \endcode +/// +/// Example matches X (regexp is one of "::X", "^foo::.*X", among others) +/// \code +/// namespace foo { namespace bar { class X; } } +/// \endcode +AST_MATCHER_P(NamedDecl, matchesName, std::string, RegExp) { + assert(!RegExp.empty()); + std::string FullNameString = "::" + Node.getQualifiedNameAsString(); + llvm::Regex RE(RegExp); + return RE.match(FullNameString); +} + +/// \brief Matches overloaded operator names. +/// +/// Matches overloaded operator names specified in strings without the +/// "operator" prefix: e.g. "<<". +/// +/// Given: +/// \code +/// class A { int operator*(); }; +/// const A &operator<<(const A &a, const A &b); +/// A a; +/// a << a; // <-- This matches +/// \endcode +/// +/// \c cxxOperatorCallExpr(hasOverloadedOperatorName("<<"))) matches the +/// specified line and +/// \c cxxRecordDecl(hasMethod(hasOverloadedOperatorName("*"))) +/// matches the declaration of \c A. +/// +/// Usable as: Matcher<CXXOperatorCallExpr>, Matcher<FunctionDecl> +inline internal::PolymorphicMatcherWithParam1< + internal::HasOverloadedOperatorNameMatcher, StringRef, + AST_POLYMORPHIC_SUPPORTED_TYPES(CXXOperatorCallExpr, FunctionDecl)> +hasOverloadedOperatorName(StringRef Name) { + return internal::PolymorphicMatcherWithParam1< + internal::HasOverloadedOperatorNameMatcher, StringRef, + AST_POLYMORPHIC_SUPPORTED_TYPES(CXXOperatorCallExpr, FunctionDecl)>(Name); +} + +/// \brief Matches C++ classes that are directly or indirectly derived from +/// a class matching \c Base. +/// +/// Note that a class is not considered to be derived from itself. +/// +/// Example matches Y, Z, C (Base == hasName("X")) +/// \code +/// class X; +/// class Y : public X {}; // directly derived +/// class Z : public Y {}; // indirectly derived +/// typedef X A; +/// typedef A B; +/// class C : public B {}; // derived from a typedef of X +/// \endcode +/// +/// In the following example, Bar matches isDerivedFrom(hasName("X")): +/// \code +/// class Foo; +/// typedef Foo X; +/// class Bar : public Foo {}; // derived from a type that X is a typedef of +/// \endcode +AST_MATCHER_P(CXXRecordDecl, isDerivedFrom, + internal::Matcher<NamedDecl>, Base) { + return Finder->classIsDerivedFrom(&Node, Base, Builder); +} + +/// \brief Overloaded method as shortcut for \c isDerivedFrom(hasName(...)). +AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isDerivedFrom, std::string, BaseName, 1) { + assert(!BaseName.empty()); + return isDerivedFrom(hasName(BaseName)).matches(Node, Finder, Builder); +} + +/// \brief Similar to \c isDerivedFrom(), but also matches classes that directly +/// match \c Base. +AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isSameOrDerivedFrom, + internal::Matcher<NamedDecl>, Base, 0) { + return Matcher<CXXRecordDecl>(anyOf(Base, isDerivedFrom(Base))) + .matches(Node, Finder, Builder); +} + +/// \brief Overloaded method as shortcut for +/// \c isSameOrDerivedFrom(hasName(...)). +AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isSameOrDerivedFrom, std::string, + BaseName, 1) { + assert(!BaseName.empty()); + return isSameOrDerivedFrom(hasName(BaseName)).matches(Node, Finder, Builder); +} + +/// \brief Matches the first method of a class or struct that satisfies \c +/// InnerMatcher. +/// +/// Given: +/// \code +/// class A { void func(); }; +/// class B { void member(); }; +/// \endcode +/// +/// \c cxxRecordDecl(hasMethod(hasName("func"))) matches the declaration of +/// \c A but not \c B. +AST_MATCHER_P(CXXRecordDecl, hasMethod, internal::Matcher<CXXMethodDecl>, + InnerMatcher) { + return matchesFirstInPointerRange(InnerMatcher, Node.method_begin(), + Node.method_end(), Finder, Builder); +} + +/// \brief Matches AST nodes that have child AST nodes that match the +/// provided matcher. +/// +/// Example matches X, Y +/// (matcher = cxxRecordDecl(has(cxxRecordDecl(hasName("X"))) +/// \code +/// class X {}; // Matches X, because X::X is a class of name X inside X. +/// class Y { class X {}; }; +/// class Z { class Y { class X {}; }; }; // Does not match Z. +/// \endcode +/// +/// ChildT must be an AST base type. +/// +/// Usable as: Any Matcher +const internal::ArgumentAdaptingMatcherFunc<internal::HasMatcher> +LLVM_ATTRIBUTE_UNUSED has = {}; + +/// \brief Matches AST nodes that have descendant AST nodes that match the +/// provided matcher. +/// +/// Example matches X, Y, Z +/// (matcher = cxxRecordDecl(hasDescendant(cxxRecordDecl(hasName("X"))))) +/// \code +/// class X {}; // Matches X, because X::X is a class of name X inside X. +/// class Y { class X {}; }; +/// class Z { class Y { class X {}; }; }; +/// \endcode +/// +/// DescendantT must be an AST base type. +/// +/// Usable as: Any Matcher +const internal::ArgumentAdaptingMatcherFunc<internal::HasDescendantMatcher> +LLVM_ATTRIBUTE_UNUSED hasDescendant = {}; + +/// \brief Matches AST nodes that have child AST nodes that match the +/// provided matcher. +/// +/// Example matches X, Y +/// (matcher = cxxRecordDecl(forEach(cxxRecordDecl(hasName("X"))) +/// \code +/// class X {}; // Matches X, because X::X is a class of name X inside X. +/// class Y { class X {}; }; +/// class Z { class Y { class X {}; }; }; // Does not match Z. +/// \endcode +/// +/// ChildT must be an AST base type. +/// +/// As opposed to 'has', 'forEach' will cause a match for each result that +/// matches instead of only on the first one. +/// +/// Usable as: Any Matcher +const internal::ArgumentAdaptingMatcherFunc<internal::ForEachMatcher> +LLVM_ATTRIBUTE_UNUSED forEach = {}; + +/// \brief Matches AST nodes that have descendant AST nodes that match the +/// provided matcher. +/// +/// Example matches X, A, B, C +/// (matcher = cxxRecordDecl(forEachDescendant(cxxRecordDecl(hasName("X"))))) +/// \code +/// class X {}; // Matches X, because X::X is a class of name X inside X. +/// class A { class X {}; }; +/// class B { class C { class X {}; }; }; +/// \endcode +/// +/// DescendantT must be an AST base type. +/// +/// As opposed to 'hasDescendant', 'forEachDescendant' will cause a match for +/// each result that matches instead of only on the first one. +/// +/// Note: Recursively combined ForEachDescendant can cause many matches: +/// cxxRecordDecl(forEachDescendant(cxxRecordDecl( +/// forEachDescendant(cxxRecordDecl()) +/// ))) +/// will match 10 times (plus injected class name matches) on: +/// \code +/// class A { class B { class C { class D { class E {}; }; }; }; }; +/// \endcode +/// +/// Usable as: Any Matcher +const internal::ArgumentAdaptingMatcherFunc<internal::ForEachDescendantMatcher> +LLVM_ATTRIBUTE_UNUSED forEachDescendant = {}; + +/// \brief Matches if the node or any descendant matches. +/// +/// Generates results for each match. +/// +/// For example, in: +/// \code +/// class A { class B {}; class C {}; }; +/// \endcode +/// The matcher: +/// \code +/// cxxRecordDecl(hasName("::A"), +/// findAll(cxxRecordDecl(isDefinition()).bind("m"))) +/// \endcode +/// will generate results for \c A, \c B and \c C. +/// +/// Usable as: Any Matcher +template <typename T> +internal::Matcher<T> findAll(const internal::Matcher<T> &Matcher) { + return eachOf(Matcher, forEachDescendant(Matcher)); +} + +/// \brief Matches AST nodes that have a parent that matches the provided +/// matcher. +/// +/// Given +/// \code +/// void f() { for (;;) { int x = 42; if (true) { int x = 43; } } } +/// \endcode +/// \c compoundStmt(hasParent(ifStmt())) matches "{ int x = 43; }". +/// +/// Usable as: Any Matcher +const internal::ArgumentAdaptingMatcherFunc< + internal::HasParentMatcher, + internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc>, + internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc>> + LLVM_ATTRIBUTE_UNUSED hasParent = {}; + +/// \brief Matches AST nodes that have an ancestor that matches the provided +/// matcher. +/// +/// Given +/// \code +/// void f() { if (true) { int x = 42; } } +/// void g() { for (;;) { int x = 43; } } +/// \endcode +/// \c expr(integerLiteral(hasAncestor(ifStmt()))) matches \c 42, but not 43. +/// +/// Usable as: Any Matcher +const internal::ArgumentAdaptingMatcherFunc< + internal::HasAncestorMatcher, + internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc>, + internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc>> + LLVM_ATTRIBUTE_UNUSED hasAncestor = {}; + +/// \brief Matches if the provided matcher does not match. +/// +/// Example matches Y (matcher = cxxRecordDecl(unless(hasName("X")))) +/// \code +/// class X {}; +/// class Y {}; +/// \endcode +/// +/// Usable as: Any Matcher +const internal::VariadicOperatorMatcherFunc<1, 1> unless = { + internal::DynTypedMatcher::VO_UnaryNot +}; + +/// \brief Matches a node if the declaration associated with that node +/// matches the given matcher. +/// +/// The associated declaration is: +/// - for type nodes, the declaration of the underlying type +/// - for CallExpr, the declaration of the callee +/// - for MemberExpr, the declaration of the referenced member +/// - for CXXConstructExpr, the declaration of the constructor +/// +/// Also usable as Matcher<T> for any T supporting the getDecl() member +/// function. e.g. various subtypes of clang::Type and various expressions. +/// +/// Usable as: Matcher<CallExpr>, Matcher<CXXConstructExpr>, +/// Matcher<DeclRefExpr>, Matcher<EnumType>, Matcher<InjectedClassNameType>, +/// Matcher<LabelStmt>, Matcher<MemberExpr>, Matcher<QualType>, +/// Matcher<RecordType>, Matcher<TagType>, +/// Matcher<TemplateSpecializationType>, Matcher<TemplateTypeParmType>, +/// Matcher<TypedefType>, Matcher<UnresolvedUsingType> +inline internal::PolymorphicMatcherWithParam1< + internal::HasDeclarationMatcher, internal::Matcher<Decl>, + void(internal::HasDeclarationSupportedTypes)> +hasDeclaration(const internal::Matcher<Decl> &InnerMatcher) { + return internal::PolymorphicMatcherWithParam1< + internal::HasDeclarationMatcher, internal::Matcher<Decl>, + void(internal::HasDeclarationSupportedTypes)>(InnerMatcher); +} + +/// \brief Matches on the implicit object argument of a member call expression. +/// +/// Example matches y.x() +/// (matcher = cxxMemberCallExpr(on(hasType(cxxRecordDecl(hasName("Y")))))) +/// \code +/// class Y { public: void x(); }; +/// void z() { Y y; y.x(); }", +/// \endcode +/// +/// FIXME: Overload to allow directly matching types? +AST_MATCHER_P(CXXMemberCallExpr, on, internal::Matcher<Expr>, + InnerMatcher) { + const Expr *ExprNode = Node.getImplicitObjectArgument() + ->IgnoreParenImpCasts(); + return (ExprNode != nullptr && + InnerMatcher.matches(*ExprNode, Finder, Builder)); +} + + +/// \brief Matches on the receiver of an ObjectiveC Message expression. +/// +/// Example +/// matcher = objCMessageExpr(hasRecieverType(asString("UIWebView *"))); +/// matches the [webView ...] message invocation. +/// \code +/// NSString *webViewJavaScript = ... +/// UIWebView *webView = ... +/// [webView stringByEvaluatingJavaScriptFromString:webViewJavascript]; +/// \endcode +AST_MATCHER_P(ObjCMessageExpr, hasReceiverType, internal::Matcher<QualType>, + InnerMatcher) { + const QualType TypeDecl = Node.getReceiverType(); + return InnerMatcher.matches(TypeDecl, Finder, Builder); +} + +/// \brief Matches when BaseName == Selector.getAsString() +/// +/// matcher = objCMessageExpr(hasSelector("loadHTMLString:baseURL:")); +/// matches the outer message expr in the code below, but NOT the message +/// invocation for self.bodyView. +/// \code +/// [self.bodyView loadHTMLString:html baseURL:NULL]; +/// \endcode +AST_MATCHER_P(ObjCMessageExpr, hasSelector, std::string, BaseName) { + Selector Sel = Node.getSelector(); + return BaseName.compare(Sel.getAsString()) == 0; +} + + +/// \brief Matches ObjC selectors whose name contains +/// a substring matched by the given RegExp. +/// matcher = objCMessageExpr(matchesSelector("loadHTMLString\:baseURL?")); +/// matches the outer message expr in the code below, but NOT the message +/// invocation for self.bodyView. +/// \code +/// [self.bodyView loadHTMLString:html baseURL:NULL]; +/// \endcode +AST_MATCHER_P(ObjCMessageExpr, matchesSelector, std::string, RegExp) { + assert(!RegExp.empty()); + std::string SelectorString = Node.getSelector().getAsString(); + llvm::Regex RE(RegExp); + return RE.match(SelectorString); +} + +/// \brief Matches when the selector is the empty selector +/// +/// Matches only when the selector of the objCMessageExpr is NULL. This may +/// represent an error condition in the tree! +AST_MATCHER(ObjCMessageExpr, hasNullSelector) { + return Node.getSelector().isNull(); +} + +/// \brief Matches when the selector is a Unary Selector +/// +/// matcher = objCMessageExpr(matchesSelector(hasUnarySelector()); +/// matches self.bodyView in the code below, but NOT the outer message +/// invocation of "loadHTMLString:baseURL:". +/// \code +/// [self.bodyView loadHTMLString:html baseURL:NULL]; +/// \endcode +AST_MATCHER(ObjCMessageExpr, hasUnarySelector) { + return Node.getSelector().isUnarySelector(); +} + +/// \brief Matches when the selector is a keyword selector +/// +/// objCMessageExpr(hasKeywordSelector()) matches the generated setFrame +/// message expression in +/// +/// \code +/// UIWebView *webView = ...; +/// CGRect bodyFrame = webView.frame; +/// bodyFrame.size.height = self.bodyContentHeight; +/// webView.frame = bodyFrame; +/// // ^---- matches here +/// \endcode +AST_MATCHER(ObjCMessageExpr, hasKeywordSelector) { + return Node.getSelector().isKeywordSelector(); +} + +/// \brief Matches when the selector has the specified number of arguments +/// +/// matcher = objCMessageExpr(numSelectorArgs(0)); +/// matches self.bodyView in the code below +/// +/// matcher = objCMessageExpr(numSelectorArgs(2)); +/// matches the invocation of "loadHTMLString:baseURL:" but not that +/// of self.bodyView +/// \code +/// [self.bodyView loadHTMLString:html baseURL:NULL]; +/// \endcode +AST_MATCHER_P(ObjCMessageExpr, numSelectorArgs, unsigned, N) { + return Node.getSelector().getNumArgs() == N; +} + +/// \brief Matches if the call expression's callee expression matches. +/// +/// Given +/// \code +/// class Y { void x() { this->x(); x(); Y y; y.x(); } }; +/// void f() { f(); } +/// \endcode +/// callExpr(callee(expr())) +/// matches this->x(), x(), y.x(), f() +/// with callee(...) +/// matching this->x, x, y.x, f respectively +/// +/// Note: Callee cannot take the more general internal::Matcher<Expr> +/// because this introduces ambiguous overloads with calls to Callee taking a +/// internal::Matcher<Decl>, as the matcher hierarchy is purely +/// implemented in terms of implicit casts. +AST_MATCHER_P(CallExpr, callee, internal::Matcher<Stmt>, + InnerMatcher) { + const Expr *ExprNode = Node.getCallee(); + return (ExprNode != nullptr && + InnerMatcher.matches(*ExprNode, Finder, Builder)); +} + +/// \brief Matches if the call expression's callee's declaration matches the +/// given matcher. +/// +/// Example matches y.x() (matcher = callExpr(callee( +/// cxxMethodDecl(hasName("x"))))) +/// \code +/// class Y { public: void x(); }; +/// void z() { Y y; y.x(); } +/// \endcode +AST_MATCHER_P_OVERLOAD(CallExpr, callee, internal::Matcher<Decl>, InnerMatcher, + 1) { + return callExpr(hasDeclaration(InnerMatcher)).matches(Node, Finder, Builder); +} + +/// \brief Matches if the expression's or declaration's type matches a type +/// matcher. +/// +/// Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X"))))) +/// and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X"))))) +/// \code +/// class X {}; +/// void y(X &x) { x; X z; } +/// \endcode +AST_POLYMORPHIC_MATCHER_P_OVERLOAD( + hasType, AST_POLYMORPHIC_SUPPORTED_TYPES(Expr, ValueDecl), + internal::Matcher<QualType>, InnerMatcher, 0) { + return InnerMatcher.matches(Node.getType(), Finder, Builder); +} + +/// \brief Overloaded to match the declaration of the expression's or value +/// declaration's type. +/// +/// In case of a value declaration (for example a variable declaration), +/// this resolves one layer of indirection. For example, in the value +/// declaration "X x;", cxxRecordDecl(hasName("X")) matches the declaration of +/// X, while varDecl(hasType(cxxRecordDecl(hasName("X")))) matches the +/// declaration of x. +/// +/// Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X"))))) +/// and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X"))))) +/// \code +/// class X {}; +/// void y(X &x) { x; X z; } +/// \endcode +/// +/// Usable as: Matcher<Expr>, Matcher<ValueDecl> +AST_POLYMORPHIC_MATCHER_P_OVERLOAD(hasType, + AST_POLYMORPHIC_SUPPORTED_TYPES(Expr, + ValueDecl), + internal::Matcher<Decl>, InnerMatcher, 1) { + return qualType(hasDeclaration(InnerMatcher)) + .matches(Node.getType(), Finder, Builder); +} + +/// \brief Matches if the type location of the declarator decl's type matches +/// the inner matcher. +/// +/// Given +/// \code +/// int x; +/// \endcode +/// declaratorDecl(hasTypeLoc(loc(asString("int")))) +/// matches int x +AST_MATCHER_P(DeclaratorDecl, hasTypeLoc, internal::Matcher<TypeLoc>, Inner) { + if (!Node.getTypeSourceInfo()) + // This happens for example for implicit destructors. + return false; + return Inner.matches(Node.getTypeSourceInfo()->getTypeLoc(), Finder, Builder); +} + +/// \brief Matches if the matched type is represented by the given string. +/// +/// Given +/// \code +/// class Y { public: void x(); }; +/// void z() { Y* y; y->x(); } +/// \endcode +/// cxxMemberCallExpr(on(hasType(asString("class Y *")))) +/// matches y->x() +AST_MATCHER_P(QualType, asString, std::string, Name) { + return Name == Node.getAsString(); +} + +/// \brief Matches if the matched type is a pointer type and the pointee type +/// matches the specified matcher. +/// +/// Example matches y->x() +/// (matcher = cxxMemberCallExpr(on(hasType(pointsTo +/// cxxRecordDecl(hasName("Y"))))))) +/// \code +/// class Y { public: void x(); }; +/// void z() { Y *y; y->x(); } +/// \endcode +AST_MATCHER_P( + QualType, pointsTo, internal::Matcher<QualType>, + InnerMatcher) { + return (!Node.isNull() && Node->isAnyPointerType() && + InnerMatcher.matches(Node->getPointeeType(), Finder, Builder)); +} + +/// \brief Overloaded to match the pointee type's declaration. +AST_MATCHER_P_OVERLOAD(QualType, pointsTo, internal::Matcher<Decl>, + InnerMatcher, 1) { + return pointsTo(qualType(hasDeclaration(InnerMatcher))) + .matches(Node, Finder, Builder); +} + +/// \brief Matches if the matched type is a reference type and the referenced +/// type matches the specified matcher. +/// +/// Example matches X &x and const X &y +/// (matcher = varDecl(hasType(references(cxxRecordDecl(hasName("X")))))) +/// \code +/// class X { +/// void a(X b) { +/// X &x = b; +/// const X &y = b; +/// } +/// }; +/// \endcode +AST_MATCHER_P(QualType, references, internal::Matcher<QualType>, + InnerMatcher) { + return (!Node.isNull() && Node->isReferenceType() && + InnerMatcher.matches(Node->getPointeeType(), Finder, Builder)); +} + +/// \brief Matches QualTypes whose canonical type matches InnerMatcher. +/// +/// Given: +/// \code +/// typedef int &int_ref; +/// int a; +/// int_ref b = a; +/// \endcode +/// +/// \c varDecl(hasType(qualType(referenceType()))))) will not match the +/// declaration of b but \c +/// varDecl(hasType(qualType(hasCanonicalType(referenceType())))))) does. +AST_MATCHER_P(QualType, hasCanonicalType, internal::Matcher<QualType>, + InnerMatcher) { + if (Node.isNull()) + return false; + return InnerMatcher.matches(Node.getCanonicalType(), Finder, Builder); +} + +/// \brief Overloaded to match the referenced type's declaration. +AST_MATCHER_P_OVERLOAD(QualType, references, internal::Matcher<Decl>, + InnerMatcher, 1) { + return references(qualType(hasDeclaration(InnerMatcher))) + .matches(Node, Finder, Builder); +} + +AST_MATCHER_P(CXXMemberCallExpr, onImplicitObjectArgument, + internal::Matcher<Expr>, InnerMatcher) { + const Expr *ExprNode = Node.getImplicitObjectArgument(); + return (ExprNode != nullptr && + InnerMatcher.matches(*ExprNode, Finder, Builder)); +} + +/// \brief Matches if the expression's type either matches the specified +/// matcher, or is a pointer to a type that matches the InnerMatcher. +AST_MATCHER_P_OVERLOAD(CXXMemberCallExpr, thisPointerType, + internal::Matcher<QualType>, InnerMatcher, 0) { + return onImplicitObjectArgument( + anyOf(hasType(InnerMatcher), hasType(pointsTo(InnerMatcher)))) + .matches(Node, Finder, Builder); +} + +/// \brief Overloaded to match the type's declaration. +AST_MATCHER_P_OVERLOAD(CXXMemberCallExpr, thisPointerType, + internal::Matcher<Decl>, InnerMatcher, 1) { + return onImplicitObjectArgument( + anyOf(hasType(InnerMatcher), hasType(pointsTo(InnerMatcher)))) + .matches(Node, Finder, Builder); +} + +/// \brief Matches a DeclRefExpr that refers to a declaration that matches the +/// specified matcher. +/// +/// Example matches x in if(x) +/// (matcher = declRefExpr(to(varDecl(hasName("x"))))) +/// \code +/// bool x; +/// if (x) {} +/// \endcode +AST_MATCHER_P(DeclRefExpr, to, internal::Matcher<Decl>, + InnerMatcher) { + const Decl *DeclNode = Node.getDecl(); + return (DeclNode != nullptr && + InnerMatcher.matches(*DeclNode, Finder, Builder)); +} + +/// \brief Matches a \c DeclRefExpr that refers to a declaration through a +/// specific using shadow declaration. +/// +/// Given +/// \code +/// namespace a { void f() {} } +/// using a::f; +/// void g() { +/// f(); // Matches this .. +/// a::f(); // .. but not this. +/// } +/// \endcode +/// declRefExpr(throughUsingDecl(anything())) +/// matches \c f() +AST_MATCHER_P(DeclRefExpr, throughUsingDecl, + internal::Matcher<UsingShadowDecl>, InnerMatcher) { + const NamedDecl *FoundDecl = Node.getFoundDecl(); + if (const UsingShadowDecl *UsingDecl = dyn_cast<UsingShadowDecl>(FoundDecl)) + return InnerMatcher.matches(*UsingDecl, Finder, Builder); + return false; +} + +/// \brief Matches the Decl of a DeclStmt which has a single declaration. +/// +/// Given +/// \code +/// int a, b; +/// int c; +/// \endcode +/// declStmt(hasSingleDecl(anything())) +/// matches 'int c;' but not 'int a, b;'. +AST_MATCHER_P(DeclStmt, hasSingleDecl, internal::Matcher<Decl>, InnerMatcher) { + if (Node.isSingleDecl()) { + const Decl *FoundDecl = Node.getSingleDecl(); + return InnerMatcher.matches(*FoundDecl, Finder, Builder); + } + return false; +} + +/// \brief Matches a variable declaration that has an initializer expression +/// that matches the given matcher. +/// +/// Example matches x (matcher = varDecl(hasInitializer(callExpr()))) +/// \code +/// bool y() { return true; } +/// bool x = y(); +/// \endcode +AST_MATCHER_P( + VarDecl, hasInitializer, internal::Matcher<Expr>, + InnerMatcher) { + const Expr *Initializer = Node.getAnyInitializer(); + return (Initializer != nullptr && + InnerMatcher.matches(*Initializer, Finder, Builder)); +} + +/// \brief Matches a variable declaration that has function scope and is a +/// non-static local variable. +/// +/// Example matches x (matcher = varDecl(hasLocalStorage()) +/// \code +/// void f() { +/// int x; +/// static int y; +/// } +/// int z; +/// \endcode +AST_MATCHER(VarDecl, hasLocalStorage) { + return Node.hasLocalStorage(); +} + +/// \brief Matches a variable declaration that does not have local storage. +/// +/// Example matches y and z (matcher = varDecl(hasGlobalStorage()) +/// \code +/// void f() { +/// int x; +/// static int y; +/// } +/// int z; +/// \endcode +AST_MATCHER(VarDecl, hasGlobalStorage) { + return Node.hasGlobalStorage(); +} + +/// \brief Matches a variable declaration that has automatic storage duration. +/// +/// Example matches x, but not y, z, or a. +/// (matcher = varDecl(hasAutomaticStorageDuration()) +/// \code +/// void f() { +/// int x; +/// static int y; +/// thread_local int z; +/// } +/// int a; +/// \endcode +AST_MATCHER(VarDecl, hasAutomaticStorageDuration) { + return Node.getStorageDuration() == SD_Automatic; +} + +/// \brief Matches a variable declaration that has static storage duration. +/// +/// Example matches y and a, but not x or z. +/// (matcher = varDecl(hasStaticStorageDuration()) +/// \code +/// void f() { +/// int x; +/// static int y; +/// thread_local int z; +/// } +/// int a; +/// \endcode +AST_MATCHER(VarDecl, hasStaticStorageDuration) { + return Node.getStorageDuration() == SD_Static; +} + +/// \brief Matches a variable declaration that has thread storage duration. +/// +/// Example matches z, but not x, z, or a. +/// (matcher = varDecl(hasThreadStorageDuration()) +/// \code +/// void f() { +/// int x; +/// static int y; +/// thread_local int z; +/// } +/// int a; +/// \endcode +AST_MATCHER(VarDecl, hasThreadStorageDuration) { + return Node.getStorageDuration() == SD_Thread; +} + +/// \brief Matches a variable declaration that is an exception variable from +/// a C++ catch block, or an Objective-C \@catch statement. +/// +/// Example matches x (matcher = varDecl(isExceptionVariable()) +/// \code +/// void f(int y) { +/// try { +/// } catch (int x) { +/// } +/// } +/// \endcode +AST_MATCHER(VarDecl, isExceptionVariable) { + return Node.isExceptionVariable(); +} + +/// \brief Checks that a call expression or a constructor call expression has +/// a specific number of arguments (including absent default arguments). +/// +/// Example matches f(0, 0) (matcher = callExpr(argumentCountIs(2))) +/// \code +/// void f(int x, int y); +/// f(0, 0); +/// \endcode +AST_POLYMORPHIC_MATCHER_P(argumentCountIs, + AST_POLYMORPHIC_SUPPORTED_TYPES(CallExpr, + CXXConstructExpr, + ObjCMessageExpr), + unsigned, N) { + return Node.getNumArgs() == N; +} + +/// \brief Matches the n'th argument of a call expression or a constructor +/// call expression. +/// +/// Example matches y in x(y) +/// (matcher = callExpr(hasArgument(0, declRefExpr()))) +/// \code +/// void x(int) { int y; x(y); } +/// \endcode +AST_POLYMORPHIC_MATCHER_P2(hasArgument, + AST_POLYMORPHIC_SUPPORTED_TYPES(CallExpr, + CXXConstructExpr, + ObjCMessageExpr), + unsigned, N, internal::Matcher<Expr>, InnerMatcher) { + return (N < Node.getNumArgs() && + InnerMatcher.matches( + *Node.getArg(N)->IgnoreParenImpCasts(), Finder, Builder)); +} + +/// \brief Matches declaration statements that contain a specific number of +/// declarations. +/// +/// Example: Given +/// \code +/// int a, b; +/// int c; +/// int d = 2, e; +/// \endcode +/// declCountIs(2) +/// matches 'int a, b;' and 'int d = 2, e;', but not 'int c;'. +AST_MATCHER_P(DeclStmt, declCountIs, unsigned, N) { + return std::distance(Node.decl_begin(), Node.decl_end()) == (ptrdiff_t)N; +} + +/// \brief Matches the n'th declaration of a declaration statement. +/// +/// Note that this does not work for global declarations because the AST +/// breaks up multiple-declaration DeclStmt's into multiple single-declaration +/// DeclStmt's. +/// Example: Given non-global declarations +/// \code +/// int a, b = 0; +/// int c; +/// int d = 2, e; +/// \endcode +/// declStmt(containsDeclaration( +/// 0, varDecl(hasInitializer(anything())))) +/// matches only 'int d = 2, e;', and +/// declStmt(containsDeclaration(1, varDecl())) +/// \code +/// matches 'int a, b = 0' as well as 'int d = 2, e;' +/// but 'int c;' is not matched. +/// \endcode +AST_MATCHER_P2(DeclStmt, containsDeclaration, unsigned, N, + internal::Matcher<Decl>, InnerMatcher) { + const unsigned NumDecls = std::distance(Node.decl_begin(), Node.decl_end()); + if (N >= NumDecls) + return false; + DeclStmt::const_decl_iterator Iterator = Node.decl_begin(); + std::advance(Iterator, N); + return InnerMatcher.matches(**Iterator, Finder, Builder); +} + +/// \brief Matches a C++ catch statement that has a catch-all handler. +/// +/// Given +/// \code +/// try { +/// // ... +/// } catch (int) { +/// // ... +/// } catch (...) { +/// // ... +/// } +/// /endcode +/// cxxCatchStmt(isCatchAll()) matches catch(...) but not catch(int). +AST_MATCHER(CXXCatchStmt, isCatchAll) { + return Node.getExceptionDecl() == nullptr; +} + +/// \brief Matches a constructor initializer. +/// +/// Given +/// \code +/// struct Foo { +/// Foo() : foo_(1) { } +/// int foo_; +/// }; +/// \endcode +/// cxxRecordDecl(has(cxxConstructorDecl( +/// hasAnyConstructorInitializer(anything()) +/// ))) +/// record matches Foo, hasAnyConstructorInitializer matches foo_(1) +AST_MATCHER_P(CXXConstructorDecl, hasAnyConstructorInitializer, + internal::Matcher<CXXCtorInitializer>, InnerMatcher) { + return matchesFirstInPointerRange(InnerMatcher, Node.init_begin(), + Node.init_end(), Finder, Builder); +} + +/// \brief Matches the field declaration of a constructor initializer. +/// +/// Given +/// \code +/// struct Foo { +/// Foo() : foo_(1) { } +/// int foo_; +/// }; +/// \endcode +/// cxxRecordDecl(has(cxxConstructorDecl(hasAnyConstructorInitializer( +/// forField(hasName("foo_")))))) +/// matches Foo +/// with forField matching foo_ +AST_MATCHER_P(CXXCtorInitializer, forField, + internal::Matcher<FieldDecl>, InnerMatcher) { + const FieldDecl *NodeAsDecl = Node.getMember(); + return (NodeAsDecl != nullptr && + InnerMatcher.matches(*NodeAsDecl, Finder, Builder)); +} + +/// \brief Matches the initializer expression of a constructor initializer. +/// +/// Given +/// \code +/// struct Foo { +/// Foo() : foo_(1) { } +/// int foo_; +/// }; +/// \endcode +/// cxxRecordDecl(has(cxxConstructorDecl(hasAnyConstructorInitializer( +/// withInitializer(integerLiteral(equals(1))))))) +/// matches Foo +/// with withInitializer matching (1) +AST_MATCHER_P(CXXCtorInitializer, withInitializer, + internal::Matcher<Expr>, InnerMatcher) { + const Expr* NodeAsExpr = Node.getInit(); + return (NodeAsExpr != nullptr && + InnerMatcher.matches(*NodeAsExpr, Finder, Builder)); +} + +/// \brief Matches a constructor initializer if it is explicitly written in +/// code (as opposed to implicitly added by the compiler). +/// +/// Given +/// \code +/// struct Foo { +/// Foo() { } +/// Foo(int) : foo_("A") { } +/// string foo_; +/// }; +/// \endcode +/// cxxConstructorDecl(hasAnyConstructorInitializer(isWritten())) +/// will match Foo(int), but not Foo() +AST_MATCHER(CXXCtorInitializer, isWritten) { + return Node.isWritten(); +} + +/// \brief Matches a constructor initializer if it is initializing a base, as +/// opposed to a member. +/// +/// Given +/// \code +/// struct B {}; +/// struct D : B { +/// int I; +/// D(int i) : I(i) {} +/// }; +/// struct E : B { +/// E() : B() {} +/// }; +/// \endcode +/// cxxConstructorDecl(hasAnyConstructorInitializer(isBaseInitializer())) +/// will match E(), but not match D(int). +AST_MATCHER(CXXCtorInitializer, isBaseInitializer) { + return Node.isBaseInitializer(); +} + +/// \brief Matches a constructor initializer if it is initializing a member, as +/// opposed to a base. +/// +/// Given +/// \code +/// struct B {}; +/// struct D : B { +/// int I; +/// D(int i) : I(i) {} +/// }; +/// struct E : B { +/// E() : B() {} +/// }; +/// \endcode +/// cxxConstructorDecl(hasAnyConstructorInitializer(isMemberInitializer())) +/// will match D(int), but not match E(). +AST_MATCHER(CXXCtorInitializer, isMemberInitializer) { + return Node.isMemberInitializer(); +} + +/// \brief Matches any argument of a call expression or a constructor call +/// expression. +/// +/// Given +/// \code +/// void x(int, int, int) { int y; x(1, y, 42); } +/// \endcode +/// callExpr(hasAnyArgument(declRefExpr())) +/// matches x(1, y, 42) +/// with hasAnyArgument(...) +/// matching y +/// +/// FIXME: Currently this will ignore parentheses and implicit casts on +/// the argument before applying the inner matcher. We'll want to remove +/// this to allow for greater control by the user once \c ignoreImplicit() +/// has been implemented. +AST_POLYMORPHIC_MATCHER_P(hasAnyArgument, + AST_POLYMORPHIC_SUPPORTED_TYPES(CallExpr, + CXXConstructExpr), + internal::Matcher<Expr>, InnerMatcher) { + for (const Expr *Arg : Node.arguments()) { + BoundNodesTreeBuilder Result(*Builder); + if (InnerMatcher.matches(*Arg->IgnoreParenImpCasts(), Finder, &Result)) { + *Builder = std::move(Result); + return true; + } + } + return false; +} + +/// \brief Matches a constructor call expression which uses list initialization. +AST_MATCHER(CXXConstructExpr, isListInitialization) { + return Node.isListInitialization(); +} + +/// \brief Matches the n'th parameter of a function declaration. +/// +/// Given +/// \code +/// class X { void f(int x) {} }; +/// \endcode +/// cxxMethodDecl(hasParameter(0, hasType(varDecl()))) +/// matches f(int x) {} +/// with hasParameter(...) +/// matching int x +AST_MATCHER_P2(FunctionDecl, hasParameter, + unsigned, N, internal::Matcher<ParmVarDecl>, + InnerMatcher) { + return (N < Node.getNumParams() && + InnerMatcher.matches( + *Node.getParamDecl(N), Finder, Builder)); +} + +/// \brief Matches any parameter of a function declaration. +/// +/// Does not match the 'this' parameter of a method. +/// +/// Given +/// \code +/// class X { void f(int x, int y, int z) {} }; +/// \endcode +/// cxxMethodDecl(hasAnyParameter(hasName("y"))) +/// matches f(int x, int y, int z) {} +/// with hasAnyParameter(...) +/// matching int y +AST_MATCHER_P(FunctionDecl, hasAnyParameter, + internal::Matcher<ParmVarDecl>, InnerMatcher) { + return matchesFirstInPointerRange(InnerMatcher, Node.param_begin(), + Node.param_end(), Finder, Builder); +} + +/// \brief Matches \c FunctionDecls that have a specific parameter count. +/// +/// Given +/// \code +/// void f(int i) {} +/// void g(int i, int j) {} +/// \endcode +/// functionDecl(parameterCountIs(2)) +/// matches g(int i, int j) {} +AST_MATCHER_P(FunctionDecl, parameterCountIs, unsigned, N) { + return Node.getNumParams() == N; +} + +/// \brief Matches the return type of a function declaration. +/// +/// Given: +/// \code +/// class X { int f() { return 1; } }; +/// \endcode +/// cxxMethodDecl(returns(asString("int"))) +/// matches int f() { return 1; } +AST_MATCHER_P(FunctionDecl, returns, + internal::Matcher<QualType>, InnerMatcher) { + return InnerMatcher.matches(Node.getReturnType(), Finder, Builder); +} + +/// \brief Matches extern "C" function declarations. +/// +/// Given: +/// \code +/// extern "C" void f() {} +/// extern "C" { void g() {} } +/// void h() {} +/// \endcode +/// functionDecl(isExternC()) +/// matches the declaration of f and g, but not the declaration h +AST_MATCHER(FunctionDecl, isExternC) { + return Node.isExternC(); +} + +/// \brief Matches deleted function declarations. +/// +/// Given: +/// \code +/// void Func(); +/// void DeletedFunc() = delete; +/// \endcode +/// functionDecl(isDeleted()) +/// matches the declaration of DeletedFunc, but not Func. +AST_MATCHER(FunctionDecl, isDeleted) { + return Node.isDeleted(); +} + +/// \brief Matches functions that have a non-throwing exception specification. +/// +/// Given: +/// \code +/// void f(); +/// void g() noexcept; +/// void h() throw(); +/// void i() throw(int); +/// void j() noexcept(false); +/// \endcode +/// functionDecl(isNoThrow()) +/// matches the declarations of g, and h, but not f, i or j. +AST_MATCHER(FunctionDecl, isNoThrow) { + const auto *FnTy = Node.getType()->getAs<FunctionProtoType>(); + + // If the function does not have a prototype, then it is assumed to be a + // throwing function (as it would if the function did not have any exception + // specification). + if (!FnTy) + return false; + + // Assume the best for any unresolved exception specification. + if (isUnresolvedExceptionSpec(FnTy->getExceptionSpecType())) + return true; + + return FnTy->isNothrow(Node.getASTContext()); +} + +/// \brief Matches constexpr variable and function declarations. +/// +/// Given: +/// \code +/// constexpr int foo = 42; +/// constexpr int bar(); +/// \endcode +/// varDecl(isConstexpr()) +/// matches the declaration of foo. +/// functionDecl(isConstexpr()) +/// matches the declaration of bar. +AST_POLYMORPHIC_MATCHER(isConstexpr, + AST_POLYMORPHIC_SUPPORTED_TYPES(VarDecl, + FunctionDecl)) { + return Node.isConstexpr(); +} + +/// \brief Matches the condition expression of an if statement, for loop, +/// or conditional operator. +/// +/// Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true)))) +/// \code +/// if (true) {} +/// \endcode +AST_POLYMORPHIC_MATCHER_P(hasCondition, + AST_POLYMORPHIC_SUPPORTED_TYPES(IfStmt, ForStmt, + WhileStmt, DoStmt, + ConditionalOperator), + internal::Matcher<Expr>, InnerMatcher) { + const Expr *const Condition = Node.getCond(); + return (Condition != nullptr && + InnerMatcher.matches(*Condition, Finder, Builder)); +} + +/// \brief Matches the then-statement of an if statement. +/// +/// Examples matches the if statement +/// (matcher = ifStmt(hasThen(cxxBoolLiteral(equals(true))))) +/// \code +/// if (false) true; else false; +/// \endcode +AST_MATCHER_P(IfStmt, hasThen, internal::Matcher<Stmt>, InnerMatcher) { + const Stmt *const Then = Node.getThen(); + return (Then != nullptr && InnerMatcher.matches(*Then, Finder, Builder)); +} + +/// \brief Matches the else-statement of an if statement. +/// +/// Examples matches the if statement +/// (matcher = ifStmt(hasElse(cxxBoolLiteral(equals(true))))) +/// \code +/// if (false) false; else true; +/// \endcode +AST_MATCHER_P(IfStmt, hasElse, internal::Matcher<Stmt>, InnerMatcher) { + const Stmt *const Else = Node.getElse(); + return (Else != nullptr && InnerMatcher.matches(*Else, Finder, Builder)); +} + +/// \brief Matches if a node equals a previously bound node. +/// +/// Matches a node if it equals the node previously bound to \p ID. +/// +/// Given +/// \code +/// class X { int a; int b; }; +/// \endcode +/// cxxRecordDecl( +/// has(fieldDecl(hasName("a"), hasType(type().bind("t")))), +/// has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t")))))) +/// matches the class \c X, as \c a and \c b have the same type. +/// +/// Note that when multiple matches are involved via \c forEach* matchers, +/// \c equalsBoundNodes acts as a filter. +/// For example: +/// compoundStmt( +/// forEachDescendant(varDecl().bind("d")), +/// forEachDescendant(declRefExpr(to(decl(equalsBoundNode("d")))))) +/// will trigger a match for each combination of variable declaration +/// and reference to that variable declaration within a compound statement. +AST_POLYMORPHIC_MATCHER_P(equalsBoundNode, + AST_POLYMORPHIC_SUPPORTED_TYPES(Stmt, Decl, Type, + QualType), + std::string, ID) { + // FIXME: Figure out whether it makes sense to allow this + // on any other node types. + // For *Loc it probably does not make sense, as those seem + // unique. For NestedNameSepcifier it might make sense, as + // those also have pointer identity, but I'm not sure whether + // they're ever reused. + internal::NotEqualsBoundNodePredicate Predicate; + Predicate.ID = ID; + Predicate.Node = ast_type_traits::DynTypedNode::create(Node); + return Builder->removeBindings(Predicate); +} + +/// \brief Matches the condition variable statement in an if statement. +/// +/// Given +/// \code +/// if (A* a = GetAPointer()) {} +/// \endcode +/// hasConditionVariableStatement(...) +/// matches 'A* a = GetAPointer()'. +AST_MATCHER_P(IfStmt, hasConditionVariableStatement, + internal::Matcher<DeclStmt>, InnerMatcher) { + const DeclStmt* const DeclarationStatement = + Node.getConditionVariableDeclStmt(); + return DeclarationStatement != nullptr && + InnerMatcher.matches(*DeclarationStatement, Finder, Builder); +} + +/// \brief Matches the index expression of an array subscript expression. +/// +/// Given +/// \code +/// int i[5]; +/// void f() { i[1] = 42; } +/// \endcode +/// arraySubscriptExpression(hasIndex(integerLiteral())) +/// matches \c i[1] with the \c integerLiteral() matching \c 1 +AST_MATCHER_P(ArraySubscriptExpr, hasIndex, + internal::Matcher<Expr>, InnerMatcher) { + if (const Expr* Expression = Node.getIdx()) + return InnerMatcher.matches(*Expression, Finder, Builder); + return false; +} + +/// \brief Matches the base expression of an array subscript expression. +/// +/// Given +/// \code +/// int i[5]; +/// void f() { i[1] = 42; } +/// \endcode +/// arraySubscriptExpression(hasBase(implicitCastExpr( +/// hasSourceExpression(declRefExpr())))) +/// matches \c i[1] with the \c declRefExpr() matching \c i +AST_MATCHER_P(ArraySubscriptExpr, hasBase, + internal::Matcher<Expr>, InnerMatcher) { + if (const Expr* Expression = Node.getBase()) + return InnerMatcher.matches(*Expression, Finder, Builder); + return false; +} + +/// \brief Matches a 'for', 'while', or 'do while' statement that has +/// a given body. +/// +/// Given +/// \code +/// for (;;) {} +/// \endcode +/// hasBody(compoundStmt()) +/// matches 'for (;;) {}' +/// with compoundStmt() +/// matching '{}' +AST_POLYMORPHIC_MATCHER_P(hasBody, + AST_POLYMORPHIC_SUPPORTED_TYPES(DoStmt, ForStmt, + WhileStmt, + CXXForRangeStmt), + internal::Matcher<Stmt>, InnerMatcher) { + const Stmt *const Statement = Node.getBody(); + return (Statement != nullptr && + InnerMatcher.matches(*Statement, Finder, Builder)); +} + +/// \brief Matches compound statements where at least one substatement matches +/// a given matcher. +/// +/// Given +/// \code +/// { {}; 1+2; } +/// \endcode +/// hasAnySubstatement(compoundStmt()) +/// matches '{ {}; 1+2; }' +/// with compoundStmt() +/// matching '{}' +AST_MATCHER_P(CompoundStmt, hasAnySubstatement, + internal::Matcher<Stmt>, InnerMatcher) { + return matchesFirstInPointerRange(InnerMatcher, Node.body_begin(), + Node.body_end(), Finder, Builder); +} + +/// \brief Checks that a compound statement contains a specific number of +/// child statements. +/// +/// Example: Given +/// \code +/// { for (;;) {} } +/// \endcode +/// compoundStmt(statementCountIs(0))) +/// matches '{}' +/// but does not match the outer compound statement. +AST_MATCHER_P(CompoundStmt, statementCountIs, unsigned, N) { + return Node.size() == N; +} + +/// \brief Matches literals that are equal to the given value. +/// +/// Example matches true (matcher = cxxBoolLiteral(equals(true))) +/// \code +/// true +/// \endcode +/// +/// Usable as: Matcher<CharacterLiteral>, Matcher<CXXBoolLiteral>, +/// Matcher<FloatingLiteral>, Matcher<IntegerLiteral> +template <typename ValueT> +internal::PolymorphicMatcherWithParam1<internal::ValueEqualsMatcher, ValueT> +equals(const ValueT &Value) { + return internal::PolymorphicMatcherWithParam1< + internal::ValueEqualsMatcher, + ValueT>(Value); +} + +/// \brief Matches the operator Name of operator expressions (binary or +/// unary). +/// +/// Example matches a || b (matcher = binaryOperator(hasOperatorName("||"))) +/// \code +/// !(a || b) +/// \endcode +AST_POLYMORPHIC_MATCHER_P(hasOperatorName, + AST_POLYMORPHIC_SUPPORTED_TYPES(BinaryOperator, + UnaryOperator), + std::string, Name) { + return Name == Node.getOpcodeStr(Node.getOpcode()); +} + +/// \brief Matches the left hand side of binary operator expressions. +/// +/// Example matches a (matcher = binaryOperator(hasLHS())) +/// \code +/// a || b +/// \endcode +AST_POLYMORPHIC_MATCHER_P(hasLHS, + AST_POLYMORPHIC_SUPPORTED_TYPES(BinaryOperator, + ArraySubscriptExpr), + internal::Matcher<Expr>, InnerMatcher) { + const Expr *LeftHandSide = Node.getLHS(); + return (LeftHandSide != nullptr && + InnerMatcher.matches(*LeftHandSide, Finder, Builder)); +} + +/// \brief Matches the right hand side of binary operator expressions. +/// +/// Example matches b (matcher = binaryOperator(hasRHS())) +/// \code +/// a || b +/// \endcode +AST_POLYMORPHIC_MATCHER_P(hasRHS, + AST_POLYMORPHIC_SUPPORTED_TYPES(BinaryOperator, + ArraySubscriptExpr), + internal::Matcher<Expr>, InnerMatcher) { + const Expr *RightHandSide = Node.getRHS(); + return (RightHandSide != nullptr && + InnerMatcher.matches(*RightHandSide, Finder, Builder)); +} + +/// \brief Matches if either the left hand side or the right hand side of a +/// binary operator matches. +inline internal::Matcher<BinaryOperator> hasEitherOperand( + const internal::Matcher<Expr> &InnerMatcher) { + return anyOf(hasLHS(InnerMatcher), hasRHS(InnerMatcher)); +} + +/// \brief Matches if the operand of a unary operator matches. +/// +/// Example matches true (matcher = hasUnaryOperand( +/// cxxBoolLiteral(equals(true)))) +/// \code +/// !true +/// \endcode +AST_MATCHER_P(UnaryOperator, hasUnaryOperand, + internal::Matcher<Expr>, InnerMatcher) { + const Expr * const Operand = Node.getSubExpr(); + return (Operand != nullptr && + InnerMatcher.matches(*Operand, Finder, Builder)); +} + +/// \brief Matches if the cast's source expression matches the given matcher. +/// +/// Example: matches "a string" (matcher = +/// hasSourceExpression(cxxConstructExpr())) +/// \code +/// class URL { URL(string); }; +/// URL url = "a string"; +/// \endcode +AST_MATCHER_P(CastExpr, hasSourceExpression, + internal::Matcher<Expr>, InnerMatcher) { + const Expr* const SubExpression = Node.getSubExpr(); + return (SubExpression != nullptr && + InnerMatcher.matches(*SubExpression, Finder, Builder)); +} + +/// \brief Matches casts whose destination type matches a given matcher. +/// +/// (Note: Clang's AST refers to other conversions as "casts" too, and calls +/// actual casts "explicit" casts.) +AST_MATCHER_P(ExplicitCastExpr, hasDestinationType, + internal::Matcher<QualType>, InnerMatcher) { + const QualType NodeType = Node.getTypeAsWritten(); + return InnerMatcher.matches(NodeType, Finder, Builder); +} + +/// \brief Matches implicit casts whose destination type matches a given +/// matcher. +/// +/// FIXME: Unit test this matcher +AST_MATCHER_P(ImplicitCastExpr, hasImplicitDestinationType, + internal::Matcher<QualType>, InnerMatcher) { + return InnerMatcher.matches(Node.getType(), Finder, Builder); +} + +/// \brief Matches RecordDecl object that are spelled with "struct." +/// +/// Example matches S, but not C or U. +/// \code +/// struct S {}; +/// class C {}; +/// union U {}; +/// \endcode +AST_MATCHER(RecordDecl, isStruct) { + return Node.isStruct(); +} + +/// \brief Matches RecordDecl object that are spelled with "union." +/// +/// Example matches U, but not C or S. +/// \code +/// struct S {}; +/// class C {}; +/// union U {}; +/// \endcode +AST_MATCHER(RecordDecl, isUnion) { + return Node.isUnion(); +} + +/// \brief Matches RecordDecl object that are spelled with "class." +/// +/// Example matches C, but not S or U. +/// \code +/// struct S {}; +/// class C {}; +/// union U {}; +/// \endcode +AST_MATCHER(RecordDecl, isClass) { + return Node.isClass(); +} + +/// \brief Matches the true branch expression of a conditional operator. +/// +/// Example matches a +/// \code +/// condition ? a : b +/// \endcode +AST_MATCHER_P(ConditionalOperator, hasTrueExpression, + internal::Matcher<Expr>, InnerMatcher) { + const Expr *Expression = Node.getTrueExpr(); + return (Expression != nullptr && + InnerMatcher.matches(*Expression, Finder, Builder)); +} + +/// \brief Matches the false branch expression of a conditional operator. +/// +/// Example matches b +/// \code +/// condition ? a : b +/// \endcode +AST_MATCHER_P(ConditionalOperator, hasFalseExpression, + internal::Matcher<Expr>, InnerMatcher) { + const Expr *Expression = Node.getFalseExpr(); + return (Expression != nullptr && + InnerMatcher.matches(*Expression, Finder, Builder)); +} + +/// \brief Matches if a declaration has a body attached. +/// +/// Example matches A, va, fa +/// \code +/// class A {}; +/// class B; // Doesn't match, as it has no body. +/// int va; +/// extern int vb; // Doesn't match, as it doesn't define the variable. +/// void fa() {} +/// void fb(); // Doesn't match, as it has no body. +/// \endcode +/// +/// Usable as: Matcher<TagDecl>, Matcher<VarDecl>, Matcher<FunctionDecl> +AST_POLYMORPHIC_MATCHER(isDefinition, + AST_POLYMORPHIC_SUPPORTED_TYPES(TagDecl, VarDecl, + FunctionDecl)) { + return Node.isThisDeclarationADefinition(); +} + +/// \brief Matches if a function declaration is variadic. +/// +/// Example matches f, but not g or h. The function i will not match, even when +/// compiled in C mode. +/// \code +/// void f(...); +/// void g(int); +/// template <typename... Ts> void h(Ts...); +/// void i(); +/// \endcode +AST_MATCHER(FunctionDecl, isVariadic) { + return Node.isVariadic(); +} + +/// \brief Matches the class declaration that the given method declaration +/// belongs to. +/// +/// FIXME: Generalize this for other kinds of declarations. +/// FIXME: What other kind of declarations would we need to generalize +/// this to? +/// +/// Example matches A() in the last line +/// (matcher = cxxConstructExpr(hasDeclaration(cxxMethodDecl( +/// ofClass(hasName("A")))))) +/// \code +/// class A { +/// public: +/// A(); +/// }; +/// A a = A(); +/// \endcode +AST_MATCHER_P(CXXMethodDecl, ofClass, + internal::Matcher<CXXRecordDecl>, InnerMatcher) { + const CXXRecordDecl *Parent = Node.getParent(); + return (Parent != nullptr && + InnerMatcher.matches(*Parent, Finder, Builder)); +} + +/// \brief Matches if the given method declaration is virtual. +/// +/// Given +/// \code +/// class A { +/// public: +/// virtual void x(); +/// }; +/// \endcode +/// matches A::x +AST_MATCHER(CXXMethodDecl, isVirtual) { + return Node.isVirtual(); +} + +/// \brief Matches if the given method or class declaration is final. +/// +/// Given: +/// \code +/// class A final {}; +/// +/// struct B { +/// virtual void f(); +/// }; +/// +/// struct C : B { +/// void f() final; +/// }; +/// \endcode +/// matches A and C::f, but not B, C, or B::f +AST_POLYMORPHIC_MATCHER(isFinal, + AST_POLYMORPHIC_SUPPORTED_TYPES(CXXRecordDecl, + CXXMethodDecl)) { + return Node.template hasAttr<FinalAttr>(); +} + +/// \brief Matches if the given method declaration is pure. +/// +/// Given +/// \code +/// class A { +/// public: +/// virtual void x() = 0; +/// }; +/// \endcode +/// matches A::x +AST_MATCHER(CXXMethodDecl, isPure) { + return Node.isPure(); +} + +/// \brief Matches if the given method declaration is const. +/// +/// Given +/// \code +/// struct A { +/// void foo() const; +/// void bar(); +/// }; +/// \endcode +/// +/// cxxMethodDecl(isConst()) matches A::foo() but not A::bar() +AST_MATCHER(CXXMethodDecl, isConst) { + return Node.isConst(); +} + +/// \brief Matches if the given method declaration declares a copy assignment +/// operator. +/// +/// Given +/// \code +/// struct A { +/// A &operator=(const A &); +/// A &operator=(A &&); +/// }; +/// \endcode +/// +/// cxxMethodDecl(isCopyAssignmentOperator()) matches the first method but not +/// the second one. +AST_MATCHER(CXXMethodDecl, isCopyAssignmentOperator) { + return Node.isCopyAssignmentOperator(); +} + +/// \brief Matches if the given method declaration overrides another method. +/// +/// Given +/// \code +/// class A { +/// public: +/// virtual void x(); +/// }; +/// class B : public A { +/// public: +/// virtual void x(); +/// }; +/// \endcode +/// matches B::x +AST_MATCHER(CXXMethodDecl, isOverride) { + return Node.size_overridden_methods() > 0 || Node.hasAttr<OverrideAttr>(); +} + +/// \brief Matches member expressions that are called with '->' as opposed +/// to '.'. +/// +/// Member calls on the implicit this pointer match as called with '->'. +/// +/// Given +/// \code +/// class Y { +/// void x() { this->x(); x(); Y y; y.x(); a; this->b; Y::b; } +/// int a; +/// static int b; +/// }; +/// \endcode +/// memberExpr(isArrow()) +/// matches this->x, x, y.x, a, this->b +AST_MATCHER(MemberExpr, isArrow) { + return Node.isArrow(); +} + +/// \brief Matches QualType nodes that are of integer type. +/// +/// Given +/// \code +/// void a(int); +/// void b(long); +/// void c(double); +/// \endcode +/// functionDecl(hasAnyParameter(hasType(isInteger()))) +/// matches "a(int)", "b(long)", but not "c(double)". +AST_MATCHER(QualType, isInteger) { + return Node->isIntegerType(); +} + +/// \brief Matches QualType nodes that are of character type. +/// +/// Given +/// \code +/// void a(char); +/// void b(wchar_t); +/// void c(double); +/// \endcode +/// functionDecl(hasAnyParameter(hasType(isAnyCharacter()))) +/// matches "a(char)", "b(wchar_t)", but not "c(double)". +AST_MATCHER(QualType, isAnyCharacter) { + return Node->isAnyCharacterType(); +} + +/// \brief Matches QualType nodes that are const-qualified, i.e., that +/// include "top-level" const. +/// +/// Given +/// \code +/// void a(int); +/// void b(int const); +/// void c(const int); +/// void d(const int*); +/// void e(int const) {}; +/// \endcode +/// functionDecl(hasAnyParameter(hasType(isConstQualified()))) +/// matches "void b(int const)", "void c(const int)" and +/// "void e(int const) {}". It does not match d as there +/// is no top-level const on the parameter type "const int *". +AST_MATCHER(QualType, isConstQualified) { + return Node.isConstQualified(); +} + +/// \brief Matches QualType nodes that are volatile-qualified, i.e., that +/// include "top-level" volatile. +/// +/// Given +/// \code +/// void a(int); +/// void b(int volatile); +/// void c(volatile int); +/// void d(volatile int*); +/// void e(int volatile) {}; +/// \endcode +/// functionDecl(hasAnyParameter(hasType(isVolatileQualified()))) +/// matches "void b(int volatile)", "void c(volatile int)" and +/// "void e(int volatile) {}". It does not match d as there +/// is no top-level volatile on the parameter type "volatile int *". +AST_MATCHER(QualType, isVolatileQualified) { + return Node.isVolatileQualified(); +} + +/// \brief Matches QualType nodes that have local CV-qualifiers attached to +/// the node, not hidden within a typedef. +/// +/// Given +/// \code +/// typedef const int const_int; +/// const_int i; +/// int *const j; +/// int *volatile k; +/// int m; +/// \endcode +/// \c varDecl(hasType(hasLocalQualifiers())) matches only \c j and \c k. +/// \c i is const-qualified but the qualifier is not local. +AST_MATCHER(QualType, hasLocalQualifiers) { + return Node.hasLocalQualifiers(); +} + +/// \brief Matches a member expression where the member is matched by a +/// given matcher. +/// +/// Given +/// \code +/// struct { int first, second; } first, second; +/// int i(second.first); +/// int j(first.second); +/// \endcode +/// memberExpr(member(hasName("first"))) +/// matches second.first +/// but not first.second (because the member name there is "second"). +AST_MATCHER_P(MemberExpr, member, + internal::Matcher<ValueDecl>, InnerMatcher) { + return InnerMatcher.matches(*Node.getMemberDecl(), Finder, Builder); +} + +/// \brief Matches a member expression where the object expression is +/// matched by a given matcher. +/// +/// Given +/// \code +/// struct X { int m; }; +/// void f(X x) { x.m; m; } +/// \endcode +/// memberExpr(hasObjectExpression(hasType(cxxRecordDecl(hasName("X"))))))) +/// matches "x.m" and "m" +/// with hasObjectExpression(...) +/// matching "x" and the implicit object expression of "m" which has type X*. +AST_MATCHER_P(MemberExpr, hasObjectExpression, + internal::Matcher<Expr>, InnerMatcher) { + return InnerMatcher.matches(*Node.getBase(), Finder, Builder); +} + +/// \brief Matches any using shadow declaration. +/// +/// Given +/// \code +/// namespace X { void b(); } +/// using X::b; +/// \endcode +/// usingDecl(hasAnyUsingShadowDecl(hasName("b")))) +/// matches \code using X::b \endcode +AST_MATCHER_P(UsingDecl, hasAnyUsingShadowDecl, + internal::Matcher<UsingShadowDecl>, InnerMatcher) { + return matchesFirstInPointerRange(InnerMatcher, Node.shadow_begin(), + Node.shadow_end(), Finder, Builder); +} + +/// \brief Matches a using shadow declaration where the target declaration is +/// matched by the given matcher. +/// +/// Given +/// \code +/// namespace X { int a; void b(); } +/// using X::a; +/// using X::b; +/// \endcode +/// usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(functionDecl()))) +/// matches \code using X::b \endcode +/// but not \code using X::a \endcode +AST_MATCHER_P(UsingShadowDecl, hasTargetDecl, + internal::Matcher<NamedDecl>, InnerMatcher) { + return InnerMatcher.matches(*Node.getTargetDecl(), Finder, Builder); +} + +/// \brief Matches template instantiations of function, class, or static +/// member variable template instantiations. +/// +/// Given +/// \code +/// template <typename T> class X {}; class A {}; X<A> x; +/// \endcode +/// or +/// \code +/// template <typename T> class X {}; class A {}; template class X<A>; +/// \endcode +/// cxxRecordDecl(hasName("::X"), isTemplateInstantiation()) +/// matches the template instantiation of X<A>. +/// +/// But given +/// \code +/// template <typename T> class X {}; class A {}; +/// template <> class X<A> {}; X<A> x; +/// \endcode +/// cxxRecordDecl(hasName("::X"), isTemplateInstantiation()) +/// does not match, as X<A> is an explicit template specialization. +/// +/// Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl> +AST_POLYMORPHIC_MATCHER(isTemplateInstantiation, + AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl, VarDecl, + CXXRecordDecl)) { + return (Node.getTemplateSpecializationKind() == TSK_ImplicitInstantiation || + Node.getTemplateSpecializationKind() == + TSK_ExplicitInstantiationDefinition); +} + +/// \brief Matches declarations that are template instantiations or are inside +/// template instantiations. +/// +/// Given +/// \code +/// template<typename T> void A(T t) { T i; } +/// A(0); +/// A(0U); +/// \endcode +/// functionDecl(isInstantiated()) +/// matches 'A(int) {...};' and 'A(unsigned) {...}'. +AST_MATCHER_FUNCTION(internal::Matcher<Decl>, isInstantiated) { + auto IsInstantiation = decl(anyOf(cxxRecordDecl(isTemplateInstantiation()), + functionDecl(isTemplateInstantiation()))); + return decl(anyOf(IsInstantiation, hasAncestor(IsInstantiation))); +} + +/// \brief Matches statements inside of a template instantiation. +/// +/// Given +/// \code +/// int j; +/// template<typename T> void A(T t) { T i; j += 42;} +/// A(0); +/// A(0U); +/// \endcode +/// declStmt(isInTemplateInstantiation()) +/// matches 'int i;' and 'unsigned i'. +/// unless(stmt(isInTemplateInstantiation())) +/// will NOT match j += 42; as it's shared between the template definition and +/// instantiation. +AST_MATCHER_FUNCTION(internal::Matcher<Stmt>, isInTemplateInstantiation) { + return stmt( + hasAncestor(decl(anyOf(cxxRecordDecl(isTemplateInstantiation()), + functionDecl(isTemplateInstantiation()))))); +} + +/// \brief Matches explicit template specializations of function, class, or +/// static member variable template instantiations. +/// +/// Given +/// \code +/// template<typename T> void A(T t) { } +/// template<> void A(int N) { } +/// \endcode +/// functionDecl(isExplicitTemplateSpecialization()) +/// matches the specialization A<int>(). +/// +/// Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl> +AST_POLYMORPHIC_MATCHER(isExplicitTemplateSpecialization, + AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl, VarDecl, + CXXRecordDecl)) { + return (Node.getTemplateSpecializationKind() == TSK_ExplicitSpecialization); +} + +/// \brief Matches \c TypeLocs for which the given inner +/// QualType-matcher matches. +AST_MATCHER_FUNCTION_P_OVERLOAD(internal::BindableMatcher<TypeLoc>, loc, + internal::Matcher<QualType>, InnerMatcher, 0) { + return internal::BindableMatcher<TypeLoc>( + new internal::TypeLocTypeMatcher(InnerMatcher)); +} + +/// \brief Matches type \c bool. +/// +/// Given +/// \code +/// struct S { bool func(); }; +/// \endcode +/// functionDecl(returns(booleanType())) +/// matches "bool func();" +AST_MATCHER(Type, booleanType) { + return Node.isBooleanType(); +} + +/// \brief Matches type \c void. +/// +/// Given +/// \code +/// struct S { void func(); }; +/// \endcode +/// functionDecl(returns(voidType())) +/// matches "void func();" +AST_MATCHER(Type, voidType) { + return Node.isVoidType(); +} + +/// \brief Matches builtin Types. +/// +/// Given +/// \code +/// struct A {}; +/// A a; +/// int b; +/// float c; +/// bool d; +/// \endcode +/// builtinType() +/// matches "int b", "float c" and "bool d" +AST_TYPE_MATCHER(BuiltinType, builtinType); + +/// \brief Matches all kinds of arrays. +/// +/// Given +/// \code +/// int a[] = { 2, 3 }; +/// int b[4]; +/// void f() { int c[a[0]]; } +/// \endcode +/// arrayType() +/// matches "int a[]", "int b[4]" and "int c[a[0]]"; +AST_TYPE_MATCHER(ArrayType, arrayType); + +/// \brief Matches C99 complex types. +/// +/// Given +/// \code +/// _Complex float f; +/// \endcode +/// complexType() +/// matches "_Complex float f" +AST_TYPE_MATCHER(ComplexType, complexType); + +/// \brief Matches arrays and C99 complex types that have a specific element +/// type. +/// +/// Given +/// \code +/// struct A {}; +/// A a[7]; +/// int b[7]; +/// \endcode +/// arrayType(hasElementType(builtinType())) +/// matches "int b[7]" +/// +/// Usable as: Matcher<ArrayType>, Matcher<ComplexType> +AST_TYPELOC_TRAVERSE_MATCHER(hasElementType, getElement, + AST_POLYMORPHIC_SUPPORTED_TYPES(ArrayType, + ComplexType)); + +/// \brief Matches C arrays with a specified constant size. +/// +/// Given +/// \code +/// void() { +/// int a[2]; +/// int b[] = { 2, 3 }; +/// int c[b[0]]; +/// } +/// \endcode +/// constantArrayType() +/// matches "int a[2]" +AST_TYPE_MATCHER(ConstantArrayType, constantArrayType); + +/// \brief Matches \c ConstantArrayType nodes that have the specified size. +/// +/// Given +/// \code +/// int a[42]; +/// int b[2 * 21]; +/// int c[41], d[43]; +/// \endcode +/// constantArrayType(hasSize(42)) +/// matches "int a[42]" and "int b[2 * 21]" +AST_MATCHER_P(ConstantArrayType, hasSize, unsigned, N) { + return Node.getSize() == N; +} + +/// \brief Matches C++ arrays whose size is a value-dependent expression. +/// +/// Given +/// \code +/// template<typename T, int Size> +/// class array { +/// T data[Size]; +/// }; +/// \endcode +/// dependentSizedArrayType +/// matches "T data[Size]" +AST_TYPE_MATCHER(DependentSizedArrayType, dependentSizedArrayType); + +/// \brief Matches C arrays with unspecified size. +/// +/// Given +/// \code +/// int a[] = { 2, 3 }; +/// int b[42]; +/// void f(int c[]) { int d[a[0]]; }; +/// \endcode +/// incompleteArrayType() +/// matches "int a[]" and "int c[]" +AST_TYPE_MATCHER(IncompleteArrayType, incompleteArrayType); + +/// \brief Matches C arrays with a specified size that is not an +/// integer-constant-expression. +/// +/// Given +/// \code +/// void f() { +/// int a[] = { 2, 3 } +/// int b[42]; +/// int c[a[0]]; +/// } +/// \endcode +/// variableArrayType() +/// matches "int c[a[0]]" +AST_TYPE_MATCHER(VariableArrayType, variableArrayType); + +/// \brief Matches \c VariableArrayType nodes that have a specific size +/// expression. +/// +/// Given +/// \code +/// void f(int b) { +/// int a[b]; +/// } +/// \endcode +/// variableArrayType(hasSizeExpr(ignoringImpCasts(declRefExpr(to( +/// varDecl(hasName("b"))))))) +/// matches "int a[b]" +AST_MATCHER_P(VariableArrayType, hasSizeExpr, + internal::Matcher<Expr>, InnerMatcher) { + return InnerMatcher.matches(*Node.getSizeExpr(), Finder, Builder); +} + +/// \brief Matches atomic types. +/// +/// Given +/// \code +/// _Atomic(int) i; +/// \endcode +/// atomicType() +/// matches "_Atomic(int) i" +AST_TYPE_MATCHER(AtomicType, atomicType); + +/// \brief Matches atomic types with a specific value type. +/// +/// Given +/// \code +/// _Atomic(int) i; +/// _Atomic(float) f; +/// \endcode +/// atomicType(hasValueType(isInteger())) +/// matches "_Atomic(int) i" +/// +/// Usable as: Matcher<AtomicType> +AST_TYPELOC_TRAVERSE_MATCHER(hasValueType, getValue, + AST_POLYMORPHIC_SUPPORTED_TYPES(AtomicType)); + +/// \brief Matches types nodes representing C++11 auto types. +/// +/// Given: +/// \code +/// auto n = 4; +/// int v[] = { 2, 3 } +/// for (auto i : v) { } +/// \endcode +/// autoType() +/// matches "auto n" and "auto i" +AST_TYPE_MATCHER(AutoType, autoType); + +/// \brief Matches \c AutoType nodes where the deduced type is a specific type. +/// +/// Note: There is no \c TypeLoc for the deduced type and thus no +/// \c getDeducedLoc() matcher. +/// +/// Given +/// \code +/// auto a = 1; +/// auto b = 2.0; +/// \endcode +/// autoType(hasDeducedType(isInteger())) +/// matches "auto a" +/// +/// Usable as: Matcher<AutoType> +AST_TYPE_TRAVERSE_MATCHER(hasDeducedType, getDeducedType, + AST_POLYMORPHIC_SUPPORTED_TYPES(AutoType)); + +/// \brief Matches \c FunctionType nodes. +/// +/// Given +/// \code +/// int (*f)(int); +/// void g(); +/// \endcode +/// functionType() +/// matches "int (*f)(int)" and the type of "g". +AST_TYPE_MATCHER(FunctionType, functionType); + +/// \brief Matches \c ParenType nodes. +/// +/// Given +/// \code +/// int (*ptr_to_array)[4]; +/// int *array_of_ptrs[4]; +/// \endcode +/// +/// \c varDecl(hasType(pointsTo(parenType()))) matches \c ptr_to_array but not +/// \c array_of_ptrs. +AST_TYPE_MATCHER(ParenType, parenType); + +/// \brief Matches \c ParenType nodes where the inner type is a specific type. +/// +/// Given +/// \code +/// int (*ptr_to_array)[4]; +/// int (*ptr_to_func)(int); +/// \endcode +/// +/// \c varDecl(hasType(pointsTo(parenType(innerType(functionType()))))) matches +/// \c ptr_to_func but not \c ptr_to_array. +/// +/// Usable as: Matcher<ParenType> +AST_TYPE_TRAVERSE_MATCHER(innerType, getInnerType, + AST_POLYMORPHIC_SUPPORTED_TYPES(ParenType)); + +/// \brief Matches block pointer types, i.e. types syntactically represented as +/// "void (^)(int)". +/// +/// The \c pointee is always required to be a \c FunctionType. +AST_TYPE_MATCHER(BlockPointerType, blockPointerType); + +/// \brief Matches member pointer types. +/// Given +/// \code +/// struct A { int i; } +/// A::* ptr = A::i; +/// \endcode +/// memberPointerType() +/// matches "A::* ptr" +AST_TYPE_MATCHER(MemberPointerType, memberPointerType); + +/// \brief Matches pointer types, but does not match Objective-C object pointer +/// types. +/// +/// Given +/// \code +/// int *a; +/// int &b = *a; +/// int c = 5; +/// +/// @interface Foo +/// @end +/// Foo *f; +/// \endcode +/// pointerType() +/// matches "int *a", but does not match "Foo *f". +AST_TYPE_MATCHER(PointerType, pointerType); + +/// \brief Matches an Objective-C object pointer type, which is different from +/// a pointer type, despite being syntactically similar. +/// +/// Given +/// \code +/// int *a; +/// +/// @interface Foo +/// @end +/// Foo *f; +/// \endcode +/// pointerType() +/// matches "Foo *f", but does not match "int *a". +AST_TYPE_MATCHER(ObjCObjectPointerType, objcObjectPointerType); + +/// \brief Matches both lvalue and rvalue reference types. +/// +/// Given +/// \code +/// int *a; +/// int &b = *a; +/// int &&c = 1; +/// auto &d = b; +/// auto &&e = c; +/// auto &&f = 2; +/// int g = 5; +/// \endcode +/// +/// \c referenceType() matches the types of \c b, \c c, \c d, \c e, and \c f. +AST_TYPE_MATCHER(ReferenceType, referenceType); + +/// \brief Matches lvalue reference types. +/// +/// Given: +/// \code +/// int *a; +/// int &b = *a; +/// int &&c = 1; +/// auto &d = b; +/// auto &&e = c; +/// auto &&f = 2; +/// int g = 5; +/// \endcode +/// +/// \c lValueReferenceType() matches the types of \c b, \c d, and \c e. \c e is +/// matched since the type is deduced as int& by reference collapsing rules. +AST_TYPE_MATCHER(LValueReferenceType, lValueReferenceType); + +/// \brief Matches rvalue reference types. +/// +/// Given: +/// \code +/// int *a; +/// int &b = *a; +/// int &&c = 1; +/// auto &d = b; +/// auto &&e = c; +/// auto &&f = 2; +/// int g = 5; +/// \endcode +/// +/// \c rValueReferenceType() matches the types of \c c and \c f. \c e is not +/// matched as it is deduced to int& by reference collapsing rules. +AST_TYPE_MATCHER(RValueReferenceType, rValueReferenceType); + +/// \brief Narrows PointerType (and similar) matchers to those where the +/// \c pointee matches a given matcher. +/// +/// Given +/// \code +/// int *a; +/// int const *b; +/// float const *f; +/// \endcode +/// pointerType(pointee(isConstQualified(), isInteger())) +/// matches "int const *b" +/// +/// Usable as: Matcher<BlockPointerType>, Matcher<MemberPointerType>, +/// Matcher<PointerType>, Matcher<ReferenceType> +AST_TYPELOC_TRAVERSE_MATCHER(pointee, getPointee, + AST_POLYMORPHIC_SUPPORTED_TYPES(BlockPointerType, + MemberPointerType, + PointerType, + ReferenceType)); + +/// \brief Matches typedef types. +/// +/// Given +/// \code +/// typedef int X; +/// \endcode +/// typedefType() +/// matches "typedef int X" +AST_TYPE_MATCHER(TypedefType, typedefType); + +/// \brief Matches template specialization types. +/// +/// Given +/// \code +/// template <typename T> +/// class C { }; +/// +/// template class C<int>; // A +/// C<char> var; // B +/// \endcode +/// +/// \c templateSpecializationType() matches the type of the explicit +/// instantiation in \c A and the type of the variable declaration in \c B. +AST_TYPE_MATCHER(TemplateSpecializationType, templateSpecializationType); + +/// \brief Matches types nodes representing unary type transformations. +/// +/// Given: +/// \code +/// typedef __underlying_type(T) type; +/// \endcode +/// unaryTransformType() +/// matches "__underlying_type(T)" +AST_TYPE_MATCHER(UnaryTransformType, unaryTransformType); + +/// \brief Matches record types (e.g. structs, classes). +/// +/// Given +/// \code +/// class C {}; +/// struct S {}; +/// +/// C c; +/// S s; +/// \endcode +/// +/// \c recordType() matches the type of the variable declarations of both \c c +/// and \c s. +AST_TYPE_MATCHER(RecordType, recordType); + +/// \brief Matches types specified with an elaborated type keyword or with a +/// qualified name. +/// +/// Given +/// \code +/// namespace N { +/// namespace M { +/// class D {}; +/// } +/// } +/// class C {}; +/// +/// class C c; +/// N::M::D d; +/// \endcode +/// +/// \c elaboratedType() matches the type of the variable declarations of both +/// \c c and \c d. +AST_TYPE_MATCHER(ElaboratedType, elaboratedType); + +/// \brief Matches ElaboratedTypes whose qualifier, a NestedNameSpecifier, +/// matches \c InnerMatcher if the qualifier exists. +/// +/// Given +/// \code +/// namespace N { +/// namespace M { +/// class D {}; +/// } +/// } +/// N::M::D d; +/// \endcode +/// +/// \c elaboratedType(hasQualifier(hasPrefix(specifiesNamespace(hasName("N")))) +/// matches the type of the variable declaration of \c d. +AST_MATCHER_P(ElaboratedType, hasQualifier, + internal::Matcher<NestedNameSpecifier>, InnerMatcher) { + if (const NestedNameSpecifier *Qualifier = Node.getQualifier()) + return InnerMatcher.matches(*Qualifier, Finder, Builder); + + return false; +} + +/// \brief Matches ElaboratedTypes whose named type matches \c InnerMatcher. +/// +/// Given +/// \code +/// namespace N { +/// namespace M { +/// class D {}; +/// } +/// } +/// N::M::D d; +/// \endcode +/// +/// \c elaboratedType(namesType(recordType( +/// hasDeclaration(namedDecl(hasName("D")))))) matches the type of the variable +/// declaration of \c d. +AST_MATCHER_P(ElaboratedType, namesType, internal::Matcher<QualType>, + InnerMatcher) { + return InnerMatcher.matches(Node.getNamedType(), Finder, Builder); +} + +/// \brief Matches types that represent the result of substituting a type for a +/// template type parameter. +/// +/// Given +/// \code +/// template <typename T> +/// void F(T t) { +/// int i = 1 + t; +/// } +/// \endcode +/// +/// \c substTemplateTypeParmType() matches the type of 't' but not '1' +AST_TYPE_MATCHER(SubstTemplateTypeParmType, substTemplateTypeParmType); + +/// \brief Matches template type parameter types. +/// +/// Example matches T, but not int. +/// (matcher = templateTypeParmType()) +/// \code +/// template <typename T> void f(int i); +/// \endcode +AST_TYPE_MATCHER(TemplateTypeParmType, templateTypeParmType); + +/// \brief Matches injected class name types. +/// +/// Example matches S s, but not S<T> s. +/// (matcher = parmVarDecl(hasType(injectedClassNameType()))) +/// \code +/// template <typename T> struct S { +/// void f(S s); +/// void g(S<T> s); +/// }; +/// \endcode +AST_TYPE_MATCHER(InjectedClassNameType, injectedClassNameType); + +/// \brief Matches decayed type +/// Example matches i[] in declaration of f. +/// (matcher = valueDecl(hasType(decayedType(hasDecayedType(pointerType()))))) +/// Example matches i[1]. +/// (matcher = expr(hasType(decayedType(hasDecayedType(pointerType()))))) +/// \code +/// void f(int i[]) { +/// i[1] = 0; +/// } +/// \endcode +AST_TYPE_MATCHER(DecayedType, decayedType); + +/// \brief Matches the decayed type, whos decayed type matches \c InnerMatcher +AST_MATCHER_P(DecayedType, hasDecayedType, internal::Matcher<QualType>, + InnerType) { + return InnerType.matches(Node.getDecayedType(), Finder, Builder); +} + +/// \brief Matches declarations whose declaration context, interpreted as a +/// Decl, matches \c InnerMatcher. +/// +/// Given +/// \code +/// namespace N { +/// namespace M { +/// class D {}; +/// } +/// } +/// \endcode +/// +/// \c cxxRcordDecl(hasDeclContext(namedDecl(hasName("M")))) matches the +/// declaration of \c class \c D. +AST_MATCHER_P(Decl, hasDeclContext, internal::Matcher<Decl>, InnerMatcher) { + const DeclContext *DC = Node.getDeclContext(); + if (!DC) return false; + return InnerMatcher.matches(*Decl::castFromDeclContext(DC), Finder, Builder); +} + +/// \brief Matches nested name specifiers. +/// +/// Given +/// \code +/// namespace ns { +/// struct A { static void f(); }; +/// void A::f() {} +/// void g() { A::f(); } +/// } +/// ns::A a; +/// \endcode +/// nestedNameSpecifier() +/// matches "ns::" and both "A::" +const internal::VariadicAllOfMatcher<NestedNameSpecifier> nestedNameSpecifier; + +/// \brief Same as \c nestedNameSpecifier but matches \c NestedNameSpecifierLoc. +const internal::VariadicAllOfMatcher< + NestedNameSpecifierLoc> nestedNameSpecifierLoc; + +/// \brief Matches \c NestedNameSpecifierLocs for which the given inner +/// NestedNameSpecifier-matcher matches. +AST_MATCHER_FUNCTION_P_OVERLOAD( + internal::BindableMatcher<NestedNameSpecifierLoc>, loc, + internal::Matcher<NestedNameSpecifier>, InnerMatcher, 1) { + return internal::BindableMatcher<NestedNameSpecifierLoc>( + new internal::LocMatcher<NestedNameSpecifierLoc, NestedNameSpecifier>( + InnerMatcher)); +} + +/// \brief Matches nested name specifiers that specify a type matching the +/// given \c QualType matcher without qualifiers. +/// +/// Given +/// \code +/// struct A { struct B { struct C {}; }; }; +/// A::B::C c; +/// \endcode +/// nestedNameSpecifier(specifiesType( +/// hasDeclaration(cxxRecordDecl(hasName("A"))) +/// )) +/// matches "A::" +AST_MATCHER_P(NestedNameSpecifier, specifiesType, + internal::Matcher<QualType>, InnerMatcher) { + if (!Node.getAsType()) + return false; + return InnerMatcher.matches(QualType(Node.getAsType(), 0), Finder, Builder); +} + +/// \brief Matches nested name specifier locs that specify a type matching the +/// given \c TypeLoc. +/// +/// Given +/// \code +/// struct A { struct B { struct C {}; }; }; +/// A::B::C c; +/// \endcode +/// nestedNameSpecifierLoc(specifiesTypeLoc(loc(type( +/// hasDeclaration(cxxRecordDecl(hasName("A"))))))) +/// matches "A::" +AST_MATCHER_P(NestedNameSpecifierLoc, specifiesTypeLoc, + internal::Matcher<TypeLoc>, InnerMatcher) { + return Node && InnerMatcher.matches(Node.getTypeLoc(), Finder, Builder); +} + +/// \brief Matches on the prefix of a \c NestedNameSpecifier. +/// +/// Given +/// \code +/// struct A { struct B { struct C {}; }; }; +/// A::B::C c; +/// \endcode +/// nestedNameSpecifier(hasPrefix(specifiesType(asString("struct A")))) and +/// matches "A::" +AST_MATCHER_P_OVERLOAD(NestedNameSpecifier, hasPrefix, + internal::Matcher<NestedNameSpecifier>, InnerMatcher, + 0) { + const NestedNameSpecifier *NextNode = Node.getPrefix(); + if (!NextNode) + return false; + return InnerMatcher.matches(*NextNode, Finder, Builder); +} + +/// \brief Matches on the prefix of a \c NestedNameSpecifierLoc. +/// +/// Given +/// \code +/// struct A { struct B { struct C {}; }; }; +/// A::B::C c; +/// \endcode +/// nestedNameSpecifierLoc(hasPrefix(loc(specifiesType(asString("struct A"))))) +/// matches "A::" +AST_MATCHER_P_OVERLOAD(NestedNameSpecifierLoc, hasPrefix, + internal::Matcher<NestedNameSpecifierLoc>, InnerMatcher, + 1) { + NestedNameSpecifierLoc NextNode = Node.getPrefix(); + if (!NextNode) + return false; + return InnerMatcher.matches(NextNode, Finder, Builder); +} + +/// \brief Matches nested name specifiers that specify a namespace matching the +/// given namespace matcher. +/// +/// Given +/// \code +/// namespace ns { struct A {}; } +/// ns::A a; +/// \endcode +/// nestedNameSpecifier(specifiesNamespace(hasName("ns"))) +/// matches "ns::" +AST_MATCHER_P(NestedNameSpecifier, specifiesNamespace, + internal::Matcher<NamespaceDecl>, InnerMatcher) { + if (!Node.getAsNamespace()) + return false; + return InnerMatcher.matches(*Node.getAsNamespace(), Finder, Builder); +} + +/// \brief Overloads for the \c equalsNode matcher. +/// FIXME: Implement for other node types. +/// @{ + +/// \brief Matches if a node equals another node. +/// +/// \c Decl has pointer identity in the AST. +AST_MATCHER_P_OVERLOAD(Decl, equalsNode, const Decl*, Other, 0) { + return &Node == Other; +} +/// \brief Matches if a node equals another node. +/// +/// \c Stmt has pointer identity in the AST. +AST_MATCHER_P_OVERLOAD(Stmt, equalsNode, const Stmt*, Other, 1) { + return &Node == Other; +} +/// \brief Matches if a node equals another node. +/// +/// \c Type has pointer identity in the AST. +AST_MATCHER_P_OVERLOAD(Type, equalsNode, const Type*, Other, 2) { + return &Node == Other; +} + +/// @} + +/// \brief Matches each case or default statement belonging to the given switch +/// statement. This matcher may produce multiple matches. +/// +/// Given +/// \code +/// switch (1) { case 1: case 2: default: switch (2) { case 3: case 4: ; } } +/// \endcode +/// switchStmt(forEachSwitchCase(caseStmt().bind("c"))).bind("s") +/// matches four times, with "c" binding each of "case 1:", "case 2:", +/// "case 3:" and "case 4:", and "s" respectively binding "switch (1)", +/// "switch (1)", "switch (2)" and "switch (2)". +AST_MATCHER_P(SwitchStmt, forEachSwitchCase, internal::Matcher<SwitchCase>, + InnerMatcher) { + BoundNodesTreeBuilder Result; + // FIXME: getSwitchCaseList() does not necessarily guarantee a stable + // iteration order. We should use the more general iterating matchers once + // they are capable of expressing this matcher (for example, it should ignore + // case statements belonging to nested switch statements). + bool Matched = false; + for (const SwitchCase *SC = Node.getSwitchCaseList(); SC; + SC = SC->getNextSwitchCase()) { + BoundNodesTreeBuilder CaseBuilder(*Builder); + bool CaseMatched = InnerMatcher.matches(*SC, Finder, &CaseBuilder); + if (CaseMatched) { + Matched = true; + Result.addMatch(CaseBuilder); + } + } + *Builder = std::move(Result); + return Matched; +} + +/// \brief Matches each constructor initializer in a constructor definition. +/// +/// Given +/// \code +/// class A { A() : i(42), j(42) {} int i; int j; }; +/// \endcode +/// cxxConstructorDecl(forEachConstructorInitializer( +/// forField(decl().bind("x")) +/// )) +/// will trigger two matches, binding for 'i' and 'j' respectively. +AST_MATCHER_P(CXXConstructorDecl, forEachConstructorInitializer, + internal::Matcher<CXXCtorInitializer>, InnerMatcher) { + BoundNodesTreeBuilder Result; + bool Matched = false; + for (const auto *I : Node.inits()) { + BoundNodesTreeBuilder InitBuilder(*Builder); + if (InnerMatcher.matches(*I, Finder, &InitBuilder)) { + Matched = true; + Result.addMatch(InitBuilder); + } + } + *Builder = std::move(Result); + return Matched; +} + +/// \brief Matches constructor declarations that are copy constructors. +/// +/// Given +/// \code +/// struct S { +/// S(); // #1 +/// S(const S &); // #2 +/// S(S &&); // #3 +/// }; +/// \endcode +/// cxxConstructorDecl(isCopyConstructor()) will match #2, but not #1 or #3. +AST_MATCHER(CXXConstructorDecl, isCopyConstructor) { + return Node.isCopyConstructor(); +} + +/// \brief Matches constructor declarations that are move constructors. +/// +/// Given +/// \code +/// struct S { +/// S(); // #1 +/// S(const S &); // #2 +/// S(S &&); // #3 +/// }; +/// \endcode +/// cxxConstructorDecl(isMoveConstructor()) will match #3, but not #1 or #2. +AST_MATCHER(CXXConstructorDecl, isMoveConstructor) { + return Node.isMoveConstructor(); +} + +/// \brief Matches constructor declarations that are default constructors. +/// +/// Given +/// \code +/// struct S { +/// S(); // #1 +/// S(const S &); // #2 +/// S(S &&); // #3 +/// }; +/// \endcode +/// cxxConstructorDecl(isDefaultConstructor()) will match #1, but not #2 or #3. +AST_MATCHER(CXXConstructorDecl, isDefaultConstructor) { + return Node.isDefaultConstructor(); +} + +/// \brief Matches constructor and conversion declarations that are marked with +/// the explicit keyword. +/// +/// Given +/// \code +/// struct S { +/// S(int); // #1 +/// explicit S(double); // #2 +/// operator int(); // #3 +/// explicit operator bool(); // #4 +/// }; +/// \endcode +/// cxxConstructorDecl(isExplicit()) will match #2, but not #1. +/// cxxConversionDecl(isExplicit()) will match #4, but not #3. +AST_POLYMORPHIC_MATCHER(isExplicit, + AST_POLYMORPHIC_SUPPORTED_TYPES(CXXConstructorDecl, + CXXConversionDecl)) { + return Node.isExplicit(); +} + +/// \brief Matches function and namespace declarations that are marked with +/// the inline keyword. +/// +/// Given +/// \code +/// inline void f(); +/// void g(); +/// namespace n { +/// inline namespace m {} +/// } +/// \endcode +/// functionDecl(isInline()) will match ::f(). +/// namespaceDecl(isInline()) will match n::m. +AST_POLYMORPHIC_MATCHER(isInline, + AST_POLYMORPHIC_SUPPORTED_TYPES(NamespaceDecl, + FunctionDecl)) { + // This is required because the spelling of the function used to determine + // whether inline is specified or not differs between the polymorphic types. + if (const auto *FD = dyn_cast<FunctionDecl>(&Node)) + return FD->isInlineSpecified(); + else if (const auto *NSD = dyn_cast<NamespaceDecl>(&Node)) + return NSD->isInline(); + llvm_unreachable("Not a valid polymorphic type"); +} + +/// \brief Matches anonymous namespace declarations. +/// +/// Given +/// \code +/// namespace n { +/// namespace {} // #1 +/// } +/// \endcode +/// namespaceDecl(isAnonymous()) will match #1 but not ::n. +AST_MATCHER(NamespaceDecl, isAnonymous) { + return Node.isAnonymousNamespace(); +} + +/// \brief If the given case statement does not use the GNU case range +/// extension, matches the constant given in the statement. +/// +/// Given +/// \code +/// switch (1) { case 1: case 1+1: case 3 ... 4: ; } +/// \endcode +/// caseStmt(hasCaseConstant(integerLiteral())) +/// matches "case 1:" +AST_MATCHER_P(CaseStmt, hasCaseConstant, internal::Matcher<Expr>, + InnerMatcher) { + if (Node.getRHS()) + return false; + + return InnerMatcher.matches(*Node.getLHS(), Finder, Builder); +} + +/// \brief Matches declaration that has a given attribute. +/// +/// Given +/// \code +/// __attribute__((device)) void f() { ... } +/// \endcode +/// decl(hasAttr(clang::attr::CUDADevice)) matches the function declaration of +/// f. If the matcher is use from clang-query, attr::Kind parameter should be +/// passed as a quoted string. e.g., hasAttr("attr::CUDADevice"). +AST_MATCHER_P(Decl, hasAttr, attr::Kind, AttrKind) { + for (const auto *Attr : Node.attrs()) { + if (Attr->getKind() == AttrKind) + return true; + } + return false; +} + +/// \brief Matches CUDA kernel call expression. +/// +/// Example matches, +/// \code +/// kernel<<<i,j>>>(); +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Stmt, + CUDAKernelCallExpr> cudaKernelCallExpr; + +} // end namespace ast_matchers +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/contrib/llvm/tools/clang/include/clang/ASTMatchers/ASTMatchersInternal.h new file mode 100644 index 0000000..d499091 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -0,0 +1,1591 @@ +//===--- ASTMatchersInternal.h - Structural query framework -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implements the base layer of the matcher framework. +// +// Matchers are methods that return a Matcher<T> which provides a method +// Matches(...) which is a predicate on an AST node. The Matches method's +// parameters define the context of the match, which allows matchers to recurse +// or store the current node as bound to a specific string, so that it can be +// retrieved later. +// +// In general, matchers have two parts: +// 1. A function Matcher<T> MatcherName(<arguments>) which returns a Matcher<T> +// based on the arguments and optionally on template type deduction based +// on the arguments. Matcher<T>s form an implicit reverse hierarchy +// to clang's AST class hierarchy, meaning that you can use a Matcher<Base> +// everywhere a Matcher<Derived> is required. +// 2. An implementation of a class derived from MatcherInterface<T>. +// +// The matcher functions are defined in ASTMatchers.h. To make it possible +// to implement both the matcher function and the implementation of the matcher +// interface in one place, ASTMatcherMacros.h defines macros that allow +// implementing a matcher in a single place. +// +// This file contains the base classes needed to construct the actual matchers. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ASTMATCHERS_ASTMATCHERSINTERNAL_H +#define LLVM_CLANG_ASTMATCHERS_ASTMATCHERSINTERNAL_H + +#include "clang/AST/ASTTypeTraits.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/StmtCXX.h" +#include "clang/AST/StmtObjC.h" +#include "clang/AST/Type.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/VariadicFunction.h" +#include "llvm/Support/ManagedStatic.h" +#include <map> +#include <string> +#include <vector> + +namespace clang { +namespace ast_matchers { + +class BoundNodes; + +namespace internal { + +/// \brief Internal version of BoundNodes. Holds all the bound nodes. +class BoundNodesMap { +public: + /// \brief Adds \c Node to the map with key \c ID. + /// + /// The node's base type should be in NodeBaseType or it will be unaccessible. + void addNode(StringRef ID, const ast_type_traits::DynTypedNode& DynNode) { + NodeMap[ID] = DynNode; + } + + /// \brief Returns the AST node bound to \c ID. + /// + /// Returns NULL if there was no node bound to \c ID or if there is a node but + /// it cannot be converted to the specified type. + template <typename T> + const T *getNodeAs(StringRef ID) const { + IDToNodeMap::const_iterator It = NodeMap.find(ID); + if (It == NodeMap.end()) { + return nullptr; + } + return It->second.get<T>(); + } + + ast_type_traits::DynTypedNode getNode(StringRef ID) const { + IDToNodeMap::const_iterator It = NodeMap.find(ID); + if (It == NodeMap.end()) { + return ast_type_traits::DynTypedNode(); + } + return It->second; + } + + /// \brief Imposes an order on BoundNodesMaps. + bool operator<(const BoundNodesMap &Other) const { + return NodeMap < Other.NodeMap; + } + + /// \brief A map from IDs to the bound nodes. + /// + /// Note that we're using std::map here, as for memoization: + /// - we need a comparison operator + /// - we need an assignment operator + typedef std::map<std::string, ast_type_traits::DynTypedNode> IDToNodeMap; + + const IDToNodeMap &getMap() const { + return NodeMap; + } + + /// \brief Returns \c true if this \c BoundNodesMap can be compared, i.e. all + /// stored nodes have memoization data. + bool isComparable() const { + for (const auto &IDAndNode : NodeMap) { + if (!IDAndNode.second.getMemoizationData()) + return false; + } + return true; + } + +private: + IDToNodeMap NodeMap; +}; + +/// \brief Creates BoundNodesTree objects. +/// +/// The tree builder is used during the matching process to insert the bound +/// nodes from the Id matcher. +class BoundNodesTreeBuilder { +public: + /// \brief A visitor interface to visit all BoundNodes results for a + /// BoundNodesTree. + class Visitor { + public: + virtual ~Visitor() {} + + /// \brief Called multiple times during a single call to VisitMatches(...). + /// + /// 'BoundNodesView' contains the bound nodes for a single match. + virtual void visitMatch(const BoundNodes& BoundNodesView) = 0; + }; + + /// \brief Add a binding from an id to a node. + void setBinding(StringRef Id, const ast_type_traits::DynTypedNode &DynNode) { + if (Bindings.empty()) + Bindings.emplace_back(); + for (BoundNodesMap &Binding : Bindings) + Binding.addNode(Id, DynNode); + } + + /// \brief Adds a branch in the tree. + void addMatch(const BoundNodesTreeBuilder &Bindings); + + /// \brief Visits all matches that this BoundNodesTree represents. + /// + /// The ownership of 'ResultVisitor' remains at the caller. + void visitMatches(Visitor* ResultVisitor); + + template <typename ExcludePredicate> + bool removeBindings(const ExcludePredicate &Predicate) { + Bindings.erase(std::remove_if(Bindings.begin(), Bindings.end(), Predicate), + Bindings.end()); + return !Bindings.empty(); + } + + /// \brief Imposes an order on BoundNodesTreeBuilders. + bool operator<(const BoundNodesTreeBuilder &Other) const { + return Bindings < Other.Bindings; + } + + /// \brief Returns \c true if this \c BoundNodesTreeBuilder can be compared, + /// i.e. all stored node maps have memoization data. + bool isComparable() const { + for (const BoundNodesMap &NodesMap : Bindings) { + if (!NodesMap.isComparable()) + return false; + } + return true; + } + +private: + SmallVector<BoundNodesMap, 16> Bindings; +}; + +class ASTMatchFinder; + +/// \brief Generic interface for all matchers. +/// +/// Used by the implementation of Matcher<T> and DynTypedMatcher. +/// In general, implement MatcherInterface<T> or SingleNodeMatcherInterface<T> +/// instead. +class DynMatcherInterface + : public llvm::ThreadSafeRefCountedBase<DynMatcherInterface> { +public: + virtual ~DynMatcherInterface() {} + + /// \brief Returns true if \p DynNode can be matched. + /// + /// May bind \p DynNode to an ID via \p Builder, or recurse into + /// the AST via \p Finder. + virtual bool dynMatches(const ast_type_traits::DynTypedNode &DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const = 0; +}; + +/// \brief Generic interface for matchers on an AST node of type T. +/// +/// Implement this if your matcher may need to inspect the children or +/// descendants of the node or bind matched nodes to names. If you are +/// writing a simple matcher that only inspects properties of the +/// current node and doesn't care about its children or descendants, +/// implement SingleNodeMatcherInterface instead. +template <typename T> +class MatcherInterface : public DynMatcherInterface { +public: + /// \brief Returns true if 'Node' can be matched. + /// + /// May bind 'Node' to an ID via 'Builder', or recurse into + /// the AST via 'Finder'. + virtual bool matches(const T &Node, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const = 0; + + bool dynMatches(const ast_type_traits::DynTypedNode &DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const override { + return matches(DynNode.getUnchecked<T>(), Finder, Builder); + } +}; + +/// \brief Interface for matchers that only evaluate properties on a single +/// node. +template <typename T> +class SingleNodeMatcherInterface : public MatcherInterface<T> { +public: + /// \brief Returns true if the matcher matches the provided node. + /// + /// A subclass must implement this instead of Matches(). + virtual bool matchesNode(const T &Node) const = 0; + +private: + /// Implements MatcherInterface::Matches. + bool matches(const T &Node, + ASTMatchFinder * /* Finder */, + BoundNodesTreeBuilder * /* Builder */) const override { + return matchesNode(Node); + } +}; + +template <typename> class Matcher; + +/// \brief Matcher that works on a \c DynTypedNode. +/// +/// It is constructed from a \c Matcher<T> object and redirects most calls to +/// underlying matcher. +/// It checks whether the \c DynTypedNode is convertible into the type of the +/// underlying matcher and then do the actual match on the actual node, or +/// return false if it is not convertible. +class DynTypedMatcher { +public: + /// \brief Takes ownership of the provided implementation pointer. + template <typename T> + DynTypedMatcher(MatcherInterface<T> *Implementation) + : AllowBind(false), + SupportedKind(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()), + RestrictKind(SupportedKind), Implementation(Implementation) {} + + /// \brief Construct from a variadic function. + enum VariadicOperator { + /// \brief Matches nodes for which all provided matchers match. + VO_AllOf, + /// \brief Matches nodes for which at least one of the provided matchers + /// matches. + VO_AnyOf, + /// \brief Matches nodes for which at least one of the provided matchers + /// matches, but doesn't stop at the first match. + VO_EachOf, + /// \brief Matches nodes that do not match the provided matcher. + /// + /// Uses the variadic matcher interface, but fails if + /// InnerMatchers.size() != 1. + VO_UnaryNot + }; + static DynTypedMatcher + constructVariadic(VariadicOperator Op, + ast_type_traits::ASTNodeKind SupportedKind, + std::vector<DynTypedMatcher> InnerMatchers); + + /// \brief Get a "true" matcher for \p NodeKind. + /// + /// It only checks that the node is of the right kind. + static DynTypedMatcher trueMatcher(ast_type_traits::ASTNodeKind NodeKind); + + void setAllowBind(bool AB) { AllowBind = AB; } + + /// \brief Check whether this matcher could ever match a node of kind \p Kind. + /// \return \c false if this matcher will never match such a node. Otherwise, + /// return \c true. + bool canMatchNodesOfKind(ast_type_traits::ASTNodeKind Kind) const; + + /// \brief Return a matcher that points to the same implementation, but + /// restricts the node types for \p Kind. + DynTypedMatcher dynCastTo(const ast_type_traits::ASTNodeKind Kind) const; + + /// \brief Returns true if the matcher matches the given \c DynNode. + bool matches(const ast_type_traits::DynTypedNode &DynNode, + ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const; + + /// \brief Same as matches(), but skips the kind check. + /// + /// It is faster, but the caller must ensure the node is valid for the + /// kind of this matcher. + bool matchesNoKindCheck(const ast_type_traits::DynTypedNode &DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const; + + /// \brief Bind the specified \p ID to the matcher. + /// \return A new matcher with the \p ID bound to it if this matcher supports + /// binding. Otherwise, returns an empty \c Optional<>. + llvm::Optional<DynTypedMatcher> tryBind(StringRef ID) const; + + /// \brief Returns a unique \p ID for the matcher. + /// + /// Casting a Matcher<T> to Matcher<U> creates a matcher that has the + /// same \c Implementation pointer, but different \c RestrictKind. We need to + /// include both in the ID to make it unique. + /// + /// \c MatcherIDType supports operator< and provides strict weak ordering. + typedef std::pair<ast_type_traits::ASTNodeKind, uint64_t> MatcherIDType; + MatcherIDType getID() const { + /// FIXME: Document the requirements this imposes on matcher + /// implementations (no new() implementation_ during a Matches()). + return std::make_pair(RestrictKind, + reinterpret_cast<uint64_t>(Implementation.get())); + } + + /// \brief Returns the type this matcher works on. + /// + /// \c matches() will always return false unless the node passed is of this + /// or a derived type. + ast_type_traits::ASTNodeKind getSupportedKind() const { + return SupportedKind; + } + + /// \brief Returns \c true if the passed \c DynTypedMatcher can be converted + /// to a \c Matcher<T>. + /// + /// This method verifies that the underlying matcher in \c Other can process + /// nodes of types T. + template <typename T> bool canConvertTo() const { + return canConvertTo(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()); + } + bool canConvertTo(ast_type_traits::ASTNodeKind To) const; + + /// \brief Construct a \c Matcher<T> interface around the dynamic matcher. + /// + /// This method asserts that \c canConvertTo() is \c true. Callers + /// should call \c canConvertTo() first to make sure that \c this is + /// compatible with T. + template <typename T> Matcher<T> convertTo() const { + assert(canConvertTo<T>()); + return unconditionalConvertTo<T>(); + } + + /// \brief Same as \c convertTo(), but does not check that the underlying + /// matcher can handle a value of T. + /// + /// If it is not compatible, then this matcher will never match anything. + template <typename T> Matcher<T> unconditionalConvertTo() const; + +private: + DynTypedMatcher(ast_type_traits::ASTNodeKind SupportedKind, + ast_type_traits::ASTNodeKind RestrictKind, + IntrusiveRefCntPtr<DynMatcherInterface> Implementation) + : AllowBind(false), + SupportedKind(SupportedKind), + RestrictKind(RestrictKind), + Implementation(std::move(Implementation)) {} + + bool AllowBind; + ast_type_traits::ASTNodeKind SupportedKind; + /// \brief A potentially stricter node kind. + /// + /// It allows to perform implicit and dynamic cast of matchers without + /// needing to change \c Implementation. + ast_type_traits::ASTNodeKind RestrictKind; + IntrusiveRefCntPtr<DynMatcherInterface> Implementation; +}; + +/// \brief Wrapper base class for a wrapping matcher. +/// +/// This is just a container for a DynTypedMatcher that can be used as a base +/// class for another matcher. +template <typename T> +class WrapperMatcherInterface : public MatcherInterface<T> { +protected: + explicit WrapperMatcherInterface(DynTypedMatcher &&InnerMatcher) + : InnerMatcher(std::move(InnerMatcher)) {} + + const DynTypedMatcher InnerMatcher; +}; + +/// \brief Wrapper of a MatcherInterface<T> *that allows copying. +/// +/// A Matcher<Base> can be used anywhere a Matcher<Derived> is +/// required. This establishes an is-a relationship which is reverse +/// to the AST hierarchy. In other words, Matcher<T> is contravariant +/// with respect to T. The relationship is built via a type conversion +/// operator rather than a type hierarchy to be able to templatize the +/// type hierarchy instead of spelling it out. +template <typename T> +class Matcher { +public: + /// \brief Takes ownership of the provided implementation pointer. + explicit Matcher(MatcherInterface<T> *Implementation) + : Implementation(Implementation) {} + + /// \brief Implicitly converts \c Other to a Matcher<T>. + /// + /// Requires \c T to be derived from \c From. + template <typename From> + Matcher(const Matcher<From> &Other, + typename std::enable_if<std::is_base_of<From, T>::value && + !std::is_same<From, T>::value>::type * = 0) + : Implementation(restrictMatcher(Other.Implementation)) { + assert(Implementation.getSupportedKind().isSame( + ast_type_traits::ASTNodeKind::getFromNodeKind<T>())); + } + + /// \brief Implicitly converts \c Matcher<Type> to \c Matcher<QualType>. + /// + /// The resulting matcher is not strict, i.e. ignores qualifiers. + template <typename TypeT> + Matcher(const Matcher<TypeT> &Other, + typename std::enable_if< + std::is_same<T, QualType>::value && + std::is_same<TypeT, Type>::value>::type* = 0) + : Implementation(new TypeToQualType<TypeT>(Other)) {} + + /// \brief Convert \c this into a \c Matcher<T> by applying dyn_cast<> to the + /// argument. + /// \c To must be a base class of \c T. + template <typename To> + Matcher<To> dynCastTo() const { + static_assert(std::is_base_of<To, T>::value, "Invalid dynCast call."); + return Matcher<To>(Implementation); + } + + /// \brief Forwards the call to the underlying MatcherInterface<T> pointer. + bool matches(const T &Node, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const { + return Implementation.matches(ast_type_traits::DynTypedNode::create(Node), + Finder, Builder); + } + + /// \brief Returns an ID that uniquely identifies the matcher. + DynTypedMatcher::MatcherIDType getID() const { + return Implementation.getID(); + } + + /// \brief Extract the dynamic matcher. + /// + /// The returned matcher keeps the same restrictions as \c this and remembers + /// that it is meant to support nodes of type \c T. + operator DynTypedMatcher() const { return Implementation; } + + /// \brief Allows the conversion of a \c Matcher<Type> to a \c + /// Matcher<QualType>. + /// + /// Depending on the constructor argument, the matcher is either strict, i.e. + /// does only matches in the absence of qualifiers, or not, i.e. simply + /// ignores any qualifiers. + template <typename TypeT> + class TypeToQualType : public WrapperMatcherInterface<QualType> { + public: + TypeToQualType(const Matcher<TypeT> &InnerMatcher) + : TypeToQualType::WrapperMatcherInterface(InnerMatcher) {} + + bool matches(const QualType &Node, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const override { + if (Node.isNull()) + return false; + return this->InnerMatcher.matches( + ast_type_traits::DynTypedNode::create(*Node), Finder, Builder); + } + }; + +private: + // For Matcher<T> <=> Matcher<U> conversions. + template <typename U> friend class Matcher; + // For DynTypedMatcher::unconditionalConvertTo<T>. + friend class DynTypedMatcher; + + static DynTypedMatcher restrictMatcher(const DynTypedMatcher &Other) { + return Other.dynCastTo(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()); + } + + explicit Matcher(const DynTypedMatcher &Implementation) + : Implementation(restrictMatcher(Implementation)) { + assert(this->Implementation.getSupportedKind() + .isSame(ast_type_traits::ASTNodeKind::getFromNodeKind<T>())); + } + + DynTypedMatcher Implementation; +}; // class Matcher + +/// \brief A convenient helper for creating a Matcher<T> without specifying +/// the template type argument. +template <typename T> +inline Matcher<T> makeMatcher(MatcherInterface<T> *Implementation) { + return Matcher<T>(Implementation); +} + +/// \brief Specialization of the conversion functions for QualType. +/// +/// This specialization provides the Matcher<Type>->Matcher<QualType> +/// conversion that the static API does. +template <> +inline Matcher<QualType> DynTypedMatcher::convertTo<QualType>() const { + assert(canConvertTo<QualType>()); + const ast_type_traits::ASTNodeKind SourceKind = getSupportedKind(); + if (SourceKind.isSame( + ast_type_traits::ASTNodeKind::getFromNodeKind<Type>())) { + // We support implicit conversion from Matcher<Type> to Matcher<QualType> + return unconditionalConvertTo<Type>(); + } + return unconditionalConvertTo<QualType>(); +} + +/// \brief Finds the first node in a range that matches the given matcher. +template <typename MatcherT, typename IteratorT> +bool matchesFirstInRange(const MatcherT &Matcher, IteratorT Start, + IteratorT End, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) { + for (IteratorT I = Start; I != End; ++I) { + BoundNodesTreeBuilder Result(*Builder); + if (Matcher.matches(*I, Finder, &Result)) { + *Builder = std::move(Result); + return true; + } + } + return false; +} + +/// \brief Finds the first node in a pointer range that matches the given +/// matcher. +template <typename MatcherT, typename IteratorT> +bool matchesFirstInPointerRange(const MatcherT &Matcher, IteratorT Start, + IteratorT End, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) { + for (IteratorT I = Start; I != End; ++I) { + BoundNodesTreeBuilder Result(*Builder); + if (Matcher.matches(**I, Finder, &Result)) { + *Builder = std::move(Result); + return true; + } + } + return false; +} + +// Metafunction to determine if type T has a member called +// getDecl. +#if defined(_MSC_VER) && (_MSC_VER < 1900) && !defined(__clang__) +// For old versions of MSVC, we use a weird nonstandard __if_exists +// statement, since before MSVC2015, it was not standards-conformant +// enough to compile the usual code below. +template <typename T> struct has_getDecl { + __if_exists(T::getDecl) { + enum { value = 1 }; + } + __if_not_exists(T::getDecl) { + enum { value = 0 }; + } +}; +#else +// There is a default template inheriting from "false_type". Then, a +// partial specialization inherits from "true_type". However, this +// specialization will only exist when the call to getDecl() isn't an +// error -- it vanishes by SFINAE when the member doesn't exist. +template <typename> struct type_sink_to_void { typedef void type; }; +template <typename T, typename = void> struct has_getDecl : std::false_type {}; +template <typename T> +struct has_getDecl< + T, typename type_sink_to_void<decltype(std::declval<T>().getDecl())>::type> + : std::true_type {}; +#endif + +/// \brief Matches overloaded operators with a specific name. +/// +/// The type argument ArgT is not used by this matcher but is used by +/// PolymorphicMatcherWithParam1 and should be StringRef. +template <typename T, typename ArgT> +class HasOverloadedOperatorNameMatcher : public SingleNodeMatcherInterface<T> { + static_assert(std::is_same<T, CXXOperatorCallExpr>::value || + std::is_base_of<FunctionDecl, T>::value, + "unsupported class for matcher"); + static_assert(std::is_same<ArgT, StringRef>::value, + "argument type must be StringRef"); + +public: + explicit HasOverloadedOperatorNameMatcher(const StringRef Name) + : SingleNodeMatcherInterface<T>(), Name(Name) {} + + bool matchesNode(const T &Node) const override { + return matchesSpecialized(Node); + } + +private: + + /// \brief CXXOperatorCallExpr exist only for calls to overloaded operators + /// so this function returns true if the call is to an operator of the given + /// name. + bool matchesSpecialized(const CXXOperatorCallExpr &Node) const { + return getOperatorSpelling(Node.getOperator()) == Name; + } + + /// \brief Returns true only if CXXMethodDecl represents an overloaded + /// operator and has the given operator name. + bool matchesSpecialized(const FunctionDecl &Node) const { + return Node.isOverloadedOperator() && + getOperatorSpelling(Node.getOverloadedOperator()) == Name; + } + + std::string Name; +}; + +/// \brief Matches named declarations with a specific name. +/// +/// See \c hasName() in ASTMatchers.h for details. +class HasNameMatcher : public SingleNodeMatcherInterface<NamedDecl> { + public: + explicit HasNameMatcher(StringRef Name); + + bool matchesNode(const NamedDecl &Node) const override; + + private: + /// \brief Unqualified match routine. + /// + /// It is much faster than the full match, but it only works for unqualified + /// matches. + bool matchesNodeUnqualified(const NamedDecl &Node) const; + + /// \brief Full match routine + /// + /// It generates the fully qualified name of the declaration (which is + /// expensive) before trying to match. + /// It is slower but simple and works on all cases. + bool matchesNodeFull(const NamedDecl &Node) const; + + const bool UseUnqualifiedMatch; + const std::string Name; +}; + +/// \brief Matches declarations for QualType and CallExpr. +/// +/// Type argument DeclMatcherT is required by PolymorphicMatcherWithParam1 but +/// not actually used. +template <typename T, typename DeclMatcherT> +class HasDeclarationMatcher : public WrapperMatcherInterface<T> { + static_assert(std::is_same<DeclMatcherT, Matcher<Decl>>::value, + "instantiated with wrong types"); + +public: + explicit HasDeclarationMatcher(const Matcher<Decl> &InnerMatcher) + : HasDeclarationMatcher::WrapperMatcherInterface(InnerMatcher) {} + + bool matches(const T &Node, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const override { + return matchesSpecialized(Node, Finder, Builder); + } + +private: + /// \brief If getDecl exists as a member of U, returns whether the inner + /// matcher matches Node.getDecl(). + template <typename U> + bool matchesSpecialized( + const U &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, + typename std::enable_if<has_getDecl<U>::value, int>::type = 0) const { + return matchesDecl(Node.getDecl(), Finder, Builder); + } + + /// \brief Extracts the TagDecl of a QualType and returns whether the inner + /// matcher matches on it. + bool matchesSpecialized(const QualType &Node, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const { + if (Node.isNull()) + return false; + + if (auto *TD = Node->getAsTagDecl()) + return matchesDecl(TD, Finder, Builder); + else if (auto *TT = Node->getAs<TypedefType>()) + return matchesDecl(TT->getDecl(), Finder, Builder); + // Do not use getAs<TemplateTypeParmType> instead of the direct dyn_cast. + // Calling getAs will return the canonical type, but that type does not + // store a TemplateTypeParmDecl. We *need* the uncanonical type, if it is + // available, and using dyn_cast ensures that. + else if (auto *TTP = dyn_cast<TemplateTypeParmType>(Node.getTypePtr())) + return matchesDecl(TTP->getDecl(), Finder, Builder); + else if (auto *OCIT = Node->getAs<ObjCInterfaceType>()) + return matchesDecl(OCIT->getDecl(), Finder, Builder); + else if (auto *UUT = Node->getAs<UnresolvedUsingType>()) + return matchesDecl(UUT->getDecl(), Finder, Builder); + else if (auto *ICNT = Node->getAs<InjectedClassNameType>()) + return matchesDecl(ICNT->getDecl(), Finder, Builder); + return false; + } + + /// \brief Gets the TemplateDecl from a TemplateSpecializationType + /// and returns whether the inner matches on it. + bool matchesSpecialized(const TemplateSpecializationType &Node, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const { + return matchesDecl(Node.getTemplateName().getAsTemplateDecl(), + Finder, Builder); + } + + /// \brief Extracts the Decl of the callee of a CallExpr and returns whether + /// the inner matcher matches on it. + bool matchesSpecialized(const CallExpr &Node, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const { + return matchesDecl(Node.getCalleeDecl(), Finder, Builder); + } + + /// \brief Extracts the Decl of the constructor call and returns whether the + /// inner matcher matches on it. + bool matchesSpecialized(const CXXConstructExpr &Node, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const { + return matchesDecl(Node.getConstructor(), Finder, Builder); + } + + /// \brief Extracts the \c ValueDecl a \c MemberExpr refers to and returns + /// whether the inner matcher matches on it. + bool matchesSpecialized(const MemberExpr &Node, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const { + return matchesDecl(Node.getMemberDecl(), Finder, Builder); + } + + /// \brief Returns whether the inner matcher \c Node. Returns false if \c Node + /// is \c NULL. + bool matchesDecl(const Decl *Node, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const { + return Node != nullptr && + this->InnerMatcher.matches( + ast_type_traits::DynTypedNode::create(*Node), Finder, Builder); + } +}; + +/// \brief IsBaseType<T>::value is true if T is a "base" type in the AST +/// node class hierarchies. +template <typename T> +struct IsBaseType { + static const bool value = + std::is_same<T, Decl>::value || + std::is_same<T, Stmt>::value || + std::is_same<T, QualType>::value || + std::is_same<T, Type>::value || + std::is_same<T, TypeLoc>::value || + std::is_same<T, NestedNameSpecifier>::value || + std::is_same<T, NestedNameSpecifierLoc>::value || + std::is_same<T, CXXCtorInitializer>::value; +}; +template <typename T> +const bool IsBaseType<T>::value; + +/// \brief Interface that allows matchers to traverse the AST. +/// FIXME: Find a better name. +/// +/// This provides three entry methods for each base node type in the AST: +/// - \c matchesChildOf: +/// Matches a matcher on every child node of the given node. Returns true +/// if at least one child node could be matched. +/// - \c matchesDescendantOf: +/// Matches a matcher on all descendant nodes of the given node. Returns true +/// if at least one descendant matched. +/// - \c matchesAncestorOf: +/// Matches a matcher on all ancestors of the given node. Returns true if +/// at least one ancestor matched. +/// +/// FIXME: Currently we only allow Stmt and Decl nodes to start a traversal. +/// In the future, we want to implement this for all nodes for which it makes +/// sense. In the case of matchesAncestorOf, we'll want to implement it for +/// all nodes, as all nodes have ancestors. +class ASTMatchFinder { +public: + /// \brief Defines how we descend a level in the AST when we pass + /// through expressions. + enum TraversalKind { + /// Will traverse any child nodes. + TK_AsIs, + /// Will not traverse implicit casts and parentheses. + TK_IgnoreImplicitCastsAndParentheses + }; + + /// \brief Defines how bindings are processed on recursive matches. + enum BindKind { + /// Stop at the first match and only bind the first match. + BK_First, + /// Create results for all combinations of bindings that match. + BK_All + }; + + /// \brief Defines which ancestors are considered for a match. + enum AncestorMatchMode { + /// All ancestors. + AMM_All, + /// Direct parent only. + AMM_ParentOnly + }; + + virtual ~ASTMatchFinder() {} + + /// \brief Returns true if the given class is directly or indirectly derived + /// from a base type matching \c base. + /// + /// A class is considered to be also derived from itself. + virtual bool classIsDerivedFrom(const CXXRecordDecl *Declaration, + const Matcher<NamedDecl> &Base, + BoundNodesTreeBuilder *Builder) = 0; + + template <typename T> + bool matchesChildOf(const T &Node, + const DynTypedMatcher &Matcher, + BoundNodesTreeBuilder *Builder, + TraversalKind Traverse, + BindKind Bind) { + static_assert(std::is_base_of<Decl, T>::value || + std::is_base_of<Stmt, T>::value || + std::is_base_of<NestedNameSpecifier, T>::value || + std::is_base_of<NestedNameSpecifierLoc, T>::value || + std::is_base_of<TypeLoc, T>::value || + std::is_base_of<QualType, T>::value, + "unsupported type for recursive matching"); + return matchesChildOf(ast_type_traits::DynTypedNode::create(Node), + Matcher, Builder, Traverse, Bind); + } + + template <typename T> + bool matchesDescendantOf(const T &Node, + const DynTypedMatcher &Matcher, + BoundNodesTreeBuilder *Builder, + BindKind Bind) { + static_assert(std::is_base_of<Decl, T>::value || + std::is_base_of<Stmt, T>::value || + std::is_base_of<NestedNameSpecifier, T>::value || + std::is_base_of<NestedNameSpecifierLoc, T>::value || + std::is_base_of<TypeLoc, T>::value || + std::is_base_of<QualType, T>::value, + "unsupported type for recursive matching"); + return matchesDescendantOf(ast_type_traits::DynTypedNode::create(Node), + Matcher, Builder, Bind); + } + + // FIXME: Implement support for BindKind. + template <typename T> + bool matchesAncestorOf(const T &Node, + const DynTypedMatcher &Matcher, + BoundNodesTreeBuilder *Builder, + AncestorMatchMode MatchMode) { + static_assert(std::is_base_of<Decl, T>::value || + std::is_base_of<NestedNameSpecifierLoc, T>::value || + std::is_base_of<Stmt, T>::value || + std::is_base_of<TypeLoc, T>::value, + "type not allowed for recursive matching"); + return matchesAncestorOf(ast_type_traits::DynTypedNode::create(Node), + Matcher, Builder, MatchMode); + } + + virtual ASTContext &getASTContext() const = 0; + +protected: + virtual bool matchesChildOf(const ast_type_traits::DynTypedNode &Node, + const DynTypedMatcher &Matcher, + BoundNodesTreeBuilder *Builder, + TraversalKind Traverse, + BindKind Bind) = 0; + + virtual bool matchesDescendantOf(const ast_type_traits::DynTypedNode &Node, + const DynTypedMatcher &Matcher, + BoundNodesTreeBuilder *Builder, + BindKind Bind) = 0; + + virtual bool matchesAncestorOf(const ast_type_traits::DynTypedNode &Node, + const DynTypedMatcher &Matcher, + BoundNodesTreeBuilder *Builder, + AncestorMatchMode MatchMode) = 0; +}; + +/// \brief A type-list implementation. +/// +/// A "linked list" of types, accessible by using the ::head and ::tail +/// typedefs. +template <typename... Ts> struct TypeList {}; // Empty sentinel type list. + +template <typename T1, typename... Ts> struct TypeList<T1, Ts...> { + /// \brief The first type on the list. + typedef T1 head; + + /// \brief A sublist with the tail. ie everything but the head. + /// + /// This type is used to do recursion. TypeList<>/EmptyTypeList indicates the + /// end of the list. + typedef TypeList<Ts...> tail; +}; + +/// \brief The empty type list. +typedef TypeList<> EmptyTypeList; + +/// \brief Helper meta-function to determine if some type \c T is present or +/// a parent type in the list. +template <typename AnyTypeList, typename T> +struct TypeListContainsSuperOf { + static const bool value = + std::is_base_of<typename AnyTypeList::head, T>::value || + TypeListContainsSuperOf<typename AnyTypeList::tail, T>::value; +}; +template <typename T> +struct TypeListContainsSuperOf<EmptyTypeList, T> { + static const bool value = false; +}; + +/// \brief A "type list" that contains all types. +/// +/// Useful for matchers like \c anything and \c unless. +typedef TypeList<Decl, Stmt, NestedNameSpecifier, NestedNameSpecifierLoc, + QualType, Type, TypeLoc, CXXCtorInitializer> AllNodeBaseTypes; + +/// \brief Helper meta-function to extract the argument out of a function of +/// type void(Arg). +/// +/// See AST_POLYMORPHIC_SUPPORTED_TYPES for details. +template <class T> struct ExtractFunctionArgMeta; +template <class T> struct ExtractFunctionArgMeta<void(T)> { + typedef T type; +}; + +/// \brief Default type lists for ArgumentAdaptingMatcher matchers. +typedef AllNodeBaseTypes AdaptativeDefaultFromTypes; +typedef TypeList<Decl, Stmt, NestedNameSpecifier, NestedNameSpecifierLoc, + TypeLoc, QualType> AdaptativeDefaultToTypes; + +/// \brief All types that are supported by HasDeclarationMatcher above. +typedef TypeList<CallExpr, CXXConstructExpr, DeclRefExpr, EnumType, + InjectedClassNameType, LabelStmt, MemberExpr, QualType, + RecordType, TagType, TemplateSpecializationType, + TemplateTypeParmType, TypedefType, + UnresolvedUsingType> HasDeclarationSupportedTypes; + +/// \brief Converts a \c Matcher<T> to a matcher of desired type \c To by +/// "adapting" a \c To into a \c T. +/// +/// The \c ArgumentAdapterT argument specifies how the adaptation is done. +/// +/// For example: +/// \c ArgumentAdaptingMatcher<HasMatcher, T>(InnerMatcher); +/// Given that \c InnerMatcher is of type \c Matcher<T>, this returns a matcher +/// that is convertible into any matcher of type \c To by constructing +/// \c HasMatcher<To, T>(InnerMatcher). +/// +/// If a matcher does not need knowledge about the inner type, prefer to use +/// PolymorphicMatcherWithParam1. +template <template <typename ToArg, typename FromArg> class ArgumentAdapterT, + typename FromTypes = AdaptativeDefaultFromTypes, + typename ToTypes = AdaptativeDefaultToTypes> +struct ArgumentAdaptingMatcherFunc { + template <typename T> class Adaptor { + public: + explicit Adaptor(const Matcher<T> &InnerMatcher) + : InnerMatcher(InnerMatcher) {} + + typedef ToTypes ReturnTypes; + + template <typename To> operator Matcher<To>() const { + return Matcher<To>(new ArgumentAdapterT<To, T>(InnerMatcher)); + } + + private: + const Matcher<T> InnerMatcher; + }; + + template <typename T> + static Adaptor<T> create(const Matcher<T> &InnerMatcher) { + return Adaptor<T>(InnerMatcher); + } + + template <typename T> + Adaptor<T> operator()(const Matcher<T> &InnerMatcher) const { + return create(InnerMatcher); + } +}; + +/// \brief A PolymorphicMatcherWithParamN<MatcherT, P1, ..., PN> object can be +/// created from N parameters p1, ..., pN (of type P1, ..., PN) and +/// used as a Matcher<T> where a MatcherT<T, P1, ..., PN>(p1, ..., pN) +/// can be constructed. +/// +/// For example: +/// - PolymorphicMatcherWithParam0<IsDefinitionMatcher>() +/// creates an object that can be used as a Matcher<T> for any type T +/// where an IsDefinitionMatcher<T>() can be constructed. +/// - PolymorphicMatcherWithParam1<ValueEqualsMatcher, int>(42) +/// creates an object that can be used as a Matcher<T> for any type T +/// where a ValueEqualsMatcher<T, int>(42) can be constructed. +template <template <typename T> class MatcherT, + typename ReturnTypesF = void(AllNodeBaseTypes)> +class PolymorphicMatcherWithParam0 { +public: + typedef typename ExtractFunctionArgMeta<ReturnTypesF>::type ReturnTypes; + template <typename T> + operator Matcher<T>() const { + static_assert(TypeListContainsSuperOf<ReturnTypes, T>::value, + "right polymorphic conversion"); + return Matcher<T>(new MatcherT<T>()); + } +}; + +template <template <typename T, typename P1> class MatcherT, + typename P1, + typename ReturnTypesF = void(AllNodeBaseTypes)> +class PolymorphicMatcherWithParam1 { +public: + explicit PolymorphicMatcherWithParam1(const P1 &Param1) + : Param1(Param1) {} + + typedef typename ExtractFunctionArgMeta<ReturnTypesF>::type ReturnTypes; + + template <typename T> + operator Matcher<T>() const { + static_assert(TypeListContainsSuperOf<ReturnTypes, T>::value, + "right polymorphic conversion"); + return Matcher<T>(new MatcherT<T, P1>(Param1)); + } + +private: + const P1 Param1; +}; + +template <template <typename T, typename P1, typename P2> class MatcherT, + typename P1, typename P2, + typename ReturnTypesF = void(AllNodeBaseTypes)> +class PolymorphicMatcherWithParam2 { +public: + PolymorphicMatcherWithParam2(const P1 &Param1, const P2 &Param2) + : Param1(Param1), Param2(Param2) {} + + typedef typename ExtractFunctionArgMeta<ReturnTypesF>::type ReturnTypes; + + template <typename T> + operator Matcher<T>() const { + static_assert(TypeListContainsSuperOf<ReturnTypes, T>::value, + "right polymorphic conversion"); + return Matcher<T>(new MatcherT<T, P1, P2>(Param1, Param2)); + } + +private: + const P1 Param1; + const P2 Param2; +}; + +/// \brief Matches any instance of the given NodeType. +/// +/// This is useful when a matcher syntactically requires a child matcher, +/// but the context doesn't care. See for example: anything(). +class TrueMatcher { + public: + typedef AllNodeBaseTypes ReturnTypes; + + template <typename T> + operator Matcher<T>() const { + return DynTypedMatcher::trueMatcher( + ast_type_traits::ASTNodeKind::getFromNodeKind<T>()) + .template unconditionalConvertTo<T>(); + } +}; + +/// \brief A Matcher that allows binding the node it matches to an id. +/// +/// BindableMatcher provides a \a bind() method that allows binding the +/// matched node to an id if the match was successful. +template <typename T> +class BindableMatcher : public Matcher<T> { +public: + explicit BindableMatcher(const Matcher<T> &M) : Matcher<T>(M) {} + explicit BindableMatcher(MatcherInterface<T> *Implementation) + : Matcher<T>(Implementation) {} + + /// \brief Returns a matcher that will bind the matched node on a match. + /// + /// The returned matcher is equivalent to this matcher, but will + /// bind the matched node on a match. + Matcher<T> bind(StringRef ID) const { + return DynTypedMatcher(*this) + .tryBind(ID) + ->template unconditionalConvertTo<T>(); + } + + /// \brief Same as Matcher<T>'s conversion operator, but enables binding on + /// the returned matcher. + operator DynTypedMatcher() const { + DynTypedMatcher Result = static_cast<const Matcher<T>&>(*this); + Result.setAllowBind(true); + return Result; + } +}; + +/// \brief Matches nodes of type T that have child nodes of type ChildT for +/// which a specified child matcher matches. +/// +/// ChildT must be an AST base type. +template <typename T, typename ChildT> +class HasMatcher : public WrapperMatcherInterface<T> { + static_assert(IsBaseType<ChildT>::value, + "has only accepts base type matcher"); + +public: + explicit HasMatcher(const Matcher<ChildT> &ChildMatcher) + : HasMatcher::WrapperMatcherInterface(ChildMatcher) {} + + bool matches(const T &Node, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const override { + return Finder->matchesChildOf( + Node, this->InnerMatcher, Builder, + ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses, + ASTMatchFinder::BK_First); + } +}; + +/// \brief Matches nodes of type T that have child nodes of type ChildT for +/// which a specified child matcher matches. ChildT must be an AST base +/// type. +/// As opposed to the HasMatcher, the ForEachMatcher will produce a match +/// for each child that matches. +template <typename T, typename ChildT> +class ForEachMatcher : public WrapperMatcherInterface<T> { + static_assert(IsBaseType<ChildT>::value, + "for each only accepts base type matcher"); + + public: + explicit ForEachMatcher(const Matcher<ChildT> &ChildMatcher) + : ForEachMatcher::WrapperMatcherInterface(ChildMatcher) {} + + bool matches(const T& Node, ASTMatchFinder* Finder, + BoundNodesTreeBuilder* Builder) const override { + return Finder->matchesChildOf( + Node, this->InnerMatcher, Builder, + ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses, + ASTMatchFinder::BK_All); + } +}; + +/// \brief VariadicOperatorMatcher related types. +/// @{ + +/// \brief Polymorphic matcher object that uses a \c +/// DynTypedMatcher::VariadicOperator operator. +/// +/// Input matchers can have any type (including other polymorphic matcher +/// types), and the actual Matcher<T> is generated on demand with an implicit +/// coversion operator. +template <typename... Ps> class VariadicOperatorMatcher { +public: + VariadicOperatorMatcher(DynTypedMatcher::VariadicOperator Op, Ps &&... Params) + : Op(Op), Params(std::forward<Ps>(Params)...) {} + + template <typename T> operator Matcher<T>() const { + return DynTypedMatcher::constructVariadic( + Op, ast_type_traits::ASTNodeKind::getFromNodeKind<T>(), + getMatchers<T>(llvm::index_sequence_for<Ps...>())) + .template unconditionalConvertTo<T>(); + } + +private: + // Helper method to unpack the tuple into a vector. + template <typename T, std::size_t... Is> + std::vector<DynTypedMatcher> getMatchers(llvm::index_sequence<Is...>) const { + return {Matcher<T>(std::get<Is>(Params))...}; + } + + const DynTypedMatcher::VariadicOperator Op; + std::tuple<Ps...> Params; +}; + +/// \brief Overloaded function object to generate VariadicOperatorMatcher +/// objects from arbitrary matchers. +template <unsigned MinCount, unsigned MaxCount> +struct VariadicOperatorMatcherFunc { + DynTypedMatcher::VariadicOperator Op; + + template <typename... Ms> + VariadicOperatorMatcher<Ms...> operator()(Ms &&... Ps) const { + static_assert(MinCount <= sizeof...(Ms) && sizeof...(Ms) <= MaxCount, + "invalid number of parameters for variadic matcher"); + return VariadicOperatorMatcher<Ms...>(Op, std::forward<Ms>(Ps)...); + } +}; + +/// @} + +template <typename T> +inline Matcher<T> DynTypedMatcher::unconditionalConvertTo() const { + return Matcher<T>(*this); +} + +/// \brief Creates a Matcher<T> that matches if all inner matchers match. +template<typename T> +BindableMatcher<T> makeAllOfComposite( + ArrayRef<const Matcher<T> *> InnerMatchers) { + // For the size() == 0 case, we return a "true" matcher. + if (InnerMatchers.size() == 0) { + return BindableMatcher<T>(TrueMatcher()); + } + // For the size() == 1 case, we simply return that one matcher. + // No need to wrap it in a variadic operation. + if (InnerMatchers.size() == 1) { + return BindableMatcher<T>(*InnerMatchers[0]); + } + + typedef llvm::pointee_iterator<const Matcher<T> *const *> PI; + std::vector<DynTypedMatcher> DynMatchers(PI(InnerMatchers.begin()), + PI(InnerMatchers.end())); + return BindableMatcher<T>( + DynTypedMatcher::constructVariadic( + DynTypedMatcher::VO_AllOf, + ast_type_traits::ASTNodeKind::getFromNodeKind<T>(), + std::move(DynMatchers)) + .template unconditionalConvertTo<T>()); +} + +/// \brief Creates a Matcher<T> that matches if +/// T is dyn_cast'able into InnerT and all inner matchers match. +/// +/// Returns BindableMatcher, as matchers that use dyn_cast have +/// the same object both to match on and to run submatchers on, +/// so there is no ambiguity with what gets bound. +template<typename T, typename InnerT> +BindableMatcher<T> makeDynCastAllOfComposite( + ArrayRef<const Matcher<InnerT> *> InnerMatchers) { + return BindableMatcher<T>( + makeAllOfComposite(InnerMatchers).template dynCastTo<T>()); +} + +/// \brief Matches nodes of type T that have at least one descendant node of +/// type DescendantT for which the given inner matcher matches. +/// +/// DescendantT must be an AST base type. +template <typename T, typename DescendantT> +class HasDescendantMatcher : public WrapperMatcherInterface<T> { + static_assert(IsBaseType<DescendantT>::value, + "has descendant only accepts base type matcher"); + +public: + explicit HasDescendantMatcher(const Matcher<DescendantT> &DescendantMatcher) + : HasDescendantMatcher::WrapperMatcherInterface(DescendantMatcher) {} + + bool matches(const T &Node, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const override { + return Finder->matchesDescendantOf(Node, this->InnerMatcher, Builder, + ASTMatchFinder::BK_First); + } +}; + +/// \brief Matches nodes of type \c T that have a parent node of type \c ParentT +/// for which the given inner matcher matches. +/// +/// \c ParentT must be an AST base type. +template <typename T, typename ParentT> +class HasParentMatcher : public WrapperMatcherInterface<T> { + static_assert(IsBaseType<ParentT>::value, + "has parent only accepts base type matcher"); + +public: + explicit HasParentMatcher(const Matcher<ParentT> &ParentMatcher) + : HasParentMatcher::WrapperMatcherInterface(ParentMatcher) {} + + bool matches(const T &Node, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const override { + return Finder->matchesAncestorOf(Node, this->InnerMatcher, Builder, + ASTMatchFinder::AMM_ParentOnly); + } +}; + +/// \brief Matches nodes of type \c T that have at least one ancestor node of +/// type \c AncestorT for which the given inner matcher matches. +/// +/// \c AncestorT must be an AST base type. +template <typename T, typename AncestorT> +class HasAncestorMatcher : public WrapperMatcherInterface<T> { + static_assert(IsBaseType<AncestorT>::value, + "has ancestor only accepts base type matcher"); + +public: + explicit HasAncestorMatcher(const Matcher<AncestorT> &AncestorMatcher) + : HasAncestorMatcher::WrapperMatcherInterface(AncestorMatcher) {} + + bool matches(const T &Node, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const override { + return Finder->matchesAncestorOf(Node, this->InnerMatcher, Builder, + ASTMatchFinder::AMM_All); + } +}; + +/// \brief Matches nodes of type T that have at least one descendant node of +/// type DescendantT for which the given inner matcher matches. +/// +/// DescendantT must be an AST base type. +/// As opposed to HasDescendantMatcher, ForEachDescendantMatcher will match +/// for each descendant node that matches instead of only for the first. +template <typename T, typename DescendantT> +class ForEachDescendantMatcher : public WrapperMatcherInterface<T> { + static_assert(IsBaseType<DescendantT>::value, + "for each descendant only accepts base type matcher"); + +public: + explicit ForEachDescendantMatcher( + const Matcher<DescendantT> &DescendantMatcher) + : ForEachDescendantMatcher::WrapperMatcherInterface(DescendantMatcher) {} + + bool matches(const T &Node, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const override { + return Finder->matchesDescendantOf(Node, this->InnerMatcher, Builder, + ASTMatchFinder::BK_All); + } +}; + +/// \brief Matches on nodes that have a getValue() method if getValue() equals +/// the value the ValueEqualsMatcher was constructed with. +template <typename T, typename ValueT> +class ValueEqualsMatcher : public SingleNodeMatcherInterface<T> { + static_assert(std::is_base_of<CharacterLiteral, T>::value || + std::is_base_of<CXXBoolLiteralExpr, T>::value || + std::is_base_of<FloatingLiteral, T>::value || + std::is_base_of<IntegerLiteral, T>::value, + "the node must have a getValue method"); + +public: + explicit ValueEqualsMatcher(const ValueT &ExpectedValue) + : ExpectedValue(ExpectedValue) {} + + bool matchesNode(const T &Node) const override { + return Node.getValue() == ExpectedValue; + } + +private: + const ValueT ExpectedValue; +}; + +/// \brief Template specializations to easily write matchers for floating point +/// literals. +template <> +inline bool ValueEqualsMatcher<FloatingLiteral, double>::matchesNode( + const FloatingLiteral &Node) const { + if ((&Node.getSemantics()) == &llvm::APFloat::IEEEsingle) + return Node.getValue().convertToFloat() == ExpectedValue; + if ((&Node.getSemantics()) == &llvm::APFloat::IEEEdouble) + return Node.getValue().convertToDouble() == ExpectedValue; + return false; +} +template <> +inline bool ValueEqualsMatcher<FloatingLiteral, float>::matchesNode( + const FloatingLiteral &Node) const { + if ((&Node.getSemantics()) == &llvm::APFloat::IEEEsingle) + return Node.getValue().convertToFloat() == ExpectedValue; + if ((&Node.getSemantics()) == &llvm::APFloat::IEEEdouble) + return Node.getValue().convertToDouble() == ExpectedValue; + return false; +} +template <> +inline bool ValueEqualsMatcher<FloatingLiteral, llvm::APFloat>::matchesNode( + const FloatingLiteral &Node) const { + return ExpectedValue.compare(Node.getValue()) == llvm::APFloat::cmpEqual; +} + +/// \brief A VariadicDynCastAllOfMatcher<SourceT, TargetT> object is a +/// variadic functor that takes a number of Matcher<TargetT> and returns a +/// Matcher<SourceT> that matches TargetT nodes that are matched by all of the +/// given matchers, if SourceT can be dynamically casted into TargetT. +/// +/// For example: +/// const VariadicDynCastAllOfMatcher< +/// Decl, CXXRecordDecl> record; +/// Creates a functor record(...) that creates a Matcher<Decl> given +/// a variable number of arguments of type Matcher<CXXRecordDecl>. +/// The returned matcher matches if the given Decl can by dynamically +/// casted to CXXRecordDecl and all given matchers match. +template <typename SourceT, typename TargetT> +class VariadicDynCastAllOfMatcher + : public llvm::VariadicFunction< + BindableMatcher<SourceT>, Matcher<TargetT>, + makeDynCastAllOfComposite<SourceT, TargetT> > { +public: + VariadicDynCastAllOfMatcher() {} +}; + +/// \brief A \c VariadicAllOfMatcher<T> object is a variadic functor that takes +/// a number of \c Matcher<T> and returns a \c Matcher<T> that matches \c T +/// nodes that are matched by all of the given matchers. +/// +/// For example: +/// const VariadicAllOfMatcher<NestedNameSpecifier> nestedNameSpecifier; +/// Creates a functor nestedNameSpecifier(...) that creates a +/// \c Matcher<NestedNameSpecifier> given a variable number of arguments of type +/// \c Matcher<NestedNameSpecifier>. +/// The returned matcher matches if all given matchers match. +template <typename T> +class VariadicAllOfMatcher : public llvm::VariadicFunction< + BindableMatcher<T>, Matcher<T>, + makeAllOfComposite<T> > { +public: + VariadicAllOfMatcher() {} +}; + +/// \brief Matches nodes of type \c TLoc for which the inner +/// \c Matcher<T> matches. +template <typename TLoc, typename T> +class LocMatcher : public WrapperMatcherInterface<TLoc> { +public: + explicit LocMatcher(const Matcher<T> &InnerMatcher) + : LocMatcher::WrapperMatcherInterface(InnerMatcher) {} + + bool matches(const TLoc &Node, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const override { + if (!Node) + return false; + return this->InnerMatcher.matches(extract(Node), Finder, Builder); + } + +private: + static ast_type_traits::DynTypedNode + extract(const NestedNameSpecifierLoc &Loc) { + return ast_type_traits::DynTypedNode::create(*Loc.getNestedNameSpecifier()); + } +}; + +/// \brief Matches \c TypeLocs based on an inner matcher matching a certain +/// \c QualType. +/// +/// Used to implement the \c loc() matcher. +class TypeLocTypeMatcher : public WrapperMatcherInterface<TypeLoc> { +public: + explicit TypeLocTypeMatcher(const Matcher<QualType> &InnerMatcher) + : TypeLocTypeMatcher::WrapperMatcherInterface(InnerMatcher) {} + + bool matches(const TypeLoc &Node, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const override { + if (!Node) + return false; + return this->InnerMatcher.matches( + ast_type_traits::DynTypedNode::create(Node.getType()), Finder, Builder); + } +}; + +/// \brief Matches nodes of type \c T for which the inner matcher matches on a +/// another node of type \c T that can be reached using a given traverse +/// function. +template <typename T> +class TypeTraverseMatcher : public WrapperMatcherInterface<T> { +public: + explicit TypeTraverseMatcher(const Matcher<QualType> &InnerMatcher, + QualType (T::*TraverseFunction)() const) + : TypeTraverseMatcher::WrapperMatcherInterface(InnerMatcher), + TraverseFunction(TraverseFunction) {} + + bool matches(const T &Node, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const override { + QualType NextNode = (Node.*TraverseFunction)(); + if (NextNode.isNull()) + return false; + return this->InnerMatcher.matches( + ast_type_traits::DynTypedNode::create(NextNode), Finder, Builder); + } + +private: + QualType (T::*TraverseFunction)() const; +}; + +/// \brief Matches nodes of type \c T in a ..Loc hierarchy, for which the inner +/// matcher matches on a another node of type \c T that can be reached using a +/// given traverse function. +template <typename T> +class TypeLocTraverseMatcher : public WrapperMatcherInterface<T> { +public: + explicit TypeLocTraverseMatcher(const Matcher<TypeLoc> &InnerMatcher, + TypeLoc (T::*TraverseFunction)() const) + : TypeLocTraverseMatcher::WrapperMatcherInterface(InnerMatcher), + TraverseFunction(TraverseFunction) {} + + bool matches(const T &Node, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const override { + TypeLoc NextNode = (Node.*TraverseFunction)(); + if (!NextNode) + return false; + return this->InnerMatcher.matches( + ast_type_traits::DynTypedNode::create(NextNode), Finder, Builder); + } + +private: + TypeLoc (T::*TraverseFunction)() const; +}; + +/// \brief Converts a \c Matcher<InnerT> to a \c Matcher<OuterT>, where +/// \c OuterT is any type that is supported by \c Getter. +/// +/// \code Getter<OuterT>::value() \endcode returns a +/// \code InnerTBase (OuterT::*)() \endcode, which is used to adapt a \c OuterT +/// object into a \c InnerT +template <typename InnerTBase, + template <typename OuterT> class Getter, + template <typename OuterT> class MatcherImpl, + typename ReturnTypesF> +class TypeTraversePolymorphicMatcher { +private: + typedef TypeTraversePolymorphicMatcher<InnerTBase, Getter, MatcherImpl, + ReturnTypesF> Self; + static Self create(ArrayRef<const Matcher<InnerTBase> *> InnerMatchers); + +public: + typedef typename ExtractFunctionArgMeta<ReturnTypesF>::type ReturnTypes; + + explicit TypeTraversePolymorphicMatcher( + ArrayRef<const Matcher<InnerTBase> *> InnerMatchers) + : InnerMatcher(makeAllOfComposite(InnerMatchers)) {} + + template <typename OuterT> operator Matcher<OuterT>() const { + return Matcher<OuterT>( + new MatcherImpl<OuterT>(InnerMatcher, Getter<OuterT>::value())); + } + + struct Func : public llvm::VariadicFunction<Self, Matcher<InnerTBase>, + &Self::create> { + Func() {} + }; + +private: + const Matcher<InnerTBase> InnerMatcher; +}; + +/// \brief A simple memoizer of T(*)() functions. +/// +/// It will call the passed 'Func' template parameter at most once. +/// Used to support AST_MATCHER_FUNCTION() macro. +template <typename Matcher, Matcher (*Func)()> class MemoizedMatcher { + struct Wrapper { + Wrapper() : M(Func()) {} + Matcher M; + }; + +public: + static const Matcher &getInstance() { + static llvm::ManagedStatic<Wrapper> Instance; + return Instance->M; + } +}; + +// Define the create() method out of line to silence a GCC warning about +// the struct "Func" having greater visibility than its base, which comes from +// using the flag -fvisibility-inlines-hidden. +template <typename InnerTBase, template <typename OuterT> class Getter, + template <typename OuterT> class MatcherImpl, typename ReturnTypesF> +TypeTraversePolymorphicMatcher<InnerTBase, Getter, MatcherImpl, ReturnTypesF> +TypeTraversePolymorphicMatcher< + InnerTBase, Getter, MatcherImpl, + ReturnTypesF>::create(ArrayRef<const Matcher<InnerTBase> *> InnerMatchers) { + return Self(InnerMatchers); +} + +// FIXME: unify ClassTemplateSpecializationDecl and TemplateSpecializationType's +// APIs for accessing the template argument list. +inline ArrayRef<TemplateArgument> +getTemplateSpecializationArgs(const ClassTemplateSpecializationDecl &D) { + return D.getTemplateArgs().asArray(); +} + +inline ArrayRef<TemplateArgument> +getTemplateSpecializationArgs(const TemplateSpecializationType &T) { + return llvm::makeArrayRef(T.getArgs(), T.getNumArgs()); +} + +struct NotEqualsBoundNodePredicate { + bool operator()(const internal::BoundNodesMap &Nodes) const { + return Nodes.getNode(ID) != Node; + } + std::string ID; + ast_type_traits::DynTypedNode Node; +}; + +} // end namespace internal +} // end namespace ast_matchers +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/ASTMatchers/ASTMatchersMacros.h b/contrib/llvm/tools/clang/include/clang/ASTMatchers/ASTMatchersMacros.h new file mode 100644 index 0000000..8ad0c16 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/ASTMatchers/ASTMatchersMacros.h @@ -0,0 +1,404 @@ +//===--- ASTMatchersMacros.h - Structural query framework -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Defines macros that enable us to define new matchers in a single place. +// Since a matcher is a function which returns a Matcher<T> object, where +// T is the type of the actual implementation of the matcher, the macros allow +// us to write matchers like functions and take care of the definition of the +// class boilerplate. +// +// Note that when you define a matcher with an AST_MATCHER* macro, only the +// function which creates the matcher goes into the current namespace - the +// class that implements the actual matcher, which gets returned by the +// generator function, is put into the 'internal' namespace. This allows us +// to only have the functions (which is all the user cares about) in the +// 'ast_matchers' namespace and hide the boilerplate. +// +// To define a matcher in user code, put it into your own namespace. This would +// help to prevent ODR violations in case a matcher with the same name is +// defined in multiple translation units: +// +// namespace my_matchers { +// AST_MATCHER_P(clang::MemberExpr, Member, +// clang::ast_matchers::internal::Matcher<clang::ValueDecl>, +// InnerMatcher) { +// return InnerMatcher.matches(*Node.getMemberDecl(), Finder, Builder); +// } +// } // namespace my_matchers +// +// Alternatively, an unnamed namespace may be used: +// +// namespace clang { +// namespace ast_matchers { +// namespace { +// AST_MATCHER_P(MemberExpr, Member, +// internal::Matcher<ValueDecl>, InnerMatcher) { +// return InnerMatcher.matches(*Node.getMemberDecl(), Finder, Builder); +// } +// } // namespace +// } // namespace ast_matchers +// } // namespace clang +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ASTMATCHERS_ASTMATCHERSMACROS_H +#define LLVM_CLANG_ASTMATCHERS_ASTMATCHERSMACROS_H + +/// \brief AST_MATCHER_FUNCTION(ReturnType, DefineMatcher) { ... } +/// defines a zero parameter function named DefineMatcher() that returns a +/// ReturnType object. +#define AST_MATCHER_FUNCTION(ReturnType, DefineMatcher) \ + inline ReturnType DefineMatcher##_getInstance(); \ + inline ReturnType DefineMatcher() { \ + return ::clang::ast_matchers::internal::MemoizedMatcher< \ + ReturnType, DefineMatcher##_getInstance>::getInstance(); \ + } \ + inline ReturnType DefineMatcher##_getInstance() + +/// \brief AST_MATCHER_FUNCTION_P(ReturnType, DefineMatcher, ParamType, Param) { +/// ... } +/// defines a single-parameter function named DefineMatcher() that returns a +/// ReturnType object. +/// +/// The code between the curly braces has access to the following variables: +/// +/// Param: the parameter passed to the function; its type +/// is ParamType. +/// +/// The code should return an instance of ReturnType. +#define AST_MATCHER_FUNCTION_P(ReturnType, DefineMatcher, ParamType, Param) \ + AST_MATCHER_FUNCTION_P_OVERLOAD(ReturnType, DefineMatcher, ParamType, Param, \ + 0) +#define AST_MATCHER_FUNCTION_P_OVERLOAD(ReturnType, DefineMatcher, ParamType, \ + Param, OverloadId) \ + inline ReturnType DefineMatcher(ParamType const &Param); \ + typedef ReturnType (&DefineMatcher##_Type##OverloadId)(ParamType const &); \ + inline ReturnType DefineMatcher(ParamType const &Param) + +/// \brief AST_MATCHER(Type, DefineMatcher) { ... } +/// defines a zero parameter function named DefineMatcher() that returns a +/// Matcher<Type> object. +/// +/// The code between the curly braces has access to the following variables: +/// +/// Node: the AST node being matched; its type is Type. +/// Finder: an ASTMatchFinder*. +/// Builder: a BoundNodesTreeBuilder*. +/// +/// The code should return true if 'Node' matches. +#define AST_MATCHER(Type, DefineMatcher) \ + namespace internal { \ + class matcher_##DefineMatcher##Matcher \ + : public ::clang::ast_matchers::internal::MatcherInterface<Type> { \ + public: \ + explicit matcher_##DefineMatcher##Matcher() {} \ + bool matches(const Type &Node, \ + ::clang::ast_matchers::internal::ASTMatchFinder *Finder, \ + ::clang::ast_matchers::internal::BoundNodesTreeBuilder \ + *Builder) const override; \ + }; \ + } \ + inline ::clang::ast_matchers::internal::Matcher<Type> DefineMatcher() { \ + return ::clang::ast_matchers::internal::makeMatcher( \ + new internal::matcher_##DefineMatcher##Matcher()); \ + } \ + inline bool internal::matcher_##DefineMatcher##Matcher::matches( \ + const Type &Node, \ + ::clang::ast_matchers::internal::ASTMatchFinder *Finder, \ + ::clang::ast_matchers::internal::BoundNodesTreeBuilder *Builder) const + +/// \brief AST_MATCHER_P(Type, DefineMatcher, ParamType, Param) { ... } +/// defines a single-parameter function named DefineMatcher() that returns a +/// Matcher<Type> object. +/// +/// The code between the curly braces has access to the following variables: +/// +/// Node: the AST node being matched; its type is Type. +/// Param: the parameter passed to the function; its type +/// is ParamType. +/// Finder: an ASTMatchFinder*. +/// Builder: a BoundNodesTreeBuilder*. +/// +/// The code should return true if 'Node' matches. +#define AST_MATCHER_P(Type, DefineMatcher, ParamType, Param) \ + AST_MATCHER_P_OVERLOAD(Type, DefineMatcher, ParamType, Param, 0) + +#define AST_MATCHER_P_OVERLOAD(Type, DefineMatcher, ParamType, Param, \ + OverloadId) \ + namespace internal { \ + class matcher_##DefineMatcher##OverloadId##Matcher \ + : public ::clang::ast_matchers::internal::MatcherInterface<Type> { \ + public: \ + explicit matcher_##DefineMatcher##OverloadId##Matcher( \ + ParamType const &A##Param) \ + : Param(A##Param) {} \ + bool matches(const Type &Node, \ + ::clang::ast_matchers::internal::ASTMatchFinder *Finder, \ + ::clang::ast_matchers::internal::BoundNodesTreeBuilder \ + *Builder) const override; \ + \ + private: \ + ParamType const Param; \ + }; \ + } \ + inline ::clang::ast_matchers::internal::Matcher<Type> DefineMatcher( \ + ParamType const &Param) { \ + return ::clang::ast_matchers::internal::makeMatcher( \ + new internal::matcher_##DefineMatcher##OverloadId##Matcher(Param)); \ + } \ + typedef ::clang::ast_matchers::internal::Matcher<Type>( \ + &DefineMatcher##_Type##OverloadId)(ParamType const &Param); \ + inline bool internal::matcher_##DefineMatcher##OverloadId##Matcher::matches( \ + const Type &Node, \ + ::clang::ast_matchers::internal::ASTMatchFinder *Finder, \ + ::clang::ast_matchers::internal::BoundNodesTreeBuilder *Builder) const + +/// \brief AST_MATCHER_P2( +/// Type, DefineMatcher, ParamType1, Param1, ParamType2, Param2) { ... } +/// defines a two-parameter function named DefineMatcher() that returns a +/// Matcher<Type> object. +/// +/// The code between the curly braces has access to the following variables: +/// +/// Node: the AST node being matched; its type is Type. +/// Param1, Param2: the parameters passed to the function; their types +/// are ParamType1 and ParamType2. +/// Finder: an ASTMatchFinder*. +/// Builder: a BoundNodesTreeBuilder*. +/// +/// The code should return true if 'Node' matches. +#define AST_MATCHER_P2(Type, DefineMatcher, ParamType1, Param1, ParamType2, \ + Param2) \ + AST_MATCHER_P2_OVERLOAD(Type, DefineMatcher, ParamType1, Param1, ParamType2, \ + Param2, 0) + +#define AST_MATCHER_P2_OVERLOAD(Type, DefineMatcher, ParamType1, Param1, \ + ParamType2, Param2, OverloadId) \ + namespace internal { \ + class matcher_##DefineMatcher##OverloadId##Matcher \ + : public ::clang::ast_matchers::internal::MatcherInterface<Type> { \ + public: \ + matcher_##DefineMatcher##OverloadId##Matcher(ParamType1 const &A##Param1, \ + ParamType2 const &A##Param2) \ + : Param1(A##Param1), Param2(A##Param2) {} \ + bool matches(const Type &Node, \ + ::clang::ast_matchers::internal::ASTMatchFinder *Finder, \ + ::clang::ast_matchers::internal::BoundNodesTreeBuilder \ + *Builder) const override; \ + \ + private: \ + ParamType1 const Param1; \ + ParamType2 const Param2; \ + }; \ + } \ + inline ::clang::ast_matchers::internal::Matcher<Type> DefineMatcher( \ + ParamType1 const &Param1, ParamType2 const &Param2) { \ + return ::clang::ast_matchers::internal::makeMatcher( \ + new internal::matcher_##DefineMatcher##OverloadId##Matcher(Param1, \ + Param2)); \ + } \ + typedef ::clang::ast_matchers::internal::Matcher<Type>( \ + &DefineMatcher##_Type##OverloadId)(ParamType1 const &Param1, \ + ParamType2 const &Param2); \ + inline bool internal::matcher_##DefineMatcher##OverloadId##Matcher::matches( \ + const Type &Node, \ + ::clang::ast_matchers::internal::ASTMatchFinder *Finder, \ + ::clang::ast_matchers::internal::BoundNodesTreeBuilder *Builder) const + +/// \brief Construct a type-list to be passed to the AST_POLYMORPHIC_MATCHER* +/// macros. +/// +/// You can't pass something like \c TypeList<Foo, Bar> to a macro, because it +/// will look at that as two arguments. However, you can pass +/// \c void(TypeList<Foo, Bar>), which works thanks to the parenthesis. +/// The \c PolymorphicMatcherWithParam* classes will unpack the function type to +/// extract the TypeList object. +#define AST_POLYMORPHIC_SUPPORTED_TYPES(...) \ + void(::clang::ast_matchers::internal::TypeList<__VA_ARGS__>) + +/// \brief AST_POLYMORPHIC_MATCHER(DefineMatcher) { ... } +/// defines a single-parameter function named DefineMatcher() that is +/// polymorphic in the return type. +/// +/// The variables are the same as for AST_MATCHER, but NodeType will be deduced +/// from the calling context. +#define AST_POLYMORPHIC_MATCHER(DefineMatcher, ReturnTypesF) \ + namespace internal { \ + template <typename NodeType> \ + class matcher_##DefineMatcher##Matcher \ + : public ::clang::ast_matchers::internal::MatcherInterface<NodeType> { \ + public: \ + bool matches(const NodeType &Node, \ + ::clang::ast_matchers::internal::ASTMatchFinder *Finder, \ + ::clang::ast_matchers::internal::BoundNodesTreeBuilder \ + *Builder) const override; \ + }; \ + } \ + inline ::clang::ast_matchers::internal::PolymorphicMatcherWithParam0< \ + internal::matcher_##DefineMatcher##Matcher, ReturnTypesF> \ + DefineMatcher() { \ + return ::clang::ast_matchers::internal::PolymorphicMatcherWithParam0< \ + internal::matcher_##DefineMatcher##Matcher, ReturnTypesF>(); \ + } \ + template <typename NodeType> \ + bool internal::matcher_##DefineMatcher##Matcher<NodeType>::matches( \ + const NodeType &Node, \ + ::clang::ast_matchers::internal::ASTMatchFinder *Finder, \ + ::clang::ast_matchers::internal::BoundNodesTreeBuilder *Builder) const + +/// \brief AST_POLYMORPHIC_MATCHER_P(DefineMatcher, ParamType, Param) { ... } +/// defines a single-parameter function named DefineMatcher() that is +/// polymorphic in the return type. +/// +/// The variables are the same as for +/// AST_MATCHER_P, with the addition of NodeType, which specifies the node type +/// of the matcher Matcher<NodeType> returned by the function matcher(). +/// +/// FIXME: Pull out common code with above macro? +#define AST_POLYMORPHIC_MATCHER_P(DefineMatcher, ReturnTypesF, ParamType, \ + Param) \ + AST_POLYMORPHIC_MATCHER_P_OVERLOAD(DefineMatcher, ReturnTypesF, ParamType, \ + Param, 0) + +#define AST_POLYMORPHIC_MATCHER_P_OVERLOAD(DefineMatcher, ReturnTypesF, \ + ParamType, Param, OverloadId) \ + namespace internal { \ + template <typename NodeType, typename ParamT> \ + class matcher_##DefineMatcher##OverloadId##Matcher \ + : public ::clang::ast_matchers::internal::MatcherInterface<NodeType> { \ + public: \ + explicit matcher_##DefineMatcher##OverloadId##Matcher( \ + ParamType const &A##Param) \ + : Param(A##Param) {} \ + bool matches(const NodeType &Node, \ + ::clang::ast_matchers::internal::ASTMatchFinder *Finder, \ + ::clang::ast_matchers::internal::BoundNodesTreeBuilder \ + *Builder) const override; \ + \ + private: \ + ParamType const Param; \ + }; \ + } \ + inline ::clang::ast_matchers::internal::PolymorphicMatcherWithParam1< \ + internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType, \ + ReturnTypesF> \ + DefineMatcher(ParamType const &Param) { \ + return ::clang::ast_matchers::internal::PolymorphicMatcherWithParam1< \ + internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType, \ + ReturnTypesF>(Param); \ + } \ + typedef ::clang::ast_matchers::internal::PolymorphicMatcherWithParam1< \ + internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType, \ + ReturnTypesF>(&DefineMatcher##_Type##OverloadId)( \ + ParamType const &Param); \ + template <typename NodeType, typename ParamT> \ + bool internal:: \ + matcher_##DefineMatcher##OverloadId##Matcher<NodeType, ParamT>::matches( \ + const NodeType &Node, \ + ::clang::ast_matchers::internal::ASTMatchFinder *Finder, \ + ::clang::ast_matchers::internal::BoundNodesTreeBuilder *Builder) \ + const + +/// \brief AST_POLYMORPHIC_MATCHER_P2( +/// DefineMatcher, ParamType1, Param1, ParamType2, Param2) { ... } +/// defines a two-parameter function named matcher() that is polymorphic in +/// the return type. +/// +/// The variables are the same as for AST_MATCHER_P2, with the +/// addition of NodeType, which specifies the node type of the matcher +/// Matcher<NodeType> returned by the function DefineMatcher(). +#define AST_POLYMORPHIC_MATCHER_P2(DefineMatcher, ReturnTypesF, ParamType1, \ + Param1, ParamType2, Param2) \ + AST_POLYMORPHIC_MATCHER_P2_OVERLOAD(DefineMatcher, ReturnTypesF, ParamType1, \ + Param1, ParamType2, Param2, 0) + +#define AST_POLYMORPHIC_MATCHER_P2_OVERLOAD(DefineMatcher, ReturnTypesF, \ + ParamType1, Param1, ParamType2, \ + Param2, OverloadId) \ + namespace internal { \ + template <typename NodeType, typename ParamT1, typename ParamT2> \ + class matcher_##DefineMatcher##OverloadId##Matcher \ + : public ::clang::ast_matchers::internal::MatcherInterface<NodeType> { \ + public: \ + matcher_##DefineMatcher##OverloadId##Matcher(ParamType1 const &A##Param1, \ + ParamType2 const &A##Param2) \ + : Param1(A##Param1), Param2(A##Param2) {} \ + bool matches(const NodeType &Node, \ + ::clang::ast_matchers::internal::ASTMatchFinder *Finder, \ + ::clang::ast_matchers::internal::BoundNodesTreeBuilder \ + *Builder) const override; \ + \ + private: \ + ParamType1 const Param1; \ + ParamType2 const Param2; \ + }; \ + } \ + inline ::clang::ast_matchers::internal::PolymorphicMatcherWithParam2< \ + internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType1, \ + ParamType2, ReturnTypesF> \ + DefineMatcher(ParamType1 const &Param1, ParamType2 const &Param2) { \ + return ::clang::ast_matchers::internal::PolymorphicMatcherWithParam2< \ + internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType1, \ + ParamType2, ReturnTypesF>(Param1, Param2); \ + } \ + typedef ::clang::ast_matchers::internal::PolymorphicMatcherWithParam2< \ + internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType1, \ + ParamType2, ReturnTypesF>(&DefineMatcher##_Type##OverloadId)( \ + ParamType1 const &Param1, ParamType2 const &Param2); \ + template <typename NodeType, typename ParamT1, typename ParamT2> \ + bool internal::matcher_##DefineMatcher##OverloadId##Matcher< \ + NodeType, ParamT1, ParamT2>:: \ + matches(const NodeType &Node, \ + ::clang::ast_matchers::internal::ASTMatchFinder *Finder, \ + ::clang::ast_matchers::internal::BoundNodesTreeBuilder *Builder) \ + const + +/// \brief Creates a variadic matcher for both a specific \c Type as well as +/// the corresponding \c TypeLoc. +#define AST_TYPE_MATCHER(NodeType, MatcherName) \ + const ::clang::ast_matchers::internal::VariadicDynCastAllOfMatcher< \ + Type, NodeType> MatcherName +// FIXME: add a matcher for TypeLoc derived classes using its custom casting +// API (no longer dyn_cast) if/when we need such matching + +/// \brief AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName) defines +/// the matcher \c MatcherName that can be used to traverse from one \c Type +/// to another. +/// +/// For a specific \c SpecificType, the traversal is done using +/// \c SpecificType::FunctionName. The existence of such a function determines +/// whether a corresponding matcher can be used on \c SpecificType. +#define AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName, ReturnTypesF) \ + namespace internal { \ + template <typename T> struct TypeMatcher##MatcherName##Getter { \ + static QualType (T::*value())() const { return &T::FunctionName; } \ + }; \ + } \ + const ::clang::ast_matchers::internal::TypeTraversePolymorphicMatcher< \ + QualType, \ + ::clang::ast_matchers::internal::TypeMatcher##MatcherName##Getter, \ + ::clang::ast_matchers::internal::TypeTraverseMatcher, \ + ReturnTypesF>::Func MatcherName + +/// \brief AST_TYPELOC_TRAVERSE_MATCHER(MatcherName, FunctionName) works +/// identical to \c AST_TYPE_TRAVERSE_MATCHER but operates on \c TypeLocs. +#define AST_TYPELOC_TRAVERSE_MATCHER(MatcherName, FunctionName, ReturnTypesF) \ + namespace internal { \ + template <typename T> struct TypeLocMatcher##MatcherName##Getter { \ + static TypeLoc (T::*value())() const { return &T::FunctionName##Loc; } \ + }; \ + } \ + const ::clang::ast_matchers::internal::TypeTraversePolymorphicMatcher< \ + TypeLoc, \ + ::clang::ast_matchers::internal::TypeLocMatcher##MatcherName##Getter, \ + ::clang::ast_matchers::internal::TypeLocTraverseMatcher, \ + ReturnTypesF>::Func MatcherName##Loc; \ + AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName##Type, ReturnTypesF) + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/Diagnostics.h b/contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/Diagnostics.h new file mode 100644 index 0000000..2c76dda --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/Diagnostics.h @@ -0,0 +1,185 @@ +//===--- Diagnostics.h - Helper class for error diagnostics -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Diagnostics class to manage error messages. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_DIAGNOSTICS_H +#define LLVM_CLANG_ASTMATCHERS_DYNAMIC_DIAGNOSTICS_H + +#include "clang/ASTMatchers/Dynamic/VariantValue.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/raw_ostream.h" +#include <string> +#include <vector> + +namespace clang { +namespace ast_matchers { +namespace dynamic { + +struct SourceLocation { + SourceLocation() : Line(), Column() {} + unsigned Line; + unsigned Column; +}; + +struct SourceRange { + SourceLocation Start; + SourceLocation End; +}; + +/// \brief A VariantValue instance annotated with its parser context. +struct ParserValue { + ParserValue() : Text(), Range(), Value() {} + StringRef Text; + SourceRange Range; + VariantValue Value; +}; + +/// \brief Helper class to manage error messages. +class Diagnostics { +public: + /// \brief Parser context types. + enum ContextType { + CT_MatcherArg = 0, + CT_MatcherConstruct = 1 + }; + + /// \brief All errors from the system. + enum ErrorType { + ET_None = 0, + + ET_RegistryMatcherNotFound = 1, + ET_RegistryWrongArgCount = 2, + ET_RegistryWrongArgType = 3, + ET_RegistryNotBindable = 4, + ET_RegistryAmbiguousOverload = 5, + ET_RegistryValueNotFound = 6, + + ET_ParserStringError = 100, + ET_ParserNoOpenParen = 101, + ET_ParserNoCloseParen = 102, + ET_ParserNoComma = 103, + ET_ParserNoCode = 104, + ET_ParserNotAMatcher = 105, + ET_ParserInvalidToken = 106, + ET_ParserMalformedBindExpr = 107, + ET_ParserTrailingCode = 108, + ET_ParserUnsignedError = 109, + ET_ParserOverloadedType = 110 + }; + + /// \brief Helper stream class. + class ArgStream { + public: + ArgStream(std::vector<std::string> *Out) : Out(Out) {} + template <class T> ArgStream &operator<<(const T &Arg) { + return operator<<(Twine(Arg)); + } + ArgStream &operator<<(const Twine &Arg); + + private: + std::vector<std::string> *Out; + }; + + /// \brief Class defining a parser context. + /// + /// Used by the parser to specify (possibly recursive) contexts where the + /// parsing/construction can fail. Any error triggered within a context will + /// keep information about the context chain. + /// This class should be used as a RAII instance in the stack. + struct Context { + public: + /// \brief About to call the constructor for a matcher. + enum ConstructMatcherEnum { ConstructMatcher }; + Context(ConstructMatcherEnum, Diagnostics *Error, StringRef MatcherName, + SourceRange MatcherRange); + /// \brief About to recurse into parsing one argument for a matcher. + enum MatcherArgEnum { MatcherArg }; + Context(MatcherArgEnum, Diagnostics *Error, StringRef MatcherName, + SourceRange MatcherRange, unsigned ArgNumber); + ~Context(); + + private: + Diagnostics *const Error; + }; + + /// \brief Context for overloaded matcher construction. + /// + /// This context will take care of merging all errors that happen within it + /// as "candidate" overloads for the same matcher. + struct OverloadContext { + public: + OverloadContext(Diagnostics* Error); + ~OverloadContext(); + + /// \brief Revert all errors that happened within this context. + void revertErrors(); + + private: + Diagnostics *const Error; + unsigned BeginIndex; + }; + + /// \brief Add an error to the diagnostics. + /// + /// All the context information will be kept on the error message. + /// \return a helper class to allow the caller to pass the arguments for the + /// error message, using the << operator. + ArgStream addError(SourceRange Range, ErrorType Error); + + /// \brief Information stored for one frame of the context. + struct ContextFrame { + ContextType Type; + SourceRange Range; + std::vector<std::string> Args; + }; + + /// \brief Information stored for each error found. + struct ErrorContent { + std::vector<ContextFrame> ContextStack; + struct Message { + SourceRange Range; + ErrorType Type; + std::vector<std::string> Args; + }; + std::vector<Message> Messages; + }; + ArrayRef<ErrorContent> errors() const { return Errors; } + + /// \brief Returns a simple string representation of each error. + /// + /// Each error only shows the error message without any context. + void printToStream(llvm::raw_ostream &OS) const; + std::string toString() const; + + /// \brief Returns the full string representation of each error. + /// + /// Each error message contains the full context. + void printToStreamFull(llvm::raw_ostream &OS) const; + std::string toStringFull() const; + +private: + /// \brief Helper function used by the constructors of ContextFrame. + ArgStream pushContextFrame(ContextType Type, SourceRange Range); + + std::vector<ContextFrame> ContextStack; + std::vector<ErrorContent> Errors; +}; + +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang + +#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_DIAGNOSTICS_H diff --git a/contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/Parser.h b/contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/Parser.h new file mode 100644 index 0000000..76926f0 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/Parser.h @@ -0,0 +1,257 @@ +//===--- Parser.h - Matcher expression parser -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Simple matcher expression parser. +/// +/// The parser understands matcher expressions of the form: +/// MatcherName(Arg0, Arg1, ..., ArgN) +/// as well as simple types like strings. +/// The parser does not know how to process the matchers. It delegates this task +/// to a Sema object received as an argument. +/// +/// \code +/// Grammar for the expressions supported: +/// <Expression> := <Literal> | <NamedValue> | <MatcherExpression> +/// <Literal> := <StringLiteral> | <Unsigned> +/// <StringLiteral> := "quoted string" +/// <Unsigned> := [0-9]+ +/// <NamedValue> := <Identifier> +/// <MatcherExpression> := <Identifier>(<ArgumentList>) | +/// <Identifier>(<ArgumentList>).bind(<StringLiteral>) +/// <Identifier> := [a-zA-Z]+ +/// <ArgumentList> := <Expression> | <Expression>,<ArgumentList> +/// \endcode +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_PARSER_H +#define LLVM_CLANG_ASTMATCHERS_DYNAMIC_PARSER_H + +#include "clang/ASTMatchers/Dynamic/Diagnostics.h" +#include "clang/ASTMatchers/Dynamic/Registry.h" +#include "clang/ASTMatchers/Dynamic/VariantValue.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { +namespace ast_matchers { +namespace dynamic { + +/// \brief Matcher expression parser. +class Parser { +public: + /// \brief Interface to connect the parser with the registry and more. + /// + /// The parser uses the Sema instance passed into + /// parseMatcherExpression() to handle all matcher tokens. The simplest + /// processor implementation would simply call into the registry to create + /// the matchers. + /// However, a more complex processor might decide to intercept the matcher + /// creation and do some extra work. For example, it could apply some + /// transformation to the matcher by adding some id() nodes, or could detect + /// specific matcher nodes for more efficient lookup. + class Sema { + public: + virtual ~Sema(); + + /// \brief Process a matcher expression. + /// + /// All the arguments passed here have already been processed. + /// + /// \param Ctor A matcher constructor looked up by lookupMatcherCtor. + /// + /// \param NameRange The location of the name in the matcher source. + /// Useful for error reporting. + /// + /// \param BindID The ID to use to bind the matcher, or a null \c StringRef + /// if no ID is specified. + /// + /// \param Args The argument list for the matcher. + /// + /// \return The matcher objects constructed by the processor, or a null + /// matcher if an error occurred. In that case, \c Error will contain a + /// description of the error. + virtual VariantMatcher actOnMatcherExpression(MatcherCtor Ctor, + SourceRange NameRange, + StringRef BindID, + ArrayRef<ParserValue> Args, + Diagnostics *Error) = 0; + + /// \brief Look up a matcher by name. + /// + /// \param MatcherName The matcher name found by the parser. + /// + /// \return The matcher constructor, or Optional<MatcherCtor>() if not + /// found. + virtual llvm::Optional<MatcherCtor> + lookupMatcherCtor(StringRef MatcherName) = 0; + + /// \brief Compute the list of completion types for \p Context. + /// + /// Each element of \p Context represents a matcher invocation, going from + /// outermost to innermost. Elements are pairs consisting of a reference to + /// the matcher constructor and the index of the next element in the + /// argument list of that matcher (or for the last element, the index of + /// the completion point in the argument list). An empty list requests + /// completion for the root matcher. + virtual std::vector<ArgKind> getAcceptedCompletionTypes( + llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> Context); + + /// \brief Compute the list of completions that match any of + /// \p AcceptedTypes. + /// + /// \param AcceptedTypes All types accepted for this completion. + /// + /// \return All completions for the specified types. + /// Completions should be valid when used in \c lookupMatcherCtor(). + /// The matcher constructed from the return of \c lookupMatcherCtor() + /// should be convertible to some type in \p AcceptedTypes. + virtual std::vector<MatcherCompletion> + getMatcherCompletions(llvm::ArrayRef<ArgKind> AcceptedTypes); + }; + + /// \brief Sema implementation that uses the matcher registry to process the + /// tokens. + class RegistrySema : public Parser::Sema { + public: + ~RegistrySema() override; + + llvm::Optional<MatcherCtor> + lookupMatcherCtor(StringRef MatcherName) override; + + VariantMatcher actOnMatcherExpression(MatcherCtor Ctor, + SourceRange NameRange, + StringRef BindID, + ArrayRef<ParserValue> Args, + Diagnostics *Error) override; + + std::vector<ArgKind> getAcceptedCompletionTypes( + llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> Context) override; + + std::vector<MatcherCompletion> + getMatcherCompletions(llvm::ArrayRef<ArgKind> AcceptedTypes) override; + }; + + typedef llvm::StringMap<VariantValue> NamedValueMap; + + /// \brief Parse a matcher expression. + /// + /// \param MatcherCode The matcher expression to parse. + /// + /// \param S The Sema instance that will help the parser + /// construct the matchers. If null, it uses the default registry. + /// + /// \param NamedValues A map of precomputed named values. This provides + /// the dictionary for the <NamedValue> rule of the grammar. + /// If null, it is ignored. + /// + /// \return The matcher object constructed by the processor, or an empty + /// Optional if an error occurred. In that case, \c Error will contain a + /// description of the error. + /// The caller takes ownership of the DynTypedMatcher object returned. + static llvm::Optional<DynTypedMatcher> + parseMatcherExpression(StringRef MatcherCode, Sema *S, + const NamedValueMap *NamedValues, + Diagnostics *Error); + static llvm::Optional<DynTypedMatcher> + parseMatcherExpression(StringRef MatcherCode, Sema *S, + Diagnostics *Error) { + return parseMatcherExpression(MatcherCode, S, nullptr, Error); + } + static llvm::Optional<DynTypedMatcher> + parseMatcherExpression(StringRef MatcherCode, Diagnostics *Error) { + return parseMatcherExpression(MatcherCode, nullptr, Error); + } + + /// \brief Parse an expression. + /// + /// Parses any expression supported by this parser. In general, the + /// \c parseMatcherExpression function is a better approach to get a matcher + /// object. + /// + /// \param S The Sema instance that will help the parser + /// construct the matchers. If null, it uses the default registry. + /// + /// \param NamedValues A map of precomputed named values. This provides + /// the dictionary for the <NamedValue> rule of the grammar. + /// If null, it is ignored. + static bool parseExpression(StringRef Code, Sema *S, + const NamedValueMap *NamedValues, + VariantValue *Value, Diagnostics *Error); + static bool parseExpression(StringRef Code, Sema *S, + VariantValue *Value, Diagnostics *Error) { + return parseExpression(Code, S, nullptr, Value, Error); + } + static bool parseExpression(StringRef Code, VariantValue *Value, + Diagnostics *Error) { + return parseExpression(Code, nullptr, Value, Error); + } + + /// \brief Complete an expression at the given offset. + /// + /// \param S The Sema instance that will help the parser + /// construct the matchers. If null, it uses the default registry. + /// + /// \param NamedValues A map of precomputed named values. This provides + /// the dictionary for the <NamedValue> rule of the grammar. + /// If null, it is ignored. + /// + /// \return The list of completions, which may be empty if there are no + /// available completions or if an error occurred. + static std::vector<MatcherCompletion> + completeExpression(StringRef Code, unsigned CompletionOffset, Sema *S, + const NamedValueMap *NamedValues); + static std::vector<MatcherCompletion> + completeExpression(StringRef Code, unsigned CompletionOffset, Sema *S) { + return completeExpression(Code, CompletionOffset, S, nullptr); + } + static std::vector<MatcherCompletion> + completeExpression(StringRef Code, unsigned CompletionOffset) { + return completeExpression(Code, CompletionOffset, nullptr); + } + +private: + class CodeTokenizer; + struct ScopedContextEntry; + struct TokenInfo; + + Parser(CodeTokenizer *Tokenizer, Sema *S, + const NamedValueMap *NamedValues, + Diagnostics *Error); + + bool parseExpressionImpl(VariantValue *Value); + bool parseMatcherExpressionImpl(const TokenInfo &NameToken, + VariantValue *Value); + bool parseIdentifierPrefixImpl(VariantValue *Value); + + void addCompletion(const TokenInfo &CompToken, + const MatcherCompletion &Completion); + void addExpressionCompletions(); + + std::vector<MatcherCompletion> + getNamedValueCompletions(ArrayRef<ArgKind> AcceptedTypes); + + CodeTokenizer *const Tokenizer; + Sema *const S; + const NamedValueMap *const NamedValues; + Diagnostics *const Error; + + typedef std::vector<std::pair<MatcherCtor, unsigned> > ContextStackTy; + ContextStackTy ContextStack; + std::vector<MatcherCompletion> Completions; +}; + +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang + +#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_PARSER_H diff --git a/contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/Registry.h b/contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/Registry.h new file mode 100644 index 0000000..3808adb --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/Registry.h @@ -0,0 +1,133 @@ +//===--- Registry.h - Matcher registry -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Registry of all known matchers. +/// +/// The registry provides a generic interface to construct any matcher by name. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_REGISTRY_H +#define LLVM_CLANG_ASTMATCHERS_DYNAMIC_REGISTRY_H + +#include "clang/ASTMatchers/Dynamic/Diagnostics.h" +#include "clang/ASTMatchers/Dynamic/VariantValue.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { +namespace ast_matchers { +namespace dynamic { + +namespace internal { +class MatcherDescriptor; +} + +typedef const internal::MatcherDescriptor *MatcherCtor; + +struct MatcherCompletion { + MatcherCompletion() {} + MatcherCompletion(StringRef TypedText, StringRef MatcherDecl, + unsigned Specificity) + : TypedText(TypedText), MatcherDecl(MatcherDecl), + Specificity(Specificity) {} + + /// \brief The text to type to select this matcher. + std::string TypedText; + + /// \brief The "declaration" of the matcher, with type information. + std::string MatcherDecl; + + /// \brief Value corresponding to the "specificity" of the converted matcher. + /// + /// Zero specificity indicates that this conversion would produce a trivial + /// matcher that will either always or never match. + /// Such matchers are excluded from code completion results. + unsigned Specificity; + + bool operator==(const MatcherCompletion &Other) const { + return TypedText == Other.TypedText && MatcherDecl == Other.MatcherDecl; + } +}; + +class Registry { +public: + /// \brief Look up a matcher in the registry by name, + /// + /// \return An opaque value which may be used to refer to the matcher + /// constructor, or Optional<MatcherCtor>() if not found. + static llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName); + + /// \brief Compute the list of completion types for \p Context. + /// + /// Each element of \p Context represents a matcher invocation, going from + /// outermost to innermost. Elements are pairs consisting of a reference to + /// the matcher constructor and the index of the next element in the + /// argument list of that matcher (or for the last element, the index of + /// the completion point in the argument list). An empty list requests + /// completion for the root matcher. + static std::vector<ArgKind> getAcceptedCompletionTypes( + llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> Context); + + /// \brief Compute the list of completions that match any of + /// \p AcceptedTypes. + /// + /// \param AcceptedTypes All types accepted for this completion. + /// + /// \return All completions for the specified types. + /// Completions should be valid when used in \c lookupMatcherCtor(). + /// The matcher constructed from the return of \c lookupMatcherCtor() + /// should be convertible to some type in \p AcceptedTypes. + static std::vector<MatcherCompletion> + getMatcherCompletions(ArrayRef<ArgKind> AcceptedTypes); + + /// \brief Construct a matcher from the registry. + /// + /// \param Ctor The matcher constructor to instantiate. + /// + /// \param NameRange The location of the name in the matcher source. + /// Useful for error reporting. + /// + /// \param Args The argument list for the matcher. The number and types of the + /// values must be valid for the matcher requested. Otherwise, the function + /// will return an error. + /// + /// \return The matcher object constructed if no error was found. + /// A null matcher if the number of arguments or argument types do not match + /// the signature. In that case \c Error will contain the description of + /// the error. + static VariantMatcher constructMatcher(MatcherCtor Ctor, + SourceRange NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error); + + /// \brief Construct a matcher from the registry and bind it. + /// + /// Similar the \c constructMatcher() above, but it then tries to bind the + /// matcher to the specified \c BindID. + /// If the matcher is not bindable, it sets an error in \c Error and returns + /// a null matcher. + static VariantMatcher constructBoundMatcher(MatcherCtor Ctor, + SourceRange NameRange, + StringRef BindID, + ArrayRef<ParserValue> Args, + Diagnostics *Error); + +private: + Registry() = delete; +}; + +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang + +#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_REGISTRY_H diff --git a/contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/VariantValue.h b/contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/VariantValue.h new file mode 100644 index 0000000..c391b24 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/VariantValue.h @@ -0,0 +1,326 @@ +//===--- VariantValue.h - Polymorphic value type -*- C++ -*-===/ +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Polymorphic value type. +/// +/// Supports all the types required for dynamic Matcher construction. +/// Used by the registry to construct matchers in a generic way. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_VARIANTVALUE_H +#define LLVM_CLANG_ASTMATCHERS_DYNAMIC_VARIANTVALUE_H + +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/ASTMatchers/ASTMatchersInternal.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/Twine.h" +#include <memory> +#include <vector> + +namespace clang { +namespace ast_matchers { +namespace dynamic { + +/// \brief Kind identifier. +/// +/// It supports all types that VariantValue can contain. +class ArgKind { + public: + enum Kind { + AK_Matcher, + AK_Unsigned, + AK_String + }; + /// \brief Constructor for non-matcher types. + ArgKind(Kind K) : K(K) { assert(K != AK_Matcher); } + + /// \brief Constructor for matcher types. + ArgKind(ast_type_traits::ASTNodeKind MatcherKind) + : K(AK_Matcher), MatcherKind(MatcherKind) {} + + Kind getArgKind() const { return K; } + ast_type_traits::ASTNodeKind getMatcherKind() const { + assert(K == AK_Matcher); + return MatcherKind; + } + + /// \brief Determines if this type can be converted to \p To. + /// + /// \param To the requested destination type. + /// + /// \param Specificity value corresponding to the "specificity" of the + /// convertion. + bool isConvertibleTo(ArgKind To, unsigned *Specificity) const; + + bool operator<(const ArgKind &Other) const { + if (K == AK_Matcher && Other.K == AK_Matcher) + return MatcherKind < Other.MatcherKind; + return K < Other.K; + } + + /// \brief String representation of the type. + std::string asString() const; + +private: + Kind K; + ast_type_traits::ASTNodeKind MatcherKind; +}; + +using ast_matchers::internal::DynTypedMatcher; + +/// \brief A variant matcher object. +/// +/// The purpose of this object is to abstract simple and polymorphic matchers +/// into a single object type. +/// Polymorphic matchers might be implemented as a list of all the possible +/// overloads of the matcher. \c VariantMatcher knows how to select the +/// appropriate overload when needed. +/// To get a real matcher object out of a \c VariantMatcher you can do: +/// - getSingleMatcher() which returns a matcher, only if it is not ambiguous +/// to decide which matcher to return. Eg. it contains only a single +/// matcher, or a polymorphic one with only one overload. +/// - hasTypedMatcher<T>()/getTypedMatcher<T>(): These calls will determine if +/// the underlying matcher(s) can unambiguously return a Matcher<T>. +class VariantMatcher { + /// \brief Methods that depend on T from hasTypedMatcher/getTypedMatcher. + class MatcherOps { + public: + MatcherOps(ast_type_traits::ASTNodeKind NodeKind) : NodeKind(NodeKind) {} + + bool canConstructFrom(const DynTypedMatcher &Matcher, + bool &IsExactMatch) const; + + /// \brief Convert \p Matcher the destination type and return it as a new + /// DynTypedMatcher. + virtual DynTypedMatcher + convertMatcher(const DynTypedMatcher &Matcher) const = 0; + + /// \brief Constructs a variadic typed matcher from \p InnerMatchers. + /// Will try to convert each inner matcher to the destination type and + /// return llvm::None if it fails to do so. + llvm::Optional<DynTypedMatcher> + constructVariadicOperator(DynTypedMatcher::VariadicOperator Op, + ArrayRef<VariantMatcher> InnerMatchers) const; + + protected: + ~MatcherOps() = default; + + private: + ast_type_traits::ASTNodeKind NodeKind; + }; + + /// \brief Payload interface to be specialized by each matcher type. + /// + /// It follows a similar interface as VariantMatcher itself. + class Payload : public RefCountedBaseVPTR { + public: + ~Payload() override; + virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const = 0; + virtual std::string getTypeAsString() const = 0; + virtual llvm::Optional<DynTypedMatcher> + getTypedMatcher(const MatcherOps &Ops) const = 0; + virtual bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, + unsigned *Specificity) const = 0; + }; + +public: + /// \brief A null matcher. + VariantMatcher(); + + /// \brief Clones the provided matcher. + static VariantMatcher SingleMatcher(const DynTypedMatcher &Matcher); + + /// \brief Clones the provided matchers. + /// + /// They should be the result of a polymorphic matcher. + static VariantMatcher + PolymorphicMatcher(std::vector<DynTypedMatcher> Matchers); + + /// \brief Creates a 'variadic' operator matcher. + /// + /// It will bind to the appropriate type on getTypedMatcher<T>(). + static VariantMatcher + VariadicOperatorMatcher(DynTypedMatcher::VariadicOperator Op, + std::vector<VariantMatcher> Args); + + /// \brief Makes the matcher the "null" matcher. + void reset(); + + /// \brief Whether the matcher is null. + bool isNull() const { return !Value; } + + /// \brief Return a single matcher, if there is no ambiguity. + /// + /// \returns the matcher, if there is only one matcher. An empty Optional, if + /// the underlying matcher is a polymorphic matcher with more than one + /// representation. + llvm::Optional<DynTypedMatcher> getSingleMatcher() const; + + /// \brief Determines if the contained matcher can be converted to + /// \c Matcher<T>. + /// + /// For the Single case, it returns true if it can be converted to + /// \c Matcher<T>. + /// For the Polymorphic case, it returns true if one, and only one, of the + /// overloads can be converted to \c Matcher<T>. If there are more than one + /// that can, the result would be ambiguous and false is returned. + template <class T> + bool hasTypedMatcher() const { + if (!Value) return false; + return Value->getTypedMatcher(TypedMatcherOps<T>()).hasValue(); + } + + /// \brief Determines if the contained matcher can be converted to \p Kind. + /// + /// \param Kind the requested destination type. + /// + /// \param Specificity value corresponding to the "specificity" of the + /// convertion. + bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, + unsigned *Specificity) const { + if (Value) + return Value->isConvertibleTo(Kind, Specificity); + return false; + } + + /// \brief Return this matcher as a \c Matcher<T>. + /// + /// Handles the different types (Single, Polymorphic) accordingly. + /// Asserts that \c hasTypedMatcher<T>() is true. + template <class T> + ast_matchers::internal::Matcher<T> getTypedMatcher() const { + assert(hasTypedMatcher<T>() && "hasTypedMatcher<T>() == false"); + return Value->getTypedMatcher(TypedMatcherOps<T>()) + ->template convertTo<T>(); + } + + /// \brief String representation of the type of the value. + /// + /// If the underlying matcher is a polymorphic one, the string will show all + /// the types. + std::string getTypeAsString() const; + +private: + explicit VariantMatcher(Payload *Value) : Value(Value) {} + + template <typename T> struct TypedMatcherOps; + + class SinglePayload; + class PolymorphicPayload; + class VariadicOpPayload; + + IntrusiveRefCntPtr<const Payload> Value; +}; + +template <typename T> +struct VariantMatcher::TypedMatcherOps final : VariantMatcher::MatcherOps { + TypedMatcherOps() + : MatcherOps(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()) {} + typedef ast_matchers::internal::Matcher<T> MatcherT; + + DynTypedMatcher + convertMatcher(const DynTypedMatcher &Matcher) const override { + return DynTypedMatcher(Matcher.convertTo<T>()); + } +}; + +/// \brief Variant value class. +/// +/// Basically, a tagged union with value type semantics. +/// It is used by the registry as the return value and argument type for the +/// matcher factory methods. +/// It can be constructed from any of the supported types. It supports +/// copy/assignment. +/// +/// Supported types: +/// - \c unsigned +/// - \c llvm::StringRef +/// - \c VariantMatcher (\c DynTypedMatcher / \c Matcher<T>) +class VariantValue { +public: + VariantValue() : Type(VT_Nothing) {} + + VariantValue(const VariantValue &Other); + ~VariantValue(); + VariantValue &operator=(const VariantValue &Other); + + /// \brief Specific constructors for each supported type. + VariantValue(unsigned Unsigned); + VariantValue(StringRef String); + VariantValue(const VariantMatcher &Matchers); + + /// \brief Returns true iff this is not an empty value. + explicit operator bool() const { return hasValue(); } + bool hasValue() const { return Type != VT_Nothing; } + + /// \brief Unsigned value functions. + bool isUnsigned() const; + unsigned getUnsigned() const; + void setUnsigned(unsigned Unsigned); + + /// \brief String value functions. + bool isString() const; + const std::string &getString() const; + void setString(StringRef String); + + /// \brief Matcher value functions. + bool isMatcher() const; + const VariantMatcher &getMatcher() const; + void setMatcher(const VariantMatcher &Matcher); + + /// \brief Determines if the contained value can be converted to \p Kind. + /// + /// \param Kind the requested destination type. + /// + /// \param Specificity value corresponding to the "specificity" of the + /// convertion. + bool isConvertibleTo(ArgKind Kind, unsigned* Specificity) const; + + /// \brief Determines if the contained value can be converted to any kind + /// in \p Kinds. + /// + /// \param Kinds the requested destination types. + /// + /// \param Specificity value corresponding to the "specificity" of the + /// convertion. It is the maximum specificity of all the possible + /// conversions. + bool isConvertibleTo(ArrayRef<ArgKind> Kinds, unsigned *Specificity) const; + + /// \brief String representation of the type of the value. + std::string getTypeAsString() const; + +private: + void reset(); + + /// \brief All supported value types. + enum ValueType { + VT_Nothing, + VT_Unsigned, + VT_String, + VT_Matcher + }; + + /// \brief All supported value types. + union AllValues { + unsigned Unsigned; + std::string *String; + VariantMatcher *Matcher; + }; + + ValueType Type; + AllValues Value; +}; + +} // end namespace dynamic +} // end namespace ast_matchers +} // end namespace clang + +#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_VARIANT_VALUE_H diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h new file mode 100644 index 0000000..cc14c7b --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h @@ -0,0 +1,49 @@ +//==- CFGReachabilityAnalysis.h - Basic reachability analysis ----*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a flow-sensitive, (mostly) path-insensitive reachability +// analysis based on Clang's CFGs. Clients can query if a given basic block +// is reachable within the CFG. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_CFGREACHABILITYANALYSIS_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_CFGREACHABILITYANALYSIS_H + +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/DenseMap.h" + +namespace clang { + +class CFG; +class CFGBlock; + +// A class that performs reachability queries for CFGBlocks. Several internal +// checks in this checker require reachability information. The requests all +// tend to have a common destination, so we lazily do a predecessor search +// from the destination node and cache the results to prevent work +// duplication. +class CFGReverseBlockReachabilityAnalysis { + typedef llvm::BitVector ReachableSet; + typedef llvm::DenseMap<unsigned, ReachableSet> ReachableMap; + ReachableSet analyzed; + ReachableMap reachable; +public: + CFGReverseBlockReachabilityAnalysis(const CFG &cfg); + + /// Returns true if the block 'Dst' can be reached from block 'Src'. + bool isReachable(const CFGBlock *Src, const CFGBlock *Dst); + +private: + void mapReachability(const CFGBlock *Dst); +}; + +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/Consumed.h b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/Consumed.h new file mode 100644 index 0000000..1f5aa12 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/Consumed.h @@ -0,0 +1,269 @@ +//===- Consumed.h ----------------------------------------------*- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// A intra-procedural analysis for checking consumed properties. This is based, +// in part, on research on linear types. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_CONSUMED_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_CONSUMED_H + +#include "clang/AST/DeclCXX.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/StmtCXX.h" +#include "clang/Analysis/Analyses/PostOrderCFGView.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Basic/SourceLocation.h" + +namespace clang { +namespace consumed { + + enum ConsumedState { + // No state information for the given variable. + CS_None, + + CS_Unknown, + CS_Unconsumed, + CS_Consumed + }; + + class ConsumedStmtVisitor; + + typedef SmallVector<PartialDiagnosticAt, 1> OptionalNotes; + typedef std::pair<PartialDiagnosticAt, OptionalNotes> DelayedDiag; + typedef std::list<DelayedDiag> DiagList; + + class ConsumedWarningsHandlerBase { + + public: + + virtual ~ConsumedWarningsHandlerBase(); + + /// \brief Emit the warnings and notes left by the analysis. + virtual void emitDiagnostics() {} + + /// \brief Warn that a variable's state doesn't match at the entry and exit + /// of a loop. + /// + /// \param Loc -- The location of the end of the loop. + /// + /// \param VariableName -- The name of the variable that has a mismatched + /// state. + virtual void warnLoopStateMismatch(SourceLocation Loc, + StringRef VariableName) {} + + /// \brief Warn about parameter typestate mismatches upon return. + /// + /// \param Loc -- The SourceLocation of the return statement. + /// + /// \param ExpectedState -- The state the return value was expected to be + /// in. + /// + /// \param ObservedState -- The state the return value was observed to be + /// in. + virtual void warnParamReturnTypestateMismatch(SourceLocation Loc, + StringRef VariableName, + StringRef ExpectedState, + StringRef ObservedState) {} + + // FIXME: Add documentation. + virtual void warnParamTypestateMismatch(SourceLocation LOC, + StringRef ExpectedState, + StringRef ObservedState) {} + + // FIXME: This can be removed when the attr propagation fix for templated + // classes lands. + /// \brief Warn about return typestates set for unconsumable types. + /// + /// \param Loc -- The location of the attributes. + /// + /// \param TypeName -- The name of the unconsumable type. + virtual void warnReturnTypestateForUnconsumableType(SourceLocation Loc, + StringRef TypeName) {} + + /// \brief Warn about return typestate mismatches. + /// + /// \param Loc -- The SourceLocation of the return statement. + /// + /// \param ExpectedState -- The state the return value was expected to be + /// in. + /// + /// \param ObservedState -- The state the return value was observed to be + /// in. + virtual void warnReturnTypestateMismatch(SourceLocation Loc, + StringRef ExpectedState, + StringRef ObservedState) {} + + /// \brief Warn about use-while-consumed errors. + /// \param MethodName -- The name of the method that was incorrectly + /// invoked. + /// + /// \param State -- The state the object was used in. + /// + /// \param Loc -- The SourceLocation of the method invocation. + virtual void warnUseOfTempInInvalidState(StringRef MethodName, + StringRef State, + SourceLocation Loc) {} + + /// \brief Warn about use-while-consumed errors. + /// \param MethodName -- The name of the method that was incorrectly + /// invoked. + /// + /// \param State -- The state the object was used in. + /// + /// \param VariableName -- The name of the variable that holds the unique + /// value. + /// + /// \param Loc -- The SourceLocation of the method invocation. + virtual void warnUseInInvalidState(StringRef MethodName, + StringRef VariableName, + StringRef State, + SourceLocation Loc) {} + }; + + class ConsumedStateMap { + + typedef llvm::DenseMap<const VarDecl *, ConsumedState> VarMapType; + typedef llvm::DenseMap<const CXXBindTemporaryExpr *, ConsumedState> + TmpMapType; + + protected: + + bool Reachable; + const Stmt *From; + VarMapType VarMap; + TmpMapType TmpMap; + + public: + ConsumedStateMap() : Reachable(true), From(nullptr) {} + ConsumedStateMap(const ConsumedStateMap &Other) + : Reachable(Other.Reachable), From(Other.From), VarMap(Other.VarMap), + TmpMap() {} + + /// \brief Warn if any of the parameters being tracked are not in the state + /// they were declared to be in upon return from a function. + void checkParamsForReturnTypestate(SourceLocation BlameLoc, + ConsumedWarningsHandlerBase &WarningsHandler) const; + + /// \brief Clear the TmpMap. + void clearTemporaries(); + + /// \brief Get the consumed state of a given variable. + ConsumedState getState(const VarDecl *Var) const; + + /// \brief Get the consumed state of a given temporary value. + ConsumedState getState(const CXXBindTemporaryExpr *Tmp) const; + + /// \brief Merge this state map with another map. + void intersect(const ConsumedStateMap &Other); + + void intersectAtLoopHead(const CFGBlock *LoopHead, const CFGBlock *LoopBack, + const ConsumedStateMap *LoopBackStates, + ConsumedWarningsHandlerBase &WarningsHandler); + + /// \brief Return true if this block is reachable. + bool isReachable() const { return Reachable; } + + /// \brief Mark the block as unreachable. + void markUnreachable(); + + /// \brief Set the source for a decision about the branching of states. + /// \param Source -- The statement that was the origin of a branching + /// decision. + void setSource(const Stmt *Source) { this->From = Source; } + + /// \brief Set the consumed state of a given variable. + void setState(const VarDecl *Var, ConsumedState State); + + /// \brief Set the consumed state of a given temporary value. + void setState(const CXXBindTemporaryExpr *Tmp, ConsumedState State); + + /// \brief Remove the temporary value from our state map. + void remove(const CXXBindTemporaryExpr *Tmp); + + /// \brief Tests to see if there is a mismatch in the states stored in two + /// maps. + /// + /// \param Other -- The second map to compare against. + bool operator!=(const ConsumedStateMap *Other) const; + }; + + class ConsumedBlockInfo { + std::vector<std::unique_ptr<ConsumedStateMap>> StateMapsArray; + std::vector<unsigned int> VisitOrder; + + public: + ConsumedBlockInfo() = default; + ConsumedBlockInfo &operator=(ConsumedBlockInfo &&Other) { + StateMapsArray = std::move(Other.StateMapsArray); + VisitOrder = std::move(Other.VisitOrder); + return *this; + } + + ConsumedBlockInfo(unsigned int NumBlocks, PostOrderCFGView *SortedGraph) + : StateMapsArray(NumBlocks), VisitOrder(NumBlocks, 0) { + unsigned int VisitOrderCounter = 0; + for (PostOrderCFGView::iterator BI = SortedGraph->begin(), + BE = SortedGraph->end(); BI != BE; ++BI) { + VisitOrder[(*BI)->getBlockID()] = VisitOrderCounter++; + } + } + + bool allBackEdgesVisited(const CFGBlock *CurrBlock, + const CFGBlock *TargetBlock); + + void addInfo(const CFGBlock *Block, ConsumedStateMap *StateMap, + std::unique_ptr<ConsumedStateMap> &OwnedStateMap); + void addInfo(const CFGBlock *Block, + std::unique_ptr<ConsumedStateMap> StateMap); + + ConsumedStateMap* borrowInfo(const CFGBlock *Block); + + void discardInfo(const CFGBlock *Block); + + std::unique_ptr<ConsumedStateMap> getInfo(const CFGBlock *Block); + + bool isBackEdge(const CFGBlock *From, const CFGBlock *To); + bool isBackEdgeTarget(const CFGBlock *Block); + }; + + /// A class that handles the analysis of uniqueness violations. + class ConsumedAnalyzer { + + ConsumedBlockInfo BlockInfo; + std::unique_ptr<ConsumedStateMap> CurrStates; + + ConsumedState ExpectedReturnState; + + void determineExpectedReturnState(AnalysisDeclContext &AC, + const FunctionDecl *D); + bool splitState(const CFGBlock *CurrBlock, + const ConsumedStmtVisitor &Visitor); + + public: + + ConsumedWarningsHandlerBase &WarningsHandler; + + ConsumedAnalyzer(ConsumedWarningsHandlerBase &WarningsHandler) + : WarningsHandler(WarningsHandler) {} + + ConsumedState getExpectedReturnState() const { return ExpectedReturnState; } + + /// \brief Check a function's CFG for consumed violations. + /// + /// We traverse the blocks in the CFG, keeping track of the state of each + /// value who's type has uniquness annotations. If methods are invoked in + /// the wrong state a warning is issued. Each block in the CFG is traversed + /// exactly once. + void run(AnalysisDeclContext &AC); + }; +}} // end namespace clang::consumed + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/Dominators.h b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/Dominators.h new file mode 100644 index 0000000..4524aeb --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/Dominators.h @@ -0,0 +1,210 @@ +//==- Dominators.h - Implementation of dominators tree for Clang CFG C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the dominators tree functionality for Clang CFGs. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_DOMINATORS_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_DOMINATORS_H + +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/CFG.h" +#include "llvm/ADT/GraphTraits.h" +#include "llvm/Support/GenericDomTree.h" +#include "llvm/Support/GenericDomTreeConstruction.h" + +// FIXME: There is no good reason for the domtree to require a print method +// which accepts an LLVM Module, so remove this (and the method's argument that +// needs it) when that is fixed. +namespace llvm { +class Module; +} + +namespace clang { + +class CFGBlock; +typedef llvm::DomTreeNodeBase<CFGBlock> DomTreeNode; + +/// \brief Concrete subclass of DominatorTreeBase for Clang +/// This class implements the dominators tree functionality given a Clang CFG. +/// +class DominatorTree : public ManagedAnalysis { + virtual void anchor(); +public: + llvm::DominatorTreeBase<CFGBlock>* DT; + + DominatorTree() { + DT = new llvm::DominatorTreeBase<CFGBlock>(false); + } + + ~DominatorTree() override { delete DT; } + + llvm::DominatorTreeBase<CFGBlock>& getBase() { return *DT; } + + /// \brief This method returns the root CFGBlock of the dominators tree. + /// + inline CFGBlock *getRoot() const { + return DT->getRoot(); + } + + /// \brief This method returns the root DomTreeNode, which is the wrapper + /// for CFGBlock. + inline DomTreeNode *getRootNode() const { + return DT->getRootNode(); + } + + /// \brief This method compares two dominator trees. + /// The method returns false if the other dominator tree matches this + /// dominator tree, otherwise returns true. + /// + inline bool compare(DominatorTree &Other) const { + DomTreeNode *R = getRootNode(); + DomTreeNode *OtherR = Other.getRootNode(); + + if (!R || !OtherR || R->getBlock() != OtherR->getBlock()) + return true; + + if (DT->compare(Other.getBase())) + return true; + + return false; + } + + /// \brief This method builds the dominator tree for a given CFG + /// The CFG information is passed via AnalysisDeclContext + /// + void buildDominatorTree(AnalysisDeclContext &AC) { + cfg = AC.getCFG(); + DT->recalculate(*cfg); + } + + /// \brief This method dumps immediate dominators for each block, + /// mainly used for debug purposes. + /// + void dump() { + llvm::errs() << "Immediate dominance tree (Node#,IDom#):\n"; + for (CFG::const_iterator I = cfg->begin(), + E = cfg->end(); I != E; ++I) { + if(DT->getNode(*I)->getIDom()) + llvm::errs() << "(" << (*I)->getBlockID() + << "," + << DT->getNode(*I)->getIDom()->getBlock()->getBlockID() + << ")\n"; + else llvm::errs() << "(" << (*I)->getBlockID() + << "," << (*I)->getBlockID() << ")\n"; + } + } + + /// \brief This method tests if one CFGBlock dominates the other. + /// The method return true if A dominates B, false otherwise. + /// Note a block always dominates itself. + /// + inline bool dominates(const CFGBlock* A, const CFGBlock* B) const { + return DT->dominates(A, B); + } + + /// \brief This method tests if one CFGBlock properly dominates the other. + /// The method return true if A properly dominates B, false otherwise. + /// + bool properlyDominates(const CFGBlock*A, const CFGBlock*B) const { + return DT->properlyDominates(A, B); + } + + /// \brief This method finds the nearest common dominator CFG block + /// for CFG block A and B. If there is no such block then return NULL. + /// + inline CFGBlock *findNearestCommonDominator(CFGBlock *A, CFGBlock *B) { + return DT->findNearestCommonDominator(A, B); + } + + inline const CFGBlock *findNearestCommonDominator(const CFGBlock *A, + const CFGBlock *B) { + return DT->findNearestCommonDominator(A, B); + } + + /// \brief This method is used to update the dominator + /// tree information when a node's immediate dominator changes. + /// + inline void changeImmediateDominator(CFGBlock *N, CFGBlock *NewIDom) { + DT->changeImmediateDominator(N, NewIDom); + } + + /// \brief This method tests if the given CFGBlock can be reachable from root. + /// Returns true if reachable, false otherwise. + /// + bool isReachableFromEntry(const CFGBlock *A) { + return DT->isReachableFromEntry(A); + } + + /// \brief This method releases the memory held by the dominator tree. + /// + virtual void releaseMemory() { + DT->releaseMemory(); + } + + /// \brief This method converts the dominator tree to human readable form. + /// + virtual void print(raw_ostream &OS, const llvm::Module* M= nullptr) const { + DT->print(OS); + } + +private: + CFG *cfg; +}; + +} // end namespace clang + +//===------------------------------------- +/// DominatorTree GraphTraits specialization so the DominatorTree can be +/// iterable by generic graph iterators. +/// +namespace llvm { +template <> struct GraphTraits< ::clang::DomTreeNode* > { + typedef ::clang::DomTreeNode NodeType; + typedef NodeType::iterator ChildIteratorType; + + static NodeType *getEntryNode(NodeType *N) { + return N; + } + static inline ChildIteratorType child_begin(NodeType *N) { + return N->begin(); + } + static inline ChildIteratorType child_end(NodeType *N) { + return N->end(); + } + + typedef df_iterator< ::clang::DomTreeNode* > nodes_iterator; + + static nodes_iterator nodes_begin(::clang::DomTreeNode *N) { + return df_begin(getEntryNode(N)); + } + + static nodes_iterator nodes_end(::clang::DomTreeNode *N) { + return df_end(getEntryNode(N)); + } +}; + +template <> struct GraphTraits< ::clang::DominatorTree* > + : public GraphTraits< ::clang::DomTreeNode* > { + static NodeType *getEntryNode(::clang::DominatorTree *DT) { + return DT->getRootNode(); + } + + static nodes_iterator nodes_begin(::clang::DominatorTree *N) { + return df_begin(getEntryNode(N)); + } + + static nodes_iterator nodes_end(::clang::DominatorTree *N) { + return df_end(getEntryNode(N)); + } +}; +} // end namespace llvm + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/FormatString.h b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/FormatString.h new file mode 100644 index 0000000..4471311 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/FormatString.h @@ -0,0 +1,679 @@ +//= FormatString.h - Analysis of printf/fprintf format strings --*- 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 APIs for analyzing the format strings of printf, fscanf, +// and friends. +// +// The structure of format strings for fprintf are described in C99 7.19.6.1. +// +// The structure of format strings for fscanf are described in C99 7.19.6.2. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H + +#include "clang/AST/CanonicalType.h" + +namespace clang { + +class TargetInfo; + +//===----------------------------------------------------------------------===// +/// Common components of both fprintf and fscanf format strings. +namespace analyze_format_string { + +/// Class representing optional flags with location and representation +/// information. +class OptionalFlag { +public: + OptionalFlag(const char *Representation) + : representation(Representation), flag(false) {} + bool isSet() { return flag; } + void set() { flag = true; } + void clear() { flag = false; } + void setPosition(const char *position) { + assert(position); + flag = true; + this->position = position; + } + const char *getPosition() const { + assert(position); + return position; + } + const char *toString() const { return representation; } + + // Overloaded operators for bool like qualities + explicit operator bool() const { return flag; } + OptionalFlag& operator=(const bool &rhs) { + flag = rhs; + return *this; // Return a reference to myself. + } +private: + const char *representation; + const char *position; + bool flag; +}; + +/// Represents the length modifier in a format string in scanf/printf. +class LengthModifier { +public: + enum Kind { + None, + AsChar, // 'hh' + AsShort, // 'h' + AsLong, // 'l' + AsLongLong, // 'll' + AsQuad, // 'q' (BSD, deprecated, for 64-bit integer types) + AsIntMax, // 'j' + AsSizeT, // 'z' + AsPtrDiff, // 't' + AsInt32, // 'I32' (MSVCRT, like __int32) + AsInt3264, // 'I' (MSVCRT, like __int3264 from MIDL) + AsInt64, // 'I64' (MSVCRT, like __int64) + AsLongDouble, // 'L' + AsAllocate, // for '%as', GNU extension to C90 scanf + AsMAllocate, // for '%ms', GNU extension to scanf + AsWide, // 'w' (MSVCRT, like l but only for c, C, s, S, or Z + AsWideChar = AsLong // for '%ls', only makes sense for printf + }; + + LengthModifier() + : Position(nullptr), kind(None) {} + LengthModifier(const char *pos, Kind k) + : Position(pos), kind(k) {} + + const char *getStart() const { + return Position; + } + + unsigned getLength() const { + switch (kind) { + default: + return 1; + case AsLongLong: + case AsChar: + return 2; + case AsInt32: + case AsInt64: + return 3; + case None: + return 0; + } + } + + Kind getKind() const { return kind; } + void setKind(Kind k) { kind = k; } + + const char *toString() const; + +private: + const char *Position; + Kind kind; +}; + +class ConversionSpecifier { +public: + enum Kind { + InvalidSpecifier = 0, + // C99 conversion specifiers. + cArg, + dArg, + DArg, // Apple extension + iArg, + IntArgBeg = dArg, IntArgEnd = iArg, + + oArg, + OArg, // Apple extension + uArg, + UArg, // Apple extension + xArg, + XArg, + UIntArgBeg = oArg, UIntArgEnd = XArg, + + fArg, + FArg, + eArg, + EArg, + gArg, + GArg, + aArg, + AArg, + DoubleArgBeg = fArg, DoubleArgEnd = AArg, + + sArg, + pArg, + nArg, + PercentArg, + CArg, + SArg, + + // ** Printf-specific ** + + ZArg, // MS extension + + // Objective-C specific specifiers. + ObjCObjArg, // '@' + ObjCBeg = ObjCObjArg, ObjCEnd = ObjCObjArg, + + // FreeBSD kernel specific specifiers. + FreeBSDbArg, + FreeBSDDArg, + FreeBSDrArg, + FreeBSDyArg, + + // GlibC specific specifiers. + PrintErrno, // 'm' + + PrintfConvBeg = ObjCObjArg, PrintfConvEnd = PrintErrno, + + // ** Scanf-specific ** + ScanListArg, // '[' + ScanfConvBeg = ScanListArg, ScanfConvEnd = ScanListArg + }; + + ConversionSpecifier(bool isPrintf = true) + : IsPrintf(isPrintf), Position(nullptr), EndScanList(nullptr), + kind(InvalidSpecifier) {} + + ConversionSpecifier(bool isPrintf, const char *pos, Kind k) + : IsPrintf(isPrintf), Position(pos), EndScanList(nullptr), kind(k) {} + + const char *getStart() const { + return Position; + } + + StringRef getCharacters() const { + return StringRef(getStart(), getLength()); + } + + bool consumesDataArgument() const { + switch (kind) { + case PrintErrno: + assert(IsPrintf); + return false; + case PercentArg: + return false; + default: + return true; + } + } + + Kind getKind() const { return kind; } + void setKind(Kind k) { kind = k; } + unsigned getLength() const { + return EndScanList ? EndScanList - Position : 1; + } + + bool isIntArg() const { return (kind >= IntArgBeg && kind <= IntArgEnd) || + kind == FreeBSDrArg || kind == FreeBSDyArg; } + bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; } + bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; } + const char *toString() const; + + bool isPrintfKind() const { return IsPrintf; } + + Optional<ConversionSpecifier> getStandardSpecifier() const; + +protected: + bool IsPrintf; + const char *Position; + const char *EndScanList; + Kind kind; +}; + +class ArgType { +public: + enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy, + AnyCharTy, CStrTy, WCStrTy, WIntTy }; + + enum MatchKind { NoMatch = 0, Match = 1, NoMatchPedantic }; + +private: + const Kind K; + QualType T; + const char *Name; + bool Ptr; +public: + ArgType(Kind k = UnknownTy, const char *n = nullptr) + : K(k), Name(n), Ptr(false) {} + ArgType(QualType t, const char *n = nullptr) + : K(SpecificTy), T(t), Name(n), Ptr(false) {} + ArgType(CanQualType t) : K(SpecificTy), T(t), Name(nullptr), Ptr(false) {} + + static ArgType Invalid() { return ArgType(InvalidTy); } + bool isValid() const { return K != InvalidTy; } + + /// Create an ArgType which corresponds to the type pointer to A. + static ArgType PtrTo(const ArgType& A) { + assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown"); + ArgType Res = A; + Res.Ptr = true; + return Res; + } + + MatchKind matchesType(ASTContext &C, QualType argTy) const; + + QualType getRepresentativeType(ASTContext &C) const; + + std::string getRepresentativeTypeName(ASTContext &C) const; +}; + +class OptionalAmount { +public: + enum HowSpecified { NotSpecified, Constant, Arg, Invalid }; + + OptionalAmount(HowSpecified howSpecified, + unsigned amount, + const char *amountStart, + unsigned amountLength, + bool usesPositionalArg) + : start(amountStart), length(amountLength), hs(howSpecified), amt(amount), + UsesPositionalArg(usesPositionalArg), UsesDotPrefix(0) {} + + OptionalAmount(bool valid = true) + : start(nullptr),length(0), hs(valid ? NotSpecified : Invalid), amt(0), + UsesPositionalArg(0), UsesDotPrefix(0) {} + + bool isInvalid() const { + return hs == Invalid; + } + + HowSpecified getHowSpecified() const { return hs; } + void setHowSpecified(HowSpecified h) { hs = h; } + + bool hasDataArgument() const { return hs == Arg; } + + unsigned getArgIndex() const { + assert(hasDataArgument()); + return amt; + } + + unsigned getConstantAmount() const { + assert(hs == Constant); + return amt; + } + + const char *getStart() const { + // We include the . character if it is given. + return start - UsesDotPrefix; + } + + unsigned getConstantLength() const { + assert(hs == Constant); + return length + UsesDotPrefix; + } + + ArgType getArgType(ASTContext &Ctx) const; + + void toString(raw_ostream &os) const; + + bool usesPositionalArg() const { return (bool) UsesPositionalArg; } + unsigned getPositionalArgIndex() const { + assert(hasDataArgument()); + return amt + 1; + } + + bool usesDotPrefix() const { return UsesDotPrefix; } + void setUsesDotPrefix() { UsesDotPrefix = true; } + +private: + const char *start; + unsigned length; + HowSpecified hs; + unsigned amt; + bool UsesPositionalArg : 1; + bool UsesDotPrefix; +}; + + +class FormatSpecifier { +protected: + LengthModifier LM; + OptionalAmount FieldWidth; + ConversionSpecifier CS; + /// Positional arguments, an IEEE extension: + /// IEEE Std 1003.1, 2004 Edition + /// http://www.opengroup.org/onlinepubs/009695399/functions/printf.html + bool UsesPositionalArg; + unsigned argIndex; +public: + FormatSpecifier(bool isPrintf) + : CS(isPrintf), UsesPositionalArg(false), argIndex(0) {} + + void setLengthModifier(LengthModifier lm) { + LM = lm; + } + + void setUsesPositionalArg() { UsesPositionalArg = true; } + + void setArgIndex(unsigned i) { + argIndex = i; + } + + unsigned getArgIndex() const { + return argIndex; + } + + unsigned getPositionalArgIndex() const { + return argIndex + 1; + } + + const LengthModifier &getLengthModifier() const { + return LM; + } + + const OptionalAmount &getFieldWidth() const { + return FieldWidth; + } + + void setFieldWidth(const OptionalAmount &Amt) { + FieldWidth = Amt; + } + + bool usesPositionalArg() const { return UsesPositionalArg; } + + bool hasValidLengthModifier(const TargetInfo &Target) const; + + bool hasStandardLengthModifier() const; + + Optional<LengthModifier> getCorrectedLengthModifier() const; + + bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const; + + bool hasStandardLengthConversionCombination() const; + + /// For a TypedefType QT, if it is a named integer type such as size_t, + /// assign the appropriate value to LM and return true. + static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM); +}; + +} // end analyze_format_string namespace + +//===----------------------------------------------------------------------===// +/// Pieces specific to fprintf format strings. + +namespace analyze_printf { + +class PrintfConversionSpecifier : + public analyze_format_string::ConversionSpecifier { +public: + PrintfConversionSpecifier() + : ConversionSpecifier(true, nullptr, InvalidSpecifier) {} + + PrintfConversionSpecifier(const char *pos, Kind k) + : ConversionSpecifier(true, pos, k) {} + + bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; } + bool isDoubleArg() const { return kind >= DoubleArgBeg && + kind <= DoubleArgEnd; } + unsigned getLength() const { + // Conversion specifiers currently only are represented by + // single characters, but we be flexible. + return 1; + } + + static bool classof(const analyze_format_string::ConversionSpecifier *CS) { + return CS->isPrintfKind(); + } +}; + +using analyze_format_string::ArgType; +using analyze_format_string::LengthModifier; +using analyze_format_string::OptionalAmount; +using analyze_format_string::OptionalFlag; + +class PrintfSpecifier : public analyze_format_string::FormatSpecifier { + OptionalFlag HasThousandsGrouping; // ''', POSIX extension. + OptionalFlag IsLeftJustified; // '-' + OptionalFlag HasPlusPrefix; // '+' + OptionalFlag HasSpacePrefix; // ' ' + OptionalFlag HasAlternativeForm; // '#' + OptionalFlag HasLeadingZeroes; // '0' + OptionalFlag HasObjCTechnicalTerm; // '[tt]' + OptionalAmount Precision; +public: + PrintfSpecifier() : + FormatSpecifier(/* isPrintf = */ true), + HasThousandsGrouping("'"), IsLeftJustified("-"), HasPlusPrefix("+"), + HasSpacePrefix(" "), HasAlternativeForm("#"), HasLeadingZeroes("0"), + HasObjCTechnicalTerm("tt") {} + + static PrintfSpecifier Parse(const char *beg, const char *end); + + // Methods for incrementally constructing the PrintfSpecifier. + void setConversionSpecifier(const PrintfConversionSpecifier &cs) { + CS = cs; + } + void setHasThousandsGrouping(const char *position) { + HasThousandsGrouping.setPosition(position); + } + void setIsLeftJustified(const char *position) { + IsLeftJustified.setPosition(position); + } + void setHasPlusPrefix(const char *position) { + HasPlusPrefix.setPosition(position); + } + void setHasSpacePrefix(const char *position) { + HasSpacePrefix.setPosition(position); + } + void setHasAlternativeForm(const char *position) { + HasAlternativeForm.setPosition(position); + } + void setHasLeadingZeros(const char *position) { + HasLeadingZeroes.setPosition(position); + } + void setHasObjCTechnicalTerm(const char *position) { + HasObjCTechnicalTerm.setPosition(position); + } + void setUsesPositionalArg() { UsesPositionalArg = true; } + + // Methods for querying the format specifier. + + const PrintfConversionSpecifier &getConversionSpecifier() const { + return cast<PrintfConversionSpecifier>(CS); + } + + void setPrecision(const OptionalAmount &Amt) { + Precision = Amt; + Precision.setUsesDotPrefix(); + } + + const OptionalAmount &getPrecision() const { + return Precision; + } + + bool consumesDataArgument() const { + return getConversionSpecifier().consumesDataArgument(); + } + + /// \brief Returns the builtin type that a data argument + /// paired with this format specifier should have. This method + /// will return null if the format specifier does not have + /// a matching data argument or the matching argument matches + /// more than one type. + ArgType getArgType(ASTContext &Ctx, bool IsObjCLiteral) const; + + const OptionalFlag &hasThousandsGrouping() const { + return HasThousandsGrouping; + } + const OptionalFlag &isLeftJustified() const { return IsLeftJustified; } + const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; } + const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; } + const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; } + const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; } + const OptionalFlag &hasObjCTechnicalTerm() const { return HasObjCTechnicalTerm; } + bool usesPositionalArg() const { return UsesPositionalArg; } + + /// Changes the specifier and length according to a QualType, retaining any + /// flags or options. Returns true on success, or false when a conversion + /// was not successful. + bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx, + bool IsObjCLiteral); + + void toString(raw_ostream &os) const; + + // Validation methods - to check if any element results in undefined behavior + bool hasValidPlusPrefix() const; + bool hasValidAlternativeForm() const; + bool hasValidLeadingZeros() const; + bool hasValidSpacePrefix() const; + bool hasValidLeftJustified() const; + bool hasValidThousandsGroupingPrefix() const; + + bool hasValidPrecision() const; + bool hasValidFieldWidth() const; +}; +} // end analyze_printf namespace + +//===----------------------------------------------------------------------===// +/// Pieces specific to fscanf format strings. + +namespace analyze_scanf { + +class ScanfConversionSpecifier : + public analyze_format_string::ConversionSpecifier { +public: + ScanfConversionSpecifier() + : ConversionSpecifier(false, nullptr, InvalidSpecifier) {} + + ScanfConversionSpecifier(const char *pos, Kind k) + : ConversionSpecifier(false, pos, k) {} + + void setEndScanList(const char *pos) { EndScanList = pos; } + + static bool classof(const analyze_format_string::ConversionSpecifier *CS) { + return !CS->isPrintfKind(); + } +}; + +using analyze_format_string::ArgType; +using analyze_format_string::LengthModifier; +using analyze_format_string::OptionalAmount; +using analyze_format_string::OptionalFlag; + +class ScanfSpecifier : public analyze_format_string::FormatSpecifier { + OptionalFlag SuppressAssignment; // '*' +public: + ScanfSpecifier() : + FormatSpecifier(/* isPrintf = */ false), + SuppressAssignment("*") {} + + void setSuppressAssignment(const char *position) { + SuppressAssignment.setPosition(position); + } + + const OptionalFlag &getSuppressAssignment() const { + return SuppressAssignment; + } + + void setConversionSpecifier(const ScanfConversionSpecifier &cs) { + CS = cs; + } + + const ScanfConversionSpecifier &getConversionSpecifier() const { + return cast<ScanfConversionSpecifier>(CS); + } + + bool consumesDataArgument() const { + return CS.consumesDataArgument() && !SuppressAssignment; + } + + ArgType getArgType(ASTContext &Ctx) const; + + bool fixType(QualType QT, QualType RawQT, const LangOptions &LangOpt, + ASTContext &Ctx); + + void toString(raw_ostream &os) const; + + static ScanfSpecifier Parse(const char *beg, const char *end); +}; + +} // end analyze_scanf namespace + +//===----------------------------------------------------------------------===// +// Parsing and processing of format strings (both fprintf and fscanf). + +namespace analyze_format_string { + +enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 }; + +class FormatStringHandler { +public: + FormatStringHandler() {} + virtual ~FormatStringHandler(); + + virtual void HandleNullChar(const char *nullCharacter) {} + + virtual void HandlePosition(const char *startPos, unsigned posLen) {} + + virtual void HandleInvalidPosition(const char *startPos, unsigned posLen, + PositionContext p) {} + + virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {} + + virtual void HandleIncompleteSpecifier(const char *startSpecifier, + unsigned specifierLen) {} + + virtual void HandleEmptyObjCModifierFlag(const char *startFlags, + unsigned flagsLen) {} + + virtual void HandleInvalidObjCModifierFlag(const char *startFlag, + unsigned flagLen) {} + + virtual void HandleObjCFlagsWithNonObjCConversion(const char *flagsStart, + const char *flagsEnd, + const char *conversionPosition) {} + // Printf-specific handlers. + + virtual bool HandleInvalidPrintfConversionSpecifier( + const analyze_printf::PrintfSpecifier &FS, + const char *startSpecifier, + unsigned specifierLen) { + return true; + } + + virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, + const char *startSpecifier, + unsigned specifierLen) { + return true; + } + + // Scanf-specific handlers. + + virtual bool HandleInvalidScanfConversionSpecifier( + const analyze_scanf::ScanfSpecifier &FS, + const char *startSpecifier, + unsigned specifierLen) { + return true; + } + + virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS, + const char *startSpecifier, + unsigned specifierLen) { + return true; + } + + virtual void HandleIncompleteScanList(const char *start, const char *end) {} +}; + +bool ParsePrintfString(FormatStringHandler &H, + const char *beg, const char *end, const LangOptions &LO, + const TargetInfo &Target, bool isFreeBSDKPrintf); + +bool ParseFormatStringHasSArg(const char *beg, const char *end, + const LangOptions &LO, const TargetInfo &Target); + +bool ParseScanfString(FormatStringHandler &H, + const char *beg, const char *end, const LangOptions &LO, + const TargetInfo &Target); + +} // end analyze_format_string namespace +} // end clang namespace +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/LiveVariables.h b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/LiveVariables.h new file mode 100644 index 0000000..e17f73a6 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/LiveVariables.h @@ -0,0 +1,117 @@ +//===- LiveVariables.h - Live Variable Analysis for Source CFGs -*- C++ --*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements Live Variables analysis for source-level CFGs. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_LIVEVARIABLES_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_LIVEVARIABLES_H + +#include "clang/AST/Decl.h" +#include "clang/Analysis/AnalysisContext.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/ImmutableSet.h" + +namespace clang { + +class CFG; +class CFGBlock; +class Stmt; +class DeclRefExpr; +class SourceManager; + +class LiveVariables : public ManagedAnalysis { +public: + class LivenessValues { + public: + + llvm::ImmutableSet<const Stmt *> liveStmts; + llvm::ImmutableSet<const VarDecl *> liveDecls; + + bool equals(const LivenessValues &V) const; + + LivenessValues() + : liveStmts(nullptr), liveDecls(nullptr) {} + + LivenessValues(llvm::ImmutableSet<const Stmt *> LiveStmts, + llvm::ImmutableSet<const VarDecl *> LiveDecls) + : liveStmts(LiveStmts), liveDecls(LiveDecls) {} + + bool isLive(const Stmt *S) const; + bool isLive(const VarDecl *D) const; + + friend class LiveVariables; + }; + + class Observer { + virtual void anchor(); + public: + virtual ~Observer() {} + + /// A callback invoked right before invoking the + /// liveness transfer function on the given statement. + virtual void observeStmt(const Stmt *S, + const CFGBlock *currentBlock, + const LivenessValues& V) {} + + /// Called when the live variables analysis registers + /// that a variable is killed. + virtual void observerKill(const DeclRefExpr *DR) {} + }; + + ~LiveVariables() override; + + /// Compute the liveness information for a given CFG. + static LiveVariables *computeLiveness(AnalysisDeclContext &analysisContext, + bool killAtAssign); + + /// Return true if a variable is live at the end of a + /// specified block. + bool isLive(const CFGBlock *B, const VarDecl *D); + + /// Returns true if a variable is live at the beginning of the + /// the statement. This query only works if liveness information + /// has been recorded at the statement level (see runOnAllBlocks), and + /// only returns liveness information for block-level expressions. + bool isLive(const Stmt *S, const VarDecl *D); + + /// Returns true the block-level expression "value" is live + /// before the given block-level expression (see runOnAllBlocks). + bool isLive(const Stmt *Loc, const Stmt *StmtVal); + + /// Print to stderr the liveness information associated with + /// each basic block. + void dumpBlockLiveness(const SourceManager& M); + + void runOnAllBlocks(Observer &obs); + + static LiveVariables *create(AnalysisDeclContext &analysisContext) { + return computeLiveness(analysisContext, true); + } + + static const void *getTag(); + +private: + LiveVariables(void *impl); + void *impl; +}; + +class RelaxedLiveVariables : public LiveVariables { +public: + static LiveVariables *create(AnalysisDeclContext &analysisContext) { + return computeLiveness(analysisContext, false); + } + + static const void *getTag(); +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/PostOrderCFGView.h b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/PostOrderCFGView.h new file mode 100644 index 0000000..a1c6504 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/PostOrderCFGView.h @@ -0,0 +1,115 @@ +//===- PostOrderCFGView.h - Post order view of CFG blocks ---------*- C++ --*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements post order view of the blocks in a CFG. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_POSTORDERCFGVIEW_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_POSTORDERCFGVIEW_H + +#include <vector> +//#include <algorithm> + +#include "llvm/ADT/PostOrderIterator.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/BitVector.h" + +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/CFG.h" + +namespace clang { + +class PostOrderCFGView : public ManagedAnalysis { + virtual void anchor(); +public: + /// \brief Implements a set of CFGBlocks using a BitVector. + /// + /// This class contains a minimal interface, primarily dictated by the SetType + /// template parameter of the llvm::po_iterator template, as used with + /// external storage. We also use this set to keep track of which CFGBlocks we + /// visit during the analysis. + class CFGBlockSet { + llvm::BitVector VisitedBlockIDs; + public: + // po_iterator requires this iterator, but the only interface needed is the + // value_type typedef. + struct iterator { typedef const CFGBlock *value_type; }; + + CFGBlockSet() {} + CFGBlockSet(const CFG *G) : VisitedBlockIDs(G->getNumBlockIDs(), false) {} + + /// \brief Set the bit associated with a particular CFGBlock. + /// This is the important method for the SetType template parameter. + std::pair<llvm::NoneType, bool> insert(const CFGBlock *Block) { + // Note that insert() is called by po_iterator, which doesn't check to + // make sure that Block is non-null. Moreover, the CFGBlock iterator will + // occasionally hand out null pointers for pruned edges, so we catch those + // here. + if (!Block) + return std::make_pair(None, false); // if an edge is trivially false. + if (VisitedBlockIDs.test(Block->getBlockID())) + return std::make_pair(None, false); + VisitedBlockIDs.set(Block->getBlockID()); + return std::make_pair(None, true); + } + + /// \brief Check if the bit for a CFGBlock has been already set. + /// This method is for tracking visited blocks in the main threadsafety + /// loop. Block must not be null. + bool alreadySet(const CFGBlock *Block) { + return VisitedBlockIDs.test(Block->getBlockID()); + } + }; + +private: + typedef llvm::po_iterator<const CFG*, CFGBlockSet, true> po_iterator; + std::vector<const CFGBlock*> Blocks; + + typedef llvm::DenseMap<const CFGBlock *, unsigned> BlockOrderTy; + BlockOrderTy BlockOrder; + +public: + typedef std::vector<const CFGBlock *>::reverse_iterator iterator; + typedef std::vector<const CFGBlock *>::const_reverse_iterator const_iterator; + + PostOrderCFGView(const CFG *cfg); + + iterator begin() { return Blocks.rbegin(); } + iterator end() { return Blocks.rend(); } + + const_iterator begin() const { return Blocks.rbegin(); } + const_iterator end() const { return Blocks.rend(); } + + bool empty() const { return begin() == end(); } + + struct BlockOrderCompare; + friend struct BlockOrderCompare; + + struct BlockOrderCompare { + const PostOrderCFGView &POV; + public: + BlockOrderCompare(const PostOrderCFGView &pov) : POV(pov) {} + bool operator()(const CFGBlock *b1, const CFGBlock *b2) const; + }; + + BlockOrderCompare getComparator() const { + return BlockOrderCompare(*this); + } + + // Used by AnalyisContext to construct this object. + static const void *getTag(); + + static PostOrderCFGView *create(AnalysisDeclContext &analysisContext); +}; + +} // end clang namespace + +#endif + diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/PseudoConstantAnalysis.h b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/PseudoConstantAnalysis.h new file mode 100644 index 0000000..c4ec2f2 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/PseudoConstantAnalysis.h @@ -0,0 +1,45 @@ +//== PseudoConstantAnalysis.h - Find Pseudo-constants in the AST -*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file tracks the usage of variables in a Decl body to see if they are +// never written to, implying that they constant. This is useful in static +// analysis to see if a developer might have intended a variable to be const. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_PSEUDOCONSTANTANALYSIS_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_PSEUDOCONSTANTANALYSIS_H + +#include "clang/AST/Stmt.h" + +namespace clang { + +class PseudoConstantAnalysis { +public: + PseudoConstantAnalysis(const Stmt *DeclBody); + ~PseudoConstantAnalysis(); + + bool isPseudoConstant(const VarDecl *VD); + bool wasReferenced(const VarDecl *VD); + +private: + void RunAnalysis(); + inline static const Decl *getDecl(const Expr *E); + + // for storing the result of analyzed ValueDecls + void *NonConstantsImpl; + void *UsedVarsImpl; + + const Stmt *DeclBody; + bool Analyzed; +}; + +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ReachableCode.h b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ReachableCode.h new file mode 100644 index 0000000..4c523bf --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ReachableCode.h @@ -0,0 +1,69 @@ +//===- ReachableCode.h -----------------------------------------*- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// A flow-sensitive, path-insensitive analysis of unreachable code. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_REACHABLECODE_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_REACHABLECODE_H + +#include "clang/Basic/SourceLocation.h" + +//===----------------------------------------------------------------------===// +// Forward declarations. +//===----------------------------------------------------------------------===// + +namespace llvm { + class BitVector; +} + +namespace clang { + class AnalysisDeclContext; + class CFGBlock; + class Preprocessor; +} + +//===----------------------------------------------------------------------===// +// API. +//===----------------------------------------------------------------------===// + +namespace clang { +namespace reachable_code { + +/// Classifications of unreachable code. +enum UnreachableKind { + UK_Return, + UK_Break, + UK_Loop_Increment, + UK_Other +}; + +class Callback { + virtual void anchor(); +public: + virtual ~Callback() {} + virtual void HandleUnreachable(UnreachableKind UK, + SourceLocation L, + SourceRange ConditionVal, + SourceRange R1, + SourceRange R2) = 0; +}; + +/// ScanReachableFromBlock - Mark all blocks reachable from Start. +/// Returns the total number of blocks that were marked reachable. +unsigned ScanReachableFromBlock(const CFGBlock *Start, + llvm::BitVector &Reachable); + +void FindUnreachableCode(AnalysisDeclContext &AC, Preprocessor &PP, + Callback &CB); + +}} // end namespace clang::reachable_code + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafety.h b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafety.h new file mode 100644 index 0000000..22694a7 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafety.h @@ -0,0 +1,226 @@ +//===- ThreadSafety.h ------------------------------------------*- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +// A intra-procedural analysis for thread safety (e.g. deadlocks and race +// conditions), based off of an annotation system. +// +// See http://clang.llvm.org/docs/LanguageExtensions.html#thread-safety-annotation-checking +// for more information. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETY_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETY_H + +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { +namespace threadSafety { + +class BeforeSet; + +/// This enum distinguishes between different kinds of operations that may +/// need to be protected by locks. We use this enum in error handling. +enum ProtectedOperationKind { + POK_VarDereference, ///< Dereferencing a variable (e.g. p in *p = 5;) + POK_VarAccess, ///< Reading or writing a variable (e.g. x in x = 5;) + POK_FunctionCall, ///< Making a function call (e.g. fool()) + POK_PassByRef, ///< Passing a guarded variable by reference. + POK_PtPassByRef, ///< Passing a pt-guarded variable by reference. +}; + +/// This enum distinguishes between different kinds of lock actions. For +/// example, it is an error to write a variable protected by shared version of a +/// mutex. +enum LockKind { + LK_Shared, ///< Shared/reader lock of a mutex. + LK_Exclusive, ///< Exclusive/writer lock of a mutex. + LK_Generic ///< Can be either Shared or Exclusive +}; + +/// This enum distinguishes between different ways to access (read or write) a +/// variable. +enum AccessKind { + AK_Read, ///< Reading a variable. + AK_Written ///< Writing a variable. +}; + +/// This enum distinguishes between different situations where we warn due to +/// inconsistent locking. +/// \enum SK_LockedSomeLoopIterations -- a mutex is locked for some but not all +/// loop iterations. +/// \enum SK_LockedSomePredecessors -- a mutex is locked in some but not all +/// predecessors of a CFGBlock. +/// \enum SK_LockedAtEndOfFunction -- a mutex is still locked at the end of a +/// function. +enum LockErrorKind { + LEK_LockedSomeLoopIterations, + LEK_LockedSomePredecessors, + LEK_LockedAtEndOfFunction, + LEK_NotLockedAtEndOfFunction +}; + +/// Handler class for thread safety warnings. +class ThreadSafetyHandler { +public: + typedef StringRef Name; + ThreadSafetyHandler() : IssueBetaWarnings(false) { } + virtual ~ThreadSafetyHandler(); + + /// Warn about lock expressions which fail to resolve to lockable objects. + /// \param Kind -- the capability's name parameter (role, mutex, etc). + /// \param Loc -- the SourceLocation of the unresolved expression. + virtual void handleInvalidLockExp(StringRef Kind, SourceLocation Loc) {} + + /// Warn about unlock function calls that do not have a prior matching lock + /// expression. + /// \param Kind -- the capability's name parameter (role, mutex, etc). + /// \param LockName -- A StringRef name for the lock expression, to be printed + /// in the error message. + /// \param Loc -- The SourceLocation of the Unlock + virtual void handleUnmatchedUnlock(StringRef Kind, Name LockName, + SourceLocation Loc) {} + + /// Warn about an unlock function call that attempts to unlock a lock with + /// the incorrect lock kind. For instance, a shared lock being unlocked + /// exclusively, or vice versa. + /// \param LockName -- A StringRef name for the lock expression, to be printed + /// in the error message. + /// \param Kind -- the capability's name parameter (role, mutex, etc). + /// \param Expected -- the kind of lock expected. + /// \param Received -- the kind of lock received. + /// \param Loc -- The SourceLocation of the Unlock. + virtual void handleIncorrectUnlockKind(StringRef Kind, Name LockName, + LockKind Expected, LockKind Received, + SourceLocation Loc) {} + + /// Warn about lock function calls for locks which are already held. + /// \param Kind -- the capability's name parameter (role, mutex, etc). + /// \param LockName -- A StringRef name for the lock expression, to be printed + /// in the error message. + /// \param Loc -- The location of the second lock expression. + virtual void handleDoubleLock(StringRef Kind, Name LockName, + SourceLocation Loc) {} + + /// Warn about situations where a mutex is sometimes held and sometimes not. + /// The three situations are: + /// 1. a mutex is locked on an "if" branch but not the "else" branch, + /// 2, or a mutex is only held at the start of some loop iterations, + /// 3. or when a mutex is locked but not unlocked inside a function. + /// \param Kind -- the capability's name parameter (role, mutex, etc). + /// \param LockName -- A StringRef name for the lock expression, to be printed + /// in the error message. + /// \param LocLocked -- The location of the lock expression where the mutex is + /// locked + /// \param LocEndOfScope -- The location of the end of the scope where the + /// mutex is no longer held + /// \param LEK -- which of the three above cases we should warn for + virtual void handleMutexHeldEndOfScope(StringRef Kind, Name LockName, + SourceLocation LocLocked, + SourceLocation LocEndOfScope, + LockErrorKind LEK) {} + + /// Warn when a mutex is held exclusively and shared at the same point. For + /// example, if a mutex is locked exclusively during an if branch and shared + /// during the else branch. + /// \param Kind -- the capability's name parameter (role, mutex, etc). + /// \param LockName -- A StringRef name for the lock expression, to be printed + /// in the error message. + /// \param Loc1 -- The location of the first lock expression. + /// \param Loc2 -- The location of the second lock expression. + virtual void handleExclusiveAndShared(StringRef Kind, Name LockName, + SourceLocation Loc1, + SourceLocation Loc2) {} + + /// Warn when a protected operation occurs while no locks are held. + /// \param Kind -- the capability's name parameter (role, mutex, etc). + /// \param D -- The decl for the protected variable or function + /// \param POK -- The kind of protected operation (e.g. variable access) + /// \param AK -- The kind of access (i.e. read or write) that occurred + /// \param Loc -- The location of the protected operation. + virtual void handleNoMutexHeld(StringRef Kind, const NamedDecl *D, + ProtectedOperationKind POK, AccessKind AK, + SourceLocation Loc) {} + + /// Warn when a protected operation occurs while the specific mutex protecting + /// the operation is not locked. + /// \param Kind -- the capability's name parameter (role, mutex, etc). + /// \param D -- The decl for the protected variable or function + /// \param POK -- The kind of protected operation (e.g. variable access) + /// \param LockName -- A StringRef name for the lock expression, to be printed + /// in the error message. + /// \param LK -- The kind of access (i.e. read or write) that occurred + /// \param Loc -- The location of the protected operation. + virtual void handleMutexNotHeld(StringRef Kind, const NamedDecl *D, + ProtectedOperationKind POK, Name LockName, + LockKind LK, SourceLocation Loc, + Name *PossibleMatch = nullptr) {} + + /// Warn when acquiring a lock that the negative capability is not held. + /// \param Kind -- the capability's name parameter (role, mutex, etc). + /// \param LockName -- The name for the lock expression, to be printed in the + /// diagnostic. + /// \param Neg -- The name of the negative capability to be printed in the + /// diagnostic. + /// \param Loc -- The location of the protected operation. + virtual void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg, + SourceLocation Loc) {} + + /// Warn when a function is called while an excluded mutex is locked. For + /// example, the mutex may be locked inside the function. + /// \param Kind -- the capability's name parameter (role, mutex, etc). + /// \param FunName -- The name of the function + /// \param LockName -- A StringRef name for the lock expression, to be printed + /// in the error message. + /// \param Loc -- The location of the function call. + virtual void handleFunExcludesLock(StringRef Kind, Name FunName, + Name LockName, SourceLocation Loc) {} + + + /// Warn that L1 cannot be acquired before L2. + virtual void handleLockAcquiredBefore(StringRef Kind, Name L1Name, + Name L2Name, SourceLocation Loc) {} + + /// Warn that there is a cycle in acquired_before/after dependencies. + virtual void handleBeforeAfterCycle(Name L1Name, SourceLocation Loc) {} + + /// Called by the analysis when starting analysis of a function. + /// Used to issue suggestions for changes to annotations. + virtual void enterFunction(const FunctionDecl *FD) {} + + /// Called by the analysis when finishing analysis of a function. + virtual void leaveFunction(const FunctionDecl *FD) {} + + bool issueBetaWarnings() { return IssueBetaWarnings; } + void setIssueBetaWarnings(bool b) { IssueBetaWarnings = b; } + +private: + bool IssueBetaWarnings; +}; + +/// \brief Check a function's CFG for thread-safety violations. +/// +/// We traverse the blocks in the CFG, compute the set of mutexes that are held +/// at the end of each block, and issue warnings for thread safety violations. +/// Each block in the CFG is traversed exactly once. +void runThreadSafetyAnalysis(AnalysisDeclContext &AC, + ThreadSafetyHandler &Handler, + BeforeSet **Bset); + +void threadSafetyCleanup(BeforeSet *Cache); + +/// \brief Helper function that returns a LockKind required for the given level +/// of access. +LockKind getLockKindFromAccessKind(AccessKind AK); + +}} // end namespace clang::threadSafety +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafetyCommon.h b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafetyCommon.h new file mode 100644 index 0000000..e357013 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafetyCommon.h @@ -0,0 +1,505 @@ +//===- ThreadSafetyCommon.h ------------------------------------*- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Parts of thread safety analysis that are not specific to thread safety +// itself have been factored into classes here, where they can be potentially +// used by other analyses. Currently these include: +// +// * Generalize clang CFG visitors. +// * Conversion of the clang CFG to SSA form. +// * Translation of clang Exprs to TIL SExprs +// +// UNDER CONSTRUCTION. USE AT YOUR OWN RISK. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYCOMMON_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYCOMMON_H + +#include "clang/Analysis/Analyses/PostOrderCFGView.h" +#include "clang/Analysis/Analyses/ThreadSafetyTIL.h" +#include "clang/Analysis/Analyses/ThreadSafetyTraverse.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Basic/OperatorKinds.h" +#include <memory> +#include <ostream> +#include <sstream> +#include <vector> + + +namespace clang { +namespace threadSafety { + + +// Various helper functions on til::SExpr +namespace sx { + +inline bool equals(const til::SExpr *E1, const til::SExpr *E2) { + return til::EqualsComparator::compareExprs(E1, E2); +} + +inline bool matches(const til::SExpr *E1, const til::SExpr *E2) { + // We treat a top-level wildcard as the "univsersal" lock. + // It matches everything for the purpose of checking locks, but not + // for unlocking them. + if (isa<til::Wildcard>(E1)) + return isa<til::Wildcard>(E2); + if (isa<til::Wildcard>(E2)) + return isa<til::Wildcard>(E1); + + return til::MatchComparator::compareExprs(E1, E2); +} + +inline bool partiallyMatches(const til::SExpr *E1, const til::SExpr *E2) { + const auto *PE1 = dyn_cast_or_null<til::Project>(E1); + if (!PE1) + return false; + const auto *PE2 = dyn_cast_or_null<til::Project>(E2); + if (!PE2) + return false; + return PE1->clangDecl() == PE2->clangDecl(); +} + +inline std::string toString(const til::SExpr *E) { + std::stringstream ss; + til::StdPrinter::print(E, ss); + return ss.str(); +} + +} // end namespace sx + + + +// This class defines the interface of a clang CFG Visitor. +// CFGWalker will invoke the following methods. +// Note that methods are not virtual; the visitor is templatized. +class CFGVisitor { + // Enter the CFG for Decl D, and perform any initial setup operations. + void enterCFG(CFG *Cfg, const NamedDecl *D, const CFGBlock *First) {} + + // Enter a CFGBlock. + void enterCFGBlock(const CFGBlock *B) {} + + // Returns true if this visitor implements handlePredecessor + bool visitPredecessors() { return true; } + + // Process a predecessor edge. + void handlePredecessor(const CFGBlock *Pred) {} + + // Process a successor back edge to a previously visited block. + void handlePredecessorBackEdge(const CFGBlock *Pred) {} + + // Called just before processing statements. + void enterCFGBlockBody(const CFGBlock *B) {} + + // Process an ordinary statement. + void handleStatement(const Stmt *S) {} + + // Process a destructor call + void handleDestructorCall(const VarDecl *VD, const CXXDestructorDecl *DD) {} + + // Called after all statements have been handled. + void exitCFGBlockBody(const CFGBlock *B) {} + + // Return true + bool visitSuccessors() { return true; } + + // Process a successor edge. + void handleSuccessor(const CFGBlock *Succ) {} + + // Process a successor back edge to a previously visited block. + void handleSuccessorBackEdge(const CFGBlock *Succ) {} + + // Leave a CFGBlock. + void exitCFGBlock(const CFGBlock *B) {} + + // Leave the CFG, and perform any final cleanup operations. + void exitCFG(const CFGBlock *Last) {} +}; + + +// Walks the clang CFG, and invokes methods on a given CFGVisitor. +class CFGWalker { +public: + CFGWalker() : CFGraph(nullptr), ACtx(nullptr), SortedGraph(nullptr) {} + + // Initialize the CFGWalker. This setup only needs to be done once, even + // if there are multiple passes over the CFG. + bool init(AnalysisDeclContext &AC) { + ACtx = &AC; + CFGraph = AC.getCFG(); + if (!CFGraph) + return false; + + // Ignore anonymous functions. + if (!dyn_cast_or_null<NamedDecl>(AC.getDecl())) + return false; + + SortedGraph = AC.getAnalysis<PostOrderCFGView>(); + if (!SortedGraph) + return false; + + return true; + } + + // Traverse the CFG, calling methods on V as appropriate. + template <class Visitor> + void walk(Visitor &V) { + PostOrderCFGView::CFGBlockSet VisitedBlocks(CFGraph); + + V.enterCFG(CFGraph, getDecl(), &CFGraph->getEntry()); + + for (const auto *CurrBlock : *SortedGraph) { + VisitedBlocks.insert(CurrBlock); + + V.enterCFGBlock(CurrBlock); + + // Process predecessors, handling back edges last + if (V.visitPredecessors()) { + SmallVector<CFGBlock*, 4> BackEdges; + // Process successors + for (CFGBlock::const_pred_iterator SI = CurrBlock->pred_begin(), + SE = CurrBlock->pred_end(); + SI != SE; ++SI) { + if (*SI == nullptr) + continue; + + if (!VisitedBlocks.alreadySet(*SI)) { + BackEdges.push_back(*SI); + continue; + } + V.handlePredecessor(*SI); + } + + for (auto *Blk : BackEdges) + V.handlePredecessorBackEdge(Blk); + } + + V.enterCFGBlockBody(CurrBlock); + + // Process statements + for (const auto &BI : *CurrBlock) { + switch (BI.getKind()) { + case CFGElement::Statement: { + V.handleStatement(BI.castAs<CFGStmt>().getStmt()); + break; + } + case CFGElement::AutomaticObjectDtor: { + CFGAutomaticObjDtor AD = BI.castAs<CFGAutomaticObjDtor>(); + CXXDestructorDecl *DD = const_cast<CXXDestructorDecl*>( + AD.getDestructorDecl(ACtx->getASTContext())); + VarDecl *VD = const_cast<VarDecl*>(AD.getVarDecl()); + V.handleDestructorCall(VD, DD); + break; + } + default: + break; + } + } + + V.exitCFGBlockBody(CurrBlock); + + // Process successors, handling back edges first. + if (V.visitSuccessors()) { + SmallVector<CFGBlock*, 8> ForwardEdges; + + // Process successors + for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(), + SE = CurrBlock->succ_end(); + SI != SE; ++SI) { + if (*SI == nullptr) + continue; + + if (!VisitedBlocks.alreadySet(*SI)) { + ForwardEdges.push_back(*SI); + continue; + } + V.handleSuccessorBackEdge(*SI); + } + + for (auto *Blk : ForwardEdges) + V.handleSuccessor(Blk); + } + + V.exitCFGBlock(CurrBlock); + } + V.exitCFG(&CFGraph->getExit()); + } + + const CFG *getGraph() const { return CFGraph; } + CFG *getGraph() { return CFGraph; } + + const NamedDecl *getDecl() const { + return dyn_cast<NamedDecl>(ACtx->getDecl()); + } + + const PostOrderCFGView *getSortedGraph() const { return SortedGraph; } + +private: + CFG *CFGraph; + AnalysisDeclContext *ACtx; + PostOrderCFGView *SortedGraph; +}; + + + + +class CapabilityExpr { + // TODO: move this back into ThreadSafety.cpp + // This is specific to thread safety. It is here because + // translateAttrExpr needs it, but that should be moved too. + +private: + const til::SExpr* CapExpr; ///< The capability expression. + bool Negated; ///< True if this is a negative capability + +public: + CapabilityExpr(const til::SExpr *E, bool Neg) : CapExpr(E), Negated(Neg) {} + + const til::SExpr* sexpr() const { return CapExpr; } + bool negative() const { return Negated; } + + CapabilityExpr operator!() const { + return CapabilityExpr(CapExpr, !Negated); + } + + bool equals(const CapabilityExpr &other) const { + return (Negated == other.Negated) && sx::equals(CapExpr, other.CapExpr); + } + + bool matches(const CapabilityExpr &other) const { + return (Negated == other.Negated) && sx::matches(CapExpr, other.CapExpr); + } + + bool matchesUniv(const CapabilityExpr &CapE) const { + return isUniversal() || matches(CapE); + } + + bool partiallyMatches(const CapabilityExpr &other) const { + return (Negated == other.Negated) && + sx::partiallyMatches(CapExpr, other.CapExpr); + } + + const ValueDecl* valueDecl() const { + if (Negated || CapExpr == nullptr) + return nullptr; + if (auto *P = dyn_cast<til::Project>(CapExpr)) + return P->clangDecl(); + if (auto *P = dyn_cast<til::LiteralPtr>(CapExpr)) + return P->clangDecl(); + return nullptr; + } + + std::string toString() const { + if (Negated) + return "!" + sx::toString(CapExpr); + return sx::toString(CapExpr); + } + + bool shouldIgnore() const { return CapExpr == nullptr; } + + bool isInvalid() const { return sexpr() && isa<til::Undefined>(sexpr()); } + + bool isUniversal() const { return sexpr() && isa<til::Wildcard>(sexpr()); } +}; + + + +// Translate clang::Expr to til::SExpr. +class SExprBuilder { +public: + /// \brief Encapsulates the lexical context of a function call. The lexical + /// context includes the arguments to the call, including the implicit object + /// argument. When an attribute containing a mutex expression is attached to + /// a method, the expression may refer to formal parameters of the method. + /// Actual arguments must be substituted for formal parameters to derive + /// the appropriate mutex expression in the lexical context where the function + /// is called. PrevCtx holds the context in which the arguments themselves + /// should be evaluated; multiple calling contexts can be chained together + /// by the lock_returned attribute. + struct CallingContext { + CallingContext *Prev; // The previous context; or 0 if none. + const NamedDecl *AttrDecl; // The decl to which the attr is attached. + const Expr *SelfArg; // Implicit object argument -- e.g. 'this' + unsigned NumArgs; // Number of funArgs + const Expr *const *FunArgs; // Function arguments + bool SelfArrow; // is Self referred to with -> or .? + + CallingContext(CallingContext *P, const NamedDecl *D = nullptr) + : Prev(P), AttrDecl(D), SelfArg(nullptr), + NumArgs(0), FunArgs(nullptr), SelfArrow(false) + {} + }; + + SExprBuilder(til::MemRegionRef A) + : Arena(A), SelfVar(nullptr), Scfg(nullptr), CurrentBB(nullptr), + CurrentBlockInfo(nullptr) { + // FIXME: we don't always have a self-variable. + SelfVar = new (Arena) til::Variable(nullptr); + SelfVar->setKind(til::Variable::VK_SFun); + } + + // Translate a clang expression in an attribute to a til::SExpr. + // Constructs the context from D, DeclExp, and SelfDecl. + CapabilityExpr translateAttrExpr(const Expr *AttrExp, const NamedDecl *D, + const Expr *DeclExp, VarDecl *SelfD=nullptr); + + CapabilityExpr translateAttrExpr(const Expr *AttrExp, CallingContext *Ctx); + + // Translate a clang statement or expression to a TIL expression. + // Also performs substitution of variables; Ctx provides the context. + // Dispatches on the type of S. + til::SExpr *translate(const Stmt *S, CallingContext *Ctx); + til::SCFG *buildCFG(CFGWalker &Walker); + + til::SExpr *lookupStmt(const Stmt *S); + + til::BasicBlock *lookupBlock(const CFGBlock *B) { + return BlockMap[B->getBlockID()]; + } + + const til::SCFG *getCFG() const { return Scfg; } + til::SCFG *getCFG() { return Scfg; } + +private: + til::SExpr *translateDeclRefExpr(const DeclRefExpr *DRE, + CallingContext *Ctx) ; + til::SExpr *translateCXXThisExpr(const CXXThisExpr *TE, CallingContext *Ctx); + til::SExpr *translateMemberExpr(const MemberExpr *ME, CallingContext *Ctx); + til::SExpr *translateCallExpr(const CallExpr *CE, CallingContext *Ctx, + const Expr *SelfE = nullptr); + til::SExpr *translateCXXMemberCallExpr(const CXXMemberCallExpr *ME, + CallingContext *Ctx); + til::SExpr *translateCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE, + CallingContext *Ctx); + til::SExpr *translateUnaryOperator(const UnaryOperator *UO, + CallingContext *Ctx); + til::SExpr *translateBinOp(til::TIL_BinaryOpcode Op, + const BinaryOperator *BO, + CallingContext *Ctx, bool Reverse = false); + til::SExpr *translateBinAssign(til::TIL_BinaryOpcode Op, + const BinaryOperator *BO, + CallingContext *Ctx, bool Assign = false); + til::SExpr *translateBinaryOperator(const BinaryOperator *BO, + CallingContext *Ctx); + til::SExpr *translateCastExpr(const CastExpr *CE, CallingContext *Ctx); + til::SExpr *translateArraySubscriptExpr(const ArraySubscriptExpr *E, + CallingContext *Ctx); + til::SExpr *translateAbstractConditionalOperator( + const AbstractConditionalOperator *C, CallingContext *Ctx); + + til::SExpr *translateDeclStmt(const DeclStmt *S, CallingContext *Ctx); + + // Map from statements in the clang CFG to SExprs in the til::SCFG. + typedef llvm::DenseMap<const Stmt*, til::SExpr*> StatementMap; + + // Map from clang local variables to indices in a LVarDefinitionMap. + typedef llvm::DenseMap<const ValueDecl *, unsigned> LVarIndexMap; + + // Map from local variable indices to SSA variables (or constants). + typedef std::pair<const ValueDecl *, til::SExpr *> NameVarPair; + typedef CopyOnWriteVector<NameVarPair> LVarDefinitionMap; + + struct BlockInfo { + LVarDefinitionMap ExitMap; + bool HasBackEdges; + unsigned UnprocessedSuccessors; // Successors yet to be processed + unsigned ProcessedPredecessors; // Predecessors already processed + + BlockInfo() + : HasBackEdges(false), UnprocessedSuccessors(0), + ProcessedPredecessors(0) {} + BlockInfo(BlockInfo &&RHS) + : ExitMap(std::move(RHS.ExitMap)), + HasBackEdges(RHS.HasBackEdges), + UnprocessedSuccessors(RHS.UnprocessedSuccessors), + ProcessedPredecessors(RHS.ProcessedPredecessors) {} + + BlockInfo &operator=(BlockInfo &&RHS) { + if (this != &RHS) { + ExitMap = std::move(RHS.ExitMap); + HasBackEdges = RHS.HasBackEdges; + UnprocessedSuccessors = RHS.UnprocessedSuccessors; + ProcessedPredecessors = RHS.ProcessedPredecessors; + } + return *this; + } + + private: + BlockInfo(const BlockInfo &) = delete; + void operator=(const BlockInfo &) = delete; + }; + + // We implement the CFGVisitor API + friend class CFGWalker; + + void enterCFG(CFG *Cfg, const NamedDecl *D, const CFGBlock *First); + void enterCFGBlock(const CFGBlock *B); + bool visitPredecessors() { return true; } + void handlePredecessor(const CFGBlock *Pred); + void handlePredecessorBackEdge(const CFGBlock *Pred); + void enterCFGBlockBody(const CFGBlock *B); + void handleStatement(const Stmt *S); + void handleDestructorCall(const VarDecl *VD, const CXXDestructorDecl *DD); + void exitCFGBlockBody(const CFGBlock *B); + bool visitSuccessors() { return true; } + void handleSuccessor(const CFGBlock *Succ); + void handleSuccessorBackEdge(const CFGBlock *Succ); + void exitCFGBlock(const CFGBlock *B); + void exitCFG(const CFGBlock *Last); + + void insertStmt(const Stmt *S, til::SExpr *E) { + SMap.insert(std::make_pair(S, E)); + } + til::SExpr *getCurrentLVarDefinition(const ValueDecl *VD); + + til::SExpr *addStatement(til::SExpr *E, const Stmt *S, + const ValueDecl *VD = nullptr); + til::SExpr *lookupVarDecl(const ValueDecl *VD); + til::SExpr *addVarDecl(const ValueDecl *VD, til::SExpr *E); + til::SExpr *updateVarDecl(const ValueDecl *VD, til::SExpr *E); + + void makePhiNodeVar(unsigned i, unsigned NPreds, til::SExpr *E); + void mergeEntryMap(LVarDefinitionMap Map); + void mergeEntryMapBackEdge(); + void mergePhiNodesBackEdge(const CFGBlock *Blk); + +private: + // Set to true when parsing capability expressions, which get translated + // inaccurately in order to hack around smart pointers etc. + static const bool CapabilityExprMode = true; + + til::MemRegionRef Arena; + til::Variable *SelfVar; // Variable to use for 'this'. May be null. + + til::SCFG *Scfg; + StatementMap SMap; // Map from Stmt to TIL Variables + LVarIndexMap LVarIdxMap; // Indices of clang local vars. + std::vector<til::BasicBlock *> BlockMap; // Map from clang to til BBs. + std::vector<BlockInfo> BBInfo; // Extra information per BB. + // Indexed by clang BlockID. + + LVarDefinitionMap CurrentLVarMap; + std::vector<til::Phi*> CurrentArguments; + std::vector<til::SExpr*> CurrentInstructions; + std::vector<til::Phi*> IncompleteArgs; + til::BasicBlock *CurrentBB; + BlockInfo *CurrentBlockInfo; +}; + + +// Dump an SCFG to llvm::errs(). +void printSCFG(CFGWalker &Walker); + + +} // end namespace threadSafety + +} // end namespace clang + +#endif // LLVM_CLANG_THREAD_SAFETY_COMMON_H diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafetyLogical.h b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafetyLogical.h new file mode 100644 index 0000000..bc78021 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafetyLogical.h @@ -0,0 +1,108 @@ +//===- ThreadSafetyLogical.h -----------------------------------*- 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 representation for logical expressions with SExpr leaves +// that are used as part of fact-checking capability expressions. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYLOGICAL_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYLOGICAL_H + +#include "clang/Analysis/Analyses/ThreadSafetyTIL.h" + +namespace clang { +namespace threadSafety { +namespace lexpr { + +class LExpr { +public: + enum Opcode { + Terminal, + And, + Or, + Not + }; + Opcode kind() const { return Kind; } + + /// \brief Logical implication. Returns true if the LExpr implies RHS, i.e. if + /// the LExpr holds, then RHS must hold. For example, (A & B) implies A. + inline bool implies(const LExpr *RHS) const; + +protected: + LExpr(Opcode Kind) : Kind(Kind) {} + +private: + Opcode Kind; +}; + +class Terminal : public LExpr { + til::SExpr *Expr; + +public: + Terminal(til::SExpr *Expr) : LExpr(LExpr::Terminal), Expr(Expr) {} + + const til::SExpr *expr() const { return Expr; } + til::SExpr *expr() { return Expr; } + + static bool classof(const LExpr *E) { return E->kind() == LExpr::Terminal; } +}; + +class BinOp : public LExpr { + LExpr *LHS, *RHS; + +protected: + BinOp(LExpr *LHS, LExpr *RHS, Opcode Code) : LExpr(Code), LHS(LHS), RHS(RHS) {} + +public: + const LExpr *left() const { return LHS; } + LExpr *left() { return LHS; } + + const LExpr *right() const { return RHS; } + LExpr *right() { return RHS; } +}; + +class And : public BinOp { +public: + And(LExpr *LHS, LExpr *RHS) : BinOp(LHS, RHS, LExpr::And) {} + + static bool classof(const LExpr *E) { return E->kind() == LExpr::And; } +}; + +class Or : public BinOp { +public: + Or(LExpr *LHS, LExpr *RHS) : BinOp(LHS, RHS, LExpr::Or) {} + + static bool classof(const LExpr *E) { return E->kind() == LExpr::Or; } +}; + +class Not : public LExpr { + LExpr *Exp; + +public: + Not(LExpr *Exp) : LExpr(LExpr::Not), Exp(Exp) {} + + const LExpr *exp() const { return Exp; } + LExpr *exp() { return Exp; } + + static bool classof(const LExpr *E) { return E->kind() == LExpr::Not; } +}; + +/// \brief Logical implication. Returns true if LHS implies RHS, i.e. if LHS +/// holds, then RHS must hold. For example, (A & B) implies A. +bool implies(const LExpr *LHS, const LExpr *RHS); + +bool LExpr::implies(const LExpr *RHS) const { + return lexpr::implies(this, RHS); +} + +} +} +} + +#endif + diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafetyOps.def b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafetyOps.def new file mode 100644 index 0000000..0d2458b --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafetyOps.def @@ -0,0 +1,57 @@ +//===- ThreadSafetyTIL.h ---------------------------------------*- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the list of core opcodes for the Thread Safety +// Typed Intermediate language. Please see ThreadSafetyTIL.h for more +// information. +// +//===----------------------------------------------------------------------===// + + +TIL_OPCODE_DEF(Future) +TIL_OPCODE_DEF(Undefined) +TIL_OPCODE_DEF(Wildcard) + +TIL_OPCODE_DEF(Literal) +TIL_OPCODE_DEF(LiteralPtr) +TIL_OPCODE_DEF(Variable) +TIL_OPCODE_DEF(Function) +TIL_OPCODE_DEF(SFunction) +TIL_OPCODE_DEF(Code) +TIL_OPCODE_DEF(Field) + +TIL_OPCODE_DEF(Apply) +TIL_OPCODE_DEF(SApply) +TIL_OPCODE_DEF(Project) + +TIL_OPCODE_DEF(Call) +TIL_OPCODE_DEF(Alloc) +TIL_OPCODE_DEF(Load) +TIL_OPCODE_DEF(Store) +TIL_OPCODE_DEF(ArrayIndex) +TIL_OPCODE_DEF(ArrayAdd) + +TIL_OPCODE_DEF(UnaryOp) +TIL_OPCODE_DEF(BinaryOp) +TIL_OPCODE_DEF(Cast) + +TIL_OPCODE_DEF(SCFG) +TIL_OPCODE_DEF(BasicBlock) +TIL_OPCODE_DEF(Phi) + +// Terminator instructions +TIL_OPCODE_DEF(Goto) +TIL_OPCODE_DEF(Branch) +TIL_OPCODE_DEF(Return) + +// pseudo-terms +TIL_OPCODE_DEF(Identifier) +TIL_OPCODE_DEF(IfThenElse) +TIL_OPCODE_DEF(Let) + diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafetyTIL.h b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafetyTIL.h new file mode 100644 index 0000000..be8a710 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafetyTIL.h @@ -0,0 +1,1918 @@ +//===- ThreadSafetyTIL.h ---------------------------------------*- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT in the llvm repository for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a simple Typed Intermediate Language, or TIL, that is used +// by the thread safety analysis (See ThreadSafety.cpp). The TIL is intended +// to be largely independent of clang, in the hope that the analysis can be +// reused for other non-C++ languages. All dependencies on clang/llvm should +// go in ThreadSafetyUtil.h. +// +// Thread safety analysis works by comparing mutex expressions, e.g. +// +// class A { Mutex mu; int dat GUARDED_BY(this->mu); } +// class B { A a; } +// +// void foo(B* b) { +// (*b).a.mu.lock(); // locks (*b).a.mu +// b->a.dat = 0; // substitute &b->a for 'this'; +// // requires lock on (&b->a)->mu +// (b->a.mu).unlock(); // unlocks (b->a.mu) +// } +// +// As illustrated by the above example, clang Exprs are not well-suited to +// represent mutex expressions directly, since there is no easy way to compare +// Exprs for equivalence. The thread safety analysis thus lowers clang Exprs +// into a simple intermediate language (IL). The IL supports: +// +// (1) comparisons for semantic equality of expressions +// (2) SSA renaming of variables +// (3) wildcards and pattern matching over expressions +// (4) hash-based expression lookup +// +// The TIL is currently very experimental, is intended only for use within +// the thread safety analysis, and is subject to change without notice. +// After the API stabilizes and matures, it may be appropriate to make this +// more generally available to other analyses. +// +// UNDER CONSTRUCTION. USE AT YOUR OWN RISK. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTIL_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTIL_H + +// All clang include dependencies for this file must be put in +// ThreadSafetyUtil.h. +#include "ThreadSafetyUtil.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <stdint.h> +#include <utility> + + +namespace clang { +namespace threadSafety { +namespace til { + + +/// Enum for the different distinct classes of SExpr +enum TIL_Opcode { +#define TIL_OPCODE_DEF(X) COP_##X, +#include "ThreadSafetyOps.def" +#undef TIL_OPCODE_DEF +}; + +/// Opcode for unary arithmetic operations. +enum TIL_UnaryOpcode : unsigned char { + UOP_Minus, // - + UOP_BitNot, // ~ + UOP_LogicNot // ! +}; + +/// Opcode for binary arithmetic operations. +enum TIL_BinaryOpcode : unsigned char { + BOP_Add, // + + BOP_Sub, // - + BOP_Mul, // * + BOP_Div, // / + BOP_Rem, // % + BOP_Shl, // << + BOP_Shr, // >> + BOP_BitAnd, // & + BOP_BitXor, // ^ + BOP_BitOr, // | + BOP_Eq, // == + BOP_Neq, // != + BOP_Lt, // < + BOP_Leq, // <= + BOP_LogicAnd, // && (no short-circuit) + BOP_LogicOr // || (no short-circuit) +}; + +/// Opcode for cast operations. +enum TIL_CastOpcode : unsigned char { + CAST_none = 0, + CAST_extendNum, // extend precision of numeric type + CAST_truncNum, // truncate precision of numeric type + CAST_toFloat, // convert to floating point type + CAST_toInt, // convert to integer type + CAST_objToPtr // convert smart pointer to pointer (C++ only) +}; + +const TIL_Opcode COP_Min = COP_Future; +const TIL_Opcode COP_Max = COP_Branch; +const TIL_UnaryOpcode UOP_Min = UOP_Minus; +const TIL_UnaryOpcode UOP_Max = UOP_LogicNot; +const TIL_BinaryOpcode BOP_Min = BOP_Add; +const TIL_BinaryOpcode BOP_Max = BOP_LogicOr; +const TIL_CastOpcode CAST_Min = CAST_none; +const TIL_CastOpcode CAST_Max = CAST_toInt; + +/// Return the name of a unary opcode. +StringRef getUnaryOpcodeString(TIL_UnaryOpcode Op); + +/// Return the name of a binary opcode. +StringRef getBinaryOpcodeString(TIL_BinaryOpcode Op); + + +/// ValueTypes are data types that can actually be held in registers. +/// All variables and expressions must have a value type. +/// Pointer types are further subdivided into the various heap-allocated +/// types, such as functions, records, etc. +/// Structured types that are passed by value (e.g. complex numbers) +/// require special handling; they use BT_ValueRef, and size ST_0. +struct ValueType { + enum BaseType : unsigned char { + BT_Void = 0, + BT_Bool, + BT_Int, + BT_Float, + BT_String, // String literals + BT_Pointer, + BT_ValueRef + }; + + enum SizeType : unsigned char { + ST_0 = 0, + ST_1, + ST_8, + ST_16, + ST_32, + ST_64, + ST_128 + }; + + inline static SizeType getSizeType(unsigned nbytes); + + template <class T> + inline static ValueType getValueType(); + + ValueType(BaseType B, SizeType Sz, bool S, unsigned char VS) + : Base(B), Size(Sz), Signed(S), VectSize(VS) + { } + + BaseType Base; + SizeType Size; + bool Signed; + unsigned char VectSize; // 0 for scalar, otherwise num elements in vector +}; + + +inline ValueType::SizeType ValueType::getSizeType(unsigned nbytes) { + switch (nbytes) { + case 1: return ST_8; + case 2: return ST_16; + case 4: return ST_32; + case 8: return ST_64; + case 16: return ST_128; + default: return ST_0; + } +} + + +template<> +inline ValueType ValueType::getValueType<void>() { + return ValueType(BT_Void, ST_0, false, 0); +} + +template<> +inline ValueType ValueType::getValueType<bool>() { + return ValueType(BT_Bool, ST_1, false, 0); +} + +template<> +inline ValueType ValueType::getValueType<int8_t>() { + return ValueType(BT_Int, ST_8, true, 0); +} + +template<> +inline ValueType ValueType::getValueType<uint8_t>() { + return ValueType(BT_Int, ST_8, false, 0); +} + +template<> +inline ValueType ValueType::getValueType<int16_t>() { + return ValueType(BT_Int, ST_16, true, 0); +} + +template<> +inline ValueType ValueType::getValueType<uint16_t>() { + return ValueType(BT_Int, ST_16, false, 0); +} + +template<> +inline ValueType ValueType::getValueType<int32_t>() { + return ValueType(BT_Int, ST_32, true, 0); +} + +template<> +inline ValueType ValueType::getValueType<uint32_t>() { + return ValueType(BT_Int, ST_32, false, 0); +} + +template<> +inline ValueType ValueType::getValueType<int64_t>() { + return ValueType(BT_Int, ST_64, true, 0); +} + +template<> +inline ValueType ValueType::getValueType<uint64_t>() { + return ValueType(BT_Int, ST_64, false, 0); +} + +template<> +inline ValueType ValueType::getValueType<float>() { + return ValueType(BT_Float, ST_32, true, 0); +} + +template<> +inline ValueType ValueType::getValueType<double>() { + return ValueType(BT_Float, ST_64, true, 0); +} + +template<> +inline ValueType ValueType::getValueType<long double>() { + return ValueType(BT_Float, ST_128, true, 0); +} + +template<> +inline ValueType ValueType::getValueType<StringRef>() { + return ValueType(BT_String, getSizeType(sizeof(StringRef)), false, 0); +} + +template<> +inline ValueType ValueType::getValueType<void*>() { + return ValueType(BT_Pointer, getSizeType(sizeof(void*)), false, 0); +} + + +class BasicBlock; + + +/// Base class for AST nodes in the typed intermediate language. +class SExpr { +public: + TIL_Opcode opcode() const { return static_cast<TIL_Opcode>(Opcode); } + + // Subclasses of SExpr must define the following: + // + // This(const This& E, ...) { + // copy constructor: construct copy of E, with some additional arguments. + // } + // + // template <class V> + // typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + // traverse all subexpressions, following the traversal/rewriter interface. + // } + // + // template <class C> typename C::CType compare(CType* E, C& Cmp) { + // compare all subexpressions, following the comparator interface + // } + void *operator new(size_t S, MemRegionRef &R) { + return ::operator new(S, R); + } + + /// SExpr objects cannot be deleted. + // This declaration is public to workaround a gcc bug that breaks building + // with REQUIRES_EH=1. + void operator delete(void *) = delete; + + /// Returns the instruction ID for this expression. + /// All basic block instructions have a unique ID (i.e. virtual register). + unsigned id() const { return SExprID; } + + /// Returns the block, if this is an instruction in a basic block, + /// otherwise returns null. + BasicBlock* block() const { return Block; } + + /// Set the basic block and instruction ID for this expression. + void setID(BasicBlock *B, unsigned id) { Block = B; SExprID = id; } + +protected: + SExpr(TIL_Opcode Op) + : Opcode(Op), Reserved(0), Flags(0), SExprID(0), Block(nullptr) {} + SExpr(const SExpr &E) + : Opcode(E.Opcode), Reserved(0), Flags(E.Flags), SExprID(0), + Block(nullptr) {} + + const unsigned char Opcode; + unsigned char Reserved; + unsigned short Flags; + unsigned SExprID; + BasicBlock* Block; + +private: + SExpr() = delete; + + /// SExpr objects must be created in an arena. + void *operator new(size_t) = delete; +}; + + +// Contains various helper functions for SExprs. +namespace ThreadSafetyTIL { + inline bool isTrivial(const SExpr *E) { + unsigned Op = E->opcode(); + return Op == COP_Variable || Op == COP_Literal || Op == COP_LiteralPtr; + } +} + +// Nodes which declare variables +class Function; +class SFunction; +class Let; + + +/// A named variable, e.g. "x". +/// +/// There are two distinct places in which a Variable can appear in the AST. +/// A variable declaration introduces a new variable, and can occur in 3 places: +/// Let-expressions: (Let (x = t) u) +/// Functions: (Function (x : t) u) +/// Self-applicable functions (SFunction (x) t) +/// +/// If a variable occurs in any other location, it is a reference to an existing +/// variable declaration -- e.g. 'x' in (x * y + z). To save space, we don't +/// allocate a separate AST node for variable references; a reference is just a +/// pointer to the original declaration. +class Variable : public SExpr { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_Variable; } + + enum VariableKind { + VK_Let, ///< Let-variable + VK_Fun, ///< Function parameter + VK_SFun ///< SFunction (self) parameter + }; + + Variable(StringRef s, SExpr *D = nullptr) + : SExpr(COP_Variable), Name(s), Definition(D), Cvdecl(nullptr) { + Flags = VK_Let; + } + Variable(SExpr *D, const clang::ValueDecl *Cvd = nullptr) + : SExpr(COP_Variable), Name(Cvd ? Cvd->getName() : "_x"), + Definition(D), Cvdecl(Cvd) { + Flags = VK_Let; + } + Variable(const Variable &Vd, SExpr *D) // rewrite constructor + : SExpr(Vd), Name(Vd.Name), Definition(D), Cvdecl(Vd.Cvdecl) { + Flags = Vd.kind(); + } + + /// Return the kind of variable (let, function param, or self) + VariableKind kind() const { return static_cast<VariableKind>(Flags); } + + /// Return the name of the variable, if any. + StringRef name() const { return Name; } + + /// Return the clang declaration for this variable, if any. + const clang::ValueDecl *clangDecl() const { return Cvdecl; } + + /// Return the definition of the variable. + /// For let-vars, this is the setting expression. + /// For function and self parameters, it is the type of the variable. + SExpr *definition() { return Definition; } + const SExpr *definition() const { return Definition; } + + void setName(StringRef S) { Name = S; } + void setKind(VariableKind K) { Flags = K; } + void setDefinition(SExpr *E) { Definition = E; } + void setClangDecl(const clang::ValueDecl *VD) { Cvdecl = VD; } + + template <class V> + typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + // This routine is only called for variable references. + return Vs.reduceVariableRef(this); + } + + template <class C> + typename C::CType compare(const Variable* E, C& Cmp) const { + return Cmp.compareVariableRefs(this, E); + } + +private: + friend class Function; + friend class SFunction; + friend class BasicBlock; + friend class Let; + + StringRef Name; // The name of the variable. + SExpr* Definition; // The TIL type or definition + const clang::ValueDecl *Cvdecl; // The clang declaration for this variable. +}; + + +/// Placeholder for an expression that has not yet been created. +/// Used to implement lazy copy and rewriting strategies. +class Future : public SExpr { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_Future; } + + enum FutureStatus { + FS_pending, + FS_evaluating, + FS_done + }; + + Future() : SExpr(COP_Future), Status(FS_pending), Result(nullptr) {} + +private: + virtual ~Future() = delete; + +public: + // A lazy rewriting strategy should subclass Future and override this method. + virtual SExpr *compute() { return nullptr; } + + // Return the result of this future if it exists, otherwise return null. + SExpr *maybeGetResult() const { + return Result; + } + + // Return the result of this future; forcing it if necessary. + SExpr *result() { + switch (Status) { + case FS_pending: + return force(); + case FS_evaluating: + return nullptr; // infinite loop; illegal recursion. + case FS_done: + return Result; + } + } + + template <class V> + typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + assert(Result && "Cannot traverse Future that has not been forced."); + return Vs.traverse(Result, Ctx); + } + + template <class C> + typename C::CType compare(const Future* E, C& Cmp) const { + if (!Result || !E->Result) + return Cmp.comparePointers(this, E); + return Cmp.compare(Result, E->Result); + } + +private: + SExpr* force(); + + FutureStatus Status; + SExpr *Result; +}; + + +/// Placeholder for expressions that cannot be represented in the TIL. +class Undefined : public SExpr { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_Undefined; } + + Undefined(const clang::Stmt *S = nullptr) : SExpr(COP_Undefined), Cstmt(S) {} + Undefined(const Undefined &U) : SExpr(U), Cstmt(U.Cstmt) {} + + template <class V> + typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + return Vs.reduceUndefined(*this); + } + + template <class C> + typename C::CType compare(const Undefined* E, C& Cmp) const { + return Cmp.trueResult(); + } + +private: + const clang::Stmt *Cstmt; +}; + + +/// Placeholder for a wildcard that matches any other expression. +class Wildcard : public SExpr { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_Wildcard; } + + Wildcard() : SExpr(COP_Wildcard) {} + Wildcard(const Wildcard &W) : SExpr(W) {} + + template <class V> typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + return Vs.reduceWildcard(*this); + } + + template <class C> + typename C::CType compare(const Wildcard* E, C& Cmp) const { + return Cmp.trueResult(); + } +}; + + +template <class T> class LiteralT; + +// Base class for literal values. +class Literal : public SExpr { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_Literal; } + + Literal(const clang::Expr *C) + : SExpr(COP_Literal), ValType(ValueType::getValueType<void>()), Cexpr(C) + { } + Literal(ValueType VT) : SExpr(COP_Literal), ValType(VT), Cexpr(nullptr) {} + Literal(const Literal &L) : SExpr(L), ValType(L.ValType), Cexpr(L.Cexpr) {} + + // The clang expression for this literal. + const clang::Expr *clangExpr() const { return Cexpr; } + + ValueType valueType() const { return ValType; } + + template<class T> const LiteralT<T>& as() const { + return *static_cast<const LiteralT<T>*>(this); + } + template<class T> LiteralT<T>& as() { + return *static_cast<LiteralT<T>*>(this); + } + + template <class V> typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx); + + template <class C> + typename C::CType compare(const Literal* E, C& Cmp) const { + // TODO: defer actual comparison to LiteralT + return Cmp.trueResult(); + } + +private: + const ValueType ValType; + const clang::Expr *Cexpr; +}; + + +// Derived class for literal values, which stores the actual value. +template<class T> +class LiteralT : public Literal { +public: + LiteralT(T Dat) : Literal(ValueType::getValueType<T>()), Val(Dat) { } + LiteralT(const LiteralT<T> &L) : Literal(L), Val(L.Val) { } + + T value() const { return Val;} + T& value() { return Val; } + +private: + T Val; +}; + + + +template <class V> +typename V::R_SExpr Literal::traverse(V &Vs, typename V::R_Ctx Ctx) { + if (Cexpr) + return Vs.reduceLiteral(*this); + + switch (ValType.Base) { + case ValueType::BT_Void: + break; + case ValueType::BT_Bool: + return Vs.reduceLiteralT(as<bool>()); + case ValueType::BT_Int: { + switch (ValType.Size) { + case ValueType::ST_8: + if (ValType.Signed) + return Vs.reduceLiteralT(as<int8_t>()); + else + return Vs.reduceLiteralT(as<uint8_t>()); + case ValueType::ST_16: + if (ValType.Signed) + return Vs.reduceLiteralT(as<int16_t>()); + else + return Vs.reduceLiteralT(as<uint16_t>()); + case ValueType::ST_32: + if (ValType.Signed) + return Vs.reduceLiteralT(as<int32_t>()); + else + return Vs.reduceLiteralT(as<uint32_t>()); + case ValueType::ST_64: + if (ValType.Signed) + return Vs.reduceLiteralT(as<int64_t>()); + else + return Vs.reduceLiteralT(as<uint64_t>()); + default: + break; + } + } + case ValueType::BT_Float: { + switch (ValType.Size) { + case ValueType::ST_32: + return Vs.reduceLiteralT(as<float>()); + case ValueType::ST_64: + return Vs.reduceLiteralT(as<double>()); + default: + break; + } + } + case ValueType::BT_String: + return Vs.reduceLiteralT(as<StringRef>()); + case ValueType::BT_Pointer: + return Vs.reduceLiteralT(as<void*>()); + case ValueType::BT_ValueRef: + break; + } + return Vs.reduceLiteral(*this); +} + + +/// A Literal pointer to an object allocated in memory. +/// At compile time, pointer literals are represented by symbolic names. +class LiteralPtr : public SExpr { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_LiteralPtr; } + + LiteralPtr(const clang::ValueDecl *D) : SExpr(COP_LiteralPtr), Cvdecl(D) {} + LiteralPtr(const LiteralPtr &R) : SExpr(R), Cvdecl(R.Cvdecl) {} + + // The clang declaration for the value that this pointer points to. + const clang::ValueDecl *clangDecl() const { return Cvdecl; } + + template <class V> + typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + return Vs.reduceLiteralPtr(*this); + } + + template <class C> + typename C::CType compare(const LiteralPtr* E, C& Cmp) const { + return Cmp.comparePointers(Cvdecl, E->Cvdecl); + } + +private: + const clang::ValueDecl *Cvdecl; +}; + + +/// A function -- a.k.a. lambda abstraction. +/// Functions with multiple arguments are created by currying, +/// e.g. (Function (x: Int) (Function (y: Int) (Code { return x + y }))) +class Function : public SExpr { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_Function; } + + Function(Variable *Vd, SExpr *Bd) + : SExpr(COP_Function), VarDecl(Vd), Body(Bd) { + Vd->setKind(Variable::VK_Fun); + } + Function(const Function &F, Variable *Vd, SExpr *Bd) // rewrite constructor + : SExpr(F), VarDecl(Vd), Body(Bd) { + Vd->setKind(Variable::VK_Fun); + } + + Variable *variableDecl() { return VarDecl; } + const Variable *variableDecl() const { return VarDecl; } + + SExpr *body() { return Body; } + const SExpr *body() const { return Body; } + + template <class V> + typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + // This is a variable declaration, so traverse the definition. + auto E0 = Vs.traverse(VarDecl->Definition, Vs.typeCtx(Ctx)); + // Tell the rewriter to enter the scope of the function. + Variable *Nvd = Vs.enterScope(*VarDecl, E0); + auto E1 = Vs.traverse(Body, Vs.declCtx(Ctx)); + Vs.exitScope(*VarDecl); + return Vs.reduceFunction(*this, Nvd, E1); + } + + template <class C> + typename C::CType compare(const Function* E, C& Cmp) const { + typename C::CType Ct = + Cmp.compare(VarDecl->definition(), E->VarDecl->definition()); + if (Cmp.notTrue(Ct)) + return Ct; + Cmp.enterScope(variableDecl(), E->variableDecl()); + Ct = Cmp.compare(body(), E->body()); + Cmp.leaveScope(); + return Ct; + } + +private: + Variable *VarDecl; + SExpr* Body; +}; + + +/// A self-applicable function. +/// A self-applicable function can be applied to itself. It's useful for +/// implementing objects and late binding. +class SFunction : public SExpr { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_SFunction; } + + SFunction(Variable *Vd, SExpr *B) + : SExpr(COP_SFunction), VarDecl(Vd), Body(B) { + assert(Vd->Definition == nullptr); + Vd->setKind(Variable::VK_SFun); + Vd->Definition = this; + } + SFunction(const SFunction &F, Variable *Vd, SExpr *B) // rewrite constructor + : SExpr(F), VarDecl(Vd), Body(B) { + assert(Vd->Definition == nullptr); + Vd->setKind(Variable::VK_SFun); + Vd->Definition = this; + } + + Variable *variableDecl() { return VarDecl; } + const Variable *variableDecl() const { return VarDecl; } + + SExpr *body() { return Body; } + const SExpr *body() const { return Body; } + + template <class V> + typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + // A self-variable points to the SFunction itself. + // A rewrite must introduce the variable with a null definition, and update + // it after 'this' has been rewritten. + Variable *Nvd = Vs.enterScope(*VarDecl, nullptr); + auto E1 = Vs.traverse(Body, Vs.declCtx(Ctx)); + Vs.exitScope(*VarDecl); + // A rewrite operation will call SFun constructor to set Vvd->Definition. + return Vs.reduceSFunction(*this, Nvd, E1); + } + + template <class C> + typename C::CType compare(const SFunction* E, C& Cmp) const { + Cmp.enterScope(variableDecl(), E->variableDecl()); + typename C::CType Ct = Cmp.compare(body(), E->body()); + Cmp.leaveScope(); + return Ct; + } + +private: + Variable *VarDecl; + SExpr* Body; +}; + + +/// A block of code -- e.g. the body of a function. +class Code : public SExpr { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_Code; } + + Code(SExpr *T, SExpr *B) : SExpr(COP_Code), ReturnType(T), Body(B) {} + Code(const Code &C, SExpr *T, SExpr *B) // rewrite constructor + : SExpr(C), ReturnType(T), Body(B) {} + + SExpr *returnType() { return ReturnType; } + const SExpr *returnType() const { return ReturnType; } + + SExpr *body() { return Body; } + const SExpr *body() const { return Body; } + + template <class V> + typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + auto Nt = Vs.traverse(ReturnType, Vs.typeCtx(Ctx)); + auto Nb = Vs.traverse(Body, Vs.lazyCtx(Ctx)); + return Vs.reduceCode(*this, Nt, Nb); + } + + template <class C> + typename C::CType compare(const Code* E, C& Cmp) const { + typename C::CType Ct = Cmp.compare(returnType(), E->returnType()); + if (Cmp.notTrue(Ct)) + return Ct; + return Cmp.compare(body(), E->body()); + } + +private: + SExpr* ReturnType; + SExpr* Body; +}; + + +/// A typed, writable location in memory +class Field : public SExpr { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_Field; } + + Field(SExpr *R, SExpr *B) : SExpr(COP_Field), Range(R), Body(B) {} + Field(const Field &C, SExpr *R, SExpr *B) // rewrite constructor + : SExpr(C), Range(R), Body(B) {} + + SExpr *range() { return Range; } + const SExpr *range() const { return Range; } + + SExpr *body() { return Body; } + const SExpr *body() const { return Body; } + + template <class V> + typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + auto Nr = Vs.traverse(Range, Vs.typeCtx(Ctx)); + auto Nb = Vs.traverse(Body, Vs.lazyCtx(Ctx)); + return Vs.reduceField(*this, Nr, Nb); + } + + template <class C> + typename C::CType compare(const Field* E, C& Cmp) const { + typename C::CType Ct = Cmp.compare(range(), E->range()); + if (Cmp.notTrue(Ct)) + return Ct; + return Cmp.compare(body(), E->body()); + } + +private: + SExpr* Range; + SExpr* Body; +}; + + +/// Apply an argument to a function. +/// Note that this does not actually call the function. Functions are curried, +/// so this returns a closure in which the first parameter has been applied. +/// Once all parameters have been applied, Call can be used to invoke the +/// function. +class Apply : public SExpr { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_Apply; } + + Apply(SExpr *F, SExpr *A) : SExpr(COP_Apply), Fun(F), Arg(A) {} + Apply(const Apply &A, SExpr *F, SExpr *Ar) // rewrite constructor + : SExpr(A), Fun(F), Arg(Ar) + {} + + SExpr *fun() { return Fun; } + const SExpr *fun() const { return Fun; } + + SExpr *arg() { return Arg; } + const SExpr *arg() const { return Arg; } + + template <class V> + typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + auto Nf = Vs.traverse(Fun, Vs.subExprCtx(Ctx)); + auto Na = Vs.traverse(Arg, Vs.subExprCtx(Ctx)); + return Vs.reduceApply(*this, Nf, Na); + } + + template <class C> + typename C::CType compare(const Apply* E, C& Cmp) const { + typename C::CType Ct = Cmp.compare(fun(), E->fun()); + if (Cmp.notTrue(Ct)) + return Ct; + return Cmp.compare(arg(), E->arg()); + } + +private: + SExpr* Fun; + SExpr* Arg; +}; + + +/// Apply a self-argument to a self-applicable function. +class SApply : public SExpr { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_SApply; } + + SApply(SExpr *Sf, SExpr *A = nullptr) : SExpr(COP_SApply), Sfun(Sf), Arg(A) {} + SApply(SApply &A, SExpr *Sf, SExpr *Ar = nullptr) // rewrite constructor + : SExpr(A), Sfun(Sf), Arg(Ar) {} + + SExpr *sfun() { return Sfun; } + const SExpr *sfun() const { return Sfun; } + + SExpr *arg() { return Arg ? Arg : Sfun; } + const SExpr *arg() const { return Arg ? Arg : Sfun; } + + bool isDelegation() const { return Arg != nullptr; } + + template <class V> + typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + auto Nf = Vs.traverse(Sfun, Vs.subExprCtx(Ctx)); + typename V::R_SExpr Na = Arg ? Vs.traverse(Arg, Vs.subExprCtx(Ctx)) + : nullptr; + return Vs.reduceSApply(*this, Nf, Na); + } + + template <class C> + typename C::CType compare(const SApply* E, C& Cmp) const { + typename C::CType Ct = Cmp.compare(sfun(), E->sfun()); + if (Cmp.notTrue(Ct) || (!arg() && !E->arg())) + return Ct; + return Cmp.compare(arg(), E->arg()); + } + +private: + SExpr* Sfun; + SExpr* Arg; +}; + + +/// Project a named slot from a C++ struct or class. +class Project : public SExpr { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_Project; } + + Project(SExpr *R, StringRef SName) + : SExpr(COP_Project), Rec(R), SlotName(SName), Cvdecl(nullptr) + { } + Project(SExpr *R, const clang::ValueDecl *Cvd) + : SExpr(COP_Project), Rec(R), SlotName(Cvd->getName()), Cvdecl(Cvd) + { } + Project(const Project &P, SExpr *R) + : SExpr(P), Rec(R), SlotName(P.SlotName), Cvdecl(P.Cvdecl) + { } + + SExpr *record() { return Rec; } + const SExpr *record() const { return Rec; } + + const clang::ValueDecl *clangDecl() const { return Cvdecl; } + + bool isArrow() const { return (Flags & 0x01) != 0; } + void setArrow(bool b) { + if (b) Flags |= 0x01; + else Flags &= 0xFFFE; + } + + StringRef slotName() const { + if (Cvdecl) + return Cvdecl->getName(); + else + return SlotName; + } + + template <class V> + typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + auto Nr = Vs.traverse(Rec, Vs.subExprCtx(Ctx)); + return Vs.reduceProject(*this, Nr); + } + + template <class C> + typename C::CType compare(const Project* E, C& Cmp) const { + typename C::CType Ct = Cmp.compare(record(), E->record()); + if (Cmp.notTrue(Ct)) + return Ct; + return Cmp.comparePointers(Cvdecl, E->Cvdecl); + } + +private: + SExpr* Rec; + StringRef SlotName; + const clang::ValueDecl *Cvdecl; +}; + + +/// Call a function (after all arguments have been applied). +class Call : public SExpr { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_Call; } + + Call(SExpr *T, const clang::CallExpr *Ce = nullptr) + : SExpr(COP_Call), Target(T), Cexpr(Ce) {} + Call(const Call &C, SExpr *T) : SExpr(C), Target(T), Cexpr(C.Cexpr) {} + + SExpr *target() { return Target; } + const SExpr *target() const { return Target; } + + const clang::CallExpr *clangCallExpr() const { return Cexpr; } + + template <class V> + typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + auto Nt = Vs.traverse(Target, Vs.subExprCtx(Ctx)); + return Vs.reduceCall(*this, Nt); + } + + template <class C> + typename C::CType compare(const Call* E, C& Cmp) const { + return Cmp.compare(target(), E->target()); + } + +private: + SExpr* Target; + const clang::CallExpr *Cexpr; +}; + + +/// Allocate memory for a new value on the heap or stack. +class Alloc : public SExpr { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_Call; } + + enum AllocKind { + AK_Stack, + AK_Heap + }; + + Alloc(SExpr *D, AllocKind K) : SExpr(COP_Alloc), Dtype(D) { Flags = K; } + Alloc(const Alloc &A, SExpr *Dt) : SExpr(A), Dtype(Dt) { Flags = A.kind(); } + + AllocKind kind() const { return static_cast<AllocKind>(Flags); } + + SExpr *dataType() { return Dtype; } + const SExpr *dataType() const { return Dtype; } + + template <class V> + typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + auto Nd = Vs.traverse(Dtype, Vs.declCtx(Ctx)); + return Vs.reduceAlloc(*this, Nd); + } + + template <class C> + typename C::CType compare(const Alloc* E, C& Cmp) const { + typename C::CType Ct = Cmp.compareIntegers(kind(), E->kind()); + if (Cmp.notTrue(Ct)) + return Ct; + return Cmp.compare(dataType(), E->dataType()); + } + +private: + SExpr* Dtype; +}; + + +/// Load a value from memory. +class Load : public SExpr { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_Load; } + + Load(SExpr *P) : SExpr(COP_Load), Ptr(P) {} + Load(const Load &L, SExpr *P) : SExpr(L), Ptr(P) {} + + SExpr *pointer() { return Ptr; } + const SExpr *pointer() const { return Ptr; } + + template <class V> + typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + auto Np = Vs.traverse(Ptr, Vs.subExprCtx(Ctx)); + return Vs.reduceLoad(*this, Np); + } + + template <class C> + typename C::CType compare(const Load* E, C& Cmp) const { + return Cmp.compare(pointer(), E->pointer()); + } + +private: + SExpr* Ptr; +}; + + +/// Store a value to memory. +/// The destination is a pointer to a field, the source is the value to store. +class Store : public SExpr { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_Store; } + + Store(SExpr *P, SExpr *V) : SExpr(COP_Store), Dest(P), Source(V) {} + Store(const Store &S, SExpr *P, SExpr *V) : SExpr(S), Dest(P), Source(V) {} + + SExpr *destination() { return Dest; } // Address to store to + const SExpr *destination() const { return Dest; } + + SExpr *source() { return Source; } // Value to store + const SExpr *source() const { return Source; } + + template <class V> + typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + auto Np = Vs.traverse(Dest, Vs.subExprCtx(Ctx)); + auto Nv = Vs.traverse(Source, Vs.subExprCtx(Ctx)); + return Vs.reduceStore(*this, Np, Nv); + } + + template <class C> + typename C::CType compare(const Store* E, C& Cmp) const { + typename C::CType Ct = Cmp.compare(destination(), E->destination()); + if (Cmp.notTrue(Ct)) + return Ct; + return Cmp.compare(source(), E->source()); + } + +private: + SExpr* Dest; + SExpr* Source; +}; + + +/// If p is a reference to an array, then p[i] is a reference to the i'th +/// element of the array. +class ArrayIndex : public SExpr { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_ArrayIndex; } + + ArrayIndex(SExpr *A, SExpr *N) : SExpr(COP_ArrayIndex), Array(A), Index(N) {} + ArrayIndex(const ArrayIndex &E, SExpr *A, SExpr *N) + : SExpr(E), Array(A), Index(N) {} + + SExpr *array() { return Array; } + const SExpr *array() const { return Array; } + + SExpr *index() { return Index; } + const SExpr *index() const { return Index; } + + template <class V> + typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + auto Na = Vs.traverse(Array, Vs.subExprCtx(Ctx)); + auto Ni = Vs.traverse(Index, Vs.subExprCtx(Ctx)); + return Vs.reduceArrayIndex(*this, Na, Ni); + } + + template <class C> + typename C::CType compare(const ArrayIndex* E, C& Cmp) const { + typename C::CType Ct = Cmp.compare(array(), E->array()); + if (Cmp.notTrue(Ct)) + return Ct; + return Cmp.compare(index(), E->index()); + } + +private: + SExpr* Array; + SExpr* Index; +}; + + +/// Pointer arithmetic, restricted to arrays only. +/// If p is a reference to an array, then p + n, where n is an integer, is +/// a reference to a subarray. +class ArrayAdd : public SExpr { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_ArrayAdd; } + + ArrayAdd(SExpr *A, SExpr *N) : SExpr(COP_ArrayAdd), Array(A), Index(N) {} + ArrayAdd(const ArrayAdd &E, SExpr *A, SExpr *N) + : SExpr(E), Array(A), Index(N) {} + + SExpr *array() { return Array; } + const SExpr *array() const { return Array; } + + SExpr *index() { return Index; } + const SExpr *index() const { return Index; } + + template <class V> + typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + auto Na = Vs.traverse(Array, Vs.subExprCtx(Ctx)); + auto Ni = Vs.traverse(Index, Vs.subExprCtx(Ctx)); + return Vs.reduceArrayAdd(*this, Na, Ni); + } + + template <class C> + typename C::CType compare(const ArrayAdd* E, C& Cmp) const { + typename C::CType Ct = Cmp.compare(array(), E->array()); + if (Cmp.notTrue(Ct)) + return Ct; + return Cmp.compare(index(), E->index()); + } + +private: + SExpr* Array; + SExpr* Index; +}; + + +/// Simple arithmetic unary operations, e.g. negate and not. +/// These operations have no side-effects. +class UnaryOp : public SExpr { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_UnaryOp; } + + UnaryOp(TIL_UnaryOpcode Op, SExpr *E) : SExpr(COP_UnaryOp), Expr0(E) { + Flags = Op; + } + UnaryOp(const UnaryOp &U, SExpr *E) : SExpr(U), Expr0(E) { Flags = U.Flags; } + + TIL_UnaryOpcode unaryOpcode() const { + return static_cast<TIL_UnaryOpcode>(Flags); + } + + SExpr *expr() { return Expr0; } + const SExpr *expr() const { return Expr0; } + + template <class V> + typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + auto Ne = Vs.traverse(Expr0, Vs.subExprCtx(Ctx)); + return Vs.reduceUnaryOp(*this, Ne); + } + + template <class C> + typename C::CType compare(const UnaryOp* E, C& Cmp) const { + typename C::CType Ct = + Cmp.compareIntegers(unaryOpcode(), E->unaryOpcode()); + if (Cmp.notTrue(Ct)) + return Ct; + return Cmp.compare(expr(), E->expr()); + } + +private: + SExpr* Expr0; +}; + + +/// Simple arithmetic binary operations, e.g. +, -, etc. +/// These operations have no side effects. +class BinaryOp : public SExpr { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_BinaryOp; } + + BinaryOp(TIL_BinaryOpcode Op, SExpr *E0, SExpr *E1) + : SExpr(COP_BinaryOp), Expr0(E0), Expr1(E1) { + Flags = Op; + } + BinaryOp(const BinaryOp &B, SExpr *E0, SExpr *E1) + : SExpr(B), Expr0(E0), Expr1(E1) { + Flags = B.Flags; + } + + TIL_BinaryOpcode binaryOpcode() const { + return static_cast<TIL_BinaryOpcode>(Flags); + } + + SExpr *expr0() { return Expr0; } + const SExpr *expr0() const { return Expr0; } + + SExpr *expr1() { return Expr1; } + const SExpr *expr1() const { return Expr1; } + + template <class V> + typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + auto Ne0 = Vs.traverse(Expr0, Vs.subExprCtx(Ctx)); + auto Ne1 = Vs.traverse(Expr1, Vs.subExprCtx(Ctx)); + return Vs.reduceBinaryOp(*this, Ne0, Ne1); + } + + template <class C> + typename C::CType compare(const BinaryOp* E, C& Cmp) const { + typename C::CType Ct = + Cmp.compareIntegers(binaryOpcode(), E->binaryOpcode()); + if (Cmp.notTrue(Ct)) + return Ct; + Ct = Cmp.compare(expr0(), E->expr0()); + if (Cmp.notTrue(Ct)) + return Ct; + return Cmp.compare(expr1(), E->expr1()); + } + +private: + SExpr* Expr0; + SExpr* Expr1; +}; + + +/// Cast expressions. +/// Cast expressions are essentially unary operations, but we treat them +/// as a distinct AST node because they only change the type of the result. +class Cast : public SExpr { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_Cast; } + + Cast(TIL_CastOpcode Op, SExpr *E) : SExpr(COP_Cast), Expr0(E) { Flags = Op; } + Cast(const Cast &C, SExpr *E) : SExpr(C), Expr0(E) { Flags = C.Flags; } + + TIL_CastOpcode castOpcode() const { + return static_cast<TIL_CastOpcode>(Flags); + } + + SExpr *expr() { return Expr0; } + const SExpr *expr() const { return Expr0; } + + template <class V> + typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + auto Ne = Vs.traverse(Expr0, Vs.subExprCtx(Ctx)); + return Vs.reduceCast(*this, Ne); + } + + template <class C> + typename C::CType compare(const Cast* E, C& Cmp) const { + typename C::CType Ct = + Cmp.compareIntegers(castOpcode(), E->castOpcode()); + if (Cmp.notTrue(Ct)) + return Ct; + return Cmp.compare(expr(), E->expr()); + } + +private: + SExpr* Expr0; +}; + + +class SCFG; + + +/// Phi Node, for code in SSA form. +/// Each Phi node has an array of possible values that it can take, +/// depending on where control flow comes from. +class Phi : public SExpr { +public: + typedef SimpleArray<SExpr *> ValArray; + + // In minimal SSA form, all Phi nodes are MultiVal. + // During conversion to SSA, incomplete Phi nodes may be introduced, which + // are later determined to be SingleVal, and are thus redundant. + enum Status { + PH_MultiVal = 0, // Phi node has multiple distinct values. (Normal) + PH_SingleVal, // Phi node has one distinct value, and can be eliminated + PH_Incomplete // Phi node is incomplete + }; + + static bool classof(const SExpr *E) { return E->opcode() == COP_Phi; } + + Phi() + : SExpr(COP_Phi), Cvdecl(nullptr) {} + Phi(MemRegionRef A, unsigned Nvals) + : SExpr(COP_Phi), Values(A, Nvals), Cvdecl(nullptr) {} + Phi(const Phi &P, ValArray &&Vs) + : SExpr(P), Values(std::move(Vs)), Cvdecl(nullptr) {} + + const ValArray &values() const { return Values; } + ValArray &values() { return Values; } + + Status status() const { return static_cast<Status>(Flags); } + void setStatus(Status s) { Flags = s; } + + /// Return the clang declaration of the variable for this Phi node, if any. + const clang::ValueDecl *clangDecl() const { return Cvdecl; } + + /// Set the clang variable associated with this Phi node. + void setClangDecl(const clang::ValueDecl *Cvd) { Cvdecl = Cvd; } + + template <class V> + typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + typename V::template Container<typename V::R_SExpr> + Nvs(Vs, Values.size()); + + for (auto *Val : Values) { + Nvs.push_back( Vs.traverse(Val, Vs.subExprCtx(Ctx)) ); + } + return Vs.reducePhi(*this, Nvs); + } + + template <class C> + typename C::CType compare(const Phi *E, C &Cmp) const { + // TODO: implement CFG comparisons + return Cmp.comparePointers(this, E); + } + +private: + ValArray Values; + const clang::ValueDecl* Cvdecl; +}; + + +/// Base class for basic block terminators: Branch, Goto, and Return. +class Terminator : public SExpr { +public: + static bool classof(const SExpr *E) { + return E->opcode() >= COP_Goto && E->opcode() <= COP_Return; + } + +protected: + Terminator(TIL_Opcode Op) : SExpr(Op) {} + Terminator(const SExpr &E) : SExpr(E) {} + +public: + /// Return the list of basic blocks that this terminator can branch to. + ArrayRef<BasicBlock*> successors(); + + ArrayRef<BasicBlock*> successors() const { + return const_cast<Terminator*>(this)->successors(); + } +}; + + +/// Jump to another basic block. +/// A goto instruction is essentially a tail-recursive call into another +/// block. In addition to the block pointer, it specifies an index into the +/// phi nodes of that block. The index can be used to retrieve the "arguments" +/// of the call. +class Goto : public Terminator { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_Goto; } + + Goto(BasicBlock *B, unsigned I) + : Terminator(COP_Goto), TargetBlock(B), Index(I) {} + Goto(const Goto &G, BasicBlock *B, unsigned I) + : Terminator(COP_Goto), TargetBlock(B), Index(I) {} + + const BasicBlock *targetBlock() const { return TargetBlock; } + BasicBlock *targetBlock() { return TargetBlock; } + + /// Returns the index into the + unsigned index() const { return Index; } + + /// Return the list of basic blocks that this terminator can branch to. + ArrayRef<BasicBlock*> successors() { + return TargetBlock; + } + + template <class V> + typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + BasicBlock *Ntb = Vs.reduceBasicBlockRef(TargetBlock); + return Vs.reduceGoto(*this, Ntb); + } + + template <class C> + typename C::CType compare(const Goto *E, C &Cmp) const { + // TODO: implement CFG comparisons + return Cmp.comparePointers(this, E); + } + +private: + BasicBlock *TargetBlock; + unsigned Index; +}; + + +/// A conditional branch to two other blocks. +/// Note that unlike Goto, Branch does not have an index. The target blocks +/// must be child-blocks, and cannot have Phi nodes. +class Branch : public Terminator { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_Branch; } + + Branch(SExpr *C, BasicBlock *T, BasicBlock *E) + : Terminator(COP_Branch), Condition(C) { + Branches[0] = T; + Branches[1] = E; + } + Branch(const Branch &Br, SExpr *C, BasicBlock *T, BasicBlock *E) + : Terminator(Br), Condition(C) { + Branches[0] = T; + Branches[1] = E; + } + + const SExpr *condition() const { return Condition; } + SExpr *condition() { return Condition; } + + const BasicBlock *thenBlock() const { return Branches[0]; } + BasicBlock *thenBlock() { return Branches[0]; } + + const BasicBlock *elseBlock() const { return Branches[1]; } + BasicBlock *elseBlock() { return Branches[1]; } + + /// Return the list of basic blocks that this terminator can branch to. + ArrayRef<BasicBlock*> successors() { + return llvm::makeArrayRef(Branches); + } + + template <class V> + typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + auto Nc = Vs.traverse(Condition, Vs.subExprCtx(Ctx)); + BasicBlock *Ntb = Vs.reduceBasicBlockRef(Branches[0]); + BasicBlock *Nte = Vs.reduceBasicBlockRef(Branches[1]); + return Vs.reduceBranch(*this, Nc, Ntb, Nte); + } + + template <class C> + typename C::CType compare(const Branch *E, C &Cmp) const { + // TODO: implement CFG comparisons + return Cmp.comparePointers(this, E); + } + +private: + SExpr* Condition; + BasicBlock *Branches[2]; +}; + + +/// Return from the enclosing function, passing the return value to the caller. +/// Only the exit block should end with a return statement. +class Return : public Terminator { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_Return; } + + Return(SExpr* Rval) : Terminator(COP_Return), Retval(Rval) {} + Return(const Return &R, SExpr* Rval) : Terminator(R), Retval(Rval) {} + + /// Return an empty list. + ArrayRef<BasicBlock*> successors() { + return None; + } + + SExpr *returnValue() { return Retval; } + const SExpr *returnValue() const { return Retval; } + + template <class V> + typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + auto Ne = Vs.traverse(Retval, Vs.subExprCtx(Ctx)); + return Vs.reduceReturn(*this, Ne); + } + + template <class C> + typename C::CType compare(const Return *E, C &Cmp) const { + return Cmp.compare(Retval, E->Retval); + } + +private: + SExpr* Retval; +}; + + +inline ArrayRef<BasicBlock*> Terminator::successors() { + switch (opcode()) { + case COP_Goto: return cast<Goto>(this)->successors(); + case COP_Branch: return cast<Branch>(this)->successors(); + case COP_Return: return cast<Return>(this)->successors(); + default: + return None; + } +} + + +/// A basic block is part of an SCFG. It can be treated as a function in +/// continuation passing style. A block consists of a sequence of phi nodes, +/// which are "arguments" to the function, followed by a sequence of +/// instructions. It ends with a Terminator, which is a Branch or Goto to +/// another basic block in the same SCFG. +class BasicBlock : public SExpr { +public: + typedef SimpleArray<SExpr*> InstrArray; + typedef SimpleArray<BasicBlock*> BlockArray; + + // TopologyNodes are used to overlay tree structures on top of the CFG, + // such as dominator and postdominator trees. Each block is assigned an + // ID in the tree according to a depth-first search. Tree traversals are + // always up, towards the parents. + struct TopologyNode { + TopologyNode() : NodeID(0), SizeOfSubTree(0), Parent(nullptr) {} + + bool isParentOf(const TopologyNode& OtherNode) { + return OtherNode.NodeID > NodeID && + OtherNode.NodeID < NodeID + SizeOfSubTree; + } + + bool isParentOfOrEqual(const TopologyNode& OtherNode) { + return OtherNode.NodeID >= NodeID && + OtherNode.NodeID < NodeID + SizeOfSubTree; + } + + int NodeID; + int SizeOfSubTree; // Includes this node, so must be > 1. + BasicBlock *Parent; // Pointer to parent. + }; + + static bool classof(const SExpr *E) { return E->opcode() == COP_BasicBlock; } + + explicit BasicBlock(MemRegionRef A) + : SExpr(COP_BasicBlock), Arena(A), CFGPtr(nullptr), BlockID(0), + Visited(0), TermInstr(nullptr) {} + BasicBlock(BasicBlock &B, MemRegionRef A, InstrArray &&As, InstrArray &&Is, + Terminator *T) + : SExpr(COP_BasicBlock), Arena(A), CFGPtr(nullptr), BlockID(0),Visited(0), + Args(std::move(As)), Instrs(std::move(Is)), TermInstr(T) {} + + /// Returns the block ID. Every block has a unique ID in the CFG. + int blockID() const { return BlockID; } + + /// Returns the number of predecessors. + size_t numPredecessors() const { return Predecessors.size(); } + size_t numSuccessors() const { return successors().size(); } + + const SCFG* cfg() const { return CFGPtr; } + SCFG* cfg() { return CFGPtr; } + + const BasicBlock *parent() const { return DominatorNode.Parent; } + BasicBlock *parent() { return DominatorNode.Parent; } + + const InstrArray &arguments() const { return Args; } + InstrArray &arguments() { return Args; } + + InstrArray &instructions() { return Instrs; } + const InstrArray &instructions() const { return Instrs; } + + /// Returns a list of predecessors. + /// The order of predecessors in the list is important; each phi node has + /// exactly one argument for each precessor, in the same order. + BlockArray &predecessors() { return Predecessors; } + const BlockArray &predecessors() const { return Predecessors; } + + ArrayRef<BasicBlock*> successors() { return TermInstr->successors(); } + ArrayRef<BasicBlock*> successors() const { return TermInstr->successors(); } + + const Terminator *terminator() const { return TermInstr; } + Terminator *terminator() { return TermInstr; } + + void setTerminator(Terminator *E) { TermInstr = E; } + + bool Dominates(const BasicBlock &Other) { + return DominatorNode.isParentOfOrEqual(Other.DominatorNode); + } + + bool PostDominates(const BasicBlock &Other) { + return PostDominatorNode.isParentOfOrEqual(Other.PostDominatorNode); + } + + /// Add a new argument. + void addArgument(Phi *V) { + Args.reserveCheck(1, Arena); + Args.push_back(V); + } + /// Add a new instruction. + void addInstruction(SExpr *V) { + Instrs.reserveCheck(1, Arena); + Instrs.push_back(V); + } + // Add a new predecessor, and return the phi-node index for it. + // Will add an argument to all phi-nodes, initialized to nullptr. + unsigned addPredecessor(BasicBlock *Pred); + + // Reserve space for Nargs arguments. + void reserveArguments(unsigned Nargs) { Args.reserve(Nargs, Arena); } + + // Reserve space for Nins instructions. + void reserveInstructions(unsigned Nins) { Instrs.reserve(Nins, Arena); } + + // Reserve space for NumPreds predecessors, including space in phi nodes. + void reservePredecessors(unsigned NumPreds); + + /// Return the index of BB, or Predecessors.size if BB is not a predecessor. + unsigned findPredecessorIndex(const BasicBlock *BB) const { + auto I = std::find(Predecessors.cbegin(), Predecessors.cend(), BB); + return std::distance(Predecessors.cbegin(), I); + } + + template <class V> + typename V::R_BasicBlock traverse(V &Vs, typename V::R_Ctx Ctx) { + typename V::template Container<SExpr*> Nas(Vs, Args.size()); + typename V::template Container<SExpr*> Nis(Vs, Instrs.size()); + + // Entering the basic block should do any scope initialization. + Vs.enterBasicBlock(*this); + + for (auto *E : Args) { + auto Ne = Vs.traverse(E, Vs.subExprCtx(Ctx)); + Nas.push_back(Ne); + } + for (auto *E : Instrs) { + auto Ne = Vs.traverse(E, Vs.subExprCtx(Ctx)); + Nis.push_back(Ne); + } + auto Nt = Vs.traverse(TermInstr, Ctx); + + // Exiting the basic block should handle any scope cleanup. + Vs.exitBasicBlock(*this); + + return Vs.reduceBasicBlock(*this, Nas, Nis, Nt); + } + + template <class C> + typename C::CType compare(const BasicBlock *E, C &Cmp) const { + // TODO: implement CFG comparisons + return Cmp.comparePointers(this, E); + } + +private: + friend class SCFG; + + int renumberInstrs(int id); // assign unique ids to all instructions + int topologicalSort(SimpleArray<BasicBlock*>& Blocks, int ID); + int topologicalFinalSort(SimpleArray<BasicBlock*>& Blocks, int ID); + void computeDominator(); + void computePostDominator(); + +private: + MemRegionRef Arena; // The arena used to allocate this block. + SCFG *CFGPtr; // The CFG that contains this block. + int BlockID : 31; // unique id for this BB in the containing CFG. + // IDs are in topological order. + bool Visited : 1; // Bit to determine if a block has been visited + // during a traversal. + BlockArray Predecessors; // Predecessor blocks in the CFG. + InstrArray Args; // Phi nodes. One argument per predecessor. + InstrArray Instrs; // Instructions. + Terminator* TermInstr; // Terminating instruction + + TopologyNode DominatorNode; // The dominator tree + TopologyNode PostDominatorNode; // The post-dominator tree +}; + + +/// An SCFG is a control-flow graph. It consists of a set of basic blocks, +/// each of which terminates in a branch to another basic block. There is one +/// entry point, and one exit point. +class SCFG : public SExpr { +public: + typedef SimpleArray<BasicBlock *> BlockArray; + typedef BlockArray::iterator iterator; + typedef BlockArray::const_iterator const_iterator; + + static bool classof(const SExpr *E) { return E->opcode() == COP_SCFG; } + + SCFG(MemRegionRef A, unsigned Nblocks) + : SExpr(COP_SCFG), Arena(A), Blocks(A, Nblocks), + Entry(nullptr), Exit(nullptr), NumInstructions(0), Normal(false) { + Entry = new (A) BasicBlock(A); + Exit = new (A) BasicBlock(A); + auto *V = new (A) Phi(); + Exit->addArgument(V); + Exit->setTerminator(new (A) Return(V)); + add(Entry); + add(Exit); + } + SCFG(const SCFG &Cfg, BlockArray &&Ba) // steals memory from Ba + : SExpr(COP_SCFG), Arena(Cfg.Arena), Blocks(std::move(Ba)), + Entry(nullptr), Exit(nullptr), NumInstructions(0), Normal(false) { + // TODO: set entry and exit! + } + + /// Return true if this CFG is valid. + bool valid() const { return Entry && Exit && Blocks.size() > 0; } + + /// Return true if this CFG has been normalized. + /// After normalization, blocks are in topological order, and block and + /// instruction IDs have been assigned. + bool normal() const { return Normal; } + + iterator begin() { return Blocks.begin(); } + iterator end() { return Blocks.end(); } + + const_iterator begin() const { return cbegin(); } + const_iterator end() const { return cend(); } + + const_iterator cbegin() const { return Blocks.cbegin(); } + const_iterator cend() const { return Blocks.cend(); } + + const BasicBlock *entry() const { return Entry; } + BasicBlock *entry() { return Entry; } + const BasicBlock *exit() const { return Exit; } + BasicBlock *exit() { return Exit; } + + /// Return the number of blocks in the CFG. + /// Block::blockID() will return a number less than numBlocks(); + size_t numBlocks() const { return Blocks.size(); } + + /// Return the total number of instructions in the CFG. + /// This is useful for building instruction side-tables; + /// A call to SExpr::id() will return a number less than numInstructions(). + unsigned numInstructions() { return NumInstructions; } + + inline void add(BasicBlock *BB) { + assert(BB->CFGPtr == nullptr); + BB->CFGPtr = this; + Blocks.reserveCheck(1, Arena); + Blocks.push_back(BB); + } + + void setEntry(BasicBlock *BB) { Entry = BB; } + void setExit(BasicBlock *BB) { Exit = BB; } + + void computeNormalForm(); + + template <class V> + typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + Vs.enterCFG(*this); + typename V::template Container<BasicBlock *> Bbs(Vs, Blocks.size()); + + for (auto *B : Blocks) { + Bbs.push_back( B->traverse(Vs, Vs.subExprCtx(Ctx)) ); + } + Vs.exitCFG(*this); + return Vs.reduceSCFG(*this, Bbs); + } + + template <class C> + typename C::CType compare(const SCFG *E, C &Cmp) const { + // TODO: implement CFG comparisons + return Cmp.comparePointers(this, E); + } + +private: + void renumberInstrs(); // assign unique ids to all instructions + +private: + MemRegionRef Arena; + BlockArray Blocks; + BasicBlock *Entry; + BasicBlock *Exit; + unsigned NumInstructions; + bool Normal; +}; + + + +/// An identifier, e.g. 'foo' or 'x'. +/// This is a pseduo-term; it will be lowered to a variable or projection. +class Identifier : public SExpr { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_Identifier; } + + Identifier(StringRef Id): SExpr(COP_Identifier), Name(Id) { } + Identifier(const Identifier& I) : SExpr(I), Name(I.Name) { } + + StringRef name() const { return Name; } + + template <class V> + typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + return Vs.reduceIdentifier(*this); + } + + template <class C> + typename C::CType compare(const Identifier* E, C& Cmp) const { + return Cmp.compareStrings(name(), E->name()); + } + +private: + StringRef Name; +}; + + +/// An if-then-else expression. +/// This is a pseduo-term; it will be lowered to a branch in a CFG. +class IfThenElse : public SExpr { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_IfThenElse; } + + IfThenElse(SExpr *C, SExpr *T, SExpr *E) + : SExpr(COP_IfThenElse), Condition(C), ThenExpr(T), ElseExpr(E) + { } + IfThenElse(const IfThenElse &I, SExpr *C, SExpr *T, SExpr *E) + : SExpr(I), Condition(C), ThenExpr(T), ElseExpr(E) + { } + + SExpr *condition() { return Condition; } // Address to store to + const SExpr *condition() const { return Condition; } + + SExpr *thenExpr() { return ThenExpr; } // Value to store + const SExpr *thenExpr() const { return ThenExpr; } + + SExpr *elseExpr() { return ElseExpr; } // Value to store + const SExpr *elseExpr() const { return ElseExpr; } + + template <class V> + typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + auto Nc = Vs.traverse(Condition, Vs.subExprCtx(Ctx)); + auto Nt = Vs.traverse(ThenExpr, Vs.subExprCtx(Ctx)); + auto Ne = Vs.traverse(ElseExpr, Vs.subExprCtx(Ctx)); + return Vs.reduceIfThenElse(*this, Nc, Nt, Ne); + } + + template <class C> + typename C::CType compare(const IfThenElse* E, C& Cmp) const { + typename C::CType Ct = Cmp.compare(condition(), E->condition()); + if (Cmp.notTrue(Ct)) + return Ct; + Ct = Cmp.compare(thenExpr(), E->thenExpr()); + if (Cmp.notTrue(Ct)) + return Ct; + return Cmp.compare(elseExpr(), E->elseExpr()); + } + +private: + SExpr* Condition; + SExpr* ThenExpr; + SExpr* ElseExpr; +}; + + +/// A let-expression, e.g. let x=t; u. +/// This is a pseduo-term; it will be lowered to instructions in a CFG. +class Let : public SExpr { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_Let; } + + Let(Variable *Vd, SExpr *Bd) : SExpr(COP_Let), VarDecl(Vd), Body(Bd) { + Vd->setKind(Variable::VK_Let); + } + Let(const Let &L, Variable *Vd, SExpr *Bd) : SExpr(L), VarDecl(Vd), Body(Bd) { + Vd->setKind(Variable::VK_Let); + } + + Variable *variableDecl() { return VarDecl; } + const Variable *variableDecl() const { return VarDecl; } + + SExpr *body() { return Body; } + const SExpr *body() const { return Body; } + + template <class V> + typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + // This is a variable declaration, so traverse the definition. + auto E0 = Vs.traverse(VarDecl->Definition, Vs.subExprCtx(Ctx)); + // Tell the rewriter to enter the scope of the let variable. + Variable *Nvd = Vs.enterScope(*VarDecl, E0); + auto E1 = Vs.traverse(Body, Ctx); + Vs.exitScope(*VarDecl); + return Vs.reduceLet(*this, Nvd, E1); + } + + template <class C> + typename C::CType compare(const Let* E, C& Cmp) const { + typename C::CType Ct = + Cmp.compare(VarDecl->definition(), E->VarDecl->definition()); + if (Cmp.notTrue(Ct)) + return Ct; + Cmp.enterScope(variableDecl(), E->variableDecl()); + Ct = Cmp.compare(body(), E->body()); + Cmp.leaveScope(); + return Ct; + } + +private: + Variable *VarDecl; + SExpr* Body; +}; + + + +const SExpr *getCanonicalVal(const SExpr *E); +SExpr* simplifyToCanonicalVal(SExpr *E); +void simplifyIncompleteArg(til::Phi *Ph); + + +} // end namespace til +} // end namespace threadSafety +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h new file mode 100644 index 0000000..705fe91 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h @@ -0,0 +1,902 @@ +//===- ThreadSafetyTraverse.h ----------------------------------*- 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 framework for doing generic traversals and rewriting +// operations over the Thread Safety TIL. +// +// UNDER CONSTRUCTION. USE AT YOUR OWN RISK. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTRAVERSE_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTRAVERSE_H + +#include "ThreadSafetyTIL.h" +#include <ostream> + +namespace clang { +namespace threadSafety { +namespace til { + +// Defines an interface used to traverse SExprs. Traversals have been made as +// generic as possible, and are intended to handle any kind of pass over the +// AST, e.g. visiters, copying, non-destructive rewriting, destructive +// (in-place) rewriting, hashing, typing, etc. +// +// Traversals implement the functional notion of a "fold" operation on SExprs. +// Each SExpr class provides a traverse method, which does the following: +// * e->traverse(v): +// // compute a result r_i for each subexpression e_i +// for (i = 1..n) r_i = v.traverse(e_i); +// // combine results into a result for e, where X is the class of e +// return v.reduceX(*e, r_1, .. r_n). +// +// A visitor can control the traversal by overriding the following methods: +// * v.traverse(e): +// return v.traverseByCase(e), which returns v.traverseX(e) +// * v.traverseX(e): (X is the class of e) +// return e->traverse(v). +// * v.reduceX(*e, r_1, .. r_n): +// compute a result for a node of type X +// +// The reduceX methods control the kind of traversal (visitor, copy, etc.). +// They are defined in derived classes. +// +// Class R defines the basic interface types (R_SExpr). +template <class Self, class R> +class Traversal { +public: + Self *self() { return static_cast<Self *>(this); } + + // Traverse an expression -- returning a result of type R_SExpr. + // Override this method to do something for every expression, regardless + // of which kind it is. + // E is a reference, so this can be use for in-place updates. + // The type T must be a subclass of SExpr. + template <class T> + typename R::R_SExpr traverse(T* &E, typename R::R_Ctx Ctx) { + return traverseSExpr(E, Ctx); + } + + // Override this method to do something for every expression. + // Does not allow in-place updates. + typename R::R_SExpr traverseSExpr(SExpr *E, typename R::R_Ctx Ctx) { + return traverseByCase(E, Ctx); + } + + // Helper method to call traverseX(e) on the appropriate type. + typename R::R_SExpr traverseByCase(SExpr *E, typename R::R_Ctx Ctx) { + switch (E->opcode()) { +#define TIL_OPCODE_DEF(X) \ + case COP_##X: \ + return self()->traverse##X(cast<X>(E), Ctx); +#include "ThreadSafetyOps.def" +#undef TIL_OPCODE_DEF + } + return self()->reduceNull(); + } + +// Traverse e, by static dispatch on the type "X" of e. +// Override these methods to do something for a particular kind of term. +#define TIL_OPCODE_DEF(X) \ + typename R::R_SExpr traverse##X(X *e, typename R::R_Ctx Ctx) { \ + return e->traverse(*self(), Ctx); \ + } +#include "ThreadSafetyOps.def" +#undef TIL_OPCODE_DEF +}; + + +// Base class for simple reducers that don't much care about the context. +class SimpleReducerBase { +public: + enum TraversalKind { + TRV_Normal, // ordinary subexpressions + TRV_Decl, // declarations (e.g. function bodies) + TRV_Lazy, // expressions that require lazy evaluation + TRV_Type // type expressions + }; + + // R_Ctx defines a "context" for the traversal, which encodes information + // about where a term appears. This can be used to encoding the + // "current continuation" for CPS transforms, or other information. + typedef TraversalKind R_Ctx; + + // Create context for an ordinary subexpression. + R_Ctx subExprCtx(R_Ctx Ctx) { return TRV_Normal; } + + // Create context for a subexpression that occurs in a declaration position + // (e.g. function body). + R_Ctx declCtx(R_Ctx Ctx) { return TRV_Decl; } + + // Create context for a subexpression that occurs in a position that + // should be reduced lazily. (e.g. code body). + R_Ctx lazyCtx(R_Ctx Ctx) { return TRV_Lazy; } + + // Create context for a subexpression that occurs in a type position. + R_Ctx typeCtx(R_Ctx Ctx) { return TRV_Type; } +}; + + +// Base class for traversals that rewrite an SExpr to another SExpr. +class CopyReducerBase : public SimpleReducerBase { +public: + // R_SExpr is the result type for a traversal. + // A copy or non-destructive rewrite returns a newly allocated term. + typedef SExpr *R_SExpr; + typedef BasicBlock *R_BasicBlock; + + // Container is a minimal interface used to store results when traversing + // SExprs of variable arity, such as Phi, Goto, and SCFG. + template <class T> class Container { + public: + // Allocate a new container with a capacity for n elements. + Container(CopyReducerBase &S, unsigned N) : Elems(S.Arena, N) {} + + // Push a new element onto the container. + void push_back(T E) { Elems.push_back(E); } + + SimpleArray<T> Elems; + }; + + CopyReducerBase(MemRegionRef A) : Arena(A) {} + +protected: + MemRegionRef Arena; +}; + + +// Base class for visit traversals. +class VisitReducerBase : public SimpleReducerBase { +public: + // A visitor returns a bool, representing success or failure. + typedef bool R_SExpr; + typedef bool R_BasicBlock; + + // A visitor "container" is a single bool, which accumulates success. + template <class T> class Container { + public: + Container(VisitReducerBase &S, unsigned N) : Success(true) {} + void push_back(bool E) { Success = Success && E; } + + bool Success; + }; +}; + + +// Implements a traversal that visits each subexpression, and returns either +// true or false. +template <class Self> +class VisitReducer : public Traversal<Self, VisitReducerBase>, + public VisitReducerBase { +public: + VisitReducer() {} + +public: + R_SExpr reduceNull() { return true; } + R_SExpr reduceUndefined(Undefined &Orig) { return true; } + R_SExpr reduceWildcard(Wildcard &Orig) { return true; } + + R_SExpr reduceLiteral(Literal &Orig) { return true; } + template<class T> + R_SExpr reduceLiteralT(LiteralT<T> &Orig) { return true; } + R_SExpr reduceLiteralPtr(Literal &Orig) { return true; } + + R_SExpr reduceFunction(Function &Orig, Variable *Nvd, R_SExpr E0) { + return Nvd && E0; + } + R_SExpr reduceSFunction(SFunction &Orig, Variable *Nvd, R_SExpr E0) { + return Nvd && E0; + } + R_SExpr reduceCode(Code &Orig, R_SExpr E0, R_SExpr E1) { + return E0 && E1; + } + R_SExpr reduceField(Field &Orig, R_SExpr E0, R_SExpr E1) { + return E0 && E1; + } + R_SExpr reduceApply(Apply &Orig, R_SExpr E0, R_SExpr E1) { + return E0 && E1; + } + R_SExpr reduceSApply(SApply &Orig, R_SExpr E0, R_SExpr E1) { + return E0 && E1; + } + R_SExpr reduceProject(Project &Orig, R_SExpr E0) { return E0; } + R_SExpr reduceCall(Call &Orig, R_SExpr E0) { return E0; } + R_SExpr reduceAlloc(Alloc &Orig, R_SExpr E0) { return E0; } + R_SExpr reduceLoad(Load &Orig, R_SExpr E0) { return E0; } + R_SExpr reduceStore(Store &Orig, R_SExpr E0, R_SExpr E1) { return E0 && E1; } + R_SExpr reduceArrayIndex(Store &Orig, R_SExpr E0, R_SExpr E1) { + return E0 && E1; + } + R_SExpr reduceArrayAdd(Store &Orig, R_SExpr E0, R_SExpr E1) { + return E0 && E1; + } + R_SExpr reduceUnaryOp(UnaryOp &Orig, R_SExpr E0) { return E0; } + R_SExpr reduceBinaryOp(BinaryOp &Orig, R_SExpr E0, R_SExpr E1) { + return E0 && E1; + } + R_SExpr reduceCast(Cast &Orig, R_SExpr E0) { return E0; } + + R_SExpr reduceSCFG(SCFG &Orig, Container<BasicBlock *> Bbs) { + return Bbs.Success; + } + R_BasicBlock reduceBasicBlock(BasicBlock &Orig, Container<R_SExpr> &As, + Container<R_SExpr> &Is, R_SExpr T) { + return (As.Success && Is.Success && T); + } + R_SExpr reducePhi(Phi &Orig, Container<R_SExpr> &As) { + return As.Success; + } + R_SExpr reduceGoto(Goto &Orig, BasicBlock *B) { + return true; + } + R_SExpr reduceBranch(Branch &O, R_SExpr C, BasicBlock *B0, BasicBlock *B1) { + return C; + } + R_SExpr reduceReturn(Return &O, R_SExpr E) { + return E; + } + + R_SExpr reduceIdentifier(Identifier &Orig) { + return true; + } + R_SExpr reduceIfThenElse(IfThenElse &Orig, R_SExpr C, R_SExpr T, R_SExpr E) { + return C && T && E; + } + R_SExpr reduceLet(Let &Orig, Variable *Nvd, R_SExpr B) { + return Nvd && B; + } + + Variable *enterScope(Variable &Orig, R_SExpr E0) { return &Orig; } + void exitScope(const Variable &Orig) {} + void enterCFG(SCFG &Cfg) {} + void exitCFG(SCFG &Cfg) {} + void enterBasicBlock(BasicBlock &BB) {} + void exitBasicBlock(BasicBlock &BB) {} + + Variable *reduceVariableRef (Variable *Ovd) { return Ovd; } + BasicBlock *reduceBasicBlockRef(BasicBlock *Obb) { return Obb; } + +public: + bool traverse(SExpr *E, TraversalKind K = TRV_Normal) { + Success = Success && this->traverseByCase(E); + return Success; + } + + static bool visit(SExpr *E) { + Self Visitor; + return Visitor.traverse(E, TRV_Normal); + } + +private: + bool Success; +}; + + +// Basic class for comparison operations over expressions. +template <typename Self> +class Comparator { +protected: + Self *self() { return reinterpret_cast<Self *>(this); } + +public: + bool compareByCase(const SExpr *E1, const SExpr* E2) { + switch (E1->opcode()) { +#define TIL_OPCODE_DEF(X) \ + case COP_##X: \ + return cast<X>(E1)->compare(cast<X>(E2), *self()); +#include "ThreadSafetyOps.def" +#undef TIL_OPCODE_DEF + } + return false; + } +}; + + +class EqualsComparator : public Comparator<EqualsComparator> { +public: + // Result type for the comparison, e.g. bool for simple equality, + // or int for lexigraphic comparison (-1, 0, 1). Must have one value which + // denotes "true". + typedef bool CType; + + CType trueResult() { return true; } + bool notTrue(CType ct) { return !ct; } + + bool compareIntegers(unsigned i, unsigned j) { return i == j; } + bool compareStrings (StringRef s, StringRef r) { return s == r; } + bool comparePointers(const void* P, const void* Q) { return P == Q; } + + bool compare(const SExpr *E1, const SExpr* E2) { + if (E1->opcode() != E2->opcode()) + return false; + return compareByCase(E1, E2); + } + + // TODO -- handle alpha-renaming of variables + void enterScope(const Variable* V1, const Variable* V2) { } + void leaveScope() { } + + bool compareVariableRefs(const Variable* V1, const Variable* V2) { + return V1 == V2; + } + + static bool compareExprs(const SExpr *E1, const SExpr* E2) { + EqualsComparator Eq; + return Eq.compare(E1, E2); + } +}; + + + +class MatchComparator : public Comparator<MatchComparator> { +public: + // Result type for the comparison, e.g. bool for simple equality, + // or int for lexigraphic comparison (-1, 0, 1). Must have one value which + // denotes "true". + typedef bool CType; + + CType trueResult() { return true; } + bool notTrue(CType ct) { return !ct; } + + bool compareIntegers(unsigned i, unsigned j) { return i == j; } + bool compareStrings (StringRef s, StringRef r) { return s == r; } + bool comparePointers(const void* P, const void* Q) { return P == Q; } + + bool compare(const SExpr *E1, const SExpr* E2) { + // Wildcards match anything. + if (E1->opcode() == COP_Wildcard || E2->opcode() == COP_Wildcard) + return true; + // otherwise normal equality. + if (E1->opcode() != E2->opcode()) + return false; + return compareByCase(E1, E2); + } + + // TODO -- handle alpha-renaming of variables + void enterScope(const Variable* V1, const Variable* V2) { } + void leaveScope() { } + + bool compareVariableRefs(const Variable* V1, const Variable* V2) { + return V1 == V2; + } + + static bool compareExprs(const SExpr *E1, const SExpr* E2) { + MatchComparator Matcher; + return Matcher.compare(E1, E2); + } +}; + + + +// inline std::ostream& operator<<(std::ostream& SS, StringRef R) { +// return SS.write(R.data(), R.size()); +// } + +// Pretty printer for TIL expressions +template <typename Self, typename StreamType> +class PrettyPrinter { +private: + bool Verbose; // Print out additional information + bool Cleanup; // Omit redundant decls. + bool CStyle; // Print exprs in C-like syntax. + +public: + PrettyPrinter(bool V = false, bool C = true, bool CS = true) + : Verbose(V), Cleanup(C), CStyle(CS) + {} + + static void print(const SExpr *E, StreamType &SS) { + Self printer; + printer.printSExpr(E, SS, Prec_MAX); + } + +protected: + Self *self() { return reinterpret_cast<Self *>(this); } + + void newline(StreamType &SS) { + SS << "\n"; + } + + // TODO: further distinguish between binary operations. + static const unsigned Prec_Atom = 0; + static const unsigned Prec_Postfix = 1; + static const unsigned Prec_Unary = 2; + static const unsigned Prec_Binary = 3; + static const unsigned Prec_Other = 4; + static const unsigned Prec_Decl = 5; + static const unsigned Prec_MAX = 6; + + // Return the precedence of a given node, for use in pretty printing. + unsigned precedence(const SExpr *E) { + switch (E->opcode()) { + case COP_Future: return Prec_Atom; + case COP_Undefined: return Prec_Atom; + case COP_Wildcard: return Prec_Atom; + + case COP_Literal: return Prec_Atom; + case COP_LiteralPtr: return Prec_Atom; + case COP_Variable: return Prec_Atom; + case COP_Function: return Prec_Decl; + case COP_SFunction: return Prec_Decl; + case COP_Code: return Prec_Decl; + case COP_Field: return Prec_Decl; + + case COP_Apply: return Prec_Postfix; + case COP_SApply: return Prec_Postfix; + case COP_Project: return Prec_Postfix; + + case COP_Call: return Prec_Postfix; + case COP_Alloc: return Prec_Other; + case COP_Load: return Prec_Postfix; + case COP_Store: return Prec_Other; + case COP_ArrayIndex: return Prec_Postfix; + case COP_ArrayAdd: return Prec_Postfix; + + case COP_UnaryOp: return Prec_Unary; + case COP_BinaryOp: return Prec_Binary; + case COP_Cast: return Prec_Atom; + + case COP_SCFG: return Prec_Decl; + case COP_BasicBlock: return Prec_MAX; + case COP_Phi: return Prec_Atom; + case COP_Goto: return Prec_Atom; + case COP_Branch: return Prec_Atom; + case COP_Return: return Prec_Other; + + case COP_Identifier: return Prec_Atom; + case COP_IfThenElse: return Prec_Other; + case COP_Let: return Prec_Decl; + } + return Prec_MAX; + } + + void printBlockLabel(StreamType & SS, const BasicBlock *BB, int index) { + if (!BB) { + SS << "BB_null"; + return; + } + SS << "BB_"; + SS << BB->blockID(); + if (index >= 0) { + SS << ":"; + SS << index; + } + } + + + void printSExpr(const SExpr *E, StreamType &SS, unsigned P, bool Sub=true) { + if (!E) { + self()->printNull(SS); + return; + } + if (Sub && E->block() && E->opcode() != COP_Variable) { + SS << "_x" << E->id(); + return; + } + if (self()->precedence(E) > P) { + // Wrap expr in () if necessary. + SS << "("; + self()->printSExpr(E, SS, Prec_MAX); + SS << ")"; + return; + } + + switch (E->opcode()) { +#define TIL_OPCODE_DEF(X) \ + case COP_##X: \ + self()->print##X(cast<X>(E), SS); \ + return; +#include "ThreadSafetyOps.def" +#undef TIL_OPCODE_DEF + } + } + + void printNull(StreamType &SS) { + SS << "#null"; + } + + void printFuture(const Future *E, StreamType &SS) { + self()->printSExpr(E->maybeGetResult(), SS, Prec_Atom); + } + + void printUndefined(const Undefined *E, StreamType &SS) { + SS << "#undefined"; + } + + void printWildcard(const Wildcard *E, StreamType &SS) { + SS << "*"; + } + + template<class T> + void printLiteralT(const LiteralT<T> *E, StreamType &SS) { + SS << E->value(); + } + + void printLiteralT(const LiteralT<uint8_t> *E, StreamType &SS) { + SS << "'" << E->value() << "'"; + } + + void printLiteral(const Literal *E, StreamType &SS) { + if (E->clangExpr()) { + SS << getSourceLiteralString(E->clangExpr()); + return; + } + else { + ValueType VT = E->valueType(); + switch (VT.Base) { + case ValueType::BT_Void: { + SS << "void"; + return; + } + case ValueType::BT_Bool: { + if (E->as<bool>().value()) + SS << "true"; + else + SS << "false"; + return; + } + case ValueType::BT_Int: { + switch (VT.Size) { + case ValueType::ST_8: + if (VT.Signed) + printLiteralT(&E->as<int8_t>(), SS); + else + printLiteralT(&E->as<uint8_t>(), SS); + return; + case ValueType::ST_16: + if (VT.Signed) + printLiteralT(&E->as<int16_t>(), SS); + else + printLiteralT(&E->as<uint16_t>(), SS); + return; + case ValueType::ST_32: + if (VT.Signed) + printLiteralT(&E->as<int32_t>(), SS); + else + printLiteralT(&E->as<uint32_t>(), SS); + return; + case ValueType::ST_64: + if (VT.Signed) + printLiteralT(&E->as<int64_t>(), SS); + else + printLiteralT(&E->as<uint64_t>(), SS); + return; + default: + break; + } + break; + } + case ValueType::BT_Float: { + switch (VT.Size) { + case ValueType::ST_32: + printLiteralT(&E->as<float>(), SS); + return; + case ValueType::ST_64: + printLiteralT(&E->as<double>(), SS); + return; + default: + break; + } + break; + } + case ValueType::BT_String: { + SS << "\""; + printLiteralT(&E->as<StringRef>(), SS); + SS << "\""; + return; + } + case ValueType::BT_Pointer: { + SS << "#ptr"; + return; + } + case ValueType::BT_ValueRef: { + SS << "#vref"; + return; + } + } + } + SS << "#lit"; + } + + void printLiteralPtr(const LiteralPtr *E, StreamType &SS) { + SS << E->clangDecl()->getNameAsString(); + } + + void printVariable(const Variable *V, StreamType &SS, bool IsVarDecl=false) { + if (CStyle && V->kind() == Variable::VK_SFun) + SS << "this"; + else + SS << V->name() << V->id(); + } + + void printFunction(const Function *E, StreamType &SS, unsigned sugared = 0) { + switch (sugared) { + default: + SS << "\\("; // Lambda + break; + case 1: + SS << "("; // Slot declarations + break; + case 2: + SS << ", "; // Curried functions + break; + } + self()->printVariable(E->variableDecl(), SS, true); + SS << ": "; + self()->printSExpr(E->variableDecl()->definition(), SS, Prec_MAX); + + const SExpr *B = E->body(); + if (B && B->opcode() == COP_Function) + self()->printFunction(cast<Function>(B), SS, 2); + else { + SS << ")"; + self()->printSExpr(B, SS, Prec_Decl); + } + } + + void printSFunction(const SFunction *E, StreamType &SS) { + SS << "@"; + self()->printVariable(E->variableDecl(), SS, true); + SS << " "; + self()->printSExpr(E->body(), SS, Prec_Decl); + } + + void printCode(const Code *E, StreamType &SS) { + SS << ": "; + self()->printSExpr(E->returnType(), SS, Prec_Decl-1); + SS << " -> "; + self()->printSExpr(E->body(), SS, Prec_Decl); + } + + void printField(const Field *E, StreamType &SS) { + SS << ": "; + self()->printSExpr(E->range(), SS, Prec_Decl-1); + SS << " = "; + self()->printSExpr(E->body(), SS, Prec_Decl); + } + + void printApply(const Apply *E, StreamType &SS, bool sugared = false) { + const SExpr *F = E->fun(); + if (F->opcode() == COP_Apply) { + printApply(cast<Apply>(F), SS, true); + SS << ", "; + } else { + self()->printSExpr(F, SS, Prec_Postfix); + SS << "("; + } + self()->printSExpr(E->arg(), SS, Prec_MAX); + if (!sugared) + SS << ")$"; + } + + void printSApply(const SApply *E, StreamType &SS) { + self()->printSExpr(E->sfun(), SS, Prec_Postfix); + if (E->isDelegation()) { + SS << "@("; + self()->printSExpr(E->arg(), SS, Prec_MAX); + SS << ")"; + } + } + + void printProject(const Project *E, StreamType &SS) { + if (CStyle) { + // Omit the this-> + if (const SApply *SAP = dyn_cast<SApply>(E->record())) { + if (const Variable *V = dyn_cast<Variable>(SAP->sfun())) { + if (!SAP->isDelegation() && V->kind() == Variable::VK_SFun) { + SS << E->slotName(); + return; + } + } + } + if (isa<Wildcard>(E->record())) { + // handle existentials + SS << "&"; + SS << E->clangDecl()->getQualifiedNameAsString(); + return; + } + } + self()->printSExpr(E->record(), SS, Prec_Postfix); + if (CStyle && E->isArrow()) { + SS << "->"; + } + else { + SS << "."; + } + SS << E->slotName(); + } + + void printCall(const Call *E, StreamType &SS) { + const SExpr *T = E->target(); + if (T->opcode() == COP_Apply) { + self()->printApply(cast<Apply>(T), SS, true); + SS << ")"; + } + else { + self()->printSExpr(T, SS, Prec_Postfix); + SS << "()"; + } + } + + void printAlloc(const Alloc *E, StreamType &SS) { + SS << "new "; + self()->printSExpr(E->dataType(), SS, Prec_Other-1); + } + + void printLoad(const Load *E, StreamType &SS) { + self()->printSExpr(E->pointer(), SS, Prec_Postfix); + if (!CStyle) + SS << "^"; + } + + void printStore(const Store *E, StreamType &SS) { + self()->printSExpr(E->destination(), SS, Prec_Other-1); + SS << " := "; + self()->printSExpr(E->source(), SS, Prec_Other-1); + } + + void printArrayIndex(const ArrayIndex *E, StreamType &SS) { + self()->printSExpr(E->array(), SS, Prec_Postfix); + SS << "["; + self()->printSExpr(E->index(), SS, Prec_MAX); + SS << "]"; + } + + void printArrayAdd(const ArrayAdd *E, StreamType &SS) { + self()->printSExpr(E->array(), SS, Prec_Postfix); + SS << " + "; + self()->printSExpr(E->index(), SS, Prec_Atom); + } + + void printUnaryOp(const UnaryOp *E, StreamType &SS) { + SS << getUnaryOpcodeString(E->unaryOpcode()); + self()->printSExpr(E->expr(), SS, Prec_Unary); + } + + void printBinaryOp(const BinaryOp *E, StreamType &SS) { + self()->printSExpr(E->expr0(), SS, Prec_Binary-1); + SS << " " << getBinaryOpcodeString(E->binaryOpcode()) << " "; + self()->printSExpr(E->expr1(), SS, Prec_Binary-1); + } + + void printCast(const Cast *E, StreamType &SS) { + if (!CStyle) { + SS << "cast["; + SS << E->castOpcode(); + SS << "]("; + self()->printSExpr(E->expr(), SS, Prec_Unary); + SS << ")"; + return; + } + self()->printSExpr(E->expr(), SS, Prec_Unary); + } + + void printSCFG(const SCFG *E, StreamType &SS) { + SS << "CFG {\n"; + for (auto BBI : *E) { + printBasicBlock(BBI, SS); + } + SS << "}"; + newline(SS); + } + + + void printBBInstr(const SExpr *E, StreamType &SS) { + bool Sub = false; + if (E->opcode() == COP_Variable) { + auto *V = cast<Variable>(E); + SS << "let " << V->name() << V->id() << " = "; + E = V->definition(); + Sub = true; + } + else if (E->opcode() != COP_Store) { + SS << "let _x" << E->id() << " = "; + } + self()->printSExpr(E, SS, Prec_MAX, Sub); + SS << ";"; + newline(SS); + } + + void printBasicBlock(const BasicBlock *E, StreamType &SS) { + SS << "BB_" << E->blockID() << ":"; + if (E->parent()) + SS << " BB_" << E->parent()->blockID(); + newline(SS); + + for (auto *A : E->arguments()) + printBBInstr(A, SS); + + for (auto *I : E->instructions()) + printBBInstr(I, SS); + + const SExpr *T = E->terminator(); + if (T) { + self()->printSExpr(T, SS, Prec_MAX, false); + SS << ";"; + newline(SS); + } + newline(SS); + } + + void printPhi(const Phi *E, StreamType &SS) { + SS << "phi("; + if (E->status() == Phi::PH_SingleVal) + self()->printSExpr(E->values()[0], SS, Prec_MAX); + else { + unsigned i = 0; + for (auto V : E->values()) { + if (i++ > 0) + SS << ", "; + self()->printSExpr(V, SS, Prec_MAX); + } + } + SS << ")"; + } + + void printGoto(const Goto *E, StreamType &SS) { + SS << "goto "; + printBlockLabel(SS, E->targetBlock(), E->index()); + } + + void printBranch(const Branch *E, StreamType &SS) { + SS << "branch ("; + self()->printSExpr(E->condition(), SS, Prec_MAX); + SS << ") "; + printBlockLabel(SS, E->thenBlock(), -1); + SS << " "; + printBlockLabel(SS, E->elseBlock(), -1); + } + + void printReturn(const Return *E, StreamType &SS) { + SS << "return "; + self()->printSExpr(E->returnValue(), SS, Prec_Other); + } + + void printIdentifier(const Identifier *E, StreamType &SS) { + SS << E->name(); + } + + void printIfThenElse(const IfThenElse *E, StreamType &SS) { + if (CStyle) { + printSExpr(E->condition(), SS, Prec_Unary); + SS << " ? "; + printSExpr(E->thenExpr(), SS, Prec_Unary); + SS << " : "; + printSExpr(E->elseExpr(), SS, Prec_Unary); + return; + } + SS << "if ("; + printSExpr(E->condition(), SS, Prec_MAX); + SS << ") then "; + printSExpr(E->thenExpr(), SS, Prec_Other); + SS << " else "; + printSExpr(E->elseExpr(), SS, Prec_Other); + } + + void printLet(const Let *E, StreamType &SS) { + SS << "let "; + printVariable(E->variableDecl(), SS, true); + SS << " = "; + printSExpr(E->variableDecl()->definition(), SS, Prec_Decl-1); + SS << "; "; + printSExpr(E->body(), SS, Prec_Decl-1); + } +}; + + +class StdPrinter : public PrettyPrinter<StdPrinter, std::ostream> { }; + + + +} // end namespace til +} // end namespace threadSafety +} // end namespace clang + +#endif // LLVM_CLANG_THREAD_SAFETY_TRAVERSE_H diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafetyUtil.h b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafetyUtil.h new file mode 100644 index 0000000..4d3402f --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafetyUtil.h @@ -0,0 +1,358 @@ +//===- ThreadSafetyUtil.h --------------------------------------*- 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 some basic utility classes for use by ThreadSafetyTIL.h +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYUTIL_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYUTIL_H + +#include "clang/AST/ExprCXX.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/AlignOf.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Compiler.h" +#include <cassert> +#include <cstddef> +#include <ostream> +#include <utility> +#include <vector> + +namespace clang { +namespace threadSafety { +namespace til { + +// Simple wrapper class to abstract away from the details of memory management. +// SExprs are allocated in pools, and deallocated all at once. +class MemRegionRef { +private: + union AlignmentType { + double d; + void *p; + long double dd; + long long ii; + }; + +public: + MemRegionRef() : Allocator(nullptr) {} + MemRegionRef(llvm::BumpPtrAllocator *A) : Allocator(A) {} + + void *allocate(size_t Sz) { + return Allocator->Allocate(Sz, llvm::AlignOf<AlignmentType>::Alignment); + } + + template <typename T> T *allocateT() { return Allocator->Allocate<T>(); } + + template <typename T> T *allocateT(size_t NumElems) { + return Allocator->Allocate<T>(NumElems); + } + +private: + llvm::BumpPtrAllocator *Allocator; +}; + + +} // end namespace til +} // end namespace threadSafety +} // end namespace clang + + +inline void *operator new(size_t Sz, + clang::threadSafety::til::MemRegionRef &R) { + return R.allocate(Sz); +} + + +namespace clang { +namespace threadSafety { + +std::string getSourceLiteralString(const clang::Expr *CE); + +using llvm::StringRef; +using clang::SourceLocation; + +namespace til { + + +// A simple fixed size array class that does not manage its own memory, +// suitable for use with bump pointer allocation. +template <class T> class SimpleArray { +public: + SimpleArray() : Data(nullptr), Size(0), Capacity(0) {} + SimpleArray(T *Dat, size_t Cp, size_t Sz = 0) + : Data(Dat), Size(Sz), Capacity(Cp) {} + SimpleArray(MemRegionRef A, size_t Cp) + : Data(Cp == 0 ? nullptr : A.allocateT<T>(Cp)), Size(0), Capacity(Cp) {} + SimpleArray(SimpleArray<T> &&A) + : Data(A.Data), Size(A.Size), Capacity(A.Capacity) { + A.Data = nullptr; + A.Size = 0; + A.Capacity = 0; + } + + SimpleArray &operator=(SimpleArray &&RHS) { + if (this != &RHS) { + Data = RHS.Data; + Size = RHS.Size; + Capacity = RHS.Capacity; + + RHS.Data = nullptr; + RHS.Size = RHS.Capacity = 0; + } + return *this; + } + + // Reserve space for at least Ncp items, reallocating if necessary. + void reserve(size_t Ncp, MemRegionRef A) { + if (Ncp <= Capacity) + return; + T *Odata = Data; + Data = A.allocateT<T>(Ncp); + Capacity = Ncp; + memcpy(Data, Odata, sizeof(T) * Size); + return; + } + + // Reserve space for at least N more items. + void reserveCheck(size_t N, MemRegionRef A) { + if (Capacity == 0) + reserve(u_max(InitialCapacity, N), A); + else if (Size + N < Capacity) + reserve(u_max(Size + N, Capacity * 2), A); + } + + typedef T *iterator; + typedef const T *const_iterator; + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + + size_t size() const { return Size; } + size_t capacity() const { return Capacity; } + + T &operator[](unsigned i) { + assert(i < Size && "Array index out of bounds."); + return Data[i]; + } + const T &operator[](unsigned i) const { + assert(i < Size && "Array index out of bounds."); + return Data[i]; + } + T &back() { + assert(Size && "No elements in the array."); + return Data[Size - 1]; + } + const T &back() const { + assert(Size && "No elements in the array."); + return Data[Size - 1]; + } + + iterator begin() { return Data; } + iterator end() { return Data + Size; } + + const_iterator begin() const { return Data; } + const_iterator end() const { return Data + Size; } + + const_iterator cbegin() const { return Data; } + const_iterator cend() const { return Data + Size; } + + reverse_iterator rbegin() { return reverse_iterator(end()); } + reverse_iterator rend() { return reverse_iterator(begin()); } + + const_reverse_iterator rbegin() const { + return const_reverse_iterator(end()); + } + const_reverse_iterator rend() const { + return const_reverse_iterator(begin()); + } + + void push_back(const T &Elem) { + assert(Size < Capacity); + Data[Size++] = Elem; + } + + // drop last n elements from array + void drop(unsigned n = 0) { + assert(Size > n); + Size -= n; + } + + void setValues(unsigned Sz, const T& C) { + assert(Sz <= Capacity); + Size = Sz; + for (unsigned i = 0; i < Sz; ++i) { + Data[i] = C; + } + } + + template <class Iter> unsigned append(Iter I, Iter E) { + size_t Osz = Size; + size_t J = Osz; + for (; J < Capacity && I != E; ++J, ++I) + Data[J] = *I; + Size = J; + return J - Osz; + } + + llvm::iterator_range<reverse_iterator> reverse() { + return llvm::make_range(rbegin(), rend()); + } + llvm::iterator_range<const_reverse_iterator> reverse() const { + return llvm::make_range(rbegin(), rend()); + } + +private: + // std::max is annoying here, because it requires a reference, + // thus forcing InitialCapacity to be initialized outside the .h file. + size_t u_max(size_t i, size_t j) { return (i < j) ? j : i; } + + static const size_t InitialCapacity = 4; + + SimpleArray(const SimpleArray<T> &A) = delete; + + T *Data; + size_t Size; + size_t Capacity; +}; + + +} // end namespace til + + +// A copy on write vector. +// The vector can be in one of three states: +// * invalid -- no operations are permitted. +// * read-only -- read operations are permitted. +// * writable -- read and write operations are permitted. +// The init(), destroy(), and makeWritable() methods will change state. +template<typename T> +class CopyOnWriteVector { + class VectorData { + public: + VectorData() : NumRefs(1) { } + VectorData(const VectorData &VD) : NumRefs(1), Vect(VD.Vect) { } + + unsigned NumRefs; + std::vector<T> Vect; + }; + + // No copy constructor or copy assignment. Use clone() with move assignment. + CopyOnWriteVector(const CopyOnWriteVector &V) = delete; + void operator=(const CopyOnWriteVector &V) = delete; + +public: + CopyOnWriteVector() : Data(nullptr) {} + CopyOnWriteVector(CopyOnWriteVector &&V) : Data(V.Data) { V.Data = nullptr; } + ~CopyOnWriteVector() { destroy(); } + + // Returns true if this holds a valid vector. + bool valid() const { return Data; } + + // Returns true if this vector is writable. + bool writable() const { return Data && Data->NumRefs == 1; } + + // If this vector is not valid, initialize it to a valid vector. + void init() { + if (!Data) { + Data = new VectorData(); + } + } + + // Destroy this vector; thus making it invalid. + void destroy() { + if (!Data) + return; + if (Data->NumRefs <= 1) + delete Data; + else + --Data->NumRefs; + Data = nullptr; + } + + // Make this vector writable, creating a copy if needed. + void makeWritable() { + if (!Data) { + Data = new VectorData(); + return; + } + if (Data->NumRefs == 1) + return; // already writeable. + --Data->NumRefs; + Data = new VectorData(*Data); + } + + // Create a lazy copy of this vector. + CopyOnWriteVector clone() { return CopyOnWriteVector(Data); } + + CopyOnWriteVector &operator=(CopyOnWriteVector &&V) { + destroy(); + Data = V.Data; + V.Data = nullptr; + return *this; + } + + typedef typename std::vector<T>::const_iterator const_iterator; + + const std::vector<T> &elements() const { return Data->Vect; } + + const_iterator begin() const { return elements().cbegin(); } + const_iterator end() const { return elements().cend(); } + + const T& operator[](unsigned i) const { return elements()[i]; } + + unsigned size() const { return Data ? elements().size() : 0; } + + // Return true if V and this vector refer to the same data. + bool sameAs(const CopyOnWriteVector &V) const { return Data == V.Data; } + + // Clear vector. The vector must be writable. + void clear() { + assert(writable() && "Vector is not writable!"); + Data->Vect.clear(); + } + + // Push a new element onto the end. The vector must be writable. + void push_back(const T &Elem) { + assert(writable() && "Vector is not writable!"); + Data->Vect.push_back(Elem); + } + + // Gets a mutable reference to the element at index(i). + // The vector must be writable. + T& elem(unsigned i) { + assert(writable() && "Vector is not writable!"); + return Data->Vect[i]; + } + + // Drops elements from the back until the vector has size i. + void downsize(unsigned i) { + assert(writable() && "Vector is not writable!"); + Data->Vect.erase(Data->Vect.begin() + i, Data->Vect.end()); + } + +private: + CopyOnWriteVector(VectorData *D) : Data(D) { + if (!Data) + return; + ++Data->NumRefs; + } + + VectorData *Data; +}; + + +inline std::ostream& operator<<(std::ostream& ss, const StringRef str) { + return ss.write(str.data(), str.size()); +} + + +} // end namespace threadSafety +} // end namespace clang + +#endif // LLVM_CLANG_THREAD_SAFETY_UTIL_H diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/UninitializedValues.h b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/UninitializedValues.h new file mode 100644 index 0000000..53ff20c --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/UninitializedValues.h @@ -0,0 +1,126 @@ +//= UninitializedValues.h - Finding uses of uninitialized values -*- 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 APIs for invoking and reported uninitialized values +// warnings. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_UNINITIALIZEDVALUES_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_UNINITIALIZEDVALUES_H + +#include "clang/AST/Stmt.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { + +class AnalysisDeclContext; +class CFG; +class DeclContext; +class Expr; +class VarDecl; + +/// A use of a variable, which might be uninitialized. +class UninitUse { +public: + struct Branch { + const Stmt *Terminator; + unsigned Output; + }; + +private: + /// The expression which uses this variable. + const Expr *User; + + /// Is this use uninitialized whenever the function is called? + bool UninitAfterCall; + + /// Is this use uninitialized whenever the variable declaration is reached? + bool UninitAfterDecl; + + /// Does this use always see an uninitialized value? + bool AlwaysUninit; + + /// This use is always uninitialized if it occurs after any of these branches + /// is taken. + SmallVector<Branch, 2> UninitBranches; + +public: + UninitUse(const Expr *User, bool AlwaysUninit) + : User(User), UninitAfterCall(false), UninitAfterDecl(false), + AlwaysUninit(AlwaysUninit) {} + + void addUninitBranch(Branch B) { + UninitBranches.push_back(B); + } + + void setUninitAfterCall() { UninitAfterCall = true; } + void setUninitAfterDecl() { UninitAfterDecl = true; } + + /// Get the expression containing the uninitialized use. + const Expr *getUser() const { return User; } + + /// The kind of uninitialized use. + enum Kind { + /// The use might be uninitialized. + Maybe, + /// The use is uninitialized whenever a certain branch is taken. + Sometimes, + /// The use is uninitialized the first time it is reached after we reach + /// the variable's declaration. + AfterDecl, + /// The use is uninitialized the first time it is reached after the function + /// is called. + AfterCall, + /// The use is always uninitialized. + Always + }; + + /// Get the kind of uninitialized use. + Kind getKind() const { + return AlwaysUninit ? Always : + UninitAfterCall ? AfterCall : + UninitAfterDecl ? AfterDecl : + !branch_empty() ? Sometimes : Maybe; + } + + typedef SmallVectorImpl<Branch>::const_iterator branch_iterator; + /// Branches which inevitably result in the variable being used uninitialized. + branch_iterator branch_begin() const { return UninitBranches.begin(); } + branch_iterator branch_end() const { return UninitBranches.end(); } + bool branch_empty() const { return UninitBranches.empty(); } +}; + +class UninitVariablesHandler { +public: + UninitVariablesHandler() {} + virtual ~UninitVariablesHandler(); + + /// Called when the uninitialized variable is used at the given expression. + virtual void handleUseOfUninitVariable(const VarDecl *vd, + const UninitUse &use) {} + + /// Called when the uninitialized variable analysis detects the + /// idiom 'int x = x'. All other uses of 'x' within the initializer + /// are handled by handleUseOfUninitVariable. + virtual void handleSelfInit(const VarDecl *vd) {} +}; + +struct UninitVariablesAnalysisStats { + unsigned NumVariablesAnalyzed; + unsigned NumBlockVisits; +}; + +void runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg, + AnalysisDeclContext &ac, + UninitVariablesHandler &handler, + UninitVariablesAnalysisStats &stats); + +} +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/AnalysisContext.h b/contrib/llvm/tools/clang/include/clang/Analysis/AnalysisContext.h new file mode 100644 index 0000000..931190e --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Analysis/AnalysisContext.h @@ -0,0 +1,480 @@ +//=== AnalysisContext.h - Analysis context for Path Sens analysis --*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines AnalysisDeclContext, a class that manages the analysis +// context data for path sensitive analysis. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_ANALYSISCONTEXT_H +#define LLVM_CLANG_ANALYSIS_ANALYSISCONTEXT_H + +#include "clang/AST/Decl.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/CodeInjector.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/Support/Allocator.h" +#include <memory> + +namespace clang { + +class Stmt; +class CFGReverseBlockReachabilityAnalysis; +class CFGStmtMap; +class LiveVariables; +class ManagedAnalysis; +class ParentMap; +class PseudoConstantAnalysis; +class LocationContextManager; +class StackFrameContext; +class BlockInvocationContext; +class AnalysisDeclContextManager; +class LocationContext; + +namespace idx { class TranslationUnit; } + +/// The base class of a hierarchy of objects representing analyses tied +/// to AnalysisDeclContext. +class ManagedAnalysis { +protected: + ManagedAnalysis() {} +public: + virtual ~ManagedAnalysis(); + + // Subclasses need to implement: + // + // static const void *getTag(); + // + // Which returns a fixed pointer address to distinguish classes of + // analysis objects. They also need to implement: + // + // static [Derived*] create(AnalysisDeclContext &Ctx); + // + // which creates the analysis object given an AnalysisDeclContext. +}; + + +/// AnalysisDeclContext contains the context data for the function or method +/// under analysis. +class AnalysisDeclContext { + /// Backpoint to the AnalysisManager object that created this + /// AnalysisDeclContext. This may be null. + AnalysisDeclContextManager *Manager; + + const Decl * const D; + + std::unique_ptr<CFG> cfg, completeCFG; + std::unique_ptr<CFGStmtMap> cfgStmtMap; + + CFG::BuildOptions cfgBuildOptions; + CFG::BuildOptions::ForcedBlkExprs *forcedBlkExprs; + + bool builtCFG, builtCompleteCFG; + std::unique_ptr<ParentMap> PM; + std::unique_ptr<PseudoConstantAnalysis> PCA; + std::unique_ptr<CFGReverseBlockReachabilityAnalysis> CFA; + + llvm::BumpPtrAllocator A; + + llvm::DenseMap<const BlockDecl*,void*> *ReferencedBlockVars; + + void *ManagedAnalyses; + +public: + AnalysisDeclContext(AnalysisDeclContextManager *Mgr, + const Decl *D); + + AnalysisDeclContext(AnalysisDeclContextManager *Mgr, + const Decl *D, + const CFG::BuildOptions &BuildOptions); + + ~AnalysisDeclContext(); + + ASTContext &getASTContext() const { return D->getASTContext(); } + const Decl *getDecl() const { return D; } + + /// Return the AnalysisDeclContextManager (if any) that created + /// this AnalysisDeclContext. + AnalysisDeclContextManager *getManager() const { + return Manager; + } + + /// Return the build options used to construct the CFG. + CFG::BuildOptions &getCFGBuildOptions() { + return cfgBuildOptions; + } + + const CFG::BuildOptions &getCFGBuildOptions() const { + return cfgBuildOptions; + } + + /// getAddEHEdges - Return true iff we are adding exceptional edges from + /// callExprs. If this is false, then try/catch statements and blocks + /// reachable from them can appear to be dead in the CFG, analysis passes must + /// cope with that. + bool getAddEHEdges() const { return cfgBuildOptions.AddEHEdges; } + bool getUseUnoptimizedCFG() const { + return !cfgBuildOptions.PruneTriviallyFalseEdges; + } + bool getAddImplicitDtors() const { return cfgBuildOptions.AddImplicitDtors; } + bool getAddInitializers() const { return cfgBuildOptions.AddInitializers; } + + void registerForcedBlockExpression(const Stmt *stmt); + const CFGBlock *getBlockForRegisteredExpression(const Stmt *stmt); + + /// \brief Get the body of the Declaration. + Stmt *getBody() const; + + /// \brief Get the body of the Declaration. + /// \param[out] IsAutosynthesized Specifies if the body is auto-generated + /// by the BodyFarm. + Stmt *getBody(bool &IsAutosynthesized) const; + + /// \brief Checks if the body of the Decl is generated by the BodyFarm. + /// + /// Note, the lookup is not free. We are going to call getBody behind + /// the scenes. + /// \sa getBody + bool isBodyAutosynthesized() const; + + /// \brief Checks if the body of the Decl is generated by the BodyFarm from a + /// model file. + /// + /// Note, the lookup is not free. We are going to call getBody behind + /// the scenes. + /// \sa getBody + bool isBodyAutosynthesizedFromModelFile() const; + + CFG *getCFG(); + + CFGStmtMap *getCFGStmtMap(); + + CFGReverseBlockReachabilityAnalysis *getCFGReachablityAnalysis(); + + /// Return a version of the CFG without any edges pruned. + CFG *getUnoptimizedCFG(); + + void dumpCFG(bool ShowColors); + + /// \brief Returns true if we have built a CFG for this analysis context. + /// Note that this doesn't correspond to whether or not a valid CFG exists, it + /// corresponds to whether we *attempted* to build one. + bool isCFGBuilt() const { return builtCFG; } + + ParentMap &getParentMap(); + PseudoConstantAnalysis *getPseudoConstantAnalysis(); + + typedef const VarDecl * const * referenced_decls_iterator; + + llvm::iterator_range<referenced_decls_iterator> + getReferencedBlockVars(const BlockDecl *BD); + + /// Return the ImplicitParamDecl* associated with 'self' if this + /// AnalysisDeclContext wraps an ObjCMethodDecl. Returns NULL otherwise. + const ImplicitParamDecl *getSelfDecl() const; + + const StackFrameContext *getStackFrame(LocationContext const *Parent, + const Stmt *S, + const CFGBlock *Blk, + unsigned Idx); + + const BlockInvocationContext * + getBlockInvocationContext(const LocationContext *parent, + const BlockDecl *BD, + const void *ContextData); + + /// Return the specified analysis object, lazily running the analysis if + /// necessary. Return NULL if the analysis could not run. + template <typename T> + T *getAnalysis() { + const void *tag = T::getTag(); + ManagedAnalysis *&data = getAnalysisImpl(tag); + if (!data) { + data = T::create(*this); + } + return static_cast<T*>(data); + } +private: + ManagedAnalysis *&getAnalysisImpl(const void* tag); + + LocationContextManager &getLocationContextManager(); +}; + +class LocationContext : public llvm::FoldingSetNode { +public: + enum ContextKind { StackFrame, Scope, Block }; + +private: + ContextKind Kind; + + // AnalysisDeclContext can't be const since some methods may modify its + // member. + AnalysisDeclContext *Ctx; + + const LocationContext *Parent; + +protected: + LocationContext(ContextKind k, AnalysisDeclContext *ctx, + const LocationContext *parent) + : Kind(k), Ctx(ctx), Parent(parent) {} + +public: + virtual ~LocationContext(); + + ContextKind getKind() const { return Kind; } + + AnalysisDeclContext *getAnalysisDeclContext() const { return Ctx; } + + const LocationContext *getParent() const { return Parent; } + + bool isParentOf(const LocationContext *LC) const; + + const Decl *getDecl() const { return getAnalysisDeclContext()->getDecl(); } + + CFG *getCFG() const { return getAnalysisDeclContext()->getCFG(); } + + template <typename T> + T *getAnalysis() const { + return getAnalysisDeclContext()->getAnalysis<T>(); + } + + ParentMap &getParentMap() const { + return getAnalysisDeclContext()->getParentMap(); + } + + const ImplicitParamDecl *getSelfDecl() const { + return Ctx->getSelfDecl(); + } + + const StackFrameContext *getCurrentStackFrame() const; + + /// Return true if the current LocationContext has no caller context. + virtual bool inTopFrame() const; + + virtual void Profile(llvm::FoldingSetNodeID &ID) = 0; + + void dumpStack(raw_ostream &OS, StringRef Indent = "") const; + void dumpStack() const; + +public: + static void ProfileCommon(llvm::FoldingSetNodeID &ID, + ContextKind ck, + AnalysisDeclContext *ctx, + const LocationContext *parent, + const void *data); +}; + +class StackFrameContext : public LocationContext { + // The callsite where this stack frame is established. + const Stmt *CallSite; + + // The parent block of the callsite. + const CFGBlock *Block; + + // The index of the callsite in the CFGBlock. + unsigned Index; + + friend class LocationContextManager; + StackFrameContext(AnalysisDeclContext *ctx, const LocationContext *parent, + const Stmt *s, const CFGBlock *blk, + unsigned idx) + : LocationContext(StackFrame, ctx, parent), CallSite(s), + Block(blk), Index(idx) {} + +public: + ~StackFrameContext() override {} + + const Stmt *getCallSite() const { return CallSite; } + + const CFGBlock *getCallSiteBlock() const { return Block; } + + /// Return true if the current LocationContext has no caller context. + bool inTopFrame() const override { return getParent() == nullptr; } + + unsigned getIndex() const { return Index; } + + void Profile(llvm::FoldingSetNodeID &ID) override; + + static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx, + const LocationContext *parent, const Stmt *s, + const CFGBlock *blk, unsigned idx) { + ProfileCommon(ID, StackFrame, ctx, parent, s); + ID.AddPointer(blk); + ID.AddInteger(idx); + } + + static bool classof(const LocationContext *Ctx) { + return Ctx->getKind() == StackFrame; + } +}; + +class ScopeContext : public LocationContext { + const Stmt *Enter; + + friend class LocationContextManager; + ScopeContext(AnalysisDeclContext *ctx, const LocationContext *parent, + const Stmt *s) + : LocationContext(Scope, ctx, parent), Enter(s) {} + +public: + ~ScopeContext() override {} + + void Profile(llvm::FoldingSetNodeID &ID) override; + + static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx, + const LocationContext *parent, const Stmt *s) { + ProfileCommon(ID, Scope, ctx, parent, s); + } + + static bool classof(const LocationContext *Ctx) { + return Ctx->getKind() == Scope; + } +}; + +class BlockInvocationContext : public LocationContext { + const BlockDecl *BD; + + // FIXME: Come up with a more type-safe way to model context-sensitivity. + const void *ContextData; + + friend class LocationContextManager; + + BlockInvocationContext(AnalysisDeclContext *ctx, + const LocationContext *parent, + const BlockDecl *bd, const void *contextData) + : LocationContext(Block, ctx, parent), BD(bd), ContextData(contextData) {} + +public: + ~BlockInvocationContext() override {} + + const BlockDecl *getBlockDecl() const { return BD; } + + const void *getContextData() const { return ContextData; } + + void Profile(llvm::FoldingSetNodeID &ID) override; + + static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx, + const LocationContext *parent, const BlockDecl *bd, + const void *contextData) { + ProfileCommon(ID, Block, ctx, parent, bd); + ID.AddPointer(contextData); + } + + static bool classof(const LocationContext *Ctx) { + return Ctx->getKind() == Block; + } +}; + +class LocationContextManager { + llvm::FoldingSet<LocationContext> Contexts; +public: + ~LocationContextManager(); + + const StackFrameContext *getStackFrame(AnalysisDeclContext *ctx, + const LocationContext *parent, + const Stmt *s, + const CFGBlock *blk, unsigned idx); + + const ScopeContext *getScope(AnalysisDeclContext *ctx, + const LocationContext *parent, + const Stmt *s); + + const BlockInvocationContext * + getBlockInvocationContext(AnalysisDeclContext *ctx, + const LocationContext *parent, + const BlockDecl *BD, + const void *ContextData); + + /// Discard all previously created LocationContext objects. + void clear(); +private: + template <typename LOC, typename DATA> + const LOC *getLocationContext(AnalysisDeclContext *ctx, + const LocationContext *parent, + const DATA *d); +}; + +class AnalysisDeclContextManager { + typedef llvm::DenseMap<const Decl*, AnalysisDeclContext*> ContextMap; + + ContextMap Contexts; + LocationContextManager LocContexts; + CFG::BuildOptions cfgBuildOptions; + + /// Pointer to an interface that can provide function bodies for + /// declarations from external source. + std::unique_ptr<CodeInjector> Injector; + + /// Flag to indicate whether or not bodies should be synthesized + /// for well-known functions. + bool SynthesizeBodies; + +public: + AnalysisDeclContextManager(bool useUnoptimizedCFG = false, + bool addImplicitDtors = false, + bool addInitializers = false, + bool addTemporaryDtors = false, + bool synthesizeBodies = false, + bool addStaticInitBranches = false, + bool addCXXNewAllocator = true, + CodeInjector* injector = nullptr); + + ~AnalysisDeclContextManager(); + + AnalysisDeclContext *getContext(const Decl *D); + + bool getUseUnoptimizedCFG() const { + return !cfgBuildOptions.PruneTriviallyFalseEdges; + } + + CFG::BuildOptions &getCFGBuildOptions() { + return cfgBuildOptions; + } + + /// Return true if faux bodies should be synthesized for well-known + /// functions. + bool synthesizeBodies() const { return SynthesizeBodies; } + + const StackFrameContext *getStackFrame(AnalysisDeclContext *Ctx, + LocationContext const *Parent, + const Stmt *S, + const CFGBlock *Blk, + unsigned Idx) { + return LocContexts.getStackFrame(Ctx, Parent, S, Blk, Idx); + } + + // Get the top level stack frame. + const StackFrameContext *getStackFrame(const Decl *D) { + return LocContexts.getStackFrame(getContext(D), nullptr, nullptr, nullptr, + 0); + } + + // Get a stack frame with parent. + StackFrameContext const *getStackFrame(const Decl *D, + LocationContext const *Parent, + const Stmt *S, + const CFGBlock *Blk, + unsigned Idx) { + return LocContexts.getStackFrame(getContext(D), Parent, S, Blk, Idx); + } + + /// Discard all previously created AnalysisDeclContexts. + void clear(); + +private: + friend class AnalysisDeclContext; + + LocationContextManager &getLocationContextManager() { + return LocContexts; + } +}; + +} // end clang namespace +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/AnalysisDiagnostic.h b/contrib/llvm/tools/clang/include/clang/Analysis/AnalysisDiagnostic.h new file mode 100644 index 0000000..8d28971 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Analysis/AnalysisDiagnostic.h @@ -0,0 +1,28 @@ +//===--- DiagnosticAnalysis.h - Diagnostics for libanalysis -----*- 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_ANALYSIS_ANALYSISDIAGNOSTIC_H +#define LLVM_CLANG_ANALYSIS_ANALYSISDIAGNOSTIC_H + +#include "clang/Basic/Diagnostic.h" + +namespace clang { + namespace diag { + enum { +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\ + SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM, +#define ANALYSISSTART +#include "clang/Basic/DiagnosticAnalysisKinds.inc" +#undef DIAG + NUM_BUILTIN_ANALYSIS_DIAGNOSTICS + }; + } // end namespace diag +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/CFG.h b/contrib/llvm/tools/clang/include/clang/Analysis/CFG.h new file mode 100644 index 0000000..293990c --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Analysis/CFG.h @@ -0,0 +1,1113 @@ +//===--- CFG.h - Classes for representing and building CFGs------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the CFG and CFGBuilder classes for representing and +// building Control-Flow Graphs (CFGs) from ASTs. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_CFG_H +#define LLVM_CLANG_ANALYSIS_CFG_H + +#include "clang/AST/Stmt.h" +#include "clang/Analysis/Support/BumpVector.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/GraphTraits.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/raw_ostream.h" +#include <bitset> +#include <cassert> +#include <iterator> +#include <memory> + +namespace clang { + class CXXDestructorDecl; + class Decl; + class Stmt; + class Expr; + class FieldDecl; + class VarDecl; + class CXXCtorInitializer; + class CXXBaseSpecifier; + class CXXBindTemporaryExpr; + class CFG; + class PrinterHelper; + class LangOptions; + class ASTContext; + class CXXRecordDecl; + class CXXDeleteExpr; + class CXXNewExpr; + class BinaryOperator; + +/// CFGElement - Represents a top-level expression in a basic block. +class CFGElement { +public: + enum Kind { + // main kind + Statement, + Initializer, + NewAllocator, + // dtor kind + AutomaticObjectDtor, + DeleteDtor, + BaseDtor, + MemberDtor, + TemporaryDtor, + DTOR_BEGIN = AutomaticObjectDtor, + DTOR_END = TemporaryDtor + }; + +protected: + // The int bits are used to mark the kind. + llvm::PointerIntPair<void *, 2> Data1; + llvm::PointerIntPair<void *, 2> Data2; + + CFGElement(Kind kind, const void *Ptr1, const void *Ptr2 = nullptr) + : Data1(const_cast<void*>(Ptr1), ((unsigned) kind) & 0x3), + Data2(const_cast<void*>(Ptr2), (((unsigned) kind) >> 2) & 0x3) { + assert(getKind() == kind); + } + + CFGElement() {} +public: + + /// \brief Convert to the specified CFGElement type, asserting that this + /// CFGElement is of the desired type. + template<typename T> + T castAs() const { + assert(T::isKind(*this)); + T t; + CFGElement& e = t; + e = *this; + return t; + } + + /// \brief Convert to the specified CFGElement type, returning None if this + /// CFGElement is not of the desired type. + template<typename T> + Optional<T> getAs() const { + if (!T::isKind(*this)) + return None; + T t; + CFGElement& e = t; + e = *this; + return t; + } + + Kind getKind() const { + unsigned x = Data2.getInt(); + x <<= 2; + x |= Data1.getInt(); + return (Kind) x; + } +}; + +class CFGStmt : public CFGElement { +public: + CFGStmt(Stmt *S) : CFGElement(Statement, S) {} + + const Stmt *getStmt() const { + return static_cast<const Stmt *>(Data1.getPointer()); + } + +private: + friend class CFGElement; + CFGStmt() {} + static bool isKind(const CFGElement &E) { + return E.getKind() == Statement; + } +}; + +/// CFGInitializer - Represents C++ base or member initializer from +/// constructor's initialization list. +class CFGInitializer : public CFGElement { +public: + CFGInitializer(CXXCtorInitializer *initializer) + : CFGElement(Initializer, initializer) {} + + CXXCtorInitializer* getInitializer() const { + return static_cast<CXXCtorInitializer*>(Data1.getPointer()); + } + +private: + friend class CFGElement; + CFGInitializer() {} + static bool isKind(const CFGElement &E) { + return E.getKind() == Initializer; + } +}; + +/// CFGNewAllocator - Represents C++ allocator call. +class CFGNewAllocator : public CFGElement { +public: + explicit CFGNewAllocator(const CXXNewExpr *S) + : CFGElement(NewAllocator, S) {} + + // Get the new expression. + const CXXNewExpr *getAllocatorExpr() const { + return static_cast<CXXNewExpr *>(Data1.getPointer()); + } + +private: + friend class CFGElement; + CFGNewAllocator() {} + static bool isKind(const CFGElement &elem) { + return elem.getKind() == NewAllocator; + } +}; + +/// CFGImplicitDtor - Represents C++ object destructor implicitly generated +/// by compiler on various occasions. +class CFGImplicitDtor : public CFGElement { +protected: + CFGImplicitDtor() {} + CFGImplicitDtor(Kind kind, const void *data1, const void *data2 = nullptr) + : CFGElement(kind, data1, data2) { + assert(kind >= DTOR_BEGIN && kind <= DTOR_END); + } + +public: + const CXXDestructorDecl *getDestructorDecl(ASTContext &astContext) const; + bool isNoReturn(ASTContext &astContext) const; + +private: + friend class CFGElement; + static bool isKind(const CFGElement &E) { + Kind kind = E.getKind(); + return kind >= DTOR_BEGIN && kind <= DTOR_END; + } +}; + +/// CFGAutomaticObjDtor - Represents C++ object destructor implicitly generated +/// for automatic object or temporary bound to const reference at the point +/// of leaving its local scope. +class CFGAutomaticObjDtor: public CFGImplicitDtor { +public: + CFGAutomaticObjDtor(const VarDecl *var, const Stmt *stmt) + : CFGImplicitDtor(AutomaticObjectDtor, var, stmt) {} + + const VarDecl *getVarDecl() const { + return static_cast<VarDecl*>(Data1.getPointer()); + } + + // Get statement end of which triggered the destructor call. + const Stmt *getTriggerStmt() const { + return static_cast<Stmt*>(Data2.getPointer()); + } + +private: + friend class CFGElement; + CFGAutomaticObjDtor() {} + static bool isKind(const CFGElement &elem) { + return elem.getKind() == AutomaticObjectDtor; + } +}; + +/// CFGDeleteDtor - Represents C++ object destructor generated +/// from a call to delete. +class CFGDeleteDtor : public CFGImplicitDtor { +public: + CFGDeleteDtor(const CXXRecordDecl *RD, const CXXDeleteExpr *DE) + : CFGImplicitDtor(DeleteDtor, RD, DE) {} + + const CXXRecordDecl *getCXXRecordDecl() const { + return static_cast<CXXRecordDecl*>(Data1.getPointer()); + } + + // Get Delete expression which triggered the destructor call. + const CXXDeleteExpr *getDeleteExpr() const { + return static_cast<CXXDeleteExpr *>(Data2.getPointer()); + } + +private: + friend class CFGElement; + CFGDeleteDtor() {} + static bool isKind(const CFGElement &elem) { + return elem.getKind() == DeleteDtor; + } +}; + +/// CFGBaseDtor - Represents C++ object destructor implicitly generated for +/// base object in destructor. +class CFGBaseDtor : public CFGImplicitDtor { +public: + CFGBaseDtor(const CXXBaseSpecifier *base) + : CFGImplicitDtor(BaseDtor, base) {} + + const CXXBaseSpecifier *getBaseSpecifier() const { + return static_cast<const CXXBaseSpecifier*>(Data1.getPointer()); + } + +private: + friend class CFGElement; + CFGBaseDtor() {} + static bool isKind(const CFGElement &E) { + return E.getKind() == BaseDtor; + } +}; + +/// CFGMemberDtor - Represents C++ object destructor implicitly generated for +/// member object in destructor. +class CFGMemberDtor : public CFGImplicitDtor { +public: + CFGMemberDtor(const FieldDecl *field) + : CFGImplicitDtor(MemberDtor, field, nullptr) {} + + const FieldDecl *getFieldDecl() const { + return static_cast<const FieldDecl*>(Data1.getPointer()); + } + +private: + friend class CFGElement; + CFGMemberDtor() {} + static bool isKind(const CFGElement &E) { + return E.getKind() == MemberDtor; + } +}; + +/// CFGTemporaryDtor - Represents C++ object destructor implicitly generated +/// at the end of full expression for temporary object. +class CFGTemporaryDtor : public CFGImplicitDtor { +public: + CFGTemporaryDtor(CXXBindTemporaryExpr *expr) + : CFGImplicitDtor(TemporaryDtor, expr, nullptr) {} + + const CXXBindTemporaryExpr *getBindTemporaryExpr() const { + return static_cast<const CXXBindTemporaryExpr *>(Data1.getPointer()); + } + +private: + friend class CFGElement; + CFGTemporaryDtor() {} + static bool isKind(const CFGElement &E) { + return E.getKind() == TemporaryDtor; + } +}; + +/// CFGTerminator - Represents CFGBlock terminator statement. +/// +/// TemporaryDtorsBranch bit is set to true if the terminator marks a branch +/// in control flow of destructors of temporaries. In this case terminator +/// statement is the same statement that branches control flow in evaluation +/// of matching full expression. +class CFGTerminator { + llvm::PointerIntPair<Stmt *, 1> Data; +public: + CFGTerminator() {} + CFGTerminator(Stmt *S, bool TemporaryDtorsBranch = false) + : Data(S, TemporaryDtorsBranch) {} + + Stmt *getStmt() { return Data.getPointer(); } + const Stmt *getStmt() const { return Data.getPointer(); } + + bool isTemporaryDtorsBranch() const { return Data.getInt(); } + + operator Stmt *() { return getStmt(); } + operator const Stmt *() const { return getStmt(); } + + Stmt *operator->() { return getStmt(); } + const Stmt *operator->() const { return getStmt(); } + + Stmt &operator*() { return *getStmt(); } + const Stmt &operator*() const { return *getStmt(); } + + explicit operator bool() const { return getStmt(); } +}; + +/// CFGBlock - Represents a single basic block in a source-level CFG. +/// It consists of: +/// +/// (1) A set of statements/expressions (which may contain subexpressions). +/// (2) A "terminator" statement (not in the set of statements). +/// (3) A list of successors and predecessors. +/// +/// Terminator: The terminator represents the type of control-flow that occurs +/// at the end of the basic block. The terminator is a Stmt* referring to an +/// AST node that has control-flow: if-statements, breaks, loops, etc. +/// If the control-flow is conditional, the condition expression will appear +/// within the set of statements in the block (usually the last statement). +/// +/// Predecessors: the order in the set of predecessors is arbitrary. +/// +/// Successors: the order in the set of successors is NOT arbitrary. We +/// currently have the following orderings based on the terminator: +/// +/// Terminator Successor Ordering +/// ----------------------------------------------------- +/// if Then Block; Else Block +/// ? operator LHS expression; RHS expression +/// &&, || expression that uses result of && or ||, RHS +/// +/// But note that any of that may be NULL in case of optimized-out edges. +/// +class CFGBlock { + class ElementList { + typedef BumpVector<CFGElement> ImplTy; + ImplTy Impl; + public: + ElementList(BumpVectorContext &C) : Impl(C, 4) {} + + typedef std::reverse_iterator<ImplTy::iterator> iterator; + typedef std::reverse_iterator<ImplTy::const_iterator> const_iterator; + typedef ImplTy::iterator reverse_iterator; + typedef ImplTy::const_iterator const_reverse_iterator; + typedef ImplTy::const_reference const_reference; + + void push_back(CFGElement e, BumpVectorContext &C) { Impl.push_back(e, C); } + reverse_iterator insert(reverse_iterator I, size_t Cnt, CFGElement E, + BumpVectorContext &C) { + return Impl.insert(I, Cnt, E, C); + } + + const_reference front() const { return Impl.back(); } + const_reference back() const { return Impl.front(); } + + iterator begin() { return Impl.rbegin(); } + iterator end() { return Impl.rend(); } + const_iterator begin() const { return Impl.rbegin(); } + const_iterator end() const { return Impl.rend(); } + reverse_iterator rbegin() { return Impl.begin(); } + reverse_iterator rend() { return Impl.end(); } + const_reverse_iterator rbegin() const { return Impl.begin(); } + const_reverse_iterator rend() const { return Impl.end(); } + + CFGElement operator[](size_t i) const { + assert(i < Impl.size()); + return Impl[Impl.size() - 1 - i]; + } + + size_t size() const { return Impl.size(); } + bool empty() const { return Impl.empty(); } + }; + + /// Stmts - The set of statements in the basic block. + ElementList Elements; + + /// Label - An (optional) label that prefixes the executable + /// statements in the block. When this variable is non-NULL, it is + /// either an instance of LabelStmt, SwitchCase or CXXCatchStmt. + Stmt *Label; + + /// Terminator - The terminator for a basic block that + /// indicates the type of control-flow that occurs between a block + /// and its successors. + CFGTerminator Terminator; + + /// LoopTarget - Some blocks are used to represent the "loop edge" to + /// the start of a loop from within the loop body. This Stmt* will be + /// refer to the loop statement for such blocks (and be null otherwise). + const Stmt *LoopTarget; + + /// BlockID - A numerical ID assigned to a CFGBlock during construction + /// of the CFG. + unsigned BlockID; + +public: + /// This class represents a potential adjacent block in the CFG. It encodes + /// whether or not the block is actually reachable, or can be proved to be + /// trivially unreachable. For some cases it allows one to encode scenarios + /// where a block was substituted because the original (now alternate) block + /// is unreachable. + class AdjacentBlock { + enum Kind { + AB_Normal, + AB_Unreachable, + AB_Alternate + }; + + CFGBlock *ReachableBlock; + llvm::PointerIntPair<CFGBlock*, 2> UnreachableBlock; + + public: + /// Construct an AdjacentBlock with a possibly unreachable block. + AdjacentBlock(CFGBlock *B, bool IsReachable); + + /// Construct an AdjacentBlock with a reachable block and an alternate + /// unreachable block. + AdjacentBlock(CFGBlock *B, CFGBlock *AlternateBlock); + + /// Get the reachable block, if one exists. + CFGBlock *getReachableBlock() const { + return ReachableBlock; + } + + /// Get the potentially unreachable block. + CFGBlock *getPossiblyUnreachableBlock() const { + return UnreachableBlock.getPointer(); + } + + /// Provide an implicit conversion to CFGBlock* so that + /// AdjacentBlock can be substituted for CFGBlock*. + operator CFGBlock*() const { + return getReachableBlock(); + } + + CFGBlock& operator *() const { + return *getReachableBlock(); + } + + CFGBlock* operator ->() const { + return getReachableBlock(); + } + + bool isReachable() const { + Kind K = (Kind) UnreachableBlock.getInt(); + return K == AB_Normal || K == AB_Alternate; + } + }; + +private: + /// Predecessors/Successors - Keep track of the predecessor / successor + /// CFG blocks. + typedef BumpVector<AdjacentBlock> AdjacentBlocks; + AdjacentBlocks Preds; + AdjacentBlocks Succs; + + /// NoReturn - This bit is set when the basic block contains a function call + /// or implicit destructor that is attributed as 'noreturn'. In that case, + /// control cannot technically ever proceed past this block. All such blocks + /// will have a single immediate successor: the exit block. This allows them + /// to be easily reached from the exit block and using this bit quickly + /// recognized without scanning the contents of the block. + /// + /// Optimization Note: This bit could be profitably folded with Terminator's + /// storage if the memory usage of CFGBlock becomes an issue. + unsigned HasNoReturnElement : 1; + + /// Parent - The parent CFG that owns this CFGBlock. + CFG *Parent; + +public: + explicit CFGBlock(unsigned blockid, BumpVectorContext &C, CFG *parent) + : Elements(C), Label(nullptr), Terminator(nullptr), LoopTarget(nullptr), + BlockID(blockid), Preds(C, 1), Succs(C, 1), HasNoReturnElement(false), + Parent(parent) {} + + // Statement iterators + typedef ElementList::iterator iterator; + typedef ElementList::const_iterator const_iterator; + typedef ElementList::reverse_iterator reverse_iterator; + typedef ElementList::const_reverse_iterator const_reverse_iterator; + + CFGElement front() const { return Elements.front(); } + CFGElement back() const { return Elements.back(); } + + iterator begin() { return Elements.begin(); } + iterator end() { return Elements.end(); } + const_iterator begin() const { return Elements.begin(); } + const_iterator end() const { return Elements.end(); } + + reverse_iterator rbegin() { return Elements.rbegin(); } + reverse_iterator rend() { return Elements.rend(); } + const_reverse_iterator rbegin() const { return Elements.rbegin(); } + const_reverse_iterator rend() const { return Elements.rend(); } + + unsigned size() const { return Elements.size(); } + bool empty() const { return Elements.empty(); } + + CFGElement operator[](size_t i) const { return Elements[i]; } + + // CFG iterators + typedef AdjacentBlocks::iterator pred_iterator; + typedef AdjacentBlocks::const_iterator const_pred_iterator; + typedef AdjacentBlocks::reverse_iterator pred_reverse_iterator; + typedef AdjacentBlocks::const_reverse_iterator const_pred_reverse_iterator; + + typedef AdjacentBlocks::iterator succ_iterator; + typedef AdjacentBlocks::const_iterator const_succ_iterator; + typedef AdjacentBlocks::reverse_iterator succ_reverse_iterator; + typedef AdjacentBlocks::const_reverse_iterator const_succ_reverse_iterator; + + pred_iterator pred_begin() { return Preds.begin(); } + pred_iterator pred_end() { return Preds.end(); } + const_pred_iterator pred_begin() const { return Preds.begin(); } + const_pred_iterator pred_end() const { return Preds.end(); } + + pred_reverse_iterator pred_rbegin() { return Preds.rbegin(); } + pred_reverse_iterator pred_rend() { return Preds.rend(); } + const_pred_reverse_iterator pred_rbegin() const { return Preds.rbegin(); } + const_pred_reverse_iterator pred_rend() const { return Preds.rend(); } + + succ_iterator succ_begin() { return Succs.begin(); } + succ_iterator succ_end() { return Succs.end(); } + const_succ_iterator succ_begin() const { return Succs.begin(); } + const_succ_iterator succ_end() const { return Succs.end(); } + + succ_reverse_iterator succ_rbegin() { return Succs.rbegin(); } + succ_reverse_iterator succ_rend() { return Succs.rend(); } + const_succ_reverse_iterator succ_rbegin() const { return Succs.rbegin(); } + const_succ_reverse_iterator succ_rend() const { return Succs.rend(); } + + unsigned succ_size() const { return Succs.size(); } + bool succ_empty() const { return Succs.empty(); } + + unsigned pred_size() const { return Preds.size(); } + bool pred_empty() const { return Preds.empty(); } + + + class FilterOptions { + public: + FilterOptions() { + IgnoreNullPredecessors = 1; + IgnoreDefaultsWithCoveredEnums = 0; + } + + unsigned IgnoreNullPredecessors : 1; + unsigned IgnoreDefaultsWithCoveredEnums : 1; + }; + + static bool FilterEdge(const FilterOptions &F, const CFGBlock *Src, + const CFGBlock *Dst); + + template <typename IMPL, bool IsPred> + class FilteredCFGBlockIterator { + private: + IMPL I, E; + const FilterOptions F; + const CFGBlock *From; + public: + explicit FilteredCFGBlockIterator(const IMPL &i, const IMPL &e, + const CFGBlock *from, + const FilterOptions &f) + : I(i), E(e), F(f), From(from) { + while (hasMore() && Filter(*I)) + ++I; + } + + bool hasMore() const { return I != E; } + + FilteredCFGBlockIterator &operator++() { + do { ++I; } while (hasMore() && Filter(*I)); + return *this; + } + + const CFGBlock *operator*() const { return *I; } + private: + bool Filter(const CFGBlock *To) { + return IsPred ? FilterEdge(F, To, From) : FilterEdge(F, From, To); + } + }; + + typedef FilteredCFGBlockIterator<const_pred_iterator, true> + filtered_pred_iterator; + + typedef FilteredCFGBlockIterator<const_succ_iterator, false> + filtered_succ_iterator; + + filtered_pred_iterator filtered_pred_start_end(const FilterOptions &f) const { + return filtered_pred_iterator(pred_begin(), pred_end(), this, f); + } + + filtered_succ_iterator filtered_succ_start_end(const FilterOptions &f) const { + return filtered_succ_iterator(succ_begin(), succ_end(), this, f); + } + + // Manipulation of block contents + + void setTerminator(CFGTerminator Term) { Terminator = Term; } + void setLabel(Stmt *Statement) { Label = Statement; } + void setLoopTarget(const Stmt *loopTarget) { LoopTarget = loopTarget; } + void setHasNoReturnElement() { HasNoReturnElement = true; } + + CFGTerminator getTerminator() { return Terminator; } + const CFGTerminator getTerminator() const { return Terminator; } + + Stmt *getTerminatorCondition(bool StripParens = true); + + const Stmt *getTerminatorCondition(bool StripParens = true) const { + return const_cast<CFGBlock*>(this)->getTerminatorCondition(StripParens); + } + + const Stmt *getLoopTarget() const { return LoopTarget; } + + Stmt *getLabel() { return Label; } + const Stmt *getLabel() const { return Label; } + + bool hasNoReturnElement() const { return HasNoReturnElement; } + + unsigned getBlockID() const { return BlockID; } + + CFG *getParent() const { return Parent; } + + void dump() const; + + void dump(const CFG *cfg, const LangOptions &LO, bool ShowColors = false) const; + void print(raw_ostream &OS, const CFG* cfg, const LangOptions &LO, + bool ShowColors) const; + void printTerminator(raw_ostream &OS, const LangOptions &LO) const; + void printAsOperand(raw_ostream &OS, bool /*PrintType*/) { + OS << "BB#" << getBlockID(); + } + + /// Adds a (potentially unreachable) successor block to the current block. + void addSuccessor(AdjacentBlock Succ, BumpVectorContext &C); + + void appendStmt(Stmt *statement, BumpVectorContext &C) { + Elements.push_back(CFGStmt(statement), C); + } + + void appendInitializer(CXXCtorInitializer *initializer, + BumpVectorContext &C) { + Elements.push_back(CFGInitializer(initializer), C); + } + + void appendNewAllocator(CXXNewExpr *NE, + BumpVectorContext &C) { + Elements.push_back(CFGNewAllocator(NE), C); + } + + void appendBaseDtor(const CXXBaseSpecifier *BS, BumpVectorContext &C) { + Elements.push_back(CFGBaseDtor(BS), C); + } + + void appendMemberDtor(FieldDecl *FD, BumpVectorContext &C) { + Elements.push_back(CFGMemberDtor(FD), C); + } + + void appendTemporaryDtor(CXXBindTemporaryExpr *E, BumpVectorContext &C) { + Elements.push_back(CFGTemporaryDtor(E), C); + } + + void appendAutomaticObjDtor(VarDecl *VD, Stmt *S, BumpVectorContext &C) { + Elements.push_back(CFGAutomaticObjDtor(VD, S), C); + } + + void appendDeleteDtor(CXXRecordDecl *RD, CXXDeleteExpr *DE, BumpVectorContext &C) { + Elements.push_back(CFGDeleteDtor(RD, DE), C); + } + + // Destructors must be inserted in reversed order. So insertion is in two + // steps. First we prepare space for some number of elements, then we insert + // the elements beginning at the last position in prepared space. + iterator beginAutomaticObjDtorsInsert(iterator I, size_t Cnt, + BumpVectorContext &C) { + return iterator(Elements.insert(I.base(), Cnt, + CFGAutomaticObjDtor(nullptr, nullptr), C)); + } + iterator insertAutomaticObjDtor(iterator I, VarDecl *VD, Stmt *S) { + *I = CFGAutomaticObjDtor(VD, S); + return ++I; + } +}; + +/// \brief CFGCallback defines methods that should be called when a logical +/// operator error is found when building the CFG. +class CFGCallback { +public: + CFGCallback() {} + virtual void compareAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue) {} + virtual void compareBitwiseEquality(const BinaryOperator *B, + bool isAlwaysTrue) {} + virtual ~CFGCallback() {} +}; + +/// CFG - Represents a source-level, intra-procedural CFG that represents the +/// control-flow of a Stmt. The Stmt can represent an entire function body, +/// or a single expression. A CFG will always contain one empty block that +/// represents the Exit point of the CFG. A CFG will also contain a designated +/// Entry block. The CFG solely represents control-flow; it consists of +/// CFGBlocks which are simply containers of Stmt*'s in the AST the CFG +/// was constructed from. +class CFG { +public: + //===--------------------------------------------------------------------===// + // CFG Construction & Manipulation. + //===--------------------------------------------------------------------===// + + class BuildOptions { + std::bitset<Stmt::lastStmtConstant> alwaysAddMask; + public: + typedef llvm::DenseMap<const Stmt *, const CFGBlock*> ForcedBlkExprs; + ForcedBlkExprs **forcedBlkExprs; + CFGCallback *Observer; + bool PruneTriviallyFalseEdges; + bool AddEHEdges; + bool AddInitializers; + bool AddImplicitDtors; + bool AddTemporaryDtors; + bool AddStaticInitBranches; + bool AddCXXNewAllocator; + bool AddCXXDefaultInitExprInCtors; + + bool alwaysAdd(const Stmt *stmt) const { + return alwaysAddMask[stmt->getStmtClass()]; + } + + BuildOptions &setAlwaysAdd(Stmt::StmtClass stmtClass, bool val = true) { + alwaysAddMask[stmtClass] = val; + return *this; + } + + BuildOptions &setAllAlwaysAdd() { + alwaysAddMask.set(); + return *this; + } + + BuildOptions() + : forcedBlkExprs(nullptr), Observer(nullptr), + PruneTriviallyFalseEdges(true), AddEHEdges(false), + AddInitializers(false), AddImplicitDtors(false), + AddTemporaryDtors(false), AddStaticInitBranches(false), + AddCXXNewAllocator(false), AddCXXDefaultInitExprInCtors(false) {} + }; + + /// \brief Provides a custom implementation of the iterator class to have the + /// same interface as Function::iterator - iterator returns CFGBlock + /// (not a pointer to CFGBlock). + class graph_iterator { + public: + typedef CFGBlock value_type; + typedef value_type& reference; + typedef value_type* pointer; + typedef BumpVector<CFGBlock*>::iterator ImplTy; + + graph_iterator(const ImplTy &i) : I(i) {} + + bool operator==(const graph_iterator &X) const { return I == X.I; } + bool operator!=(const graph_iterator &X) const { return I != X.I; } + + reference operator*() const { return **I; } + pointer operator->() const { return *I; } + operator CFGBlock* () { return *I; } + + graph_iterator &operator++() { ++I; return *this; } + graph_iterator &operator--() { --I; return *this; } + + private: + ImplTy I; + }; + + class const_graph_iterator { + public: + typedef const CFGBlock value_type; + typedef value_type& reference; + typedef value_type* pointer; + typedef BumpVector<CFGBlock*>::const_iterator ImplTy; + + const_graph_iterator(const ImplTy &i) : I(i) {} + + bool operator==(const const_graph_iterator &X) const { return I == X.I; } + bool operator!=(const const_graph_iterator &X) const { return I != X.I; } + + reference operator*() const { return **I; } + pointer operator->() const { return *I; } + operator CFGBlock* () const { return *I; } + + const_graph_iterator &operator++() { ++I; return *this; } + const_graph_iterator &operator--() { --I; return *this; } + + private: + ImplTy I; + }; + + /// buildCFG - Builds a CFG from an AST. + static std::unique_ptr<CFG> buildCFG(const Decl *D, Stmt *AST, ASTContext *C, + const BuildOptions &BO); + + /// createBlock - Create a new block in the CFG. The CFG owns the block; + /// the caller should not directly free it. + CFGBlock *createBlock(); + + /// setEntry - Set the entry block of the CFG. This is typically used + /// only during CFG construction. Most CFG clients expect that the + /// entry block has no predecessors and contains no statements. + void setEntry(CFGBlock *B) { Entry = B; } + + /// setIndirectGotoBlock - Set the block used for indirect goto jumps. + /// This is typically used only during CFG construction. + void setIndirectGotoBlock(CFGBlock *B) { IndirectGotoBlock = B; } + + //===--------------------------------------------------------------------===// + // Block Iterators + //===--------------------------------------------------------------------===// + + typedef BumpVector<CFGBlock*> CFGBlockListTy; + typedef CFGBlockListTy::iterator iterator; + typedef CFGBlockListTy::const_iterator const_iterator; + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + + CFGBlock & front() { return *Blocks.front(); } + CFGBlock & back() { return *Blocks.back(); } + + iterator begin() { return Blocks.begin(); } + iterator end() { return Blocks.end(); } + const_iterator begin() const { return Blocks.begin(); } + const_iterator end() const { return Blocks.end(); } + + graph_iterator nodes_begin() { return graph_iterator(Blocks.begin()); } + graph_iterator nodes_end() { return graph_iterator(Blocks.end()); } + const_graph_iterator nodes_begin() const { + return const_graph_iterator(Blocks.begin()); + } + const_graph_iterator nodes_end() const { + return const_graph_iterator(Blocks.end()); + } + + reverse_iterator rbegin() { return Blocks.rbegin(); } + reverse_iterator rend() { return Blocks.rend(); } + const_reverse_iterator rbegin() const { return Blocks.rbegin(); } + const_reverse_iterator rend() const { return Blocks.rend(); } + + CFGBlock & getEntry() { return *Entry; } + const CFGBlock & getEntry() const { return *Entry; } + CFGBlock & getExit() { return *Exit; } + const CFGBlock & getExit() const { return *Exit; } + + CFGBlock * getIndirectGotoBlock() { return IndirectGotoBlock; } + const CFGBlock * getIndirectGotoBlock() const { return IndirectGotoBlock; } + + typedef std::vector<const CFGBlock*>::const_iterator try_block_iterator; + try_block_iterator try_blocks_begin() const { + return TryDispatchBlocks.begin(); + } + try_block_iterator try_blocks_end() const { + return TryDispatchBlocks.end(); + } + + void addTryDispatchBlock(const CFGBlock *block) { + TryDispatchBlocks.push_back(block); + } + + /// Records a synthetic DeclStmt and the DeclStmt it was constructed from. + /// + /// The CFG uses synthetic DeclStmts when a single AST DeclStmt contains + /// multiple decls. + void addSyntheticDeclStmt(const DeclStmt *Synthetic, + const DeclStmt *Source) { + assert(Synthetic->isSingleDecl() && "Can handle single declarations only"); + assert(Synthetic != Source && "Don't include original DeclStmts in map"); + assert(!SyntheticDeclStmts.count(Synthetic) && "Already in map"); + SyntheticDeclStmts[Synthetic] = Source; + } + + typedef llvm::DenseMap<const DeclStmt *, const DeclStmt *>::const_iterator + synthetic_stmt_iterator; + + /// Iterates over synthetic DeclStmts in the CFG. + /// + /// Each element is a (synthetic statement, source statement) pair. + /// + /// \sa addSyntheticDeclStmt + synthetic_stmt_iterator synthetic_stmt_begin() const { + return SyntheticDeclStmts.begin(); + } + + /// \sa synthetic_stmt_begin + synthetic_stmt_iterator synthetic_stmt_end() const { + return SyntheticDeclStmts.end(); + } + + //===--------------------------------------------------------------------===// + // Member templates useful for various batch operations over CFGs. + //===--------------------------------------------------------------------===// + + template <typename CALLBACK> + void VisitBlockStmts(CALLBACK& O) const { + for (const_iterator I=begin(), E=end(); I != E; ++I) + for (CFGBlock::const_iterator BI=(*I)->begin(), BE=(*I)->end(); + BI != BE; ++BI) { + if (Optional<CFGStmt> stmt = BI->getAs<CFGStmt>()) + O(const_cast<Stmt*>(stmt->getStmt())); + } + } + + //===--------------------------------------------------------------------===// + // CFG Introspection. + //===--------------------------------------------------------------------===// + + /// getNumBlockIDs - Returns the total number of BlockIDs allocated (which + /// start at 0). + unsigned getNumBlockIDs() const { return NumBlockIDs; } + + /// size - Return the total number of CFGBlocks within the CFG + /// This is simply a renaming of the getNumBlockIDs(). This is necessary + /// because the dominator implementation needs such an interface. + unsigned size() const { return NumBlockIDs; } + + //===--------------------------------------------------------------------===// + // CFG Debugging: Pretty-Printing and Visualization. + //===--------------------------------------------------------------------===// + + void viewCFG(const LangOptions &LO) const; + void print(raw_ostream &OS, const LangOptions &LO, bool ShowColors) const; + void dump(const LangOptions &LO, bool ShowColors) const; + + //===--------------------------------------------------------------------===// + // Internal: constructors and data. + //===--------------------------------------------------------------------===// + + CFG() + : Entry(nullptr), Exit(nullptr), IndirectGotoBlock(nullptr), NumBlockIDs(0), + Blocks(BlkBVC, 10) {} + + llvm::BumpPtrAllocator& getAllocator() { + return BlkBVC.getAllocator(); + } + + BumpVectorContext &getBumpVectorContext() { + return BlkBVC; + } + +private: + CFGBlock *Entry; + CFGBlock *Exit; + CFGBlock* IndirectGotoBlock; // Special block to contain collective dispatch + // for indirect gotos + unsigned NumBlockIDs; + + BumpVectorContext BlkBVC; + + CFGBlockListTy Blocks; + + /// C++ 'try' statements are modeled with an indirect dispatch block. + /// This is the collection of such blocks present in the CFG. + std::vector<const CFGBlock *> TryDispatchBlocks; + + /// Collects DeclStmts synthesized for this CFG and maps each one back to its + /// source DeclStmt. + llvm::DenseMap<const DeclStmt *, const DeclStmt *> SyntheticDeclStmts; +}; +} // end namespace clang + +//===----------------------------------------------------------------------===// +// GraphTraits specializations for CFG basic block graphs (source-level CFGs) +//===----------------------------------------------------------------------===// + +namespace llvm { + +/// Implement simplify_type for CFGTerminator, so that we can dyn_cast from +/// CFGTerminator to a specific Stmt class. +template <> struct simplify_type< ::clang::CFGTerminator> { + typedef ::clang::Stmt *SimpleType; + static SimpleType getSimplifiedValue(::clang::CFGTerminator Val) { + return Val.getStmt(); + } +}; + +// Traits for: CFGBlock + +template <> struct GraphTraits< ::clang::CFGBlock *> { + typedef ::clang::CFGBlock NodeType; + typedef ::clang::CFGBlock::succ_iterator ChildIteratorType; + + static NodeType* getEntryNode(::clang::CFGBlock *BB) + { return BB; } + + static inline ChildIteratorType child_begin(NodeType* N) + { return N->succ_begin(); } + + static inline ChildIteratorType child_end(NodeType* N) + { return N->succ_end(); } +}; + +template <> struct GraphTraits< const ::clang::CFGBlock *> { + typedef const ::clang::CFGBlock NodeType; + typedef ::clang::CFGBlock::const_succ_iterator ChildIteratorType; + + static NodeType* getEntryNode(const clang::CFGBlock *BB) + { return BB; } + + static inline ChildIteratorType child_begin(NodeType* N) + { return N->succ_begin(); } + + static inline ChildIteratorType child_end(NodeType* N) + { return N->succ_end(); } +}; + +template <> struct GraphTraits<Inverse< ::clang::CFGBlock*> > { + typedef ::clang::CFGBlock NodeType; + typedef ::clang::CFGBlock::const_pred_iterator ChildIteratorType; + + static NodeType *getEntryNode(Inverse< ::clang::CFGBlock*> G) + { return G.Graph; } + + static inline ChildIteratorType child_begin(NodeType* N) + { return N->pred_begin(); } + + static inline ChildIteratorType child_end(NodeType* N) + { return N->pred_end(); } +}; + +template <> struct GraphTraits<Inverse<const ::clang::CFGBlock*> > { + typedef const ::clang::CFGBlock NodeType; + typedef ::clang::CFGBlock::const_pred_iterator ChildIteratorType; + + static NodeType *getEntryNode(Inverse<const ::clang::CFGBlock*> G) + { return G.Graph; } + + static inline ChildIteratorType child_begin(NodeType* N) + { return N->pred_begin(); } + + static inline ChildIteratorType child_end(NodeType* N) + { return N->pred_end(); } +}; + +// Traits for: CFG + +template <> struct GraphTraits< ::clang::CFG* > + : public GraphTraits< ::clang::CFGBlock *> { + + typedef ::clang::CFG::graph_iterator nodes_iterator; + + static NodeType *getEntryNode(::clang::CFG* F) { return &F->getEntry(); } + static nodes_iterator nodes_begin(::clang::CFG* F) { return F->nodes_begin();} + static nodes_iterator nodes_end(::clang::CFG* F) { return F->nodes_end(); } + static unsigned size(::clang::CFG* F) { return F->size(); } +}; + +template <> struct GraphTraits<const ::clang::CFG* > + : public GraphTraits<const ::clang::CFGBlock *> { + + typedef ::clang::CFG::const_graph_iterator nodes_iterator; + + static NodeType *getEntryNode( const ::clang::CFG* F) { + return &F->getEntry(); + } + static nodes_iterator nodes_begin( const ::clang::CFG* F) { + return F->nodes_begin(); + } + static nodes_iterator nodes_end( const ::clang::CFG* F) { + return F->nodes_end(); + } + static unsigned size(const ::clang::CFG* F) { + return F->size(); + } +}; + +template <> struct GraphTraits<Inverse< ::clang::CFG*> > + : public GraphTraits<Inverse< ::clang::CFGBlock*> > { + + typedef ::clang::CFG::graph_iterator nodes_iterator; + + static NodeType *getEntryNode( ::clang::CFG* F) { return &F->getExit(); } + static nodes_iterator nodes_begin( ::clang::CFG* F) {return F->nodes_begin();} + static nodes_iterator nodes_end( ::clang::CFG* F) { return F->nodes_end(); } +}; + +template <> struct GraphTraits<Inverse<const ::clang::CFG*> > + : public GraphTraits<Inverse<const ::clang::CFGBlock*> > { + + typedef ::clang::CFG::const_graph_iterator nodes_iterator; + + static NodeType *getEntryNode(const ::clang::CFG* F) { return &F->getExit(); } + static nodes_iterator nodes_begin(const ::clang::CFG* F) { + return F->nodes_begin(); + } + static nodes_iterator nodes_end(const ::clang::CFG* F) { + return F->nodes_end(); + } +}; +} // end llvm namespace + +#endif // LLVM_CLANG_ANALYSIS_CFG_H diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/CFGStmtMap.h b/contrib/llvm/tools/clang/include/clang/Analysis/CFGStmtMap.h new file mode 100644 index 0000000..4dfa91d --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Analysis/CFGStmtMap.h @@ -0,0 +1,52 @@ +//===--- CFGStmtMap.h - Map from Stmt* to CFGBlock* -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the CFGStmtMap class, which defines a mapping from +// Stmt* to CFGBlock* +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_CFGSTMTMAP_H +#define LLVM_CLANG_ANALYSIS_CFGSTMTMAP_H + +#include "clang/Analysis/CFG.h" + +namespace clang { + +class CFG; +class CFGBlock; +class ParentMap; +class Stmt; + +class CFGStmtMap { + ParentMap *PM; + void *M; + + CFGStmtMap(ParentMap *pm, void *m) : PM(pm), M(m) {} + +public: + ~CFGStmtMap(); + + /// Returns a new CFGMap for the given CFG. It is the caller's + /// responsibility to 'delete' this object when done using it. + static CFGStmtMap *Build(CFG* C, ParentMap *PM); + + /// Returns the CFGBlock the specified Stmt* appears in. For Stmt* that + /// are terminators, the CFGBlock is the block they appear as a terminator, + /// and not the block they appear as a block-level expression (e.g, '&&'). + /// CaseStmts and LabelStmts map to the CFGBlock they label. + CFGBlock *getBlock(Stmt * S); + + const CFGBlock *getBlock(const Stmt * S) const { + return const_cast<CFGStmtMap*>(this)->getBlock(const_cast<Stmt*>(S)); + } +}; + +} // end clang namespace +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/CallGraph.h b/contrib/llvm/tools/clang/include/clang/Analysis/CallGraph.h new file mode 100644 index 0000000..eda22a5 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Analysis/CallGraph.h @@ -0,0 +1,253 @@ +//== CallGraph.h - AST-based Call graph ------------------------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the AST-based CallGraph. +// +// A call graph for functions whose definitions/bodies are available in the +// current translation unit. The graph has a "virtual" root node that contains +// edges to all externally available functions. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_CALLGRAPH_H +#define LLVM_CLANG_ANALYSIS_CALLGRAPH_H + +#include "clang/AST/DeclBase.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/GraphTraits.h" +#include "llvm/ADT/SetVector.h" + +namespace clang { +class CallGraphNode; + +/// \brief The AST-based call graph. +/// +/// The call graph extends itself with the given declarations by implementing +/// the recursive AST visitor, which constructs the graph by visiting the given +/// declarations. +class CallGraph : public RecursiveASTVisitor<CallGraph> { + friend class CallGraphNode; + + typedef llvm::DenseMap<const Decl *, CallGraphNode *> FunctionMapTy; + + /// FunctionMap owns all CallGraphNodes. + FunctionMapTy FunctionMap; + + /// This is a virtual root node that has edges to all the functions. + CallGraphNode *Root; + +public: + CallGraph(); + ~CallGraph(); + + /// \brief Populate the call graph with the functions in the given + /// declaration. + /// + /// Recursively walks the declaration to find all the dependent Decls as well. + void addToCallGraph(Decl *D) { + TraverseDecl(D); + } + + /// \brief Determine if a declaration should be included in the graph. + static bool includeInGraph(const Decl *D); + + /// \brief Lookup the node for the given declaration. + CallGraphNode *getNode(const Decl *) const; + + /// \brief Lookup the node for the given declaration. If none found, insert + /// one into the graph. + CallGraphNode *getOrInsertNode(Decl *); + + /// Iterators through all the elements in the graph. Note, this gives + /// non-deterministic order. + typedef FunctionMapTy::iterator iterator; + typedef FunctionMapTy::const_iterator const_iterator; + iterator begin() { return FunctionMap.begin(); } + iterator end() { return FunctionMap.end(); } + const_iterator begin() const { return FunctionMap.begin(); } + const_iterator end() const { return FunctionMap.end(); } + + /// \brief Get the number of nodes in the graph. + unsigned size() const { return FunctionMap.size(); } + + /// \ brief Get the virtual root of the graph, all the functions available + /// externally are represented as callees of the node. + CallGraphNode *getRoot() const { return Root; } + + /// Iterators through all the nodes of the graph that have no parent. These + /// are the unreachable nodes, which are either unused or are due to us + /// failing to add a call edge due to the analysis imprecision. + typedef llvm::SetVector<CallGraphNode *>::iterator nodes_iterator; + typedef llvm::SetVector<CallGraphNode *>::const_iterator const_nodes_iterator; + + void print(raw_ostream &os) const; + void dump() const; + void viewGraph() const; + + void addNodesForBlocks(DeclContext *D); + + /// Part of recursive declaration visitation. We recursively visit all the + /// declarations to collect the root functions. + bool VisitFunctionDecl(FunctionDecl *FD) { + // We skip function template definitions, as their semantics is + // only determined when they are instantiated. + if (includeInGraph(FD)) { + // Add all blocks declared inside this function to the graph. + addNodesForBlocks(FD); + // If this function has external linkage, anything could call it. + // Note, we are not precise here. For example, the function could have + // its address taken. + addNodeForDecl(FD, FD->isGlobal()); + } + return true; + } + + /// Part of recursive declaration visitation. + bool VisitObjCMethodDecl(ObjCMethodDecl *MD) { + if (includeInGraph(MD)) { + addNodesForBlocks(MD); + addNodeForDecl(MD, true); + } + return true; + } + + // We are only collecting the declarations, so do not step into the bodies. + bool TraverseStmt(Stmt *S) { return true; } + + bool shouldWalkTypesOfTypeLocs() const { return false; } + +private: + /// \brief Add the given declaration to the call graph. + void addNodeForDecl(Decl *D, bool IsGlobal); + + /// \brief Allocate a new node in the graph. + CallGraphNode *allocateNewNode(Decl *); +}; + +class CallGraphNode { +public: + typedef CallGraphNode* CallRecord; + +private: + /// \brief The function/method declaration. + Decl *FD; + + /// \brief The list of functions called from this node. + SmallVector<CallRecord, 5> CalledFunctions; + +public: + CallGraphNode(Decl *D) : FD(D) {} + + typedef SmallVectorImpl<CallRecord>::iterator iterator; + typedef SmallVectorImpl<CallRecord>::const_iterator const_iterator; + + /// Iterators through all the callees/children of the node. + inline iterator begin() { return CalledFunctions.begin(); } + inline iterator end() { return CalledFunctions.end(); } + inline const_iterator begin() const { return CalledFunctions.begin(); } + inline const_iterator end() const { return CalledFunctions.end(); } + + inline bool empty() const {return CalledFunctions.empty(); } + inline unsigned size() const {return CalledFunctions.size(); } + + void addCallee(CallGraphNode *N, CallGraph *CG) { + CalledFunctions.push_back(N); + } + + Decl *getDecl() const { return FD; } + + void print(raw_ostream &os) const; + void dump() const; +}; + +} // end clang namespace + +// Graph traits for iteration, viewing. +namespace llvm { +template <> struct GraphTraits<clang::CallGraphNode*> { + typedef clang::CallGraphNode NodeType; + typedef clang::CallGraphNode::CallRecord CallRecordTy; + typedef std::pointer_to_unary_function<CallRecordTy, + clang::CallGraphNode*> CGNDerefFun; + static NodeType *getEntryNode(clang::CallGraphNode *CGN) { return CGN; } + typedef mapped_iterator<NodeType::iterator, CGNDerefFun> ChildIteratorType; + static inline ChildIteratorType child_begin(NodeType *N) { + return map_iterator(N->begin(), CGNDerefFun(CGNDeref)); + } + static inline ChildIteratorType child_end (NodeType *N) { + return map_iterator(N->end(), CGNDerefFun(CGNDeref)); + } + static clang::CallGraphNode *CGNDeref(CallRecordTy P) { + return P; + } +}; + +template <> struct GraphTraits<const clang::CallGraphNode*> { + typedef const clang::CallGraphNode NodeType; + typedef NodeType::const_iterator ChildIteratorType; + static NodeType *getEntryNode(const clang::CallGraphNode *CGN) { return CGN; } + static inline ChildIteratorType child_begin(NodeType *N) { return N->begin();} + static inline ChildIteratorType child_end(NodeType *N) { return N->end(); } +}; + +template <> struct GraphTraits<clang::CallGraph*> + : public GraphTraits<clang::CallGraphNode*> { + + static NodeType *getEntryNode(clang::CallGraph *CGN) { + return CGN->getRoot(); // Start at the external node! + } + typedef std::pair<const clang::Decl*, clang::CallGraphNode*> PairTy; + typedef std::pointer_to_unary_function<PairTy, clang::CallGraphNode&> DerefFun; + // nodes_iterator/begin/end - Allow iteration over all nodes in the graph + typedef mapped_iterator<clang::CallGraph::iterator, DerefFun> nodes_iterator; + + static nodes_iterator nodes_begin(clang::CallGraph *CG) { + return map_iterator(CG->begin(), DerefFun(CGdereference)); + } + static nodes_iterator nodes_end (clang::CallGraph *CG) { + return map_iterator(CG->end(), DerefFun(CGdereference)); + } + static clang::CallGraphNode &CGdereference(PairTy P) { + return *(P.second); + } + + static unsigned size(clang::CallGraph *CG) { + return CG->size(); + } +}; + +template <> struct GraphTraits<const clang::CallGraph*> : + public GraphTraits<const clang::CallGraphNode*> { + static NodeType *getEntryNode(const clang::CallGraph *CGN) { + return CGN->getRoot(); + } + typedef std::pair<const clang::Decl*, clang::CallGraphNode*> PairTy; + typedef std::pointer_to_unary_function<PairTy, clang::CallGraphNode&> DerefFun; + // nodes_iterator/begin/end - Allow iteration over all nodes in the graph + typedef mapped_iterator<clang::CallGraph::const_iterator, + DerefFun> nodes_iterator; + + static nodes_iterator nodes_begin(const clang::CallGraph *CG) { + return map_iterator(CG->begin(), DerefFun(CGdereference)); + } + static nodes_iterator nodes_end(const clang::CallGraph *CG) { + return map_iterator(CG->end(), DerefFun(CGdereference)); + } + static clang::CallGraphNode &CGdereference(PairTy P) { + return *(P.second); + } + + static unsigned size(const clang::CallGraph *CG) { + return CG->size(); + } +}; + +} // end llvm namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/CodeInjector.h b/contrib/llvm/tools/clang/include/clang/Analysis/CodeInjector.h new file mode 100644 index 0000000..413a55b --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Analysis/CodeInjector.h @@ -0,0 +1,46 @@ +//===-- CodeInjector.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the clang::CodeInjector interface which is responsible for +/// injecting AST of function definitions that may not be available in the +/// original source. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_CODEINJECTOR_H +#define LLVM_CLANG_ANALYSIS_CODEINJECTOR_H + +namespace clang { + +class Stmt; +class FunctionDecl; +class ObjCMethodDecl; + +/// \brief CodeInjector is an interface which is responsible for injecting AST +/// of function definitions that may not be available in the original source. +/// +/// The getBody function will be called each time the static analyzer examines a +/// function call that has no definition available in the current translation +/// unit. If the returned statement is not a null pointer, it is assumed to be +/// the body of a function which will be used for the analysis. The source of +/// the body can be arbitrary, but it is advised to use memoization to avoid +/// unnecessary reparsing of the external source that provides the body of the +/// functions. +class CodeInjector { +public: + CodeInjector(); + virtual ~CodeInjector(); + + virtual Stmt *getBody(const FunctionDecl *D) = 0; + virtual Stmt *getBody(const ObjCMethodDecl *D) = 0; +}; +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/DomainSpecific/CocoaConventions.h b/contrib/llvm/tools/clang/include/clang/Analysis/DomainSpecific/CocoaConventions.h new file mode 100644 index 0000000..8b3fcff --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Analysis/DomainSpecific/CocoaConventions.h @@ -0,0 +1,42 @@ +//===- CocoaConventions.h - Special handling of Cocoa conventions -*- C++ -*--// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements cocoa naming convention analysis. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_DOMAINSPECIFIC_COCOACONVENTIONS_H +#define LLVM_CLANG_ANALYSIS_DOMAINSPECIFIC_COCOACONVENTIONS_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { +class FunctionDecl; +class QualType; + +namespace ento { +namespace cocoa { + + bool isRefType(QualType RetTy, StringRef Prefix, + StringRef Name = StringRef()); + + bool isCocoaObjectRef(QualType T); + +} + +namespace coreFoundation { + bool isCFObjectRef(QualType T); + + bool followsCreateRule(const FunctionDecl *FD); +} + +}} // end: "clang:ento" + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/DomainSpecific/ObjCNoReturn.h b/contrib/llvm/tools/clang/include/clang/Analysis/DomainSpecific/ObjCNoReturn.h new file mode 100644 index 0000000..f9e800a --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Analysis/DomainSpecific/ObjCNoReturn.h @@ -0,0 +1,46 @@ +//= ObjCNoReturn.h - Handling of Cocoa APIs known not to return --*- C++ -*---// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements special handling of recognizing ObjC API hooks that +// do not return but aren't marked as such in API headers. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_DOMAINSPECIFIC_OBJCNORETURN_H +#define LLVM_CLANG_ANALYSIS_DOMAINSPECIFIC_OBJCNORETURN_H + +#include "clang/Basic/IdentifierTable.h" + +namespace clang { + +class ASTContext; +class ObjCMessageExpr; + +class ObjCNoReturn { + /// Cached "raise" selector. + Selector RaiseSel; + + /// Cached identifier for "NSException". + IdentifierInfo *NSExceptionII; + + enum { NUM_RAISE_SELECTORS = 2 }; + + /// Cached set of selectors in NSException that are 'noreturn'. + Selector NSExceptionInstanceRaiseSelectors[NUM_RAISE_SELECTORS]; + +public: + ObjCNoReturn(ASTContext &C); + + /// Return true if the given message expression is known to never + /// return. + bool isImplicitNoReturn(const ObjCMessageExpr *ME); +}; +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/FlowSensitive/DataflowValues.h b/contrib/llvm/tools/clang/include/clang/Analysis/FlowSensitive/DataflowValues.h new file mode 100644 index 0000000..f86b2b0 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Analysis/FlowSensitive/DataflowValues.h @@ -0,0 +1,172 @@ +//===--- DataflowValues.h - Data structure for dataflow values --*- 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 skeleton data structure for encapsulating the dataflow +// values for a CFG. Typically this is subclassed to provide methods for +// computing these values from a CFG. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSES_DATAFLOW_VALUES +#define LLVM_CLANG_ANALYSES_DATAFLOW_VALUES + +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/ProgramPoint.h" +#include "llvm/ADT/DenseMap.h" + +//===----------------------------------------------------------------------===// +/// Dataflow Directional Tag Classes. These are used for tag dispatching +/// within the dataflow solver/transfer functions to determine what direction +/// a dataflow analysis flows. +//===----------------------------------------------------------------------===// + +namespace clang { +namespace dataflow { + struct forward_analysis_tag {}; + struct backward_analysis_tag {}; +} // end namespace dataflow + +//===----------------------------------------------------------------------===// +/// DataflowValues. Container class to store dataflow values for a CFG. +//===----------------------------------------------------------------------===// + +template <typename ValueTypes, + typename _AnalysisDirTag = dataflow::forward_analysis_tag > +class DataflowValues { + + //===--------------------------------------------------------------------===// + // Type declarations. + //===--------------------------------------------------------------------===// + +public: + typedef typename ValueTypes::ValTy ValTy; + typedef typename ValueTypes::AnalysisDataTy AnalysisDataTy; + typedef _AnalysisDirTag AnalysisDirTag; + typedef llvm::DenseMap<ProgramPoint, ValTy> EdgeDataMapTy; + typedef llvm::DenseMap<const CFGBlock*, ValTy> BlockDataMapTy; + typedef llvm::DenseMap<const Stmt*, ValTy> StmtDataMapTy; + + //===--------------------------------------------------------------------===// + // Predicates. + //===--------------------------------------------------------------------===// + +public: + /// isForwardAnalysis - Returns true if the dataflow values are computed + /// from a forward analysis. + bool isForwardAnalysis() { return isForwardAnalysis(AnalysisDirTag()); } + + /// isBackwardAnalysis - Returns true if the dataflow values are computed + /// from a backward analysis. + bool isBackwardAnalysis() { return !isForwardAnalysis(); } + +private: + bool isForwardAnalysis(dataflow::forward_analysis_tag) { return true; } + bool isForwardAnalysis(dataflow::backward_analysis_tag) { return false; } + + //===--------------------------------------------------------------------===// + // Initialization and accessors methods. + //===--------------------------------------------------------------------===// + +public: + DataflowValues() : StmtDataMap(NULL) {} + ~DataflowValues() { delete StmtDataMap; } + + /// InitializeValues - Invoked by the solver to initialize state needed for + /// dataflow analysis. This method is usually specialized by subclasses. + void InitializeValues(const CFG& cfg) {} + + + /// getEdgeData - Retrieves the dataflow values associated with a + /// CFG edge. + ValTy& getEdgeData(const BlockEdge &E) { + typename EdgeDataMapTy::iterator I = EdgeDataMap.find(E); + assert (I != EdgeDataMap.end() && "No data associated with Edge."); + return I->second; + } + + const ValTy& getEdgeData(const BlockEdge &E) const { + return reinterpret_cast<DataflowValues*>(this)->getEdgeData(E); + } + + /// getBlockData - Retrieves the dataflow values associated with a + /// specified CFGBlock. If the dataflow analysis is a forward analysis, + /// this data is associated with the END of the block. If the analysis + /// is a backwards analysis, it is associated with the ENTRY of the block. + ValTy& getBlockData(const CFGBlock *B) { + typename BlockDataMapTy::iterator I = BlockDataMap.find(B); + assert (I != BlockDataMap.end() && "No data associated with block."); + return I->second; + } + + const ValTy& getBlockData(const CFGBlock *B) const { + return const_cast<DataflowValues*>(this)->getBlockData(B); + } + + /// getStmtData - Retrieves the dataflow values associated with a + /// specified Stmt. If the dataflow analysis is a forward analysis, + /// this data corresponds to the point immediately before a Stmt. + /// If the analysis is a backwards analysis, it is associated with + /// the point after a Stmt. This data is only computed for block-level + /// expressions, and only when requested when the analysis is executed. + ValTy& getStmtData(const Stmt *S) { + assert (StmtDataMap && "Dataflow values were not computed for statements."); + typename StmtDataMapTy::iterator I = StmtDataMap->find(S); + assert (I != StmtDataMap->end() && "No data associated with statement."); + return I->second; + } + + const ValTy& getStmtData(const Stmt *S) const { + return const_cast<DataflowValues*>(this)->getStmtData(S); + } + + /// getEdgeDataMap - Retrieves the internal map between CFG edges and + /// dataflow values. Usually used by a dataflow solver to compute + /// values for blocks. + EdgeDataMapTy& getEdgeDataMap() { return EdgeDataMap; } + const EdgeDataMapTy& getEdgeDataMap() const { return EdgeDataMap; } + + /// getBlockDataMap - Retrieves the internal map between CFGBlocks and + /// dataflow values. If the dataflow analysis operates in the forward + /// direction, the values correspond to the dataflow values at the start + /// of the block. Otherwise, for a backward analysis, the values correpsond + /// to the dataflow values at the end of the block. + BlockDataMapTy& getBlockDataMap() { return BlockDataMap; } + const BlockDataMapTy& getBlockDataMap() const { return BlockDataMap; } + + /// getStmtDataMap - Retrieves the internal map between Stmts and + /// dataflow values. + StmtDataMapTy& getStmtDataMap() { + if (!StmtDataMap) StmtDataMap = new StmtDataMapTy(); + return *StmtDataMap; + } + + const StmtDataMapTy& getStmtDataMap() const { + return const_cast<DataflowValues*>(this)->getStmtDataMap(); + } + + /// getAnalysisData - Retrieves the meta data associated with a + /// dataflow analysis for analyzing a particular CFG. + /// This is typically consumed by transfer function code (via the solver). + /// This can also be used by subclasses to interpret the dataflow values. + AnalysisDataTy& getAnalysisData() { return AnalysisData; } + const AnalysisDataTy& getAnalysisData() const { return AnalysisData; } + + //===--------------------------------------------------------------------===// + // Internal data. + //===--------------------------------------------------------------------===// + +protected: + EdgeDataMapTy EdgeDataMap; + BlockDataMapTy BlockDataMap; + StmtDataMapTy* StmtDataMap; + AnalysisDataTy AnalysisData; +}; + +} // end namespace clang +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/ProgramPoint.h b/contrib/llvm/tools/clang/include/clang/Analysis/ProgramPoint.h new file mode 100644 index 0000000..6d816fd --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Analysis/ProgramPoint.h @@ -0,0 +1,704 @@ +//==- ProgramPoint.h - Program Points for Path-Sensitive Analysis --*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interface ProgramPoint, which identifies a +// distinct location in a function. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_PROGRAMPOINT_H +#define LLVM_CLANG_ANALYSIS_PROGRAMPOINT_H + +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/CFG.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/DataTypes.h" +#include <cassert> +#include <string> +#include <utility> + +namespace clang { + +class AnalysisDeclContext; +class FunctionDecl; +class LocationContext; + +/// ProgramPoints can be "tagged" as representing points specific to a given +/// analysis entity. Tags are abstract annotations, with an associated +/// description and potentially other information. +class ProgramPointTag { +public: + ProgramPointTag(void *tagKind = nullptr) : TagKind(tagKind) {} + virtual ~ProgramPointTag(); + virtual StringRef getTagDescription() const = 0; + +protected: + /// Used to implement 'isKind' in subclasses. + const void *getTagKind() { return TagKind; } + +private: + const void *TagKind; +}; + +class SimpleProgramPointTag : public ProgramPointTag { + std::string Desc; +public: + SimpleProgramPointTag(StringRef MsgProvider, StringRef Msg); + StringRef getTagDescription() const override; +}; + +class ProgramPoint { +public: + enum Kind { BlockEdgeKind, + BlockEntranceKind, + BlockExitKind, + PreStmtKind, + PreStmtPurgeDeadSymbolsKind, + PostStmtPurgeDeadSymbolsKind, + PostStmtKind, + PreLoadKind, + PostLoadKind, + PreStoreKind, + PostStoreKind, + PostConditionKind, + PostLValueKind, + MinPostStmtKind = PostStmtKind, + MaxPostStmtKind = PostLValueKind, + PostInitializerKind, + CallEnterKind, + CallExitBeginKind, + CallExitEndKind, + PreImplicitCallKind, + PostImplicitCallKind, + MinImplicitCallKind = PreImplicitCallKind, + MaxImplicitCallKind = PostImplicitCallKind, + EpsilonKind}; + +private: + const void *Data1; + llvm::PointerIntPair<const void *, 2, unsigned> Data2; + + // The LocationContext could be NULL to allow ProgramPoint to be used in + // context insensitive analysis. + llvm::PointerIntPair<const LocationContext *, 2, unsigned> L; + + llvm::PointerIntPair<const ProgramPointTag *, 2, unsigned> Tag; + +protected: + ProgramPoint() {} + ProgramPoint(const void *P, + Kind k, + const LocationContext *l, + const ProgramPointTag *tag = nullptr) + : Data1(P), + Data2(nullptr, (((unsigned) k) >> 0) & 0x3), + L(l, (((unsigned) k) >> 2) & 0x3), + Tag(tag, (((unsigned) k) >> 4) & 0x3) { + assert(getKind() == k); + assert(getLocationContext() == l); + assert(getData1() == P); + } + + ProgramPoint(const void *P1, + const void *P2, + Kind k, + const LocationContext *l, + const ProgramPointTag *tag = nullptr) + : Data1(P1), + Data2(P2, (((unsigned) k) >> 0) & 0x3), + L(l, (((unsigned) k) >> 2) & 0x3), + Tag(tag, (((unsigned) k) >> 4) & 0x3) {} + +protected: + const void *getData1() const { return Data1; } + const void *getData2() const { return Data2.getPointer(); } + void setData2(const void *d) { Data2.setPointer(d); } + +public: + /// Create a new ProgramPoint object that is the same as the original + /// except for using the specified tag value. + ProgramPoint withTag(const ProgramPointTag *tag) const { + return ProgramPoint(getData1(), getData2(), getKind(), + getLocationContext(), tag); + } + + /// \brief Convert to the specified ProgramPoint type, asserting that this + /// ProgramPoint is of the desired type. + template<typename T> + T castAs() const { + assert(T::isKind(*this)); + T t; + ProgramPoint& PP = t; + PP = *this; + return t; + } + + /// \brief Convert to the specified ProgramPoint type, returning None if this + /// ProgramPoint is not of the desired type. + template<typename T> + Optional<T> getAs() const { + if (!T::isKind(*this)) + return None; + T t; + ProgramPoint& PP = t; + PP = *this; + return t; + } + + Kind getKind() const { + unsigned x = Tag.getInt(); + x <<= 2; + x |= L.getInt(); + x <<= 2; + x |= Data2.getInt(); + return (Kind) x; + } + + /// \brief Is this a program point corresponding to purge/removal of dead + /// symbols and bindings. + bool isPurgeKind() { + Kind K = getKind(); + return (K == PostStmtPurgeDeadSymbolsKind || + K == PreStmtPurgeDeadSymbolsKind); + } + + const ProgramPointTag *getTag() const { return Tag.getPointer(); } + + const LocationContext *getLocationContext() const { + return L.getPointer(); + } + + // For use with DenseMap. This hash is probably slow. + unsigned getHashValue() const { + llvm::FoldingSetNodeID ID; + Profile(ID); + return ID.ComputeHash(); + } + + bool operator==(const ProgramPoint & RHS) const { + return Data1 == RHS.Data1 && + Data2 == RHS.Data2 && + L == RHS.L && + Tag == RHS.Tag; + } + + bool operator!=(const ProgramPoint &RHS) const { + return Data1 != RHS.Data1 || + Data2 != RHS.Data2 || + L != RHS.L || + Tag != RHS.Tag; + } + + void Profile(llvm::FoldingSetNodeID& ID) const { + ID.AddInteger((unsigned) getKind()); + ID.AddPointer(getData1()); + ID.AddPointer(getData2()); + ID.AddPointer(getLocationContext()); + ID.AddPointer(getTag()); + } + + static ProgramPoint getProgramPoint(const Stmt *S, ProgramPoint::Kind K, + const LocationContext *LC, + const ProgramPointTag *tag); +}; + +class BlockEntrance : public ProgramPoint { +public: + BlockEntrance(const CFGBlock *B, const LocationContext *L, + const ProgramPointTag *tag = nullptr) + : ProgramPoint(B, BlockEntranceKind, L, tag) { + assert(B && "BlockEntrance requires non-null block"); + } + + const CFGBlock *getBlock() const { + return reinterpret_cast<const CFGBlock*>(getData1()); + } + + Optional<CFGElement> getFirstElement() const { + const CFGBlock *B = getBlock(); + return B->empty() ? Optional<CFGElement>() : B->front(); + } + +private: + friend class ProgramPoint; + BlockEntrance() {} + static bool isKind(const ProgramPoint &Location) { + return Location.getKind() == BlockEntranceKind; + } +}; + +class BlockExit : public ProgramPoint { +public: + BlockExit(const CFGBlock *B, const LocationContext *L) + : ProgramPoint(B, BlockExitKind, L) {} + + const CFGBlock *getBlock() const { + return reinterpret_cast<const CFGBlock*>(getData1()); + } + + const Stmt *getTerminator() const { + return getBlock()->getTerminator(); + } + +private: + friend class ProgramPoint; + BlockExit() {} + static bool isKind(const ProgramPoint &Location) { + return Location.getKind() == BlockExitKind; + } +}; + +class StmtPoint : public ProgramPoint { +public: + StmtPoint(const Stmt *S, const void *p2, Kind k, const LocationContext *L, + const ProgramPointTag *tag) + : ProgramPoint(S, p2, k, L, tag) { + assert(S); + } + + const Stmt *getStmt() const { return (const Stmt*) getData1(); } + + template <typename T> + const T* getStmtAs() const { return dyn_cast<T>(getStmt()); } + +protected: + StmtPoint() {} +private: + friend class ProgramPoint; + static bool isKind(const ProgramPoint &Location) { + unsigned k = Location.getKind(); + return k >= PreStmtKind && k <= MaxPostStmtKind; + } +}; + + +class PreStmt : public StmtPoint { +public: + PreStmt(const Stmt *S, const LocationContext *L, const ProgramPointTag *tag, + const Stmt *SubStmt = nullptr) + : StmtPoint(S, SubStmt, PreStmtKind, L, tag) {} + + const Stmt *getSubStmt() const { return (const Stmt*) getData2(); } + +private: + friend class ProgramPoint; + PreStmt() {} + static bool isKind(const ProgramPoint &Location) { + return Location.getKind() == PreStmtKind; + } +}; + +class PostStmt : public StmtPoint { +protected: + PostStmt() {} + PostStmt(const Stmt *S, const void *data, Kind k, const LocationContext *L, + const ProgramPointTag *tag = nullptr) + : StmtPoint(S, data, k, L, tag) {} + +public: + explicit PostStmt(const Stmt *S, Kind k, const LocationContext *L, + const ProgramPointTag *tag = nullptr) + : StmtPoint(S, nullptr, k, L, tag) {} + + explicit PostStmt(const Stmt *S, const LocationContext *L, + const ProgramPointTag *tag = nullptr) + : StmtPoint(S, nullptr, PostStmtKind, L, tag) {} + +private: + friend class ProgramPoint; + static bool isKind(const ProgramPoint &Location) { + unsigned k = Location.getKind(); + return k >= MinPostStmtKind && k <= MaxPostStmtKind; + } +}; + +// PostCondition represents the post program point of a branch condition. +class PostCondition : public PostStmt { +public: + PostCondition(const Stmt *S, const LocationContext *L, + const ProgramPointTag *tag = nullptr) + : PostStmt(S, PostConditionKind, L, tag) {} + +private: + friend class ProgramPoint; + PostCondition() {} + static bool isKind(const ProgramPoint &Location) { + return Location.getKind() == PostConditionKind; + } +}; + +class LocationCheck : public StmtPoint { +protected: + LocationCheck() {} + LocationCheck(const Stmt *S, const LocationContext *L, + ProgramPoint::Kind K, const ProgramPointTag *tag) + : StmtPoint(S, nullptr, K, L, tag) {} + +private: + friend class ProgramPoint; + static bool isKind(const ProgramPoint &location) { + unsigned k = location.getKind(); + return k == PreLoadKind || k == PreStoreKind; + } +}; + +class PreLoad : public LocationCheck { +public: + PreLoad(const Stmt *S, const LocationContext *L, + const ProgramPointTag *tag = nullptr) + : LocationCheck(S, L, PreLoadKind, tag) {} + +private: + friend class ProgramPoint; + PreLoad() {} + static bool isKind(const ProgramPoint &location) { + return location.getKind() == PreLoadKind; + } +}; + +class PreStore : public LocationCheck { +public: + PreStore(const Stmt *S, const LocationContext *L, + const ProgramPointTag *tag = nullptr) + : LocationCheck(S, L, PreStoreKind, tag) {} + +private: + friend class ProgramPoint; + PreStore() {} + static bool isKind(const ProgramPoint &location) { + return location.getKind() == PreStoreKind; + } +}; + +class PostLoad : public PostStmt { +public: + PostLoad(const Stmt *S, const LocationContext *L, + const ProgramPointTag *tag = nullptr) + : PostStmt(S, PostLoadKind, L, tag) {} + +private: + friend class ProgramPoint; + PostLoad() {} + static bool isKind(const ProgramPoint &Location) { + return Location.getKind() == PostLoadKind; + } +}; + +/// \brief Represents a program point after a store evaluation. +class PostStore : public PostStmt { +public: + /// Construct the post store point. + /// \param Loc can be used to store the information about the location + /// used in the form it was uttered in the code. + PostStore(const Stmt *S, const LocationContext *L, const void *Loc, + const ProgramPointTag *tag = nullptr) + : PostStmt(S, PostStoreKind, L, tag) { + assert(getData2() == nullptr); + setData2(Loc); + } + + /// \brief Returns the information about the location used in the store, + /// how it was uttered in the code. + const void *getLocationValue() const { + return getData2(); + } + +private: + friend class ProgramPoint; + PostStore() {} + static bool isKind(const ProgramPoint &Location) { + return Location.getKind() == PostStoreKind; + } +}; + +class PostLValue : public PostStmt { +public: + PostLValue(const Stmt *S, const LocationContext *L, + const ProgramPointTag *tag = nullptr) + : PostStmt(S, PostLValueKind, L, tag) {} + +private: + friend class ProgramPoint; + PostLValue() {} + static bool isKind(const ProgramPoint &Location) { + return Location.getKind() == PostLValueKind; + } +}; + +/// Represents a point after we ran remove dead bindings BEFORE +/// processing the given statement. +class PreStmtPurgeDeadSymbols : public StmtPoint { +public: + PreStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L, + const ProgramPointTag *tag = nullptr) + : StmtPoint(S, nullptr, PreStmtPurgeDeadSymbolsKind, L, tag) { } + +private: + friend class ProgramPoint; + PreStmtPurgeDeadSymbols() {} + static bool isKind(const ProgramPoint &Location) { + return Location.getKind() == PreStmtPurgeDeadSymbolsKind; + } +}; + +/// Represents a point after we ran remove dead bindings AFTER +/// processing the given statement. +class PostStmtPurgeDeadSymbols : public StmtPoint { +public: + PostStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L, + const ProgramPointTag *tag = nullptr) + : StmtPoint(S, nullptr, PostStmtPurgeDeadSymbolsKind, L, tag) { } + +private: + friend class ProgramPoint; + PostStmtPurgeDeadSymbols() {} + static bool isKind(const ProgramPoint &Location) { + return Location.getKind() == PostStmtPurgeDeadSymbolsKind; + } +}; + +class BlockEdge : public ProgramPoint { +public: + BlockEdge(const CFGBlock *B1, const CFGBlock *B2, const LocationContext *L) + : ProgramPoint(B1, B2, BlockEdgeKind, L) { + assert(B1 && "BlockEdge: source block must be non-null"); + assert(B2 && "BlockEdge: destination block must be non-null"); + } + + const CFGBlock *getSrc() const { + return static_cast<const CFGBlock*>(getData1()); + } + + const CFGBlock *getDst() const { + return static_cast<const CFGBlock*>(getData2()); + } + +private: + friend class ProgramPoint; + BlockEdge() {} + static bool isKind(const ProgramPoint &Location) { + return Location.getKind() == BlockEdgeKind; + } +}; + +class PostInitializer : public ProgramPoint { +public: + /// \brief Construct a PostInitializer point that represents a location after + /// CXXCtorInitializer expression evaluation. + /// + /// \param I The initializer. + /// \param Loc The location of the field being initialized. + PostInitializer(const CXXCtorInitializer *I, + const void *Loc, + const LocationContext *L) + : ProgramPoint(I, Loc, PostInitializerKind, L) {} + + const CXXCtorInitializer *getInitializer() const { + return static_cast<const CXXCtorInitializer *>(getData1()); + } + + /// \brief Returns the location of the field. + const void *getLocationValue() const { + return getData2(); + } + +private: + friend class ProgramPoint; + PostInitializer() {} + static bool isKind(const ProgramPoint &Location) { + return Location.getKind() == PostInitializerKind; + } +}; + +/// Represents an implicit call event. +/// +/// The nearest statement is provided for diagnostic purposes. +class ImplicitCallPoint : public ProgramPoint { +public: + ImplicitCallPoint(const Decl *D, SourceLocation Loc, Kind K, + const LocationContext *L, const ProgramPointTag *Tag) + : ProgramPoint(Loc.getPtrEncoding(), D, K, L, Tag) {} + + const Decl *getDecl() const { return static_cast<const Decl *>(getData2()); } + SourceLocation getLocation() const { + return SourceLocation::getFromPtrEncoding(getData1()); + } + +protected: + ImplicitCallPoint() {} +private: + friend class ProgramPoint; + static bool isKind(const ProgramPoint &Location) { + return Location.getKind() >= MinImplicitCallKind && + Location.getKind() <= MaxImplicitCallKind; + } +}; + +/// Represents a program point just before an implicit call event. +/// +/// Explicit calls will appear as PreStmt program points. +class PreImplicitCall : public ImplicitCallPoint { +public: + PreImplicitCall(const Decl *D, SourceLocation Loc, const LocationContext *L, + const ProgramPointTag *Tag = nullptr) + : ImplicitCallPoint(D, Loc, PreImplicitCallKind, L, Tag) {} + +private: + friend class ProgramPoint; + PreImplicitCall() {} + static bool isKind(const ProgramPoint &Location) { + return Location.getKind() == PreImplicitCallKind; + } +}; + +/// Represents a program point just after an implicit call event. +/// +/// Explicit calls will appear as PostStmt program points. +class PostImplicitCall : public ImplicitCallPoint { +public: + PostImplicitCall(const Decl *D, SourceLocation Loc, const LocationContext *L, + const ProgramPointTag *Tag = nullptr) + : ImplicitCallPoint(D, Loc, PostImplicitCallKind, L, Tag) {} + +private: + friend class ProgramPoint; + PostImplicitCall() {} + static bool isKind(const ProgramPoint &Location) { + return Location.getKind() == PostImplicitCallKind; + } +}; + +/// Represents a point when we begin processing an inlined call. +/// CallEnter uses the caller's location context. +class CallEnter : public ProgramPoint { +public: + CallEnter(const Stmt *stmt, const StackFrameContext *calleeCtx, + const LocationContext *callerCtx) + : ProgramPoint(stmt, calleeCtx, CallEnterKind, callerCtx, nullptr) {} + + const Stmt *getCallExpr() const { + return static_cast<const Stmt *>(getData1()); + } + + const StackFrameContext *getCalleeContext() const { + return static_cast<const StackFrameContext *>(getData2()); + } + +private: + friend class ProgramPoint; + CallEnter() {} + static bool isKind(const ProgramPoint &Location) { + return Location.getKind() == CallEnterKind; + } +}; + +/// Represents a point when we start the call exit sequence (for inlined call). +/// +/// The call exit is simulated with a sequence of nodes, which occur between +/// CallExitBegin and CallExitEnd. The following operations occur between the +/// two program points: +/// - CallExitBegin +/// - Bind the return value +/// - Run Remove dead bindings (to clean up the dead symbols from the callee). +/// - CallExitEnd +class CallExitBegin : public ProgramPoint { +public: + // CallExitBegin uses the callee's location context. + CallExitBegin(const StackFrameContext *L) + : ProgramPoint(nullptr, CallExitBeginKind, L, nullptr) {} + +private: + friend class ProgramPoint; + CallExitBegin() {} + static bool isKind(const ProgramPoint &Location) { + return Location.getKind() == CallExitBeginKind; + } +}; + +/// Represents a point when we finish the call exit sequence (for inlined call). +/// \sa CallExitBegin +class CallExitEnd : public ProgramPoint { +public: + // CallExitEnd uses the caller's location context. + CallExitEnd(const StackFrameContext *CalleeCtx, + const LocationContext *CallerCtx) + : ProgramPoint(CalleeCtx, CallExitEndKind, CallerCtx, nullptr) {} + + const StackFrameContext *getCalleeContext() const { + return static_cast<const StackFrameContext *>(getData1()); + } + +private: + friend class ProgramPoint; + CallExitEnd() {} + static bool isKind(const ProgramPoint &Location) { + return Location.getKind() == CallExitEndKind; + } +}; + +/// This is a meta program point, which should be skipped by all the diagnostic +/// reasoning etc. +class EpsilonPoint : public ProgramPoint { +public: + EpsilonPoint(const LocationContext *L, const void *Data1, + const void *Data2 = nullptr, + const ProgramPointTag *tag = nullptr) + : ProgramPoint(Data1, Data2, EpsilonKind, L, tag) {} + + const void *getData() const { return getData1(); } + +private: + friend class ProgramPoint; + EpsilonPoint() {} + static bool isKind(const ProgramPoint &Location) { + return Location.getKind() == EpsilonKind; + } +}; + +} // end namespace clang + + +namespace llvm { // Traits specialization for DenseMap + +template <> struct DenseMapInfo<clang::ProgramPoint> { + +static inline clang::ProgramPoint getEmptyKey() { + uintptr_t x = + reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getEmptyKey()) & ~0x7; + return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), nullptr); +} + +static inline clang::ProgramPoint getTombstoneKey() { + uintptr_t x = + reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getTombstoneKey()) & ~0x7; + return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), nullptr); +} + +static unsigned getHashValue(const clang::ProgramPoint &Loc) { + return Loc.getHashValue(); +} + +static bool isEqual(const clang::ProgramPoint &L, + const clang::ProgramPoint &R) { + return L == R; +} + +}; + +template <> +struct isPodLike<clang::ProgramPoint> { static const bool value = true; }; + +} // end namespace llvm + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/Support/BumpVector.h b/contrib/llvm/tools/clang/include/clang/Analysis/Support/BumpVector.h new file mode 100644 index 0000000..591d17b --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Analysis/Support/BumpVector.h @@ -0,0 +1,250 @@ +//===-- BumpVector.h - Vector-like ADT that uses bump allocation --*- 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 BumpVector, a vector-like ADT whose contents are +// allocated from a BumpPtrAllocator. +// +//===----------------------------------------------------------------------===// + +// FIXME: Most of this is copy-and-paste from SmallVector.h. We can +// refactor this core logic into something common that is shared between +// the two. The main thing that is different is the allocation strategy. + +#ifndef LLVM_CLANG_ANALYSIS_SUPPORT_BUMPVECTOR_H +#define LLVM_CLANG_ANALYSIS_SUPPORT_BUMPVECTOR_H + +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/type_traits.h" +#include <algorithm> +#include <cstring> +#include <iterator> +#include <memory> + +namespace clang { + +class BumpVectorContext { + llvm::PointerIntPair<llvm::BumpPtrAllocator*, 1> Alloc; +public: + /// Construct a new BumpVectorContext that creates a new BumpPtrAllocator + /// and destroys it when the BumpVectorContext object is destroyed. + BumpVectorContext() : Alloc(new llvm::BumpPtrAllocator(), 1) {} + + BumpVectorContext(BumpVectorContext &&Other) : Alloc(Other.Alloc) { + Other.Alloc.setInt(false); + Other.Alloc.setPointer(nullptr); + } + + /// Construct a new BumpVectorContext that reuses an existing + /// BumpPtrAllocator. This BumpPtrAllocator is not destroyed when the + /// BumpVectorContext object is destroyed. + BumpVectorContext(llvm::BumpPtrAllocator &A) : Alloc(&A, 0) {} + + ~BumpVectorContext() { + if (Alloc.getInt()) + delete Alloc.getPointer(); + } + + llvm::BumpPtrAllocator &getAllocator() { return *Alloc.getPointer(); } +}; + +template<typename T> +class BumpVector { + T *Begin, *End, *Capacity; +public: + // Default ctor - Initialize to empty. + explicit BumpVector(BumpVectorContext &C, unsigned N) + : Begin(nullptr), End(nullptr), Capacity(nullptr) { + reserve(C, N); + } + + ~BumpVector() { + if (std::is_class<T>::value) { + // Destroy the constructed elements in the vector. + destroy_range(Begin, End); + } + } + + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef T* iterator; + typedef const T* const_iterator; + + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + typedef std::reverse_iterator<iterator> reverse_iterator; + + typedef T& reference; + typedef const T& const_reference; + typedef T* pointer; + typedef const T* const_pointer; + + // forward iterator creation methods. + iterator begin() { return Begin; } + const_iterator begin() const { return Begin; } + iterator end() { return End; } + const_iterator end() const { return End; } + + // reverse iterator creation methods. + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); } + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { return const_reverse_iterator(begin());} + + bool empty() const { return Begin == End; } + size_type size() const { return End-Begin; } + + reference operator[](unsigned idx) { + assert(Begin + idx < End); + return Begin[idx]; + } + const_reference operator[](unsigned idx) const { + assert(Begin + idx < End); + return Begin[idx]; + } + + reference front() { + return begin()[0]; + } + const_reference front() const { + return begin()[0]; + } + + reference back() { + return end()[-1]; + } + const_reference back() const { + return end()[-1]; + } + + void pop_back() { + --End; + End->~T(); + } + + T pop_back_val() { + T Result = back(); + pop_back(); + return Result; + } + + void clear() { + if (std::is_class<T>::value) { + destroy_range(Begin, End); + } + End = Begin; + } + + /// data - Return a pointer to the vector's buffer, even if empty(). + pointer data() { + return pointer(Begin); + } + + /// data - Return a pointer to the vector's buffer, even if empty(). + const_pointer data() const { + return const_pointer(Begin); + } + + void push_back(const_reference Elt, BumpVectorContext &C) { + if (End < Capacity) { + Retry: + new (End) T(Elt); + ++End; + return; + } + grow(C); + goto Retry; + } + + /// insert - Insert some number of copies of element into a position. Return + /// iterator to position after last inserted copy. + iterator insert(iterator I, size_t Cnt, const_reference E, + BumpVectorContext &C) { + assert (I >= Begin && I <= End && "Iterator out of bounds."); + if (End + Cnt <= Capacity) { + Retry: + move_range_right(I, End, Cnt); + construct_range(I, I + Cnt, E); + End += Cnt; + return I + Cnt; + } + ptrdiff_t D = I - Begin; + grow(C, size() + Cnt); + I = Begin + D; + goto Retry; + } + + void reserve(BumpVectorContext &C, unsigned N) { + if (unsigned(Capacity-Begin) < N) + grow(C, N); + } + + /// capacity - Return the total number of elements in the currently allocated + /// buffer. + size_t capacity() const { return Capacity - Begin; } + +private: + /// grow - double the size of the allocated memory, guaranteeing space for at + /// least one more element or MinSize if specified. + void grow(BumpVectorContext &C, size_type MinSize = 1); + + void construct_range(T *S, T *E, const T &Elt) { + for (; S != E; ++S) + new (S) T(Elt); + } + + void destroy_range(T *S, T *E) { + while (S != E) { + --E; + E->~T(); + } + } + + void move_range_right(T *S, T *E, size_t D) { + for (T *I = E + D - 1, *IL = S + D - 1; I != IL; --I) { + --E; + new (I) T(*E); + E->~T(); + } + } +}; + +// Define this out-of-line to dissuade the C++ compiler from inlining it. +template <typename T> +void BumpVector<T>::grow(BumpVectorContext &C, size_t MinSize) { + size_t CurCapacity = Capacity-Begin; + size_t CurSize = size(); + size_t NewCapacity = 2*CurCapacity; + if (NewCapacity < MinSize) + NewCapacity = MinSize; + + // Allocate the memory from the BumpPtrAllocator. + T *NewElts = C.getAllocator().template Allocate<T>(NewCapacity); + + // Copy the elements over. + if (Begin != End) { + if (std::is_class<T>::value) { + std::uninitialized_copy(Begin, End, NewElts); + // Destroy the original elements. + destroy_range(Begin, End); + } else { + // Use memcpy for PODs (std::uninitialized_copy optimizes to memmove). + memcpy(NewElts, Begin, CurSize * sizeof(T)); + } + } + + // For now, leak 'Begin'. We can add it back to a freelist in + // BumpVectorContext. + Begin = NewElts; + End = NewElts+CurSize; + Capacity = Begin+NewCapacity; +} + +} // end: clang namespace +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/ABI.h b/contrib/llvm/tools/clang/include/clang/Basic/ABI.h new file mode 100644 index 0000000..75e9faf --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/ABI.h @@ -0,0 +1,211 @@ +//===----- ABI.h - ABI related declarations ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Enums/classes describing ABI related information about constructors, +/// destructors and thunks. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_ABI_H +#define LLVM_CLANG_BASIC_ABI_H + +#include "llvm/Support/DataTypes.h" +#include <cstring> + +namespace clang { + +/// \brief C++ constructor types. +enum CXXCtorType { + Ctor_Complete, ///< Complete object ctor + Ctor_Base, ///< Base object ctor + Ctor_Comdat, ///< The COMDAT used for ctors + Ctor_CopyingClosure, ///< Copying closure variant of a ctor + Ctor_DefaultClosure, ///< Default closure variant of a ctor +}; + +/// \brief C++ destructor types. +enum CXXDtorType { + Dtor_Deleting, ///< Deleting dtor + Dtor_Complete, ///< Complete object dtor + Dtor_Base, ///< Base object dtor + Dtor_Comdat ///< The COMDAT used for dtors +}; + +/// \brief A return adjustment. +struct ReturnAdjustment { + /// \brief The non-virtual adjustment from the derived object to its + /// nearest virtual base. + int64_t NonVirtual; + + /// \brief Holds the ABI-specific information about the virtual return + /// adjustment, if needed. + union VirtualAdjustment { + // Itanium ABI + struct { + /// \brief The offset (in bytes), relative to the address point + /// of the virtual base class offset. + int64_t VBaseOffsetOffset; + } Itanium; + + // Microsoft ABI + struct { + /// \brief The offset (in bytes) of the vbptr, relative to the beginning + /// of the derived class. + uint32_t VBPtrOffset; + + /// \brief Index of the virtual base in the vbtable. + uint32_t VBIndex; + } Microsoft; + + VirtualAdjustment() { + memset(this, 0, sizeof(*this)); + } + + bool Equals(const VirtualAdjustment &Other) const { + return memcmp(this, &Other, sizeof(Other)) == 0; + } + + bool isEmpty() const { + VirtualAdjustment Zero; + return Equals(Zero); + } + + bool Less(const VirtualAdjustment &RHS) const { + return memcmp(this, &RHS, sizeof(RHS)) < 0; + } + } Virtual; + + ReturnAdjustment() : NonVirtual(0) {} + + bool isEmpty() const { return !NonVirtual && Virtual.isEmpty(); } + + friend bool operator==(const ReturnAdjustment &LHS, + const ReturnAdjustment &RHS) { + return LHS.NonVirtual == RHS.NonVirtual && LHS.Virtual.Equals(RHS.Virtual); + } + + friend bool operator!=(const ReturnAdjustment &LHS, const ReturnAdjustment &RHS) { + return !(LHS == RHS); + } + + friend bool operator<(const ReturnAdjustment &LHS, + const ReturnAdjustment &RHS) { + if (LHS.NonVirtual < RHS.NonVirtual) + return true; + + return LHS.NonVirtual == RHS.NonVirtual && LHS.Virtual.Less(RHS.Virtual); + } +}; + +/// \brief A \c this pointer adjustment. +struct ThisAdjustment { + /// \brief The non-virtual adjustment from the derived object to its + /// nearest virtual base. + int64_t NonVirtual; + + /// \brief Holds the ABI-specific information about the virtual this + /// adjustment, if needed. + union VirtualAdjustment { + // Itanium ABI + struct { + /// \brief The offset (in bytes), relative to the address point, + /// of the virtual call offset. + int64_t VCallOffsetOffset; + } Itanium; + + struct { + /// \brief The offset of the vtordisp (in bytes), relative to the ECX. + int32_t VtordispOffset; + + /// \brief The offset of the vbptr of the derived class (in bytes), + /// relative to the ECX after vtordisp adjustment. + int32_t VBPtrOffset; + + /// \brief The offset (in bytes) of the vbase offset in the vbtable. + int32_t VBOffsetOffset; + } Microsoft; + + VirtualAdjustment() { + memset(this, 0, sizeof(*this)); + } + + bool Equals(const VirtualAdjustment &Other) const { + return memcmp(this, &Other, sizeof(Other)) == 0; + } + + bool isEmpty() const { + VirtualAdjustment Zero; + return Equals(Zero); + } + + bool Less(const VirtualAdjustment &RHS) const { + return memcmp(this, &RHS, sizeof(RHS)) < 0; + } + } Virtual; + + ThisAdjustment() : NonVirtual(0) { } + + bool isEmpty() const { return !NonVirtual && Virtual.isEmpty(); } + + friend bool operator==(const ThisAdjustment &LHS, + const ThisAdjustment &RHS) { + return LHS.NonVirtual == RHS.NonVirtual && LHS.Virtual.Equals(RHS.Virtual); + } + + friend bool operator!=(const ThisAdjustment &LHS, const ThisAdjustment &RHS) { + return !(LHS == RHS); + } + + friend bool operator<(const ThisAdjustment &LHS, + const ThisAdjustment &RHS) { + if (LHS.NonVirtual < RHS.NonVirtual) + return true; + + return LHS.NonVirtual == RHS.NonVirtual && LHS.Virtual.Less(RHS.Virtual); + } +}; + +class CXXMethodDecl; + +/// \brief The \c this pointer adjustment as well as an optional return +/// adjustment for a thunk. +struct ThunkInfo { + /// \brief The \c this pointer adjustment. + ThisAdjustment This; + + /// \brief The return adjustment. + ReturnAdjustment Return; + + /// \brief Holds a pointer to the overridden method this thunk is for, + /// if needed by the ABI to distinguish different thunks with equal + /// adjustments. Otherwise, null. + /// CAUTION: In the unlikely event you need to sort ThunkInfos, consider using + /// an ABI-specific comparator. + const CXXMethodDecl *Method; + + ThunkInfo() : Method(nullptr) { } + + ThunkInfo(const ThisAdjustment &This, const ReturnAdjustment &Return, + const CXXMethodDecl *Method = nullptr) + : This(This), Return(Return), Method(Method) {} + + friend bool operator==(const ThunkInfo &LHS, const ThunkInfo &RHS) { + return LHS.This == RHS.This && LHS.Return == RHS.Return && + LHS.Method == RHS.Method; + } + + bool isEmpty() const { + return This.isEmpty() && Return.isEmpty() && Method == nullptr; + } +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/AddressSpaces.h b/contrib/llvm/tools/clang/include/clang/Basic/AddressSpaces.h new file mode 100644 index 0000000..8dd7566 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/AddressSpaces.h @@ -0,0 +1,51 @@ +//===--- AddressSpaces.h - Language-specific address spaces -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Provides definitions for the various language-specific address +/// spaces. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_ADDRESSSPACES_H +#define LLVM_CLANG_BASIC_ADDRESSSPACES_H + +namespace clang { + +namespace LangAS { + +/// \brief Defines the set of possible language-specific address spaces. +/// +/// This uses a high starting offset so as not to conflict with any address +/// space used by a target. +enum ID { + Offset = 0xFFFF00, + + opencl_global = Offset, + opencl_local, + opencl_constant, + opencl_generic, + + cuda_device, + cuda_constant, + cuda_shared, + + Last, + Count = Last-Offset +}; + +/// The type of a lookup table which maps from language-specific address spaces +/// to target-specific ones. +typedef unsigned Map[Count]; + +} + +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/AllDiagnostics.h b/contrib/llvm/tools/clang/include/clang/Basic/AllDiagnostics.h new file mode 100644 index 0000000..18a2b8a --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/AllDiagnostics.h @@ -0,0 +1,40 @@ +//===--- AllDiagnostics.h - Aggregate Diagnostic headers --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Includes all the separate Diagnostic headers & some related helpers. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_ALLDIAGNOSTICS_H +#define LLVM_CLANG_BASIC_ALLDIAGNOSTICS_H + +#include "clang/AST/ASTDiagnostic.h" +#include "clang/AST/CommentDiagnostic.h" +#include "clang/Analysis/AnalysisDiagnostic.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Lex/LexDiagnostic.h" +#include "clang/Parse/ParseDiagnostic.h" +#include "clang/Sema/SemaDiagnostic.h" +#include "clang/Serialization/SerializationDiagnostic.h" + +namespace clang { +template <size_t SizeOfStr, typename FieldType> +class StringSizerHelper { + char FIELD_TOO_SMALL[SizeOfStr <= FieldType(~0U) ? 1 : -1]; +public: + enum { Size = SizeOfStr }; +}; +} // end namespace clang + +#define STR_SIZE(str, fieldTy) clang::StringSizerHelper<sizeof(str)-1, \ + fieldTy>::Size + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Attr.td b/contrib/llvm/tools/clang/include/clang/Basic/Attr.td new file mode 100644 index 0000000..d5ba722 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/Attr.td @@ -0,0 +1,2172 @@ +//==--- Attr.td - attribute definitions -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// The documentation is organized by category. Attributes can have category- +// specific documentation that is collated within the larger document. +class DocumentationCategory<string name> { + string Name = name; + code Content = [{}]; +} +def DocCatFunction : DocumentationCategory<"Function Attributes">; +def DocCatVariable : DocumentationCategory<"Variable Attributes">; +def DocCatType : DocumentationCategory<"Type Attributes">; +def DocCatStmt : DocumentationCategory<"Statement Attributes">; +// Attributes listed under the Undocumented category do not generate any public +// documentation. Ideally, this category should be used for internal-only +// attributes which contain no spellings. +def DocCatUndocumented : DocumentationCategory<"Undocumented">; + +class DocDeprecated<string replacement = ""> { + // If the Replacement field is empty, no replacement will be listed with the + // documentation. Otherwise, the documentation will specify the attribute has + // been superseded by this replacement. + string Replacement = replacement; +} + +// Specifies the documentation to be associated with the given category. +class Documentation { + DocumentationCategory Category; + code Content; + + // If the heading is empty, one may be picked automatically. If the attribute + // only has one spelling, no heading is required as the attribute's sole + // spelling is sufficient. If all spellings are semantically common, the + // heading will be the semantic spelling. If the spellings are not + // semantically common and no heading is provided, an error will be emitted. + string Heading = ""; + + // When set, specifies that the attribute is deprecated and can optionally + // specify a replacement attribute. + DocDeprecated Deprecated; +} + +// Specifies that the attribute is explicitly undocumented. This can be a +// helpful placeholder for the attribute while working on the implementation, +// but should not be used once feature work has been completed. +def Undocumented : Documentation { + let Category = DocCatUndocumented; +} + +include "clang/Basic/AttrDocs.td" + +// An attribute's subject is whatever it appertains to. In this file, it is +// more accurately a list of things that an attribute can appertain to. All +// Decls and Stmts are possibly AttrSubjects (even though the syntax may not +// allow attributes on a given Decl or Stmt). +class AttrSubject; + +include "clang/Basic/DeclNodes.td" +include "clang/Basic/StmtNodes.td" + +// A subset-subject is an AttrSubject constrained to operate only on some subset +// of that subject. +// +// The code fragment is a boolean expression that will confirm that the subject +// meets the requirements; the subject will have the name S, and will have the +// type specified by the base. It should be a simple boolean expression. +class SubsetSubject<AttrSubject base, code check> : AttrSubject { + AttrSubject Base = base; + code CheckCode = check; +} + +// This is the type of a variable which C++11 allows alignas(...) to appertain +// to. +def NormalVar : SubsetSubject<Var, + [{S->getStorageClass() != VarDecl::Register && + S->getKind() != Decl::ImplicitParam && + S->getKind() != Decl::ParmVar && + S->getKind() != Decl::NonTypeTemplateParm}]>; +def NonBitField : SubsetSubject<Field, + [{!S->isBitField()}]>; + +def ObjCInstanceMethod : SubsetSubject<ObjCMethod, + [{S->isInstanceMethod()}]>; + +def ObjCInterfaceDeclInitMethod : SubsetSubject<ObjCMethod, + [{S->getMethodFamily() == OMF_init && + (isa<ObjCInterfaceDecl>(S->getDeclContext()) || + (isa<ObjCCategoryDecl>(S->getDeclContext()) && + cast<ObjCCategoryDecl>(S->getDeclContext())->IsClassExtension()))}]>; + +def Struct : SubsetSubject<Record, + [{!S->isUnion()}]>; + +def TLSVar : SubsetSubject<Var, + [{S->getTLSKind() != 0}]>; + +def SharedVar : SubsetSubject<Var, + [{S->hasGlobalStorage() && !S->getTLSKind()}]>; + +def GlobalVar : SubsetSubject<Var, + [{S->hasGlobalStorage()}]>; + +// FIXME: this hack is needed because DeclNodes.td defines the base Decl node +// type to be a class, not a definition. This makes it impossible to create an +// attribute subject which accepts a Decl. Normally, this is not a problem, +// because the attribute can have no Subjects clause to accomplish this. But in +// the case of a SubsetSubject, there's no way to express it without this hack. +def DeclBase : AttrSubject; +def FunctionLike : SubsetSubject<DeclBase, + [{S->getFunctionType(false) != nullptr}]>; + +def OpenCLKernelFunction : SubsetSubject<Function, [{ + S->hasAttr<OpenCLKernelAttr>() +}]>; + +// HasFunctionProto is a more strict version of FunctionLike, so it should +// never be specified in a Subjects list along with FunctionLike (due to the +// inclusive nature of subject testing). +def HasFunctionProto : SubsetSubject<DeclBase, + [{(S->getFunctionType(true) != nullptr && + isa<FunctionProtoType>(S->getFunctionType())) || + isa<ObjCMethodDecl>(S) || + isa<BlockDecl>(S)}]>; + +// A single argument to an attribute +class Argument<string name, bit optional, bit fake = 0> { + string Name = name; + bit Optional = optional; + + /// A fake argument is used to store and serialize additional information + /// in an attribute without actually changing its parsing or pretty-printing. + bit Fake = fake; +} + +class BoolArgument<string name, bit opt = 0> : Argument<name, opt>; +class IdentifierArgument<string name, bit opt = 0> : Argument<name, opt>; +class IntArgument<string name, bit opt = 0> : Argument<name, opt>; +class StringArgument<string name, bit opt = 0> : Argument<name, opt>; +class ExprArgument<string name, bit opt = 0> : Argument<name, opt>; +class FunctionArgument<string name, bit opt = 0> : Argument<name, opt>; +class TypeArgument<string name, bit opt = 0> : Argument<name, opt>; +class UnsignedArgument<string name, bit opt = 0> : Argument<name, opt>; +class VariadicUnsignedArgument<string name> : Argument<name, 1>; +class VariadicExprArgument<string name> : Argument<name, 1>; +class VariadicStringArgument<string name> : Argument<name, 1>; + +// A version of the form major.minor[.subminor]. +class VersionArgument<string name, bit opt = 0> : Argument<name, opt>; + +// This one's a doozy, so it gets its own special type +// It can be an unsigned integer, or a type. Either can +// be dependent. +class AlignedArgument<string name, bit opt = 0> : Argument<name, opt>; + +// A bool argument with a default value +class DefaultBoolArgument<string name, bit default> : BoolArgument<name, 1> { + bit Default = default; +} + +// An integer argument with a default value +class DefaultIntArgument<string name, int default> : IntArgument<name, 1> { + int Default = default; +} + +// This argument is more complex, it includes the enumerator type name, +// a list of strings to accept, and a list of enumerators to map them to. +class EnumArgument<string name, string type, list<string> values, + list<string> enums, bit opt = 0, bit fake = 0> + : Argument<name, opt, fake> { + string Type = type; + list<string> Values = values; + list<string> Enums = enums; +} + +// FIXME: There should be a VariadicArgument type that takes any other type +// of argument and generates the appropriate type. +class VariadicEnumArgument<string name, string type, list<string> values, + list<string> enums> : Argument<name, 1> { + string Type = type; + list<string> Values = values; + list<string> Enums = enums; +} + +// This handles one spelling of an attribute. +class Spelling<string name, string variety> { + string Name = name; + string Variety = variety; + bit KnownToGCC; +} + +class GNU<string name> : Spelling<name, "GNU">; +class Declspec<string name> : Spelling<name, "Declspec">; +class CXX11<string namespace, string name, int version = 1> + : Spelling<name, "CXX11"> { + string Namespace = namespace; + int Version = version; +} +class Keyword<string name> : Spelling<name, "Keyword">; +class Pragma<string namespace, string name> : Spelling<name, "Pragma"> { + string Namespace = namespace; +} + +// The GCC spelling implies GNU<name, "GNU"> and CXX11<"gnu", name> and also +// sets KnownToGCC to 1. This spelling should be used for any GCC-compatible +// attributes. +class GCC<string name> : Spelling<name, "GCC"> { + let KnownToGCC = 1; +} + +class Accessor<string name, list<Spelling> spellings> { + string Name = name; + list<Spelling> Spellings = spellings; +} + +class SubjectDiag<bit warn> { + bit Warn = warn; +} +def WarnDiag : SubjectDiag<1>; +def ErrorDiag : SubjectDiag<0>; + +class SubjectList<list<AttrSubject> subjects, SubjectDiag diag = WarnDiag, + string customDiag = ""> { + list<AttrSubject> Subjects = subjects; + SubjectDiag Diag = diag; + string CustomDiag = customDiag; +} + +class LangOpt<string name, bit negated = 0> { + string Name = name; + bit Negated = negated; +} +def MicrosoftExt : LangOpt<"MicrosoftExt">; +def Borland : LangOpt<"Borland">; +def CUDA : LangOpt<"CUDA">; +def COnly : LangOpt<"CPlusPlus", 1>; + +// Defines targets for target-specific attributes. The list of strings should +// specify architectures for which the target applies, based off the ArchType +// enumeration in Triple.h. +class TargetArch<list<string> arches> { + list<string> Arches = arches; + list<string> OSes; + list<string> CXXABIs; +} +def TargetARM : TargetArch<["arm", "thumb"]>; +def TargetMips : TargetArch<["mips", "mipsel"]>; +def TargetMSP430 : TargetArch<["msp430"]>; +def TargetX86 : TargetArch<["x86"]>; +def TargetWindows : TargetArch<["x86", "x86_64", "arm", "thumb"]> { + let OSes = ["Win32"]; +} +def TargetMicrosoftCXXABI : TargetArch<["x86", "x86_64", "arm", "thumb"]> { + let CXXABIs = ["Microsoft"]; +} + +class Attr { + // The various ways in which an attribute can be spelled in source + list<Spelling> Spellings; + // The things to which an attribute can appertain + SubjectList Subjects; + // The arguments allowed on an attribute + list<Argument> Args = []; + // Accessors which should be generated for the attribute. + list<Accessor> Accessors = []; + // Set to true for attributes with arguments which require delayed parsing. + bit LateParsed = 0; + // Set to false to prevent an attribute from being propagated from a template + // to the instantiation. + bit Clone = 1; + // Set to true for attributes which must be instantiated within templates + bit TemplateDependent = 0; + // Set to true for attributes that have a corresponding AST node. + bit ASTNode = 1; + // Set to true for attributes which have handler in Sema. + bit SemaHandler = 1; + // Set to true for attributes that are completely ignored. + bit Ignored = 0; + // Set to true if the attribute's parsing does not match its semantic + // content. Eg) It parses 3 args, but semantically takes 4 args. Opts out of + // common attribute error checking. + bit HasCustomParsing = 0; + // Set to true if all of the attribute's arguments should be parsed in an + // unevaluated context. + bit ParseArgumentsAsUnevaluated = 0; + // Set to true if this attribute can be duplicated on a subject when merging + // attributes. By default, attributes are not merged. + bit DuplicatesAllowedWhileMerging = 0; + // Lists language options, one of which is required to be true for the + // attribute to be applicable. If empty, no language options are required. + list<LangOpt> LangOpts = []; + // Any additional text that should be included verbatim in the class. + // Note: Any additional data members will leak and should be constructed + // externally on the ASTContext. + code AdditionalMembers = [{}]; + // Any documentation that should be associated with the attribute. Since an + // attribute may be documented under multiple categories, more than one + // Documentation entry may be listed. + list<Documentation> Documentation; +} + +/// A type attribute is not processed on a declaration or a statement. +class TypeAttr : Attr { + // By default, type attributes do not get an AST node. + let ASTNode = 0; +} + +/// An inheritable attribute is inherited by later redeclarations. +class InheritableAttr : Attr; + +/// A target-specific attribute. This class is meant to be used as a mixin +/// with InheritableAttr or Attr depending on the attribute's needs. +class TargetSpecificAttr<TargetArch target> { + TargetArch Target = target; + // Attributes are generally required to have unique spellings for their names + // so that the parser can determine what kind of attribute it has parsed. + // However, target-specific attributes are special in that the attribute only + // "exists" for a given target. So two target-specific attributes can share + // the same name when they exist in different targets. To support this, a + // Kind can be explicitly specified for a target-specific attribute. This + // corresponds to the AttributeList::AT_* enum that is generated and it + // should contain a shared value between the attributes. + // + // Target-specific attributes which use this feature should ensure that the + // spellings match exactly betweeen the attributes, and if the arguments or + // subjects differ, should specify HasCustomParsing = 1 and implement their + // own parsing and semantic handling requirements as-needed. + string ParseKind; +} + +/// An inheritable parameter attribute is inherited by later +/// redeclarations, even when it's written on a parameter. +class InheritableParamAttr : InheritableAttr; + +/// An ignored attribute, which we parse but discard with no checking. +class IgnoredAttr : Attr { + let Ignored = 1; + let ASTNode = 0; + let SemaHandler = 0; + let Documentation = [Undocumented]; +} + +// +// Attributes begin here +// + +def AddressSpace : TypeAttr { + let Spellings = [GNU<"address_space">]; + let Args = [IntArgument<"AddressSpace">]; + let Documentation = [Undocumented]; +} + +def Alias : Attr { + let Spellings = [GCC<"alias">]; + let Args = [StringArgument<"Aliasee">]; + let Subjects = SubjectList<[Function, GlobalVar], ErrorDiag, + "ExpectedFunctionGlobalVarMethodOrProperty">; + let Documentation = [Undocumented]; +} + +def Aligned : InheritableAttr { + let Spellings = [GCC<"aligned">, Declspec<"align">, Keyword<"alignas">, + Keyword<"_Alignas">]; +// let Subjects = SubjectList<[NonBitField, NormalVar, Tag]>; + let Args = [AlignedArgument<"Alignment", 1>]; + let Accessors = [Accessor<"isGNU", [GCC<"aligned">]>, + Accessor<"isC11", [Keyword<"_Alignas">]>, + Accessor<"isAlignas", [Keyword<"alignas">, + Keyword<"_Alignas">]>, + Accessor<"isDeclspec",[Declspec<"align">]>]; + let Documentation = [Undocumented]; +} + +def AlignValue : Attr { + let Spellings = [ + // Unfortunately, this is semantically an assertion, not a directive + // (something else must ensure the alignment), so aligned_value is a + // probably a better name. We might want to add an aligned_value spelling in + // the future (and a corresponding C++ attribute), but this can be done + // later once we decide if we also want them to have slightly-different + // semantics than Intel's align_value. + GNU<"align_value"> + // Intel's compiler on Windows also supports: + // , Declspec<"align_value"> + ]; + let Args = [ExprArgument<"Alignment">]; + let Subjects = SubjectList<[Var, TypedefName], WarnDiag, + "ExpectedVariableOrTypedef">; + let Documentation = [AlignValueDocs]; +} + +def AlignMac68k : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly. + let Spellings = []; + let SemaHandler = 0; + let Documentation = [Undocumented]; +} + +def AlwaysInline : InheritableAttr { + let Spellings = [GCC<"always_inline">, Keyword<"__forceinline">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [Undocumented]; +} + +def TLSModel : InheritableAttr { + let Spellings = [GCC<"tls_model">]; + let Subjects = SubjectList<[TLSVar], ErrorDiag, "ExpectedTLSVar">; + let Args = [StringArgument<"Model">]; + let Documentation = [TLSModelDocs]; +} + +def AnalyzerNoReturn : InheritableAttr { + let Spellings = [GNU<"analyzer_noreturn">]; + let Documentation = [Undocumented]; +} + +def Annotate : InheritableParamAttr { + let Spellings = [GNU<"annotate">]; + let Args = [StringArgument<"Annotation">]; + let Documentation = [Undocumented]; +} + +def ARMInterrupt : InheritableAttr, TargetSpecificAttr<TargetARM> { + // NOTE: If you add any additional spellings, MSP430Interrupt's and + // MipsInterrupt's spellings must match. + let Spellings = [GNU<"interrupt">]; + let Args = [EnumArgument<"Interrupt", "InterruptType", + ["IRQ", "FIQ", "SWI", "ABORT", "UNDEF", ""], + ["IRQ", "FIQ", "SWI", "ABORT", "UNDEF", "Generic"], + 1>]; + let ParseKind = "Interrupt"; + let HasCustomParsing = 1; + let Documentation = [ARMInterruptDocs]; +} + +def AsmLabel : InheritableAttr { + let Spellings = [Keyword<"asm">, Keyword<"__asm__">]; + let Args = [StringArgument<"Label">]; + let SemaHandler = 0; + let Documentation = [Undocumented]; +} + +def Availability : InheritableAttr { + let Spellings = [GNU<"availability">]; + let Args = [IdentifierArgument<"platform">, VersionArgument<"introduced">, + VersionArgument<"deprecated">, VersionArgument<"obsoleted">, + BoolArgument<"unavailable">, StringArgument<"message">]; + let AdditionalMembers = +[{static llvm::StringRef getPrettyPlatformName(llvm::StringRef Platform) { + return llvm::StringSwitch<llvm::StringRef>(Platform) + .Case("android", "Android") + .Case("ios", "iOS") + .Case("macosx", "OS X") + .Case("tvos", "tvOS") + .Case("watchos", "watchOS") + .Case("ios_app_extension", "iOS (App Extension)") + .Case("macosx_app_extension", "OS X (App Extension)") + .Case("tvos_app_extension", "tvOS (App Extension)") + .Case("watchos_app_extension", "watchOS (App Extension)") + .Default(llvm::StringRef()); +} }]; + let HasCustomParsing = 1; + let DuplicatesAllowedWhileMerging = 1; +// let Subjects = SubjectList<[Named]>; + let Documentation = [AvailabilityDocs]; +} + +def Blocks : InheritableAttr { + let Spellings = [GNU<"blocks">]; + let Args = [EnumArgument<"Type", "BlockType", ["byref"], ["ByRef"]>]; + let Documentation = [Undocumented]; +} + +def Bounded : IgnoredAttr { + let Spellings = [GNU<"bounded">]; +} + +def CarriesDependency : InheritableParamAttr { + let Spellings = [GNU<"carries_dependency">, + CXX11<"","carries_dependency", 200809>]; + let Subjects = SubjectList<[ParmVar, ObjCMethod, Function], ErrorDiag>; + let Documentation = [CarriesDependencyDocs]; +} + +def CDecl : InheritableAttr { + let Spellings = [GCC<"cdecl">, Keyword<"__cdecl">, Keyword<"_cdecl">]; +// let Subjects = [Function, ObjCMethod]; + let Documentation = [Undocumented]; +} + +// cf_audited_transfer indicates that the given function has been +// audited and has been marked with the appropriate cf_consumed and +// cf_returns_retained attributes. It is generally applied by +// '#pragma clang arc_cf_code_audited' rather than explicitly. +def CFAuditedTransfer : InheritableAttr { + let Spellings = [GNU<"cf_audited_transfer">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [Undocumented]; +} + +// cf_unknown_transfer is an explicit opt-out of cf_audited_transfer. +// It indicates that the function has unknown or unautomatable +// transfer semantics. +def CFUnknownTransfer : InheritableAttr { + let Spellings = [GNU<"cf_unknown_transfer">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [Undocumented]; +} + +def CFReturnsRetained : InheritableAttr { + let Spellings = [GNU<"cf_returns_retained">]; +// let Subjects = SubjectList<[ObjCMethod, ObjCProperty, Function]>; + let Documentation = [Undocumented]; +} + +def CFReturnsNotRetained : InheritableAttr { + let Spellings = [GNU<"cf_returns_not_retained">]; +// let Subjects = SubjectList<[ObjCMethod, ObjCProperty, Function]>; + let Documentation = [Undocumented]; +} + +def CFConsumed : InheritableParamAttr { + let Spellings = [GNU<"cf_consumed">]; + let Subjects = SubjectList<[ParmVar]>; + let Documentation = [Undocumented]; +} + +def Cleanup : InheritableAttr { + let Spellings = [GCC<"cleanup">]; + let Args = [FunctionArgument<"FunctionDecl">]; + let Subjects = SubjectList<[Var]>; + let Documentation = [Undocumented]; +} + +def Cold : InheritableAttr { + let Spellings = [GCC<"cold">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [Undocumented]; +} + +def Common : InheritableAttr { + let Spellings = [GCC<"common">]; + let Subjects = SubjectList<[Var]>; + let Documentation = [Undocumented]; +} + +def Const : InheritableAttr { + let Spellings = [GCC<"const">, GCC<"__const">]; + let Documentation = [Undocumented]; +} + +def Constructor : InheritableAttr { + let Spellings = [GCC<"constructor">]; + let Args = [DefaultIntArgument<"Priority", 65535>]; + let Subjects = SubjectList<[Function]>; + let Documentation = [Undocumented]; +} + +def CUDAConstant : InheritableAttr { + let Spellings = [GNU<"constant">]; + let Subjects = SubjectList<[Var]>; + let LangOpts = [CUDA]; + let Documentation = [Undocumented]; +} + +def CUDACudartBuiltin : IgnoredAttr { + let Spellings = [GNU<"cudart_builtin">]; + let LangOpts = [CUDA]; +} + +def CUDADevice : InheritableAttr { + let Spellings = [GNU<"device">]; + let Subjects = SubjectList<[Function, Var]>; + let LangOpts = [CUDA]; + let Documentation = [Undocumented]; +} + +def CUDADeviceBuiltin : IgnoredAttr { + let Spellings = [GNU<"device_builtin">]; + let LangOpts = [CUDA]; +} + +def CUDADeviceBuiltinSurfaceType : IgnoredAttr { + let Spellings = [GNU<"device_builtin_surface_type">]; + let LangOpts = [CUDA]; +} + +def CUDADeviceBuiltinTextureType : IgnoredAttr { + let Spellings = [GNU<"device_builtin_texture_type">]; + let LangOpts = [CUDA]; +} + +def CUDAGlobal : InheritableAttr { + let Spellings = [GNU<"global">]; + let Subjects = SubjectList<[Function]>; + let LangOpts = [CUDA]; + let Documentation = [Undocumented]; +} + +def CUDAHost : InheritableAttr { + let Spellings = [GNU<"host">]; + let Subjects = SubjectList<[Function]>; + let LangOpts = [CUDA]; + let Documentation = [Undocumented]; +} + +def CUDAInvalidTarget : InheritableAttr { + let Spellings = []; + let Subjects = SubjectList<[Function]>; + let LangOpts = [CUDA]; + let Documentation = [Undocumented]; +} + +def CUDALaunchBounds : InheritableAttr { + let Spellings = [GNU<"launch_bounds">]; + let Args = [ExprArgument<"MaxThreads">, ExprArgument<"MinBlocks", 1>]; + let LangOpts = [CUDA]; + let Subjects = SubjectList<[ObjCMethod, FunctionLike], WarnDiag, + "ExpectedFunctionOrMethod">; + // An AST node is created for this attribute, but is not used by other parts + // of the compiler. However, this node needs to exist in the AST because + // non-LLVM backends may be relying on the attribute's presence. + let Documentation = [Undocumented]; +} + +def CUDAShared : InheritableAttr { + let Spellings = [GNU<"shared">]; + let Subjects = SubjectList<[Var]>; + let LangOpts = [CUDA]; + let Documentation = [Undocumented]; +} + +def C11NoReturn : InheritableAttr { + let Spellings = [Keyword<"_Noreturn">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let SemaHandler = 0; + let Documentation = [C11NoReturnDocs]; +} + +def CXX11NoReturn : InheritableAttr { + let Spellings = [CXX11<"","noreturn", 200809>]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [CXX11NoReturnDocs]; +} + +def OpenCLKernel : InheritableAttr { + let Spellings = [Keyword<"__kernel">, Keyword<"kernel">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [Undocumented]; +} + +// This attribute is both a type attribute, and a declaration attribute (for +// parameter variables). +def OpenCLImageAccess : Attr { + let Spellings = [Keyword<"__read_only">, Keyword<"read_only">, + Keyword<"__write_only">, Keyword<"write_only">, + Keyword<"__read_write">, Keyword<"read_write">]; + let Subjects = SubjectList<[ParmVar], ErrorDiag>; + let Accessors = [Accessor<"isReadOnly", [Keyword<"__read_only">, + Keyword<"read_only">]>, + Accessor<"isReadWrite", [Keyword<"__read_write">, + Keyword<"read_write">]>, + Accessor<"isWriteOnly", [Keyword<"__write_only">, + Keyword<"write_only">]>]; + let Documentation = [Undocumented]; +} + +def OpenCLPrivateAddressSpace : TypeAttr { + let Spellings = [Keyword<"__private">, Keyword<"private">]; + let Documentation = [OpenCLAddressSpacePrivateDocs]; +} + +def OpenCLGlobalAddressSpace : TypeAttr { + let Spellings = [Keyword<"__global">, Keyword<"global">]; + let Documentation = [OpenCLAddressSpaceGlobalDocs]; +} + +def OpenCLLocalAddressSpace : TypeAttr { + let Spellings = [Keyword<"__local">, Keyword<"local">]; + let Documentation = [OpenCLAddressSpaceLocalDocs]; +} + +def OpenCLConstantAddressSpace : TypeAttr { + let Spellings = [Keyword<"__constant">, Keyword<"constant">]; + let Documentation = [OpenCLAddressSpaceConstantDocs]; +} + +def OpenCLGenericAddressSpace : TypeAttr { + let Spellings = [Keyword<"__generic">, Keyword<"generic">]; + let Documentation = [OpenCLAddressSpaceGenericDocs]; +} + +def Deprecated : InheritableAttr { + let Spellings = [GCC<"deprecated">, Declspec<"deprecated">, + CXX11<"","deprecated", 201309>]; + let Args = [StringArgument<"Message", 1>]; + let Documentation = [Undocumented]; +} + +def Destructor : InheritableAttr { + let Spellings = [GCC<"destructor">]; + let Args = [DefaultIntArgument<"Priority", 65535>]; + let Subjects = SubjectList<[Function]>; + let Documentation = [Undocumented]; +} + +def EnableIf : InheritableAttr { + let Spellings = [GNU<"enable_if">]; + let Subjects = SubjectList<[Function]>; + let Args = [ExprArgument<"Cond">, StringArgument<"Message">]; + let TemplateDependent = 1; + let Documentation = [EnableIfDocs]; +} + +def ExtVectorType : Attr { + let Spellings = [GNU<"ext_vector_type">]; + let Subjects = SubjectList<[TypedefName], ErrorDiag>; + let Args = [ExprArgument<"NumElements">]; + let ASTNode = 0; + let Documentation = [Undocumented]; +} + +def FallThrough : Attr { + let Spellings = [CXX11<"clang", "fallthrough">]; +// let Subjects = [NullStmt]; + let Documentation = [FallthroughDocs]; +} + +def FastCall : InheritableAttr { + let Spellings = [GCC<"fastcall">, Keyword<"__fastcall">, + Keyword<"_fastcall">]; +// let Subjects = [Function, ObjCMethod]; + let Documentation = [FastCallDocs]; +} + +def Final : InheritableAttr { + let Spellings = [Keyword<"final">, Keyword<"sealed">]; + let Accessors = [Accessor<"isSpelledAsSealed", [Keyword<"sealed">]>]; + let SemaHandler = 0; + let Documentation = [Undocumented]; +} + +def MinSize : InheritableAttr { + let Spellings = [GNU<"minsize">]; + let Subjects = SubjectList<[Function, ObjCMethod], ErrorDiag>; + let Documentation = [Undocumented]; +} + +def FlagEnum : InheritableAttr { + let Spellings = [GNU<"flag_enum">]; + let Subjects = SubjectList<[Enum]>; + let Documentation = [FlagEnumDocs]; + let LangOpts = [COnly]; +} + +def Flatten : InheritableAttr { + let Spellings = [GCC<"flatten">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [FlattenDocs]; +} + +def Format : InheritableAttr { + let Spellings = [GCC<"format">]; + let Args = [IdentifierArgument<"Type">, IntArgument<"FormatIdx">, + IntArgument<"FirstArg">]; + let Subjects = SubjectList<[ObjCMethod, Block, HasFunctionProto], WarnDiag, + "ExpectedFunctionWithProtoType">; + let Documentation = [FormatDocs]; +} + +def FormatArg : InheritableAttr { + let Spellings = [GCC<"format_arg">]; + let Args = [IntArgument<"FormatIdx">]; + let Subjects = SubjectList<[ObjCMethod, HasFunctionProto], WarnDiag, + "ExpectedFunctionWithProtoType">; + let Documentation = [Undocumented]; +} + +def GNUInline : InheritableAttr { + let Spellings = [GCC<"gnu_inline">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [Undocumented]; +} + +def Hot : InheritableAttr { + let Spellings = [GCC<"hot">]; + let Subjects = SubjectList<[Function]>; + // An AST node is created for this attribute, but not actually used beyond + // semantic checking for mutual exclusion with the Cold attribute. + let Documentation = [Undocumented]; +} + +def IBAction : InheritableAttr { + let Spellings = [GNU<"ibaction">]; + let Subjects = SubjectList<[ObjCInstanceMethod], WarnDiag, + "ExpectedObjCInstanceMethod">; + // An AST node is created for this attribute, but is not used by other parts + // of the compiler. However, this node needs to exist in the AST because + // external tools rely on it. + let Documentation = [Undocumented]; +} + +def IBOutlet : InheritableAttr { + let Spellings = [GNU<"iboutlet">]; +// let Subjects = [ObjCIvar, ObjCProperty]; + let Documentation = [Undocumented]; +} + +def IBOutletCollection : InheritableAttr { + let Spellings = [GNU<"iboutletcollection">]; + let Args = [TypeArgument<"Interface", 1>]; +// let Subjects = [ObjCIvar, ObjCProperty]; + let Documentation = [Undocumented]; +} + +def Restrict : InheritableAttr { + let Spellings = [Declspec<"restrict">, GCC<"malloc">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [Undocumented]; +} + +def MaxFieldAlignment : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly. + let Spellings = []; + let Args = [UnsignedArgument<"Alignment">]; + let SemaHandler = 0; + let Documentation = [Undocumented]; +} + +def MayAlias : InheritableAttr { + // FIXME: this is a type attribute in GCC, but a declaration attribute here. + let Spellings = [GCC<"may_alias">]; + let Documentation = [Undocumented]; +} + +def MSABI : InheritableAttr { + let Spellings = [GCC<"ms_abi">]; +// let Subjects = [Function, ObjCMethod]; + let Documentation = [MSABIDocs]; +} + +def MSP430Interrupt : InheritableAttr, TargetSpecificAttr<TargetMSP430> { + // NOTE: If you add any additional spellings, ARMInterrupt's and + // MipsInterrupt's spellings must match. + let Spellings = [GNU<"interrupt">]; + let Args = [UnsignedArgument<"Number">]; + let ParseKind = "Interrupt"; + let HasCustomParsing = 1; + let Documentation = [Undocumented]; +} + +def Mips16 : InheritableAttr, TargetSpecificAttr<TargetMips> { + let Spellings = [GCC<"mips16">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [Undocumented]; +} + +def MipsInterrupt : InheritableAttr, TargetSpecificAttr<TargetMips> { + // NOTE: If you add any additional spellings, ARMInterrupt's and + // MSP430Interrupt's spellings must match. + let Spellings = [GNU<"interrupt">]; + let Subjects = SubjectList<[Function]>; + let Args = [EnumArgument<"Interrupt", "InterruptType", + ["vector=sw0", "vector=sw1", "vector=hw0", + "vector=hw1", "vector=hw2", "vector=hw3", + "vector=hw4", "vector=hw5", "eic", ""], + ["sw0", "sw1", "hw0", "hw1", "hw2", "hw3", + "hw4", "hw5", "eic", "eic"] + >]; + let ParseKind = "Interrupt"; + let Documentation = [MipsInterruptDocs]; +} + +def Mode : Attr { + let Spellings = [GCC<"mode">]; + let Args = [IdentifierArgument<"Mode">]; + let Documentation = [Undocumented]; +} + +def Naked : InheritableAttr { + let Spellings = [GCC<"naked">, Declspec<"naked">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [Undocumented]; +} + +def NeonPolyVectorType : TypeAttr { + let Spellings = [GNU<"neon_polyvector_type">]; + let Args = [IntArgument<"NumElements">]; + let Documentation = [Undocumented]; +} + +def NeonVectorType : TypeAttr { + let Spellings = [GNU<"neon_vector_type">]; + let Args = [IntArgument<"NumElements">]; + let Documentation = [Undocumented]; +} + +def ReturnsTwice : InheritableAttr { + let Spellings = [GCC<"returns_twice">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [Undocumented]; +} + +def DisableTailCalls : InheritableAttr { + let Spellings = [GNU<"disable_tail_calls">, + CXX11<"clang", "disable_tail_calls">]; + let Subjects = SubjectList<[Function, ObjCMethod]>; + let Documentation = [DisableTailCallsDocs]; +} + +def NoAlias : InheritableAttr { + let Spellings = [Declspec<"noalias">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [NoAliasDocs]; +} + +def NoCommon : InheritableAttr { + let Spellings = [GCC<"nocommon">]; + let Subjects = SubjectList<[Var]>; + let Documentation = [Undocumented]; +} + +def NoDebug : InheritableAttr { + let Spellings = [GCC<"nodebug">]; + let Documentation = [Undocumented]; +} + +def NoDuplicate : InheritableAttr { + let Spellings = [GNU<"noduplicate">, CXX11<"clang", "noduplicate">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [NoDuplicateDocs]; +} + +def NoInline : InheritableAttr { + let Spellings = [GCC<"noinline">, Declspec<"noinline">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [Undocumented]; +} + +def NoMips16 : InheritableAttr, TargetSpecificAttr<TargetMips> { + let Spellings = [GCC<"nomips16">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [Undocumented]; +} + +// This is not a TargetSpecificAttr so that is silently accepted and +// ignored on other targets as encouraged by the OpenCL spec. +// +// See OpenCL 1.2 6.11.5: "It is our intention that a particular +// implementation of OpenCL be free to ignore all attributes and the +// resulting executable binary will produce the same result." +// +// However, only AMD GPU targets will emit the corresponding IR +// attribute. +// +// FIXME: This provides a sub-optimal error message if you attempt to +// use this in CUDA, since CUDA does not use the same terminology. +def AMDGPUNumVGPR : InheritableAttr { + let Spellings = [GNU<"amdgpu_num_vgpr">]; + let Args = [UnsignedArgument<"NumVGPR">]; + let Documentation = [AMDGPUNumVGPRDocs]; + +// FIXME: This should be for OpenCLKernelFunction, but is not to +// workaround needing to see kernel attribute before others to know if +// this should be rejected on non-kernels. + let Subjects = SubjectList<[Function], ErrorDiag, + "ExpectedKernelFunction">; +} + +def AMDGPUNumSGPR : InheritableAttr { + let Spellings = [GNU<"amdgpu_num_sgpr">]; + let Args = [UnsignedArgument<"NumSGPR">]; + let Documentation = [AMDGPUNumSGPRDocs]; + let Subjects = SubjectList<[Function], ErrorDiag, + "ExpectedKernelFunction">; +} + +def NoSplitStack : InheritableAttr { + let Spellings = [GCC<"no_split_stack">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [NoSplitStackDocs]; +} + +def NonNull : InheritableAttr { + let Spellings = [GCC<"nonnull">]; + let Subjects = SubjectList<[ObjCMethod, HasFunctionProto, ParmVar], WarnDiag, + "ExpectedFunctionMethodOrParameter">; + let Args = [VariadicUnsignedArgument<"Args">]; + let AdditionalMembers = +[{bool isNonNull(unsigned idx) const { + if (!args_size()) + return true; + for (const auto &V : args()) + if (V == idx) + return true; + return false; + } }]; + // FIXME: We should merge duplicates into a single nonnull attribute. + let DuplicatesAllowedWhileMerging = 1; + let Documentation = [NonNullDocs]; +} + +def ReturnsNonNull : InheritableAttr { + let Spellings = [GCC<"returns_nonnull">]; + let Subjects = SubjectList<[ObjCMethod, Function], WarnDiag, + "ExpectedFunctionOrMethod">; + let Documentation = [ReturnsNonNullDocs]; +} + +// pass_object_size(N) indicates that the parameter should have +// __builtin_object_size with Type=N evaluated on the parameter at the callsite. +def PassObjectSize : InheritableParamAttr { + let Spellings = [GNU<"pass_object_size">]; + let Args = [IntArgument<"Type">]; + let Subjects = SubjectList<[ParmVar]>; + let Documentation = [PassObjectSizeDocs]; +} + +// Nullability type attributes. +def TypeNonNull : TypeAttr { + let Spellings = [Keyword<"_Nonnull">]; + let Documentation = [TypeNonNullDocs]; +} + +def TypeNullable : TypeAttr { + let Spellings = [Keyword<"_Nullable">]; + let Documentation = [TypeNullableDocs]; +} + +def TypeNullUnspecified : TypeAttr { + let Spellings = [Keyword<"_Null_unspecified">]; + let Documentation = [TypeNullUnspecifiedDocs]; +} + +def ObjCKindOf : TypeAttr { + let Spellings = [Keyword<"__kindof">]; + let Documentation = [Undocumented]; +} + +def AssumeAligned : InheritableAttr { + let Spellings = [GCC<"assume_aligned">]; + let Subjects = SubjectList<[ObjCMethod, Function]>; + let Args = [ExprArgument<"Alignment">, ExprArgument<"Offset", 1>]; + let Documentation = [AssumeAlignedDocs]; +} + +def NoReturn : InheritableAttr { + let Spellings = [GCC<"noreturn">, Declspec<"noreturn">]; + // FIXME: Does GCC allow this on the function instead? + let Documentation = [Undocumented]; +} + +def NoInstrumentFunction : InheritableAttr { + let Spellings = [GCC<"no_instrument_function">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [Undocumented]; +} + +def NotTailCalled : InheritableAttr { + let Spellings = [GNU<"not_tail_called">, CXX11<"clang", "not_tail_called">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [NotTailCalledDocs]; +} + +def NoThrow : InheritableAttr { + let Spellings = [GCC<"nothrow">, Declspec<"nothrow">]; + let Documentation = [Undocumented]; +} + +def NvWeak : IgnoredAttr { + let Spellings = [GNU<"nv_weak">]; + let LangOpts = [CUDA]; +} + +def ObjCBridge : InheritableAttr { + let Spellings = [GNU<"objc_bridge">]; + let Subjects = SubjectList<[Record, TypedefName], ErrorDiag, + "ExpectedStructOrUnionOrTypedef">; + let Args = [IdentifierArgument<"BridgedType">]; + let Documentation = [Undocumented]; +} + +def ObjCBridgeMutable : InheritableAttr { + let Spellings = [GNU<"objc_bridge_mutable">]; + let Subjects = SubjectList<[Record], ErrorDiag>; + let Args = [IdentifierArgument<"BridgedType">]; + let Documentation = [Undocumented]; +} + +def ObjCBridgeRelated : InheritableAttr { + let Spellings = [GNU<"objc_bridge_related">]; + let Subjects = SubjectList<[Record], ErrorDiag>; + let Args = [IdentifierArgument<"RelatedClass">, + IdentifierArgument<"ClassMethod", 1>, + IdentifierArgument<"InstanceMethod", 1>]; + let HasCustomParsing = 1; + let Documentation = [Undocumented]; +} + +def NSReturnsRetained : InheritableAttr { + let Spellings = [GNU<"ns_returns_retained">]; +// let Subjects = SubjectList<[ObjCMethod, ObjCProperty, Function]>; + let Documentation = [Undocumented]; +} + +def NSReturnsNotRetained : InheritableAttr { + let Spellings = [GNU<"ns_returns_not_retained">]; +// let Subjects = SubjectList<[ObjCMethod, ObjCProperty, Function]>; + let Documentation = [Undocumented]; +} + +def NSReturnsAutoreleased : InheritableAttr { + let Spellings = [GNU<"ns_returns_autoreleased">]; +// let Subjects = SubjectList<[ObjCMethod, ObjCProperty, Function]>; + let Documentation = [Undocumented]; +} + +def NSConsumesSelf : InheritableAttr { + let Spellings = [GNU<"ns_consumes_self">]; + let Subjects = SubjectList<[ObjCMethod]>; + let Documentation = [Undocumented]; +} + +def NSConsumed : InheritableParamAttr { + let Spellings = [GNU<"ns_consumed">]; + let Subjects = SubjectList<[ParmVar]>; + let Documentation = [Undocumented]; +} + +def ObjCException : InheritableAttr { + let Spellings = [GNU<"objc_exception">]; + let Subjects = SubjectList<[ObjCInterface], ErrorDiag>; + let Documentation = [Undocumented]; +} + +def ObjCMethodFamily : InheritableAttr { + let Spellings = [GNU<"objc_method_family">]; + let Subjects = SubjectList<[ObjCMethod], ErrorDiag>; + let Args = [EnumArgument<"Family", "FamilyKind", + ["none", "alloc", "copy", "init", "mutableCopy", "new"], + ["OMF_None", "OMF_alloc", "OMF_copy", "OMF_init", + "OMF_mutableCopy", "OMF_new"]>]; + let Documentation = [ObjCMethodFamilyDocs]; +} + +def ObjCNSObject : InheritableAttr { + let Spellings = [GNU<"NSObject">]; + let Documentation = [Undocumented]; +} + +def ObjCIndependentClass : InheritableAttr { + let Spellings = [GNU<"objc_independent_class">]; + let Documentation = [Undocumented]; +} + +def ObjCPreciseLifetime : InheritableAttr { + let Spellings = [GNU<"objc_precise_lifetime">]; + let Subjects = SubjectList<[Var], ErrorDiag>; + let Documentation = [Undocumented]; +} + +def ObjCReturnsInnerPointer : InheritableAttr { + let Spellings = [GNU<"objc_returns_inner_pointer">]; + let Subjects = SubjectList<[ObjCMethod, ObjCProperty], ErrorDiag>; + let Documentation = [Undocumented]; +} + +def ObjCRequiresSuper : InheritableAttr { + let Spellings = [GNU<"objc_requires_super">]; + let Subjects = SubjectList<[ObjCMethod], ErrorDiag>; + let Documentation = [ObjCRequiresSuperDocs]; +} + +def ObjCRootClass : InheritableAttr { + let Spellings = [GNU<"objc_root_class">]; + let Subjects = SubjectList<[ObjCInterface], ErrorDiag>; + let Documentation = [Undocumented]; +} + +def ObjCExplicitProtocolImpl : InheritableAttr { + let Spellings = [GNU<"objc_protocol_requires_explicit_implementation">]; + let Subjects = SubjectList<[ObjCProtocol], ErrorDiag>; + let Documentation = [Undocumented]; +} + +def ObjCDesignatedInitializer : Attr { + let Spellings = [GNU<"objc_designated_initializer">]; + let Subjects = SubjectList<[ObjCInterfaceDeclInitMethod], ErrorDiag, + "ExpectedObjCInterfaceDeclInitMethod">; + let Documentation = [Undocumented]; +} + +def ObjCRuntimeName : Attr { + let Spellings = [GNU<"objc_runtime_name">]; + let Subjects = SubjectList<[ObjCInterface, ObjCProtocol], ErrorDiag>; + let Args = [StringArgument<"MetadataName">]; + let Documentation = [ObjCRuntimeNameDocs]; +} + +def ObjCBoxable : Attr { + let Spellings = [GNU<"objc_boxable">]; + let Subjects = SubjectList<[Record], ErrorDiag, "ExpectedStructOrUnion">; + let Documentation = [ObjCBoxableDocs]; +} + +def OptimizeNone : InheritableAttr { + let Spellings = [GNU<"optnone">, CXX11<"clang", "optnone">]; + let Subjects = SubjectList<[Function, ObjCMethod]>; + let Documentation = [OptnoneDocs]; +} + +def Overloadable : Attr { + let Spellings = [GNU<"overloadable">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [OverloadableDocs]; +} + +def Override : InheritableAttr { + let Spellings = [Keyword<"override">]; + let SemaHandler = 0; + let Documentation = [Undocumented]; +} + +def Ownership : InheritableAttr { + let Spellings = [GNU<"ownership_holds">, GNU<"ownership_returns">, + GNU<"ownership_takes">]; + let Accessors = [Accessor<"isHolds", [GNU<"ownership_holds">]>, + Accessor<"isReturns", [GNU<"ownership_returns">]>, + Accessor<"isTakes", [GNU<"ownership_takes">]>]; + let AdditionalMembers = [{ + enum OwnershipKind { Holds, Returns, Takes }; + OwnershipKind getOwnKind() const { + return isHolds() ? Holds : + isTakes() ? Takes : + Returns; + } + }]; + let Args = [IdentifierArgument<"Module">, VariadicUnsignedArgument<"Args">]; + let Subjects = SubjectList<[HasFunctionProto], WarnDiag, + "ExpectedFunctionWithProtoType">; + let Documentation = [Undocumented]; +} + +def Packed : InheritableAttr { + let Spellings = [GCC<"packed">]; +// let Subjects = [Tag, Field]; + let Documentation = [Undocumented]; +} + +def IntelOclBicc : InheritableAttr { + let Spellings = [GNU<"intel_ocl_bicc">]; +// let Subjects = [Function, ObjCMethod]; + let Documentation = [Undocumented]; +} + +def Pcs : InheritableAttr { + let Spellings = [GCC<"pcs">]; + let Args = [EnumArgument<"PCS", "PCSType", + ["aapcs", "aapcs-vfp"], + ["AAPCS", "AAPCS_VFP"]>]; +// let Subjects = [Function, ObjCMethod]; + let Documentation = [PcsDocs]; +} + +def Pure : InheritableAttr { + let Spellings = [GCC<"pure">]; + let Documentation = [Undocumented]; +} + +def Regparm : TypeAttr { + let Spellings = [GCC<"regparm">]; + let Args = [UnsignedArgument<"NumParams">]; + let Documentation = [RegparmDocs]; +} + +def ReqdWorkGroupSize : InheritableAttr { + let Spellings = [GNU<"reqd_work_group_size">]; + let Args = [UnsignedArgument<"XDim">, UnsignedArgument<"YDim">, + UnsignedArgument<"ZDim">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [Undocumented]; +} + +def WorkGroupSizeHint : InheritableAttr { + let Spellings = [GNU<"work_group_size_hint">]; + let Args = [UnsignedArgument<"XDim">, + UnsignedArgument<"YDim">, + UnsignedArgument<"ZDim">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [Undocumented]; +} + +def InitPriority : InheritableAttr { + let Spellings = [GNU<"init_priority">]; + let Args = [UnsignedArgument<"Priority">]; + let Subjects = SubjectList<[Var], ErrorDiag>; + let Documentation = [Undocumented]; +} + +def Section : InheritableAttr { + let Spellings = [GCC<"section">, Declspec<"allocate">]; + let Args = [StringArgument<"Name">]; + let Subjects = SubjectList<[Function, GlobalVar, + ObjCMethod, ObjCProperty], ErrorDiag, + "ExpectedFunctionGlobalVarMethodOrProperty">; + let Documentation = [SectionDocs]; +} + +def Sentinel : InheritableAttr { + let Spellings = [GCC<"sentinel">]; + let Args = [DefaultIntArgument<"Sentinel", 0>, + DefaultIntArgument<"NullPos", 0>]; +// let Subjects = SubjectList<[Function, ObjCMethod, Block, Var]>; + let Documentation = [Undocumented]; +} + +def StdCall : InheritableAttr { + let Spellings = [GCC<"stdcall">, Keyword<"__stdcall">, Keyword<"_stdcall">]; +// let Subjects = [Function, ObjCMethod]; + let Documentation = [StdCallDocs]; +} + +def SysVABI : InheritableAttr { + let Spellings = [GCC<"sysv_abi">]; +// let Subjects = [Function, ObjCMethod]; + let Documentation = [Undocumented]; +} + +def ThisCall : InheritableAttr { + let Spellings = [GCC<"thiscall">, Keyword<"__thiscall">, + Keyword<"_thiscall">]; +// let Subjects = [Function, ObjCMethod]; + let Documentation = [ThisCallDocs]; +} + +def VectorCall : InheritableAttr { + let Spellings = [GNU<"vectorcall">, Keyword<"__vectorcall">, + Keyword<"_vectorcall">]; +// let Subjects = [Function, ObjCMethod]; + let Documentation = [VectorCallDocs]; +} + +def Pascal : InheritableAttr { + let Spellings = [GNU<"pascal">, Keyword<"__pascal">, Keyword<"_pascal">]; +// let Subjects = [Function, ObjCMethod]; + let Documentation = [Undocumented]; +} + +def Target : InheritableAttr { + let Spellings = [GCC<"target">]; + let Args = [StringArgument<"featuresStr">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [TargetDocs]; + let AdditionalMembers = [{ + typedef std::pair<std::vector<std::string>, StringRef> ParsedTargetAttr; + ParsedTargetAttr parse() const { + ParsedTargetAttr Ret; + SmallVector<StringRef, 1> AttrFeatures; + getFeaturesStr().split(AttrFeatures, ","); + + // Grab the various features and prepend a "+" to turn on the feature to + // the backend and add them to our existing set of features. + for (auto &Feature : AttrFeatures) { + // Go ahead and trim whitespace rather than either erroring or + // accepting it weirdly. + Feature = Feature.trim(); + + // We don't support cpu tuning this way currently. + // TODO: Support the fpmath option. It will require checking + // overall feature validity for the function with the rest of the + // attributes on the function. + if (Feature.startswith("fpmath=") || Feature.startswith("tune=")) + continue; + + // While we're here iterating check for a different target cpu. + if (Feature.startswith("arch=")) + Ret.second = Feature.split("=").second.trim(); + else if (Feature.startswith("no-")) + Ret.first.push_back("-" + Feature.split("-").second.str()); + else + Ret.first.push_back("+" + Feature.str()); + } + return Ret; + } + }]; +} + +def TransparentUnion : InheritableAttr { + let Spellings = [GCC<"transparent_union">]; +// let Subjects = SubjectList<[Record, TypedefName]>; + let Documentation = [Undocumented]; +} + +def Unavailable : InheritableAttr { + let Spellings = [GNU<"unavailable">]; + let Args = [StringArgument<"Message", 1>, + EnumArgument<"ImplicitReason", "ImplicitReason", + ["", "", "", ""], + ["IR_None", + "IR_ARCForbiddenType", + "IR_ForbiddenWeak", + "IR_ARCForbiddenConversion", + "IR_ARCInitReturnsUnrelated", + "IR_ARCFieldWithOwnership"], 1, /*fake*/ 1>]; + let Documentation = [Undocumented]; +} + +def ArcWeakrefUnavailable : InheritableAttr { + let Spellings = [GNU<"objc_arc_weak_reference_unavailable">]; + let Subjects = SubjectList<[ObjCInterface], ErrorDiag>; + let Documentation = [Undocumented]; +} + +def ObjCGC : TypeAttr { + let Spellings = [GNU<"objc_gc">]; + let Args = [IdentifierArgument<"Kind">]; + let Documentation = [Undocumented]; +} + +def ObjCOwnership : InheritableAttr { + let Spellings = [GNU<"objc_ownership">]; + let Args = [IdentifierArgument<"Kind">]; + let ASTNode = 0; + let Documentation = [Undocumented]; +} + +def ObjCRequiresPropertyDefs : InheritableAttr { + let Spellings = [GNU<"objc_requires_property_definitions">]; + let Subjects = SubjectList<[ObjCInterface], ErrorDiag>; + let Documentation = [Undocumented]; +} + +def Unused : InheritableAttr { + let Spellings = [GCC<"unused">]; + let Subjects = SubjectList<[Var, ObjCIvar, Type, Label, Field, ObjCMethod, + FunctionLike], WarnDiag, + "ExpectedVariableFunctionOrLabel">; + let Documentation = [Undocumented]; +} + +def Used : InheritableAttr { + let Spellings = [GCC<"used">]; + let Documentation = [Undocumented]; +} + +def Uuid : InheritableAttr { + let Spellings = [Declspec<"uuid">]; + let Args = [StringArgument<"Guid">]; +// let Subjects = SubjectList<[CXXRecord]>; + let LangOpts = [MicrosoftExt, Borland]; + let Documentation = [Undocumented]; +} + +def VectorSize : TypeAttr { + let Spellings = [GCC<"vector_size">]; + let Args = [ExprArgument<"NumBytes">]; + let Documentation = [Undocumented]; +} + +def VecTypeHint : InheritableAttr { + let Spellings = [GNU<"vec_type_hint">]; + let Args = [TypeArgument<"TypeHint">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [Undocumented]; +} + +def Visibility : InheritableAttr { + let Clone = 0; + let Spellings = [GCC<"visibility">]; + let Args = [EnumArgument<"Visibility", "VisibilityType", + ["default", "hidden", "internal", "protected"], + ["Default", "Hidden", "Hidden", "Protected"]>]; + let Documentation = [Undocumented]; +} + +def TypeVisibility : InheritableAttr { + let Clone = 0; + let Spellings = [GNU<"type_visibility">, CXX11<"clang", "type_visibility">]; + let Args = [EnumArgument<"Visibility", "VisibilityType", + ["default", "hidden", "internal", "protected"], + ["Default", "Hidden", "Hidden", "Protected"]>]; +// let Subjects = [Tag, ObjCInterface, Namespace]; + let Documentation = [Undocumented]; +} + +def VecReturn : InheritableAttr { + let Spellings = [GNU<"vecreturn">]; + let Subjects = SubjectList<[CXXRecord], ErrorDiag>; + let Documentation = [Undocumented]; +} + +def WarnUnused : InheritableAttr { + let Spellings = [GNU<"warn_unused">]; + let Subjects = SubjectList<[Record]>; + let Documentation = [Undocumented]; +} + +def WarnUnusedResult : InheritableAttr { + let Spellings = [GCC<"warn_unused_result">, + CXX11<"clang", "warn_unused_result">]; + let Subjects = SubjectList<[ObjCMethod, CXXRecord, FunctionLike], WarnDiag, + "ExpectedFunctionMethodOrClass">; + let Documentation = [Undocumented]; +} + +def Weak : InheritableAttr { + let Spellings = [GCC<"weak">]; + let Subjects = SubjectList<[Var, Function, CXXRecord]>; + let Documentation = [Undocumented]; +} + +def WeakImport : InheritableAttr { + let Spellings = [GNU<"weak_import">]; + let Documentation = [Undocumented]; +} + +def WeakRef : InheritableAttr { + let Spellings = [GCC<"weakref">]; + // A WeakRef that has an argument is treated as being an AliasAttr + let Args = [StringArgument<"Aliasee", 1>]; + let Subjects = SubjectList<[Var, Function], ErrorDiag>; + let Documentation = [Undocumented]; +} + +def X86ForceAlignArgPointer : InheritableAttr, TargetSpecificAttr<TargetX86> { + let Spellings = [GNU<"force_align_arg_pointer">]; + // Technically, this appertains to a FunctionDecl, but the target-specific + // code silently allows anything function-like (such as typedefs or function + // pointers), but does not apply the attribute to them. + let Documentation = [Undocumented]; +} + +def NoSanitize : InheritableAttr { + let Spellings = [GNU<"no_sanitize">, CXX11<"clang", "no_sanitize">]; + let Args = [VariadicStringArgument<"Sanitizers">]; + let Subjects = SubjectList<[Function, ObjCMethod], ErrorDiag>; + let Documentation = [NoSanitizeDocs]; + let AdditionalMembers = [{ + SanitizerMask getMask() const { + SanitizerMask Mask = 0; + for (auto SanitizerName : sanitizers()) { + SanitizerMask ParsedMask = + parseSanitizerValue(SanitizerName, /*AllowGroups=*/true); + Mask |= expandSanitizerGroups(ParsedMask); + } + return Mask; + } + }]; +} + +// Attributes to disable a specific sanitizer. No new sanitizers should be added +// to this list; the no_sanitize attribute should be extended instead. +def NoSanitizeSpecific : InheritableAttr { + let Spellings = [GCC<"no_address_safety_analysis">, + GCC<"no_sanitize_address">, + GCC<"no_sanitize_thread">, + GNU<"no_sanitize_memory">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [NoSanitizeAddressDocs, NoSanitizeThreadDocs, + NoSanitizeMemoryDocs]; + let ASTNode = 0; +} + +// C/C++ Thread safety attributes (e.g. for deadlock, data race checking) + +def GuardedVar : InheritableAttr { + let Spellings = [GNU<"guarded_var">]; + let Subjects = SubjectList<[Field, SharedVar], WarnDiag, + "ExpectedFieldOrGlobalVar">; + let Documentation = [Undocumented]; +} + +def PtGuardedVar : InheritableAttr { + let Spellings = [GNU<"pt_guarded_var">]; + let Subjects = SubjectList<[Field, SharedVar], WarnDiag, + "ExpectedFieldOrGlobalVar">; + let Documentation = [Undocumented]; +} + +def Lockable : InheritableAttr { + let Spellings = [GNU<"lockable">]; + let Subjects = SubjectList<[Record]>; + let Documentation = [Undocumented]; + let ASTNode = 0; // Replaced by Capability +} + +def ScopedLockable : InheritableAttr { + let Spellings = [GNU<"scoped_lockable">]; + let Subjects = SubjectList<[Record]>; + let Documentation = [Undocumented]; +} + +def Capability : InheritableAttr { + let Spellings = [GNU<"capability">, CXX11<"clang", "capability">, + GNU<"shared_capability">, + CXX11<"clang", "shared_capability">]; + let Subjects = SubjectList<[Record, TypedefName], ErrorDiag, + "ExpectedStructOrUnionOrTypedef">; + let Args = [StringArgument<"Name">]; + let Accessors = [Accessor<"isShared", + [GNU<"shared_capability">, + CXX11<"clang","shared_capability">]>]; + let Documentation = [Undocumented]; + let AdditionalMembers = [{ + bool isMutex() const { return getName().equals_lower("mutex"); } + bool isRole() const { return getName().equals_lower("role"); } + }]; +} + +def AssertCapability : InheritableAttr { + let Spellings = [GNU<"assert_capability">, + CXX11<"clang", "assert_capability">, + GNU<"assert_shared_capability">, + CXX11<"clang", "assert_shared_capability">]; + let Subjects = SubjectList<[Function]>; + let LateParsed = 1; + let TemplateDependent = 1; + let ParseArgumentsAsUnevaluated = 1; + let DuplicatesAllowedWhileMerging = 1; + let Args = [ExprArgument<"Expr">]; + let Accessors = [Accessor<"isShared", + [GNU<"assert_shared_capability">, + CXX11<"clang", "assert_shared_capability">]>]; + let Documentation = [AssertCapabilityDocs]; +} + +def AcquireCapability : InheritableAttr { + let Spellings = [GNU<"acquire_capability">, + CXX11<"clang", "acquire_capability">, + GNU<"acquire_shared_capability">, + CXX11<"clang", "acquire_shared_capability">, + GNU<"exclusive_lock_function">, + GNU<"shared_lock_function">]; + let Subjects = SubjectList<[Function]>; + let LateParsed = 1; + let TemplateDependent = 1; + let ParseArgumentsAsUnevaluated = 1; + let DuplicatesAllowedWhileMerging = 1; + let Args = [VariadicExprArgument<"Args">]; + let Accessors = [Accessor<"isShared", + [GNU<"acquire_shared_capability">, + CXX11<"clang", "acquire_shared_capability">, + GNU<"shared_lock_function">]>]; + let Documentation = [AcquireCapabilityDocs]; +} + +def TryAcquireCapability : InheritableAttr { + let Spellings = [GNU<"try_acquire_capability">, + CXX11<"clang", "try_acquire_capability">, + GNU<"try_acquire_shared_capability">, + CXX11<"clang", "try_acquire_shared_capability">]; + let Subjects = SubjectList<[Function], + ErrorDiag>; + let LateParsed = 1; + let TemplateDependent = 1; + let ParseArgumentsAsUnevaluated = 1; + let DuplicatesAllowedWhileMerging = 1; + let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">]; + let Accessors = [Accessor<"isShared", + [GNU<"try_acquire_shared_capability">, + CXX11<"clang", "try_acquire_shared_capability">]>]; + let Documentation = [TryAcquireCapabilityDocs]; +} + +def ReleaseCapability : InheritableAttr { + let Spellings = [GNU<"release_capability">, + CXX11<"clang", "release_capability">, + GNU<"release_shared_capability">, + CXX11<"clang", "release_shared_capability">, + GNU<"release_generic_capability">, + CXX11<"clang", "release_generic_capability">, + GNU<"unlock_function">]; + let Subjects = SubjectList<[Function]>; + let LateParsed = 1; + let TemplateDependent = 1; + let ParseArgumentsAsUnevaluated = 1; + let DuplicatesAllowedWhileMerging = 1; + let Args = [VariadicExprArgument<"Args">]; + let Accessors = [Accessor<"isShared", + [GNU<"release_shared_capability">, + CXX11<"clang", "release_shared_capability">]>, + Accessor<"isGeneric", + [GNU<"release_generic_capability">, + CXX11<"clang", "release_generic_capability">, + GNU<"unlock_function">]>]; + let Documentation = [ReleaseCapabilityDocs]; +} + +def RequiresCapability : InheritableAttr { + let Spellings = [GNU<"requires_capability">, + CXX11<"clang", "requires_capability">, + GNU<"exclusive_locks_required">, + GNU<"requires_shared_capability">, + CXX11<"clang", "requires_shared_capability">, + GNU<"shared_locks_required">]; + let Args = [VariadicExprArgument<"Args">]; + let LateParsed = 1; + let TemplateDependent = 1; + let ParseArgumentsAsUnevaluated = 1; + let DuplicatesAllowedWhileMerging = 1; + let Subjects = SubjectList<[Function]>; + let Accessors = [Accessor<"isShared", [GNU<"requires_shared_capability">, + GNU<"shared_locks_required">, + CXX11<"clang","requires_shared_capability">]>]; + let Documentation = [Undocumented]; +} + +def NoThreadSafetyAnalysis : InheritableAttr { + let Spellings = [GNU<"no_thread_safety_analysis">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [Undocumented]; +} + +def GuardedBy : InheritableAttr { + let Spellings = [GNU<"guarded_by">]; + let Args = [ExprArgument<"Arg">]; + let LateParsed = 1; + let TemplateDependent = 1; + let ParseArgumentsAsUnevaluated = 1; + let DuplicatesAllowedWhileMerging = 1; + let Subjects = SubjectList<[Field, SharedVar], WarnDiag, + "ExpectedFieldOrGlobalVar">; + let Documentation = [Undocumented]; +} + +def PtGuardedBy : InheritableAttr { + let Spellings = [GNU<"pt_guarded_by">]; + let Args = [ExprArgument<"Arg">]; + let LateParsed = 1; + let TemplateDependent = 1; + let ParseArgumentsAsUnevaluated = 1; + let DuplicatesAllowedWhileMerging = 1; + let Subjects = SubjectList<[Field, SharedVar], WarnDiag, + "ExpectedFieldOrGlobalVar">; + let Documentation = [Undocumented]; +} + +def AcquiredAfter : InheritableAttr { + let Spellings = [GNU<"acquired_after">]; + let Args = [VariadicExprArgument<"Args">]; + let LateParsed = 1; + let TemplateDependent = 1; + let ParseArgumentsAsUnevaluated = 1; + let DuplicatesAllowedWhileMerging = 1; + let Subjects = SubjectList<[Field, SharedVar], WarnDiag, + "ExpectedFieldOrGlobalVar">; + let Documentation = [Undocumented]; +} + +def AcquiredBefore : InheritableAttr { + let Spellings = [GNU<"acquired_before">]; + let Args = [VariadicExprArgument<"Args">]; + let LateParsed = 1; + let TemplateDependent = 1; + let ParseArgumentsAsUnevaluated = 1; + let DuplicatesAllowedWhileMerging = 1; + let Subjects = SubjectList<[Field, SharedVar], WarnDiag, + "ExpectedFieldOrGlobalVar">; + let Documentation = [Undocumented]; +} + +def AssertExclusiveLock : InheritableAttr { + let Spellings = [GNU<"assert_exclusive_lock">]; + let Args = [VariadicExprArgument<"Args">]; + let LateParsed = 1; + let TemplateDependent = 1; + let ParseArgumentsAsUnevaluated = 1; + let DuplicatesAllowedWhileMerging = 1; + let Subjects = SubjectList<[Function]>; + let Documentation = [Undocumented]; +} + +def AssertSharedLock : InheritableAttr { + let Spellings = [GNU<"assert_shared_lock">]; + let Args = [VariadicExprArgument<"Args">]; + let LateParsed = 1; + let TemplateDependent = 1; + let ParseArgumentsAsUnevaluated = 1; + let DuplicatesAllowedWhileMerging = 1; + let Subjects = SubjectList<[Function]>; + let Documentation = [Undocumented]; +} + +// The first argument is an integer or boolean value specifying the return value +// of a successful lock acquisition. +def ExclusiveTrylockFunction : InheritableAttr { + let Spellings = [GNU<"exclusive_trylock_function">]; + let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">]; + let LateParsed = 1; + let TemplateDependent = 1; + let ParseArgumentsAsUnevaluated = 1; + let DuplicatesAllowedWhileMerging = 1; + let Subjects = SubjectList<[Function]>; + let Documentation = [Undocumented]; +} + +// The first argument is an integer or boolean value specifying the return value +// of a successful lock acquisition. +def SharedTrylockFunction : InheritableAttr { + let Spellings = [GNU<"shared_trylock_function">]; + let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">]; + let LateParsed = 1; + let TemplateDependent = 1; + let ParseArgumentsAsUnevaluated = 1; + let DuplicatesAllowedWhileMerging = 1; + let Subjects = SubjectList<[Function]>; + let Documentation = [Undocumented]; +} + +def LockReturned : InheritableAttr { + let Spellings = [GNU<"lock_returned">]; + let Args = [ExprArgument<"Arg">]; + let LateParsed = 1; + let TemplateDependent = 1; + let ParseArgumentsAsUnevaluated = 1; + let Subjects = SubjectList<[Function]>; + let Documentation = [Undocumented]; +} + +def LocksExcluded : InheritableAttr { + let Spellings = [GNU<"locks_excluded">]; + let Args = [VariadicExprArgument<"Args">]; + let LateParsed = 1; + let TemplateDependent = 1; + let ParseArgumentsAsUnevaluated = 1; + let DuplicatesAllowedWhileMerging = 1; + let Subjects = SubjectList<[Function]>; + let Documentation = [Undocumented]; +} + +// C/C++ consumed attributes. + +def Consumable : InheritableAttr { + let Spellings = [GNU<"consumable">]; + let Subjects = SubjectList<[CXXRecord]>; + let Args = [EnumArgument<"DefaultState", "ConsumedState", + ["unknown", "consumed", "unconsumed"], + ["Unknown", "Consumed", "Unconsumed"]>]; + let Documentation = [ConsumableDocs]; +} + +def ConsumableAutoCast : InheritableAttr { + let Spellings = [GNU<"consumable_auto_cast_state">]; + let Subjects = SubjectList<[CXXRecord]>; + let Documentation = [Undocumented]; +} + +def ConsumableSetOnRead : InheritableAttr { + let Spellings = [GNU<"consumable_set_state_on_read">]; + let Subjects = SubjectList<[CXXRecord]>; + let Documentation = [Undocumented]; +} + +def CallableWhen : InheritableAttr { + let Spellings = [GNU<"callable_when">]; + let Subjects = SubjectList<[CXXMethod]>; + let Args = [VariadicEnumArgument<"CallableStates", "ConsumedState", + ["unknown", "consumed", "unconsumed"], + ["Unknown", "Consumed", "Unconsumed"]>]; + let Documentation = [CallableWhenDocs]; +} + +def ParamTypestate : InheritableAttr { + let Spellings = [GNU<"param_typestate">]; + let Subjects = SubjectList<[ParmVar]>; + let Args = [EnumArgument<"ParamState", "ConsumedState", + ["unknown", "consumed", "unconsumed"], + ["Unknown", "Consumed", "Unconsumed"]>]; + let Documentation = [ParamTypestateDocs]; +} + +def ReturnTypestate : InheritableAttr { + let Spellings = [GNU<"return_typestate">]; + let Subjects = SubjectList<[Function, ParmVar]>; + let Args = [EnumArgument<"State", "ConsumedState", + ["unknown", "consumed", "unconsumed"], + ["Unknown", "Consumed", "Unconsumed"]>]; + let Documentation = [ReturnTypestateDocs]; +} + +def SetTypestate : InheritableAttr { + let Spellings = [GNU<"set_typestate">]; + let Subjects = SubjectList<[CXXMethod]>; + let Args = [EnumArgument<"NewState", "ConsumedState", + ["unknown", "consumed", "unconsumed"], + ["Unknown", "Consumed", "Unconsumed"]>]; + let Documentation = [SetTypestateDocs]; +} + +def TestTypestate : InheritableAttr { + let Spellings = [GNU<"test_typestate">]; + let Subjects = SubjectList<[CXXMethod]>; + let Args = [EnumArgument<"TestState", "ConsumedState", + ["consumed", "unconsumed"], + ["Consumed", "Unconsumed"]>]; + let Documentation = [TestTypestateDocs]; +} + +// Type safety attributes for `void *' pointers and type tags. + +def ArgumentWithTypeTag : InheritableAttr { + let Spellings = [GNU<"argument_with_type_tag">, + GNU<"pointer_with_type_tag">]; + let Args = [IdentifierArgument<"ArgumentKind">, + UnsignedArgument<"ArgumentIdx">, + UnsignedArgument<"TypeTagIdx">, + BoolArgument<"IsPointer">]; + let HasCustomParsing = 1; + let Documentation = [ArgumentWithTypeTagDocs, PointerWithTypeTagDocs]; +} + +def TypeTagForDatatype : InheritableAttr { + let Spellings = [GNU<"type_tag_for_datatype">]; + let Args = [IdentifierArgument<"ArgumentKind">, + TypeArgument<"MatchingCType">, + BoolArgument<"LayoutCompatible">, + BoolArgument<"MustBeNull">]; +// let Subjects = SubjectList<[Var], ErrorDiag>; + let HasCustomParsing = 1; + let Documentation = [TypeTagForDatatypeDocs]; +} + +// Microsoft-related attributes + +def MSNoVTable : InheritableAttr, TargetSpecificAttr<TargetMicrosoftCXXABI> { + let Spellings = [Declspec<"novtable">]; + let Subjects = SubjectList<[CXXRecord]>; + let Documentation = [MSNoVTableDocs]; +} + +def : IgnoredAttr { + let Spellings = [Declspec<"property">]; +} + +def MSStruct : InheritableAttr { + let Spellings = [GCC<"ms_struct">]; + let Subjects = SubjectList<[Record]>; + let Documentation = [Undocumented]; +} + +def DLLExport : InheritableAttr, TargetSpecificAttr<TargetWindows> { + let Spellings = [Declspec<"dllexport">, GCC<"dllexport">]; + let Subjects = SubjectList<[Function, Var, CXXRecord]>; + let Documentation = [Undocumented]; +} + +def DLLImport : InheritableAttr, TargetSpecificAttr<TargetWindows> { + let Spellings = [Declspec<"dllimport">, GCC<"dllimport">]; + let Subjects = SubjectList<[Function, Var, CXXRecord]>; + let Documentation = [Undocumented]; +} + +def SelectAny : InheritableAttr { + let Spellings = [Declspec<"selectany">]; + let LangOpts = [MicrosoftExt]; + let Documentation = [Undocumented]; +} + +def Thread : Attr { + let Spellings = [Declspec<"thread">]; + let LangOpts = [MicrosoftExt]; + let Documentation = [ThreadDocs]; + let Subjects = SubjectList<[Var]>; +} + +def Win64 : IgnoredAttr { + let Spellings = [Keyword<"__w64">]; + let LangOpts = [MicrosoftExt]; +} + +def Ptr32 : TypeAttr { + let Spellings = [Keyword<"__ptr32">]; + let Documentation = [Undocumented]; +} + +def Ptr64 : TypeAttr { + let Spellings = [Keyword<"__ptr64">]; + let Documentation = [Undocumented]; +} + +def SPtr : TypeAttr { + let Spellings = [Keyword<"__sptr">]; + let Documentation = [Undocumented]; +} + +def UPtr : TypeAttr { + let Spellings = [Keyword<"__uptr">]; + let Documentation = [Undocumented]; +} + +def MSInheritance : InheritableAttr { + let LangOpts = [MicrosoftExt]; + let Args = [DefaultBoolArgument<"BestCase", 1>]; + let Spellings = [Keyword<"__single_inheritance">, + Keyword<"__multiple_inheritance">, + Keyword<"__virtual_inheritance">, + Keyword<"__unspecified_inheritance">]; + let AdditionalMembers = [{ + static bool hasVBPtrOffsetField(Spelling Inheritance) { + return Inheritance == Keyword_unspecified_inheritance; + } + + // Only member pointers to functions need a this adjustment, since it can be + // combined with the field offset for data pointers. + static bool hasNVOffsetField(bool IsMemberFunction, Spelling Inheritance) { + return IsMemberFunction && Inheritance >= Keyword_multiple_inheritance; + } + + static bool hasVBTableOffsetField(Spelling Inheritance) { + return Inheritance >= Keyword_virtual_inheritance; + } + + static bool hasOnlyOneField(bool IsMemberFunction, + Spelling Inheritance) { + if (IsMemberFunction) + return Inheritance <= Keyword_single_inheritance; + return Inheritance <= Keyword_multiple_inheritance; + } + }]; + let Documentation = [MSInheritanceDocs]; +} + +def MSVtorDisp : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly. + let Spellings = []; + let Args = [UnsignedArgument<"vdm">]; + let SemaHandler = 0; + + let AdditionalMembers = [{ + enum Mode { + Never, + ForVBaseOverride, + ForVFTable + }; + + Mode getVtorDispMode() const { return Mode(vdm); } + }]; + let Documentation = [Undocumented]; +} + +def InitSeg : Attr { + let Spellings = [Pragma<"", "init_seg">]; + let Args = [StringArgument<"Section">]; + let SemaHandler = 0; + let Documentation = [InitSegDocs]; + let AdditionalMembers = [{ + void printPrettyPragma(raw_ostream &OS, const PrintingPolicy &Policy) const { + OS << '(' << getSection() << ')'; + } + }]; +} + +def Unaligned : IgnoredAttr { + let Spellings = [Keyword<"__unaligned">]; +} + +def LoopHint : Attr { + /// #pragma clang loop <option> directive + /// vectorize: vectorizes loop operations if State == Enable. + /// vectorize_width: vectorize loop operations with width 'Value'. + /// interleave: interleave multiple loop iterations if State == Enable. + /// interleave_count: interleaves 'Value' loop interations. + /// unroll: fully unroll loop if State == Enable. + /// unroll_count: unrolls loop 'Value' times. + + /// #pragma unroll <argument> directive + /// <no arg>: fully unrolls loop. + /// boolean: fully unrolls loop if State == Enable. + /// expression: unrolls loop 'Value' times. + + let Spellings = [Pragma<"clang", "loop">, Pragma<"", "unroll">, + Pragma<"", "nounroll">]; + + /// State of the loop optimization specified by the spelling. + let Args = [EnumArgument<"Option", "OptionType", + ["vectorize", "vectorize_width", "interleave", "interleave_count", + "unroll", "unroll_count"], + ["Vectorize", "VectorizeWidth", "Interleave", "InterleaveCount", + "Unroll", "UnrollCount"]>, + EnumArgument<"State", "LoopHintState", + ["enable", "disable", "numeric", "assume_safety", "full"], + ["Enable", "Disable", "Numeric", "AssumeSafety", "Full"]>, + ExprArgument<"Value">]; + + let AdditionalMembers = [{ + static const char *getOptionName(int Option) { + switch(Option) { + case Vectorize: return "vectorize"; + case VectorizeWidth: return "vectorize_width"; + case Interleave: return "interleave"; + case InterleaveCount: return "interleave_count"; + case Unroll: return "unroll"; + case UnrollCount: return "unroll_count"; + } + llvm_unreachable("Unhandled LoopHint option."); + } + + void printPrettyPragma(raw_ostream &OS, const PrintingPolicy &Policy) const { + unsigned SpellingIndex = getSpellingListIndex(); + // For "#pragma unroll" and "#pragma nounroll" the string "unroll" or + // "nounroll" is already emitted as the pragma name. + if (SpellingIndex == Pragma_nounroll) + return; + else if (SpellingIndex == Pragma_unroll) { + OS << getValueString(Policy); + return; + } + + assert(SpellingIndex == Pragma_clang_loop && "Unexpected spelling"); + OS << getOptionName(option) << getValueString(Policy); + } + + // Return a string containing the loop hint argument including the + // enclosing parentheses. + std::string getValueString(const PrintingPolicy &Policy) const { + std::string ValueName; + llvm::raw_string_ostream OS(ValueName); + OS << "("; + if (state == Numeric) + value->printPretty(OS, nullptr, Policy); + else if (state == Enable) + OS << "enable"; + else if (state == Full) + OS << "full"; + else if (state == AssumeSafety) + OS << "assume_safety"; + else + OS << "disable"; + OS << ")"; + return OS.str(); + } + + // Return a string suitable for identifying this attribute in diagnostics. + std::string getDiagnosticName(const PrintingPolicy &Policy) const { + unsigned SpellingIndex = getSpellingListIndex(); + if (SpellingIndex == Pragma_nounroll) + return "#pragma nounroll"; + else if (SpellingIndex == Pragma_unroll) + return "#pragma unroll" + (option == UnrollCount ? getValueString(Policy) : ""); + + assert(SpellingIndex == Pragma_clang_loop && "Unexpected spelling"); + return getOptionName(option) + getValueString(Policy); + } + }]; + + let Documentation = [LoopHintDocs, UnrollHintDocs]; +} + +def CapturedRecord : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly. + let Spellings = []; + let SemaHandler = 0; + let Documentation = [Undocumented]; +} + +def OMPThreadPrivateDecl : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly. + let Spellings = []; + let SemaHandler = 0; + let Documentation = [Undocumented]; +} + +def InternalLinkage : InheritableAttr { + let Spellings = [GNU<"internal_linkage">, CXX11<"clang", "internal_linkage">]; + let Subjects = SubjectList<[Var, Function, CXXRecord]>; + let Documentation = [InternalLinkageDocs]; +} diff --git a/contrib/llvm/tools/clang/include/clang/Basic/AttrDocs.td b/contrib/llvm/tools/clang/include/clang/Basic/AttrDocs.td new file mode 100644 index 0000000..2567d55 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/AttrDocs.td @@ -0,0 +1,1861 @@ +//==--- AttrDocs.td - Attribute documentation ----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +def GlobalDocumentation { + code Intro =[{.. + ------------------------------------------------------------------- + NOTE: This file is automatically generated by running clang-tblgen + -gen-attr-docs. Do not edit this file by hand!! + ------------------------------------------------------------------- + +=================== +Attributes in Clang +=================== +.. contents:: + :local: + +Introduction +============ + +This page lists the attributes currently supported by Clang. +}]; +} + +def SectionDocs : Documentation { + let Category = DocCatVariable; + let Content = [{ +The ``section`` attribute allows you to specify a specific section a +global variable or function should be in after translation. + }]; + let Heading = "section (gnu::section, __declspec(allocate))"; +} + +def InitSegDocs : Documentation { + let Category = DocCatVariable; + let Content = [{ +The attribute applied by ``pragma init_seg()`` controls the section into +which global initialization function pointers are emitted. It is only +available with ``-fms-extensions``. Typically, this function pointer is +emitted into ``.CRT$XCU`` on Windows. The user can change the order of +initialization by using a different section name with the same +``.CRT$XC`` prefix and a suffix that sorts lexicographically before or +after the standard ``.CRT$XCU`` sections. See the init_seg_ +documentation on MSDN for more information. + +.. _init_seg: http://msdn.microsoft.com/en-us/library/7977wcck(v=vs.110).aspx + }]; +} + +def TLSModelDocs : Documentation { + let Category = DocCatVariable; + let Content = [{ +The ``tls_model`` attribute allows you to specify which thread-local storage +model to use. It accepts the following strings: + +* global-dynamic +* local-dynamic +* initial-exec +* local-exec + +TLS models are mutually exclusive. + }]; +} + +def ThreadDocs : Documentation { + let Category = DocCatVariable; + let Content = [{ +The ``__declspec(thread)`` attribute declares a variable with thread local +storage. It is available under the ``-fms-extensions`` flag for MSVC +compatibility. See the documentation for `__declspec(thread)`_ on MSDN. + +.. _`__declspec(thread)`: http://msdn.microsoft.com/en-us/library/9w1sdazb.aspx + +In Clang, ``__declspec(thread)`` is generally equivalent in functionality to the +GNU ``__thread`` keyword. The variable must not have a destructor and must have +a constant initializer, if any. The attribute only applies to variables +declared with static storage duration, such as globals, class static data +members, and static locals. + }]; +} + +def CarriesDependencyDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The ``carries_dependency`` attribute specifies dependency propagation into and +out of functions. + +When specified on a function or Objective-C method, the ``carries_dependency`` +attribute means that the return value carries a dependency out of the function, +so that the implementation need not constrain ordering upon return from that +function. Implementations of the function and its caller may choose to preserve +dependencies instead of emitting memory ordering instructions such as fences. + +Note, this attribute does not change the meaning of the program, but may result +in generation of more efficient code. + }]; +} + +def C11NoReturnDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +A function declared as ``_Noreturn`` shall not return to its caller. The +compiler will generate a diagnostic for a function declared as ``_Noreturn`` +that appears to be capable of returning to its caller. + }]; +} + +def CXX11NoReturnDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +A function declared as ``[[noreturn]]`` shall not return to its caller. The +compiler will generate a diagnostic for a function declared as ``[[noreturn]]`` +that appears to be capable of returning to its caller. + }]; +} + +def AssertCapabilityDocs : Documentation { + let Category = DocCatFunction; + let Heading = "assert_capability (assert_shared_capability, clang::assert_capability, clang::assert_shared_capability)"; + let Content = [{ +Marks a function that dynamically tests whether a capability is held, and halts +the program if it is not held. + }]; +} + +def AcquireCapabilityDocs : Documentation { + let Category = DocCatFunction; + let Heading = "acquire_capability (acquire_shared_capability, clang::acquire_capability, clang::acquire_shared_capability)"; + let Content = [{ +Marks a function as acquiring a capability. + }]; +} + +def TryAcquireCapabilityDocs : Documentation { + let Category = DocCatFunction; + let Heading = "try_acquire_capability (try_acquire_shared_capability, clang::try_acquire_capability, clang::try_acquire_shared_capability)"; + let Content = [{ +Marks a function that attempts to acquire a capability. This function may fail to +actually acquire the capability; they accept a Boolean value determining +whether acquiring the capability means success (true), or failing to acquire +the capability means success (false). + }]; +} + +def ReleaseCapabilityDocs : Documentation { + let Category = DocCatFunction; + let Heading = "release_capability (release_shared_capability, clang::release_capability, clang::release_shared_capability)"; + let Content = [{ +Marks a function as releasing a capability. + }]; +} + +def AssumeAlignedDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Use ``__attribute__((assume_aligned(<alignment>[,<offset>]))`` on a function +declaration to specify that the return value of the function (which must be a +pointer type) has the specified offset, in bytes, from an address with the +specified alignment. The offset is taken to be zero if omitted. + +.. code-block:: c++ + + // The returned pointer value has 32-byte alignment. + void *a() __attribute__((assume_aligned (32))); + + // The returned pointer value is 4 bytes greater than an address having + // 32-byte alignment. + void *b() __attribute__((assume_aligned (32, 4))); + +Note that this attribute provides information to the compiler regarding a +condition that the code already ensures is true. It does not cause the compiler +to enforce the provided alignment assumption. + }]; +} + +def EnableIfDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +.. Note:: Some features of this attribute are experimental. The meaning of + multiple enable_if attributes on a single declaration is subject to change in + a future version of clang. Also, the ABI is not standardized and the name + mangling may change in future versions. To avoid that, use asm labels. + +The ``enable_if`` attribute can be placed on function declarations to control +which overload is selected based on the values of the function's arguments. +When combined with the ``overloadable`` attribute, this feature is also +available in C. + +.. code-block:: c++ + + int isdigit(int c); + int isdigit(int c) __attribute__((enable_if(c <= -1 || c > 255, "chosen when 'c' is out of range"))) __attribute__((unavailable("'c' must have the value of an unsigned char or EOF"))); + + void foo(char c) { + isdigit(c); + isdigit(10); + isdigit(-10); // results in a compile-time error. + } + +The enable_if attribute takes two arguments, the first is an expression written +in terms of the function parameters, the second is a string explaining why this +overload candidate could not be selected to be displayed in diagnostics. The +expression is part of the function signature for the purposes of determining +whether it is a redeclaration (following the rules used when determining +whether a C++ template specialization is ODR-equivalent), but is not part of +the type. + +The enable_if expression is evaluated as if it were the body of a +bool-returning constexpr function declared with the arguments of the function +it is being applied to, then called with the parameters at the call site. If the +result is false or could not be determined through constant expression +evaluation, then this overload will not be chosen and the provided string may +be used in a diagnostic if the compile fails as a result. + +Because the enable_if expression is an unevaluated context, there are no global +state changes, nor the ability to pass information from the enable_if +expression to the function body. For example, suppose we want calls to +strnlen(strbuf, maxlen) to resolve to strnlen_chk(strbuf, maxlen, size of +strbuf) only if the size of strbuf can be determined: + +.. code-block:: c++ + + __attribute__((always_inline)) + static inline size_t strnlen(const char *s, size_t maxlen) + __attribute__((overloadable)) + __attribute__((enable_if(__builtin_object_size(s, 0) != -1))), + "chosen when the buffer size is known but 'maxlen' is not"))) + { + return strnlen_chk(s, maxlen, __builtin_object_size(s, 0)); + } + +Multiple enable_if attributes may be applied to a single declaration. In this +case, the enable_if expressions are evaluated from left to right in the +following manner. First, the candidates whose enable_if expressions evaluate to +false or cannot be evaluated are discarded. If the remaining candidates do not +share ODR-equivalent enable_if expressions, the overload resolution is +ambiguous. Otherwise, enable_if overload resolution continues with the next +enable_if attribute on the candidates that have not been discarded and have +remaining enable_if attributes. In this way, we pick the most specific +overload out of a number of viable overloads using enable_if. + +.. code-block:: c++ + + void f() __attribute__((enable_if(true, ""))); // #1 + void f() __attribute__((enable_if(true, ""))) __attribute__((enable_if(true, ""))); // #2 + + void g(int i, int j) __attribute__((enable_if(i, ""))); // #1 + void g(int i, int j) __attribute__((enable_if(j, ""))) __attribute__((enable_if(true))); // #2 + +In this example, a call to f() is always resolved to #2, as the first enable_if +expression is ODR-equivalent for both declarations, but #1 does not have another +enable_if expression to continue evaluating, so the next round of evaluation has +only a single candidate. In a call to g(1, 1), the call is ambiguous even though +#2 has more enable_if attributes, because the first enable_if expressions are +not ODR-equivalent. + +Query for this feature with ``__has_attribute(enable_if)``. + }]; +} + +def PassObjectSizeDocs : Documentation { + let Category = DocCatVariable; // Technically it's a parameter doc, but eh. + let Content = [{ +.. Note:: The mangling of functions with parameters that are annotated with + ``pass_object_size`` is subject to change. You can get around this by + using ``__asm__("foo")`` to explicitly name your functions, thus preserving + your ABI; also, non-overloadable C functions with ``pass_object_size`` are + not mangled. + +The ``pass_object_size(Type)`` attribute can be placed on function parameters to +instruct clang to call ``__builtin_object_size(param, Type)`` at each callsite +of said function, and implicitly pass the result of this call in as an invisible +argument of type ``size_t`` directly after the parameter annotated with +``pass_object_size``. Clang will also replace any calls to +``__builtin_object_size(param, Type)`` in the function by said implicit +parameter. + +Example usage: + +.. code-block:: c + + int bzero1(char *const p __attribute__((pass_object_size(0)))) + __attribute__((noinline)) { + int i = 0; + for (/**/; i < (int)__builtin_object_size(p, 0); ++i) { + p[i] = 0; + } + return i; + } + + int main() { + char chars[100]; + int n = bzero1(&chars[0]); + assert(n == sizeof(chars)); + return 0; + } + +If successfully evaluating ``__builtin_object_size(param, Type)`` at the +callsite is not possible, then the "failed" value is passed in. So, using the +definition of ``bzero1`` from above, the following code would exit cleanly: + +.. code-block:: c + + int main2(int argc, char *argv[]) { + int n = bzero1(argv); + assert(n == -1); + return 0; + } + +``pass_object_size`` plays a part in overload resolution. If two overload +candidates are otherwise equally good, then the overload with one or more +parameters with ``pass_object_size`` is preferred. This implies that the choice +between two identical overloads both with ``pass_object_size`` on one or more +parameters will always be ambiguous; for this reason, having two such overloads +is illegal. For example: + +.. code-block:: c++ + + #define PS(N) __attribute__((pass_object_size(N))) + // OK + void Foo(char *a, char *b); // Overload A + // OK -- overload A has no parameters with pass_object_size. + void Foo(char *a PS(0), char *b PS(0)); // Overload B + // Error -- Same signature (sans pass_object_size) as overload B, and both + // overloads have one or more parameters with the pass_object_size attribute. + void Foo(void *a PS(0), void *b); + + // OK + void Bar(void *a PS(0)); // Overload C + // OK + void Bar(char *c PS(1)); // Overload D + + void main() { + char known[10], *unknown; + Foo(unknown, unknown); // Calls overload B + Foo(known, unknown); // Calls overload B + Foo(unknown, known); // Calls overload B + Foo(known, known); // Calls overload B + + Bar(known); // Calls overload D + Bar(unknown); // Calls overload D + } + +Currently, ``pass_object_size`` is a bit restricted in terms of its usage: + +* Only one use of ``pass_object_size`` is allowed per parameter. + +* It is an error to take the address of a function with ``pass_object_size`` on + any of its parameters. If you wish to do this, you can create an overload + without ``pass_object_size`` on any parameters. + +* It is an error to apply the ``pass_object_size`` attribute to parameters that + are not pointers. Additionally, any parameter that ``pass_object_size`` is + applied to must be marked ``const`` at its function's definition. + }]; +} + +def OverloadableDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Clang provides support for C++ function overloading in C. Function overloading +in C is introduced using the ``overloadable`` attribute. For example, one +might provide several overloaded versions of a ``tgsin`` function that invokes +the appropriate standard function computing the sine of a value with ``float``, +``double``, or ``long double`` precision: + +.. code-block:: c + + #include <math.h> + float __attribute__((overloadable)) tgsin(float x) { return sinf(x); } + double __attribute__((overloadable)) tgsin(double x) { return sin(x); } + long double __attribute__((overloadable)) tgsin(long double x) { return sinl(x); } + +Given these declarations, one can call ``tgsin`` with a ``float`` value to +receive a ``float`` result, with a ``double`` to receive a ``double`` result, +etc. Function overloading in C follows the rules of C++ function overloading +to pick the best overload given the call arguments, with a few C-specific +semantics: + +* Conversion from ``float`` or ``double`` to ``long double`` is ranked as a + floating-point promotion (per C99) rather than as a floating-point conversion + (as in C++). + +* A conversion from a pointer of type ``T*`` to a pointer of type ``U*`` is + considered a pointer conversion (with conversion rank) if ``T`` and ``U`` are + compatible types. + +* A conversion from type ``T`` to a value of type ``U`` is permitted if ``T`` + and ``U`` are compatible types. This conversion is given "conversion" rank. + +The declaration of ``overloadable`` functions is restricted to function +declarations and definitions. Most importantly, if any function with a given +name is given the ``overloadable`` attribute, then all function declarations +and definitions with that name (and in that scope) must have the +``overloadable`` attribute. This rule even applies to redeclarations of +functions whose original declaration had the ``overloadable`` attribute, e.g., + +.. code-block:: c + + int f(int) __attribute__((overloadable)); + float f(float); // error: declaration of "f" must have the "overloadable" attribute + + int g(int) __attribute__((overloadable)); + int g(int) { } // error: redeclaration of "g" must also have the "overloadable" attribute + +Functions marked ``overloadable`` must have prototypes. Therefore, the +following code is ill-formed: + +.. code-block:: c + + int h() __attribute__((overloadable)); // error: h does not have a prototype + +However, ``overloadable`` functions are allowed to use a ellipsis even if there +are no named parameters (as is permitted in C++). This feature is particularly +useful when combined with the ``unavailable`` attribute: + +.. code-block:: c++ + + void honeypot(...) __attribute__((overloadable, unavailable)); // calling me is an error + +Functions declared with the ``overloadable`` attribute have their names mangled +according to the same rules as C++ function names. For example, the three +``tgsin`` functions in our motivating example get the mangled names +``_Z5tgsinf``, ``_Z5tgsind``, and ``_Z5tgsine``, respectively. There are two +caveats to this use of name mangling: + +* Future versions of Clang may change the name mangling of functions overloaded + in C, so you should not depend on an specific mangling. To be completely + safe, we strongly urge the use of ``static inline`` with ``overloadable`` + functions. + +* The ``overloadable`` attribute has almost no meaning when used in C++, + because names will already be mangled and functions are already overloadable. + However, when an ``overloadable`` function occurs within an ``extern "C"`` + linkage specification, it's name *will* be mangled in the same way as it + would in C. + +Query for this feature with ``__has_extension(attribute_overloadable)``. + }]; +} + +def ObjCMethodFamilyDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Many methods in Objective-C have conventional meanings determined by their +selectors. It is sometimes useful to be able to mark a method as having a +particular conventional meaning despite not having the right selector, or as +not having the conventional meaning that its selector would suggest. For these +use cases, we provide an attribute to specifically describe the "method family" +that a method belongs to. + +**Usage**: ``__attribute__((objc_method_family(X)))``, where ``X`` is one of +``none``, ``alloc``, ``copy``, ``init``, ``mutableCopy``, or ``new``. This +attribute can only be placed at the end of a method declaration: + +.. code-block:: objc + + - (NSString *)initMyStringValue __attribute__((objc_method_family(none))); + +Users who do not wish to change the conventional meaning of a method, and who +merely want to document its non-standard retain and release semantics, should +use the retaining behavior attributes (``ns_returns_retained``, +``ns_returns_not_retained``, etc). + +Query for this feature with ``__has_attribute(objc_method_family)``. + }]; +} + +def NoDuplicateDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The ``noduplicate`` attribute can be placed on function declarations to control +whether function calls to this function can be duplicated or not as a result of +optimizations. This is required for the implementation of functions with +certain special requirements, like the OpenCL "barrier" function, that might +need to be run concurrently by all the threads that are executing in lockstep +on the hardware. For example this attribute applied on the function +"nodupfunc" in the code below avoids that: + +.. code-block:: c + + void nodupfunc() __attribute__((noduplicate)); + // Setting it as a C++11 attribute is also valid + // void nodupfunc() [[clang::noduplicate]]; + void foo(); + void bar(); + + nodupfunc(); + if (a > n) { + foo(); + } else { + bar(); + } + +gets possibly modified by some optimizations into code similar to this: + +.. code-block:: c + + if (a > n) { + nodupfunc(); + foo(); + } else { + nodupfunc(); + bar(); + } + +where the call to "nodupfunc" is duplicated and sunk into the two branches +of the condition. + }]; +} + +def NoSplitStackDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The ``no_split_stack`` attribute disables the emission of the split stack +preamble for a particular function. It has no effect if ``-fsplit-stack`` +is not specified. + }]; +} + +def ObjCRequiresSuperDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Some Objective-C classes allow a subclass to override a particular method in a +parent class but expect that the overriding method also calls the overridden +method in the parent class. For these cases, we provide an attribute to +designate that a method requires a "call to ``super``" in the overriding +method in the subclass. + +**Usage**: ``__attribute__((objc_requires_super))``. This attribute can only +be placed at the end of a method declaration: + +.. code-block:: objc + + - (void)foo __attribute__((objc_requires_super)); + +This attribute can only be applied the method declarations within a class, and +not a protocol. Currently this attribute does not enforce any placement of +where the call occurs in the overriding method (such as in the case of +``-dealloc`` where the call must appear at the end). It checks only that it +exists. + +Note that on both OS X and iOS that the Foundation framework provides a +convenience macro ``NS_REQUIRES_SUPER`` that provides syntactic sugar for this +attribute: + +.. code-block:: objc + + - (void)foo NS_REQUIRES_SUPER; + +This macro is conditionally defined depending on the compiler's support for +this attribute. If the compiler does not support the attribute the macro +expands to nothing. + +Operationally, when a method has this annotation the compiler will warn if the +implementation of an override in a subclass does not call super. For example: + +.. code-block:: objc + + warning: method possibly missing a [super AnnotMeth] call + - (void) AnnotMeth{}; + ^ + }]; +} + +def ObjCRuntimeNameDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +By default, the Objective-C interface or protocol identifier is used +in the metadata name for that object. The `objc_runtime_name` +attribute allows annotated interfaces or protocols to use the +specified string argument in the object's metadata name instead of the +default name. + +**Usage**: ``__attribute__((objc_runtime_name("MyLocalName")))``. This attribute +can only be placed before an @protocol or @interface declaration: + +.. code-block:: objc + + __attribute__((objc_runtime_name("MyLocalName"))) + @interface Message + @end + + }]; +} + +def ObjCBoxableDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Structs and unions marked with the ``objc_boxable`` attribute can be used +with the Objective-C boxed expression syntax, ``@(...)``. + +**Usage**: ``__attribute__((objc_boxable))``. This attribute +can only be placed on a declaration of a trivially-copyable struct or union: + +.. code-block:: objc + + struct __attribute__((objc_boxable)) some_struct { + int i; + }; + union __attribute__((objc_boxable)) some_union { + int i; + float f; + }; + typedef struct __attribute__((objc_boxable)) _some_struct some_struct; + + // ... + + some_struct ss; + NSValue *boxed = @(ss); + + }]; +} + +def AvailabilityDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The ``availability`` attribute can be placed on declarations to describe the +lifecycle of that declaration relative to operating system versions. Consider +the function declaration for a hypothetical function ``f``: + +.. code-block:: c++ + + void f(void) __attribute__((availability(macosx,introduced=10.4,deprecated=10.6,obsoleted=10.7))); + +The availability attribute states that ``f`` was introduced in Mac OS X 10.4, +deprecated in Mac OS X 10.6, and obsoleted in Mac OS X 10.7. This information +is used by Clang to determine when it is safe to use ``f``: for example, if +Clang is instructed to compile code for Mac OS X 10.5, a call to ``f()`` +succeeds. If Clang is instructed to compile code for Mac OS X 10.6, the call +succeeds but Clang emits a warning specifying that the function is deprecated. +Finally, if Clang is instructed to compile code for Mac OS X 10.7, the call +fails because ``f()`` is no longer available. + +The availability attribute is a comma-separated list starting with the +platform name and then including clauses specifying important milestones in the +declaration's lifetime (in any order) along with additional information. Those +clauses can be: + +introduced=\ *version* + The first version in which this declaration was introduced. + +deprecated=\ *version* + The first version in which this declaration was deprecated, meaning that + users should migrate away from this API. + +obsoleted=\ *version* + The first version in which this declaration was obsoleted, meaning that it + was removed completely and can no longer be used. + +unavailable + This declaration is never available on this platform. + +message=\ *string-literal* + Additional message text that Clang will provide when emitting a warning or + error about use of a deprecated or obsoleted declaration. Useful to direct + users to replacement APIs. + +Multiple availability attributes can be placed on a declaration, which may +correspond to different platforms. Only the availability attribute with the +platform corresponding to the target platform will be used; any others will be +ignored. If no availability attribute specifies availability for the current +target platform, the availability attributes are ignored. Supported platforms +are: + +``ios`` + Apple's iOS operating system. The minimum deployment target is specified by + the ``-mios-version-min=*version*`` or ``-miphoneos-version-min=*version*`` + command-line arguments. + +``macosx`` + Apple's Mac OS X operating system. The minimum deployment target is + specified by the ``-mmacosx-version-min=*version*`` command-line argument. + +``tvos`` + Apple's tvOS operating system. The minimum deployment target is specified by + the ``-mtvos-version-min=*version*`` command-line argument. + +``watchos`` + Apple's watchOS operating system. The minimum deployment target is specified by + the ``-mwatchos-version-min=*version*`` command-line argument. + +A declaration can be used even when deploying back to a platform version prior +to when the declaration was introduced. When this happens, the declaration is +`weakly linked +<https://developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BPFrameworks/Concepts/WeakLinking.html>`_, +as if the ``weak_import`` attribute were added to the declaration. A +weakly-linked declaration may or may not be present a run-time, and a program +can determine whether the declaration is present by checking whether the +address of that declaration is non-NULL. + +If there are multiple declarations of the same entity, the availability +attributes must either match on a per-platform basis or later +declarations must not have availability attributes for that +platform. For example: + +.. code-block:: c + + void g(void) __attribute__((availability(macosx,introduced=10.4))); + void g(void) __attribute__((availability(macosx,introduced=10.4))); // okay, matches + void g(void) __attribute__((availability(ios,introduced=4.0))); // okay, adds a new platform + void g(void); // okay, inherits both macosx and ios availability from above. + void g(void) __attribute__((availability(macosx,introduced=10.5))); // error: mismatch + +When one method overrides another, the overriding method can be more widely available than the overridden method, e.g.,: + +.. code-block:: objc + + @interface A + - (id)method __attribute__((availability(macosx,introduced=10.4))); + - (id)method2 __attribute__((availability(macosx,introduced=10.4))); + @end + + @interface B : A + - (id)method __attribute__((availability(macosx,introduced=10.3))); // okay: method moved into base class later + - (id)method __attribute__((availability(macosx,introduced=10.5))); // error: this method was available via the base class in 10.4 + @end + }]; +} + +def FallthroughDocs : Documentation { + let Category = DocCatStmt; + let Content = [{ +The ``clang::fallthrough`` attribute is used along with the +``-Wimplicit-fallthrough`` argument to annotate intentional fall-through +between switch labels. It can only be applied to a null statement placed at a +point of execution between any statement and the next switch label. It is +common to mark these places with a specific comment, but this attribute is +meant to replace comments with a more strict annotation, which can be checked +by the compiler. This attribute doesn't change semantics of the code and can +be used wherever an intended fall-through occurs. It is designed to mimic +control-flow statements like ``break;``, so it can be placed in most places +where ``break;`` can, but only if there are no statements on the execution path +between it and the next switch label. + +Here is an example: + +.. code-block:: c++ + + // compile with -Wimplicit-fallthrough + switch (n) { + case 22: + case 33: // no warning: no statements between case labels + f(); + case 44: // warning: unannotated fall-through + g(); + [[clang::fallthrough]]; + case 55: // no warning + if (x) { + h(); + break; + } + else { + i(); + [[clang::fallthrough]]; + } + case 66: // no warning + p(); + [[clang::fallthrough]]; // warning: fallthrough annotation does not + // directly precede case label + q(); + case 77: // warning: unannotated fall-through + r(); + } + }]; +} + +def ARMInterruptDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Clang supports the GNU style ``__attribute__((interrupt("TYPE")))`` attribute on +ARM targets. This attribute may be attached to a function definition and +instructs the backend to generate appropriate function entry/exit code so that +it can be used directly as an interrupt service routine. + +The parameter passed to the interrupt attribute is optional, but if +provided it must be a string literal with one of the following values: "IRQ", +"FIQ", "SWI", "ABORT", "UNDEF". + +The semantics are as follows: + +- If the function is AAPCS, Clang instructs the backend to realign the stack to + 8 bytes on entry. This is a general requirement of the AAPCS at public + interfaces, but may not hold when an exception is taken. Doing this allows + other AAPCS functions to be called. +- If the CPU is M-class this is all that needs to be done since the architecture + itself is designed in such a way that functions obeying the normal AAPCS ABI + constraints are valid exception handlers. +- If the CPU is not M-class, the prologue and epilogue are modified to save all + non-banked registers that are used, so that upon return the user-mode state + will not be corrupted. Note that to avoid unnecessary overhead, only + general-purpose (integer) registers are saved in this way. If VFP operations + are needed, that state must be saved manually. + + Specifically, interrupt kinds other than "FIQ" will save all core registers + except "lr" and "sp". "FIQ" interrupts will save r0-r7. +- If the CPU is not M-class, the return instruction is changed to one of the + canonical sequences permitted by the architecture for exception return. Where + possible the function itself will make the necessary "lr" adjustments so that + the "preferred return address" is selected. + + Unfortunately the compiler is unable to make this guarantee for an "UNDEF" + handler, where the offset from "lr" to the preferred return address depends on + the execution state of the code which generated the exception. In this case + a sequence equivalent to "movs pc, lr" will be used. + }]; +} + +def MipsInterruptDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Clang supports the GNU style ``__attribute__((interrupt("ARGUMENT")))`` attribute on +MIPS targets. This attribute may be attached to a function definition and instructs +the backend to generate appropriate function entry/exit code so that it can be used +directly as an interrupt service routine. + +By default, the compiler will produce a function prologue and epilogue suitable for +an interrupt service routine that handles an External Interrupt Controller (eic) +generated interrupt. This behaviour can be explicitly requested with the "eic" +argument. + +Otherwise, for use with vectored interrupt mode, the argument passed should be +of the form "vector=LEVEL" where LEVEL is one of the following values: +"sw0", "sw1", "hw0", "hw1", "hw2", "hw3", "hw4", "hw5". The compiler will +then set the interrupt mask to the corresponding level which will mask all +interrupts up to and including the argument. + +The semantics are as follows: + +- The prologue is modified so that the Exception Program Counter (EPC) and + Status coprocessor registers are saved to the stack. The interrupt mask is + set so that the function can only be interrupted by a higher priority + interrupt. The epilogue will restore the previous values of EPC and Status. + +- The prologue and epilogue are modified to save and restore all non-kernel + registers as necessary. + +- The FPU is disabled in the prologue, as the floating pointer registers are not + spilled to the stack. + +- The function return sequence is changed to use an exception return instruction. + +- The parameter sets the interrupt mask for the function corresponding to the + interrupt level specified. If no mask is specified the interrupt mask + defaults to "eic". + }]; +} + +def TargetDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Clang supports the GNU style ``__attribute__((target("OPTIONS")))`` attribute. +This attribute may be attached to a function definition and instructs +the backend to use different code generation options than were passed on the +command line. + +The current set of options correspond to the existing "subtarget features" for +the target with or without a "-mno-" in front corresponding to the absence +of the feature, as well as ``arch="CPU"`` which will change the default "CPU" +for the function. + +Example "subtarget features" from the x86 backend include: "mmx", "sse", "sse4.2", +"avx", "xop" and largely correspond to the machine specific options handled by +the front end. +}]; +} + +def DocCatAMDGPURegisterAttributes : + DocumentationCategory<"AMD GPU Register Attributes"> { + let Content = [{ +Clang supports attributes for controlling register usage on AMD GPU +targets. These attributes may be attached to a kernel function +definition and is an optimization hint to the backend for the maximum +number of registers to use. This is useful in cases where register +limited occupancy is known to be an important factor for the +performance for the kernel. + +The semantics are as follows: + +- The backend will attempt to limit the number of used registers to + the specified value, but the exact number used is not + guaranteed. The number used may be rounded up to satisfy the + allocation requirements or ABI constraints of the subtarget. For + example, on Southern Islands VGPRs may only be allocated in + increments of 4, so requesting a limit of 39 VGPRs will really + attempt to use up to 40. Requesting more registers than the + subtarget supports will truncate to the maximum allowed. The backend + may also use fewer registers than requested whenever possible. + +- 0 implies the default no limit on register usage. + +- Ignored on older VLIW subtargets which did not have separate scalar + and vector registers, R600 through Northern Islands. + +}]; +} + + +def AMDGPUNumVGPRDocs : Documentation { + let Category = DocCatAMDGPURegisterAttributes; + let Content = [{ +Clang supports the +``__attribute__((amdgpu_num_vgpr(<num_registers>)))`` attribute on AMD +Southern Islands GPUs and later for controlling the number of vector +registers. A typical value would be between 4 and 256 in increments +of 4. +}]; +} + +def AMDGPUNumSGPRDocs : Documentation { + let Category = DocCatAMDGPURegisterAttributes; + let Content = [{ + +Clang supports the +``__attribute__((amdgpu_num_sgpr(<num_registers>)))`` attribute on AMD +Southern Islands GPUs and later for controlling the number of scalar +registers. A typical value would be between 8 and 104 in increments of +8. + +Due to common instruction constraints, an additional 2-4 SGPRs are +typically required for internal use depending on features used. This +value is a hint for the total number of SGPRs to use, and not the +number of user SGPRs, so no special consideration needs to be given +for these. +}]; +} + +def DocCatCallingConvs : DocumentationCategory<"Calling Conventions"> { + let Content = [{ +Clang supports several different calling conventions, depending on the target +platform and architecture. The calling convention used for a function determines +how parameters are passed, how results are returned to the caller, and other +low-level details of calling a function. + }]; +} + +def PcsDocs : Documentation { + let Category = DocCatCallingConvs; + let Content = [{ +On ARM targets, this attribute can be used to select calling conventions +similar to ``stdcall`` on x86. Valid parameter values are "aapcs" and +"aapcs-vfp". + }]; +} + +def RegparmDocs : Documentation { + let Category = DocCatCallingConvs; + let Content = [{ +On 32-bit x86 targets, the regparm attribute causes the compiler to pass +the first three integer parameters in EAX, EDX, and ECX instead of on the +stack. This attribute has no effect on variadic functions, and all parameters +are passed via the stack as normal. + }]; +} + +def SysVABIDocs : Documentation { + let Category = DocCatCallingConvs; + let Content = [{ +On Windows x86_64 targets, this attribute changes the calling convention of a +function to match the default convention used on Sys V targets such as Linux, +Mac, and BSD. This attribute has no effect on other targets. + }]; +} + +def MSABIDocs : Documentation { + let Category = DocCatCallingConvs; + let Content = [{ +On non-Windows x86_64 targets, this attribute changes the calling convention of +a function to match the default convention used on Windows x86_64. This +attribute has no effect on Windows targets or non-x86_64 targets. + }]; +} + +def StdCallDocs : Documentation { + let Category = DocCatCallingConvs; + let Content = [{ +On 32-bit x86 targets, this attribute changes the calling convention of a +function to clear parameters off of the stack on return. This convention does +not support variadic calls or unprototyped functions in C, and has no effect on +x86_64 targets. This calling convention is used widely by the Windows API and +COM applications. See the documentation for `__stdcall`_ on MSDN. + +.. _`__stdcall`: http://msdn.microsoft.com/en-us/library/zxk0tw93.aspx + }]; +} + +def FastCallDocs : Documentation { + let Category = DocCatCallingConvs; + let Content = [{ +On 32-bit x86 targets, this attribute changes the calling convention of a +function to use ECX and EDX as register parameters and clear parameters off of +the stack on return. This convention does not support variadic calls or +unprototyped functions in C, and has no effect on x86_64 targets. This calling +convention is supported primarily for compatibility with existing code. Users +seeking register parameters should use the ``regparm`` attribute, which does +not require callee-cleanup. See the documentation for `__fastcall`_ on MSDN. + +.. _`__fastcall`: http://msdn.microsoft.com/en-us/library/6xa169sk.aspx + }]; +} + +def ThisCallDocs : Documentation { + let Category = DocCatCallingConvs; + let Content = [{ +On 32-bit x86 targets, this attribute changes the calling convention of a +function to use ECX for the first parameter (typically the implicit ``this`` +parameter of C++ methods) and clear parameters off of the stack on return. This +convention does not support variadic calls or unprototyped functions in C, and +has no effect on x86_64 targets. See the documentation for `__thiscall`_ on +MSDN. + +.. _`__thiscall`: http://msdn.microsoft.com/en-us/library/ek8tkfbw.aspx + }]; +} + +def VectorCallDocs : Documentation { + let Category = DocCatCallingConvs; + let Content = [{ +On 32-bit x86 *and* x86_64 targets, this attribute changes the calling +convention of a function to pass vector parameters in SSE registers. + +On 32-bit x86 targets, this calling convention is similar to ``__fastcall``. +The first two integer parameters are passed in ECX and EDX. Subsequent integer +parameters are passed in memory, and callee clears the stack. On x86_64 +targets, the callee does *not* clear the stack, and integer parameters are +passed in RCX, RDX, R8, and R9 as is done for the default Windows x64 calling +convention. + +On both 32-bit x86 and x86_64 targets, vector and floating point arguments are +passed in XMM0-XMM5. Homogenous vector aggregates of up to four elements are +passed in sequential SSE registers if enough are available. If AVX is enabled, +256 bit vectors are passed in YMM0-YMM5. Any vector or aggregate type that +cannot be passed in registers for any reason is passed by reference, which +allows the caller to align the parameter memory. + +See the documentation for `__vectorcall`_ on MSDN for more details. + +.. _`__vectorcall`: http://msdn.microsoft.com/en-us/library/dn375768.aspx + }]; +} + +def DocCatConsumed : DocumentationCategory<"Consumed Annotation Checking"> { + let Content = [{ +Clang supports additional attributes for checking basic resource management +properties, specifically for unique objects that have a single owning reference. +The following attributes are currently supported, although **the implementation +for these annotations is currently in development and are subject to change.** + }]; +} + +def SetTypestateDocs : Documentation { + let Category = DocCatConsumed; + let Content = [{ +Annotate methods that transition an object into a new state with +``__attribute__((set_typestate(new_state)))``. The new state must be +unconsumed, consumed, or unknown. + }]; +} + +def CallableWhenDocs : Documentation { + let Category = DocCatConsumed; + let Content = [{ +Use ``__attribute__((callable_when(...)))`` to indicate what states a method +may be called in. Valid states are unconsumed, consumed, or unknown. Each +argument to this attribute must be a quoted string. E.g.: + +``__attribute__((callable_when("unconsumed", "unknown")))`` + }]; +} + +def TestTypestateDocs : Documentation { + let Category = DocCatConsumed; + let Content = [{ +Use ``__attribute__((test_typestate(tested_state)))`` to indicate that a method +returns true if the object is in the specified state.. + }]; +} + +def ParamTypestateDocs : Documentation { + let Category = DocCatConsumed; + let Content = [{ +This attribute specifies expectations about function parameters. Calls to an +function with annotated parameters will issue a warning if the corresponding +argument isn't in the expected state. The attribute is also used to set the +initial state of the parameter when analyzing the function's body. + }]; +} + +def ReturnTypestateDocs : Documentation { + let Category = DocCatConsumed; + let Content = [{ +The ``return_typestate`` attribute can be applied to functions or parameters. +When applied to a function the attribute specifies the state of the returned +value. The function's body is checked to ensure that it always returns a value +in the specified state. On the caller side, values returned by the annotated +function are initialized to the given state. + +When applied to a function parameter it modifies the state of an argument after +a call to the function returns. The function's body is checked to ensure that +the parameter is in the expected state before returning. + }]; +} + +def ConsumableDocs : Documentation { + let Category = DocCatConsumed; + let Content = [{ +Each ``class`` that uses any of the typestate annotations must first be marked +using the ``consumable`` attribute. Failure to do so will result in a warning. + +This attribute accepts a single parameter that must be one of the following: +``unknown``, ``consumed``, or ``unconsumed``. + }]; +} + +def NoSanitizeDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Use the ``no_sanitize`` attribute on a function declaration to specify +that a particular instrumentation or set of instrumentations should not be +applied to that function. The attribute takes a list of string literals, +which have the same meaning as values accepted by the ``-fno-sanitize=`` +flag. For example, ``__attribute__((no_sanitize("address", "thread")))`` +specifies that AddressSanitizer and ThreadSanitizer should not be applied +to the function. + +See :ref:`Controlling Code Generation <controlling-code-generation>` for a +full list of supported sanitizer flags. + }]; +} + +def NoSanitizeAddressDocs : Documentation { + let Category = DocCatFunction; + // This function has multiple distinct spellings, and so it requires a custom + // heading to be specified. The most common spelling is sufficient. + let Heading = "no_sanitize_address (no_address_safety_analysis, gnu::no_address_safety_analysis, gnu::no_sanitize_address)"; + let Content = [{ +.. _langext-address_sanitizer: + +Use ``__attribute__((no_sanitize_address))`` on a function declaration to +specify that address safety instrumentation (e.g. AddressSanitizer) should +not be applied to that function. + }]; +} + +def NoSanitizeThreadDocs : Documentation { + let Category = DocCatFunction; + let Heading = "no_sanitize_thread"; + let Content = [{ +.. _langext-thread_sanitizer: + +Use ``__attribute__((no_sanitize_thread))`` on a function declaration to +specify that checks for data races on plain (non-atomic) memory accesses should +not be inserted by ThreadSanitizer. The function is still instrumented by the +tool to avoid false positives and provide meaningful stack traces. + }]; +} + +def NoSanitizeMemoryDocs : Documentation { + let Category = DocCatFunction; + let Heading = "no_sanitize_memory"; + let Content = [{ +.. _langext-memory_sanitizer: + +Use ``__attribute__((no_sanitize_memory))`` on a function declaration to +specify that checks for uninitialized memory should not be inserted +(e.g. by MemorySanitizer). The function may still be instrumented by the tool +to avoid false positives in other places. + }]; +} + +def DocCatTypeSafety : DocumentationCategory<"Type Safety Checking"> { + let Content = [{ +Clang supports additional attributes to enable checking type safety properties +that can't be enforced by the C type system. Use cases include: + +* MPI library implementations, where these attributes enable checking that + the buffer type matches the passed ``MPI_Datatype``; +* for HDF5 library there is a similar use case to MPI; +* checking types of variadic functions' arguments for functions like + ``fcntl()`` and ``ioctl()``. + +You can detect support for these attributes with ``__has_attribute()``. For +example: + +.. code-block:: c++ + + #if defined(__has_attribute) + # if __has_attribute(argument_with_type_tag) && \ + __has_attribute(pointer_with_type_tag) && \ + __has_attribute(type_tag_for_datatype) + # define ATTR_MPI_PWT(buffer_idx, type_idx) __attribute__((pointer_with_type_tag(mpi,buffer_idx,type_idx))) + /* ... other macros ... */ + # endif + #endif + + #if !defined(ATTR_MPI_PWT) + # define ATTR_MPI_PWT(buffer_idx, type_idx) + #endif + + int MPI_Send(void *buf, int count, MPI_Datatype datatype /*, other args omitted */) + ATTR_MPI_PWT(1,3); + }]; +} + +def ArgumentWithTypeTagDocs : Documentation { + let Category = DocCatTypeSafety; + let Heading = "argument_with_type_tag"; + let Content = [{ +Use ``__attribute__((argument_with_type_tag(arg_kind, arg_idx, +type_tag_idx)))`` on a function declaration to specify that the function +accepts a type tag that determines the type of some other argument. +``arg_kind`` is an identifier that should be used when annotating all +applicable type tags. + +This attribute is primarily useful for checking arguments of variadic functions +(``pointer_with_type_tag`` can be used in most non-variadic cases). + +For example: + +.. code-block:: c++ + + int fcntl(int fd, int cmd, ...) + __attribute__(( argument_with_type_tag(fcntl,3,2) )); + }]; +} + +def PointerWithTypeTagDocs : Documentation { + let Category = DocCatTypeSafety; + let Heading = "pointer_with_type_tag"; + let Content = [{ +Use ``__attribute__((pointer_with_type_tag(ptr_kind, ptr_idx, type_tag_idx)))`` +on a function declaration to specify that the function accepts a type tag that +determines the pointee type of some other pointer argument. + +For example: + +.. code-block:: c++ + + int MPI_Send(void *buf, int count, MPI_Datatype datatype /*, other args omitted */) + __attribute__(( pointer_with_type_tag(mpi,1,3) )); + }]; +} + +def TypeTagForDatatypeDocs : Documentation { + let Category = DocCatTypeSafety; + let Content = [{ +Clang supports annotating type tags of two forms. + +* **Type tag that is an expression containing a reference to some declared + identifier.** Use ``__attribute__((type_tag_for_datatype(kind, type)))`` on a + declaration with that identifier: + + .. code-block:: c++ + + extern struct mpi_datatype mpi_datatype_int + __attribute__(( type_tag_for_datatype(mpi,int) )); + #define MPI_INT ((MPI_Datatype) &mpi_datatype_int) + +* **Type tag that is an integral literal.** Introduce a ``static const`` + variable with a corresponding initializer value and attach + ``__attribute__((type_tag_for_datatype(kind, type)))`` on that declaration, + for example: + + .. code-block:: c++ + + #define MPI_INT ((MPI_Datatype) 42) + static const MPI_Datatype mpi_datatype_int + __attribute__(( type_tag_for_datatype(mpi,int) )) = 42 + +The attribute also accepts an optional third argument that determines how the +expression is compared to the type tag. There are two supported flags: + +* ``layout_compatible`` will cause types to be compared according to + layout-compatibility rules (C++11 [class.mem] p 17, 18). This is + implemented to support annotating types like ``MPI_DOUBLE_INT``. + + For example: + + .. code-block:: c++ + + /* In mpi.h */ + struct internal_mpi_double_int { double d; int i; }; + extern struct mpi_datatype mpi_datatype_double_int + __attribute__(( type_tag_for_datatype(mpi, struct internal_mpi_double_int, layout_compatible) )); + + #define MPI_DOUBLE_INT ((MPI_Datatype) &mpi_datatype_double_int) + + /* In user code */ + struct my_pair { double a; int b; }; + struct my_pair *buffer; + MPI_Send(buffer, 1, MPI_DOUBLE_INT /*, ... */); // no warning + + struct my_int_pair { int a; int b; } + struct my_int_pair *buffer2; + MPI_Send(buffer2, 1, MPI_DOUBLE_INT /*, ... */); // warning: actual buffer element + // type 'struct my_int_pair' + // doesn't match specified MPI_Datatype + +* ``must_be_null`` specifies that the expression should be a null pointer + constant, for example: + + .. code-block:: c++ + + /* In mpi.h */ + extern struct mpi_datatype mpi_datatype_null + __attribute__(( type_tag_for_datatype(mpi, void, must_be_null) )); + + #define MPI_DATATYPE_NULL ((MPI_Datatype) &mpi_datatype_null) + + /* In user code */ + MPI_Send(buffer, 1, MPI_DATATYPE_NULL /*, ... */); // warning: MPI_DATATYPE_NULL + // was specified but buffer + // is not a null pointer + }]; +} + +def FlattenDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The ``flatten`` attribute causes calls within the attributed function to +be inlined unless it is impossible to do so, for example if the body of the +callee is unavailable or if the callee has the ``noinline`` attribute. + }]; +} + +def FormatDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ + +Clang supports the ``format`` attribute, which indicates that the function +accepts a ``printf`` or ``scanf``-like format string and corresponding +arguments or a ``va_list`` that contains these arguments. + +Please see `GCC documentation about format attribute +<http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html>`_ to find details +about attribute syntax. + +Clang implements two kinds of checks with this attribute. + +#. Clang checks that the function with the ``format`` attribute is called with + a format string that uses format specifiers that are allowed, and that + arguments match the format string. This is the ``-Wformat`` warning, it is + on by default. + +#. Clang checks that the format string argument is a literal string. This is + the ``-Wformat-nonliteral`` warning, it is off by default. + + Clang implements this mostly the same way as GCC, but there is a difference + for functions that accept a ``va_list`` argument (for example, ``vprintf``). + GCC does not emit ``-Wformat-nonliteral`` warning for calls to such + functions. Clang does not warn if the format string comes from a function + parameter, where the function is annotated with a compatible attribute, + otherwise it warns. For example: + + .. code-block:: c + + __attribute__((__format__ (__scanf__, 1, 3))) + void foo(const char* s, char *buf, ...) { + va_list ap; + va_start(ap, buf); + + vprintf(s, ap); // warning: format string is not a string literal + } + + In this case we warn because ``s`` contains a format string for a + ``scanf``-like function, but it is passed to a ``printf``-like function. + + If the attribute is removed, clang still warns, because the format string is + not a string literal. + + Another example: + + .. code-block:: c + + __attribute__((__format__ (__printf__, 1, 3))) + void foo(const char* s, char *buf, ...) { + va_list ap; + va_start(ap, buf); + + vprintf(s, ap); // warning + } + + In this case Clang does not warn because the format string ``s`` and + the corresponding arguments are annotated. If the arguments are + incorrect, the caller of ``foo`` will receive a warning. + }]; +} + +def AlignValueDocs : Documentation { + let Category = DocCatType; + let Content = [{ +The align_value attribute can be added to the typedef of a pointer type or the +declaration of a variable of pointer or reference type. It specifies that the +pointer will point to, or the reference will bind to, only objects with at +least the provided alignment. This alignment value must be some positive power +of 2. + + .. code-block:: c + + typedef double * aligned_double_ptr __attribute__((align_value(64))); + void foo(double & x __attribute__((align_value(128)), + aligned_double_ptr y) { ... } + +If the pointer value does not have the specified alignment at runtime, the +behavior of the program is undefined. + }]; +} + +def FlagEnumDocs : Documentation { + let Category = DocCatType; + let Content = [{ +This attribute can be added to an enumerator to signal to the compiler that it +is intended to be used as a flag type. This will cause the compiler to assume +that the range of the type includes all of the values that you can get by +manipulating bits of the enumerator when issuing warnings. + }]; +} + +def MSInheritanceDocs : Documentation { + let Category = DocCatType; + let Heading = "__single_inhertiance, __multiple_inheritance, __virtual_inheritance"; + let Content = [{ +This collection of keywords is enabled under ``-fms-extensions`` and controls +the pointer-to-member representation used on ``*-*-win32`` targets. + +The ``*-*-win32`` targets utilize a pointer-to-member representation which +varies in size and alignment depending on the definition of the underlying +class. + +However, this is problematic when a forward declaration is only available and +no definition has been made yet. In such cases, Clang is forced to utilize the +most general representation that is available to it. + +These keywords make it possible to use a pointer-to-member representation other +than the most general one regardless of whether or not the definition will ever +be present in the current translation unit. + +This family of keywords belong between the ``class-key`` and ``class-name``: + +.. code-block:: c++ + + struct __single_inheritance S; + int S::*i; + struct S {}; + +This keyword can be applied to class templates but only has an effect when used +on full specializations: + +.. code-block:: c++ + + template <typename T, typename U> struct __single_inheritance A; // warning: inheritance model ignored on primary template + template <typename T> struct __multiple_inheritance A<T, T>; // warning: inheritance model ignored on partial specialization + template <> struct __single_inheritance A<int, float>; + +Note that choosing an inheritance model less general than strictly necessary is +an error: + +.. code-block:: c++ + + struct __multiple_inheritance S; // error: inheritance model does not match definition + int S::*i; + struct S {}; +}]; +} + +def MSNoVTableDocs : Documentation { + let Category = DocCatType; + let Content = [{ +This attribute can be added to a class declaration or definition to signal to +the compiler that constructors and destructors will not reference the virtual +function table. It is only supported when using the Microsoft C++ ABI. + }]; +} + +def OptnoneDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The ``optnone`` attribute suppresses essentially all optimizations +on a function or method, regardless of the optimization level applied to +the compilation unit as a whole. This is particularly useful when you +need to debug a particular function, but it is infeasible to build the +entire application without optimization. Avoiding optimization on the +specified function can improve the quality of the debugging information +for that function. + +This attribute is incompatible with the ``always_inline`` and ``minsize`` +attributes. + }]; +} + +def LoopHintDocs : Documentation { + let Category = DocCatStmt; + let Heading = "#pragma clang loop"; + let Content = [{ +The ``#pragma clang loop`` directive allows loop optimization hints to be +specified for the subsequent loop. The directive allows vectorization, +interleaving, and unrolling to be enabled or disabled. Vector width as well +as interleave and unrolling count can be manually specified. See +`language extensions +<http://clang.llvm.org/docs/LanguageExtensions.html#extensions-for-loop-hint-optimizations>`_ +for details. + }]; +} + +def UnrollHintDocs : Documentation { + let Category = DocCatStmt; + let Heading = "#pragma unroll, #pragma nounroll"; + let Content = [{ +Loop unrolling optimization hints can be specified with ``#pragma unroll`` and +``#pragma nounroll``. The pragma is placed immediately before a for, while, +do-while, or c++11 range-based for loop. + +Specifying ``#pragma unroll`` without a parameter directs the loop unroller to +attempt to fully unroll the loop if the trip count is known at compile time and +attempt to partially unroll the loop if the trip count is not known at compile +time: + +.. code-block:: c++ + + #pragma unroll + for (...) { + ... + } + +Specifying the optional parameter, ``#pragma unroll _value_``, directs the +unroller to unroll the loop ``_value_`` times. The parameter may optionally be +enclosed in parentheses: + +.. code-block:: c++ + + #pragma unroll 16 + for (...) { + ... + } + + #pragma unroll(16) + for (...) { + ... + } + +Specifying ``#pragma nounroll`` indicates that the loop should not be unrolled: + +.. code-block:: c++ + + #pragma nounroll + for (...) { + ... + } + +``#pragma unroll`` and ``#pragma unroll _value_`` have identical semantics to +``#pragma clang loop unroll(full)`` and +``#pragma clang loop unroll_count(_value_)`` respectively. ``#pragma nounroll`` +is equivalent to ``#pragma clang loop unroll(disable)``. See +`language extensions +<http://clang.llvm.org/docs/LanguageExtensions.html#extensions-for-loop-hint-optimizations>`_ +for further details including limitations of the unroll hints. + }]; +} + +def DocOpenCLAddressSpaces : DocumentationCategory<"OpenCL Address Spaces"> { + let Content = [{ +The address space qualifier may be used to specify the region of memory that is +used to allocate the object. OpenCL supports the following address spaces: +__generic(generic), __global(global), __local(local), __private(private), +__constant(constant). + + .. code-block:: c + + __constant int c = ...; + + __generic int* foo(global int* g) { + __local int* l; + private int p; + ... + return l; + } + +More details can be found in the OpenCL C language Spec v2.0, Section 6.5. + }]; +} + +def OpenCLAddressSpaceGenericDocs : Documentation { + let Category = DocOpenCLAddressSpaces; + let Content = [{ +The generic address space attribute is only available with OpenCL v2.0 and later. +It can be used with pointer types. Variables in global and local scope and +function parameters in non-kernel functions can have the generic address space +type attribute. It is intended to be a placeholder for any other address space +except for '__constant' in OpenCL code which can be used with multiple address +spaces. + }]; +} + +def OpenCLAddressSpaceConstantDocs : Documentation { + let Category = DocOpenCLAddressSpaces; + let Content = [{ +The constant address space attribute signals that an object is located in +a constant (non-modifiable) memory region. It is available to all work items. +Any type can be annotated with the constant address space attribute. Objects +with the constant address space qualifier can be declared in any scope and must +have an initializer. + }]; +} + +def OpenCLAddressSpaceGlobalDocs : Documentation { + let Category = DocOpenCLAddressSpaces; + let Content = [{ +The global address space attribute specifies that an object is allocated in +global memory, which is accessible by all work items. The content stored in this +memory area persists between kernel executions. Pointer types to the global +address space are allowed as function parameters or local variables. Starting +with OpenCL v2.0, the global address space can be used with global (program +scope) variables and static local variable as well. + }]; +} + +def OpenCLAddressSpaceLocalDocs : Documentation { + let Category = DocOpenCLAddressSpaces; + let Content = [{ +The local address space specifies that an object is allocated in the local (work +group) memory area, which is accessible to all work items in the same work +group. The content stored in this memory region is not accessible after +the kernel execution ends. In a kernel function scope, any variable can be in +the local address space. In other scopes, only pointer types to the local address +space are allowed. Local address space variables cannot have an initializer. + }]; +} + +def OpenCLAddressSpacePrivateDocs : Documentation { + let Category = DocOpenCLAddressSpaces; + let Content = [{ +The private address space specifies that an object is allocated in the private +(work item) memory. Other work items cannot access the same memory area and its +content is destroyed after work item execution ends. Local variables can be +declared in the private address space. Function arguments are always in the +private address space. Kernel function arguments of a pointer or an array type +cannot point to the private address space. + }]; +} + +def NullabilityDocs : DocumentationCategory<"Nullability Attributes"> { + let Content = [{ +Whether a particular pointer may be "null" is an important concern when working with pointers in the C family of languages. The various nullability attributes indicate whether a particular pointer can be null or not, which makes APIs more expressive and can help static analysis tools identify bugs involving null pointers. Clang supports several kinds of nullability attributes: the ``nonnull`` and ``returns_nonnull`` attributes indicate which function or method parameters and result types can never be null, while nullability type qualifiers indicate which pointer types can be null (``_Nullable``) or cannot be null (``_Nonnull``). + +The nullability (type) qualifiers express whether a value of a given pointer type can be null (the ``_Nullable`` qualifier), doesn't have a defined meaning for null (the ``_Nonnull`` qualifier), or for which the purpose of null is unclear (the ``_Null_unspecified`` qualifier). Because nullability qualifiers are expressed within the type system, they are more general than the ``nonnull`` and ``returns_nonnull`` attributes, allowing one to express (for example) a nullable pointer to an array of nonnull pointers. Nullability qualifiers are written to the right of the pointer to which they apply. For example: + + .. code-block:: c + + // No meaningful result when 'ptr' is null (here, it happens to be undefined behavior). + int fetch(int * _Nonnull ptr) { return *ptr; } + + // 'ptr' may be null. + int fetch_or_zero(int * _Nullable ptr) { + return ptr ? *ptr : 0; + } + + // A nullable pointer to non-null pointers to const characters. + const char *join_strings(const char * _Nonnull * _Nullable strings, unsigned n); + +In Objective-C, there is an alternate spelling for the nullability qualifiers that can be used in Objective-C methods and properties using context-sensitive, non-underscored keywords. For example: + + .. code-block:: objective-c + + @interface NSView : NSResponder + - (nullable NSView *)ancestorSharedWithView:(nonnull NSView *)aView; + @property (assign, nullable) NSView *superview; + @property (readonly, nonnull) NSArray *subviews; + @end + }]; +} + +def TypeNonNullDocs : Documentation { + let Category = NullabilityDocs; + let Content = [{ +The ``_Nonnull`` nullability qualifier indicates that null is not a meaningful value for a value of the ``_Nonnull`` pointer type. For example, given a declaration such as: + + .. code-block:: c + + int fetch(int * _Nonnull ptr); + +a caller of ``fetch`` should not provide a null value, and the compiler will produce a warning if it sees a literal null value passed to ``fetch``. Note that, unlike the declaration attribute ``nonnull``, the presence of ``_Nonnull`` does not imply that passing null is undefined behavior: ``fetch`` is free to consider null undefined behavior or (perhaps for backward-compatibility reasons) defensively handle null. + }]; +} + +def TypeNullableDocs : Documentation { + let Category = NullabilityDocs; + let Content = [{ +The ``_Nullable`` nullability qualifier indicates that a value of the ``_Nullable`` pointer type can be null. For example, given: + + .. code-block:: c + + int fetch_or_zero(int * _Nullable ptr); + +a caller of ``fetch_or_zero`` can provide null. + }]; +} + +def TypeNullUnspecifiedDocs : Documentation { + let Category = NullabilityDocs; + let Content = [{ +The ``_Null_unspecified`` nullability qualifier indicates that neither the ``_Nonnull`` nor ``_Nullable`` qualifiers make sense for a particular pointer type. It is used primarily to indicate that the role of null with specific pointers in a nullability-annotated header is unclear, e.g., due to overly-complex implementations or historical factors with a long-lived API. + }]; +} + +def NonNullDocs : Documentation { + let Category = NullabilityDocs; + let Content = [{ +The ``nonnull`` attribute indicates that some function parameters must not be null, and can be used in several different ways. It's original usage (`from GCC <https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes>`_) is as a function (or Objective-C method) attribute that specifies which parameters of the function are nonnull in a comma-separated list. For example: + + .. code-block:: c + + extern void * my_memcpy (void *dest, const void *src, size_t len) + __attribute__((nonnull (1, 2))); + +Here, the ``nonnull`` attribute indicates that parameters 1 and 2 +cannot have a null value. Omitting the parenthesized list of parameter indices means that all parameters of pointer type cannot be null: + + .. code-block:: c + + extern void * my_memcpy (void *dest, const void *src, size_t len) + __attribute__((nonnull)); + +Clang also allows the ``nonnull`` attribute to be placed directly on a function (or Objective-C method) parameter, eliminating the need to specify the parameter index ahead of type. For example: + + .. code-block:: c + + extern void * my_memcpy (void *dest __attribute__((nonnull)), + const void *src __attribute__((nonnull)), size_t len); + +Note that the ``nonnull`` attribute indicates that passing null to a non-null parameter is undefined behavior, which the optimizer may take advantage of to, e.g., remove null checks. The ``_Nonnull`` type qualifier indicates that a pointer cannot be null in a more general manner (because it is part of the type system) and does not imply undefined behavior, making it more widely applicable. + }]; +} + +def ReturnsNonNullDocs : Documentation { + let Category = NullabilityDocs; + let Content = [{ +The ``returns_nonnull`` attribute indicates that a particular function (or Objective-C method) always returns a non-null pointer. For example, a particular system ``malloc`` might be defined to terminate a process when memory is not available rather than returning a null pointer: + + .. code-block:: c + + extern void * malloc (size_t size) __attribute__((returns_nonnull)); + +The ``returns_nonnull`` attribute implies that returning a null pointer is undefined behavior, which the optimizer may take advantage of. The ``_Nonnull`` type qualifier indicates that a pointer cannot be null in a more general manner (because it is part of the type system) and does not imply undefined behavior, making it more widely applicable +}]; +} + +def NoAliasDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The ``noalias`` attribute indicates that the only memory accesses inside +function are loads and stores from objects pointed to by its pointer-typed +arguments, with arbitrary offsets. + }]; +} + +def NotTailCalledDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The ``not_tail_called`` attribute prevents tail-call optimization on statically bound calls. It has no effect on indirect calls. Virtual functions, objective-c methods, and functions marked as ``always_inline`` cannot be marked as ``not_tail_called``. + +For example, it prevents tail-call optimization in the following case: + + .. code-block: c + + int __attribute__((not_tail_called)) foo1(int); + + int foo2(int a) { + return foo1(a); // No tail-call optimization on direct calls. + } + +However, it doesn't prevent tail-call optimization in this case: + + .. code-block: c + + int __attribute__((not_tail_called)) foo1(int); + + int foo2(int a) { + int (*fn)(int) = &foo1; + + // not_tail_called has no effect on an indirect call even if the call can be + // resolved at compile time. + return (*fn)(a); + } + +Marking virtual functions as ``not_tail_called`` is an error: + + .. code-block: c++ + + class Base { + public: + // not_tail_called on a virtual function is an error. + [[clang::not_tail_called]] virtual int foo1(); + + virtual int foo2(); + + // Non-virtual functions can be marked ``not_tail_called``. + [[clang::not_tail_called]] int foo3(); + }; + + class Derived1 : public Base { + public: + int foo1() override; + + // not_tail_called on a virtual function is an error. + [[clang::not_tail_called]] int foo2() override; + }; + }]; +} + +def InternalLinkageDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The ``internal_linkage`` attribute changes the linkage type of the declaration to internal. +This is similar to C-style ``static``, but can be used on classes and class methods. When applied to a class definition, +this attribute affects all methods and static data members of that class. +This can be used to contain the ABI of a C++ library by excluding unwanted class methods from the export tables. + }]; +} + +def DisableTailCallsDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The ``disable_tail_calls`` attribute instructs the backend to not perform tail call optimization inside the marked function. + +For example: + + .. code-block:: c + + int callee(int); + + int foo(int a) __attribute__((disable_tail_calls)) { + return callee(a); // This call is not tail-call optimized. + } + +Marking virtual functions as ``disable_tail_calls`` is legal. + + .. code-block: c++ + + int callee(int); + + class Base { + public: + [[clang::disable_tail_calls]] virtual int foo1() { + return callee(); // This call is not tail-call optimized. + } + }; + + class Derived1 : public Base { + public: + int foo1() override { + return callee(); // This call is tail-call optimized. + } + }; + + }]; +} diff --git a/contrib/llvm/tools/clang/include/clang/Basic/AttrKinds.h b/contrib/llvm/tools/clang/include/clang/Basic/AttrKinds.h new file mode 100644 index 0000000..f0b0a64 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/AttrKinds.h @@ -0,0 +1,34 @@ +//===----- Attr.h - Enum values for C Attribute Kinds ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the clang::attr::Kind enum. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_ATTRKINDS_H +#define LLVM_CLANG_BASIC_ATTRKINDS_H + +namespace clang { + +namespace attr { + +// \brief A list of all the recognized kinds of attributes. +enum Kind { +#define ATTR(X) X, +#define LAST_INHERITABLE_ATTR(X) X, LAST_INHERITABLE = X, +#define LAST_INHERITABLE_PARAM_ATTR(X) X, LAST_INHERITABLE_PARAM = X, +#include "clang/Basic/AttrList.inc" + NUM_ATTRS +}; + +} // end namespace attr +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Attributes.h b/contrib/llvm/tools/clang/include/clang/Basic/Attributes.h new file mode 100644 index 0000000..a2b8684 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/Attributes.h @@ -0,0 +1,39 @@ +//===--- Attributes.h - Attributes header -----------------------*- 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_BASIC_ATTRIBUTES_H +#define LLVM_CLANG_BASIC_ATTRIBUTES_H + +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/TargetInfo.h" + +namespace clang { + +class IdentifierInfo; + +enum class AttrSyntax { + /// Is the identifier known as a GNU-style attribute? + GNU, + /// Is the identifier known as a __declspec-style attribute? + Declspec, + // Is the identifier known as a C++-style attribute? + CXX, + // Is the identifier known as a pragma attribute? + Pragma +}; + +/// \brief Return the version number associated with the attribute if we +/// recognize and implement the attribute specified by the given information. +int hasAttribute(AttrSyntax Syntax, const IdentifierInfo *Scope, + const IdentifierInfo *Attr, const TargetInfo &Target, + const LangOptions &LangOpts); + +} // end namespace clang + +#endif // LLVM_CLANG_BASIC_ATTRIBUTES_H diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Builtins.def b/contrib/llvm/tools/clang/include/clang/Basic/Builtins.def new file mode 100644 index 0000000..4f474eb --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/Builtins.def @@ -0,0 +1,1257 @@ +//===--- Builtins.def - Builtin function info database ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the standard builtin function database. Users of this file +// must define the BUILTIN macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +// FIXME: This should really be a .td file, but that requires modifying tblgen. +// Perhaps tblgen should have plugins. + +// The first value provided to the macro specifies the function name of the +// builtin, and results in a clang::builtin::BIXX enum value for XX. + +// The second value provided to the macro specifies the type of the function +// (result value, then each argument) as follows: +// v -> void +// b -> boolean +// c -> char +// s -> short +// i -> int +// h -> half +// f -> float +// d -> double +// z -> size_t +// F -> constant CFString +// G -> id +// H -> SEL +// M -> struct objc_super +// a -> __builtin_va_list +// A -> "reference" to __builtin_va_list +// V -> Vector, followed by the number of elements and the base type. +// E -> ext_vector, followed by the number of elements and the base type. +// X -> _Complex, followed by the base type. +// Y -> ptrdiff_t +// P -> FILE +// J -> jmp_buf +// SJ -> sigjmp_buf +// K -> ucontext_t +// p -> pid_t +// . -> "...". This may only occur at the end of the function list. +// +// Types may be prefixed with the following modifiers: +// L -> long (e.g. Li for 'long int') +// LL -> long long +// LLL -> __int128_t (e.g. LLLi) +// W -> int64_t +// S -> signed +// U -> unsigned +// I -> Required to constant fold to an integer constant expression. +// +// Types may be postfixed with the following modifiers: +// * -> pointer (optionally followed by an address space number, if no address +// space is specified than any address space will be accepted) +// & -> reference (optionally followed by an address space number) +// C -> const +// D -> volatile + +// The third value provided to the macro specifies information about attributes +// of the function. These must be kept in sync with the predicates in the +// Builtin::Context class. Currently we have: +// n -> nothrow +// r -> noreturn +// c -> const +// t -> signature is meaningless, use custom typechecking +// F -> this is a libc/libm function with a '__builtin_' prefix added. +// f -> this is a libc/libm function without the '__builtin_' prefix. It can +// be followed by ':headername:' to state which header this function +// comes from. +// i -> this is a runtime library implemented function without the +// '__builtin_' prefix. It will be implemented in compiler-rt or libgcc. +// p:N: -> this is a printf-like function whose Nth argument is the format +// string. +// P:N: -> similar to the p:N: attribute, but the function is like vprintf +// in that it accepts its arguments as a va_list rather than +// through an ellipsis +// s:N: -> this is a scanf-like function whose Nth argument is the format +// string. +// S:N: -> similar to the s:N: attribute, but the function is like vscanf +// in that it accepts its arguments as a va_list rather than +// through an ellipsis +// e -> const, but only when -fmath-errno=0 +// j -> returns_twice (like setjmp) +// u -> arguments are not evaluated for their side-effects +// FIXME: gcc has nonnull + +#if defined(BUILTIN) && !defined(LIBBUILTIN) +# define LIBBUILTIN(ID, TYPE, ATTRS, HEADER, BUILTIN_LANG) BUILTIN(ID, TYPE, ATTRS) +#endif + +#if defined(BUILTIN) && !defined(LANGBUILTIN) +# define LANGBUILTIN(ID, TYPE, ATTRS, BUILTIN_LANG) BUILTIN(ID, TYPE, ATTRS) +#endif + +// Standard libc/libm functions: +BUILTIN(__builtin_atan2 , "ddd" , "Fnc") +BUILTIN(__builtin_atan2f, "fff" , "Fnc") +BUILTIN(__builtin_atan2l, "LdLdLd", "Fnc") +BUILTIN(__builtin_abs , "ii" , "ncF") +BUILTIN(__builtin_copysign, "ddd", "ncF") +BUILTIN(__builtin_copysignf, "fff", "ncF") +BUILTIN(__builtin_copysignl, "LdLdLd", "ncF") +BUILTIN(__builtin_fabs , "dd" , "ncF") +BUILTIN(__builtin_fabsf, "ff" , "ncF") +BUILTIN(__builtin_fabsl, "LdLd", "ncF") +BUILTIN(__builtin_fmod , "ddd" , "Fnc") +BUILTIN(__builtin_fmodf, "fff" , "Fnc") +BUILTIN(__builtin_fmodl, "LdLdLd", "Fnc") +BUILTIN(__builtin_frexp , "ddi*" , "Fn") +BUILTIN(__builtin_frexpf, "ffi*" , "Fn") +BUILTIN(__builtin_frexpl, "LdLdi*", "Fn") +BUILTIN(__builtin_huge_val, "d", "nc") +BUILTIN(__builtin_huge_valf, "f", "nc") +BUILTIN(__builtin_huge_vall, "Ld", "nc") +BUILTIN(__builtin_inf , "d" , "nc") +BUILTIN(__builtin_inff , "f" , "nc") +BUILTIN(__builtin_infl , "Ld" , "nc") +BUILTIN(__builtin_labs , "LiLi" , "Fnc") +BUILTIN(__builtin_llabs, "LLiLLi", "Fnc") +BUILTIN(__builtin_ldexp , "ddi" , "Fnc") +BUILTIN(__builtin_ldexpf, "ffi" , "Fnc") +BUILTIN(__builtin_ldexpl, "LdLdi", "Fnc") +BUILTIN(__builtin_modf , "ddd*" , "Fn") +BUILTIN(__builtin_modff, "fff*" , "Fn") +BUILTIN(__builtin_modfl, "LdLdLd*", "Fn") +BUILTIN(__builtin_nan, "dcC*" , "ncF") +BUILTIN(__builtin_nanf, "fcC*" , "ncF") +BUILTIN(__builtin_nanl, "LdcC*", "ncF") +BUILTIN(__builtin_nans, "dcC*" , "ncF") +BUILTIN(__builtin_nansf, "fcC*" , "ncF") +BUILTIN(__builtin_nansl, "LdcC*", "ncF") +BUILTIN(__builtin_powi , "ddi" , "Fnc") +BUILTIN(__builtin_powif, "ffi" , "Fnc") +BUILTIN(__builtin_powil, "LdLdi", "Fnc") +BUILTIN(__builtin_pow , "ddd" , "Fnc") +BUILTIN(__builtin_powf, "fff" , "Fnc") +BUILTIN(__builtin_powl, "LdLdLd", "Fnc") + +// Standard unary libc/libm functions with double/float/long double variants: +BUILTIN(__builtin_acos , "dd" , "Fnc") +BUILTIN(__builtin_acosf, "ff" , "Fnc") +BUILTIN(__builtin_acosl, "LdLd", "Fnc") +BUILTIN(__builtin_acosh , "dd" , "Fnc") +BUILTIN(__builtin_acoshf, "ff" , "Fnc") +BUILTIN(__builtin_acoshl, "LdLd", "Fnc") +BUILTIN(__builtin_asin , "dd" , "Fnc") +BUILTIN(__builtin_asinf, "ff" , "Fnc") +BUILTIN(__builtin_asinl, "LdLd", "Fnc") +BUILTIN(__builtin_asinh , "dd" , "Fnc") +BUILTIN(__builtin_asinhf, "ff" , "Fnc") +BUILTIN(__builtin_asinhl, "LdLd", "Fnc") +BUILTIN(__builtin_atan , "dd" , "Fnc") +BUILTIN(__builtin_atanf, "ff" , "Fnc") +BUILTIN(__builtin_atanl, "LdLd", "Fnc") +BUILTIN(__builtin_atanh , "dd", "Fnc") +BUILTIN(__builtin_atanhf, "ff", "Fnc") +BUILTIN(__builtin_atanhl, "LdLd", "Fnc") +BUILTIN(__builtin_cbrt , "dd", "Fnc") +BUILTIN(__builtin_cbrtf, "ff", "Fnc") +BUILTIN(__builtin_cbrtl, "LdLd", "Fnc") +BUILTIN(__builtin_ceil , "dd" , "Fnc") +BUILTIN(__builtin_ceilf, "ff" , "Fnc") +BUILTIN(__builtin_ceill, "LdLd", "Fnc") +BUILTIN(__builtin_cos , "dd" , "Fnc") +BUILTIN(__builtin_cosf, "ff" , "Fnc") +BUILTIN(__builtin_cosh , "dd" , "Fnc") +BUILTIN(__builtin_coshf, "ff" , "Fnc") +BUILTIN(__builtin_coshl, "LdLd", "Fnc") +BUILTIN(__builtin_cosl, "LdLd", "Fnc") +BUILTIN(__builtin_erf , "dd", "Fnc") +BUILTIN(__builtin_erff, "ff", "Fnc") +BUILTIN(__builtin_erfl, "LdLd", "Fnc") +BUILTIN(__builtin_erfc , "dd", "Fnc") +BUILTIN(__builtin_erfcf, "ff", "Fnc") +BUILTIN(__builtin_erfcl, "LdLd", "Fnc") +BUILTIN(__builtin_exp , "dd" , "Fnc") +BUILTIN(__builtin_expf, "ff" , "Fnc") +BUILTIN(__builtin_expl, "LdLd", "Fnc") +BUILTIN(__builtin_exp2 , "dd" , "Fnc") +BUILTIN(__builtin_exp2f, "ff" , "Fnc") +BUILTIN(__builtin_exp2l, "LdLd", "Fnc") +BUILTIN(__builtin_expm1 , "dd", "Fnc") +BUILTIN(__builtin_expm1f, "ff", "Fnc") +BUILTIN(__builtin_expm1l, "LdLd", "Fnc") +BUILTIN(__builtin_fdim, "ddd", "Fnc") +BUILTIN(__builtin_fdimf, "fff", "Fnc") +BUILTIN(__builtin_fdiml, "LdLdLd", "Fnc") +BUILTIN(__builtin_floor , "dd" , "Fnc") +BUILTIN(__builtin_floorf, "ff" , "Fnc") +BUILTIN(__builtin_floorl, "LdLd", "Fnc") +BUILTIN(__builtin_fma, "dddd", "Fnc") +BUILTIN(__builtin_fmaf, "ffff", "Fnc") +BUILTIN(__builtin_fmal, "LdLdLdLd", "Fnc") +BUILTIN(__builtin_fmax, "ddd", "Fnc") +BUILTIN(__builtin_fmaxf, "fff", "Fnc") +BUILTIN(__builtin_fmaxl, "LdLdLd", "Fnc") +BUILTIN(__builtin_fmin, "ddd", "Fnc") +BUILTIN(__builtin_fminf, "fff", "Fnc") +BUILTIN(__builtin_fminl, "LdLdLd", "Fnc") +BUILTIN(__builtin_hypot , "ddd" , "Fnc") +BUILTIN(__builtin_hypotf, "fff" , "Fnc") +BUILTIN(__builtin_hypotl, "LdLdLd", "Fnc") +BUILTIN(__builtin_ilogb , "id", "Fnc") +BUILTIN(__builtin_ilogbf, "if", "Fnc") +BUILTIN(__builtin_ilogbl, "iLd", "Fnc") +BUILTIN(__builtin_lgamma , "dd", "Fnc") +BUILTIN(__builtin_lgammaf, "ff", "Fnc") +BUILTIN(__builtin_lgammal, "LdLd", "Fnc") +BUILTIN(__builtin_llrint, "LLid", "Fnc") +BUILTIN(__builtin_llrintf, "LLif", "Fnc") +BUILTIN(__builtin_llrintl, "LLiLd", "Fnc") +BUILTIN(__builtin_llround , "LLid", "Fnc") +BUILTIN(__builtin_llroundf, "LLif", "Fnc") +BUILTIN(__builtin_llroundl, "LLiLd", "Fnc") +BUILTIN(__builtin_log , "dd" , "Fnc") +BUILTIN(__builtin_log10 , "dd" , "Fnc") +BUILTIN(__builtin_log10f, "ff" , "Fnc") +BUILTIN(__builtin_log10l, "LdLd", "Fnc") +BUILTIN(__builtin_log1p , "dd" , "Fnc") +BUILTIN(__builtin_log1pf, "ff" , "Fnc") +BUILTIN(__builtin_log1pl, "LdLd", "Fnc") +BUILTIN(__builtin_log2, "dd" , "Fnc") +BUILTIN(__builtin_log2f, "ff" , "Fnc") +BUILTIN(__builtin_log2l, "LdLd" , "Fnc") +BUILTIN(__builtin_logb , "dd", "Fnc") +BUILTIN(__builtin_logbf, "ff", "Fnc") +BUILTIN(__builtin_logbl, "LdLd", "Fnc") +BUILTIN(__builtin_logf, "ff" , "Fnc") +BUILTIN(__builtin_logl, "LdLd", "Fnc") +BUILTIN(__builtin_lrint , "Lid", "Fnc") +BUILTIN(__builtin_lrintf, "Lif", "Fnc") +BUILTIN(__builtin_lrintl, "LiLd", "Fnc") +BUILTIN(__builtin_lround , "Lid", "Fnc") +BUILTIN(__builtin_lroundf, "Lif", "Fnc") +BUILTIN(__builtin_lroundl, "LiLd", "Fnc") +BUILTIN(__builtin_nearbyint , "dd", "Fnc") +BUILTIN(__builtin_nearbyintf, "ff", "Fnc") +BUILTIN(__builtin_nearbyintl, "LdLd", "Fnc") +BUILTIN(__builtin_nextafter , "ddd", "Fnc") +BUILTIN(__builtin_nextafterf, "fff", "Fnc") +BUILTIN(__builtin_nextafterl, "LdLdLd", "Fnc") +BUILTIN(__builtin_nexttoward , "ddLd", "Fnc") +BUILTIN(__builtin_nexttowardf, "ffLd", "Fnc") +BUILTIN(__builtin_nexttowardl, "LdLdLd", "Fnc") +BUILTIN(__builtin_remainder , "ddd", "Fnc") +BUILTIN(__builtin_remainderf, "fff", "Fnc") +BUILTIN(__builtin_remainderl, "LdLdLd", "Fnc") +BUILTIN(__builtin_remquo , "dddi*", "Fn") +BUILTIN(__builtin_remquof, "fffi*", "Fn") +BUILTIN(__builtin_remquol, "LdLdLdi*", "Fn") +BUILTIN(__builtin_rint , "dd", "Fnc") +BUILTIN(__builtin_rintf, "ff", "Fnc") +BUILTIN(__builtin_rintl, "LdLd", "Fnc") +BUILTIN(__builtin_round, "dd" , "Fnc") +BUILTIN(__builtin_roundf, "ff" , "Fnc") +BUILTIN(__builtin_roundl, "LdLd" , "Fnc") +BUILTIN(__builtin_scalbln , "ddLi", "Fnc") +BUILTIN(__builtin_scalblnf, "ffLi", "Fnc") +BUILTIN(__builtin_scalblnl, "LdLdLi", "Fnc") +BUILTIN(__builtin_scalbn , "ddi", "Fnc") +BUILTIN(__builtin_scalbnf, "ffi", "Fnc") +BUILTIN(__builtin_scalbnl, "LdLdi", "Fnc") +BUILTIN(__builtin_sin , "dd" , "Fnc") +BUILTIN(__builtin_sinf, "ff" , "Fnc") +BUILTIN(__builtin_sinh , "dd" , "Fnc") +BUILTIN(__builtin_sinhf, "ff" , "Fnc") +BUILTIN(__builtin_sinhl, "LdLd", "Fnc") +BUILTIN(__builtin_sinl, "LdLd", "Fnc") +BUILTIN(__builtin_sqrt , "dd" , "Fnc") +BUILTIN(__builtin_sqrtf, "ff" , "Fnc") +BUILTIN(__builtin_sqrtl, "LdLd", "Fnc") +BUILTIN(__builtin_tan , "dd" , "Fnc") +BUILTIN(__builtin_tanf, "ff" , "Fnc") +BUILTIN(__builtin_tanh , "dd" , "Fnc") +BUILTIN(__builtin_tanhf, "ff" , "Fnc") +BUILTIN(__builtin_tanhl, "LdLd", "Fnc") +BUILTIN(__builtin_tanl, "LdLd", "Fnc") +BUILTIN(__builtin_tgamma , "dd", "Fnc") +BUILTIN(__builtin_tgammaf, "ff", "Fnc") +BUILTIN(__builtin_tgammal, "LdLd", "Fnc") +BUILTIN(__builtin_trunc , "dd", "Fnc") +BUILTIN(__builtin_truncf, "ff", "Fnc") +BUILTIN(__builtin_truncl, "LdLd", "Fnc") + +// C99 complex builtins +BUILTIN(__builtin_cabs, "dXd", "Fnc") +BUILTIN(__builtin_cabsf, "fXf", "Fnc") +BUILTIN(__builtin_cabsl, "LdXLd", "Fnc") +BUILTIN(__builtin_cacos, "XdXd", "Fnc") +BUILTIN(__builtin_cacosf, "XfXf", "Fnc") +BUILTIN(__builtin_cacosh, "XdXd", "Fnc") +BUILTIN(__builtin_cacoshf, "XfXf", "Fnc") +BUILTIN(__builtin_cacoshl, "XLdXLd", "Fnc") +BUILTIN(__builtin_cacosl, "XLdXLd", "Fnc") +BUILTIN(__builtin_carg, "dXd", "Fnc") +BUILTIN(__builtin_cargf, "fXf", "Fnc") +BUILTIN(__builtin_cargl, "LdXLd", "Fnc") +BUILTIN(__builtin_casin, "XdXd", "Fnc") +BUILTIN(__builtin_casinf, "XfXf", "Fnc") +BUILTIN(__builtin_casinh, "XdXd", "Fnc") +BUILTIN(__builtin_casinhf, "XfXf", "Fnc") +BUILTIN(__builtin_casinhl, "XLdXLd", "Fnc") +BUILTIN(__builtin_casinl, "XLdXLd", "Fnc") +BUILTIN(__builtin_catan, "XdXd", "Fnc") +BUILTIN(__builtin_catanf, "XfXf", "Fnc") +BUILTIN(__builtin_catanh, "XdXd", "Fnc") +BUILTIN(__builtin_catanhf, "XfXf", "Fnc") +BUILTIN(__builtin_catanhl, "XLdXLd", "Fnc") +BUILTIN(__builtin_catanl, "XLdXLd", "Fnc") +BUILTIN(__builtin_ccos, "XdXd", "Fnc") +BUILTIN(__builtin_ccosf, "XfXf", "Fnc") +BUILTIN(__builtin_ccosl, "XLdXLd", "Fnc") +BUILTIN(__builtin_ccosh, "XdXd", "Fnc") +BUILTIN(__builtin_ccoshf, "XfXf", "Fnc") +BUILTIN(__builtin_ccoshl, "XLdXLd", "Fnc") +BUILTIN(__builtin_cexp, "XdXd", "Fnc") +BUILTIN(__builtin_cexpf, "XfXf", "Fnc") +BUILTIN(__builtin_cexpl, "XLdXLd", "Fnc") +BUILTIN(__builtin_cimag, "dXd", "Fnc") +BUILTIN(__builtin_cimagf, "fXf", "Fnc") +BUILTIN(__builtin_cimagl, "LdXLd", "Fnc") +BUILTIN(__builtin_conj, "XdXd", "Fnc") +BUILTIN(__builtin_conjf, "XfXf", "Fnc") +BUILTIN(__builtin_conjl, "XLdXLd", "Fnc") +BUILTIN(__builtin_clog, "XdXd", "Fnc") +BUILTIN(__builtin_clogf, "XfXf", "Fnc") +BUILTIN(__builtin_clogl, "XLdXLd", "Fnc") +BUILTIN(__builtin_cproj, "XdXd", "Fnc") +BUILTIN(__builtin_cprojf, "XfXf", "Fnc") +BUILTIN(__builtin_cprojl, "XLdXLd", "Fnc") +BUILTIN(__builtin_cpow, "XdXdXd", "Fnc") +BUILTIN(__builtin_cpowf, "XfXfXf", "Fnc") +BUILTIN(__builtin_cpowl, "XLdXLdXLd", "Fnc") +BUILTIN(__builtin_creal, "dXd", "Fnc") +BUILTIN(__builtin_crealf, "fXf", "Fnc") +BUILTIN(__builtin_creall, "LdXLd", "Fnc") +BUILTIN(__builtin_csin, "XdXd", "Fnc") +BUILTIN(__builtin_csinf, "XfXf", "Fnc") +BUILTIN(__builtin_csinl, "XLdXLd", "Fnc") +BUILTIN(__builtin_csinh, "XdXd", "Fnc") +BUILTIN(__builtin_csinhf, "XfXf", "Fnc") +BUILTIN(__builtin_csinhl, "XLdXLd", "Fnc") +BUILTIN(__builtin_csqrt, "XdXd", "Fnc") +BUILTIN(__builtin_csqrtf, "XfXf", "Fnc") +BUILTIN(__builtin_csqrtl, "XLdXLd", "Fnc") +BUILTIN(__builtin_ctan, "XdXd", "Fnc") +BUILTIN(__builtin_ctanf, "XfXf", "Fnc") +BUILTIN(__builtin_ctanl, "XLdXLd", "Fnc") +BUILTIN(__builtin_ctanh, "XdXd", "Fnc") +BUILTIN(__builtin_ctanhf, "XfXf", "Fnc") +BUILTIN(__builtin_ctanhl, "XLdXLd", "Fnc") + +// FP Comparisons. +BUILTIN(__builtin_isgreater , "i.", "Fnc") +BUILTIN(__builtin_isgreaterequal, "i.", "Fnc") +BUILTIN(__builtin_isless , "i.", "Fnc") +BUILTIN(__builtin_islessequal , "i.", "Fnc") +BUILTIN(__builtin_islessgreater , "i.", "Fnc") +BUILTIN(__builtin_isunordered , "i.", "Fnc") + +// Unary FP classification +BUILTIN(__builtin_fpclassify, "iiiii.", "Fnc") +BUILTIN(__builtin_isfinite, "i.", "Fnc") +BUILTIN(__builtin_isinf, "i.", "Fnc") +BUILTIN(__builtin_isinf_sign, "i.", "Fnc") +BUILTIN(__builtin_isnan, "i.", "Fnc") +BUILTIN(__builtin_isnormal, "i.", "Fnc") + +// FP signbit builtins +BUILTIN(__builtin_signbit, "i.", "Fnc") +BUILTIN(__builtin_signbitf, "if", "Fnc") +BUILTIN(__builtin_signbitl, "iLd", "Fnc") + +// Builtins for arithmetic. +BUILTIN(__builtin_clzs , "iUs" , "nc") +BUILTIN(__builtin_clz , "iUi" , "nc") +BUILTIN(__builtin_clzl , "iULi" , "nc") +BUILTIN(__builtin_clzll, "iULLi", "nc") +// TODO: int clzimax(uintmax_t) +BUILTIN(__builtin_ctzs , "iUs" , "nc") +BUILTIN(__builtin_ctz , "iUi" , "nc") +BUILTIN(__builtin_ctzl , "iULi" , "nc") +BUILTIN(__builtin_ctzll, "iULLi", "nc") +// TODO: int ctzimax(uintmax_t) +BUILTIN(__builtin_ffs , "ii" , "Fnc") +BUILTIN(__builtin_ffsl , "iLi" , "Fnc") +BUILTIN(__builtin_ffsll, "iLLi", "Fnc") +BUILTIN(__builtin_parity , "iUi" , "nc") +BUILTIN(__builtin_parityl , "iULi" , "nc") +BUILTIN(__builtin_parityll, "iULLi", "nc") +BUILTIN(__builtin_popcount , "iUi" , "nc") +BUILTIN(__builtin_popcountl , "iULi" , "nc") +BUILTIN(__builtin_popcountll, "iULLi", "nc") + +// FIXME: These type signatures are not correct for targets with int != 32-bits +// or with ULL != 64-bits. +BUILTIN(__builtin_bswap16, "UsUs", "nc") +BUILTIN(__builtin_bswap32, "UiUi", "nc") +BUILTIN(__builtin_bswap64, "ULLiULLi", "nc") + +// Random GCC builtins +BUILTIN(__builtin_constant_p, "i.", "nctu") +BUILTIN(__builtin_classify_type, "i.", "nctu") +BUILTIN(__builtin___CFStringMakeConstantString, "FC*cC*", "nc") +BUILTIN(__builtin___NSStringMakeConstantString, "FC*cC*", "nc") +BUILTIN(__builtin_va_start, "vA.", "nt") +BUILTIN(__builtin_va_end, "vA", "n") +BUILTIN(__builtin_va_copy, "vAA", "n") +BUILTIN(__builtin_stdarg_start, "vA.", "n") +BUILTIN(__builtin_assume_aligned, "v*vC*z.", "nc") +BUILTIN(__builtin_bcmp, "iv*v*z", "Fn") +BUILTIN(__builtin_bcopy, "vv*v*z", "n") +BUILTIN(__builtin_bzero, "vv*z", "nF") +BUILTIN(__builtin_fprintf, "iP*cC*.", "Fp:1:") +BUILTIN(__builtin_memchr, "v*vC*iz", "nF") +BUILTIN(__builtin_memcmp, "ivC*vC*z", "nF") +BUILTIN(__builtin_memcpy, "v*v*vC*z", "nF") +BUILTIN(__builtin_memmove, "v*v*vC*z", "nF") +BUILTIN(__builtin_mempcpy, "v*v*vC*z", "nF") +BUILTIN(__builtin_memset, "v*v*iz", "nF") +BUILTIN(__builtin_printf, "icC*.", "Fp:0:") +BUILTIN(__builtin_stpcpy, "c*c*cC*", "nF") +BUILTIN(__builtin_stpncpy, "c*c*cC*z", "nF") +BUILTIN(__builtin_strcasecmp, "icC*cC*", "nF") +BUILTIN(__builtin_strcat, "c*c*cC*", "nF") +BUILTIN(__builtin_strchr, "c*cC*i", "nF") +BUILTIN(__builtin_strcmp, "icC*cC*", "nF") +BUILTIN(__builtin_strcpy, "c*c*cC*", "nF") +BUILTIN(__builtin_strcspn, "zcC*cC*", "nF") +BUILTIN(__builtin_strdup, "c*cC*", "nF") +BUILTIN(__builtin_strlen, "zcC*", "nF") +BUILTIN(__builtin_strncasecmp, "icC*cC*z", "nF") +BUILTIN(__builtin_strncat, "c*c*cC*z", "nF") +BUILTIN(__builtin_strncmp, "icC*cC*z", "nF") +BUILTIN(__builtin_strncpy, "c*c*cC*z", "nF") +BUILTIN(__builtin_strndup, "c*cC*z", "nF") +BUILTIN(__builtin_strpbrk, "c*cC*cC*", "nF") +BUILTIN(__builtin_strrchr, "c*cC*i", "nF") +BUILTIN(__builtin_strspn, "zcC*cC*", "nF") +BUILTIN(__builtin_strstr, "c*cC*cC*", "nF") +BUILTIN(__builtin_return_address, "v*IUi", "n") +BUILTIN(__builtin_extract_return_addr, "v*v*", "n") +BUILTIN(__builtin_frame_address, "v*IUi", "n") +BUILTIN(__builtin___clear_cache, "vc*c*", "n") +BUILTIN(__builtin_flt_rounds, "i", "nc") +BUILTIN(__builtin_setjmp, "iv**", "j") +BUILTIN(__builtin_longjmp, "vv**i", "r") +BUILTIN(__builtin_unwind_init, "v", "") +BUILTIN(__builtin_eh_return_data_regno, "iIi", "nc") +BUILTIN(__builtin_snprintf, "ic*zcC*.", "nFp:2:") +BUILTIN(__builtin_vsprintf, "ic*cC*a", "nFP:1:") +BUILTIN(__builtin_vsnprintf, "ic*zcC*a", "nFP:2:") + +// GCC exception builtins +BUILTIN(__builtin_eh_return, "vzv*", "r") // FIXME: Takes intptr_t, not size_t! +BUILTIN(__builtin_frob_return_addr, "v*v*", "n") +BUILTIN(__builtin_dwarf_cfa, "v*", "n") +BUILTIN(__builtin_init_dwarf_reg_size_table, "vv*", "n") +BUILTIN(__builtin_dwarf_sp_column, "Ui", "n") +BUILTIN(__builtin_extend_pointer, "ULLiv*", "n") // _Unwind_Word == uint64_t + +// GCC Object size checking builtins +BUILTIN(__builtin_object_size, "zvC*i", "nu") +BUILTIN(__builtin___memcpy_chk, "v*v*vC*zz", "nF") +BUILTIN(__builtin___memccpy_chk, "v*v*vC*izz", "nF") +BUILTIN(__builtin___memmove_chk, "v*v*vC*zz", "nF") +BUILTIN(__builtin___mempcpy_chk, "v*v*vC*zz", "nF") +BUILTIN(__builtin___memset_chk, "v*v*izz", "nF") +BUILTIN(__builtin___stpcpy_chk, "c*c*cC*z", "nF") +BUILTIN(__builtin___strcat_chk, "c*c*cC*z", "nF") +BUILTIN(__builtin___strcpy_chk, "c*c*cC*z", "nF") +BUILTIN(__builtin___strlcat_chk, "zc*cC*zz", "nF") +BUILTIN(__builtin___strlcpy_chk, "zc*cC*zz", "nF") +BUILTIN(__builtin___strncat_chk, "c*c*cC*zz", "nF") +BUILTIN(__builtin___strncpy_chk, "c*c*cC*zz", "nF") +BUILTIN(__builtin___stpncpy_chk, "c*c*cC*zz", "nF") +BUILTIN(__builtin___snprintf_chk, "ic*zizcC*.", "Fp:4:") +BUILTIN(__builtin___sprintf_chk, "ic*izcC*.", "Fp:3:") +BUILTIN(__builtin___vsnprintf_chk, "ic*zizcC*a", "FP:4:") +BUILTIN(__builtin___vsprintf_chk, "ic*izcC*a", "FP:3:") +BUILTIN(__builtin___fprintf_chk, "iP*icC*.", "Fp:2:") +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_unpredictable, "LiLi" , "nc") +BUILTIN(__builtin_expect, "LiLiLi" , "nc") +BUILTIN(__builtin_prefetch, "vvC*.", "nc") +BUILTIN(__builtin_readcyclecounter, "ULLi", "n") +BUILTIN(__builtin_trap, "v", "nr") +BUILTIN(__builtin_debugtrap, "v", "n") +BUILTIN(__builtin_unreachable, "v", "nr") +BUILTIN(__builtin_shufflevector, "v." , "nc") +BUILTIN(__builtin_convertvector, "v." , "nct") +BUILTIN(__builtin_alloca, "v*z" , "Fn") +BUILTIN(__builtin_call_with_static_chain, "v.", "nt") + +// "Overloaded" Atomic operator builtins. These are overloaded to support data +// types of i8, i16, i32, i64, and i128. The front-end sees calls to the +// non-suffixed version of these (which has a bogus type) and transforms them to +// the right overloaded version in Sema (plus casts). + +// FIXME: These assume that char -> i8, short -> i16, int -> i32, +// long long -> i64. + +BUILTIN(__sync_fetch_and_add, "v.", "t") +BUILTIN(__sync_fetch_and_add_1, "ccD*c.", "nt") +BUILTIN(__sync_fetch_and_add_2, "ssD*s.", "nt") +BUILTIN(__sync_fetch_and_add_4, "iiD*i.", "nt") +BUILTIN(__sync_fetch_and_add_8, "LLiLLiD*LLi.", "nt") +BUILTIN(__sync_fetch_and_add_16, "LLLiLLLiD*LLLi.", "nt") + +BUILTIN(__sync_fetch_and_sub, "v.", "t") +BUILTIN(__sync_fetch_and_sub_1, "ccD*c.", "nt") +BUILTIN(__sync_fetch_and_sub_2, "ssD*s.", "nt") +BUILTIN(__sync_fetch_and_sub_4, "iiD*i.", "nt") +BUILTIN(__sync_fetch_and_sub_8, "LLiLLiD*LLi.", "nt") +BUILTIN(__sync_fetch_and_sub_16, "LLLiLLLiD*LLLi.", "nt") + +BUILTIN(__sync_fetch_and_or, "v.", "t") +BUILTIN(__sync_fetch_and_or_1, "ccD*c.", "nt") +BUILTIN(__sync_fetch_and_or_2, "ssD*s.", "nt") +BUILTIN(__sync_fetch_and_or_4, "iiD*i.", "nt") +BUILTIN(__sync_fetch_and_or_8, "LLiLLiD*LLi.", "nt") +BUILTIN(__sync_fetch_and_or_16, "LLLiLLLiD*LLLi.", "nt") + +BUILTIN(__sync_fetch_and_and, "v.", "t") +BUILTIN(__sync_fetch_and_and_1, "ccD*c.", "tn") +BUILTIN(__sync_fetch_and_and_2, "ssD*s.", "tn") +BUILTIN(__sync_fetch_and_and_4, "iiD*i.", "tn") +BUILTIN(__sync_fetch_and_and_8, "LLiLLiD*LLi.", "tn") +BUILTIN(__sync_fetch_and_and_16, "LLLiLLLiD*LLLi.", "tn") + +BUILTIN(__sync_fetch_and_xor, "v.", "t") +BUILTIN(__sync_fetch_and_xor_1, "ccD*c.", "tn") +BUILTIN(__sync_fetch_and_xor_2, "ssD*s.", "tn") +BUILTIN(__sync_fetch_and_xor_4, "iiD*i.", "tn") +BUILTIN(__sync_fetch_and_xor_8, "LLiLLiD*LLi.", "tn") +BUILTIN(__sync_fetch_and_xor_16, "LLLiLLLiD*LLLi.", "tn") + +BUILTIN(__sync_fetch_and_nand, "v.", "t") +BUILTIN(__sync_fetch_and_nand_1, "ccD*c.", "tn") +BUILTIN(__sync_fetch_and_nand_2, "ssD*s.", "tn") +BUILTIN(__sync_fetch_and_nand_4, "iiD*i.", "tn") +BUILTIN(__sync_fetch_and_nand_8, "LLiLLiD*LLi.", "tn") +BUILTIN(__sync_fetch_and_nand_16, "LLLiLLLiD*LLLi.", "tn") + +BUILTIN(__sync_add_and_fetch, "v.", "t") +BUILTIN(__sync_add_and_fetch_1, "ccD*c.", "tn") +BUILTIN(__sync_add_and_fetch_2, "ssD*s.", "tn") +BUILTIN(__sync_add_and_fetch_4, "iiD*i.", "tn") +BUILTIN(__sync_add_and_fetch_8, "LLiLLiD*LLi.", "tn") +BUILTIN(__sync_add_and_fetch_16, "LLLiLLLiD*LLLi.", "tn") + +BUILTIN(__sync_sub_and_fetch, "v.", "t") +BUILTIN(__sync_sub_and_fetch_1, "ccD*c.", "tn") +BUILTIN(__sync_sub_and_fetch_2, "ssD*s.", "tn") +BUILTIN(__sync_sub_and_fetch_4, "iiD*i.", "tn") +BUILTIN(__sync_sub_and_fetch_8, "LLiLLiD*LLi.", "tn") +BUILTIN(__sync_sub_and_fetch_16, "LLLiLLLiD*LLLi.", "tn") + +BUILTIN(__sync_or_and_fetch, "v.", "t") +BUILTIN(__sync_or_and_fetch_1, "ccD*c.", "tn") +BUILTIN(__sync_or_and_fetch_2, "ssD*s.", "tn") +BUILTIN(__sync_or_and_fetch_4, "iiD*i.", "tn") +BUILTIN(__sync_or_and_fetch_8, "LLiLLiD*LLi.", "tn") +BUILTIN(__sync_or_and_fetch_16, "LLLiLLLiD*LLLi.", "tn") + +BUILTIN(__sync_and_and_fetch, "v.", "t") +BUILTIN(__sync_and_and_fetch_1, "ccD*c.", "tn") +BUILTIN(__sync_and_and_fetch_2, "ssD*s.", "tn") +BUILTIN(__sync_and_and_fetch_4, "iiD*i.", "tn") +BUILTIN(__sync_and_and_fetch_8, "LLiLLiD*LLi.", "tn") +BUILTIN(__sync_and_and_fetch_16, "LLLiLLLiD*LLLi.", "tn") + +BUILTIN(__sync_xor_and_fetch, "v.", "t") +BUILTIN(__sync_xor_and_fetch_1, "ccD*c.", "tn") +BUILTIN(__sync_xor_and_fetch_2, "ssD*s.", "tn") +BUILTIN(__sync_xor_and_fetch_4, "iiD*i.", "tn") +BUILTIN(__sync_xor_and_fetch_8, "LLiLLiD*LLi.", "tn") +BUILTIN(__sync_xor_and_fetch_16, "LLLiLLLiD*LLLi.", "tn") + +BUILTIN(__sync_nand_and_fetch, "v.", "t") +BUILTIN(__sync_nand_and_fetch_1, "ccD*c.", "tn") +BUILTIN(__sync_nand_and_fetch_2, "ssD*s.", "tn") +BUILTIN(__sync_nand_and_fetch_4, "iiD*i.", "tn") +BUILTIN(__sync_nand_and_fetch_8, "LLiLLiD*LLi.", "tn") +BUILTIN(__sync_nand_and_fetch_16, "LLLiLLLiD*LLLi.", "tn") + +BUILTIN(__sync_bool_compare_and_swap, "v.", "t") +BUILTIN(__sync_bool_compare_and_swap_1, "bcD*cc.", "tn") +BUILTIN(__sync_bool_compare_and_swap_2, "bsD*ss.", "tn") +BUILTIN(__sync_bool_compare_and_swap_4, "biD*ii.", "tn") +BUILTIN(__sync_bool_compare_and_swap_8, "bLLiD*LLiLLi.", "tn") +BUILTIN(__sync_bool_compare_and_swap_16, "bLLLiD*LLLiLLLi.", "tn") + +BUILTIN(__sync_val_compare_and_swap, "v.", "t") +BUILTIN(__sync_val_compare_and_swap_1, "ccD*cc.", "tn") +BUILTIN(__sync_val_compare_and_swap_2, "ssD*ss.", "tn") +BUILTIN(__sync_val_compare_and_swap_4, "iiD*ii.", "tn") +BUILTIN(__sync_val_compare_and_swap_8, "LLiLLiD*LLiLLi.", "tn") +BUILTIN(__sync_val_compare_and_swap_16, "LLLiLLLiD*LLLiLLLi.", "tn") + +BUILTIN(__sync_lock_test_and_set, "v.", "t") +BUILTIN(__sync_lock_test_and_set_1, "ccD*c.", "tn") +BUILTIN(__sync_lock_test_and_set_2, "ssD*s.", "tn") +BUILTIN(__sync_lock_test_and_set_4, "iiD*i.", "tn") +BUILTIN(__sync_lock_test_and_set_8, "LLiLLiD*LLi.", "tn") +BUILTIN(__sync_lock_test_and_set_16, "LLLiLLLiD*LLLi.", "tn") + +BUILTIN(__sync_lock_release, "v.", "t") +BUILTIN(__sync_lock_release_1, "vcD*.", "tn") +BUILTIN(__sync_lock_release_2, "vsD*.", "tn") +BUILTIN(__sync_lock_release_4, "viD*.", "tn") +BUILTIN(__sync_lock_release_8, "vLLiD*.", "tn") +BUILTIN(__sync_lock_release_16, "vLLLiD*.", "tn") + +BUILTIN(__sync_swap, "v.", "t") +BUILTIN(__sync_swap_1, "ccD*c.", "tn") +BUILTIN(__sync_swap_2, "ssD*s.", "tn") +BUILTIN(__sync_swap_4, "iiD*i.", "tn") +BUILTIN(__sync_swap_8, "LLiLLiD*LLi.", "tn") +BUILTIN(__sync_swap_16, "LLLiLLLiD*LLLi.", "tn") + +// Some of our atomics builtins are handled by AtomicExpr rather than +// as normal builtin CallExprs. This macro is used for such builtins. +#ifndef ATOMIC_BUILTIN +#define ATOMIC_BUILTIN(ID, TYPE, ATTRS) BUILTIN(ID, TYPE, ATTRS) +#endif + +// C11 _Atomic operations for <stdatomic.h>. +ATOMIC_BUILTIN(__c11_atomic_init, "v.", "t") +ATOMIC_BUILTIN(__c11_atomic_load, "v.", "t") +ATOMIC_BUILTIN(__c11_atomic_store, "v.", "t") +ATOMIC_BUILTIN(__c11_atomic_exchange, "v.", "t") +ATOMIC_BUILTIN(__c11_atomic_compare_exchange_strong, "v.", "t") +ATOMIC_BUILTIN(__c11_atomic_compare_exchange_weak, "v.", "t") +ATOMIC_BUILTIN(__c11_atomic_fetch_add, "v.", "t") +ATOMIC_BUILTIN(__c11_atomic_fetch_sub, "v.", "t") +ATOMIC_BUILTIN(__c11_atomic_fetch_and, "v.", "t") +ATOMIC_BUILTIN(__c11_atomic_fetch_or, "v.", "t") +ATOMIC_BUILTIN(__c11_atomic_fetch_xor, "v.", "t") +BUILTIN(__c11_atomic_thread_fence, "vi", "n") +BUILTIN(__c11_atomic_signal_fence, "vi", "n") +BUILTIN(__c11_atomic_is_lock_free, "iz", "n") + +// GNU atomic builtins. +ATOMIC_BUILTIN(__atomic_load, "v.", "t") +ATOMIC_BUILTIN(__atomic_load_n, "v.", "t") +ATOMIC_BUILTIN(__atomic_store, "v.", "t") +ATOMIC_BUILTIN(__atomic_store_n, "v.", "t") +ATOMIC_BUILTIN(__atomic_exchange, "v.", "t") +ATOMIC_BUILTIN(__atomic_exchange_n, "v.", "t") +ATOMIC_BUILTIN(__atomic_compare_exchange, "v.", "t") +ATOMIC_BUILTIN(__atomic_compare_exchange_n, "v.", "t") +ATOMIC_BUILTIN(__atomic_fetch_add, "v.", "t") +ATOMIC_BUILTIN(__atomic_fetch_sub, "v.", "t") +ATOMIC_BUILTIN(__atomic_fetch_and, "v.", "t") +ATOMIC_BUILTIN(__atomic_fetch_or, "v.", "t") +ATOMIC_BUILTIN(__atomic_fetch_xor, "v.", "t") +ATOMIC_BUILTIN(__atomic_fetch_nand, "v.", "t") +ATOMIC_BUILTIN(__atomic_add_fetch, "v.", "t") +ATOMIC_BUILTIN(__atomic_sub_fetch, "v.", "t") +ATOMIC_BUILTIN(__atomic_and_fetch, "v.", "t") +ATOMIC_BUILTIN(__atomic_or_fetch, "v.", "t") +ATOMIC_BUILTIN(__atomic_xor_fetch, "v.", "t") +ATOMIC_BUILTIN(__atomic_nand_fetch, "v.", "t") +BUILTIN(__atomic_test_and_set, "bvD*i", "n") +BUILTIN(__atomic_clear, "vvD*i", "n") +BUILTIN(__atomic_thread_fence, "vi", "n") +BUILTIN(__atomic_signal_fence, "vi", "n") +BUILTIN(__atomic_always_lock_free, "izvCD*", "n") +BUILTIN(__atomic_is_lock_free, "izvCD*", "n") + +#undef ATOMIC_BUILTIN + +// Non-overloaded atomic builtins. +BUILTIN(__sync_synchronize, "v.", "n") +// GCC does not support these, they are a Clang extension. +BUILTIN(__sync_fetch_and_min, "iiD*i", "n") +BUILTIN(__sync_fetch_and_max, "iiD*i", "n") +BUILTIN(__sync_fetch_and_umin, "UiUiD*Ui", "n") +BUILTIN(__sync_fetch_and_umax, "UiUiD*Ui", "n") + +// Random libc builtins. +BUILTIN(__builtin_abort, "v", "Fnr") +BUILTIN(__builtin_index, "c*cC*i", "Fn") +BUILTIN(__builtin_rindex, "c*cC*i", "Fn") + +// Microsoft builtins. These are only active with -fms-extensions. +LANGBUILTIN(_alloca, "v*z", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(__assume, "vb", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(__debugbreak, "v", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(__exception_code, "ULi", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_exception_code, "ULi", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(__exception_info, "v*", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_exception_info, "v*", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(__abnormal_termination, "i", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_abnormal_termination, "i", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(__GetExceptionInfo, "v*.", "ntu", ALL_MS_LANGUAGES) +LANGBUILTIN(_InterlockedCompareExchange, "LiLiD*LiLi", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_InterlockedCompareExchangePointer, "v*v*D*v*v*", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_InterlockedDecrement, "LiLiD*", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_InterlockedExchangeAdd, "LiLiD*Li", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_InterlockedExchange, "LiLiD*Li", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_InterlockedExchangePointer, "v*v*D*v*", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_InterlockedIncrement, "LiLiD*", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(__noop, "i.", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(__readfsdword, "ULiULi", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(__va_start, "vc**.", "nt", ALL_MS_LANGUAGES) + +// Microsoft library builtins. +LIBBUILTIN(_setjmpex, "iJ", "fj", "setjmpex.h", ALL_MS_LANGUAGES) + +// C99 library functions +// C99 stdlib.h +LIBBUILTIN(abort, "v", "fr", "stdlib.h", ALL_LANGUAGES) +LIBBUILTIN(calloc, "v*zz", "f", "stdlib.h", ALL_LANGUAGES) +LIBBUILTIN(exit, "vi", "fr", "stdlib.h", ALL_LANGUAGES) +LIBBUILTIN(_Exit, "vi", "fr", "stdlib.h", ALL_LANGUAGES) +LIBBUILTIN(malloc, "v*z", "f", "stdlib.h", ALL_LANGUAGES) +LIBBUILTIN(realloc, "v*v*z", "f", "stdlib.h", ALL_LANGUAGES) +// C99 string.h +LIBBUILTIN(memcpy, "v*v*vC*z", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(memcmp, "ivC*vC*z", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(memmove, "v*v*vC*z", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strcpy, "c*c*cC*", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strncpy, "c*c*cC*z", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strcmp, "icC*cC*", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strncmp, "icC*cC*z", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strcat, "c*c*cC*", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strncat, "c*c*cC*z", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strxfrm, "zc*cC*z", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(memchr, "v*vC*iz", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strchr, "c*cC*i", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strcspn, "zcC*cC*", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strpbrk, "c*cC*cC*", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strrchr, "c*cC*i", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strspn, "zcC*cC*", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strstr, "c*cC*cC*", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strtok, "c*c*cC*", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(memset, "v*v*iz", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strerror, "c*i", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strlen, "zcC*", "f", "string.h", ALL_LANGUAGES) +// C99 stdio.h +LIBBUILTIN(printf, "icC*.", "fp:0:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(fprintf, "iP*cC*.", "fp:1:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(snprintf, "ic*zcC*.", "fp:2:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(sprintf, "ic*cC*.", "fp:1:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(vprintf, "icC*a", "fP:0:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(vfprintf, "i.", "fP:1:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(vsnprintf, "ic*zcC*a", "fP:2:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(vsprintf, "ic*cC*a", "fP:1:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(scanf, "icC*R.", "fs:0:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(fscanf, "iP*RcC*R.", "fs:1:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(sscanf, "icC*RcC*R.", "fs:1:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(vscanf, "icC*Ra", "fS:0:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(vfscanf, "iP*RcC*Ra", "fS:1:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(vsscanf, "icC*RcC*Ra", "fS:1:", "stdio.h", ALL_LANGUAGES) +// C99 +// In some systems setjmp is a macro that expands to _setjmp. We undefine +// it here to avoid having two identical LIBBUILTIN entries. +#undef setjmp +LIBBUILTIN(setjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES) +LIBBUILTIN(longjmp, "vJi", "fr", "setjmp.h", ALL_LANGUAGES) + +// Non-C library functions, active in GNU mode only. +// Functions with (returns_twice) attribute (marked as "j") are still active in +// all languages, because losing this attribute would result in miscompilation +// when these functions are used in non-GNU mode. PR16138. +LIBBUILTIN(alloca, "v*z", "f", "stdlib.h", ALL_GNU_LANGUAGES) +// POSIX string.h +LIBBUILTIN(stpcpy, "c*c*cC*", "f", "string.h", ALL_GNU_LANGUAGES) +LIBBUILTIN(stpncpy, "c*c*cC*z", "f", "string.h", ALL_GNU_LANGUAGES) +LIBBUILTIN(strdup, "c*cC*", "f", "string.h", ALL_GNU_LANGUAGES) +LIBBUILTIN(strndup, "c*cC*z", "f", "string.h", ALL_GNU_LANGUAGES) +// POSIX strings.h +LIBBUILTIN(index, "c*cC*i", "f", "strings.h", ALL_GNU_LANGUAGES) +LIBBUILTIN(rindex, "c*cC*i", "f", "strings.h", ALL_GNU_LANGUAGES) +LIBBUILTIN(bzero, "vv*z", "f", "strings.h", ALL_GNU_LANGUAGES) +// In some systems str[n]casejmp is a macro that expands to _str[n]icmp. +// We undefine then here to avoid wrong name. +#undef strcasecmp +#undef strncasecmp +LIBBUILTIN(strcasecmp, "icC*cC*", "f", "strings.h", ALL_GNU_LANGUAGES) +LIBBUILTIN(strncasecmp, "icC*cC*z", "f", "strings.h", ALL_GNU_LANGUAGES) +// POSIX unistd.h +LIBBUILTIN(_exit, "vi", "fr", "unistd.h", ALL_GNU_LANGUAGES) +LIBBUILTIN(vfork, "p", "fj", "unistd.h", ALL_LANGUAGES) +// POSIX setjmp.h + +LIBBUILTIN(_setjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES) +LIBBUILTIN(__sigsetjmp, "iSJi", "fj", "setjmp.h", ALL_LANGUAGES) +LIBBUILTIN(sigsetjmp, "iSJi", "fj", "setjmp.h", ALL_LANGUAGES) +LIBBUILTIN(setjmp_syscall, "iJ", "fj", "setjmp.h", ALL_LANGUAGES) +LIBBUILTIN(savectx, "iJ", "fj", "setjmp.h", ALL_LANGUAGES) +LIBBUILTIN(qsetjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES) +LIBBUILTIN(getcontext, "iK*", "fj", "setjmp.h", ALL_LANGUAGES) + +LIBBUILTIN(_longjmp, "vJi", "fr", "setjmp.h", ALL_GNU_LANGUAGES) +LIBBUILTIN(siglongjmp, "vSJi", "fr", "setjmp.h", ALL_GNU_LANGUAGES) +// non-standard but very common +LIBBUILTIN(strlcpy, "zc*cC*z", "f", "string.h", ALL_GNU_LANGUAGES) +LIBBUILTIN(strlcat, "zc*cC*z", "f", "string.h", ALL_GNU_LANGUAGES) +// id objc_msgSend(id, SEL, ...) +LIBBUILTIN(objc_msgSend, "GGH.", "f", "objc/message.h", OBJC_LANG) +// long double objc_msgSend_fpret(id self, SEL op, ...) +LIBBUILTIN(objc_msgSend_fpret, "LdGH.", "f", "objc/message.h", OBJC_LANG) +// _Complex long double objc_msgSend_fp2ret(id self, SEL op, ...) +LIBBUILTIN(objc_msgSend_fp2ret, "XLdGH.", "f", "objc/message.h", OBJC_LANG) +// void objc_msgSend_stret (id, SEL, ...) +LIBBUILTIN(objc_msgSend_stret, "vGH.", "f", "objc/message.h", OBJC_LANG) +// id objc_msgSendSuper(struct objc_super *super, SEL op, ...) +LIBBUILTIN(objc_msgSendSuper, "GM*H.", "f", "objc/message.h", OBJC_LANG) +// void objc_msgSendSuper_stret(struct objc_super *super, SEL op, ...) +LIBBUILTIN(objc_msgSendSuper_stret, "vM*H.", "f", "objc/message.h", OBJC_LANG) +// id objc_getClass(const char *name) +LIBBUILTIN(objc_getClass, "GcC*", "f", "objc/runtime.h", OBJC_LANG) +// id objc_getMetaClass(const char *name) +LIBBUILTIN(objc_getMetaClass, "GcC*", "f", "objc/runtime.h", OBJC_LANG) +// void objc_enumerationMutation(id) +LIBBUILTIN(objc_enumerationMutation, "vG", "f", "objc/runtime.h", OBJC_LANG) + +// id objc_read_weak(id *location) +LIBBUILTIN(objc_read_weak, "GG*", "f", "objc/objc-auto.h", OBJC_LANG) +// id objc_assign_weak(id value, id *location) +LIBBUILTIN(objc_assign_weak, "GGG*", "f", "objc/objc-auto.h", OBJC_LANG) +// id objc_assign_ivar(id value, id dest, ptrdiff_t offset) +LIBBUILTIN(objc_assign_ivar, "GGGY", "f", "objc/objc-auto.h", OBJC_LANG) +// id objc_assign_global(id val, id *dest) +LIBBUILTIN(objc_assign_global, "GGG*", "f", "objc/objc-auto.h", OBJC_LANG) +// id objc_assign_strongCast(id val, id *dest +LIBBUILTIN(objc_assign_strongCast, "GGG*", "f", "objc/objc-auto.h", OBJC_LANG) + +// id objc_exception_extract(void *localExceptionData) +LIBBUILTIN(objc_exception_extract, "Gv*", "f", "objc/objc-exception.h", OBJC_LANG) +// void objc_exception_try_enter(void *localExceptionData) +LIBBUILTIN(objc_exception_try_enter, "vv*", "f", "objc/objc-exception.h", OBJC_LANG) +// void objc_exception_try_exit(void *localExceptionData) +LIBBUILTIN(objc_exception_try_exit, "vv*", "f", "objc/objc-exception.h", OBJC_LANG) +// int objc_exception_match(Class exceptionClass, id exception) +LIBBUILTIN(objc_exception_match, "iGG", "f", "objc/objc-exception.h", OBJC_LANG) +// void objc_exception_throw(id exception) +LIBBUILTIN(objc_exception_throw, "vG", "f", "objc/objc-exception.h", OBJC_LANG) + +// int objc_sync_enter(id obj) +LIBBUILTIN(objc_sync_enter, "iG", "f", "objc/objc-sync.h", OBJC_LANG) +// int objc_sync_exit(id obj) +LIBBUILTIN(objc_sync_exit, "iG", "f", "objc/objc-sync.h", OBJC_LANG) + +BUILTIN(__builtin_objc_memmove_collectable, "v*v*vC*z", "nF") + +// void NSLog(NSString *fmt, ...) +LIBBUILTIN(NSLog, "vG.", "fp:0:", "Foundation/NSObjCRuntime.h", OBJC_LANG) +// void NSLogv(NSString *fmt, va_list args) +LIBBUILTIN(NSLogv, "vGa", "fP:0:", "Foundation/NSObjCRuntime.h", OBJC_LANG) + +// Builtin math library functions +LIBBUILTIN(atan2, "ddd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(atan2f, "fff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(atan2l, "LdLdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(abs, "ii", "fnc", "stdlib.h", ALL_LANGUAGES) +LIBBUILTIN(labs, "LiLi", "fnc", "stdlib.h", ALL_LANGUAGES) +LIBBUILTIN(llabs, "LLiLLi", "fnc", "stdlib.h", ALL_LANGUAGES) + +LIBBUILTIN(copysign, "ddd", "fnc", "math.h", ALL_LANGUAGES) +LIBBUILTIN(copysignf, "fff", "fnc", "math.h", ALL_LANGUAGES) +LIBBUILTIN(copysignl, "LdLdLd", "fnc", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(fabs, "dd", "fnc", "math.h", ALL_LANGUAGES) +LIBBUILTIN(fabsf, "ff", "fnc", "math.h", ALL_LANGUAGES) +LIBBUILTIN(fabsl, "LdLd", "fnc", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(fmod, "ddd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(fmodf, "fff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(fmodl, "LdLdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(frexp, "ddi*", "fn", "math.h", ALL_LANGUAGES) +LIBBUILTIN(frexpf, "ffi*", "fn", "math.h", ALL_LANGUAGES) +LIBBUILTIN(frexpl, "LdLdi*", "fn", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(ldexp, "ddi", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(ldexpf, "ffi", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(ldexpl, "LdLdi", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(modf, "ddd*", "fn", "math.h", ALL_LANGUAGES) +LIBBUILTIN(modff, "fff*", "fn", "math.h", ALL_LANGUAGES) +LIBBUILTIN(modfl, "LdLdLd*", "fn", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(nan, "dcC*", "fnc", "math.h", ALL_LANGUAGES) +LIBBUILTIN(nanf, "fcC*", "fnc", "math.h", ALL_LANGUAGES) +LIBBUILTIN(nanl, "LdcC*", "fnc", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(pow, "ddd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(powf, "fff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(powl, "LdLdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(acos, "dd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(acosf, "ff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(acosl, "LdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(acosh, "dd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(acoshf, "ff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(acoshl, "LdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(asin, "dd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(asinf, "ff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(asinl, "LdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(asinh, "dd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(asinhf, "ff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(asinhl, "LdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(atan, "dd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(atanf, "ff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(atanl, "LdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(atanh, "dd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(atanhf, "ff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(atanhl, "LdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(cbrt, "dd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(cbrtf, "ff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(cbrtl, "LdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(ceil, "dd", "fnc", "math.h", ALL_LANGUAGES) +LIBBUILTIN(ceilf, "ff", "fnc", "math.h", ALL_LANGUAGES) +LIBBUILTIN(ceill, "LdLd", "fnc", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(cos, "dd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(cosf, "ff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(cosl, "LdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(cosh, "dd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(coshf, "ff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(coshl, "LdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(erf, "dd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(erff, "ff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(erfl, "LdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(erfc, "dd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(erfcf, "ff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(erfcl, "LdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(exp, "dd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(expf, "ff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(expl, "LdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(exp2, "dd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(exp2f, "ff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(exp2l, "LdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(expm1, "dd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(expm1f, "ff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(expm1l, "LdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(fdim, "ddd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(fdimf, "fff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(fdiml, "LdLdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(floor, "dd", "fnc", "math.h", ALL_LANGUAGES) +LIBBUILTIN(floorf, "ff", "fnc", "math.h", ALL_LANGUAGES) +LIBBUILTIN(floorl, "LdLd", "fnc", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(fma, "dddd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(fmaf, "ffff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(fmal, "LdLdLdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(fmax, "ddd", "fnc", "math.h", ALL_LANGUAGES) +LIBBUILTIN(fmaxf, "fff", "fnc", "math.h", ALL_LANGUAGES) +LIBBUILTIN(fmaxl, "LdLdLd", "fnc", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(fmin, "ddd", "fnc", "math.h", ALL_LANGUAGES) +LIBBUILTIN(fminf, "fff", "fnc", "math.h", ALL_LANGUAGES) +LIBBUILTIN(fminl, "LdLdLd", "fnc", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(hypot, "ddd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(hypotf, "fff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(hypotl, "LdLdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(ilogb, "id", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(ilogbf, "if", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(ilogbl, "iLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(lgamma, "dd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(lgammaf, "ff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(lgammal, "LdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(llrint, "LLid", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(llrintf, "LLif", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(llrintl, "LLiLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(llround, "LLid", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(llroundf, "LLif", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(llroundl, "LLiLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(log, "dd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(logf, "ff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(logl, "LdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(log10, "dd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(log10f, "ff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(log10l, "LdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(log1p, "dd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(log1pf, "ff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(log1pl, "LdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(log2, "dd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(log2f, "ff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(log2l, "LdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(logb, "dd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(logbf, "ff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(logbl, "LdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(lrint, "Lid", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(lrintf, "Lif", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(lrintl, "LiLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(lround, "Lid", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(lroundf, "Lif", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(lroundl, "LiLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(nearbyint, "dd", "fnc", "math.h", ALL_LANGUAGES) +LIBBUILTIN(nearbyintf, "ff", "fnc", "math.h", ALL_LANGUAGES) +LIBBUILTIN(nearbyintl, "LdLd", "fnc", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(nextafter, "ddd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(nextafterf, "fff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(nextafterl, "LdLdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(nexttoward, "ddLd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(nexttowardf, "ffLd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(nexttowardl, "LdLdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(remainder, "ddd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(remainderf, "fff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(remainderl, "LdLdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(rint, "dd", "fnc", "math.h", ALL_LANGUAGES) +LIBBUILTIN(rintf, "ff", "fnc", "math.h", ALL_LANGUAGES) +LIBBUILTIN(rintl, "LdLd", "fnc", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(round, "dd", "fnc", "math.h", ALL_LANGUAGES) +LIBBUILTIN(roundf, "ff", "fnc", "math.h", ALL_LANGUAGES) +LIBBUILTIN(roundl, "LdLd", "fnc", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(scalbln, "ddLi", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(scalblnf, "ffLi", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(scalblnl, "LdLdLi", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(scalbn, "ddi", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(scalbnf, "ffi", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(scalbnl, "LdLdi", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(sin, "dd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(sinf, "ff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(sinl, "LdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(sinh, "dd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(sinhf, "ff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(sinhl, "LdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(sqrt, "dd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(sqrtf, "ff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(sqrtl, "LdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(tan, "dd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(tanf, "ff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(tanl, "LdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(tanh, "dd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(tanhf, "ff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(tanhl, "LdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(tgamma, "dd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(tgammaf, "ff", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(tgammal, "LdLd", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(trunc, "dd", "fnc", "math.h", ALL_LANGUAGES) +LIBBUILTIN(truncf, "ff", "fnc", "math.h", ALL_LANGUAGES) +LIBBUILTIN(truncl, "LdLd", "fnc", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(cabs, "dXd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cabsf, "fXf", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cabsl, "LdXLd", "fnc", "complex.h", ALL_LANGUAGES) + +LIBBUILTIN(cacos, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cacosf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cacosl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) + +LIBBUILTIN(cacosh, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cacoshf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cacoshl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) + +LIBBUILTIN(carg, "dXd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cargf, "fXf", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cargl, "LdXLd", "fnc", "complex.h", ALL_LANGUAGES) + +LIBBUILTIN(casin, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(casinf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(casinl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) + +LIBBUILTIN(casinh, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(casinhf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(casinhl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) + +LIBBUILTIN(catan, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(catanf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(catanl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) + +LIBBUILTIN(catanh, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(catanhf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(catanhl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) + +LIBBUILTIN(ccos, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(ccosf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(ccosl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) + +LIBBUILTIN(ccosh, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(ccoshf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(ccoshl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) + +LIBBUILTIN(cexp, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cexpf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cexpl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) + +LIBBUILTIN(cimag, "dXd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cimagf, "fXf", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cimagl, "LdXLd", "fnc", "complex.h", ALL_LANGUAGES) + +LIBBUILTIN(conj, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(conjf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(conjl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) + +LIBBUILTIN(clog, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(clogf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(clogl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) + +LIBBUILTIN(cproj, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cprojf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cprojl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) + +LIBBUILTIN(cpow, "XdXdXd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cpowf, "XfXfXf", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cpowl, "XLdXLdXLd", "fnc", "complex.h", ALL_LANGUAGES) + +LIBBUILTIN(creal, "dXd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(crealf, "fXf", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(creall, "LdXLd", "fnc", "complex.h", ALL_LANGUAGES) + +LIBBUILTIN(csin, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(csinf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(csinl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) + +LIBBUILTIN(csinh, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(csinhf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(csinhl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) + +LIBBUILTIN(csqrt, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(csqrtf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(csqrtl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) + +LIBBUILTIN(ctan, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(ctanf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(ctanl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) + +LIBBUILTIN(ctanh, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(ctanhf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(ctanhl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) + +// __sinpi and friends are OS X specific library functions, but otherwise much +// like the standard (non-complex) sin (etc). +LIBBUILTIN(__sinpi, "dd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(__sinpif, "ff", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(__cospi, "dd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(__cospif, "ff", "fne", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(__tanpi, "dd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(__tanpif, "ff", "fne", "math.h", ALL_LANGUAGES) + +// Similarly, __exp10 is OS X only +LIBBUILTIN(__exp10, "dd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(__exp10f, "ff", "fne", "math.h", ALL_LANGUAGES) + +// Blocks runtime Builtin math library functions +LIBBUILTIN(_Block_object_assign, "vv*vC*iC", "f", "Blocks.h", ALL_LANGUAGES) +LIBBUILTIN(_Block_object_dispose, "vvC*iC", "f", "Blocks.h", ALL_LANGUAGES) +// FIXME: Also declare NSConcreteGlobalBlock and NSConcreteStackBlock. + +// Annotation function +BUILTIN(__builtin_annotation, "v.", "tn") + +// Invariants +BUILTIN(__builtin_assume, "vb", "n") + +// Multiprecision Arithmetic Builtins. +BUILTIN(__builtin_addcb, "UcUcCUcCUcCUc*", "n") +BUILTIN(__builtin_addcs, "UsUsCUsCUsCUs*", "n") +BUILTIN(__builtin_addc, "UiUiCUiCUiCUi*", "n") +BUILTIN(__builtin_addcl, "ULiULiCULiCULiCULi*", "n") +BUILTIN(__builtin_addcll, "ULLiULLiCULLiCULLiCULLi*", "n") +BUILTIN(__builtin_subcb, "UcUcCUcCUcCUc*", "n") +BUILTIN(__builtin_subcs, "UsUsCUsCUsCUs*", "n") +BUILTIN(__builtin_subc, "UiUiCUiCUiCUi*", "n") +BUILTIN(__builtin_subcl, "ULiULiCULiCULiCULi*", "n") +BUILTIN(__builtin_subcll, "ULLiULLiCULLiCULLiCULLi*", "n") + +// Checked Arithmetic Builtins for Security. +BUILTIN(__builtin_add_overflow, "v.", "nt") +BUILTIN(__builtin_sub_overflow, "v.", "nt") +BUILTIN(__builtin_mul_overflow, "v.", "nt") +BUILTIN(__builtin_uadd_overflow, "bUiCUiCUi*", "n") +BUILTIN(__builtin_uaddl_overflow, "bULiCULiCULi*", "n") +BUILTIN(__builtin_uaddll_overflow, "bULLiCULLiCULLi*", "n") +BUILTIN(__builtin_usub_overflow, "bUiCUiCUi*", "n") +BUILTIN(__builtin_usubl_overflow, "bULiCULiCULi*", "n") +BUILTIN(__builtin_usubll_overflow, "bULLiCULLiCULLi*", "n") +BUILTIN(__builtin_umul_overflow, "bUiCUiCUi*", "n") +BUILTIN(__builtin_umull_overflow, "bULiCULiCULi*", "n") +BUILTIN(__builtin_umulll_overflow, "bULLiCULLiCULLi*", "n") +BUILTIN(__builtin_sadd_overflow, "bSiCSiCSi*", "n") +BUILTIN(__builtin_saddl_overflow, "bSLiCSLiCSLi*", "n") +BUILTIN(__builtin_saddll_overflow, "bSLLiCSLLiCSLLi*", "n") +BUILTIN(__builtin_ssub_overflow, "bSiCSiCSi*", "n") +BUILTIN(__builtin_ssubl_overflow, "bSLiCSLiCSLi*", "n") +BUILTIN(__builtin_ssubll_overflow, "bSLLiCSLLiCSLLi*", "n") +BUILTIN(__builtin_smul_overflow, "bSiCSiCSi*", "n") +BUILTIN(__builtin_smull_overflow, "bSLiCSLiCSLi*", "n") +BUILTIN(__builtin_smulll_overflow, "bSLLiCSLLiCSLLi*", "n") + +// Clang builtins (not available in GCC). +BUILTIN(__builtin_addressof, "v*v&", "nct") +BUILTIN(__builtin_operator_new, "v*z", "c") +BUILTIN(__builtin_operator_delete, "vv*", "n") + +// Safestack builtins +BUILTIN(__builtin___get_unsafe_stack_start, "v*", "Fn") +BUILTIN(__builtin___get_unsafe_stack_ptr, "v*", "Fn") + +// Nontemporal loads/stores builtins +BUILTIN(__builtin_nontemporal_store, "v.", "t") +BUILTIN(__builtin_nontemporal_load, "v.", "t") + +#undef BUILTIN +#undef LIBBUILTIN +#undef LANGBUILTIN diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Builtins.h b/contrib/llvm/tools/clang/include/clang/Basic/Builtins.h new file mode 100644 index 0000000..c0a6af9 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/Builtins.h @@ -0,0 +1,220 @@ +//===--- Builtins.h - Builtin function header -------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines enum values for all the target-independent builtin +/// functions. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_BUILTINS_H +#define LLVM_CLANG_BASIC_BUILTINS_H + +#include "llvm/ADT/ArrayRef.h" +#include <cstring> + +// VC++ defines 'alloca' as an object-like macro, which interferes with our +// builtins. +#undef alloca + +namespace clang { +class TargetInfo; +class IdentifierTable; +class ASTContext; +class QualType; +class LangOptions; + +enum LanguageID { + GNU_LANG = 0x1, // builtin requires GNU mode. + C_LANG = 0x2, // builtin for c only. + CXX_LANG = 0x4, // builtin for cplusplus only. + OBJC_LANG = 0x8, // builtin for objective-c and objective-c++ + MS_LANG = 0x10, // builtin requires MS mode. + ALL_LANGUAGES = C_LANG | CXX_LANG | OBJC_LANG, // builtin for all languages. + ALL_GNU_LANGUAGES = ALL_LANGUAGES | GNU_LANG, // builtin requires GNU mode. + ALL_MS_LANGUAGES = ALL_LANGUAGES | MS_LANG // builtin requires MS mode. +}; + +namespace Builtin { +enum ID { + NotBuiltin = 0, // This is not a builtin function. +#define BUILTIN(ID, TYPE, ATTRS) BI##ID, +#include "clang/Basic/Builtins.def" + FirstTSBuiltin +}; + +struct Info { + const char *Name, *Type, *Attributes, *HeaderName; + LanguageID Langs; + const char *Features; +}; + +/// \brief Holds information about both target-independent and +/// target-specific builtins, allowing easy queries by clients. +/// +/// Builtins from an optional auxiliary target are stored in +/// AuxTSRecords. Their IDs are shifted up by TSRecords.size() and need to +/// be translated back with getAuxBuiltinID() before use. +class Context { + llvm::ArrayRef<Info> TSRecords; + llvm::ArrayRef<Info> AuxTSRecords; + +public: + Context() {} + + /// \brief Perform target-specific initialization + /// \param AuxTarget Target info to incorporate builtins from. May be nullptr. + void InitializeTarget(const TargetInfo &Target, const TargetInfo *AuxTarget); + + /// \brief Mark the identifiers for all the builtins with their + /// appropriate builtin ID # and mark any non-portable builtin identifiers as + /// such. + void initializeBuiltins(IdentifierTable &Table, const LangOptions& LangOpts); + + /// \brief Return the identifier name for the specified builtin, + /// e.g. "__builtin_abs". + const char *getName(unsigned ID) const { + return getRecord(ID).Name; + } + + /// \brief Get the type descriptor string for the specified builtin. + const char *getTypeString(unsigned ID) const { + return getRecord(ID).Type; + } + + /// \brief Return true if this function is a target-specific builtin + bool isTSBuiltin(unsigned ID) const { + return ID >= Builtin::FirstTSBuiltin; + } + + /// \brief Return true if this function has no side effects and doesn't + /// read memory. + bool isConst(unsigned ID) const { + return strchr(getRecord(ID).Attributes, 'c') != nullptr; + } + + /// \brief Return true if we know this builtin never throws an exception. + bool isNoThrow(unsigned ID) const { + return strchr(getRecord(ID).Attributes, 'n') != nullptr; + } + + /// \brief Return true if we know this builtin never returns. + bool isNoReturn(unsigned ID) const { + return strchr(getRecord(ID).Attributes, 'r') != nullptr; + } + + /// \brief Return true if we know this builtin can return twice. + bool isReturnsTwice(unsigned ID) const { + return strchr(getRecord(ID).Attributes, 'j') != nullptr; + } + + /// \brief Returns true if this builtin does not perform the side-effects + /// of its arguments. + bool isUnevaluated(unsigned ID) const { + return strchr(getRecord(ID).Attributes, 'u') != nullptr; + } + + /// \brief Return true if this is a builtin for a libc/libm function, + /// with a "__builtin_" prefix (e.g. __builtin_abs). + bool isLibFunction(unsigned ID) const { + return strchr(getRecord(ID).Attributes, 'F') != nullptr; + } + + /// \brief Determines whether this builtin is a predefined libc/libm + /// function, such as "malloc", where we know the signature a + /// priori. + bool isPredefinedLibFunction(unsigned ID) const { + return strchr(getRecord(ID).Attributes, 'f') != nullptr; + } + + /// \brief Determines whether this builtin is a predefined compiler-rt/libgcc + /// function, such as "__clear_cache", where we know the signature a + /// priori. + bool isPredefinedRuntimeFunction(unsigned ID) const { + return strchr(getRecord(ID).Attributes, 'i') != nullptr; + } + + /// \brief Determines whether this builtin has custom typechecking. + bool hasCustomTypechecking(unsigned ID) const { + return strchr(getRecord(ID).Attributes, 't') != nullptr; + } + + /// \brief Determines whether this builtin has a result or any arguments which + /// are pointer types. + bool hasPtrArgsOrResult(unsigned ID) const { + return strchr(getRecord(ID).Type, '*') != nullptr; + } + + /// \brief Completely forget that the given ID was ever considered a builtin, + /// e.g., because the user provided a conflicting signature. + void forgetBuiltin(unsigned ID, IdentifierTable &Table); + + /// \brief If this is a library function that comes from a specific + /// header, retrieve that header name. + const char *getHeaderName(unsigned ID) const { + return getRecord(ID).HeaderName; + } + + /// \brief Determine whether this builtin is like printf in its + /// formatting rules and, if so, set the index to the format string + /// argument and whether this function as a va_list argument. + bool isPrintfLike(unsigned ID, unsigned &FormatIdx, bool &HasVAListArg); + + /// \brief Determine whether this builtin is like scanf in its + /// formatting rules and, if so, set the index to the format string + /// argument and whether this function as a va_list argument. + bool isScanfLike(unsigned ID, unsigned &FormatIdx, bool &HasVAListArg); + + /// \brief Return true if this function has no side effects and doesn't + /// read memory, except for possibly errno. + /// + /// Such functions can be const when the MathErrno lang option is disabled. + bool isConstWithoutErrno(unsigned ID) const { + return strchr(getRecord(ID).Attributes, 'e') != nullptr; + } + + const char *getRequiredFeatures(unsigned ID) const { + return getRecord(ID).Features; + } + + /// \brief Return true if builtin ID belongs to AuxTarget. + bool isAuxBuiltinID(unsigned ID) const { + return ID >= (Builtin::FirstTSBuiltin + TSRecords.size()); + } + + /// Return real buitin ID (i.e. ID it would have furing compilation + /// for AuxTarget). + unsigned getAuxBuiltinID(unsigned ID) const { return ID - TSRecords.size(); } + + /// Returns true if this is a libc/libm function without the '__builtin_' + /// prefix. + static bool isBuiltinFunc(const char *Name); + +private: + const Info &getRecord(unsigned ID) const; + + /// \brief Is this builtin supported according to the given language options? + bool builtinIsSupported(const Builtin::Info &BuiltinInfo, + const LangOptions &LangOpts); + + /// \brief Helper function for isPrintfLike and isScanfLike. + bool isLike(unsigned ID, unsigned &FormatIdx, bool &HasVAListArg, + const char *Fmt) const; +}; + +} + +/// \brief Kinds of BuiltinTemplateDecl. +enum BuiltinTemplateKind : int { + /// \brief This names the __make_integer_seq BuiltinTemplateDecl. + BTK__make_integer_seq +}; + +} // end namespace clang +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsAArch64.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsAArch64.def new file mode 100644 index 0000000..b440443 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsAArch64.def @@ -0,0 +1,65 @@ +//==- BuiltinsAArch64.def - AArch64 Builtin function database ----*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the AArch64-specific builtin function database. Users of +// this file must define the BUILTIN macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +// The format of this database matches clang/Basic/Builtins.def. + +// In libgcc +BUILTIN(__clear_cache, "vv*v*", "i") + +BUILTIN(__builtin_arm_ldrex, "v.", "t") +BUILTIN(__builtin_arm_ldaex, "v.", "t") +BUILTIN(__builtin_arm_strex, "i.", "t") +BUILTIN(__builtin_arm_stlex, "i.", "t") +BUILTIN(__builtin_arm_clrex, "v", "") + +// Bit manipulation +BUILTIN(__builtin_arm_rbit, "UiUi", "nc") +BUILTIN(__builtin_arm_rbit64, "LUiLUi", "nc") + +// HINT +BUILTIN(__builtin_arm_nop, "v", "") +BUILTIN(__builtin_arm_yield, "v", "") +BUILTIN(__builtin_arm_wfe, "v", "") +BUILTIN(__builtin_arm_wfi, "v", "") +BUILTIN(__builtin_arm_sev, "v", "") +BUILTIN(__builtin_arm_sevl, "v", "") + +// CRC32 +BUILTIN(__builtin_arm_crc32b, "UiUiUc", "nc") +BUILTIN(__builtin_arm_crc32cb, "UiUiUc", "nc") +BUILTIN(__builtin_arm_crc32h, "UiUiUs", "nc") +BUILTIN(__builtin_arm_crc32ch, "UiUiUs", "nc") +BUILTIN(__builtin_arm_crc32w, "UiUiUi", "nc") +BUILTIN(__builtin_arm_crc32cw, "UiUiUi", "nc") +BUILTIN(__builtin_arm_crc32d, "UiUiLUi", "nc") +BUILTIN(__builtin_arm_crc32cd, "UiUiLUi", "nc") + +// Memory barrier +BUILTIN(__builtin_arm_dmb, "vUi", "nc") +BUILTIN(__builtin_arm_dsb, "vUi", "nc") +BUILTIN(__builtin_arm_isb, "vUi", "nc") + +// Prefetch +BUILTIN(__builtin_arm_prefetch, "vvC*UiUiUiUi", "nc") + +// System Registers +BUILTIN(__builtin_arm_rsr, "UicC*", "nc") +BUILTIN(__builtin_arm_rsr64, "LUicC*", "nc") +BUILTIN(__builtin_arm_rsrp, "v*cC*", "nc") +BUILTIN(__builtin_arm_wsr, "vcC*Ui", "nc") +BUILTIN(__builtin_arm_wsr64, "vcC*LUi", "nc") +BUILTIN(__builtin_arm_wsrp, "vcC*vC*", "nc") +BUILTIN(__builtin_thread_pointer, "v*", "nc") + +#undef BUILTIN diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsAMDGPU.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsAMDGPU.def new file mode 100644 index 0000000..bb9931f --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsAMDGPU.def @@ -0,0 +1,36 @@ +//==- BuiltinsAMDGPU.def - AMDGPU Builtin function database ------*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the R600-specific builtin function database. Users of this +// file must define the BUILTIN macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +// The format of this database matches clang/Basic/Builtins.def. + +BUILTIN(__builtin_amdgpu_div_scale, "dddbb*", "n") +BUILTIN(__builtin_amdgpu_div_scalef, "fffbb*", "n") +BUILTIN(__builtin_amdgpu_div_fmas, "ddddb", "nc") +BUILTIN(__builtin_amdgpu_div_fmasf, "ffffb", "nc") +BUILTIN(__builtin_amdgpu_div_fixup, "dddd", "nc") +BUILTIN(__builtin_amdgpu_div_fixupf, "ffff", "nc") +BUILTIN(__builtin_amdgpu_trig_preop, "ddi", "nc") +BUILTIN(__builtin_amdgpu_trig_preopf, "ffi", "nc") +BUILTIN(__builtin_amdgpu_rcp, "dd", "nc") +BUILTIN(__builtin_amdgpu_rcpf, "ff", "nc") +BUILTIN(__builtin_amdgpu_rsq, "dd", "nc") +BUILTIN(__builtin_amdgpu_rsqf, "ff", "nc") +BUILTIN(__builtin_amdgpu_rsq_clamped, "dd", "nc") +BUILTIN(__builtin_amdgpu_rsq_clampedf, "ff", "nc") +BUILTIN(__builtin_amdgpu_ldexp, "ddi", "nc") +BUILTIN(__builtin_amdgpu_ldexpf, "ffi", "nc") +BUILTIN(__builtin_amdgpu_class, "bdi", "nc") +BUILTIN(__builtin_amdgpu_classf, "bfi", "nc") + +#undef BUILTIN diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsARM.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsARM.def new file mode 100644 index 0000000..3e8e2bf --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsARM.def @@ -0,0 +1,114 @@ +//===--- BuiltinsARM.def - ARM Builtin function database ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ARM-specific builtin function database. Users of +// this file must define the BUILTIN macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +// The format of this database matches clang/Basic/Builtins.def. + +#if defined(BUILTIN) && !defined(LANGBUILTIN) +# define LANGBUILTIN(ID, TYPE, ATTRS, BUILTIN_LANG) BUILTIN(ID, TYPE, ATTRS) +#endif + +// In libgcc +BUILTIN(__clear_cache, "vv*v*", "i") +BUILTIN(__builtin_thread_pointer, "v*", "") + +// Saturating arithmetic +BUILTIN(__builtin_arm_qadd, "iii", "nc") +BUILTIN(__builtin_arm_qsub, "iii", "nc") +BUILTIN(__builtin_arm_ssat, "iiUi", "nc") +BUILTIN(__builtin_arm_usat, "UiUiUi", "nc") + +// Bit manipulation +BUILTIN(__builtin_arm_rbit, "UiUi", "nc") + +// Store and load exclusive +BUILTIN(__builtin_arm_ldrexd, "LLUiv*", "") +BUILTIN(__builtin_arm_strexd, "iLLUiv*", "") + +BUILTIN(__builtin_arm_ldrex, "v.", "t") +BUILTIN(__builtin_arm_ldaex, "v.", "t") +BUILTIN(__builtin_arm_strex, "i.", "t") +BUILTIN(__builtin_arm_stlex, "i.", "t") +BUILTIN(__builtin_arm_clrex, "v", "") + +// VFP +BUILTIN(__builtin_arm_get_fpscr, "Ui", "nc") +BUILTIN(__builtin_arm_set_fpscr, "vUi", "nc") +BUILTIN(__builtin_arm_vcvtr_f, "ffi", "nc") +BUILTIN(__builtin_arm_vcvtr_d, "fdi", "nc") + +// Coprocessor +BUILTIN(__builtin_arm_mcr, "vUIiUIiUiUIiUIiUIi", "") +BUILTIN(__builtin_arm_mcr2, "vUIiUIiUiUIiUIiUIi", "") +BUILTIN(__builtin_arm_mrc, "UiUIiUIiUIiUIiUIi", "") +BUILTIN(__builtin_arm_mrc2, "UiUIiUIiUIiUIiUIi", "") +BUILTIN(__builtin_arm_cdp, "vUiUiUiUiUiUi", "") +BUILTIN(__builtin_arm_cdp2, "vUiUiUiUiUiUi", "") +BUILTIN(__builtin_arm_mcrr, "vUIiUIiUiUiUIi", "") +BUILTIN(__builtin_arm_mcrr2, "vUIiUIiUiUiUIi", "") + +// CRC32 +BUILTIN(__builtin_arm_crc32b, "UiUiUc", "nc") +BUILTIN(__builtin_arm_crc32cb, "UiUiUc", "nc") +BUILTIN(__builtin_arm_crc32h, "UiUiUs", "nc") +BUILTIN(__builtin_arm_crc32ch, "UiUiUs", "nc") +BUILTIN(__builtin_arm_crc32w, "UiUiUi", "nc") +BUILTIN(__builtin_arm_crc32cw, "UiUiUi", "nc") +BUILTIN(__builtin_arm_crc32d, "UiUiLLUi", "nc") +BUILTIN(__builtin_arm_crc32cd, "UiUiLLUi", "nc") + +// HINT +BUILTIN(__builtin_arm_nop, "v", "") +BUILTIN(__builtin_arm_yield, "v", "") +BUILTIN(__builtin_arm_wfe, "v", "") +BUILTIN(__builtin_arm_wfi, "v", "") +BUILTIN(__builtin_arm_sev, "v", "") +BUILTIN(__builtin_arm_sevl, "v", "") +BUILTIN(__builtin_arm_dbg, "vUi", "") + +// Data barrier +BUILTIN(__builtin_arm_dmb, "vUi", "nc") +BUILTIN(__builtin_arm_dsb, "vUi", "nc") +BUILTIN(__builtin_arm_isb, "vUi", "nc") + +// Prefetch +BUILTIN(__builtin_arm_prefetch, "vvC*UiUi", "nc") + +// System registers (ACLE) +BUILTIN(__builtin_arm_rsr, "UicC*", "nc") +BUILTIN(__builtin_arm_rsr64, "LLUicC*", "nc") +BUILTIN(__builtin_arm_rsrp, "v*cC*", "nc") +BUILTIN(__builtin_arm_wsr, "vcC*Ui", "nc") +BUILTIN(__builtin_arm_wsr64, "vcC*LLUi", "nc") +BUILTIN(__builtin_arm_wsrp, "vcC*vC*", "nc") + +// MSVC +LANGBUILTIN(__emit, "vIUiC", "", ALL_MS_LANGUAGES) + +LANGBUILTIN(__yield, "v", "", ALL_MS_LANGUAGES) +LANGBUILTIN(__wfe, "v", "", ALL_MS_LANGUAGES) +LANGBUILTIN(__wfi, "v", "", ALL_MS_LANGUAGES) +LANGBUILTIN(__sev, "v", "", ALL_MS_LANGUAGES) +LANGBUILTIN(__sevl, "v", "", ALL_MS_LANGUAGES) + +LANGBUILTIN(__dmb, "vUi", "nc", ALL_MS_LANGUAGES) +LANGBUILTIN(__dsb, "vUi", "nc", ALL_MS_LANGUAGES) +LANGBUILTIN(__isb, "vUi", "nc", ALL_MS_LANGUAGES) +LANGBUILTIN(__ldrexd, "WiWiCD*", "", ALL_MS_LANGUAGES) +LANGBUILTIN(_MoveFromCoprocessor, "UiIUiIUiIUiIUiIUi", "", ALL_MS_LANGUAGES) +LANGBUILTIN(_MoveFromCoprocessor2, "UiIUiIUiIUiIUiIUi", "", ALL_MS_LANGUAGES) +LANGBUILTIN(_MoveToCoprocessor, "vUiIUiIUiIUiIUiIUi", "", ALL_MS_LANGUAGES) +LANGBUILTIN(_MoveToCoprocessor2, "vUiIUiIUiIUiIUiIUi", "", ALL_MS_LANGUAGES) + +#undef BUILTIN +#undef LANGBUILTIN diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsHexagon.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsHexagon.def new file mode 100644 index 0000000..c071a46 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsHexagon.def @@ -0,0 +1,878 @@ +//===-- BuiltinsHexagon.def - Hexagon Builtin function database --*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Hexagon-specific builtin function database. Users of +// this file must define the BUILTIN macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +// The format of this database matches clang/Basic/Builtins.def. + +// The builtins below are not autogenerated from iset.py. +// Make sure you do not overwrite these. + +BUILTIN(__builtin_SI_to_SXTHI_asrh, "ii", "") +BUILTIN(__builtin_circ_ldd, "LLi*LLi*LLi*ii", "") + +// The builtins above are not autogenerated from iset.py. +// Make sure you do not overwrite these. + +BUILTIN(__builtin_HEXAGON_C2_cmpeq,"bii","") +BUILTIN(__builtin_HEXAGON_C2_cmpgt,"bii","") +BUILTIN(__builtin_HEXAGON_C2_cmpgtu,"bii","") +BUILTIN(__builtin_HEXAGON_C2_cmpeqp,"bLLiLLi","") +BUILTIN(__builtin_HEXAGON_C2_cmpgtp,"bLLiLLi","") +BUILTIN(__builtin_HEXAGON_C2_cmpgtup,"bLLiLLi","") +BUILTIN(__builtin_HEXAGON_A4_rcmpeqi,"iii","") +BUILTIN(__builtin_HEXAGON_A4_rcmpneqi,"iii","") +BUILTIN(__builtin_HEXAGON_A4_rcmpeq,"iii","") +BUILTIN(__builtin_HEXAGON_A4_rcmpneq,"iii","") +BUILTIN(__builtin_HEXAGON_C2_bitsset,"bii","") +BUILTIN(__builtin_HEXAGON_C2_bitsclr,"bii","") +BUILTIN(__builtin_HEXAGON_C4_nbitsset,"bii","") +BUILTIN(__builtin_HEXAGON_C4_nbitsclr,"bii","") +BUILTIN(__builtin_HEXAGON_C2_cmpeqi,"bii","") +BUILTIN(__builtin_HEXAGON_C2_cmpgti,"bii","") +BUILTIN(__builtin_HEXAGON_C2_cmpgtui,"bii","") +BUILTIN(__builtin_HEXAGON_C2_cmpgei,"bii","") +BUILTIN(__builtin_HEXAGON_C2_cmpgeui,"bii","") +BUILTIN(__builtin_HEXAGON_C2_cmplt,"bii","") +BUILTIN(__builtin_HEXAGON_C2_cmpltu,"bii","") +BUILTIN(__builtin_HEXAGON_C2_bitsclri,"bii","") +BUILTIN(__builtin_HEXAGON_C4_nbitsclri,"bii","") +BUILTIN(__builtin_HEXAGON_C4_cmpneqi,"bii","") +BUILTIN(__builtin_HEXAGON_C4_cmpltei,"bii","") +BUILTIN(__builtin_HEXAGON_C4_cmplteui,"bii","") +BUILTIN(__builtin_HEXAGON_C4_cmpneq,"bii","") +BUILTIN(__builtin_HEXAGON_C4_cmplte,"bii","") +BUILTIN(__builtin_HEXAGON_C4_cmplteu,"bii","") +BUILTIN(__builtin_HEXAGON_C2_and,"bii","") +BUILTIN(__builtin_HEXAGON_C2_or,"bii","") +BUILTIN(__builtin_HEXAGON_C2_xor,"bii","") +BUILTIN(__builtin_HEXAGON_C2_andn,"bii","") +BUILTIN(__builtin_HEXAGON_C2_not,"bi","") +BUILTIN(__builtin_HEXAGON_C2_orn,"bii","") +BUILTIN(__builtin_HEXAGON_C4_and_and,"biii","") +BUILTIN(__builtin_HEXAGON_C4_and_or,"biii","") +BUILTIN(__builtin_HEXAGON_C4_or_and,"biii","") +BUILTIN(__builtin_HEXAGON_C4_or_or,"biii","") +BUILTIN(__builtin_HEXAGON_C4_and_andn,"biii","") +BUILTIN(__builtin_HEXAGON_C4_and_orn,"biii","") +BUILTIN(__builtin_HEXAGON_C4_or_andn,"biii","") +BUILTIN(__builtin_HEXAGON_C4_or_orn,"biii","") +BUILTIN(__builtin_HEXAGON_C2_pxfer_map,"bi","") +BUILTIN(__builtin_HEXAGON_C2_any8,"bi","") +BUILTIN(__builtin_HEXAGON_C2_all8,"bi","") +BUILTIN(__builtin_HEXAGON_C2_vitpack,"iii","") +BUILTIN(__builtin_HEXAGON_C2_mux,"iiii","") +BUILTIN(__builtin_HEXAGON_C2_muxii,"iiii","") +BUILTIN(__builtin_HEXAGON_C2_muxir,"iiii","") +BUILTIN(__builtin_HEXAGON_C2_muxri,"iiii","") +BUILTIN(__builtin_HEXAGON_C2_vmux,"LLiiLLiLLi","") +BUILTIN(__builtin_HEXAGON_C2_mask,"LLii","") +BUILTIN(__builtin_HEXAGON_A2_vcmpbeq,"bLLiLLi","") +BUILTIN(__builtin_HEXAGON_A4_vcmpbeqi,"bLLii","") +BUILTIN(__builtin_HEXAGON_A4_vcmpbeq_any,"bLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vcmpbgtu,"bLLiLLi","") +BUILTIN(__builtin_HEXAGON_A4_vcmpbgtui,"bLLii","") +BUILTIN(__builtin_HEXAGON_A4_vcmpbgt,"bLLiLLi","") +BUILTIN(__builtin_HEXAGON_A4_vcmpbgti,"bLLii","") +BUILTIN(__builtin_HEXAGON_A4_cmpbeq,"bii","") +BUILTIN(__builtin_HEXAGON_A4_cmpbeqi,"bii","") +BUILTIN(__builtin_HEXAGON_A4_cmpbgtu,"bii","") +BUILTIN(__builtin_HEXAGON_A4_cmpbgtui,"bii","") +BUILTIN(__builtin_HEXAGON_A4_cmpbgt,"bii","") +BUILTIN(__builtin_HEXAGON_A4_cmpbgti,"bii","") +BUILTIN(__builtin_HEXAGON_A2_vcmpheq,"bLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vcmphgt,"bLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vcmphgtu,"bLLiLLi","") +BUILTIN(__builtin_HEXAGON_A4_vcmpheqi,"bLLii","") +BUILTIN(__builtin_HEXAGON_A4_vcmphgti,"bLLii","") +BUILTIN(__builtin_HEXAGON_A4_vcmphgtui,"bLLii","") +BUILTIN(__builtin_HEXAGON_A4_cmpheq,"bii","") +BUILTIN(__builtin_HEXAGON_A4_cmphgt,"bii","") +BUILTIN(__builtin_HEXAGON_A4_cmphgtu,"bii","") +BUILTIN(__builtin_HEXAGON_A4_cmpheqi,"bii","") +BUILTIN(__builtin_HEXAGON_A4_cmphgti,"bii","") +BUILTIN(__builtin_HEXAGON_A4_cmphgtui,"bii","") +BUILTIN(__builtin_HEXAGON_A2_vcmpweq,"bLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vcmpwgt,"bLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vcmpwgtu,"bLLiLLi","") +BUILTIN(__builtin_HEXAGON_A4_vcmpweqi,"bLLii","") +BUILTIN(__builtin_HEXAGON_A4_vcmpwgti,"bLLii","") +BUILTIN(__builtin_HEXAGON_A4_vcmpwgtui,"bLLii","") +BUILTIN(__builtin_HEXAGON_A4_boundscheck,"biLLi","") +BUILTIN(__builtin_HEXAGON_A4_tlbmatch,"bLLii","") +BUILTIN(__builtin_HEXAGON_C2_tfrpr,"ii","") +BUILTIN(__builtin_HEXAGON_C2_tfrrp,"bi","") +BUILTIN(__builtin_HEXAGON_C4_fastcorner9,"bii","") +BUILTIN(__builtin_HEXAGON_C4_fastcorner9_not,"bii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_acc_hh_s0,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_acc_hh_s1,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_acc_hl_s0,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_acc_hl_s1,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_acc_lh_s0,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_acc_lh_s1,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_acc_ll_s0,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_acc_ll_s1,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_nac_hh_s0,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_nac_hh_s1,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_nac_hl_s0,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_nac_hl_s1,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_nac_lh_s0,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_nac_lh_s1,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_nac_ll_s0,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_nac_ll_s1,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_acc_sat_hh_s0,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_acc_sat_hh_s1,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_acc_sat_hl_s0,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_acc_sat_hl_s1,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_acc_sat_lh_s0,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_acc_sat_lh_s1,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_acc_sat_ll_s0,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_acc_sat_ll_s1,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_nac_sat_hh_s0,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_nac_sat_hh_s1,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_nac_sat_hl_s0,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_nac_sat_hl_s1,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_nac_sat_lh_s0,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_nac_sat_lh_s1,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_nac_sat_ll_s0,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_nac_sat_ll_s1,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_hh_s0,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_hh_s1,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_hl_s0,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_hl_s1,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_lh_s0,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_lh_s1,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_ll_s0,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_ll_s1,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_sat_hh_s0,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_sat_hh_s1,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_sat_hl_s0,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_sat_hl_s1,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_sat_lh_s0,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_sat_lh_s1,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_sat_ll_s0,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_sat_ll_s1,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_rnd_hh_s0,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_rnd_hh_s1,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_rnd_hl_s0,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_rnd_hl_s1,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_rnd_lh_s0,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_rnd_lh_s1,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_rnd_ll_s0,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_rnd_ll_s1,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_sat_rnd_hh_s0,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_sat_rnd_hh_s1,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_sat_rnd_hl_s0,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_sat_rnd_hl_s1,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_sat_rnd_lh_s0,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_sat_rnd_lh_s1,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_sat_rnd_ll_s0,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_sat_rnd_ll_s1,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpyd_acc_hh_s0,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyd_acc_hh_s1,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyd_acc_hl_s0,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyd_acc_hl_s1,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyd_acc_lh_s0,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyd_acc_lh_s1,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyd_acc_ll_s0,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyd_acc_ll_s1,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyd_nac_hh_s0,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyd_nac_hh_s1,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyd_nac_hl_s0,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyd_nac_hl_s1,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyd_nac_lh_s0,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyd_nac_lh_s1,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyd_nac_ll_s0,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyd_nac_ll_s1,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyd_hh_s0,"LLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyd_hh_s1,"LLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyd_hl_s0,"LLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyd_hl_s1,"LLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyd_lh_s0,"LLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyd_lh_s1,"LLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyd_ll_s0,"LLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyd_ll_s1,"LLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyd_rnd_hh_s0,"LLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyd_rnd_hh_s1,"LLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyd_rnd_hl_s0,"LLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyd_rnd_hl_s1,"LLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyd_rnd_lh_s0,"LLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyd_rnd_lh_s1,"LLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyd_rnd_ll_s0,"LLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyd_rnd_ll_s1,"LLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyu_acc_hh_s0,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyu_acc_hh_s1,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyu_acc_hl_s0,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyu_acc_hl_s1,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyu_acc_lh_s0,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyu_acc_lh_s1,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyu_acc_ll_s0,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyu_acc_ll_s1,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyu_nac_hh_s0,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyu_nac_hh_s1,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyu_nac_hl_s0,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyu_nac_hl_s1,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyu_nac_lh_s0,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyu_nac_lh_s1,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyu_nac_ll_s0,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyu_nac_ll_s1,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyu_hh_s0,"Uiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyu_hh_s1,"Uiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyu_hl_s0,"Uiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyu_hl_s1,"Uiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyu_lh_s0,"Uiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyu_lh_s1,"Uiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyu_ll_s0,"Uiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyu_ll_s1,"Uiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyud_acc_hh_s0,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyud_acc_hh_s1,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyud_acc_hl_s0,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyud_acc_hl_s1,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyud_acc_lh_s0,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyud_acc_lh_s1,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyud_acc_ll_s0,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyud_acc_ll_s1,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyud_nac_hh_s0,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyud_nac_hh_s1,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyud_nac_hl_s0,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyud_nac_hl_s1,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyud_nac_lh_s0,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyud_nac_lh_s1,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyud_nac_ll_s0,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyud_nac_ll_s1,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyud_hh_s0,"ULLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyud_hh_s1,"ULLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyud_hl_s0,"ULLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyud_hl_s1,"ULLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyud_lh_s0,"ULLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyud_lh_s1,"ULLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyud_ll_s0,"ULLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyud_ll_s1,"ULLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpysmi,"iii","") +BUILTIN(__builtin_HEXAGON_M2_macsip,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_macsin,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_dpmpyss_s0,"LLiii","") +BUILTIN(__builtin_HEXAGON_M2_dpmpyss_acc_s0,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_dpmpyss_nac_s0,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_dpmpyuu_s0,"ULLiii","") +BUILTIN(__builtin_HEXAGON_M2_dpmpyuu_acc_s0,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_dpmpyuu_nac_s0,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_up,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_up_s1,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpy_up_s1_sat,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpyu_up,"Uiii","") +BUILTIN(__builtin_HEXAGON_M2_mpysu_up,"iii","") +BUILTIN(__builtin_HEXAGON_M2_dpmpyss_rnd_s0,"iii","") +BUILTIN(__builtin_HEXAGON_M4_mac_up_s1_sat,"iiii","") +BUILTIN(__builtin_HEXAGON_M4_nac_up_s1_sat,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_mpyi,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mpyui,"iii","") +BUILTIN(__builtin_HEXAGON_M2_maci,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_acci,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_accii,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_nacci,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_naccii,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_subacc,"iiii","") +BUILTIN(__builtin_HEXAGON_M4_mpyrr_addr,"iiii","") +BUILTIN(__builtin_HEXAGON_M4_mpyri_addr_u2,"iiii","") +BUILTIN(__builtin_HEXAGON_M4_mpyri_addr,"iiii","") +BUILTIN(__builtin_HEXAGON_M4_mpyri_addi,"iiii","") +BUILTIN(__builtin_HEXAGON_M4_mpyrr_addi,"iiii","") +BUILTIN(__builtin_HEXAGON_M2_vmpy2s_s0,"LLiii","") +BUILTIN(__builtin_HEXAGON_M2_vmpy2s_s1,"LLiii","") +BUILTIN(__builtin_HEXAGON_M2_vmac2s_s0,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_vmac2s_s1,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_vmpy2su_s0,"LLiii","") +BUILTIN(__builtin_HEXAGON_M2_vmpy2su_s1,"LLiii","") +BUILTIN(__builtin_HEXAGON_M2_vmac2su_s0,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_vmac2su_s1,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_vmpy2s_s0pack,"iii","") +BUILTIN(__builtin_HEXAGON_M2_vmpy2s_s1pack,"iii","") +BUILTIN(__builtin_HEXAGON_M2_vmac2,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_vmpy2es_s0,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_vmpy2es_s1,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_vmac2es_s0,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_vmac2es_s1,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_vmac2es,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_vrmac_s0,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_vrmpy_s0,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_vdmpyrs_s0,"iLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_vdmpyrs_s1,"iLLiLLi","") +BUILTIN(__builtin_HEXAGON_M5_vrmpybuu,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M5_vrmacbuu,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M5_vrmpybsu,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M5_vrmacbsu,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M5_vmpybuu,"LLiii","") +BUILTIN(__builtin_HEXAGON_M5_vmpybsu,"LLiii","") +BUILTIN(__builtin_HEXAGON_M5_vmacbuu,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M5_vmacbsu,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M5_vdmpybsu,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M5_vdmacbsu,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_vdmacs_s0,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_vdmacs_s1,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_vdmpys_s0,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_vdmpys_s1,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_cmpyrs_s0,"iii","") +BUILTIN(__builtin_HEXAGON_M2_cmpyrs_s1,"iii","") +BUILTIN(__builtin_HEXAGON_M2_cmpyrsc_s0,"iii","") +BUILTIN(__builtin_HEXAGON_M2_cmpyrsc_s1,"iii","") +BUILTIN(__builtin_HEXAGON_M2_cmacs_s0,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_cmacs_s1,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_cmacsc_s0,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_cmacsc_s1,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_cmpys_s0,"LLiii","") +BUILTIN(__builtin_HEXAGON_M2_cmpys_s1,"LLiii","") +BUILTIN(__builtin_HEXAGON_M2_cmpysc_s0,"LLiii","") +BUILTIN(__builtin_HEXAGON_M2_cmpysc_s1,"LLiii","") +BUILTIN(__builtin_HEXAGON_M2_cnacs_s0,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_cnacs_s1,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_cnacsc_s0,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_cnacsc_s1,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_vrcmpys_s1,"LLiLLii","") +BUILTIN(__builtin_HEXAGON_M2_vrcmpys_acc_s1,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_M2_vrcmpys_s1rp,"iLLii","") +BUILTIN(__builtin_HEXAGON_M2_mmacls_s0,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_mmacls_s1,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_mmachs_s0,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_mmachs_s1,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_mmpyl_s0,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_mmpyl_s1,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_mmpyh_s0,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_mmpyh_s1,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_mmacls_rs0,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_mmacls_rs1,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_mmachs_rs0,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_mmachs_rs1,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_mmpyl_rs0,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_mmpyl_rs1,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_mmpyh_rs0,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_mmpyh_rs1,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M4_vrmpyeh_s0,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M4_vrmpyeh_s1,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M4_vrmpyeh_acc_s0,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M4_vrmpyeh_acc_s1,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M4_vrmpyoh_s0,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M4_vrmpyoh_s1,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M4_vrmpyoh_acc_s0,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M4_vrmpyoh_acc_s1,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_hmmpyl_rs1,"iii","") +BUILTIN(__builtin_HEXAGON_M2_hmmpyh_rs1,"iii","") +BUILTIN(__builtin_HEXAGON_M2_hmmpyl_s1,"iii","") +BUILTIN(__builtin_HEXAGON_M2_hmmpyh_s1,"iii","") +BUILTIN(__builtin_HEXAGON_M2_mmaculs_s0,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_mmaculs_s1,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_mmacuhs_s0,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_mmacuhs_s1,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_mmpyul_s0,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_mmpyul_s1,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_mmpyuh_s0,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_mmpyuh_s1,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_mmaculs_rs0,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_mmaculs_rs1,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_mmacuhs_rs0,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_mmacuhs_rs1,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_mmpyul_rs0,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_mmpyul_rs1,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_mmpyuh_rs0,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_mmpyuh_rs1,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_vrcmaci_s0,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_vrcmacr_s0,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_vrcmaci_s0c,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_vrcmacr_s0c,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_cmaci_s0,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_cmacr_s0,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M2_vrcmpyi_s0,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_vrcmpyr_s0,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_vrcmpyi_s0c,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_vrcmpyr_s0c,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_cmpyi_s0,"LLiii","") +BUILTIN(__builtin_HEXAGON_M2_cmpyr_s0,"LLiii","") +BUILTIN(__builtin_HEXAGON_M4_cmpyi_wh,"iLLii","") +BUILTIN(__builtin_HEXAGON_M4_cmpyr_wh,"iLLii","") +BUILTIN(__builtin_HEXAGON_M4_cmpyi_whc,"iLLii","") +BUILTIN(__builtin_HEXAGON_M4_cmpyr_whc,"iLLii","") +BUILTIN(__builtin_HEXAGON_M2_vcmpy_s0_sat_i,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_vcmpy_s0_sat_r,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_vcmpy_s1_sat_i,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_vcmpy_s1_sat_r,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_vcmac_s0_sat_i,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_vcmac_s0_sat_r,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_S2_vcrotate,"LLiLLii","") +BUILTIN(__builtin_HEXAGON_S4_vrcrotate_acc,"LLiLLiLLiii","") +BUILTIN(__builtin_HEXAGON_S4_vrcrotate,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_S2_vcnegh,"LLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_vrcnegh,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_M4_pmpyw,"LLiii","") +BUILTIN(__builtin_HEXAGON_M4_vpmpyh,"LLiii","") +BUILTIN(__builtin_HEXAGON_M4_pmpyw_acc,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_M4_vpmpyh_acc,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_A2_add,"iii","") +BUILTIN(__builtin_HEXAGON_A2_sub,"iii","") +BUILTIN(__builtin_HEXAGON_A2_addsat,"iii","") +BUILTIN(__builtin_HEXAGON_A2_subsat,"iii","") +BUILTIN(__builtin_HEXAGON_A2_addi,"iii","") +BUILTIN(__builtin_HEXAGON_A2_addh_l16_ll,"iii","") +BUILTIN(__builtin_HEXAGON_A2_addh_l16_hl,"iii","") +BUILTIN(__builtin_HEXAGON_A2_addh_l16_sat_ll,"iii","") +BUILTIN(__builtin_HEXAGON_A2_addh_l16_sat_hl,"iii","") +BUILTIN(__builtin_HEXAGON_A2_subh_l16_ll,"iii","") +BUILTIN(__builtin_HEXAGON_A2_subh_l16_hl,"iii","") +BUILTIN(__builtin_HEXAGON_A2_subh_l16_sat_ll,"iii","") +BUILTIN(__builtin_HEXAGON_A2_subh_l16_sat_hl,"iii","") +BUILTIN(__builtin_HEXAGON_A2_addh_h16_ll,"iii","") +BUILTIN(__builtin_HEXAGON_A2_addh_h16_lh,"iii","") +BUILTIN(__builtin_HEXAGON_A2_addh_h16_hl,"iii","") +BUILTIN(__builtin_HEXAGON_A2_addh_h16_hh,"iii","") +BUILTIN(__builtin_HEXAGON_A2_addh_h16_sat_ll,"iii","") +BUILTIN(__builtin_HEXAGON_A2_addh_h16_sat_lh,"iii","") +BUILTIN(__builtin_HEXAGON_A2_addh_h16_sat_hl,"iii","") +BUILTIN(__builtin_HEXAGON_A2_addh_h16_sat_hh,"iii","") +BUILTIN(__builtin_HEXAGON_A2_subh_h16_ll,"iii","") +BUILTIN(__builtin_HEXAGON_A2_subh_h16_lh,"iii","") +BUILTIN(__builtin_HEXAGON_A2_subh_h16_hl,"iii","") +BUILTIN(__builtin_HEXAGON_A2_subh_h16_hh,"iii","") +BUILTIN(__builtin_HEXAGON_A2_subh_h16_sat_ll,"iii","") +BUILTIN(__builtin_HEXAGON_A2_subh_h16_sat_lh,"iii","") +BUILTIN(__builtin_HEXAGON_A2_subh_h16_sat_hl,"iii","") +BUILTIN(__builtin_HEXAGON_A2_subh_h16_sat_hh,"iii","") +BUILTIN(__builtin_HEXAGON_A2_aslh,"ii","") +BUILTIN(__builtin_HEXAGON_A2_asrh,"ii","") +BUILTIN(__builtin_HEXAGON_A2_addp,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_addpsat,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_addsp,"LLiiLLi","") +BUILTIN(__builtin_HEXAGON_A2_subp,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_neg,"ii","") +BUILTIN(__builtin_HEXAGON_A2_negsat,"ii","") +BUILTIN(__builtin_HEXAGON_A2_abs,"ii","") +BUILTIN(__builtin_HEXAGON_A2_abssat,"ii","") +BUILTIN(__builtin_HEXAGON_A2_vconj,"LLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_negp,"LLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_absp,"LLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_max,"iii","") +BUILTIN(__builtin_HEXAGON_A2_maxu,"Uiii","") +BUILTIN(__builtin_HEXAGON_A2_min,"iii","") +BUILTIN(__builtin_HEXAGON_A2_minu,"Uiii","") +BUILTIN(__builtin_HEXAGON_A2_maxp,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_maxup,"ULLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_minp,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_minup,"ULLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_tfr,"ii","") +BUILTIN(__builtin_HEXAGON_A2_tfrsi,"ii","") +BUILTIN(__builtin_HEXAGON_A2_tfrp,"LLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_tfrpi,"LLii","") +BUILTIN(__builtin_HEXAGON_A2_zxtb,"ii","") +BUILTIN(__builtin_HEXAGON_A2_sxtb,"ii","") +BUILTIN(__builtin_HEXAGON_A2_zxth,"ii","") +BUILTIN(__builtin_HEXAGON_A2_sxth,"ii","") +BUILTIN(__builtin_HEXAGON_A2_combinew,"LLiii","") +BUILTIN(__builtin_HEXAGON_A4_combineri,"LLiii","") +BUILTIN(__builtin_HEXAGON_A4_combineir,"LLiii","") +BUILTIN(__builtin_HEXAGON_A2_combineii,"LLiii","") +BUILTIN(__builtin_HEXAGON_A2_combine_hh,"iii","") +BUILTIN(__builtin_HEXAGON_A2_combine_hl,"iii","") +BUILTIN(__builtin_HEXAGON_A2_combine_lh,"iii","") +BUILTIN(__builtin_HEXAGON_A2_combine_ll,"iii","") +BUILTIN(__builtin_HEXAGON_A2_tfril,"iii","") +BUILTIN(__builtin_HEXAGON_A2_tfrih,"iii","") +BUILTIN(__builtin_HEXAGON_A2_and,"iii","") +BUILTIN(__builtin_HEXAGON_A2_or,"iii","") +BUILTIN(__builtin_HEXAGON_A2_xor,"iii","") +BUILTIN(__builtin_HEXAGON_A2_not,"ii","") +BUILTIN(__builtin_HEXAGON_M2_xor_xacc,"iiii","") +BUILTIN(__builtin_HEXAGON_M4_xor_xacc,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A4_andn,"iii","") +BUILTIN(__builtin_HEXAGON_A4_orn,"iii","") +BUILTIN(__builtin_HEXAGON_A4_andnp,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A4_ornp,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_S4_addaddi,"iiii","") +BUILTIN(__builtin_HEXAGON_S4_subaddi,"iiii","") +BUILTIN(__builtin_HEXAGON_M4_and_and,"iiii","") +BUILTIN(__builtin_HEXAGON_M4_and_andn,"iiii","") +BUILTIN(__builtin_HEXAGON_M4_and_or,"iiii","") +BUILTIN(__builtin_HEXAGON_M4_and_xor,"iiii","") +BUILTIN(__builtin_HEXAGON_M4_or_and,"iiii","") +BUILTIN(__builtin_HEXAGON_M4_or_andn,"iiii","") +BUILTIN(__builtin_HEXAGON_M4_or_or,"iiii","") +BUILTIN(__builtin_HEXAGON_M4_or_xor,"iiii","") +BUILTIN(__builtin_HEXAGON_S4_or_andix,"iiii","") +BUILTIN(__builtin_HEXAGON_S4_or_andi,"iiii","") +BUILTIN(__builtin_HEXAGON_S4_or_ori,"iiii","") +BUILTIN(__builtin_HEXAGON_M4_xor_and,"iiii","") +BUILTIN(__builtin_HEXAGON_M4_xor_or,"iiii","") +BUILTIN(__builtin_HEXAGON_M4_xor_andn,"iiii","") +BUILTIN(__builtin_HEXAGON_A2_subri,"iii","") +BUILTIN(__builtin_HEXAGON_A2_andir,"iii","") +BUILTIN(__builtin_HEXAGON_A2_orir,"iii","") +BUILTIN(__builtin_HEXAGON_A2_andp,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_orp,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_xorp,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_notp,"LLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_sxtw,"LLii","") +BUILTIN(__builtin_HEXAGON_A2_sat,"iLLi","") +BUILTIN(__builtin_HEXAGON_A2_roundsat,"iLLi","") +BUILTIN(__builtin_HEXAGON_A2_sath,"ii","") +BUILTIN(__builtin_HEXAGON_A2_satuh,"ii","") +BUILTIN(__builtin_HEXAGON_A2_satub,"ii","") +BUILTIN(__builtin_HEXAGON_A2_satb,"ii","") +BUILTIN(__builtin_HEXAGON_A2_vaddub,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vaddb_map,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vaddubs,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vaddh,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vaddhs,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vadduhs,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A5_vaddhubs,"iLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vaddw,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vaddws,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_S4_vxaddsubw,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_S4_vxsubaddw,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_S4_vxaddsubh,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_S4_vxsubaddh,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_S4_vxaddsubhr,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_S4_vxsubaddhr,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_svavgh,"iii","") +BUILTIN(__builtin_HEXAGON_A2_svavghs,"iii","") +BUILTIN(__builtin_HEXAGON_A2_svnavgh,"iii","") +BUILTIN(__builtin_HEXAGON_A2_svaddh,"iii","") +BUILTIN(__builtin_HEXAGON_A2_svaddhs,"iii","") +BUILTIN(__builtin_HEXAGON_A2_svadduhs,"iii","") +BUILTIN(__builtin_HEXAGON_A2_svsubh,"iii","") +BUILTIN(__builtin_HEXAGON_A2_svsubhs,"iii","") +BUILTIN(__builtin_HEXAGON_A2_svsubuhs,"iii","") +BUILTIN(__builtin_HEXAGON_A2_vraddub,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vraddub_acc,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_vraddh,"iLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_vradduh,"iLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vsubub,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vsubb_map,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vsububs,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vsubh,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vsubhs,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vsubuhs,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vsubw,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vsubws,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vabsh,"LLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vabshsat,"LLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vabsw,"LLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vabswsat,"LLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_vabsdiffw,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_M2_vabsdiffh,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vrsadub,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vrsadub_acc,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vavgub,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vavguh,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vavgh,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vnavgh,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vavgw,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vnavgw,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vavgwr,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vnavgwr,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vavgwcr,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vnavgwcr,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vavghcr,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vnavghcr,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vavguw,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vavguwr,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vavgubr,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vavguhr,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vavghr,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vnavghr,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A4_round_ri,"iii","") +BUILTIN(__builtin_HEXAGON_A4_round_rr,"iii","") +BUILTIN(__builtin_HEXAGON_A4_round_ri_sat,"iii","") +BUILTIN(__builtin_HEXAGON_A4_round_rr_sat,"iii","") +BUILTIN(__builtin_HEXAGON_A4_cround_ri,"iii","") +BUILTIN(__builtin_HEXAGON_A4_cround_rr,"iii","") +BUILTIN(__builtin_HEXAGON_A4_vrminh,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_A4_vrmaxh,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_A4_vrminuh,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_A4_vrmaxuh,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_A4_vrminw,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_A4_vrmaxw,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_A4_vrminuw,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_A4_vrmaxuw,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_A2_vminb,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vmaxb,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vminub,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vmaxub,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vminh,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vmaxh,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vminuh,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vmaxuh,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vminw,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vmaxw,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vminuw,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A2_vmaxuw,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_A4_modwrapu,"iii","") +BUILTIN(__builtin_HEXAGON_F2_sfadd,"fff","") +BUILTIN(__builtin_HEXAGON_F2_sfsub,"fff","") +BUILTIN(__builtin_HEXAGON_F2_sfmpy,"fff","") +BUILTIN(__builtin_HEXAGON_F2_sffma,"ffff","") +BUILTIN(__builtin_HEXAGON_F2_sffma_sc,"ffffi","") +BUILTIN(__builtin_HEXAGON_F2_sffms,"ffff","") +BUILTIN(__builtin_HEXAGON_F2_sffma_lib,"ffff","") +BUILTIN(__builtin_HEXAGON_F2_sffms_lib,"ffff","") +BUILTIN(__builtin_HEXAGON_F2_sfcmpeq,"bff","") +BUILTIN(__builtin_HEXAGON_F2_sfcmpgt,"bff","") +BUILTIN(__builtin_HEXAGON_F2_sfcmpge,"bff","") +BUILTIN(__builtin_HEXAGON_F2_sfcmpuo,"bff","") +BUILTIN(__builtin_HEXAGON_F2_sfmax,"fff","") +BUILTIN(__builtin_HEXAGON_F2_sfmin,"fff","") +BUILTIN(__builtin_HEXAGON_F2_sfclass,"bfi","") +BUILTIN(__builtin_HEXAGON_F2_sfimm_p,"fi","") +BUILTIN(__builtin_HEXAGON_F2_sfimm_n,"fi","") +BUILTIN(__builtin_HEXAGON_F2_sffixupn,"fff","") +BUILTIN(__builtin_HEXAGON_F2_sffixupd,"fff","") +BUILTIN(__builtin_HEXAGON_F2_sffixupr,"ff","") +BUILTIN(__builtin_HEXAGON_F2_dfadd,"ddd","") +BUILTIN(__builtin_HEXAGON_F2_dfsub,"ddd","") +BUILTIN(__builtin_HEXAGON_F2_dfmpy,"ddd","") +BUILTIN(__builtin_HEXAGON_F2_dffma,"dddd","") +BUILTIN(__builtin_HEXAGON_F2_dffms,"dddd","") +BUILTIN(__builtin_HEXAGON_F2_dffma_lib,"dddd","") +BUILTIN(__builtin_HEXAGON_F2_dffms_lib,"dddd","") +BUILTIN(__builtin_HEXAGON_F2_dffma_sc,"ddddi","") +BUILTIN(__builtin_HEXAGON_F2_dfmax,"ddd","") +BUILTIN(__builtin_HEXAGON_F2_dfmin,"ddd","") +BUILTIN(__builtin_HEXAGON_F2_dfcmpeq,"bdd","") +BUILTIN(__builtin_HEXAGON_F2_dfcmpgt,"bdd","") +BUILTIN(__builtin_HEXAGON_F2_dfcmpge,"bdd","") +BUILTIN(__builtin_HEXAGON_F2_dfcmpuo,"bdd","") +BUILTIN(__builtin_HEXAGON_F2_dfclass,"bdi","") +BUILTIN(__builtin_HEXAGON_F2_dfimm_p,"di","") +BUILTIN(__builtin_HEXAGON_F2_dfimm_n,"di","") +BUILTIN(__builtin_HEXAGON_F2_dffixupn,"ddd","") +BUILTIN(__builtin_HEXAGON_F2_dffixupd,"ddd","") +BUILTIN(__builtin_HEXAGON_F2_dffixupr,"dd","") +BUILTIN(__builtin_HEXAGON_F2_conv_sf2df,"df","") +BUILTIN(__builtin_HEXAGON_F2_conv_df2sf,"fd","") +BUILTIN(__builtin_HEXAGON_F2_conv_uw2sf,"fi","") +BUILTIN(__builtin_HEXAGON_F2_conv_uw2df,"di","") +BUILTIN(__builtin_HEXAGON_F2_conv_w2sf,"fi","") +BUILTIN(__builtin_HEXAGON_F2_conv_w2df,"di","") +BUILTIN(__builtin_HEXAGON_F2_conv_ud2sf,"fLLi","") +BUILTIN(__builtin_HEXAGON_F2_conv_ud2df,"dLLi","") +BUILTIN(__builtin_HEXAGON_F2_conv_d2sf,"fLLi","") +BUILTIN(__builtin_HEXAGON_F2_conv_d2df,"dLLi","") +BUILTIN(__builtin_HEXAGON_F2_conv_sf2uw,"if","") +BUILTIN(__builtin_HEXAGON_F2_conv_sf2w,"if","") +BUILTIN(__builtin_HEXAGON_F2_conv_sf2ud,"LLif","") +BUILTIN(__builtin_HEXAGON_F2_conv_sf2d,"LLif","") +BUILTIN(__builtin_HEXAGON_F2_conv_df2uw,"id","") +BUILTIN(__builtin_HEXAGON_F2_conv_df2w,"id","") +BUILTIN(__builtin_HEXAGON_F2_conv_df2ud,"LLid","") +BUILTIN(__builtin_HEXAGON_F2_conv_df2d,"LLid","") +BUILTIN(__builtin_HEXAGON_F2_conv_sf2uw_chop,"if","") +BUILTIN(__builtin_HEXAGON_F2_conv_sf2w_chop,"if","") +BUILTIN(__builtin_HEXAGON_F2_conv_sf2ud_chop,"LLif","") +BUILTIN(__builtin_HEXAGON_F2_conv_sf2d_chop,"LLif","") +BUILTIN(__builtin_HEXAGON_F2_conv_df2uw_chop,"id","") +BUILTIN(__builtin_HEXAGON_F2_conv_df2w_chop,"id","") +BUILTIN(__builtin_HEXAGON_F2_conv_df2ud_chop,"LLid","") +BUILTIN(__builtin_HEXAGON_F2_conv_df2d_chop,"LLid","") +BUILTIN(__builtin_HEXAGON_S2_asr_r_r,"iii","") +BUILTIN(__builtin_HEXAGON_S2_asl_r_r,"iii","") +BUILTIN(__builtin_HEXAGON_S2_lsr_r_r,"iii","") +BUILTIN(__builtin_HEXAGON_S2_lsl_r_r,"iii","") +BUILTIN(__builtin_HEXAGON_S2_asr_r_p,"LLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_asl_r_p,"LLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_lsr_r_p,"LLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_lsl_r_p,"LLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_asr_r_r_acc,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_asl_r_r_acc,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_lsr_r_r_acc,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_lsl_r_r_acc,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_asr_r_p_acc,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_asl_r_p_acc,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_lsr_r_p_acc,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_lsl_r_p_acc,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_asr_r_r_nac,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_asl_r_r_nac,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_lsr_r_r_nac,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_lsl_r_r_nac,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_asr_r_p_nac,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_asl_r_p_nac,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_lsr_r_p_nac,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_lsl_r_p_nac,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_asr_r_r_and,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_asl_r_r_and,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_lsr_r_r_and,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_lsl_r_r_and,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_asr_r_r_or,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_asl_r_r_or,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_lsr_r_r_or,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_lsl_r_r_or,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_asr_r_p_and,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_asl_r_p_and,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_lsr_r_p_and,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_lsl_r_p_and,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_asr_r_p_or,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_asl_r_p_or,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_lsr_r_p_or,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_lsl_r_p_or,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_asr_r_p_xor,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_asl_r_p_xor,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_lsr_r_p_xor,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_lsl_r_p_xor,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_asr_r_r_sat,"iii","") +BUILTIN(__builtin_HEXAGON_S2_asl_r_r_sat,"iii","") +BUILTIN(__builtin_HEXAGON_S2_asr_i_r,"iii","") +BUILTIN(__builtin_HEXAGON_S2_lsr_i_r,"iii","") +BUILTIN(__builtin_HEXAGON_S2_asl_i_r,"iii","") +BUILTIN(__builtin_HEXAGON_S2_asr_i_p,"LLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_lsr_i_p,"LLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_asl_i_p,"LLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_asr_i_r_acc,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_lsr_i_r_acc,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_asl_i_r_acc,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_asr_i_p_acc,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_lsr_i_p_acc,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_asl_i_p_acc,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_asr_i_r_nac,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_lsr_i_r_nac,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_asl_i_r_nac,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_asr_i_p_nac,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_lsr_i_p_nac,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_asl_i_p_nac,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_lsr_i_r_xacc,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_asl_i_r_xacc,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_lsr_i_p_xacc,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_asl_i_p_xacc,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_asr_i_r_and,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_lsr_i_r_and,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_asl_i_r_and,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_asr_i_r_or,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_lsr_i_r_or,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_asl_i_r_or,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_asr_i_p_and,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_lsr_i_p_and,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_asl_i_p_and,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_asr_i_p_or,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_lsr_i_p_or,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_asl_i_p_or,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_asl_i_r_sat,"iii","") +BUILTIN(__builtin_HEXAGON_S2_asr_i_r_rnd,"iii","") +BUILTIN(__builtin_HEXAGON_S2_asr_i_r_rnd_goodsyntax,"iii","") +BUILTIN(__builtin_HEXAGON_S2_asr_i_p_rnd,"LLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_asr_i_p_rnd_goodsyntax,"LLiLLii","") +BUILTIN(__builtin_HEXAGON_S4_lsli,"iii","") +BUILTIN(__builtin_HEXAGON_S2_addasl_rrri,"iiii","") +BUILTIN(__builtin_HEXAGON_S4_andi_asl_ri,"iiii","") +BUILTIN(__builtin_HEXAGON_S4_ori_asl_ri,"iiii","") +BUILTIN(__builtin_HEXAGON_S4_addi_asl_ri,"iiii","") +BUILTIN(__builtin_HEXAGON_S4_subi_asl_ri,"iiii","") +BUILTIN(__builtin_HEXAGON_S4_andi_lsr_ri,"iiii","") +BUILTIN(__builtin_HEXAGON_S4_ori_lsr_ri,"iiii","") +BUILTIN(__builtin_HEXAGON_S4_addi_lsr_ri,"iiii","") +BUILTIN(__builtin_HEXAGON_S4_subi_lsr_ri,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_valignib,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_valignrb,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_vspliceib,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_vsplicerb,"LLiLLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_vsplatrh,"LLii","") +BUILTIN(__builtin_HEXAGON_S2_vsplatrb,"ii","") +BUILTIN(__builtin_HEXAGON_S2_insert,"iiiii","") +BUILTIN(__builtin_HEXAGON_S2_tableidxb_goodsyntax,"iiiii","") +BUILTIN(__builtin_HEXAGON_S2_tableidxh_goodsyntax,"iiiii","") +BUILTIN(__builtin_HEXAGON_S2_tableidxw_goodsyntax,"iiiii","") +BUILTIN(__builtin_HEXAGON_S2_tableidxd_goodsyntax,"iiiii","") +BUILTIN(__builtin_HEXAGON_A4_bitspliti,"LLiii","") +BUILTIN(__builtin_HEXAGON_A4_bitsplit,"LLiii","") +BUILTIN(__builtin_HEXAGON_S4_extract,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_extractu,"iiii","") +BUILTIN(__builtin_HEXAGON_S2_insertp,"LLiLLiLLiii","") +BUILTIN(__builtin_HEXAGON_S4_extractp,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_S2_extractup,"LLiLLiii","") +BUILTIN(__builtin_HEXAGON_S2_insert_rp,"iiiLLi","") +BUILTIN(__builtin_HEXAGON_S4_extract_rp,"iiLLi","") +BUILTIN(__builtin_HEXAGON_S2_extractu_rp,"iiLLi","") +BUILTIN(__builtin_HEXAGON_S2_insertp_rp,"LLiLLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_S4_extractp_rp,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_S2_extractup_rp,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_S2_tstbit_i,"bii","") +BUILTIN(__builtin_HEXAGON_S4_ntstbit_i,"bii","") +BUILTIN(__builtin_HEXAGON_S2_setbit_i,"iii","") +BUILTIN(__builtin_HEXAGON_S2_togglebit_i,"iii","") +BUILTIN(__builtin_HEXAGON_S2_clrbit_i,"iii","") +BUILTIN(__builtin_HEXAGON_S2_tstbit_r,"bii","") +BUILTIN(__builtin_HEXAGON_S4_ntstbit_r,"bii","") +BUILTIN(__builtin_HEXAGON_S2_setbit_r,"iii","") +BUILTIN(__builtin_HEXAGON_S2_togglebit_r,"iii","") +BUILTIN(__builtin_HEXAGON_S2_clrbit_r,"iii","") +BUILTIN(__builtin_HEXAGON_S2_asr_i_vh,"LLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_lsr_i_vh,"LLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_asl_i_vh,"LLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_asr_r_vh,"LLiLLii","") +BUILTIN(__builtin_HEXAGON_S5_asrhub_rnd_sat_goodsyntax,"iLLii","") +BUILTIN(__builtin_HEXAGON_S5_asrhub_sat,"iLLii","") +BUILTIN(__builtin_HEXAGON_S5_vasrhrnd_goodsyntax,"LLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_asl_r_vh,"LLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_lsr_r_vh,"LLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_lsl_r_vh,"LLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_asr_i_vw,"LLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_asr_i_svw_trun,"iLLii","") +BUILTIN(__builtin_HEXAGON_S2_asr_r_svw_trun,"iLLii","") +BUILTIN(__builtin_HEXAGON_S2_lsr_i_vw,"LLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_asl_i_vw,"LLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_asr_r_vw,"LLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_asl_r_vw,"LLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_lsr_r_vw,"LLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_lsl_r_vw,"LLiLLii","") +BUILTIN(__builtin_HEXAGON_S2_vrndpackwh,"iLLi","") +BUILTIN(__builtin_HEXAGON_S2_vrndpackwhs,"iLLi","") +BUILTIN(__builtin_HEXAGON_S2_vsxtbh,"LLii","") +BUILTIN(__builtin_HEXAGON_S2_vzxtbh,"LLii","") +BUILTIN(__builtin_HEXAGON_S2_vsathub,"iLLi","") +BUILTIN(__builtin_HEXAGON_S2_svsathub,"ii","") +BUILTIN(__builtin_HEXAGON_S2_svsathb,"ii","") +BUILTIN(__builtin_HEXAGON_S2_vsathb,"iLLi","") +BUILTIN(__builtin_HEXAGON_S2_vtrunohb,"iLLi","") +BUILTIN(__builtin_HEXAGON_S2_vtrunewh,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_S2_vtrunowh,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_S2_vtrunehb,"iLLi","") +BUILTIN(__builtin_HEXAGON_S2_vsxthw,"LLii","") +BUILTIN(__builtin_HEXAGON_S2_vzxthw,"LLii","") +BUILTIN(__builtin_HEXAGON_S2_vsatwh,"iLLi","") +BUILTIN(__builtin_HEXAGON_S2_vsatwuh,"iLLi","") +BUILTIN(__builtin_HEXAGON_S2_packhl,"LLiii","") +BUILTIN(__builtin_HEXAGON_A2_swiz,"ii","") +BUILTIN(__builtin_HEXAGON_S2_vsathub_nopack,"LLiLLi","") +BUILTIN(__builtin_HEXAGON_S2_vsathb_nopack,"LLiLLi","") +BUILTIN(__builtin_HEXAGON_S2_vsatwh_nopack,"LLiLLi","") +BUILTIN(__builtin_HEXAGON_S2_vsatwuh_nopack,"LLiLLi","") +BUILTIN(__builtin_HEXAGON_S2_shuffob,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_S2_shuffeb,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_S2_shuffoh,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_S2_shuffeh,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_S5_popcountp,"iLLi","") +BUILTIN(__builtin_HEXAGON_S4_parity,"iii","") +BUILTIN(__builtin_HEXAGON_S2_parityp,"iLLiLLi","") +BUILTIN(__builtin_HEXAGON_S2_lfsp,"LLiLLiLLi","") +BUILTIN(__builtin_HEXAGON_S2_clbnorm,"ii","") +BUILTIN(__builtin_HEXAGON_S4_clbaddi,"iii","") +BUILTIN(__builtin_HEXAGON_S4_clbpnorm,"iLLi","") +BUILTIN(__builtin_HEXAGON_S4_clbpaddi,"iLLii","") +BUILTIN(__builtin_HEXAGON_S2_clb,"ii","") +BUILTIN(__builtin_HEXAGON_S2_cl0,"ii","") +BUILTIN(__builtin_HEXAGON_S2_cl1,"ii","") +BUILTIN(__builtin_HEXAGON_S2_clbp,"iLLi","") +BUILTIN(__builtin_HEXAGON_S2_cl0p,"iLLi","") +BUILTIN(__builtin_HEXAGON_S2_cl1p,"iLLi","") +BUILTIN(__builtin_HEXAGON_S2_brev,"ii","") +BUILTIN(__builtin_HEXAGON_S2_brevp,"LLiLLi","") +BUILTIN(__builtin_HEXAGON_S2_ct0,"ii","") +BUILTIN(__builtin_HEXAGON_S2_ct1,"ii","") +BUILTIN(__builtin_HEXAGON_S2_ct0p,"iLLi","") +BUILTIN(__builtin_HEXAGON_S2_ct1p,"iLLi","") +BUILTIN(__builtin_HEXAGON_S2_interleave,"LLiLLi","") +BUILTIN(__builtin_HEXAGON_S2_deinterleave,"LLiLLi","") + +#undef BUILTIN diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsLe64.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsLe64.def new file mode 100644 index 0000000..5328606 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsLe64.def @@ -0,0 +1,19 @@ +//==- BuiltinsLe64.def - Le64 Builtin function database ----------*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Le64-specific builtin function database. Users of this +// file must define the BUILTIN macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +// The format of this database matches clang/Basic/Builtins.def. + +BUILTIN(__clear_cache, "vv*v*", "i") + +#undef BUILTIN diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsMips.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsMips.def new file mode 100644 index 0000000..2d217f7 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsMips.def @@ -0,0 +1,900 @@ +//===-- BuiltinsMips.def - Mips Builtin function database --------*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the MIPS-specific builtin function database. Users of +// this file must define the BUILTIN macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +// The format of this database matches clang/Basic/Builtins.def. + +// MIPS DSP Rev 1 + +// Add/subtract with optional saturation +BUILTIN(__builtin_mips_addu_qb, "V4ScV4ScV4Sc", "n") +BUILTIN(__builtin_mips_addu_s_qb, "V4ScV4ScV4Sc", "n") +BUILTIN(__builtin_mips_subu_qb, "V4ScV4ScV4Sc", "n") +BUILTIN(__builtin_mips_subu_s_qb, "V4ScV4ScV4Sc", "n") + +BUILTIN(__builtin_mips_addq_ph, "V2sV2sV2s", "n") +BUILTIN(__builtin_mips_addq_s_ph, "V2sV2sV2s", "n") +BUILTIN(__builtin_mips_subq_ph, "V2sV2sV2s", "n") +BUILTIN(__builtin_mips_subq_s_ph, "V2sV2sV2s", "n") + +BUILTIN(__builtin_mips_madd, "LLiLLiii", "nc") +BUILTIN(__builtin_mips_maddu, "LLiLLiUiUi", "nc") +BUILTIN(__builtin_mips_msub, "LLiLLiii", "nc") +BUILTIN(__builtin_mips_msubu, "LLiLLiUiUi", "nc") + +BUILTIN(__builtin_mips_addq_s_w, "iii", "n") +BUILTIN(__builtin_mips_subq_s_w, "iii", "n") + +BUILTIN(__builtin_mips_addsc, "iii", "n") +BUILTIN(__builtin_mips_addwc, "iii", "n") + +BUILTIN(__builtin_mips_modsub, "iii", "nc") + +BUILTIN(__builtin_mips_raddu_w_qb, "iV4Sc", "nc") + +BUILTIN(__builtin_mips_absq_s_ph, "V2sV2s", "n") +BUILTIN(__builtin_mips_absq_s_w, "ii", "n") + +BUILTIN(__builtin_mips_precrq_qb_ph, "V4ScV2sV2s", "nc") +BUILTIN(__builtin_mips_precrqu_s_qb_ph, "V4ScV2sV2s", "n") +BUILTIN(__builtin_mips_precrq_ph_w, "V2sii", "nc") +BUILTIN(__builtin_mips_precrq_rs_ph_w, "V2sii", "n") +BUILTIN(__builtin_mips_preceq_w_phl, "iV2s", "nc") +BUILTIN(__builtin_mips_preceq_w_phr, "iV2s", "nc") +BUILTIN(__builtin_mips_precequ_ph_qbl, "V2sV4Sc", "nc") +BUILTIN(__builtin_mips_precequ_ph_qbr, "V2sV4Sc", "nc") +BUILTIN(__builtin_mips_precequ_ph_qbla, "V2sV4Sc", "nc") +BUILTIN(__builtin_mips_precequ_ph_qbra, "V2sV4Sc", "nc") +BUILTIN(__builtin_mips_preceu_ph_qbl, "V2sV4Sc", "nc") +BUILTIN(__builtin_mips_preceu_ph_qbr, "V2sV4Sc", "nc") +BUILTIN(__builtin_mips_preceu_ph_qbla, "V2sV4Sc", "nc") +BUILTIN(__builtin_mips_preceu_ph_qbra, "V2sV4Sc", "nc") + +BUILTIN(__builtin_mips_shll_qb, "V4ScV4Sci", "n") +BUILTIN(__builtin_mips_shrl_qb, "V4ScV4Sci", "nc") +BUILTIN(__builtin_mips_shll_ph, "V2sV2si", "n") +BUILTIN(__builtin_mips_shll_s_ph, "V2sV2si", "n") +BUILTIN(__builtin_mips_shra_ph, "V2sV2si", "nc") +BUILTIN(__builtin_mips_shra_r_ph, "V2sV2si", "nc") +BUILTIN(__builtin_mips_shll_s_w, "iii", "n") +BUILTIN(__builtin_mips_shra_r_w, "iii", "nc") +BUILTIN(__builtin_mips_shilo, "LLiLLii", "nc") + +BUILTIN(__builtin_mips_muleu_s_ph_qbl, "V2sV4ScV2s", "n") +BUILTIN(__builtin_mips_muleu_s_ph_qbr, "V2sV4ScV2s", "n") +BUILTIN(__builtin_mips_mulq_rs_ph, "V2sV2sV2s", "n") +BUILTIN(__builtin_mips_muleq_s_w_phl, "iV2sV2s", "n") +BUILTIN(__builtin_mips_muleq_s_w_phr, "iV2sV2s", "n") +BUILTIN(__builtin_mips_mulsaq_s_w_ph, "LLiLLiV2sV2s", "n") +BUILTIN(__builtin_mips_maq_s_w_phl, "LLiLLiV2sV2s", "n") +BUILTIN(__builtin_mips_maq_s_w_phr, "LLiLLiV2sV2s", "n") +BUILTIN(__builtin_mips_maq_sa_w_phl, "LLiLLiV2sV2s", "n") +BUILTIN(__builtin_mips_maq_sa_w_phr, "LLiLLiV2sV2s", "n") +BUILTIN(__builtin_mips_mult, "LLiii", "nc") +BUILTIN(__builtin_mips_multu, "LLiUiUi", "nc") + +BUILTIN(__builtin_mips_dpau_h_qbl, "LLiLLiV4ScV4Sc", "nc") +BUILTIN(__builtin_mips_dpau_h_qbr, "LLiLLiV4ScV4Sc", "nc") +BUILTIN(__builtin_mips_dpsu_h_qbl, "LLiLLiV4ScV4Sc", "nc") +BUILTIN(__builtin_mips_dpsu_h_qbr, "LLiLLiV4ScV4Sc", "nc") +BUILTIN(__builtin_mips_dpaq_s_w_ph, "LLiLLiV2sV2s", "n") +BUILTIN(__builtin_mips_dpsq_s_w_ph, "LLiLLiV2sV2s", "n") +BUILTIN(__builtin_mips_dpaq_sa_l_w, "LLiLLiii", "n") +BUILTIN(__builtin_mips_dpsq_sa_l_w, "LLiLLiii", "n") + +BUILTIN(__builtin_mips_cmpu_eq_qb, "vV4ScV4Sc", "n") +BUILTIN(__builtin_mips_cmpu_lt_qb, "vV4ScV4Sc", "n") +BUILTIN(__builtin_mips_cmpu_le_qb, "vV4ScV4Sc", "n") +BUILTIN(__builtin_mips_cmpgu_eq_qb, "iV4ScV4Sc", "n") +BUILTIN(__builtin_mips_cmpgu_lt_qb, "iV4ScV4Sc", "n") +BUILTIN(__builtin_mips_cmpgu_le_qb, "iV4ScV4Sc", "n") +BUILTIN(__builtin_mips_cmp_eq_ph, "vV2sV2s", "n") +BUILTIN(__builtin_mips_cmp_lt_ph, "vV2sV2s", "n") +BUILTIN(__builtin_mips_cmp_le_ph, "vV2sV2s", "n") + +BUILTIN(__builtin_mips_extr_s_h, "iLLii", "n") +BUILTIN(__builtin_mips_extr_w, "iLLii", "n") +BUILTIN(__builtin_mips_extr_rs_w, "iLLii", "n") +BUILTIN(__builtin_mips_extr_r_w, "iLLii", "n") +BUILTIN(__builtin_mips_extp, "iLLii", "n") +BUILTIN(__builtin_mips_extpdp, "iLLii", "n") + +BUILTIN(__builtin_mips_wrdsp, "viIi", "n") +BUILTIN(__builtin_mips_rddsp, "iIi", "n") +BUILTIN(__builtin_mips_insv, "iii", "n") +BUILTIN(__builtin_mips_bitrev, "ii", "nc") +BUILTIN(__builtin_mips_packrl_ph, "V2sV2sV2s", "nc") +BUILTIN(__builtin_mips_repl_qb, "V4Sci", "nc") +BUILTIN(__builtin_mips_repl_ph, "V2si", "nc") +BUILTIN(__builtin_mips_pick_qb, "V4ScV4ScV4Sc", "n") +BUILTIN(__builtin_mips_pick_ph, "V2sV2sV2s", "n") +BUILTIN(__builtin_mips_mthlip, "LLiLLii", "n") +BUILTIN(__builtin_mips_bposge32, "i", "n") +BUILTIN(__builtin_mips_lbux, "iv*i", "n") +BUILTIN(__builtin_mips_lhx, "iv*i", "n") +BUILTIN(__builtin_mips_lwx, "iv*i", "n") + +// MIPS DSP Rev 2 + +BUILTIN(__builtin_mips_absq_s_qb, "V4ScV4Sc", "n") + +BUILTIN(__builtin_mips_addqh_ph, "V2sV2sV2s", "nc") +BUILTIN(__builtin_mips_addqh_r_ph, "V2sV2sV2s", "nc") +BUILTIN(__builtin_mips_addqh_w, "iii", "nc") +BUILTIN(__builtin_mips_addqh_r_w, "iii", "nc") + +BUILTIN(__builtin_mips_addu_ph, "V2sV2sV2s", "n") +BUILTIN(__builtin_mips_addu_s_ph, "V2sV2sV2s", "n") + +BUILTIN(__builtin_mips_adduh_qb, "V4ScV4ScV4Sc", "nc") +BUILTIN(__builtin_mips_adduh_r_qb, "V4ScV4ScV4Sc", "nc") + +BUILTIN(__builtin_mips_append, "iiiIi", "nc") +BUILTIN(__builtin_mips_balign, "iiiIi", "nc") + +BUILTIN(__builtin_mips_cmpgdu_eq_qb, "iV4ScV4Sc", "n") +BUILTIN(__builtin_mips_cmpgdu_lt_qb, "iV4ScV4Sc", "n") +BUILTIN(__builtin_mips_cmpgdu_le_qb, "iV4ScV4Sc", "n") + +BUILTIN(__builtin_mips_dpa_w_ph, "LLiLLiV2sV2s", "nc") +BUILTIN(__builtin_mips_dps_w_ph, "LLiLLiV2sV2s", "nc") + +BUILTIN(__builtin_mips_dpaqx_s_w_ph, "LLiLLiV2sV2s", "n") +BUILTIN(__builtin_mips_dpaqx_sa_w_ph, "LLiLLiV2sV2s", "n") +BUILTIN(__builtin_mips_dpax_w_ph, "LLiLLiV2sV2s", "nc") +BUILTIN(__builtin_mips_dpsx_w_ph, "LLiLLiV2sV2s", "nc") +BUILTIN(__builtin_mips_dpsqx_s_w_ph, "LLiLLiV2sV2s", "n") +BUILTIN(__builtin_mips_dpsqx_sa_w_ph, "LLiLLiV2sV2s", "n") + +BUILTIN(__builtin_mips_mul_ph, "V2sV2sV2s", "n") +BUILTIN(__builtin_mips_mul_s_ph, "V2sV2sV2s", "n") + +BUILTIN(__builtin_mips_mulq_rs_w, "iii", "n") +BUILTIN(__builtin_mips_mulq_s_ph, "V2sV2sV2s", "n") +BUILTIN(__builtin_mips_mulq_s_w, "iii", "n") +BUILTIN(__builtin_mips_mulsa_w_ph, "LLiLLiV2sV2s", "nc") + +BUILTIN(__builtin_mips_precr_qb_ph, "V4ScV2sV2s", "n") +BUILTIN(__builtin_mips_precr_sra_ph_w, "V2siiIi", "nc") +BUILTIN(__builtin_mips_precr_sra_r_ph_w, "V2siiIi", "nc") + +BUILTIN(__builtin_mips_prepend, "iiiIi", "nc") + +BUILTIN(__builtin_mips_shra_qb, "V4ScV4Sci", "nc") +BUILTIN(__builtin_mips_shra_r_qb, "V4ScV4Sci", "nc") +BUILTIN(__builtin_mips_shrl_ph, "V2sV2si", "nc") + +BUILTIN(__builtin_mips_subqh_ph, "V2sV2sV2s", "nc") +BUILTIN(__builtin_mips_subqh_r_ph, "V2sV2sV2s", "nc") +BUILTIN(__builtin_mips_subqh_w, "iii", "nc") +BUILTIN(__builtin_mips_subqh_r_w, "iii", "nc") + +BUILTIN(__builtin_mips_subu_ph, "V2sV2sV2s", "n") +BUILTIN(__builtin_mips_subu_s_ph, "V2sV2sV2s", "n") + +BUILTIN(__builtin_mips_subuh_qb, "V4ScV4ScV4Sc", "nc") +BUILTIN(__builtin_mips_subuh_r_qb, "V4ScV4ScV4Sc", "nc") + +// MIPS MSA + +BUILTIN(__builtin_msa_add_a_b, "V16ScV16ScV16Sc", "nc") +BUILTIN(__builtin_msa_add_a_h, "V8SsV8SsV8Ss", "nc") +BUILTIN(__builtin_msa_add_a_w, "V4SiV4SiV4Si", "nc") +BUILTIN(__builtin_msa_add_a_d, "V2SLLiV2SLLiV2SLLi", "nc") + +BUILTIN(__builtin_msa_adds_a_b, "V16ScV16ScV16Sc", "nc") +BUILTIN(__builtin_msa_adds_a_h, "V8SsV8SsV8Ss", "nc") +BUILTIN(__builtin_msa_adds_a_w, "V4SiV4SiV4Si", "nc") +BUILTIN(__builtin_msa_adds_a_d, "V2SLLiV2SLLiV2SLLi", "nc") + +BUILTIN(__builtin_msa_adds_s_b, "V16ScV16ScV16Sc", "nc") +BUILTIN(__builtin_msa_adds_s_h, "V8SsV8SsV8Ss", "nc") +BUILTIN(__builtin_msa_adds_s_w, "V4SiV4SiV4Si", "nc") +BUILTIN(__builtin_msa_adds_s_d, "V2SLLiV2SLLiV2SLLi", "nc") + +BUILTIN(__builtin_msa_adds_u_b, "V16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_msa_adds_u_h, "V8UsV8UsV8Us", "nc") +BUILTIN(__builtin_msa_adds_u_w, "V4UiV4UiV4Ui", "nc") +BUILTIN(__builtin_msa_adds_u_d, "V2ULLiV2ULLiV2ULLi", "nc") + +BUILTIN(__builtin_msa_addv_b, "V16cV16cV16c", "nc") +BUILTIN(__builtin_msa_addv_h, "V8sV8sV8s", "nc") +BUILTIN(__builtin_msa_addv_w, "V4iV4iV4i", "nc") +BUILTIN(__builtin_msa_addv_d, "V2LLiV2LLiV2LLi", "nc") + +BUILTIN(__builtin_msa_addvi_b, "V16cV16cIUi", "nc") +BUILTIN(__builtin_msa_addvi_h, "V8sV8sIUi", "nc") +BUILTIN(__builtin_msa_addvi_w, "V4iV4iIUi", "nc") +BUILTIN(__builtin_msa_addvi_d, "V2LLiV2LLiIUi", "nc") + +BUILTIN(__builtin_msa_and_v, "V16UcV16UcV16Uc", "nc") + +BUILTIN(__builtin_msa_andi_b, "V16UcV16UcIUi", "nc") + +BUILTIN(__builtin_msa_asub_s_b, "V16ScV16ScV16Sc", "nc") +BUILTIN(__builtin_msa_asub_s_h, "V8SsV8SsV8Ss", "nc") +BUILTIN(__builtin_msa_asub_s_w, "V4SiV4SiV4Si", "nc") +BUILTIN(__builtin_msa_asub_s_d, "V2SLLiV2SLLiV2SLLi", "nc") + +BUILTIN(__builtin_msa_asub_u_b, "V16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_msa_asub_u_h, "V8UsV8UsV8Us", "nc") +BUILTIN(__builtin_msa_asub_u_w, "V4UiV4UiV4Ui", "nc") +BUILTIN(__builtin_msa_asub_u_d, "V2ULLiV2ULLiV2ULLi", "nc") + +BUILTIN(__builtin_msa_ave_s_b, "V16ScV16ScV16Sc", "nc") +BUILTIN(__builtin_msa_ave_s_h, "V8SsV8SsV8Ss", "nc") +BUILTIN(__builtin_msa_ave_s_w, "V4SiV4SiV4Si", "nc") +BUILTIN(__builtin_msa_ave_s_d, "V2SLLiV2SLLiV2SLLi", "nc") + +BUILTIN(__builtin_msa_ave_u_b, "V16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_msa_ave_u_h, "V8UsV8UsV8Us", "nc") +BUILTIN(__builtin_msa_ave_u_w, "V4UiV4UiV4Ui", "nc") +BUILTIN(__builtin_msa_ave_u_d, "V2ULLiV2ULLiV2ULLi", "nc") + +BUILTIN(__builtin_msa_aver_s_b, "V16ScV16ScV16Sc", "nc") +BUILTIN(__builtin_msa_aver_s_h, "V8SsV8SsV8Ss", "nc") +BUILTIN(__builtin_msa_aver_s_w, "V4SiV4SiV4Si", "nc") +BUILTIN(__builtin_msa_aver_s_d, "V2SLLiV2SLLiV2SLLi", "nc") + +BUILTIN(__builtin_msa_aver_u_b, "V16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_msa_aver_u_h, "V8UsV8UsV8Us", "nc") +BUILTIN(__builtin_msa_aver_u_w, "V4UiV4UiV4Ui", "nc") +BUILTIN(__builtin_msa_aver_u_d, "V2ULLiV2ULLiV2ULLi", "nc") + +BUILTIN(__builtin_msa_bclr_b, "V16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_msa_bclr_h, "V8UsV8UsV8Us", "nc") +BUILTIN(__builtin_msa_bclr_w, "V4UiV4UiV4Ui", "nc") +BUILTIN(__builtin_msa_bclr_d, "V2ULLiV2ULLiV2ULLi", "nc") + +BUILTIN(__builtin_msa_bclri_b, "V16UcV16UcIUi", "nc") +BUILTIN(__builtin_msa_bclri_h, "V8UsV8UsIUi", "nc") +BUILTIN(__builtin_msa_bclri_w, "V4UiV4UiIUi", "nc") +BUILTIN(__builtin_msa_bclri_d, "V2ULLiV2ULLiIUi", "nc") + +BUILTIN(__builtin_msa_binsl_b, "V16UcV16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_msa_binsl_h, "V8UsV8UsV8UsV8Us", "nc") +BUILTIN(__builtin_msa_binsl_w, "V4UiV4UiV4UiV4Ui", "nc") +BUILTIN(__builtin_msa_binsl_d, "V2ULLiV2ULLiV2ULLiV2ULLi", "nc") + +BUILTIN(__builtin_msa_binsli_b, "V16UcV16UcV16UcIUi", "nc") +BUILTIN(__builtin_msa_binsli_h, "V8UsV8UsV8UsIUi", "nc") +BUILTIN(__builtin_msa_binsli_w, "V4UiV4UiV4UiIUi", "nc") +BUILTIN(__builtin_msa_binsli_d, "V2ULLiV2ULLiV2ULLiIUi", "nc") + +BUILTIN(__builtin_msa_binsr_b, "V16UcV16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_msa_binsr_h, "V8UsV8UsV8UsV8Us", "nc") +BUILTIN(__builtin_msa_binsr_w, "V4UiV4UiV4UiV4Ui", "nc") +BUILTIN(__builtin_msa_binsr_d, "V2ULLiV2ULLiV2ULLiV2ULLi", "nc") + +BUILTIN(__builtin_msa_binsri_b, "V16UcV16UcV16UcIUi", "nc") +BUILTIN(__builtin_msa_binsri_h, "V8UsV8UsV8UsIUi", "nc") +BUILTIN(__builtin_msa_binsri_w, "V4UiV4UiV4UiIUi", "nc") +BUILTIN(__builtin_msa_binsri_d, "V2ULLiV2ULLiV2ULLiIUi", "nc") + +BUILTIN(__builtin_msa_bmnz_v, "V16UcV16UcV16UcV16Uc", "nc") + +BUILTIN(__builtin_msa_bmnzi_b, "V16UcV16UcV16UcIUi", "nc") + +BUILTIN(__builtin_msa_bmz_v, "V16UcV16UcV16UcV16Uc", "nc") + +BUILTIN(__builtin_msa_bmzi_b, "V16UcV16UcV16UcIUi", "nc") + +BUILTIN(__builtin_msa_bneg_b, "V16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_msa_bneg_h, "V8UsV8UsV8Us", "nc") +BUILTIN(__builtin_msa_bneg_w, "V4UiV4UiV4Ui", "nc") +BUILTIN(__builtin_msa_bneg_d, "V2ULLiV2ULLiV2ULLi", "nc") + +BUILTIN(__builtin_msa_bnegi_b, "V16UcV16UcIUi", "nc") +BUILTIN(__builtin_msa_bnegi_h, "V8UsV8UsIUi", "nc") +BUILTIN(__builtin_msa_bnegi_w, "V4UiV4UiIUi", "nc") +BUILTIN(__builtin_msa_bnegi_d, "V2ULLiV2ULLiIUi", "nc") + +BUILTIN(__builtin_msa_bnz_b, "iV16Uc", "nc") +BUILTIN(__builtin_msa_bnz_h, "iV8Us", "nc") +BUILTIN(__builtin_msa_bnz_w, "iV4Ui", "nc") +BUILTIN(__builtin_msa_bnz_d, "iV2ULLi", "nc") + +BUILTIN(__builtin_msa_bnz_v, "iV16Uc", "nc") + +BUILTIN(__builtin_msa_bsel_v, "V16UcV16UcV16UcV16Uc", "nc") + +BUILTIN(__builtin_msa_bseli_b, "V16UcV16UcV16UcIUi", "nc") + +BUILTIN(__builtin_msa_bset_b, "V16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_msa_bset_h, "V8UsV8UsV8Us", "nc") +BUILTIN(__builtin_msa_bset_w, "V4UiV4UiV4Ui", "nc") +BUILTIN(__builtin_msa_bset_d, "V2ULLiV2ULLiV2ULLi", "nc") + +BUILTIN(__builtin_msa_bseti_b, "V16UcV16UcIUi", "nc") +BUILTIN(__builtin_msa_bseti_h, "V8UsV8UsIUi", "nc") +BUILTIN(__builtin_msa_bseti_w, "V4UiV4UiIUi", "nc") +BUILTIN(__builtin_msa_bseti_d, "V2ULLiV2ULLiIUi", "nc") + +BUILTIN(__builtin_msa_bz_b, "iV16Uc", "nc") +BUILTIN(__builtin_msa_bz_h, "iV8Us", "nc") +BUILTIN(__builtin_msa_bz_w, "iV4Ui", "nc") +BUILTIN(__builtin_msa_bz_d, "iV2ULLi", "nc") + +BUILTIN(__builtin_msa_bz_v, "iV16Uc", "nc") + +BUILTIN(__builtin_msa_ceq_b, "V16ScV16ScV16Sc", "nc") +BUILTIN(__builtin_msa_ceq_h, "V8SsV8SsV8Ss", "nc") +BUILTIN(__builtin_msa_ceq_w, "V4SiV4SiV4Si", "nc") +BUILTIN(__builtin_msa_ceq_d, "V2SLLiV2SLLiV2SLLi", "nc") + +BUILTIN(__builtin_msa_ceqi_b, "V16ScV16ScISi", "nc") +BUILTIN(__builtin_msa_ceqi_h, "V8SsV8SsISi", "nc") +BUILTIN(__builtin_msa_ceqi_w, "V4SiV4SiISi", "nc") +BUILTIN(__builtin_msa_ceqi_d, "V2SLLiV2SLLiISi", "nc") + +BUILTIN(__builtin_msa_cfcmsa, "iIi", "n") + +BUILTIN(__builtin_msa_cle_s_b, "V16ScV16ScV16Sc", "nc") +BUILTIN(__builtin_msa_cle_s_h, "V8SsV8SsV8Ss", "nc") +BUILTIN(__builtin_msa_cle_s_w, "V4SiV4SiV4Si", "nc") +BUILTIN(__builtin_msa_cle_s_d, "V2SLLiV2SLLiV2SLLi", "nc") + +BUILTIN(__builtin_msa_cle_u_b, "V16ScV16UcV16Uc", "nc") +BUILTIN(__builtin_msa_cle_u_h, "V8SsV8UsV8Us", "nc") +BUILTIN(__builtin_msa_cle_u_w, "V4SiV4UiV4Ui", "nc") +BUILTIN(__builtin_msa_cle_u_d, "V2SLLiV2ULLiV2ULLi", "nc") + +BUILTIN(__builtin_msa_clei_s_b, "V16ScV16ScISi", "nc") +BUILTIN(__builtin_msa_clei_s_h, "V8SsV8SsISi", "nc") +BUILTIN(__builtin_msa_clei_s_w, "V4SiV4SiISi", "nc") +BUILTIN(__builtin_msa_clei_s_d, "V2SLLiV2SLLiISi", "nc") + +BUILTIN(__builtin_msa_clei_u_b, "V16ScV16UcIUi", "nc") +BUILTIN(__builtin_msa_clei_u_h, "V8SsV8UsIUi", "nc") +BUILTIN(__builtin_msa_clei_u_w, "V4SiV4UiIUi", "nc") +BUILTIN(__builtin_msa_clei_u_d, "V2SLLiV2ULLiIUi", "nc") + +BUILTIN(__builtin_msa_clt_s_b, "V16ScV16ScV16Sc", "nc") +BUILTIN(__builtin_msa_clt_s_h, "V8SsV8SsV8Ss", "nc") +BUILTIN(__builtin_msa_clt_s_w, "V4SiV4SiV4Si", "nc") +BUILTIN(__builtin_msa_clt_s_d, "V2SLLiV2SLLiV2SLLi", "nc") + +BUILTIN(__builtin_msa_clt_u_b, "V16ScV16UcV16Uc", "nc") +BUILTIN(__builtin_msa_clt_u_h, "V8SsV8UsV8Us", "nc") +BUILTIN(__builtin_msa_clt_u_w, "V4SiV4UiV4Ui", "nc") +BUILTIN(__builtin_msa_clt_u_d, "V2SLLiV2ULLiV2ULLi", "nc") + +BUILTIN(__builtin_msa_clti_s_b, "V16ScV16ScISi", "nc") +BUILTIN(__builtin_msa_clti_s_h, "V8SsV8SsISi", "nc") +BUILTIN(__builtin_msa_clti_s_w, "V4SiV4SiISi", "nc") +BUILTIN(__builtin_msa_clti_s_d, "V2SLLiV2SLLiISi", "nc") + +BUILTIN(__builtin_msa_clti_u_b, "V16ScV16UcIUi", "nc") +BUILTIN(__builtin_msa_clti_u_h, "V8SsV8UsIUi", "nc") +BUILTIN(__builtin_msa_clti_u_w, "V4SiV4UiIUi", "nc") +BUILTIN(__builtin_msa_clti_u_d, "V2SLLiV2ULLiIUi", "nc") + +BUILTIN(__builtin_msa_copy_s_b, "iV16ScIUi", "nc") +BUILTIN(__builtin_msa_copy_s_h, "iV8SsIUi", "nc") +BUILTIN(__builtin_msa_copy_s_w, "iV4SiIUi", "nc") +BUILTIN(__builtin_msa_copy_s_d, "LLiV2SLLiIUi", "nc") + +BUILTIN(__builtin_msa_copy_u_b, "iV16UcIUi", "nc") +BUILTIN(__builtin_msa_copy_u_h, "iV8UsIUi", "nc") +BUILTIN(__builtin_msa_copy_u_w, "iV4UiIUi", "nc") +BUILTIN(__builtin_msa_copy_u_d, "LLiV2ULLiIUi", "nc") + +BUILTIN(__builtin_msa_ctcmsa, "vIii", "n") + +BUILTIN(__builtin_msa_div_s_b, "V16ScV16ScV16Sc", "nc") +BUILTIN(__builtin_msa_div_s_h, "V8SsV8SsV8Ss", "nc") +BUILTIN(__builtin_msa_div_s_w, "V4SiV4SiV4Si", "nc") +BUILTIN(__builtin_msa_div_s_d, "V2SLLiV2SLLiV2SLLi", "nc") + +BUILTIN(__builtin_msa_div_u_b, "V16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_msa_div_u_h, "V8UsV8UsV8Us", "nc") +BUILTIN(__builtin_msa_div_u_w, "V4UiV4UiV4Ui", "nc") +BUILTIN(__builtin_msa_div_u_d, "V2ULLiV2ULLiV2ULLi", "nc") + +BUILTIN(__builtin_msa_dotp_s_h, "V8SsV16ScV16Sc", "nc") +BUILTIN(__builtin_msa_dotp_s_w, "V4SiV8SsV8Ss", "nc") +BUILTIN(__builtin_msa_dotp_s_d, "V2SLLiV4SiV4Si", "nc") + +BUILTIN(__builtin_msa_dotp_u_h, "V8UsV16UcV16Uc", "nc") +BUILTIN(__builtin_msa_dotp_u_w, "V4UiV8UsV8Us", "nc") +BUILTIN(__builtin_msa_dotp_u_d, "V2ULLiV4UiV4Ui", "nc") + +BUILTIN(__builtin_msa_dpadd_s_h, "V8SsV8SsV16ScV16Sc", "nc") +BUILTIN(__builtin_msa_dpadd_s_w, "V4SiV4SiV8SsV8Ss", "nc") +BUILTIN(__builtin_msa_dpadd_s_d, "V2SLLiV2SLLiV4SiV4Si", "nc") + +BUILTIN(__builtin_msa_dpadd_u_h, "V8UsV8UsV16UcV16Uc", "nc") +BUILTIN(__builtin_msa_dpadd_u_w, "V4UiV4UiV8UsV8Us", "nc") +BUILTIN(__builtin_msa_dpadd_u_d, "V2ULLiV2ULLiV4UiV4Ui", "nc") + +BUILTIN(__builtin_msa_dpsub_s_h, "V8SsV8SsV16ScV16Sc", "nc") +BUILTIN(__builtin_msa_dpsub_s_w, "V4SiV4SiV8SsV8Ss", "nc") +BUILTIN(__builtin_msa_dpsub_s_d, "V2SLLiV2SLLiV4SiV4Si", "nc") + +BUILTIN(__builtin_msa_dpsub_u_h, "V8UsV8UsV16UcV16Uc", "nc") +BUILTIN(__builtin_msa_dpsub_u_w, "V4UiV4UiV8UsV8Us", "nc") +BUILTIN(__builtin_msa_dpsub_u_d, "V2ULLiV2ULLiV4UiV4Ui", "nc") + +BUILTIN(__builtin_msa_fadd_w, "V4fV4fV4f", "nc") +BUILTIN(__builtin_msa_fadd_d, "V2dV2dV2d", "nc") + +BUILTIN(__builtin_msa_fcaf_w, "V4iV4fV4f", "nc") +BUILTIN(__builtin_msa_fcaf_d, "V2LLiV2dV2d", "nc") + +BUILTIN(__builtin_msa_fceq_w, "V4iV4fV4f", "nc") +BUILTIN(__builtin_msa_fceq_d, "V2LLiV2dV2d", "nc") + +BUILTIN(__builtin_msa_fclass_w, "V4iV4f", "nc") +BUILTIN(__builtin_msa_fclass_d, "V2LLiV2d", "nc") + +BUILTIN(__builtin_msa_fcle_w, "V4iV4fV4f", "nc") +BUILTIN(__builtin_msa_fcle_d, "V2LLiV2dV2d", "nc") + +BUILTIN(__builtin_msa_fclt_w, "V4iV4fV4f", "nc") +BUILTIN(__builtin_msa_fclt_d, "V2LLiV2dV2d", "nc") + +BUILTIN(__builtin_msa_fcne_w, "V4iV4fV4f", "nc") +BUILTIN(__builtin_msa_fcne_d, "V2LLiV2dV2d", "nc") + +BUILTIN(__builtin_msa_fcor_w, "V4iV4fV4f", "nc") +BUILTIN(__builtin_msa_fcor_d, "V2LLiV2dV2d", "nc") + +BUILTIN(__builtin_msa_fcueq_w, "V4iV4fV4f", "nc") +BUILTIN(__builtin_msa_fcueq_d, "V2LLiV2dV2d", "nc") + +BUILTIN(__builtin_msa_fcule_w, "V4iV4fV4f", "nc") +BUILTIN(__builtin_msa_fcule_d, "V2LLiV2dV2d", "nc") + +BUILTIN(__builtin_msa_fcult_w, "V4iV4fV4f", "nc") +BUILTIN(__builtin_msa_fcult_d, "V2LLiV2dV2d", "nc") + +BUILTIN(__builtin_msa_fcun_w, "V4iV4fV4f", "nc") +BUILTIN(__builtin_msa_fcun_d, "V2LLiV2dV2d", "nc") + +BUILTIN(__builtin_msa_fcune_w, "V4iV4fV4f", "nc") +BUILTIN(__builtin_msa_fcune_d, "V2LLiV2dV2d", "nc") + +BUILTIN(__builtin_msa_fdiv_w, "V4fV4fV4f", "nc") +BUILTIN(__builtin_msa_fdiv_d, "V2dV2dV2d", "nc") + +BUILTIN(__builtin_msa_fexdo_h, "V8hV4fV4f", "nc") +BUILTIN(__builtin_msa_fexdo_w, "V4fV2dV2d", "nc") + +BUILTIN(__builtin_msa_fexp2_w, "V4fV4fV4i", "nc") +BUILTIN(__builtin_msa_fexp2_d, "V2dV2dV2LLi", "nc") + +BUILTIN(__builtin_msa_fexupl_w, "V4fV8h", "nc") +BUILTIN(__builtin_msa_fexupl_d, "V2dV4f", "nc") + +BUILTIN(__builtin_msa_fexupr_w, "V4fV8h", "nc") +BUILTIN(__builtin_msa_fexupr_d, "V2dV4f", "nc") + +BUILTIN(__builtin_msa_ffint_s_w, "V4fV4Si", "nc") +BUILTIN(__builtin_msa_ffint_s_d, "V2dV2SLLi", "nc") + +BUILTIN(__builtin_msa_ffint_u_w, "V4fV4Ui", "nc") +BUILTIN(__builtin_msa_ffint_u_d, "V2dV2ULLi", "nc") + +// ffql uses integers since long _Fract is not implemented +BUILTIN(__builtin_msa_ffql_w, "V4fV8Ss", "nc") +BUILTIN(__builtin_msa_ffql_d, "V2dV4Si", "nc") + +// ffqr uses integers since long _Fract is not implemented +BUILTIN(__builtin_msa_ffqr_w, "V4fV8Ss", "nc") +BUILTIN(__builtin_msa_ffqr_d, "V2dV4Si", "nc") + +BUILTIN(__builtin_msa_fill_b, "V16Sci", "nc") +BUILTIN(__builtin_msa_fill_h, "V8Ssi", "nc") +BUILTIN(__builtin_msa_fill_w, "V4Sii", "nc") +BUILTIN(__builtin_msa_fill_d, "V2SLLiLLi", "nc") + +BUILTIN(__builtin_msa_flog2_w, "V4fV4f", "nc") +BUILTIN(__builtin_msa_flog2_d, "V2dV2d", "nc") + +BUILTIN(__builtin_msa_fmadd_w, "V4fV4fV4fV4f", "nc") +BUILTIN(__builtin_msa_fmadd_d, "V2dV2dV2dV2d", "nc") + +BUILTIN(__builtin_msa_fmax_w, "V4fV4fV4f", "nc") +BUILTIN(__builtin_msa_fmax_d, "V2dV2dV2d", "nc") + +BUILTIN(__builtin_msa_fmax_a_w, "V4fV4fV4f", "nc") +BUILTIN(__builtin_msa_fmax_a_d, "V2dV2dV2d", "nc") + +BUILTIN(__builtin_msa_fmin_w, "V4fV4fV4f", "nc") +BUILTIN(__builtin_msa_fmin_d, "V2dV2dV2d", "nc") + +BUILTIN(__builtin_msa_fmin_a_w, "V4fV4fV4f", "nc") +BUILTIN(__builtin_msa_fmin_a_d, "V2dV2dV2d", "nc") + +BUILTIN(__builtin_msa_fmsub_w, "V4fV4fV4fV4f", "nc") +BUILTIN(__builtin_msa_fmsub_d, "V2dV2dV2dV2d", "nc") + +BUILTIN(__builtin_msa_fmul_w, "V4fV4fV4f", "nc") +BUILTIN(__builtin_msa_fmul_d, "V2dV2dV2d", "nc") + +BUILTIN(__builtin_msa_frint_w, "V4fV4f", "nc") +BUILTIN(__builtin_msa_frint_d, "V2dV2d", "nc") + +BUILTIN(__builtin_msa_frcp_w, "V4fV4f", "nc") +BUILTIN(__builtin_msa_frcp_d, "V2dV2d", "nc") + +BUILTIN(__builtin_msa_frsqrt_w, "V4fV4f", "nc") +BUILTIN(__builtin_msa_frsqrt_d, "V2dV2d", "nc") + +BUILTIN(__builtin_msa_fsaf_w, "V4iV4fV4f", "nc") +BUILTIN(__builtin_msa_fsaf_d, "V2LLiV2dV2d", "nc") + +BUILTIN(__builtin_msa_fseq_w, "V4iV4fV4f", "nc") +BUILTIN(__builtin_msa_fseq_d, "V2LLiV2dV2d", "nc") + +BUILTIN(__builtin_msa_fsle_w, "V4iV4fV4f", "nc") +BUILTIN(__builtin_msa_fsle_d, "V2LLiV2dV2d", "nc") + +BUILTIN(__builtin_msa_fslt_w, "V4iV4fV4f", "nc") +BUILTIN(__builtin_msa_fslt_d, "V2LLiV2dV2d", "nc") + +BUILTIN(__builtin_msa_fsne_w, "V4iV4fV4f", "nc") +BUILTIN(__builtin_msa_fsne_d, "V2LLiV2dV2d", "nc") + +BUILTIN(__builtin_msa_fsor_w, "V4iV4fV4f", "nc") +BUILTIN(__builtin_msa_fsor_d, "V2LLiV2dV2d", "nc") + +BUILTIN(__builtin_msa_fsqrt_w, "V4fV4f", "nc") +BUILTIN(__builtin_msa_fsqrt_d, "V2dV2d", "nc") + +BUILTIN(__builtin_msa_fsub_w, "V4fV4fV4f", "nc") +BUILTIN(__builtin_msa_fsub_d, "V2dV2dV2d", "nc") + +BUILTIN(__builtin_msa_fsueq_w, "V4iV4fV4f", "nc") +BUILTIN(__builtin_msa_fsueq_d, "V2LLiV2dV2d", "nc") + +BUILTIN(__builtin_msa_fsule_w, "V4iV4fV4f", "nc") +BUILTIN(__builtin_msa_fsule_d, "V2LLiV2dV2d", "nc") + +BUILTIN(__builtin_msa_fsult_w, "V4iV4fV4f", "nc") +BUILTIN(__builtin_msa_fsult_d, "V2LLiV2dV2d", "nc") + +BUILTIN(__builtin_msa_fsun_w, "V4iV4fV4f", "nc") +BUILTIN(__builtin_msa_fsun_d, "V2LLiV2dV2d", "nc") + +BUILTIN(__builtin_msa_fsune_w, "V4iV4fV4f", "nc") +BUILTIN(__builtin_msa_fsune_d, "V2LLiV2dV2d", "nc") + +BUILTIN(__builtin_msa_ftint_s_w, "V4SiV4f", "nc") +BUILTIN(__builtin_msa_ftint_s_d, "V2SLLiV2d", "nc") + +BUILTIN(__builtin_msa_ftint_u_w, "V4UiV4f", "nc") +BUILTIN(__builtin_msa_ftint_u_d, "V2ULLiV2d", "nc") + +BUILTIN(__builtin_msa_ftq_h, "V4UiV4fV4f", "nc") +BUILTIN(__builtin_msa_ftq_w, "V2ULLiV2dV2d", "nc") + +BUILTIN(__builtin_msa_ftrunc_s_w, "V4SiV4f", "nc") +BUILTIN(__builtin_msa_ftrunc_s_d, "V2SLLiV2d", "nc") + +BUILTIN(__builtin_msa_ftrunc_u_w, "V4UiV4f", "nc") +BUILTIN(__builtin_msa_ftrunc_u_d, "V2ULLiV2d", "nc") + +BUILTIN(__builtin_msa_hadd_s_h, "V8SsV16ScV16Sc", "nc") +BUILTIN(__builtin_msa_hadd_s_w, "V4SiV8SsV8Ss", "nc") +BUILTIN(__builtin_msa_hadd_s_d, "V2SLLiV4SiV4Si", "nc") + +BUILTIN(__builtin_msa_hadd_u_h, "V8UsV16UcV16Uc", "nc") +BUILTIN(__builtin_msa_hadd_u_w, "V4UiV8UsV8Us", "nc") +BUILTIN(__builtin_msa_hadd_u_d, "V2ULLiV4UiV4Ui", "nc") + +BUILTIN(__builtin_msa_hsub_s_h, "V8SsV16ScV16Sc", "nc") +BUILTIN(__builtin_msa_hsub_s_w, "V4SiV8SsV8Ss", "nc") +BUILTIN(__builtin_msa_hsub_s_d, "V2SLLiV4SiV4Si", "nc") + +BUILTIN(__builtin_msa_hsub_u_h, "V8UsV16UcV16Uc", "nc") +BUILTIN(__builtin_msa_hsub_u_w, "V4UiV8UsV8Us", "nc") +BUILTIN(__builtin_msa_hsub_u_d, "V2ULLiV4UiV4Ui", "nc") + +BUILTIN(__builtin_msa_ilvev_b, "V16cV16cV16c", "nc") +BUILTIN(__builtin_msa_ilvev_h, "V8sV8sV8s", "nc") +BUILTIN(__builtin_msa_ilvev_w, "V4iV4iV4i", "nc") +BUILTIN(__builtin_msa_ilvev_d, "V2LLiV2LLiV2LLi", "nc") + +BUILTIN(__builtin_msa_ilvl_b, "V16cV16cV16c", "nc") +BUILTIN(__builtin_msa_ilvl_h, "V8sV8sV8s", "nc") +BUILTIN(__builtin_msa_ilvl_w, "V4iV4iV4i", "nc") +BUILTIN(__builtin_msa_ilvl_d, "V2LLiV2LLiV2LLi", "nc") + +BUILTIN(__builtin_msa_ilvod_b, "V16cV16cV16c", "nc") +BUILTIN(__builtin_msa_ilvod_h, "V8sV8sV8s", "nc") +BUILTIN(__builtin_msa_ilvod_w, "V4iV4iV4i", "nc") +BUILTIN(__builtin_msa_ilvod_d, "V2LLiV2LLiV2LLi", "nc") + +BUILTIN(__builtin_msa_ilvr_b, "V16cV16cV16c", "nc") +BUILTIN(__builtin_msa_ilvr_h, "V8sV8sV8s", "nc") +BUILTIN(__builtin_msa_ilvr_w, "V4iV4iV4i", "nc") +BUILTIN(__builtin_msa_ilvr_d, "V2LLiV2LLiV2LLi", "nc") + +BUILTIN(__builtin_msa_insert_b, "V16ScV16ScIUii", "nc") +BUILTIN(__builtin_msa_insert_h, "V8SsV8SsIUii", "nc") +BUILTIN(__builtin_msa_insert_w, "V4SiV4SiIUii", "nc") +BUILTIN(__builtin_msa_insert_d, "V2SLLiV2SLLiIUiLLi", "nc") + +BUILTIN(__builtin_msa_insve_b, "V16ScV16ScIUiV16Sc", "nc") +BUILTIN(__builtin_msa_insve_h, "V8SsV8SsIUiV8Ss", "nc") +BUILTIN(__builtin_msa_insve_w, "V4SiV4SiIUiV4Si", "nc") +BUILTIN(__builtin_msa_insve_d, "V2SLLiV2SLLiIUiV2SLLi", "nc") + +BUILTIN(__builtin_msa_ld_b, "V16Scv*Ii", "nc") +BUILTIN(__builtin_msa_ld_h, "V8Ssv*Ii", "nc") +BUILTIN(__builtin_msa_ld_w, "V4Siv*Ii", "nc") +BUILTIN(__builtin_msa_ld_d, "V2SLLiv*Ii", "nc") + +BUILTIN(__builtin_msa_ldi_b, "V16cIi", "nc") +BUILTIN(__builtin_msa_ldi_h, "V8sIi", "nc") +BUILTIN(__builtin_msa_ldi_w, "V4iIi", "nc") +BUILTIN(__builtin_msa_ldi_d, "V2LLiIi", "nc") + +BUILTIN(__builtin_msa_madd_q_h, "V8SsV8SsV8SsV8Ss", "nc") +BUILTIN(__builtin_msa_madd_q_w, "V4SiV4SiV4SiV4Si", "nc") + +BUILTIN(__builtin_msa_maddr_q_h, "V8SsV8SsV8SsV8Ss", "nc") +BUILTIN(__builtin_msa_maddr_q_w, "V4SiV4SiV4SiV4Si", "nc") + +BUILTIN(__builtin_msa_maddv_b, "V16ScV16ScV16ScV16Sc", "nc") +BUILTIN(__builtin_msa_maddv_h, "V8SsV8SsV8SsV8Ss", "nc") +BUILTIN(__builtin_msa_maddv_w, "V4SiV4SiV4SiV4Si", "nc") +BUILTIN(__builtin_msa_maddv_d, "V2SLLiV2SLLiV2SLLiV2SLLi", "nc") + +BUILTIN(__builtin_msa_max_a_b, "V16ScV16ScV16Sc", "nc") +BUILTIN(__builtin_msa_max_a_h, "V8SsV8SsV8Ss", "nc") +BUILTIN(__builtin_msa_max_a_w, "V4SiV4SiV4Si", "nc") +BUILTIN(__builtin_msa_max_a_d, "V2SLLiV2SLLiV2SLLi", "nc") + +BUILTIN(__builtin_msa_max_s_b, "V16ScV16ScV16Sc", "nc") +BUILTIN(__builtin_msa_max_s_h, "V8SsV8SsV8Ss", "nc") +BUILTIN(__builtin_msa_max_s_w, "V4SiV4SiV4Si", "nc") +BUILTIN(__builtin_msa_max_s_d, "V2SLLiV2SLLiV2SLLi", "nc") + +BUILTIN(__builtin_msa_max_u_b, "V16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_msa_max_u_h, "V8UsV8UsV8Us", "nc") +BUILTIN(__builtin_msa_max_u_w, "V4UiV4UiV4Ui", "nc") +BUILTIN(__builtin_msa_max_u_d, "V2ULLiV2ULLiV2ULLi", "nc") + +BUILTIN(__builtin_msa_maxi_s_b, "V16ScV16ScIi", "nc") +BUILTIN(__builtin_msa_maxi_s_h, "V8SsV8SsIi", "nc") +BUILTIN(__builtin_msa_maxi_s_w, "V4SiV4SiIi", "nc") +BUILTIN(__builtin_msa_maxi_s_d, "V2SLLiV2SLLiIi", "nc") + +BUILTIN(__builtin_msa_maxi_u_b, "V16UcV16UcIi", "nc") +BUILTIN(__builtin_msa_maxi_u_h, "V8UsV8UsIi", "nc") +BUILTIN(__builtin_msa_maxi_u_w, "V4UiV4UiIi", "nc") +BUILTIN(__builtin_msa_maxi_u_d, "V2ULLiV2ULLiIi", "nc") + +BUILTIN(__builtin_msa_min_a_b, "V16ScV16ScV16Sc", "nc") +BUILTIN(__builtin_msa_min_a_h, "V8SsV8SsV8Ss", "nc") +BUILTIN(__builtin_msa_min_a_w, "V4SiV4SiV4Si", "nc") +BUILTIN(__builtin_msa_min_a_d, "V2SLLiV2SLLiV2SLLi", "nc") + +BUILTIN(__builtin_msa_min_s_b, "V16ScV16ScV16Sc", "nc") +BUILTIN(__builtin_msa_min_s_h, "V8SsV8SsV8Ss", "nc") +BUILTIN(__builtin_msa_min_s_w, "V4SiV4SiV4Si", "nc") +BUILTIN(__builtin_msa_min_s_d, "V2SLLiV2SLLiV2SLLi", "nc") + +BUILTIN(__builtin_msa_min_u_b, "V16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_msa_min_u_h, "V8UsV8UsV8Us", "nc") +BUILTIN(__builtin_msa_min_u_w, "V4UiV4UiV4Ui", "nc") +BUILTIN(__builtin_msa_min_u_d, "V2ULLiV2ULLiV2ULLi", "nc") + +BUILTIN(__builtin_msa_mini_s_b, "V16ScV16ScIi", "nc") +BUILTIN(__builtin_msa_mini_s_h, "V8SsV8SsIi", "nc") +BUILTIN(__builtin_msa_mini_s_w, "V4SiV4SiIi", "nc") +BUILTIN(__builtin_msa_mini_s_d, "V2SLLiV2SLLiIi", "nc") + +BUILTIN(__builtin_msa_mini_u_b, "V16UcV16UcIi", "nc") +BUILTIN(__builtin_msa_mini_u_h, "V8UsV8UsIi", "nc") +BUILTIN(__builtin_msa_mini_u_w, "V4UiV4UiIi", "nc") +BUILTIN(__builtin_msa_mini_u_d, "V2ULLiV2ULLiIi", "nc") + +BUILTIN(__builtin_msa_mod_s_b, "V16ScV16ScV16Sc", "nc") +BUILTIN(__builtin_msa_mod_s_h, "V8SsV8SsV8Ss", "nc") +BUILTIN(__builtin_msa_mod_s_w, "V4SiV4SiV4Si", "nc") +BUILTIN(__builtin_msa_mod_s_d, "V2SLLiV2SLLiV2SLLi", "nc") + +BUILTIN(__builtin_msa_mod_u_b, "V16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_msa_mod_u_h, "V8UsV8UsV8Us", "nc") +BUILTIN(__builtin_msa_mod_u_w, "V4UiV4UiV4Ui", "nc") +BUILTIN(__builtin_msa_mod_u_d, "V2ULLiV2ULLiV2ULLi", "nc") + +BUILTIN(__builtin_msa_move_v, "V16ScV16Sc", "nc") + +BUILTIN(__builtin_msa_msub_q_h, "V8SsV8SsV8SsV8Ss", "nc") +BUILTIN(__builtin_msa_msub_q_w, "V4SiV4SiV4SiV4Si", "nc") + +BUILTIN(__builtin_msa_msubr_q_h, "V8SsV8SsV8SsV8Ss", "nc") +BUILTIN(__builtin_msa_msubr_q_w, "V4SiV4SiV4SiV4Si", "nc") + +BUILTIN(__builtin_msa_msubv_b, "V16ScV16ScV16ScV16Sc", "nc") +BUILTIN(__builtin_msa_msubv_h, "V8SsV8SsV8SsV8Ss", "nc") +BUILTIN(__builtin_msa_msubv_w, "V4SiV4SiV4SiV4Si", "nc") +BUILTIN(__builtin_msa_msubv_d, "V2SLLiV2SLLiV2SLLiV2SLLi", "nc") + +BUILTIN(__builtin_msa_mul_q_h, "V8SsV8SsV8Ss", "nc") +BUILTIN(__builtin_msa_mul_q_w, "V4SiV4SiV4Si", "nc") + +BUILTIN(__builtin_msa_mulr_q_h, "V8SsV8SsV8Ss", "nc") +BUILTIN(__builtin_msa_mulr_q_w, "V4SiV4SiV4Si", "nc") + +BUILTIN(__builtin_msa_mulv_b, "V16ScV16ScV16Sc", "nc") +BUILTIN(__builtin_msa_mulv_h, "V8SsV8SsV8Ss", "nc") +BUILTIN(__builtin_msa_mulv_w, "V4SiV4SiV4Si", "nc") +BUILTIN(__builtin_msa_mulv_d, "V2SLLiV2SLLiV2SLLi", "nc") + +BUILTIN(__builtin_msa_nloc_b, "V16ScV16Sc", "nc") +BUILTIN(__builtin_msa_nloc_h, "V8SsV8Ss", "nc") +BUILTIN(__builtin_msa_nloc_w, "V4SiV4Si", "nc") +BUILTIN(__builtin_msa_nloc_d, "V2SLLiV2SLLi", "nc") + +BUILTIN(__builtin_msa_nlzc_b, "V16ScV16Sc", "nc") +BUILTIN(__builtin_msa_nlzc_h, "V8SsV8Ss", "nc") +BUILTIN(__builtin_msa_nlzc_w, "V4SiV4Si", "nc") +BUILTIN(__builtin_msa_nlzc_d, "V2SLLiV2SLLi", "nc") + +BUILTIN(__builtin_msa_nor_v, "V16UcV16UcV16Uc", "nc") + +BUILTIN(__builtin_msa_nori_b, "V16UcV16cIUi", "nc") + +BUILTIN(__builtin_msa_or_v, "V16UcV16UcV16Uc", "nc") + +BUILTIN(__builtin_msa_ori_b, "V16UcV16UcIUi", "nc") + +BUILTIN(__builtin_msa_pckev_b, "V16cV16cV16c", "nc") +BUILTIN(__builtin_msa_pckev_h, "V8sV8sV8s", "nc") +BUILTIN(__builtin_msa_pckev_w, "V4iV4iV4i", "nc") +BUILTIN(__builtin_msa_pckev_d, "V2LLiV2LLiV2LLi", "nc") + +BUILTIN(__builtin_msa_pckod_b, "V16cV16cV16c", "nc") +BUILTIN(__builtin_msa_pckod_h, "V8sV8sV8s", "nc") +BUILTIN(__builtin_msa_pckod_w, "V4iV4iV4i", "nc") +BUILTIN(__builtin_msa_pckod_d, "V2LLiV2LLiV2LLi", "nc") + +BUILTIN(__builtin_msa_pcnt_b, "V16ScV16Sc", "nc") +BUILTIN(__builtin_msa_pcnt_h, "V8SsV8Ss", "nc") +BUILTIN(__builtin_msa_pcnt_w, "V4SiV4Si", "nc") +BUILTIN(__builtin_msa_pcnt_d, "V2SLLiV2SLLi", "nc") + +BUILTIN(__builtin_msa_sat_s_b, "V16ScV16ScIUi", "nc") +BUILTIN(__builtin_msa_sat_s_h, "V8SsV8SsIUi", "nc") +BUILTIN(__builtin_msa_sat_s_w, "V4SiV4SiIUi", "nc") +BUILTIN(__builtin_msa_sat_s_d, "V2SLLiV2SLLiIUi", "nc") + +BUILTIN(__builtin_msa_sat_u_b, "V16UcV16UcIUi", "nc") +BUILTIN(__builtin_msa_sat_u_h, "V8UsV8UsIUi", "nc") +BUILTIN(__builtin_msa_sat_u_w, "V4UiV4UiIUi", "nc") +BUILTIN(__builtin_msa_sat_u_d, "V2ULLiV2ULLiIUi", "nc") + +BUILTIN(__builtin_msa_shf_b, "V16cV16cIUi", "nc") +BUILTIN(__builtin_msa_shf_h, "V8sV8sIUi", "nc") +BUILTIN(__builtin_msa_shf_w, "V4iV4iIUi", "nc") + +BUILTIN(__builtin_msa_sld_b, "V16cV16cV16cUi", "nc") +BUILTIN(__builtin_msa_sld_h, "V8sV8sV8sUi", "nc") +BUILTIN(__builtin_msa_sld_w, "V4iV4iV4iUi", "nc") +BUILTIN(__builtin_msa_sld_d, "V2LLiV2LLiV2LLiUi", "nc") + +BUILTIN(__builtin_msa_sldi_b, "V16cV16cV16cIUi", "nc") +BUILTIN(__builtin_msa_sldi_h, "V8sV8sV8sIUi", "nc") +BUILTIN(__builtin_msa_sldi_w, "V4iV4iV4iIUi", "nc") +BUILTIN(__builtin_msa_sldi_d, "V2LLiV2LLiV2LLiIUi", "nc") + +BUILTIN(__builtin_msa_sll_b, "V16cV16cV16c", "nc") +BUILTIN(__builtin_msa_sll_h, "V8sV8sV8s", "nc") +BUILTIN(__builtin_msa_sll_w, "V4iV4iV4i", "nc") +BUILTIN(__builtin_msa_sll_d, "V2LLiV2LLiV2LLi", "nc") + +BUILTIN(__builtin_msa_slli_b, "V16cV16cIUi", "nc") +BUILTIN(__builtin_msa_slli_h, "V8sV8sIUi", "nc") +BUILTIN(__builtin_msa_slli_w, "V4iV4iIUi", "nc") +BUILTIN(__builtin_msa_slli_d, "V2LLiV2LLiIUi", "nc") + +BUILTIN(__builtin_msa_splat_b, "V16cV16cUi", "nc") +BUILTIN(__builtin_msa_splat_h, "V8sV8sUi", "nc") +BUILTIN(__builtin_msa_splat_w, "V4iV4iUi", "nc") +BUILTIN(__builtin_msa_splat_d, "V2LLiV2LLiUi", "nc") + +BUILTIN(__builtin_msa_splati_b, "V16cV16cIUi", "nc") +BUILTIN(__builtin_msa_splati_h, "V8sV8sIUi", "nc") +BUILTIN(__builtin_msa_splati_w, "V4iV4iIUi", "nc") +BUILTIN(__builtin_msa_splati_d, "V2LLiV2LLiIUi", "nc") + +BUILTIN(__builtin_msa_sra_b, "V16cV16cV16c", "nc") +BUILTIN(__builtin_msa_sra_h, "V8sV8sV8s", "nc") +BUILTIN(__builtin_msa_sra_w, "V4iV4iV4i", "nc") +BUILTIN(__builtin_msa_sra_d, "V2LLiV2LLiV2LLi", "nc") + +BUILTIN(__builtin_msa_srai_b, "V16cV16cIUi", "nc") +BUILTIN(__builtin_msa_srai_h, "V8sV8sIUi", "nc") +BUILTIN(__builtin_msa_srai_w, "V4iV4iIUi", "nc") +BUILTIN(__builtin_msa_srai_d, "V2LLiV2LLiIUi", "nc") + +BUILTIN(__builtin_msa_srar_b, "V16cV16cV16c", "nc") +BUILTIN(__builtin_msa_srar_h, "V8sV8sV8s", "nc") +BUILTIN(__builtin_msa_srar_w, "V4iV4iV4i", "nc") +BUILTIN(__builtin_msa_srar_d, "V2LLiV2LLiV2LLi", "nc") + +BUILTIN(__builtin_msa_srari_b, "V16cV16cIUi", "nc") +BUILTIN(__builtin_msa_srari_h, "V8sV8sIUi", "nc") +BUILTIN(__builtin_msa_srari_w, "V4iV4iIUi", "nc") +BUILTIN(__builtin_msa_srari_d, "V2LLiV2LLiIUi", "nc") + +BUILTIN(__builtin_msa_srl_b, "V16cV16cV16c", "nc") +BUILTIN(__builtin_msa_srl_h, "V8sV8sV8s", "nc") +BUILTIN(__builtin_msa_srl_w, "V4iV4iV4i", "nc") +BUILTIN(__builtin_msa_srl_d, "V2LLiV2LLiV2LLi", "nc") + +BUILTIN(__builtin_msa_srli_b, "V16cV16cIUi", "nc") +BUILTIN(__builtin_msa_srli_h, "V8sV8sIUi", "nc") +BUILTIN(__builtin_msa_srli_w, "V4iV4iIUi", "nc") +BUILTIN(__builtin_msa_srli_d, "V2LLiV2LLiIUi", "nc") + +BUILTIN(__builtin_msa_srlr_b, "V16cV16cV16c", "nc") +BUILTIN(__builtin_msa_srlr_h, "V8sV8sV8s", "nc") +BUILTIN(__builtin_msa_srlr_w, "V4iV4iV4i", "nc") +BUILTIN(__builtin_msa_srlr_d, "V2LLiV2LLiV2LLi", "nc") + +BUILTIN(__builtin_msa_srlri_b, "V16cV16cIUi", "nc") +BUILTIN(__builtin_msa_srlri_h, "V8sV8sIUi", "nc") +BUILTIN(__builtin_msa_srlri_w, "V4iV4iIUi", "nc") +BUILTIN(__builtin_msa_srlri_d, "V2LLiV2LLiIUi", "nc") + +BUILTIN(__builtin_msa_st_b, "vV16Scv*Ii", "nc") +BUILTIN(__builtin_msa_st_h, "vV8Ssv*Ii", "nc") +BUILTIN(__builtin_msa_st_w, "vV4Siv*Ii", "nc") +BUILTIN(__builtin_msa_st_d, "vV2SLLiv*Ii", "nc") + +BUILTIN(__builtin_msa_subs_s_b, "V16ScV16ScV16Sc", "nc") +BUILTIN(__builtin_msa_subs_s_h, "V8SsV8SsV8Ss", "nc") +BUILTIN(__builtin_msa_subs_s_w, "V4SiV4SiV4Si", "nc") +BUILTIN(__builtin_msa_subs_s_d, "V2SLLiV2SLLiV2SLLi", "nc") + +BUILTIN(__builtin_msa_subs_u_b, "V16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_msa_subs_u_h, "V8UsV8UsV8Us", "nc") +BUILTIN(__builtin_msa_subs_u_w, "V4UiV4UiV4Ui", "nc") +BUILTIN(__builtin_msa_subs_u_d, "V2ULLiV2ULLiV2ULLi", "nc") + +BUILTIN(__builtin_msa_subsus_u_b, "V16UcV16UcV16Sc", "nc") +BUILTIN(__builtin_msa_subsus_u_h, "V8UsV8UsV8Ss", "nc") +BUILTIN(__builtin_msa_subsus_u_w, "V4UiV4UiV4Si", "nc") +BUILTIN(__builtin_msa_subsus_u_d, "V2ULLiV2ULLiV2SLLi", "nc") + +BUILTIN(__builtin_msa_subsuu_s_b, "V16ScV16UcV16Uc", "nc") +BUILTIN(__builtin_msa_subsuu_s_h, "V8SsV8UsV8Us", "nc") +BUILTIN(__builtin_msa_subsuu_s_w, "V4SiV4UiV4Ui", "nc") +BUILTIN(__builtin_msa_subsuu_s_d, "V2SLLiV2ULLiV2ULLi", "nc") + +BUILTIN(__builtin_msa_subv_b, "V16cV16cV16c", "nc") +BUILTIN(__builtin_msa_subv_h, "V8sV8sV8s", "nc") +BUILTIN(__builtin_msa_subv_w, "V4iV4iV4i", "nc") +BUILTIN(__builtin_msa_subv_d, "V2LLiV2LLiV2LLi", "nc") + +BUILTIN(__builtin_msa_subvi_b, "V16cV16cIUi", "nc") +BUILTIN(__builtin_msa_subvi_h, "V8sV8sIUi", "nc") +BUILTIN(__builtin_msa_subvi_w, "V4iV4iIUi", "nc") +BUILTIN(__builtin_msa_subvi_d, "V2LLiV2LLiIUi", "nc") + +BUILTIN(__builtin_msa_vshf_b, "V16cV16cV16cV16c", "nc") +BUILTIN(__builtin_msa_vshf_h, "V8sV8sV8sV8s", "nc") +BUILTIN(__builtin_msa_vshf_w, "V4iV4iV4iV4i", "nc") +BUILTIN(__builtin_msa_vshf_d, "V2LLiV2LLiV2LLiV2LLi", "nc") + +BUILTIN(__builtin_msa_xor_v, "V16cV16cV16c", "nc") + +BUILTIN(__builtin_msa_xori_b, "V16cV16cIUi", "nc") + +#undef BUILTIN diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsNEON.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsNEON.def new file mode 100644 index 0000000..7800ae69 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsNEON.def @@ -0,0 +1,21 @@ +//===--- BuiltinsNEON.def - NEON Builtin function database ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the NEON-specific builtin function database. Users of +// this file must define the BUILTIN macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +// The format of this database matches clang/Basic/Builtins.def. + +#define GET_NEON_BUILTINS +#include "clang/Basic/arm_neon.inc" +#undef GET_NEON_BUILTINS + +#undef BUILTIN diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsNVPTX.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsNVPTX.def new file mode 100644 index 0000000..3ab6413 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsNVPTX.def @@ -0,0 +1,569 @@ +//===--- BuiltinsPTX.def - PTX Builtin function database ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the PTX-specific builtin function database. Users of +// this file must define the BUILTIN macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +// The format of this database matches clang/Basic/Builtins.def. + +// Builtins retained from previous PTX back-end +BUILTIN(__builtin_ptx_read_tid_x, "i", "nc") +BUILTIN(__builtin_ptx_read_tid_y, "i", "nc") +BUILTIN(__builtin_ptx_read_tid_z, "i", "nc") +BUILTIN(__builtin_ptx_read_tid_w, "i", "nc") + +BUILTIN(__builtin_ptx_read_ntid_x, "i", "nc") +BUILTIN(__builtin_ptx_read_ntid_y, "i", "nc") +BUILTIN(__builtin_ptx_read_ntid_z, "i", "nc") +BUILTIN(__builtin_ptx_read_ntid_w, "i", "nc") + +BUILTIN(__builtin_ptx_read_ctaid_x, "i", "nc") +BUILTIN(__builtin_ptx_read_ctaid_y, "i", "nc") +BUILTIN(__builtin_ptx_read_ctaid_z, "i", "nc") +BUILTIN(__builtin_ptx_read_ctaid_w, "i", "nc") + +BUILTIN(__builtin_ptx_read_nctaid_x, "i", "nc") +BUILTIN(__builtin_ptx_read_nctaid_y, "i", "nc") +BUILTIN(__builtin_ptx_read_nctaid_z, "i", "nc") +BUILTIN(__builtin_ptx_read_nctaid_w, "i", "nc") + +BUILTIN(__builtin_ptx_read_laneid, "i", "nc") +BUILTIN(__builtin_ptx_read_warpid, "i", "nc") +BUILTIN(__builtin_ptx_read_nwarpid, "i", "nc") + +BUILTIN(__builtin_ptx_read_smid, "i", "nc") +BUILTIN(__builtin_ptx_read_nsmid, "i", "nc") +BUILTIN(__builtin_ptx_read_gridid, "i", "nc") + +BUILTIN(__builtin_ptx_read_lanemask_eq, "i", "nc") +BUILTIN(__builtin_ptx_read_lanemask_le, "i", "nc") +BUILTIN(__builtin_ptx_read_lanemask_lt, "i", "nc") +BUILTIN(__builtin_ptx_read_lanemask_ge, "i", "nc") +BUILTIN(__builtin_ptx_read_lanemask_gt, "i", "nc") + +BUILTIN(__builtin_ptx_read_clock, "i", "n") +BUILTIN(__builtin_ptx_read_clock64, "LLi", "n") + +BUILTIN(__builtin_ptx_read_pm0, "i", "n") +BUILTIN(__builtin_ptx_read_pm1, "i", "n") +BUILTIN(__builtin_ptx_read_pm2, "i", "n") +BUILTIN(__builtin_ptx_read_pm3, "i", "n") + +BUILTIN(__builtin_ptx_bar_sync, "vi", "n") + + +// Builtins exposed as part of NVVM +// MISC + +BUILTIN(__nvvm_clz_i, "ii", "") +BUILTIN(__nvvm_clz_ll, "iLLi", "") +BUILTIN(__nvvm_popc_i, "ii", "") +BUILTIN(__nvvm_popc_ll, "iLLi", "") +BUILTIN(__nvvm_prmt, "UiUiUiUi", "") + +// Min Max + +BUILTIN(__nvvm_min_i, "iii", "") +BUILTIN(__nvvm_min_ui, "UiUiUi", "") +BUILTIN(__nvvm_min_ll, "LLiLLiLLi", "") +BUILTIN(__nvvm_min_ull, "ULLiULLiULLi", "") + +BUILTIN(__nvvm_max_i, "iii", "") +BUILTIN(__nvvm_max_ui, "UiUiUi", "") +BUILTIN(__nvvm_max_ll, "LLiLLiLLi", "") +BUILTIN(__nvvm_max_ull, "ULLiULLiULLi", "") + +BUILTIN(__nvvm_fmax_ftz_f, "fff", "") +BUILTIN(__nvvm_fmax_f, "fff", "") +BUILTIN(__nvvm_fmin_ftz_f, "fff", "") +BUILTIN(__nvvm_fmin_f, "fff", "") + +BUILTIN(__nvvm_fmax_d, "ddd", "") +BUILTIN(__nvvm_fmin_d, "ddd", "") + +// Multiplication + +BUILTIN(__nvvm_mulhi_i, "iii", "") +BUILTIN(__nvvm_mulhi_ui, "UiUiUi", "") +BUILTIN(__nvvm_mulhi_ll, "LLiLLiLLi", "") +BUILTIN(__nvvm_mulhi_ull, "ULLiULLiULLi", "") + +BUILTIN(__nvvm_mul_rn_ftz_f, "fff", "") +BUILTIN(__nvvm_mul_rn_f, "fff", "") +BUILTIN(__nvvm_mul_rz_ftz_f, "fff", "") +BUILTIN(__nvvm_mul_rz_f, "fff", "") +BUILTIN(__nvvm_mul_rm_ftz_f, "fff", "") +BUILTIN(__nvvm_mul_rm_f, "fff", "") +BUILTIN(__nvvm_mul_rp_ftz_f, "fff", "") +BUILTIN(__nvvm_mul_rp_f, "fff", "") + +BUILTIN(__nvvm_mul_rn_d, "ddd", "") +BUILTIN(__nvvm_mul_rz_d, "ddd", "") +BUILTIN(__nvvm_mul_rm_d, "ddd", "") +BUILTIN(__nvvm_mul_rp_d, "ddd", "") + +BUILTIN(__nvvm_mul24_i, "iii", "") +BUILTIN(__nvvm_mul24_ui, "UiUiUi", "") + +// Div + +BUILTIN(__nvvm_div_approx_ftz_f, "fff", "") +BUILTIN(__nvvm_div_approx_f, "fff", "") + +BUILTIN(__nvvm_div_rn_ftz_f, "fff", "") +BUILTIN(__nvvm_div_rn_f, "fff", "") +BUILTIN(__nvvm_div_rz_ftz_f, "fff", "") +BUILTIN(__nvvm_div_rz_f, "fff", "") +BUILTIN(__nvvm_div_rm_ftz_f, "fff", "") +BUILTIN(__nvvm_div_rm_f, "fff", "") +BUILTIN(__nvvm_div_rp_ftz_f, "fff", "") +BUILTIN(__nvvm_div_rp_f, "fff", "") + +BUILTIN(__nvvm_div_rn_d, "ddd", "") +BUILTIN(__nvvm_div_rz_d, "ddd", "") +BUILTIN(__nvvm_div_rm_d, "ddd", "") +BUILTIN(__nvvm_div_rp_d, "ddd", "") + +// Brev + +BUILTIN(__nvvm_brev32, "UiUi", "") +BUILTIN(__nvvm_brev64, "ULLiULLi", "") + +// Sad + +BUILTIN(__nvvm_sad_i, "iiii", "") +BUILTIN(__nvvm_sad_ui, "UiUiUiUi", "") + +// Floor, Ceil + +BUILTIN(__nvvm_floor_ftz_f, "ff", "") +BUILTIN(__nvvm_floor_f, "ff", "") +BUILTIN(__nvvm_floor_d, "dd", "") + +BUILTIN(__nvvm_ceil_ftz_f, "ff", "") +BUILTIN(__nvvm_ceil_f, "ff", "") +BUILTIN(__nvvm_ceil_d, "dd", "") + +// Abs + +BUILTIN(__nvvm_abs_i, "ii", "") +BUILTIN(__nvvm_abs_ll, "LLiLLi", "") + +BUILTIN(__nvvm_fabs_ftz_f, "ff", "") +BUILTIN(__nvvm_fabs_f, "ff", "") +BUILTIN(__nvvm_fabs_d, "dd", "") + +// Round + +BUILTIN(__nvvm_round_ftz_f, "ff", "") +BUILTIN(__nvvm_round_f, "ff", "") +BUILTIN(__nvvm_round_d, "dd", "") + +// Trunc + +BUILTIN(__nvvm_trunc_ftz_f, "ff", "") +BUILTIN(__nvvm_trunc_f, "ff", "") +BUILTIN(__nvvm_trunc_d, "dd", "") + +// Saturate + +BUILTIN(__nvvm_saturate_ftz_f, "ff", "") +BUILTIN(__nvvm_saturate_f, "ff", "") +BUILTIN(__nvvm_saturate_d, "dd", "") + +// Exp2, Log2 + +BUILTIN(__nvvm_ex2_approx_ftz_f, "ff", "") +BUILTIN(__nvvm_ex2_approx_f, "ff", "") +BUILTIN(__nvvm_ex2_approx_d, "dd", "") + +BUILTIN(__nvvm_lg2_approx_ftz_f, "ff", "") +BUILTIN(__nvvm_lg2_approx_f, "ff", "") +BUILTIN(__nvvm_lg2_approx_d, "dd", "") + +// Sin, Cos + +BUILTIN(__nvvm_sin_approx_ftz_f, "ff", "") +BUILTIN(__nvvm_sin_approx_f, "ff", "") + +BUILTIN(__nvvm_cos_approx_ftz_f, "ff", "") +BUILTIN(__nvvm_cos_approx_f, "ff", "") + +// Fma + +BUILTIN(__nvvm_fma_rn_ftz_f, "ffff", "") +BUILTIN(__nvvm_fma_rn_f, "ffff", "") +BUILTIN(__nvvm_fma_rz_ftz_f, "ffff", "") +BUILTIN(__nvvm_fma_rz_f, "ffff", "") +BUILTIN(__nvvm_fma_rm_ftz_f, "ffff", "") +BUILTIN(__nvvm_fma_rm_f, "ffff", "") +BUILTIN(__nvvm_fma_rp_ftz_f, "ffff", "") +BUILTIN(__nvvm_fma_rp_f, "ffff", "") +BUILTIN(__nvvm_fma_rn_d, "dddd", "") +BUILTIN(__nvvm_fma_rz_d, "dddd", "") +BUILTIN(__nvvm_fma_rm_d, "dddd", "") +BUILTIN(__nvvm_fma_rp_d, "dddd", "") + +// Rcp + +BUILTIN(__nvvm_rcp_rn_ftz_f, "ff", "") +BUILTIN(__nvvm_rcp_rn_f, "ff", "") +BUILTIN(__nvvm_rcp_rz_ftz_f, "ff", "") +BUILTIN(__nvvm_rcp_rz_f, "ff", "") +BUILTIN(__nvvm_rcp_rm_ftz_f, "ff", "") +BUILTIN(__nvvm_rcp_rm_f, "ff", "") +BUILTIN(__nvvm_rcp_rp_ftz_f, "ff", "") +BUILTIN(__nvvm_rcp_rp_f, "ff", "") + +BUILTIN(__nvvm_rcp_rn_d, "dd", "") +BUILTIN(__nvvm_rcp_rz_d, "dd", "") +BUILTIN(__nvvm_rcp_rm_d, "dd", "") +BUILTIN(__nvvm_rcp_rp_d, "dd", "") +BUILTIN(__nvvm_rcp_approx_ftz_d, "dd", "") + +// Sqrt + +BUILTIN(__nvvm_sqrt_rn_ftz_f, "ff", "") +BUILTIN(__nvvm_sqrt_rn_f, "ff", "") +BUILTIN(__nvvm_sqrt_rz_ftz_f, "ff", "") +BUILTIN(__nvvm_sqrt_rz_f, "ff", "") +BUILTIN(__nvvm_sqrt_rm_ftz_f, "ff", "") +BUILTIN(__nvvm_sqrt_rm_f, "ff", "") +BUILTIN(__nvvm_sqrt_rp_ftz_f, "ff", "") +BUILTIN(__nvvm_sqrt_rp_f, "ff", "") +BUILTIN(__nvvm_sqrt_approx_ftz_f, "ff", "") +BUILTIN(__nvvm_sqrt_approx_f, "ff", "") + +BUILTIN(__nvvm_sqrt_rn_d, "dd", "") +BUILTIN(__nvvm_sqrt_rz_d, "dd", "") +BUILTIN(__nvvm_sqrt_rm_d, "dd", "") +BUILTIN(__nvvm_sqrt_rp_d, "dd", "") + +// Rsqrt + +BUILTIN(__nvvm_rsqrt_approx_ftz_f, "ff", "") +BUILTIN(__nvvm_rsqrt_approx_f, "ff", "") +BUILTIN(__nvvm_rsqrt_approx_d, "dd", "") + +// Add + +BUILTIN(__nvvm_add_rn_ftz_f, "fff", "") +BUILTIN(__nvvm_add_rn_f, "fff", "") +BUILTIN(__nvvm_add_rz_ftz_f, "fff", "") +BUILTIN(__nvvm_add_rz_f, "fff", "") +BUILTIN(__nvvm_add_rm_ftz_f, "fff", "") +BUILTIN(__nvvm_add_rm_f, "fff", "") +BUILTIN(__nvvm_add_rp_ftz_f, "fff", "") +BUILTIN(__nvvm_add_rp_f, "fff", "") + +BUILTIN(__nvvm_add_rn_d, "ddd", "") +BUILTIN(__nvvm_add_rz_d, "ddd", "") +BUILTIN(__nvvm_add_rm_d, "ddd", "") +BUILTIN(__nvvm_add_rp_d, "ddd", "") + +// Convert + +BUILTIN(__nvvm_d2f_rn_ftz, "fd", "") +BUILTIN(__nvvm_d2f_rn, "fd", "") +BUILTIN(__nvvm_d2f_rz_ftz, "fd", "") +BUILTIN(__nvvm_d2f_rz, "fd", "") +BUILTIN(__nvvm_d2f_rm_ftz, "fd", "") +BUILTIN(__nvvm_d2f_rm, "fd", "") +BUILTIN(__nvvm_d2f_rp_ftz, "fd", "") +BUILTIN(__nvvm_d2f_rp, "fd", "") + +BUILTIN(__nvvm_d2i_rn, "id", "") +BUILTIN(__nvvm_d2i_rz, "id", "") +BUILTIN(__nvvm_d2i_rm, "id", "") +BUILTIN(__nvvm_d2i_rp, "id", "") + +BUILTIN(__nvvm_d2ui_rn, "Uid", "") +BUILTIN(__nvvm_d2ui_rz, "Uid", "") +BUILTIN(__nvvm_d2ui_rm, "Uid", "") +BUILTIN(__nvvm_d2ui_rp, "Uid", "") + +BUILTIN(__nvvm_i2d_rn, "di", "") +BUILTIN(__nvvm_i2d_rz, "di", "") +BUILTIN(__nvvm_i2d_rm, "di", "") +BUILTIN(__nvvm_i2d_rp, "di", "") + +BUILTIN(__nvvm_ui2d_rn, "dUi", "") +BUILTIN(__nvvm_ui2d_rz, "dUi", "") +BUILTIN(__nvvm_ui2d_rm, "dUi", "") +BUILTIN(__nvvm_ui2d_rp, "dUi", "") + +BUILTIN(__nvvm_f2i_rn_ftz, "if", "") +BUILTIN(__nvvm_f2i_rn, "if", "") +BUILTIN(__nvvm_f2i_rz_ftz, "if", "") +BUILTIN(__nvvm_f2i_rz, "if", "") +BUILTIN(__nvvm_f2i_rm_ftz, "if", "") +BUILTIN(__nvvm_f2i_rm, "if", "") +BUILTIN(__nvvm_f2i_rp_ftz, "if", "") +BUILTIN(__nvvm_f2i_rp, "if", "") + +BUILTIN(__nvvm_f2ui_rn_ftz, "Uif", "") +BUILTIN(__nvvm_f2ui_rn, "Uif", "") +BUILTIN(__nvvm_f2ui_rz_ftz, "Uif", "") +BUILTIN(__nvvm_f2ui_rz, "Uif", "") +BUILTIN(__nvvm_f2ui_rm_ftz, "Uif", "") +BUILTIN(__nvvm_f2ui_rm, "Uif", "") +BUILTIN(__nvvm_f2ui_rp_ftz, "Uif", "") +BUILTIN(__nvvm_f2ui_rp, "Uif", "") + +BUILTIN(__nvvm_i2f_rn, "fi", "") +BUILTIN(__nvvm_i2f_rz, "fi", "") +BUILTIN(__nvvm_i2f_rm, "fi", "") +BUILTIN(__nvvm_i2f_rp, "fi", "") + +BUILTIN(__nvvm_ui2f_rn, "fUi", "") +BUILTIN(__nvvm_ui2f_rz, "fUi", "") +BUILTIN(__nvvm_ui2f_rm, "fUi", "") +BUILTIN(__nvvm_ui2f_rp, "fUi", "") + +BUILTIN(__nvvm_lohi_i2d, "dii", "") + +BUILTIN(__nvvm_d2i_lo, "id", "") +BUILTIN(__nvvm_d2i_hi, "id", "") + +BUILTIN(__nvvm_f2ll_rn_ftz, "LLif", "") +BUILTIN(__nvvm_f2ll_rn, "LLif", "") +BUILTIN(__nvvm_f2ll_rz_ftz, "LLif", "") +BUILTIN(__nvvm_f2ll_rz, "LLif", "") +BUILTIN(__nvvm_f2ll_rm_ftz, "LLif", "") +BUILTIN(__nvvm_f2ll_rm, "LLif", "") +BUILTIN(__nvvm_f2ll_rp_ftz, "LLif", "") +BUILTIN(__nvvm_f2ll_rp, "LLif", "") + +BUILTIN(__nvvm_f2ull_rn_ftz, "ULLif", "") +BUILTIN(__nvvm_f2ull_rn, "ULLif", "") +BUILTIN(__nvvm_f2ull_rz_ftz, "ULLif", "") +BUILTIN(__nvvm_f2ull_rz, "ULLif", "") +BUILTIN(__nvvm_f2ull_rm_ftz, "ULLif", "") +BUILTIN(__nvvm_f2ull_rm, "ULLif", "") +BUILTIN(__nvvm_f2ull_rp_ftz, "ULLif", "") +BUILTIN(__nvvm_f2ull_rp, "ULLif", "") + +BUILTIN(__nvvm_d2ll_rn, "LLid", "") +BUILTIN(__nvvm_d2ll_rz, "LLid", "") +BUILTIN(__nvvm_d2ll_rm, "LLid", "") +BUILTIN(__nvvm_d2ll_rp, "LLid", "") + +BUILTIN(__nvvm_d2ull_rn, "ULLid", "") +BUILTIN(__nvvm_d2ull_rz, "ULLid", "") +BUILTIN(__nvvm_d2ull_rm, "ULLid", "") +BUILTIN(__nvvm_d2ull_rp, "ULLid", "") + +BUILTIN(__nvvm_ll2f_rn, "fLLi", "") +BUILTIN(__nvvm_ll2f_rz, "fLLi", "") +BUILTIN(__nvvm_ll2f_rm, "fLLi", "") +BUILTIN(__nvvm_ll2f_rp, "fLLi", "") + +BUILTIN(__nvvm_ull2f_rn, "fULLi", "") +BUILTIN(__nvvm_ull2f_rz, "fULLi", "") +BUILTIN(__nvvm_ull2f_rm, "fULLi", "") +BUILTIN(__nvvm_ull2f_rp, "fULLi", "") + +BUILTIN(__nvvm_ll2d_rn, "dLLi", "") +BUILTIN(__nvvm_ll2d_rz, "dLLi", "") +BUILTIN(__nvvm_ll2d_rm, "dLLi", "") +BUILTIN(__nvvm_ll2d_rp, "dLLi", "") + +BUILTIN(__nvvm_ull2d_rn, "dULLi", "") +BUILTIN(__nvvm_ull2d_rz, "dULLi", "") +BUILTIN(__nvvm_ull2d_rm, "dULLi", "") +BUILTIN(__nvvm_ull2d_rp, "dULLi", "") + +BUILTIN(__nvvm_f2h_rn_ftz, "Usf", "") +BUILTIN(__nvvm_f2h_rn, "Usf", "") + +BUILTIN(__nvvm_h2f, "fUs", "") + +// Bitcast + +BUILTIN(__nvvm_bitcast_f2i, "if", "") +BUILTIN(__nvvm_bitcast_i2f, "fi", "") + +BUILTIN(__nvvm_bitcast_ll2d, "dLLi", "") +BUILTIN(__nvvm_bitcast_d2ll, "LLid", "") + +// Sync + +BUILTIN(__syncthreads, "v", "") +BUILTIN(__nvvm_bar0, "v", "") +BUILTIN(__nvvm_bar0_popc, "ii", "") +BUILTIN(__nvvm_bar0_and, "ii", "") +BUILTIN(__nvvm_bar0_or, "ii", "") + +// Membar + +BUILTIN(__nvvm_membar_cta, "v", "") +BUILTIN(__nvvm_membar_gl, "v", "") +BUILTIN(__nvvm_membar_sys, "v", "") + +// Memcpy, Memset + +BUILTIN(__nvvm_memcpy, "vUc*Uc*zi","") +BUILTIN(__nvvm_memset, "vUc*Uczi","") + +// Image + +BUILTIN(__builtin_ptx_read_image2Dfi_, "V4fiiii", "") +BUILTIN(__builtin_ptx_read_image2Dff_, "V4fiiff", "") +BUILTIN(__builtin_ptx_read_image2Dii_, "V4iiiii", "") +BUILTIN(__builtin_ptx_read_image2Dif_, "V4iiiff", "") + +BUILTIN(__builtin_ptx_read_image3Dfi_, "V4fiiiiii", "") +BUILTIN(__builtin_ptx_read_image3Dff_, "V4fiiffff", "") +BUILTIN(__builtin_ptx_read_image3Dii_, "V4iiiiiii", "") +BUILTIN(__builtin_ptx_read_image3Dif_, "V4iiiffff", "") + +BUILTIN(__builtin_ptx_write_image2Df_, "viiiffff", "") +BUILTIN(__builtin_ptx_write_image2Di_, "viiiiiii", "") +BUILTIN(__builtin_ptx_write_image2Dui_, "viiiUiUiUiUi", "") +BUILTIN(__builtin_ptx_get_image_depthi_, "ii", "") +BUILTIN(__builtin_ptx_get_image_heighti_, "ii", "") +BUILTIN(__builtin_ptx_get_image_widthi_, "ii", "") +BUILTIN(__builtin_ptx_get_image_channel_data_typei_, "ii", "") +BUILTIN(__builtin_ptx_get_image_channel_orderi_, "ii", "") + +// Atomic +// +// We need the atom intrinsics because +// - they are used in converging analysis +// - they are used in address space analysis and optimization +// So it does not hurt to expose them as builtins. +// +BUILTIN(__nvvm_atom_add_g_i, "iiD*1i", "n") +BUILTIN(__nvvm_atom_add_s_i, "iiD*3i", "n") +BUILTIN(__nvvm_atom_add_gen_i, "iiD*i", "n") +BUILTIN(__nvvm_atom_add_g_l, "LiLiD*1Li", "n") +BUILTIN(__nvvm_atom_add_s_l, "LiLiD*3Li", "n") +BUILTIN(__nvvm_atom_add_gen_l, "LiLiD*Li", "n") +BUILTIN(__nvvm_atom_add_g_ll, "LLiLLiD*1LLi", "n") +BUILTIN(__nvvm_atom_add_s_ll, "LLiLLiD*3LLi", "n") +BUILTIN(__nvvm_atom_add_gen_ll, "LLiLLiD*LLi", "n") +BUILTIN(__nvvm_atom_add_g_f, "ffD*1f", "n") +BUILTIN(__nvvm_atom_add_s_f, "ffD*3f", "n") +BUILTIN(__nvvm_atom_add_gen_f, "ffD*f", "n") +BUILTIN(__nvvm_atom_add_g_d, "ddD*1d", "n") +BUILTIN(__nvvm_atom_add_s_d, "ddD*3d", "n") +BUILTIN(__nvvm_atom_add_gen_d, "ddD*d", "n") + +BUILTIN(__nvvm_atom_sub_g_i, "iiD*1i", "n") +BUILTIN(__nvvm_atom_sub_s_i, "iiD*3i", "n") +BUILTIN(__nvvm_atom_sub_gen_i, "iiD*i", "n") +BUILTIN(__nvvm_atom_sub_g_l, "LiLiD*1Li", "n") +BUILTIN(__nvvm_atom_sub_s_l, "LiLiD*3Li", "n") +BUILTIN(__nvvm_atom_sub_gen_l, "LiLiD*Li", "n") +BUILTIN(__nvvm_atom_sub_g_ll, "LLiLLiD*1LLi", "n") +BUILTIN(__nvvm_atom_sub_s_ll, "LLiLLiD*3LLi", "n") +BUILTIN(__nvvm_atom_sub_gen_ll, "LLiLLiD*LLi", "n") + +BUILTIN(__nvvm_atom_xchg_g_i, "iiD*1i", "n") +BUILTIN(__nvvm_atom_xchg_s_i, "iiD*3i", "n") +BUILTIN(__nvvm_atom_xchg_gen_i, "iiD*i", "n") +BUILTIN(__nvvm_atom_xchg_g_l, "LiLiD*1Li", "n") +BUILTIN(__nvvm_atom_xchg_s_l, "LiLiD*3Li", "n") +BUILTIN(__nvvm_atom_xchg_gen_l, "LiLiD*Li", "n") +BUILTIN(__nvvm_atom_xchg_g_ll, "LLiLLiD*1LLi", "n") +BUILTIN(__nvvm_atom_xchg_s_ll, "LLiLLiD*3LLi", "n") +BUILTIN(__nvvm_atom_xchg_gen_ll, "LLiLLiD*LLi", "n") + +BUILTIN(__nvvm_atom_max_g_i, "iiD*1i", "n") +BUILTIN(__nvvm_atom_max_s_i, "iiD*3i", "n") +BUILTIN(__nvvm_atom_max_gen_i, "iiD*i", "n") +BUILTIN(__nvvm_atom_max_g_ui, "UiUiD*1Ui", "n") +BUILTIN(__nvvm_atom_max_s_ui, "UiUiD*3Ui", "n") +BUILTIN(__nvvm_atom_max_gen_ui, "UiUiD*Ui", "n") +BUILTIN(__nvvm_atom_max_g_l, "LiLiD*1Li", "n") +BUILTIN(__nvvm_atom_max_s_l, "LiLiD*3Li", "n") +BUILTIN(__nvvm_atom_max_gen_l, "LiLiD*Li", "n") +BUILTIN(__nvvm_atom_max_g_ul, "ULiULiD*1ULi", "n") +BUILTIN(__nvvm_atom_max_s_ul, "ULiULiD*3ULi", "n") +BUILTIN(__nvvm_atom_max_gen_ul, "ULiULiD*ULi", "n") +BUILTIN(__nvvm_atom_max_g_ll, "LLiLLiD*1LLi", "n") +BUILTIN(__nvvm_atom_max_s_ll, "LLiLLiD*3LLi", "n") +BUILTIN(__nvvm_atom_max_gen_ll, "LLiLLiD*LLi", "n") +BUILTIN(__nvvm_atom_max_g_ull, "ULLiULLiD*1ULLi", "n") +BUILTIN(__nvvm_atom_max_s_ull, "ULLiULLiD*3ULLi", "n") +BUILTIN(__nvvm_atom_max_gen_ull, "ULLiULLiD*ULLi", "n") + +BUILTIN(__nvvm_atom_min_g_i, "iiD*1i", "n") +BUILTIN(__nvvm_atom_min_s_i, "iiD*3i", "n") +BUILTIN(__nvvm_atom_min_gen_i, "iiD*i", "n") +BUILTIN(__nvvm_atom_min_g_ui, "UiUiD*1Ui", "n") +BUILTIN(__nvvm_atom_min_s_ui, "UiUiD*3Ui", "n") +BUILTIN(__nvvm_atom_min_gen_ui, "UiUiD*Ui", "n") +BUILTIN(__nvvm_atom_min_g_l, "LiLiD*1Li", "n") +BUILTIN(__nvvm_atom_min_s_l, "LiLiD*3Li", "n") +BUILTIN(__nvvm_atom_min_gen_l, "LiLiD*Li", "n") +BUILTIN(__nvvm_atom_min_g_ul, "ULiULiD*1ULi", "n") +BUILTIN(__nvvm_atom_min_s_ul, "ULiULiD*3ULi", "n") +BUILTIN(__nvvm_atom_min_gen_ul, "ULiULiD*ULi", "n") +BUILTIN(__nvvm_atom_min_g_ll, "LLiLLiD*1LLi", "n") +BUILTIN(__nvvm_atom_min_s_ll, "LLiLLiD*3LLi", "n") +BUILTIN(__nvvm_atom_min_gen_ll, "LLiLLiD*LLi", "n") +BUILTIN(__nvvm_atom_min_g_ull, "ULLiULLiD*1ULLi", "n") +BUILTIN(__nvvm_atom_min_s_ull, "ULLiULLiD*3ULLi", "n") +BUILTIN(__nvvm_atom_min_gen_ull, "ULLiULLiD*ULLi", "n") + +BUILTIN(__nvvm_atom_inc_g_ui, "UiUiD*1Ui", "n") +BUILTIN(__nvvm_atom_inc_s_ui, "UiUiD*3Ui", "n") +BUILTIN(__nvvm_atom_inc_gen_ui, "UiUiD*Ui", "n") +BUILTIN(__nvvm_atom_dec_g_ui, "UiUiD*1Ui", "n") +BUILTIN(__nvvm_atom_dec_s_ui, "UiUiD*3Ui", "n") +BUILTIN(__nvvm_atom_dec_gen_ui, "UiUiD*Ui", "n") + +BUILTIN(__nvvm_atom_and_g_i, "iiD*1i", "n") +BUILTIN(__nvvm_atom_and_s_i, "iiD*3i", "n") +BUILTIN(__nvvm_atom_and_gen_i, "iiD*i", "n") +BUILTIN(__nvvm_atom_and_g_l, "LiLiD*1Li", "n") +BUILTIN(__nvvm_atom_and_s_l, "LiLiD*3Li", "n") +BUILTIN(__nvvm_atom_and_gen_l, "LiLiD*Li", "n") +BUILTIN(__nvvm_atom_and_g_ll, "LLiLLiD*1LLi", "n") +BUILTIN(__nvvm_atom_and_s_ll, "LLiLLiD*3LLi", "n") +BUILTIN(__nvvm_atom_and_gen_ll, "LLiLLiD*LLi", "n") + +BUILTIN(__nvvm_atom_or_g_i, "iiD*1i", "n") +BUILTIN(__nvvm_atom_or_s_i, "iiD*3i", "n") +BUILTIN(__nvvm_atom_or_gen_i, "iiD*i", "n") +BUILTIN(__nvvm_atom_or_g_l, "LiLiD*1Li", "n") +BUILTIN(__nvvm_atom_or_s_l, "LiLiD*3Li", "n") +BUILTIN(__nvvm_atom_or_gen_l, "LiLiD*Li", "n") +BUILTIN(__nvvm_atom_or_g_ll, "LLiLLiD*1LLi", "n") +BUILTIN(__nvvm_atom_or_s_ll, "LLiLLiD*3LLi", "n") +BUILTIN(__nvvm_atom_or_gen_ll, "LLiLLiD*LLi", "n") + +BUILTIN(__nvvm_atom_xor_g_i, "iiD*1i", "n") +BUILTIN(__nvvm_atom_xor_s_i, "iiD*3i", "n") +BUILTIN(__nvvm_atom_xor_gen_i, "iiD*i", "n") +BUILTIN(__nvvm_atom_xor_g_l, "LiLiD*1Li", "n") +BUILTIN(__nvvm_atom_xor_s_l, "LiLiD*3Li", "n") +BUILTIN(__nvvm_atom_xor_gen_l, "LiLiD*Li", "n") +BUILTIN(__nvvm_atom_xor_g_ll, "LLiLLiD*1LLi", "n") +BUILTIN(__nvvm_atom_xor_s_ll, "LLiLLiD*3LLi", "n") +BUILTIN(__nvvm_atom_xor_gen_ll, "LLiLLiD*LLi", "n") + +BUILTIN(__nvvm_atom_cas_g_i, "iiD*1ii", "n") +BUILTIN(__nvvm_atom_cas_s_i, "iiD*3ii", "n") +BUILTIN(__nvvm_atom_cas_gen_i, "iiD*ii", "n") +BUILTIN(__nvvm_atom_cas_g_l, "LiLiD*1LiLi", "n") +BUILTIN(__nvvm_atom_cas_s_l, "LiLiD*3LiLi", "n") +BUILTIN(__nvvm_atom_cas_gen_l, "LiLiD*LiLi", "n") +BUILTIN(__nvvm_atom_cas_g_ll, "LLiLLiD*1LLiLLi", "n") +BUILTIN(__nvvm_atom_cas_s_ll, "LLiLLiD*3LLiLLi", "n") +BUILTIN(__nvvm_atom_cas_gen_ll, "LLiLLiD*LLiLLi", "n") + +// Compiler Error Warn +BUILTIN(__nvvm_compiler_error, "vcC*4", "n") +BUILTIN(__nvvm_compiler_warn, "vcC*4", "n") + +#undef BUILTIN diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsPPC.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsPPC.def new file mode 100644 index 0000000..5681c1f2 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsPPC.def @@ -0,0 +1,379 @@ +//===--- BuiltinsPPC.def - PowerPC Builtin function database ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the PowerPC-specific builtin function database. Users of +// this file must define the BUILTIN macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +// FIXME: this needs to be the full list supported by GCC. Right now, I'm just +// adding stuff on demand. + +// The format of this database matches clang/Basic/Builtins.def. + +BUILTIN(__builtin_ppc_get_timebase, "ULLi", "n") + +// This is just a placeholder, the types and attributes are wrong. +BUILTIN(__builtin_altivec_vaddcuw, "V4UiV4UiV4Ui", "") + +BUILTIN(__builtin_altivec_vaddsbs, "V16ScV16ScV16Sc", "") +BUILTIN(__builtin_altivec_vaddubs, "V16UcV16UcV16Uc", "") +BUILTIN(__builtin_altivec_vaddshs, "V8SsV8SsV8Ss", "") +BUILTIN(__builtin_altivec_vadduhs, "V8UsV8UsV8Us", "") +BUILTIN(__builtin_altivec_vaddsws, "V4SiV4SiV4Si", "") +BUILTIN(__builtin_altivec_vadduws, "V4UiV4UiV4Ui", "") +BUILTIN(__builtin_altivec_vaddeuqm, "V1ULLLiV1ULLLiV1ULLLiV1ULLLi","") +BUILTIN(__builtin_altivec_vaddcuq, "V1ULLLiV1ULLLiV1ULLLi","") +BUILTIN(__builtin_altivec_vaddecuq, "V1ULLLiV1ULLLiV1ULLLiV1ULLLi","") + +BUILTIN(__builtin_altivec_vsubsbs, "V16ScV16ScV16Sc", "") +BUILTIN(__builtin_altivec_vsububs, "V16UcV16UcV16Uc", "") +BUILTIN(__builtin_altivec_vsubshs, "V8SsV8SsV8Ss", "") +BUILTIN(__builtin_altivec_vsubuhs, "V8UsV8UsV8Us", "") +BUILTIN(__builtin_altivec_vsubsws, "V4SiV4SiV4Si", "") +BUILTIN(__builtin_altivec_vsubuws, "V4UiV4UiV4Ui", "") +BUILTIN(__builtin_altivec_vsubeuqm, "V1ULLLiV1ULLLiV1ULLLiV1ULLLi","") +BUILTIN(__builtin_altivec_vsubcuq, "V1ULLLiV1ULLLiV1ULLLi","") +BUILTIN(__builtin_altivec_vsubecuq, "V1ULLLiV1ULLLiV1ULLLiV1ULLLi","") + +BUILTIN(__builtin_altivec_vavgsb, "V16ScV16ScV16Sc", "") +BUILTIN(__builtin_altivec_vavgub, "V16UcV16UcV16Uc", "") +BUILTIN(__builtin_altivec_vavgsh, "V8SsV8SsV8Ss", "") +BUILTIN(__builtin_altivec_vavguh, "V8UsV8UsV8Us", "") +BUILTIN(__builtin_altivec_vavgsw, "V4SiV4SiV4Si", "") +BUILTIN(__builtin_altivec_vavguw, "V4UiV4UiV4Ui", "") + +BUILTIN(__builtin_altivec_vrfip, "V4fV4f", "") + +BUILTIN(__builtin_altivec_vcfsx, "V4fV4ii", "") +BUILTIN(__builtin_altivec_vcfux, "V4fV4ii", "") +BUILTIN(__builtin_altivec_vctsxs, "V4SiV4fi", "") +BUILTIN(__builtin_altivec_vctuxs, "V4UiV4fi", "") + +BUILTIN(__builtin_altivec_dss, "vUi", "") +BUILTIN(__builtin_altivec_dssall, "v", "") +BUILTIN(__builtin_altivec_dst, "vvC*iUi", "") +BUILTIN(__builtin_altivec_dstt, "vvC*iUi", "") +BUILTIN(__builtin_altivec_dstst, "vvC*iUi", "") +BUILTIN(__builtin_altivec_dststt, "vvC*iUi", "") + +BUILTIN(__builtin_altivec_vexptefp, "V4fV4f", "") + +BUILTIN(__builtin_altivec_vrfim, "V4fV4f", "") + +BUILTIN(__builtin_altivec_lvx, "V4iivC*", "") +BUILTIN(__builtin_altivec_lvxl, "V4iivC*", "") +BUILTIN(__builtin_altivec_lvebx, "V16civC*", "") +BUILTIN(__builtin_altivec_lvehx, "V8sivC*", "") +BUILTIN(__builtin_altivec_lvewx, "V4iivC*", "") + +BUILTIN(__builtin_altivec_vlogefp, "V4fV4f", "") + +BUILTIN(__builtin_altivec_lvsl, "V16cUcvC*", "") +BUILTIN(__builtin_altivec_lvsr, "V16cUcvC*", "") + +BUILTIN(__builtin_altivec_vmaddfp, "V4fV4fV4fV4f", "") +BUILTIN(__builtin_altivec_vmhaddshs, "V8sV8sV8sV8s", "") +BUILTIN(__builtin_altivec_vmhraddshs, "V8sV8sV8sV8s", "") + +BUILTIN(__builtin_altivec_vmsumubm, "V4UiV16UcV16UcV4Ui", "") +BUILTIN(__builtin_altivec_vmsummbm, "V4SiV16ScV16UcV4Si", "") +BUILTIN(__builtin_altivec_vmsumuhm, "V4UiV8UsV8UsV4Ui", "") +BUILTIN(__builtin_altivec_vmsumshm, "V4SiV8SsV8SsV4Si", "") +BUILTIN(__builtin_altivec_vmsumuhs, "V4UiV8UsV8UsV4Ui", "") +BUILTIN(__builtin_altivec_vmsumshs, "V4SiV8SsV8SsV4Si", "") + +BUILTIN(__builtin_altivec_vmuleub, "V8UsV16UcV16Uc", "") +BUILTIN(__builtin_altivec_vmulesb, "V8SsV16ScV16Sc", "") +BUILTIN(__builtin_altivec_vmuleuh, "V4UiV8UsV8Us", "") +BUILTIN(__builtin_altivec_vmulesh, "V4SiV8SsV8Ss", "") +BUILTIN(__builtin_altivec_vmuleuw, "V2ULLiV4UiV4Ui", "") +BUILTIN(__builtin_altivec_vmulesw, "V2SLLiV4SiV4Si", "") +BUILTIN(__builtin_altivec_vmuloub, "V8UsV16UcV16Uc", "") +BUILTIN(__builtin_altivec_vmulosb, "V8SsV16ScV16Sc", "") +BUILTIN(__builtin_altivec_vmulouh, "V4UiV8UsV8Us", "") +BUILTIN(__builtin_altivec_vmulosh, "V4SiV8SsV8Ss", "") +BUILTIN(__builtin_altivec_vmulouw, "V2ULLiV4UiV4Ui", "") +BUILTIN(__builtin_altivec_vmulosw, "V2SLLiV4SiV4Si", "") + +BUILTIN(__builtin_altivec_vnmsubfp, "V4fV4fV4fV4f", "") + +BUILTIN(__builtin_altivec_vpkpx, "V8sV4UiV4Ui", "") +BUILTIN(__builtin_altivec_vpkuhus, "V16UcV8UsV8Us", "") +BUILTIN(__builtin_altivec_vpkshss, "V16ScV8SsV8Ss", "") +BUILTIN(__builtin_altivec_vpkuwus, "V8UsV4UiV4Ui", "") +BUILTIN(__builtin_altivec_vpkswss, "V8SsV4SiV4Si", "") +BUILTIN(__builtin_altivec_vpkshus, "V16UcV8SsV8Ss", "") +BUILTIN(__builtin_altivec_vpkswus, "V8UsV4SiV4Si", "") +BUILTIN(__builtin_altivec_vpksdss, "V4SiV2SLLiV2SLLi", "") +BUILTIN(__builtin_altivec_vpksdus, "V4UiV2SLLiV2SLLi", "") +BUILTIN(__builtin_altivec_vpkudus, "V4UiV2ULLiV2ULLi", "") +BUILTIN(__builtin_altivec_vpkudum, "V4UiV2ULLiV2ULLi", "") + +BUILTIN(__builtin_altivec_vperm_4si, "V4iV4iV4iV16Uc", "") + +BUILTIN(__builtin_altivec_stvx, "vV4iiv*", "") +BUILTIN(__builtin_altivec_stvxl, "vV4iiv*", "") +BUILTIN(__builtin_altivec_stvebx, "vV16civ*", "") +BUILTIN(__builtin_altivec_stvehx, "vV8siv*", "") +BUILTIN(__builtin_altivec_stvewx, "vV4iiv*", "") + +BUILTIN(__builtin_altivec_vcmpbfp, "V4iV4fV4f", "") + +BUILTIN(__builtin_altivec_vcmpgefp, "V4iV4fV4f", "") + +BUILTIN(__builtin_altivec_vcmpequb, "V16cV16cV16c", "") +BUILTIN(__builtin_altivec_vcmpequh, "V8sV8sV8s", "") +BUILTIN(__builtin_altivec_vcmpequw, "V4iV4iV4i", "") +BUILTIN(__builtin_altivec_vcmpequd, "V2LLiV2LLiV2LLi", "") +BUILTIN(__builtin_altivec_vcmpeqfp, "V4iV4fV4f", "") + +BUILTIN(__builtin_altivec_vcmpgtsb, "V16cV16ScV16Sc", "") +BUILTIN(__builtin_altivec_vcmpgtub, "V16cV16UcV16Uc", "") +BUILTIN(__builtin_altivec_vcmpgtsh, "V8sV8SsV8Ss", "") +BUILTIN(__builtin_altivec_vcmpgtuh, "V8sV8UsV8Us", "") +BUILTIN(__builtin_altivec_vcmpgtsw, "V4iV4SiV4Si", "") +BUILTIN(__builtin_altivec_vcmpgtuw, "V4iV4UiV4Ui", "") +BUILTIN(__builtin_altivec_vcmpgtsd, "V2LLiV2LLiV2LLi", "") +BUILTIN(__builtin_altivec_vcmpgtud, "V2LLiV2ULLiV2ULLi", "") +BUILTIN(__builtin_altivec_vcmpgtfp, "V4iV4fV4f", "") + +BUILTIN(__builtin_altivec_vmaxsb, "V16ScV16ScV16Sc", "") +BUILTIN(__builtin_altivec_vmaxub, "V16UcV16UcV16Uc", "") +BUILTIN(__builtin_altivec_vmaxsh, "V8SsV8SsV8Ss", "") +BUILTIN(__builtin_altivec_vmaxuh, "V8UsV8UsV8Us", "") +BUILTIN(__builtin_altivec_vmaxsw, "V4SiV4SiV4Si", "") +BUILTIN(__builtin_altivec_vmaxuw, "V4UiV4UiV4Ui", "") +BUILTIN(__builtin_altivec_vmaxsd, "V2LLiV2LLiV2LLi", "") +BUILTIN(__builtin_altivec_vmaxud, "V2ULLiV2ULLiV2ULLi", "") +BUILTIN(__builtin_altivec_vmaxfp, "V4fV4fV4f", "") + +BUILTIN(__builtin_altivec_mfvscr, "V8Us", "") + +BUILTIN(__builtin_altivec_vminsb, "V16ScV16ScV16Sc", "") +BUILTIN(__builtin_altivec_vminub, "V16UcV16UcV16Uc", "") +BUILTIN(__builtin_altivec_vminsh, "V8SsV8SsV8Ss", "") +BUILTIN(__builtin_altivec_vminuh, "V8UsV8UsV8Us", "") +BUILTIN(__builtin_altivec_vminsw, "V4SiV4SiV4Si", "") +BUILTIN(__builtin_altivec_vminuw, "V4UiV4UiV4Ui", "") +BUILTIN(__builtin_altivec_vminsd, "V2LLiV2LLiV2LLi", "") +BUILTIN(__builtin_altivec_vminud, "V2ULLiV2ULLiV2ULLi", "") +BUILTIN(__builtin_altivec_vminfp, "V4fV4fV4f", "") + +BUILTIN(__builtin_altivec_mtvscr, "vV4i", "") + +BUILTIN(__builtin_altivec_vrefp, "V4fV4f", "") + +BUILTIN(__builtin_altivec_vrlb, "V16cV16cV16Uc", "") +BUILTIN(__builtin_altivec_vrlh, "V8sV8sV8Us", "") +BUILTIN(__builtin_altivec_vrlw, "V4iV4iV4Ui", "") +BUILTIN(__builtin_altivec_vrld, "V2LLiV2LLiV2ULLi", "") + +BUILTIN(__builtin_altivec_vsel_4si, "V4iV4iV4iV4Ui", "") + +BUILTIN(__builtin_altivec_vsl, "V4iV4iV4i", "") +BUILTIN(__builtin_altivec_vslo, "V4iV4iV4i", "") + +BUILTIN(__builtin_altivec_vsrab, "V16cV16cV16Uc", "") +BUILTIN(__builtin_altivec_vsrah, "V8sV8sV8Us", "") +BUILTIN(__builtin_altivec_vsraw, "V4iV4iV4Ui", "") + +BUILTIN(__builtin_altivec_vsr, "V4iV4iV4i", "") +BUILTIN(__builtin_altivec_vsro, "V4iV4iV4i", "") + +BUILTIN(__builtin_altivec_vrfin, "V4fV4f", "") + +BUILTIN(__builtin_altivec_vrsqrtefp, "V4fV4f", "") + +BUILTIN(__builtin_altivec_vsubcuw, "V4UiV4UiV4Ui", "") + +BUILTIN(__builtin_altivec_vsum4sbs, "V4SiV16ScV4Si", "") +BUILTIN(__builtin_altivec_vsum4ubs, "V4UiV16UcV4Ui", "") +BUILTIN(__builtin_altivec_vsum4shs, "V4SiV8SsV4Si", "") + +BUILTIN(__builtin_altivec_vsum2sws, "V4SiV4SiV4Si", "") + +BUILTIN(__builtin_altivec_vsumsws, "V4SiV4SiV4Si", "") + +BUILTIN(__builtin_altivec_vrfiz, "V4fV4f", "") + +BUILTIN(__builtin_altivec_vupkhsb, "V8sV16c", "") +BUILTIN(__builtin_altivec_vupkhpx, "V4UiV8s", "") +BUILTIN(__builtin_altivec_vupkhsh, "V4iV8s", "") +BUILTIN(__builtin_altivec_vupkhsw, "V2LLiV4i", "") + +BUILTIN(__builtin_altivec_vupklsb, "V8sV16c", "") +BUILTIN(__builtin_altivec_vupklpx, "V4UiV8s", "") +BUILTIN(__builtin_altivec_vupklsh, "V4iV8s", "") +BUILTIN(__builtin_altivec_vupklsw, "V2LLiV4i", "") + +BUILTIN(__builtin_altivec_vcmpbfp_p, "iiV4fV4f", "") + +BUILTIN(__builtin_altivec_vcmpgefp_p, "iiV4fV4f", "") + +BUILTIN(__builtin_altivec_vcmpequb_p, "iiV16cV16c", "") +BUILTIN(__builtin_altivec_vcmpequh_p, "iiV8sV8s", "") +BUILTIN(__builtin_altivec_vcmpequw_p, "iiV4iV4i", "") +BUILTIN(__builtin_altivec_vcmpequd_p, "iiV2LLiV2LLi", "") +BUILTIN(__builtin_altivec_vcmpeqfp_p, "iiV4fV4f", "") + +BUILTIN(__builtin_altivec_vcmpgtsb_p, "iiV16ScV16Sc", "") +BUILTIN(__builtin_altivec_vcmpgtub_p, "iiV16UcV16Uc", "") +BUILTIN(__builtin_altivec_vcmpgtsh_p, "iiV8SsV8Ss", "") +BUILTIN(__builtin_altivec_vcmpgtuh_p, "iiV8UsV8Us", "") +BUILTIN(__builtin_altivec_vcmpgtsw_p, "iiV4SiV4Si", "") +BUILTIN(__builtin_altivec_vcmpgtuw_p, "iiV4UiV4Ui", "") +BUILTIN(__builtin_altivec_vcmpgtsd_p, "iiV2LLiV2LLi", "") +BUILTIN(__builtin_altivec_vcmpgtud_p, "iiV2ULLiV2ULLi", "") +BUILTIN(__builtin_altivec_vcmpgtfp_p, "iiV4fV4f", "") + +BUILTIN(__builtin_altivec_vgbbd, "V16UcV16Uc", "") +BUILTIN(__builtin_altivec_vbpermq, "V2ULLiV16UcV16Uc", "") + +// P8 Crypto built-ins. +BUILTIN(__builtin_altivec_crypto_vsbox, "V2ULLiV2ULLi", "") +BUILTIN(__builtin_altivec_crypto_vpermxor, "V16UcV16UcV16UcV16Uc", "") +BUILTIN(__builtin_altivec_crypto_vshasigmaw, "V4UiV4UiIiIi", "") +BUILTIN(__builtin_altivec_crypto_vshasigmad, "V2ULLiV2ULLiIiIi", "") +BUILTIN(__builtin_altivec_crypto_vcipher, "V2ULLiV2ULLiV2ULLi", "") +BUILTIN(__builtin_altivec_crypto_vcipherlast, "V2ULLiV2ULLiV2ULLi", "") +BUILTIN(__builtin_altivec_crypto_vncipher, "V2ULLiV2ULLiV2ULLi", "") +BUILTIN(__builtin_altivec_crypto_vncipherlast, "V2ULLiV2ULLiV2ULLi", "") +BUILTIN(__builtin_altivec_crypto_vpmsumb, "V16UcV16UcV16Uc", "") +BUILTIN(__builtin_altivec_crypto_vpmsumh, "V8UsV8UsV8Us", "") +BUILTIN(__builtin_altivec_crypto_vpmsumw, "V4UiV4UiV4Ui", "") +BUILTIN(__builtin_altivec_crypto_vpmsumd, "V2ULLiV2ULLiV2ULLi", "") + +BUILTIN(__builtin_altivec_vclzb, "V16UcV16Uc", "") +BUILTIN(__builtin_altivec_vclzh, "V8UsV8Us", "") +BUILTIN(__builtin_altivec_vclzw, "V4UiV4Ui", "") +BUILTIN(__builtin_altivec_vclzd, "V2ULLiV2ULLi", "") + +// VSX built-ins. + +BUILTIN(__builtin_vsx_lxvd2x, "V2divC*", "") +BUILTIN(__builtin_vsx_lxvw4x, "V4iivC*", "") + +BUILTIN(__builtin_vsx_stxvd2x, "vV2div*", "") +BUILTIN(__builtin_vsx_stxvw4x, "vV4iiv*", "") + +BUILTIN(__builtin_vsx_xvmaxdp, "V2dV2dV2d", "") +BUILTIN(__builtin_vsx_xvmaxsp, "V4fV4fV4f", "") +BUILTIN(__builtin_vsx_xsmaxdp, "ddd", "") + +BUILTIN(__builtin_vsx_xvmindp, "V2dV2dV2d", "") +BUILTIN(__builtin_vsx_xvminsp, "V4fV4fV4f", "") +BUILTIN(__builtin_vsx_xsmindp, "ddd", "") + +BUILTIN(__builtin_vsx_xvdivdp, "V2dV2dV2d", "") +BUILTIN(__builtin_vsx_xvdivsp, "V4fV4fV4f", "") + +BUILTIN(__builtin_vsx_xvrdpip, "V2dV2d", "") +BUILTIN(__builtin_vsx_xvrspip, "V4fV4f", "") + +BUILTIN(__builtin_vsx_xvcmpeqdp, "V2ULLiV2dV2d", "") +BUILTIN(__builtin_vsx_xvcmpeqsp, "V4UiV4fV4f", "") + +BUILTIN(__builtin_vsx_xvcmpeqdp_p, "iiV2dV2d", "") +BUILTIN(__builtin_vsx_xvcmpeqsp_p, "iiV4fV4f", "") + +BUILTIN(__builtin_vsx_xvcmpgedp, "V2ULLiV2dV2d", "") +BUILTIN(__builtin_vsx_xvcmpgesp, "V4UiV4fV4f", "") + +BUILTIN(__builtin_vsx_xvcmpgedp_p, "iiV2dV2d", "") +BUILTIN(__builtin_vsx_xvcmpgesp_p, "iiV4fV4f", "") + +BUILTIN(__builtin_vsx_xvcmpgtdp, "V2ULLiV2dV2d", "") +BUILTIN(__builtin_vsx_xvcmpgtsp, "V4UiV4fV4f", "") + +BUILTIN(__builtin_vsx_xvcmpgtdp_p, "iiV2dV2d", "") +BUILTIN(__builtin_vsx_xvcmpgtsp_p, "iiV4fV4f", "") + +BUILTIN(__builtin_vsx_xvrdpim, "V2dV2d", "") +BUILTIN(__builtin_vsx_xvrspim, "V4fV4f", "") + +BUILTIN(__builtin_vsx_xvrdpi, "V2dV2d", "") +BUILTIN(__builtin_vsx_xvrspi, "V4fV4f", "") + +BUILTIN(__builtin_vsx_xvrdpic, "V2dV2d", "") +BUILTIN(__builtin_vsx_xvrspic, "V4fV4f", "") + +BUILTIN(__builtin_vsx_xvrdpiz, "V2dV2d", "") +BUILTIN(__builtin_vsx_xvrspiz, "V4fV4f", "") + +BUILTIN(__builtin_vsx_xvmaddadp, "V2dV2dV2dV2d", "") +BUILTIN(__builtin_vsx_xvmaddasp, "V4fV4fV4fV4f", "") + +BUILTIN(__builtin_vsx_xvmsubadp, "V2dV2dV2dV2d", "") +BUILTIN(__builtin_vsx_xvmsubasp, "V4fV4fV4fV4f", "") + +BUILTIN(__builtin_vsx_xvmuldp, "V2dV2dV2d", "") +BUILTIN(__builtin_vsx_xvmulsp, "V4fV4fV4f", "") + +BUILTIN(__builtin_vsx_xvnmaddadp, "V2dV2dV2dV2d", "") +BUILTIN(__builtin_vsx_xvnmaddasp, "V4fV4fV4fV4f", "") + +BUILTIN(__builtin_vsx_xvnmsubadp, "V2dV2dV2dV2d", "") +BUILTIN(__builtin_vsx_xvnmsubasp, "V4fV4fV4fV4f", "") + +BUILTIN(__builtin_vsx_xvredp, "V2dV2d", "") +BUILTIN(__builtin_vsx_xvresp, "V4fV4f", "") + +BUILTIN(__builtin_vsx_xvrsqrtedp, "V2dV2d", "") +BUILTIN(__builtin_vsx_xvrsqrtesp, "V4fV4f", "") + +BUILTIN(__builtin_vsx_xvsqrtdp, "V2dV2d", "") +BUILTIN(__builtin_vsx_xvsqrtsp, "V4fV4f", "") + +BUILTIN(__builtin_vsx_xxleqv, "V4UiV4UiV4Ui", "") + +BUILTIN(__builtin_vsx_xvcpsgndp, "V2dV2dV2d", "") +BUILTIN(__builtin_vsx_xvcpsgnsp, "V4fV4fV4f", "") + +// HTM builtins +BUILTIN(__builtin_tbegin, "UiUIi", "") +BUILTIN(__builtin_tend, "UiUIi", "") + +BUILTIN(__builtin_tabort, "UiUi", "") +BUILTIN(__builtin_tabortdc, "UiUiUiUi", "") +BUILTIN(__builtin_tabortdci, "UiUiUii", "") +BUILTIN(__builtin_tabortwc, "UiUiUiUi", "") +BUILTIN(__builtin_tabortwci, "UiUiUii", "") + +BUILTIN(__builtin_tcheck, "Ui", "") +BUILTIN(__builtin_treclaim, "UiUi", "") +BUILTIN(__builtin_trechkpt, "Ui", "") +BUILTIN(__builtin_tsr, "UiUi", "") + +BUILTIN(__builtin_tendall, "Ui", "") +BUILTIN(__builtin_tresume, "Ui", "") +BUILTIN(__builtin_tsuspend, "Ui", "") + +BUILTIN(__builtin_get_texasr, "LUi", "c") +BUILTIN(__builtin_get_texasru, "LUi", "c") +BUILTIN(__builtin_get_tfhar, "LUi", "c") +BUILTIN(__builtin_get_tfiar, "LUi", "c") + +BUILTIN(__builtin_set_texasr, "vLUi", "c") +BUILTIN(__builtin_set_texasru, "vLUi", "c") +BUILTIN(__builtin_set_tfhar, "vLUi", "c") +BUILTIN(__builtin_set_tfiar, "vLUi", "c") + +BUILTIN(__builtin_ttest, "LUi", "") + +// Scalar built-ins +BUILTIN(__builtin_divwe, "SiSiSi", "") +BUILTIN(__builtin_divweu, "UiUiUi", "") +BUILTIN(__builtin_divde, "SLLiSLLiSLLi", "") +BUILTIN(__builtin_divdeu, "ULLiULLiULLi", "") +BUILTIN(__builtin_bpermd, "SLLiSLLiSLLi", "") + +// FIXME: Obviously incomplete. + +#undef BUILTIN diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsSystemZ.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsSystemZ.def new file mode 100644 index 0000000..68d5a1c --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsSystemZ.def @@ -0,0 +1,252 @@ +//===-- BuiltinsSystemZ.def - SystemZ Builtin function database -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the SystemZ-specific builtin function database. Users of +// this file must define the BUILTIN macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +// The format of this database matches clang/Basic/Builtins.def. + +// Transactional-memory intrinsics +BUILTIN(__builtin_tbegin, "iv*", "j") +BUILTIN(__builtin_tbegin_nofloat, "iv*", "j") +BUILTIN(__builtin_tbeginc, "v", "nj") +BUILTIN(__builtin_tabort, "vi", "r") +BUILTIN(__builtin_tend, "i", "n") +BUILTIN(__builtin_tx_nesting_depth, "i", "nc") +BUILTIN(__builtin_tx_assist, "vi", "n") +BUILTIN(__builtin_non_tx_store, "vULi*ULi", "") + +// Vector intrinsics. +// These all map directly to z instructions, except that some variants ending +// in "s" have a final "int *" that receives the post-instruction CC value. + +// Vector support instructions (chapter 21 of the PoP) +BUILTIN(__builtin_s390_lcbb, "UivC*Ii", "nc") +BUILTIN(__builtin_s390_vlbb, "V16ScvC*Ii", "") +BUILTIN(__builtin_s390_vll, "V16ScUivC*", "") +BUILTIN(__builtin_s390_vstl, "vV16ScUiv*", "") +BUILTIN(__builtin_s390_vperm, "V16UcV16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_s390_vpdi, "V2ULLiV2ULLiV2ULLiIi", "nc") +BUILTIN(__builtin_s390_vpksh, "V16ScV8SsV8Ss", "nc") +BUILTIN(__builtin_s390_vpkshs, "V16ScV8SsV8Ssi*", "nc") +BUILTIN(__builtin_s390_vpksf, "V8SsV4SiV4Si", "nc") +BUILTIN(__builtin_s390_vpksfs, "V8SsV4SiV4Sii*", "nc") +BUILTIN(__builtin_s390_vpksg, "V4SiV2SLLiV2SLLi", "nc") +BUILTIN(__builtin_s390_vpksgs, "V4SiV2SLLiV2SLLii*", "nc") +BUILTIN(__builtin_s390_vpklsh, "V16UcV8UsV8Us", "nc") +BUILTIN(__builtin_s390_vpklshs, "V16UcV8UsV8Usi*", "nc") +BUILTIN(__builtin_s390_vpklsf, "V8UsV4UiV4Ui", "nc") +BUILTIN(__builtin_s390_vpklsfs, "V8UsV4UiV4Uii*", "nc") +BUILTIN(__builtin_s390_vpklsg, "V4UiV2ULLiV2ULLi", "nc") +BUILTIN(__builtin_s390_vpklsgs, "V4UiV2ULLiV2ULLii*", "nc") +BUILTIN(__builtin_s390_vuphb, "V8SsV16Sc", "nc") +BUILTIN(__builtin_s390_vuphh, "V4SiV8Ss", "nc") +BUILTIN(__builtin_s390_vuphf, "V2SLLiV4Si", "nc") +BUILTIN(__builtin_s390_vuplb, "V8SsV16Sc", "nc") +BUILTIN(__builtin_s390_vuplhw, "V4SiV8Ss", "nc") +BUILTIN(__builtin_s390_vuplf, "V2SLLiV4Si", "nc") +BUILTIN(__builtin_s390_vuplhb, "V8UsV16Uc", "nc") +BUILTIN(__builtin_s390_vuplhh, "V4UiV8Us", "nc") +BUILTIN(__builtin_s390_vuplhf, "V2ULLiV4Ui", "nc") +BUILTIN(__builtin_s390_vupllb, "V8UsV16Uc", "nc") +BUILTIN(__builtin_s390_vupllh, "V4UiV8Us", "nc") +BUILTIN(__builtin_s390_vupllf, "V2ULLiV4Ui", "nc") + +// Vector integer instructions (chapter 22 of the PoP) +BUILTIN(__builtin_s390_vaq, "V16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_s390_vacq, "V16UcV16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_s390_vaccb, "V16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_s390_vacch, "V8UsV8UsV8Us", "nc") +BUILTIN(__builtin_s390_vaccf, "V4UiV4UiV4Ui", "nc") +BUILTIN(__builtin_s390_vaccg, "V2ULLiV2ULLiV2ULLi", "nc") +BUILTIN(__builtin_s390_vaccq, "V16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_s390_vacccq, "V16UcV16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_s390_vavgb, "V16ScV16ScV16Sc", "nc") +BUILTIN(__builtin_s390_vavgh, "V8SsV8SsV8Ss", "nc") +BUILTIN(__builtin_s390_vavgf, "V4SiV4SiV4Si", "nc") +BUILTIN(__builtin_s390_vavgg, "V2SLLiV2SLLiV2SLLi", "nc") +BUILTIN(__builtin_s390_vavglb, "V16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_s390_vavglh, "V8UsV8UsV8Us", "nc") +BUILTIN(__builtin_s390_vavglf, "V4UiV4UiV4Ui", "nc") +BUILTIN(__builtin_s390_vavglg, "V2ULLiV2ULLiV2ULLi", "nc") +BUILTIN(__builtin_s390_vceqbs, "V16ScV16ScV16Sci*", "nc") +BUILTIN(__builtin_s390_vceqhs, "V8SsV8SsV8Ssi*", "nc") +BUILTIN(__builtin_s390_vceqfs, "V4SiV4SiV4Sii*", "nc") +BUILTIN(__builtin_s390_vceqgs, "V2SLLiV2SLLiV2SLLii*", "nc") +BUILTIN(__builtin_s390_vchbs, "V16ScV16ScV16Sci*", "nc") +BUILTIN(__builtin_s390_vchhs, "V8SsV8SsV8Ssi*", "nc") +BUILTIN(__builtin_s390_vchfs, "V4SiV4SiV4Sii*", "nc") +BUILTIN(__builtin_s390_vchgs, "V2SLLiV2SLLiV2SLLii*", "nc") +BUILTIN(__builtin_s390_vchlbs, "V16ScV16UcV16Uci*", "nc") +BUILTIN(__builtin_s390_vchlhs, "V8SsV8UsV8Usi*", "nc") +BUILTIN(__builtin_s390_vchlfs, "V4SiV4UiV4Uii*", "nc") +BUILTIN(__builtin_s390_vchlgs, "V2SLLiV2ULLiV2ULLii*", "nc") +BUILTIN(__builtin_s390_vcksm, "V4UiV4UiV4Ui", "nc") +BUILTIN(__builtin_s390_vclzb, "V16UcV16Uc", "nc") +BUILTIN(__builtin_s390_vclzh, "V8UsV8Us", "nc") +BUILTIN(__builtin_s390_vclzf, "V4UiV4Ui", "nc") +BUILTIN(__builtin_s390_vclzg, "V2ULLiV2ULLi", "nc") +BUILTIN(__builtin_s390_vctzb, "V16UcV16Uc", "nc") +BUILTIN(__builtin_s390_vctzh, "V8UsV8Us", "nc") +BUILTIN(__builtin_s390_vctzf, "V4UiV4Ui", "nc") +BUILTIN(__builtin_s390_vctzg, "V2ULLiV2ULLi", "nc") +BUILTIN(__builtin_s390_verimb, "V16UcV16UcV16UcV16UcIi", "nc") +BUILTIN(__builtin_s390_verimh, "V8UsV8UsV8UsV8UsIi", "nc") +BUILTIN(__builtin_s390_verimf, "V4UiV4UiV4UiV4UiIi", "nc") +BUILTIN(__builtin_s390_verimg, "V2ULLiV2ULLiV2ULLiV2ULLiIi", "nc") +BUILTIN(__builtin_s390_verllb, "V16UcV16UcUi", "nc") +BUILTIN(__builtin_s390_verllh, "V8UsV8UsUi", "nc") +BUILTIN(__builtin_s390_verllf, "V4UiV4UiUi", "nc") +BUILTIN(__builtin_s390_verllg, "V2ULLiV2ULLiUi", "nc") +BUILTIN(__builtin_s390_verllvb, "V16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_s390_verllvh, "V8UsV8UsV8Us", "nc") +BUILTIN(__builtin_s390_verllvf, "V4UiV4UiV4Ui", "nc") +BUILTIN(__builtin_s390_verllvg, "V2ULLiV2ULLiV2ULLi", "nc") +BUILTIN(__builtin_s390_vgfmb, "V8UsV16UcV16Uc", "nc") +BUILTIN(__builtin_s390_vgfmh, "V4UiV8UsV8Us", "nc") +BUILTIN(__builtin_s390_vgfmf, "V2ULLiV4UiV4Ui", "nc") +BUILTIN(__builtin_s390_vgfmg, "V16UcV2ULLiV2ULLi", "nc") +BUILTIN(__builtin_s390_vgfmab, "V8UsV16UcV16UcV8Us", "nc") +BUILTIN(__builtin_s390_vgfmah, "V4UiV8UsV8UsV4Ui", "nc") +BUILTIN(__builtin_s390_vgfmaf, "V2ULLiV4UiV4UiV2ULLi", "nc") +BUILTIN(__builtin_s390_vgfmag, "V16UcV2ULLiV2ULLiV16Uc", "nc") +BUILTIN(__builtin_s390_vmahb, "V16ScV16ScV16ScV16Sc", "nc") +BUILTIN(__builtin_s390_vmahh, "V8SsV8SsV8SsV8Ss", "nc") +BUILTIN(__builtin_s390_vmahf, "V4SiV4SiV4SiV4Si", "nc") +BUILTIN(__builtin_s390_vmalhb, "V16UcV16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_s390_vmalhh, "V8UsV8UsV8UsV8Us", "nc") +BUILTIN(__builtin_s390_vmalhf, "V4UiV4UiV4UiV4Ui", "nc") +BUILTIN(__builtin_s390_vmaeb, "V8SsV16ScV16ScV8Ss", "nc") +BUILTIN(__builtin_s390_vmaeh, "V4SiV8SsV8SsV4Si", "nc") +BUILTIN(__builtin_s390_vmaef, "V2SLLiV4SiV4SiV2SLLi", "nc") +BUILTIN(__builtin_s390_vmaleb, "V8UsV16UcV16UcV8Us", "nc") +BUILTIN(__builtin_s390_vmaleh, "V4UiV8UsV8UsV4Ui", "nc") +BUILTIN(__builtin_s390_vmalef, "V2ULLiV4UiV4UiV2ULLi", "nc") +BUILTIN(__builtin_s390_vmaob, "V8SsV16ScV16ScV8Ss", "nc") +BUILTIN(__builtin_s390_vmaoh, "V4SiV8SsV8SsV4Si", "nc") +BUILTIN(__builtin_s390_vmaof, "V2SLLiV4SiV4SiV2SLLi", "nc") +BUILTIN(__builtin_s390_vmalob, "V8UsV16UcV16UcV8Us", "nc") +BUILTIN(__builtin_s390_vmaloh, "V4UiV8UsV8UsV4Ui", "nc") +BUILTIN(__builtin_s390_vmalof, "V2ULLiV4UiV4UiV2ULLi", "nc") +BUILTIN(__builtin_s390_vmhb, "V16ScV16ScV16Sc", "nc") +BUILTIN(__builtin_s390_vmhh, "V8SsV8SsV8Ss", "nc") +BUILTIN(__builtin_s390_vmhf, "V4SiV4SiV4Si", "nc") +BUILTIN(__builtin_s390_vmlhb, "V16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_s390_vmlhh, "V8UsV8UsV8Us", "nc") +BUILTIN(__builtin_s390_vmlhf, "V4UiV4UiV4Ui", "nc") +BUILTIN(__builtin_s390_vmeb, "V8SsV16ScV16Sc", "nc") +BUILTIN(__builtin_s390_vmeh, "V4SiV8SsV8Ss", "nc") +BUILTIN(__builtin_s390_vmef, "V2SLLiV4SiV4Si", "nc") +BUILTIN(__builtin_s390_vmleb, "V8UsV16UcV16Uc", "nc") +BUILTIN(__builtin_s390_vmleh, "V4UiV8UsV8Us", "nc") +BUILTIN(__builtin_s390_vmlef, "V2ULLiV4UiV4Ui", "nc") +BUILTIN(__builtin_s390_vmob, "V8SsV16ScV16Sc", "nc") +BUILTIN(__builtin_s390_vmoh, "V4SiV8SsV8Ss", "nc") +BUILTIN(__builtin_s390_vmof, "V2SLLiV4SiV4Si", "nc") +BUILTIN(__builtin_s390_vmlob, "V8UsV16UcV16Uc", "nc") +BUILTIN(__builtin_s390_vmloh, "V4UiV8UsV8Us", "nc") +BUILTIN(__builtin_s390_vmlof, "V2ULLiV4UiV4Ui", "nc") +BUILTIN(__builtin_s390_vpopctb, "V16UcV16Uc", "nc") +BUILTIN(__builtin_s390_vpopcth, "V8UsV8Us", "nc") +BUILTIN(__builtin_s390_vpopctf, "V4UiV4Ui", "nc") +BUILTIN(__builtin_s390_vpopctg, "V2ULLiV2ULLi", "nc") +BUILTIN(__builtin_s390_vsq, "V16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_s390_vsbcbiq, "V16UcV16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_s390_vsbiq, "V16UcV16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_s390_vscbib, "V16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_s390_vscbih, "V8UsV8UsV8Us", "nc") +BUILTIN(__builtin_s390_vscbif, "V4UiV4UiV4Ui", "nc") +BUILTIN(__builtin_s390_vscbig, "V2ULLiV2ULLiV2ULLi", "nc") +BUILTIN(__builtin_s390_vscbiq, "V16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_s390_vsl, "V16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_s390_vslb, "V16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_s390_vsldb, "V16UcV16UcV16UcIi", "nc") +BUILTIN(__builtin_s390_vsra, "V16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_s390_vsrab, "V16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_s390_vsrl, "V16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_s390_vsrlb, "V16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_s390_vsumb, "V4UiV16UcV16Uc", "nc") +BUILTIN(__builtin_s390_vsumh, "V4UiV8UsV8Us", "nc") +BUILTIN(__builtin_s390_vsumgh, "V2ULLiV8UsV8Us", "nc") +BUILTIN(__builtin_s390_vsumgf, "V2ULLiV4UiV4Ui", "nc") +BUILTIN(__builtin_s390_vsumqf, "V16UcV4UiV4Ui", "nc") +BUILTIN(__builtin_s390_vsumqg, "V16UcV2ULLiV2ULLi", "nc") +BUILTIN(__builtin_s390_vtm, "iV16UcV16Uc", "nc") + +// Vector string instructions (chapter 23 of the PoP) +BUILTIN(__builtin_s390_vfaeb, "V16UcV16UcV16UcIi", "nc") +BUILTIN(__builtin_s390_vfaebs, "V16UcV16UcV16UcIii*", "nc") +BUILTIN(__builtin_s390_vfaeh, "V8UsV8UsV8UsIi", "nc") +BUILTIN(__builtin_s390_vfaehs, "V8UsV8UsV8UsIii*", "nc") +BUILTIN(__builtin_s390_vfaef, "V4UiV4UiV4UiIi", "nc") +BUILTIN(__builtin_s390_vfaefs, "V4UiV4UiV4UiIii*", "nc") +BUILTIN(__builtin_s390_vfaezb, "V16UcV16UcV16UcIi", "nc") +BUILTIN(__builtin_s390_vfaezbs, "V16UcV16UcV16UcIii*", "nc") +BUILTIN(__builtin_s390_vfaezh, "V8UsV8UsV8UsIi", "nc") +BUILTIN(__builtin_s390_vfaezhs, "V8UsV8UsV8UsIii*", "nc") +BUILTIN(__builtin_s390_vfaezf, "V4UiV4UiV4UiIi", "nc") +BUILTIN(__builtin_s390_vfaezfs, "V4UiV4UiV4UiIii*", "nc") +BUILTIN(__builtin_s390_vfeeb, "V16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_s390_vfeebs, "V16UcV16UcV16Uci*", "nc") +BUILTIN(__builtin_s390_vfeeh, "V8UsV8UsV8Us", "nc") +BUILTIN(__builtin_s390_vfeehs, "V8UsV8UsV8Usi*", "nc") +BUILTIN(__builtin_s390_vfeef, "V4UiV4UiV4Ui", "nc") +BUILTIN(__builtin_s390_vfeefs, "V4UiV4UiV4Uii*", "nc") +BUILTIN(__builtin_s390_vfeezb, "V16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_s390_vfeezbs, "V16UcV16UcV16Uci*", "nc") +BUILTIN(__builtin_s390_vfeezh, "V8UsV8UsV8Us", "nc") +BUILTIN(__builtin_s390_vfeezhs, "V8UsV8UsV8Usi*", "nc") +BUILTIN(__builtin_s390_vfeezf, "V4UiV4UiV4Ui", "nc") +BUILTIN(__builtin_s390_vfeezfs, "V4UiV4UiV4Uii*", "nc") +BUILTIN(__builtin_s390_vfeneb, "V16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_s390_vfenebs, "V16UcV16UcV16Uci*", "nc") +BUILTIN(__builtin_s390_vfeneh, "V8UsV8UsV8Us", "nc") +BUILTIN(__builtin_s390_vfenehs, "V8UsV8UsV8Usi*", "nc") +BUILTIN(__builtin_s390_vfenef, "V4UiV4UiV4Ui", "nc") +BUILTIN(__builtin_s390_vfenefs, "V4UiV4UiV4Uii*", "nc") +BUILTIN(__builtin_s390_vfenezb, "V16UcV16UcV16Uc", "nc") +BUILTIN(__builtin_s390_vfenezbs, "V16UcV16UcV16Uci*", "nc") +BUILTIN(__builtin_s390_vfenezh, "V8UsV8UsV8Us", "nc") +BUILTIN(__builtin_s390_vfenezhs, "V8UsV8UsV8Usi*", "nc") +BUILTIN(__builtin_s390_vfenezf, "V4UiV4UiV4Ui", "nc") +BUILTIN(__builtin_s390_vfenezfs, "V4UiV4UiV4Uii*", "nc") +BUILTIN(__builtin_s390_vistrb, "V16UcV16Uc", "nc") +BUILTIN(__builtin_s390_vistrbs, "V16UcV16Uci*", "nc") +BUILTIN(__builtin_s390_vistrh, "V8UsV8Us", "nc") +BUILTIN(__builtin_s390_vistrhs, "V8UsV8Usi*", "nc") +BUILTIN(__builtin_s390_vistrf, "V4UiV4Ui", "nc") +BUILTIN(__builtin_s390_vistrfs, "V4UiV4Uii*", "nc") +BUILTIN(__builtin_s390_vstrcb, "V16UcV16UcV16UcV16UcIi", "nc") +BUILTIN(__builtin_s390_vstrcbs, "V16UcV16UcV16UcV16UcIii*", "nc") +BUILTIN(__builtin_s390_vstrch, "V8UsV8UsV8UsV8UsIi", "nc") +BUILTIN(__builtin_s390_vstrchs, "V8UsV8UsV8UsV8UsIii*", "nc") +BUILTIN(__builtin_s390_vstrcf, "V4UiV4UiV4UiV4UiIi", "nc") +BUILTIN(__builtin_s390_vstrcfs, "V4UiV4UiV4UiV4UiIii*", "nc") +BUILTIN(__builtin_s390_vstrczb, "V16UcV16UcV16UcV16UcIi", "nc") +BUILTIN(__builtin_s390_vstrczbs, "V16UcV16UcV16UcV16UcIii*", "nc") +BUILTIN(__builtin_s390_vstrczh, "V8UsV8UsV8UsV8UsIi", "nc") +BUILTIN(__builtin_s390_vstrczhs, "V8UsV8UsV8UsV8UsIii*", "nc") +BUILTIN(__builtin_s390_vstrczf, "V4UiV4UiV4UiV4UiIi", "nc") +BUILTIN(__builtin_s390_vstrczfs, "V4UiV4UiV4UiV4UiIii*", "nc") + +// Vector floating-point instructions (chapter 24 of the PoP) +BUILTIN(__builtin_s390_vfcedbs, "V2SLLiV2dV2di*", "nc") +BUILTIN(__builtin_s390_vfchdbs, "V2SLLiV2dV2di*", "nc") +BUILTIN(__builtin_s390_vfchedbs, "V2SLLiV2dV2di*", "nc") +BUILTIN(__builtin_s390_vfidb, "V2dV2dIiIi", "nc") +BUILTIN(__builtin_s390_vflndb, "V2dV2d", "nc") +BUILTIN(__builtin_s390_vflpdb, "V2dV2d", "nc") +BUILTIN(__builtin_s390_vfmadb, "V2dV2dV2dV2d", "nc") +BUILTIN(__builtin_s390_vfmsdb, "V2dV2dV2dV2d", "nc") +BUILTIN(__builtin_s390_vfsqdb, "V2dV2d", "nc") +BUILTIN(__builtin_s390_vftcidb, "V2SLLiV2dIii*", "nc") + +#undef BUILTIN diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsWebAssembly.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsWebAssembly.def new file mode 100644 index 0000000..9754335 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsWebAssembly.def @@ -0,0 +1,24 @@ +// BuiltinsWebAssembly.def - WebAssembly builtin function database -*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file defines the WebAssembly-specific builtin function database. +/// Users of this file must define the BUILTIN macro to make use of this +/// information. +/// +//===----------------------------------------------------------------------===// + +// The format of this database matches clang/Basic/Builtins.def. + +// Note that memory_size is not "c" (readnone) because it must be sequenced with +// respect to grow_memory calls. +BUILTIN(__builtin_wasm_memory_size, "z", "n") +BUILTIN(__builtin_wasm_grow_memory, "vz", "n") + +#undef BUILTIN diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86.def new file mode 100644 index 0000000..f738cc1 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86.def @@ -0,0 +1,1577 @@ +//===--- BuiltinsX86.def - X86 Builtin function database --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the X86-specific builtin function database. Users of +// this file must define the BUILTIN macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +// The format of this database matches clang/Basic/Builtins.def. + +// FIXME: Ideally we would be able to pull this information from what +// LLVM already knows about X86 builtins. We need to match the LLVM +// definition anyway, since code generation will lower to the +// intrinsic if one exists. + +#if defined(BUILTIN) && !defined(TARGET_BUILTIN) +# define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) BUILTIN(ID, TYPE, ATTRS) +#endif + +// FIXME: Are these nothrow/const? + +// Miscellaneous builtin for checking x86 cpu features. +// TODO: Make this somewhat generic so that other backends +// can use it? +BUILTIN(__builtin_cpu_supports, "bcC*", "nc") + +// Win64-compatible va_list functions +BUILTIN(__builtin_ms_va_start, "vc*&.", "nt") +BUILTIN(__builtin_ms_va_end, "vc*&", "n") +BUILTIN(__builtin_ms_va_copy, "vc*&c*&", "n") + +// Undefined Values +// +TARGET_BUILTIN(__builtin_ia32_undef128, "V2d", "nc", "") +TARGET_BUILTIN(__builtin_ia32_undef256, "V4d", "nc", "") +TARGET_BUILTIN(__builtin_ia32_undef512, "V8d", "nc", "") + +// FLAGS +// +TARGET_BUILTIN(__builtin_ia32_readeflags_u32, "Ui", "n", "") +TARGET_BUILTIN(__builtin_ia32_readeflags_u64, "ULLi", "n", "") +TARGET_BUILTIN(__builtin_ia32_writeeflags_u32, "vUi", "n", "") +TARGET_BUILTIN(__builtin_ia32_writeeflags_u64, "vULLi", "n", "") + +// 3DNow! +// +TARGET_BUILTIN(__builtin_ia32_femms, "v", "", "3dnow") +TARGET_BUILTIN(__builtin_ia32_pavgusb, "V8cV8cV8c", "nc", "3dnow") +TARGET_BUILTIN(__builtin_ia32_pf2id, "V2iV2f", "nc", "3dnow") +TARGET_BUILTIN(__builtin_ia32_pfacc, "V2fV2fV2f", "nc", "3dnow") +TARGET_BUILTIN(__builtin_ia32_pfadd, "V2fV2fV2f", "nc", "3dnow") +TARGET_BUILTIN(__builtin_ia32_pfcmpeq, "V2iV2fV2f", "nc", "3dnow") +TARGET_BUILTIN(__builtin_ia32_pfcmpge, "V2iV2fV2f", "nc", "3dnow") +TARGET_BUILTIN(__builtin_ia32_pfcmpgt, "V2iV2fV2f", "nc", "3dnow") +TARGET_BUILTIN(__builtin_ia32_pfmax, "V2fV2fV2f", "nc", "3dnow") +TARGET_BUILTIN(__builtin_ia32_pfmin, "V2fV2fV2f", "nc", "3dnow") +TARGET_BUILTIN(__builtin_ia32_pfmul, "V2fV2fV2f", "nc", "3dnow") +TARGET_BUILTIN(__builtin_ia32_pfrcp, "V2fV2f", "nc", "3dnow") +TARGET_BUILTIN(__builtin_ia32_pfrcpit1, "V2fV2fV2f", "nc", "3dnow") +TARGET_BUILTIN(__builtin_ia32_pfrcpit2, "V2fV2fV2f", "nc", "3dnow") +TARGET_BUILTIN(__builtin_ia32_pfrsqrt, "V2fV2f", "nc", "3dnow") +TARGET_BUILTIN(__builtin_ia32_pfrsqit1, "V2fV2fV2f", "nc", "3dnow") +TARGET_BUILTIN(__builtin_ia32_pfsub, "V2fV2fV2f", "nc", "3dnow") +TARGET_BUILTIN(__builtin_ia32_pfsubr, "V2fV2fV2f", "nc", "3dnow") +TARGET_BUILTIN(__builtin_ia32_pi2fd, "V2fV2i", "nc", "3dnow") +TARGET_BUILTIN(__builtin_ia32_pmulhrw, "V4sV4sV4s", "nc", "3dnow") +// 3DNow! Extensions (3dnowa). +TARGET_BUILTIN(__builtin_ia32_pf2iw, "V2iV2f", "nc", "3dnowa") +TARGET_BUILTIN(__builtin_ia32_pfnacc, "V2fV2fV2f", "nc", "3dnowa") +TARGET_BUILTIN(__builtin_ia32_pfpnacc, "V2fV2fV2f", "nc", "3dnowa") +TARGET_BUILTIN(__builtin_ia32_pi2fw, "V2fV2i", "nc", "3dnowa") +TARGET_BUILTIN(__builtin_ia32_pswapdsf, "V2fV2f", "nc", "3dnowa") +TARGET_BUILTIN(__builtin_ia32_pswapdsi, "V2iV2i", "nc", "3dnowa") + +// MMX +// +// All MMX instructions will be generated via builtins. Any MMX vector +// types (<1 x i64>, <2 x i32>, etc.) that aren't used by these builtins will be +// expanded by the back-end. +// FIXME: _mm_prefetch must be a built-in because it takes a compile-time constant +// argument and our prior approach of using a #define to the current built-in +// doesn't work in the presence of re-declaration of _mm_prefetch for windows. +TARGET_BUILTIN(_mm_prefetch, "vcC*i", "nc", "mmx") +TARGET_BUILTIN(__builtin_ia32_emms, "v", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_paddb, "V8cV8cV8c", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_paddw, "V4sV4sV4s", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_paddd, "V2iV2iV2i", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_paddsb, "V8cV8cV8c", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_paddsw, "V4sV4sV4s", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_paddusb, "V8cV8cV8c", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_paddusw, "V4sV4sV4s", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_psubb, "V8cV8cV8c", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_psubw, "V4sV4sV4s", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_psubd, "V2iV2iV2i", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_psubsb, "V8cV8cV8c", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_psubsw, "V4sV4sV4s", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_psubusb, "V8cV8cV8c", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_psubusw, "V4sV4sV4s", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_pmulhw, "V4sV4sV4s", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_pmullw, "V4sV4sV4s", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_pmaddwd, "V2iV4sV4s", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_pand, "V1LLiV1LLiV1LLi", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_pandn, "V1LLiV1LLiV1LLi", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_por, "V1LLiV1LLiV1LLi", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_pxor, "V1LLiV1LLiV1LLi", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_psllw, "V4sV4sV1LLi", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_pslld, "V2iV2iV1LLi", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_psllq, "V1LLiV1LLiV1LLi", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_psrlw, "V4sV4sV1LLi", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_psrld, "V2iV2iV1LLi", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_psrlq, "V1LLiV1LLiV1LLi", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_psraw, "V4sV4sV1LLi", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_psrad, "V2iV2iV1LLi", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_psllwi, "V4sV4si", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_pslldi, "V2iV2ii", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_psllqi, "V1LLiV1LLii", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_psrlwi, "V4sV4si", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_psrldi, "V2iV2ii", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_psrlqi, "V1LLiV1LLii", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_psrawi, "V4sV4si", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_psradi, "V2iV2ii", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_packsswb, "V8cV4sV4s", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_packssdw, "V4sV2iV2i", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_packuswb, "V8cV4sV4s", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_punpckhbw, "V8cV8cV8c", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_punpckhwd, "V4sV4sV4s", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_punpckhdq, "V2iV2iV2i", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_punpcklbw, "V8cV8cV8c", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_punpcklwd, "V4sV4sV4s", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_punpckldq, "V2iV2iV2i", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_pcmpeqb, "V8cV8cV8c", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_pcmpeqw, "V4sV4sV4s", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_pcmpeqd, "V2iV2iV2i", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_pcmpgtb, "V8cV8cV8c", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_pcmpgtw, "V4sV4sV4s", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_pcmpgtd, "V2iV2iV2i", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_maskmovq, "vV8cV8cc*", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_movntq, "vV1LLi*V1LLi", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_vec_init_v2si, "V2iii", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_vec_init_v4hi, "V4sssss", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_vec_init_v8qi, "V8ccccccccc", "", "mmx") +TARGET_BUILTIN(__builtin_ia32_vec_ext_v2si, "iV2ii", "", "mmx") + +// MMX2 (MMX+SSE) intrinsics +TARGET_BUILTIN(__builtin_ia32_cvtpi2ps, "V4fV4fV2i", "", "sse") +TARGET_BUILTIN(__builtin_ia32_cvtps2pi, "V2iV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_cvttps2pi, "V2iV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_pavgb, "V8cV8cV8c", "", "sse") +TARGET_BUILTIN(__builtin_ia32_pavgw, "V4sV4sV4s", "", "sse") +TARGET_BUILTIN(__builtin_ia32_pmaxsw, "V4sV4sV4s", "", "sse") +TARGET_BUILTIN(__builtin_ia32_pmaxub, "V8cV8cV8c", "", "sse") +TARGET_BUILTIN(__builtin_ia32_pminsw, "V4sV4sV4s", "", "sse") +TARGET_BUILTIN(__builtin_ia32_pminub, "V8cV8cV8c", "", "sse") +TARGET_BUILTIN(__builtin_ia32_pmovmskb, "iV8c", "", "sse") +TARGET_BUILTIN(__builtin_ia32_pmulhuw, "V4sV4sV4s", "", "sse") +TARGET_BUILTIN(__builtin_ia32_psadbw, "V4sV8cV8c", "", "sse") +TARGET_BUILTIN(__builtin_ia32_pshufw, "V4sV4sIc", "", "sse") + +// MMX+SSE2 +TARGET_BUILTIN(__builtin_ia32_cvtpd2pi, "V2iV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_cvtpi2pd, "V2dV2i", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_cvttpd2pi, "V2iV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_paddq, "V1LLiV1LLiV1LLi", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_pmuludq, "V1LLiV2iV2i", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_psubq, "V1LLiV1LLiV1LLi", "", "sse2") + +// MMX+SSSE3 +TARGET_BUILTIN(__builtin_ia32_pabsb, "V8cV8c", "", "ssse3") +TARGET_BUILTIN(__builtin_ia32_pabsd, "V2iV2i", "", "ssse3") +TARGET_BUILTIN(__builtin_ia32_pabsw, "V4sV4s", "", "ssse3") +TARGET_BUILTIN(__builtin_ia32_palignr, "V8cV8cV8cIc", "", "ssse3") +TARGET_BUILTIN(__builtin_ia32_phaddd, "V2iV2iV2i", "", "ssse3") +TARGET_BUILTIN(__builtin_ia32_phaddsw, "V4sV4sV4s", "", "ssse3") +TARGET_BUILTIN(__builtin_ia32_phaddw, "V4sV4sV4s", "", "ssse3") +TARGET_BUILTIN(__builtin_ia32_phsubd, "V2iV2iV2i", "", "ssse3") +TARGET_BUILTIN(__builtin_ia32_phsubsw, "V4sV4sV4s", "", "ssse3") +TARGET_BUILTIN(__builtin_ia32_phsubw, "V4sV4sV4s", "", "ssse3") +TARGET_BUILTIN(__builtin_ia32_pmaddubsw, "V8cV8cV8c", "", "ssse3") +TARGET_BUILTIN(__builtin_ia32_pmulhrsw, "V4sV4sV4s", "", "ssse3") +TARGET_BUILTIN(__builtin_ia32_pshufb, "V8cV8cV8c", "", "ssse3") +TARGET_BUILTIN(__builtin_ia32_psignw, "V4sV4sV4s", "", "ssse3") +TARGET_BUILTIN(__builtin_ia32_psignb, "V8cV8cV8c", "", "ssse3") +TARGET_BUILTIN(__builtin_ia32_psignd, "V2iV2iV2i", "", "ssse3") + +// SSE intrinsics. +TARGET_BUILTIN(__builtin_ia32_comieq, "iV4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_comilt, "iV4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_comile, "iV4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_comigt, "iV4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_comige, "iV4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_comineq, "iV4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_ucomieq, "iV4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_ucomilt, "iV4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_ucomile, "iV4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_ucomigt, "iV4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_ucomige, "iV4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_ucomineq, "iV4fV4f", "", "sse") + +TARGET_BUILTIN(__builtin_ia32_comisdeq, "iV2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_comisdlt, "iV2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_comisdle, "iV2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_comisdgt, "iV2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_comisdge, "iV2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_comisdneq, "iV2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_ucomisdeq, "iV2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_ucomisdlt, "iV2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_ucomisdle, "iV2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_ucomisdgt, "iV2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_ucomisdge, "iV2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_ucomisdneq, "iV2dV2d", "", "sse2") + +TARGET_BUILTIN(__builtin_ia32_cmpps, "V4fV4fV4fIc", "", "sse") +TARGET_BUILTIN(__builtin_ia32_cmpeqps, "V4fV4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_cmpltps, "V4fV4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_cmpleps, "V4fV4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_cmpunordps, "V4fV4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_cmpneqps, "V4fV4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_cmpnltps, "V4fV4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_cmpnleps, "V4fV4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_cmpordps, "V4fV4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_cmpss, "V4fV4fV4fIc", "", "sse") +TARGET_BUILTIN(__builtin_ia32_cmpeqss, "V4fV4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_cmpltss, "V4fV4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_cmpless, "V4fV4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_cmpunordss, "V4fV4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_cmpneqss, "V4fV4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_cmpnltss, "V4fV4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_cmpnless, "V4fV4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_cmpordss, "V4fV4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_minps, "V4fV4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_maxps, "V4fV4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_minss, "V4fV4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_maxss, "V4fV4fV4f", "", "sse") + +TARGET_BUILTIN(__builtin_ia32_cmppd, "V2dV2dV2dIc", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_cmpeqpd, "V2dV2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_cmpltpd, "V2dV2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_cmplepd, "V2dV2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_cmpunordpd, "V2dV2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_cmpneqpd, "V2dV2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_cmpnltpd, "V2dV2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_cmpnlepd, "V2dV2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_cmpordpd, "V2dV2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_cmpsd, "V2dV2dV2dIc", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_cmpeqsd, "V2dV2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_cmpltsd, "V2dV2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_cmplesd, "V2dV2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_cmpunordsd, "V2dV2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_cmpneqsd, "V2dV2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_cmpnltsd, "V2dV2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_cmpnlesd, "V2dV2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_cmpordsd, "V2dV2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_minpd, "V2dV2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_maxpd, "V2dV2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_minsd, "V2dV2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_maxsd, "V2dV2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_paddsb128, "V16cV16cV16c", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_paddsw128, "V8sV8sV8s", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_psubsb128, "V16cV16cV16c", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_psubsw128, "V8sV8sV8s", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_paddusb128, "V16cV16cV16c", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_paddusw128, "V8sV8sV8s", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_psubusb128, "V16cV16cV16c", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_psubusw128, "V8sV8sV8s", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_pmulhw128, "V8sV8sV8s", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_pavgb128, "V16cV16cV16c", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_pavgw128, "V8sV8sV8s", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_pmaxub128, "V16cV16cV16c", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_pmaxsw128, "V8sV8sV8s", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_pminub128, "V16cV16cV16c", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_pminsw128, "V8sV8sV8s", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_packsswb128, "V16cV8sV8s", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_packssdw128, "V8sV4iV4i", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_packuswb128, "V16cV8sV8s", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_pmulhuw128, "V8sV8sV8s", "", "sse2") + +TARGET_BUILTIN(__builtin_ia32_addsubps, "V4fV4fV4f", "", "sse3") +TARGET_BUILTIN(__builtin_ia32_addsubpd, "V2dV2dV2d", "", "sse3") +TARGET_BUILTIN(__builtin_ia32_haddps, "V4fV4fV4f", "", "sse3") +TARGET_BUILTIN(__builtin_ia32_haddpd, "V2dV2dV2d", "", "sse3") +TARGET_BUILTIN(__builtin_ia32_hsubps, "V4fV4fV4f", "", "sse3") +TARGET_BUILTIN(__builtin_ia32_hsubpd, "V2dV2dV2d", "", "sse3") +TARGET_BUILTIN(__builtin_ia32_phaddw128, "V8sV8sV8s", "", "ssse3") +TARGET_BUILTIN(__builtin_ia32_phaddd128, "V4iV4iV4i", "", "ssse3") +TARGET_BUILTIN(__builtin_ia32_phaddsw128, "V8sV8sV8s", "", "ssse3") +TARGET_BUILTIN(__builtin_ia32_phsubw128, "V8sV8sV8s", "", "ssse3") +TARGET_BUILTIN(__builtin_ia32_phsubd128, "V4iV4iV4i", "", "ssse3") +TARGET_BUILTIN(__builtin_ia32_phsubsw128, "V8sV8sV8s", "", "ssse3") +TARGET_BUILTIN(__builtin_ia32_pmaddubsw128, "V8sV16cV16c", "", "ssse3") +TARGET_BUILTIN(__builtin_ia32_pmulhrsw128, "V8sV8sV8s", "", "ssse3") +TARGET_BUILTIN(__builtin_ia32_pshufb128, "V16cV16cV16c", "", "ssse3") +TARGET_BUILTIN(__builtin_ia32_psignb128, "V16cV16cV16c", "", "ssse3") +TARGET_BUILTIN(__builtin_ia32_psignw128, "V8sV8sV8s", "", "ssse3") +TARGET_BUILTIN(__builtin_ia32_psignd128, "V4iV4iV4i", "", "ssse3") +TARGET_BUILTIN(__builtin_ia32_pabsb128, "V16cV16c", "", "ssse3") +TARGET_BUILTIN(__builtin_ia32_pabsw128, "V8sV8s", "", "ssse3") +TARGET_BUILTIN(__builtin_ia32_pabsd128, "V4iV4i", "", "ssse3") + +TARGET_BUILTIN(__builtin_ia32_ldmxcsr, "vUi", "", "sse") +TARGET_BUILTIN(__builtin_ia32_stmxcsr, "Ui", "", "sse") +TARGET_BUILTIN(__builtin_ia32_cvtss2si, "iV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_cvtss2si64, "LLiV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_storeups, "vf*V4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_storehps, "vV2i*V4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_storelps, "vV2i*V4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_movmskps, "iV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_movntps, "vf*V4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_sfence, "v", "", "sse") +TARGET_BUILTIN(__builtin_ia32_rcpps, "V4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_rcpss, "V4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_rsqrtps, "V4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_rsqrtss, "V4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_sqrtps, "V4fV4f", "", "sse") +TARGET_BUILTIN(__builtin_ia32_sqrtss, "V4fV4f", "", "sse") + +TARGET_BUILTIN(__builtin_ia32_maskmovdqu, "vV16cV16cc*", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_storeupd, "vd*V2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_movmskpd, "iV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_pmovmskb128, "iV16c", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_movnti, "vi*i", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_movnti64, "vLLi*LLi", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_movntpd, "vd*V2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_movntdq, "vV2LLi*V2LLi", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_psadbw128, "V2LLiV16cV16c", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_sqrtpd, "V2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_sqrtsd, "V2dV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_cvtdq2pd, "V2dV4i", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_cvtdq2ps, "V4fV4i", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_cvtpd2dq, "V2LLiV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_cvtpd2ps, "V4fV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_cvttpd2dq, "V4iV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_cvtsd2si, "iV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_cvtsd2si64, "LLiV2d", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_cvtps2dq, "V4iV4f", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_cvtps2pd, "V2dV4f", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_cvttps2dq, "V4iV4f", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_clflush, "vvC*", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_lfence, "v", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_mfence, "v", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_pause, "v", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_storedqu, "vc*V16c", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_pmuludq128, "V2LLiV4iV4i", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_psraw128, "V8sV8sV8s", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_psrad128, "V4iV4iV4i", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_psrlw128, "V8sV8sV8s", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_psrld128, "V4iV4iV4i", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_psrlq128, "V2LLiV2LLiV2LLi", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_psllw128, "V8sV8sV8s", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_pslld128, "V4iV4iV4i", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_psllq128, "V2LLiV2LLiV2LLi", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_psllwi128, "V8sV8si", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_pslldi128, "V4iV4ii", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_psllqi128, "V2LLiV2LLii", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_psrlwi128, "V8sV8si", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_psrldi128, "V4iV4ii", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_psrlqi128, "V2LLiV2LLii", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_psrawi128, "V8sV8si", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_psradi128, "V4iV4ii", "", "sse2") +TARGET_BUILTIN(__builtin_ia32_pmaddwd128, "V4iV8sV8s", "", "sse2") + +TARGET_BUILTIN(__builtin_ia32_monitor, "vv*UiUi", "", "sse3") +TARGET_BUILTIN(__builtin_ia32_mwait, "vUiUi", "", "sse3") +TARGET_BUILTIN(__builtin_ia32_lddqu, "V16ccC*", "", "sse3") + +TARGET_BUILTIN(__builtin_ia32_palignr128, "V16cV16cV16cIc", "", "ssse3") + +TARGET_BUILTIN(__builtin_ia32_insertps128, "V4fV4fV4fIc", "", "sse4.1") +TARGET_BUILTIN(__builtin_ia32_pblendvb128, "V16cV16cV16cV16c", "", "sse4.1") +TARGET_BUILTIN(__builtin_ia32_blendvpd, "V2dV2dV2dV2d", "", "sse4.1") +TARGET_BUILTIN(__builtin_ia32_blendvps, "V4fV4fV4fV4f", "", "sse4.1") +TARGET_BUILTIN(__builtin_ia32_packusdw128, "V8sV4iV4i", "", "sse4.1") + +TARGET_BUILTIN(__builtin_ia32_pmaxsb128, "V16cV16cV16c", "", "sse4.1") +TARGET_BUILTIN(__builtin_ia32_pmaxsd128, "V4iV4iV4i", "", "sse4.1") +TARGET_BUILTIN(__builtin_ia32_pmaxud128, "V4iV4iV4i", "", "sse4.1") +TARGET_BUILTIN(__builtin_ia32_pmaxuw128, "V8sV8sV8s", "", "sse4.1") +TARGET_BUILTIN(__builtin_ia32_pminsb128, "V16cV16cV16c", "", "sse4.1") +TARGET_BUILTIN(__builtin_ia32_pminsd128, "V4iV4iV4i", "", "sse4.1") +TARGET_BUILTIN(__builtin_ia32_pminud128, "V4iV4iV4i", "", "sse4.1") +TARGET_BUILTIN(__builtin_ia32_pminuw128, "V8sV8sV8s", "", "sse4.1") +TARGET_BUILTIN(__builtin_ia32_pmovzxbd128, "V4iV16c", "", "sse4.1") +TARGET_BUILTIN(__builtin_ia32_pmovzxbq128, "V2LLiV16c", "", "sse4.1") +TARGET_BUILTIN(__builtin_ia32_pmovzxbw128, "V8sV16c", "", "sse4.1") +TARGET_BUILTIN(__builtin_ia32_pmovzxdq128, "V2LLiV4i", "", "sse4.1") +TARGET_BUILTIN(__builtin_ia32_pmovzxwd128, "V4iV8s", "", "sse4.1") +TARGET_BUILTIN(__builtin_ia32_pmovzxwq128, "V2LLiV8s", "", "sse4.1") +TARGET_BUILTIN(__builtin_ia32_pmuldq128, "V2LLiV4iV4i", "", "sse4.1") +TARGET_BUILTIN(__builtin_ia32_pmulld128, "V4iV4iV4i", "", "sse4.1") +TARGET_BUILTIN(__builtin_ia32_roundps, "V4fV4fIi", "", "sse4.1") +TARGET_BUILTIN(__builtin_ia32_roundss, "V4fV4fV4fIi", "", "sse4.1") +TARGET_BUILTIN(__builtin_ia32_roundsd, "V2dV2dV2dIi", "", "sse4.1") +TARGET_BUILTIN(__builtin_ia32_roundpd, "V2dV2dIi", "", "sse4.1") +TARGET_BUILTIN(__builtin_ia32_dpps, "V4fV4fV4fIc", "", "sse4.1") +TARGET_BUILTIN(__builtin_ia32_dppd, "V2dV2dV2dIc", "", "sse4.1") +TARGET_BUILTIN(__builtin_ia32_movntdqa, "V2LLiV2LLiC*", "", "sse4.1") +TARGET_BUILTIN(__builtin_ia32_ptestz128, "iV2LLiV2LLi", "", "sse4.1") +TARGET_BUILTIN(__builtin_ia32_ptestc128, "iV2LLiV2LLi", "", "sse4.1") +TARGET_BUILTIN(__builtin_ia32_ptestnzc128, "iV2LLiV2LLi", "", "sse4.1") +TARGET_BUILTIN(__builtin_ia32_mpsadbw128, "V16cV16cV16cIc", "", "sse4.1") +TARGET_BUILTIN(__builtin_ia32_phminposuw128, "V8sV8s", "", "sse4.1") + +// SSE 4.2 +TARGET_BUILTIN(__builtin_ia32_pcmpistrm128, "V16cV16cV16cIc", "", "sse4.2") +TARGET_BUILTIN(__builtin_ia32_pcmpistri128, "iV16cV16cIc", "", "sse4.2") +TARGET_BUILTIN(__builtin_ia32_pcmpestrm128, "V16cV16ciV16ciIc", "", "sse4.2") +TARGET_BUILTIN(__builtin_ia32_pcmpestri128, "iV16ciV16ciIc","", "sse4.2") + +TARGET_BUILTIN(__builtin_ia32_pcmpistria128, "iV16cV16cIc","", "sse4.2") +TARGET_BUILTIN(__builtin_ia32_pcmpistric128, "iV16cV16cIc","", "sse4.2") +TARGET_BUILTIN(__builtin_ia32_pcmpistrio128, "iV16cV16cIc","", "sse4.2") +TARGET_BUILTIN(__builtin_ia32_pcmpistris128, "iV16cV16cIc","", "sse4.2") +TARGET_BUILTIN(__builtin_ia32_pcmpistriz128, "iV16cV16cIc","", "sse4.2") +TARGET_BUILTIN(__builtin_ia32_pcmpestria128, "iV16ciV16ciIc","", "sse4.2") +TARGET_BUILTIN(__builtin_ia32_pcmpestric128, "iV16ciV16ciIc","", "sse4.2") +TARGET_BUILTIN(__builtin_ia32_pcmpestrio128, "iV16ciV16ciIc","", "sse4.2") +TARGET_BUILTIN(__builtin_ia32_pcmpestris128, "iV16ciV16ciIc","", "sse4.2") +TARGET_BUILTIN(__builtin_ia32_pcmpestriz128, "iV16ciV16ciIc","", "sse4.2") + +TARGET_BUILTIN(__builtin_ia32_crc32qi, "UiUiUc", "", "sse4.2") +TARGET_BUILTIN(__builtin_ia32_crc32hi, "UiUiUs", "", "sse4.2") +TARGET_BUILTIN(__builtin_ia32_crc32si, "UiUiUi", "", "sse4.2") +TARGET_BUILTIN(__builtin_ia32_crc32di, "ULLiULLiULLi", "", "sse4.2") + +// SSE4a +TARGET_BUILTIN(__builtin_ia32_extrqi, "V2LLiV2LLiIcIc", "", "sse4a") +TARGET_BUILTIN(__builtin_ia32_extrq, "V2LLiV2LLiV16c", "", "sse4a") +TARGET_BUILTIN(__builtin_ia32_insertqi, "V2LLiV2LLiV2LLiIcIc", "", "sse4a") +TARGET_BUILTIN(__builtin_ia32_insertq, "V2LLiV2LLiV2LLi", "", "sse4a") +TARGET_BUILTIN(__builtin_ia32_movntsd, "vd*V2d", "", "sse4a") +TARGET_BUILTIN(__builtin_ia32_movntss, "vf*V4f", "", "sse4a") + +// AES +TARGET_BUILTIN(__builtin_ia32_aesenc128, "V2LLiV2LLiV2LLi", "", "aes") +TARGET_BUILTIN(__builtin_ia32_aesenclast128, "V2LLiV2LLiV2LLi", "", "aes") +TARGET_BUILTIN(__builtin_ia32_aesdec128, "V2LLiV2LLiV2LLi", "", "aes") +TARGET_BUILTIN(__builtin_ia32_aesdeclast128, "V2LLiV2LLiV2LLi", "", "aes") +TARGET_BUILTIN(__builtin_ia32_aesimc128, "V2LLiV2LLi", "", "aes") +TARGET_BUILTIN(__builtin_ia32_aeskeygenassist128, "V2LLiV2LLiIc", "", "aes") + +// CLMUL +TARGET_BUILTIN(__builtin_ia32_pclmulqdq128, "V2LLiV2LLiV2LLiIc", "", "pclmul") + +// AVX +TARGET_BUILTIN(__builtin_ia32_addsubpd256, "V4dV4dV4d", "", "avx") +TARGET_BUILTIN(__builtin_ia32_addsubps256, "V8fV8fV8f", "", "avx") +TARGET_BUILTIN(__builtin_ia32_haddpd256, "V4dV4dV4d", "", "avx") +TARGET_BUILTIN(__builtin_ia32_hsubps256, "V8fV8fV8f", "", "avx") +TARGET_BUILTIN(__builtin_ia32_hsubpd256, "V4dV4dV4d", "", "avx") +TARGET_BUILTIN(__builtin_ia32_haddps256, "V8fV8fV8f", "", "avx") +TARGET_BUILTIN(__builtin_ia32_maxpd256, "V4dV4dV4d", "", "avx") +TARGET_BUILTIN(__builtin_ia32_maxps256, "V8fV8fV8f", "", "avx") +TARGET_BUILTIN(__builtin_ia32_minpd256, "V4dV4dV4d", "", "avx") +TARGET_BUILTIN(__builtin_ia32_minps256, "V8fV8fV8f", "", "avx") +TARGET_BUILTIN(__builtin_ia32_vpermilvarpd, "V2dV2dV2LLi", "", "avx") +TARGET_BUILTIN(__builtin_ia32_vpermilvarps, "V4fV4fV4i", "", "avx") +TARGET_BUILTIN(__builtin_ia32_vpermilvarpd256, "V4dV4dV4LLi", "", "avx") +TARGET_BUILTIN(__builtin_ia32_vpermilvarps256, "V8fV8fV8i", "", "avx") +TARGET_BUILTIN(__builtin_ia32_blendvpd256, "V4dV4dV4dV4d", "", "avx") +TARGET_BUILTIN(__builtin_ia32_blendvps256, "V8fV8fV8fV8f", "", "avx") +TARGET_BUILTIN(__builtin_ia32_dpps256, "V8fV8fV8fIc", "", "avx") +TARGET_BUILTIN(__builtin_ia32_cmppd256, "V4dV4dV4dIc", "", "avx") +TARGET_BUILTIN(__builtin_ia32_cmpps256, "V8fV8fV8fIc", "", "avx") +TARGET_BUILTIN(__builtin_ia32_cvtdq2pd256, "V4dV4i", "", "avx") +TARGET_BUILTIN(__builtin_ia32_cvtdq2ps256, "V8fV8i", "", "avx") +TARGET_BUILTIN(__builtin_ia32_cvtpd2ps256, "V4fV4d", "", "avx") +TARGET_BUILTIN(__builtin_ia32_cvtps2dq256, "V8iV8f", "", "avx") +TARGET_BUILTIN(__builtin_ia32_cvtps2pd256, "V4dV4f", "", "avx") +TARGET_BUILTIN(__builtin_ia32_cvttpd2dq256, "V4iV4d", "", "avx") +TARGET_BUILTIN(__builtin_ia32_cvtpd2dq256, "V4iV4d", "", "avx") +TARGET_BUILTIN(__builtin_ia32_cvttps2dq256, "V8iV8f", "", "avx") +TARGET_BUILTIN(__builtin_ia32_vperm2f128_pd256, "V4dV4dV4dIc", "", "avx") +TARGET_BUILTIN(__builtin_ia32_vperm2f128_ps256, "V8fV8fV8fIc", "", "avx") +TARGET_BUILTIN(__builtin_ia32_vperm2f128_si256, "V8iV8iV8iIc", "", "avx") +TARGET_BUILTIN(__builtin_ia32_sqrtpd256, "V4dV4d", "", "avx") +TARGET_BUILTIN(__builtin_ia32_sqrtps256, "V8fV8f", "", "avx") +TARGET_BUILTIN(__builtin_ia32_rsqrtps256, "V8fV8f", "", "avx") +TARGET_BUILTIN(__builtin_ia32_rcpps256, "V8fV8f", "", "avx") +TARGET_BUILTIN(__builtin_ia32_roundpd256, "V4dV4dIi", "", "avx") +TARGET_BUILTIN(__builtin_ia32_roundps256, "V8fV8fIi", "", "avx") +TARGET_BUILTIN(__builtin_ia32_vtestzpd, "iV2dV2d", "", "avx") +TARGET_BUILTIN(__builtin_ia32_vtestcpd, "iV2dV2d", "", "avx") +TARGET_BUILTIN(__builtin_ia32_vtestnzcpd, "iV2dV2d", "", "avx") +TARGET_BUILTIN(__builtin_ia32_vtestzps, "iV4fV4f", "", "avx") +TARGET_BUILTIN(__builtin_ia32_vtestcps, "iV4fV4f", "", "avx") +TARGET_BUILTIN(__builtin_ia32_vtestnzcps, "iV4fV4f", "", "avx") +TARGET_BUILTIN(__builtin_ia32_vtestzpd256, "iV4dV4d", "", "avx") +TARGET_BUILTIN(__builtin_ia32_vtestcpd256, "iV4dV4d", "", "avx") +TARGET_BUILTIN(__builtin_ia32_vtestnzcpd256, "iV4dV4d", "", "avx") +TARGET_BUILTIN(__builtin_ia32_vtestzps256, "iV8fV8f", "", "avx") +TARGET_BUILTIN(__builtin_ia32_vtestcps256, "iV8fV8f", "", "avx") +TARGET_BUILTIN(__builtin_ia32_vtestnzcps256, "iV8fV8f", "", "avx") +TARGET_BUILTIN(__builtin_ia32_ptestz256, "iV4LLiV4LLi", "", "avx") +TARGET_BUILTIN(__builtin_ia32_ptestc256, "iV4LLiV4LLi", "", "avx") +TARGET_BUILTIN(__builtin_ia32_ptestnzc256, "iV4LLiV4LLi", "", "avx") +TARGET_BUILTIN(__builtin_ia32_movmskpd256, "iV4d", "", "avx") +TARGET_BUILTIN(__builtin_ia32_movmskps256, "iV8f", "", "avx") +TARGET_BUILTIN(__builtin_ia32_vzeroall, "v", "", "avx") +TARGET_BUILTIN(__builtin_ia32_vzeroupper, "v", "", "avx") +TARGET_BUILTIN(__builtin_ia32_vbroadcastf128_pd256, "V4dV2dC*", "", "avx") +TARGET_BUILTIN(__builtin_ia32_vbroadcastf128_ps256, "V8fV4fC*", "", "avx") +TARGET_BUILTIN(__builtin_ia32_storeupd256, "vd*V4d", "", "avx") +TARGET_BUILTIN(__builtin_ia32_storeups256, "vf*V8f", "", "avx") +TARGET_BUILTIN(__builtin_ia32_storedqu256, "vc*V32c", "", "avx") +TARGET_BUILTIN(__builtin_ia32_lddqu256, "V32ccC*", "", "avx") +TARGET_BUILTIN(__builtin_ia32_movntdq256, "vV4LLi*V4LLi", "", "avx") +TARGET_BUILTIN(__builtin_ia32_movntpd256, "vd*V4d", "", "avx") +TARGET_BUILTIN(__builtin_ia32_movntps256, "vf*V8f", "", "avx") +TARGET_BUILTIN(__builtin_ia32_maskloadpd, "V2dV2dC*V2LLi", "", "avx") +TARGET_BUILTIN(__builtin_ia32_maskloadps, "V4fV4fC*V4i", "", "avx") +TARGET_BUILTIN(__builtin_ia32_maskloadpd256, "V4dV4dC*V4LLi", "", "avx") +TARGET_BUILTIN(__builtin_ia32_maskloadps256, "V8fV8fC*V8i", "", "avx") +TARGET_BUILTIN(__builtin_ia32_maskstorepd, "vV2d*V2LLiV2d", "", "avx") +TARGET_BUILTIN(__builtin_ia32_maskstoreps, "vV4f*V4iV4f", "", "avx") +TARGET_BUILTIN(__builtin_ia32_maskstorepd256, "vV4d*V4LLiV4d", "", "avx") +TARGET_BUILTIN(__builtin_ia32_maskstoreps256, "vV8f*V8iV8f", "", "avx") + +// AVX2 +TARGET_BUILTIN(__builtin_ia32_mpsadbw256, "V32cV32cV32cIc", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pabsb256, "V32cV32c", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pabsw256, "V16sV16s", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pabsd256, "V8iV8i", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_packsswb256, "V32cV16sV16s", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_packssdw256, "V16sV8iV8i", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_packuswb256, "V32cV16sV16s", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_packusdw256, "V16sV8iV8i", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_paddsb256, "V32cV32cV32c", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_paddsw256, "V16sV16sV16s", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psubsb256, "V32cV32cV32c", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psubsw256, "V16sV16sV16s", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_paddusb256, "V32cV32cV32c", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_paddusw256, "V16sV16sV16s", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psubusb256, "V32cV32cV32c", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psubusw256, "V16sV16sV16s", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_palignr256, "V32cV32cV32cIc", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pavgb256, "V32cV32cV32c", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pavgw256, "V16sV16sV16s", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pblendvb256, "V32cV32cV32cV32c", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_phaddw256, "V16sV16sV16s", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_phaddd256, "V8iV8iV8i", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_phaddsw256, "V16sV16sV16s", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_phsubw256, "V16sV16sV16s", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_phsubd256, "V8iV8iV8i", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_phsubsw256, "V16sV16sV16s", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pmaddubsw256, "V16sV32cV32c", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pmaddwd256, "V8iV16sV16s", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pmaxub256, "V32cV32cV32c", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pmaxuw256, "V16sV16sV16s", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pmaxud256, "V8iV8iV8i", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pmaxsb256, "V32cV32cV32c", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pmaxsw256, "V16sV16sV16s", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pmaxsd256, "V8iV8iV8i", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pminub256, "V32cV32cV32c", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pminuw256, "V16sV16sV16s", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pminud256, "V8iV8iV8i", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pminsb256, "V32cV32cV32c", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pminsw256, "V16sV16sV16s", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pminsd256, "V8iV8iV8i", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pmovmskb256, "iV32c", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pmovsxbw256, "V16sV16c", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pmovsxbd256, "V8iV16c", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pmovsxbq256, "V4LLiV16c", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pmovsxwd256, "V8iV8s", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pmovsxwq256, "V4LLiV8s", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pmovsxdq256, "V4LLiV4i", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pmovzxbw256, "V16sV16c", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pmovzxbd256, "V8iV16c", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pmovzxbq256, "V4LLiV16c", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pmovzxwd256, "V8iV8s", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pmovzxwq256, "V4LLiV8s", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pmovzxdq256, "V4LLiV4i", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pmuldq256, "V4LLiV8iV8i", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pmulhrsw256, "V16sV16sV16s", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pmulhuw256, "V16sV16sV16s", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pmulhw256, "V16sV16sV16s", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pmuludq256, "V4LLiV8iV8i", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psadbw256, "V4LLiV32cV32c", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pshufb256, "V32cV32cV32c", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psignb256, "V32cV32cV32c", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psignw256, "V16sV16sV16s", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psignd256, "V8iV8iV8i", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pslldqi256, "V4LLiV4LLiIi", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psllwi256, "V16sV16si", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psllw256, "V16sV16sV8s", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pslldi256, "V8iV8ii", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_pslld256, "V8iV8iV4i", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psllqi256, "V4LLiV4LLii", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psllq256, "V4LLiV4LLiV2LLi", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psrawi256, "V16sV16si", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psraw256, "V16sV16sV8s", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psradi256, "V8iV8ii", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psrad256, "V8iV8iV4i", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psrldqi256, "V4LLiV4LLiIi", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psrlwi256, "V16sV16si", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psrlw256, "V16sV16sV8s", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psrldi256, "V8iV8ii", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psrld256, "V8iV8iV4i", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psrlqi256, "V4LLiV4LLii", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psrlq256, "V4LLiV4LLiV2LLi", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_movntdqa256, "V4LLiV4LLiC*", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_permvarsi256, "V8iV8iV8i", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_permvarsf256, "V8fV8fV8i", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_permti256, "V4LLiV4LLiV4LLiIc", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_maskloadd256, "V8iV8iC*V8i", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_maskloadq256, "V4LLiV4LLiC*V4LLi", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_maskloadd, "V4iV4iC*V4i", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_maskloadq, "V2LLiV2LLiC*V2LLi", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_maskstored256, "vV8i*V8iV8i", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_maskstoreq256, "vV4LLi*V4LLiV4LLi", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_maskstored, "vV4i*V4iV4i", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_maskstoreq, "vV2LLi*V2LLiV2LLi", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psllv8si, "V8iV8iV8i", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psllv4si, "V4iV4iV4i", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psllv4di, "V4LLiV4LLiV4LLi", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psllv2di, "V2LLiV2LLiV2LLi", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psrav8si, "V8iV8iV8i", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psrav4si, "V4iV4iV4i", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psrlv8si, "V8iV8iV8i", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psrlv4si, "V4iV4iV4i", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psrlv4di, "V4LLiV4LLiV4LLi", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_psrlv2di, "V2LLiV2LLiV2LLi", "", "avx2") + +// GATHER +TARGET_BUILTIN(__builtin_ia32_gatherd_pd, "V2dV2ddC*V4iV2dIc", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_gatherd_pd256, "V4dV4ddC*V4iV4dIc", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_gatherq_pd, "V2dV2ddC*V2LLiV2dIc", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_gatherq_pd256, "V4dV4ddC*V4LLiV4dIc", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_gatherd_ps, "V4fV4ffC*V4iV4fIc", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_gatherd_ps256, "V8fV8ffC*V8iV8fIc", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_gatherq_ps, "V4fV4ffC*V2LLiV4fIc", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_gatherq_ps256, "V4fV4ffC*V4LLiV4fIc", "", "avx2") + +TARGET_BUILTIN(__builtin_ia32_gatherd_q, "V2LLiV2LLiLLiC*V4iV2LLiIc", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_gatherd_q256, "V4LLiV4LLiLLiC*V4iV4LLiIc", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_gatherq_q, "V2LLiV2LLiLLiC*V2LLiV2LLiIc", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_gatherq_q256, "V4LLiV4LLiLLiC*V4LLiV4LLiIc", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_gatherd_d, "V4iV4iiC*V4iV4iIc", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_gatherd_d256, "V8iV8iiC*V8iV8iIc", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_gatherq_d, "V4iV4iiC*V2LLiV4iIc", "", "avx2") +TARGET_BUILTIN(__builtin_ia32_gatherq_d256, "V4iV4iiC*V4LLiV4iIc", "", "avx2") + +// F16C +TARGET_BUILTIN(__builtin_ia32_vcvtps2ph, "V8sV4fIi", "", "f16c") +TARGET_BUILTIN(__builtin_ia32_vcvtps2ph256, "V8sV8fIi", "", "f16c") +TARGET_BUILTIN(__builtin_ia32_vcvtps2ph512, "V16sV16fIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_vcvtph2ps, "V4fV8s", "", "f16c") +TARGET_BUILTIN(__builtin_ia32_vcvtph2ps256, "V8fV8s", "", "f16c") +TARGET_BUILTIN(__builtin_ia32_vcvtph2ps512, "V16fV16s", "", "avx512f") + +// RDRAND +TARGET_BUILTIN(__builtin_ia32_rdrand16_step, "UiUs*", "", "rdrnd") +TARGET_BUILTIN(__builtin_ia32_rdrand32_step, "UiUi*", "", "rdrnd") +TARGET_BUILTIN(__builtin_ia32_rdrand64_step, "UiULLi*", "", "rdrnd") + +// FSGSBASE +TARGET_BUILTIN(__builtin_ia32_rdfsbase32, "Ui", "", "fsgsbase") +TARGET_BUILTIN(__builtin_ia32_rdfsbase64, "ULLi", "", "fsgsbase") +TARGET_BUILTIN(__builtin_ia32_rdgsbase32, "Ui", "", "fsgsbase") +TARGET_BUILTIN(__builtin_ia32_rdgsbase64, "ULLi", "", "fsgsbase") +TARGET_BUILTIN(__builtin_ia32_wrfsbase32, "vUi", "", "fsgsbase") +TARGET_BUILTIN(__builtin_ia32_wrfsbase64, "vULLi", "", "fsgsbase") +TARGET_BUILTIN(__builtin_ia32_wrgsbase32, "vUi", "", "fsgsbase") +TARGET_BUILTIN(__builtin_ia32_wrgsbase64, "vULLi", "", "fsgsbase") + +// FXSR +TARGET_BUILTIN(__builtin_ia32_fxrstor, "vv*", "", "fxsr") +TARGET_BUILTIN(__builtin_ia32_fxrstor64, "vv*", "", "fxsr") +TARGET_BUILTIN(__builtin_ia32_fxsave, "vv*", "", "fxsr") +TARGET_BUILTIN(__builtin_ia32_fxsave64, "vv*", "", "fxsr") + +// XSAVE +TARGET_BUILTIN(__builtin_ia32_xsave, "vv*ULLi", "", "xsave") +TARGET_BUILTIN(__builtin_ia32_xsave64, "vv*ULLi", "", "xsave") +TARGET_BUILTIN(__builtin_ia32_xrstor, "vv*ULLi", "", "xsave") +TARGET_BUILTIN(__builtin_ia32_xrstor64, "vv*ULLi", "", "xsave") +TARGET_BUILTIN(__builtin_ia32_xsaveopt, "vv*ULLi", "", "xsaveopt") +TARGET_BUILTIN(__builtin_ia32_xsaveopt64, "vv*ULLi", "", "xsaveopt") +TARGET_BUILTIN(__builtin_ia32_xrstors, "vv*ULLi", "", "xsaves") +TARGET_BUILTIN(__builtin_ia32_xrstors64, "vv*ULLi", "", "xsaves") +TARGET_BUILTIN(__builtin_ia32_xsavec, "vv*ULLi", "", "xsavec") +TARGET_BUILTIN(__builtin_ia32_xsavec64, "vv*ULLi", "", "xsavec") +TARGET_BUILTIN(__builtin_ia32_xsaves, "vv*ULLi", "", "xsaves") +TARGET_BUILTIN(__builtin_ia32_xsaves64, "vv*ULLi", "", "xsaves") + +// ADX +TARGET_BUILTIN(__builtin_ia32_addcarryx_u32, "UcUcUiUiUi*", "", "adx") +TARGET_BUILTIN(__builtin_ia32_addcarryx_u64, "UcUcULLiULLiULLi*", "", "adx") +TARGET_BUILTIN(__builtin_ia32_addcarry_u32, "UcUcUiUiUi*", "", "adx") +TARGET_BUILTIN(__builtin_ia32_addcarry_u64, "UcUcULLiULLiULLi*", "", "adx") +TARGET_BUILTIN(__builtin_ia32_subborrow_u32, "UcUcUiUiUi*", "", "adx") +TARGET_BUILTIN(__builtin_ia32_subborrow_u64, "UcUcULLiULLiULLi*", "", "adx") + +// RDSEED +TARGET_BUILTIN(__builtin_ia32_rdseed16_step, "UiUs*", "", "rdseed") +TARGET_BUILTIN(__builtin_ia32_rdseed32_step, "UiUi*", "", "rdseed") +TARGET_BUILTIN(__builtin_ia32_rdseed64_step, "UiULLi*", "", "rdseed") + +// BMI +TARGET_BUILTIN(__builtin_ia32_bextr_u32, "UiUiUi", "", "bmi") +TARGET_BUILTIN(__builtin_ia32_bextr_u64, "ULLiULLiULLi", "", "bmi") + +// BMI2 +TARGET_BUILTIN(__builtin_ia32_bzhi_si, "UiUiUi", "", "bmi2") +TARGET_BUILTIN(__builtin_ia32_bzhi_di, "ULLiULLiULLi", "", "bmi2") +TARGET_BUILTIN(__builtin_ia32_pdep_si, "UiUiUi", "", "bmi2") +TARGET_BUILTIN(__builtin_ia32_pdep_di, "ULLiULLiULLi", "", "bmi2") +TARGET_BUILTIN(__builtin_ia32_pext_si, "UiUiUi", "", "bmi2") +TARGET_BUILTIN(__builtin_ia32_pext_di, "ULLiULLiULLi", "", "bmi2") + +// TBM +TARGET_BUILTIN(__builtin_ia32_bextri_u32, "UiUiIUi", "", "tbm") +TARGET_BUILTIN(__builtin_ia32_bextri_u64, "ULLiULLiIULLi", "", "tbm") + +// SHA +TARGET_BUILTIN(__builtin_ia32_sha1rnds4, "V4iV4iV4iIc", "", "sha") +TARGET_BUILTIN(__builtin_ia32_sha1nexte, "V4iV4iV4i", "", "sha") +TARGET_BUILTIN(__builtin_ia32_sha1msg1, "V4iV4iV4i", "", "sha") +TARGET_BUILTIN(__builtin_ia32_sha1msg2, "V4iV4iV4i", "", "sha") +TARGET_BUILTIN(__builtin_ia32_sha256rnds2, "V4iV4iV4iV4i", "", "sha") +TARGET_BUILTIN(__builtin_ia32_sha256msg1, "V4iV4iV4i", "", "sha") +TARGET_BUILTIN(__builtin_ia32_sha256msg2, "V4iV4iV4i", "", "sha") + +// FMA +TARGET_BUILTIN(__builtin_ia32_vfmaddps, "V4fV4fV4fV4f", "", "fma|fma4") +TARGET_BUILTIN(__builtin_ia32_vfmaddpd, "V2dV2dV2dV2d", "", "fma|fma4") +TARGET_BUILTIN(__builtin_ia32_vfmaddss, "V4fV4fV4fV4f", "", "fma|fma4") +TARGET_BUILTIN(__builtin_ia32_vfmaddsd, "V2dV2dV2dV2d", "", "fma|fma4") +TARGET_BUILTIN(__builtin_ia32_vfmsubps, "V4fV4fV4fV4f", "", "fma|fma4") +TARGET_BUILTIN(__builtin_ia32_vfmsubpd, "V2dV2dV2dV2d", "", "fma|fma4") +TARGET_BUILTIN(__builtin_ia32_vfmsubss, "V4fV4fV4fV4f", "", "fma|fma4") +TARGET_BUILTIN(__builtin_ia32_vfmsubsd, "V2dV2dV2dV2d", "", "fma|fma4") +TARGET_BUILTIN(__builtin_ia32_vfnmaddps, "V4fV4fV4fV4f", "", "fma|fma4") +TARGET_BUILTIN(__builtin_ia32_vfnmaddpd, "V2dV2dV2dV2d", "", "fma|fma4") +TARGET_BUILTIN(__builtin_ia32_vfnmaddss, "V4fV4fV4fV4f", "", "fma|fma4") +TARGET_BUILTIN(__builtin_ia32_vfnmaddsd, "V2dV2dV2dV2d", "", "fma|fma4") +TARGET_BUILTIN(__builtin_ia32_vfnmsubps, "V4fV4fV4fV4f", "", "fma|fma4") +TARGET_BUILTIN(__builtin_ia32_vfnmsubpd, "V2dV2dV2dV2d", "", "fma|fma4") +TARGET_BUILTIN(__builtin_ia32_vfnmsubss, "V4fV4fV4fV4f", "", "fma|fma4") +TARGET_BUILTIN(__builtin_ia32_vfnmsubsd, "V2dV2dV2dV2d", "", "fma|fma4") +TARGET_BUILTIN(__builtin_ia32_vfmaddsubps, "V4fV4fV4fV4f", "", "fma|fma4") +TARGET_BUILTIN(__builtin_ia32_vfmaddsubpd, "V2dV2dV2dV2d", "", "fma|fma4") +TARGET_BUILTIN(__builtin_ia32_vfmsubaddps, "V4fV4fV4fV4f", "", "fma|fma4") +TARGET_BUILTIN(__builtin_ia32_vfmsubaddpd, "V2dV2dV2dV2d", "", "fma|fma4") +TARGET_BUILTIN(__builtin_ia32_vfmaddps256, "V8fV8fV8fV8f", "", "fma|fma4") +TARGET_BUILTIN(__builtin_ia32_vfmaddpd256, "V4dV4dV4dV4d", "", "fma|fma4") +TARGET_BUILTIN(__builtin_ia32_vfmsubps256, "V8fV8fV8fV8f", "", "fma|fma4") +TARGET_BUILTIN(__builtin_ia32_vfmsubpd256, "V4dV4dV4dV4d", "", "fma|fma4") +TARGET_BUILTIN(__builtin_ia32_vfnmaddps256, "V8fV8fV8fV8f", "", "fma|fma4") +TARGET_BUILTIN(__builtin_ia32_vfnmaddpd256, "V4dV4dV4dV4d", "", "fma|fma4") +TARGET_BUILTIN(__builtin_ia32_vfnmsubps256, "V8fV8fV8fV8f", "", "fma|fma4") +TARGET_BUILTIN(__builtin_ia32_vfnmsubpd256, "V4dV4dV4dV4d", "", "fma|fma4") +TARGET_BUILTIN(__builtin_ia32_vfmaddsubps256, "V8fV8fV8fV8f", "", "fma|fma4") +TARGET_BUILTIN(__builtin_ia32_vfmaddsubpd256, "V4dV4dV4dV4d", "", "fma|fma4") +TARGET_BUILTIN(__builtin_ia32_vfmsubaddps256, "V8fV8fV8fV8f", "", "fma|fma4") +TARGET_BUILTIN(__builtin_ia32_vfmsubaddpd256, "V4dV4dV4dV4d", "", "fma|fma4") + +TARGET_BUILTIN(__builtin_ia32_vfmaddpd128_mask, "V2dV2dV2dV2dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmaddpd128_mask3, "V2dV2dV2dV2dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmaddpd128_maskz, "V2dV2dV2dV2dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmaddpd256_mask, "V4dV4dV4dV4dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmaddpd256_mask3, "V4dV4dV4dV4dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmaddpd256_maskz, "V4dV4dV4dV4dUc", "", "avx512vl") + +TARGET_BUILTIN(__builtin_ia32_vfmaddpd512_mask, "V8dV8dV8dV8dUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_vfmaddpd512_mask3, "V8dV8dV8dV8dUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_vfmaddpd512_maskz, "V8dV8dV8dV8dUcIi", "", "avx512f") + +TARGET_BUILTIN(__builtin_ia32_vfmaddps128_mask, "V4fV4fV4fV4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmaddps128_mask3, "V4fV4fV4fV4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmaddps128_maskz, "V4fV4fV4fV4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmaddps256_mask, "V8fV8fV8fV8fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmaddps256_mask3, "V8fV8fV8fV8fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmaddps256_maskz, "V8fV8fV8fV8fUc", "", "avx512vl") + +TARGET_BUILTIN(__builtin_ia32_vfmaddps512_mask, "V16fV16fV16fV16fUsIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_vfmaddps512_mask3, "V16fV16fV16fV16fUsIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_vfmaddps512_maskz, "V16fV16fV16fV16fUsIi", "", "avx512f") + +TARGET_BUILTIN(__builtin_ia32_vfmaddsubpd128_mask, "V2dV2dV2dV2dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmaddsubpd128_mask3, "V2dV2dV2dV2dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmaddsubpd128_maskz, "V2dV2dV2dV2dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmaddsubpd256_mask, "V4dV4dV4dV4dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmaddsubpd256_mask3, "V4dV4dV4dV4dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmaddsubpd256_maskz, "V4dV4dV4dV4dUc", "", "avx512vl") + +TARGET_BUILTIN(__builtin_ia32_vfmaddsubpd512_mask, "V8dV8dV8dV8dUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_vfmaddsubpd512_mask3, "V8dV8dV8dV8dUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_vfmaddsubpd512_maskz, "V8dV8dV8dV8dUcIi", "", "avx512f") + +TARGET_BUILTIN(__builtin_ia32_vfmaddsubps128_mask, "V4fV4fV4fV4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmaddsubps128_mask3, "V4fV4fV4fV4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmaddsubps128_maskz, "V4fV4fV4fV4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmaddsubps256_mask, "V8fV8fV8fV8fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmaddsubps256_mask3, "V8fV8fV8fV8fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmaddsubps256_maskz, "V8fV8fV8fV8fUc", "", "avx512vl") + +TARGET_BUILTIN(__builtin_ia32_vfmaddsubps512_mask, "V16fV16fV16fV16fUsIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_vfmaddsubps512_mask3, "V16fV16fV16fV16fUsIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_vfmaddsubps512_maskz, "V16fV16fV16fV16fUsIi", "", "avx512f") + +TARGET_BUILTIN(__builtin_ia32_vfmsubpd128_mask3, "V2dV2dV2dV2dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmsubpd256_mask3, "V4dV4dV4dV4dUc", "", "avx512vl") + +TARGET_BUILTIN(__builtin_ia32_vfmsubpd512_mask3, "V8dV8dV8dV8dUcIi", "", "avx512f") + +TARGET_BUILTIN(__builtin_ia32_vfmsubps128_mask3, "V4fV4fV4fV4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmsubps256_mask3, "V8fV8fV8fV8fUc", "", "avx512vl") + +TARGET_BUILTIN(__builtin_ia32_vfmsubps512_mask3, "V16fV16fV16fV16fUsIi", "", "avx512f") + +TARGET_BUILTIN(__builtin_ia32_vfmsubaddpd128_mask3, "V2dV2dV2dV2dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmsubaddpd256_mask3, "V4dV4dV4dV4dUc", "", "avx512vl") + +TARGET_BUILTIN(__builtin_ia32_vfmsubaddpd512_mask3, "V8dV8dV8dV8dUcIi", "", "avx512f") + +TARGET_BUILTIN(__builtin_ia32_vfmsubaddps128_mask3, "V4fV4fV4fV4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmsubaddps256_mask3, "V8fV8fV8fV8fUc", "", "avx512vl") + +TARGET_BUILTIN(__builtin_ia32_vfmsubaddps512_mask3, "V16fV16fV16fV16fUsIi", "", "avx512f") + +TARGET_BUILTIN(__builtin_ia32_vfnmaddpd128_mask, "V2dV2dV2dV2dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfnmaddpd256_mask, "V4dV4dV4dV4dUc", "", "avx512vl") + +TARGET_BUILTIN(__builtin_ia32_vfnmaddpd512_mask, "V8dV8dV8dV8dUcIi", "", "avx512f") + +TARGET_BUILTIN(__builtin_ia32_vfnmaddps128_mask, "V4fV4fV4fV4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfnmaddps256_mask, "V8fV8fV8fV8fUc", "", "avx512vl") + +TARGET_BUILTIN(__builtin_ia32_vfnmaddps512_mask, "V16fV16fV16fV16fUsIi", "", "avx512f") + +TARGET_BUILTIN(__builtin_ia32_vfnmsubpd128_mask, "V2dV2dV2dV2dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfnmsubpd128_mask3, "V2dV2dV2dV2dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfnmsubpd256_mask, "V4dV4dV4dV4dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfnmsubpd256_mask3, "V4dV4dV4dV4dUc", "", "avx512vl") + +TARGET_BUILTIN(__builtin_ia32_vfnmsubpd512_mask, "V8dV8dV8dV8dUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_vfnmsubpd512_mask3, "V8dV8dV8dV8dUcIi", "", "avx512f") + +TARGET_BUILTIN(__builtin_ia32_vfnmsubps128_mask, "V4fV4fV4fV4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfnmsubps128_mask3, "V4fV4fV4fV4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfnmsubps256_mask, "V8fV8fV8fV8fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfnmsubps256_mask3, "V8fV8fV8fV8fUc", "", "avx512vl") + +TARGET_BUILTIN(__builtin_ia32_vfnmsubps512_mask, "V16fV16fV16fV16fUsIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_vfnmsubps512_mask3, "V16fV16fV16fV16fUsIi", "", "avx512f") + +// XOP +TARGET_BUILTIN(__builtin_ia32_vpmacssww, "V8sV8sV8sV8s", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpmacsww, "V8sV8sV8sV8s", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpmacsswd, "V4iV8sV8sV4i", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpmacswd, "V4iV8sV8sV4i", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpmacssdd, "V4iV4iV4iV4i", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpmacsdd, "V4iV4iV4iV4i", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpmacssdql, "V2LLiV4iV4iV2LLi", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpmacsdql, "V2LLiV4iV4iV2LLi", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpmacssdqh, "V2LLiV4iV4iV2LLi", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpmacsdqh, "V2LLiV4iV4iV2LLi", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpmadcsswd, "V4iV8sV8sV4i", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpmadcswd, "V4iV8sV8sV4i", "", "xop") + +TARGET_BUILTIN(__builtin_ia32_vphaddbw, "V8sV16c", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vphaddbd, "V4iV16c", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vphaddbq, "V2LLiV16c", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vphaddwd, "V4iV8s", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vphaddwq, "V2LLiV8s", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vphadddq, "V2LLiV4i", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vphaddubw, "V8sV16c", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vphaddubd, "V4iV16c", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vphaddubq, "V2LLiV16c", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vphadduwd, "V4iV8s", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vphadduwq, "V2LLiV8s", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vphaddudq, "V2LLiV4i", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vphsubbw, "V8sV16c", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vphsubwd, "V4iV8s", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vphsubdq, "V2LLiV4i", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpcmov, "V2LLiV2LLiV2LLiV2LLi", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpcmov_256, "V4LLiV4LLiV4LLiV4LLi", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpperm, "V16cV16cV16cV16c", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vprotb, "V16cV16cV16c", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vprotw, "V8sV8sV8s", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vprotd, "V4iV4iV4i", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vprotq, "V2LLiV2LLiV2LLi", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vprotbi, "V16cV16cIc", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vprotwi, "V8sV8sIc", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vprotdi, "V4iV4iIc", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vprotqi, "V2LLiV2LLiIc", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpshlb, "V16cV16cV16c", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpshlw, "V8sV8sV8s", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpshld, "V4iV4iV4i", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpshlq, "V2LLiV2LLiV2LLi", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpshab, "V16cV16cV16c", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpshaw, "V8sV8sV8s", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpshad, "V4iV4iV4i", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpshaq, "V2LLiV2LLiV2LLi", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpcomub, "V16cV16cV16cIc", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpcomuw, "V8sV8sV8sIc", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpcomud, "V4iV4iV4iIc", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpcomuq, "V2LLiV2LLiV2LLiIc", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpcomb, "V16cV16cV16cIc", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpcomw, "V8sV8sV8sIc", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpcomd, "V4iV4iV4iIc", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpcomq, "V2LLiV2LLiV2LLiIc", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpermil2pd, "V2dV2dV2dV2LLiIc", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpermil2pd256, "V4dV4dV4dV4LLiIc", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpermil2ps, "V4fV4fV4fV4iIc", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vpermil2ps256, "V8fV8fV8fV8iIc", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vfrczss, "V4fV4f", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vfrczsd, "V2dV2d", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vfrczps, "V4fV4f", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vfrczpd, "V2dV2d", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vfrczps256, "V8fV8f", "", "xop") +TARGET_BUILTIN(__builtin_ia32_vfrczpd256, "V4dV4d", "", "xop") + +TARGET_BUILTIN(__builtin_ia32_xbegin, "i", "", "rtm") +TARGET_BUILTIN(__builtin_ia32_xend, "v", "", "rtm") +TARGET_BUILTIN(__builtin_ia32_xabort, "vIc", "", "rtm") +TARGET_BUILTIN(__builtin_ia32_xtest, "i", "", "rtm") + +BUILTIN(__builtin_ia32_rdpmc, "ULLii", "") +BUILTIN(__builtin_ia32_rdtsc, "ULLi", "") +BUILTIN(__builtin_ia32_rdtscp, "ULLiUi*", "") +// PKU +TARGET_BUILTIN(__builtin_ia32_rdpkru, "Ui", "", "pku") +TARGET_BUILTIN(__builtin_ia32_wrpkru, "vUi", "", "pku") + +// AVX-512 +TARGET_BUILTIN(__builtin_ia32_sqrtpd512_mask, "V8dV8dV8dUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_sqrtps512_mask, "V16fV16fV16fUsIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_rsqrt14sd, "V2dV2dV2dV2dUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_rsqrt14ss, "V4fV4fV4fV4fUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_rsqrt14pd512_mask, "V8dV8dV8dUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_rsqrt14ps512_mask, "V16fV16fV16fUs", "", "avx512f") + +TARGET_BUILTIN(__builtin_ia32_rsqrt28sd_round, "V2dV2dV2dV2dUcIi", "", "avx512er") +TARGET_BUILTIN(__builtin_ia32_rsqrt28ss_round, "V4fV4fV4fV4fUcIi", "", "avx512er") +TARGET_BUILTIN(__builtin_ia32_rsqrt28pd_mask, "V8dV8dV8dUcIi", "", "avx512er") +TARGET_BUILTIN(__builtin_ia32_rsqrt28ps_mask, "V16fV16fV16fUsIi", "", "avx512er") + +TARGET_BUILTIN(__builtin_ia32_rcp14sd, "V2dV2dV2dV2dUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_rcp14ss, "V4fV4fV4fV4fUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_rcp14pd512_mask, "V8dV8dV8dUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_rcp14ps512_mask, "V16fV16fV16fUs", "", "avx512f") + +TARGET_BUILTIN(__builtin_ia32_rcp28sd_round, "V2dV2dV2dV2dUcIi", "", "avx512er") +TARGET_BUILTIN(__builtin_ia32_rcp28ss_round, "V4fV4fV4fV4fUcIi", "", "avx512er") +TARGET_BUILTIN(__builtin_ia32_rcp28pd_mask, "V8dV8dV8dUcIi", "", "avx512er") +TARGET_BUILTIN(__builtin_ia32_rcp28ps_mask, "V16fV16fV16fUsIi", "", "avx512er") +TARGET_BUILTIN(__builtin_ia32_exp2pd_mask, "V8dV8dV8dUcIi", "", "avx512er") +TARGET_BUILTIN(__builtin_ia32_exp2ps_mask, "V16fV16fV16fUsIi", "", "avx512er") + +TARGET_BUILTIN(__builtin_ia32_cvttps2dq512_mask, "V16iV16fV16iUsIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_cvttps2udq512_mask, "V16iV16fV16iUsIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_cvttpd2dq512_mask, "V8iV8dV8iUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_cvttpd2udq512_mask, "V8iV8dV8iUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_cmpps512_mask, "UsV16fV16fIiUsIi", "", "avx512f") + +TARGET_BUILTIN(__builtin_ia32_cmpps256_mask, "UcV8fV8fIiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cmpps128_mask, "UcV4fV4fIiUc", "", "avx512vl") + +TARGET_BUILTIN(__builtin_ia32_pcmpeqb512_mask, "LLiV64cV64cLLi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_pcmpeqd512_mask, "sV16iV16is", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_pcmpeqq512_mask, "cV8LLiV8LLic", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_pcmpeqw512_mask, "iV32sV32si", "", "avx512bw") + +TARGET_BUILTIN(__builtin_ia32_pcmpeqb256_mask, "iV32cV32ci", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pcmpeqd256_mask, "cV8iV8ic", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pcmpeqq256_mask, "cV4LLiV4LLic", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pcmpeqw256_mask, "sV16sV16ss", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pcmpeqb128_mask, "sV16cV16cs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pcmpeqd128_mask, "cV4iV4ic", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pcmpeqq128_mask, "cV2LLiV2LLic", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pcmpeqw128_mask, "cV8sV8sc", "", "avx512vl,avx512bw") + +TARGET_BUILTIN(__builtin_ia32_pcmpgtb512_mask, "LLiV64cV64cLLi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_pcmpgtd512_mask, "sV16iV16is", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_pcmpgtq512_mask, "cV8LLiV8LLic", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_pcmpgtw512_mask, "iV32sV32si", "", "avx512bw") + +TARGET_BUILTIN(__builtin_ia32_pcmpgtb256_mask, "iV32cV32ci", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pcmpgtd256_mask, "cV8iV8ic", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pcmpgtq256_mask, "cV4LLiV4LLic", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pcmpgtw256_mask, "sV16sV16ss", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pcmpgtb128_mask, "sV16cV16cs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pcmpgtd128_mask, "cV4iV4ic", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pcmpgtq128_mask, "cV2LLiV2LLic", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pcmpgtw128_mask, "cV8sV8sc", "", "avx512vl,avx512bw") + +TARGET_BUILTIN(__builtin_ia32_cmppd512_mask, "UcV8dV8dIiUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_cmppd256_mask, "UcV4dV4dIiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cmppd128_mask, "UcV2dV2dIiUc", "", "avx512vl") + +TARGET_BUILTIN(__builtin_ia32_rndscaleps_mask, "V16fV16fIiV16fUsIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_rndscalepd_mask, "V8dV8dIiV8dUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_cvtps2dq512_mask, "V16iV16fV16iUsIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_cvtpd2dq512_mask, "V8iV8dV8iUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_cvtps2udq512_mask, "V16iV16fV16iUsIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_cvtpd2udq512_mask, "V8iV8dV8iUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_minps512_mask, "V16fV16fV16fV16fUsIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_minpd512_mask, "V8dV8dV8dV8dUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_maxps512_mask, "V16fV16fV16fV16fUsIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_maxpd512_mask, "V8dV8dV8dV8dUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_cvtdq2ps512_mask, "V16fV16iV16fUsIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_cvtudq2ps512_mask, "V16fV16iV16fUsIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_cvtdq2pd512_mask, "V8dV8iV8dUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_cvtudq2pd512_mask, "V8dV8iV8dUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_cvtpd2ps512_mask, "V8fV8dV8fUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_vcvtps2ph512_mask, "V16sV16fIiV16sUs", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_vcvtph2ps512_mask, "V16fV16sV16fUsIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_pandd512_mask, "V16iV16iV16iV16iUs", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_pandq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_pord512_mask, "V16iV16iV16iV16iUs", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_porq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_pxord512_mask, "V16iV16iV16iV16iUs", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_pxorq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_pabsd512_mask, "V16iV16iV16iUs", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_pabsq512_mask, "V8LLiV8LLiV8LLiUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_pmaxsd512_mask, "V16iV16iV16iV16iUs", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_pmaxsq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_pmaxud512_mask, "V16iV16iV16iV16iUs", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_pmaxuq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_pminsd512_mask, "V16iV16iV16iV16iUs", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_pminsq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_pminud512_mask, "V16iV16iV16iV16iUs", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_pminuq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_pmuldq512_mask, "V8LLiV16iV16iV8LLiUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_pmuludq512_mask, "V8LLiV16iV16iV8LLiUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_blendmd_512_mask, "V16iV16iV16iUs", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_blendmq_512_mask, "V8LLiV8LLiV8LLiUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_blendmps_512_mask, "V16fV16fV16fUs", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_blendmpd_512_mask, "V8dV8dV8dUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_ptestmd512, "UsV16iV16iUs", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_ptestmq512, "UcV8LLiV8LLiUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_pbroadcastd512_gpr_mask, "V16iiV16iUs", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_pbroadcastq512_gpr_mask, "V8LLiLLiV8LLiUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_pbroadcastq512_mem_mask, "V8LLiLLiV8LLiUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_loaddqusi512_mask, "V16ivC*V16iUs", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_loaddqudi512_mask, "V8LLivC*V8LLiUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_loadups512_mask, "V16fvC*V16fUs", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_loadaps512_mask, "V16fvC*V16fUs", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_loadupd512_mask, "V8dvC*V8dUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_loadapd512_mask, "V8dvC*V8dUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_storedqudi512_mask, "vv*V8LLiUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_storedqusi512_mask, "vv*V16iUs", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_storeupd512_mask, "vv*V8dUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_storeapd512_mask, "vv*V8dUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_storeups512_mask, "vv*V16fUs", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_storeaps512_mask, "vv*V16fUs", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_vpermt2vard512_mask, "V16iV16iV16iV16iUs", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_vpermt2varq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_vpermt2varps512_mask, "V16fV16iV16fV16fUs", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_vpermt2varpd512_mask, "V8dV8LLiV8dV8dUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_alignq512_mask, "V8LLiV8LLiV8LLiIiV8LLiUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_alignd512_mask, "V16iV16iV16iIiV16iUs", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_extractf64x4_mask, "V4dV8dIiV4dUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_extractf32x4_mask, "V4fV16fIiV4fUc", "", "avx512f") + +TARGET_BUILTIN(__builtin_ia32_gathersiv8df, "V8dV8dvC*V8iUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_gathersiv16sf, "V16fV16fvC*UsIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_gatherdiv8df, "V8dV8dvC*V8LLiUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_gatherdiv16sf, "V8fV8fvC*V8LLiUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_gathersiv8di, "V8LLiV8LLivC*V8iUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_gathersiv16si, "V16iV16ivC*UsIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_gatherdiv8di, "V8LLiV8LLivC*V8LLiUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_gatherdiv16si, "V8iV8ivC*V8LLiUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_scattersiv8df, "vv*UcV8iV8dIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_scattersiv16sf, "vv*UsV16iV16fIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_scatterdiv8df, "vv*UcV8LLiV8dIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_scatterdiv16sf, "vv*UcV8LLiV8fIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_scattersiv8di, "vv*UcV8iV8LLiIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_scattersiv16si, "vv*UsV16iV16iIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_scatterdiv8di, "vv*UcV8LLiV8LLiIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_scatterdiv16si, "vv*UcV8LLiV8iIi", "", "avx512f") + +TARGET_BUILTIN(__builtin_ia32_gatherpfdpd, "vUcV8ivC*IiIi", "", "avx512pf") +TARGET_BUILTIN(__builtin_ia32_gatherpfdps, "vUsV16ivC*IiIi", "", "avx512pf") +TARGET_BUILTIN(__builtin_ia32_gatherpfqpd, "vUcV8LLivC*IiIi", "", "avx512pf") +TARGET_BUILTIN(__builtin_ia32_gatherpfqps, "vUcV8LLivC*IiIi", "", "avx512pf") +TARGET_BUILTIN(__builtin_ia32_scatterpfdpd, "vUcV8iv*IiIi", "", "avx512pf") +TARGET_BUILTIN(__builtin_ia32_scatterpfdps, "vUsV16iv*IiIi", "", "avx512pf") +TARGET_BUILTIN(__builtin_ia32_scatterpfqpd, "vUcV8LLiv*IiIi", "", "avx512pf") +TARGET_BUILTIN(__builtin_ia32_scatterpfqps, "vUcV8LLiv*IiIi", "", "avx512pf") + +TARGET_BUILTIN(__builtin_ia32_knothi, "UsUs", "", "avx512f") + +TARGET_BUILTIN(__builtin_ia32_cmpb128_mask, "UsV16cV16cIiUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_cmpd128_mask, "UcV4iV4iIiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cmpq128_mask, "UcV2LLiV2LLiIiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cmpw128_mask, "UcV8sV8sIiUc", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_cmpb256_mask, "UiV32cV32cIiUi", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_cmpd256_mask, "UcV8iV8iIiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cmpq256_mask, "UcV4LLiV4LLiIiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cmpw256_mask, "UsV16sV16sIiUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_cmpb512_mask, "ULLiV64cV64cIiULLi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_cmpd512_mask, "UsV16iV16iIiUs", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_cmpq512_mask, "UcV8LLiV8LLiIiUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_cmpw512_mask, "UiV32sV32sIiUi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_ucmpb128_mask, "UsV16cV16cIiUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_ucmpd128_mask, "UcV4iV4iIiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_ucmpq128_mask, "UcV2LLiV2LLiIiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_ucmpw128_mask, "UcV8sV8sIiUc", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_ucmpb256_mask, "UiV32cV32cIiUi", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_ucmpd256_mask, "UcV8iV8iIiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_ucmpq256_mask, "UcV4LLiV4LLiIiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_ucmpw256_mask, "UsV16sV16sIiUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_ucmpb512_mask, "ULLiV64cV64cIiULLi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_ucmpd512_mask, "UsV16iV16iIiUs", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_ucmpq512_mask, "UcV8LLiV8LLiIiUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_ucmpw512_mask, "UiV32sV32sIiUi", "", "avx512bw") + +TARGET_BUILTIN(__builtin_ia32_paddd256_mask, "V8iV8iV8iV8iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_paddq256_mask, "V4LLiV4LLiV4LLiV4LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_psubd256_mask, "V8iV8iV8iV8iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_psubq256_mask, "V4LLiV4LLiV4LLiV4LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_paddd128_mask, "V4iV4iV4iV4iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_paddq128_mask, "V2LLiV2LLiV2LLiV2LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_psubd128_mask, "V4iV4iV4iV4iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_psubq128_mask, "V2LLiV2LLiV2LLiV2LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pmuldq256_mask, "V4LLiV8iV8iV4LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pmuldq128_mask, "V2LLiV4iV4iV2LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pmuludq256_mask, "V4LLiV8iV8iV4LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pmuludq128_mask, "V2LLiV4iV4iV2LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pmulld256_mask, "V8iV8iV8iV8iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pmulld128_mask, "V4iV4iV4iV4iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pandd256_mask, "V8iV8iV8iV8iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pandd128_mask, "V4iV4iV4iV4iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pandnd256_mask, "V8iV8iV8iV8iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pandnd128_mask, "V4iV4iV4iV4iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pord256_mask, "V8iV8iV8iV8iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pord128_mask, "V4iV4iV4iV4iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pxord256_mask, "V8iV8iV8iV8iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pxord128_mask, "V4iV4iV4iV4iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pandq256_mask, "V4LLiV4LLiV4LLiV4LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pandq128_mask, "V2LLiV2LLiV2LLiV2LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pandnq256_mask, "V4LLiV4LLiV4LLiV4LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pandnq128_mask, "V2LLiV2LLiV2LLiV2LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_porq256_mask, "V4LLiV4LLiV4LLiV4LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_porq128_mask, "V2LLiV2LLiV2LLiV2LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pxorq256_mask, "V4LLiV4LLiV4LLiV4LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pxorq128_mask, "V2LLiV2LLiV2LLiV2LLiUc", "", "avx512vl") + +TARGET_BUILTIN(__builtin_ia32_paddb512_mask, "V64cV64cV64cV64cULLi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_psubb512_mask, "V64cV64cV64cV64cULLi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_paddw512_mask, "V32sV32sV32sV32sUi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_psubw512_mask, "V32sV32sV32sV32sUi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmullw512_mask, "V32sV32sV32sV32sUi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_paddb256_mask, "V32cV32cV32cV32cUi", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_paddw256_mask, "V16sV16sV16sV16sUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_psubb256_mask, "V32cV32cV32cV32cUi", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_psubw256_mask, "V16sV16sV16sV16sUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_paddb128_mask, "V16cV16cV16cV16cUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_paddw128_mask, "V8sV8sV8sV8sUc", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_psubb128_mask, "V16cV16cV16cV16cUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_psubw128_mask, "V8sV8sV8sV8sUc", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmullw256_mask, "V16sV16sV16sV16sUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmullw128_mask, "V8sV8sV8sV8sUc", "", "avx512vl,avx512bw") + +TARGET_BUILTIN(__builtin_ia32_pandnd512_mask, "V16iV16iV16iV16iUs", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_pandnq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_paddq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_psubq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_paddd512_mask, "V16iV16iV16iV16iUs", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_psubd512_mask, "V16iV16iV16iV16iUs", "", "avx512f") + +TARGET_BUILTIN(__builtin_ia32_pmulld512_mask, "V16iV16iV16iV16iUs", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_pmullq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "", "avx512dq") +TARGET_BUILTIN(__builtin_ia32_xorpd512_mask, "V8dV8dV8dV8dUc", "", "avx512dq") +TARGET_BUILTIN(__builtin_ia32_xorps512_mask, "V16fV16fV16fV16fUs", "", "avx512dq") +TARGET_BUILTIN(__builtin_ia32_orpd512_mask, "V8dV8dV8dV8dUc", "", "avx512dq") +TARGET_BUILTIN(__builtin_ia32_orps512_mask, "V16fV16fV16fV16fUs", "", "avx512dq") +TARGET_BUILTIN(__builtin_ia32_andpd512_mask, "V8dV8dV8dV8dUc", "", "avx512dq") +TARGET_BUILTIN(__builtin_ia32_andps512_mask, "V16fV16fV16fV16fUs", "", "avx512dq") +TARGET_BUILTIN(__builtin_ia32_andnpd512_mask, "V8dV8dV8dV8dUc", "", "avx512dq") +TARGET_BUILTIN(__builtin_ia32_andnps512_mask, "V16fV16fV16fV16fUs", "", "avx512dq") +TARGET_BUILTIN(__builtin_ia32_pmullq256_mask, "V4LLiV4LLiV4LLiV4LLiUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_pmullq128_mask, "V2LLiV2LLiV2LLiV2LLiUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_andnpd256_mask, "V4dV4dV4dV4dUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_andnpd128_mask, "V2dV2dV2dV2dUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_andnps256_mask, "V8fV8fV8fV8fUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_andnps128_mask, "V4fV4fV4fV4fUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_andpd256_mask, "V4dV4dV4dV4dUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_andpd128_mask, "V2dV2dV2dV2dUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_andps256_mask, "V8fV8fV8fV8fUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_andps128_mask, "V4fV4fV4fV4fUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_xorpd256_mask, "V4dV4dV4dV4dUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_xorpd128_mask, "V2dV2dV2dV2dUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_xorps256_mask, "V8fV8fV8fV8fUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_xorps128_mask, "V4fV4fV4fV4fUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_orpd256_mask, "V4dV4dV4dV4dUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_orpd128_mask, "V2dV2dV2dV2dUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_orps256_mask, "V8fV8fV8fV8fUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_orps128_mask, "V4fV4fV4fV4fUc", "", "avx512vl,avx512dq") + +TARGET_BUILTIN(__builtin_ia32_blendmb_512_mask, "V64cV64cV64cULLi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_blendmw_512_mask, "V32sV32sV32sUi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_pabsb512_mask, "V64cV64cV64cULLi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_pabsw512_mask, "V32sV32sV32sUi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_packssdw512_mask, "V32sV16iV16iV32sUi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_packsswb512_mask, "V64cV32sV32sV64cULLi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_packusdw512_mask, "V32sV16iV16iV32sUi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_packuswb512_mask, "V64cV32sV32sV64cULLi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_paddsb512_mask, "V64cV64cV64cV64cULLi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_paddsw512_mask, "V32sV32sV32sV32sUi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_paddusb512_mask, "V64cV64cV64cV64cULLi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_paddusw512_mask, "V32sV32sV32sV32sUi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_pavgb512_mask, "V64cV64cV64cV64cULLi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_pavgw512_mask, "V32sV32sV32sV32sUi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmaxsb512_mask, "V64cV64cV64cV64cULLi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmaxsw512_mask, "V32sV32sV32sV32sUi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmaxub512_mask, "V64cV64cV64cV64cULLi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmaxuw512_mask, "V32sV32sV32sV32sUi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_pminsb512_mask, "V64cV64cV64cV64cULLi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_pminsw512_mask, "V32sV32sV32sV32sUi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_pminub512_mask, "V64cV64cV64cV64cULLi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_pminuw512_mask, "V32sV32sV32sV32sUi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_pshufb512_mask, "V64cV64cV64cV64cULLi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_psubsb512_mask, "V64cV64cV64cV64cULLi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_psubsw512_mask, "V32sV32sV32sV32sUi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_psubusb512_mask, "V64cV64cV64cV64cULLi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_psubusw512_mask, "V32sV32sV32sV32sUi", "", "avx512bw") + +TARGET_BUILTIN(__builtin_ia32_vpermi2varhi512_mask, "V32sV32sV32sV32sUi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_vpermt2varhi512_mask, "V32sV32sV32sV32sUi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_vpermt2varhi512_maskz, "V32sV32sV32sV32sUi", "", "avx512bw") + +TARGET_BUILTIN(__builtin_ia32_vpconflictdi_512_mask, "V8LLiV8LLiV8LLiUc", "", "avx512cd") +TARGET_BUILTIN(__builtin_ia32_vpconflictsi_512_mask, "V16iV16iV16iUs", "", "avx512cd") +TARGET_BUILTIN(__builtin_ia32_vplzcntd_512_mask, "V16iV16iV16iUs", "", "avx512cd") +TARGET_BUILTIN(__builtin_ia32_vplzcntq_512_mask, "V8LLiV8LLiV8LLiUc", "", "avx512cd") + +TARGET_BUILTIN(__builtin_ia32_blendmb_128_mask, "V16cV16cV16cUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_blendmb_256_mask, "V32cV32cV32cUi", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_blendmw_128_mask, "V8sV8sV8sUc", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_blendmw_256_mask, "V16sV16sV16sUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pabsb128_mask, "V16cV16cV16cUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pabsb256_mask, "V32cV32cV32cUi", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pabsw128_mask, "V8sV8sV8sUc", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pabsw256_mask, "V16sV16sV16sUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_packssdw128_mask, "V8sV4iV4iV8sUc", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_packssdw256_mask, "V16sV8iV8iV16sUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_packsswb128_mask, "V16cV8sV8sV16cUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_packsswb256_mask, "V32cV16sV16sV32cUi", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_packusdw128_mask, "V8sV4iV4iV8sUc", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_packusdw256_mask, "V16sV8iV8iV16sUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_packuswb128_mask, "V16cV8sV8sV16cUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_packuswb256_mask, "V32cV16sV16sV32cUi", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_paddsb128_mask, "V16cV16cV16cV16cUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_paddsb256_mask, "V32cV32cV32cV32cUi", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_paddsw128_mask, "V8sV8sV8sV8sUc", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_paddsw256_mask, "V16sV16sV16sV16sUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_paddusb128_mask, "V16cV16cV16cV16cUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_paddusb256_mask, "V32cV32cV32cV32cUi", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_paddusw128_mask, "V8sV8sV8sV8sUc", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_paddusw256_mask, "V16sV16sV16sV16sUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pavgb128_mask, "V16cV16cV16cV16cUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pavgb256_mask, "V32cV32cV32cV32cUi", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pavgw128_mask, "V8sV8sV8sV8sUc", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pavgw256_mask, "V16sV16sV16sV16sUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmaxsb128_mask, "V16cV16cV16cV16cUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmaxsb256_mask, "V32cV32cV32cV32cUi", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmaxsw128_mask, "V8sV8sV8sV8sUc", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmaxsw256_mask, "V16sV16sV16sV16sUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmaxub128_mask, "V16cV16cV16cV16cUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmaxub256_mask, "V32cV32cV32cV32cUi", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmaxuw128_mask, "V8sV8sV8sV8sUc", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmaxuw256_mask, "V16sV16sV16sV16sUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pminsb128_mask, "V16cV16cV16cV16cUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pminsb256_mask, "V32cV32cV32cV32cUi", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pminsw128_mask, "V8sV8sV8sV8sUc", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pminsw256_mask, "V16sV16sV16sV16sUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pminub128_mask, "V16cV16cV16cV16cUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pminub256_mask, "V32cV32cV32cV32cUi", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pminuw128_mask, "V8sV8sV8sV8sUc", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pminuw256_mask, "V16sV16sV16sV16sUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pshufb128_mask, "V16cV16cV16cV16cUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pshufb256_mask, "V32cV32cV32cV32cUi", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_psubsb128_mask, "V16cV16cV16cV16cUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_psubsb256_mask, "V32cV32cV32cV32cUi", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_psubsw128_mask, "V8sV8sV8sV8sUc", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_psubsw256_mask, "V16sV16sV16sV16sUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_psubusb128_mask, "V16cV16cV16cV16cUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_psubusb256_mask, "V32cV32cV32cV32cUi", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_psubusw128_mask, "V8sV8sV8sV8sUc", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_psubusw256_mask, "V16sV16sV16sV16sUs", "", "avx512vl,avx512bw") + +TARGET_BUILTIN(__builtin_ia32_vpermi2varhi128_mask, "V8sV8sV8sV8sUc", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_vpermi2varhi256_mask, "V16sV16sV16sV16sUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_vpermt2varhi128_mask, "V8sV8sV8sV8sUc", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_vpermt2varhi128_maskz, "V8sV8sV8sV8sUc", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_vpermt2varhi256_mask, "V16sV16sV16sV16sUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_vpermt2varhi256_maskz, "V16sV16sV16sV16sUs", "", "avx512vl,avx512bw") + +TARGET_BUILTIN(__builtin_ia32_pmulhrsw512_mask, "V32sV32sV32sV32sUi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmulhuw512_mask, "V32sV32sV32sV32sUi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmulhw512_mask, "V32sV32sV32sV32sUi", "", "avx512bw") + +TARGET_BUILTIN(__builtin_ia32_addpd512_mask, "V8dV8dV8dV8dUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_addps512_mask, "V16fV16fV16fV16fUsIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_divpd512_mask, "V8dV8dV8dV8dUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_divps512_mask, "V16fV16fV16fV16fUsIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_mulpd512_mask, "V8dV8dV8dV8dUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_mulps512_mask, "V16fV16fV16fV16fUsIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_subpd512_mask, "V8dV8dV8dV8dUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_subps512_mask, "V16fV16fV16fV16fUsIi", "", "avx512f") + +TARGET_BUILTIN(__builtin_ia32_pmaddubsw512_mask, "V32sV64cV64cV32sUi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmaddwd512_mask, "V16iV32sV32sV16iUs", "", "avx512bw") + +TARGET_BUILTIN(__builtin_ia32_addss_round, "V4fV4fV4fV4fUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_divss_round, "V4fV4fV4fV4fUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_mulss_round, "V4fV4fV4fV4fUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_subss_round, "V4fV4fV4fV4fUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_maxss_round, "V4fV4fV4fV4fUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_minss_round, "V4fV4fV4fV4fUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_addsd_round, "V2dV2dV2dV2dUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_divsd_round, "V2dV2dV2dV2dUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_mulsd_round, "V2dV2dV2dV2dUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_subsd_round, "V2dV2dV2dV2dUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_maxsd_round, "V2dV2dV2dV2dUcIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_minsd_round, "V2dV2dV2dV2dUcIi", "", "avx512f") + +TARGET_BUILTIN(__builtin_ia32_addpd128_mask, "V2dV2dV2dV2dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_addpd256_mask, "V4dV4dV4dV4dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_addps128_mask, "V4fV4fV4fV4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_addps256_mask, "V8fV8fV8fV8fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_blendmd_128_mask, "V4iV4iV4iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_blendmd_256_mask, "V8iV8iV8iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_blendmpd_128_mask, "V2dV2dV2dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_blendmpd_256_mask, "V4dV4dV4dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_blendmps_128_mask, "V4fV4fV4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_blendmps_256_mask, "V8fV8fV8fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_blendmq_128_mask, "V2LLiV2LLiV2LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_blendmq_256_mask, "V4LLiV4LLiV4LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_compressdf128_mask, "V2dV2dV2dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_compressdf256_mask, "V4dV4dV4dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_compressdi128_mask, "V2LLiV2LLiV2LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_compressdi256_mask, "V4LLiV4LLiV4LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_compresssf128_mask, "V4fV4fV4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_compresssf256_mask, "V8fV8fV8fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_compresssi128_mask, "V4iV4iV4iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_compresssi256_mask, "V8iV8iV8iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_compressstoredf128_mask, "vV2d*V2dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_compressstoredf256_mask, "vV4d*V4dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_compressstoredi128_mask, "vV2LLi*V2LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_compressstoredi256_mask, "vV4LLi*V4LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_compressstoresf128_mask, "vV4f*V4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_compressstoresf256_mask, "vV8f*V8fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_compressstoresi128_mask, "vV4i*V4iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_compressstoresi256_mask, "vV8i*V8iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cvtdq2pd128_mask, "V2dV4iV2dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cvtdq2pd256_mask, "V4dV4iV4dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cvtdq2ps128_mask, "V4fV4iV4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cvtdq2ps256_mask, "V8fV8iV8fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cvtpd2dq128_mask, "V4iV2dV4iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cvtpd2dq256_mask, "V4iV4dV4iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cvtpd2ps_mask, "V4fV2dV4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cvtpd2ps256_mask, "V4fV4dV4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cvtpd2udq128_mask, "V4iV2dV4iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cvtpd2udq256_mask, "V4iV4dV4iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cvtps2dq128_mask, "V4iV4fV4iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cvtps2dq256_mask, "V8iV8fV8iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cvtps2pd128_mask, "V2dV4fV2dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cvtps2pd256_mask, "V4dV4fV4dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cvtps2udq128_mask, "V4iV4fV4iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cvtps2udq256_mask, "V8iV8fV8iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cvttpd2dq128_mask, "V4iV2dV4iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cvttpd2dq256_mask, "V4iV4dV4iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cvttpd2udq128_mask, "V4iV2dV4iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cvttpd2udq256_mask, "V4iV4dV4iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cvttps2dq128_mask, "V4iV4fV4iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cvttps2dq256_mask, "V8iV8fV8iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cvttps2udq128_mask, "V4iV4fV4iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cvttps2udq256_mask, "V8iV8fV8iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cvtudq2pd128_mask, "V2dV4iV2dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cvtudq2pd256_mask, "V4dV4iV4dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cvtudq2ps128_mask, "V4fV4iV4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_cvtudq2ps256_mask, "V8fV8iV8fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_divpd_mask, "V2dV2dV2dV2dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_divpd256_mask, "V4dV4dV4dV4dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_divps_mask, "V4fV4fV4fV4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_divps256_mask, "V8fV8fV8fV8fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_expanddf128_mask, "V2dV2dV2dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_expanddf256_mask, "V4dV4dV4dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_expanddi128_mask, "V2LLiV2LLiV2LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_expanddi256_mask, "V4LLiV4LLiV4LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_expandloaddf128_mask, "V2dV2d*V2dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_expandloaddf256_mask, "V4dV4d*V4dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_expandloaddi128_mask, "V4iV2LLi*V2LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_expandloaddi256_mask, "V4LLiV4LLi*V4LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_expandloadsf128_mask, "V4fV4f*V4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_expandloadsf256_mask, "V8fV8f*V8fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_expandloadsi128_mask, "V4iV4i*V4iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_expandloadsi256_mask, "V8iV8i*V8iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_expandsf128_mask, "V4fV4fV4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_expandsf256_mask, "V8fV8fV8fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_expandsi128_mask, "V4iV4iV4iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_expandsi256_mask, "V8iV8iV8iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_getexppd128_mask, "V2dV2dV2dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_getexppd256_mask, "V4dV4dV4dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_getexpps128_mask, "V4fV4fV4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_getexpps256_mask, "V8fV8fV8fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_maxpd_mask, "V2dV2dV2dV2dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_maxpd256_mask, "V4dV4dV4dV4dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_maxps_mask, "V4fV4fV4fV4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_maxps256_mask, "V8fV8fV8fV8fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_minpd_mask, "V2dV2dV2dV2dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_minpd256_mask, "V4dV4dV4dV4dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_minps_mask, "V4fV4fV4fV4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_minps256_mask, "V8fV8fV8fV8fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_mulpd_mask, "V2dV2dV2dV2dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_mulpd256_mask, "V4dV4dV4dV4dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_mulps_mask, "V4fV4fV4fV4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_mulps256_mask, "V8fV8fV8fV8fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pabsd128_mask, "V4iV4iV4iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pabsd256_mask, "V8iV8iV8iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pabsq128_mask, "V2LLiV2LLiV2LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pabsq256_mask, "V4LLiV4LLiV4LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pmaxsd128_mask, "V4iV4iV4iV4iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pmaxsd256_mask, "V8iV8iV8iV8iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pmaxsq128_mask, "V2LLiV2LLiV2LLiV2LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pmaxsq256_mask, "V4LLiV4LLiV4LLiV4LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pmaxud128_mask, "V4iV4iV4iV4iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pmaxud256_mask, "V8iV8iV8iV8iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pmaxuq128_mask, "V2LLiV2LLiV2LLiV2LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pmaxuq256_mask, "V4LLiV4LLiV4LLiV4LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pminsd128_mask, "V4iV4iV4iV4iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pminsd256_mask, "V8iV8iV8iV8iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pminsq128_mask, "V2LLiV2LLiV2LLiV2LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pminsq256_mask, "V4LLiV4LLiV4LLiV4LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pminud128_mask, "V4iV4iV4iV4iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pminud256_mask, "V8iV8iV8iV8iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pminuq128_mask, "V2LLiV2LLiV2LLiV2LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pminuq256_mask, "V4LLiV4LLiV4LLiV4LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_rndscalepd_128_mask, "V2dV2dIiV2dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_rndscalepd_256_mask, "V4dV4dIiV4dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_rndscaleps_128_mask, "V4fV4fIiV4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_rndscaleps_256_mask, "V8fV8fIiV8fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_scalefpd128_mask, "V2dV2dV2dV2dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_scalefpd256_mask, "V4dV4dV4dV4dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_scalefps128_mask, "V4fV4fV4fV4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_scalefps256_mask, "V8fV8fV8fV8fUc", "", "avx512vl") + +TARGET_BUILTIN(__builtin_ia32_scatterdiv2df, "vv*UcV2LLiV2dIi", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_scatterdiv2di, "vv*UcV2LLiV2LLiIi", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_scatterdiv4df, "vv*UcV4LLiV4dIi", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_scatterdiv4di, "vv*UcV4LLiV4LLiIi", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_scatterdiv4sf, "vv*UcV2LLiV4fIi", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_scatterdiv4si, "vv*UcV2LLiV4iIi", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_scatterdiv8sf, "vv*UcV4LLiV4fIi", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_scatterdiv8si, "vv*UcV4LLiV4iIi", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_scattersiv2df, "vv*UcV4iV2dIi", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_scattersiv2di, "vv*UcV4iV2LLiIi", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_scattersiv4df, "vv*UcV4iV4dIi", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_scattersiv4di, "vv*UcV4iV4LLiIi", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_scattersiv4sf, "vv*UcV4iV4fIi", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_scattersiv4si, "vv*UcV4iV4iIi", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_scattersiv8sf, "vv*UcV8iV8fIi", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_scattersiv8si, "vv*UcV8iV8iIi", "", "avx512vl") + +TARGET_BUILTIN(__builtin_ia32_sqrtpd128_mask, "V2dV2dV2dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_sqrtpd256_mask, "V4dV4dV4dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_sqrtps128_mask, "V4fV4fV4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_sqrtps256_mask, "V8fV8fV8fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_subpd128_mask, "V2dV2dV2dV2dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_subpd256_mask, "V4dV4dV4dV4dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_subps128_mask, "V4fV4fV4fV4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_subps256_mask, "V8fV8fV8fV8fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vpermi2vard128_mask, "V4iV4iV4iV4iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vpermi2vard256_mask, "V8iV8iV8iV8iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vpermi2varpd128_mask, "V2dV2dV2LLiV2dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vpermi2varpd256_mask, "V4dV4dV4LLiV4dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vpermi2varps128_mask, "V4fV4fV4iV4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vpermi2varps256_mask, "V8fV8fV8iV8fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vpermi2varq128_mask, "V2LLiV2LLiV2LLiV2LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vpermi2varq256_mask, "V4LLiV4LLiV4LLiV4LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vpermt2vard128_mask, "V4iV4iV4iV4iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vpermt2vard128_maskz, "V4iV4iV4iV4iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vpermt2vard256_mask, "V8iV8iV8iV8iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vpermt2vard256_maskz, "V8iV8iV8iV8iUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vpermt2varpd128_mask, "V2dV2LLiV2dV2dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vpermt2varpd128_maskz, "V2dV2LLiV2dV2dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vpermt2varpd256_mask, "V4dV4LLiV4dV4dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vpermt2varpd256_maskz, "V4dV4LLiV4dV4dUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vpermt2varps128_mask, "V4fV4iV4fV4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vpermt2varps128_maskz, "V4fV4iV4fV4fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vpermt2varps256_mask, "V8fV8iV8fV8fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vpermt2varps256_maskz, "V8fV8iV8fV8fUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vpermt2varq128_mask, "V2LLiV2LLiV2LLiV2LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vpermt2varq128_maskz, "V2LLiV2LLiV2LLiV2LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vpermt2varq256_mask, "V4LLiV4LLiV4LLiV4LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_vpermt2varq256_maskz, "V4LLiV4LLiV4LLiV4LLiUc", "", "avx512vl") +TARGET_BUILTIN(__builtin_ia32_pmovswb512_mask, "V32cV32sV32cUi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmovuswb512_mask, "V32cV32sV32cUi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmovwb512_mask, "V32cV32sV32cUi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_punpckhbw512_mask, "V64cV64cV64cV64cULLi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_punpckhwd512_mask, "V32sV32sV32sV32sUi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_punpcklbw512_mask, "V64cV64cV64cV64cULLi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_punpcklwd512_mask, "V32sV32sV32sV32sUi", "", "avx512bw") +TARGET_BUILTIN(__builtin_ia32_cvtpd2qq128_mask, "V2LLiV2dV2LLiUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvtpd2qq256_mask, "V4LLiV4dV4LLiUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvtpd2uqq128_mask, "V2LLiV2dV2LLiUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvtpd2uqq256_mask, "V4LLiV4dV4LLiUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvtps2qq128_mask, "V2LLiV4fV2LLiUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvtps2qq256_mask, "V4LLiV4fV4LLiUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvtps2uqq128_mask, "V2LLiV4fV2LLiUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvtps2uqq256_mask, "V4LLiV4fV4LLiUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvtqq2pd128_mask, "V2dV2LLiV2dUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvtqq2pd256_mask, "V4dV4LLiV4dUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvtqq2ps128_mask, "V4fV2LLiV4fUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvtqq2ps256_mask, "V4fV4LLiV4fUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvttpd2qq128_mask, "V2LLiV2dV2LLiUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvttpd2qq256_mask, "V4LLiV4dV4LLiUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvttpd2uqq128_mask, "V2LLiV2dV2LLiUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvttpd2uqq256_mask, "V4LLiV4dV4LLiUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvttps2qq128_mask, "V2LLiV4fV2LLiUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvttps2qq256_mask, "V4LLiV4fV4LLiUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvttps2uqq128_mask, "V2LLiV4fV2LLiUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvttps2uqq256_mask, "V4LLiV4fV4LLiUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvtuqq2pd128_mask, "V2dV2LLiV2dUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvtuqq2pd256_mask, "V4dV4LLiV4dUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvtuqq2ps128_mask, "V4fV2LLiV4fUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvtuqq2ps256_mask, "V4fV4LLiV4fUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_rangepd128_mask, "V2dV2dV2dIiV2dUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_rangepd256_mask, "V4dV4dV4dIiV4dUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_rangeps128_mask, "V4fV4fV4fIiV4fUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_rangeps256_mask, "V8fV8fV8fIiV8fUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_reducepd128_mask, "V2dV2dIiV2dUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_reducepd256_mask, "V4dV4dIiV4dUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_reduceps128_mask, "V4fV4fIiV4fUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_reduceps256_mask, "V8fV8fIiV8fUc", "", "avx512vl,avx512dq") +TARGET_BUILTIN(__builtin_ia32_pmaddubsw128_mask, "V8sV16cV16cV8sUc", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmaddubsw256_mask, "V16sV32cV32cV16sUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmaddwd128_mask, "V4iV8sV8sV4iUc", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmaddwd256_mask, "V8iV16sV16sV8iUc", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmovswb128_mask, "V16cV8sV16cUc", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmovswb256_mask, "V16cV16sV16cUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmovuswb128_mask, "V16cV8sV16cUc", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmovuswb256_mask, "V16cV16sV16cUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmovwb128_mask, "V16cV8sV16cUc", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmovwb256_mask, "V16cV16sV16cUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmulhrsw128_mask, "V8sV8sV8sV8sUc", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmulhrsw256_mask, "V16sV16sV16sV16sUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmulhuw128_mask, "V8sV8sV8sV8sUc", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmulhuw256_mask, "V16sV16sV16sV16sUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmulhw128_mask, "V8sV8sV8sV8sUc", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_pmulhw256_mask, "V16sV16sV16sV16sUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_punpckhbw128_mask, "V16cV16cV16cV16cUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_punpckhbw256_mask, "V32cV32cV32cV32cUi", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_punpckhwd128_mask, "V8sV8sV8sV8sUc", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_punpckhwd256_mask, "V16sV16sV16sV16sUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_punpcklbw128_mask, "V16cV16cV16cV16cUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_punpcklbw256_mask, "V32cV32cV32cV32cUi", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_punpcklwd128_mask, "V8sV8sV8sV8sUc", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_punpcklwd256_mask, "V16sV16sV16sV16sUs", "", "avx512vl,avx512bw") +TARGET_BUILTIN(__builtin_ia32_cvtpd2qq512_mask, "V8LLiV8dV8LLiUcIi", "", "avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvtpd2uqq512_mask, "V8LLiV8dV8LLiUcIi", "", "avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvtps2qq512_mask, "V8LLiV8fV8LLiUcIi", "", "avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvtps2uqq512_mask, "V8LLiV8fV8LLiUcIi", "", "avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvtqq2pd512_mask, "V8dV8LLiV8dUcIi", "", "avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvtqq2ps512_mask, "V8fV8LLiV8fUcIi", "", "avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvttpd2qq512_mask, "V8LLiV8dV8LLiUcIi", "", "avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvttpd2uqq512_mask, "V8LLiV8dV8LLiUcIi", "", "avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvttps2qq512_mask, "V8LLiV8fV8LLiUcIi", "", "avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvttps2uqq512_mask, "V8LLiV8fV8LLiUcIi", "", "avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvtuqq2pd512_mask, "V8dV8LLiV8dUcIi", "", "avx512dq") +TARGET_BUILTIN(__builtin_ia32_cvtuqq2ps512_mask, "V8fV8LLiV8fUcIi", "", "avx512dq") +TARGET_BUILTIN(__builtin_ia32_rangepd512_mask, "V8dV8dV8dIiV8dUcIi", "", "avx512dq") +TARGET_BUILTIN(__builtin_ia32_rangeps512_mask, "V16fV16fV16fIiV16fUsIi", "", "avx512dq") +TARGET_BUILTIN(__builtin_ia32_reducepd512_mask, "V8dV8dIiV8dUcIi", "", "avx512dq") +TARGET_BUILTIN(__builtin_ia32_reduceps512_mask, "V16fV16fIiV16fUsIi", "", "avx512dq") + +#undef BUILTIN +#undef TARGET_BUILTIN diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsXCore.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsXCore.def new file mode 100644 index 0000000..672d205 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsXCore.def @@ -0,0 +1,22 @@ +//===--- BuiltinsXCore.def - XCore Builtin function database ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the XCore-specific builtin function database. Users of +// this file must define the BUILTIN macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +// The format of this database matches clang/Basic/Builtins.def. + +BUILTIN(__builtin_bitrev, "UiUi", "nc") +BUILTIN(__builtin_getid, "Si", "nc") +BUILTIN(__builtin_getps, "UiUi", "n") +BUILTIN(__builtin_setps, "vUiUi", "n") + +#undef BUILTIN diff --git a/contrib/llvm/tools/clang/include/clang/Basic/CapturedStmt.h b/contrib/llvm/tools/clang/include/clang/Basic/CapturedStmt.h new file mode 100644 index 0000000..c4a289b --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/CapturedStmt.h @@ -0,0 +1,24 @@ +//===--- CapturedStmt.h - Types for CapturedStmts ---------------*- 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_BASIC_CAPTUREDSTMT_H +#define LLVM_CLANG_BASIC_CAPTUREDSTMT_H + +namespace clang { + +/// \brief The different kinds of captured statement. +enum CapturedRegionKind { + CR_Default, + CR_OpenMP +}; + +} // end namespace clang + +#endif // LLVM_CLANG_BASIC_CAPTUREDSTMT_H diff --git a/contrib/llvm/tools/clang/include/clang/Basic/CharInfo.h b/contrib/llvm/tools/clang/include/clang/Basic/CharInfo.h new file mode 100644 index 0000000..dd9c554 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/CharInfo.h @@ -0,0 +1,198 @@ +//===--- clang/Basic/CharInfo.h - Classifying ASCII Characters ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_CHARINFO_H +#define LLVM_CLANG_BASIC_CHARINFO_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/DataTypes.h" + +namespace clang { +namespace charinfo { + extern const uint16_t InfoTable[256]; + + enum { + CHAR_HORZ_WS = 0x0001, // '\t', '\f', '\v'. Note, no '\0' + CHAR_VERT_WS = 0x0002, // '\r', '\n' + CHAR_SPACE = 0x0004, // ' ' + CHAR_DIGIT = 0x0008, // 0-9 + CHAR_XLETTER = 0x0010, // a-f,A-F + CHAR_UPPER = 0x0020, // A-Z + CHAR_LOWER = 0x0040, // a-z + CHAR_UNDER = 0x0080, // _ + CHAR_PERIOD = 0x0100, // . + CHAR_RAWDEL = 0x0200, // {}[]#<>%:;?*+-/^&|~!=,"' + CHAR_PUNCT = 0x0400 // `$@() + }; + + enum { + CHAR_XUPPER = CHAR_XLETTER | CHAR_UPPER, + CHAR_XLOWER = CHAR_XLETTER | CHAR_LOWER + }; +} // end namespace charinfo + +/// Returns true if this is an ASCII character. +LLVM_READNONE static inline bool isASCII(char c) { + return static_cast<unsigned char>(c) <= 127; +} + +/// Returns true if this is a valid first character of a C identifier, +/// which is [a-zA-Z_]. +LLVM_READONLY static inline bool isIdentifierHead(unsigned char c, + bool AllowDollar = false) { + using namespace charinfo; + if (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER|CHAR_UNDER)) + return true; + return AllowDollar && c == '$'; +} + +/// Returns true if this is a body character of a C identifier, +/// which is [a-zA-Z0-9_]. +LLVM_READONLY static inline bool isIdentifierBody(unsigned char c, + bool AllowDollar = false) { + using namespace charinfo; + if (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER|CHAR_DIGIT|CHAR_UNDER)) + return true; + return AllowDollar && c == '$'; +} + +/// Returns true if this character is horizontal ASCII whitespace: +/// ' ', '\\t', '\\f', '\\v'. +/// +/// Note that this returns false for '\\0'. +LLVM_READONLY static inline bool isHorizontalWhitespace(unsigned char c) { + using namespace charinfo; + return (InfoTable[c] & (CHAR_HORZ_WS|CHAR_SPACE)) != 0; +} + +/// Returns true if this character is vertical ASCII whitespace: '\\n', '\\r'. +/// +/// Note that this returns false for '\\0'. +LLVM_READONLY static inline bool isVerticalWhitespace(unsigned char c) { + using namespace charinfo; + return (InfoTable[c] & CHAR_VERT_WS) != 0; +} + +/// Return true if this character is horizontal or vertical ASCII whitespace: +/// ' ', '\\t', '\\f', '\\v', '\\n', '\\r'. +/// +/// Note that this returns false for '\\0'. +LLVM_READONLY static inline bool isWhitespace(unsigned char c) { + using namespace charinfo; + return (InfoTable[c] & (CHAR_HORZ_WS|CHAR_VERT_WS|CHAR_SPACE)) != 0; +} + +/// Return true if this character is an ASCII digit: [0-9] +LLVM_READONLY static inline bool isDigit(unsigned char c) { + using namespace charinfo; + return (InfoTable[c] & CHAR_DIGIT) != 0; +} + +/// Return true if this character is a lowercase ASCII letter: [a-z] +LLVM_READONLY static inline bool isLowercase(unsigned char c) { + using namespace charinfo; + return (InfoTable[c] & CHAR_LOWER) != 0; +} + +/// Return true if this character is an uppercase ASCII letter: [A-Z] +LLVM_READONLY static inline bool isUppercase(unsigned char c) { + using namespace charinfo; + return (InfoTable[c] & CHAR_UPPER) != 0; +} + +/// Return true if this character is an ASCII letter: [a-zA-Z] +LLVM_READONLY static inline bool isLetter(unsigned char c) { + using namespace charinfo; + return (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER)) != 0; +} + +/// Return true if this character is an ASCII letter or digit: [a-zA-Z0-9] +LLVM_READONLY static inline bool isAlphanumeric(unsigned char c) { + using namespace charinfo; + return (InfoTable[c] & (CHAR_DIGIT|CHAR_UPPER|CHAR_LOWER)) != 0; +} + +/// Return true if this character is an ASCII hex digit: [0-9a-fA-F] +LLVM_READONLY static inline bool isHexDigit(unsigned char c) { + using namespace charinfo; + return (InfoTable[c] & (CHAR_DIGIT|CHAR_XLETTER)) != 0; +} + +/// Return true if this character is an ASCII punctuation character. +/// +/// Note that '_' is both a punctuation character and an identifier character! +LLVM_READONLY static inline bool isPunctuation(unsigned char c) { + using namespace charinfo; + return (InfoTable[c] & (CHAR_UNDER|CHAR_PERIOD|CHAR_RAWDEL|CHAR_PUNCT)) != 0; +} + +/// Return true if this character is an ASCII printable character; that is, a +/// character that should take exactly one column to print in a fixed-width +/// terminal. +LLVM_READONLY static inline bool isPrintable(unsigned char c) { + using namespace charinfo; + return (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER|CHAR_PERIOD|CHAR_PUNCT| + CHAR_DIGIT|CHAR_UNDER|CHAR_RAWDEL|CHAR_SPACE)) != 0; +} + +/// Return true if this is the body character of a C preprocessing number, +/// which is [a-zA-Z0-9_.]. +LLVM_READONLY static inline bool isPreprocessingNumberBody(unsigned char c) { + using namespace charinfo; + return (InfoTable[c] & + (CHAR_UPPER|CHAR_LOWER|CHAR_DIGIT|CHAR_UNDER|CHAR_PERIOD)) != 0; +} + +/// Return true if this is the body character of a C++ raw string delimiter. +LLVM_READONLY static inline bool isRawStringDelimBody(unsigned char c) { + using namespace charinfo; + return (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER|CHAR_PERIOD| + CHAR_DIGIT|CHAR_UNDER|CHAR_RAWDEL)) != 0; +} + + +/// Converts the given ASCII character to its lowercase equivalent. +/// +/// If the character is not an uppercase character, it is returned as is. +LLVM_READONLY static inline char toLowercase(char c) { + if (isUppercase(c)) + return c + 'a' - 'A'; + return c; +} + +/// Converts the given ASCII character to its uppercase equivalent. +/// +/// If the character is not a lowercase character, it is returned as is. +LLVM_READONLY static inline char toUppercase(char c) { + if (isLowercase(c)) + return c + 'A' - 'a'; + return c; +} + + +/// Return true if this is a valid ASCII identifier. +/// +/// Note that this is a very simple check; it does not accept '$' or UCNs as +/// valid identifier characters. +LLVM_READONLY static inline bool isValidIdentifier(StringRef S) { + if (S.empty() || !isIdentifierHead(S[0])) + return false; + + for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) + if (!isIdentifierBody(*I)) + return false; + + return true; +} + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/CommentNodes.td b/contrib/llvm/tools/clang/include/clang/Basic/CommentNodes.td new file mode 100644 index 0000000..7bf32b7 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/CommentNodes.td @@ -0,0 +1,27 @@ +class Comment<bit abstract = 0> { + bit Abstract = abstract; +} + +class DComment<Comment base, bit abstract = 0> : Comment<abstract> { + Comment Base = base; +} + +def InlineContentComment : Comment<1>; + def TextComment : DComment<InlineContentComment>; + def InlineCommandComment : DComment<InlineContentComment>; + def HTMLTagComment : DComment<InlineContentComment, 1>; + def HTMLStartTagComment : DComment<HTMLTagComment>; + def HTMLEndTagComment : DComment<HTMLTagComment>; + +def BlockContentComment : Comment<1>; + def ParagraphComment : DComment<BlockContentComment>; + def BlockCommandComment : DComment<BlockContentComment>; + def ParamCommandComment : DComment<BlockCommandComment>; + def TParamCommandComment : DComment<BlockCommandComment>; + def VerbatimBlockComment : DComment<BlockCommandComment>; + def VerbatimLineComment : DComment<BlockCommandComment>; + +def VerbatimBlockLineComment : Comment; + +def FullComment : Comment; + diff --git a/contrib/llvm/tools/clang/include/clang/Basic/CommentOptions.h b/contrib/llvm/tools/clang/include/clang/Basic/CommentOptions.h new file mode 100644 index 0000000..92419f9 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/CommentOptions.h @@ -0,0 +1,39 @@ +//===--- CommentOptions.h - Options for parsing comments -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the clang::CommentOptions interface. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_COMMENTOPTIONS_H +#define LLVM_CLANG_BASIC_COMMENTOPTIONS_H + +#include <string> +#include <vector> + +namespace clang { + +/// \brief Options for controlling comment parsing. +struct CommentOptions { + typedef std::vector<std::string> BlockCommandNamesTy; + + /// \brief Command names to treat as block commands in comments. + /// Should not include the leading backslash. + BlockCommandNamesTy BlockCommandNames; + + /// \brief Treat ordinary comments as documentation comments. + bool ParseAllComments; + + CommentOptions() : ParseAllComments(false) { } +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DeclNodes.td b/contrib/llvm/tools/clang/include/clang/Basic/DeclNodes.td new file mode 100644 index 0000000..723ea54 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/DeclNodes.td @@ -0,0 +1,88 @@ +class AttrSubject; + +class Decl<bit abstract = 0> : AttrSubject { + bit Abstract = abstract; +} + +class DDecl<Decl base, bit abstract = 0> : Decl<abstract> { + Decl Base = base; +} + +class DeclContext { } + +def TranslationUnit : Decl, DeclContext; +def ExternCContext : Decl, DeclContext; +def Named : Decl<1>; + def Namespace : DDecl<Named>, DeclContext; + def UsingDirective : DDecl<Named>; + def NamespaceAlias : DDecl<Named>; + def Label : DDecl<Named>; + def Type : DDecl<Named, 1>; + def TypedefName : DDecl<Type, 1>; + def Typedef : DDecl<TypedefName>; + def TypeAlias : DDecl<TypedefName>; + def ObjCTypeParam : DDecl<TypedefName>; + def UnresolvedUsingTypename : DDecl<Type>; + def Tag : DDecl<Type, 1>, DeclContext; + def Enum : DDecl<Tag>; + def Record : DDecl<Tag>; + def CXXRecord : DDecl<Record>; + def ClassTemplateSpecialization : DDecl<CXXRecord>; + def ClassTemplatePartialSpecialization + : DDecl<ClassTemplateSpecialization>; + def TemplateTypeParm : DDecl<Type>; + def Value : DDecl<Named, 1>; + def EnumConstant : DDecl<Value>; + def UnresolvedUsingValue : DDecl<Value>; + def IndirectField : DDecl<Value>; + def Declarator : DDecl<Value, 1>; + def Field : DDecl<Declarator>; + def ObjCIvar : DDecl<Field>; + def ObjCAtDefsField : DDecl<Field>; + def MSProperty : DDecl<Declarator>; + def Function : DDecl<Declarator>, DeclContext; + def CXXMethod : DDecl<Function>; + def CXXConstructor : DDecl<CXXMethod>; + def CXXDestructor : DDecl<CXXMethod>; + def CXXConversion : DDecl<CXXMethod>; + def Var : DDecl<Declarator>; + def VarTemplateSpecialization : DDecl<Var>; + def VarTemplatePartialSpecialization + : DDecl<VarTemplateSpecialization>; + def ImplicitParam : DDecl<Var>; + def ParmVar : DDecl<Var>; + def NonTypeTemplateParm : DDecl<Declarator>; + def Template : DDecl<Named, 1>; + def RedeclarableTemplate : DDecl<Template, 1>; + def FunctionTemplate : DDecl<RedeclarableTemplate>; + def ClassTemplate : DDecl<RedeclarableTemplate>; + def VarTemplate : DDecl<RedeclarableTemplate>; + def TypeAliasTemplate : DDecl<RedeclarableTemplate>; + def TemplateTemplateParm : DDecl<Template>; + def BuiltinTemplate : DDecl<Template>; + def Using : DDecl<Named>; + def UsingShadow : DDecl<Named>; + def ObjCMethod : DDecl<Named>, DeclContext; + def ObjCContainer : DDecl<Named, 1>, DeclContext; + def ObjCCategory : DDecl<ObjCContainer>; + def ObjCProtocol : DDecl<ObjCContainer>; + def ObjCInterface : DDecl<ObjCContainer>; + def ObjCImpl : DDecl<ObjCContainer, 1>; + def ObjCCategoryImpl : DDecl<ObjCImpl>; + def ObjCImplementation : DDecl<ObjCImpl>; + def ObjCProperty : DDecl<Named>; + def ObjCCompatibleAlias : DDecl<Named>; +def LinkageSpec : Decl, DeclContext; +def ObjCPropertyImpl : Decl; +def FileScopeAsm : Decl; +def AccessSpec : Decl; +def Friend : Decl; +def FriendTemplate : Decl; +def StaticAssert : Decl; +def Block : Decl, DeclContext; +def Captured : Decl, DeclContext; +def ClassScopeFunctionSpecialization : Decl; +def Import : Decl; +def OMPThreadPrivate : Decl; +def Empty : Decl; + diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.h b/contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.h new file mode 100644 index 0000000..1d6c19b --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.h @@ -0,0 +1,1414 @@ +//===--- Diagnostic.h - C Language Family Diagnostic Handling ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the Diagnostic-related interfaces. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_DIAGNOSTIC_H +#define LLVM_CLANG_BASIC_DIAGNOSTIC_H + +#include "clang/Basic/DiagnosticIDs.h" +#include "clang/Basic/DiagnosticOptions.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/Specifiers.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/iterator_range.h" +#include <list> +#include <vector> + +namespace clang { + class DeclContext; + class DiagnosticBuilder; + class DiagnosticConsumer; + class DiagnosticErrorTrap; + class DiagnosticOptions; + class IdentifierInfo; + class LangOptions; + class Preprocessor; + class StoredDiagnostic; + namespace tok { + enum TokenKind : unsigned short; + } + +/// \brief Annotates a diagnostic with some code that should be +/// inserted, removed, or replaced to fix the problem. +/// +/// This kind of hint should be used when we are certain that the +/// introduction, removal, or modification of a particular (small!) +/// amount of code will correct a compilation error. The compiler +/// should also provide full recovery from such errors, such that +/// suppressing the diagnostic output can still result in successful +/// compilation. +class FixItHint { +public: + /// \brief Code that should be replaced to correct the error. Empty for an + /// insertion hint. + CharSourceRange RemoveRange; + + /// \brief Code in the specific range that should be inserted in the insertion + /// location. + CharSourceRange InsertFromRange; + + /// \brief The actual code to insert at the insertion location, as a + /// string. + std::string CodeToInsert; + + bool BeforePreviousInsertions; + + /// \brief Empty code modification hint, indicating that no code + /// modification is known. + FixItHint() : BeforePreviousInsertions(false) { } + + bool isNull() const { + return !RemoveRange.isValid(); + } + + /// \brief Create a code modification hint that inserts the given + /// code string at a specific location. + static FixItHint CreateInsertion(SourceLocation InsertionLoc, + StringRef Code, + bool BeforePreviousInsertions = false) { + FixItHint Hint; + Hint.RemoveRange = + CharSourceRange::getCharRange(InsertionLoc, InsertionLoc); + Hint.CodeToInsert = Code; + Hint.BeforePreviousInsertions = BeforePreviousInsertions; + return Hint; + } + + /// \brief Create a code modification hint that inserts the given + /// code from \p FromRange at a specific location. + static FixItHint CreateInsertionFromRange(SourceLocation InsertionLoc, + CharSourceRange FromRange, + bool BeforePreviousInsertions = false) { + FixItHint Hint; + Hint.RemoveRange = + CharSourceRange::getCharRange(InsertionLoc, InsertionLoc); + Hint.InsertFromRange = FromRange; + Hint.BeforePreviousInsertions = BeforePreviousInsertions; + return Hint; + } + + /// \brief Create a code modification hint that removes the given + /// source range. + static FixItHint CreateRemoval(CharSourceRange RemoveRange) { + FixItHint Hint; + Hint.RemoveRange = RemoveRange; + return Hint; + } + static FixItHint CreateRemoval(SourceRange RemoveRange) { + return CreateRemoval(CharSourceRange::getTokenRange(RemoveRange)); + } + + /// \brief Create a code modification hint that replaces the given + /// source range with the given code string. + static FixItHint CreateReplacement(CharSourceRange RemoveRange, + StringRef Code) { + FixItHint Hint; + Hint.RemoveRange = RemoveRange; + Hint.CodeToInsert = Code; + return Hint; + } + + static FixItHint CreateReplacement(SourceRange RemoveRange, + StringRef Code) { + return CreateReplacement(CharSourceRange::getTokenRange(RemoveRange), Code); + } +}; + +/// \brief Concrete class used by the front-end to report problems and issues. +/// +/// This massages the diagnostics (e.g. handling things like "report warnings +/// as errors" and passes them off to the DiagnosticConsumer for reporting to +/// the user. DiagnosticsEngine is tied to one translation unit and one +/// SourceManager. +class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> { + DiagnosticsEngine(const DiagnosticsEngine &) = delete; + void operator=(const DiagnosticsEngine &) = delete; + +public: + /// \brief The level of the diagnostic, after it has been through mapping. + enum Level { + Ignored = DiagnosticIDs::Ignored, + Note = DiagnosticIDs::Note, + Remark = DiagnosticIDs::Remark, + Warning = DiagnosticIDs::Warning, + Error = DiagnosticIDs::Error, + Fatal = DiagnosticIDs::Fatal + }; + + enum ArgumentKind { + ak_std_string, ///< std::string + ak_c_string, ///< const char * + ak_sint, ///< int + ak_uint, ///< unsigned + ak_tokenkind, ///< enum TokenKind : unsigned + ak_identifierinfo, ///< IdentifierInfo + ak_qualtype, ///< QualType + ak_declarationname, ///< DeclarationName + ak_nameddecl, ///< NamedDecl * + ak_nestednamespec, ///< NestedNameSpecifier * + ak_declcontext, ///< DeclContext * + ak_qualtype_pair, ///< pair<QualType, QualType> + ak_attr ///< Attr * + }; + + /// \brief Represents on argument value, which is a union discriminated + /// by ArgumentKind, with a value. + typedef std::pair<ArgumentKind, intptr_t> ArgumentValue; + +private: + unsigned char AllExtensionsSilenced; // Used by __extension__ + bool IgnoreAllWarnings; // Ignore all warnings: -w + bool WarningsAsErrors; // Treat warnings like errors. + bool EnableAllWarnings; // Enable all warnings. + bool ErrorsAsFatal; // Treat errors like fatal errors. + bool SuppressSystemWarnings; // Suppress warnings in system headers. + bool SuppressAllDiagnostics; // Suppress all diagnostics. + bool ElideType; // Elide common types of templates. + bool PrintTemplateTree; // Print a tree when comparing templates. + bool ShowColors; // Color printing is enabled. + OverloadsShown ShowOverloads; // Which overload candidates to show. + unsigned ErrorLimit; // Cap of # errors emitted, 0 -> no limit. + unsigned TemplateBacktraceLimit; // Cap on depth of template backtrace stack, + // 0 -> no limit. + unsigned ConstexprBacktraceLimit; // Cap on depth of constexpr evaluation + // backtrace stack, 0 -> no limit. + diag::Severity ExtBehavior; // Map extensions to warnings or errors? + IntrusiveRefCntPtr<DiagnosticIDs> Diags; + IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts; + DiagnosticConsumer *Client; + std::unique_ptr<DiagnosticConsumer> Owner; + SourceManager *SourceMgr; + + /// \brief Mapping information for diagnostics. + /// + /// Mapping info is packed into four bits per diagnostic. The low three + /// bits are the mapping (an instance of diag::Severity), or zero if unset. + /// The high bit is set when the mapping was established as a user mapping. + /// If the high bit is clear, then the low bits are set to the default + /// value, and should be mapped with -pedantic, -Werror, etc. + /// + /// A new DiagState is created and kept around when diagnostic pragmas modify + /// the state so that we know what is the diagnostic state at any given + /// source location. + class DiagState { + llvm::DenseMap<unsigned, DiagnosticMapping> DiagMap; + + public: + typedef llvm::DenseMap<unsigned, DiagnosticMapping>::iterator iterator; + typedef llvm::DenseMap<unsigned, DiagnosticMapping>::const_iterator + const_iterator; + + void setMapping(diag::kind Diag, DiagnosticMapping Info) { + DiagMap[Diag] = Info; + } + + DiagnosticMapping &getOrAddMapping(diag::kind Diag); + + const_iterator begin() const { return DiagMap.begin(); } + const_iterator end() const { return DiagMap.end(); } + }; + + /// \brief Keeps and automatically disposes all DiagStates that we create. + std::list<DiagState> DiagStates; + + /// \brief Represents a point in source where the diagnostic state was + /// modified because of a pragma. + /// + /// 'Loc' can be null if the point represents the diagnostic state + /// modifications done through the command-line. + struct DiagStatePoint { + DiagState *State; + FullSourceLoc Loc; + DiagStatePoint(DiagState *State, FullSourceLoc Loc) + : State(State), Loc(Loc) { } + + bool operator<(const DiagStatePoint &RHS) const { + // If Loc is invalid it means it came from <command-line>, in which case + // we regard it as coming before any valid source location. + if (RHS.Loc.isInvalid()) + return false; + if (Loc.isInvalid()) + return true; + return Loc.isBeforeInTranslationUnitThan(RHS.Loc); + } + }; + + /// \brief A sorted vector of all DiagStatePoints representing changes in + /// diagnostic state due to diagnostic pragmas. + /// + /// The vector is always sorted according to the SourceLocation of the + /// DiagStatePoint. + typedef std::vector<DiagStatePoint> DiagStatePointsTy; + mutable DiagStatePointsTy DiagStatePoints; + + /// \brief Keeps the DiagState that was active during each diagnostic 'push' + /// so we can get back at it when we 'pop'. + std::vector<DiagState *> DiagStateOnPushStack; + + DiagState *GetCurDiagState() const { + assert(!DiagStatePoints.empty()); + return DiagStatePoints.back().State; + } + + void PushDiagStatePoint(DiagState *State, SourceLocation L) { + FullSourceLoc Loc(L, getSourceManager()); + // Make sure that DiagStatePoints is always sorted according to Loc. + assert(Loc.isValid() && "Adding invalid loc point"); + assert(!DiagStatePoints.empty() && + (DiagStatePoints.back().Loc.isInvalid() || + DiagStatePoints.back().Loc.isBeforeInTranslationUnitThan(Loc)) && + "Previous point loc comes after or is the same as new one"); + DiagStatePoints.push_back(DiagStatePoint(State, Loc)); + } + + /// \brief Finds the DiagStatePoint that contains the diagnostic state of + /// the given source location. + DiagStatePointsTy::iterator GetDiagStatePointForLoc(SourceLocation Loc) const; + + /// \brief Sticky flag set to \c true when an error is emitted. + bool ErrorOccurred; + + /// \brief Sticky flag set to \c true when an "uncompilable error" occurs. + /// I.e. an error that was not upgraded from a warning by -Werror. + bool UncompilableErrorOccurred; + + /// \brief Sticky flag set to \c true when a fatal error is emitted. + bool FatalErrorOccurred; + + /// \brief Indicates that an unrecoverable error has occurred. + bool UnrecoverableErrorOccurred; + + /// \brief Counts for DiagnosticErrorTrap to check whether an error occurred + /// during a parsing section, e.g. during parsing a function. + unsigned TrapNumErrorsOccurred; + unsigned TrapNumUnrecoverableErrorsOccurred; + + /// \brief The level of the last diagnostic emitted. + /// + /// This is used to emit continuation diagnostics with the same level as the + /// diagnostic that they follow. + DiagnosticIDs::Level LastDiagLevel; + + unsigned NumWarnings; ///< Number of warnings reported + unsigned NumErrors; ///< Number of errors reported + + /// \brief A function pointer that converts an opaque diagnostic + /// argument to a strings. + /// + /// This takes the modifiers and argument that was present in the diagnostic. + /// + /// The PrevArgs array indicates the previous arguments formatted for this + /// diagnostic. Implementations of this function can use this information to + /// avoid redundancy across arguments. + /// + /// This is a hack to avoid a layering violation between libbasic and libsema. + typedef void (*ArgToStringFnTy)( + ArgumentKind Kind, intptr_t Val, + StringRef Modifier, StringRef Argument, + ArrayRef<ArgumentValue> PrevArgs, + SmallVectorImpl<char> &Output, + void *Cookie, + ArrayRef<intptr_t> QualTypeVals); + void *ArgToStringCookie; + ArgToStringFnTy ArgToStringFn; + + /// \brief ID of the "delayed" diagnostic, which is a (typically + /// fatal) diagnostic that had to be delayed because it was found + /// while emitting another diagnostic. + unsigned DelayedDiagID; + + /// \brief First string argument for the delayed diagnostic. + std::string DelayedDiagArg1; + + /// \brief Second string argument for the delayed diagnostic. + std::string DelayedDiagArg2; + + /// \brief Optional flag value. + /// + /// Some flags accept values, for instance: -Wframe-larger-than=<value> and + /// -Rpass=<value>. The content of this string is emitted after the flag name + /// and '='. + std::string FlagValue; + +public: + explicit DiagnosticsEngine( + const IntrusiveRefCntPtr<DiagnosticIDs> &Diags, + DiagnosticOptions *DiagOpts, + DiagnosticConsumer *client = nullptr, + bool ShouldOwnClient = true); + ~DiagnosticsEngine(); + + const IntrusiveRefCntPtr<DiagnosticIDs> &getDiagnosticIDs() const { + return Diags; + } + + /// \brief Retrieve the diagnostic options. + DiagnosticOptions &getDiagnosticOptions() const { return *DiagOpts; } + + typedef llvm::iterator_range<DiagState::const_iterator> diag_mapping_range; + + /// \brief Get the current set of diagnostic mappings. + diag_mapping_range getDiagnosticMappings() const { + const DiagState &DS = *GetCurDiagState(); + return diag_mapping_range(DS.begin(), DS.end()); + } + + DiagnosticConsumer *getClient() { return Client; } + const DiagnosticConsumer *getClient() const { return Client; } + + /// \brief Determine whether this \c DiagnosticsEngine object own its client. + bool ownsClient() const { return Owner != nullptr; } + + /// \brief Return the current diagnostic client along with ownership of that + /// client. + std::unique_ptr<DiagnosticConsumer> takeClient() { return std::move(Owner); } + + bool hasSourceManager() const { return SourceMgr != nullptr; } + SourceManager &getSourceManager() const { + assert(SourceMgr && "SourceManager not set!"); + return *SourceMgr; + } + void setSourceManager(SourceManager *SrcMgr) { SourceMgr = SrcMgr; } + + //===--------------------------------------------------------------------===// + // DiagnosticsEngine characterization methods, used by a client to customize + // how diagnostics are emitted. + // + + /// \brief Copies the current DiagMappings and pushes the new copy + /// onto the top of the stack. + void pushMappings(SourceLocation Loc); + + /// \brief Pops the current DiagMappings off the top of the stack, + /// causing the new top of the stack to be the active mappings. + /// + /// \returns \c true if the pop happens, \c false if there is only one + /// DiagMapping on the stack. + bool popMappings(SourceLocation Loc); + + /// \brief Set the diagnostic client associated with this diagnostic object. + /// + /// \param ShouldOwnClient true if the diagnostic object should take + /// ownership of \c client. + void setClient(DiagnosticConsumer *client, bool ShouldOwnClient = true); + + /// \brief Specify a limit for the number of errors we should + /// emit before giving up. + /// + /// Zero disables the limit. + void setErrorLimit(unsigned Limit) { ErrorLimit = Limit; } + + /// \brief Specify the maximum number of template instantiation + /// notes to emit along with a given diagnostic. + void setTemplateBacktraceLimit(unsigned Limit) { + TemplateBacktraceLimit = Limit; + } + + /// \brief Retrieve the maximum number of template instantiation + /// notes to emit along with a given diagnostic. + unsigned getTemplateBacktraceLimit() const { + return TemplateBacktraceLimit; + } + + /// \brief Specify the maximum number of constexpr evaluation + /// notes to emit along with a given diagnostic. + void setConstexprBacktraceLimit(unsigned Limit) { + ConstexprBacktraceLimit = Limit; + } + + /// \brief Retrieve the maximum number of constexpr evaluation + /// notes to emit along with a given diagnostic. + unsigned getConstexprBacktraceLimit() const { + return ConstexprBacktraceLimit; + } + + /// \brief When set to true, any unmapped warnings are ignored. + /// + /// If this and WarningsAsErrors are both set, then this one wins. + void setIgnoreAllWarnings(bool Val) { IgnoreAllWarnings = Val; } + bool getIgnoreAllWarnings() const { return IgnoreAllWarnings; } + + /// \brief When set to true, any unmapped ignored warnings are no longer + /// ignored. + /// + /// If this and IgnoreAllWarnings are both set, then that one wins. + void setEnableAllWarnings(bool Val) { EnableAllWarnings = Val; } + bool getEnableAllWarnings() const { return EnableAllWarnings; } + + /// \brief When set to true, any warnings reported are issued as errors. + void setWarningsAsErrors(bool Val) { WarningsAsErrors = Val; } + bool getWarningsAsErrors() const { return WarningsAsErrors; } + + /// \brief When set to true, any error reported is made a fatal error. + void setErrorsAsFatal(bool Val) { ErrorsAsFatal = Val; } + bool getErrorsAsFatal() const { return ErrorsAsFatal; } + + /// \brief When set to true mask warnings that come from system headers. + void setSuppressSystemWarnings(bool Val) { SuppressSystemWarnings = Val; } + bool getSuppressSystemWarnings() const { return SuppressSystemWarnings; } + + /// \brief Suppress all diagnostics, to silence the front end when we + /// know that we don't want any more diagnostics to be passed along to the + /// client + void setSuppressAllDiagnostics(bool Val = true) { + SuppressAllDiagnostics = Val; + } + bool getSuppressAllDiagnostics() const { return SuppressAllDiagnostics; } + + /// \brief Set type eliding, to skip outputting same types occurring in + /// template types. + void setElideType(bool Val = true) { ElideType = Val; } + bool getElideType() { return ElideType; } + + /// \brief Set tree printing, to outputting the template difference in a + /// tree format. + void setPrintTemplateTree(bool Val = false) { PrintTemplateTree = Val; } + bool getPrintTemplateTree() { return PrintTemplateTree; } + + /// \brief Set color printing, so the type diffing will inject color markers + /// into the output. + void setShowColors(bool Val = false) { ShowColors = Val; } + bool getShowColors() { return ShowColors; } + + /// \brief Specify which overload candidates to show when overload resolution + /// fails. + /// + /// By default, we show all candidates. + void setShowOverloads(OverloadsShown Val) { + ShowOverloads = Val; + } + OverloadsShown getShowOverloads() const { return ShowOverloads; } + + /// \brief Pretend that the last diagnostic issued was ignored, so any + /// subsequent notes will be suppressed. + /// + /// This can be used by clients who suppress diagnostics themselves. + void setLastDiagnosticIgnored() { + if (LastDiagLevel == DiagnosticIDs::Fatal) + FatalErrorOccurred = true; + LastDiagLevel = DiagnosticIDs::Ignored; + } + + /// \brief Determine whether the previous diagnostic was ignored. This can + /// be used by clients that want to determine whether notes attached to a + /// diagnostic will be suppressed. + bool isLastDiagnosticIgnored() const { + return LastDiagLevel == DiagnosticIDs::Ignored; + } + + /// \brief Controls whether otherwise-unmapped extension diagnostics are + /// mapped onto ignore/warning/error. + /// + /// This corresponds to the GCC -pedantic and -pedantic-errors option. + void setExtensionHandlingBehavior(diag::Severity H) { ExtBehavior = H; } + diag::Severity getExtensionHandlingBehavior() const { return ExtBehavior; } + + /// \brief Counter bumped when an __extension__ block is/ encountered. + /// + /// When non-zero, all extension diagnostics are entirely silenced, no + /// matter how they are mapped. + void IncrementAllExtensionsSilenced() { ++AllExtensionsSilenced; } + void DecrementAllExtensionsSilenced() { --AllExtensionsSilenced; } + bool hasAllExtensionsSilenced() { return AllExtensionsSilenced != 0; } + + /// \brief This allows the client to specify that certain warnings are + /// ignored. + /// + /// Notes can never be mapped, errors can only be mapped to fatal, and + /// WARNINGs and EXTENSIONs can be mapped arbitrarily. + /// + /// \param Loc The source location that this change of diagnostic state should + /// take affect. It can be null if we are setting the latest state. + void setSeverity(diag::kind Diag, diag::Severity Map, SourceLocation Loc); + + /// \brief Change an entire diagnostic group (e.g. "unknown-pragmas") to + /// have the specified mapping. + /// + /// \returns true (and ignores the request) if "Group" was unknown, false + /// otherwise. + /// + /// \param Flavor The flavor of group to affect. -Rfoo does not affect the + /// state of the -Wfoo group and vice versa. + /// + /// \param Loc The source location that this change of diagnostic state should + /// take affect. It can be null if we are setting the state from command-line. + bool setSeverityForGroup(diag::Flavor Flavor, StringRef Group, + diag::Severity Map, + SourceLocation Loc = SourceLocation()); + + /// \brief Set the warning-as-error flag for the given diagnostic group. + /// + /// This function always only operates on the current diagnostic state. + /// + /// \returns True if the given group is unknown, false otherwise. + bool setDiagnosticGroupWarningAsError(StringRef Group, bool Enabled); + + /// \brief Set the error-as-fatal flag for the given diagnostic group. + /// + /// This function always only operates on the current diagnostic state. + /// + /// \returns True if the given group is unknown, false otherwise. + bool setDiagnosticGroupErrorAsFatal(StringRef Group, bool Enabled); + + /// \brief Add the specified mapping to all diagnostics of the specified + /// flavor. + /// + /// Mainly to be used by -Wno-everything to disable all warnings but allow + /// subsequent -W options to enable specific warnings. + void setSeverityForAll(diag::Flavor Flavor, diag::Severity Map, + SourceLocation Loc = SourceLocation()); + + bool hasErrorOccurred() const { return ErrorOccurred; } + + /// \brief Errors that actually prevent compilation, not those that are + /// upgraded from a warning by -Werror. + bool hasUncompilableErrorOccurred() const { + return UncompilableErrorOccurred; + } + bool hasFatalErrorOccurred() const { return FatalErrorOccurred; } + + /// \brief Determine whether any kind of unrecoverable error has occurred. + bool hasUnrecoverableErrorOccurred() const { + return FatalErrorOccurred || UnrecoverableErrorOccurred; + } + + unsigned getNumWarnings() const { return NumWarnings; } + + void setNumWarnings(unsigned NumWarnings) { + this->NumWarnings = NumWarnings; + } + + /// \brief Return an ID for a diagnostic with the specified format string and + /// level. + /// + /// If this is the first request for this diagnostic, it is registered and + /// created, otherwise the existing ID is returned. + /// + /// \param FormatString A fixed diagnostic format string that will be hashed + /// and mapped to a unique DiagID. + template <unsigned N> + unsigned getCustomDiagID(Level L, const char (&FormatString)[N]) { + return Diags->getCustomDiagID((DiagnosticIDs::Level)L, + StringRef(FormatString, N - 1)); + } + + /// \brief Converts a diagnostic argument (as an intptr_t) into the string + /// that represents it. + void ConvertArgToString(ArgumentKind Kind, intptr_t Val, + StringRef Modifier, StringRef Argument, + ArrayRef<ArgumentValue> PrevArgs, + SmallVectorImpl<char> &Output, + ArrayRef<intptr_t> QualTypeVals) const { + ArgToStringFn(Kind, Val, Modifier, Argument, PrevArgs, Output, + ArgToStringCookie, QualTypeVals); + } + + void SetArgToStringFn(ArgToStringFnTy Fn, void *Cookie) { + ArgToStringFn = Fn; + ArgToStringCookie = Cookie; + } + + /// \brief Note that the prior diagnostic was emitted by some other + /// \c DiagnosticsEngine, and we may be attaching a note to that diagnostic. + void notePriorDiagnosticFrom(const DiagnosticsEngine &Other) { + LastDiagLevel = Other.LastDiagLevel; + } + + /// \brief Reset the state of the diagnostic object to its initial + /// configuration. + void Reset(); + + //===--------------------------------------------------------------------===// + // DiagnosticsEngine classification and reporting interfaces. + // + + /// \brief Determine whether the diagnostic is known to be ignored. + /// + /// This can be used to opportunistically avoid expensive checks when it's + /// known for certain that the diagnostic has been suppressed at the + /// specified location \p Loc. + /// + /// \param Loc The source location we are interested in finding out the + /// diagnostic state. Can be null in order to query the latest state. + bool isIgnored(unsigned DiagID, SourceLocation Loc) const { + return Diags->getDiagnosticSeverity(DiagID, Loc, *this) == + diag::Severity::Ignored; + } + + /// \brief Based on the way the client configured the DiagnosticsEngine + /// object, classify the specified diagnostic ID into a Level, consumable by + /// the DiagnosticConsumer. + /// + /// To preserve invariant assumptions, this function should not be used to + /// influence parse or semantic analysis actions. Instead consider using + /// \c isIgnored(). + /// + /// \param Loc The source location we are interested in finding out the + /// diagnostic state. Can be null in order to query the latest state. + Level getDiagnosticLevel(unsigned DiagID, SourceLocation Loc) const { + return (Level)Diags->getDiagnosticLevel(DiagID, Loc, *this); + } + + /// \brief Issue the message to the client. + /// + /// This actually returns an instance of DiagnosticBuilder which emits the + /// diagnostics (through @c ProcessDiag) when it is destroyed. + /// + /// \param DiagID A member of the @c diag::kind enum. + /// \param Loc Represents the source location associated with the diagnostic, + /// which can be an invalid location if no position information is available. + inline DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID); + inline DiagnosticBuilder Report(unsigned DiagID); + + void Report(const StoredDiagnostic &storedDiag); + + /// \brief Determine whethere there is already a diagnostic in flight. + bool isDiagnosticInFlight() const { return CurDiagID != ~0U; } + + /// \brief Set the "delayed" diagnostic that will be emitted once + /// the current diagnostic completes. + /// + /// If a diagnostic is already in-flight but the front end must + /// report a problem (e.g., with an inconsistent file system + /// state), this routine sets a "delayed" diagnostic that will be + /// emitted after the current diagnostic completes. This should + /// only be used for fatal errors detected at inconvenient + /// times. If emitting a delayed diagnostic causes a second delayed + /// diagnostic to be introduced, that second delayed diagnostic + /// will be ignored. + /// + /// \param DiagID The ID of the diagnostic being delayed. + /// + /// \param Arg1 A string argument that will be provided to the + /// diagnostic. A copy of this string will be stored in the + /// DiagnosticsEngine object itself. + /// + /// \param Arg2 A string argument that will be provided to the + /// diagnostic. A copy of this string will be stored in the + /// DiagnosticsEngine object itself. + void SetDelayedDiagnostic(unsigned DiagID, StringRef Arg1 = "", + StringRef Arg2 = ""); + + /// \brief Clear out the current diagnostic. + void Clear() { CurDiagID = ~0U; } + + /// \brief Return the value associated with this diagnostic flag. + StringRef getFlagValue() const { return FlagValue; } + +private: + /// \brief Report the delayed diagnostic. + void ReportDelayed(); + + // This is private state used by DiagnosticBuilder. We put it here instead of + // in DiagnosticBuilder in order to keep DiagnosticBuilder a small lightweight + // object. This implementation choice means that we can only have one + // diagnostic "in flight" at a time, but this seems to be a reasonable + // tradeoff to keep these objects small. Assertions verify that only one + // diagnostic is in flight at a time. + friend class DiagnosticIDs; + friend class DiagnosticBuilder; + friend class Diagnostic; + friend class PartialDiagnostic; + friend class DiagnosticErrorTrap; + + /// \brief The location of the current diagnostic that is in flight. + SourceLocation CurDiagLoc; + + /// \brief The ID of the current diagnostic that is in flight. + /// + /// This is set to ~0U when there is no diagnostic in flight. + unsigned CurDiagID; + + enum { + /// \brief The maximum number of arguments we can hold. + /// + /// We currently only support up to 10 arguments (%0-%9). A single + /// diagnostic with more than that almost certainly has to be simplified + /// anyway. + MaxArguments = 10, + }; + + /// \brief The number of entries in Arguments. + signed char NumDiagArgs; + + /// \brief Specifies whether an argument is in DiagArgumentsStr or + /// in DiagArguments. + /// + /// This is an array of ArgumentKind::ArgumentKind enum values, one for each + /// argument. + unsigned char DiagArgumentsKind[MaxArguments]; + + /// \brief Holds the values of each string argument for the current + /// diagnostic. + /// + /// This is only used when the corresponding ArgumentKind is ak_std_string. + std::string DiagArgumentsStr[MaxArguments]; + + /// \brief The values for the various substitution positions. + /// + /// This is used when the argument is not an std::string. The specific + /// value is mangled into an intptr_t and the interpretation depends on + /// exactly what sort of argument kind it is. + intptr_t DiagArgumentsVal[MaxArguments]; + + /// \brief The list of ranges added to this diagnostic. + SmallVector<CharSourceRange, 8> DiagRanges; + + /// \brief If valid, provides a hint with some code to insert, remove, + /// or modify at a particular position. + SmallVector<FixItHint, 8> DiagFixItHints; + + DiagnosticMapping makeUserMapping(diag::Severity Map, SourceLocation L) { + bool isPragma = L.isValid(); + DiagnosticMapping Mapping = + DiagnosticMapping::Make(Map, /*IsUser=*/true, isPragma); + + // If this is a pragma mapping, then set the diagnostic mapping flags so + // that we override command line options. + if (isPragma) { + Mapping.setNoWarningAsError(true); + Mapping.setNoErrorAsFatal(true); + } + + return Mapping; + } + + /// \brief Used to report a diagnostic that is finally fully formed. + /// + /// \returns true if the diagnostic was emitted, false if it was suppressed. + bool ProcessDiag() { + return Diags->ProcessDiag(*this); + } + + /// @name Diagnostic Emission + /// @{ +protected: + // Sema requires access to the following functions because the current design + // of SFINAE requires it to use its own SemaDiagnosticBuilder, which needs to + // access us directly to ensure we minimize the emitted code for the common + // Sema::Diag() patterns. + friend class Sema; + + /// \brief Emit the current diagnostic and clear the diagnostic state. + /// + /// \param Force Emit the diagnostic regardless of suppression settings. + bool EmitCurrentDiagnostic(bool Force = false); + + unsigned getCurrentDiagID() const { return CurDiagID; } + + SourceLocation getCurrentDiagLoc() const { return CurDiagLoc; } + + /// @} + + friend class ASTReader; + friend class ASTWriter; +}; + +/// \brief RAII class that determines when any errors have occurred +/// between the time the instance was created and the time it was +/// queried. +class DiagnosticErrorTrap { + DiagnosticsEngine &Diag; + unsigned NumErrors; + unsigned NumUnrecoverableErrors; + +public: + explicit DiagnosticErrorTrap(DiagnosticsEngine &Diag) + : Diag(Diag) { reset(); } + + /// \brief Determine whether any errors have occurred since this + /// object instance was created. + bool hasErrorOccurred() const { + return Diag.TrapNumErrorsOccurred > NumErrors; + } + + /// \brief Determine whether any unrecoverable errors have occurred since this + /// object instance was created. + bool hasUnrecoverableErrorOccurred() const { + return Diag.TrapNumUnrecoverableErrorsOccurred > NumUnrecoverableErrors; + } + + /// \brief Set to initial state of "no errors occurred". + void reset() { + NumErrors = Diag.TrapNumErrorsOccurred; + NumUnrecoverableErrors = Diag.TrapNumUnrecoverableErrorsOccurred; + } +}; + +//===----------------------------------------------------------------------===// +// DiagnosticBuilder +//===----------------------------------------------------------------------===// + +/// \brief A little helper class used to produce diagnostics. +/// +/// This is constructed by the DiagnosticsEngine::Report method, and +/// allows insertion of extra information (arguments and source ranges) into +/// the currently "in flight" diagnostic. When the temporary for the builder +/// is destroyed, the diagnostic is issued. +/// +/// Note that many of these will be created as temporary objects (many call +/// sites), so we want them to be small and we never want their address taken. +/// This ensures that compilers with somewhat reasonable optimizers will promote +/// the common fields to registers, eliminating increments of the NumArgs field, +/// for example. +class DiagnosticBuilder { + mutable DiagnosticsEngine *DiagObj = nullptr; + mutable unsigned NumArgs = 0; + + /// \brief Status variable indicating if this diagnostic is still active. + /// + // NOTE: This field is redundant with DiagObj (IsActive iff (DiagObj == 0)), + // but LLVM is not currently smart enough to eliminate the null check that + // Emit() would end up with if we used that as our status variable. + mutable bool IsActive = false; + + /// \brief Flag indicating that this diagnostic is being emitted via a + /// call to ForceEmit. + mutable bool IsForceEmit = false; + + void operator=(const DiagnosticBuilder &) = delete; + friend class DiagnosticsEngine; + + DiagnosticBuilder() = default; + + explicit DiagnosticBuilder(DiagnosticsEngine *diagObj) + : DiagObj(diagObj), IsActive(true) { + assert(diagObj && "DiagnosticBuilder requires a valid DiagnosticsEngine!"); + diagObj->DiagRanges.clear(); + diagObj->DiagFixItHints.clear(); + } + + friend class PartialDiagnostic; + +protected: + void FlushCounts() { + DiagObj->NumDiagArgs = NumArgs; + } + + /// \brief Clear out the current diagnostic. + void Clear() const { + DiagObj = nullptr; + IsActive = false; + IsForceEmit = false; + } + + /// \brief Determine whether this diagnostic is still active. + bool isActive() const { return IsActive; } + + /// \brief Force the diagnostic builder to emit the diagnostic now. + /// + /// Once this function has been called, the DiagnosticBuilder object + /// should not be used again before it is destroyed. + /// + /// \returns true if a diagnostic was emitted, false if the + /// diagnostic was suppressed. + bool Emit() { + // If this diagnostic is inactive, then its soul was stolen by the copy ctor + // (or by a subclass, as in SemaDiagnosticBuilder). + if (!isActive()) return false; + + // When emitting diagnostics, we set the final argument count into + // the DiagnosticsEngine object. + FlushCounts(); + + // Process the diagnostic. + bool Result = DiagObj->EmitCurrentDiagnostic(IsForceEmit); + + // This diagnostic is dead. + Clear(); + + return Result; + } + +public: + /// Copy constructor. When copied, this "takes" the diagnostic info from the + /// input and neuters it. + DiagnosticBuilder(const DiagnosticBuilder &D) { + DiagObj = D.DiagObj; + IsActive = D.IsActive; + IsForceEmit = D.IsForceEmit; + D.Clear(); + NumArgs = D.NumArgs; + } + + /// \brief Retrieve an empty diagnostic builder. + static DiagnosticBuilder getEmpty() { + return DiagnosticBuilder(); + } + + /// \brief Emits the diagnostic. + ~DiagnosticBuilder() { + Emit(); + } + + /// \brief Forces the diagnostic to be emitted. + const DiagnosticBuilder &setForceEmit() const { + IsForceEmit = true; + return *this; + } + + /// \brief Conversion of DiagnosticBuilder to bool always returns \c true. + /// + /// This allows is to be used in boolean error contexts (where \c true is + /// used to indicate that an error has occurred), like: + /// \code + /// return Diag(...); + /// \endcode + operator bool() const { return true; } + + void AddString(StringRef S) const { + assert(isActive() && "Clients must not add to cleared diagnostic!"); + assert(NumArgs < DiagnosticsEngine::MaxArguments && + "Too many arguments to diagnostic!"); + DiagObj->DiagArgumentsKind[NumArgs] = DiagnosticsEngine::ak_std_string; + DiagObj->DiagArgumentsStr[NumArgs++] = S; + } + + void AddTaggedVal(intptr_t V, DiagnosticsEngine::ArgumentKind Kind) const { + assert(isActive() && "Clients must not add to cleared diagnostic!"); + assert(NumArgs < DiagnosticsEngine::MaxArguments && + "Too many arguments to diagnostic!"); + DiagObj->DiagArgumentsKind[NumArgs] = Kind; + DiagObj->DiagArgumentsVal[NumArgs++] = V; + } + + void AddSourceRange(const CharSourceRange &R) const { + assert(isActive() && "Clients must not add to cleared diagnostic!"); + DiagObj->DiagRanges.push_back(R); + } + + void AddFixItHint(const FixItHint &Hint) const { + assert(isActive() && "Clients must not add to cleared diagnostic!"); + if (!Hint.isNull()) + DiagObj->DiagFixItHints.push_back(Hint); + } + + void addFlagValue(StringRef V) const { DiagObj->FlagValue = V; } +}; + +struct AddFlagValue { + explicit AddFlagValue(StringRef V) : Val(V) {} + StringRef Val; +}; + +/// \brief Register a value for the flag in the current diagnostic. This +/// value will be shown as the suffix "=value" after the flag name. It is +/// useful in cases where the diagnostic flag accepts values (e.g., +/// -Rpass or -Wframe-larger-than). +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const AddFlagValue V) { + DB.addFlagValue(V.Val); + return DB; +} + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + StringRef S) { + DB.AddString(S); + return DB; +} + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const char *Str) { + DB.AddTaggedVal(reinterpret_cast<intptr_t>(Str), + DiagnosticsEngine::ak_c_string); + return DB; +} + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, int I) { + DB.AddTaggedVal(I, DiagnosticsEngine::ak_sint); + return DB; +} + +// We use enable_if here to prevent that this overload is selected for +// pointers or other arguments that are implicitly convertible to bool. +template <typename T> +inline +typename std::enable_if<std::is_same<T, bool>::value, + const DiagnosticBuilder &>::type +operator<<(const DiagnosticBuilder &DB, T I) { + DB.AddTaggedVal(I, DiagnosticsEngine::ak_sint); + return DB; +} + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + unsigned I) { + DB.AddTaggedVal(I, DiagnosticsEngine::ak_uint); + return DB; +} + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + tok::TokenKind I) { + DB.AddTaggedVal(static_cast<unsigned>(I), DiagnosticsEngine::ak_tokenkind); + return DB; +} + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const IdentifierInfo *II) { + DB.AddTaggedVal(reinterpret_cast<intptr_t>(II), + DiagnosticsEngine::ak_identifierinfo); + return DB; +} + +// Adds a DeclContext to the diagnostic. The enable_if template magic is here +// so that we only match those arguments that are (statically) DeclContexts; +// other arguments that derive from DeclContext (e.g., RecordDecls) will not +// match. +template<typename T> +inline +typename std::enable_if<std::is_same<T, DeclContext>::value, + const DiagnosticBuilder &>::type +operator<<(const DiagnosticBuilder &DB, T *DC) { + DB.AddTaggedVal(reinterpret_cast<intptr_t>(DC), + DiagnosticsEngine::ak_declcontext); + return DB; +} + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + SourceRange R) { + DB.AddSourceRange(CharSourceRange::getTokenRange(R)); + return DB; +} + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + ArrayRef<SourceRange> Ranges) { + for (SourceRange R : Ranges) + DB.AddSourceRange(CharSourceRange::getTokenRange(R)); + return DB; +} + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const CharSourceRange &R) { + DB.AddSourceRange(R); + return DB; +} + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const FixItHint &Hint) { + DB.AddFixItHint(Hint); + return DB; +} + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + ArrayRef<FixItHint> Hints) { + for (const FixItHint &Hint : Hints) + DB.AddFixItHint(Hint); + return DB; +} + +/// A nullability kind paired with a bit indicating whether it used a +/// context-sensitive keyword. +typedef std::pair<NullabilityKind, bool> DiagNullabilityKind; + +const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + DiagNullabilityKind nullability); + +inline DiagnosticBuilder DiagnosticsEngine::Report(SourceLocation Loc, + unsigned DiagID) { + assert(CurDiagID == ~0U && "Multiple diagnostics in flight at once!"); + CurDiagLoc = Loc; + CurDiagID = DiagID; + FlagValue.clear(); + return DiagnosticBuilder(this); +} + +inline DiagnosticBuilder DiagnosticsEngine::Report(unsigned DiagID) { + return Report(SourceLocation(), DiagID); +} + +//===----------------------------------------------------------------------===// +// Diagnostic +//===----------------------------------------------------------------------===// + +/// A little helper class (which is basically a smart pointer that forwards +/// info from DiagnosticsEngine) that allows clients to enquire about the +/// currently in-flight diagnostic. +class Diagnostic { + const DiagnosticsEngine *DiagObj; + StringRef StoredDiagMessage; +public: + explicit Diagnostic(const DiagnosticsEngine *DO) : DiagObj(DO) {} + Diagnostic(const DiagnosticsEngine *DO, StringRef storedDiagMessage) + : DiagObj(DO), StoredDiagMessage(storedDiagMessage) {} + + const DiagnosticsEngine *getDiags() const { return DiagObj; } + unsigned getID() const { return DiagObj->CurDiagID; } + const SourceLocation &getLocation() const { return DiagObj->CurDiagLoc; } + bool hasSourceManager() const { return DiagObj->hasSourceManager(); } + SourceManager &getSourceManager() const { return DiagObj->getSourceManager();} + + unsigned getNumArgs() const { return DiagObj->NumDiagArgs; } + + /// \brief Return the kind of the specified index. + /// + /// Based on the kind of argument, the accessors below can be used to get + /// the value. + /// + /// \pre Idx < getNumArgs() + DiagnosticsEngine::ArgumentKind getArgKind(unsigned Idx) const { + assert(Idx < getNumArgs() && "Argument index out of range!"); + return (DiagnosticsEngine::ArgumentKind)DiagObj->DiagArgumentsKind[Idx]; + } + + /// \brief Return the provided argument string specified by \p Idx. + /// \pre getArgKind(Idx) == DiagnosticsEngine::ak_std_string + const std::string &getArgStdStr(unsigned Idx) const { + assert(getArgKind(Idx) == DiagnosticsEngine::ak_std_string && + "invalid argument accessor!"); + return DiagObj->DiagArgumentsStr[Idx]; + } + + /// \brief Return the specified C string argument. + /// \pre getArgKind(Idx) == DiagnosticsEngine::ak_c_string + const char *getArgCStr(unsigned Idx) const { + assert(getArgKind(Idx) == DiagnosticsEngine::ak_c_string && + "invalid argument accessor!"); + return reinterpret_cast<const char*>(DiagObj->DiagArgumentsVal[Idx]); + } + + /// \brief Return the specified signed integer argument. + /// \pre getArgKind(Idx) == DiagnosticsEngine::ak_sint + int getArgSInt(unsigned Idx) const { + assert(getArgKind(Idx) == DiagnosticsEngine::ak_sint && + "invalid argument accessor!"); + return (int)DiagObj->DiagArgumentsVal[Idx]; + } + + /// \brief Return the specified unsigned integer argument. + /// \pre getArgKind(Idx) == DiagnosticsEngine::ak_uint + unsigned getArgUInt(unsigned Idx) const { + assert(getArgKind(Idx) == DiagnosticsEngine::ak_uint && + "invalid argument accessor!"); + return (unsigned)DiagObj->DiagArgumentsVal[Idx]; + } + + /// \brief Return the specified IdentifierInfo argument. + /// \pre getArgKind(Idx) == DiagnosticsEngine::ak_identifierinfo + const IdentifierInfo *getArgIdentifier(unsigned Idx) const { + assert(getArgKind(Idx) == DiagnosticsEngine::ak_identifierinfo && + "invalid argument accessor!"); + return reinterpret_cast<IdentifierInfo*>(DiagObj->DiagArgumentsVal[Idx]); + } + + /// \brief Return the specified non-string argument in an opaque form. + /// \pre getArgKind(Idx) != DiagnosticsEngine::ak_std_string + intptr_t getRawArg(unsigned Idx) const { + assert(getArgKind(Idx) != DiagnosticsEngine::ak_std_string && + "invalid argument accessor!"); + return DiagObj->DiagArgumentsVal[Idx]; + } + + /// \brief Return the number of source ranges associated with this diagnostic. + unsigned getNumRanges() const { + return DiagObj->DiagRanges.size(); + } + + /// \pre Idx < getNumRanges() + const CharSourceRange &getRange(unsigned Idx) const { + assert(Idx < getNumRanges() && "Invalid diagnostic range index!"); + return DiagObj->DiagRanges[Idx]; + } + + /// \brief Return an array reference for this diagnostic's ranges. + ArrayRef<CharSourceRange> getRanges() const { + return DiagObj->DiagRanges; + } + + unsigned getNumFixItHints() const { + return DiagObj->DiagFixItHints.size(); + } + + const FixItHint &getFixItHint(unsigned Idx) const { + assert(Idx < getNumFixItHints() && "Invalid index!"); + return DiagObj->DiagFixItHints[Idx]; + } + + ArrayRef<FixItHint> getFixItHints() const { + return DiagObj->DiagFixItHints; + } + + /// \brief Format this diagnostic into a string, substituting the + /// formal arguments into the %0 slots. + /// + /// The result is appended onto the \p OutStr array. + void FormatDiagnostic(SmallVectorImpl<char> &OutStr) const; + + /// \brief Format the given format-string into the output buffer using the + /// arguments stored in this diagnostic. + void FormatDiagnostic(const char *DiagStr, const char *DiagEnd, + SmallVectorImpl<char> &OutStr) const; +}; + +/** + * \brief Represents a diagnostic in a form that can be retained until its + * corresponding source manager is destroyed. + */ +class StoredDiagnostic { + unsigned ID; + DiagnosticsEngine::Level Level; + FullSourceLoc Loc; + std::string Message; + std::vector<CharSourceRange> Ranges; + std::vector<FixItHint> FixIts; + +public: + StoredDiagnostic() = default; + StoredDiagnostic(DiagnosticsEngine::Level Level, const Diagnostic &Info); + StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID, + StringRef Message); + StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID, + StringRef Message, FullSourceLoc Loc, + ArrayRef<CharSourceRange> Ranges, + ArrayRef<FixItHint> Fixits); + + /// \brief Evaluates true when this object stores a diagnostic. + explicit operator bool() const { return Message.size() > 0; } + + unsigned getID() const { return ID; } + DiagnosticsEngine::Level getLevel() const { return Level; } + const FullSourceLoc &getLocation() const { return Loc; } + StringRef getMessage() const { return Message; } + + void setLocation(FullSourceLoc Loc) { this->Loc = Loc; } + + typedef std::vector<CharSourceRange>::const_iterator range_iterator; + range_iterator range_begin() const { return Ranges.begin(); } + range_iterator range_end() const { return Ranges.end(); } + unsigned range_size() const { return Ranges.size(); } + + ArrayRef<CharSourceRange> getRanges() const { + return llvm::makeArrayRef(Ranges); + } + + + typedef std::vector<FixItHint>::const_iterator fixit_iterator; + fixit_iterator fixit_begin() const { return FixIts.begin(); } + fixit_iterator fixit_end() const { return FixIts.end(); } + unsigned fixit_size() const { return FixIts.size(); } + + ArrayRef<FixItHint> getFixIts() const { + return llvm::makeArrayRef(FixIts); + } +}; + +/// \brief Abstract interface, implemented by clients of the front-end, which +/// formats and prints fully processed diagnostics. +class DiagnosticConsumer { +protected: + unsigned NumWarnings; ///< Number of warnings reported + unsigned NumErrors; ///< Number of errors reported + +public: + DiagnosticConsumer() : NumWarnings(0), NumErrors(0) { } + + unsigned getNumErrors() const { return NumErrors; } + unsigned getNumWarnings() const { return NumWarnings; } + virtual void clear() { NumWarnings = NumErrors = 0; } + + virtual ~DiagnosticConsumer(); + + /// \brief Callback to inform the diagnostic client that processing + /// of a source file is beginning. + /// + /// Note that diagnostics may be emitted outside the processing of a source + /// file, for example during the parsing of command line options. However, + /// diagnostics with source range information are required to only be emitted + /// in between BeginSourceFile() and EndSourceFile(). + /// + /// \param LangOpts The language options for the source file being processed. + /// \param PP The preprocessor object being used for the source; this is + /// optional, e.g., it may not be present when processing AST source files. + virtual void BeginSourceFile(const LangOptions &LangOpts, + const Preprocessor *PP = nullptr) {} + + /// \brief Callback to inform the diagnostic client that processing + /// of a source file has ended. + /// + /// The diagnostic client should assume that any objects made available via + /// BeginSourceFile() are inaccessible. + virtual void EndSourceFile() {} + + /// \brief Callback to inform the diagnostic client that processing of all + /// source files has ended. + virtual void finish() {} + + /// \brief Indicates whether the diagnostics handled by this + /// DiagnosticConsumer should be included in the number of diagnostics + /// reported by DiagnosticsEngine. + /// + /// The default implementation returns true. + virtual bool IncludeInDiagnosticCounts() const; + + /// \brief Handle this diagnostic, reporting it to the user or + /// capturing it to a log as needed. + /// + /// The default implementation just keeps track of the total number of + /// warnings and errors. + virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, + const Diagnostic &Info); +}; + +/// \brief A diagnostic client that ignores all diagnostics. +class IgnoringDiagConsumer : public DiagnosticConsumer { + virtual void anchor(); + void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, + const Diagnostic &Info) override { + // Just ignore it. + } +}; + +/// \brief Diagnostic consumer that forwards diagnostics along to an +/// existing, already-initialized diagnostic consumer. +/// +class ForwardingDiagnosticConsumer : public DiagnosticConsumer { + DiagnosticConsumer &Target; + +public: + ForwardingDiagnosticConsumer(DiagnosticConsumer &Target) : Target(Target) {} + + ~ForwardingDiagnosticConsumer() override; + + void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, + const Diagnostic &Info) override; + void clear() override; + + bool IncludeInDiagnosticCounts() const override; +}; + +// Struct used for sending info about how a type should be printed. +struct TemplateDiffTypes { + intptr_t FromType; + intptr_t ToType; + unsigned PrintTree : 1; + unsigned PrintFromType : 1; + unsigned ElideType : 1; + unsigned ShowColors : 1; + // The printer sets this variable to true if the template diff was used. + unsigned TemplateDiffUsed : 1; +}; + +/// Special character that the diagnostic printer will use to toggle the bold +/// attribute. The character itself will be not be printed. +const char ToggleHighlight = 127; + + +/// ProcessWarningOptions - Initialize the diagnostic client and process the +/// warning options specified on the command line. +void ProcessWarningOptions(DiagnosticsEngine &Diags, + const DiagnosticOptions &Opts, + bool ReportDiags = true); + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.td b/contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.td new file mode 100644 index 0000000..48cbf09 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.td @@ -0,0 +1,127 @@ +//===--- Diagnostic.td - C Language Family Diagnostic Handling ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TableGen core definitions for the diagnostics +// and diagnostic control. +// +//===----------------------------------------------------------------------===// + +// Define the diagnostic severities. +class Severity<string N> { + string Name = N; +} +def SEV_Ignored : Severity<"Ignored">; +def SEV_Remark : Severity<"Remark">; +def SEV_Warning : Severity<"Warning">; +def SEV_Error : Severity<"Error">; +def SEV_Fatal : Severity<"Fatal">; + +// Define the diagnostic classes. +class DiagClass; +def CLASS_NOTE : DiagClass; +def CLASS_REMARK : DiagClass; +def CLASS_WARNING : DiagClass; +def CLASS_EXTENSION : DiagClass; +def CLASS_ERROR : DiagClass; + +// Responses to a diagnostic in a SFINAE context. +class SFINAEResponse; +def SFINAE_SubstitutionFailure : SFINAEResponse; +def SFINAE_Suppress : SFINAEResponse; +def SFINAE_Report : SFINAEResponse; +def SFINAE_AccessControl : SFINAEResponse; + +// Diagnostic Categories. These can be applied to groups or individual +// diagnostics to specify a category. +class DiagCategory<string Name> { + string CategoryName = Name; +} + +// Diagnostic Groups. +class DiagGroup<string Name, list<DiagGroup> subgroups = []> { + string GroupName = Name; + list<DiagGroup> SubGroups = subgroups; + string CategoryName = ""; +} +class InGroup<DiagGroup G> { DiagGroup Group = G; } +//class IsGroup<string Name> { DiagGroup Group = DiagGroup<Name>; } + + +// This defines all of the named diagnostic categories. +include "DiagnosticCategories.td" + +// This defines all of the named diagnostic groups. +include "DiagnosticGroups.td" + + +// All diagnostics emitted by the compiler are an indirect subclass of this. +class Diagnostic<string text, DiagClass DC, Severity defaultmapping> { + /// Component is specified by the file with a big let directive. + string Component = ?; + string Text = text; + DiagClass Class = DC; + SFINAEResponse SFINAE = SFINAE_Suppress; + bit AccessControl = 0; + bit WarningNoWerror = 0; + bit ShowInSystemHeader = 0; + Severity DefaultSeverity = defaultmapping; + DiagGroup Group; + string CategoryName = ""; +} + +class SFINAEFailure { + SFINAEResponse SFINAE = SFINAE_SubstitutionFailure; +} +class NoSFINAE { + SFINAEResponse SFINAE = SFINAE_Report; +} +class AccessControl { + SFINAEResponse SFINAE = SFINAE_AccessControl; +} + +class ShowInSystemHeader { + bit ShowInSystemHeader = 1; +} + +class SuppressInSystemHeader { + bit ShowInSystemHeader = 0; +} + +// FIXME: ExtWarn and Extension should also be SFINAEFailure by default. +class Error<string str> : Diagnostic<str, CLASS_ERROR, SEV_Error>, SFINAEFailure { + bit ShowInSystemHeader = 1; +} +class Warning<string str> : Diagnostic<str, CLASS_WARNING, SEV_Warning>; +class Remark<string str> : Diagnostic<str, CLASS_REMARK, SEV_Ignored>; +class Extension<string str> : Diagnostic<str, CLASS_EXTENSION, SEV_Ignored>; +class ExtWarn<string str> : Diagnostic<str, CLASS_EXTENSION, SEV_Warning>; +class Note<string str> : Diagnostic<str, CLASS_NOTE, SEV_Fatal/*ignored*/>; + + +class DefaultIgnore { Severity DefaultSeverity = SEV_Ignored; } +class DefaultWarn { Severity DefaultSeverity = SEV_Warning; } +class DefaultError { Severity DefaultSeverity = SEV_Error; } +class DefaultFatal { Severity DefaultSeverity = SEV_Fatal; } +class DefaultWarnNoWerror { + bit WarningNoWerror = 1; +} +class DefaultRemark { Severity DefaultSeverity = SEV_Remark; } + +// Definitions for Diagnostics. +include "DiagnosticASTKinds.td" +include "DiagnosticAnalysisKinds.td" +include "DiagnosticCommentKinds.td" +include "DiagnosticCommonKinds.td" +include "DiagnosticDriverKinds.td" +include "DiagnosticFrontendKinds.td" +include "DiagnosticLexKinds.td" +include "DiagnosticParseKinds.td" +include "DiagnosticSemaKinds.td" +include "DiagnosticSerializationKinds.td" + diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticASTKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticASTKinds.td new file mode 100644 index 0000000..0b37030 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticASTKinds.td @@ -0,0 +1,266 @@ +//==--- DiagnosticASTKinds.td - libast diagnostics ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +let Component = "AST" in { + +// Constant expression diagnostics. These (and their users) belong in Sema. +def note_expr_divide_by_zero : Note<"division by zero">; +def note_constexpr_invalid_cast : Note< + "%select{reinterpret_cast|dynamic_cast|cast that performs the conversions of" + " a reinterpret_cast|cast from %1}0 is not allowed in a constant expression">; +def note_constexpr_invalid_downcast : Note< + "cannot cast object of dynamic type %0 to type %1">; +def note_constexpr_overflow : Note< + "value %0 is outside the range of representable values of type %1">; +def note_constexpr_negative_shift : Note<"negative shift count %0">; +def note_constexpr_large_shift : Note< + "shift count %0 >= width of type %1 (%2 bit%s2)">; +def note_constexpr_lshift_of_negative : Note<"left shift of negative value %0">; +def note_constexpr_lshift_discards : Note<"signed left shift discards bits">; +def note_constexpr_invalid_function : Note< + "%select{non-constexpr|undefined}0 %select{function|constructor}1 %2 cannot " + "be used in a constant expression">; +def note_constexpr_no_return : Note< + "control reached end of constexpr function">; +def note_constexpr_virtual_call : Note< + "cannot evaluate virtual function call in a constant expression">; +def note_constexpr_virtual_base : Note< + "cannot construct object of type %0 with virtual base class " + "in a constant expression">; +def note_constexpr_nonliteral : Note< + "non-literal type %0 cannot be used in a constant expression">; +def note_constexpr_non_global : Note< + "%select{pointer|reference}0 to %select{|subobject of }1" + "%select{temporary|%3}2 is not a constant expression">; +def note_constexpr_uninitialized : Note< + "%select{|sub}0object of type %1 is not initialized">; +def note_constexpr_array_index : Note<"cannot refer to element %0 of " + "%select{array of %2 elements|non-array object}1 in a constant expression">; +def note_constexpr_float_arithmetic : Note< + "floating point arithmetic produces %select{an infinity|a NaN}0">; +def note_constexpr_pointer_subtraction_not_same_array : Note< + "subtracted pointers are not elements of the same array">; +def note_constexpr_pointer_subtraction_zero_size : Note< + "subtraction of pointers to type %0 of zero size">; +def note_constexpr_pointer_comparison_base_classes : Note< + "comparison of addresses of subobjects of different base classes " + "has unspecified value">; +def note_constexpr_pointer_comparison_base_field : Note< + "comparison of address of base class subobject %0 of class %1 to field %2 " + "has unspecified value">; +def note_constexpr_pointer_comparison_differing_access : Note< + "comparison of address of fields %0 and %2 of %4 with differing access " + "specifiers (%1 vs %3) has unspecified value">; +def note_constexpr_compare_virtual_mem_ptr : Note< + "comparison of pointer to virtual member function %0 has unspecified value">; +def note_constexpr_past_end : Note< + "dereferenced pointer past the end of %select{|subobject of }0" + "%select{temporary|%2}1 is not a constant expression">; +def note_constexpr_past_end_subobject : Note< + "cannot %select{access base class of|access derived class of|access field of|" + "access array element of|ERROR|call member function on|" + "access real component of|access imaginary component of}0 " + "pointer past the end of object">; +def note_constexpr_null_subobject : Note< + "cannot %select{access base class of|access derived class of|access field of|" + "access array element of|perform pointer arithmetic on|" + "call member function on|access real component of|" + "access imaginary component of}0 null pointer">; +def note_constexpr_var_init_non_constant : Note< + "initializer of %0 is not a constant expression">; +def note_constexpr_typeid_polymorphic : Note< + "typeid applied to expression of polymorphic type %0 is " + "not allowed in a constant expression">; +def note_constexpr_void_comparison : Note< + "comparison between unequal pointers to void has unspecified result">; +def note_constexpr_temporary_here : Note<"temporary created here">; +def note_constexpr_conditional_never_const : Note< + "both arms of conditional operator are unable to produce a " + "constant expression">; +def note_constexpr_depth_limit_exceeded : Note< + "constexpr evaluation exceeded maximum depth of %0 calls">; +def note_constexpr_call_limit_exceeded : Note< + "constexpr evaluation hit maximum call limit">; +def note_constexpr_step_limit_exceeded : Note< + "constexpr evaluation hit maximum step limit; possible infinite loop?">; +def note_constexpr_this : Note< + "%select{|implicit }0use of 'this' pointer is only allowed within the " + "evaluation of a call to a 'constexpr' member function">; +def note_constexpr_lifetime_ended : Note< + "%select{read of|assignment to|increment of|decrement of}0 " + "%select{temporary|variable}1 whose lifetime has ended">; +def note_constexpr_access_uninit : Note< + "%select{read of|assignment to|increment of|decrement of}0 " + "object outside its lifetime is not allowed in a constant expression">; +def note_constexpr_use_uninit_reference : Note< + "use of reference outside its lifetime " + "is not allowed in a constant expression">; +def note_constexpr_modify_const_type : Note< + "modification of object of const-qualified type %0 is not allowed " + "in a constant expression">; +def note_constexpr_access_volatile_type : Note< + "%select{read of|assignment to|increment of|decrement of}0 " + "volatile-qualified type %1 is not allowed in a constant expression">; +def note_constexpr_access_volatile_obj : Note< + "%select{read of|assignment to|increment of|decrement of}0 volatile " + "%select{temporary|object %2|member %2}1 is not allowed in " + "a constant expression">; +def note_constexpr_ltor_mutable : Note< + "read of mutable member %0 is not allowed in a constant expression">; +def note_constexpr_ltor_non_const_int : Note< + "read of non-const variable %0 is not allowed in a constant expression">; +def note_constexpr_ltor_non_constexpr : Note< + "read of non-constexpr variable %0 is not allowed in a constant expression">; +def note_constexpr_access_null : Note< + "%select{read of|assignment to|increment of|decrement of}0 " + "dereferenced null pointer is not allowed in a constant expression">; +def note_constexpr_access_past_end : Note< + "%select{read of|assignment to|increment of|decrement of}0 " + "dereferenced one-past-the-end pointer is not allowed in a constant expression">; +def note_constexpr_access_inactive_union_member : Note< + "%select{read of|assignment to|increment of|decrement of}0 " + "member %1 of union with %select{active member %3|no active member}2 " + "is not allowed in a constant expression">; +def note_constexpr_access_static_temporary : Note< + "%select{read of|assignment to|increment of|decrement of}0 temporary " + "is not allowed in a constant expression outside the expression that " + "created the temporary">; +def note_constexpr_modify_global : Note< + "a constant expression cannot modify an object that is visible outside " + "that expression">; +def note_constexpr_stmt_expr_unsupported : Note< + "this use of statement expressions is not supported in a " + "constant expression">; +def note_constexpr_calls_suppressed : Note< + "(skipping %0 call%s0 in backtrace; use -fconstexpr-backtrace-limit=0 to " + "see all)">; +def note_constexpr_call_here : Note<"in call to '%0'">; +def note_constexpr_baa_insufficient_alignment : Note< + "%select{alignment of|offset of the aligned pointer from}0 the base pointee " + "object (%1 %plural{1:byte|:bytes}1) is %select{less than|not a multiple of}0 the " + "asserted %2 %plural{1:byte|:bytes}2">; +def note_constexpr_baa_value_insufficient_alignment : Note< + "value of the aligned pointer (%0) is not a multiple of the asserted %1 " + "%plural{1:byte|:bytes}1">; + +def warn_integer_constant_overflow : Warning< + "overflow in expression; result is %0 with type %1">, + InGroup<DiagGroup<"integer-overflow">>; + +// inline asm related. +let CategoryName = "Inline Assembly Issue" in { + def err_asm_invalid_escape : Error< + "invalid %% escape in inline assembly string">; + def err_asm_unknown_symbolic_operand_name : Error< + "unknown symbolic operand name in inline assembly string">; + + def err_asm_unterminated_symbolic_operand_name : Error< + "unterminated symbolic operand name in inline assembly string">; + def err_asm_empty_symbolic_operand_name : Error< + "empty symbolic operand name in inline assembly string">; + def err_asm_invalid_operand_number : Error< + "invalid operand number in inline asm string">; +} + +// vtable related. +let CategoryName = "VTable ABI Issue" in { + def err_vftable_ambiguous_component : Error< + "ambiguous vftable component for %0 introduced via covariant thunks; " + "this is an inherent limitation of the ABI">; + def note_covariant_thunk : Note< + "covariant thunk required by %0">; +} + +// Importing ASTs +def err_odr_variable_type_inconsistent : Error< + "external variable %0 declared with incompatible types in different " + "translation units (%1 vs. %2)">; +def err_odr_variable_multiple_def : Error< + "external variable %0 defined in multiple translation units">; +def note_odr_value_here : Note<"declared here with type %0">; +def note_odr_defined_here : Note<"also defined here">; +def err_odr_function_type_inconsistent : Error< + "external function %0 declared with incompatible types in different " + "translation units (%1 vs. %2)">; +def warn_odr_tag_type_inconsistent : Warning< + "type %0 has incompatible definitions in different translation units">, + InGroup<DiagGroup<"odr">>; +def note_odr_tag_kind_here: Note< + "%0 is a %select{struct|interface|union|class|enum}1 here">; +def note_odr_field : Note<"field %0 has type %1 here">; +def note_odr_missing_field : Note<"no corresponding field here">; +def note_odr_bit_field : Note<"bit-field %0 with type %1 and length %2 here">; +def note_odr_not_bit_field : Note<"field %0 is not a bit-field">; +def note_odr_base : Note<"class has base type %0">; +def note_odr_virtual_base : Note< + "%select{non-virtual|virtual}0 derivation here">; +def note_odr_missing_base : Note<"no corresponding base class here">; +def note_odr_number_of_bases : Note< + "class has %0 base %plural{1:class|:classes}0">; +def note_odr_enumerator : Note<"enumerator %0 with value %1 here">; +def note_odr_missing_enumerator : Note<"no corresponding enumerator here">; + +def err_odr_field_type_inconsistent : Error< + "field %0 declared with incompatible types in different " + "translation units (%1 vs. %2)">; + +// Importing Objective-C ASTs +def err_odr_ivar_type_inconsistent : Error< + "instance variable %0 declared with incompatible types in different " + "translation units (%1 vs. %2)">; +def err_odr_objc_superclass_inconsistent : Error< + "class %0 has incompatible superclasses">; +def note_odr_objc_superclass : Note<"inherits from superclass %0 here">; +def note_odr_objc_missing_superclass : Note<"no corresponding superclass here">; +def err_odr_objc_method_result_type_inconsistent : Error< + "%select{class|instance}0 method %1 has incompatible result types in " + "different translation units (%2 vs. %3)">; +def err_odr_objc_method_num_params_inconsistent : Error< + "%select{class|instance}0 method %1 has a different number of parameters in " + "different translation units (%2 vs. %3)">; +def err_odr_objc_method_param_type_inconsistent : Error< + "%select{class|instance}0 method %1 has a parameter with a different types " + "in different translation units (%2 vs. %3)">; +def err_odr_objc_method_variadic_inconsistent : Error< + "%select{class|instance}0 method %1 is variadic in one translation unit " + "and not variadic in another">; +def note_odr_objc_method_here : Note< + "%select{class|instance}0 method %1 also declared here">; +def err_odr_objc_property_type_inconsistent : Error< + "property %0 declared with incompatible types in different " + "translation units (%1 vs. %2)">; +def err_odr_objc_property_impl_kind_inconsistent : Error< + "property %0 is implemented with %select{@synthesize|@dynamic}1 in one " + "translation but %select{@dynamic|@synthesize}1 in another translation unit">; +def note_odr_objc_property_impl_kind : Note< + "property %0 is implemented with %select{@synthesize|@dynamic}1 here">; +def err_odr_objc_synthesize_ivar_inconsistent : Error< + "property %0 is synthesized to different ivars in different translation " + "units (%1 vs. %2)">; +def note_odr_objc_synthesize_ivar_here : Note< + "property is synthesized to ivar %0 here">; + +// Importing C++ ASTs +def err_odr_different_num_template_parameters : Error< + "template parameter lists have a different number of parameters (%0 vs %1)">; +def note_odr_template_parameter_list : Note< + "template parameter list also declared here">; +def err_odr_different_template_parameter_kind : Error< + "template parameter has different kinds in different translation units">; +def note_odr_template_parameter_here : Note< + "template parameter declared here">; +def err_odr_parameter_pack_non_pack : Error< + "parameter kind mismatch; parameter is %select{not a|a}0 parameter pack">; +def note_odr_parameter_pack_non_pack : Note< + "%select{parameter|parameter pack}0 declared here">; +def err_odr_non_type_parameter_type_inconsistent : Error< + "non-type template parameter declared with incompatible types in different " + "translation units (%0 vs. %1)">; +def err_unsupported_ast_node: Error<"cannot import unsupported AST node %0">; +} diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticAnalysisKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticAnalysisKinds.td new file mode 100644 index 0000000..5461212 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticAnalysisKinds.td @@ -0,0 +1,12 @@ +//==--- DiagnosticAnalysisKinds.td - libanalysis diagnostics --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +let Component = "Analysis" in { + +} diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticCategories.h b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticCategories.h new file mode 100644 index 0000000..4dd067b --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticCategories.h @@ -0,0 +1,26 @@ +//===- DiagnosticCategories.h - Diagnostic Categories Enumerators-*- 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_BASIC_DIAGNOSTICCATEGORIES_H +#define LLVM_CLANG_BASIC_DIAGNOSTICCATEGORIES_H + +namespace clang { + namespace diag { + enum { +#define GET_CATEGORY_TABLE +#define CATEGORY(X, ENUM) ENUM, +#include "clang/Basic/DiagnosticGroups.inc" +#undef CATEGORY +#undef GET_CATEGORY_TABLE + DiagCat_NUM_CATEGORIES + }; + } // end namespace diag +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticCategories.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticCategories.td new file mode 100644 index 0000000..37b8569 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticCategories.td @@ -0,0 +1,11 @@ +//==--- DiagnosticCategories.td - Diagnostic Category Definitions ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +class CatInlineAsm : DiagCategory<"Inline Assembly Issue">; +class CatBackend : DiagCategory<"Backend Issue">; diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticCommentKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticCommentKinds.td new file mode 100644 index 0000000..ab24582 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticCommentKinds.td @@ -0,0 +1,172 @@ +//==--- DiagnosticCommentKinds.td - diagnostics related to comments -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +let Component = "Comment" in { +let CategoryName = "Documentation Issue" in { + +// HTML parsing errors. These are under -Wdocumentation to make sure the user +// knows that we didn't parse something as they might expect. + +def warn_doc_html_start_tag_expected_quoted_string : Warning< + "expected quoted string after equals sign">, + InGroup<Documentation>, DefaultIgnore; + +def warn_doc_html_start_tag_expected_ident_or_greater : Warning< + "HTML start tag prematurely ended, expected attribute name or '>'">, + InGroup<Documentation>, DefaultIgnore; + +def note_doc_html_tag_started_here : Note< + "HTML tag started here">; + +// HTML semantic errors + +def warn_doc_html_end_forbidden : Warning< + "HTML end tag '%0' is forbidden">, + InGroup<DocumentationHTML>, DefaultIgnore; + +def warn_doc_html_end_unbalanced : Warning< + "HTML end tag does not match any start tag">, + InGroup<DocumentationHTML>, DefaultIgnore; + +def warn_doc_html_start_end_mismatch : Warning< + "HTML start tag '%0' closed by '%1'">, + InGroup<DocumentationHTML>, DefaultIgnore; + +def note_doc_html_end_tag : Note< + "end tag">; + +def warn_doc_html_missing_end_tag : Warning< + "HTML tag '%0' requires an end tag">, + InGroup<DocumentationHTML>, DefaultIgnore; + +// Commands + +def warn_doc_block_command_empty_paragraph : Warning< + "empty paragraph passed to '%select{\\|@}0%1' command">, + InGroup<Documentation>, DefaultIgnore; + +def warn_doc_block_command_duplicate : Warning< + "duplicated command '%select{\\|@}0%1'">, + InGroup<Documentation>, DefaultIgnore; + +def note_doc_block_command_previous : Note< + "previous command '%select{\\|@}0%1' here">; + +def note_doc_block_command_previous_alias : Note< + "previous command '%select{\\|@}0%1' (an alias of '\\%2') here">; + +// \param command + +def warn_doc_param_invalid_direction : Warning< + "unrecognized parameter passing direction, " + "valid directions are '[in]', '[out]' and '[in,out]'">, + InGroup<Documentation>, DefaultIgnore; + +def warn_doc_param_spaces_in_direction : Warning< + "whitespace is not allowed in parameter passing direction">, + InGroup<DocumentationPedantic>, DefaultIgnore; + +def warn_doc_param_not_attached_to_a_function_decl : Warning< + "'%select{\\|@}0param' command used in a comment that is not attached to " + "a function declaration">, + InGroup<Documentation>, DefaultIgnore; + +def warn_doc_function_method_decl_mismatch : Warning< + "'%select{\\|@}0%select{function|functiongroup|method|methodgroup|callback}1' " + "command should be used in a comment attached to " + "%select{a function|a function|an Objective-C method|an Objective-C method|" + "a pointer to function}2 declaration">, + InGroup<Documentation>, DefaultIgnore; + +def warn_doc_api_container_decl_mismatch : Warning< + "'%select{\\|@}0%select{class|interface|protocol|struct|union}1' " + "command should not be used in a comment attached to a " + "non-%select{class|interface|protocol|struct|union}2 declaration">, + InGroup<Documentation>, DefaultIgnore; + +def warn_doc_container_decl_mismatch : Warning< + "'%select{\\|@}0%select{classdesign|coclass|dependency|helper" + "|helperclass|helps|instancesize|ownership|performance|security|superclass}1' " + "command should not be used in a comment attached to a non-container declaration">, + InGroup<Documentation>, DefaultIgnore; + +def warn_doc_param_duplicate : Warning< + "parameter '%0' is already documented">, + InGroup<Documentation>, DefaultIgnore; + +def note_doc_param_previous : Note< + "previous documentation">; + +def warn_doc_param_not_found : Warning< + "parameter '%0' not found in the function declaration">, + InGroup<Documentation>, DefaultIgnore; + +def note_doc_param_name_suggestion : Note< + "did you mean '%0'?">; + +// tparam command + +def warn_doc_tparam_not_attached_to_a_template_decl : Warning< + "'%select{\\|@}0tparam' command used in a comment that is not attached to " + "a template declaration">, + InGroup<Documentation>, DefaultIgnore; + +def warn_doc_tparam_duplicate : Warning< + "template parameter '%0' is already documented">, + InGroup<Documentation>, DefaultIgnore; + +def note_doc_tparam_previous : Note< + "previous documentation">; + +def warn_doc_tparam_not_found : Warning< + "template parameter '%0' not found in the template declaration">, + InGroup<Documentation>, DefaultIgnore; + +def note_doc_tparam_name_suggestion : Note< + "did you mean '%0'?">; + +// \returns command + +def warn_doc_returns_not_attached_to_a_function_decl : Warning< + "'%select{\\|@}0%1' command used in a comment that is not attached to " + "a function or method declaration">, + InGroup<Documentation>, DefaultIgnore; + +def warn_doc_returns_attached_to_a_void_function : Warning< + "'%select{\\|@}0%1' command used in a comment that is attached to a " + "%select{function returning void|constructor|destructor|" + "method returning void}2">, + InGroup<Documentation>, DefaultIgnore; + +// \deprecated command + +def warn_doc_deprecated_not_sync : Warning< + "declaration is marked with '\\deprecated' command but does not have " + "a deprecation attribute">, + InGroup<DocumentationDeprecatedSync>, DefaultIgnore; + +def note_add_deprecation_attr : Note< + "add a deprecation attribute to the declaration to silence this warning">; + +// verbatim block commands + +def warn_verbatim_block_end_without_start : Warning< + "'%select{\\|@}0%1' command does not terminate a verbatim text block">, + InGroup<Documentation>, DefaultIgnore; + +def warn_unknown_comment_command_name : Warning< + "unknown command tag name">, + InGroup<DocumentationUnknownCommand>, DefaultIgnore; + +def warn_correct_comment_command_name : Warning< + "unknown command tag name '%0'; did you mean '%1'?">, + InGroup<DocumentationUnknownCommand>, DefaultIgnore; + +} // end of documentation issue category +} // end of AST component diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticCommonKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticCommonKinds.td new file mode 100644 index 0000000..ccc271a --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -0,0 +1,217 @@ +//==--- DiagnosticCommonKinds.td - common diagnostics ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Common Helpers +//===----------------------------------------------------------------------===// + +let Component = "Common" in { + +// Basic. + +def fatal_too_many_errors + : Error<"too many errors emitted, stopping now">, DefaultFatal; + +def note_declared_at : Note<"declared here">; +def note_previous_definition : Note<"previous definition is here">; +def note_previous_declaration : Note<"previous declaration is here">; +def note_previous_implicit_declaration : Note< + "previous implicit declaration is here">; +def note_previous_use : Note<"previous use is here">; +def note_duplicate_case_prev : Note<"previous case defined here">; +def note_forward_declaration : Note<"forward declaration of %0">; +def note_type_being_defined : Note< + "definition of %0 is not complete until the closing '}'">; +/// note_matching - this is used as a continuation of a previous diagnostic, +/// e.g. to specify the '(' when we expected a ')'. +def note_matching : Note<"to match this %0">; + +def note_using : Note<"using">; +def note_possibility : Note<"one possibility">; +def note_also_found : Note<"also found">; + +// Parse && Lex + +let CategoryName = "Lexical or Preprocessor Issue" in { + +def err_expected_colon_after_setter_name : Error< + "method name referenced in property setter attribute " + "must end with ':'">; +def err_expected_string_literal : Error<"expected string literal " + "%select{in %1|for diagnostic message in static_assert|" + "for optional message in 'availability' attribute}0">; +def err_invalid_string_udl : Error< + "string literal with user-defined suffix cannot be used here">; +def err_invalid_character_udl : Error< + "character literal with user-defined suffix cannot be used here">; +def err_invalid_numeric_udl : Error< + "numeric literal with user-defined suffix cannot be used here">; + +} + +// Parse && Sema + +let CategoryName = "Parse Issue" in { + +def err_expected : Error<"expected %0">; +def err_expected_either : Error<"expected %0 or %1">; +def err_expected_after : Error<"expected %1 after %0">; + +def err_param_redefinition : Error<"redefinition of parameter %0">; +def warn_method_param_redefinition : Warning<"redefinition of method parameter %0">; +def warn_method_param_declaration : Warning<"redeclaration of method parameter %0">, + InGroup<DuplicateArgDecl>, DefaultIgnore; +def err_invalid_storage_class_in_func_decl : Error< + "invalid storage class specifier in function declarator">; +def err_expected_namespace_name : Error<"expected namespace name">; +def ext_variadic_templates : ExtWarn< + "variadic templates are a C++11 extension">, InGroup<CXX11>; +def warn_cxx98_compat_variadic_templates : + Warning<"variadic templates are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_default_special_members : Error< + "only special member functions may be defaulted">; +def err_deleted_non_function : Error< + "only functions can have deleted definitions">; +def err_module_not_found : Error<"module '%0' not found">, DefaultFatal; +def err_module_not_built : Error<"could not build module '%0'">, DefaultFatal; +def err_module_build_disabled: Error< + "module '%0' is needed but has not been provided, and implicit use of module " + "files is disabled">, DefaultFatal; +def err_module_unavailable : Error< + "module '%0' %select{is incompatible with|requires}1 feature '%2'">; +def err_module_header_missing : Error< + "%select{|umbrella }0header '%1' not found">; +def err_module_lock_failure : Error< + "could not acquire lock file for module '%0'">, DefaultFatal; +def err_module_lock_timeout : Error< + "timed out waiting to acquire lock file for module '%0'">, DefaultFatal; +def err_module_cycle : Error<"cyclic dependency in module '%0': %1">, + DefaultFatal; +def note_pragma_entered_here : Note<"#pragma entered here">; +def note_decl_hiding_tag_type : Note< + "%1 %0 is hidden by a non-type declaration of %0 here">; +def err_attribute_not_type_attr : Error< + "%0 attribute cannot be applied to types">; +def err_enum_template : Error<"enumeration cannot be a template">; + +} + +let CategoryName = "Nullability Issue" in { + +def warn_nullability_duplicate : Warning< + "duplicate nullability specifier %0">, + InGroup<Nullability>; + +def warn_conflicting_nullability_attr_overriding_ret_types : Warning< + "conflicting nullability specifier on return types, %0 " + "conflicts with existing specifier %1">, + InGroup<Nullability>; + +def warn_conflicting_nullability_attr_overriding_param_types : Warning< + "conflicting nullability specifier on parameter types, %0 " + "conflicts with existing specifier %1">, + InGroup<Nullability>; + +def err_nullability_conflicting : Error< + "nullability specifier %0 conflicts with existing specifier %1">; + +} + +// Sema && Lex +def ext_c99_longlong : Extension< + "'long long' is an extension when C99 mode is not enabled">, + InGroup<LongLong>; +def ext_cxx11_longlong : Extension< + "'long long' is a C++11 extension">, + InGroup<CXX11LongLong>; +def warn_cxx98_compat_longlong : Warning< + "'long long' is incompatible with C++98">, + InGroup<CXX98CompatPedantic>, DefaultIgnore; +def err_integer_literal_too_large : Error< + "integer literal is too large to be represented in any %select{signed |}0" + "integer type">; +def ext_integer_literal_too_large_for_signed : ExtWarn< + "integer literal is too large to be represented in a signed integer type, " + "interpreting as unsigned">, + InGroup<ImplicitlyUnsignedLiteral>; +def warn_old_implicitly_unsigned_long : Warning< + "integer literal is too large to be represented in type 'long', " + "interpreting as 'unsigned long' per C89; this literal will " + "%select{have type 'long long'|be ill-formed}0 in C99 onwards">, + InGroup<C99Compat>; +def warn_old_implicitly_unsigned_long_cxx : Warning< + "integer literal is too large to be represented in type 'long', " + "interpreting as 'unsigned long' per C++98; this literal will " + "%select{have type 'long long'|be ill-formed}0 in C++11 onwards">, + InGroup<CXX11Compat>; +def ext_old_implicitly_unsigned_long_cxx : ExtWarn< + "integer literal is too large to be represented in type 'long' and is " + "subject to undefined behavior under C++98, interpreting as 'unsigned long'; " + "this literal will %select{have type 'long long'|be ill-formed}0 " + "in C++11 onwards">, + InGroup<CXX11Compat>; + +// SEH +def err_seh_expected_handler : Error< + "expected '__except' or '__finally' block">; +def err_seh___except_block : Error< + "%0 only allowed in __except block or filter expression">; +def err_seh___except_filter : Error< + "%0 only allowed in __except filter expression">; +def err_seh___finally_block : Error< + "%0 only allowed in __finally block">; + +// Sema && AST +def note_invalid_subexpr_in_const_expr : Note< + "subexpression not valid in a constant expression">; + +// Targets + +def err_target_unknown_triple : Error< + "unknown target triple '%0', please use -triple or -arch">; +def err_target_unknown_cpu : Error<"unknown target CPU '%0'">; +def err_target_unknown_abi : Error<"unknown target ABI '%0'">; +def err_target_unknown_fpmath : Error<"unknown FP unit '%0'">; +def err_target_unsupported_fpmath : Error< + "the '%0' unit is not supported with this instruction set">; +def err_target_unsupported_unaligned : Error< + "the %0 sub-architecture does not support unaligned accesses">; +def err_opt_not_valid_with_opt : Error< + "option '%0' cannot be specified with '%1'">; + +// Source manager +def err_cannot_open_file : Error<"cannot open file '%0': %1">, DefaultFatal; +def err_file_modified : Error< + "file '%0' modified since it was first processed">, DefaultFatal; +def err_unsupported_bom : Error<"%0 byte order mark detected in '%1', but " + "encoding is not supported">, DefaultFatal; +def err_unable_to_rename_temp : Error< + "unable to rename temporary '%0' to output file '%1': '%2'">; +def err_unable_to_make_temp : Error< + "unable to make temporary file: %0">; + +// Modules +def err_module_format_unhandled : Error< + "no handler registered for module format '%0'">, DefaultFatal; + +// TransformActions +// TODO: Use a custom category name to distinguish rewriter errors. +def err_mt_message : Error<"[rewriter] %0">, SuppressInSystemHeader; +def warn_mt_message : Warning<"[rewriter] %0">; +def note_mt_message : Note<"[rewriter] %0">; + +// ARCMigrate +def warn_arcmt_nsalloc_realloc : Warning<"[rewriter] call returns pointer to GC managed memory; it will become unmanaged in ARC">; +def err_arcmt_nsinvocation_ownership : Error<"NSInvocation's %0 is not safe to be used with an object with ownership other than __unsafe_unretained">; + +// OpenMP +def err_omp_more_one_clause : Error< + "directive '#pragma omp %0' cannot contain more than one '%1' clause%select{| with '%3' name modifier| with 'source' dependence}2">; +} diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticDriverKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticDriverKinds.td new file mode 100644 index 0000000..ce270bf --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -0,0 +1,226 @@ +//==--- DiagnosticDriverKinds.td - libdriver diagnostics ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +let Component = "Driver" in { + +def err_drv_no_such_file : Error<"no such file or directory: '%0'">; +def err_drv_unsupported_opt : Error<"unsupported option '%0'">; +def err_drv_unsupported_opt_for_target : Error< + "unsupported option '%0' for target '%1'">; +def err_drv_unsupported_option_argument : Error< + "unsupported argument '%1' to option '%0'">; +def err_drv_unknown_stdin_type : Error< + "-E or -x required when input is from standard input">; +def err_drv_unknown_stdin_type_clang_cl : Error< + "use /Tc or /Tp to set input type for standard input">; +def err_drv_unknown_language : Error<"language not recognized: '%0'">; +def err_drv_invalid_arch_name : Error< + "invalid arch name '%0'">; +def err_drv_invalid_thread_model_for_target : Error< + "invalid thread model '%0' in '%1' for this target">; +def err_drv_invalid_linker_name : Error< + "invalid linker name in argument '%0'">; +def err_drv_invalid_rtlib_name : Error< + "invalid runtime library name in argument '%0'">; +def err_drv_unsupported_rtlib_for_platform : Error< + "unsupported runtime library '%0' for platform '%1'">; +def err_drv_invalid_stdlib_name : Error< + "invalid library name in argument '%0'">; +def err_drv_invalid_output_with_multiple_archs : Error< + "cannot use '%0' output with multiple -arch options">; +def err_drv_no_input_files : Error<"no input files">; +def err_drv_use_of_Z_option : Error< + "unsupported use of internal gcc -Z option '%0'">; +def err_drv_output_argument_with_multiple_files : Error< + "cannot specify -o when generating multiple output files">; +def err_drv_out_file_argument_with_multiple_sources : Error< + "cannot specify '%0%1' when compiling multiple source files">; +def err_no_external_assembler : Error< + "there is no external assembler that can be used on this platform">; +def err_drv_unable_to_remove_file : Error< + "unable to remove file: %0">; +def err_drv_command_failure : Error< + "unable to execute command: %0">; +def err_drv_invalid_darwin_version : Error< + "invalid Darwin version number: %0">; +def err_drv_missing_argument : Error< + "argument to '%0' is missing (expected %1 value%s1)">; +def err_drv_invalid_Xarch_argument_with_args : Error< + "invalid Xarch argument: '%0', options requiring arguments are unsupported">; +def err_drv_invalid_Xarch_argument_isdriver : Error< + "invalid Xarch argument: '%0', cannot change driver behavior inside Xarch argument">; +def err_drv_argument_only_allowed_with : Error< + "invalid argument '%0' only allowed with '%1'">; +def err_drv_argument_not_allowed_with : Error< + "invalid argument '%0' not allowed with '%1'">; +def err_drv_invalid_version_number : Error< + "invalid version number in '%0'">; +def err_drv_no_linker_llvm_support : Error< + "'%0': unable to pass LLVM bit-code files to linker">; +def err_drv_no_ast_support : Error< + "'%0': unable to use AST files with this tool">; +def err_drv_no_module_support : Error< + "'%0': unable to use module files with this tool">; +def err_drv_clang_unsupported : Error< + "the clang compiler does not support '%0'">; +def err_drv_clang_unsupported_opt_cxx_darwin_i386 : Error< + "the clang compiler does not support '%0' for C++ on Darwin/i386">; +def err_drv_command_failed : Error< + "%0 command failed with exit code %1 (use -v to see invocation)">; +def err_drv_command_signalled : Error< + "%0 command failed due to signal (use -v to see invocation)">; +def err_drv_force_crash : Error< + "failing because environment variable '%0' is set">; +def err_drv_invalid_mfloat_abi : Error< + "invalid float ABI '%0'">; +def err_drv_invalid_libcxx_deployment : Error< + "invalid deployment target for -stdlib=libc++ (requires %0 or later)">; +def err_drv_invalid_argument_to_fdebug_prefix_map : Error< + "invalid argument '%0' to -fdebug-prefix-map">; +def err_drv_malformed_sanitizer_blacklist : Error< + "malformed sanitizer blacklist: '%0'">; + +def err_target_unsupported_arch + : Error<"the target architecture '%0' is not supported by the target '%1'">; + +def err_drv_I_dash_not_supported : Error< + "'%0' not supported, please use -iquote instead">; +def err_drv_unknown_argument : Error<"unknown argument: '%0'">; +def err_drv_invalid_value : Error<"invalid value '%1' in '%0'">; +def err_drv_invalid_int_value : Error<"invalid integral value '%1' in '%0'">; +def err_drv_invalid_remap_file : Error< + "invalid option '%0' not of the form <from-file>;<to-file>">; +def err_drv_invalid_gcc_output_type : Error< + "invalid output type '%0' for use with gcc tool">; +def err_drv_cc_print_options_failure : Error< + "unable to open CC_PRINT_OPTIONS file: %0">; +def err_drv_preamble_format : Error< + "incorrect format for -preamble-bytes=N,END">; +def err_drv_conflicting_deployment_targets : Error< + "conflicting deployment targets, both '%0' and '%1' are present in environment">; +def err_drv_objc_gc_arr : Error< + "cannot specify both '-fobjc-arc' and '%0'">; +def err_arc_unsupported_on_runtime : Error< + "-fobjc-arc is not supported on platforms using the legacy runtime">; +def err_arc_unsupported_on_toolchain : Error< // feel free to generalize this + "-fobjc-arc is not supported on versions of OS X prior to 10.6">; +def err_objc_weak_with_gc : Error< + "-fobjc-weak is not supported in Objective-C garbage collection">; +def err_objc_weak_unsupported : Error< + "-fobjc-weak is not supported on the current deployment target">; +def err_drv_mg_requires_m_or_mm : Error< + "option '-MG' requires '-M' or '-MM'">; +def err_drv_unknown_objc_runtime : Error< + "unknown or ill-formed Objective-C runtime '%0'">; +def err_drv_emit_llvm_link : Error< + "-emit-llvm cannot be used when linking">; +def err_drv_optimization_remark_pattern : Error< + "%0 in '%1'">; +def err_drv_no_neon_modifier : Error<"[no]neon is not accepted as modifier, please use [no]simd instead">; +def err_drv_invalid_omp_target : Error<"OpenMP target is invalid: '%0'">; +def err_drv_omp_host_ir_file_not_found : Error< + "The provided host compiler IR file '%0' is required to generate code for OpenMP target regions but cannot be found.">; + +def warn_O4_is_O3 : Warning<"-O4 is equivalent to -O3">, InGroup<Deprecated>; +def warn_drv_lto_libpath : Warning<"libLTO.dylib relative to clang installed dir not found; using 'ld' default search path instead">, + InGroup<LibLTO>; +def warn_drv_optimization_value : Warning<"optimization level '%0' is not supported; using '%1%2' instead">, + InGroup<InvalidCommandLineArgument>; +def warn_ignored_gcc_optimization : Warning<"optimization flag '%0' is not supported">, + InGroup<IgnoredOptimizationArgument>; +def warn_c_kext : Warning< + "ignoring -fapple-kext which is valid for C++ and Objective-C++ only">; +def warn_drv_input_file_unused : Warning< + "%0: '%1' input unused%select{ when '%3' is present|}2">, + InGroup<UnusedCommandLineArgument>; +def warn_drv_input_file_unused_by_cpp : Warning< + "%0: '%1' input unused in cpp mode">, + InGroup<UnusedCommandLineArgument>; +def warn_drv_preprocessed_input_file_unused : Warning< + "%0: previously preprocessed input%select{ unused when '%2' is present|}1">, + InGroup<UnusedCommandLineArgument>; +def warn_drv_unused_argument : Warning< + "argument unused during compilation: '%0'">, + InGroup<UnusedCommandLineArgument>; +def warn_drv_empty_joined_argument : Warning< + "joined argument expects additional value: '%0'">, + InGroup<UnusedCommandLineArgument>; +def warn_drv_clang_unsupported : Warning< + "the clang compiler does not support '%0'">; +def warn_drv_deprecated_arg : Warning< + "argument '%0' is deprecated, use '%1' instead">, InGroup<Deprecated>; +def warn_drv_assuming_mfloat_abi_is : Warning< + "unknown platform, assuming -mfloat-abi=%0">; +def warn_ignoring_ftabstop_value : Warning< + "ignoring invalid -ftabstop value '%0', using default value %1">; +def warn_drv_overriding_flag_option : Warning< + "overriding '%0' option with '%1'">, + InGroup<DiagGroup<"overriding-t-option">>; +def warn_drv_treating_input_as_cxx : Warning< + "treating '%0' input as '%1' when in C++ mode, this behavior is deprecated">, + InGroup<Deprecated>; +def warn_drv_objc_gc_unsupported : Warning< + "Objective-C garbage collection is not supported on this platform, ignoring '%0'">; +def warn_drv_pch_not_first_include : Warning< + "precompiled header '%0' was ignored because '%1' is not first '-include'">; +def warn_missing_sysroot : Warning<"no such sysroot directory: '%0'">, + InGroup<DiagGroup<"missing-sysroot">>; +def warn_debug_compression_unavailable : Warning<"cannot compress debug sections (zlib not installed)">, + InGroup<DiagGroup<"debug-compression-unavailable">>; +def warn_drv_enabling_rtti_with_exceptions : Warning< + "implicitly enabling rtti for exception handling">, + InGroup<DiagGroup<"rtti-for-exceptions">>; +def warn_drv_disabling_vptr_no_rtti_default : Warning< + "implicitly disabling vptr sanitizer because rtti wasn't enabled">, + InGroup<DiagGroup<"auto-disable-vptr-sanitizer">>; + +def note_drv_command_failed_diag_msg : Note< + "diagnostic msg: %0">; +def note_drv_t_option_is_global : Note< + "The last /TC or /TP option takes precedence over earlier instances">; +def note_drv_address_sanitizer_debug_runtime : Note< + "AddressSanitizer doesn't support linking with debug runtime libraries yet">; + +def err_analyzer_config_no_value : Error< + "analyzer-config option '%0' has a key but no value">; +def err_analyzer_config_multiple_values : Error< + "analyzer-config option '%0' should contain only one '='">; + +def err_drv_modules_validate_once_requires_timestamp : Error< + "option '-fmodules-validate-once-per-build-session' requires " + "'-fbuild-session-timestamp=<seconds since Epoch>' or '-fbuild-session-file=<file>'">; + +def err_test_module_file_extension_format : Error< + "-ftest-module-file-extension argument '%0' is not of the required form " + "'blockname:major:minor:hashed:user info'">; + +def warn_drv_invoking_fallback : Warning<"falling back to %0">, + InGroup<Fallback>; + +def warn_target_unsupported_nan2008 : Warning< + "ignoring '-mnan=2008' option because the '%0' architecture does not support it">, + InGroup<UnsupportedNan>; +def warn_target_unsupported_nanlegacy : Warning< + "ignoring '-mnan=legacy' option because the '%0' architecture does not support it">, + InGroup<UnsupportedNan>; + +def warn_drv_unable_to_find_directory_expected : Warning< + "unable to find %0 directory, expected to be in '%1'">, + InGroup<InvalidOrNonExistentDirectory>, DefaultIgnore; + +def warn_drv_ps4_force_pic : Warning< + "option '%0' was ignored by the PS4 toolchain, using '-fPIC'">, + InGroup<OptionIgnored>; + +def warn_drv_ps4_sdk_dir : Warning< + "environment variable SCE_PS4_SDK_DIR is set, but points to invalid or nonexistent directory '%0'">, + InGroup<InvalidOrNonExistentDirectory>; + +def err_drv_unsupported_linker : Error<"unsupported value '%0' for -linker option">; +} diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticFrontendKinds.td new file mode 100644 index 0000000..033834b --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -0,0 +1,219 @@ +//==--- DiagnosticFrontendKinds.td - frontend diagnostics -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +class BackendInfo : CatBackend, ShowInSystemHeader; + +let Component = "Frontend" in { + +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: %0">; +def err_fe_error_backend : Error<"error in backend: %0">, DefaultFatal; + +def err_fe_inline_asm : Error<"%0">, CatInlineAsm; +def warn_fe_inline_asm : Warning<"%0">, CatInlineAsm, InGroup<BackendInlineAsm>; +def note_fe_inline_asm : Note<"%0">, CatInlineAsm; +def note_fe_inline_asm_here : Note<"instantiated into assembly here">; +def err_fe_cannot_link_module : Error<"cannot link module '%0': %1">, + DefaultFatal; + +def warn_fe_frame_larger_than : Warning<"stack frame size of %0 bytes in %q1">, + BackendInfo, InGroup<BackendFrameLargerThanEQ>; +def warn_fe_backend_frame_larger_than: Warning<"%0">, + BackendInfo, InGroup<BackendFrameLargerThanEQ>; +def err_fe_backend_frame_larger_than: Error<"%0">, BackendInfo; +def note_fe_backend_frame_larger_than: Note<"%0">, BackendInfo; + +def warn_fe_backend_plugin: Warning<"%0">, BackendInfo, InGroup<BackendPlugin>; +def err_fe_backend_plugin: Error<"%0">, BackendInfo; +def remark_fe_backend_plugin: Remark<"%0">, BackendInfo, InGroup<RemarkBackendPlugin>; +def note_fe_backend_plugin: Note<"%0">, BackendInfo; + +def warn_fe_override_module : Warning< + "overriding the module target triple with %0">, + InGroup<DiagGroup<"override-module">>; + +def remark_fe_backend_optimization_remark : Remark<"%0">, BackendInfo, + InGroup<BackendOptimizationRemark>; +def remark_fe_backend_optimization_remark_missed : Remark<"%0">, BackendInfo, + InGroup<BackendOptimizationRemarkMissed>; +def remark_fe_backend_optimization_remark_analysis : Remark<"%0">, BackendInfo, + InGroup<BackendOptimizationRemarkAnalysis>; +def remark_fe_backend_optimization_remark_analysis_fpcommute : Remark<"%0; " + "allow reordering by specifying '#pragma clang loop vectorize(enable)' " + "before the loop or by providing the compiler option '-ffast-math'.">, + BackendInfo, InGroup<BackendOptimizationRemarkAnalysis>; +def remark_fe_backend_optimization_remark_analysis_aliasing : Remark<"%0; " + "allow reordering by specifying '#pragma clang loop vectorize(enable)' " + "before the loop. If the arrays will always be independent specify " + "'#pragma clang loop vectorize(assume_safety)' before the loop or provide " + "the '__restrict__' qualifier with the independent array arguments. " + "Erroneous results will occur if these options are incorrectly applied!">, + BackendInfo, InGroup<BackendOptimizationRemarkAnalysis>; +def warn_fe_backend_optimization_failure : Warning<"%0">, BackendInfo, + InGroup<BackendOptimizationFailure>, DefaultWarn; +def note_fe_backend_optimization_remark_invalid_loc : Note<"could " + "not determine the original source location for %0:%1:%2">; + +def remark_sanitize_address_insert_extra_padding_accepted : Remark< + "-fsanitize-address-field-padding applied to %0">, ShowInSystemHeader, + InGroup<SanitizeAddressRemarks>; +def remark_sanitize_address_insert_extra_padding_rejected : Remark< + "-fsanitize-address-field-padding ignored for %0 because it " + "%select{is not C++|is packed|is a union|is trivially copyable|" + "has trivial destructor|is standard layout|is in a blacklisted file|" + "is blacklisted}1">, ShowInSystemHeader, + InGroup<SanitizeAddressRemarks>; + +def err_fe_invalid_code_complete_file : Error< + "cannot locate code-completion file %0">, DefaultFatal; +def err_fe_stdout_binary : Error<"unable to change standard output to binary">, + DefaultFatal; +def err_fe_dependency_file_requires_MT : Error< + "-dependency-file requires at least one -MT or -MQ option">; +def err_fe_invalid_plugin_name : Error< + "unable to find plugin '%0'">; +def err_fe_expected_compiler_job : Error< + "unable to handle compilation, expected exactly one compiler job in '%0'">; +def err_fe_expected_clang_command : Error< + "expected a clang compiler command">; +def err_fe_remap_missing_to_file : Error< + "could not remap file '%0' to the contents of file '%1'">, DefaultFatal; +def err_fe_remap_missing_from_file : Error< + "could not remap from missing file '%0'">, DefaultFatal; +def err_fe_unable_to_load_pch : Error< + "unable to load PCH file">; +def err_fe_unable_to_load_plugin : Error< + "unable to load plugin '%0': '%1'">; +def err_fe_unable_to_create_target : Error< + "unable to create target: '%0'">; +def err_fe_unable_to_interface_with_target : Error< + "unable to interface with target machine">; +def err_fe_unable_to_open_output : Error< + "unable to open output file '%0': '%1'">; +def err_fe_pth_file_has_no_source_header : Error< + "PTH file '%0' does not designate an original source header file for -include-pth">; +def warn_fe_macro_contains_embedded_newline : Warning< + "macro '%0' contains embedded newline; text after the newline is ignored">; +def warn_fe_cc_print_header_failure : Warning< + "unable to open CC_PRINT_HEADERS file: %0 (using stderr)">; +def warn_fe_cc_log_diagnostics_failure : Warning< + "unable to open CC_LOG_DIAGNOSTICS file: %0 (using stderr)">; +def err_fe_no_pch_in_dir : Error< + "no suitable precompiled header file found in directory '%0'">; +def err_fe_action_not_available : Error< + "action %0 not compiled in">; + +def warn_fe_serialized_diag_merge_failure : Warning< + "unable to merge a subprocess's serialized diagnostics">, + InGroup<SerializedDiagnostics>; +def warn_fe_serialized_diag_failure : Warning< + "unable to open file %0 for serializing diagnostics (%1)">, + InGroup<SerializedDiagnostics>; + +def err_verify_missing_line : Error< + "missing or invalid line number following '@' in expected %0">; +def err_verify_missing_file : Error< + "file '%0' could not be located in expected %1">; +def err_verify_invalid_range : Error< + "invalid range following '-' in expected %0">; +def err_verify_missing_start : Error< + "cannot find start ('{{') of expected %0">; +def err_verify_missing_end : Error< + "cannot find end ('}}') of expected %0">; +def err_verify_invalid_content : Error< + "invalid expected %0: %1">; +def err_verify_missing_regex : Error< + "cannot find start of regex ('{{') in %0">; +def err_verify_inconsistent_diags : Error< + "'%0' diagnostics %select{expected|seen}1 but not %select{seen|expected}1: " + "%2">; +def err_verify_invalid_no_diags : Error< + "%select{expected|'expected-no-diagnostics'}0 directive cannot follow " + "%select{'expected-no-diagnostics' directive|other expected directives}0">; +def err_verify_no_directives : Error< + "no expected directives found: consider use of 'expected-no-diagnostics'">; + +def note_fixit_applied : Note<"FIX-IT applied suggested code changes">; +def note_fixit_in_macro : Note< + "FIX-IT unable to apply suggested code changes in a macro">; +def note_fixit_failed : Note< + "FIX-IT unable to apply suggested code changes">; +def note_fixit_unfixed_error : Note<"FIX-IT detected an error it cannot fix">; +def warn_fixit_no_changes : Note< + "FIX-IT detected errors it could not fix; no output will be generated">; + +// PCH reader +def err_relocatable_without_isysroot : Error< + "must specify system root with -isysroot when building a relocatable " + "PCH file">; + +def warn_unknown_diag_option : Warning< + "unknown %select{warning|remark}0 option '%1'%select{|; did you mean '%3'?}2">, + InGroup<UnknownWarningOption>; +def warn_unknown_warning_specifier : Warning< + "unknown %0 warning specifier: '%1'">, + InGroup<UnknownWarningOption>; + +def err_unknown_analyzer_checker : Error< + "no analyzer checkers are associated with '%0'">; +def note_suggest_disabling_all_checkers : Note< + "use -analyzer-disable-all-checks to disable all static analyzer checkers">; + +def warn_incompatible_analyzer_plugin_api : Warning< + "checker plugin '%0' is not compatible with this version of the analyzer">, + InGroup<DiagGroup<"analyzer-incompatible-plugin"> >; +def note_incompatible_analyzer_plugin_api : Note< + "current API version is '%0', but plugin was compiled with version '%1'">; + +def warn_module_config_mismatch : Warning< + "module file %0 cannot be loaded due to a configuration mismatch with the current " + "compilation">, InGroup<DiagGroup<"module-file-config-mismatch">>, DefaultError; +def err_module_map_not_found : Error<"module map file '%0' not found">, + DefaultFatal; +def err_missing_module_name : Error< + "no module name provided; specify one with -fmodule-name=">, + DefaultFatal; +def err_missing_module : Error< + "no module named '%0' declared in module map file '%1'">, DefaultFatal; +def err_no_submodule : Error<"no submodule named %0 in module '%1'">; +def err_no_submodule_suggest : Error< + "no submodule named %0 in module '%1'; did you mean '%2'?">; +def warn_missing_submodule : Warning<"missing submodule '%0'">, + InGroup<IncompleteUmbrella>; +def err_module_cannot_create_includes : Error< + "cannot create includes file for module %0: %1">; +def warn_module_config_macro_undef : Warning< + "%select{definition|#undef}0 of configuration macro '%1' has no effect on " + "the import of '%2'; pass '%select{-D%1=...|-U%1}0' on the command line " + "to configure the module">, + InGroup<ConfigMacros>; +def note_module_def_undef_here : Note< + "macro was %select{defined|#undef'd}0 here">; +def remark_module_build : Remark<"building module '%0' as '%1'">, + InGroup<ModuleBuild>; +def remark_module_build_done : Remark<"finished building module '%0'">, + InGroup<ModuleBuild>; +def err_modules_embed_file_not_found : + Error<"file '%0' specified by '-fmodules-embed-file=' not found">, + DefaultFatal; + +def err_test_module_file_extension_version : Error< + "test module file extension '%0' has different version (%1.%2) than expected " + "(%3.%4)">; + +def err_conflicting_module_names : Error< + "conflicting module names specified: '-fmodule-name=%0' and " + "'-fmodule-implementation-of %1'">; + +def err_missing_vfs_overlay_file : Error< + "virtual filesystem overlay file '%0' not found">, DefaultFatal; +def err_invalid_vfs_overlay : Error< + "invalid virtual filesystem overlay file '%0'">, DefaultFatal; +} diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticGroups.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticGroups.td new file mode 100644 index 0000000..8e5f57d --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticGroups.td @@ -0,0 +1,848 @@ +//==--- DiagnosticGroups.td - Diagnostic Group Definitions ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +def ImplicitFunctionDeclare : DiagGroup<"implicit-function-declaration">; +def ImplicitInt : DiagGroup<"implicit-int">; + +// Aggregation warning settings. +def Implicit : DiagGroup<"implicit", [ + ImplicitFunctionDeclare, + ImplicitInt +]>; + +// Empty DiagGroups are recognized by clang but ignored. +def : DiagGroup<"abi">; +def AbsoluteValue : DiagGroup<"absolute-value">; +def AddressOfTemporary : DiagGroup<"address-of-temporary">; +def : DiagGroup<"aggregate-return">; +def GNUAlignofExpression : DiagGroup<"gnu-alignof-expression">; +def AmbigMemberTemplate : DiagGroup<"ambiguous-member-template">; +def GNUAnonymousStruct : DiagGroup<"gnu-anonymous-struct">; +def GNUAutoType : DiagGroup<"gnu-auto-type">; +def ArrayBounds : DiagGroup<"array-bounds">; +def ArrayBoundsPointerArithmetic : DiagGroup<"array-bounds-pointer-arithmetic">; +def Availability : DiagGroup<"availability">; +def Section : DiagGroup<"section">; +def AutoImport : DiagGroup<"auto-import">; +def CXX14BinaryLiteral : DiagGroup<"c++14-binary-literal">; +def GNUBinaryLiteral : DiagGroup<"gnu-binary-literal">; +def GNUCompoundLiteralInitializer : DiagGroup<"gnu-compound-literal-initializer">; +def BitFieldConstantConversion : DiagGroup<"bitfield-constant-conversion">; +def BitFieldWidth : DiagGroup<"bitfield-width">; +def ConstantConversion : + DiagGroup<"constant-conversion", [ BitFieldConstantConversion ] >; +def LiteralConversion : DiagGroup<"literal-conversion">; +def StringConversion : DiagGroup<"string-conversion">; +def SignConversion : DiagGroup<"sign-conversion">; +def PointerBoolConversion : DiagGroup<"pointer-bool-conversion">; +def UndefinedBoolConversion : DiagGroup<"undefined-bool-conversion">; +def BoolConversion : DiagGroup<"bool-conversion", [PointerBoolConversion, + UndefinedBoolConversion]>; +def IntConversion : DiagGroup<"int-conversion">; +def EnumConversion : DiagGroup<"enum-conversion">; +def FloatConversion : DiagGroup<"float-conversion">; +def DoublePromotion : DiagGroup<"double-promotion">; +def EnumTooLarge : DiagGroup<"enum-too-large">; +def UnsupportedNan : DiagGroup<"unsupported-nan">; +def NonLiteralNullConversion : DiagGroup<"non-literal-null-conversion">; +def NullConversion : DiagGroup<"null-conversion">; +def ImplicitConversionFloatingPointToBool : + DiagGroup<"implicit-conversion-floating-point-to-bool">; +def ObjCLiteralConversion : DiagGroup<"objc-literal-conversion">; +def BadArrayNewLength : DiagGroup<"bad-array-new-length">; +def MacroRedefined : DiagGroup<"macro-redefined">; +def BuiltinMacroRedefined : DiagGroup<"builtin-macro-redefined">; +def BuiltinRequiresHeader : DiagGroup<"builtin-requires-header">; +def C99Compat : DiagGroup<"c99-compat">; +def CXXCompat: DiagGroup<"c++-compat">; +def ExternCCompat : DiagGroup<"extern-c-compat">; +def KeywordCompat : DiagGroup<"keyword-compat">; +def GNUCaseRange : DiagGroup<"gnu-case-range">; +def CastAlign : DiagGroup<"cast-align">; +def CastQual : DiagGroup<"cast-qual">; +def : DiagGroup<"char-align">; +def Comment : DiagGroup<"comment">; +def GNUComplexInteger : DiagGroup<"gnu-complex-integer">; +def GNUConditionalOmittedOperand : DiagGroup<"gnu-conditional-omitted-operand">; +def ConfigMacros : DiagGroup<"config-macros">; +def : DiagGroup<"ctor-dtor-privacy">; +def GNUDesignator : DiagGroup<"gnu-designator">; +def GNUStringLiteralOperatorTemplate : + DiagGroup<"gnu-string-literal-operator-template">; + +def DeleteIncomplete : DiagGroup<"delete-incomplete">; +def DeleteNonVirtualDtor : DiagGroup<"delete-non-virtual-dtor">; +def AbstractFinalClass : DiagGroup<"abstract-final-class">; + +def CXX11CompatDeprecatedWritableStr : + DiagGroup<"c++11-compat-deprecated-writable-strings">; + +def DeprecatedAttributes : DiagGroup<"deprecated-attributes">; +def DeprecatedDeclarations : DiagGroup<"deprecated-declarations">; +def UnavailableDeclarations : DiagGroup<"unavailable-declarations">; +def PartialAvailability : DiagGroup<"partial-availability">; +def DeprecatedImplementations :DiagGroup<"deprecated-implementations">; +def DeprecatedIncrementBool : DiagGroup<"deprecated-increment-bool">; +def DeprecatedRegister : DiagGroup<"deprecated-register">; +def DeprecatedWritableStr : DiagGroup<"deprecated-writable-strings", + [CXX11CompatDeprecatedWritableStr]>; +// FIXME: Why is DeprecatedImplementations not in this group? +def Deprecated : DiagGroup<"deprecated", [DeprecatedAttributes, + DeprecatedDeclarations, + DeprecatedIncrementBool, + DeprecatedRegister, + DeprecatedWritableStr]>, + DiagCategory<"Deprecations">; + +def LibLTO : DiagGroup<"liblto">; +def : DiagGroup<"disabled-optimization">; +def : DiagGroup<"discard-qual">; +def : DiagGroup<"div-by-zero">; + +def DocumentationHTML : DiagGroup<"documentation-html">; +def DocumentationUnknownCommand : DiagGroup<"documentation-unknown-command">; +def DocumentationPedantic : DiagGroup<"documentation-pedantic", + [DocumentationUnknownCommand]>; +def DocumentationDeprecatedSync : DiagGroup<"documentation-deprecated-sync">; +def Documentation : DiagGroup<"documentation", + [DocumentationHTML, + DocumentationDeprecatedSync]>; + +def EmptyBody : DiagGroup<"empty-body">; +def Exceptions : DiagGroup<"exceptions">; + +def GNUEmptyInitializer : DiagGroup<"gnu-empty-initializer">; +def GNUEmptyStruct : DiagGroup<"gnu-empty-struct">; +def ExtraTokens : DiagGroup<"extra-tokens">; +def CXX11ExtraSemi : DiagGroup<"c++11-extra-semi">; +def ExtraSemi : DiagGroup<"extra-semi", [CXX11ExtraSemi]>; + +def GNUFlexibleArrayInitializer : DiagGroup<"gnu-flexible-array-initializer">; +def GNUFlexibleArrayUnionMember : DiagGroup<"gnu-flexible-array-union-member">; +def GNUFoldingConstant : DiagGroup<"gnu-folding-constant">; +def FormatExtraArgs : DiagGroup<"format-extra-args">; +def FormatZeroLength : DiagGroup<"format-zero-length">; + +// Warnings for C++1y code which is not compatible with prior C++ standards. +def CXXPre14Compat : DiagGroup<"c++98-c++11-compat">; +def CXXPre14CompatPedantic : DiagGroup<"c++98-c++11-compat-pedantic", + [CXXPre14Compat]>; +def CXXPre1zCompat : DiagGroup<"c++98-c++11-c++14-compat">; +def CXXPre1zCompatPedantic : DiagGroup<"c++98-c++11-c++14-compat-pedantic", + [CXXPre1zCompat]>; + +def CXX98CompatBindToTemporaryCopy : + DiagGroup<"c++98-compat-bind-to-temporary-copy">; +def CXX98CompatLocalTypeTemplateArgs : + DiagGroup<"c++98-compat-local-type-template-args">; +def CXX98CompatUnnamedTypeTemplateArgs : + DiagGroup<"c++98-compat-unnamed-type-template-args">; + +def CXX98Compat : DiagGroup<"c++98-compat", + [CXX98CompatLocalTypeTemplateArgs, + CXX98CompatUnnamedTypeTemplateArgs, + CXXPre14Compat, + CXXPre1zCompat]>; +// Warnings for C++11 features which are Extensions in C++98 mode. +def CXX98CompatPedantic : DiagGroup<"c++98-compat-pedantic", + [CXX98Compat, + CXX98CompatBindToTemporaryCopy, + CXXPre14CompatPedantic, + CXXPre1zCompatPedantic]>; + +def CXX11Narrowing : DiagGroup<"c++11-narrowing">; + +def CXX11WarnOverrideMethod : DiagGroup<"inconsistent-missing-override">; + +// Original name of this warning in Clang +def : DiagGroup<"c++0x-narrowing", [CXX11Narrowing]>; + +// Name of this warning in GCC +def : DiagGroup<"narrowing", [CXX11Narrowing]>; + +def CXX11CompatReservedUserDefinedLiteral : + DiagGroup<"c++11-compat-reserved-user-defined-literal">; +def ReservedUserDefinedLiteral : + DiagGroup<"reserved-user-defined-literal", + [CXX11CompatReservedUserDefinedLiteral]>; + +def CXX11Compat : DiagGroup<"c++11-compat", + [CXX11Narrowing, + CXX11CompatReservedUserDefinedLiteral, + CXX11CompatDeprecatedWritableStr, + CXXPre14Compat, + CXXPre1zCompat]>; +def : DiagGroup<"c++0x-compat", [CXX11Compat]>; +def CXX11CompatPedantic : DiagGroup<"c++11-compat-pedantic", + [CXXPre14CompatPedantic, + CXXPre1zCompatPedantic]>; + +def CXX14Compat : DiagGroup<"c++14-compat", [CXXPre1zCompat]>; +def CXX14CompatPedantic : DiagGroup<"c++14-compat-pedantic", + [CXXPre1zCompatPedantic]>; + +def CXX1zCompat : DiagGroup<"c++1z-compat", [DeprecatedRegister, + DeprecatedIncrementBool]>; + +def : DiagGroup<"effc++">; +def DivZero : DiagGroup<"division-by-zero">; +def ExitTimeDestructors : DiagGroup<"exit-time-destructors">; +def FlexibleArrayExtensions : DiagGroup<"flexible-array-extensions">; +def FourByteMultiChar : DiagGroup<"four-char-constants">; +def GlobalConstructors : DiagGroup<"global-constructors">; +def BitwiseOpParentheses: DiagGroup<"bitwise-op-parentheses">; +def LogicalOpParentheses: DiagGroup<"logical-op-parentheses">; +def LogicalNotParentheses: DiagGroup<"logical-not-parentheses">; +def ShiftOpParentheses: DiagGroup<"shift-op-parentheses">; +def OverloadedShiftOpParentheses: DiagGroup<"overloaded-shift-op-parentheses">; +def DanglingElse: DiagGroup<"dangling-else">; +def DanglingField : DiagGroup<"dangling-field">; +def DistributedObjectModifiers : DiagGroup<"distributed-object-modifiers">; +def FlagEnum : DiagGroup<"flag-enum">; +def IncrementBool : DiagGroup<"increment-bool", [DeprecatedIncrementBool]>; +def InfiniteRecursion : DiagGroup<"infinite-recursion">; +def GNUImaginaryConstant : DiagGroup<"gnu-imaginary-constant">; +def IgnoredQualifiers : DiagGroup<"ignored-qualifiers">; +def : DiagGroup<"import">; +def GNUIncludeNext : DiagGroup<"gnu-include-next">; +def IncompatibleMSStruct : DiagGroup<"incompatible-ms-struct">; +def IncompatiblePointerTypesDiscardsQualifiers + : DiagGroup<"incompatible-pointer-types-discards-qualifiers">; +def IncompatiblePointerTypes + : DiagGroup<"incompatible-pointer-types", + [IncompatiblePointerTypesDiscardsQualifiers]>; +def IncompleteUmbrella : DiagGroup<"incomplete-umbrella">; +def NonModularIncludeInFrameworkModule + : DiagGroup<"non-modular-include-in-framework-module">; +def NonModularIncludeInModule : DiagGroup<"non-modular-include-in-module", + [NonModularIncludeInFrameworkModule]>; +def IncompleteModule : DiagGroup<"incomplete-module", + [IncompleteUmbrella, NonModularIncludeInModule]>; + +def CXX11InlineNamespace : DiagGroup<"c++11-inline-namespace">; +def InvalidNoreturn : DiagGroup<"invalid-noreturn">; +def InvalidSourceEncoding : DiagGroup<"invalid-source-encoding">; +def KNRPromotedParameter : DiagGroup<"knr-promoted-parameter">; +def : DiagGroup<"init-self">; +def : DiagGroup<"inline">; +def : DiagGroup<"invalid-pch">; +def GNULabelsAsValue : DiagGroup<"gnu-label-as-value">; +def LiteralRange : DiagGroup<"literal-range">; +def LocalTypeTemplateArgs : DiagGroup<"local-type-template-args", + [CXX98CompatLocalTypeTemplateArgs]>; +def RangeLoopAnalysis : DiagGroup<"range-loop-analysis">; +def ForLoopAnalysis : DiagGroup<"for-loop-analysis">; +def LoopAnalysis : DiagGroup<"loop-analysis", [ForLoopAnalysis, + RangeLoopAnalysis]>; +def MalformedWarningCheck : DiagGroup<"malformed-warning-check">; +def Main : DiagGroup<"main">; +def MainReturnType : DiagGroup<"main-return-type">; +def MissingBraces : DiagGroup<"missing-braces">; +def MissingDeclarations: DiagGroup<"missing-declarations">; +def : DiagGroup<"missing-format-attribute">; +def : DiagGroup<"missing-include-dirs">; +def MissingNoreturn : DiagGroup<"missing-noreturn">; +def MultiChar : DiagGroup<"multichar">; +def : DiagGroup<"nested-externs">; +def CXX11LongLong : DiagGroup<"c++11-long-long">; +def LongLong : DiagGroup<"long-long", [CXX11LongLong]>; +def ImplicitlyUnsignedLiteral : DiagGroup<"implicitly-unsigned-literal">; +def MethodSignatures : DiagGroup<"method-signatures">; +def MismatchedParameterTypes : DiagGroup<"mismatched-parameter-types">; +def MismatchedReturnTypes : DiagGroup<"mismatched-return-types">; +def MismatchedTags : DiagGroup<"mismatched-tags">; +def MissingFieldInitializers : DiagGroup<"missing-field-initializers">; +def ModuleBuild : DiagGroup<"module-build">; +def ModuleConflict : DiagGroup<"module-conflict">; +def ModuleFileExtension : DiagGroup<"module-file-extension">; +def NewlineEOF : DiagGroup<"newline-eof">; +def Nullability : DiagGroup<"nullability">; +def NullabilityDeclSpec : DiagGroup<"nullability-declspec">; +def NullableToNonNullConversion : DiagGroup<"nullable-to-nonnull-conversion">; +def NullabilityCompleteness : DiagGroup<"nullability-completeness">; +def NullArithmetic : DiagGroup<"null-arithmetic">; +def NullCharacter : DiagGroup<"null-character">; +def NullDereference : DiagGroup<"null-dereference">; +def InitializerOverrides : DiagGroup<"initializer-overrides">; +def NonNull : DiagGroup<"nonnull">; +def NonPODVarargs : DiagGroup<"non-pod-varargs">; +def ClassVarargs : DiagGroup<"class-varargs", [NonPODVarargs]>; +def : DiagGroup<"nonportable-cfstrings">; +def NonVirtualDtor : DiagGroup<"non-virtual-dtor">; +def OveralignedType : DiagGroup<"over-aligned">; +def OldStyleCast : DiagGroup<"old-style-cast">; +def : DiagGroup<"old-style-definition">; +def OutOfLineDeclaration : DiagGroup<"out-of-line-declaration">; +def : DiagGroup<"overflow">; +def ForwardClassReceiver : DiagGroup<"receiver-forward-class">; +def MethodAccess : DiagGroup<"objc-method-access">; +def ObjCReceiver : DiagGroup<"receiver-expr">; +// FIXME: Remove this when Xcode removes the warning setting. +def : DiagGroup<"receiver-is-weak">; +def OperatorNewReturnsNull : DiagGroup<"new-returns-null">; +def OverlengthStrings : DiagGroup<"overlength-strings">; +def OverloadedVirtual : DiagGroup<"overloaded-virtual">; +def PrivateExtern : DiagGroup<"private-extern">; +def SelTypeCast : DiagGroup<"cast-of-sel-type">; +def FunctionDefInObjCContainer : DiagGroup<"function-def-in-objc-container">; +def BadFunctionCast : DiagGroup<"bad-function-cast">; +def ObjCPropertyImpl : DiagGroup<"objc-property-implementation">; +def ObjCPropertyNoAttribute : DiagGroup<"objc-property-no-attribute">; +def ObjCProtocolQualifiers : DiagGroup<"objc-protocol-qualifiers">; +def ObjCMissingSuperCalls : DiagGroup<"objc-missing-super-calls">; +def ObjCDesignatedInit : DiagGroup<"objc-designated-initializers">; +def ObjCRetainBlockProperty : DiagGroup<"objc-noncopy-retain-block-property">; +def ObjCReadonlyPropertyHasSetter : DiagGroup<"objc-readonly-with-setter-property">; +def ObjCInvalidIBOutletProperty : DiagGroup<"invalid-iboutlet">; +def ObjCRootClass : DiagGroup<"objc-root-class">; +def ObjCPointerIntrospectPerformSelector : DiagGroup<"deprecated-objc-pointer-introspection-performSelector">; +def ObjCPointerIntrospect : DiagGroup<"deprecated-objc-pointer-introspection", [ObjCPointerIntrospectPerformSelector]>; +def ObjCMultipleMethodNames : DiagGroup<"objc-multiple-method-names">; +def DeprecatedObjCIsaUsage : DiagGroup<"deprecated-objc-isa-usage">; +def ExplicitInitializeCall : DiagGroup<"explicit-initialize-call">; +def Packed : DiagGroup<"packed">; +def Padded : DiagGroup<"padded">; +def PessimizingMove : DiagGroup<"pessimizing-move">; +def PointerArith : DiagGroup<"pointer-arith">; +def PoundWarning : DiagGroup<"#warnings">; +def PoundPragmaMessage : DiagGroup<"#pragma-messages">, + DiagCategory<"#pragma message Directive">; +def : DiagGroup<"pointer-to-int-cast">; +def : DiagGroup<"redundant-decls">; +def RedeclaredClassMember : DiagGroup<"redeclared-class-member">; +def GNURedeclaredEnum : DiagGroup<"gnu-redeclared-enum">; +def RedundantMove : DiagGroup<"redundant-move">; +def Register : DiagGroup<"register", [DeprecatedRegister]>; +def ReturnStackAddress : DiagGroup<"return-stack-address">; +def ReturnTypeCLinkage : DiagGroup<"return-type-c-linkage">; +def ReturnType : DiagGroup<"return-type", [ReturnTypeCLinkage]>; +def BindToTemporaryCopy : DiagGroup<"bind-to-temporary-copy", + [CXX98CompatBindToTemporaryCopy]>; +def SelfAssignmentField : DiagGroup<"self-assign-field">; +def SelfAssignment : DiagGroup<"self-assign", [SelfAssignmentField]>; +def SelfMove : DiagGroup<"self-move">; +def SemiBeforeMethodBody : DiagGroup<"semicolon-before-method-body">; +def Sentinel : DiagGroup<"sentinel">; +def MissingMethodReturnType : DiagGroup<"missing-method-return-type">; +def Shadow : DiagGroup<"shadow">; +def Shorten64To32 : DiagGroup<"shorten-64-to-32">; +def : DiagGroup<"sign-promo">; +def SignCompare : DiagGroup<"sign-compare">; +def : DiagGroup<"stack-protector">; +def : DiagGroup<"switch-default">; +def : DiagGroup<"synth">; +def SizeofArrayArgument : DiagGroup<"sizeof-array-argument">; +def SizeofArrayDecay : DiagGroup<"sizeof-array-decay">; +def SizeofPointerMemaccess : DiagGroup<"sizeof-pointer-memaccess">; +def StaticInInline : DiagGroup<"static-in-inline">; +def StaticLocalInInline : DiagGroup<"static-local-in-inline">; +def GNUStaticFloatInit : DiagGroup<"gnu-static-float-init">; +def StaticFloatInit : DiagGroup<"static-float-init", [GNUStaticFloatInit]>; +def GNUStatementExpression : DiagGroup<"gnu-statement-expression">; +def StringCompare : DiagGroup<"string-compare">; +def StringPlusInt : DiagGroup<"string-plus-int">; +def StringPlusChar : DiagGroup<"string-plus-char">; +def StrncatSize : DiagGroup<"strncat-size">; +def TautologicalOutOfRangeCompare : DiagGroup<"tautological-constant-out-of-range-compare">; +def TautologicalPointerCompare : DiagGroup<"tautological-pointer-compare">; +def TautologicalOverlapCompare : DiagGroup<"tautological-overlap-compare">; +def TautologicalUndefinedCompare : DiagGroup<"tautological-undefined-compare">; +def TautologicalCompare : DiagGroup<"tautological-compare", + [TautologicalOutOfRangeCompare, + TautologicalPointerCompare, + TautologicalOverlapCompare, + TautologicalUndefinedCompare]>; +def HeaderHygiene : DiagGroup<"header-hygiene">; +def DuplicateDeclSpecifier : DiagGroup<"duplicate-decl-specifier">; +def CompareDistinctPointerType : DiagGroup<"compare-distinct-pointer-types">; +def GNUUnionCast : DiagGroup<"gnu-union-cast">; +def GNUVariableSizedTypeNotAtEnd : DiagGroup<"gnu-variable-sized-type-not-at-end">; +def Varargs : DiagGroup<"varargs">; + +def Unsequenced : DiagGroup<"unsequenced">; +// GCC name for -Wunsequenced +def : DiagGroup<"sequence-point", [Unsequenced]>; + +// Preprocessor warnings. +def AmbiguousMacro : DiagGroup<"ambiguous-macro">; +def KeywordAsMacro : DiagGroup<"keyword-macro">; +def ReservedIdAsMacro : DiagGroup<"reserved-id-macro">; + +// Just silence warnings about -Wstrict-aliasing for now. +def : DiagGroup<"strict-aliasing=0">; +def : DiagGroup<"strict-aliasing=1">; +def : DiagGroup<"strict-aliasing=2">; +def : DiagGroup<"strict-aliasing">; + +// Just silence warnings about -Wstrict-overflow for now. +def : DiagGroup<"strict-overflow=0">; +def : DiagGroup<"strict-overflow=1">; +def : DiagGroup<"strict-overflow=2">; +def : DiagGroup<"strict-overflow=3">; +def : DiagGroup<"strict-overflow=4">; +def : DiagGroup<"strict-overflow=5">; +def : DiagGroup<"strict-overflow">; + +def InvalidOffsetof : DiagGroup<"invalid-offsetof">; +def : DiagGroup<"strict-prototypes">; +def StrictSelector : DiagGroup<"strict-selector-match">; +def MethodDuplicate : DiagGroup<"duplicate-method-match">; +def ObjCCStringFormat : DiagGroup<"cstring-format-directive">; +def CoveredSwitchDefault : DiagGroup<"covered-switch-default">; +def SwitchBool : DiagGroup<"switch-bool">; +def SwitchEnum : DiagGroup<"switch-enum">; +def Switch : DiagGroup<"switch">; +def ImplicitFallthroughPerFunction : + DiagGroup<"implicit-fallthrough-per-function">; +def ImplicitFallthrough : DiagGroup<"implicit-fallthrough", + [ImplicitFallthroughPerFunction]>; +def InvalidPPToken : DiagGroup<"invalid-pp-token">; +def Trigraphs : DiagGroup<"trigraphs">; + +def : DiagGroup<"type-limits">; +def UndefinedReinterpretCast : DiagGroup<"undefined-reinterpret-cast">; +def ReinterpretBaseClass : DiagGroup<"reinterpret-base-class">; +def Unicode : DiagGroup<"unicode">; +def UninitializedMaybe : DiagGroup<"conditional-uninitialized">; +def UninitializedSometimes : DiagGroup<"sometimes-uninitialized">; +def UninitializedStaticSelfInit : DiagGroup<"static-self-init">; +def Uninitialized : DiagGroup<"uninitialized", [UninitializedSometimes, + UninitializedStaticSelfInit]>; +def UnknownPragmas : DiagGroup<"unknown-pragmas">; +def IgnoredPragmas : DiagGroup<"ignored-pragmas">; +def Pragmas : DiagGroup<"pragmas", [UnknownPragmas, IgnoredPragmas]>; +def UnknownWarningOption : DiagGroup<"unknown-warning-option">; +def NSobjectAttribute : DiagGroup<"NSObject-attribute">; +def IndependentClassAttribute : DiagGroup<"IndependentClass-attribute">; +def UnknownAttributes : DiagGroup<"unknown-attributes">; +def IgnoredAttributes : DiagGroup<"ignored-attributes">; +def Attributes : DiagGroup<"attributes", [UnknownAttributes, + IgnoredAttributes]>; +def UnknownSanitizers : DiagGroup<"unknown-sanitizers">; +def UnnamedTypeTemplateArgs : DiagGroup<"unnamed-type-template-args", + [CXX98CompatUnnamedTypeTemplateArgs]>; +def UnsupportedFriend : DiagGroup<"unsupported-friend">; +def UnusedArgument : DiagGroup<"unused-argument">; +def UnusedCommandLineArgument : DiagGroup<"unused-command-line-argument">; +def IgnoredOptimizationArgument : DiagGroup<"ignored-optimization-argument">; +def InvalidCommandLineArgument : DiagGroup<"invalid-command-line-argument", + [IgnoredOptimizationArgument]>; +def UnusedComparison : DiagGroup<"unused-comparison">; +def UnusedExceptionParameter : DiagGroup<"unused-exception-parameter">; +def UnneededInternalDecl : DiagGroup<"unneeded-internal-declaration">; +def UnneededMemberFunction : DiagGroup<"unneeded-member-function">; +def UnusedPrivateField : DiagGroup<"unused-private-field">; +def UnusedFunction : DiagGroup<"unused-function", [UnneededInternalDecl]>; +def UnusedMemberFunction : DiagGroup<"unused-member-function", + [UnneededMemberFunction]>; +def UnusedLabel : DiagGroup<"unused-label">; +def UnusedParameter : DiagGroup<"unused-parameter">; +def UnusedResult : DiagGroup<"unused-result">; +def PotentiallyEvaluatedExpression : DiagGroup<"potentially-evaluated-expression">; +def UnevaluatedExpression : DiagGroup<"unevaluated-expression", + [PotentiallyEvaluatedExpression]>; +def UnusedValue : DiagGroup<"unused-value", [UnusedComparison, UnusedResult, + UnevaluatedExpression]>; +def UnusedConstVariable : DiagGroup<"unused-const-variable">; +def UnusedVariable : DiagGroup<"unused-variable", + [UnusedConstVariable]>; +def UnusedLocalTypedef : DiagGroup<"unused-local-typedef">; +def UnusedPropertyIvar : DiagGroup<"unused-property-ivar">; +def UnusedGetterReturnValue : DiagGroup<"unused-getter-return-value">; +def UsedButMarkedUnused : DiagGroup<"used-but-marked-unused">; +def UserDefinedLiterals : DiagGroup<"user-defined-literals">; +def Reorder : DiagGroup<"reorder">; +def UndeclaredSelector : DiagGroup<"undeclared-selector">; +def ImplicitAtomic : DiagGroup<"implicit-atomic-properties">; +def CustomAtomic : DiagGroup<"custom-atomic-properties">; +def AtomicProperties : DiagGroup<"atomic-properties", + [ImplicitAtomic, CustomAtomic]>; +def ARCUnsafeRetainedAssign : DiagGroup<"arc-unsafe-retained-assign">; +def ARCRetainCycles : DiagGroup<"arc-retain-cycles">; +def ARCNonPodMemAccess : DiagGroup<"arc-non-pod-memaccess">; +def AutomaticReferenceCounting : DiagGroup<"arc", + [ARCUnsafeRetainedAssign, + ARCRetainCycles, + ARCNonPodMemAccess]>; +def ARCRepeatedUseOfWeakMaybe : DiagGroup<"arc-maybe-repeated-use-of-weak">; +def ARCRepeatedUseOfWeak : DiagGroup<"arc-repeated-use-of-weak", + [ARCRepeatedUseOfWeakMaybe]>; +def ObjCBridge : DiagGroup<"bridge-cast">; + +def DeallocInCategory:DiagGroup<"dealloc-in-category">; +def SelectorTypeMismatch : DiagGroup<"selector-type-mismatch">; +def Selector : DiagGroup<"selector", [SelectorTypeMismatch]>; +def Protocol : DiagGroup<"protocol">; +def AtProtocol : DiagGroup<"at-protocol">; +def PropertyAccessDotSyntax: DiagGroup<"property-access-dot-syntax">; +def PropertyAttr : DiagGroup<"property-attribute-mismatch">; +def SuperSubClassMismatch : DiagGroup<"super-class-method-mismatch">; +def OverridingMethodMismatch : DiagGroup<"overriding-method-mismatch">; +def VariadicMacros : DiagGroup<"variadic-macros">; +def VectorConversion : DiagGroup<"vector-conversion">; // clang specific +def VexingParse : DiagGroup<"vexing-parse">; +def VLA : DiagGroup<"vla">; +def VLAExtension : DiagGroup<"vla-extension">; +def VolatileRegisterVar : DiagGroup<"volatile-register-var">; +def Visibility : DiagGroup<"visibility">; +def ZeroLengthArray : DiagGroup<"zero-length-array">; +def GNUZeroLineDirective : DiagGroup<"gnu-zero-line-directive">; +def GNUZeroVariadicMacroArguments : DiagGroup<"gnu-zero-variadic-macro-arguments">; +def Fallback : DiagGroup<"fallback">; + +// This covers both the deprecated case (in C++98) +// and the extension case (in C++11 onwards). +def WritableStrings : DiagGroup<"writable-strings", [DeprecatedWritableStr]>; + +// GCC calls -Wdeprecated-writable-strings -Wwrite-strings. +// +// Bizarrely, this warning flag enables -fconst-strings in C. This is +// GCC-compatible, but really weird. +// +// FIXME: Should this affect C++11 (where this is an error, +// not just deprecated) or not? +def GCCWriteStrings : DiagGroup<"write-strings" , [WritableStrings]>; + +def CharSubscript : DiagGroup<"char-subscripts">; +def LargeByValueCopy : DiagGroup<"large-by-value-copy">; +def DuplicateArgDecl : DiagGroup<"duplicate-method-arg">; + +// Unreachable code warning groups. +// +// The goal is make -Wunreachable-code on by default, in -Wall, or at +// least actively used, with more noisy versions of the warning covered +// under separate flags. +// +def UnreachableCodeLoopIncrement : DiagGroup<"unreachable-code-loop-increment">; +def UnreachableCode : DiagGroup<"unreachable-code", + [UnreachableCodeLoopIncrement]>; +def UnreachableCodeBreak : DiagGroup<"unreachable-code-break">; +def UnreachableCodeReturn : DiagGroup<"unreachable-code-return">; +def UnreachableCodeAggressive : DiagGroup<"unreachable-code-aggressive", + [UnreachableCode, + UnreachableCodeBreak, + UnreachableCodeReturn]>; + +// Aggregation warning settings. + +// Populate -Waddress with warnings from other groups. +def : DiagGroup<"address", [PointerBoolConversion, + StringCompare, + TautologicalPointerCompare]>; + +// -Widiomatic-parentheses contains warnings about 'idiomatic' +// missing parentheses; it is off by default. We do not include it +// in -Wparentheses because most users who use -Wparentheses explicitly +// do not want these warnings. +def ParenthesesOnEquality : DiagGroup<"parentheses-equality">; +def Parentheses : DiagGroup<"parentheses", + [LogicalOpParentheses, + LogicalNotParentheses, + BitwiseOpParentheses, + ShiftOpParentheses, + OverloadedShiftOpParentheses, + ParenthesesOnEquality, + DanglingElse]>; + +// -Wconversion has its own warnings, but we split a few out for +// legacy reasons: +// - some people want just 64-to-32 warnings +// - conversion warnings with constant sources are on by default +// - conversion warnings for literals are on by default +// - bool-to-pointer conversion warnings are on by default +// - __null-to-integer conversion warnings are on by default +def Conversion : DiagGroup<"conversion", + [BoolConversion, + ConstantConversion, + EnumConversion, + FloatConversion, + Shorten64To32, + IntConversion, + LiteralConversion, + NonLiteralNullConversion, // (1-1)->pointer (etc) + NullConversion, // NULL->non-pointer + ObjCLiteralConversion, + SignConversion, + StringConversion]>, + DiagCategory<"Value Conversion Issue">; + +def Unused : DiagGroup<"unused", + [UnusedArgument, UnusedFunction, UnusedLabel, + // UnusedParameter, (matches GCC's behavior) + // UnusedMemberFunction, (clean-up llvm before enabling) + UnusedPrivateField, UnusedLocalTypedef, + UnusedValue, UnusedVariable, UnusedPropertyIvar]>, + DiagCategory<"Unused Entity Issue">; + +// Format settings. +def FormatInvalidSpecifier : DiagGroup<"format-invalid-specifier">; +def FormatSecurity : DiagGroup<"format-security">; +def FormatNonStandard : DiagGroup<"format-non-iso">; +def FormatY2K : DiagGroup<"format-y2k">; +def FormatPedantic : DiagGroup<"format-pedantic">; +def Format : DiagGroup<"format", + [FormatExtraArgs, FormatZeroLength, NonNull, + FormatSecurity, FormatY2K, FormatInvalidSpecifier]>, + DiagCategory<"Format String Issue">; +def FormatNonLiteral : DiagGroup<"format-nonliteral">; +def Format2 : DiagGroup<"format=2", + [FormatNonLiteral, FormatSecurity, FormatY2K]>; + +def TypeSafety : DiagGroup<"type-safety">; + +def IntToVoidPointerCast : DiagGroup<"int-to-void-pointer-cast">; +def IntToPointerCast : DiagGroup<"int-to-pointer-cast", + [IntToVoidPointerCast]>; + +def Move : DiagGroup<"move", [PessimizingMove, RedundantMove, SelfMove]>; + +def Extra : DiagGroup<"extra", [ + MissingFieldInitializers, + IgnoredQualifiers, + InitializerOverrides, + SemiBeforeMethodBody, + MissingMethodReturnType, + SignCompare, + UnusedParameter + ]>; + +def Most : DiagGroup<"most", [ + CharSubscript, + Comment, + DeleteNonVirtualDtor, + Format, + Implicit, + InfiniteRecursion, + MismatchedTags, + MissingBraces, + Move, + MultiChar, + Reorder, + ReturnType, + SelfAssignment, + SelfMove, + SizeofArrayArgument, + SizeofArrayDecay, + StringPlusInt, + Trigraphs, + Uninitialized, + UnknownPragmas, + Unused, + VolatileRegisterVar, + ObjCMissingSuperCalls, + ObjCDesignatedInit, + OverloadedVirtual, + PrivateExtern, + SelTypeCast, + ExternCCompat + ]>; + +// Thread Safety warnings +def ThreadSafetyAttributes : DiagGroup<"thread-safety-attributes">; +def ThreadSafetyAnalysis : DiagGroup<"thread-safety-analysis">; +def ThreadSafetyPrecise : DiagGroup<"thread-safety-precise">; +def ThreadSafetyReference : DiagGroup<"thread-safety-reference">; +def ThreadSafetyNegative : DiagGroup<"thread-safety-negative">; +def ThreadSafety : DiagGroup<"thread-safety", + [ThreadSafetyAttributes, + ThreadSafetyAnalysis, + ThreadSafetyPrecise, + ThreadSafetyReference]>; +def ThreadSafetyVerbose : DiagGroup<"thread-safety-verbose">; +def ThreadSafetyBeta : DiagGroup<"thread-safety-beta">; + +// Uniqueness Analysis warnings +def Consumed : DiagGroup<"consumed">; + +// Note that putting warnings in -Wall will not disable them by default. If a +// warning should be active _only_ when -Wall is passed in, mark it as +// DefaultIgnore in addition to putting it here. +def All : DiagGroup<"all", [Most, Parentheses, Switch, SwitchBool]>; + +// Warnings that should be in clang-cl /w4. +def : DiagGroup<"CL4", [All, Extra]>; + +// Warnings enabled by -pedantic. This is magically filled in by TableGen. +def Pedantic : DiagGroup<"pedantic">; + +// Aliases. +def : DiagGroup<"", [Extra]>; // -W = -Wextra +def : DiagGroup<"endif-labels", [ExtraTokens]>; // -Wendif-labels=-Wextra-tokens +def : DiagGroup<"comments", [Comment]>; // -Wcomments = -Wcomment +def : DiagGroup<"conversion-null", + [NullConversion]>; // -Wconversion-null = -Wnull-conversion +def : DiagGroup<"bool-conversions", + [BoolConversion]>; // -Wbool-conversions = -Wbool-conversion +def : DiagGroup<"int-conversions", + [IntConversion]>; // -Wint-conversions = -Wint-conversion +def : DiagGroup<"vector-conversions", + [VectorConversion]>; // -Wvector-conversions = -Wvector-conversion +def : DiagGroup<"unused-local-typedefs", [UnusedLocalTypedef]>; + // -Wunused-local-typedefs = -Wunused-local-typedef + +// A warning group for warnings that we want to have on by default in clang, +// but which aren't on by default in GCC. +def NonGCC : DiagGroup<"non-gcc", + [SignCompare, Conversion, LiteralRange]>; + +// A warning group for warnings about using C++11 features as extensions in +// earlier C++ versions. +def CXX11 : DiagGroup<"c++11-extensions", [CXX11ExtraSemi, CXX11InlineNamespace, + CXX11LongLong]>; + +// A warning group for warnings about using C++14 features as extensions in +// earlier C++ versions. +def CXX14 : DiagGroup<"c++14-extensions", [CXX14BinaryLiteral]>; + +// A warning group for warnings about using C++1z features as extensions in +// earlier C++ versions. +def CXX1z : DiagGroup<"c++1z-extensions">; + +def : DiagGroup<"c++0x-extensions", [CXX11]>; +def : DiagGroup<"c++1y-extensions", [CXX14]>; + +def DelegatingCtorCycles : + DiagGroup<"delegating-ctor-cycles">; + +// A warning group for warnings about using C11 features as extensions. +def C11 : DiagGroup<"c11-extensions">; + +// A warning group for warnings about using C99 features as extensions. +def C99 : DiagGroup<"c99-extensions">; + +// A warning group for warnings about GCC extensions. +def GNU : DiagGroup<"gnu", [GNUAlignofExpression, GNUAnonymousStruct, + GNUAutoType, + GNUBinaryLiteral, GNUCaseRange, + GNUComplexInteger, GNUCompoundLiteralInitializer, + GNUConditionalOmittedOperand, GNUDesignator, + GNUEmptyInitializer, GNUEmptyStruct, + VLAExtension, GNUFlexibleArrayInitializer, + GNUFlexibleArrayUnionMember, GNUFoldingConstant, + GNUImaginaryConstant, GNUIncludeNext, + GNULabelsAsValue, + RedeclaredClassMember, GNURedeclaredEnum, + GNUStatementExpression, GNUStaticFloatInit, + GNUStringLiteralOperatorTemplate, + GNUUnionCast, GNUVariableSizedTypeNotAtEnd, + ZeroLengthArray, GNUZeroLineDirective, + GNUZeroVariadicMacroArguments]>; +// A warning group for warnings about code that clang accepts but gcc doesn't. +def GccCompat : DiagGroup<"gcc-compat">; + +// Warnings for Microsoft extensions. +def MicrosoftCharize : DiagGroup<"microsoft-charize">; +def MicrosoftInclude : DiagGroup<"microsoft-include">; +def MicrosoftCppMacro : DiagGroup<"microsoft-cpp-macro">; +def MicrosoftFixedEnum : DiagGroup<"microsoft-fixed-enum">; +def MicrosoftSealed : DiagGroup<"microsoft-sealed">; +def MicrosoftUnqualifiedFriend : DiagGroup<"microsoft-unqualified-friend">; +def MicrosoftExceptionSpec : DiagGroup<"microsoft-exception-spec">; +def MicrosoftUsingDecl : DiagGroup<"microsoft-using-decl">; +def MicrosoftMutableReference : DiagGroup<"microsoft-mutable-reference">; +def MicrosoftPureDefinition : DiagGroup<"microsoft-pure-definition">; +def MicrosoftUnionMemberReference : DiagGroup< + "microsoft-union-member-reference">; +def MicrosoftExplicitConstructorCall : DiagGroup< + "microsoft-explicit-constructor-call">; +def MicrosoftEnumValue : DiagGroup<"microsoft-enum-value">; +def MicrosoftDefaultArgRedefinition : + DiagGroup<"microsoft-default-arg-redefinition">; +def MicrosoftTemplate : DiagGroup<"microsoft-template">; +def MicrosoftRedeclareStatic : DiagGroup<"microsoft-redeclare-static">; +def MicrosoftEnumForwardReference : + DiagGroup<"microsoft-enum-forward-reference">; +def MicrosoftGoto : DiagGroup<"microsoft-goto">; +def MicrosoftFlexibleArray : DiagGroup<"microsoft-flexible-array">; +def MicrosoftExtraQualification : DiagGroup<"microsoft-extra-qualification">; +def MicrosoftCast : DiagGroup<"microsoft-cast">; +def MicrosoftConstInit : DiagGroup<"microsoft-const-init">; +def MicrosoftVoidPseudoDtor : DiagGroup<"microsoft-void-pseudo-dtor">; +def MicrosoftAnonTag : DiagGroup<"microsoft-anon-tag">; +def MicrosoftCommentPaste : DiagGroup<"microsoft-comment-paste">; +def MicrosoftEndOfFile : DiagGroup<"microsoft-end-of-file">; +// Aliases. +def : DiagGroup<"msvc-include", [MicrosoftInclude]>; + // -Wmsvc-include = -Wmicrosoft-include + +// Warnings group for warnings about Microsoft extensions. +def Microsoft : DiagGroup<"microsoft", + [MicrosoftCharize, MicrosoftInclude, MicrosoftCppMacro, MicrosoftFixedEnum, + MicrosoftSealed, MicrosoftUnqualifiedFriend, MicrosoftExceptionSpec, + MicrosoftUsingDecl, MicrosoftMutableReference, MicrosoftPureDefinition, + MicrosoftUnionMemberReference, MicrosoftExplicitConstructorCall, + MicrosoftEnumValue, MicrosoftDefaultArgRedefinition, MicrosoftTemplate, + MicrosoftRedeclareStatic, MicrosoftEnumForwardReference, MicrosoftGoto, + MicrosoftFlexibleArray, MicrosoftExtraQualification, MicrosoftCast, + MicrosoftConstInit, MicrosoftVoidPseudoDtor, MicrosoftAnonTag, + MicrosoftCommentPaste, MicrosoftEndOfFile]>; + +def ObjCNonUnifiedException : DiagGroup<"objc-nonunified-exceptions">; + +def ObjCProtocolMethodImpl : DiagGroup<"objc-protocol-method-implementation">; + +def ObjCNoPropertyAutoSynthesis : DiagGroup<"objc-property-synthesis">; + +// ObjC API warning groups. +def ObjCRedundantLiteralUse : DiagGroup<"objc-redundant-literal-use">; +def ObjCRedundantAPIUse : DiagGroup<"objc-redundant-api-use", [ + ObjCRedundantLiteralUse + ]>; + +def ObjCCocoaAPI : DiagGroup<"objc-cocoa-api", [ + ObjCRedundantAPIUse + ]>; + +def ObjCStringComparison : DiagGroup<"objc-string-compare">; +def ObjCStringConcatenation : DiagGroup<"objc-string-concatenation">; +def ObjCLiteralComparison : DiagGroup<"objc-literal-compare", [ + ObjCStringComparison + ]>; + +// Inline ASM warnings. +def ASMOperandWidths : DiagGroup<"asm-operand-widths">; +def ASM : DiagGroup<"asm", [ + ASMOperandWidths + ]>; + +// OpenMP warnings. +def SourceUsesOpenMP : DiagGroup<"source-uses-openmp">; +def OpenMPClauses : DiagGroup<"openmp-clauses">; +def OpenMPLoopForm : DiagGroup<"openmp-loop-form">; + +// Backend warnings. +def BackendInlineAsm : DiagGroup<"inline-asm">; +def BackendFrameLargerThanEQ : DiagGroup<"frame-larger-than=">; +def BackendPlugin : DiagGroup<"backend-plugin">; +def RemarkBackendPlugin : DiagGroup<"remark-backend-plugin">; +def BackendOptimizationRemark : DiagGroup<"pass">; +def BackendOptimizationRemarkMissed : DiagGroup<"pass-missed">; +def BackendOptimizationRemarkAnalysis : DiagGroup<"pass-analysis">; +def BackendOptimizationFailure : DiagGroup<"pass-failed">; + +// Instrumentation based profiling warnings. +def ProfileInstrOutOfDate : DiagGroup<"profile-instr-out-of-date">; +def ProfileInstrUnprofiled : DiagGroup<"profile-instr-unprofiled">; + +// AddressSanitizer frontent instrumentation remarks. +def SanitizeAddressRemarks : DiagGroup<"sanitize-address">; + +// Issues with serialized diagnostics. +def SerializedDiagnostics : DiagGroup<"serialized-diagnostics">; + +// A warning group for warnings about code that clang accepts when +// compiling CUDA C/C++ but which is not compatible with the CUDA spec. +def CudaCompat : DiagGroup<"cuda-compat">; + +// A warning group for things that will change semantics in the future. +def FutureCompat : DiagGroup<"future-compat">; + +def InvalidOrNonExistentDirectory : DiagGroup<"invalid-or-nonexistent-directory">; + +def OptionIgnored : DiagGroup<"option-ignored">; diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticIDs.h b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticIDs.h new file mode 100644 index 0000000..a675dfa --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticIDs.h @@ -0,0 +1,287 @@ +//===--- DiagnosticIDs.h - Diagnostic IDs Handling --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the Diagnostic IDs-related interfaces. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_DIAGNOSTICIDS_H +#define LLVM_CLANG_BASIC_DIAGNOSTICIDS_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { + class DiagnosticsEngine; + class SourceLocation; + + // Import the diagnostic enums themselves. + namespace diag { + // Start position for diagnostics. + enum { + DIAG_START_COMMON = 0, + DIAG_START_DRIVER = DIAG_START_COMMON + 300, + DIAG_START_FRONTEND = DIAG_START_DRIVER + 100, + DIAG_START_SERIALIZATION = DIAG_START_FRONTEND + 100, + DIAG_START_LEX = DIAG_START_SERIALIZATION + 120, + DIAG_START_PARSE = DIAG_START_LEX + 300, + DIAG_START_AST = DIAG_START_PARSE + 500, + DIAG_START_COMMENT = DIAG_START_AST + 110, + DIAG_START_SEMA = DIAG_START_COMMENT + 100, + DIAG_START_ANALYSIS = DIAG_START_SEMA + 3000, + DIAG_UPPER_LIMIT = DIAG_START_ANALYSIS + 100 + }; + + class CustomDiagInfo; + + /// \brief All of the diagnostics that can be emitted by the frontend. + typedef unsigned kind; + + // Get typedefs for common diagnostics. + enum { +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\ + SFINAE,CATEGORY,NOWERROR,SHOWINSYSHEADER) ENUM, +#define COMMONSTART +#include "clang/Basic/DiagnosticCommonKinds.inc" + NUM_BUILTIN_COMMON_DIAGNOSTICS +#undef DIAG + }; + + /// Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs + /// to either Ignore (nothing), Remark (emit a remark), Warning + /// (emit a warning) or Error (emit as an error). It allows clients to + /// map ERRORs to Error or Fatal (stop emitting diagnostics after this one). + enum class Severity { + // NOTE: 0 means "uncomputed". + Ignored = 1, ///< Do not present this diagnostic, ignore it. + Remark = 2, ///< Present this diagnostic as a remark. + Warning = 3, ///< Present this diagnostic as a warning. + Error = 4, ///< Present this diagnostic as an error. + Fatal = 5 ///< Present this diagnostic as a fatal error. + }; + + /// Flavors of diagnostics we can emit. Used to filter for a particular + /// kind of diagnostic (for instance, for -W/-R flags). + enum class Flavor { + WarningOrError, ///< A diagnostic that indicates a problem or potential + ///< problem. Can be made fatal by -Werror. + Remark ///< A diagnostic that indicates normal progress through + ///< compilation. + }; + } + +class DiagnosticMapping { + unsigned Severity : 3; + unsigned IsUser : 1; + unsigned IsPragma : 1; + unsigned HasNoWarningAsError : 1; + unsigned HasNoErrorAsFatal : 1; + +public: + static DiagnosticMapping Make(diag::Severity Severity, bool IsUser, + bool IsPragma) { + DiagnosticMapping Result; + Result.Severity = (unsigned)Severity; + Result.IsUser = IsUser; + Result.IsPragma = IsPragma; + Result.HasNoWarningAsError = 0; + Result.HasNoErrorAsFatal = 0; + return Result; + } + + diag::Severity getSeverity() const { return (diag::Severity)Severity; } + void setSeverity(diag::Severity Value) { Severity = (unsigned)Value; } + + bool isUser() const { return IsUser; } + bool isPragma() const { return IsPragma; } + + bool hasNoWarningAsError() const { return HasNoWarningAsError; } + void setNoWarningAsError(bool Value) { HasNoWarningAsError = Value; } + + bool hasNoErrorAsFatal() const { return HasNoErrorAsFatal; } + void setNoErrorAsFatal(bool Value) { HasNoErrorAsFatal = Value; } +}; + +/// \brief Used for handling and querying diagnostic IDs. +/// +/// Can be used and shared by multiple Diagnostics for multiple translation units. +class DiagnosticIDs : public RefCountedBase<DiagnosticIDs> { +public: + /// \brief The level of the diagnostic, after it has been through mapping. + enum Level { + Ignored, Note, Remark, Warning, Error, Fatal + }; + +private: + /// \brief Information for uniquing and looking up custom diags. + diag::CustomDiagInfo *CustomDiagInfo; + +public: + DiagnosticIDs(); + ~DiagnosticIDs(); + + /// \brief Return an ID for a diagnostic with the specified format string and + /// level. + /// + /// If this is the first request for this diagnostic, it is registered and + /// created, otherwise the existing ID is returned. + + // FIXME: Replace this function with a create-only facilty like + // createCustomDiagIDFromFormatString() to enforce safe usage. At the time of + // writing, nearly all callers of this function were invalid. + unsigned getCustomDiagID(Level L, StringRef FormatString); + + //===--------------------------------------------------------------------===// + // Diagnostic classification and reporting interfaces. + // + + /// \brief Given a diagnostic ID, return a description of the issue. + StringRef getDescription(unsigned DiagID) const; + + /// \brief Return true if the unmapped diagnostic levelof the specified + /// diagnostic ID is a Warning or Extension. + /// + /// This only works on builtin diagnostics, not custom ones, and is not + /// legal to call on NOTEs. + static bool isBuiltinWarningOrExtension(unsigned DiagID); + + /// \brief Return true if the specified diagnostic is mapped to errors by + /// default. + static bool isDefaultMappingAsError(unsigned DiagID); + + /// \brief Determine whether the given built-in diagnostic ID is a Note. + static bool isBuiltinNote(unsigned DiagID); + + /// \brief Determine whether the given built-in diagnostic ID is for an + /// extension of some sort. + static bool isBuiltinExtensionDiag(unsigned DiagID) { + bool ignored; + return isBuiltinExtensionDiag(DiagID, ignored); + } + + /// \brief Determine whether the given built-in diagnostic ID is for an + /// extension of some sort, and whether it is enabled by default. + /// + /// This also returns EnabledByDefault, which is set to indicate whether the + /// diagnostic is ignored by default (in which case -pedantic enables it) or + /// treated as a warning/error by default. + /// + static bool isBuiltinExtensionDiag(unsigned DiagID, bool &EnabledByDefault); + + + /// \brief Return the lowest-level warning option that enables the specified + /// diagnostic. + /// + /// If there is no -Wfoo flag that controls the diagnostic, this returns null. + static StringRef getWarningOptionForDiag(unsigned DiagID); + + /// \brief Return the category number that a specified \p DiagID belongs to, + /// or 0 if no category. + static unsigned getCategoryNumberForDiag(unsigned DiagID); + + /// \brief Return the number of diagnostic categories. + static unsigned getNumberOfCategories(); + + /// \brief Given a category ID, return the name of the category. + static StringRef getCategoryNameFromID(unsigned CategoryID); + + /// \brief Return true if a given diagnostic falls into an ARC diagnostic + /// category. + static bool isARCDiagnostic(unsigned DiagID); + + /// \brief Enumeration describing how the emission of a diagnostic should + /// be treated when it occurs during C++ template argument deduction. + enum SFINAEResponse { + /// \brief The diagnostic should not be reported, but it should cause + /// template argument deduction to fail. + /// + /// The vast majority of errors that occur during template argument + /// deduction fall into this category. + SFINAE_SubstitutionFailure, + + /// \brief The diagnostic should be suppressed entirely. + /// + /// Warnings generally fall into this category. + SFINAE_Suppress, + + /// \brief The diagnostic should be reported. + /// + /// The diagnostic should be reported. Various fatal errors (e.g., + /// template instantiation depth exceeded) fall into this category. + SFINAE_Report, + + /// \brief The diagnostic is an access-control diagnostic, which will be + /// substitution failures in some contexts and reported in others. + SFINAE_AccessControl + }; + + /// \brief Determines whether the given built-in diagnostic ID is + /// for an error that is suppressed if it occurs during C++ template + /// argument deduction. + /// + /// When an error is suppressed due to SFINAE, the template argument + /// deduction fails but no diagnostic is emitted. Certain classes of + /// errors, such as those errors that involve C++ access control, + /// are not SFINAE errors. + static SFINAEResponse getDiagnosticSFINAEResponse(unsigned DiagID); + + /// \brief Get the set of all diagnostic IDs in the group with the given name. + /// + /// \param[out] Diags - On return, the diagnostics in the group. + /// \returns \c true if the given group is unknown, \c false otherwise. + bool getDiagnosticsInGroup(diag::Flavor Flavor, StringRef Group, + SmallVectorImpl<diag::kind> &Diags) const; + + /// \brief Get the set of all diagnostic IDs. + void getAllDiagnostics(diag::Flavor Flavor, + SmallVectorImpl<diag::kind> &Diags) const; + + /// \brief Get the diagnostic option with the closest edit distance to the + /// given group name. + static StringRef getNearestOption(diag::Flavor Flavor, StringRef Group); + +private: + /// \brief Classify the specified diagnostic ID into a Level, consumable by + /// the DiagnosticClient. + /// + /// The classification is based on the way the client configured the + /// DiagnosticsEngine object. + /// + /// \param Loc The source location for which we are interested in finding out + /// the diagnostic state. Can be null in order to query the latest state. + DiagnosticIDs::Level + getDiagnosticLevel(unsigned DiagID, SourceLocation Loc, + const DiagnosticsEngine &Diag) const LLVM_READONLY; + + diag::Severity + getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc, + const DiagnosticsEngine &Diag) const LLVM_READONLY; + + /// \brief Used to report a diagnostic that is finally fully formed. + /// + /// \returns \c true if the diagnostic was emitted, \c false if it was + /// suppressed. + bool ProcessDiag(DiagnosticsEngine &Diag) const; + + /// \brief Used to emit a diagnostic that is finally fully formed, + /// ignoring suppression. + void EmitDiag(DiagnosticsEngine &Diag, Level DiagLevel) const; + + /// \brief Whether the diagnostic may leave the AST in a state where some + /// invariants can break. + bool isUnrecoverable(unsigned DiagID) const; + + friend class DiagnosticsEngine; +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticLexKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticLexKinds.td new file mode 100644 index 0000000..ed6ff20 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -0,0 +1,673 @@ +//==--- DiagnosticLexKinds.td - liblex diagnostics ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Lexer Diagnostics +//===----------------------------------------------------------------------===// + +let Component = "Lex", CategoryName = "Lexical or Preprocessor Issue" in { + +def null_in_char_or_string : Warning< + "null character(s) preserved in %select{char|string}0 literal">, + InGroup<NullCharacter>; +def null_in_file : Warning<"null character ignored">, InGroup<NullCharacter>; +def warn_nested_block_comment : Warning<"'/*' within block comment">, + InGroup<Comment>; +def escaped_newline_block_comment_end : Warning< + "escaped newline between */ characters at block comment end">, + InGroup<Comment>; +def backslash_newline_space : Warning< + "backslash and newline separated by space">, + InGroup<DiagGroup<"backslash-newline-escape">>; + +// Digraphs. +def warn_cxx98_compat_less_colon_colon : Warning< + "'<::' is treated as digraph '<:' (aka '[') followed by ':' in C++98">, + InGroup<CXX98Compat>, DefaultIgnore; + +// Trigraphs. +def trigraph_ignored : Warning<"trigraph ignored">, InGroup<Trigraphs>; +def trigraph_ignored_block_comment : Warning< + "ignored trigraph would end block comment">, InGroup<Trigraphs>; +def trigraph_ends_block_comment : Warning<"trigraph ends block comment">, + InGroup<Trigraphs>; +def trigraph_converted : Warning<"trigraph converted to '%0' character">, + InGroup<Trigraphs>; + +def ext_multi_line_line_comment : Extension<"multi-line // comment">, + InGroup<Comment>; +def ext_line_comment : Extension< + "// comments are not allowed in this language">, + InGroup<Comment>; +def ext_no_newline_eof : Extension<"no newline at end of file">, + InGroup<NewlineEOF>; +def warn_no_newline_eof : Warning<"no newline at end of file">, + InGroup<NewlineEOF>, DefaultIgnore; + +def warn_cxx98_compat_no_newline_eof : Warning< + "C++98 requires newline at end of file">, + InGroup<CXX98CompatPedantic>, DefaultIgnore; + +def ext_dollar_in_identifier : Extension<"'$' in identifier">, + InGroup<DiagGroup<"dollar-in-identifier-extension">>; +def ext_charize_microsoft : Extension< + "charizing operator #@ is a Microsoft extension">, + InGroup<MicrosoftCharize>; +def ext_comment_paste_microsoft : Extension< + "pasting two '/' tokens into a '//' comment is a Microsoft extension">, + InGroup<MicrosoftCommentPaste>; +def ext_ctrl_z_eof_microsoft : Extension< + "treating Ctrl-Z as end-of-file is a Microsoft extension">, + InGroup<MicrosoftEndOfFile>; + +def ext_token_used : Extension<"extension used">, + InGroup<DiagGroup<"language-extension-token">>; + +def warn_cxx11_keyword : Warning<"'%0' is a keyword in C++11">, + InGroup<CXX11Compat>, DefaultIgnore; + +def ext_unterminated_char_or_string : ExtWarn< + "missing terminating %select{'|'\"'}0 character">, InGroup<InvalidPPToken>; +def ext_empty_character : ExtWarn<"empty character constant">, + InGroup<InvalidPPToken>; +def err_unterminated_block_comment : Error<"unterminated /* comment">; +def err_invalid_character_to_charify : Error< + "invalid argument to convert to character">; +def err_unterminated___pragma : Error<"missing terminating ')' character">; + +def err_conflict_marker : Error<"version control conflict marker in file">; + +def err_raw_delim_too_long : Error< + "raw string delimiter longer than 16 characters" + "; use PREFIX( )PREFIX to delimit raw string">; +def err_invalid_char_raw_delim : Error< + "invalid character '%0' character in raw string delimiter" + "; use PREFIX( )PREFIX to delimit raw string">; +def err_unterminated_raw_string : Error< + "raw string missing terminating delimiter )%0\"">; +def warn_cxx98_compat_raw_string_literal : Warning< + "raw string literals are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; + +def ext_multichar_character_literal : ExtWarn< + "multi-character character constant">, InGroup<MultiChar>; +def ext_four_char_character_literal : Extension< + "multi-character character constant">, InGroup<FourByteMultiChar>; + + +// Unicode and UCNs +def err_invalid_utf8 : Error< + "source file is not valid UTF-8">; +def err_non_ascii : Error< + "non-ASCII characters are not allowed outside of literals and identifiers">; +def ext_unicode_whitespace : ExtWarn< + "treating Unicode character as whitespace">, + InGroup<DiagGroup<"unicode-whitespace">>; + +def err_hex_escape_no_digits : Error< + "\\%0 used with no following hex digits">; +def warn_ucn_escape_no_digits : Warning< + "\\%0 used with no following hex digits; " + "treating as '\\' followed by identifier">, InGroup<Unicode>; +def err_ucn_escape_incomplete : Error< + "incomplete universal character name">; +def warn_ucn_escape_incomplete : Warning< + "incomplete universal character name; " + "treating as '\\' followed by identifier">, InGroup<Unicode>; +def note_ucn_four_not_eight : Note<"did you mean to use '\\u'?">; + +def err_ucn_escape_basic_scs : Error< + "character '%0' cannot be specified by a universal character name">; +def err_ucn_control_character : Error< + "universal character name refers to a control character">; +def err_ucn_escape_invalid : Error<"invalid universal character">; +def warn_ucn_escape_surrogate : Warning< + "universal character name refers to a surrogate character">, + InGroup<Unicode>; + +def warn_c99_compat_unicode_id : Warning< + "%select{using this character in an identifier|starting an identifier with " + "this character}0 is incompatible with C99">, + InGroup<C99Compat>, DefaultIgnore; +def warn_cxx98_compat_unicode_id : Warning< + "using this character in an identifier is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; + +def warn_cxx98_compat_literal_ucn_escape_basic_scs : Warning< + "specifying character '%0' with a universal character name " + "is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; +def warn_cxx98_compat_literal_ucn_control_character : Warning< + "universal character name referring to a control character " + "is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; +def warn_ucn_not_valid_in_c89 : Warning< + "universal character names are only valid in C99 or C++; " + "treating as '\\' followed by identifier">, InGroup<Unicode>; +def warn_ucn_not_valid_in_c89_literal : ExtWarn< + "universal character names are only valid in C99 or C++">, InGroup<Unicode>; + + +// Literal +def ext_nonstandard_escape : Extension< + "use of non-standard escape character '\\%0'">; +def ext_unknown_escape : ExtWarn<"unknown escape sequence '\\%0'">, + InGroup<DiagGroup<"unknown-escape-sequence">>; +def err_invalid_digit : Error< + "invalid digit '%0' in %select{decimal|octal|binary}1 constant">; +def err_invalid_suffix_constant : Error< + "invalid suffix '%0' on %select{integer|floating}1 constant">; +def warn_cxx11_compat_digit_separator : Warning< + "digit separators are incompatible with C++ standards before C++14">, + InGroup<CXXPre14Compat>, DefaultIgnore; +def err_digit_separator_not_between_digits : Error< + "digit separator cannot appear at %select{start|end}0 of digit sequence">; +def warn_extraneous_char_constant : Warning< + "extraneous characters in character constant ignored">; +def warn_char_constant_too_large : Warning< + "character constant too long for its type">; +def err_multichar_utf_character_literal : Error< + "Unicode character literals may not contain multiple characters">; +def err_exponent_has_no_digits : Error<"exponent has no digits">; +def ext_imaginary_constant : Extension< + "imaginary constants are a GNU extension">, InGroup<GNUImaginaryConstant>; +def err_hexconstant_requires: Error< + "hexadecimal floating constants require %select{an exponent|a significand}0">; +def ext_hexconstant_invalid : Extension< + "hexadecimal floating constants are a C99 feature">, InGroup<C99>; +def ext_binary_literal : Extension< + "binary integer literals are a GNU extension">, InGroup<GNUBinaryLiteral>; +def ext_binary_literal_cxx14 : Extension< + "binary integer literals are a C++14 extension">, InGroup<CXX14BinaryLiteral>; +def warn_cxx11_compat_binary_literal : Warning< + "binary integer literals are incompatible with C++ standards before C++14">, + InGroup<CXXPre14CompatPedantic>, DefaultIgnore; +def err_pascal_string_too_long : Error<"Pascal string is too long">; +def err_escape_too_large : Error< + "%select{hex|octal}0 escape sequence out of range">; +def ext_string_too_long : Extension<"string literal of length %0 exceeds " + "maximum length %1 that %select{C90|ISO C99|C++}2 compilers are required to " + "support">, InGroup<OverlengthStrings>; +def err_character_too_large : Error< + "character too large for enclosing character literal type">; +def warn_c99_compat_unicode_literal : Warning< + "unicode literals are incompatible with C99">, + InGroup<C99Compat>, DefaultIgnore; +def warn_cxx98_compat_unicode_literal : Warning< + "unicode literals are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def warn_cxx14_compat_u8_character_literal : Warning< + "unicode literals are incompatible with C++ standards before C++1z">, + InGroup<CXXPre1zCompat>, DefaultIgnore; +def warn_cxx11_compat_user_defined_literal : Warning< + "identifier after literal will be treated as a user-defined literal suffix " + "in C++11">, InGroup<CXX11Compat>, DefaultIgnore; +def warn_cxx11_compat_reserved_user_defined_literal : Warning< + "identifier after literal will be treated as a reserved user-defined literal " + "suffix in C++11">, + InGroup<CXX11CompatReservedUserDefinedLiteral>, DefaultIgnore; +def ext_reserved_user_defined_literal : ExtWarn< + "invalid suffix on literal; C++11 requires a space between literal and " + "identifier">, InGroup<ReservedUserDefinedLiteral>, DefaultError; +def ext_ms_reserved_user_defined_literal : ExtWarn< + "invalid suffix on literal; C++11 requires a space between literal and " + "identifier">, InGroup<ReservedUserDefinedLiteral>; +def err_unsupported_string_concat : Error< + "unsupported non-standard concatenation of string literals">; +def err_string_concat_mixed_suffix : Error< + "differing user-defined suffixes ('%0' and '%1') in string literal " + "concatenation">; +def err_pp_invalid_udl : Error< + "%select{character|integer}0 literal with user-defined suffix " + "cannot be used in preprocessor constant expression">; +def err_bad_string_encoding : Error< + "illegal character encoding in string literal">; +def warn_bad_string_encoding : ExtWarn< + "illegal character encoding in string literal">, + InGroup<InvalidSourceEncoding>; +def err_bad_character_encoding : Error< + "illegal character encoding in character literal">; +def warn_bad_character_encoding : ExtWarn< + "illegal character encoding in character literal">, + InGroup<InvalidSourceEncoding>; +def err_lexing_string : Error<"failure when lexing a string">; + + +//===----------------------------------------------------------------------===// +// PTH Diagnostics +//===----------------------------------------------------------------------===// +def err_invalid_pth_file : Error< + "invalid or corrupt PTH file '%0'">; + +//===----------------------------------------------------------------------===// +// Preprocessor Diagnostics +//===----------------------------------------------------------------------===// + +let CategoryName = "User-Defined Issue" in { +def pp_hash_warning : Warning<"%0">, + InGroup<PoundWarning>, ShowInSystemHeader; +def err_pp_hash_error : Error<"%0">; +} + +def pp_include_next_in_primary : Warning< + "#include_next in primary source file">, + InGroup<DiagGroup<"include-next-outside-header">>; +def pp_include_macros_out_of_predefines : Error< + "the #__include_macros directive is only for internal use by -imacros">; +def pp_include_next_absolute_path : Warning< + "#include_next with absolute path">, + InGroup<DiagGroup<"include-next-absolute-path">>; +def ext_c99_whitespace_required_after_macro_name : ExtWarn< + "ISO C99 requires whitespace after the macro name">, InGroup<C99>; +def ext_missing_whitespace_after_macro_name : ExtWarn< + "whitespace required after macro name">; +def warn_missing_whitespace_after_macro_name : Warning< + "whitespace recommended after macro name">; + +def pp_pragma_once_in_main_file : Warning<"#pragma once in main file">, + InGroup<DiagGroup<"pragma-once-outside-header">>; +def pp_pragma_sysheader_in_main_file : Warning< + "#pragma system_header ignored in main file">, + InGroup<DiagGroup<"pragma-system-header-outside-header">>; +def pp_poisoning_existing_macro : Warning<"poisoning existing macro">; +def pp_out_of_date_dependency : Warning< + "current file is older than dependency %0">; +def ext_pp_undef_builtin_macro : ExtWarn<"undefining builtin macro">, + InGroup<BuiltinMacroRedefined>; +def ext_pp_redef_builtin_macro : ExtWarn<"redefining builtin macro">, + InGroup<BuiltinMacroRedefined>; +def pp_disabled_macro_expansion : Warning< + "disabled expansion of recursive macro">, DefaultIgnore, + InGroup<DiagGroup<"disabled-macro-expansion">>; +def pp_macro_not_used : Warning<"macro is not used">, DefaultIgnore, + InGroup<DiagGroup<"unused-macros">>; +def warn_pp_undef_identifier : Warning< + "%0 is not defined, evaluates to 0">, + InGroup<DiagGroup<"undef">>, DefaultIgnore; +def warn_pp_ambiguous_macro : Warning< + "ambiguous expansion of macro %0">, InGroup<AmbiguousMacro>; +def note_pp_ambiguous_macro_chosen : Note< + "expanding this definition of %0">; +def note_pp_ambiguous_macro_other : Note< + "other definition of %0">; +def warn_pp_macro_hides_keyword : Extension< + "keyword is hidden by macro definition">, InGroup<KeywordAsMacro>; +def warn_pp_macro_is_reserved_id : Warning< + "macro name is a reserved identifier">, DefaultIgnore, + InGroup<ReservedIdAsMacro>; +def warn_pp_objc_macro_redef_ignored : Warning< + "ignoring redefinition of Objective-C qualifier macro">, + InGroup<DiagGroup<"objc-macro-redefinition">>; + +def pp_invalid_string_literal : Warning< + "invalid string literal, ignoring final '\\'">; +def warn_pp_expr_overflow : Warning< + "integer overflow in preprocessor expression">; +def warn_pp_convert_to_positive : Warning< + "%select{left|right}0 side of operator converted from negative value to " + "unsigned: %1">; + +def ext_pp_import_directive : Extension<"#import is a language extension">, + InGroup<DiagGroup<"import-preprocessor-directive-pedantic">>; +def err_pp_import_directive_ms : Error< + "#import of type library is an unsupported Microsoft feature">; +def ext_pp_include_search_ms : ExtWarn< + "#include resolved using non-portable Microsoft search rules as: %0">, + InGroup<MicrosoftInclude>; + +def ext_pp_ident_directive : Extension<"#ident is a language extension">; +def ext_pp_include_next_directive : Extension< + "#include_next is a language extension">, InGroup<GNUIncludeNext>; +def ext_pp_warning_directive : Extension<"#warning is a language extension">; + +def ext_pp_extra_tokens_at_eol : ExtWarn< + "extra tokens at end of #%0 directive">, InGroup<ExtraTokens>; + +def ext_pp_comma_expr : Extension<"comma operator in operand of #if">; +def ext_pp_bad_vaargs_use : Extension< + "__VA_ARGS__ can only appear in the expansion of a C99 variadic macro">; +def ext_pp_macro_redef : ExtWarn<"%0 macro redefined">, InGroup<MacroRedefined>; +def ext_variadic_macro : Extension<"variadic macros are a C99 feature">, + InGroup<VariadicMacros>; +def warn_cxx98_compat_variadic_macro : Warning< + "variadic macros are incompatible with C++98">, + InGroup<CXX98CompatPedantic>, DefaultIgnore; +def ext_named_variadic_macro : Extension< + "named variadic macros are a GNU extension">, InGroup<VariadicMacros>; +def err_embedded_directive : Error< + "embedding a #%0 directive within macro arguments is not supported">; +def ext_embedded_directive : Extension< + "embedding a directive within macro arguments has undefined behavior">, + InGroup<DiagGroup<"embedded-directive">>; +def ext_missing_varargs_arg : Extension< + "must specify at least one argument for '...' parameter of variadic macro">, + InGroup<GNUZeroVariadicMacroArguments>; +def ext_empty_fnmacro_arg : Extension< + "empty macro arguments are a C99 feature">, InGroup<C99>; +def warn_cxx98_compat_empty_fnmacro_arg : Warning< + "empty macro arguments are incompatible with C++98">, + InGroup<CXX98CompatPedantic>, DefaultIgnore; +def note_macro_here : Note<"macro %0 defined here">; + +def err_pp_opencl_variadic_macros : + Error<"variadic macros not supported in OpenCL">; + +def err_pp_invalid_directive : Error<"invalid preprocessing directive">; +def err_pp_directive_required : Error< + "%0 must be used within a preprocessing directive">; +def err_pp_file_not_found : Error<"'%0' file not found">, DefaultFatal; +def err_pp_file_not_found_not_fatal : Error< + "'%0' file not found with <angled> include; use \"quotes\" instead">; +def err_pp_error_opening_file : Error< + "error opening file '%0': %1">, DefaultFatal; +def err_pp_empty_filename : Error<"empty filename">; +def err_pp_include_too_deep : Error<"#include nested too deeply">; +def err_pp_expects_filename : Error<"expected \"FILENAME\" or <FILENAME>">; +def err_pp_macro_not_identifier : Error<"macro name must be an identifier">; +def err_pp_missing_macro_name : Error<"macro name missing">; +def err_pp_missing_rparen_in_macro_def : Error< + "missing ')' in macro parameter list">; +def err_pp_invalid_tok_in_arg_list : Error< + "invalid token in macro parameter list">; +def err_pp_expected_ident_in_arg_list : Error< + "expected identifier in macro parameter list">; +def err_pp_expected_comma_in_arg_list : Error< + "expected comma in macro parameter list">; +def err_pp_duplicate_name_in_arg_list : Error< + "duplicate macro parameter name %0">; +def err_pp_stringize_not_parameter : Error< + "'#' is not followed by a macro parameter">; +def err_pp_malformed_ident : Error<"invalid #ident directive">; +def err_pp_unterminated_conditional : Error< + "unterminated conditional directive">; +def pp_err_else_after_else : Error<"#else after #else">; +def pp_err_elif_after_else : Error<"#elif after #else">; +def pp_err_else_without_if : Error<"#else without #if">; +def pp_err_elif_without_if : Error<"#elif without #if">; +def err_pp_endif_without_if : Error<"#endif without #if">; +def err_pp_expected_value_in_expr : Error<"expected value in expression">; +def err_pp_expected_rparen : Error<"expected ')' in preprocessor expression">; +def err_pp_expected_eol : Error< + "expected end of line in preprocessor expression">; +def err_pp_expected_after : Error<"missing %1 after %0">; +def err_pp_colon_without_question : Error<"':' without preceding '?'">; +def err_pp_division_by_zero : Error< + "division by zero in preprocessor expression">; +def err_pp_remainder_by_zero : Error< + "remainder by zero in preprocessor expression">; +def err_pp_expr_bad_token_binop : Error< + "token is not a valid binary operator in a preprocessor subexpression">; +def err_pp_expr_bad_token_start_expr : Error< + "invalid token at start of a preprocessor expression">; +def err_pp_invalid_poison : Error<"can only poison identifier tokens">; +def err_pp_used_poisoned_id : Error<"attempt to use a poisoned identifier">; + +def err_feature_check_malformed : Error< + "builtin feature check macro requires a parenthesized identifier">; + +def err_warning_check_malformed : Error< + "builtin warning check macro requires a parenthesized string">; +def warn_has_warning_invalid_option : + ExtWarn<"__has_warning expected option name (e.g. \"-Wundef\")">, + InGroup<MalformedWarningCheck>; + +def err_pp_identifier_arg_not_identifier : Error< + "cannot convert %0 token to an identifier">; + +def warn_pragma_include_alias_mismatch_angle : + ExtWarn<"angle-bracketed include <%0> cannot be aliased to double-quoted " + "include \"%1\"">, InGroup<UnknownPragmas>; +def warn_pragma_include_alias_mismatch_quote : + ExtWarn<"double-quoted include \"%0\" cannot be aliased to angle-bracketed " + "include <%1>">, InGroup<UnknownPragmas>; +def warn_pragma_include_alias_expected : + ExtWarn<"pragma include_alias expected '%0'">, + InGroup<UnknownPragmas>; +def warn_pragma_include_alias_expected_filename : + ExtWarn<"pragma include_alias expected include filename">, + InGroup<UnknownPragmas>; + +// - #pragma warning(...) +def warn_pragma_warning_expected : + ExtWarn<"#pragma warning expected '%0'">, + InGroup<UnknownPragmas>; +def warn_pragma_warning_spec_invalid : + ExtWarn<"#pragma warning expected 'push', 'pop', 'default', 'disable'," + " 'error', 'once', 'suppress', 1, 2, 3, or 4">, + InGroup<UnknownPragmas>; +def warn_pragma_warning_push_level : + ExtWarn<"#pragma warning(push, level) requires a level between 0 and 4">, + InGroup<UnknownPragmas>; +def warn_pragma_warning_expected_number : + ExtWarn<"#pragma warning expected a warning number">, + InGroup<UnknownPragmas>; + +def err__Pragma_malformed : Error< + "_Pragma takes a parenthesized string literal">; +def err_pragma_message_malformed : Error< + "pragma %select{message|warning|error}0 requires parenthesized string">; +def err_pragma_push_pop_macro_malformed : Error< + "pragma %0 requires a parenthesized string">; +def warn_pragma_pop_macro_no_push : Warning< + "pragma pop_macro could not pop '%0', no matching push_macro">, + InGroup<IgnoredPragmas>; +def warn_pragma_message : Warning<"%0">, + InGroup<PoundPragmaMessage>, DefaultWarnNoWerror; +def err_pragma_message : Error<"%0">; +def warn_pragma_ignored : Warning<"unknown pragma ignored">, + InGroup<UnknownPragmas>, DefaultIgnore; +def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">, + InGroup<UnknownPragmas>; +def ext_on_off_switch_syntax : + ExtWarn<"expected 'ON' or 'OFF' or 'DEFAULT' in pragma">, + InGroup<UnknownPragmas>; +def ext_pragma_syntax_eod : + ExtWarn<"expected end of directive in pragma">, + InGroup<UnknownPragmas>; +def warn_stdc_fenv_access_not_supported : + Warning<"pragma STDC FENV_ACCESS ON is not supported, ignoring pragma">, + InGroup<UnknownPragmas>; +def warn_pragma_diagnostic_invalid : + ExtWarn<"pragma diagnostic expected 'error', 'warning', 'ignored', 'fatal'," + " 'push', or 'pop'">, + InGroup<UnknownPragmas>; +def warn_pragma_diagnostic_cannot_pop : + ExtWarn<"pragma diagnostic pop could not pop, no matching push">, + InGroup<UnknownPragmas>; +def warn_pragma_diagnostic_invalid_option : + ExtWarn<"pragma diagnostic expected option name (e.g. \"-Wundef\")">, + InGroup<UnknownPragmas>; +def warn_pragma_diagnostic_invalid_token : + ExtWarn<"unexpected token in pragma diagnostic">, + InGroup<UnknownPragmas>; +def warn_pragma_diagnostic_unknown_warning : + ExtWarn<"unknown warning group '%0', ignored">, + InGroup<UnknownPragmas>; +// - #pragma __debug +def warn_pragma_debug_unexpected_command : Warning< + "unexpected debug command '%0'">, InGroup<IgnoredPragmas>; + +def err_defined_macro_name : Error<"'defined' cannot be used as a macro name">; +def err_paste_at_start : Error< + "'##' cannot appear at start of macro expansion">; +def err_paste_at_end : Error<"'##' cannot appear at end of macro expansion">; +def ext_paste_comma : Extension< + "token pasting of ',' and __VA_ARGS__ is a GNU extension">, InGroup<GNUZeroVariadicMacroArguments>; +def err_unterm_macro_invoc : Error< + "unterminated function-like macro invocation">; +def err_too_many_args_in_macro_invoc : Error< + "too many arguments provided to function-like macro invocation">; +def note_suggest_parens_for_macro : Note< + "parentheses are required around macro argument containing braced " + "initializer list">; +def note_init_list_at_beginning_of_macro_argument : Note< + "cannot use initializer list at the beginning of a macro argument">; +def err_too_few_args_in_macro_invoc : Error< + "too few arguments provided to function-like macro invocation">; +def err_pp_bad_paste : Error< + "pasting formed '%0', an invalid preprocessing token">; +def ext_pp_bad_paste_ms : ExtWarn< + "pasting formed '%0', an invalid preprocessing token">, DefaultError, + InGroup<DiagGroup<"invalid-token-paste">>; +def err_pp_operator_used_as_macro_name : Error< + "C++ operator %0 (aka %1) used as a macro name">; +def ext_pp_operator_used_as_macro_name : Extension< + err_pp_operator_used_as_macro_name.Text>, InGroup<MicrosoftCppMacro>; +def err_pp_illegal_floating_literal : Error< + "floating point literal in preprocessor expression">; +def err_pp_line_requires_integer : Error< + "#line directive requires a positive integer argument">; +def ext_pp_line_zero : Extension< + "#line directive with zero argument is a GNU extension">, + InGroup<GNUZeroLineDirective>; +def err_pp_line_invalid_filename : Error< + "invalid filename for #line directive">; +def warn_pp_line_decimal : Warning< + "%select{#line|GNU line marker}0 directive interprets number as decimal, not octal">; +def err_pp_line_digit_sequence : Error< + "%select{#line|GNU line marker}0 directive requires a simple digit sequence">; +def err_pp_linemarker_requires_integer : Error< + "line marker directive requires a positive integer argument">; +def err_pp_linemarker_invalid_filename : Error< + "invalid filename for line marker directive">; +def err_pp_linemarker_invalid_flag : Error< + "invalid flag line marker directive">; +def err_pp_linemarker_invalid_pop : Error< + "invalid line marker flag '2': cannot pop empty include stack">; +def ext_pp_line_too_big : Extension< + "C requires #line number to be less than %0, allowed as extension">; +def warn_cxx98_compat_pp_line_too_big : Warning< + "#line number greater than 32767 is incompatible with C++98">, + InGroup<CXX98CompatPedantic>, DefaultIgnore; + +def err_pp_visibility_non_macro : Error<"no macro named %0">; + +def err_pp_arc_cf_code_audited_syntax : Error<"expected 'begin' or 'end'">; +def err_pp_double_begin_of_arc_cf_code_audited : Error< + "already inside '#pragma clang arc_cf_code_audited'">; +def err_pp_unmatched_end_of_arc_cf_code_audited : Error< + "not currently inside '#pragma clang arc_cf_code_audited'">; +def err_pp_include_in_arc_cf_code_audited : Error< + "cannot #include files inside '#pragma clang arc_cf_code_audited'">; +def err_pp_eof_in_arc_cf_code_audited : Error< + "'#pragma clang arc_cf_code_audited' was not ended within this file">; + +def warn_pp_date_time : Warning< + "expansion of date or time macro is not reproducible">, + ShowInSystemHeader, DefaultIgnore, InGroup<DiagGroup<"date-time">>; + +// Module map parsing +def err_mmap_unknown_token : Error<"skipping stray token">; +def err_mmap_expected_module : Error<"expected module declaration">; +def err_mmap_expected_module_name : Error<"expected module name">; +def err_mmap_expected_lbrace : Error<"expected '{' to start module '%0'">; +def err_mmap_expected_rbrace : Error<"expected '}'">; +def note_mmap_lbrace_match : Note<"to match this '{'">; +def err_mmap_expected_rsquare : Error<"expected ']' to close attribute">; +def note_mmap_lsquare_match : Note<"to match this ']'">; +def err_mmap_expected_member : Error< + "expected umbrella, header, submodule, or module export">; +def err_mmap_expected_header : Error<"expected a header name after '%0'">; +def err_mmap_expected_mmap_file : Error<"expected a module map file name">; +def err_mmap_module_redefinition : Error< + "redefinition of module '%0'">; +def note_mmap_prev_definition : Note<"previously defined here">; +def err_mmap_umbrella_dir_not_found : Error< + "umbrella directory '%0' not found">; +def err_mmap_umbrella_clash : Error< + "umbrella for module '%0' already covers this directory">; +def err_mmap_module_id : Error< + "expected a module name or '*'">; +def err_mmap_expected_library_name : Error< + "expected %select{library|framework}0 name as a string">; +def err_mmap_config_macro_submodule : Error< + "configuration macros are only allowed in top-level modules">; +def err_mmap_use_decl_submodule : Error< + "use declarations are only allowed in top-level modules">; +def err_mmap_expected_config_macro : Error< + "expected configuration macro name after ','">; +def err_mmap_expected_conflicts_comma : Error< + "expected ',' after conflicting module name">; +def err_mmap_expected_conflicts_message : Error< + "expected a message describing the conflict with '%0'">; +def err_mmap_missing_module_unqualified : Error< + "no module named '%0' visible from '%1'">; +def err_mmap_missing_module_qualified : Error< + "no module named '%0' in '%1'">; +def err_mmap_top_level_inferred_submodule : Error< + "only submodules and framework modules may be inferred with wildcard syntax">; +def err_mmap_inferred_no_umbrella : Error< + "inferred submodules require a module with an umbrella">; +def err_mmap_inferred_framework_submodule : Error< + "inferred submodule cannot be a framework submodule">; +def err_mmap_explicit_inferred_framework : Error< + "inferred framework modules cannot be 'explicit'">; +def err_mmap_missing_exclude_name : Error< + "expected excluded module name">; +def err_mmap_inferred_redef : Error< + "redefinition of inferred submodule">; +def err_mmap_expected_lbrace_wildcard : Error< + "expected '{' to start inferred submodule">; +def err_mmap_expected_inferred_member : Error< + "expected %select{module exclusion with 'exclude'|'export *'}0">; +def err_mmap_expected_export_wildcard : Error< + "only '*' can be exported from an inferred submodule">; +def err_mmap_explicit_top_level : Error< + "'explicit' is not permitted on top-level modules">; +def err_mmap_nested_submodule_id : Error< + "qualified module name can only be used to define modules at the top level">; +def err_mmap_expected_feature : Error<"expected a feature name">; +def err_mmap_expected_attribute : Error<"expected an attribute name">; +def warn_mmap_unknown_attribute : Warning<"unknown attribute '%0'">, + InGroup<IgnoredAttributes>; + +def warn_auto_module_import : Warning< + "treating #%select{include|import|include_next|__include_macros}0 as an " + "import of module '%1'">, InGroup<AutoImport>, DefaultIgnore; +def note_implicit_top_level_module_import_here : Note< + "submodule of top-level module '%0' implicitly imported here">; +def warn_uncovered_module_header : Warning< + "umbrella header for module '%0' does not include header '%1'">, + InGroup<IncompleteUmbrella>; +def err_expected_id_building_module : Error< + "expected a module name in '__building_module' expression">; +def warn_use_of_private_header_outside_module : Warning< + "use of private header from outside its module: '%0'">, + InGroup<DiagGroup<"private-header">>, DefaultError; +def err_undeclared_use_of_module : Error< + "module %0 does not depend on a module exporting '%1'">; +def warn_non_modular_include_in_framework_module : Warning< + "include of non-modular header inside framework module '%0'">, + InGroup<NonModularIncludeInFrameworkModule>, DefaultIgnore; +def warn_non_modular_include_in_module : Warning< + "include of non-modular header inside module '%0'">, + InGroup<NonModularIncludeInModule>, DefaultIgnore; +def warn_module_conflict : Warning< + "module '%0' conflicts with already-imported module '%1': %2">, + InGroup<ModuleConflict>; + +def warn_header_guard : Warning< + "%0 is used as a header guard here, followed by #define of a different macro">, + InGroup<DiagGroup<"header-guard">>; +def note_header_guard : Note< + "%0 is defined here; did you mean %1?">; + +let CategoryName = "Nullability Issue" in { + +def err_pp_assume_nonnull_syntax : Error<"expected 'begin' or 'end'">; +def err_pp_double_begin_of_assume_nonnull : Error< + "already inside '#pragma clang assume_nonnull'">; +def err_pp_unmatched_end_of_assume_nonnull : Error< + "not currently inside '#pragma clang assume_nonnull'">; +def err_pp_include_in_assume_nonnull : Error< + "cannot #include files inside '#pragma clang assume_nonnull'">; +def err_pp_eof_in_assume_nonnull : Error< + "'#pragma clang assume_nonnull' was not ended within this file">; + +} + +} diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticOptions.def b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticOptions.def new file mode 100644 index 0000000..f4ba6da --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticOptions.def @@ -0,0 +1,99 @@ +//===--- DiagOptions.def - Diagnostic option database ------------- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the diagnostic options. Users of this file +// must define the DIAGOPT macro to make use of this information. +// Optionally, the user may also define ENUM_DIAGOPT (for options +// that have enumeration type and VALUE_DIAGOPT (for options that +// describe a value rather than a flag). The SEMANTIC_* variants of these macros +// indicate options that affect the processing of the program, rather than +// simply the output. +// +//===----------------------------------------------------------------------===// +#ifndef DIAGOPT +# error Define the DIAGOPT macro to handle language options +#endif + +#ifndef VALUE_DIAGOPT +# define VALUE_DIAGOPT(Name, Bits, Default) \ +DIAGOPT(Name, Bits, Default) +#endif + +#ifndef ENUM_DIAGOPT +# define ENUM_DIAGOPT(Name, Type, Bits, Default) \ +DIAGOPT(Name, Bits, Default) +#endif + +#ifndef SEMANTIC_DIAGOPT +# define SEMANTIC_DIAGOPT(Name, Bits, Default) DIAGOPT(Name, Bits, Default) +#endif + +#ifndef SEMANTIC_VALUE_DIAGOPT +# define SEMANTIC_VALUE_DIAGOPT(Name, Bits, Default) \ + VALUE_DIAGOPT(Name, Bits, Default) +#endif + +#ifndef SEMANTIC_ENUM_DIAGOPT +# define SEMANTIC_ENUM_DIAGOPT(Name, Type, Bits, Default) \ + ENUM_DIAGOPT(Name, Type, Bits, Default) +#endif + +SEMANTIC_DIAGOPT(IgnoreWarnings, 1, 0) /// -w +DIAGOPT(NoRewriteMacros, 1, 0) /// -Wno-rewrite-macros +DIAGOPT(Pedantic, 1, 0) /// -pedantic +DIAGOPT(PedanticErrors, 1, 0) /// -pedantic-errors +DIAGOPT(ShowColumn, 1, 1) /// Show column number on diagnostics. +DIAGOPT(ShowLocation, 1, 1) /// Show source location information. +DIAGOPT(ShowCarets, 1, 1) /// Show carets in diagnostics. +DIAGOPT(ShowFixits, 1, 1) /// Show fixit information. +DIAGOPT(ShowSourceRanges, 1, 0) /// Show source ranges in numeric form. +DIAGOPT(ShowParseableFixits, 1, 0) /// Show machine parseable fix-its. +DIAGOPT(ShowPresumedLoc, 1, 0) /// Show presumed location for diagnostics. +DIAGOPT(ShowOptionNames, 1, 0) /// Show the option name for mappable + /// diagnostics. +DIAGOPT(ShowNoteIncludeStack, 1, 0) /// Show include stacks for notes. +VALUE_DIAGOPT(ShowCategories, 2, 0) /// Show categories: 0 -> none, 1 -> Number, + /// 2 -> Full Name. + +ENUM_DIAGOPT(Format, TextDiagnosticFormat, 2, Clang) /// Format for diagnostics: + +DIAGOPT(ShowColors, 1, 0) /// Show diagnostics with ANSI color sequences. +ENUM_DIAGOPT(ShowOverloads, OverloadsShown, 1, + Ovl_All) /// Overload candidates to show. +DIAGOPT(VerifyDiagnostics, 1, 0) /// Check that diagnostics match the expected + /// diagnostics, indicated by markers in the + /// input source file. +ENUM_DIAGOPT(VerifyIgnoreUnexpected, DiagnosticLevelMask, 4, + DiagnosticLevelMask::None) /// Ignore unexpected diagnostics of + /// the specified levels when using + /// -verify. +DIAGOPT(ElideType, 1, 0) /// Elide identical types in template diffing +DIAGOPT(ShowTemplateTree, 1, 0) /// Print a template tree when diffing +DIAGOPT(CLFallbackMode, 1, 0) /// Format for clang-cl fallback mode + +VALUE_DIAGOPT(ErrorLimit, 32, 0) /// Limit # errors emitted. +/// Limit depth of macro expansion backtrace. +VALUE_DIAGOPT(MacroBacktraceLimit, 32, DefaultMacroBacktraceLimit) +/// Limit depth of instantiation backtrace. +VALUE_DIAGOPT(TemplateBacktraceLimit, 32, DefaultTemplateBacktraceLimit) +/// Limit depth of constexpr backtrace. +VALUE_DIAGOPT(ConstexprBacktraceLimit, 32, DefaultConstexprBacktraceLimit) +/// Limit number of times to perform spell checking. +VALUE_DIAGOPT(SpellCheckingLimit, 32, DefaultSpellCheckingLimit) + +VALUE_DIAGOPT(TabStop, 32, DefaultTabStop) /// The distance between tab stops. +/// Column limit for formatting message diagnostics, or 0 if unused. +VALUE_DIAGOPT(MessageLength, 32, 0) + +#undef DIAGOPT +#undef ENUM_DIAGOPT +#undef VALUE_DIAGOPT +#undef SEMANTIC_DIAGOPT +#undef SEMANTIC_ENUM_DIAGOPT +#undef SEMANTIC_VALUE_DIAGOPT diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticOptions.h b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticOptions.h new file mode 100644 index 0000000..c9b0c5d --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticOptions.h @@ -0,0 +1,118 @@ +//===--- 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_BASIC_DIAGNOSTICOPTIONS_H +#define LLVM_CLANG_BASIC_DIAGNOSTICOPTIONS_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include <string> +#include <type_traits> +#include <vector> + +namespace clang { + +/// \brief Specifies which overload candidates to display when overload +/// resolution fails. +enum OverloadsShown : unsigned { + Ovl_All, ///< Show all overloads. + Ovl_Best ///< Show just the "best" overload candidates. +}; + +/// \brief A bitmask representing the diagnostic levels used by +/// VerifyDiagnosticConsumer. +enum class DiagnosticLevelMask : unsigned { + None = 0, + Note = 1 << 0, + Remark = 1 << 1, + Warning = 1 << 2, + Error = 1 << 3, + All = Note | Remark | Warning | Error +}; + +inline DiagnosticLevelMask operator~(DiagnosticLevelMask M) { + using UT = std::underlying_type<DiagnosticLevelMask>::type; + return static_cast<DiagnosticLevelMask>(~static_cast<UT>(M)); +} + +inline DiagnosticLevelMask operator|(DiagnosticLevelMask LHS, + DiagnosticLevelMask RHS) { + using UT = std::underlying_type<DiagnosticLevelMask>::type; + return static_cast<DiagnosticLevelMask>( + static_cast<UT>(LHS) | static_cast<UT>(RHS)); +} + +inline DiagnosticLevelMask operator&(DiagnosticLevelMask LHS, + DiagnosticLevelMask RHS) { + using UT = std::underlying_type<DiagnosticLevelMask>::type; + return static_cast<DiagnosticLevelMask>( + static_cast<UT>(LHS) & static_cast<UT>(RHS)); +} + +raw_ostream& operator<<(raw_ostream& Out, DiagnosticLevelMask M); + +/// \brief Options for controlling the compiler diagnostics engine. +class DiagnosticOptions : public RefCountedBase<DiagnosticOptions>{ +public: + enum TextDiagnosticFormat { Clang, MSVC, Vi }; + + // Default values. + enum { DefaultTabStop = 8, MaxTabStop = 100, + DefaultMacroBacktraceLimit = 6, + DefaultTemplateBacktraceLimit = 10, + DefaultConstexprBacktraceLimit = 10, + DefaultSpellCheckingLimit = 50 }; + + // Define simple diagnostic options (with no accessors). +#define DIAGOPT(Name, Bits, Default) unsigned Name : Bits; +#define ENUM_DIAGOPT(Name, Type, Bits, Default) +#include "clang/Basic/DiagnosticOptions.def" + +protected: + // Define diagnostic options of enumeration type. These are private, and will + // have accessors (below). +#define DIAGOPT(Name, Bits, Default) +#define ENUM_DIAGOPT(Name, Type, Bits, Default) unsigned Name : Bits; +#include "clang/Basic/DiagnosticOptions.def" + +public: + /// \brief The file to log diagnostic output to. + std::string DiagnosticLogFile; + + /// \brief The file to serialize diagnostics to (non-appending). + std::string DiagnosticSerializationFile; + + /// The list of -W... options used to alter the diagnostic mappings, with the + /// prefixes removed. + std::vector<std::string> Warnings; + + /// The list of -R... options used to alter the diagnostic mappings, with the + /// prefixes removed. + std::vector<std::string> Remarks; + +public: + // Define accessors/mutators for diagnostic options of enumeration type. +#define DIAGOPT(Name, Bits, Default) +#define ENUM_DIAGOPT(Name, Type, Bits, Default) \ + Type get##Name() const { return static_cast<Type>(Name); } \ + void set##Name(Type Value) { Name = static_cast<unsigned>(Value); } +#include "clang/Basic/DiagnosticOptions.def" + + DiagnosticOptions() { +#define DIAGOPT(Name, Bits, Default) Name = Default; +#define ENUM_DIAGOPT(Name, Type, Bits, Default) set##Name(Default); +#include "clang/Basic/DiagnosticOptions.def" + } +}; + +typedef DiagnosticOptions::TextDiagnosticFormat TextDiagnosticFormat; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticParseKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticParseKinds.td new file mode 100644 index 0000000..f8dee2f --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -0,0 +1,985 @@ +//==--- DiagnosticParseKinds.td - libparse diagnostics --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Parser Diagnostics +//===----------------------------------------------------------------------===// + +let Component = "Parse" in { + +def w_asm_qualifier_ignored : Warning<"ignored %0 qualifier on asm">, + CatInlineAsm; +def warn_file_asm_volatile : Warning< + "meaningless 'volatile' on asm outside function">, CatInlineAsm; + +let CategoryName = "Inline Assembly Issue" in { +def err_asm_empty : Error<"__asm used with no assembly instructions">; +def err_inline_ms_asm_parsing : Error<"%0">; +def err_msasm_unsupported_arch : Error< + "Unsupported architecture '%0' for MS-style inline assembly">; +def err_msasm_unable_to_create_target : Error< + "MS-style inline assembly is not available: %0">; +def err_gnu_inline_asm_disabled : Error< + "GNU-style inline assembly is disabled">; +} + +let CategoryName = "Parse Issue" in { + +def ext_empty_translation_unit : Extension< + "ISO C requires a translation unit to contain at least one declaration">, + InGroup<DiagGroup<"empty-translation-unit">>; +def warn_cxx98_compat_top_level_semi : Warning< + "extra ';' outside of a function is incompatible with C++98">, + InGroup<CXX98CompatPedantic>, DefaultIgnore; +def ext_extra_semi : Extension< + "extra ';' %select{" + "outside of a function|" + "inside a %1|" + "inside instance variable list|" + "after member function definition}0">, + InGroup<ExtraSemi>; +def ext_extra_semi_cxx11 : Extension< + "extra ';' outside of a function is a C++11 extension">, + InGroup<CXX11ExtraSemi>; +def warn_extra_semi_after_mem_fn_def : Warning< + "extra ';' after member function definition">, + InGroup<ExtraSemi>, DefaultIgnore; + +def ext_thread_before : Extension<"'__thread' before '%0'">; +def ext_keyword_as_ident : ExtWarn< + "keyword '%0' will be made available as an identifier " + "%select{here|for the remainder of the translation unit}1">, + InGroup<KeywordCompat>; + +def ext_nullability : Extension< + "type nullability specifier %0 is a Clang extension">, + InGroup<DiagGroup<"nullability-extension">>; + +def error_empty_enum : Error<"use of empty enum">; + +def ext_ident_list_in_param : Extension< + "type-less parameter names in function declaration">; +def ext_c99_variable_decl_in_for_loop : Extension< + "variable declaration in for loop is a C99-specific feature">, InGroup<C99>; +def ext_c99_compound_literal : Extension< + "compound literals are a C99-specific feature">, InGroup<C99>; +def ext_enumerator_list_comma_c : Extension< + "commas at the end of enumerator lists are a C99-specific " + "feature">, InGroup<C99>; +def ext_enumerator_list_comma_cxx : Extension< + "commas at the end of enumerator lists are a C++11 extension">, + InGroup<CXX11>; +def warn_cxx98_compat_enumerator_list_comma : Warning< + "commas at the end of enumerator lists are incompatible with C++98">, + InGroup<CXX98CompatPedantic>, DefaultIgnore; +def err_enumerator_list_missing_comma : Error< + "missing ',' between enumerators">; +def err_enumerator_unnamed_no_def : Error< + "unnamed enumeration must be a definition">; +def ext_cxx11_enum_fixed_underlying_type : Extension< + "enumeration types with a fixed underlying type are a C++11 extension">, + InGroup<CXX11>; +def ext_c_enum_fixed_underlying_type : Extension< + "enumeration types with a fixed underlying type are a Microsoft extension">, + InGroup<MicrosoftFixedEnum>; +def warn_cxx98_compat_enum_fixed_underlying_type : Warning< + "enumeration types with a fixed underlying type are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def warn_cxx98_compat_alignof : Warning< + "alignof expressions are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def ext_alignof_expr : ExtWarn< + "%0 applied to an expression is a GNU extension">, InGroup<GNUAlignofExpression>; + +def warn_microsoft_dependent_exists : Warning< + "dependent %select{__if_not_exists|__if_exists}0 declarations are ignored">, + InGroup<DiagGroup<"microsoft-exists">>; +def warn_microsoft_qualifiers_ignored : Warning< + "qualifiers after comma in declarator list are ignored">, + InGroup<IgnoredAttributes>; + +def ext_c11_generic_selection : Extension< + "generic selections are a C11-specific feature">, InGroup<C11>; +def err_duplicate_default_assoc : Error< + "duplicate default generic association">; +def note_previous_default_assoc : Note< + "previous default generic association is here">; + +def ext_c11_alignment : Extension< + "%0 is a C11-specific feature">, InGroup<C11>; + +def ext_c11_noreturn : Extension< + "_Noreturn functions are a C11-specific feature">, InGroup<C11>; +def err_c11_noreturn_misplaced : Error< + "'_Noreturn' keyword must precede function declarator">; + +def ext_gnu_indirect_goto : Extension< + "use of GNU indirect-goto extension">, InGroup<GNULabelsAsValue>; +def ext_gnu_address_of_label : Extension< + "use of GNU address-of-label extension">, InGroup<GNULabelsAsValue>; +def err_stmtexpr_file_scope : Error< + "statement expression not allowed at file scope">; +def ext_gnu_statement_expr : Extension< + "use of GNU statement expression extension">, InGroup<GNUStatementExpression>; +def ext_gnu_conditional_expr : Extension< + "use of GNU ?: conditional expression extension, omitting middle operand">, InGroup<GNUConditionalOmittedOperand>; +def ext_gnu_empty_initializer : Extension< + "use of GNU empty initializer extension">, InGroup<GNUEmptyInitializer>; +def ext_gnu_array_range : Extension<"use of GNU array range extension">, + InGroup<GNUDesignator>; +def ext_gnu_missing_equal_designator : ExtWarn< + "use of GNU 'missing =' extension in designator">, + InGroup<GNUDesignator>; +def err_expected_equal_designator : Error<"expected '=' or another designator">; +def ext_gnu_old_style_field_designator : ExtWarn< + "use of GNU old-style field designator extension">, + InGroup<GNUDesignator>; +def ext_gnu_case_range : Extension<"use of GNU case range extension">, + InGroup<GNUCaseRange>; + +// Generic errors. +def err_expected_expression : Error<"expected expression">; +def err_expected_type : Error<"expected a type">; +def err_expected_external_declaration : Error<"expected external declaration">; +def err_extraneous_closing_brace : Error<"extraneous closing brace ('}')">; +def err_expected_semi_declaration : Error< + "expected ';' at end of declaration">; +def err_expected_semi_decl_list : Error< + "expected ';' at end of declaration list">; +def ext_expected_semi_decl_list : ExtWarn< + "expected ';' at end of declaration list">; +def err_expected_member_name_or_semi : Error< + "expected member name or ';' after declaration specifiers">; +def err_function_declared_typedef : Error< + "function definition declared 'typedef'">; +def err_at_defs_cxx : Error<"@defs is not supported in Objective-C++">; +def err_at_in_class : Error<"unexpected '@' in member specification">; +def err_unexpected_semi : Error<"unexpected ';' before %0">; + +def err_expected_fn_body : Error< + "expected function body after function declarator">; +def warn_attribute_on_function_definition : Warning< + "GCC does not allow %0 attribute in this position on a function definition">, + InGroup<GccCompat>; +def warn_gcc_attribute_location : Warning< + "GCC does not allow an attribute in this position on a function declaration">, + InGroup<GccCompat>; +def warn_attribute_no_decl : Warning< + "attribute %0 ignored, because it is not attached to a declaration">, + InGroup<IgnoredAttributes>; +def err_expected_method_body : Error<"expected method body">; +def err_declspec_after_virtspec : Error< + "'%0' qualifier may not appear after the virtual specifier '%1'">; +def err_invalid_token_after_toplevel_declarator : Error< + "expected ';' after top level declarator">; +def err_invalid_token_after_declarator_suggest_equal : Error< + "invalid %0 at end of declaration; did you mean '='?">; +def err_expected_statement : Error<"expected statement">; +def err_expected_lparen_after : Error<"expected '(' after '%0'">; +def err_expected_rparen_after : Error<"expected ')' after '%0'">; +def err_expected_punc : Error<"expected ')' or ',' after '%0'">; +def err_expected_less_after : Error<"expected '<' after '%0'">; +def err_expected_lbrace_in_compound_literal : Error< + "expected '{' in compound literal">; +def err_expected_while : Error<"expected 'while' in do/while loop">; + +def err_expected_semi_after_stmt : Error<"expected ';' after %0 statement">; +def err_expected_semi_after_expr : Error<"expected ';' after expression">; +def err_extraneous_token_before_semi : Error<"extraneous '%0' before ';'">; + +def err_expected_semi_after_method_proto : Error< + "expected ';' after method prototype">; +def err_expected_semi_after_namespace_name : Error< + "expected ';' after namespace name">; +def err_unexpected_namespace_attributes_alias : Error< + "attributes cannot be specified on namespace alias">; +def err_unexpected_nested_namespace_attribute : Error< + "attributes cannot be specified on a nested namespace definition">; +def err_inline_namespace_alias : Error<"namespace alias cannot be inline">; +def err_namespace_nonnamespace_scope : Error< + "namespaces can only be defined in global or namespace scope">; +def ext_nested_namespace_definition : ExtWarn< + "nested namespace definition is a C++1z extension; " + "define each namespace separately">, InGroup<CXX1z>; +def warn_cxx14_compat_nested_namespace_definition : Warning< + "nested namespace definition is incompatible with C++ standards before C++1z">, + InGroup<CXXPre1zCompat>, DefaultIgnore; +def err_inline_nested_namespace_definition : Error< + "nested namespace definition cannot be 'inline'">; +def err_expected_semi_after_attribute_list : Error< + "expected ';' after attribute list">; +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_single_decl_assign_in_for_range : Error< + "range-based 'for' statement uses ':', not '='">; +def warn_missing_selector_name : Warning< + "%0 used as the name of the previous parameter rather than as part " + "of the selector">, + InGroup<DiagGroup<"missing-selector-name">>; +def note_missing_selector_name : Note< + "introduce a parameter name to make %0 part of the selector">; +def note_force_empty_selector_name : Note< + "or insert whitespace before ':' to use %0 as parameter name " + "and have an empty entry in the selector">; +def err_label_end_of_compound_statement : Error< + "label at end of compound statement: expected statement">; +def err_address_of_label_outside_fn : Error< + "use of address-of-label extension outside of a function body">; +def err_asm_operand_wide_string_literal : Error< + "cannot use %select{unicode|wide}0 string literal in 'asm'">; +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">; +def err_atimport : Error< +"use of '@import' when modules are disabled">; + +def err_invalid_reference_qualifier_application : Error< + "'%0' qualifier may not be applied to a reference">; +def err_illegal_decl_reference_to_reference : Error< + "%0 declared as a reference to a reference">; +def ext_rvalue_reference : ExtWarn< + "rvalue references are a C++11 extension">, InGroup<CXX11>; +def warn_cxx98_compat_rvalue_reference : Warning< + "rvalue references are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def ext_ref_qualifier : ExtWarn< + "reference qualifiers on functions are a C++11 extension">, InGroup<CXX11>; +def warn_cxx98_compat_ref_qualifier : Warning< + "reference qualifiers on functions are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def ext_inline_namespace : ExtWarn< + "inline namespaces are a C++11 feature">, InGroup<CXX11InlineNamespace>; +def warn_cxx98_compat_inline_namespace : Warning< + "inline namespaces are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def ext_generalized_initializer_lists : ExtWarn< + "generalized initializer lists are a C++11 extension">, + InGroup<CXX11>; +def warn_cxx98_compat_generalized_initializer_lists : Warning< + "generalized initializer lists are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_init_list_bin_op : Error<"initializer list cannot be used on the " + "%select{left|right}0 hand side of operator '%1'">; +def warn_cxx98_compat_trailing_return_type : Warning< + "trailing return types are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def ext_auto_storage_class : ExtWarn< + "'auto' storage class specifier is not permitted in C++11, and will not " + "be supported in future releases">, InGroup<DiagGroup<"auto-storage-class">>; +def ext_decltype_auto_type_specifier : ExtWarn< + "'decltype(auto)' type specifier is a C++14 extension">, InGroup<CXX14>; +def warn_cxx11_compat_decltype_auto_type_specifier : Warning< + "'decltype(auto)' type specifier is incompatible with C++ standards before " + "C++14">, InGroup<CXXPre14Compat>, DefaultIgnore; +def ext_auto_type : Extension< + "'__auto_type' is a GNU extension">, + InGroup<GNUAutoType>; +def ext_for_range : ExtWarn< + "range-based for loop is a C++11 extension">, InGroup<CXX11>; +def warn_cxx98_compat_for_range : Warning< + "range-based for loop is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_for_range_identifier : Error< + "range-based for loop requires type for loop variable">; +def err_for_range_expected_decl : Error< + "for range declaration must declare a variable">; +def err_argument_required_after_attribute : Error< + "argument required after attribute">; +def err_missing_param : Error<"expected parameter declarator">; +def err_missing_comma_before_ellipsis : Error< + "C requires a comma prior to the ellipsis in a variadic function type">; +def err_unexpected_typedef_ident : Error< + "unexpected type name %0: expected identifier">; +def warn_cxx98_compat_decltype : Warning< + "'decltype' type specifier is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_unexpected_scope_on_base_decltype : Error< + "unexpected namespace scope prior to decltype">; +def err_expected_class_name : Error<"expected class name">; +def err_expected_class_name_not_template : + Error<"'typename' is redundant; base classes are implicitly types">; +def err_unspecified_vla_size_with_static : Error< + "'static' may not be used with an unspecified variable length array size">; +def err_unspecified_size_with_static : Error< + "'static' may not be used without an array size">; +def err_expected_parentheses_around_typename : Error< + "expected parentheses around type name in %0 expression">; + +def err_expected_case_before_expression: Error< + "expected 'case' keyword before expression">; + +// Declarations. +def err_typename_requires_specqual : Error< + "type name requires a specifier or qualifier">; +def err_typename_invalid_storageclass : Error< + "type name does not allow storage class to be specified">; +def err_typename_invalid_functionspec : Error< + "type name does not allow function specifier to be specified">; +def err_typename_invalid_constexpr : Error< + "type name does not allow constexpr specifier to be specified">; +def err_typename_identifiers_only : Error< + "typename is allowed for identifiers only">; + +def err_friend_invalid_in_context : Error< + "'friend' used outside of class">; +def err_templated_using_directive_declaration : Error< + "cannot template a using %select{directive|declaration}0">; +def err_unexpected_colon_in_nested_name_spec : Error< + "unexpected ':' in nested name specifier; did you mean '::'?">; +def err_unexpected_token_in_nested_name_spec : Error< + "'%0' cannot be a part of nested name specifier; did you mean ':'?">; +def err_bool_redeclaration : Error< + "redeclaration of C++ built-in type 'bool'">; +def ext_c11_static_assert : Extension< + "_Static_assert is a C11-specific feature">, InGroup<C11>; +def warn_cxx98_compat_static_assert : Warning< + "static_assert declarations are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_paren_after_colon_colon : Error< + "unexpected parenthesis after '::'">; +def err_function_definition_not_allowed : Error< + "function definition is not allowed here">; +def err_expected_end_of_enumerator : Error< + "expected '= constant-expression' or end of enumerator definition">; +def err_expected_coloncolon_after_super : Error< + "expected '::' after '__super'">; + +/// Objective-C parser diagnostics +def err_expected_minus_or_plus : Error< + "method type specifier must start with '-' or '+'">; +def err_objc_no_attributes_on_category : Error< + "attributes may not be specified on a category">; +def err_objc_missing_end : Error<"missing '@end'">; +def note_objc_container_start : Note< + "%select{class|protocol|category|class extension|implementation" + "|category implementation}0 started here">; +def warn_objc_protocol_qualifier_missing_id : Warning< + "protocol has no object type specified; defaults to qualified 'id'">; +def err_objc_unknown_at : Error<"expected an Objective-C directive after '@'">; +def err_illegal_super_cast : Error< + "cannot cast 'super' (it isn't an expression)">; +def err_nsnumber_nonliteral_unary : Error< + "@%0 must be followed by a number to form an NSNumber object">; +def warn_cstyle_param : Warning< + "use of C-style parameters in Objective-C method declarations" + " is deprecated">, InGroup<DeprecatedDeclarations>; + +let CategoryName = "ARC Parse Issue" in { +def err_arc_bridge_retain : Error< + "unknown cast annotation __bridge_retain; did you mean __bridge_retained?">; +// To be default mapped to an error later. +def warn_arc_bridge_cast_nonarc : Warning< + "'%0' casts have no effect when not using ARC">, + InGroup<DiagGroup<"arc-bridge-casts-disallowed-in-nonarc">>; +} + +def err_objc_illegal_visibility_spec : Error< + "illegal visibility specification">; +def err_objc_illegal_interface_qual : Error<"illegal interface qualifier">; +def err_objc_expected_equal_for_getter : Error< + "expected '=' for Objective-C getter">; +def err_objc_expected_equal_for_setter : Error< + "expected '=' for Objective-C setter">; +def err_objc_expected_selector_for_getter_setter : Error< + "expected selector for Objective-C %select{setter|getter}0">; +def err_objc_property_requires_field_name : Error< + "property requires fields to be named">; +def err_objc_property_bitfield : Error<"property name cannot be a bitfield">; +def err_objc_expected_property_attr : Error<"unknown property attribute %0">; +def err_objc_properties_require_objc2 : Error< + "properties are an Objective-C 2 feature">; +def err_objc_unexpected_attr : Error< + "prefix attribute must be followed by an interface or protocol">; +def err_objc_postfix_attribute : Error < + "postfix attributes are not allowed on Objective-C directives">; +def err_objc_postfix_attribute_hint : Error < + "postfix attributes are not allowed on Objective-C directives, place" + " them in front of '%select{@interface|@protocol}0'">; +def err_objc_directive_only_in_protocol : Error< + "directive may only be specified in protocols only">; +def err_missing_catch_finally : Error< + "@try statement without a @catch and @finally clause">; +def err_objc_concat_string : Error<"unexpected token after Objective-C string">; +def err_expected_objc_container : Error< + "'@end' must appear in an Objective-C context">; +def err_unexpected_protocol_qualifier : Error< + "@implementation declaration cannot be protocol qualified">; +def err_objc_unexpected_atend : Error< + "'@end' appears where closing brace '}' is expected">; +def error_property_ivar_decl : Error< + "property synthesize requires specification of an ivar">; +def err_synthesized_property_name : Error< + "expected a property name in @synthesize">; +def warn_semicolon_before_method_body : Warning< + "semicolon before method body is ignored">, + InGroup<DiagGroup<"semicolon-before-method-body">>, DefaultIgnore; +def note_extra_comma_message_arg : Note< + "comma separating Objective-C messaging arguments">; + +def err_expected_field_designator : Error< + "expected a field designator, such as '.field = 4'">; + +def err_declaration_does_not_declare_param : Error< + "declaration does not declare a parameter">; +def err_no_matching_param : Error<"parameter named %0 is missing">; + +/// C++ parser diagnostics +def err_invalid_operator_on_type : Error< + "cannot use %select{dot|arrow}0 operator on a type">; +def err_expected_unqualified_id : Error< + "expected %select{identifier|unqualified-id}0">; +def err_brackets_go_after_unqualified_id : Error< + "brackets are not allowed here; to declare an array, " + "place the brackets after the %select{identifier|name}0">; +def err_unexpected_unqualified_id : Error<"type-id cannot have a name">; +def err_func_def_no_params : Error< + "function definition does not declare parameters">; +def err_expected_lparen_after_type : Error< + "expected '(' for function-style cast or type construction">; +def err_expected_init_in_condition : Error< + "variable declaration in condition must have an initializer">; +def err_expected_init_in_condition_lparen : Error< + "variable declaration in condition cannot have a parenthesized initializer">; +def err_extraneous_rparen_in_condition : Error< + "extraneous ')' after condition, expected a statement">; +def warn_dangling_else : Warning< + "add explicit braces to avoid dangling else">, + InGroup<DanglingElse>; +def err_expected_member_or_base_name : Error< + "expected class member or base class name">; +def err_expected_lbrace_after_base_specifiers : Error< + "expected '{' after base class list">; +def err_missing_end_of_definition : Error< + "missing '}' at end of definition of %q0">; +def note_missing_end_of_definition_before : Note< + "still within definition of %q0 here">; +def ext_ellipsis_exception_spec : Extension< + "exception specification of '...' is a Microsoft extension">, + InGroup<MicrosoftExceptionSpec>; +def err_dynamic_and_noexcept_specification : Error< + "cannot have both throw() and noexcept() clause on the same function">; +def err_except_spec_unparsed : Error< + "unexpected end of exception specification">; +def warn_cxx98_compat_noexcept_decl : Warning< + "noexcept specifications are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_expected_catch : Error<"expected catch">; +def err_using_namespace_in_class : Error< + "'using namespace' is not allowed in classes">; +def err_constructor_bad_name : Error< + "missing return type for function %0; did you mean the constructor name %1?">; +def err_destructor_tilde_identifier : Error< + "expected a class name after '~' to name a destructor">; +def err_destructor_tilde_scope : Error< + "'~' in destructor name should be after nested name specifier">; +def err_destructor_template_id : Error< + "destructor name %0 does not refer to a template">; +def err_default_arg_unparsed : Error< + "unexpected end of default argument expression">; +def err_bracket_depth_exceeded : Error< + "bracket nesting level exceeded maximum of %0">, DefaultFatal; +def note_bracket_depth : Note< + "use -fbracket-depth=N to increase maximum nesting level">; +def err_misplaced_ellipsis_in_declaration : Error< + "'...' must %select{immediately precede declared identifier|" + "be innermost component of anonymous pack declaration}0">; +def warn_misplaced_ellipsis_vararg : Warning< + "'...' in this location creates a C-style varargs function" + "%select{, not a function parameter pack|}0">, + InGroup<DiagGroup<"ambiguous-ellipsis">>; +def note_misplaced_ellipsis_vararg_existing_ellipsis : Note< + "preceding '...' declares a function parameter pack">; +def note_misplaced_ellipsis_vararg_add_ellipsis : Note< + "place '...' %select{immediately before declared identifier|here}0 " + "to declare a function parameter pack">; +def note_misplaced_ellipsis_vararg_add_comma : Note< + "insert ',' before '...' to silence this warning">; +def ext_abstract_pack_declarator_parens : ExtWarn< + "ISO C++11 requires a parenthesized pack declaration to have a name">, + InGroup<DiagGroup<"anonymous-pack-parens">>; +def err_function_is_not_record : Error< + "unexpected %0 in function call; perhaps remove the %0?">; +def err_super_in_using_declaration : Error< + "'__super' cannot be used with a using declaration">; + +// C++ derived classes +def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">; + +// C++ operator overloading +def err_literal_operator_string_prefix : Error< + "string literal after 'operator' cannot have an encoding prefix">; +def err_literal_operator_string_not_empty : Error< + "string literal after 'operator' must be '\"\"'">; +def warn_cxx98_compat_literal_operator : Warning< + "literal operators are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; + +// Classes. +def err_anon_type_definition : Error< + "declaration of anonymous %0 must be a definition">; +def err_default_delete_in_multiple_declaration : Error< + "'= %select{default|delete}0' is a function definition and must occur in a " + "standalone declaration">; + +def warn_cxx98_compat_noexcept_expr : Warning< + "noexcept expressions are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def warn_cxx98_compat_nullptr : Warning< + "'nullptr' is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; + +def warn_cxx14_compat_attribute : Warning< + "attributes on %select{a namespace|an enumerator}0 declaration are " + "incompatible with C++ standards before C++1z">, + InGroup<CXXPre1zCompat>, DefaultIgnore; +def warn_cxx98_compat_alignas : Warning<"'alignas' is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def warn_cxx98_compat_attribute : Warning< + "C++11 attribute syntax is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_cxx11_attribute_forbids_arguments : Error< + "attribute %0 cannot have an argument list">; +def err_attribute_requires_arguments : Error< + "parentheses must be omitted if %0 attribute's argument list is empty">; +def err_cxx11_attribute_forbids_ellipsis : Error< + "attribute '%0' cannot be used as an attribute pack">; +def err_cxx11_attribute_repeated : Error< + "attribute %0 cannot appear multiple times in an attribute specifier">; +def err_attributes_not_allowed : Error<"an attribute list cannot appear here">; +def err_l_square_l_square_not_attribute : Error< + "C++11 only allows consecutive left square brackets when " + "introducing an attribute">; +def err_ms_declspec_type : Error< + "__declspec attributes must be an identifier or string literal">; +def err_ms_property_no_getter_or_putter : Error< + "property does not specify a getter or a putter">; +def err_ms_property_unknown_accessor : Error< + "expected 'get' or 'put' in property declaration">; +def err_ms_property_has_set_accessor : Error< + "putter for property must be specified as 'put', not 'set'">; +def err_ms_property_missing_accessor_kind : Error< + "missing 'get=' or 'put='">; +def err_ms_property_expected_equal : Error< + "expected '=' after '%0'">; +def err_ms_property_duplicate_accessor : Error< + "property declaration specifies '%0' accessor twice">; +def err_ms_property_expected_accessor_name : Error< + "expected name of accessor method">; +def err_ms_property_expected_comma_or_rparen : Error< + "expected ',' or ')' at end of property accessor list">; +def err_ms_property_initializer : Error< + "property declaration cannot have an in-class initializer">; + +/// C++ Templates +def err_expected_template : Error<"expected template">; +def err_unknown_template_name : Error< + "unknown template name %0">; +def err_expected_comma_greater : Error< + "expected ',' or '>' in template-parameter-list">; +def err_class_on_template_template_param : Error< + "template template parameter requires 'class' after the parameter list">; +def ext_template_template_param_typename : ExtWarn< + "template template parameter using 'typename' is a C++1z extension">, + InGroup<CXX1z>; +def warn_cxx14_compat_template_template_param_typename : Warning< + "template template parameter using 'typename' is " + "incompatible with C++ standards before C++1z">, + InGroup<CXXPre1zCompat>, DefaultIgnore; +def err_template_spec_syntax_non_template : Error< + "identifier followed by '<' indicates a class template specialization but " + "%0 %select{does not refer to a template|refers to a function template|" + "<unused>|refers to a variable template|<unused>}1">; +def err_id_after_template_in_nested_name_spec : Error< + "expected template name after 'template' keyword in nested name specifier">; +def err_two_right_angle_brackets_need_space : Error< + "a space is required between consecutive right angle brackets (use '> >')">; +def err_right_angle_bracket_equal_needs_space : Error< + "a space is required between a right angle bracket and an equals sign " + "(use '> =')">; +def warn_cxx11_right_shift_in_template_arg : Warning< + "use of right-shift operator ('>>') in template argument will require " + "parentheses in C++11">, InGroup<CXX11Compat>; +def warn_cxx98_compat_two_right_angle_brackets : Warning< + "consecutive right angle brackets are incompatible with C++98 (use '> >')">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_templated_invalid_declaration : Error< + "a static_assert declaration cannot be a template">; +def err_multiple_template_declarators : Error< + "%select{|a template declaration|an explicit template specialization|" + "an explicit template instantiation}0 can " + "only %select{|declare|declare|instantiate}0 a single entity">; +def err_explicit_instantiation_with_definition : Error< + "explicit template instantiation cannot have a definition; if this " + "definition is meant to be an explicit specialization, add '<>' after the " + "'template' keyword">; +def err_template_defn_explicit_instantiation : Error< + "%select{function|class|variable}0 cannot be defined in an explicit instantiation; if this " + "declaration is meant to be a %select{function|class|variable}0 definition, remove the 'template' keyword">; +def err_friend_explicit_instantiation : Error< + "friend cannot be declared in an explicit instantiation; if this " + "declaration is meant to be a friend declaration, remove the 'template' keyword">; +def err_explicit_instantiation_enum : Error< + "enumerations cannot be explicitly instantiated">; +def err_expected_template_parameter : Error<"expected template parameter">; + +def err_missing_dependent_template_keyword : Error< + "use 'template' keyword to treat '%0' as a dependent template name">; +def warn_missing_dependent_template_keyword : ExtWarn< + "use 'template' keyword to treat '%0' as a dependent template name">; + +def ext_extern_template : Extension< + "extern templates are a C++11 extension">, InGroup<CXX11>; +def warn_cxx98_compat_extern_template : Warning< + "extern templates are incompatible with C++98">, + InGroup<CXX98CompatPedantic>, DefaultIgnore; +def warn_static_inline_explicit_inst_ignored : Warning< + "ignoring '%select{static|inline}0' keyword on explicit template " + "instantiation">, InGroup<DiagGroup<"static-inline-explicit-instantiation">>; + +// Constructor template diagnostics. +def err_out_of_line_constructor_template_id : Error< + "out-of-line constructor for %0 cannot have template arguments">; +def err_out_of_line_template_id_type_names_constructor : Error< + "qualified reference to %0 is a constructor name rather than a " + "%select{template name|type}1 wherever a constructor can be declared">; + +def err_expected_qualified_after_typename : Error< + "expected a qualified name after 'typename'">; +def warn_expected_qualified_after_typename : ExtWarn< + "expected a qualified name after 'typename'">; + +def err_typename_refers_to_non_type_template : Error< + "typename specifier refers to a non-type 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 %1 %2">; + +def err_default_template_template_parameter_not_template : Error< + "default template argument for a template template parameter must be a class " + "template">; + +def ext_fold_expression : ExtWarn< + "pack fold expression is a C++1z extension">, + InGroup<CXX1z>; +def warn_cxx14_compat_fold_expression : Warning< + "pack fold expression is incompatible with C++ standards before C++1z">, + InGroup<CXXPre1zCompat>, DefaultIgnore; +def err_expected_fold_operator : Error< + "expected a foldable binary operator in fold expression">; +def err_fold_operator_mismatch : Error< + "operators in fold expression must be the same">; + +def err_ctor_init_missing_comma : Error< + "missing ',' between base or member initializers">; + +// C++ declarations +def err_friend_decl_defines_type : Error< + "cannot define a type in a friend declaration">; +def err_missing_whitespace_digraph : Error< + "found '<::' after a " + "%select{template name|const_cast|dynamic_cast|reinterpret_cast|static_cast}0" + " which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?">; + +def ext_defaulted_deleted_function : ExtWarn< + "%select{defaulted|deleted}0 function definitions are a C++11 extension">, + InGroup<CXX11>; +def warn_cxx98_compat_defaulted_deleted_function : Warning< + "%select{defaulted|deleted}0 function definitions are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; + +// C++11 in-class member initialization +def ext_nonstatic_member_init : ExtWarn< + "in-class initialization of non-static data member is a C++11 extension">, + InGroup<CXX11>; +def warn_cxx98_compat_nonstatic_member_init : Warning< + "in-class initialization of non-static data members is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_bitfield_member_init: Error< + "bitfield member cannot have an in-class initializer">; +def err_incomplete_array_member_init: Error< + "array bound cannot be deduced from an in-class initializer">; + +// C++11 alias-declaration +def ext_alias_declaration : ExtWarn< + "alias declarations are a C++11 extension">, InGroup<CXX11>; +def warn_cxx98_compat_alias_declaration : Warning< + "alias declarations are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_alias_declaration_not_identifier : Error< + "name defined in alias declaration must be an identifier">; +def err_alias_declaration_specialization : Error< + "%select{partial specialization|explicit specialization|explicit instantiation}0 of alias templates is not permitted">; + +// C++11 override control +def ext_override_control_keyword : ExtWarn< + "'%0' keyword is a C++11 extension">, InGroup<CXX11>; +def warn_cxx98_compat_override_control_keyword : Warning< + "'%0' keyword is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_override_control_interface : Error< + "'%0' keyword not permitted with interface types">; +def ext_ms_sealed_keyword : ExtWarn< + "'sealed' keyword is a Microsoft extension">, + InGroup<MicrosoftSealed>; + +def err_access_specifier_interface : Error< + "interface types cannot specify '%select{private|protected}0' access">; + +def err_duplicate_virt_specifier : Error< + "class member already marked '%0'">; + +def err_scoped_enum_missing_identifier : Error< + "scoped enumeration requires a name">; +def ext_scoped_enum : ExtWarn< + "scoped enumerations are a C++11 extension">, InGroup<CXX11>; +def warn_cxx98_compat_scoped_enum : Warning< + "scoped enumerations are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; + +def err_expected_parameter_pack : Error< + "expected the name of a parameter pack">; +def err_paren_sizeof_parameter_pack : Error< + "missing parentheses around the size of parameter pack %0">; +def err_sizeof_parameter_pack : Error< + "expected parenthesized parameter pack name in 'sizeof...' expression">; + +// C++11 lambda expressions +def err_expected_comma_or_rsquare : Error< + "expected ',' or ']' in lambda capture list">; +def err_this_captured_by_reference : Error< + "'this' cannot be captured by reference">; +def err_expected_capture : Error< + "expected variable name or 'this' in lambda capture list">; +def err_expected_lambda_body : Error<"expected body of lambda expression">; +def warn_cxx98_compat_lambda : Warning< + "lambda expressions are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_lambda_missing_parens : Error< + "lambda requires '()' before %select{'mutable'|return type|" + "attribute specifier}0">; + +// Availability attribute +def err_expected_version : Error< + "expected a version of the form 'major[.minor[.subminor]]'">; +def warn_expected_consistent_version_separator : Warning< + "use same version number separators '_' or '.'; as in " + "'major[.minor[.subminor]]'">, InGroup<Availability>; +def err_zero_version : Error< + "version number must have non-zero major, minor, or sub-minor version">; +def err_availability_expected_platform : Error< + "expected a platform name, e.g., 'macosx'">; + +// objc_bridge_related attribute +def err_objcbridge_related_expected_related_class : Error< + "expected a related ObjectiveC class name, e.g., 'NSColor'">; +def err_objcbridge_related_selector_name : Error< + "expected a class method selector with single argument, e.g., 'colorWithCGColor:'">; + +def err_availability_expected_change : Error< + "expected 'introduced', 'deprecated', or 'obsoleted'">; +def err_availability_unknown_change : Error< + "%0 is not an availability stage; use 'introduced', 'deprecated', or " + "'obsoleted'">; +def err_availability_redundant : Error< + "redundant %0 availability change; only the last specified change will " + "be used">; +def warn_availability_and_unavailable : Warning< + "'unavailable' availability overrides all other availability information">, + InGroup<Availability>; + +// Type safety attributes +def err_type_safety_unknown_flag : Error< + "invalid comparison flag %0; use 'layout_compatible' or 'must_be_null'">; + +// Type traits +def err_type_trait_arity : Error< + "type trait requires %0%select{| or more}1 argument%select{|s}2; have " + "%3 argument%s3">; + +// Language specific pragmas +// - Generic warnings +def warn_pragma_expected_lparen : Warning< + "missing '(' after '#pragma %0' - ignoring">, InGroup<IgnoredPragmas>; +def warn_pragma_expected_rparen : Warning< + "missing ')' after '#pragma %0' - ignoring">, InGroup<IgnoredPragmas>; +def warn_pragma_expected_identifier : Warning< + "expected identifier in '#pragma %0' - ignored">, InGroup<IgnoredPragmas>; +def warn_pragma_expected_section_name : Warning< + "expected a string literal for the section name in '#pragma %0' - ignored">, + InGroup<IgnoredPragmas>; +def warn_pragma_expected_section_push_pop_or_name : Warning< + "expected push, pop or a string literal for the section name in '#pragma %0' - ignored">, + InGroup<IgnoredPragmas>; +def warn_pragma_expected_section_label_or_name : Warning< + "expected a stack label or a string literal for the section name in '#pragma %0' - ignored">, + InGroup<IgnoredPragmas>; +def warn_pragma_expected_init_seg : Warning< + "expected 'compiler', 'lib', 'user', or a string literal for the section name in '#pragma %0' - ignored">, + InGroup<IgnoredPragmas>; +def warn_pragma_expected_integer : Warning< + "expected integer between %0 and %1 inclusive in '#pragma %2' - ignored">, + InGroup<IgnoredPragmas>; +def warn_pragma_ms_struct : Warning< + "incorrect use of '#pragma ms_struct on|off' - ignored">, + InGroup<IgnoredPragmas>; +def warn_pragma_extra_tokens_at_eol : Warning< + "extra tokens at end of '#pragma %0' - ignored">, + InGroup<IgnoredPragmas>; +def warn_pragma_expected_punc : Warning< + "expected ')' or ',' in '#pragma %0'">, InGroup<IgnoredPragmas>; +def warn_pragma_expected_non_wide_string : Warning< + "expected non-wide string literal in '#pragma %0'">, InGroup<IgnoredPragmas>; +// - Generic errors +def err_pragma_missing_argument : Error< + "missing argument to '#pragma %0'%select{|; expected %2}1">; +// - #pragma options +def warn_pragma_options_expected_align : Warning< + "expected 'align' following '#pragma options' - ignored">, + InGroup<IgnoredPragmas>; +def warn_pragma_align_expected_equal : Warning< + "expected '=' following '#pragma %select{align|options align}0' - ignored">, + InGroup<IgnoredPragmas>; +def warn_pragma_align_invalid_option : Warning< + "invalid alignment option in '#pragma %select{align|options align}0' - ignored">, + InGroup<IgnoredPragmas>; +// - #pragma pack +def warn_pragma_unsupported_action : Warning< + "known but unsupported action '%1' for '#pragma %0' - ignored">, + InGroup<IgnoredPragmas>; +def warn_pragma_invalid_specific_action : Warning< + "unknown action '%1' for '#pragma %0' - ignored">, + InGroup<IgnoredPragmas>; +def warn_pragma_expected_action_or_r_paren : Warning< + "expected action or ')' in '#pragma %0' - ignored">, + InGroup<IgnoredPragmas>; +def warn_pragma_invalid_action : Warning< + "unknown action for '#pragma %0' - ignored">, + InGroup<IgnoredPragmas>; +def warn_pragma_pack_malformed : Warning< + "expected integer or identifier in '#pragma pack' - ignored">, + InGroup<IgnoredPragmas>; +// - #pragma unused +def warn_pragma_unused_expected_var : Warning< + "expected '#pragma unused' argument to be a variable name">, + InGroup<IgnoredPragmas>; +// - #pragma init_seg +def warn_pragma_init_seg_unsupported_target : Warning< + "'#pragma init_seg' is only supported when targeting a " + "Microsoft environment">, + InGroup<IgnoredPragmas>; +// - #pragma fp_contract +def err_pragma_fp_contract_scope : Error< + "'#pragma fp_contract' can only appear at file scope or at the start of a " + "compound statement">; +// - #pragma comment +def err_pragma_comment_malformed : Error< + "pragma comment requires parenthesized identifier and optional string">; +def err_pragma_comment_unknown_kind : Error<"unknown kind of pragma comment">; +// PS4 recognizes only #pragma comment(lib) +def warn_pragma_comment_ignored : Warning<"'#pragma comment %0' ignored">, + InGroup<IgnoredPragmas>; +// - #pragma detect_mismatch +def err_pragma_detect_mismatch_malformed : Error< + "pragma detect_mismatch is malformed; it requires two comma-separated " + "string literals">; +// - #pragma pointers_to_members +def err_pragma_pointers_to_members_unknown_kind : Error< + "unexpected %0, expected to see one of %select{|'best_case', 'full_generality', }1" + "'single_inheritance', 'multiple_inheritance', or 'virtual_inheritance'">; +// - #pragma clang optimize on/off +def err_pragma_optimize_invalid_argument : Error< + "unexpected argument '%0' to '#pragma clang optimize'; " + "expected 'on' or 'off'">; +def err_pragma_optimize_extra_argument : Error< + "unexpected extra argument '%0' to '#pragma clang optimize'">; + +// OpenCL EXTENSION pragma (OpenCL 1.1 [9.1]) +def warn_pragma_expected_colon : Warning< + "missing ':' after %0 - ignoring">, InGroup<IgnoredPragmas>; +def warn_pragma_expected_enable_disable : Warning< + "expected 'enable' or 'disable' - ignoring">, InGroup<IgnoredPragmas>; +def warn_pragma_unknown_extension : Warning< + "unknown OpenCL extension %0 - ignoring">, InGroup<IgnoredPragmas>; + +// OpenCL error +def err_opencl_taking_function_address_parser : Error< + "taking address of function is not allowed">; + +// OpenMP support. +def warn_pragma_omp_ignored : Warning< + "unexpected '#pragma omp ...' in program">, InGroup<SourceUsesOpenMP>, DefaultIgnore; +def warn_omp_extra_tokens_at_eol : Warning< + "extra tokens at the end of '#pragma omp %0' are ignored">, + InGroup<ExtraTokens>; +def warn_pragma_expected_colon_r_paren : Warning< + "missing ':' or ')' after %0 - ignoring">, InGroup<IgnoredPragmas>; +def err_omp_unknown_directive : Error< + "expected an OpenMP directive">; +def err_omp_unexpected_directive : Error< + "unexpected OpenMP directive '#pragma omp %0'">; +def err_omp_expected_punc : Error< + "expected ',' or ')' in '%0' %select{clause|directive}1">; +def err_omp_unexpected_clause : Error< + "unexpected OpenMP clause '%0' in directive '#pragma omp %1'">; +def err_omp_immediate_directive : Error< + "'#pragma omp %0' %select{|with '%2' clause }1cannot be an immediate substatement">; +def err_omp_expected_identifier_for_critical : Error< + "expected identifier specifying the name of the 'omp critical' directive">; +def err_omp_unknown_map_type : Error< + "incorrect map type, expected one of 'to', 'from', 'tofrom', 'alloc', 'release', or 'delete'">; +def err_omp_unknown_map_type_modifier : Error< + "incorrect map type modifier, expected 'always'">; +def err_omp_map_type_missing : Error< + "missing map type">; + +// Pragma loop support. +def err_pragma_loop_missing_argument : Error< + "missing argument; expected %select{an integer value|" + "'enable', %select{'assume_safety'|'full'}1 or 'disable'}0">; +def err_pragma_loop_invalid_option : Error< + "%select{invalid|missing}0 option%select{ %1|}0; expected vectorize, " + "vectorize_width, interleave, interleave_count, unroll, or unroll_count">; +def err_pragma_invalid_keyword : Error< + "invalid argument; expected 'enable', %select{'assume_safety'|'full'}0 or 'disable'">; + +// Pragma unroll support. +def warn_pragma_unroll_cuda_value_in_parens : Warning< + "argument to '#pragma unroll' should not be in parentheses in CUDA C/C++">, + InGroup<CudaCompat>; +} // end of Parse Issue category. + +let CategoryName = "Modules Issue" in { +def err_module_expected_ident : Error< + "expected a module name after module import">; +def err_module_expected_semi : Error< + "expected ';' after module name">; +def err_missing_before_module_end : Error<"expected %0 at end of module">; +} + +let CategoryName = "Generics Issue" in { + +def err_objc_expected_type_parameter : Error< + "expected type parameter name">; + +def err_objc_parameterized_implementation : Error< + "@implementation cannot have type parameters">; + +def err_objc_type_args_after_protocols : Error< + "protocol qualifiers must precede type arguments">; +} + +let CategoryName = "Coroutines Issue" in { +def err_for_co_await_not_range_for : Error< + "'co_await' modifier can only be applied to range-based for loop">; +} + +} // end of Parser diagnostics diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td new file mode 100644 index 0000000..59f5095 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -0,0 +1,8221 @@ + +//==--- DiagnosticSemaKinds.td - libsema diagnostics ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Semantic Analysis +//===----------------------------------------------------------------------===// + +let Component = "Sema" in { +let CategoryName = "Semantic Issue" in { + +def note_previous_decl : Note<"%0 declared here">; +def note_entity_declared_at : Note<"%0 declared here">; +def note_callee_decl : Note<"%0 declared here">; +def note_defined_here : Note<"%0 defined here">; + +// For loop analysis +def warn_variables_not_in_loop_body : Warning< + "variable%select{s| %1|s %1 and %2|s %1, %2, and %3|s %1, %2, %3, and %4}0 " + "used in loop condition not modified in loop body">, + InGroup<ForLoopAnalysis>, DefaultIgnore; +def warn_redundant_loop_iteration : Warning< + "variable %0 is %select{decremented|incremented}1 both in the loop header " + "and in the loop body">, + InGroup<ForLoopAnalysis>, DefaultIgnore; +def note_loop_iteration_here : Note<"%select{decremented|incremented}0 here">; + +def warn_for_range_const_reference_copy : Warning< + "loop variable %0 " + "%diff{has type $ but is initialized with type $" + "| is initialized with a value of a different type}1,2 resulting in a copy">, + InGroup<RangeLoopAnalysis>, DefaultIgnore; +def note_use_type_or_non_reference : Note< + "use non-reference type %0 to keep the copy or type %1 to prevent copying">; +def warn_for_range_variable_always_copy : Warning< + "loop variable %0 is always a copy because the range of type %1 does not " + "return a reference">, + InGroup<RangeLoopAnalysis>, DefaultIgnore; +def note_use_non_reference_type : Note<"use non-reference type %0">; +def warn_for_range_copy : Warning< + "loop variable %0 of type %1 creates a copy from type %2">, + InGroup<RangeLoopAnalysis>, DefaultIgnore; +def note_use_reference_type : Note<"use reference type %0 to prevent copying">; + +def warn_duplicate_enum_values : Warning< + "element %0 has been implicitly assigned %1 which another element has " + "been assigned">, InGroup<DiagGroup<"duplicate-enum">>, DefaultIgnore; +def note_duplicate_element : Note<"element %0 also has value %1">; + +// Absolute value functions +def warn_unsigned_abs : Warning< + "taking the absolute value of unsigned type %0 has no effect">, + InGroup<AbsoluteValue>; +def note_remove_abs : Note< + "remove the call to '%0' since unsigned values cannot be negative">; +def warn_abs_too_small : Warning< + "absolute value function %0 given an argument of type %1 but has parameter " + "of type %2 which may cause truncation of value">, InGroup<AbsoluteValue>; +def warn_wrong_absolute_value_type : Warning< + "using %select{integer|floating point|complex}1 absolute value function %0 " + "when argument is of %select{integer|floating point|complex}2 type">, + InGroup<AbsoluteValue>; +def note_replace_abs_function : Note<"use function '%0' instead">; +def warn_pointer_abs : Warning< + "taking the absolute value of %select{pointer|function|array}0 type %1 is suspicious">, + InGroup<AbsoluteValue>; + +def warn_infinite_recursive_function : Warning< + "all paths through this function will call itself">, + InGroup<InfiniteRecursion>, DefaultIgnore; + +// Constant expressions +def err_expr_not_ice : Error< + "expression is not an %select{integer|integral}0 constant expression">; +def ext_expr_not_ice : Extension< + "expression is not an %select{integer|integral}0 constant expression; " + "folding it to a constant is a GNU extension">, InGroup<GNUFoldingConstant>; +def err_typecheck_converted_constant_expression : Error< + "value of type %0 is not implicitly convertible to %1">; +def err_typecheck_converted_constant_expression_disallowed : Error< + "conversion from %0 to %1 is not allowed in a converted constant expression">; +def err_typecheck_converted_constant_expression_indirect : Error< + "conversion from %0 to %1 in converted constant expression would " + "bind reference to a temporary">; +def err_expr_not_cce : Error< + "%select{case value|enumerator value|non-type template argument|array size}0 " + "is not a constant expression">; +def ext_cce_narrowing : ExtWarn< + "%select{case value|enumerator value|non-type template argument|array size}0 " + "%select{cannot be narrowed from type %2 to %3|" + "evaluates to %2, which cannot be narrowed to type %3}1">, + InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure; +def err_ice_not_integral : Error< + "integral constant expression must have integral or unscoped enumeration " + "type, not %0">; +def err_ice_incomplete_type : Error< + "integral constant expression has incomplete class type %0">; +def err_ice_explicit_conversion : Error< + "integral constant expression requires explicit conversion from %0 to %1">; +def note_ice_conversion_here : Note< + "conversion to %select{integral|enumeration}0 type %1 declared here">; +def err_ice_ambiguous_conversion : Error< + "ambiguous conversion from type %0 to an integral or unscoped " + "enumeration type">; +def err_ice_too_large : Error< + "integer constant expression evaluates to value %0 that cannot be " + "represented in a %1-bit %select{signed|unsigned}2 integer type">; +def err_expr_not_string_literal : Error<"expression is not a string literal">; + +// Semantic analysis of constant literals. +def ext_predef_outside_function : Warning< + "predefined identifier is only valid inside function">, + InGroup<DiagGroup<"predefined-identifier-outside-function">>; +def warn_float_overflow : Warning< + "magnitude of floating-point constant too large for type %0; maximum is %1">, + InGroup<LiteralRange>; +def warn_float_underflow : Warning< + "magnitude of floating-point constant too small for type %0; minimum is %1">, + InGroup<LiteralRange>; +def warn_double_const_requires_fp64 : Warning< + "double precision constant requires cl_khr_fp64, casting to single precision">; + +// C99 variable-length arrays +def ext_vla : Extension<"variable length arrays are a C99 feature">, + InGroup<VLAExtension>; +def warn_vla_used : Warning<"variable length array used">, + InGroup<VLA>, DefaultIgnore; +def err_vla_non_pod : Error<"variable length array of non-POD element type %0">; +def err_vla_in_sfinae : Error< + "variable length array cannot be formed during template argument deduction">; +def err_array_star_in_function_definition : Error< + "variable length array must be bound in function definition">; +def err_vla_decl_in_file_scope : Error< + "variable length array declaration not allowed at file scope">; +def err_vla_decl_has_static_storage : Error< + "variable length array declaration cannot have 'static' storage duration">; +def err_vla_decl_has_extern_linkage : Error< + "variable length array declaration cannot have 'extern' linkage">; +def ext_vla_folded_to_constant : Extension< + "variable length array folded to constant array as an extension">, InGroup<GNUFoldingConstant>; + +// C99 variably modified types +def err_variably_modified_template_arg : Error< + "variably modified type %0 cannot be used as a template argument">; +def err_variably_modified_nontype_template_param : Error< + "non-type template parameter of variably modified type %0">; +def err_variably_modified_new_type : Error< + "'new' cannot allocate object of variably modified type %0">; + +// C99 Designated Initializers +def ext_designated_init : Extension< + "designated initializers are a C99 feature">, InGroup<C99>; +def err_array_designator_negative : Error< + "array designator value '%0' is negative">; +def err_array_designator_empty_range : Error< + "array designator range [%0, %1] is empty">; +def err_array_designator_non_array : Error< + "array designator cannot initialize non-array type %0">; +def err_array_designator_too_large : Error< + "array designator index (%0) exceeds array bounds (%1)">; +def err_field_designator_non_aggr : Error< + "field designator cannot initialize a " + "%select{non-struct, non-union|non-class}0 type %1">; +def err_field_designator_unknown : Error< + "field designator %0 does not refer to any field in type %1">; +def err_field_designator_nonfield : Error< + "field designator %0 does not refer to a non-static data member">; +def note_field_designator_found : Note<"field designator refers here">; +def err_designator_for_scalar_init : Error< + "designator in initializer for scalar type %0">; +def warn_subobject_initializer_overrides : Warning< + "subobject initialization overrides initialization of other fields " + "within its enclosing subobject">, InGroup<InitializerOverrides>; +def warn_initializer_overrides : Warning< + "initializer overrides prior initialization of this subobject">, + InGroup<InitializerOverrides>; +def note_previous_initializer : Note< + "previous initialization %select{|with side effects }0is here" + "%select{| (side effects may not occur at run time)}0">; +def err_designator_into_flexible_array_member : Error< + "designator into flexible array member subobject">; +def note_flexible_array_member : Note< + "initialized flexible array member %0 is here">; +def ext_flexible_array_init : Extension< + "flexible array initialization is a GNU extension">, InGroup<GNUFlexibleArrayInitializer>; + +// Declarations. +def ext_duplicate_declspec : ExtWarn<"duplicate '%0' declaration specifier">, + InGroup<DuplicateDeclSpecifier>; +def warn_duplicate_declspec : Warning<"duplicate '%0' declaration specifier">, + InGroup<DuplicateDeclSpecifier>; +def ext_plain_complex : ExtWarn< + "plain '_Complex' requires a type specifier; assuming '_Complex double'">; +def ext_integer_complex : Extension< + "complex integer types are a GNU extension">, InGroup<GNUComplexInteger>; + +def err_invalid_sign_spec : Error<"'%0' cannot be signed or unsigned">; +def err_invalid_width_spec : Error< + "'%select{|short|long|long long}0 %1' is invalid">; +def err_invalid_complex_spec : Error<"'_Complex %0' is invalid">; +def err_friend_decl_spec : Error<"'%0' is invalid in friend declarations">; + +def ext_auto_type_specifier : ExtWarn< + "'auto' type specifier is a C++11 extension">, InGroup<CXX11>; +def warn_auto_storage_class : Warning< + "'auto' storage class specifier is redundant and incompatible with C++11">, + InGroup<CXX11Compat>, DefaultIgnore; + +def warn_deprecated_register : Warning< + "'register' storage class specifier is deprecated " + "and incompatible with C++1z">, InGroup<DeprecatedRegister>; +def ext_register_storage_class : ExtWarn< + "ISO C++1z does not allow 'register' storage class specifier">, + DefaultError, InGroup<Register>; + +def err_invalid_decl_spec_combination : Error< + "cannot combine with previous '%0' declaration specifier">; +def err_invalid_vector_decl_spec_combination : Error< + "cannot combine with previous '%0' declaration specifier. " + "'__vector' must be first">; +def err_invalid_pixel_decl_spec_combination : Error< + "'__pixel' must be preceded by '__vector'. " + "'%0' declaration specifier not allowed here">; +def err_invalid_vector_bool_decl_spec : Error< + "cannot use '%0' with '__vector bool'">; +def err_invalid_vector_long_decl_spec : Error< + "cannot use 'long' with '__vector'">; +def err_invalid_vector_float_decl_spec : Error< + "cannot use 'float' with '__vector'">; +def err_invalid_vector_double_decl_spec : Error < + "use of 'double' with '__vector' requires VSX support to be enabled " + "(available on POWER7 or later)">; +def err_invalid_vector_long_long_decl_spec : Error < + "use of 'long long' with '__vector bool' requires VSX support (available on " + "POWER7 or later) or extended Altivec support (available on POWER8 or later) " + "to be enabled">; +def err_invalid_vector_long_double_decl_spec : Error< + "cannot use 'long double' with '__vector'">; +def warn_vector_long_decl_spec_combination : Warning< + "Use of 'long' with '__vector' is deprecated">, InGroup<Deprecated>; + +def err_use_of_tag_name_without_tag : Error< + "must use '%1' tag to refer to type %0%select{| in this scope}2">; + +def err_redeclaration_different_type : Error< + "redeclaration of %0 with a different type%diff{: $ vs $|}1,2">; +def err_bad_variable_name : Error< + "%0 cannot be the name of a variable or data member">; +def err_bad_parameter_name : Error< + "%0 cannot be the name of a parameter">; +def err_parameter_name_omitted : Error<"parameter name omitted">; +def warn_mips_interrupt_attribute : Warning< + "MIPS 'interrupt' attribute only applies to functions that have " + "%select{no parameters|a 'void' return type}0">, + InGroup<IgnoredAttributes>; +def warn_unused_parameter : Warning<"unused parameter %0">, + InGroup<UnusedParameter>, DefaultIgnore; +def warn_unused_variable : Warning<"unused variable %0">, + InGroup<UnusedVariable>, DefaultIgnore; +def warn_unused_local_typedef : Warning< + "unused %select{typedef|type alias}0 %1">, + InGroup<UnusedLocalTypedef>, DefaultIgnore; +def warn_unused_property_backing_ivar : + Warning<"ivar %0 which backs the property is not " + "referenced in this property's accessor">, + InGroup<UnusedPropertyIvar>, DefaultIgnore; +def warn_unused_const_variable : Warning<"unused variable %0">, + InGroup<UnusedConstVariable>, DefaultIgnore; +def warn_unused_exception_param : Warning<"unused exception parameter %0">, + InGroup<UnusedExceptionParameter>, DefaultIgnore; +def warn_decl_in_param_list : Warning< + "declaration of %0 will not be visible outside of this function">, + InGroup<Visibility>; +def warn_redefinition_in_param_list : Warning< + "redefinition of %0 will not be visible outside of this function">, + InGroup<Visibility>; +def warn_empty_parens_are_function_decl : Warning< + "empty parentheses interpreted as a function declaration">, + InGroup<VexingParse>; +def warn_parens_disambiguated_as_function_declaration : Warning< + "parentheses were disambiguated as a function declaration">, + InGroup<VexingParse>; +def note_additional_parens_for_variable_declaration : Note< + "add a pair of parentheses to declare a variable">; +def note_empty_parens_function_call : Note< + "change this ',' to a ';' to call %0">; +def note_empty_parens_default_ctor : Note< + "remove parentheses to declare a variable">; +def note_empty_parens_zero_initialize : Note< + "replace parentheses with an initializer to declare a variable">; +def warn_unused_function : Warning<"unused function %0">, + InGroup<UnusedFunction>, DefaultIgnore; +def warn_unused_member_function : Warning<"unused member function %0">, + InGroup<UnusedMemberFunction>, DefaultIgnore; +def warn_used_but_marked_unused: Warning<"%0 was marked unused but was used">, + InGroup<UsedButMarkedUnused>, DefaultIgnore; +def warn_unneeded_internal_decl : Warning< + "%select{function|variable}0 %1 is not needed and will not be emitted">, + InGroup<UnneededInternalDecl>, DefaultIgnore; +def warn_unneeded_static_internal_decl : Warning< + "'static' function %0 declared in header file " + "should be declared 'static inline'">, + InGroup<UnneededInternalDecl>, DefaultIgnore; +def warn_unneeded_member_function : Warning< + "member function %0 is not needed and will not be emitted">, + InGroup<UnneededMemberFunction>, DefaultIgnore; +def warn_unused_private_field: Warning<"private field %0 is not used">, + InGroup<UnusedPrivateField>, DefaultIgnore; + +def warn_parameter_size: Warning< + "%0 is a large (%1 bytes) pass-by-value argument; " + "pass it by reference instead ?">, InGroup<LargeByValueCopy>; +def warn_return_value_size: Warning< + "return value of %0 is a large (%1 bytes) pass-by-value object; " + "pass it by reference instead ?">, InGroup<LargeByValueCopy>; +def warn_return_value_udt: Warning< + "%0 has C-linkage specified, but returns user-defined type %1 which is " + "incompatible with C">, InGroup<ReturnTypeCLinkage>; +def warn_return_value_udt_incomplete: Warning< + "%0 has C-linkage specified, but returns incomplete type %1 which could be " + "incompatible with C">, InGroup<ReturnTypeCLinkage>; +def warn_implicit_function_decl : Warning< + "implicit declaration of function %0">, + InGroup<ImplicitFunctionDeclare>, DefaultIgnore; +def ext_implicit_function_decl : ExtWarn< + "implicit declaration of function %0 is invalid in C99">, + InGroup<ImplicitFunctionDeclare>; +def note_function_suggestion : Note<"did you mean %0?">; + +def err_ellipsis_first_param : Error< + "ISO C requires a named parameter before '...'">; +def err_declarator_need_ident : Error<"declarator requires an identifier">; +def err_language_linkage_spec_unknown : Error<"unknown linkage language">; +def err_language_linkage_spec_not_ascii : Error< + "string literal in language linkage specifier cannot have an " + "encoding-prefix">; +def warn_use_out_of_scope_declaration : Warning< + "use of out-of-scope declaration of %0">; +def err_inline_non_function : Error< + "'inline' can only appear on functions">; +def err_noreturn_non_function : Error< + "'_Noreturn' can only appear on functions">; +def warn_qual_return_type : Warning< + "'%0' type qualifier%s1 on return type %plural{1:has|:have}1 no effect">, + InGroup<IgnoredQualifiers>, DefaultIgnore; + +def warn_decl_shadow : + Warning<"declaration shadows a %select{" + "local variable|" + "variable in %2|" + "static data member of %2|" + "field of %2}1">, + InGroup<Shadow>, DefaultIgnore; + +// C++ using declarations +def err_using_requires_qualname : Error< + "using declaration requires a qualified name">; +def err_using_typename_non_type : Error< + "'typename' keyword used on a non-type">; +def err_using_dependent_value_is_type : Error< + "dependent using declaration resolved to type without 'typename'">; +def err_using_decl_nested_name_specifier_is_not_class : Error< + "using declaration in class refers into '%0', which is not a class">; +def err_using_decl_nested_name_specifier_is_current_class : Error< + "using declaration refers to its own class">; +def err_using_decl_nested_name_specifier_is_not_base_class : Error< + "using declaration refers into '%0', which is not a base class of %1">; +def err_using_decl_constructor_not_in_direct_base : Error< + "%0 is not a direct base of %1, cannot inherit constructors">; +def err_using_decl_constructor_conflict : Error< + "cannot inherit constructor, already inherited constructor with " + "the same signature">; +def note_using_decl_constructor_conflict_current_ctor : Note< + "conflicting constructor">; +def note_using_decl_constructor_conflict_previous_ctor : Note< + "previous constructor">; +def note_using_decl_constructor_conflict_previous_using : Note< + "previously inherited here">; +def warn_using_decl_constructor_ellipsis : Warning< + "inheriting constructor does not inherit ellipsis">, + InGroup<DiagGroup<"inherited-variadic-ctor">>; +def note_using_decl_constructor_ellipsis : Note< + "constructor declared with ellipsis here">; +def err_using_decl_can_not_refer_to_class_member : Error< + "using declaration cannot refer to class member">; +def note_using_decl_class_member_workaround : Note< + "use %select{an alias declaration|a typedef declaration|a reference}0 " + "instead">; +def err_using_decl_can_not_refer_to_namespace : Error< + "using declaration cannot refer to namespace">; +def err_using_decl_constructor : Error< + "using declaration cannot refer to a constructor">; +def warn_cxx98_compat_using_decl_constructor : Warning< + "inheriting constructors are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_using_decl_destructor : Error< + "using declaration cannot refer to a destructor">; +def err_using_decl_template_id : Error< + "using declaration cannot refer to a template specialization">; +def note_using_decl_target : Note<"target of using declaration">; +def note_using_decl_conflict : Note<"conflicting declaration">; +def err_using_decl_redeclaration : Error<"redeclaration of using decl">; +def err_using_decl_conflict : Error< + "target of using declaration conflicts with declaration already in scope">; +def err_using_decl_conflict_reverse : Error< + "declaration conflicts with target of using declaration already in scope">; +def note_using_decl : Note<"%select{|previous }0using declaration">; + +def warn_access_decl_deprecated : Warning< + "access declarations are deprecated; use using declarations instead">, + InGroup<Deprecated>; +def err_access_decl : Error< + "ISO C++11 does not allow access declarations; " + "use using declarations instead">; +def warn_exception_spec_deprecated : Warning< + "dynamic exception specifications are deprecated">, + InGroup<Deprecated>, DefaultIgnore; +def note_exception_spec_deprecated : Note<"use '%0' instead">; +def warn_deprecated_copy_operation : Warning< + "definition of implicit copy %select{constructor|assignment operator}1 " + "for %0 is deprecated because it has a user-declared " + "%select{copy %select{assignment operator|constructor}1|destructor}2">, + InGroup<Deprecated>, DefaultIgnore; + +def warn_global_constructor : Warning< + "declaration requires a global constructor">, + InGroup<GlobalConstructors>, DefaultIgnore; +def warn_global_destructor : Warning< + "declaration requires a global destructor">, + InGroup<GlobalConstructors>, DefaultIgnore; +def warn_exit_time_destructor : Warning< + "declaration requires an exit-time destructor">, + InGroup<ExitTimeDestructors>, DefaultIgnore; + +def err_invalid_thread : Error< + "'%0' is only allowed on variable declarations">; +def err_thread_non_global : Error< + "'%0' variables must have global storage">; +def err_thread_unsupported : Error< + "thread-local storage is not supported for the current target">; + +def warn_maybe_falloff_nonvoid_function : Warning< + "control may reach end of non-void function">, + InGroup<ReturnType>; +def warn_falloff_nonvoid_function : Warning< + "control reaches end of non-void function">, + InGroup<ReturnType>; +def err_maybe_falloff_nonvoid_block : Error< + "control may reach end of non-void block">; +def err_falloff_nonvoid_block : Error< + "control reaches end of non-void block">; +def warn_suggest_noreturn_function : Warning< + "%select{function|method}0 %1 could be declared with attribute 'noreturn'">, + InGroup<MissingNoreturn>, DefaultIgnore; +def warn_suggest_noreturn_block : Warning< + "block could be declared with attribute 'noreturn'">, + InGroup<MissingNoreturn>, DefaultIgnore; + +// Unreachable code. +def warn_unreachable : Warning< + "code will never be executed">, + InGroup<UnreachableCode>, DefaultIgnore; +def warn_unreachable_break : Warning< + "'break' will never be executed">, + InGroup<UnreachableCodeBreak>, DefaultIgnore; +def warn_unreachable_return : Warning< + "'return' will never be executed">, + InGroup<UnreachableCodeReturn>, DefaultIgnore; +def warn_unreachable_loop_increment : Warning< + "loop will run at most once (loop increment never executed)">, + InGroup<UnreachableCodeLoopIncrement>, DefaultIgnore; +def note_unreachable_silence : Note< + "silence by adding parentheses to mark code as explicitly dead">; + +/// Built-in functions. +def ext_implicit_lib_function_decl : ExtWarn< + "implicitly declaring library function '%0' with type %1">, + InGroup<ImplicitFunctionDeclare>; +def note_include_header_or_declare : Note< + "include the header <%0> or explicitly provide a declaration for '%1'">; +def note_previous_builtin_declaration : Note<"%0 is a builtin with type %1">; +def warn_implicit_decl_requires_sysheader : Warning< + "declaration of built-in function '%1' requires inclusion of the header <%0>">, + InGroup<BuiltinRequiresHeader>; +def warn_redecl_library_builtin : Warning< + "incompatible redeclaration of library function %0">, + InGroup<DiagGroup<"incompatible-library-redeclaration">>; +def err_builtin_definition : Error<"definition of builtin function %0">; +def err_arm_invalid_specialreg : Error<"invalid special register for builtin">; +def err_invalid_cpu_supports : Error<"invalid cpu feature string for builtin">; +def err_builtin_needs_feature : Error<"%0 needs target feature %1">; +def err_function_needs_feature + : Error<"always_inline function %1 requires target feature '%2', but would " + "be inlined into function %0 that is compiled without support for " + "'%2'">; +def warn_builtin_unknown : Warning<"use of unknown builtin %0">, + InGroup<ImplicitFunctionDeclare>, DefaultError; +def warn_dyn_class_memaccess : Warning< + "%select{destination for|source of|first operand of|second operand of}0 this " + "%1 call is a pointer to %select{|class containing a }2dynamic class %3; " + "vtable pointer will be %select{overwritten|copied|moved|compared}4">, + InGroup<DiagGroup<"dynamic-class-memaccess">>; +def note_bad_memaccess_silence : Note< + "explicitly cast the pointer to silence this warning">; +def warn_sizeof_pointer_expr_memaccess : Warning< + "'%0' call operates on objects of type %1 while the size is based on a " + "different type %2">, + InGroup<SizeofPointerMemaccess>; +def warn_sizeof_pointer_expr_memaccess_note : Note< + "did you mean to %select{dereference the argument to 'sizeof' (and multiply " + "it by the number of elements)|remove the addressof in the argument to " + "'sizeof' (and multiply it by the number of elements)|provide an explicit " + "length}0?">; +def warn_sizeof_pointer_type_memaccess : Warning< + "argument to 'sizeof' in %0 call is the same pointer type %1 as the " + "%select{destination|source}2; expected %3 or an explicit length">, + InGroup<SizeofPointerMemaccess>; +def warn_strlcpycat_wrong_size : Warning< + "size argument in %0 call appears to be size of the source; " + "expected the size of the destination">, + InGroup<DiagGroup<"strlcpy-strlcat-size">>; +def note_strlcpycat_wrong_size : Note< + "change size argument to be the size of the destination">; +def warn_memsize_comparison : Warning< + "size argument in %0 call is a comparison">, + InGroup<DiagGroup<"memsize-comparison">>; +def note_memsize_comparison_paren : Note< + "did you mean to compare the result of %0 instead?">; +def note_memsize_comparison_cast_silence : Note< + "explicitly cast the argument to size_t to silence this warning">; + +def warn_strncat_large_size : Warning< + "the value of the size argument in 'strncat' is too large, might lead to a " + "buffer overflow">, InGroup<StrncatSize>; +def warn_strncat_src_size : Warning<"size argument in 'strncat' call appears " + "to be size of the source">, InGroup<StrncatSize>; +def warn_strncat_wrong_size : Warning< + "the value of the size argument to 'strncat' is wrong">, InGroup<StrncatSize>; +def note_strncat_wrong_size : Note< + "change the argument to be the free space in the destination buffer minus " + "the terminating null byte">; + +def warn_assume_side_effects : Warning< + "the argument to %0 has side effects that will be discarded">, + InGroup<DiagGroup<"assume">>; + +def warn_memcpy_chk_overflow : Warning< + "%0 will always overflow destination buffer">, + InGroup<DiagGroup<"builtin-memcpy-chk-size">>; + +/// main() +// static main() is not an error in C, just in C++. +def warn_static_main : Warning<"'main' should not be declared static">, + InGroup<Main>; +def err_static_main : Error<"'main' is not allowed to be declared static">; +def err_inline_main : Error<"'main' is not allowed to be declared inline">; +def ext_variadic_main : ExtWarn< + "'main' is not allowed to be declared variadic">, InGroup<Main>; +def ext_noreturn_main : ExtWarn< + "'main' is not allowed to be declared _Noreturn">, InGroup<Main>; +def note_main_remove_noreturn : Note<"remove '_Noreturn'">; +def err_constexpr_main : Error< + "'main' is not allowed to be declared constexpr">; +def err_deleted_main : Error<"'main' is not allowed to be deleted">; +def err_mainlike_template_decl : Error<"%0 cannot be a template">; +def err_main_returns_nonint : Error<"'main' must return 'int'">; +def ext_main_returns_nonint : ExtWarn<"return type of 'main' is not 'int'">, + InGroup<MainReturnType>; +def note_main_change_return_type : Note<"change return type to 'int'">; +def err_main_surplus_args : Error<"too many parameters (%0) for 'main': " + "must be 0, 2, or 3">; +def warn_main_one_arg : Warning<"only one parameter on 'main' declaration">, + InGroup<Main>; +def err_main_arg_wrong : Error<"%select{first|second|third|fourth}0 " + "parameter of 'main' (%select{argument count|argument array|environment|" + "platform-specific data}0) must be of type %1">; +def err_main_global_variable : + Error<"main cannot be declared as global variable">; +def warn_main_redefined : Warning<"variable named 'main' with external linkage " + "has undefined behavior">, InGroup<Main>; +def ext_main_used : Extension< + "ISO C++ does not allow 'main' to be used by a program">, InGroup<Main>; + +/// parser diagnostics +def ext_no_declarators : ExtWarn<"declaration does not declare anything">, + InGroup<MissingDeclarations>; +def ext_typedef_without_a_name : ExtWarn<"typedef requires a name">, + InGroup<MissingDeclarations>; +def err_typedef_not_identifier : Error<"typedef name must be an identifier">; +def err_typedef_changes_linkage : Error<"unsupported: typedef changes linkage" + " of anonymous type, but linkage was already computed">; +def note_typedef_changes_linkage : Note<"use a tag name here to establish " + "linkage prior to definition">; +def err_statically_allocated_object : Error< + "interface type cannot be statically allocated">; +def err_object_cannot_be_passed_returned_by_value : Error< + "interface type %1 cannot be %select{returned|passed}0 by value" + "; did you forget * in %1?">; +def err_parameters_retval_cannot_have_fp16_type : Error< + "%select{parameters|function return value}0 cannot have __fp16 type; did you forget * ?">; +def err_opencl_half_load_store : Error< + "%select{loading directly from|assigning directly to}0 pointer to type %1 is not allowed">; +def err_opencl_cast_to_half : Error<"casting to type %0 is not allowed">; +def err_opencl_half_declaration : Error< + "declaring variable of type %0 is not allowed">; +def err_opencl_half_param : Error< + "declaring function parameter of type %0 is not allowed; did you forget * ?">; +def err_opencl_half_return : Error< + "declaring function return value of type %0 is not allowed; did you forget * ?">; +def warn_enum_value_overflow : Warning<"overflow in enumeration value">; +def warn_pragma_options_align_reset_failed : Warning< + "#pragma options align=reset failed: %0">, + InGroup<IgnoredPragmas>; +def err_pragma_options_align_mac68k_target_unsupported : Error< + "mac68k alignment pragma is not supported on this target">; +def warn_pragma_pack_invalid_alignment : Warning< + "expected #pragma pack parameter to be '1', '2', '4', '8', or '16'">, + InGroup<IgnoredPragmas>; +// Follow the Microsoft implementation. +def warn_pragma_pack_show : Warning<"value of #pragma pack(show) == %0">; +def warn_pragma_pack_pop_identifer_and_alignment : Warning< + "specifying both a name and alignment to 'pop' is undefined">; +def warn_pragma_pop_failed : Warning<"#pragma %0(pop, ...) failed: %1">, + InGroup<IgnoredPragmas>; +def warn_cxx_ms_struct : + Warning<"ms_struct may not produce Microsoft-compatible layouts for classes " + "with base classes or virtual functions">, + DefaultError, InGroup<IncompatibleMSStruct>; +def err_section_conflict : Error<"%0 causes a section type conflict with %1">; +def err_no_base_classes : Error<"invalid use of '__super', %0 has no base classes">; +def err_invalid_super_scope : Error<"invalid use of '__super', " + "this keyword can only be used inside class or member function scope">; +def err_super_in_lambda_unsupported : Error< + "use of '__super' inside a lambda is unsupported">; + +def warn_pragma_unused_undeclared_var : Warning< + "undeclared variable %0 used as an argument for '#pragma unused'">, + InGroup<IgnoredPragmas>; +def warn_pragma_unused_expected_var_arg : Warning< + "only variables can be arguments to '#pragma unused'">, + InGroup<IgnoredPragmas>; +def err_pragma_push_visibility_mismatch : Error< + "#pragma visibility push with no matching #pragma visibility pop">; +def note_surrounding_namespace_ends_here : Note< + "surrounding namespace with visibility attribute ends here">; +def err_pragma_pop_visibility_mismatch : Error< + "#pragma visibility pop with no matching #pragma visibility push">; +def note_surrounding_namespace_starts_here : Note< + "surrounding namespace with visibility attribute starts here">; +def err_pragma_loop_invalid_argument_type : Error< + "invalid argument of type %0; expected an integer type">; +def err_pragma_loop_invalid_argument_value : Error< + "%select{invalid value '%0'; must be positive|value '%0' is too large}1">; +def err_pragma_loop_compatibility : Error< + "%select{incompatible|duplicate}0 directives '%1' and '%2'">; +def err_pragma_loop_precedes_nonloop : Error< + "expected a for, while, or do-while loop to follow '%0'">; + +/// Objective-C parser diagnostics +def err_duplicate_class_def : Error< + "duplicate interface definition for class %0">; +def err_undef_superclass : Error< + "cannot find interface declaration for %0, superclass of %1">; +def err_forward_superclass : Error< + "attempting to use the forward class %0 as superclass of %1">; +def err_no_nsconstant_string_class : Error< + "cannot find interface declaration for %0">; +def err_recursive_superclass : Error< + "trying to recursively use %0 as superclass of %1">; +def err_conflicting_aliasing_type : Error<"conflicting types for alias %0">; +def warn_undef_interface : Warning<"cannot find interface declaration for %0">; +def warn_duplicate_protocol_def : Warning<"duplicate protocol definition of %0 is ignored">; +def err_protocol_has_circular_dependency : Error< + "protocol has circular dependency">; +def err_undeclared_protocol : Error<"cannot find protocol declaration for %0">; +def warn_undef_protocolref : Warning<"cannot find protocol definition for %0">; +def warn_atprotocol_protocol : Warning< + "@protocol is using a forward protocol declaration of %0">, InGroup<AtProtocol>; +def warn_readonly_property : Warning< + "attribute 'readonly' of property %0 restricts attribute " + "'readwrite' of property inherited from %1">, + InGroup<PropertyAttr>; + +def warn_property_attribute : Warning< + "'%1' attribute on property %0 does not match the property inherited from %2">, + InGroup<PropertyAttr>; +def warn_property_types_are_incompatible : Warning< + "property type %0 is incompatible with type %1 inherited from %2">, + InGroup<DiagGroup<"incompatible-property-type">>; +def warn_protocol_property_mismatch : Warning< + "property of type %0 was selected for synthesis">, + InGroup<DiagGroup<"protocol-property-synthesis-ambiguity">>; +def err_undef_interface : Error<"cannot find interface declaration for %0">; +def err_category_forward_interface : Error< + "cannot define %select{category|class extension}0 for undefined class %1">; +def err_class_extension_after_impl : Error< + "cannot declare class extension for %0 after class implementation">; +def note_implementation_declared : Note< + "class implementation is declared here">; +def note_while_in_implementation : Note< + "detected while default synthesizing properties in class implementation">; +def note_class_declared : Note< + "class is declared here">; +def note_receiver_class_declared : Note< + "receiver is instance of class declared here">; +def note_receiver_expr_here : Note< + "receiver expression is here">; +def note_receiver_is_id : Note< + "receiver is treated with 'id' type for purpose of method lookup">; +def note_suppressed_class_declare : Note< + "class with specified objc_requires_property_definitions attribute is declared here">; +def err_objc_root_class_subclass : Error< + "objc_root_class attribute may only be specified on a root class declaration">; +def warn_objc_root_class_missing : Warning< + "class %0 defined without specifying a base class">, + InGroup<ObjCRootClass>; +def note_objc_needs_superclass : Note< + "add a super class to fix this problem">; +def warn_dup_category_def : Warning< + "duplicate definition of category %1 on interface %0">; +def err_conflicting_super_class : Error<"conflicting super class name %0">; +def err_dup_implementation_class : Error<"reimplementation of class %0">; +def err_dup_implementation_category : Error< + "reimplementation of category %1 for class %0">; +def err_conflicting_ivar_type : Error< + "instance variable %0 has conflicting type%diff{: $ vs $|}1,2">; +def err_duplicate_ivar_declaration : Error< + "instance variable is already declared">; +def warn_on_superclass_use : Warning< + "class implementation may not have super class">; +def err_conflicting_ivar_bitwidth : Error< + "instance variable %0 has conflicting bit-field width">; +def err_conflicting_ivar_name : Error< + "conflicting instance variable names: %0 vs %1">; +def err_inconsistent_ivar_count : Error< + "inconsistent number of instance variables specified">; +def warn_undef_method_impl : Warning<"method definition for %0 not found">, + InGroup<DiagGroup<"incomplete-implementation">>; + +def warn_conflicting_overriding_ret_types : Warning< + "conflicting return type in " + "declaration of %0%diff{: $ vs $|}1,2">, + InGroup<OverridingMethodMismatch>, DefaultIgnore; + +def warn_conflicting_ret_types : Warning< + "conflicting return type in " + "implementation of %0%diff{: $ vs $|}1,2">, + InGroup<MismatchedReturnTypes>; + +def warn_conflicting_overriding_ret_type_modifiers : Warning< + "conflicting distributed object modifiers on return type " + "in declaration of %0">, + InGroup<OverridingMethodMismatch>, DefaultIgnore; + +def warn_conflicting_ret_type_modifiers : Warning< + "conflicting distributed object modifiers on return type " + "in implementation of %0">, + InGroup<DistributedObjectModifiers>; + +def warn_non_covariant_overriding_ret_types : Warning< + "conflicting return type in " + "declaration of %0: %1 vs %2">, + InGroup<OverridingMethodMismatch>, DefaultIgnore; + +def warn_non_covariant_ret_types : Warning< + "conflicting return type in " + "implementation of %0: %1 vs %2">, + InGroup<MethodSignatures>, DefaultIgnore; + +def warn_conflicting_overriding_param_types : Warning< + "conflicting parameter types in " + "declaration of %0%diff{: $ vs $|}1,2">, + InGroup<OverridingMethodMismatch>, DefaultIgnore; + +def warn_conflicting_param_types : Warning< + "conflicting parameter types in " + "implementation of %0%diff{: $ vs $|}1,2">, + InGroup<MismatchedParameterTypes>; + +def warn_conflicting_param_modifiers : Warning< + "conflicting distributed object modifiers on parameter type " + "in implementation of %0">, + InGroup<DistributedObjectModifiers>; + +def warn_conflicting_overriding_param_modifiers : Warning< + "conflicting distributed object modifiers on parameter type " + "in declaration of %0">, + InGroup<OverridingMethodMismatch>, DefaultIgnore; + +def warn_non_contravariant_overriding_param_types : Warning< + "conflicting parameter types in " + "declaration of %0: %1 vs %2">, + InGroup<OverridingMethodMismatch>, DefaultIgnore; + +def warn_non_contravariant_param_types : Warning< + "conflicting parameter types in " + "implementation of %0: %1 vs %2">, + InGroup<MethodSignatures>, DefaultIgnore; + +def warn_conflicting_overriding_variadic :Warning< + "conflicting variadic declaration of method and its " + "implementation">, + InGroup<OverridingMethodMismatch>, DefaultIgnore; + +def warn_conflicting_variadic :Warning< + "conflicting variadic declaration of method and its " + "implementation">; + +def warn_category_method_impl_match:Warning< + "category is implementing a method which will also be implemented" + " by its primary class">, InGroup<ObjCProtocolMethodImpl>; + +def warn_implements_nscopying : Warning< +"default assign attribute on property %0 which implements " +"NSCopying protocol is not appropriate with -fobjc-gc[-only]">; + +def warn_multiple_method_decl : Warning<"multiple methods named %0 found">, + InGroup<ObjCMultipleMethodNames>; +def warn_strict_multiple_method_decl : Warning< + "multiple methods named %0 found">, InGroup<StrictSelector>, DefaultIgnore; +def warn_accessor_property_type_mismatch : Warning< + "type of property %0 does not match type of accessor %1">; +def not_conv_function_declared_at : Note<"type conversion function declared here">; +def note_method_declared_at : Note<"method %0 declared here">; +def note_property_attribute : Note<"property %0 is declared " + "%select{deprecated|unavailable|partial}1 here">; +def err_setter_type_void : Error<"type of setter must be void">; +def err_duplicate_method_decl : Error<"duplicate declaration of method %0">; +def warn_duplicate_method_decl : + Warning<"multiple declarations of method %0 found and ignored">, + InGroup<MethodDuplicate>, DefaultIgnore; +def warn_objc_cdirective_format_string : + Warning<"using %0 directive in %select{NSString|CFString}1 " + "which is being passed as a formatting argument to the formatting " + "%select{method|CFfunction}2">, + InGroup<ObjCCStringFormat>, DefaultIgnore; +def err_objc_var_decl_inclass : + Error<"cannot declare variable inside @interface or @protocol">; +def error_missing_method_context : Error< + "missing context for method declaration">; +def err_objc_property_attr_mutually_exclusive : Error< + "property attributes '%0' and '%1' are mutually exclusive">; +def err_objc_property_requires_object : Error< + "property with '%0' attribute must be of object type">; +def warn_objc_property_no_assignment_attribute : Warning< + "no 'assign', 'retain', or 'copy' attribute is specified - " + "'assign' is assumed">, + InGroup<ObjCPropertyNoAttribute>; +def warn_objc_isa_use : Warning< + "direct access to Objective-C's isa is deprecated in favor of " + "object_getClass()">, InGroup<DeprecatedObjCIsaUsage>; +def warn_objc_isa_assign : Warning< + "assignment to Objective-C's isa is deprecated in favor of " + "object_setClass()">, InGroup<DeprecatedObjCIsaUsage>; +def warn_objc_pointer_masking : Warning< + "bitmasking for introspection of Objective-C object pointers is strongly " + "discouraged">, + InGroup<ObjCPointerIntrospect>; +def warn_objc_pointer_masking_performSelector : Warning<warn_objc_pointer_masking.Text>, + InGroup<ObjCPointerIntrospectPerformSelector>; +def warn_objc_property_default_assign_on_object : Warning< + "default property attribute 'assign' not appropriate for non-GC object">, + InGroup<ObjCPropertyNoAttribute>; +def warn_property_attr_mismatch : Warning< + "property attribute in class extension does not match the primary class">, + InGroup<PropertyAttr>; +def warn_property_implicitly_mismatched : Warning < + "primary property declaration is implicitly strong while redeclaration " + "in class extension is weak">, + InGroup<DiagGroup<"objc-property-implicit-mismatch">>; +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 warn_objc_property_retain_of_block : Warning< + "retain'ed block property does not copy the block " + "- use copy attribute instead">, InGroup<ObjCRetainBlockProperty>; +def warn_objc_readonly_property_has_setter : Warning< + "setter cannot be specified for a readonly property">, + InGroup<ObjCReadonlyPropertyHasSetter>; +def warn_atomic_property_rule : Warning< + "writable atomic property %0 cannot pair a synthesized %select{getter|setter}1 " + "with a user defined %select{getter|setter}2">, + InGroup<DiagGroup<"atomic-property-with-user-defined-accessor">>; +def note_atomic_property_fixup_suggest : Note<"setter and getter must both be " + "synthesized, or both be user defined,or the property must be nonatomic">; +def err_atomic_property_nontrivial_assign_op : Error< + "atomic property of reference type %0 cannot have non-trivial assignment" + " operator">; +def warn_cocoa_naming_owned_rule : Warning< + "property follows Cocoa naming" + " convention for returning 'owned' objects">, + InGroup<DiagGroup<"objc-property-matches-cocoa-ownership-rule">>; +def err_cocoa_naming_owned_rule : Error< + "property follows Cocoa naming" + " convention for returning 'owned' objects">; +def note_cocoa_naming_declare_family : Note< + "explicitly declare getter %objcinstance0 with '%1' to return an 'unowned' " + "object">; +def warn_auto_synthesizing_protocol_property :Warning< + "auto property synthesis will not synthesize property %0" + " declared in protocol %1">, + InGroup<DiagGroup<"objc-protocol-property-synthesis">>; +def warn_no_autosynthesis_shared_ivar_property : Warning < + "auto property synthesis will not synthesize property " + "%0 because it cannot share an ivar with another synthesized property">, + InGroup<ObjCNoPropertyAutoSynthesis>; +def warn_no_autosynthesis_property : Warning< + "auto property synthesis will not synthesize property " + "%0 because it is 'readwrite' but it will be synthesized 'readonly' " + "via another property">, + InGroup<ObjCNoPropertyAutoSynthesis>; +def warn_autosynthesis_property_in_superclass : Warning< + "auto property synthesis will not synthesize property " + "%0; it will be implemented by its superclass, use @dynamic to " + "acknowledge intention">, + InGroup<ObjCNoPropertyAutoSynthesis>; +def warn_autosynthesis_property_ivar_match :Warning< + "autosynthesized property %0 will use %select{|synthesized}1 instance variable " + "%2, not existing instance variable %3">, + InGroup<DiagGroup<"objc-autosynthesis-property-ivar-name-match">>; +def warn_missing_explicit_synthesis : Warning < + "auto property synthesis is synthesizing property not explicitly synthesized">, + InGroup<DiagGroup<"objc-missing-property-synthesis">>, DefaultIgnore; +def warn_property_getter_owning_mismatch : Warning< + "property declared as returning non-retained objects" + "; getter returning retained objects">; +def warn_property_redecl_getter_mismatch : Warning< + "getter name mismatch between property redeclaration (%1) and its original " + "declaration (%0)">, InGroup<PropertyAttr>; +def error_property_setter_ambiguous_use : Error< + "synthesized properties %0 and %1 both claim setter %2 -" + " use of this setter will cause unexpected behavior">; +def warn_default_atomic_custom_getter_setter : Warning< + "atomic by default property %0 has a user defined %select{getter|setter}1 " + "(property should be marked 'atomic' if this is intended)">, + InGroup<CustomAtomic>, DefaultIgnore; +def err_use_continuation_class : Error< + "illegal redeclaration of property in class extension %0" + " (attribute must be 'readwrite', while its primary must be 'readonly')">; +def err_type_mismatch_continuation_class : Error< + "type of property %0 in class extension does not match " + "property type in primary class">; +def err_use_continuation_class_redeclaration_readwrite : Error< + "illegal redeclaration of 'readwrite' property in class extension %0" + " (perhaps you intended this to be a 'readwrite' redeclaration of a " + "'readonly' public property?)">; +def err_continuation_class : Error<"class extension 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 or one of " + "its extensions">; +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 note_protocol_property_declare : Note< + "it could also be property of type %0 declared here">; +def note_property_synthesize : Note< + "property synthesized here">; +def error_synthesize_category_decl : Error< + "@synthesize not allowed in a category's implementation">; +def error_reference_property : Error< + "property of reference type is not supported">; +def error_missing_property_interface : Error< + "property implementation in a category with no category declaration">; +def error_bad_category_property_decl : Error< + "property implementation must have its declaration in the category %0">; +def error_bad_property_context : Error< + "property implementation must be in a class or category implementation">; +def error_missing_property_ivar_decl : Error< + "synthesized property %0 must either be named the same as a compatible" + " instance variable or must explicitly name an instance variable">; +def err_arc_perform_selector_retains : Error< + "performSelector names a selector which retains the object">; +def warn_arc_perform_selector_leaks : Warning< + "performSelector may cause a leak because its selector is unknown">, + InGroup<DiagGroup<"arc-performSelector-leaks">>; +def warn_dealloc_in_category : Warning< +"-dealloc is being overridden in a category">, +InGroup<DeallocInCategory>; +def err_gc_weak_property_strong_type : Error< + "weak attribute declared on a __strong type property in GC mode">; +def warn_arc_repeated_use_of_weak : Warning < + "weak %select{variable|property|implicit property|instance variable}0 %1 is " + "accessed multiple times in this %select{function|method|block|lambda}2 " + "but may be unpredictably set to nil; assign to a strong variable to keep " + "the object alive">, + InGroup<ARCRepeatedUseOfWeak>, DefaultIgnore; +def warn_implicitly_retains_self : Warning < + "block implicitly retains 'self'; explicitly mention 'self' to indicate " + "this is intended behavior">, + InGroup<DiagGroup<"implicit-retain-self">>, DefaultIgnore; +def warn_arc_possible_repeated_use_of_weak : Warning < + "weak %select{variable|property|implicit property|instance variable}0 %1 may " + "be accessed multiple times in this %select{function|method|block|lambda}2 " + "and may be unpredictably set to nil; assign to a strong variable to keep " + "the object alive">, + InGroup<ARCRepeatedUseOfWeakMaybe>, DefaultIgnore; +def note_arc_weak_also_accessed_here : Note< + "also accessed here">; +def err_incomplete_synthesized_property : Error< + "cannot synthesize property %0 with incomplete type %1">; + +def error_property_ivar_type : Error< + "type of property %0 (%1) does not match type of instance variable %2 (%3)">; +def error_property_accessor_type : Error< + "type of property %0 (%1) does not match type of accessor %2 (%3)">; +def error_ivar_in_superclass_use : Error< + "property %0 attempting to use instance variable %1 declared in super class %2">; +def error_weak_property : Error< + "existing instance variable %1 for __weak property %0 must be __weak">; +def error_strong_property : Error< + "existing instance variable %1 for strong property %0 may not be __weak">; +def error_dynamic_property_ivar_decl : Error< + "dynamic property cannot have instance variable specification">; +def error_duplicate_ivar_use : Error< + "synthesized properties %0 and %1 both claim instance variable %2">; +def error_property_implemented : Error<"property %0 is already implemented">; +def warn_objc_missing_super_call : Warning< + "method possibly missing a [super %0] call">, + InGroup<ObjCMissingSuperCalls>; +def error_dealloc_bad_result_type : Error< + "dealloc return type must be correctly specified as 'void' under ARC, " + "instead of %0">; +def warn_undeclared_selector : Warning< + "undeclared selector %0">, InGroup<UndeclaredSelector>, DefaultIgnore; +def warn_undeclared_selector_with_typo : Warning< + "undeclared selector %0; did you mean %1?">, + InGroup<UndeclaredSelector>, DefaultIgnore; +def warn_implicit_atomic_property : Warning< + "property is assumed atomic by default">, InGroup<ImplicitAtomic>, DefaultIgnore; +def note_auto_readonly_iboutlet_fixup_suggest : Note< + "property should be changed to be readwrite">; +def warn_auto_readonly_iboutlet_property : Warning< + "readonly IBOutlet property %0 when auto-synthesized may " + "not work correctly with 'nib' loader">, + InGroup<DiagGroup<"readonly-iboutlet-property">>; +def warn_auto_implicit_atomic_property : Warning< + "property is assumed atomic when auto-synthesizing the property">, + InGroup<ImplicitAtomic>, DefaultIgnore; +def warn_unimplemented_selector: Warning< + "no method with selector %0 is implemented in this translation unit">, + InGroup<Selector>, DefaultIgnore; +def warn_unimplemented_protocol_method : Warning< + "method %0 in protocol %1 not implemented">, InGroup<Protocol>; +def warning_multiple_selectors: Warning< + "several methods with selector %0 of mismatched types are found " + "for the @selector expression">, + InGroup<SelectorTypeMismatch>, DefaultIgnore; + +def err_objc_kindof_nonobject : Error< + "'__kindof' specifier cannot be applied to non-object type %0">; +def err_objc_kindof_wrong_position : Error< + "'__kindof' type specifier must precede the declarator">; + +// C++ declarations +def err_static_assert_expression_is_not_constant : Error< + "static_assert expression is not an integral constant expression">; +def err_static_assert_failed : Error<"static_assert failed%select{ %1|}0">; +def ext_static_assert_no_message : ExtWarn< + "static_assert with no message is a C++1z extension">, InGroup<CXX1z>; +def warn_cxx14_compat_static_assert_no_message : Warning< + "static_assert with no message is incompatible with C++ standards before C++1z">, + DefaultIgnore, InGroup<CXXPre1zCompat>; + +def warn_inline_namespace_reopened_noninline : Warning< + "inline namespace cannot be reopened as a non-inline namespace">; +def err_inline_namespace_mismatch : Error< + "%select{|non-}0inline namespace " + "cannot be reopened as %select{non-|}0inline">; + +def err_unexpected_friend : Error< + "friends can only be classes or functions">; +def ext_enum_friend : ExtWarn< + "befriending enumeration type %0 is a C++11 extension">, InGroup<CXX11>; +def warn_cxx98_compat_enum_friend : Warning< + "befriending enumeration type %0 is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def ext_nonclass_type_friend : ExtWarn< + "non-class friend type %0 is a C++11 extension">, InGroup<CXX11>; +def warn_cxx98_compat_nonclass_type_friend : Warning< + "non-class friend type %0 is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_friend_is_member : Error< + "friends cannot be members of the declaring class">; +def warn_cxx98_compat_friend_is_member : Warning< + "friend declaration naming a member of the declaring class is incompatible " + "with C++98">, InGroup<CXX98Compat>, DefaultIgnore; +def ext_unelaborated_friend_type : ExtWarn< + "unelaborated friend declaration is a C++11 extension; specify " + "'%select{struct|interface|union|class|enum}0' to befriend %1">, + InGroup<CXX11>; +def warn_cxx98_compat_unelaborated_friend_type : Warning< + "befriending %1 without '%select{struct|interface|union|class|enum}0' " + "keyword is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; +def err_qualified_friend_not_found : Error< + "no function named %0 with type %1 was found in the specified scope">; +def err_introducing_special_friend : Error< + "must use a qualified name when declaring a %select{constructor|" + "destructor|conversion operator}0 as a friend">; +def err_tagless_friend_type_template : Error< + "friend type templates must use an elaborated type">; +def err_no_matching_local_friend : Error< + "no matching function found in local scope">; +def err_no_matching_local_friend_suggest : Error< + "no matching function %0 found in local scope; did you mean %3?">; +def err_partial_specialization_friend : Error< + "partial specialization cannot be declared as a friend">; +def err_qualified_friend_def : Error< + "friend function definition cannot be qualified with '%0'">; +def err_friend_def_in_local_class : Error< + "friend function cannot be defined in a local class">; +def err_friend_not_first_in_declaration : Error< + "'friend' must appear first in a non-function declaration">; +def err_using_decl_friend : Error< + "cannot befriend target of using declaration">; +def warn_template_qualified_friend_unsupported : Warning< + "dependent nested name specifier '%0' for friend class declaration is " + "not supported; turning off access control for %1">, + InGroup<UnsupportedFriend>; +def warn_template_qualified_friend_ignored : Warning< + "dependent nested name specifier '%0' for friend template declaration is " + "not supported; ignoring this friend declaration">, + InGroup<UnsupportedFriend>; +def ext_friend_tag_redecl_outside_namespace : ExtWarn< + "unqualified friend declaration referring to type outside of the nearest " + "enclosing namespace is a Microsoft extension; add a nested name specifier">, + InGroup<MicrosoftUnqualifiedFriend>; +def err_pure_friend : Error<"friend declaration cannot have a pure-specifier">; + +def err_invalid_member_in_interface : Error< + "%select{data member |non-public member function |static member function |" + "user-declared constructor|user-declared destructor|operator |" + "nested class }0%1 is not permitted within an interface type">; +def err_invalid_base_in_interface : Error< + "interface type cannot inherit from " + "%select{'struct|non-public 'interface|'class}0 %1'">; + +def err_abstract_type_in_decl : Error< + "%select{return|parameter|variable|field|instance variable|" + "synthesized instance variable}0 type %1 is an abstract class">; +def err_allocation_of_abstract_type : Error< + "allocating an object of abstract class type %0">; +def err_throw_abstract_type : Error< + "cannot throw an object of abstract type %0">; +def err_array_of_abstract_type : Error<"array of abstract class type %0">; +def err_capture_of_abstract_type : Error< + "by-copy capture of value of abstract type %0">; +def err_capture_of_incomplete_type : Error< + "by-copy capture of variable %0 with incomplete type %1">; +def err_capture_default_non_local : Error< + "non-local lambda expression cannot have a capture-default">; + +def err_multiple_final_overriders : Error< + "virtual function %q0 has more than one final overrider in %1">; +def note_final_overrider : Note<"final overrider of %q0 in %1">; + +def err_type_defined_in_type_specifier : Error< + "%0 cannot be defined in a type specifier">; +def err_type_defined_in_result_type : Error< + "%0 cannot be defined in the result type of a function">; +def err_type_defined_in_param_type : Error< + "%0 cannot be defined in a parameter type">; +def err_type_defined_in_alias_template : Error< + "%0 cannot be defined in a type alias template">; +def err_type_defined_in_condition : Error< + "%0 cannot be defined in a condition">; + +def note_pure_virtual_function : Note< + "unimplemented pure virtual method %0 in %1">; + +def note_pure_qualified_call_kext : Note< + "qualified call to %0::%1 is treated as a virtual call to %1 due to -fapple-kext">; + +def err_deleted_decl_not_first : Error< + "deleted definition must be first declaration">; + +def err_deleted_override : Error< + "deleted function %0 cannot override a non-deleted function">; + +def err_non_deleted_override : Error< + "non-deleted function %0 cannot override a deleted function">; + +def warn_weak_vtable : Warning< + "%0 has no out-of-line virtual method definitions; its vtable will be " + "emitted in every translation unit">, + InGroup<DiagGroup<"weak-vtables">>, DefaultIgnore; +def warn_weak_template_vtable : Warning< + "explicit template instantiation %0 will emit a vtable in every " + "translation unit">, + InGroup<DiagGroup<"weak-template-vtables">>, DefaultIgnore; + +def ext_using_undefined_std : ExtWarn< + "using directive refers to implicitly-defined namespace 'std'">; + +// C++ exception specifications +def err_exception_spec_in_typedef : Error< + "exception specifications are not allowed in %select{typedefs|type aliases}0">; +def err_distant_exception_spec : Error< + "exception specifications are not allowed beyond a single level " + "of indirection">; +def err_incomplete_in_exception_spec : Error< + "%select{|pointer to |reference to }0incomplete type %1 is not allowed " + "in exception specification">; +def err_rref_in_exception_spec : Error< + "rvalue reference type %0 is not allowed in exception specification">; +def err_mismatched_exception_spec : Error< + "exception specification in declaration does not match previous declaration">; +def ext_mismatched_exception_spec : ExtWarn<err_mismatched_exception_spec.Text>, + InGroup<MicrosoftExceptionSpec>; +def err_override_exception_spec : Error< + "exception specification of overriding function is more lax than " + "base version">; +def ext_override_exception_spec : ExtWarn<err_override_exception_spec.Text>, + InGroup<MicrosoftExceptionSpec>; +def err_incompatible_exception_specs : Error< + "target exception specification is not superset of source">; +def err_deep_exception_specs_differ : Error< + "exception specifications of %select{return|argument}0 types differ">; +def err_missing_exception_specification : Error< + "%0 is missing exception specification '%1'">; +def ext_missing_exception_specification : ExtWarn< + err_missing_exception_specification.Text>, + InGroup<DiagGroup<"missing-exception-spec">>; +def ext_ms_missing_exception_specification : ExtWarn< + err_missing_exception_specification.Text>, + InGroup<MicrosoftExceptionSpec>; +def err_noexcept_needs_constant_expression : Error< + "argument to noexcept specifier must be a constant expression">; +def err_exception_spec_not_parsed : Error< + "exception specification is not available until end of class definition">; + +// C++ access checking +def err_class_redeclared_with_different_access : Error< + "%0 redeclared with '%1' access">; +def err_access : Error< + "%1 is a %select{private|protected}0 member of %3">, AccessControl; +def ext_ms_using_declaration_inaccessible : ExtWarn< + "using declaration referring to inaccessible member '%0' (which refers " + "to accessible member '%1') is a Microsoft compatibility extension">, + AccessControl, InGroup<MicrosoftUsingDecl>; +def err_access_ctor : Error< + "calling a %select{private|protected}0 constructor of class %2">, + AccessControl; +def ext_rvalue_to_reference_access_ctor : Extension< + "C++98 requires an accessible copy constructor for class %2 when binding " + "a reference to a temporary; was %select{private|protected}0">, + AccessControl, InGroup<BindToTemporaryCopy>; +def err_access_base_ctor : Error< + // The ERRORs represent other special members that aren't constructors, in + // hopes that someone will bother noticing and reporting if they appear + "%select{base class|inherited virtual base class}0 %1 has %select{private|" + "protected}3 %select{default |copy |move |*ERROR* |*ERROR* " + "|*ERROR*|}2constructor">, AccessControl; +def err_access_field_ctor : Error< + // The ERRORs represent other special members that aren't constructors, in + // hopes that someone will bother noticing and reporting if they appear + "field of type %0 has %select{private|protected}2 " + "%select{default |copy |move |*ERROR* |*ERROR* |*ERROR* |}1constructor">, + AccessControl; +def err_access_friend_function : Error< + "friend function %1 is a %select{private|protected}0 member of %3">, + AccessControl; + +def err_access_dtor : Error< + "calling a %select{private|protected}1 destructor of class %0">, + AccessControl; +def err_access_dtor_base : + Error<"base class %0 has %select{private|protected}1 destructor">, + AccessControl; +def err_access_dtor_vbase : + Error<"inherited virtual base class %1 has " + "%select{private|protected}2 destructor">, + AccessControl; +def err_access_dtor_temp : + Error<"temporary of type %0 has %select{private|protected}1 destructor">, + AccessControl; +def err_access_dtor_exception : + Error<"exception object of type %0 has %select{private|protected}1 " + "destructor">, AccessControl; +def err_access_dtor_field : + Error<"field of type %1 has %select{private|protected}2 destructor">, + AccessControl; +def err_access_dtor_var : + Error<"variable of type %1 has %select{private|protected}2 destructor">, + AccessControl; +def err_access_dtor_ivar : + Error<"instance variable of type %0 has %select{private|protected}1 " + "destructor">, + AccessControl; +def note_previous_access_declaration : Note< + "previously declared '%1' here">; +def note_access_natural : Note< + "%select{|implicitly }1declared %select{private|protected}0 here">; +def note_access_constrained_by_path : Note< + "constrained by %select{|implicitly }1%select{private|protected}0" + " inheritance here">; +def note_access_protected_restricted_noobject : Note< + "must name member using the type of the current context %0">; +def note_access_protected_restricted_ctordtor : Note< + "protected %select{constructor|destructor}0 can only be used to " + "%select{construct|destroy}0 a base class subobject">; +def note_access_protected_restricted_object : Note< + "can only access this member on an object of type %0">; +def warn_cxx98_compat_sfinae_access_control : Warning< + "substitution failure due to access control is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore, NoSFINAE; + +// C++ name lookup +def err_incomplete_nested_name_spec : Error< + "incomplete type %0 named in nested name specifier">; +def err_dependent_nested_name_spec : Error< + "nested name specifier for a declaration cannot depend on a template " + "parameter">; +def err_nested_name_member_ref_lookup_ambiguous : Error< + "lookup of %0 in member access expression is ambiguous">; +def ext_nested_name_member_ref_lookup_ambiguous : ExtWarn< + "lookup of %0 in member access expression is ambiguous; using member of %1">, + InGroup<AmbigMemberTemplate>; +def note_ambig_member_ref_object_type : Note< + "lookup in the object type %0 refers here">; +def note_ambig_member_ref_scope : Note< + "lookup from the current scope refers here">; +def err_qualified_member_nonclass : Error< + "qualified member access refers to a member in %0">; +def err_incomplete_member_access : Error< + "member access into incomplete type %0">; +def err_incomplete_type : Error< + "incomplete type %0 where a complete type is required">; +def warn_cxx98_compat_enum_nested_name_spec : Warning< + "enumeration type in nested name specifier is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_nested_name_spec_is_not_class : Error< + "%0 cannot appear before '::' because it is not a class" + "%select{ or namespace|, namespace, or enumeration}1; did you mean ':'?">; +def ext_nested_name_spec_is_enum : ExtWarn< + "use of enumeration in a nested name specifier is a C++11 extension">, + InGroup<CXX11>; + +// C++ class members +def err_storageclass_invalid_for_member : Error< + "storage class specified for a member declaration">; +def err_mutable_function : Error<"'mutable' cannot be applied to functions">; +def err_mutable_reference : Error<"'mutable' cannot be applied to references">; +def ext_mutable_reference : ExtWarn< + "'mutable' on a reference type is a Microsoft extension">, + InGroup<MicrosoftMutableReference>; +def err_mutable_const : Error<"'mutable' and 'const' cannot be mixed">; +def err_mutable_nonmember : Error< + "'mutable' can only be applied to member variables">; +def err_virtual_in_union : Error< + "unions cannot have virtual functions">; +def err_virtual_non_function : Error< + "'virtual' can only appear on non-static member functions">; +def err_virtual_out_of_class : Error< + "'virtual' can only be specified inside the class definition">; +def err_virtual_member_function_template : Error< + "'virtual' cannot be specified on member function templates">; +def err_static_overrides_virtual : Error< + "'static' member function %0 overrides a virtual function in a base class">; +def err_explicit_non_function : Error< + "'explicit' can only appear on non-static member functions">; +def err_explicit_out_of_class : Error< + "'explicit' can only be specified inside the class definition">; +def err_explicit_non_ctor_or_conv_function : Error< + "'explicit' can only be applied to a constructor or conversion function">; +def err_static_not_bitfield : Error<"static member %0 cannot be a bit-field">; +def err_static_out_of_line : Error< + "'static' can only be specified inside the class definition">; +def err_storage_class_for_static_member : Error< + "static data member definition cannot specify a storage class">; +def err_typedef_not_bitfield : Error<"typedef member %0 cannot be a bit-field">; +def err_not_integral_type_bitfield : Error< + "bit-field %0 has non-integral type %1">; +def err_not_integral_type_anon_bitfield : Error< + "anonymous bit-field has non-integral type %0">; +def err_member_function_initialization : Error< + "initializer on function does not look like a pure-specifier">; +def err_non_virtual_pure : Error< + "%0 is not virtual and cannot be declared pure">; +def ext_pure_function_definition : ExtWarn< + "function definition with pure-specifier is a Microsoft extension">, + InGroup<MicrosoftPureDefinition>; +def err_implicit_object_parameter_init : Error< + "cannot initialize object parameter of type %0 with an expression " + "of type %1">; +def err_qualified_member_of_unrelated : Error< + "%q0 is not a member of class %1">; + +def warn_call_to_pure_virtual_member_function_from_ctor_dtor : Warning< + "call to pure virtual member function %0 has undefined behavior; " + "overrides of %0 in subclasses are not available in the " + "%select{constructor|destructor}1 of %2">; + +def note_member_declared_at : Note<"member is declared here">; +def note_ivar_decl : Note<"instance variable is declared here">; +def note_bitfield_decl : Note<"bit-field is declared here">; +def note_implicit_param_decl : Note<"%0 is an implicit parameter">; +def note_member_synthesized_at : Note< + "implicit %select{default constructor|copy constructor|move constructor|copy " + "assignment operator|move assignment operator|destructor}0 for %1 first " + "required here">; +def note_inhctor_synthesized_at : Note< + "inheriting constructor for %0 first required here">; +def err_missing_default_ctor : Error< + "%select{|implicit default |inheriting }0constructor for %1 must explicitly " + "initialize the %select{base class|member}2 %3 which does not have a default " + "constructor">; +def note_due_to_dllexported_class : Note< + "due to '%0' being dllexported%select{|; try compiling in C++11 mode}1">; + +def err_illegal_union_or_anon_struct_member : Error< + "%select{anonymous struct|union}0 member %1 has a non-trivial " + "%select{constructor|copy constructor|move constructor|copy assignment " + "operator|move assignment operator|destructor}2">; +def warn_cxx98_compat_nontrivial_union_or_anon_struct_member : Warning< + "%select{anonymous struct|union}0 member %1 with a non-trivial " + "%select{constructor|copy constructor|move constructor|copy assignment " + "operator|move assignment operator|destructor}2 is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; + +def note_nontrivial_virtual_dtor : Note< + "destructor for %0 is not trivial because it is virtual">; +def note_nontrivial_has_virtual : Note< + "because type %0 has a virtual %select{member function|base class}1">; +def note_nontrivial_no_def_ctor : Note< + "because %select{base class of |field of |}0type %1 has no " + "default constructor">; +def note_user_declared_ctor : Note< + "implicit default constructor suppressed by user-declared constructor">; +def note_nontrivial_no_copy : Note< + "because no %select{<<ERROR>>|constructor|constructor|assignment operator|" + "assignment operator|<<ERROR>>}2 can be used to " + "%select{<<ERROR>>|copy|move|copy|move|<<ERROR>>}2 " + "%select{base class|field|an object}0 of type %3">; +def note_nontrivial_user_provided : Note< + "because %select{base class of |field of |}0type %1 has a user-provided " + "%select{default constructor|copy constructor|move constructor|" + "copy assignment operator|move assignment operator|destructor}2">; +def note_nontrivial_in_class_init : Note< + "because field %0 has an initializer">; +def note_nontrivial_param_type : Note< + "because its parameter is %diff{of type $, not $|of the wrong type}2,3">; +def note_nontrivial_default_arg : Note<"because it has a default argument">; +def note_nontrivial_variadic : Note<"because it is a variadic function">; +def note_nontrivial_subobject : Note< + "because the function selected to %select{construct|copy|move|copy|move|" + "destroy}2 %select{base class|field}0 of type %1 is not trivial">; +def note_nontrivial_objc_ownership : Note< + "because type %0 has a member with %select{no|no|__strong|__weak|" + "__autoreleasing}1 ownership">; + +def err_static_data_member_not_allowed_in_anon_struct : Error< + "static data member %0 not allowed in anonymous struct">; +def ext_static_data_member_in_union : ExtWarn< + "static data member %0 in union is a C++11 extension">, InGroup<CXX11>; +def warn_cxx98_compat_static_data_member_in_union : Warning< + "static data member %0 in union is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def ext_union_member_of_reference_type : ExtWarn< + "union member %0 has reference type %1, which is a Microsoft extension">, + InGroup<MicrosoftUnionMemberReference>; +def err_union_member_of_reference_type : Error< + "union member %0 has reference type %1">; +def ext_anonymous_struct_union_qualified : Extension< + "anonymous %select{struct|union}0 cannot be '%1'">; +def err_different_return_type_for_overriding_virtual_function : Error< + "virtual function %0 has a different return type " + "%diff{($) than the function it overrides (which has return type $)|" + "than the function it overrides}1,2">; +def note_overridden_virtual_function : Note< + "overridden virtual function is here">; +def err_conflicting_overriding_cc_attributes : Error< + "virtual function %0 has different calling convention attributes " + "%diff{($) than the function it overrides (which has calling convention $)|" + "than the function it overrides}1,2">; + +def err_covariant_return_inaccessible_base : Error< + "invalid covariant return for virtual function: %1 is a " + "%select{private|protected}2 base class of %0">, AccessControl; +def err_covariant_return_ambiguous_derived_to_base_conv : Error< + "return type of virtual function %3 is not covariant with the return type of " + "the function it overrides (ambiguous conversion from derived class " + "%0 to base class %1:%2)">; +def err_covariant_return_not_derived : Error< + "return type of virtual function %0 is not covariant with the return type of " + "the function it overrides (%1 is not derived from %2)">; +def err_covariant_return_incomplete : Error< + "return type of virtual function %0 is not covariant with the return type of " + "the function it overrides (%1 is incomplete)">; +def err_covariant_return_type_different_qualifications : Error< + "return type of virtual function %0 is not covariant with the return type of " + "the function it overrides (%1 has different qualifiers than %2)">; +def err_covariant_return_type_class_type_more_qualified : Error< + "return type of virtual function %0 is not covariant with the return type of " + "the function it overrides (class type %1 is more qualified than class " + "type %2">; + +// C++ constructors +def err_constructor_cannot_be : Error<"constructor cannot be declared '%0'">; +def err_invalid_qualified_constructor : Error< + "'%0' qualifier is not allowed on a constructor">; +def err_ref_qualifier_constructor : Error< + "ref-qualifier '%select{&&|&}0' is not allowed on a constructor">; + +def err_constructor_return_type : Error< + "constructor cannot have a return type">; +def err_constructor_redeclared : Error<"constructor cannot be redeclared">; +def err_constructor_byvalue_arg : Error< + "copy constructor must pass its first argument by reference">; +def warn_no_constructor_for_refconst : Warning< + "%select{struct|interface|union|class|enum}0 %1 does not declare any " + "constructor to initialize its non-modifiable members">; +def note_refconst_member_not_initialized : Note< + "%select{const|reference}0 member %1 will never be initialized">; +def ext_ms_explicit_constructor_call : ExtWarn< + "explicit constructor calls are a Microsoft extension">, + InGroup<MicrosoftExplicitConstructorCall>; + +// C++ destructors +def err_destructor_not_member : Error< + "destructor must be a non-static member function">; +def err_destructor_cannot_be : Error<"destructor cannot be declared '%0'">; +def err_invalid_qualified_destructor : Error< + "'%0' qualifier is not allowed on a destructor">; +def err_ref_qualifier_destructor : Error< + "ref-qualifier '%select{&&|&}0' is not allowed on a destructor">; +def err_destructor_return_type : Error<"destructor cannot have a return type">; +def err_destructor_redeclared : Error<"destructor cannot be redeclared">; +def err_destructor_with_params : Error<"destructor cannot have any parameters">; +def err_destructor_variadic : Error<"destructor cannot be variadic">; +def err_destructor_typedef_name : Error< + "destructor cannot be declared using a %select{typedef|type alias}1 %0 of the class name">; +def err_destructor_name : Error< + "expected the class name after '~' to name the enclosing class">; +def err_destructor_class_name : Error< + "expected the class name after '~' to name a destructor">; +def err_ident_in_dtor_not_a_type : Error< + "identifier %0 in object destruction expression does not name a type">; +def err_destructor_expr_type_mismatch : Error< + "destructor type %0 in object destruction expression does not match the " + "type %1 of the object being destroyed">; +def note_destructor_type_here : Note< + "type %0 is declared here">; + +def err_destructor_template : Error< + "destructor cannot be declared as a template">; + +// C++ initialization +def err_init_conversion_failed : Error< + "cannot initialize %select{a variable|a parameter|return object|an " + "exception object|a member subobject|an array element|a new value|a value|a " + "base class|a constructor delegation|a vector element|a block element|a " + "complex element|a lambda capture|a compound literal initializer|a " + "related result|a parameter of CF audited function}0 " + "%diff{of type $ with an %select{rvalue|lvalue}2 of type $|" + "with an %select{rvalue|lvalue}2 of incompatible type}1,3" + "%select{|: different classes%diff{ ($ vs $)|}5,6" + "|: different number of parameters (%5 vs %6)" + "|: type mismatch at %ordinal5 parameter%diff{ ($ vs $)|}6,7" + "|: different return type%diff{ ($ vs $)|}5,6" + "|: different qualifiers (" + "%select{none|const|restrict|const and restrict|volatile|const and volatile|" + "volatile and restrict|const, volatile, and restrict}5 vs " + "%select{none|const|restrict|const and restrict|volatile|const and volatile|" + "volatile and restrict|const, volatile, and restrict}6)}4">; + +def err_lvalue_to_rvalue_ref : Error<"rvalue reference %diff{to type $ cannot " + "bind to lvalue of type $|cannot bind to incompatible lvalue}0,1">; +def err_lvalue_reference_bind_to_initlist : Error< + "%select{non-const|volatile}0 lvalue reference to type %1 cannot bind to an " + "initializer list temporary">; +def err_lvalue_reference_bind_to_temporary : Error< + "%select{non-const|volatile}0 lvalue reference %diff{to type $ cannot bind " + "to a temporary of type $|cannot bind to incompatible temporary}1,2">; +def err_lvalue_reference_bind_to_unrelated : Error< + "%select{non-const|volatile}0 lvalue reference " + "%diff{to type $ cannot bind to a value of unrelated type $|" + "cannot bind to a value of unrelated type}1,2">; +def err_reference_bind_drops_quals : Error< + "binding value %diff{of type $ to reference to type $|to reference}0,1 " + "drops %select{<<ERROR>>|'const'|'restrict'|'const' and 'restrict'|" + "'volatile'|'const' and 'volatile'|'restrict' and 'volatile'|" + "'const', 'restrict', and 'volatile'}2 qualifier%plural{1:|2:|4:|:s}2">; +def err_reference_bind_failed : Error< + "reference %diff{to type $ could not bind to an %select{rvalue|lvalue}1 of " + "type $|could not bind to %select{rvalue|lvalue}1 of incompatible type}0,2">; +def err_reference_bind_init_list : Error< + "reference to type %0 cannot bind to an initializer list">; +def warn_temporary_array_to_pointer_decay : Warning< + "pointer is initialized by a temporary array, which will be destroyed at the " + "end of the full-expression">, + InGroup<DiagGroup<"address-of-array-temporary">>; +def err_init_list_bad_dest_type : Error< + "%select{|non-aggregate }0type %1 cannot be initialized with an initializer " + "list">; +def err_member_function_call_bad_cvr : Error<"member function %0 not viable: " + "'this' argument has type %1, but function is not marked " + "%select{const|restrict|const or restrict|volatile|const or volatile|" + "volatile or restrict|const, volatile, or restrict}2">; + +def err_reference_bind_to_bitfield : Error< + "%select{non-const|volatile}0 reference cannot bind to " + "bit-field%select{| %1}2">; +def err_reference_bind_to_vector_element : Error< + "%select{non-const|volatile}0 reference cannot bind to vector element">; +def err_reference_var_requires_init : Error< + "declaration of reference variable %0 requires an initializer">; +def err_reference_without_init : Error< + "reference to type %0 requires an initializer">; +def note_value_initialization_here : Note< + "in value-initialization of type %0 here">; +def err_reference_has_multiple_inits : Error< + "reference cannot be initialized with multiple values">; +def err_init_non_aggr_init_list : Error< + "initialization of non-aggregate type %0 with an initializer list">; +def err_init_reference_member_uninitialized : Error< + "reference member of type %0 uninitialized">; +def note_uninit_reference_member : Note< + "uninitialized reference member is here">; +def warn_field_is_uninit : Warning<"field %0 is uninitialized when used here">, + InGroup<Uninitialized>; +def warn_base_class_is_uninit : Warning< + "base class %0 is uninitialized when used here to access %q1">, + InGroup<Uninitialized>; +def warn_reference_field_is_uninit : Warning< + "reference %0 is not yet bound to a value when used here">, + InGroup<Uninitialized>; +def note_uninit_in_this_constructor : Note< + "during field initialization in %select{this|the implicit default}0 " + "constructor">; +def warn_static_self_reference_in_init : Warning< + "static variable %0 is suspiciously used within its own initialization">, + InGroup<UninitializedStaticSelfInit>; +def warn_uninit_self_reference_in_init : Warning< + "variable %0 is uninitialized when used within its own initialization">, + InGroup<Uninitialized>; +def warn_uninit_self_reference_in_reference_init : Warning< + "reference %0 is not yet bound to a value when used within its own" + " initialization">, + InGroup<Uninitialized>; +def warn_uninit_var : Warning< + "variable %0 is uninitialized when %select{used here|captured by block}1">, + InGroup<Uninitialized>, DefaultIgnore; +def warn_sometimes_uninit_var : Warning< + "variable %0 is %select{used|captured}1 uninitialized whenever " + "%select{'%3' condition is %select{true|false}4|" + "'%3' loop %select{is entered|exits because its condition is false}4|" + "'%3' loop %select{condition is true|exits because its condition is false}4|" + "switch %3 is taken|" + "its declaration is reached|" + "%3 is called}2">, + InGroup<UninitializedSometimes>, DefaultIgnore; +def warn_maybe_uninit_var : Warning< + "variable %0 may be uninitialized when " + "%select{used here|captured by block}1">, + InGroup<UninitializedMaybe>, DefaultIgnore; +def note_uninit_var_def : Note<"variable %0 is declared here">; +def note_uninit_var_use : Note< + "%select{uninitialized use occurs|variable is captured by block}0 here">; +def warn_uninit_byref_blockvar_captured_by_block : Warning< + "block pointer variable %0 is uninitialized when captured by block">, + InGroup<Uninitialized>, DefaultIgnore; +def note_block_var_fixit_add_initialization : Note< + "did you mean to use __block %0?">; +def note_in_omitted_aggregate_initializer : Note< + "in implicit initialization of %select{array element %1|field %1}0 " + "with omitted initializer">; +def note_in_reference_temporary_list_initializer : Note< + "in initialization of temporary of type %0 created to " + "list-initialize this reference">; +def note_var_fixit_add_initialization : Note< + "initialize the variable %0 to silence this warning">; +def note_uninit_fixit_remove_cond : Note< + "remove the %select{'%1' if its condition|condition if it}0 " + "is always %select{false|true}2">; +def err_init_incomplete_type : Error<"initialization of incomplete type %0">; + +def warn_unsequenced_mod_mod : Warning< + "multiple unsequenced modifications to %0">, InGroup<Unsequenced>; +def warn_unsequenced_mod_use : Warning< + "unsequenced modification and access to %0">, InGroup<Unsequenced>; + +def err_temp_copy_no_viable : Error< + "no viable constructor %select{copying variable|copying parameter|" + "returning object|throwing object|copying member subobject|copying array " + "element|allocating object|copying temporary|initializing base subobject|" + "initializing vector element|capturing value}0 of type %1">; +def ext_rvalue_to_reference_temp_copy_no_viable : Extension< + "no viable constructor %select{copying variable|copying parameter|" + "returning object|throwing object|copying member subobject|copying array " + "element|allocating object|copying temporary|initializing base subobject|" + "initializing vector element|capturing value}0 of type %1; C++98 requires a copy " + "constructor when binding a reference to a temporary">, + InGroup<BindToTemporaryCopy>; +def err_temp_copy_ambiguous : Error< + "ambiguous constructor call when %select{copying variable|copying " + "parameter|returning object|throwing object|copying member subobject|copying " + "array element|allocating object|copying temporary|initializing base subobject|" + "initializing vector element|capturing value}0 of type %1">; +def err_temp_copy_deleted : Error< + "%select{copying variable|copying parameter|returning object|throwing " + "object|copying member subobject|copying array element|allocating object|" + "copying temporary|initializing base subobject|initializing vector element|" + "capturing value}0 of type %1 invokes deleted constructor">; +def err_temp_copy_incomplete : Error< + "copying a temporary object of incomplete type %0">; +def warn_cxx98_compat_temp_copy : Warning< + "%select{copying variable|copying parameter|returning object|throwing " + "object|copying member subobject|copying array element|allocating object|" + "copying temporary|initializing base subobject|initializing vector element}1 " + "of type %2 when binding a reference to a temporary would %select{invoke " + "an inaccessible constructor|find no viable constructor|find ambiguous " + "constructors|invoke a deleted constructor}0 in C++98">, + InGroup<CXX98CompatBindToTemporaryCopy>, DefaultIgnore; +def err_selected_explicit_constructor : Error< + "chosen constructor is explicit in copy-initialization">; +def note_constructor_declared_here : Note< + "constructor declared here">; + +// C++11 decltype +def err_decltype_in_declarator : Error< + "'decltype' cannot be used to name a declaration">; + +// C++11 auto +def warn_cxx98_compat_auto_type_specifier : Warning< + "'auto' type specifier is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_auto_variable_cannot_appear_in_own_initializer : Error< + "variable %0 declared with %select{'auto'|'decltype(auto)'|'__auto_type'}1 " + "type cannot appear in its own initializer">; +def err_illegal_decl_array_of_auto : Error< + "'%0' declared as array of %1">; +def err_new_array_of_auto : Error< + "cannot allocate array of 'auto'">; +def err_auto_not_allowed : Error< + "%select{'auto'|'decltype(auto)'|'__auto_type'}0 not allowed " + "%select{in function prototype" + "|in non-static struct member|in struct member" + "|in non-static union member|in union member" + "|in non-static class member|in interface member" + "|in exception declaration|in template parameter|in block literal" + "|in template argument|in typedef|in type alias|in function return type" + "|in conversion function type|here|in lambda parameter" + "|in type allocated by 'new'|in K&R-style function parameter}1">; +def err_auto_not_allowed_var_inst : Error< + "'auto' variable template instantiation is not allowed">; +def err_auto_var_requires_init : Error< + "declaration of variable %0 with type %1 requires an initializer">; +def err_auto_new_requires_ctor_arg : Error< + "new expression for type %0 requires a constructor argument">; +def err_auto_new_list_init : Error< + "new expression for type %0 cannot use list-initialization">; +def err_auto_var_init_no_expression : Error< + "initializer for variable %0 with type %1 is empty">; +def err_auto_var_init_multiple_expressions : Error< + "initializer for variable %0 with type %1 contains multiple expressions">; +def err_auto_var_init_paren_braces : Error< + "cannot deduce type for variable %1 with type %2 from " + "%select{parenthesized|nested}0 initializer list">; +def err_auto_new_ctor_multiple_expressions : Error< + "new expression for type %0 contains multiple constructor arguments">; +def err_auto_missing_trailing_return : Error< + "'auto' return without trailing return type; deduced return types are a " + "C++14 extension">; +def err_deduced_return_type : Error< + "deduced return types are a C++14 extension">; +def err_trailing_return_without_auto : Error< + "function with trailing return type must specify return type 'auto', not %0">; +def err_trailing_return_in_parens : Error< + "trailing return type may not be nested within parentheses">; +def err_auto_var_deduction_failure : Error< + "variable %0 with type %1 has incompatible initializer of type %2">; +def err_auto_var_deduction_failure_from_init_list : Error< + "cannot deduce actual type for variable %0 with type %1 from initializer list">; +def err_auto_new_deduction_failure : Error< + "new expression for type %0 has incompatible constructor argument of type %1">; +def err_auto_different_deductions : Error< + "'%select{auto|decltype(auto)|__auto_type}0' deduced as %1 in declaration " + "of %2 and deduced as %3 in declaration of %4">; +def err_implied_std_initializer_list_not_found : Error< + "cannot deduce type of initializer list because std::initializer_list was " + "not found; include <initializer_list>">; +def err_malformed_std_initializer_list : Error< + "std::initializer_list must be a class template with a single type parameter">; +def warn_dangling_std_initializer_list : Warning< + "array backing the initializer list will be destroyed at the end of " + "%select{the full-expression|the constructor}0">, + InGroup<DiagGroup<"dangling-initializer-list">>; +def err_auto_init_list_from_c : Error< + "cannot use __auto_type with initializer list in C">; +def err_auto_bitfield : Error< + "cannot pass bit-field as __auto_type initializer in C">; + +// C++1y decltype(auto) type +def err_decltype_auto_cannot_be_combined : Error< + "'decltype(auto)' cannot be combined with other type specifiers">; +def err_decltype_auto_function_declarator_not_declaration : Error< + "'decltype(auto)' can only be used as a return type " + "in a function declaration">; +def err_decltype_auto_compound_type : Error< + "cannot form %select{pointer to|reference to|array of}0 'decltype(auto)'">; +def err_decltype_auto_initializer_list : Error< + "cannot deduce 'decltype(auto)' from initializer list">; + +// C++1y deduced return types +def err_auto_fn_deduction_failure : Error< + "cannot deduce return type %0 from returned value of type %1">; +def err_auto_fn_different_deductions : Error< + "'%select{auto|decltype(auto)}0' in return type deduced as %1 here but " + "deduced as %2 in earlier return statement">; +def err_auto_fn_used_before_defined : Error< + "function %0 with deduced return type cannot be used before it is defined">; +def err_auto_fn_no_return_but_not_auto : Error< + "cannot deduce return type %0 for function with no return statements">; +def err_auto_fn_return_void_but_not_auto : Error< + "cannot deduce return type %0 from omitted return expression">; +def err_auto_fn_return_init_list : Error< + "cannot deduce return type from initializer list">; +def err_auto_fn_virtual : Error< + "function with deduced return type cannot be virtual">; + +// C++11 override control +def override_keyword_only_allowed_on_virtual_member_functions : Error< + "only virtual member functions can be marked '%0'">; +def override_keyword_hides_virtual_member_function : Error< + "non-virtual member function marked '%0' hides virtual member " + "%select{function|functions}1">; +def err_function_marked_override_not_overriding : Error< + "%0 marked 'override' but does not override any member functions">; +def warn_function_marked_not_override_overriding : Warning < + "%0 overrides a member function but is not marked 'override'">, + InGroup<CXX11WarnOverrideMethod>; +def err_class_marked_final_used_as_base : Error< + "base %0 is marked '%select{final|sealed}1'">; +def warn_abstract_final_class : Warning< + "abstract class is marked '%select{final|sealed}0'">, InGroup<AbstractFinalClass>; + +// C++11 attributes +def err_repeat_attribute : Error<"%0 attribute cannot be repeated">; + +// C++11 final +def err_final_function_overridden : Error< + "declaration of %0 overrides a '%select{final|sealed}1' function">; + +// C++11 scoped enumerations +def err_enum_invalid_underlying : Error< + "non-integral type %0 is an invalid underlying type">; +def err_enumerator_too_large : Error< + "enumerator value is not representable in the underlying type %0">; +def ext_enumerator_too_large : ExtWarn< + "enumerator value is not representable in the underlying type %0">, + InGroup<MicrosoftEnumValue>; +def err_enumerator_wrapped : Error< + "enumerator value %0 is not representable in the underlying type %1">; +def err_enum_redeclare_type_mismatch : Error< + "enumeration redeclared with different underlying type %0 (was %1)">; +def err_enum_redeclare_fixed_mismatch : Error< + "enumeration previously declared with %select{non|}0fixed underlying type">; +def err_enum_redeclare_scoped_mismatch : Error< + "enumeration previously declared as %select{un|}0scoped">; +def err_enum_class_reference : Error< + "reference to %select{|scoped }0enumeration must use 'enum' " + "not 'enum class'">; +def err_only_enums_have_underlying_types : Error< + "only enumeration types have underlying types">; +def err_underlying_type_of_incomplete_enum : Error< + "cannot determine underlying type of incomplete enumeration type %0">; + +// C++11 delegating constructors +def err_delegating_ctor : Error< + "delegating constructors are permitted only in C++11">; +def warn_cxx98_compat_delegating_ctor : Warning< + "delegating constructors are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_delegating_initializer_alone : Error< + "an initializer for a delegating constructor must appear alone">; +def warn_delegating_ctor_cycle : Warning< + "constructor for %0 creates a delegation cycle">, DefaultError, + InGroup<DelegatingCtorCycles>; +def note_it_delegates_to : Note<"it delegates to">; +def note_which_delegates_to : Note<"which delegates to">; + +// C++11 range-based for loop +def err_for_range_decl_must_be_var : Error< + "for range declaration must declare a variable">; +def err_for_range_storage_class : Error< + "loop variable %0 may not be declared %select{'extern'|'static'|" + "'__private_extern__'|'auto'|'register'|'constexpr'}1">; +def err_type_defined_in_for_range : Error< + "types may not be defined in a for range declaration">; +def err_for_range_deduction_failure : Error< + "cannot use type %0 as a range">; +def err_for_range_incomplete_type : Error< + "cannot use incomplete type %0 as a range">; +def err_for_range_iter_deduction_failure : Error< + "cannot use type %0 as an iterator">; +def err_for_range_member_begin_end_mismatch : Error< + "range type %0 has '%select{begin|end}1' member but no '%select{end|begin}1' member">; +def err_for_range_begin_end_types_differ : Error< + "'begin' and 'end' must return the same type (got %0 and %1)">; +def note_in_for_range: Note< + "when looking up '%select{begin|end}0' function for range expression " + "of type %1">; +def err_for_range_invalid: Error< + "invalid range expression of type %0; no viable '%select{begin|end}1' " + "function available">; +def err_range_on_array_parameter : Error< + "cannot build range expression with array function parameter %0 since " + "parameter with array type %1 is treated as pointer type %2">; +def err_for_range_dereference : Error< + "invalid range expression of type %0; did you mean to dereference it " + "with '*'?">; +def note_for_range_invalid_iterator : Note < + "in implicit call to 'operator%select{!=|*|++}0' for iterator of type %1">; +def note_for_range_begin_end : Note< + "selected '%select{begin|end}0' %select{function|template }1%2 with iterator type %3">; + +// C++11 constexpr +def warn_cxx98_compat_constexpr : Warning< + "'constexpr' specifier is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +// FIXME: Maybe this should also go in -Wc++14-compat? +def warn_cxx14_compat_constexpr_not_const : Warning< + "'constexpr' non-static member function will not be implicitly 'const' " + "in C++14; add 'const' to avoid a change in behavior">, + InGroup<DiagGroup<"constexpr-not-const">>; +def err_invalid_constexpr : Error< + "%select{function parameter|typedef|non-static data member}0 " + "cannot be constexpr">; +def err_invalid_constexpr_member : Error<"non-static data member cannot be " + "constexpr%select{; did you intend to make it %select{const|static}0?|}1">; +def err_constexpr_tag : Error< + "%select{class|struct|interface|union|enum}0 cannot be marked constexpr">; +def err_constexpr_dtor : Error<"destructor cannot be marked constexpr">; +def err_constexpr_no_declarators : Error< + "constexpr can only be used in variable and function declarations">; +def err_invalid_constexpr_var_decl : Error< + "constexpr variable declaration must be a definition">; +def err_constexpr_static_mem_var_requires_init : Error< + "declaration of constexpr static data member %0 requires an initializer">; +def err_constexpr_var_non_literal : Error< + "constexpr variable cannot have non-literal type %0">; +def err_constexpr_var_requires_const_init : Error< + "constexpr variable %0 must be initialized by a constant expression">; +def err_constexpr_redecl_mismatch : Error< + "%select{non-constexpr declaration of %0 follows constexpr declaration" + "|constexpr declaration of %0 follows non-constexpr declaration}1">; +def err_constexpr_virtual : Error<"virtual function cannot be constexpr">; +def err_constexpr_virtual_base : Error< + "constexpr %select{member function|constructor}0 not allowed in " + "%select{struct|interface|class}1 with virtual base " + "%plural{1:class|:classes}2">; +def note_non_literal_incomplete : Note< + "incomplete type %0 is not a literal type">; +def note_non_literal_virtual_base : Note<"%select{struct|interface|class}0 " + "with virtual base %plural{1:class|:classes}1 is not a literal type">; +def note_constexpr_virtual_base_here : Note<"virtual base class declared here">; +def err_constexpr_non_literal_return : Error< + "constexpr function's return type %0 is not a literal type">; +def err_constexpr_non_literal_param : Error< + "constexpr %select{function|constructor}1's %ordinal0 parameter type %2 is " + "not a literal type">; +def err_constexpr_body_invalid_stmt : Error< + "statement not allowed in constexpr %select{function|constructor}0">; +def ext_constexpr_body_invalid_stmt : ExtWarn< + "use of this statement in a constexpr %select{function|constructor}0 " + "is a C++14 extension">, InGroup<CXX14>; +def warn_cxx11_compat_constexpr_body_invalid_stmt : Warning< + "use of this statement in a constexpr %select{function|constructor}0 " + "is incompatible with C++ standards before C++14">, + InGroup<CXXPre14Compat>, DefaultIgnore; +def ext_constexpr_type_definition : ExtWarn< + "type definition in a constexpr %select{function|constructor}0 " + "is a C++14 extension">, InGroup<CXX14>; +def warn_cxx11_compat_constexpr_type_definition : Warning< + "type definition in a constexpr %select{function|constructor}0 " + "is incompatible with C++ standards before C++14">, + InGroup<CXXPre14Compat>, DefaultIgnore; +def err_constexpr_vla : Error< + "variably-modified type %0 cannot be used in a constexpr " + "%select{function|constructor}1">; +def ext_constexpr_local_var : ExtWarn< + "variable declaration in a constexpr %select{function|constructor}0 " + "is a C++14 extension">, InGroup<CXX14>; +def warn_cxx11_compat_constexpr_local_var : Warning< + "variable declaration in a constexpr %select{function|constructor}0 " + "is incompatible with C++ standards before C++14">, + InGroup<CXXPre14Compat>, DefaultIgnore; +def err_constexpr_local_var_static : Error< + "%select{static|thread_local}1 variable not permitted in a constexpr " + "%select{function|constructor}0">; +def err_constexpr_local_var_non_literal_type : Error< + "variable of non-literal type %1 cannot be defined in a constexpr " + "%select{function|constructor}0">; +def err_constexpr_local_var_no_init : Error< + "variables defined in a constexpr %select{function|constructor}0 must be " + "initialized">; +def ext_constexpr_function_never_constant_expr : ExtWarn< + "constexpr %select{function|constructor}0 never produces a " + "constant expression">, InGroup<DiagGroup<"invalid-constexpr">>, DefaultError; +def err_enable_if_never_constant_expr : Error< + "'enable_if' attribute expression never produces a constant expression">; +def err_constexpr_body_no_return : Error< + "no return statement in constexpr function">; +def err_constexpr_return_missing_expr : Error< + "non-void constexpr function %0 should return a value">; +def warn_cxx11_compat_constexpr_body_no_return : Warning< + "constexpr function with no return statements is incompatible with C++ " + "standards before C++14">, InGroup<CXXPre14Compat>, DefaultIgnore; +def ext_constexpr_body_multiple_return : ExtWarn< + "multiple return statements in constexpr function is a C++14 extension">, + InGroup<CXX14>; +def warn_cxx11_compat_constexpr_body_multiple_return : Warning< + "multiple return statements in constexpr function " + "is incompatible with C++ standards before C++14">, + InGroup<CXXPre14Compat>, DefaultIgnore; +def note_constexpr_body_previous_return : Note< + "previous return statement is here">; +def err_constexpr_function_try_block : Error< + "function try block not allowed in constexpr %select{function|constructor}0">; +def err_constexpr_union_ctor_no_init : Error< + "constexpr union constructor does not initialize any member">; +def err_constexpr_ctor_missing_init : Error< + "constexpr constructor must initialize all members">; +def note_constexpr_ctor_missing_init : Note< + "member not initialized by constructor">; +def note_non_literal_no_constexpr_ctors : Note< + "%0 is not literal because it is not an aggregate and has no constexpr " + "constructors other than copy or move constructors">; +def note_non_literal_base_class : Note< + "%0 is not literal because it has base class %1 of non-literal type">; +def note_non_literal_field : Note< + "%0 is not literal because it has data member %1 of " + "%select{non-literal|volatile}3 type %2">; +def note_non_literal_user_provided_dtor : Note< + "%0 is not literal because it has a user-provided destructor">; +def note_non_literal_nontrivial_dtor : Note< + "%0 is not literal because it has a non-trivial destructor">; +def warn_private_extern : Warning< + "use of __private_extern__ on a declaration may not produce external symbol " + "private to the linkage unit and is deprecated">, InGroup<PrivateExtern>; +def note_private_extern : Note< + "use __attribute__((visibility(\"hidden\"))) attribute instead">; + +// C++ Concepts TS +def err_concept_wrong_decl_kind : Error< + "'concept' can only appear on the definition of a function template or variable template">; +def err_concept_decls_may_only_appear_in_namespace_scope : Error< + "concept declarations may only appear in namespace scope">; +def err_function_concept_not_defined : Error< + "function concept declaration must be a definition">; +def err_var_concept_not_initialized : Error< + "variable concept declaration must be initialized">; +def err_function_concept_exception_spec : Error< + "function concept cannot have exception specification">; +def err_concept_decl_invalid_specifiers : Error< + "%select{variable|function}0 concept cannot be declared " + "'%select{thread_local|inline|friend|constexpr}1'">; +def err_function_concept_with_params : Error< + "function concept cannot have any parameters">; + +// C++11 char16_t/char32_t +def warn_cxx98_compat_unicode_type : Warning< + "'%0' type specifier is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; + +// __make_integer_seq +def err_integer_sequence_negative_length : Error< + "integer sequences must have non-negative sequence length">; +def err_integer_sequence_integral_element_type : Error< + "integer sequences must have integral element type">; + +// Objective-C++ +def err_objc_decls_may_only_appear_in_global_scope : Error< + "Objective-C declarations may only appear in global scope">; +def warn_auto_var_is_id : Warning< + "'auto' deduced as 'id' in declaration of %0">, + InGroup<DiagGroup<"auto-var-id">>; + +// Attributes +def err_nsobject_attribute : Error< + "'NSObject' attribute is for pointer types only">; +def err_attributes_are_not_compatible : Error< + "%0 and %1 attributes are not compatible">; +def err_attribute_wrong_number_arguments : Error< + "%0 attribute %plural{0:takes no arguments|1:takes one argument|" + ":requires exactly %1 arguments}1">; +def err_attribute_too_many_arguments : Error< + "%0 attribute takes no more than %1 argument%s1">; +def err_attribute_too_few_arguments : Error< + "%0 attribute takes at least %1 argument%s1">; +def err_attribute_invalid_vector_type : Error<"invalid vector element type %0">; +def err_attribute_bad_neon_vector_size : Error< + "Neon vector size must be 64 or 128 bits">; +def warn_unsupported_target_attribute + : Warning<"Ignoring unsupported '%0' in the target attribute string">, + InGroup<IgnoredAttributes>; +def err_attribute_unsupported + : Error<"%0 attribute is not supported for this target">; +// The err_*_attribute_argument_not_int are seperate because they're used by +// VerifyIntegerConstantExpression. +def err_aligned_attribute_argument_not_int : Error< + "'aligned' attribute requires integer constant">; +def err_align_value_attribute_argument_not_int : Error< + "'align_value' attribute requires integer constant">; +def err_alignas_attribute_wrong_decl_type : Error< + "%0 attribute cannot be applied to a %select{function parameter|" + "variable with 'register' storage class|'catch' variable|bit-field}1">; +def err_alignas_missing_on_definition : Error< + "%0 must be specified on definition if it is specified on any declaration">; +def note_alignas_on_declaration : Note<"declared with %0 attribute here">; +def err_alignas_mismatch : Error< + "redeclaration has different alignment requirement (%1 vs %0)">; +def err_alignas_underaligned : Error< + "requested alignment is less than minimum alignment of %1 for type %0">; +def err_attribute_argument_n_type : Error< + "%0 attribute requires parameter %1 to be %select{int or bool|an integer " + "constant|a string|an identifier}2">; +def err_attribute_argument_type : Error< + "%0 attribute requires %select{int or bool|an integer " + "constant|a string|an identifier}1">; +def err_attribute_argument_outof_range : Error< + "%0 attribute requires integer constant between %1 and %2 inclusive">; +def err_init_priority_object_attr : Error< + "can only use 'init_priority' attribute on file-scope definitions " + "of objects of class type">; +def err_attribute_argument_vec_type_hint : Error< + "invalid attribute argument %0 - expecting a vector or vectorizable scalar type">; +def err_attribute_argument_out_of_bounds : Error< + "%0 attribute parameter %1 is out of bounds">; +def err_attribute_only_once_per_parameter : Error< + "%0 attribute can only be applied once per parameter">; +def err_attribute_uuid_malformed_guid : Error< + "uuid attribute contains a malformed GUID">; +def warn_attribute_pointers_only : Warning< + "%0 attribute only applies to%select{| constant}1 pointer arguments">, + InGroup<IgnoredAttributes>; +def err_attribute_pointers_only : Error<warn_attribute_pointers_only.Text>; +def warn_attribute_return_pointers_only : Warning< + "%0 attribute only applies to return values that are pointers">, + InGroup<IgnoredAttributes>; +def warn_attribute_return_pointers_refs_only : Warning< + "%0 attribute only applies to return values that are pointers or references">, + InGroup<IgnoredAttributes>; +def warn_attribute_pointer_or_reference_only : Warning< + "%0 attribute only applies to a pointer or reference (%1 is invalid)">, + InGroup<IgnoredAttributes>; +def err_attribute_no_member_pointers : Error< + "%0 attribute cannot be used with pointers to members">; +def err_attribute_invalid_implicit_this_argument : Error< + "%0 attribute is invalid for the implicit this argument">; +def err_ownership_type : Error< + "%0 attribute only applies to %select{pointer|integer}1 arguments">; +def err_ownership_returns_index_mismatch : Error< + "'ownership_returns' attribute index does not match; here it is %0">; +def note_ownership_returns_index_mismatch : Note< + "declared with index %0 here">; +def err_format_strftime_third_parameter : Error< + "strftime format attribute requires 3rd parameter to be 0">; +def err_format_attribute_requires_variadic : Error< + "format attribute requires variadic function">; +def err_format_attribute_not : Error<"format argument not %0">; +def err_format_attribute_result_not : Error<"function does not return %0">; +def err_format_attribute_implicit_this_format_string : Error< + "format attribute cannot specify the implicit this argument as the format " + "string">; +def err_init_method_bad_return_type : Error< + "init methods must return an object pointer type, not %0">; +def err_attribute_invalid_size : Error< + "vector size not an integral multiple of component size">; +def err_attribute_zero_size : Error<"zero vector size">; +def err_attribute_size_too_large : Error<"vector size too large">; +def err_typecheck_vector_not_convertable : Error< + "cannot convert between vector values of different size (%0 and %1)">; +def err_typecheck_vector_not_convertable_non_scalar : Error< + "cannot convert between vector and non-scalar values (%0 and %1)">; +def err_typecheck_vector_lengths_not_equal : Error< + "vector operands do not have the same number of elements (%0 and %1)">; +def err_ext_vector_component_exceeds_length : Error< + "vector component access exceeds type %0">; +def err_ext_vector_component_name_illegal : Error< + "illegal vector component name '%0'">; +def err_attribute_address_space_negative : Error< + "address space is negative">; +def err_attribute_address_space_too_high : Error< + "address space is larger than the maximum supported (%0)">; +def err_attribute_address_multiple_qualifiers : Error< + "multiple address spaces specified for type">; +def err_attribute_address_function_type : Error< + "function type may not be qualified with an address space">; +def err_as_qualified_auto_decl : Error< + "automatic variable qualified with an address space">; +def err_arg_with_address_space : Error< + "parameter may not be qualified with an address space">; +def err_field_with_address_space : Error< + "field may not be qualified with an address space">; +def err_attr_objc_ownership_redundant : Error< + "the type %0 is already explicitly ownership-qualified">; +def err_invalid_nsnumber_type : Error< + "%0 is not a valid literal type for NSNumber">; +def err_objc_illegal_boxed_expression_type : Error< + "illegal type %0 used in a boxed expression">; +def err_objc_non_trivially_copyable_boxed_expression_type : Error< + "non-trivially copyable type %0 cannot be used in a boxed expression">; +def err_objc_incomplete_boxed_expression_type : Error< + "incomplete type %0 used in a boxed expression">; +def err_undeclared_objc_literal_class : Error< + "definition of class %0 must be available to use Objective-C " + "%select{array literals|dictionary literals|numeric literals|boxed expressions|" + "string literals}1">; +def err_undeclared_boxing_method : Error< + "declaration of %0 is missing in %1 class">; +def err_objc_literal_method_sig : Error< + "literal construction method %0 has incompatible signature">; +def note_objc_literal_method_param : Note< + "%select{first|second|third}0 parameter has unexpected type %1 " + "(should be %2)">; +def note_objc_literal_method_return : Note< + "method returns unexpected type %0 (should be an object type)">; +def err_invalid_collection_element : Error< + "collection element of type %0 is not an Objective-C object">; +def err_box_literal_collection : Error< + "%select{string|character|boolean|numeric}0 literal must be prefixed by '@' " + "in a collection">; +def warn_objc_literal_comparison : Warning< + "direct comparison of %select{an array literal|a dictionary literal|" + "a numeric literal|a boxed expression|}0 has undefined behavior">, + InGroup<ObjCLiteralComparison>; +def err_missing_atsign_prefix : Error< + "string literal must be prefixed by '@' ">; +def warn_objc_string_literal_comparison : Warning< + "direct comparison of a string literal has undefined behavior">, + InGroup<ObjCStringComparison>; +def warn_concatenated_nsarray_literal : Warning< + "concatenated NSString literal for an NSArray expression - " + "possibly missing a comma">, + InGroup<ObjCStringConcatenation>; +def note_objc_literal_comparison_isequal : Note< + "use 'isEqual:' instead">; +def warn_objc_collection_literal_element : Warning< + "object of type %0 is not compatible with " + "%select{array element type|dictionary key type|dictionary value type}1 %2">, + InGroup<ObjCLiteralConversion>; + +def err_attribute_argument_is_zero : Error< + "%0 attribute must be greater than 0">; +def warn_attribute_argument_n_negative : Warning< + "%0 attribute parameter %1 is negative and will be ignored">, + InGroup<CudaCompat>; +def err_property_function_in_objc_container : Error< + "use of Objective-C property in function nested in Objective-C " + "container not supported, move function outside its container">; + +let CategoryName = "Cocoa API Issue" in { +def warn_objc_redundant_literal_use : Warning< + "using %0 with a literal is redundant">, InGroup<ObjCRedundantLiteralUse>; +} + +def err_attr_tlsmodel_arg : Error<"tls_model must be \"global-dynamic\", " + "\"local-dynamic\", \"initial-exec\" or \"local-exec\"">; + +def err_tls_var_aligned_over_maximum : Error< + "alignment (%0) of thread-local variable %1 is greater than the maximum supported " + "alignment (%2) for a thread-local variable on this target">; + +def err_only_annotate_after_access_spec : Error< + "access specifier can only have annotation attributes">; + +def err_attribute_section_invalid_for_target : Error< + "argument to 'section' attribute is not valid for this target: %0">; +def warn_mismatched_section : Warning< + "section does not match previous declaration">, InGroup<Section>; + +def err_anonymous_property: Error< + "anonymous property is not supported">; +def err_property_is_variably_modified : Error< + "property %0 has a variably modified type">; +def err_no_accessor_for_property : Error< + "no %select{getter|setter}0 defined for property %1">; +def error_cannot_find_suitable_accessor : Error< + "cannot find suitable %select{getter|setter}0 for property %1">; + +def err_alignment_not_power_of_two : Error< + "requested alignment is not a power of 2">; +def err_alignment_dependent_typedef_name : Error< + "requested alignment is dependent but declaration is not dependent">; + +def err_attribute_aligned_too_great : Error< + "requested alignment must be %0 bytes or smaller">; +def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning< + "%q0 redeclared without %1 attribute: previous %1 ignored">, + InGroup<DiagGroup<"inconsistent-dllimport">>; +def warn_dllimport_dropped_from_inline_function : Warning< + "%q0 redeclared inline; %1 attribute ignored">, + InGroup<IgnoredAttributes>; +def warn_attribute_ignored : Warning<"%0 attribute ignored">, + InGroup<IgnoredAttributes>; +def warn_attribute_ignored_on_inline : + Warning<"%0 attribute ignored on inline function">, + InGroup<IgnoredAttributes>; +def warn_attribute_after_definition_ignored : Warning< + "attribute %0 after definition is ignored">, + InGroup<IgnoredAttributes>; +def warn_unknown_attribute_ignored : Warning< + "unknown attribute %0 ignored">, InGroup<UnknownAttributes>; +def warn_cxx11_gnu_attribute_on_type : Warning< + "attribute %0 ignored, because it cannot be applied to a type">, + InGroup<IgnoredAttributes>; +def warn_unhandled_ms_attribute_ignored : Warning< + "__declspec attribute %0 is not supported">, + InGroup<IgnoredAttributes>; +def err_attribute_invalid_on_stmt : Error< + "%0 attribute cannot be applied to a statement">; +def warn_declspec_attribute_ignored : Warning< + "attribute %0 is ignored, place it after " + "\"%select{class|struct|interface|union|enum}1\" to apply attribute to " + "type declaration">, InGroup<IgnoredAttributes>; +def warn_attribute_precede_definition : Warning< + "attribute declaration must precede definition">, + InGroup<IgnoredAttributes>; +def warn_attribute_void_function_method : Warning< + "attribute %0 cannot be applied to " + "%select{functions|Objective-C method}1 without return value">, + InGroup<IgnoredAttributes>; +def warn_attribute_weak_on_field : Warning< + "__weak attribute cannot be specified on a field declaration">, + InGroup<IgnoredAttributes>; +def warn_gc_attribute_weak_on_local : Warning< + "Objective-C GC does not allow weak variables on the stack">, + InGroup<IgnoredAttributes>; +def warn_nsobject_attribute : Warning< + "'NSObject' attribute may be put on a typedef only; attribute is ignored">, + InGroup<NSobjectAttribute>; +def warn_independentclass_attribute : Warning< + "'objc_independent_class' attribute may be put on a typedef only; " + "attribute is ignored">, + InGroup<IndependentClassAttribute>; +def warn_ptr_independentclass_attribute : Warning< + "'objc_independent_class' attribute may be put on Objective-C object " + "pointer type only; attribute is ignored">, + InGroup<IndependentClassAttribute>; +def warn_attribute_weak_on_local : Warning< + "__weak attribute cannot be specified on an automatic variable when ARC " + "is not enabled">, + InGroup<IgnoredAttributes>; +def warn_weak_identifier_undeclared : Warning< + "weak identifier %0 never declared">; +def err_attribute_weak_static : Error< + "weak declaration cannot have internal linkage">; +def err_attribute_selectany_non_extern_data : Error< + "'selectany' can only be applied to data items with external linkage">; +def err_declspec_thread_on_thread_variable : Error< + "'__declspec(thread)' applied to variable that already has a " + "thread-local storage specifier">; +def err_attribute_dll_not_extern : Error< + "%q0 must have external linkage when declared %q1">; +def err_attribute_dll_thread_local : Error< + "%q0 cannot be thread local when declared %q1">; +def err_attribute_dll_lambda : Error< + "lambda cannot be declared %0">; +def warn_attribute_invalid_on_definition : Warning< + "'%0' attribute cannot be specified on a definition">, + InGroup<IgnoredAttributes>; +def err_attribute_dll_redeclaration : Error< + "redeclaration of %q0 cannot add %q1 attribute">; +def warn_attribute_dll_redeclaration : Warning< + "redeclaration of %q0 should not add %q1 attribute">, + InGroup<DiagGroup<"dll-attribute-on-redeclaration">>; +def err_attribute_dllimport_function_definition : Error< + "dllimport cannot be applied to non-inline function definition">; +def err_attribute_dll_deleted : Error< + "attribute %q0 cannot be applied to a deleted function">; +def err_attribute_dllimport_data_definition : Error< + "definition of dllimport data">; +def err_attribute_dllimport_static_field_definition : Error< + "definition of dllimport static field not allowed">; +def warn_attribute_dllimport_static_field_definition : Warning< + "definition of dllimport static field">, + InGroup<DiagGroup<"dllimport-static-field-def">>; +def warn_attribute_dllexport_explicit_instantiation_decl : Warning< + "explicit instantiation declaration should not be 'dllexport'">, + InGroup<DiagGroup<"dllexport-explicit-instantiation-decl">>; +def warn_invalid_initializer_from_system_header : Warning< + "invalid constructor form class in system header, should not be explicit">, + InGroup<DiagGroup<"invalid-initializer-from-system-header">>; +def note_used_in_initialization_here : Note<"used in initialization here">; +def err_attribute_dll_member_of_dll_class : Error< + "attribute %q0 cannot be applied to member of %q1 class">; +def warn_attribute_dll_instantiated_base_class : Warning< + "propagating dll attribute to %select{already instantiated|explicitly specialized}0 " + "base class template without dll attribute is not supported">, + InGroup<DiagGroup<"unsupported-dll-base-class-template">>, DefaultIgnore; +def err_attribute_dll_ambiguous_default_ctor : Error< + "'__declspec(dllexport)' cannot be applied to more than one default constructor in %0">; +def err_attribute_weakref_not_static : Error< + "weakref declaration must have internal linkage">; +def err_attribute_weakref_not_global_context : Error< + "weakref declaration of %0 must be in a global context">; +def err_attribute_weakref_without_alias : Error< + "weakref declaration of %0 must also have an alias attribute">; +def err_alias_not_supported_on_darwin : Error < + "only weak aliases are supported on darwin">; +def err_alias_to_undefined : Error< + "alias must point to a defined variable or function">; +def warn_alias_to_weak_alias : Warning< + "alias will always resolve to %0 even if weak definition of alias %1 is overridden">, + InGroup<IgnoredAttributes>; +def warn_alias_with_section : Warning< + "alias will not be in section '%0' but in the same section as the aliasee">, + InGroup<IgnoredAttributes>; +def err_duplicate_mangled_name : Error< + "definition with same mangled name as another definition">; +def err_cyclic_alias : Error< + "alias definition is part of a cycle">; +def warn_attribute_wrong_decl_type : Warning< + "%0 attribute only applies to %select{functions|unions|" + "variables and functions|functions and methods|parameters|" + "functions, methods and blocks|functions, methods, and classes|" + "functions, methods, and parameters|classes|enums|variables|methods|" + "variables, functions and labels|fields and global variables|structs|" + "variables and typedefs|thread-local variables|" + "variables and fields|variables, data members and tag types|" + "types and namespaces|Objective-C interfaces|methods and properties|" + "struct or union|struct, union or class|types|" + "Objective-C instance methods|init methods of interface or class extension declarations|" + "variables, functions and classes|Objective-C protocols|" + "functions and global variables|structs, unions, and typedefs|structs and typedefs|" + "interface or protocol declarations|kernel functions|non-K&R-style functions}1">, + InGroup<IgnoredAttributes>; +def err_attribute_wrong_decl_type : Error<warn_attribute_wrong_decl_type.Text>; +def warn_type_attribute_wrong_type : Warning< + "'%0' only applies to %select{function|pointer|" + "Objective-C object or block pointer}1 types; type here is %2">, + InGroup<IgnoredAttributes>; +def warn_incomplete_encoded_type : Warning< + "encoding of %0 type is incomplete because %1 component has unknown encoding">, + InGroup<DiagGroup<"encode-type">>; +def warn_attribute_requires_functions_or_static_globals : Warning< + "%0 only applies to variables with static storage duration and functions">, + InGroup<IgnoredAttributes>; +def warn_gnu_inline_attribute_requires_inline : Warning< + "'gnu_inline' attribute requires function to be marked 'inline'," + " attribute ignored">, + InGroup<IgnoredAttributes>; +def err_attribute_vecreturn_only_vector_member : Error< + "the vecreturn attribute can only be used on a class or structure with one member, which must be a vector">; +def err_attribute_vecreturn_only_pod_record : Error< + "the vecreturn attribute can only be used on a POD (plain old data) class or structure (i.e. no virtual functions)">; +def err_cconv_change : Error< + "function declared '%0' here was previously declared " + "%select{'%2'|without calling convention}1">; +def warn_cconv_ignored : Warning< + "calling convention %0 ignored for this target">, InGroup<IgnoredAttributes>; +def err_cconv_knr : Error< + "function with no prototype cannot use the %0 calling convention">; +def warn_cconv_knr : Warning< + err_cconv_knr.Text>, + InGroup<DiagGroup<"missing-prototype-for-cc">>; +def err_cconv_varargs : Error< + "variadic function cannot use %0 calling convention">; +def warn_cconv_varargs : Warning< + "%0 calling convention ignored on variadic function">, + InGroup<IgnoredAttributes>; +def warn_cconv_structors : Warning< + "%0 calling convention ignored on constructor/destructor">, + InGroup<IgnoredAttributes>; +def err_regparm_mismatch : Error<"function declared with regparm(%0) " + "attribute was previously declared " + "%plural{0:without the regparm|:with the regparm(%1)}1 attribute">; +def err_returns_retained_mismatch : Error< + "function declared with the ns_returns_retained attribute " + "was previously declared without the ns_returns_retained attribute">; +def err_objc_precise_lifetime_bad_type : Error< + "objc_precise_lifetime only applies to retainable types; type here is %0">; +def warn_objc_precise_lifetime_meaningless : Error< + "objc_precise_lifetime is not meaningful for " + "%select{__unsafe_unretained|__autoreleasing}0 objects">; +def err_invalid_pcs : Error<"invalid PCS type">; +def warn_attribute_not_on_decl : Warning< + "%0 attribute ignored when parsing type">, InGroup<IgnoredAttributes>; +def err_base_specifier_attribute : Error< + "%0 attribute cannot be applied to a base specifier">; +def err_invalid_attribute_on_virtual_function : Error< + "%0 attribute cannot be applied to virtual functions">; + +// Availability attribute +def warn_availability_unknown_platform : Warning< + "unknown platform %0 in availability macro">, InGroup<Availability>; +def warn_availability_version_ordering : Warning< + "feature cannot be %select{introduced|deprecated|obsoleted}0 in %1 version " + "%2 before it was %select{introduced|deprecated|obsoleted}3 in version %4; " + "attribute ignored">, InGroup<Availability>; +def warn_mismatched_availability: Warning< + "availability does not match previous declaration">, InGroup<Availability>; +def warn_mismatched_availability_override : Warning< + "%select{|overriding }4method %select{introduced after|" + "deprecated before|obsoleted before}0 " + "%select{the protocol method it implements|overridden method}4 " + "on %1 (%2 vs. %3)">, InGroup<Availability>; +def warn_mismatched_availability_override_unavail : Warning< + "%select{|overriding }1method cannot be unavailable on %0 when " + "%select{the protocol method it implements|its overridden method}1 is " + "available">, + InGroup<Availability>; +def note_overridden_method : Note< + "overridden method is here">; +def note_protocol_method : Note< + "protocol method is here">; + +// Thread Safety Attributes +def warn_invalid_capability_name : Warning< + "invalid capability name '%0'; capability name must be 'mutex' or 'role'">, + InGroup<ThreadSafetyAttributes>, DefaultIgnore; +def warn_thread_attribute_ignored : Warning< + "ignoring %0 attribute because its argument is invalid">, + InGroup<ThreadSafetyAttributes>, DefaultIgnore; +def warn_thread_attribute_argument_not_lockable : Warning< + "%0 attribute requires arguments whose type is annotated " + "with 'capability' attribute; type here is %1">, + InGroup<ThreadSafetyAttributes>, DefaultIgnore; +def warn_thread_attribute_decl_not_lockable : Warning< + "%0 attribute can only be applied in a context annotated " + "with 'capability(\"mutex\")' attribute">, + InGroup<ThreadSafetyAttributes>, DefaultIgnore; +def warn_thread_attribute_decl_not_pointer : Warning< + "%0 only applies to pointer types; type here is %1">, + InGroup<ThreadSafetyAttributes>, DefaultIgnore; +def err_attribute_argument_out_of_range : Error< + "%0 attribute parameter %1 is out of bounds: " + "%plural{0:no parameters to index into|" + "1:can only be 1, since there is one parameter|" + ":must be between 1 and %2}2">; + +// Thread Safety Analysis +def warn_unlock_but_no_lock : Warning<"releasing %0 '%1' that was not held">, + InGroup<ThreadSafetyAnalysis>, DefaultIgnore; +def warn_unlock_kind_mismatch : Warning< + "releasing %0 '%1' using %select{shared|exclusive}2 access, expected " + "%select{shared|exclusive}3 access">, + InGroup<ThreadSafetyAnalysis>, DefaultIgnore; +def warn_double_lock : Warning<"acquiring %0 '%1' that is already held">, + InGroup<ThreadSafetyAnalysis>, DefaultIgnore; +def warn_no_unlock : Warning< + "%0 '%1' is still held at the end of function">, + InGroup<ThreadSafetyAnalysis>, DefaultIgnore; +def warn_expecting_locked : Warning< + "expecting %0 '%1' to be held at the end of function">, + InGroup<ThreadSafetyAnalysis>, DefaultIgnore; +// FIXME: improve the error message about locks not in scope +def warn_lock_some_predecessors : Warning< + "%0 '%1' is not held on every path through here">, + InGroup<ThreadSafetyAnalysis>, DefaultIgnore; +def warn_expecting_lock_held_on_loop : Warning< + "expecting %0 '%1' to be held at start of each loop">, + InGroup<ThreadSafetyAnalysis>, DefaultIgnore; +def note_locked_here : Note<"%0 acquired here">; +def warn_lock_exclusive_and_shared : Warning< + "%0 '%1' is acquired exclusively and shared in the same scope">, + InGroup<ThreadSafetyAnalysis>, DefaultIgnore; +def note_lock_exclusive_and_shared : Note< + "the other acquisition of %0 '%1' is here">; +def warn_variable_requires_any_lock : Warning< + "%select{reading|writing}1 variable '%0' requires holding " + "%select{any mutex|any mutex exclusively}1">, + InGroup<ThreadSafetyAnalysis>, DefaultIgnore; +def warn_var_deref_requires_any_lock : Warning< + "%select{reading|writing}1 the value pointed to by '%0' requires holding " + "%select{any mutex|any mutex exclusively}1">, + InGroup<ThreadSafetyAnalysis>, DefaultIgnore; +def warn_fun_excludes_mutex : Warning< + "cannot call function '%1' while %0 '%2' is held">, + InGroup<ThreadSafetyAnalysis>, DefaultIgnore; +def warn_cannot_resolve_lock : Warning< + "cannot resolve lock expression">, + InGroup<ThreadSafetyAnalysis>, DefaultIgnore; +def warn_acquired_before : Warning< + "%0 '%1' must be acquired before '%2'">, + InGroup<ThreadSafetyAnalysis>, DefaultIgnore; +def warn_acquired_before_after_cycle : Warning< + "Cycle in acquired_before/after dependencies, starting with '%0'">, + InGroup<ThreadSafetyAnalysis>, DefaultIgnore; + + +// Thread safety warnings negative capabilities +def warn_acquire_requires_negative_cap : Warning< + "acquiring %0 '%1' requires negative capability '%2'">, + InGroup<ThreadSafetyNegative>, DefaultIgnore; + +// Thread safety warnings on pass by reference +def warn_guarded_pass_by_reference : Warning< + "passing variable '%1' by reference requires holding %0 " + "%select{'%2'|'%2' exclusively}3">, + InGroup<ThreadSafetyReference>, DefaultIgnore; +def warn_pt_guarded_pass_by_reference : Warning< + "passing the value that '%1' points to by reference requires holding %0 " + "%select{'%2'|'%2' exclusively}3">, + InGroup<ThreadSafetyReference>, DefaultIgnore; + +// Imprecise thread safety warnings +def warn_variable_requires_lock : Warning< + "%select{reading|writing}3 variable '%1' requires holding %0 " + "%select{'%2'|'%2' exclusively}3">, + InGroup<ThreadSafetyAnalysis>, DefaultIgnore; +def warn_var_deref_requires_lock : Warning< + "%select{reading|writing}3 the value pointed to by '%1' requires " + "holding %0 %select{'%2'|'%2' exclusively}3">, + InGroup<ThreadSafetyAnalysis>, DefaultIgnore; +def warn_fun_requires_lock : Warning< + "calling function '%1' requires holding %0 %select{'%2'|'%2' exclusively}3">, + InGroup<ThreadSafetyAnalysis>, DefaultIgnore; + +// Precise thread safety warnings +def warn_variable_requires_lock_precise : + Warning<warn_variable_requires_lock.Text>, + InGroup<ThreadSafetyPrecise>, DefaultIgnore; +def warn_var_deref_requires_lock_precise : + Warning<warn_var_deref_requires_lock.Text>, + InGroup<ThreadSafetyPrecise>, DefaultIgnore; +def warn_fun_requires_lock_precise : + Warning<warn_fun_requires_lock.Text>, + InGroup<ThreadSafetyPrecise>, DefaultIgnore; +def note_found_mutex_near_match : Note<"found near match '%0'">; + +// Verbose thread safety warnings +def warn_thread_safety_verbose : Warning<"Thread safety verbose warning.">, + InGroup<ThreadSafetyVerbose>, DefaultIgnore; +def note_thread_warning_in_fun : Note<"Thread warning in function '%0'">; +def note_guarded_by_declared_here : Note<"Guarded_by declared here.">; + +// Dummy warning that will trigger "beta" warnings from the analysis if enabled. +def warn_thread_safety_beta : Warning<"Thread safety beta warning.">, + InGroup<ThreadSafetyBeta>, DefaultIgnore; + +// Consumed warnings +def warn_use_in_invalid_state : Warning< + "invalid invocation of method '%0' on object '%1' while it is in the '%2' " + "state">, InGroup<Consumed>, DefaultIgnore; +def warn_use_of_temp_in_invalid_state : Warning< + "invalid invocation of method '%0' on a temporary object while it is in the " + "'%1' state">, InGroup<Consumed>, DefaultIgnore; +def warn_attr_on_unconsumable_class : Warning< + "consumed analysis attribute is attached to member of class '%0' which isn't " + "marked as consumable">, InGroup<Consumed>, DefaultIgnore; +def warn_return_typestate_for_unconsumable_type : Warning< + "return state set for an unconsumable type '%0'">, InGroup<Consumed>, + DefaultIgnore; +def warn_return_typestate_mismatch : Warning< + "return value not in expected state; expected '%0', observed '%1'">, + InGroup<Consumed>, DefaultIgnore; +def warn_loop_state_mismatch : Warning< + "state of variable '%0' must match at the entry and exit of loop">, + InGroup<Consumed>, DefaultIgnore; +def warn_param_return_typestate_mismatch : Warning< + "parameter '%0' not in expected state when the function returns: expected " + "'%1', observed '%2'">, InGroup<Consumed>, DefaultIgnore; +def warn_param_typestate_mismatch : Warning< + "argument not in expected state; expected '%0', observed '%1'">, + InGroup<Consumed>, DefaultIgnore; + +// no_sanitize attribute +def warn_unknown_sanitizer_ignored : Warning< + "unknown sanitizer '%0' ignored">, InGroup<UnknownSanitizers>; + +def warn_impcast_vector_scalar : Warning< + "implicit conversion turns vector to scalar: %0 to %1">, + InGroup<Conversion>, DefaultIgnore; +def warn_impcast_complex_scalar : Warning< + "implicit conversion discards imaginary component: %0 to %1">, + InGroup<Conversion>, DefaultIgnore; +def warn_impcast_float_precision : Warning< + "implicit conversion loses floating-point precision: %0 to %1">, + InGroup<Conversion>, DefaultIgnore; +def warn_impcast_double_promotion : Warning< + "implicit conversion increases floating-point precision: %0 to %1">, + InGroup<DoublePromotion>, DefaultIgnore; +def warn_impcast_float_integer : Warning< + "implicit conversion turns floating-point number into integer: %0 to %1">, + InGroup<FloatConversion>, DefaultIgnore; +def warn_impcast_integer_sign : Warning< + "implicit conversion changes signedness: %0 to %1">, + InGroup<SignConversion>, DefaultIgnore; +def warn_impcast_integer_sign_conditional : Warning< + "operand of ? changes signedness: %0 to %1">, + InGroup<SignConversion>, DefaultIgnore; +def warn_impcast_integer_precision : Warning< + "implicit conversion loses integer precision: %0 to %1">, + InGroup<Conversion>, DefaultIgnore; +def warn_impcast_integer_64_32 : Warning< + "implicit conversion loses integer precision: %0 to %1">, + InGroup<Shorten64To32>, DefaultIgnore; +def warn_impcast_integer_precision_constant : Warning< + "implicit conversion from %2 to %3 changes value from %0 to %1">, + InGroup<ConstantConversion>; +def warn_impcast_bitfield_precision_constant : Warning< + "implicit truncation from %2 to bitfield changes value from %0 to %1">, + InGroup<BitFieldConstantConversion>; +def warn_impcast_literal_float_to_integer : Warning< + "implicit conversion from %0 to %1 changes value from %2 to %3">, + InGroup<LiteralConversion>; +def warn_impcast_string_literal_to_bool : Warning< + "implicit conversion turns string literal into bool: %0 to %1">, + InGroup<StringConversion>, DefaultIgnore; +def warn_impcast_different_enum_types : Warning< + "implicit conversion from enumeration type %0 to different enumeration type " + "%1">, InGroup<EnumConversion>; +def warn_impcast_bool_to_null_pointer : Warning< + "initialization of pointer of type %0 to null from a constant boolean " + "expression">, InGroup<BoolConversion>; +def warn_non_literal_null_pointer : Warning< + "expression which evaluates to zero treated as a null pointer constant of " + "type %0">, InGroup<NonLiteralNullConversion>; +def warn_impcast_null_pointer_to_integer : Warning< + "implicit conversion of %select{NULL|nullptr}0 constant to %1">, + InGroup<NullConversion>; +def warn_impcast_floating_point_to_bool : Warning< + "implicit conversion turns floating-point number into bool: %0 to %1">, + InGroup<ImplicitConversionFloatingPointToBool>; +def ext_ms_impcast_fn_obj : ExtWarn< + "implicit conversion between pointer-to-function and pointer-to-object is a " + "Microsoft extension">, InGroup<MicrosoftCast>; + +def warn_impcast_pointer_to_bool : Warning< + "address of%select{| function| array}0 '%1' will always evaluate to " + "'true'">, + InGroup<PointerBoolConversion>; +def warn_cast_nonnull_to_bool : Warning< + "nonnull %select{function call|parameter}0 '%1' will evaluate to " + "'true' on first encounter">, + InGroup<PointerBoolConversion>; +def warn_this_bool_conversion : Warning< + "'this' pointer cannot be null in well-defined C++ code; pointer may be " + "assumed to always convert to true">, InGroup<UndefinedBoolConversion>; +def warn_address_of_reference_bool_conversion : Warning< + "reference cannot be bound to dereferenced null pointer in well-defined C++ " + "code; pointer may be assumed to always convert to true">, + InGroup<UndefinedBoolConversion>; + +def warn_null_pointer_compare : Warning< + "comparison of %select{address of|function|array}0 '%1' %select{not |}2" + "equal to a null pointer is always %select{true|false}2">, + InGroup<TautologicalPointerCompare>; +def warn_nonnull_expr_compare : Warning< + "comparison of nonnull %select{function call|parameter}0 '%1' " + "%select{not |}2equal to a null pointer is '%select{true|false}2' on first " + "encounter">, + InGroup<TautologicalPointerCompare>; +def warn_this_null_compare : Warning< + "'this' pointer cannot be null in well-defined C++ code; comparison may be " + "assumed to always evaluate to %select{true|false}0">, + InGroup<TautologicalUndefinedCompare>; +def warn_address_of_reference_null_compare : Warning< + "reference cannot be bound to dereferenced null pointer in well-defined C++ " + "code; comparison may be assumed to always evaluate to " + "%select{true|false}0">, + InGroup<TautologicalUndefinedCompare>; +def note_reference_is_return_value : Note<"%0 returns a reference">; + +def note_function_warning_silence : Note< + "prefix with the address-of operator to silence this warning">; +def note_function_to_function_call : Note< + "suffix with parentheses to turn this into a function call">; +def warn_impcast_objective_c_literal_to_bool : Warning< + "implicit boolean conversion of Objective-C object literal always " + "evaluates to true">, + InGroup<ObjCLiteralConversion>; + +def warn_cast_align : Warning< + "cast from %0 to %1 increases required alignment from %2 to %3">, + InGroup<CastAlign>, DefaultIgnore; +def warn_old_style_cast : Warning< + "use of old-style cast">, InGroup<OldStyleCast>, DefaultIgnore; + +// Separate between casts to void* and non-void* pointers. +// Some APIs use (abuse) void* for something like a user context, +// and often that value is an integer even if it isn't a pointer itself. +// Having a separate warning flag allows users to control the warning +// for their workflow. +def warn_int_to_pointer_cast : Warning< + "cast to %1 from smaller integer type %0">, + InGroup<IntToPointerCast>; +def warn_int_to_void_pointer_cast : Warning< + "cast to %1 from smaller integer type %0">, + InGroup<IntToVoidPointerCast>; + +def warn_attribute_packed_for_bitfield : Warning< + "'packed' attribute was ignored on bit-fields with single-byte alignment " + "in older versions of GCC and Clang">, + InGroup<DiagGroup<"attribute-packed-for-bitfield">>; +def warn_transparent_union_attribute_field_size_align : Warning< + "%select{alignment|size}0 of field %1 (%2 bits) does not match the " + "%select{alignment|size}0 of the first field in transparent union; " + "transparent_union attribute ignored">, + InGroup<IgnoredAttributes>; +def note_transparent_union_first_field_size_align : Note< + "%select{alignment|size}0 of first field is %1 bits">; +def warn_transparent_union_attribute_not_definition : Warning< + "transparent_union attribute can only be applied to a union definition; " + "attribute ignored">, + InGroup<IgnoredAttributes>; +def warn_transparent_union_attribute_floating : Warning< + "first field of a transparent union cannot have %select{floating point|" + "vector}0 type %1; transparent_union attribute ignored">, + InGroup<IgnoredAttributes>; +def warn_transparent_union_attribute_zero_fields : Warning< + "transparent union definition must contain at least one field; " + "transparent_union attribute ignored">, + InGroup<IgnoredAttributes>; +def warn_attribute_type_not_supported : Warning< + "%0 attribute argument not supported: %1">, + InGroup<IgnoredAttributes>; +def warn_attribute_unknown_visibility : Warning<"unknown visibility %0">, + InGroup<IgnoredAttributes>; +def warn_attribute_protected_visibility : + Warning<"target does not support 'protected' visibility; using 'default'">, + InGroup<DiagGroup<"unsupported-visibility">>; +def err_mismatched_visibility: Error<"visibility does not match previous declaration">; +def note_previous_attribute : Note<"previous attribute is here">; +def note_conflicting_attribute : Note<"conflicting attribute is here">; +def note_attribute : Note<"attribute is here">; +def err_mismatched_ms_inheritance : Error< + "inheritance model does not match %select{definition|previous declaration}0">; +def warn_ignored_ms_inheritance : Warning< + "inheritance model ignored on %select{primary template|partial specialization}0">, + InGroup<IgnoredAttributes>; +def note_previous_ms_inheritance : Note< + "previous inheritance model specified here">; +def err_machine_mode : Error<"%select{unknown|unsupported}0 machine mode %1">; +def err_mode_not_primitive : Error< + "mode attribute only supported for integer and floating-point types">; +def err_mode_wrong_type : Error< + "type of machine mode does not match type of base type">; +def warn_vector_mode_deprecated : Warning< + "specifying vector types with the 'mode' attribute is deprecated; " + "use the 'vector_size' attribute instead">, + InGroup<DeprecatedAttributes>; +def err_complex_mode_vector_type : Error< + "type of machine mode does not support base vector types">; +def err_attr_wrong_decl : Error< + "%0 attribute invalid on this declaration, requires typedef or value">; +def warn_attribute_nonnull_no_pointers : Warning< + "'nonnull' attribute applied to function with no pointer arguments">, + InGroup<IgnoredAttributes>; +def warn_attribute_nonnull_parm_no_args : Warning< + "'nonnull' attribute when used on parameters takes no arguments">, + InGroup<IgnoredAttributes>; +def warn_attribute_sentinel_named_arguments : Warning< + "'sentinel' attribute requires named arguments">, + InGroup<IgnoredAttributes>; +def warn_attribute_sentinel_not_variadic : Warning< + "'sentinel' attribute only supported for variadic %select{functions|blocks}0">, + InGroup<IgnoredAttributes>; +def err_attribute_sentinel_less_than_zero : Error< + "'sentinel' parameter 1 less than zero">; +def err_attribute_sentinel_not_zero_or_one : Error< + "'sentinel' parameter 2 not 0 or 1">; +def warn_cleanup_ext : Warning< + "GCC does not allow the 'cleanup' attribute argument to be anything other " + "than a simple identifier">, + InGroup<GccCompat>; +def err_attribute_cleanup_arg_not_function : Error< + "'cleanup' argument %select{|%1 |%1 }0is not a %select{||single }0function">; +def err_attribute_cleanup_func_must_take_one_arg : Error< + "'cleanup' function %0 must take 1 parameter">; +def err_attribute_cleanup_func_arg_incompatible_type : Error< + "'cleanup' function %0 parameter has " + "%diff{type $ which is incompatible with type $|incompatible type}1,2">; +def err_attribute_regparm_wrong_platform : Error< + "'regparm' is not valid on this platform">; +def err_attribute_regparm_invalid_number : Error< + "'regparm' parameter must be between 0 and %0 inclusive">; +def err_attribute_not_supported_in_lang : Error< + "%0 attribute is not supported in %select{C|C++|Objective-C}1">; + + +// Clang-Specific Attributes +def warn_attribute_iboutlet : Warning< + "%0 attribute can only be applied to instance variables or properties">, + InGroup<IgnoredAttributes>; +def err_iboutletcollection_type : Error< + "invalid type %0 as argument of iboutletcollection attribute">; +def err_iboutletcollection_builtintype : Error< + "type argument of iboutletcollection attribute cannot be a builtin type">; +def warn_iboutlet_object_type : Warning< + "%select{instance variable|property}2 with %0 attribute must " + "be an object type (invalid %1)">, InGroup<ObjCInvalidIBOutletProperty>; +def warn_iboutletcollection_property_assign : Warning< + "IBOutletCollection properties should be copy/strong and not assign">, + InGroup<ObjCInvalidIBOutletProperty>; + +def err_attribute_overloadable_missing : Error< + "%select{overloaded function|redeclaration of}0 %1 must have the " + "'overloadable' attribute">; +def note_attribute_overloadable_prev_overload : Note< + "previous overload of function is here">; +def err_attribute_overloadable_no_prototype : Error< + "'overloadable' function %0 must have a prototype">; +def warn_ns_attribute_wrong_return_type : Warning< + "%0 attribute only applies to %select{functions|methods|properties}1 that " + "return %select{an Objective-C object|a pointer|a non-retainable pointer}2">, + InGroup<IgnoredAttributes>; +def warn_ns_attribute_wrong_parameter_type : Warning< + "%0 attribute only applies to " + "%select{Objective-C object|pointer|pointer-to-CF-pointer}1 parameters">, + InGroup<IgnoredAttributes>; +def warn_objc_requires_super_protocol : Warning< + "%0 attribute cannot be applied to %select{methods in protocols|dealloc}1">, + InGroup<DiagGroup<"requires-super-attribute">>; +def note_protocol_decl : Note< + "protocol is declared here">; +def note_protocol_decl_undefined : Note< + "protocol %0 has no definition">; + +// objc_designated_initializer attribute diagnostics. +def warn_objc_designated_init_missing_super_call : Warning< + "designated initializer missing a 'super' call to a designated initializer of the super class">, + InGroup<ObjCDesignatedInit>; +def note_objc_designated_init_marked_here : Note< + "method marked as designated initializer of the class here">; +def warn_objc_designated_init_non_super_designated_init_call : Warning< + "designated initializer should only invoke a designated initializer on 'super'">, + InGroup<ObjCDesignatedInit>; +def warn_objc_designated_init_non_designated_init_call : Warning< + "designated initializer invoked a non-designated initializer">, + InGroup<ObjCDesignatedInit>; +def warn_objc_secondary_init_super_init_call : Warning< + "convenience initializer should not invoke an initializer on 'super'">, + InGroup<ObjCDesignatedInit>; +def warn_objc_secondary_init_missing_init_call : Warning< + "convenience initializer missing a 'self' call to another initializer">, + InGroup<ObjCDesignatedInit>; +def warn_objc_implementation_missing_designated_init_override : Warning< + "method override for the designated initializer of the superclass %objcinstance0 not found">, + InGroup<ObjCDesignatedInit>; + +// objc_bridge attribute diagnostics. +def err_objc_attr_not_id : Error< + "parameter of %0 attribute must be a single name of an Objective-C %select{class|protocol}1">; +def err_objc_attr_typedef_not_id : Error< + "parameter of %0 attribute must be 'id' when used on a typedef">; +def err_objc_attr_typedef_not_void_pointer : Error< + "'objc_bridge(id)' is only allowed on structs and typedefs of void pointers">; +def err_objc_cf_bridged_not_interface : Error< + "CF object of type %0 is bridged to %1, which is not an Objective-C class">; +def err_objc_ns_bridged_invalid_cfobject : Error< + "ObjectiveC object of type %0 is bridged to %1, which is not valid CF object">; +def warn_objc_invalid_bridge : Warning< + "%0 bridges to %1, not %2">, InGroup<ObjCBridge>; +def warn_objc_invalid_bridge_to_cf : Warning< + "%0 cannot bridge to %1">, InGroup<ObjCBridge>; + +// objc_bridge_related attribute diagnostics. +def err_objc_bridged_related_invalid_class : Error< + "could not find Objective-C class %0 to convert %1 to %2">; +def err_objc_bridged_related_invalid_class_name : Error< + "%0 must be name of an Objective-C class to be able to convert %1 to %2">; +def err_objc_bridged_related_known_method : Error< + "%0 must be explicitly converted to %1; use %select{%objcclass2|%objcinstance2}3 " + "method for this conversion">; + +def err_objc_attr_protocol_requires_definition : Error< + "attribute %0 can only be applied to @protocol definitions, not forward declarations">; + +// Function Parameter Semantic Analysis. +def err_param_with_void_type : Error<"argument may not have 'void' type">; +def err_void_only_param : Error< + "'void' must be the first and only parameter if specified">; +def err_void_param_qualified : Error< + "'void' as parameter must not have type qualifiers">; +def err_ident_list_in_fn_declaration : Error< + "a parameter list without types is only allowed in a function definition">; +def ext_param_not_declared : Extension< + "parameter %0 was not declared, defaulting to type 'int'">; +def err_param_default_argument : Error< + "C does not support default arguments">; +def err_param_default_argument_redefinition : Error< + "redefinition of default argument">; +def ext_param_default_argument_redefinition : ExtWarn< + err_param_default_argument_redefinition.Text>, + InGroup<MicrosoftDefaultArgRedefinition>; +def err_param_default_argument_missing : Error< + "missing default argument on parameter">; +def err_param_default_argument_missing_name : Error< + "missing default argument on parameter %0">; +def err_param_default_argument_references_param : Error< + "default argument references parameter %0">; +def err_param_default_argument_references_local : Error< + "default argument references local variable %0 of enclosing function">; +def err_param_default_argument_references_this : Error< + "default argument references 'this'">; +def err_param_default_argument_nonfunc : Error< + "default arguments can only be specified for parameters in a function " + "declaration">; +def err_param_default_argument_template_redecl : Error< + "default arguments cannot be added to a function template that has already " + "been declared">; +def err_param_default_argument_member_template_redecl : Error< + "default arguments cannot be added to an out-of-line definition of a member " + "of a %select{class template|class template partial specialization|nested " + "class in a template}0">; +def err_param_default_argument_on_parameter_pack : Error< + "parameter pack cannot have a default argument">; +def err_uninitialized_member_for_assign : Error< + "cannot define the implicit copy assignment operator for %0, because " + "non-static %select{reference|const}1 member %2 cannot use copy " + "assignment operator">; +def err_uninitialized_member_in_ctor : Error< + "%select{|implicit default |inheriting }0constructor for %1 must explicitly " + "initialize the %select{reference|const}2 member %3">; +def err_default_arg_makes_ctor_special : Error< + "addition of default argument on redeclaration makes this constructor a " + "%select{default|copy|move}0 constructor">; + +def err_use_of_default_argument_to_function_declared_later : Error< + "use of default argument to function %0 that is declared later in class %1">; +def note_default_argument_declared_here : Note< + "default argument declared here">; + +def ext_param_promoted_not_compatible_with_prototype : ExtWarn< + "%diff{promoted type $ of K&R function parameter is not compatible with the " + "parameter type $|promoted type of K&R function parameter is not compatible " + "with parameter type}0,1 declared in a previous prototype">, + InGroup<KNRPromotedParameter>; + + +// C++ Overloading Semantic Analysis. +def err_ovl_diff_return_type : Error< + "functions that differ only in their return type cannot be overloaded">; +def err_ovl_static_nonstatic_member : Error< + "static and non-static member functions with the same parameter types " + "cannot be overloaded">; + +def err_ovl_no_viable_function_in_call : Error< + "no matching function for call to %0">; +def err_ovl_no_viable_member_function_in_call : Error< + "no matching member function for call to %0">; +def err_ovl_ambiguous_call : Error< + "call to %0 is ambiguous">; +def err_ovl_deleted_call : Error< + "call to %select{unavailable|deleted}0 function %1%2">; +def err_ovl_ambiguous_member_call : Error< + "call to member function %0 is ambiguous">; +def err_ovl_deleted_member_call : Error< + "call to %select{unavailable|deleted}0 member function %1%2">; +def note_ovl_too_many_candidates : Note< + "remaining %0 candidate%s0 omitted; " + "pass -fshow-overloads=all to show them">; +def note_ovl_candidate : Note<"candidate " + "%select{function|function|constructor|" + "function |function |constructor |" + "is the implicit default constructor|" + "is the implicit copy constructor|" + "is the implicit move constructor|" + "is the implicit copy assignment operator|" + "is the implicit move assignment operator|" + "is an inherited constructor}0%1" + "%select{| has different class%diff{ (expected $ but has $)|}3,4" + "| has different number of parameters (expected %3 but has %4)" + "| has type mismatch at %ordinal3 parameter" + "%diff{ (expected $ but has $)|}4,5" + "| has different return type%diff{ ($ expected but has $)|}3,4" + "| has different qualifiers (expected " + "%select{none|const|restrict|const and restrict|volatile|const and volatile" + "|volatile and restrict|const, volatile, and restrict}3 but found " + "%select{none|const|restrict|const and restrict|volatile|const and volatile" + "|volatile and restrict|const, volatile, and restrict}4)}2">; + +def note_ovl_candidate_inherited_constructor : Note<"inherited from here">; +def note_ovl_candidate_illegal_constructor : Note< + "candidate %select{constructor|template}0 ignored: " + "instantiation %select{takes|would take}0 its own class type by value">; +def note_ovl_candidate_bad_deduction : Note< + "candidate template ignored: failed template argument deduction">; +def note_ovl_candidate_incomplete_deduction : Note<"candidate template ignored: " + "couldn't infer template argument %0">; +def note_ovl_candidate_inconsistent_deduction : Note< + "candidate template ignored: deduced conflicting %select{types|values|" + "templates}0 for parameter %1%diff{ ($ vs. $)|}2,3">; +def note_ovl_candidate_explicit_arg_mismatch_named : Note< + "candidate template ignored: invalid explicitly-specified argument " + "for template parameter %0">; +def note_ovl_candidate_explicit_arg_mismatch_unnamed : Note< + "candidate template ignored: invalid explicitly-specified argument " + "for %ordinal0 template parameter">; +def note_ovl_candidate_instantiation_depth : Note< + "candidate template ignored: substitution exceeded maximum template " + "instantiation depth">; +def note_ovl_candidate_underqualified : Note< + "candidate template ignored: cannot deduce a type for %0 that would " + "make %2 equal %1">; +def note_ovl_candidate_substitution_failure : Note< + "candidate template ignored: substitution failure%0%1">; +def note_ovl_candidate_disabled_by_enable_if : Note< + "candidate template ignored: disabled by %0%1">; +def note_ovl_candidate_has_pass_object_size_params: Note< + "candidate address cannot be taken because parameter %0 has " + "pass_object_size attribute">; +def note_ovl_candidate_disabled_by_enable_if_attr : Note< + "candidate disabled: %0">; +def err_addrof_function_disabled_by_enable_if_attr : Error< + "cannot take address of function %0 becuase it has one or more " + "non-tautological enable_if conditions">; +def note_addrof_ovl_candidate_disabled_by_enable_if_attr : Note< + "candidate function made ineligible by enable_if">; +def note_ovl_candidate_failed_overload_resolution : Note< + "candidate template ignored: couldn't resolve reference to overloaded " + "function %0">; +def note_ovl_candidate_deduced_mismatch : Note< + "candidate template ignored: deduced type " + "%diff{$ of %ordinal0 parameter does not match adjusted type $ of argument" + "|of %ordinal0 parameter does not match adjusted type of argument}1,2%3">; +def note_ovl_candidate_non_deduced_mismatch : Note< + "candidate template ignored: could not match %diff{$ against $|types}0,1">; +// This note is needed because the above note would sometimes print two +// different types with the same name. Remove this note when the above note +// can handle that case properly. +def note_ovl_candidate_non_deduced_mismatch_qualified : Note< + "candidate template ignored: could not match %q0 against %q1">; + +// Note that we don't treat templates differently for this diagnostic. +def note_ovl_candidate_arity : Note<"candidate " + "%select{function|function|constructor|function|function|constructor|" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "constructor (the implicit move constructor)|" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|" + "constructor (inherited)}0 %select{|template }1" + "not viable: requires%select{ at least| at most|}2 %3 argument%s3, but %4 " + "%plural{1:was|:were}4 provided">; + +def note_ovl_candidate_arity_one : Note<"candidate " + "%select{function|function|constructor|function|function|constructor|" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "constructor (the implicit move constructor)|" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|" + "constructor (inherited)}0 %select{|template }1not viable: " + "%select{requires at least|allows at most single|requires single}2 " + "argument %3, but %plural{0:no|:%4}4 arguments were provided">; + +def note_ovl_candidate_deleted : Note< + "candidate %select{function|function|constructor|" + "function |function |constructor |" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "constructor (the implicit move constructor)|" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|" + "constructor (inherited)}0%1 has been " + "%select{explicitly made unavailable|explicitly deleted|" + "implicitly deleted}2">; + +// Giving the index of the bad argument really clutters this message, and +// it's relatively unimportant because 1) it's generally obvious which +// argument(s) are of the given object type and 2) the fix is usually +// to complete the type, which doesn't involve changes to the call line +// anyway. If people complain, we can change it. +def note_ovl_candidate_bad_conv_incomplete : Note<"candidate " + "%select{function|function|constructor|" + "function |function |constructor |" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "constructor (the implicit move constructor)|" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|" + "constructor (inherited)}0%1 " + "not viable: cannot convert argument of incomplete type " + "%diff{$ to $|to parameter type}2,3">; +def note_ovl_candidate_bad_list_argument : Note<"candidate " + "%select{function|function|constructor|" + "function |function |constructor |" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "constructor (the implicit move constructor)|" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|" + "constructor (inherited)}0%1 " + "not viable: cannot convert initializer list argument to %3">; +def note_ovl_candidate_bad_overload : Note<"candidate " + "%select{function|function|constructor|" + "function |function |constructor |" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "constructor (the implicit move constructor)|" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|" + "constructor (inherited)}0%1" + " not viable: no overload of %3 matching %2 for %ordinal4 argument">; +def note_ovl_candidate_bad_conv : Note<"candidate " + "%select{function|function|constructor|" + "function |function |constructor |" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "constructor (the implicit move constructor)|" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|" + "constructor (inherited)}0%1" + " not viable: no known conversion " + "%diff{from $ to $|from argument type to parameter type}2,3 for " + "%select{%ordinal5 argument|object argument}4" + "%select{|; dereference the argument with *|" + "; take the address of the argument with &|" + "; remove *|" + "; remove &}6">; +def note_ovl_candidate_bad_arc_conv : Note<"candidate " + "%select{function|function|constructor|" + "function |function |constructor |" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "constructor (the implicit move constructor)|" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|" + "constructor (inherited)}0%1" + " not viable: cannot implicitly convert argument " + "%diff{of type $ to $|type to parameter type}2,3 for " + "%select{%ordinal5 argument|object argument}4 under ARC">; +def note_ovl_candidate_bad_lvalue : Note<"candidate " + "%select{function|function|constructor|" + "function |function |constructor |" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "constructor (the implicit move constructor)|" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|" + "constructor (inherited)}0%1" + " not viable: expects an l-value for " + "%select{%ordinal3 argument|object argument}2">; +def note_ovl_candidate_bad_addrspace : Note<"candidate " + "%select{function|function|constructor|" + "function |function |constructor |" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "constructor (the implicit move constructor)|" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|" + "constructor (inherited)}0%1 not viable: " + "%select{%ordinal6|'this'}5 argument (%2) is in " + "address space %3, but parameter must be in address space %4">; +def note_ovl_candidate_bad_gc : Note<"candidate " + "%select{function|function|constructor|" + "function |function |constructor |" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "constructor (the implicit move constructor)|" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|" + "constructor (inherited)}0%1 not viable: " + "%select{%ordinal6|'this'}5 argument (%2) has %select{no|__weak|__strong}3 " + "ownership, but parameter has %select{no|__weak|__strong}4 ownership">; +def note_ovl_candidate_bad_ownership : Note<"candidate " + "%select{function|function|constructor|" + "function |function |constructor |" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "constructor (the implicit move constructor)|" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|" + "constructor (inherited)}0%1 not viable: " + "%select{%ordinal6|'this'}5 argument (%2) has " + "%select{no|__unsafe_unretained|__strong|__weak|__autoreleasing}3 ownership," + " but parameter has %select{no|__unsafe_unretained|__strong|__weak|" + "__autoreleasing}4 ownership">; +def note_ovl_candidate_bad_cvr_this : Note<"candidate " + "%select{|function|||function|||||" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|}0 not viable: " + "'this' argument has type %2, but method is not marked " + "%select{const|restrict|const or restrict|volatile|const or volatile|" + "volatile or restrict|const, volatile, or restrict}3">; +def note_ovl_candidate_bad_cvr : Note<"candidate " + "%select{function|function|constructor|" + "function |function |constructor |" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "constructor (the implicit move constructor)|" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|" + "constructor (inherited)}0%1 not viable: " + "%ordinal4 argument (%2) would lose " + "%select{const|restrict|const and restrict|volatile|const and volatile|" + "volatile and restrict|const, volatile, and restrict}3 qualifier" + "%select{||s||s|s|s}3">; +def note_ovl_candidate_bad_base_to_derived_conv : Note<"candidate " + "%select{function|function|constructor|" + "function |function |constructor |" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "constructor (the implicit move constructor)|" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|" + "constructor (inherited)}0%1" + " not viable: cannot %select{convert from|convert from|bind}2 " + "%select{base class pointer|superclass|base class object of type}2 %3 to " + "%select{derived class pointer|subclass|derived class reference}2 %4 for " + "%ordinal5 argument">; +def note_ovl_candidate_bad_target : Note< + "candidate %select{function|function|constructor|" + "function |function |constructor |" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "constructor (the implicit move constructor)|" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|" + "constructor (inherited)}0 not viable: call to " + "%select{__device__|__global__|__host__|__host__ __device__|invalid}1 function from" + " %select{__device__|__global__|__host__|__host__ __device__|invalid}2 function">; +def note_implicit_member_target_infer_collision : Note< + "implicit %select{" + "default constructor|" + "copy constructor|" + "move constructor|" + "copy assignment operator|" + "move assignment operator|" + "destructor}0 inferred target collision: call to both " + "%select{__device__|__global__|__host__|__host__ __device__}1 and " + "%select{__device__|__global__|__host__|__host__ __device__}2 members">; + +def note_ambiguous_type_conversion: Note< + "because of ambiguity in conversion %diff{of $ to $|between types}0,1">; +def note_ovl_builtin_binary_candidate : Note< + "built-in candidate %0">; +def note_ovl_builtin_unary_candidate : Note< + "built-in candidate %0">; +def err_ovl_no_viable_function_in_init : Error< + "no matching constructor for initialization of %0">; +def err_ovl_no_conversion_in_cast : Error< + "cannot convert %1 to %2 without a conversion operator">; +def err_ovl_no_viable_conversion_in_cast : Error< + "no matching conversion for %select{|static_cast|reinterpret_cast|" + "dynamic_cast|C-style cast|functional-style cast}0 from %1 to %2">; +def err_ovl_ambiguous_conversion_in_cast : Error< + "ambiguous conversion for %select{|static_cast|reinterpret_cast|" + "dynamic_cast|C-style cast|functional-style cast}0 from %1 to %2">; +def err_ovl_deleted_conversion_in_cast : Error< + "%select{|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" + "functional-style cast}0 from %1 to %2 uses deleted function">; +def err_ovl_ambiguous_init : Error<"call to constructor of %0 is ambiguous">; +def err_ref_init_ambiguous : Error< + "reference initialization of type %0 with initializer of type %1 is ambiguous">; +def err_ovl_deleted_init : Error< + "call to %select{unavailable|deleted}0 constructor of %1">; +def err_ovl_deleted_special_init : Error< + "call to implicitly-deleted %select{default constructor|copy constructor|" + "move constructor|copy assignment operator|move assignment operator|" + "destructor|function}0 of %1">; +def err_ovl_ambiguous_oper_unary : Error< + "use of overloaded operator '%0' is ambiguous (operand type %1)">; +def err_ovl_ambiguous_oper_binary : Error< + "use of overloaded operator '%0' is ambiguous (with operand types %1 and %2)">; +def err_ovl_no_viable_oper : Error<"no viable overloaded '%0'">; +def note_assign_lhs_incomplete : Note<"type %0 is incomplete">; +def err_ovl_deleted_oper : Error< + "overload resolution selected %select{unavailable|deleted}0 operator '%1'%2">; +def err_ovl_deleted_special_oper : Error< + "object of type %0 cannot be %select{constructed|copied|moved|assigned|" + "assigned|destroyed}1 because its %select{default constructor|" + "copy constructor|move constructor|copy assignment operator|" + "move assignment operator|destructor}1 is implicitly deleted">; +def err_ovl_no_viable_subscript : + Error<"no viable overloaded operator[] for type %0">; +def err_ovl_no_oper : + Error<"type %0 does not provide a %select{subscript|call}1 operator">; +def err_ovl_unresolvable : Error< + "reference to overloaded function could not be resolved; " + "did you mean to call it%select{| with no arguments}0?">; +def err_bound_member_function : Error< + "reference to non-static member function must be called" + "%select{|; did you mean to call it with no arguments?}0">; +def note_possible_target_of_call : Note<"possible target for call">; + +def err_ovl_no_viable_object_call : Error< + "no matching function for call to object of type %0">; +def err_ovl_ambiguous_object_call : Error< + "call to object of type %0 is ambiguous">; +def err_ovl_deleted_object_call : Error< + "call to %select{unavailable|deleted}0 function call operator in type %1%2">; +def note_ovl_surrogate_cand : Note<"conversion candidate of type %0">; +def err_member_call_without_object : Error< + "call to non-static member function without an object argument">; + +// C++ Address of Overloaded Function +def err_addr_ovl_no_viable : Error< + "address of overloaded function %0 does not match required type %1">; +def err_addr_ovl_ambiguous : Error< + "address of overloaded function %0 is ambiguous">; +def err_addr_ovl_not_func_ptrref : Error< + "address of overloaded function %0 cannot be converted to type %1">; +def err_addr_ovl_no_qualifier : Error< + "cannot form member pointer of type %0 without '&' and class name">; + +// C++11 Literal Operators +def err_ovl_no_viable_literal_operator : Error< + "no matching literal operator for call to %0" + "%select{| with argument of type %2| with arguments of types %2 and %3}1" + "%select{| or 'const char *'}4" + "%select{|, and no matching literal operator template}5">; + +// C++ Template Declarations +def err_template_param_shadow : Error< + "declaration of %0 shadows template parameter">; +def note_template_param_here : Note<"template parameter is declared here">; +def warn_template_export_unsupported : Warning< + "exported templates are unsupported">; +def err_template_outside_namespace_or_class_scope : Error< + "templates can only be declared in namespace or class scope">; +def err_template_inside_local_class : Error< + "templates cannot be declared inside of a local class">; +def err_template_linkage : Error<"templates must have C++ linkage">; +def err_template_typedef : Error<"a typedef cannot be a template">; +def err_template_unnamed_class : Error< + "cannot declare a class template with no name">; +def err_template_param_list_different_arity : Error< + "%select{too few|too many}0 template parameters in template " + "%select{|template parameter }1redeclaration">; +def note_template_param_list_different_arity : Note< + "%select{too few|too many}0 template parameters in template template " + "argument">; +def note_template_prev_declaration : Note< + "previous template %select{declaration|template parameter}0 is here">; +def err_template_param_different_kind : Error< + "template parameter has a different kind in template " + "%select{|template parameter }0redeclaration">; +def note_template_param_different_kind : Note< + "template parameter has a different kind in template argument">; + +def err_template_nontype_parm_different_type : Error< + "template non-type parameter has a different type %0 in template " + "%select{|template parameter }1redeclaration">; + +def note_template_nontype_parm_different_type : Note< + "template non-type parameter has a different type %0 in template argument">; +def note_template_nontype_parm_prev_declaration : Note< + "previous non-type template parameter with type %0 is here">; +def err_template_nontype_parm_bad_type : Error< + "a non-type template parameter cannot have type %0">; +def err_template_param_default_arg_redefinition : Error< + "template parameter redefines default argument">; +def note_template_param_prev_default_arg : Note< + "previous default template argument defined here">; +def err_template_param_default_arg_missing : Error< + "template parameter missing a default argument">; +def ext_template_parameter_default_in_function_template : ExtWarn< + "default template arguments for a function template are a C++11 extension">, + InGroup<CXX11>; +def warn_cxx98_compat_template_parameter_default_in_function_template : Warning< + "default template arguments for a function template are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_template_parameter_default_template_member : Error< + "cannot add a default template argument to the definition of a member of a " + "class template">; +def err_template_parameter_default_friend_template : Error< + "default template argument not permitted on a friend template">; +def err_template_template_parm_no_parms : Error< + "template template parameter must have its own template parameters">; + +def ext_variable_template : ExtWarn<"variable templates are a C++14 extension">, + InGroup<CXX14>; +def warn_cxx11_compat_variable_template : Warning< + "variable templates are incompatible with C++ standards before C++14">, + InGroup<CXXPre14Compat>, DefaultIgnore; +def err_template_variable_noparams : Error< + "extraneous 'template<>' in declaration of variable %0">; +def err_template_member : Error<"member %0 declared as a template">; +def err_template_member_noparams : Error< + "extraneous 'template<>' in declaration of member %0">; +def err_template_tag_noparams : Error< + "extraneous 'template<>' in declaration of %0 %1">; +def err_template_decl_ref : Error< + "cannot refer to %select{class|variable}0 template %1 without a template argument list">; + +// C++ Template Argument Lists +def err_template_missing_args : Error< + "use of class template %0 requires template arguments">; +def err_template_arg_list_different_arity : Error< + "%select{too few|too many}0 template arguments for " + "%select{class template|function template|template template parameter" + "|template}1 %2">; +def note_template_decl_here : Note<"template is declared here">; +def err_template_arg_must_be_type : Error< + "template argument for template type parameter must be a type">; +def err_template_arg_must_be_type_suggest : Error< + "template argument for template type parameter must be a type; " + "did you forget 'typename'?">; +def ext_ms_template_type_arg_missing_typename : ExtWarn< + "template argument for template type parameter must be a type; " + "omitted 'typename' is a Microsoft extension">, + InGroup<MicrosoftTemplate>; +def err_template_arg_must_be_expr : Error< + "template argument for non-type template parameter must be an expression">; +def err_template_arg_nontype_ambig : Error< + "template argument for non-type template parameter is treated as function type %0">; +def err_template_arg_must_be_template : Error< + "template argument for template template parameter must be a class template%select{| or type alias template}0">; +def ext_template_arg_local_type : ExtWarn< + "template argument uses local type %0">, InGroup<LocalTypeTemplateArgs>; +def ext_template_arg_unnamed_type : ExtWarn< + "template argument uses unnamed type">, InGroup<UnnamedTypeTemplateArgs>; +def warn_cxx98_compat_template_arg_local_type : Warning< + "local type %0 as template argument is incompatible with C++98">, + InGroup<CXX98CompatLocalTypeTemplateArgs>, DefaultIgnore; +def warn_cxx98_compat_template_arg_unnamed_type : Warning< + "unnamed type as template argument is incompatible with C++98">, + InGroup<CXX98CompatUnnamedTypeTemplateArgs>, DefaultIgnore; +def note_template_unnamed_type_here : Note< + "unnamed type used in template argument was declared here">; +def err_template_arg_overload_type : Error< + "template argument is the type of an unresolved overloaded function">; +def err_template_arg_not_class_template : Error< + "template argument does not refer to a class template or template " + "template parameter">; +def note_template_arg_refers_here_func : Note< + "template argument refers to function template %0, here">; +def err_template_arg_template_params_mismatch : Error< + "template template argument has different template parameters than its " + "corresponding template template parameter">; +def err_template_arg_not_integral_or_enumeral : Error< + "non-type template argument of type %0 must have an integral or enumeration" + " type">; +def err_template_arg_not_ice : Error< + "non-type template argument of type %0 is not an integral constant " + "expression">; +def err_template_arg_not_address_constant : Error< + "non-type template argument of type %0 is not a constant expression">; +def warn_cxx98_compat_template_arg_null : Warning< + "use of null pointer as non-type template argument is incompatible with " + "C++98">, InGroup<CXX98Compat>, DefaultIgnore; +def err_template_arg_untyped_null_constant : Error< + "null non-type template argument must be cast to template parameter type %0">; +def err_template_arg_wrongtype_null_constant : Error< + "null non-type template argument of type %0 does not match template parameter " + "of type %1">; +def err_deduced_non_type_template_arg_type_mismatch : Error< + "deduced non-type template argument does not have the same type as the " + "its corresponding template parameter%diff{ ($ vs $)|}0,1">; +def err_non_type_template_arg_subobject : Error< + "non-type template argument refers to subobject '%0'">; +def err_non_type_template_arg_addr_label_diff : Error< + "template argument / label address difference / what did you expect?">; +def err_template_arg_not_convertible : Error< + "non-type template argument of type %0 cannot be converted to a value " + "of type %1">; +def warn_template_arg_negative : Warning< + "non-type template argument with value '%0' converted to '%1' for unsigned " + "template parameter of type %2">, InGroup<Conversion>, DefaultIgnore; +def warn_template_arg_too_large : Warning< + "non-type template argument value '%0' truncated to '%1' for " + "template parameter of type %2">, InGroup<Conversion>, DefaultIgnore; +def err_template_arg_no_ref_bind : Error< + "non-type template parameter of reference type " + "%diff{$ cannot bind to template argument of type $" + "|cannot bind to template of incompatible argument type}0,1">; +def err_template_arg_ref_bind_ignores_quals : Error< + "reference binding of non-type template parameter " + "%diff{of type $ to template argument of type $|to template argument}0,1 " + "ignores qualifiers">; +def err_template_arg_not_decl_ref : Error< + "non-type template argument does not refer to any declaration">; +def err_template_arg_not_address_of : Error< + "non-type template argument for template parameter of pointer type %0 must " + "have its address taken">; +def err_template_arg_address_of_non_pointer : Error< + "address taken in non-type template argument for template parameter of " + "reference type %0">; +def err_template_arg_reference_var : Error< + "non-type template argument of reference type %0 is not an object">; +def err_template_arg_field : Error< + "non-type template argument refers to non-static data member %0">; +def err_template_arg_method : Error< + "non-type template argument refers to non-static member function %0">; +def err_template_arg_object_no_linkage : Error< + "non-type template argument refers to %select{function|object}0 %1 that " + "does not have linkage">; +def warn_cxx98_compat_template_arg_object_internal : Warning< + "non-type template argument referring to %select{function|object}0 %1 with " + "internal linkage is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def ext_template_arg_object_internal : ExtWarn< + "non-type template argument referring to %select{function|object}0 %1 with " + "internal linkage is a C++11 extension">, InGroup<CXX11>; +def err_template_arg_thread_local : Error< + "non-type template argument refers to thread-local object">; +def note_template_arg_internal_object : Note< + "non-type template argument refers to %select{function|object}0 here">; +def note_template_arg_refers_here : Note< + "non-type template argument refers here">; +def err_template_arg_not_object_or_func : Error< + "non-type template argument does not refer to an object or function">; +def err_template_arg_not_pointer_to_member_form : Error< + "non-type template argument is not a pointer to member constant">; +def err_template_arg_member_ptr_base_derived_not_supported : Error< + "sorry, non-type template argument of pointer-to-member type %1 that refers " + "to member %q0 of a different class is not supported yet">; +def ext_template_arg_extra_parens : ExtWarn< + "address non-type template argument cannot be surrounded by parentheses">; +def warn_cxx98_compat_template_arg_extra_parens : Warning< + "redundant parentheses surrounding address non-type template argument are " + "incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; +def err_pointer_to_member_type : Error< + "invalid use of pointer to member type after %select{.*|->*}0">; +def err_pointer_to_member_call_drops_quals : Error< + "call to pointer to member function of type %0 drops '%1' qualifier%s2">; +def err_pointer_to_member_oper_value_classify: Error< + "pointer-to-member function type %0 can only be called on an " + "%select{rvalue|lvalue}1">; +def ext_ms_deref_template_argument: ExtWarn< + "non-type template argument containing a dereference operation is a " + "Microsoft extension">, InGroup<MicrosoftTemplate>; +def ext_ms_delayed_template_argument: ExtWarn< + "using the undeclared type %0 as a default template argument is a " + "Microsoft extension">, InGroup<MicrosoftTemplate>; + +// C++ template specialization +def err_template_spec_unknown_kind : Error< + "can only provide an explicit specialization for a class template, function " + "template, variable template, or a member function, static data member, " + "%select{or member class|member class, or member enumeration}0 of a " + "class template">; +def note_specialized_entity : Note< + "explicitly specialized declaration is here">; +def err_template_spec_decl_function_scope : Error< + "explicit specialization of %0 in function scope">; +def err_template_spec_decl_class_scope : Error< + "explicit specialization of %0 in class scope">; +def err_template_spec_decl_friend : Error< + "cannot declare an explicit specialization in a friend">; +def err_template_spec_decl_out_of_scope_global : Error< + "%select{class template|class template partial|variable template|" + "variable template partial|function template|member function|" + "static data member|member class|member enumeration}0 " + "specialization of %1 must originally be declared in the global scope">; +def err_template_spec_decl_out_of_scope : Error< + "%select{class template|class template partial|variable template|" + "variable template partial|function template|member " + "function|static data member|member class|member enumeration}0 " + "specialization of %1 must originally be declared in namespace %2">; +def ext_template_spec_decl_out_of_scope : ExtWarn< + "first declaration of %select{class template|class template partial|" + "variable template|variable template partial|" + "function template|member function|static data member|member class|" + "member enumeration}0 specialization of %1 outside namespace %2 is a " + "C++11 extension">, InGroup<CXX11>; +def warn_cxx98_compat_template_spec_decl_out_of_scope : Warning< + "%select{class template|class template partial|variable template|" + "variable template partial|function template|member " + "function|static data member|member class|member enumeration}0 " + "specialization of %1 outside namespace %2 is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_template_spec_redecl_out_of_scope : Error< + "%select{class template|class template partial|variable template|" + "variable template partial|function template|member " + "function|static data member|member class|member enumeration}0 " + "specialization of %1 not in a namespace enclosing %2">; +def ext_ms_template_spec_redecl_out_of_scope: ExtWarn< + "%select{class template|class template partial|variable template|" + "variable template partial|function template|member " + "function|static data member|member class|member enumeration}0 " + "specialization of %1 outside namespace enclosing %2 " + "is a Microsoft extension">, InGroup<MicrosoftTemplate>; +def err_template_spec_redecl_global_scope : Error< + "%select{class template|class template partial|variable template|" + "variable template partial|function template|member " + "function|static data member|member class|member enumeration}0 " + "specialization of %1 must occur at global scope">; +def err_spec_member_not_instantiated : Error< + "specialization of member %q0 does not specialize an instantiated member">; +def note_specialized_decl : Note<"attempt to specialize declaration here">; +def err_specialization_after_instantiation : Error< + "explicit specialization of %0 after instantiation">; +def note_instantiation_required_here : Note< + "%select{implicit|explicit}0 instantiation first required here">; +def err_template_spec_friend : Error< + "template specialization declaration cannot be a friend">; +def err_template_spec_default_arg : Error< + "default argument not permitted on an explicit " + "%select{instantiation|specialization}0 of function %1">; +def err_not_class_template_specialization : Error< + "cannot specialize a %select{dependent template|template template " + "parameter}0">; +def err_function_specialization_in_class : Error< + "cannot specialize a function %0 within class scope">; +def ext_function_specialization_in_class : ExtWarn< + "explicit specialization of %0 within class scope is a Microsoft extension">, + InGroup<MicrosoftTemplate>; +def ext_explicit_specialization_storage_class : ExtWarn< + "explicit specialization cannot have a storage class">; +def err_explicit_specialization_inconsistent_storage_class : Error< + "explicit specialization has extraneous, inconsistent storage class " + "'%select{none|extern|static|__private_extern__|auto|register}0'">; + +// C++ class template specializations and out-of-line definitions +def err_template_spec_needs_header : Error< + "template specialization requires 'template<>'">; +def err_template_spec_needs_template_parameters : Error< + "template specialization or definition requires a template parameter list " + "corresponding to the nested type %0">; +def err_template_param_list_matches_nontemplate : Error< + "template parameter list matching the non-templated nested type %0 should " + "be empty ('template<>')">; +def err_alias_template_extra_headers : Error< + "extraneous template parameter list in alias template declaration">; +def err_template_spec_extra_headers : Error< + "extraneous template parameter list in template specialization or " + "out-of-line template definition">; +def warn_template_spec_extra_headers : Warning< + "extraneous template parameter list in template specialization">; +def note_explicit_template_spec_does_not_need_header : Note< + "'template<>' header not required for explicitly-specialized class %0 " + "declared here">; +def err_template_qualified_declarator_no_match : Error< + "nested name specifier '%0' for declaration does not refer into a class, " + "class template or class template partial specialization">; +def err_specialize_member_of_template : Error< + "cannot specialize %select{|(with 'template<>') }0a member of an " + "unspecialized template">; + +// C++ Class Template Partial Specialization +def err_default_arg_in_partial_spec : Error< + "default template argument in a class template partial specialization">; +def err_dependent_non_type_arg_in_partial_spec : Error< + "non-type template argument depends on a template parameter of the " + "partial specialization">; +def note_dependent_non_type_default_arg_in_partial_spec : Note< + "template parameter is used in default argument declared here">; +def err_dependent_typed_non_type_arg_in_partial_spec : Error< + "non-type template argument specializes a template parameter with " + "dependent type %0">; +def err_partial_spec_args_match_primary_template : Error< + "%select{class|variable}0 template partial specialization does not " + "specialize any template argument; to %select{declare|define}1 the " + "primary template, remove the template argument list">; +def warn_partial_specs_not_deducible : Warning< + "%select{class|variable}0 template partial specialization contains " + "%select{a template parameter|template parameters}1 that cannot be " + "deduced; this partial specialization will never be used">; +def note_partial_spec_unused_parameter : Note< + "non-deducible template parameter %0">; +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">; +def err_partial_spec_fully_specialized : Error< + "partial specialization of %0 does not use any of its template parameters">; + +// C++ Variable Template Partial Specialization +def err_var_partial_spec_redeclared : Error< + "variable template partial specialization %0 cannot be redefined">; +def note_var_prev_partial_spec_here : Note< + "previous declaration of variable template partial specialization is here">; +def err_var_spec_no_template : Error< + "no variable template matches%select{| partial}0 specialization">; +def err_var_spec_no_template_but_method : Error< + "no variable template matches specialization; " + "did you mean to use %0 as function template instead?">; + +// C++ Function template specializations +def err_function_template_spec_no_match : Error< + "no function template matches function template specialization %0">; +def err_function_template_spec_ambiguous : Error< + "function template specialization %0 ambiguously refers to more than one " + "function template; explicitly specify%select{| additional}1 template " + "arguments to identify a particular function template">; +def note_function_template_spec_matched : Note< + "function template matches specialization %0">; +def err_function_template_partial_spec : Error< + "function template partial specialization is not allowed">; + +// C++ Template Instantiation +def err_template_recursion_depth_exceeded : Error< + "recursive template instantiation exceeded maximum depth of %0">, + DefaultFatal, NoSFINAE; +def note_template_recursion_depth : Note< + "use -ftemplate-depth=N to increase recursive template instantiation depth">; + +def err_template_instantiate_within_definition : Error< + "%select{implicit|explicit}0 instantiation of template %1 within its" + " own definition">; +def err_template_instantiate_undefined : Error< + "%select{implicit|explicit}0 instantiation of undefined template %1">; +def err_implicit_instantiate_member_undefined : Error< + "implicit instantiation of undefined member %0">; +def note_template_class_instantiation_was_here : Note< + "class template %0 was instantiated here">; +def note_template_class_explicit_specialization_was_here : Note< + "class template %0 was explicitly specialized here">; +def note_template_class_instantiation_here : Note< + "in instantiation of template class %0 requested here">; +def note_template_member_class_here : Note< + "in instantiation of member class %0 requested here">; +def note_template_member_function_here : Note< + "in instantiation of member function %q0 requested here">; +def note_function_template_spec_here : Note< + "in instantiation of function template specialization %q0 requested here">; +def note_template_static_data_member_def_here : Note< + "in instantiation of static data member %q0 requested here">; +def note_template_variable_def_here : Note< + "in instantiation of variable template specialization %q0 requested here">; +def note_template_enum_def_here : Note< + "in instantiation of enumeration %q0 requested here">; +def note_template_nsdmi_here : Note< + "in instantiation of default member initializer %q0 requested here">; +def note_template_type_alias_instantiation_here : Note< + "in instantiation of template type alias %0 requested here">; +def note_template_exception_spec_instantiation_here : Note< + "in instantiation of exception specification for %0 requested here">; + +def note_default_arg_instantiation_here : Note< + "in instantiation of default argument for '%0' required here">; +def note_default_function_arg_instantiation_here : Note< + "in instantiation of default function argument expression " + "for '%0' required here">; +def note_explicit_template_arg_substitution_here : Note< + "while substituting explicitly-specified template arguments into function " + "template %0 %1">; +def note_function_template_deduction_instantiation_here : Note< + "while substituting deduced template arguments into function template %0 " + "%1">; +def note_partial_spec_deduct_instantiation_here : Note< + "during template argument deduction for class template partial " + "specialization %0 %1">; +def note_prior_template_arg_substitution : Note< + "while substituting prior template arguments into %select{non-type|template}0" + " template parameter%1 %2">; +def note_template_default_arg_checking : Note< + "while checking a default template argument used here">; +def note_instantiation_contexts_suppressed : Note< + "(skipping %0 context%s0 in backtrace; use -ftemplate-backtrace-limit=0 to " + "see all)">; + +def err_field_instantiates_to_function : Error< + "data member instantiated with function type %0">; +def err_variable_instantiates_to_function : Error< + "%select{variable|static data member}0 instantiated with function type %1">; +def err_nested_name_spec_non_tag : Error< + "type %0 cannot be used prior to '::' because it has no members">; + +// C++ Explicit Instantiation +def err_explicit_instantiation_duplicate : Error< + "duplicate explicit instantiation of %0">; +def ext_explicit_instantiation_duplicate : ExtWarn< + "duplicate explicit instantiation of %0 ignored as a Microsoft extension">, + InGroup<MicrosoftTemplate>; +def note_previous_explicit_instantiation : Note< + "previous explicit instantiation is here">; +def ext_explicit_instantiation_after_specialization : Extension< + "explicit instantiation of %0 that occurs after an explicit " + "specialization will be ignored (C++11 extension)">, + InGroup<CXX11>; +def warn_cxx98_compat_explicit_instantiation_after_specialization : Warning< + "explicit instantiation of %0 that occurs after an explicit " + "specialization is incompatible with C++98">, + InGroup<CXX98CompatPedantic>, DefaultIgnore; +def note_previous_template_specialization : Note< + "previous template specialization is here">; +def err_explicit_instantiation_nontemplate_type : Error< + "explicit instantiation of non-templated type %0">; +def note_nontemplate_decl_here : Note< + "non-templated declaration is here">; +def err_explicit_instantiation_in_class : Error< + "explicit instantiation of %0 in class scope">; +def err_explicit_instantiation_out_of_scope : Error< + "explicit instantiation of %0 not in a namespace enclosing %1">; +def err_explicit_instantiation_must_be_global : Error< + "explicit instantiation of %0 must occur at global scope">; +def warn_explicit_instantiation_out_of_scope_0x : Warning< + "explicit instantiation of %0 not in a namespace enclosing %1">, + InGroup<CXX11Compat>, DefaultIgnore; +def warn_explicit_instantiation_must_be_global_0x : Warning< + "explicit instantiation of %0 must occur at global scope">, + InGroup<CXX11Compat>, DefaultIgnore; + +def err_explicit_instantiation_requires_name : Error< + "explicit instantiation declaration requires a name">; +def err_explicit_instantiation_of_typedef : Error< + "explicit instantiation of typedef %0">; +def err_explicit_instantiation_storage_class : Error< + "explicit instantiation cannot have a storage class">; +def err_explicit_instantiation_not_known : Error< + "explicit instantiation of %0 does not refer to a function template, " + "variable template, member function, member class, or static data member">; +def note_explicit_instantiation_here : Note< + "explicit instantiation refers here">; +def err_explicit_instantiation_data_member_not_instantiated : Error< + "explicit instantiation refers to static data member %q0 that is not an " + "instantiation">; +def err_explicit_instantiation_member_function_not_instantiated : Error< + "explicit instantiation refers to member function %q0 that is not an " + "instantiation">; +def err_explicit_instantiation_ambiguous : Error< + "partial ordering for explicit instantiation of %0 is ambiguous">; +def note_explicit_instantiation_candidate : Note< + "explicit instantiation candidate function template here %0">; +def err_explicit_instantiation_inline : Error< + "explicit instantiation cannot be 'inline'">; +def warn_explicit_instantiation_inline_0x : Warning< + "explicit instantiation cannot be 'inline'">, InGroup<CXX11Compat>, + DefaultIgnore; +def err_explicit_instantiation_constexpr : Error< + "explicit instantiation cannot be 'constexpr'">; +def ext_explicit_instantiation_without_qualified_id : Extension< + "qualifier in explicit instantiation of %q0 requires a template-id " + "(a typedef is not permitted)">; +def err_explicit_instantiation_without_template_id : Error< + "explicit instantiation of %q0 must specify a template argument list">; +def err_explicit_instantiation_unqualified_wrong_namespace : Error< + "explicit instantiation of %q0 must occur in namespace %1">; +def warn_explicit_instantiation_unqualified_wrong_namespace_0x : Warning< + "explicit instantiation of %q0 must occur in namespace %1">, + InGroup<CXX11Compat>, DefaultIgnore; +def err_explicit_instantiation_undefined_member : Error< + "explicit instantiation of undefined %select{member class|member function|" + "static data member}0 %1 of class template %2">; +def err_explicit_instantiation_undefined_func_template : Error< + "explicit instantiation of undefined function template %0">; +def err_explicit_instantiation_undefined_var_template : Error< + "explicit instantiation of undefined variable template %q0">; +def err_explicit_instantiation_declaration_after_definition : Error< + "explicit instantiation declaration (with 'extern') follows explicit " + "instantiation definition (without 'extern')">; +def note_explicit_instantiation_definition_here : Note< + "explicit instantiation definition is here">; +def err_invalid_var_template_spec_type : Error<"type %2 " + "of %select{explicit instantiation|explicit specialization|" + "partial specialization|redeclaration}0 of %1 does not match" + " expected type %3">; +def err_mismatched_exception_spec_explicit_instantiation : Error< + "exception specification in explicit instantiation does not match " + "instantiated one">; +def ext_mismatched_exception_spec_explicit_instantiation : ExtWarn< + err_mismatched_exception_spec_explicit_instantiation.Text>, + InGroup<MicrosoftExceptionSpec>; + +// C++ typename-specifiers +def err_typename_nested_not_found : Error<"no type named %0 in %1">; +def err_typename_nested_not_found_enable_if : Error< + "no type named 'type' in %0; 'enable_if' cannot be used to disable " + "this declaration">; +def err_typename_nested_not_type : Error< + "typename specifier refers to non-type member %0 in %1">; +def note_typename_refers_here : Note< + "referenced member %0 is declared here">; +def err_typename_missing : Error< + "missing 'typename' prior to dependent type name '%0%1'">; +def ext_typename_missing : ExtWarn< + "missing 'typename' prior to dependent type name '%0%1'">, + InGroup<DiagGroup<"typename-missing">>; +def ext_typename_outside_of_template : ExtWarn< + "'typename' occurs outside of a template">, InGroup<CXX11>; +def warn_cxx98_compat_typename_outside_of_template : Warning< + "use of 'typename' outside of a template is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_typename_refers_to_using_value_decl : Error< + "typename specifier refers to a dependent using declaration for a value " + "%0 in %1">; +def note_using_value_decl_missing_typename : Note< + "add 'typename' to treat this using declaration as a type">; + +def err_template_kw_refers_to_non_template : Error< + "%0 following the 'template' keyword does not refer to a template">; +def err_template_kw_refers_to_class_template : Error< + "'%0%1' instantiated to a class template, not a function template">; +def note_referenced_class_template : Error< + "class template declared here">; +def err_template_kw_missing : Error< + "missing 'template' keyword prior to dependent template name '%0%1'">; +def ext_template_outside_of_template : ExtWarn< + "'template' keyword outside of a template">, InGroup<CXX11>; +def warn_cxx98_compat_template_outside_of_template : Warning< + "use of 'template' keyword outside of a template is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; + +def err_non_type_template_in_nested_name_specifier : Error< + "qualified name refers into a specialization of %select{function|variable}0 " + "template %1">; +def err_template_id_not_a_type : Error< + "template name refers to non-type template %0">; +def note_template_declared_here : Note< + "%select{function template|class template|variable template" + "|type alias template|template template parameter}0 " + "%1 declared here">; +def err_alias_template_expansion_into_fixed_list : Error< + "pack expansion used as argument for non-pack parameter of alias template">; +def note_parameter_type : Note< + "parameter of type %0 is declared here">; + +// C++11 Variadic Templates +def err_template_param_pack_default_arg : Error< + "template parameter pack cannot have a default argument">; +def err_template_param_pack_must_be_last_template_parameter : Error< + "template parameter pack must be the last template parameter">; + +def err_template_parameter_pack_non_pack : Error< + "%select{template type|non-type template|template template}0 parameter" + "%select{| pack}1 conflicts with previous %select{template type|" + "non-type template|template template}0 parameter%select{ pack|}1">; +def note_template_parameter_pack_non_pack : Note< + "%select{template type|non-type template|template template}0 parameter" + "%select{| pack}1 does not match %select{template type|non-type template" + "|template template}0 parameter%select{ pack|}1 in template argument">; +def note_template_parameter_pack_here : Note< + "previous %select{template type|non-type template|template template}0 " + "parameter%select{| pack}1 declared here">; + +def err_unexpanded_parameter_pack : Error< + "%select{expression|base type|declaration type|data member type|bit-field " + "size|static assertion|fixed underlying type|enumerator value|" + "using declaration|friend declaration|qualifier|initializer|default argument|" + "non-type template parameter type|exception type|partial specialization|" + "__if_exists name|__if_not_exists name|lambda|block}0 contains" + "%plural{0: an|:}1 unexpanded parameter pack" + "%plural{0:|1: %2|2:s %2 and %3|:s %2, %3, ...}1">; + +def err_pack_expansion_without_parameter_packs : Error< + "pack expansion does not contain any unexpanded parameter packs">; +def err_pack_expansion_length_conflict : Error< + "pack expansion contains parameter packs %0 and %1 that have different " + "lengths (%2 vs. %3)">; +def err_pack_expansion_length_conflict_multilevel : Error< + "pack expansion contains parameter pack %0 that has a different " + "length (%1 vs. %2) from outer parameter packs">; +def err_pack_expansion_member_init : Error< + "pack expansion for initialization of member %0">; + +def err_function_parameter_pack_without_parameter_packs : Error< + "type %0 of function parameter pack does not contain any unexpanded " + "parameter packs">; +def err_ellipsis_in_declarator_not_parameter : Error< + "only function and template parameters can be parameter packs">; + +def err_sizeof_pack_no_pack_name : Error< + "%0 does not refer to the name of a parameter pack">; + +def err_fold_expression_packs_both_sides : Error< + "binary fold expression has unexpanded parameter packs in both operands">; +def err_fold_expression_empty : Error< + "unary fold expression has empty expansion for operator '%0' " + "with no fallback value">; +def err_fold_expression_bad_operand : Error< + "expression not permitted as operand of fold expression">; + +def err_unexpected_typedef : Error< + "unexpected type name %0: expected expression">; +def err_unexpected_namespace : Error< + "unexpected namespace name %0: expected expression">; +def err_undeclared_var_use : Error<"use of undeclared identifier %0">; +def ext_undeclared_unqual_id_with_dependent_base : ExtWarn< + "use of undeclared identifier %0; " + "unqualified lookup into dependent bases of class template %1 is a Microsoft extension">, + InGroup<MicrosoftTemplate>; +def ext_found_via_dependent_bases_lookup : ExtWarn<"use of identifier %0 " + "found via unqualified lookup into dependent bases of class templates is a " + "Microsoft extension">, InGroup<MicrosoftTemplate>; +def note_dependent_var_use : Note<"must qualify identifier to find this " + "declaration in dependent base class">; +def err_not_found_by_two_phase_lookup : Error<"call to function %0 that is neither " + "visible in the template definition nor found by argument-dependent lookup">; +def note_not_found_by_two_phase_lookup : Note<"%0 should be declared prior to the " + "call site%select{| or in %2| or in an associated namespace of one of its arguments}1">; +def err_undeclared_use : Error<"use of undeclared %0">; +def warn_partial_availability : Warning<"%0 is only available conditionally">, + InGroup<PartialAvailability>, DefaultIgnore; +def note_partial_availability_silence : Note< + "explicitly redeclare %0 to silence this warning">; +def warn_partial_message : Warning<"%0 is partial: %1">, + InGroup<PartialAvailability>, DefaultIgnore; +def warn_partial_fwdclass_message : Warning< + "%0 may be partial because the receiver type is unknown">, + InGroup<PartialAvailability>, DefaultIgnore; +def warn_deprecated : Warning<"%0 is deprecated">, + InGroup<DeprecatedDeclarations>; +def warn_property_method_deprecated : + Warning<"property access is using %0 method which is deprecated">, + InGroup<DeprecatedDeclarations>; +def warn_deprecated_message : Warning<"%0 is deprecated: %1">, + InGroup<DeprecatedDeclarations>; +def warn_deprecated_anonymous_namespace : Warning< + "'deprecated' attribute on anonymous namespace ignored">, + InGroup<IgnoredAttributes>; +def warn_deprecated_fwdclass_message : Warning< + "%0 may be deprecated because the receiver type is unknown">, + InGroup<DeprecatedDeclarations>; +def warn_deprecated_def : Warning< + "Implementing deprecated %select{method|class|category}0">, + InGroup<DeprecatedImplementations>, DefaultIgnore; +def err_unavailable : Error<"%0 is unavailable">; +def err_property_method_unavailable : + Error<"property access is using %0 method which is unavailable">; +def err_unavailable_message : Error<"%0 is unavailable: %1">; +def warn_unavailable_fwdclass_message : Warning< + "%0 may be unavailable because the receiver type is unknown">, + InGroup<UnavailableDeclarations>; +def note_availability_specified_here : Note< + "%0 has been explicitly marked " + "%select{unavailable|deleted|deprecated|partial}1 here">; +def note_implicitly_deleted : Note< + "explicitly defaulted function was implicitly deleted here">; +def note_inherited_deleted_here : Note< + "deleted constructor was inherited here">; +def note_cannot_inherit : Note< + "constructor cannot be inherited">; +def warn_not_enough_argument : Warning< + "not enough variable arguments in %0 declaration to fit a sentinel">, + InGroup<Sentinel>; +def warn_missing_sentinel : Warning < + "missing sentinel in %select{function call|method dispatch|block call}0">, + InGroup<Sentinel>; +def note_sentinel_here : Note< + "%select{function|method|block}0 has been explicitly marked sentinel here">; +def warn_missing_prototype : Warning< + "no previous prototype for function %0">, + InGroup<DiagGroup<"missing-prototypes">>, DefaultIgnore; +def note_declaration_not_a_prototype : Note< + "this declaration is not a prototype; add 'void' to make it a prototype for a zero-parameter function">; +def warn_missing_variable_declarations : Warning< + "no previous extern declaration for non-static variable %0">, + InGroup<DiagGroup<"missing-variable-declarations">>, DefaultIgnore; +def err_static_data_member_reinitialization : + Error<"static data member %0 already has an initializer">; +def err_redefinition : Error<"redefinition of %0">; +def err_alias_after_tentative : + Error<"alias definition of %0 after tentative definition">; +def err_alias_is_definition : + Error<"definition %0 cannot also be an alias">; +def err_definition_of_implicitly_declared_member : Error< + "definition of implicitly declared %select{default constructor|copy " + "constructor|move constructor|copy assignment operator|move assignment " + "operator|destructor|function}1">; +def err_definition_of_explicitly_defaulted_member : Error< + "definition of explicitly defaulted %select{default constructor|copy " + "constructor|move constructor|copy assignment operator|move assignment " + "operator|destructor}0">; +def err_redefinition_extern_inline : Error< + "redefinition of a 'extern inline' function %0 is not supported in " + "%select{C99 mode|C++}1">; + +def note_deleted_dtor_no_operator_delete : Note< + "virtual destructor requires an unambiguous, accessible 'operator delete'">; +def note_deleted_special_member_class_subobject : Note< + "%select{default constructor|copy constructor|move constructor|" + "copy assignment operator|move assignment operator|destructor}0 of " + "%1 is implicitly deleted because " + "%select{base class %3|%select{||||variant }4field %3}2 has " + "%select{no|a deleted|multiple|an inaccessible|a non-trivial}4 " + "%select{%select{default constructor|copy constructor|move constructor|copy " + "assignment operator|move assignment operator|destructor}0|destructor}5" + "%select{||s||}4">; +def note_deleted_default_ctor_uninit_field : Note< + "default constructor of %0 is implicitly deleted because field %1 of " + "%select{reference|const-qualified}3 type %2 would not be initialized">; +def note_deleted_default_ctor_all_const : Note< + "default constructor of %0 is implicitly deleted because all " + "%select{data members|data members of an anonymous union member}1" + " are const-qualified">; +def note_deleted_copy_ctor_rvalue_reference : Note< + "copy constructor of %0 is implicitly deleted because field %1 is of " + "rvalue reference type %2">; +def note_deleted_copy_user_declared_move : Note< + "copy %select{constructor|assignment operator}0 is implicitly deleted because" + " %1 has a user-declared move %select{constructor|assignment operator}2">; +def note_deleted_assign_field : Note< + "%select{copy|move}0 assignment operator of %1 is implicitly deleted " + "because field %2 is of %select{reference|const-qualified}4 type %3">; + +// These should be errors. +def warn_undefined_internal : Warning< + "%select{function|variable}0 %q1 has internal linkage but is not defined">, + InGroup<DiagGroup<"undefined-internal">>; +def warn_undefined_inline : Warning<"inline function %q0 is not defined">, + InGroup<DiagGroup<"undefined-inline">>; +def note_used_here : Note<"used here">; + +def err_internal_linkage_redeclaration : Error< + "'internal_linkage' attribute does not appear on the first declaration of %0">; +def warn_internal_linkage_local_storage : Warning< + "'internal_linkage' attribute on a non-static local variable is ignored">, + InGroup<IgnoredAttributes>; + +def ext_internal_in_extern_inline : ExtWarn< + "static %select{function|variable}0 %1 is used in an inline function with " + "external linkage">, InGroup<StaticInInline>; +def ext_internal_in_extern_inline_quiet : Extension< + "static %select{function|variable}0 %1 is used in an inline function with " + "external linkage">, InGroup<StaticInInline>; +def warn_static_local_in_extern_inline : Warning< + "non-constant static local variable in inline function may be different " + "in different files">, InGroup<StaticLocalInInline>; +def note_convert_inline_to_static : Note< + "use 'static' to give inline function %0 internal linkage">; + +def ext_redefinition_of_typedef : ExtWarn< + "redefinition of typedef %0 is a C11 feature">, + InGroup<DiagGroup<"typedef-redefinition"> >; +def err_redefinition_variably_modified_typedef : Error< + "redefinition of %select{typedef|type alias}0 for variably-modified type %1">; + +def err_inline_decl_follows_def : Error< + "inline declaration of %0 follows non-inline definition">; +def err_inline_declaration_block_scope : Error< + "inline declaration of %0 not allowed in block scope">; +def err_static_non_static : Error< + "static declaration of %0 follows non-static declaration">; +def err_different_language_linkage : Error< + "declaration of %0 has a different language linkage">; +def ext_retained_language_linkage : Extension< + "friend function %0 retaining previous language linkage is an extension">, + InGroup<DiagGroup<"retained-language-linkage">>; +def err_extern_c_global_conflict : Error< + "declaration of %1 %select{with C language linkage|in global scope}0 " + "conflicts with declaration %select{in global scope|with C language linkage}0">; +def note_extern_c_global_conflict : Note< + "declared %select{in global scope|with C language linkage}0 here">; +def warn_weak_import : Warning < + "an already-declared variable is made a weak_import declaration %0">; +def ext_static_non_static : Extension< + "redeclaring non-static %0 as static is a Microsoft extension">, + InGroup<MicrosoftRedeclareStatic>; +def err_non_static_static : Error< + "non-static declaration of %0 follows static declaration">; +def err_extern_non_extern : Error< + "extern declaration of %0 follows non-extern declaration">; +def err_non_extern_extern : Error< + "non-extern declaration of %0 follows extern declaration">; +def err_non_thread_thread : Error< + "non-thread-local declaration of %0 follows thread-local declaration">; +def err_thread_non_thread : Error< + "thread-local declaration of %0 follows non-thread-local declaration">; +def err_thread_thread_different_kind : Error< + "thread-local declaration of %0 with %select{static|dynamic}1 initialization " + "follows declaration with %select{dynamic|static}1 initialization">; +def err_redefinition_different_type : Error< + "redefinition of %0 with a different type%diff{: $ vs $|}1,2">; +def err_redefinition_different_kind : Error< + "redefinition of %0 as different kind of symbol">; +def err_redefinition_different_namespace_alias : Error< + "redefinition of %0 as an alias for a different namespace">; +def note_previous_namespace_alias : Note< + "previously defined as an alias for %0">; +def warn_forward_class_redefinition : Warning< + "redefinition of forward class %0 of a typedef name of an object type is ignored">, + InGroup<DiagGroup<"objc-forward-class-redefinition">>; +def err_redefinition_different_typedef : Error< + "%select{typedef|type alias|type alias template}0 " + "redefinition with different types%diff{ ($ vs $)|}1,2">; +def err_tag_reference_non_tag : Error< + "elaborated type refers to %select{a non-tag type|a typedef|a type alias|a template|a type alias template}0">; +def err_tag_reference_conflict : Error< + "implicit declaration introduced by elaborated type conflicts with " + "%select{a declaration|a typedef|a type alias|a template}0 of the same name">; +def err_dependent_tag_decl : Error< + "%select{declaration|definition}0 of " + "%select{struct|interface|union|class|enum}1 in a dependent scope">; +def err_tag_definition_of_typedef : Error< + "definition of type %0 conflicts with %select{typedef|type alias}1 of the same name">; +def err_conflicting_types : Error<"conflicting types for %0">; +def err_different_pass_object_size_params : Error< + "conflicting pass_object_size attributes on parameters">; +def err_late_asm_label_name : Error< + "cannot apply asm label to %select{variable|function}0 after its first use">; +def err_different_asm_label : Error<"conflicting asm label">; +def err_nested_redefinition : Error<"nested redefinition of %0">; +def err_use_with_wrong_tag : Error< + "use of %0 with tag type that does not match previous declaration">; +def warn_struct_class_tag_mismatch : Warning< + "%select{struct|interface|class}0%select{| template}1 %2 was previously " + "declared as a %select{struct|interface|class}3%select{| template}1">, + InGroup<MismatchedTags>, DefaultIgnore; +def warn_struct_class_previous_tag_mismatch : Warning< + "%2 defined as %select{a struct|an interface|a class}0%select{| template}1 " + "here but previously declared as " + "%select{a struct|an interface|a class}3%select{| template}1">, + InGroup<MismatchedTags>, DefaultIgnore; +def note_struct_class_suggestion : Note< + "did you mean %select{struct|interface|class}0 here?">; +def ext_forward_ref_enum : Extension< + "ISO C forbids forward references to 'enum' types">; +def err_forward_ref_enum : Error< + "ISO C++ forbids forward references to 'enum' types">; +def ext_ms_forward_ref_enum : Extension< + "forward references to 'enum' types are a Microsoft extension">, + InGroup<MicrosoftEnumForwardReference>; +def ext_forward_ref_enum_def : Extension< + "redeclaration of already-defined enum %0 is a GNU extension">, + InGroup<GNURedeclaredEnum>; + +def err_redefinition_of_enumerator : Error<"redefinition of enumerator %0">; +def err_duplicate_member : Error<"duplicate member %0">; +def err_misplaced_ivar : Error< + "instance variables may not be placed in %select{categories|class extension}0">; +def warn_ivars_in_interface : Warning< + "declaration of instance variables in the interface is deprecated">, + InGroup<DiagGroup<"objc-interface-ivars">>, DefaultIgnore; +def ext_enum_value_not_int : Extension< + "ISO C restricts enumerator values to range of 'int' (%0 is too " + "%select{small|large}1)">; +def ext_enum_too_large : ExtWarn< + "enumeration values exceed range of largest integer">, InGroup<EnumTooLarge>; +def ext_enumerator_increment_too_large : ExtWarn< + "incremented enumerator value %0 is not representable in the " + "largest integer type">, InGroup<EnumTooLarge>; +def warn_flag_enum_constant_out_of_range : Warning< + "enumeration value %0 is out of range of flags in enumeration type %1">, + InGroup<FlagEnum>; + +def warn_illegal_constant_array_size : Extension< + "size of static array must be an integer constant expression">; +def err_vm_decl_in_file_scope : Error< + "variably modified type declaration not allowed at file scope">; +def err_vm_decl_has_extern_linkage : Error< + "variably modified type declaration cannot have 'extern' linkage">; +def err_typecheck_field_variable_size : Error< + "fields must have a constant size: 'variable length array in structure' " + "extension will never be supported">; +def err_vm_func_decl : Error< + "function declaration cannot have variably modified type">; +def err_array_too_large : Error< + "array is too large (%0 elements)">; +def warn_array_new_too_large : Warning<"array is too large (%0 elements)">, + // FIXME PR11644: ", will throw std::bad_array_new_length at runtime" + InGroup<BadArrayNewLength>; + +// -Wpadded, -Wpacked +def warn_padded_struct_field : Warning< + "padding %select{struct|interface|class}0 %1 with %2 " + "%select{byte|bit}3%s2 to align %4">, + InGroup<Padded>, DefaultIgnore; +def warn_padded_struct_anon_field : Warning< + "padding %select{struct|interface|class}0 %1 with %2 " + "%select{byte|bit}3%s2 to align anonymous bit-field">, + InGroup<Padded>, DefaultIgnore; +def warn_padded_struct_size : Warning< + "padding size of %0 with %1 %select{byte|bit}2%s1 to alignment boundary">, + InGroup<Padded>, DefaultIgnore; +def warn_unnecessary_packed : Warning< + "packed attribute is unnecessary for %0">, InGroup<Packed>, DefaultIgnore; + +def err_typecheck_negative_array_size : Error<"array size is negative">; +def warn_typecheck_negative_array_new_size : Warning<"array size is negative">, + // FIXME PR11644: ", will throw std::bad_array_new_length at runtime" + InGroup<BadArrayNewLength>; +def warn_typecheck_function_qualifiers_ignored : Warning< + "'%0' qualifier on function type %1 has no effect">, + InGroup<IgnoredQualifiers>; +def warn_typecheck_function_qualifiers_unspecified : Warning< + "'%0' qualifier on function type %1 has unspecified behavior">; +def warn_typecheck_reference_qualifiers : Warning< + "'%0' qualifier on reference type %1 has no effect">, + InGroup<IgnoredQualifiers>; +def err_typecheck_invalid_restrict_not_pointer : Error< + "restrict requires a pointer or reference (%0 is invalid)">; +def err_typecheck_invalid_restrict_not_pointer_noarg : Error< + "restrict requires a pointer or reference">; +def err_typecheck_invalid_restrict_invalid_pointee : Error< + "pointer to function type %0 may not be 'restrict' qualified">; +def ext_typecheck_zero_array_size : Extension< + "zero size arrays are an extension">, InGroup<ZeroLengthArray>; +def err_typecheck_zero_array_size : Error< + "zero-length arrays are not permitted in C++">; +def warn_typecheck_zero_static_array_size : Warning< + "'static' has no effect on zero-length arrays">, + InGroup<ArrayBounds>; +def err_array_size_non_int : Error<"size of array has non-integer type %0">; +def err_init_element_not_constant : Error< + "initializer element is not a compile-time constant">; +def ext_aggregate_init_not_constant : Extension< + "initializer for aggregate is not a compile-time constant">, InGroup<C99>; +def err_local_cant_init : Error< + "'__local' variable cannot have an initializer">; +def err_block_extern_cant_init : Error< + "'extern' variable cannot have an initializer">; +def warn_extern_init : Warning<"'extern' variable has an initializer">, + InGroup<DiagGroup<"extern-initializer">>; +def err_variable_object_no_init : Error< + "variable-sized object may not be initialized">; +def err_excess_initializers : Error< + "excess elements in %select{array|vector|scalar|union|struct}0 initializer">; +def ext_excess_initializers : ExtWarn< + "excess elements in %select{array|vector|scalar|union|struct}0 initializer">; +def err_excess_initializers_in_char_array_initializer : Error< + "excess elements in char array initializer">; +def ext_excess_initializers_in_char_array_initializer : ExtWarn< + "excess elements in char array initializer">; +def err_initializer_string_for_char_array_too_long : Error< + "initializer-string for char array is too long">; +def ext_initializer_string_for_char_array_too_long : ExtWarn< + "initializer-string for char array is too long">; +def warn_missing_field_initializers : Warning< + "missing field %0 initializer">, + InGroup<MissingFieldInitializers>, DefaultIgnore; +def warn_braces_around_scalar_init : Warning< + "braces around scalar initializer">, InGroup<DiagGroup<"braced-scalar-init">>; +def ext_many_braces_around_scalar_init : ExtWarn< + "too many braces around scalar initializer">, + InGroup<DiagGroup<"many-braces-around-scalar-init">>; +def ext_complex_component_init : Extension< + "complex initialization specifying real and imaginary components " + "is an extension">, InGroup<DiagGroup<"complex-component-init">>; +def err_empty_scalar_initializer : Error<"scalar initializer cannot be empty">; +def warn_cxx98_compat_empty_scalar_initializer : Warning< + "scalar initialized from empty initializer list is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def warn_cxx98_compat_reference_list_init : Warning< + "reference initialized from initializer list is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def warn_cxx98_compat_initializer_list_init : Warning< + "initialization of initializer_list object is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def warn_cxx98_compat_ctor_list_init : Warning< + "constructor call from initializer list is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_illegal_initializer : Error< + "illegal initializer (only variables can be initialized)">; +def err_illegal_initializer_type : Error<"illegal initializer type %0">; +def ext_init_list_type_narrowing : ExtWarn< + "type %0 cannot be narrowed to %1 in initializer list">, + InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure; +def ext_init_list_variable_narrowing : ExtWarn< + "non-constant-expression cannot be narrowed from type %0 to %1 in " + "initializer list">, InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure; +def ext_init_list_constant_narrowing : ExtWarn< + "constant expression evaluates to %0 which cannot be narrowed to type %1">, + InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure; +def warn_init_list_type_narrowing : Warning< + "type %0 cannot be narrowed to %1 in initializer list in C++11">, + InGroup<CXX11Narrowing>, DefaultIgnore; +def warn_init_list_variable_narrowing : Warning< + "non-constant-expression cannot be narrowed from type %0 to %1 in " + "initializer list in C++11">, + InGroup<CXX11Narrowing>, DefaultIgnore; +def warn_init_list_constant_narrowing : Warning< + "constant expression evaluates to %0 which cannot be narrowed to type %1 in " + "C++11">, + InGroup<CXX11Narrowing>, DefaultIgnore; +def note_init_list_narrowing_silence : Note< + "insert an explicit cast to silence this issue">; +def err_init_objc_class : Error< + "cannot initialize Objective-C class type %0">; +def err_implicit_empty_initializer : Error< + "initializer for aggregate with no elements requires explicit braces">; +def err_bitfield_has_negative_width : Error< + "bit-field %0 has negative width (%1)">; +def err_anon_bitfield_has_negative_width : Error< + "anonymous bit-field has negative width (%0)">; +def err_bitfield_has_zero_width : Error<"named bit-field %0 has zero width">; +def err_bitfield_width_exceeds_type_width : Error< + "width of bit-field %0 (%1 bits) exceeds %select{width|size}2 " + "of its type (%3 bit%s3)">; +def err_anon_bitfield_width_exceeds_type_width : Error< + "width of anonymous bit-field (%0 bits) exceeds %select{width|size}1 " + "of its type (%2 bit%s2)">; +def err_incorrect_number_of_vector_initializers : Error< + "number of elements must be either one or match the size of the vector">; + +// Used by C++ which allows bit-fields that are wider than the type. +def warn_bitfield_width_exceeds_type_width: Warning< + "width of bit-field %0 (%1 bits) exceeds the width of its type; value will " + "be truncated to %2 bit%s2">, InGroup<BitFieldWidth>; +def warn_anon_bitfield_width_exceeds_type_width : Warning< + "width of anonymous bit-field (%0 bits) exceeds width of its type; value " + "will be truncated to %1 bit%s1">, InGroup<BitFieldWidth>; + +def warn_missing_braces : Warning< + "suggest braces around initialization of subobject">, + InGroup<MissingBraces>, DefaultIgnore; + +def err_redefinition_of_label : Error<"redefinition of label %0">; +def err_undeclared_label_use : Error<"use of undeclared label %0">; +def err_goto_ms_asm_label : Error< + "cannot jump from this goto statement to label %0 inside an inline assembly block">; +def note_goto_ms_asm_label : Note< + "inline assembly label %0 declared here">; +def warn_unused_label : Warning<"unused label %0">, + InGroup<UnusedLabel>, DefaultIgnore; + +def err_goto_into_protected_scope : Error< + "cannot jump from this goto statement to its label">; +def ext_goto_into_protected_scope : ExtWarn< + "jump from this goto statement to its label is a Microsoft extension">, + InGroup<MicrosoftGoto>; +def warn_cxx98_compat_goto_into_protected_scope : Warning< + "jump from this goto statement to its label is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_switch_into_protected_scope : Error< + "cannot jump from switch statement to this case label">; +def warn_cxx98_compat_switch_into_protected_scope : Warning< + "jump from switch statement to this case label is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_indirect_goto_without_addrlabel : Error< + "indirect goto in function with no address-of-label expressions">; +def err_indirect_goto_in_protected_scope : Error< + "cannot jump from this indirect goto statement to one of its possible targets">; +def warn_cxx98_compat_indirect_goto_in_protected_scope : Warning< + "jump from this indirect goto statement to one of its possible targets " + "is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; +def note_indirect_goto_target : Note< + "possible target of indirect goto statement">; +def note_protected_by_variable_init : Note< + "jump bypasses variable initialization">; +def note_protected_by_variable_nontriv_destructor : Note< + "jump bypasses variable with a non-trivial destructor">; +def note_protected_by_variable_non_pod : Note< + "jump bypasses initialization of non-POD variable">; +def note_protected_by_cleanup : Note< + "jump bypasses initialization of variable with __attribute__((cleanup))">; +def note_protected_by_vla_typedef : Note< + "jump bypasses initialization of VLA typedef">; +def note_protected_by_vla_type_alias : Note< + "jump bypasses initialization of VLA type alias">; +def note_protected_by_vla : Note< + "jump bypasses initialization of variable length array">; +def note_protected_by_objc_try : Note< + "jump bypasses initialization of @try block">; +def note_protected_by_objc_catch : Note< + "jump bypasses initialization of @catch block">; +def note_protected_by_objc_finally : Note< + "jump bypasses initialization of @finally block">; +def note_protected_by_objc_synchronized : Note< + "jump bypasses initialization of @synchronized block">; +def note_protected_by_objc_autoreleasepool : Note< + "jump bypasses auto release push of @autoreleasepool block">; +def note_protected_by_cxx_try : Note< + "jump bypasses initialization of try block">; +def note_protected_by_cxx_catch : Note< + "jump bypasses initialization of catch block">; +def note_protected_by_seh_try : Note< + "jump bypasses initialization of __try block">; +def note_protected_by_seh_except : Note< + "jump bypasses initialization of __except block">; +def note_protected_by_seh_finally : Note< + "jump bypasses initialization of __finally block">; +def note_protected_by___block : Note< + "jump bypasses setup of __block variable">; +def note_protected_by_objc_strong_init : Note< + "jump bypasses initialization of __strong variable">; +def note_protected_by_objc_weak_init : Note< + "jump bypasses initialization of __weak variable">; +def note_enters_block_captures_cxx_obj : Note< + "jump enters lifetime of block which captures a destructible C++ object">; +def note_enters_block_captures_strong : Note< + "jump enters lifetime of block which strongly captures a variable">; +def note_enters_block_captures_weak : Note< + "jump enters lifetime of block which weakly captures a variable">; + +def note_exits_cleanup : Note< + "jump exits scope of variable with __attribute__((cleanup))">; +def note_exits_dtor : Note< + "jump exits scope of variable with non-trivial destructor">; +def note_exits_temporary_dtor : Note< + "jump exits scope of lifetime-extended temporary with non-trivial " + "destructor">; +def note_exits___block : Note< + "jump exits scope of __block variable">; +def note_exits_objc_try : Note< + "jump exits @try block">; +def note_exits_objc_catch : Note< + "jump exits @catch block">; +def note_exits_objc_finally : Note< + "jump exits @finally block">; +def note_exits_objc_synchronized : Note< + "jump exits @synchronized block">; +def note_exits_cxx_try : Note< + "jump exits try block">; +def note_exits_cxx_catch : Note< + "jump exits catch block">; +def note_exits_seh_try : Note< + "jump exits __try block">; +def note_exits_seh_except : Note< + "jump exits __except block">; +def note_exits_seh_finally : Note< + "jump exits __finally block">; +def note_exits_objc_autoreleasepool : Note< + "jump exits autoreleasepool block">; +def note_exits_objc_strong : Note< + "jump exits scope of __strong variable">; +def note_exits_objc_weak : Note< + "jump exits scope of __weak variable">; +def note_exits_block_captures_cxx_obj : Note< + "jump exits lifetime of block which captures a destructible C++ object">; +def note_exits_block_captures_strong : Note< + "jump exits lifetime of block which strongly captures a variable">; +def note_exits_block_captures_weak : Note< + "jump exits lifetime of block which weakly captures a variable">; + +def err_func_returning_qualified_void : ExtWarn< + "function cannot return qualified void type %0">, + InGroup<DiagGroup<"qualified-void-return-type">>; +def err_func_returning_array_function : Error< + "function cannot return %select{array|function}0 type %1">; +def err_field_declared_as_function : Error<"field %0 declared as a function">; +def err_field_incomplete : Error<"field has incomplete type %0">; +def ext_variable_sized_type_in_struct : ExtWarn< + "field %0 with variable sized type %1 not at the end of a struct or class is" + " a GNU extension">, InGroup<GNUVariableSizedTypeNotAtEnd>; + +def ext_c99_flexible_array_member : Extension< + "flexible array members are a C99 feature">, InGroup<C99>; +def err_flexible_array_virtual_base : Error< + "flexible array member %0 not allowed in " + "%select{struct|interface|union|class|enum}1 which has a virtual base class">; +def err_flexible_array_empty_aggregate : Error< + "flexible array member %0 not allowed in otherwise empty " + "%select{struct|interface|union|class|enum}1">; +def err_flexible_array_has_nontrivial_dtor : Error< + "flexible array member %0 of type %1 with non-trivial destruction">; +def ext_flexible_array_in_struct : Extension< + "%0 may not be nested in a struct due to flexible array member">, + InGroup<FlexibleArrayExtensions>; +def ext_flexible_array_in_array : Extension< + "%0 may not be used as an array element due to flexible array member">, + InGroup<FlexibleArrayExtensions>; +def err_flexible_array_init : Error< + "initialization of flexible array member is not allowed">; +def ext_flexible_array_empty_aggregate_ms : Extension< + "flexible array member %0 in otherwise empty " + "%select{struct|interface|union|class|enum}1 is a Microsoft extension">, + InGroup<MicrosoftFlexibleArray>; +def err_flexible_array_union : Error< + "flexible array member %0 in a union is not allowed">; +def ext_flexible_array_union_ms : Extension< + "flexible array member %0 in a union is a Microsoft extension">, + InGroup<MicrosoftFlexibleArray>; +def ext_flexible_array_empty_aggregate_gnu : Extension< + "flexible array member %0 in otherwise empty " + "%select{struct|interface|union|class|enum}1 is a GNU extension">, + InGroup<GNUEmptyStruct>; +def ext_flexible_array_union_gnu : Extension< + "flexible array member %0 in a union is a GNU extension">, InGroup<GNUFlexibleArrayUnionMember>; + +let CategoryName = "ARC Semantic Issue" in { + +// ARC-mode diagnostics. + +let CategoryName = "ARC Weak References" in { + +def err_arc_weak_no_runtime : Error< + "cannot create __weak reference because the current deployment target " + "does not support weak references">; +def err_arc_weak_disabled : Error< + "cannot create __weak reference in file using manual reference counting">; +def err_synthesizing_arc_weak_property_disabled : Error< + "cannot synthesize weak property in file using manual reference counting">; +def err_synthesizing_arc_weak_property_no_runtime : Error< + "cannot synthesize weak property because the current deployment target " + "does not support weak references">; +def err_arc_unsupported_weak_class : Error< + "class is incompatible with __weak references">; +def err_arc_weak_unavailable_assign : Error< + "assignment of a weak-unavailable object to a __weak object">; +def err_arc_weak_unavailable_property : Error< + "synthesizing __weak instance variable of type %0, which does not " + "support weak references">; +def note_implemented_by_class : Note< + "when implemented by class %0">; +def err_arc_convesion_of_weak_unavailable : Error< + "%select{implicit conversion|cast}0 of weak-unavailable object of type %1 to" + " a __weak object of type %2">; + +} // end "ARC Weak References" category + +let CategoryName = "ARC Restrictions" in { + +def err_unavailable_in_arc : Error< + "%0 is unavailable in ARC">; +def note_arc_forbidden_type : Note< + "declaration uses type that is ill-formed in ARC">; +def note_performs_forbidden_arc_conversion : Note< + "inline function performs a conversion which is forbidden in ARC">; +def note_arc_init_returns_unrelated : Note< + "init method must return a type related to its receiver type">; +def note_arc_weak_disabled : Note< + "declaration uses __weak, but ARC is disabled">; +def note_arc_weak_no_runtime : Note<"declaration uses __weak, which " + "the current deployment target does not support">; +def note_arc_field_with_ownership : Note< + "field has non-trivial ownership qualification">; + +def err_arc_illegal_explicit_message : Error< + "ARC forbids explicit message send of %0">; +def err_arc_unused_init_message : Error< + "the result of a delegate init call must be immediately returned " + "or assigned to 'self'">; +def err_arc_mismatched_cast : Error< + "%select{implicit conversion|cast}0 of " + "%select{%2|a non-Objective-C pointer type %2|a block pointer|" + "an Objective-C pointer|an indirect pointer to an Objective-C pointer}1" + " to %3 is disallowed with ARC">; +def err_arc_nolifetime_behavior : Error< + "explicit ownership qualifier on cast result has no effect">; +def err_arc_objc_object_in_tag : Error< + "ARC forbids %select{Objective-C objects|blocks}0 in " + "%select{struct|interface|union|<<ERROR>>|enum}1">; +def err_arc_objc_property_default_assign_on_object : Error< + "ARC forbids synthesizing a property of an Objective-C object " + "with unspecified ownership or storage attribute">; +def err_arc_illegal_selector : Error< + "ARC forbids use of %0 in a @selector">; +def err_arc_illegal_method_def : Error< + "ARC forbids %select{implementation|synthesis}0 of %1">; +def warn_arc_strong_pointer_objc_pointer : Warning< + "method parameter of type %0 with no explicit ownership">, + InGroup<DiagGroup<"explicit-ownership-type">>, DefaultIgnore; + +} // end "ARC Restrictions" category + +def err_arc_lost_method_convention : Error< + "method was declared as %select{an 'alloc'|a 'copy'|an 'init'|a 'new'}0 " + "method, but its implementation doesn't match because %select{" + "its result type is not an object pointer|" + "its result type is unrelated to its receiver type}1">; +def note_arc_lost_method_convention : Note<"declaration in interface">; +def err_arc_gained_method_convention : Error< + "method implementation does not match its declaration">; +def note_arc_gained_method_convention : Note< + "declaration in interface is not in the '%select{alloc|copy|init|new}0' " + "family because %select{its result type is not an object pointer|" + "its result type is unrelated to its receiver type}1">; +def err_typecheck_arc_assign_self : Error< + "cannot assign to 'self' outside of a method in the init family">; +def err_typecheck_arc_assign_self_class_method : Error< + "cannot assign to 'self' in a class method">; +def err_typecheck_arr_assign_enumeration : Error< + "fast enumeration variables cannot be modified in ARC by default; " + "declare the variable __strong to allow this">; +def warn_arc_retained_assign : Warning< + "assigning retained object to %select{weak|unsafe_unretained}0 " + "%select{property|variable}1" + "; object will be released after assignment">, + InGroup<ARCUnsafeRetainedAssign>; +def warn_arc_retained_property_assign : Warning< + "assigning retained object to unsafe property" + "; object will be released after assignment">, + InGroup<ARCUnsafeRetainedAssign>; +def warn_arc_literal_assign : Warning< + "assigning %select{array literal|dictionary literal|numeric literal|boxed expression|<should not happen>|block literal}0" + " to a weak %select{property|variable}1" + "; object will be released after assignment">, + InGroup<ARCUnsafeRetainedAssign>; +def err_arc_new_array_without_ownership : Error< + "'new' cannot allocate an array of %0 with no explicit ownership">; +def err_arc_autoreleasing_var : Error< + "%select{__block variables|global variables|fields|instance variables}0 cannot have " + "__autoreleasing ownership">; +def err_arc_autoreleasing_capture : Error< + "cannot capture __autoreleasing variable in a " + "%select{block|lambda by copy}0">; +def err_arc_thread_ownership : Error< + "thread-local variable has non-trivial ownership: type is %0">; +def err_arc_indirect_no_ownership : Error< + "%select{pointer|reference}1 to non-const type %0 with no explicit ownership">; +def err_arc_array_param_no_ownership : Error< + "must explicitly describe intended ownership of an object array parameter">; +def err_arc_pseudo_dtor_inconstant_quals : Error< + "pseudo-destructor destroys object of type %0 with inconsistently-qualified " + "type %1">; +def err_arc_init_method_unrelated_result_type : Error< + "init methods must return a type related to the receiver type">; +def err_arc_nonlocal_writeback : Error< + "passing address of %select{non-local|non-scalar}0 object to " + "__autoreleasing parameter for write-back">; +def err_arc_method_not_found : Error< + "no known %select{instance|class}1 method for selector %0">; +def err_arc_receiver_forward_class : Error< + "receiver %0 for class message is a forward declaration">; +def err_arc_may_not_respond : Error< + "no visible @interface for %0 declares the selector %1">; +def err_arc_receiver_forward_instance : Error< + "receiver type %0 for instance message is a forward declaration">; +def warn_receiver_forward_instance : Warning< + "receiver type %0 for instance message is a forward declaration">, + InGroup<ForwardClassReceiver>, DefaultIgnore; +def err_arc_collection_forward : Error< + "collection expression type %0 is a forward declaration">; +def err_arc_multiple_method_decl : Error< + "multiple methods named %0 found with mismatched result, " + "parameter type or attributes">; +def warn_arc_lifetime_result_type : Warning< + "ARC %select{unused|__unsafe_unretained|__strong|__weak|__autoreleasing}0 " + "lifetime qualifier on return type is ignored">, + InGroup<IgnoredQualifiers>; + +let CategoryName = "ARC Retain Cycle" in { + +def warn_arc_retain_cycle : Warning< + "capturing %0 strongly in this block is likely to lead to a retain cycle">, + InGroup<ARCRetainCycles>; +def note_arc_retain_cycle_owner : Note< + "block will be retained by %select{the captured object|an object strongly " + "retained by the captured object}0">; + +} // end "ARC Retain Cycle" category + +def warn_arc_object_memaccess : Warning< + "%select{destination for|source of}0 this %1 call is a pointer to " + "ownership-qualified type %2">, InGroup<ARCNonPodMemAccess>; + +let CategoryName = "ARC and @properties" in { + +def err_arc_strong_property_ownership : Error< + "existing instance variable %1 for strong property %0 may not be " + "%select{|__unsafe_unretained||__weak}2">; +def err_arc_assign_property_ownership : Error< + "existing instance variable %1 for property %0 with %select{unsafe_unretained|assign}2 " + "attribute must be __unsafe_unretained">; +def err_arc_inconsistent_property_ownership : Error< + "%select{|unsafe_unretained|strong|weak}1 property %0 may not also be " + "declared %select{|__unsafe_unretained|__strong|__weak|__autoreleasing}2">; + +} // end "ARC and @properties" category + +def err_arc_atomic_ownership : Error< + "cannot perform atomic operation on a pointer to type %0: type has " + "non-trivial ownership">; + +let CategoryName = "ARC Casting Rules" in { + +def err_arc_bridge_cast_incompatible : Error< + "incompatible types casting %0 to %1 with a %select{__bridge|" + "__bridge_transfer|__bridge_retained}2 cast">; +def err_arc_bridge_cast_wrong_kind : Error< + "cast of %select{Objective-C|block|C}0 pointer type %1 to " + "%select{Objective-C|block|C}2 pointer type %3 cannot use %select{__bridge|" + "__bridge_transfer|__bridge_retained}4">; +def err_arc_cast_requires_bridge : Error< + "%select{cast|implicit conversion}0 of %select{Objective-C|block|C}1 " + "pointer type %2 to %select{Objective-C|block|C}3 pointer type %4 " + "requires a bridged cast">; +def note_arc_bridge : Note< + "use __bridge to convert directly (no change in ownership)">; +def note_arc_cstyle_bridge : Note< + "use __bridge with C-style cast to convert directly (no change in ownership)">; +def note_arc_bridge_transfer : Note< + "use %select{__bridge_transfer|CFBridgingRelease call}1 to transfer " + "ownership of a +1 %0 into ARC">; +def note_arc_cstyle_bridge_transfer : Note< + "use __bridge_transfer with C-style cast to transfer " + "ownership of a +1 %0 into ARC">; +def note_arc_bridge_retained : Note< + "use %select{__bridge_retained|CFBridgingRetain call}1 to make an " + "ARC object available as a +1 %0">; +def note_arc_cstyle_bridge_retained : Note< + "use __bridge_retained with C-style cast to make an " + "ARC object available as a +1 %0">; + +} // ARC Casting category + +} // ARC category name + +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 of type %1">; +def err_illegal_decl_array_incomplete_type : Error< + "array has incomplete element type %0">; +def err_illegal_message_expr_incomplete_type : Error< + "Objective-C message has incomplete result type %0">; +def err_illegal_decl_array_of_references : Error< + "'%0' declared as array of references of type %1">; +def err_decl_negative_array_size : Error< + "'%0' declared as an array with a negative size">; +def err_array_static_outside_prototype : Error< + "%0 used in array declarator outside of function prototype">; +def err_array_static_not_outermost : Error< + "%0 used in non-outermost array type derivation">; +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 of type %1">; +def err_illegal_decl_mempointer_to_reference : Error< + "'%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< + "'%0' does not point into a class">; +def err_mempointer_in_nonclass_type : Error< + "member pointer refers into non-class type %0">; +def err_reference_to_void : Error<"cannot form a reference to 'void'">; +def err_nonfunction_block_type : Error< + "block pointer to non-function type is invalid">; +def err_return_block_has_expr : Error<"void block should not return a value">; +def err_block_return_missing_expr : Error< + "non-void block should return a value">; +def err_func_def_incomplete_result : Error< + "incomplete result type %0 in function definition">; +def err_atomic_specifier_bad_type : Error< + "_Atomic cannot be applied to " + "%select{incomplete |array |function |reference |atomic |qualified |}0type " + "%1 %select{||||||which is not trivially copyable}0">; + +// Expressions. +def ext_sizeof_alignof_function_type : Extension< + "invalid application of '%select{sizeof|alignof|vec_step}0' to a " + "function type">, InGroup<PointerArith>; +def ext_sizeof_alignof_void_type : Extension< + "invalid application of '%select{sizeof|alignof|vec_step}0' to a void " + "type">, InGroup<PointerArith>; +def err_opencl_sizeof_alignof_type : Error< + "invalid application of '%select{sizeof|alignof|vec_step|__builtin_omp_required_simd_align}0' to a void type">; +def err_sizeof_alignof_incomplete_type : Error< + "invalid application of '%select{sizeof|alignof|vec_step|__builtin_omp_required_simd_align}0' to an " + "incomplete type %1">; +def err_sizeof_alignof_function_type : Error< + "invalid application of '%select{sizeof|alignof|vec_step|__builtin_omp_required_simd_align}0' to a " + "function type">; +def err_openmp_default_simd_align_expr : Error< + "invalid application of '__builtin_omp_required_simd_align' to an expression, only type is allowed">; +def err_sizeof_alignof_typeof_bitfield : Error< + "invalid application of '%select{sizeof|alignof|typeof}0' to bit-field">; +def err_alignof_member_of_incomplete_type : Error< + "invalid application of 'alignof' to a field of a class still being defined">; +def err_vecstep_non_scalar_vector_type : Error< + "'vec_step' requires built-in scalar or vector type, %0 invalid">; +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">; +def ext_offsetof_extended_field_designator : Extension< + "using extended field designator is an extension">, + InGroup<DiagGroup<"extended-offsetof">>; +def ext_offsetof_non_pod_type : ExtWarn<"offset of on non-POD type %0">, + InGroup<InvalidOffsetof>; +def ext_offsetof_non_standardlayout_type : ExtWarn< + "offset of on non-standard-layout type %0">, InGroup<InvalidOffsetof>; +def err_offsetof_bitfield : Error<"cannot compute offset of bit-field %0">; +def err_offsetof_field_of_virtual_base : Error< + "invalid application of 'offsetof' to a field of a virtual base">; +def warn_sub_ptr_zero_size_types : Warning< + "subtraction of pointers to type %0 of zero size has undefined behavior">, + InGroup<PointerArith>; + +def warn_floatingpoint_eq : Warning< + "comparing floating point with == or != is unsafe">, + InGroup<DiagGroup<"float-equal">>, DefaultIgnore; + +def warn_remainder_division_by_zero : Warning< + "%select{remainder|division}0 by zero is undefined">, + InGroup<DivZero>; +def warn_shift_lhs_negative : Warning<"shifting a negative signed value is undefined">, + InGroup<DiagGroup<"shift-negative-value">>; +def warn_shift_negative : Warning<"shift count is negative">, + InGroup<DiagGroup<"shift-count-negative">>; +def warn_shift_gt_typewidth : Warning<"shift count >= width of type">, + InGroup<DiagGroup<"shift-count-overflow">>; +def warn_shift_result_gt_typewidth : Warning< + "signed shift result (%0) requires %1 bits to represent, but %2 only has " + "%3 bits">, InGroup<DiagGroup<"shift-overflow">>; +def warn_shift_result_sets_sign_bit : Warning< + "signed shift result (%0) sets the sign bit of the shift expression's " + "type (%1) and becomes negative">, + InGroup<DiagGroup<"shift-sign-overflow">>, DefaultIgnore; + +def warn_precedence_bitwise_rel : Warning< + "%0 has lower precedence than %1; %1 will be evaluated first">, + InGroup<Parentheses>; +def note_precedence_bitwise_first : Note< + "place parentheses around the %0 expression to evaluate it first">; +def note_precedence_silence : Note< + "place parentheses around the '%0' expression to silence this warning">; + +def warn_precedence_conditional : Warning< + "operator '?:' has lower precedence than '%0'; '%0' will be evaluated first">, + InGroup<Parentheses>; +def note_precedence_conditional_first : Note< + "place parentheses around the '?:' expression to evaluate it first">; + +def warn_logical_instead_of_bitwise : Warning< + "use of logical '%0' with constant operand">, + InGroup<DiagGroup<"constant-logical-operand">>; +def note_logical_instead_of_bitwise_change_operator : Note< + "use '%0' for a bitwise operation">; +def note_logical_instead_of_bitwise_remove_constant : Note< + "remove constant to silence this warning">; + +def warn_bitwise_op_in_bitwise_op : Warning< + "'%0' within '%1'">, InGroup<BitwiseOpParentheses>; + +def warn_logical_and_in_logical_or : Warning< + "'&&' within '||'">, InGroup<LogicalOpParentheses>; + +def warn_overloaded_shift_in_comparison :Warning< + "overloaded operator %select{>>|<<}0 has higher precedence than " + "comparison operator">, + InGroup<OverloadedShiftOpParentheses>; +def note_evaluate_comparison_first :Note< + "place parentheses around comparison expression to evaluate it first">; + +def warn_addition_in_bitshift : Warning< + "operator '%0' has lower precedence than '%1'; " + "'%1' will be evaluated first">, InGroup<ShiftOpParentheses>; + +def warn_self_assignment : Warning< + "explicitly assigning value of variable of type %0 to itself">, + InGroup<SelfAssignment>, DefaultIgnore; +def warn_self_move : Warning< + "explicitly moving variable of type %0 to itself">, + InGroup<SelfMove>, DefaultIgnore; + +def warn_redundant_move_on_return : Warning< + "redundant move in return statement">, + InGroup<RedundantMove>, DefaultIgnore; +def warn_pessimizing_move_on_return : Warning< + "moving a local object in a return statement prevents copy elision">, + InGroup<PessimizingMove>, DefaultIgnore; +def warn_pessimizing_move_on_initialization : Warning< + "moving a temporary object prevents copy elision">, + InGroup<PessimizingMove>, DefaultIgnore; +def note_remove_move : Note<"remove std::move call here">; + +def warn_string_plus_int : Warning< + "adding %0 to a string does not append to the string">, + InGroup<StringPlusInt>; +def warn_string_plus_char : Warning< + "adding %0 to a string pointer does not append to the string">, + InGroup<StringPlusChar>; +def note_string_plus_scalar_silence : Note< + "use array indexing to silence this warning">; + +def warn_sizeof_array_param : Warning< + "sizeof on array function parameter will return size of %0 instead of %1">, + InGroup<SizeofArrayArgument>; + +def warn_sizeof_array_decay : Warning< + "sizeof on pointer operation will return size of %0 instead of %1">, + InGroup<SizeofArrayDecay>; + +def err_sizeof_nonfragile_interface : Error< + "application of '%select{alignof|sizeof}1' to interface %0 is " + "not supported on this architecture and platform">; +def err_atdef_nonfragile_interface : Error< + "use of @defs is not supported on this architecture and platform">; +def err_subscript_nonfragile_interface : Error< + "subscript requires size of interface %0, which is not constant for " + "this architecture and platform">; + +def err_arithmetic_nonfragile_interface : Error< + "arithmetic on pointer to interface %0, which is not a constant size for " + "this architecture and platform">; + + +def ext_subscript_non_lvalue : Extension< + "ISO C90 does not allow subscripting non-lvalue array">; +def err_typecheck_subscript_value : Error< + "subscripted value is not an array, pointer, or vector">; +def err_typecheck_subscript_not_integer : Error< + "array subscript is not an integer">; +def err_subscript_function_type : Error< + "subscript of pointer to function type %0">; +def err_subscript_incomplete_type : Error< + "subscript of pointer to incomplete type %0">; +def err_dereference_incomplete_type : Error< + "dereference of pointer to incomplete type %0">; +def ext_gnu_subscript_void_type : Extension< + "subscript of a pointer to void is a GNU extension">, InGroup<PointerArith>; +def err_typecheck_member_reference_struct_union : Error< + "member reference base type %0 is not a structure or union">; +def err_typecheck_member_reference_ivar : Error< + "%0 does not have a member named %1">; +def error_arc_weak_ivar_access : Error< + "dereferencing a __weak pointer is not allowed due to possible " + "null value caused by race condition, assign it to strong variable first">; +def err_typecheck_member_reference_arrow : Error< + "member reference type %0 is not a pointer">; +def err_typecheck_member_reference_suggestion : Error< + "member reference type %0 is %select{a|not a}1 pointer; did you mean to use '%select{->|.}1'?">; +def note_typecheck_member_reference_suggestion : Note< + "did you mean to use '.' instead?">; +def note_member_reference_arrow_from_operator_arrow : Note< + "'->' applied to return value of the operator->() declared here">; +def err_typecheck_member_reference_type : Error< + "cannot refer to type member %0 in %1 with '%select{.|->}2'">; +def err_typecheck_member_reference_unknown : Error< + "cannot refer to member %0 in %1 with '%select{.|->}2'">; +def err_member_reference_needs_call : Error< + "base of member reference is a function; perhaps you meant to call " + "it%select{| with no arguments}0?">; +def warn_subscript_is_char : Warning<"array subscript is of type 'char'">, + InGroup<CharSubscript>, DefaultIgnore; + +def err_typecheck_incomplete_tag : Error<"incomplete definition of type %0">; +def err_no_member : Error<"no member named %0 in %1">; +def err_no_member_overloaded_arrow : Error< + "no member named %0 in %1; did you mean to use '->' instead of '.'?">; + +def err_member_not_yet_instantiated : Error< + "no member %0 in %1; it has not yet been instantiated">; +def note_non_instantiated_member_here : Note< + "not-yet-instantiated member is declared here">; + +def err_enumerator_does_not_exist : Error< + "enumerator %0 does not exist in instantiation of %1">; +def note_enum_specialized_here : Note< + "enum %0 was explicitly specialized here">; + +def err_member_redeclared : Error<"class member cannot be redeclared">; +def ext_member_redeclared : ExtWarn<"class member cannot be redeclared">, + InGroup<RedeclaredClassMember>; +def err_member_redeclared_in_instantiation : Error< + "multiple overloads of %0 instantiate to the same signature %1">; +def err_member_name_of_class : Error<"member %0 has the same name as its class">; +def err_member_def_undefined_record : Error< + "out-of-line definition of %0 from class %1 without definition">; +def err_member_decl_does_not_match : Error< + "out-of-line %select{declaration|definition}2 of %0 " + "does not match any declaration in %1">; +def err_friend_decl_with_def_arg_must_be_def : Error< + "friend declaration specifying a default argument must be a definition">; +def err_friend_decl_with_def_arg_redeclared : Error< + "friend declaration specifying a default argument must be the only declaration">; +def err_friend_decl_does_not_match : Error< + "friend declaration of %0 does not match any declaration in %1">; +def err_member_decl_does_not_match_suggest : Error< + "out-of-line %select{declaration|definition}2 of %0 " + "does not match any declaration in %1; did you mean %3?">; +def err_member_def_does_not_match_ret_type : Error< + "return type of out-of-line definition of %q0 differs from " + "that in the declaration">; +def err_nonstatic_member_out_of_line : Error< + "non-static data member defined out-of-line">; +def err_qualified_typedef_declarator : Error< + "typedef declarator cannot be qualified">; +def err_qualified_param_declarator : Error< + "parameter declarator cannot be qualified">; +def ext_out_of_line_declaration : ExtWarn< + "out-of-line declaration of a member must be a definition">, + InGroup<OutOfLineDeclaration>, DefaultError; +def err_member_extra_qualification : Error< + "extra qualification on member %0">; +def warn_member_extra_qualification : Warning< + err_member_extra_qualification.Text>, InGroup<MicrosoftExtraQualification>; +def warn_namespace_member_extra_qualification : Warning< + "extra qualification on member %0">, + InGroup<DiagGroup<"extra-qualification">>; +def err_member_qualification : Error< + "non-friend class member %0 cannot have a qualified name">; +def note_member_def_close_match : Note<"member declaration nearly matches">; +def note_member_def_close_const_match : Note< + "member declaration does not match because " + "it %select{is|is not}0 const qualified">; +def note_member_def_close_param_match : Note< + "type of %ordinal0 parameter of member declaration does not match definition" + "%diff{ ($ vs $)|}1,2">; +def note_local_decl_close_match : Note<"local declaration nearly matches">; +def note_local_decl_close_param_match : Note< + "type of %ordinal0 parameter of local declaration does not match definition" + "%diff{ ($ vs $)|}1,2">; +def err_typecheck_ivar_variable_size : Error< + "instance variables must have a constant size">; +def err_ivar_reference_type : Error< + "instance variables cannot be of reference type">; +def err_typecheck_illegal_increment_decrement : Error< + "cannot %select{decrement|increment}1 value of type %0">; +def err_typecheck_expect_int : Error< + "used type %0 where integer is required">; +def err_typecheck_arithmetic_incomplete_type : Error< + "arithmetic on a pointer to an incomplete type %0">; +def err_typecheck_pointer_arith_function_type : Error< + "arithmetic on%select{ a|}0 pointer%select{|s}0 to%select{ the|}2 " + "function type%select{|s}2 %1%select{| and %3}2">; +def err_typecheck_pointer_arith_void_type : Error< + "arithmetic on%select{ a|}0 pointer%select{|s}0 to void">; +def err_typecheck_decl_incomplete_type : Error< + "variable has incomplete type %0">; +def err_typecheck_decl_incomplete_type___float128 : Error< + "support for type '__float128' is not yet implemented">; +def ext_typecheck_decl_incomplete_type : ExtWarn< + "tentative definition of variable with internal linkage has incomplete non-array type %0">, + InGroup<DiagGroup<"tentative-definition-incomplete-type">>; +def err_tentative_def_incomplete_type : Error< + "tentative definition has type %0 that is never completed">; +def warn_tentative_incomplete_array : Warning< + "tentative array definition assumed to have one element">; +def err_typecheck_incomplete_array_needs_initializer : Error< + "definition of variable with array type needs an explicit size " + "or an initializer">; +def err_array_init_not_init_list : Error< + "array initializer must be an initializer " + "list%select{| or string literal| or wide string literal}0">; +def err_array_init_narrow_string_into_wchar : Error< + "initializing wide char array with non-wide string literal">; +def err_array_init_wide_string_into_char : Error< + "initializing char array with wide string literal">; +def err_array_init_incompat_wide_string_into_wchar : Error< + "initializing wide char array with incompatible wide string literal">; +def err_array_init_different_type : Error< + "cannot initialize array %diff{of type $ with array of type $|" + "with different type of array}0,1">; +def err_array_init_non_constant_array : Error< + "cannot initialize array %diff{of type $ with non-constant array of type $|" + "with different type of array}0,1">; +def ext_array_init_copy : Extension< + "initialization of an array " + "%diff{of type $ from a compound literal of type $|" + "from a compound literal}0,1 is a GNU extension">, InGroup<GNUCompoundLiteralInitializer>; +// This is intentionally not disabled by -Wno-gnu. +def ext_array_init_parens : ExtWarn< + "parenthesized initialization of a member array is a GNU extension">, + InGroup<DiagGroup<"gnu-array-member-paren-init">>, DefaultError; +def warn_deprecated_string_literal_conversion : Warning< + "conversion from string literal to %0 is deprecated">, + InGroup<CXX11CompatDeprecatedWritableStr>; +def ext_deprecated_string_literal_conversion : ExtWarn< + "ISO C++11 does not allow conversion from string literal to %0">, + InGroup<WritableStrings>, SFINAEFailure; +def err_realimag_invalid_type : Error<"invalid type %0 to %1 operator">; +def err_typecheck_sclass_fscope : Error< + "illegal storage class on file-scoped variable">; +def warn_standalone_specifier : Warning<"'%0' ignored on this declaration">, + InGroup<MissingDeclarations>; +def ext_standalone_specifier : ExtWarn<"'%0' is not permitted on a declaration " + "of a type">, InGroup<MissingDeclarations>; +def err_standalone_class_nested_name_specifier : Error< + "forward declaration of %select{class|struct|interface|union|enum}0 cannot " + "have a nested name specifier">; +def err_typecheck_sclass_func : Error<"illegal storage class on function">; +def err_static_block_func : Error< + "function declared in block scope cannot have 'static' storage class">; +def err_typecheck_address_of : Error<"address of %select{bit-field" + "|vector element|property expression|register variable}0 requested">; +def ext_typecheck_addrof_void : Extension< + "ISO C forbids taking the address of an expression of type 'void'">; +def err_unqualified_pointer_member_function : Error< + "must explicitly qualify name of member function when taking its address">; +def err_invalid_form_pointer_member_function : Error< + "cannot create a non-constant pointer to member function">; +def err_address_of_function_with_pass_object_size_params: Error< + "cannot take address of function %0 because parameter %1 has " + "pass_object_size attribute">; +def err_parens_pointer_member_function : Error< + "cannot parenthesize the name of a method when forming a member pointer">; +def err_typecheck_invalid_lvalue_addrof_addrof_function : Error< + "extra '&' taking address of overloaded function">; +def err_typecheck_invalid_lvalue_addrof : Error< + "cannot take the address of an rvalue of type %0">; +def ext_typecheck_addrof_temporary : ExtWarn< + "taking the address of a temporary object of type %0">, + InGroup<DiagGroup<"address-of-temporary">>, DefaultError; +def err_typecheck_addrof_temporary : Error< + "taking the address of a temporary object of type %0">; +def err_typecheck_addrof_dtor : Error< + "taking the address of a destructor">; +def err_typecheck_unary_expr : Error< + "invalid argument type %0 to unary expression">; +def err_typecheck_indirection_requires_pointer : Error< + "indirection requires pointer operand (%0 invalid)">; +def ext_typecheck_indirection_through_void_pointer : ExtWarn< + "ISO C++ does not allow indirection on operand of type %0">, + InGroup<DiagGroup<"void-ptr-dereference">>; +def warn_indirection_through_null : Warning< + "indirection of non-volatile null pointer will be deleted, not trap">, InGroup<NullDereference>; +def note_indirection_through_null : Note< + "consider using __builtin_trap() or qualifying pointer with 'volatile'">; +def warn_pointer_indirection_from_incompatible_type : Warning< + "dereference of type %1 that was reinterpret_cast from type %0 has undefined " + "behavior">, + InGroup<UndefinedReinterpretCast>, DefaultIgnore; + +def err_objc_object_assignment : Error< + "cannot assign to class object (%0 invalid)">; +def err_typecheck_invalid_operands : Error< + "invalid operands to binary expression (%0 and %1)">; +def err_typecheck_sub_ptr_compatible : Error< + "%diff{$ and $ are not pointers to compatible types|" + "pointers to incompatible types}0,1">; +def ext_typecheck_ordered_comparison_of_pointer_integer : ExtWarn< + "ordered comparison between pointer and integer (%0 and %1)">; +def ext_typecheck_ordered_comparison_of_pointer_and_zero : Extension< + "ordered comparison between pointer and zero (%0 and %1) is an extension">; +def ext_typecheck_ordered_comparison_of_function_pointers : ExtWarn< + "ordered comparison of function pointers (%0 and %1)">; +def ext_typecheck_comparison_of_fptr_to_void : Extension< + "equality comparison between function pointer and void pointer (%0 and %1)">; +def err_typecheck_comparison_of_fptr_to_void : Error< + "equality comparison between function pointer and void pointer (%0 and %1)">; +def ext_typecheck_comparison_of_pointer_integer : ExtWarn< + "comparison between pointer and integer (%0 and %1)">; +def err_typecheck_comparison_of_pointer_integer : Error< + "comparison between pointer and integer (%0 and %1)">; +def ext_typecheck_comparison_of_distinct_pointers : ExtWarn< + "comparison of distinct pointer types%diff{ ($ and $)|}0,1">, + InGroup<CompareDistinctPointerType>; +def ext_typecheck_cond_incompatible_operands : ExtWarn< + "incompatible operand types (%0 and %1)">; +def err_cond_voidptr_arc : Error < + "operands to conditional of types%diff{ $ and $|}0,1 are incompatible " + "in ARC mode">; +def err_typecheck_comparison_of_distinct_pointers : Error< + "comparison of distinct pointer types%diff{ ($ and $)|}0,1">; +def ext_typecheck_comparison_of_distinct_pointers_nonstandard : ExtWarn< + "comparison of distinct pointer types (%0 and %1) uses non-standard " + "composite pointer type %2">, InGroup<CompareDistinctPointerType>; +def err_typecheck_op_on_nonoverlapping_address_space_pointers : Error< + "%select{comparison between %diff{ ($ and $)|}0,1" + "|arithmetic operation with operands of type %diff{ ($ and $)|}0,1}2" + " which are pointers to non-overlapping address spaces">; + +def err_typecheck_assign_const : Error< + "%select{" + "cannot assign to return value because function %1 returns a const value|" + "cannot assign to variable %1 with const-qualified type %2|" + "cannot assign to %select{non-|}1static data member %2 " + "with const-qualified type %3|" + "cannot assign to non-static data member within const member function %1|" + "read-only variable is not assignable}0">; + +def note_typecheck_assign_const : Note< + "%select{" + "function %1 which returns const-qualified type %2 declared here|" + "variable %1 declared const here|" + "%select{non-|}1static data member %2 declared const here|" + "member function %q1 is declared const here}0">; + +def warn_mixed_sign_comparison : Warning< + "comparison of integers of different signs: %0 and %1">, + InGroup<SignCompare>, DefaultIgnore; +def warn_lunsigned_always_true_comparison : Warning< + "comparison of unsigned%select{| enum}2 expression %0 is always %1">, + InGroup<TautologicalCompare>; +def warn_out_of_range_compare : Warning< + "comparison of %select{constant %0|true|false}1 with " + "%select{expression of type %2|boolean expression}3 is always " + "%select{false|true}4">, InGroup<TautologicalOutOfRangeCompare>; +def warn_runsigned_always_true_comparison : Warning< + "comparison of %0 unsigned%select{| enum}2 expression is always %1">, + InGroup<TautologicalCompare>; +def warn_comparison_of_mixed_enum_types : Warning< + "comparison of two values with different enumeration types" + "%diff{ ($ and $)|}0,1">, + InGroup<DiagGroup<"enum-compare">>; +def warn_null_in_arithmetic_operation : Warning< + "use of NULL in arithmetic operation">, + InGroup<NullArithmetic>; +def warn_null_in_comparison_operation : Warning< + "comparison between NULL and non-pointer " + "%select{(%1 and NULL)|(NULL and %1)}0">, + InGroup<NullArithmetic>; +def err_shift_rhs_only_vector : Error< + "requested shift is a vector of type %0 but the first operand is not a " + "vector (%1)">; + +def warn_logical_not_on_lhs_of_comparison : Warning< + "logical not is only applied to the left hand side of this comparison">, + InGroup<LogicalNotParentheses>; +def note_logical_not_fix : Note< + "add parentheses after the '!' to evaluate the comparison first">; +def note_logical_not_silence_with_parens : Note< + "add parentheses around left hand side expression to silence this warning">; + +def err_invalid_this_use : Error< + "invalid use of 'this' outside of a non-static member function">; +def err_this_static_member_func : Error< + "'this' cannot be%select{| implicitly}0 used in a static member function " + "declaration">; +def err_invalid_member_use_in_static_method : Error< + "invalid use of member %0 in static member function">; +def err_invalid_qualified_function_type : Error< + "%select{static |non-}0member function %select{of type %2 |}1" + "cannot have '%3' qualifier">; +def err_compound_qualified_function_type : Error< + "%select{block pointer|pointer|reference}0 to function type %select{%2 |}1" + "cannot have '%3' qualifier">; + +def err_ref_qualifier_overload : Error< + "cannot overload a member function %select{without a ref-qualifier|with " + "ref-qualifier '&'|with ref-qualifier '&&'}0 with a member function %select{" + "without a ref-qualifier|with ref-qualifier '&'|with ref-qualifier '&&'}1">; + +def err_invalid_non_static_member_use : Error< + "invalid use of non-static data member %0">; +def err_nested_non_static_member_use : Error< + "%select{call to non-static member function|use of non-static data member}0 " + "%2 of %1 from nested type %3">; +def warn_cxx98_compat_non_static_member_use : Warning< + "use of non-static data member %0 in an unevaluated context is " + "incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; +def err_invalid_incomplete_type_use : Error< + "invalid use of incomplete type %0">; +def err_builtin_func_cast_more_than_one_arg : Error< + "function-style cast to a builtin type can only take one argument">; +def err_value_init_for_array_type : Error< + "array types cannot be value-initialized">; +def err_value_init_for_function_type : Error< + "function types cannot be value-initialized">; +def warn_format_nonliteral_noargs : Warning< + "format string is not a string literal (potentially insecure)">, + InGroup<FormatSecurity>; +def warn_format_nonliteral : Warning< + "format string is not a string literal">, + InGroup<FormatNonLiteral>, DefaultIgnore; + +def err_unexpected_interface : Error< + "unexpected interface name %0: expected expression">; +def err_ref_non_value : Error<"%0 does not refer to a value">; +def err_ref_vm_type : Error< + "cannot refer to declaration with a variably modified type inside block">; +def err_ref_flexarray_type : Error< + "cannot refer to declaration of structure variable with flexible array member " + "inside block">; +def err_ref_array_type : Error< + "cannot refer to declaration with an array type inside block">; +def err_property_not_found : Error< + "property %0 not found on object of type %1">; +def err_invalid_property_name : Error< + "%0 is not a valid property name (accessing an object of type %1)">; +def err_getter_not_found : Error< + "no getter method for read from property">; +def err_objc_subscript_method_not_found : Error< + "expected method to %select{read|write}1 %select{dictionary|array}2 element not " + "found on object of type %0">; +def err_objc_subscript_index_type : Error< + "method index parameter type %0 is not integral type">; +def err_objc_subscript_key_type : Error< + "method key parameter type %0 is not object type">; +def err_objc_subscript_dic_object_type : Error< + "method object parameter type %0 is not object type">; +def err_objc_subscript_object_type : Error< + "cannot assign to this %select{dictionary|array}1 because assigning method's " + "2nd parameter of type %0 is not an Objective-C pointer type">; +def err_objc_subscript_base_type : Error< + "%select{dictionary|array}1 subscript base type %0 is not an Objective-C object">; +def err_objc_multiple_subscript_type_conversion : Error< + "indexing expression is invalid because subscript type %0 has " + "multiple type conversion functions">; +def err_objc_subscript_type_conversion : Error< + "indexing expression is invalid because subscript type %0 is not an integral" + " or Objective-C pointer type">; +def err_objc_subscript_pointer : Error< + "indexing expression is invalid because subscript type %0 is not an" + " Objective-C pointer">; +def err_objc_indexing_method_result_type : Error< + "method for accessing %select{dictionary|array}1 element must have Objective-C" + " object return type instead of %0">; +def err_objc_index_incomplete_class_type : Error< + "Objective-C index expression has incomplete class type %0">; +def err_illegal_container_subscripting_op : Error< + "illegal operation on Objective-C container subscripting">; +def err_property_not_found_forward_class : Error< + "property %0 cannot be found in forward class object %1">; +def err_property_not_as_forward_class : Error< + "property %0 refers to an incomplete Objective-C class %1 " + "(with no @interface available)">; +def note_forward_class : Note< + "forward declaration of class here">; +def err_duplicate_property : Error< + "property has a previous declaration">; +def ext_gnu_void_ptr : Extension< + "arithmetic on%select{ a|}0 pointer%select{|s}0 to void is a GNU extension">, + InGroup<PointerArith>; +def ext_gnu_ptr_func_arith : Extension< + "arithmetic on%select{ a|}0 pointer%select{|s}0 to%select{ the|}2 function " + "type%select{|s}2 %1%select{| and %3}2 is a GNU extension">, + InGroup<PointerArith>; +def error_readonly_message_assignment : Error< + "assigning to 'readonly' return result of an Objective-C message not allowed">; +def ext_integer_increment_complex : Extension< + "ISO C does not support '++'/'--' on complex integer type %0">; +def ext_integer_complement_complex : Extension< + "ISO C does not support '~' for complex conjugation of %0">; +def err_nosetter_property_assignment : Error< + "%select{assignment to readonly property|" + "no setter method %1 for assignment to property}0">; +def err_nosetter_property_incdec : Error< + "%select{%select{increment|decrement}1 of readonly property|" + "no setter method %2 for %select{increment|decrement}1 of property}0">; +def err_nogetter_property_compound_assignment : Error< + "a getter method is needed to perform a compound assignment on a property">; +def err_nogetter_property_incdec : Error< + "no getter method %1 for %select{increment|decrement}0 of property">; +def error_no_subobject_property_setting : Error< + "expression is not assignable">; +def err_qualified_objc_access : Error< + "%select{property|instance variable}0 access cannot be qualified with '%1'">; + +def ext_freestanding_complex : Extension< + "complex numbers are an extension in a freestanding C99 implementation">; + +// FIXME: Remove when we support imaginary. +def err_imaginary_not_supported : Error<"imaginary types are not supported">; + +// Obj-c expressions +def warn_root_inst_method_not_found : Warning< + "instance method %0 is being used on 'Class' which is not in the root class">, + InGroup<MethodAccess>; +def warn_class_method_not_found : Warning< + "class method %objcclass0 not found (return type defaults to 'id')">, + InGroup<MethodAccess>; +def warn_instance_method_on_class_found : Warning< + "instance method %0 found instead of class method %1">, + InGroup<MethodAccess>; +def warn_inst_method_not_found : Warning< + "instance method %objcinstance0 not found (return type defaults to 'id')">, + InGroup<MethodAccess>; +def warn_instance_method_not_found_with_typo : Warning< + "instance method %objcinstance0 not found (return type defaults to 'id')" + "; did you mean %objcinstance2?">, InGroup<MethodAccess>; +def warn_class_method_not_found_with_typo : Warning< + "class method %objcclass0 not found (return type defaults to 'id')" + "; did you mean %objcclass2?">, InGroup<MethodAccess>; +def error_method_not_found_with_typo : Error< + "%select{instance|class}1 method %0 not found " + "; did you mean %2?">; +def error_no_super_class_message : Error< + "no @interface declaration found in class messaging of %0">; +def error_root_class_cannot_use_super : Error< + "%0 cannot use 'super' because it is a root class">; +def err_invalid_receiver_to_message_super : Error< + "'super' is only valid in a method body">; +def err_invalid_receiver_class_message : Error< + "receiver type %0 is not an Objective-C class">; +def err_missing_open_square_message_send : Error< + "missing '[' at start of message send expression">; +def warn_bad_receiver_type : Warning< + "receiver type %0 is not 'id' or interface pointer, consider " + "casting it to 'id'">,InGroup<ObjCReceiver>; +def err_bad_receiver_type : Error<"bad receiver type %0">; +def err_incomplete_receiver_type : Error<"incomplete receiver type %0">; +def err_unknown_receiver_suggest : Error< + "unknown receiver %0; did you mean %1?">; +def error_objc_throw_expects_object : Error< + "@throw requires an Objective-C object type (%0 invalid)">; +def error_objc_synchronized_expects_object : Error< + "@synchronized requires an Objective-C object type (%0 invalid)">; +def error_rethrow_used_outside_catch : Error< + "@throw (rethrow) used outside of a @catch block">; +def err_attribute_multiple_objc_gc : Error< + "multiple garbage collection attributes specified for type">; +def err_catch_param_not_objc_type : Error< + "@catch parameter is not a pointer to an interface type">; +def err_illegal_qualifiers_on_catch_parm : Error< + "illegal qualifiers on @catch parameter">; +def err_storage_spec_on_catch_parm : Error< + "@catch parameter cannot have storage specifier '%0'">; +def warn_register_objc_catch_parm : Warning< + "'register' storage specifier on @catch parameter will be ignored">; +def err_qualified_objc_catch_parm : Error< + "@catch parameter declarator cannot be qualified">; +def warn_objc_pointer_cxx_catch_fragile : Warning< + "cannot catch an exception thrown with @throw in C++ in the non-unified " + "exception model">, InGroup<ObjCNonUnifiedException>; +def err_objc_object_catch : Error< + "cannot catch an Objective-C object by value">; +def err_incomplete_type_objc_at_encode : Error< + "'@encode' of incomplete type %0">; +def warn_objc_circular_container : Warning< + "adding '%0' to '%1' might cause circular dependency in container">, + InGroup<DiagGroup<"objc-circular-container">>; +def note_objc_circular_container_declared_here : Note<"'%0' declared here">; + +def warn_setter_getter_impl_required : Warning< + "property %0 requires method %1 to be defined - " + "use @synthesize, @dynamic or provide a method implementation " + "in this class implementation">, + InGroup<ObjCPropertyImpl>; +def warn_setter_getter_impl_required_in_category : Warning< + "property %0 requires method %1 to be defined - " + "use @dynamic or provide a method implementation in this category">, + InGroup<ObjCPropertyImpl>; +def note_parameter_named_here : Note< + "passing argument to parameter %0 here">; +def note_parameter_here : Note< + "passing argument to parameter here">; +def note_method_return_type_change : Note< + "compiler has implicitly changed method %0 return type">; + +// C++ casts +// These messages adhere to the TryCast pattern: %0 is an int specifying the +// cast type, %1 is the source type, %2 is the destination type. +def err_bad_reinterpret_cast_overload : Error< + "reinterpret_cast cannot resolve overloaded function %0 to type %1">; + +def warn_reinterpret_different_from_static : Warning< + "'reinterpret_cast' %select{from|to}3 class %0 %select{to|from}3 its " + "%select{virtual base|base at non-zero offset}2 %1 behaves differently from " + "'static_cast'">, InGroup<ReinterpretBaseClass>; +def note_reinterpret_updowncast_use_static: Note< + "use 'static_cast' to adjust the pointer correctly while " + "%select{upcasting|downcasting}0">; + +def err_bad_static_cast_overload : Error< + "address of overloaded function %0 cannot be static_cast to type %1">; + +def err_bad_cstyle_cast_overload : Error< + "address of overloaded function %0 cannot be cast to type %1">; + + +def err_bad_cxx_cast_generic : Error< + "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" + "functional-style cast}0 from %1 to %2 is not allowed">; +def err_bad_cxx_cast_unrelated_class : Error< + "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" + "functional-style cast}0 from %1 to %2, which are not related by " + "inheritance, is not allowed">; +def note_type_incomplete : Note<"%0 is incomplete">; +def err_bad_cxx_cast_rvalue : Error< + "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" + "functional-style cast}0 from rvalue to reference type %2">; +def err_bad_cxx_cast_bitfield : Error< + "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" + "functional-style cast}0 from bit-field lvalue to reference type %2">; +def err_bad_cxx_cast_qualifiers_away : Error< + "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" + "functional-style cast}0 from %1 to %2 casts away qualifiers">; +def err_bad_const_cast_dest : Error< + "%select{const_cast||||C-style cast|functional-style cast}0 to %2, " + "which is not a reference, pointer-to-object, or pointer-to-data-member">; +def ext_cast_fn_obj : Extension< + "cast between pointer-to-function and pointer-to-object is an extension">; +def ext_ms_cast_fn_obj : ExtWarn< + "static_cast between pointer-to-function and pointer-to-object is a " + "Microsoft extension">, InGroup<MicrosoftCast>; +def warn_cxx98_compat_cast_fn_obj : Warning< + "cast between pointer-to-function and pointer-to-object is incompatible with C++98">, + InGroup<CXX98CompatPedantic>, DefaultIgnore; +def err_bad_reinterpret_cast_small_int : Error< + "cast from pointer to smaller type %2 loses information">; +def err_bad_cxx_cast_vector_to_scalar_different_size : Error< + "%select{||reinterpret_cast||C-style cast|}0 from vector %1 " + "to scalar %2 of different size">; +def err_bad_cxx_cast_scalar_to_vector_different_size : Error< + "%select{||reinterpret_cast||C-style cast|}0 from scalar %1 " + "to vector %2 of different size">; +def err_bad_cxx_cast_vector_to_vector_different_size : Error< + "%select{||reinterpret_cast||C-style cast|}0 from vector %1 " + "to vector %2 of different size">; +def err_bad_lvalue_to_rvalue_cast : Error< + "cannot cast from lvalue of type %1 to rvalue reference type %2; types are " + "not compatible">; +def err_bad_static_cast_pointer_nonpointer : Error< + "cannot cast from type %1 to pointer type %2">; +def err_bad_static_cast_member_pointer_nonmp : Error< + "cannot cast from type %1 to member pointer type %2">; +def err_bad_cxx_cast_member_pointer_size : Error< + "cannot %select{||reinterpret_cast||C-style cast|}0 from member pointer " + "type %1 to member pointer type %2 of different size">; +def err_bad_reinterpret_cast_reference : Error< + "reinterpret_cast of a %0 to %1 needs its address, which is not allowed">; +def warn_undefined_reinterpret_cast : Warning< + "reinterpret_cast from %0 to %1 has undefined behavior">, + InGroup<UndefinedReinterpretCast>, DefaultIgnore; + +// These messages don't adhere to the pattern. +// FIXME: Display the path somehow better. +def err_ambiguous_base_to_derived_cast : Error< + "ambiguous cast from base %0 to derived %1:%2">; +def err_static_downcast_via_virtual : Error< + "cannot cast %0 to %1 via virtual base %2">; +def err_downcast_from_inaccessible_base : Error< + "cannot cast %select{private|protected}2 base class %1 to %0">; +def err_upcast_to_inaccessible_base : Error< + "cannot cast %0 to its %select{private|protected}2 base class %1">; +def err_bad_dynamic_cast_not_ref_or_ptr : Error< + "%0 is not a reference or pointer">; +def err_bad_dynamic_cast_not_class : Error<"%0 is not a class">; +def err_bad_dynamic_cast_incomplete : Error<"%0 is an incomplete type">; +def err_bad_dynamic_cast_not_ptr : Error<"%0 is not a pointer">; +def err_bad_dynamic_cast_not_polymorphic : Error<"%0 is not polymorphic">; + +// Other C++ expressions +def err_need_header_before_typeid : Error< + "you need to include <typeinfo> before using the 'typeid' operator">; +def err_need_header_before_ms_uuidof : Error< + "you need to include <guiddef.h> before using the '__uuidof' operator">; +def err_ms___leave_not_in___try : Error< + "'__leave' statement not in __try block">; +def err_uuidof_without_guid : Error< + "cannot call operator __uuidof on a type with no GUID">; +def err_uuidof_with_multiple_guids : Error< + "cannot call operator __uuidof on a type with multiple GUIDs">; +def err_incomplete_typeid : Error<"'typeid' of incomplete type %0">; +def err_variably_modified_typeid : Error<"'typeid' of variably modified type %0">; +def err_static_illegal_in_new : Error< + "the 'static' modifier for the array size is not legal in new expressions">; +def err_array_new_needs_size : Error< + "array size must be specified in new expressions">; +def err_bad_new_type : Error< + "cannot allocate %select{function|reference}1 type %0 with new">; +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 have dynamic size">; +def err_new_array_init_args : Error< + "array 'new' cannot have initialization arguments">; +def ext_new_paren_array_nonconst : ExtWarn< + "when type is in parentheses, array cannot have dynamic size">; +def err_placement_new_non_placement_delete : Error< + "'new' expression with placement arguments refers to non-placement " + "'operator delete'">; +def err_array_size_not_integral : Error< + "array size expression must have integral or %select{|unscoped }0" + "enumeration type, not %1">; +def err_array_size_incomplete_type : Error< + "array size expression has incomplete class type %0">; +def err_array_size_explicit_conversion : Error< + "array size expression of type %0 requires explicit conversion to type %1">; +def note_array_size_conversion : Note< + "conversion to %select{integral|enumeration}0 type %1 declared here">; +def err_array_size_ambiguous_conversion : Error< + "ambiguous conversion of array size expression of type %0 to an integral or " + "enumeration type">; +def ext_array_size_conversion : Extension< + "implicit conversion from array size expression of type %0 to " + "%select{integral|enumeration}1 type %2 is a C++11 extension">, + InGroup<CXX11>; +def warn_cxx98_compat_array_size_conversion : Warning< + "implicit conversion from array size expression of type %0 to " + "%select{integral|enumeration}1 type %2 is incompatible with C++98">, + InGroup<CXX98CompatPedantic>, DefaultIgnore; +def err_address_space_qualified_new : Error< + "'new' cannot allocate objects of type %0 in address space '%1'">; +def err_address_space_qualified_delete : Error< + "'delete' cannot delete objects of type %0 in address space '%1'">; + +def err_default_init_const : Error< + "default initialization of an object of const type %0" + "%select{| without a user-provided default constructor}1">; +def ext_default_init_const : ExtWarn< + "default initialization of an object of const type %0" + "%select{| without a user-provided default constructor}1 " + "is a Microsoft extension">, + InGroup<MicrosoftConstInit>; +def err_delete_operand : Error<"cannot delete expression of type %0">; +def ext_delete_void_ptr_operand : ExtWarn< + "cannot delete expression with pointer-to-'void' type %0">, + InGroup<DeleteIncomplete>; +def err_ambiguous_delete_operand : Error< + "ambiguous conversion of delete expression of type %0 to a pointer">; +def warn_delete_incomplete : Warning< + "deleting pointer to incomplete type %0 may cause undefined behavior">, + InGroup<DeleteIncomplete>; +def err_delete_incomplete_class_type : Error< + "deleting incomplete class type %0; no conversions to pointer type">; +def err_delete_explicit_conversion : Error< + "converting delete expression from type %0 to type %1 invokes an explicit " + "conversion function">; +def note_delete_conversion : Note<"conversion to pointer type %0">; +def warn_delete_array_type : Warning< + "'delete' applied to a pointer-to-array type %0 treated as 'delete[]'">; +def warn_mismatched_delete_new : Warning< + "'delete%select{|[]}0' applied to a pointer that was allocated with " + "'new%select{[]|}0'; did you mean 'delete%select{[]|}0'?">, + InGroup<DiagGroup<"mismatched-new-delete">>; +def note_allocated_here : Note<"allocated with 'new%select{[]|}0' here">; +def err_no_suitable_delete_member_function_found : Error< + "no suitable member %0 in %1">; +def err_ambiguous_suitable_delete_member_function_found : Error< + "multiple suitable %0 functions in %1">; +def note_member_declared_here : Note< + "member %0 declared here">; +def err_decrement_bool : Error<"cannot decrement expression of type bool">; +def warn_increment_bool : Warning< + "incrementing expression of type bool is deprecated and " + "incompatible with C++1z">, InGroup<DeprecatedIncrementBool>; +def ext_increment_bool : ExtWarn< + "ISO C++1z does not allow incrementing expression of type bool">, + DefaultError, InGroup<IncrementBool>; +def err_increment_decrement_enum : Error< + "cannot %select{decrement|increment}0 expression of enum type %1">; +def err_catch_incomplete_ptr : Error< + "cannot catch pointer to incomplete type %0">; +def err_catch_incomplete_ref : Error< + "cannot catch reference to incomplete type %0">; +def err_catch_incomplete : Error<"cannot catch incomplete type %0">; +def err_catch_rvalue_ref : Error<"cannot catch exceptions by rvalue reference">; +def err_qualified_catch_declarator : Error< + "exception declarator cannot be qualified">; +def err_early_catch_all : Error<"catch-all handler must come last">; +def err_bad_memptr_rhs : Error< + "right hand operand to %0 has non-pointer-to-member type %1">; +def err_bad_memptr_lhs : Error< + "left hand operand to %0 must be a %select{|pointer to }1class " + "compatible with the right hand operand, but is %2">; +def warn_exception_caught_by_earlier_handler : Warning< + "exception of type %0 will be caught by earlier handler">, + InGroup<Exceptions>; +def note_previous_exception_handler : Note<"for type %0">; +def err_exceptions_disabled : Error< + "cannot use '%0' with exceptions disabled">; +def err_objc_exceptions_disabled : Error< + "cannot use '%0' with Objective-C exceptions disabled">; +def err_seh_try_outside_functions : Error< + "cannot use SEH '__try' in blocks, captured regions, or Obj-C method decls">; +def err_mixing_cxx_try_seh_try : Error< + "cannot use C++ 'try' in the same function as SEH '__try'">; +def err_seh_try_unsupported : Error< + "SEH '__try' is not supported on this target">; +def note_conflicting_try_here : Note< + "conflicting %0 here">; +def warn_jump_out_of_seh_finally : Warning< + "jump out of __finally block has undefined behavior">, + InGroup<DiagGroup<"jump-seh-finally">>; +def warn_non_virtual_dtor : Warning< + "%0 has virtual functions but non-virtual destructor">, + InGroup<NonVirtualDtor>, DefaultIgnore; +def warn_delete_non_virtual_dtor : Warning< + "delete called on non-final %0 that has virtual functions " + "but non-virtual destructor">, + InGroup<DeleteNonVirtualDtor>, DefaultIgnore; +def warn_delete_abstract_non_virtual_dtor : Warning< + "delete called on %0 that is abstract but has non-virtual destructor">, + InGroup<DeleteNonVirtualDtor>; +def warn_overloaded_virtual : Warning< + "%q0 hides overloaded virtual %select{function|functions}1">, + InGroup<OverloadedVirtual>, DefaultIgnore; +def note_hidden_overloaded_virtual_declared_here : Note< + "hidden overloaded virtual function %q0 declared here" + "%select{|: different classes%diff{ ($ vs $)|}2,3" + "|: different number of parameters (%2 vs %3)" + "|: type mismatch at %ordinal2 parameter%diff{ ($ vs $)|}3,4" + "|: different return type%diff{ ($ vs $)|}2,3" + "|: different qualifiers (" + "%select{none|const|restrict|const and restrict|volatile|const and volatile|" + "volatile and restrict|const, volatile, and restrict}2 vs " + "%select{none|const|restrict|const and restrict|volatile|const and volatile|" + "volatile and restrict|const, volatile, and restrict}3)}1">; +def warn_using_directive_in_header : Warning< + "using namespace directive in global context in header">, + InGroup<HeaderHygiene>, DefaultIgnore; +def warn_overaligned_type : Warning< + "type %0 requires %1 bytes of alignment and the default allocator only " + "guarantees %2 bytes">, + InGroup<OveralignedType>, DefaultIgnore; + +def err_conditional_void_nonvoid : Error< + "%select{left|right}1 operand to ? is void, but %select{right|left}1 operand " + "is of type %0">; +def err_conditional_ambiguous : Error< + "conditional expression is ambiguous; " + "%diff{$ can be converted to $ and vice versa|" + "types can be convert to each other}0,1">; +def err_conditional_ambiguous_ovl : Error< + "conditional expression is ambiguous; %diff{$ and $|types}0,1 " + "can be converted to several common types">; +def err_conditional_vector_size : Error< + "vector condition type %0 and result type %1 do not have the same number " + "of elements">; +def err_conditional_vector_element_size : Error< + "vector condition type %0 and result type %1 do not have elements of the " + "same size">; + +def err_throw_incomplete : Error< + "cannot throw object of incomplete type %0">; +def err_throw_incomplete_ptr : Error< + "cannot throw pointer to object of incomplete type %0">; +def err_return_in_constructor_handler : Error< + "return in the catch of a function try block of a constructor is illegal">; +def warn_cdtor_function_try_handler_mem_expr : Warning< + "cannot refer to a non-static member from the handler of a " + "%select{constructor|destructor}0 function try block">, InGroup<Exceptions>; + +let CategoryName = "Lambda Issue" in { + def err_capture_more_than_once : Error< + "%0 can appear only once in a capture list">; + def err_reference_capture_with_reference_default : Error< + "'&' cannot precede a capture when the capture default is '&'">; + def err_this_capture_with_copy_default : Error< + "'this' cannot be explicitly captured when the capture default is '='">; + def err_copy_capture_with_copy_default : Error< + "'&' must precede a capture when the capture default is '='">; + def err_capture_does_not_name_variable : Error< + "%0 in capture list does not name a variable">; + def err_capture_non_automatic_variable : Error< + "%0 cannot be captured because it does not have automatic storage " + "duration">; + def err_this_capture : Error< + "'this' cannot be %select{implicitly |}0captured in this context">; + def err_lambda_capture_anonymous_var : Error< + "unnamed variable cannot be implicitly captured in a lambda expression">; + def err_lambda_capture_flexarray_type : Error< + "variable %0 with flexible array member cannot be captured in " + "a lambda expression">; + def err_lambda_impcap : Error< + "variable %0 cannot be implicitly captured in a lambda with no " + "capture-default specified">; + def note_lambda_decl : Note<"lambda expression begins here">; + def err_lambda_unevaluated_operand : Error< + "lambda expression in an unevaluated operand">; + def err_lambda_in_constant_expression : Error< + "a lambda expression may not appear inside of a constant expression">; + def err_lambda_return_init_list : Error< + "cannot deduce lambda return type from initializer list">; + def err_lambda_capture_default_arg : Error< + "lambda expression in default argument cannot capture any entity">; + def err_lambda_incomplete_result : Error< + "incomplete result type %0 in lambda expression">; + def err_noreturn_lambda_has_return_expr : Error< + "lambda declared 'noreturn' should not return">; + def warn_maybe_falloff_nonvoid_lambda : Warning< + "control may reach end of non-void lambda">, + InGroup<ReturnType>; + def warn_falloff_nonvoid_lambda : Warning< + "control reaches end of non-void lambda">, + InGroup<ReturnType>; + def err_access_lambda_capture : Error< + // The ERRORs represent other special members that aren't constructors, in + // hopes that someone will bother noticing and reporting if they appear + "capture of variable '%0' as type %1 calls %select{private|protected}3 " + "%select{default |copy |move |*ERROR* |*ERROR* |*ERROR* |}2constructor">, + AccessControl; + def note_lambda_to_block_conv : Note< + "implicit capture of lambda object due to conversion to block pointer " + "here">; + + // C++14 lambda init-captures. + def warn_cxx11_compat_init_capture : Warning< + "initialized lambda captures are incompatible with C++ standards " + "before C++14">, InGroup<CXXPre14Compat>, DefaultIgnore; + def ext_init_capture : ExtWarn< + "initialized lambda captures are a C++14 extension">, InGroup<CXX14>; + def err_init_capture_no_expression : Error< + "initializer missing for lambda capture %0">; + def err_init_capture_multiple_expressions : Error< + "initializer for lambda capture %0 contains multiple expressions">; + def err_init_capture_paren_braces : Error< + "cannot deduce type for lambda capture %1 from " + "%select{parenthesized|nested}0 initializer list">; + def err_init_capture_deduction_failure : Error< + "cannot deduce type for lambda capture %0 from initializer of type %2">; + def err_init_capture_deduction_failure_from_init_list : Error< + "cannot deduce type for lambda capture %0 from initializer list">; +} + +def err_return_in_captured_stmt : Error< + "cannot return from %0">; +def err_capture_block_variable : Error< + "__block variable %0 cannot be captured in a " + "%select{lambda expression|captured statement}1">; + +def err_operator_arrow_circular : Error< + "circular pointer delegation detected">; +def err_operator_arrow_depth_exceeded : Error< + "use of 'operator->' on type %0 would invoke a sequence of more than %1 " + "'operator->' calls">; +def note_operator_arrow_here : Note< + "'operator->' declared here produces an object of type %0">; +def note_operator_arrows_suppressed : Note< + "(skipping %0 'operator->'%s0 in backtrace)">; +def note_operator_arrow_depth : Note< + "use -foperator-arrow-depth=N to increase 'operator->' limit">; + +def err_pseudo_dtor_base_not_scalar : Error< + "object expression of non-scalar type %0 cannot be used in a " + "pseudo-destructor expression">; +def ext_pseudo_dtor_on_void : ExtWarn< + "pseudo-destructors on type void are a Microsoft extension">, + InGroup<MicrosoftVoidPseudoDtor>; +def err_pseudo_dtor_type_mismatch : Error< + "the type of object expression " + "%diff{($) does not match the type being destroyed ($)|" + "does not match the type being destroyed}0,1 " + "in pseudo-destructor expression">; +def err_pseudo_dtor_call_with_args : Error< + "call to pseudo-destructor cannot have any arguments">; +def err_dtor_expr_without_call : Error< + "reference to %select{destructor|pseudo-destructor}0 must be called" + "%select{|; did you mean to call it with no arguments?}1">; +def err_pseudo_dtor_destructor_non_type : Error< + "%0 does not refer to a type name in pseudo-destructor expression; expected " + "the name of type %1">; +def err_invalid_use_of_function_type : Error< + "a function type is not allowed here">; +def err_invalid_use_of_array_type : Error<"an array type is not allowed here">; +def err_typecheck_bool_condition : Error< + "value of type %0 is not contextually convertible to 'bool'">; +def err_typecheck_ambiguous_condition : Error< + "conversion %diff{from $ to $|between types}0,1 is ambiguous">; +def err_typecheck_nonviable_condition : Error< + "no viable conversion%select{%diff{ from $ to $|}1,2|" + "%diff{ from returned value of type $ to function return type $|}1,2}0">; +def err_typecheck_nonviable_condition_incomplete : Error< + "no viable conversion%diff{ from $ to incomplete type $|}0,1">; +def err_typecheck_deleted_function : Error< + "conversion function %diff{from $ to $|between types}0,1 " + "invokes a deleted function">; + +def err_expected_class_or_namespace : Error<"%0 is not a class" + "%select{ or namespace|, namespace, or enumeration}1">; +def err_invalid_declarator_scope : Error<"cannot define or redeclare %0 here " + "because namespace %1 does not enclose namespace %2">; +def err_invalid_declarator_global_scope : Error< + "definition or redeclaration of %0 cannot name the global scope">; +def err_invalid_declarator_in_function : Error< + "definition or redeclaration of %0 not allowed inside a function">; +def err_invalid_declarator_in_block : Error< + "definition or redeclaration of %0 not allowed inside a block">; +def err_not_tag_in_scope : Error< + "no %select{struct|interface|union|class|enum}0 named %1 in %2">; + +def err_no_typeid_with_fno_rtti : Error< + "cannot use typeid with -fno-rtti">; +def err_no_dynamic_cast_with_fno_rtti : Error< + "cannot use dynamic_cast with -fno-rtti">; + +def err_cannot_form_pointer_to_member_of_reference_type : Error< + "cannot form a pointer-to-member to member %0 of reference type %1">; +def err_incomplete_object_call : Error< + "incomplete type in call to object of type %0">; + +def warn_condition_is_assignment : Warning<"using the result of an " + "assignment as a condition without parentheses">, + InGroup<Parentheses>; +// Completely identical except off by default. +def warn_condition_is_idiomatic_assignment : Warning<"using the result " + "of an assignment as a condition without parentheses">, + InGroup<DiagGroup<"idiomatic-parentheses">>, DefaultIgnore; +def note_condition_assign_to_comparison : Note< + "use '==' to turn this assignment into an equality comparison">; +def note_condition_or_assign_to_comparison : Note< + "use '!=' to turn this compound assignment into an inequality comparison">; +def note_condition_assign_silence : Note< + "place parentheses around the assignment to silence this warning">; + +def warn_equality_with_extra_parens : Warning<"equality comparison with " + "extraneous parentheses">, InGroup<ParenthesesOnEquality>; +def note_equality_comparison_to_assign : Note< + "use '=' to turn this equality comparison into an assignment">; +def note_equality_comparison_silence : Note< + "remove extraneous parentheses around the comparison to silence this warning">; + +// assignment related diagnostics (also for argument passing, returning, etc). +// In most of these diagnostics the %2 is a value from the +// Sema::AssignmentAction enumeration +def err_typecheck_convert_incompatible : Error< + "%select{%diff{assigning to $ from incompatible type $|" + "assigning to type from incompatible type}0,1" + "|%diff{passing $ to parameter of incompatible type $|" + "passing type to parameter of incompatible type}0,1" + "|%diff{returning $ from a function with incompatible result type $|" + "returning type from a function with incompatible result type}0,1" + "|%diff{converting $ to incompatible type $|" + "converting type to incompatible type}0,1" + "|%diff{initializing $ with an expression of incompatible type $|" + "initializing type with an expression of incompatible type}0,1" + "|%diff{sending $ to parameter of incompatible type $|" + "sending type to parameter of incompatible type}0,1" + "|%diff{casting $ to incompatible type $|" + "casting type to incompatible type}0,1}2" + "%select{|; dereference with *|" + "; take the address with &|" + "; remove *|" + "; remove &}3" + "%select{|: different classes%diff{ ($ vs $)|}5,6" + "|: different number of parameters (%5 vs %6)" + "|: type mismatch at %ordinal5 parameter%diff{ ($ vs $)|}6,7" + "|: different return type%diff{ ($ vs $)|}5,6" + "|: different qualifiers (" + "%select{none|const|restrict|const and restrict|volatile|const and volatile|" + "volatile and restrict|const, volatile, and restrict}5 vs " + "%select{none|const|restrict|const and restrict|volatile|const and volatile|" + "volatile and restrict|const, volatile, and restrict}6)}4">; +def err_typecheck_missing_return_type_incompatible : Error< + "%diff{return type $ must match previous return type $|" + "return type must match previous return type}0,1 when %select{block " + "literal|lambda expression}2 has unspecified explicit return type">; + +def not_incomplete_class_and_qualified_id : Note< + "conformance of forward class %0 to protocol %1 can not be confirmed">; +def warn_incompatible_qualified_id : Warning< + "%select{%diff{assigning to $ from incompatible type $|" + "assigning to type from incompatible type}0,1" + "|%diff{passing $ to parameter of incompatible type $|" + "passing type to parameter of incompatible type}0,1" + "|%diff{returning $ from a function with incompatible result type $|" + "returning type from a function with incompatible result type}0,1" + "|%diff{converting $ to incompatible type $|" + "converting type to incompatible type}0,1" + "|%diff{initializing $ with an expression of incompatible type $|" + "initializing type with an expression of incompatible type}0,1" + "|%diff{sending $ to parameter of incompatible type $|" + "sending type to parameter of incompatible type}0,1" + "|%diff{casting $ to incompatible type $|" + "casting type to incompatible type}0,1}2">; +def ext_typecheck_convert_pointer_int : ExtWarn< + "incompatible pointer to integer conversion " + "%select{%diff{assigning to $ from $|assigning to different types}0,1" + "|%diff{passing $ to parameter of type $|" + "passing to parameter of different type}0,1" + "|%diff{returning $ from a function with result type $|" + "returning from function with different return type}0,1" + "|%diff{converting $ to type $|converting between types}0,1" + "|%diff{initializing $ with an expression of type $|" + "initializing with expression of different type}0,1" + "|%diff{sending $ to parameter of type $|" + "sending to parameter of different type}0,1" + "|%diff{casting $ to type $|casting between types}0,1}2" + "%select{|; dereference with *|" + "; take the address with &|" + "; remove *|" + "; remove &}3">, + InGroup<IntConversion>; +def ext_typecheck_convert_int_pointer : ExtWarn< + "incompatible integer to pointer conversion " + "%select{%diff{assigning to $ from $|assigning to different types}0,1" + "|%diff{passing $ to parameter of type $|" + "passing to parameter of different type}0,1" + "|%diff{returning $ from a function with result type $|" + "returning from function with different return type}0,1" + "|%diff{converting $ to type $|converting between types}0,1" + "|%diff{initializing $ with an expression of type $|" + "initializing with expression of different type}0,1" + "|%diff{sending $ to parameter of type $|" + "sending to parameter of different type}0,1" + "|%diff{casting $ to type $|casting between types}0,1}2" + "%select{|; dereference with *|" + "; take the address with &|" + "; remove *|" + "; remove &}3">, + InGroup<IntConversion>; +def ext_typecheck_convert_pointer_void_func : Extension< + "%select{%diff{assigning to $ from $|assigning to different types}0,1" + "|%diff{passing $ to parameter of type $|" + "passing to parameter of different type}0,1" + "|%diff{returning $ from a function with result type $|" + "returning from function with different return type}0,1" + "|%diff{converting $ to type $|converting between types}0,1" + "|%diff{initializing $ with an expression of type $|" + "initializing with expression of different type}0,1" + "|%diff{sending $ to parameter of type $|" + "sending to parameter of different type}0,1" + "|%diff{casting $ to type $|casting between types}0,1}2" + " converts between void pointer and function pointer">; +def ext_typecheck_convert_incompatible_pointer_sign : ExtWarn< + "%select{%diff{assigning to $ from $|assigning to different types}0,1" + "|%diff{passing $ to parameter of type $|" + "passing to parameter of different type}0,1" + "|%diff{returning $ from a function with result type $|" + "returning from function with different return type}0,1" + "|%diff{converting $ to type $|converting between types}0,1" + "|%diff{initializing $ with an expression of type $|" + "initializing with expression of different type}0,1" + "|%diff{sending $ to parameter of type $|" + "sending to parameter of different type}0,1" + "|%diff{casting $ to type $|casting between types}0,1}2" + " converts between pointers to integer types with different sign">, + InGroup<DiagGroup<"pointer-sign">>; +def ext_typecheck_convert_incompatible_pointer : ExtWarn< + "incompatible pointer types " + "%select{%diff{assigning to $ from $|assigning to different types}0,1" + "|%diff{passing $ to parameter of type $|" + "passing to parameter of different type}0,1" + "|%diff{returning $ from a function with result type $|" + "returning from function with different return type}0,1" + "|%diff{converting $ to type $|converting between types}0,1" + "|%diff{initializing $ with an expression of type $|" + "initializing with expression of different type}0,1" + "|%diff{sending $ to parameter of type $|" + "sending to parameter of different type}0,1" + "|%diff{casting $ to type $|casting between types}0,1}2" + "%select{|; dereference with *|" + "; take the address with &|" + "; remove *|" + "; remove &}3">, + InGroup<IncompatiblePointerTypes>; +def ext_typecheck_convert_discards_qualifiers : ExtWarn< + "%select{%diff{assigning to $ from $|assigning to different types}0,1" + "|%diff{passing $ to parameter of type $|" + "passing to parameter of different type}0,1" + "|%diff{returning $ from a function with result type $|" + "returning from function with different return type}0,1" + "|%diff{converting $ to type $|converting between types}0,1" + "|%diff{initializing $ with an expression of type $|" + "initializing with expression of different type}0,1" + "|%diff{sending $ to parameter of type $|" + "sending to parameter of different type}0,1" + "|%diff{casting $ to type $|casting between types}0,1}2" + " discards qualifiers">, + InGroup<IncompatiblePointerTypesDiscardsQualifiers>; +def ext_nested_pointer_qualifier_mismatch : ExtWarn< + "%select{%diff{assigning to $ from $|assigning to different types}0,1" + "|%diff{passing $ to parameter of type $|" + "passing to parameter of different type}0,1" + "|%diff{returning $ from a function with result type $|" + "returning from function with different return type}0,1" + "|%diff{converting $ to type $|converting between types}0,1" + "|%diff{initializing $ with an expression of type $|" + "initializing with expression of different type}0,1" + "|%diff{sending $ to parameter of type $|" + "sending to parameter of different type}0,1" + "|%diff{casting $ to type $|casting between types}0,1}2" + " discards qualifiers in nested pointer types">, + InGroup<IncompatiblePointerTypesDiscardsQualifiers>; +def warn_incompatible_vectors : Warning< + "incompatible vector types " + "%select{%diff{assigning to $ from $|assigning to different types}0,1" + "|%diff{passing $ to parameter of type $|" + "passing to parameter of different type}0,1" + "|%diff{returning $ from a function with result type $|" + "returning from function with different return type}0,1" + "|%diff{converting $ to type $|converting between types}0,1" + "|%diff{initializing $ with an expression of type $|" + "initializing with expression of different type}0,1" + "|%diff{sending $ to parameter of type $|" + "sending to parameter of different type}0,1" + "|%diff{casting $ to type $|casting between types}0,1}2">, + InGroup<VectorConversion>, DefaultIgnore; +def err_int_to_block_pointer : Error< + "invalid block pointer conversion " + "%select{%diff{assigning to $ from $|assigning to different types}0,1" + "|%diff{passing $ to parameter of type $|" + "passing to parameter of different type}0,1" + "|%diff{returning $ from a function with result type $|" + "returning from function with different return type}0,1" + "|%diff{converting $ to type $|converting between types}0,1" + "|%diff{initializing $ with an expression of type $|" + "initializing with expression of different type}0,1" + "|%diff{sending $ to parameter of type $|" + "sending to parameter of different type}0,1" + "|%diff{casting $ to type $|casting between types}0,1}2">; +def err_typecheck_convert_incompatible_block_pointer : Error< + "incompatible block pointer types " + "%select{%diff{assigning to $ from $|assigning to different types}0,1" + "|%diff{passing $ to parameter of type $|" + "passing to parameter of different type}0,1" + "|%diff{returning $ from a function with result type $|" + "returning from function with different return type}0,1" + "|%diff{converting $ to type $|converting between types}0,1" + "|%diff{initializing $ with an expression of type $|" + "initializing with expression of different type}0,1" + "|%diff{sending $ to parameter of type $|" + "sending to parameter of different type}0,1" + "|%diff{casting $ to type $|casting between types}0,1}2">; +def err_typecheck_incompatible_address_space : Error< + "%select{%diff{assigning $ to $|assigning to different types}1,0" + "|%diff{passing $ to parameter of type $|" + "passing to parameter of different type}0,1" + "|%diff{returning $ from a function with result type $|" + "returning from function with different return type}0,1" + "|%diff{converting $ to type $|converting between types}0,1" + "|%diff{initializing $ with an expression of type $|" + "initializing with expression of different type}0,1" + "|%diff{sending $ to parameter of type $|" + "sending to parameter of different type}0,1" + "|%diff{casting $ to type $|casting between types}0,1}2" + " changes address space of pointer">; +def err_typecheck_incompatible_ownership : Error< + "%select{%diff{assigning $ to $|assigning to different types}1,0" + "|%diff{passing $ to parameter of type $|" + "passing to parameter of different type}0,1" + "|%diff{returning $ from a function with result type $|" + "returning from function with different return type}0,1" + "|%diff{converting $ to type $|converting between types}0,1" + "|%diff{initializing $ with an expression of type $|" + "initializing with expression of different type}0,1" + "|%diff{sending $ to parameter of type $|" + "sending to parameter of different type}0,1" + "|%diff{casting $ to type $|casting between types}0,1}2" + " changes retain/release properties of pointer">; +def err_typecheck_comparison_of_distinct_blocks : Error< + "comparison of distinct block types%diff{ ($ and $)|}0,1">; + +def err_typecheck_array_not_modifiable_lvalue : Error< + "array type %0 is not assignable">; +def err_typecheck_non_object_not_modifiable_lvalue : Error< + "non-object type %0 is not assignable">; +def err_typecheck_expression_not_modifiable_lvalue : Error< + "expression is not assignable">; +def err_typecheck_incomplete_type_not_modifiable_lvalue : Error< + "incomplete type %0 is not assignable">; +def err_typecheck_lvalue_casts_not_supported : Error< + "assignment to cast is illegal, lvalue casts are not supported">; + +def err_typecheck_duplicate_vector_components_not_mlvalue : Error< + "vector is not assignable (contains duplicate components)">; +def err_block_decl_ref_not_modifiable_lvalue : Error< + "variable is not assignable (missing __block type specifier)">; +def err_lambda_decl_ref_not_modifiable_lvalue : Error< + "cannot assign to a variable captured by copy in a non-mutable lambda">; +def err_typecheck_call_not_function : Error< + "called object type %0 is not a function or function pointer">; +def err_call_incomplete_return : Error< + "calling function with incomplete return type %0">; +def err_call_function_incomplete_return : Error< + "calling %0 with incomplete return type %1">; +def err_call_incomplete_argument : Error< + "argument type %0 is incomplete">; +def err_typecheck_call_too_few_args : Error< + "too few %select{|||execution configuration }0arguments to " + "%select{function|block|method|kernel function}0 call, " + "expected %1, have %2">; +def err_typecheck_call_too_few_args_one : Error< + "too few %select{|||execution configuration }0arguments to " + "%select{function|block|method|kernel function}0 call, " + "single argument %1 was not specified">; +def err_typecheck_call_too_few_args_at_least : Error< + "too few %select{|||execution configuration }0arguments to " + "%select{function|block|method|kernel function}0 call, " + "expected at least %1, have %2">; +def err_typecheck_call_too_few_args_at_least_one : Error< + "too few %select{|||execution configuration }0arguments to " + "%select{function|block|method|kernel function}0 call, " + "at least argument %1 must be specified">; +def err_typecheck_call_too_few_args_suggest : Error< + "too few %select{|||execution configuration }0arguments to " + "%select{function|block|method|kernel function}0 call, " + "expected %1, have %2; did you mean %3?">; +def err_typecheck_call_too_few_args_at_least_suggest : Error< + "too few %select{|||execution configuration }0arguments to " + "%select{function|block|method|kernel function}0 call, " + "expected at least %1, have %2; did you mean %3?">; +def err_typecheck_call_too_many_args : Error< + "too many %select{|||execution configuration }0arguments to " + "%select{function|block|method|kernel function}0 call, " + "expected %1, have %2">; +def err_typecheck_call_too_many_args_one : Error< + "too many %select{|||execution configuration }0arguments to " + "%select{function|block|method|kernel function}0 call, " + "expected single argument %1, have %2 arguments">; +def err_typecheck_call_too_many_args_at_most : Error< + "too many %select{|||execution configuration }0arguments to " + "%select{function|block|method|kernel function}0 call, " + "expected at most %1, have %2">; +def err_typecheck_call_too_many_args_at_most_one : Error< + "too many %select{|||execution configuration }0arguments to " + "%select{function|block|method|kernel function}0 call, " + "expected at most single argument %1, have %2 arguments">; +def err_typecheck_call_too_many_args_suggest : Error< + "too many %select{|||execution configuration }0arguments to " + "%select{function|block|method|kernel function}0 call, " + "expected %1, have %2; did you mean %3?">; +def err_typecheck_call_too_many_args_at_most_suggest : Error< + "too many %select{|||execution configuration }0arguments to " + "%select{function|block|method|kernel function}0 call, " + "expected at most %1, have %2; did you mean %3?">; + +def err_arc_typecheck_convert_incompatible_pointer : Error< + "incompatible pointer types passing retainable parameter of type %0" + "to a CF function expecting %1 type">; + +def err_builtin_fn_use : Error<"builtin functions must be directly called">; + +def warn_call_wrong_number_of_arguments : Warning< + "too %select{few|many}0 arguments in call to %1">; +def err_atomic_builtin_must_be_pointer : Error< + "address argument to atomic builtin must be a pointer (%0 invalid)">; +def err_atomic_builtin_must_be_pointer_intptr : Error< + "address argument to atomic builtin must be a pointer to integer or pointer" + " (%0 invalid)">; +def err_atomic_builtin_must_be_pointer_intfltptr : Error< + "address argument to atomic builtin must be a pointer to integer," + " floating-point or pointer (%0 invalid)">; +def err_atomic_builtin_pointer_size : Error< + "address argument to atomic builtin must be a pointer to 1,2,4,8 or 16 byte " + "type (%0 invalid)">; +def err_atomic_exclusive_builtin_pointer_size : Error< + "address argument to load or store exclusive builtin must be a pointer to" + " 1,2,4 or 8 byte type (%0 invalid)">; +def err_atomic_op_needs_atomic : Error< + "address argument to atomic operation must be a pointer to _Atomic " + "type (%0 invalid)">; +def err_atomic_op_needs_non_const_atomic : Error< + "address argument to atomic operation must be a pointer to non-const _Atomic " + "type (%0 invalid)">; +def err_atomic_op_needs_non_const_pointer : Error< + "address argument to atomic operation must be a pointer to non-const " + "type (%0 invalid)">; +def err_atomic_op_needs_trivial_copy : Error< + "address argument to atomic operation must be a pointer to a " + "trivially-copyable type (%0 invalid)">; +def err_atomic_op_needs_atomic_int_or_ptr : Error< + "address argument to atomic operation must be a pointer to %select{|atomic }0" + "integer or pointer (%1 invalid)">; +def err_atomic_op_bitwise_needs_atomic_int : Error< + "address argument to bitwise atomic operation must be a pointer to " + "%select{|atomic }0integer (%1 invalid)">; +def warn_atomic_op_has_invalid_memory_order : Warning< + "memory order argument to atomic operation is invalid">, + InGroup<DiagGroup<"atomic-memory-ordering">>; + +def err_overflow_builtin_must_be_int : Error< + "operand argument to overflow builtin must be an integer (%0 invalid)">; +def err_overflow_builtin_must_be_ptr_int : Error< + "result argument to overflow builtin must be a pointer " + "to a non-const integer (%0 invalid)">; + +def err_atomic_load_store_uses_lib : Error< + "atomic %select{load|store}0 requires runtime support that is not " + "available for this target">; + +def err_nontemporal_builtin_must_be_pointer : Error< + "address argument to nontemporal builtin must be a pointer (%0 invalid)">; +def err_nontemporal_builtin_must_be_pointer_intfltptr_or_vector : Error< + "address argument to nontemporal builtin must be a pointer to integer, float, " + "pointer, or a vector of such types (%0 invalid)">; + +def err_deleted_function_use : Error<"attempt to use a deleted function">; + +def err_kern_type_not_void_return : Error< + "kernel function type %0 must have void return type">; +def err_config_scalar_return : Error< + "CUDA special function 'cudaConfigureCall' must have scalar return type">; +def err_kern_call_not_global_function : Error< + "kernel call to non-global function %0">; +def err_global_call_not_config : Error< + "call to global function %0 not configured">; +def err_ref_bad_target : Error< + "reference to %select{__device__|__global__|__host__|__host__ __device__}0 " + "function %1 in %select{__device__|__global__|__host__|__host__ __device__}2 function">; +def warn_host_calls_from_host_device : Warning< + "calling __host__ function %0 from __host__ __device__ function %1 can lead to runtime errors">, + InGroup<CudaCompat>; + +def warn_non_pod_vararg_with_format_string : Warning< + "cannot pass %select{non-POD|non-trivial}0 object of type %1 to variadic " + "%select{function|block|method|constructor}2; expected type from format " + "string was %3">, InGroup<NonPODVarargs>, DefaultError; +// The arguments to this diagnostic should match the warning above. +def err_cannot_pass_objc_interface_to_vararg_format : Error< + "cannot pass object with interface type %1 by value to variadic " + "%select{function|block|method|constructor}2; expected type from format " + "string was %3">; + +def err_cannot_pass_objc_interface_to_vararg : Error< + "cannot pass object with interface type %0 by value through variadic " + "%select{function|block|method|constructor}1">; +def warn_cannot_pass_non_pod_arg_to_vararg : Warning< + "cannot pass object of %select{non-POD|non-trivial}0 type %1 through variadic" + " %select{function|block|method|constructor}2; call will abort at runtime">, + InGroup<NonPODVarargs>, DefaultError; +def warn_cxx98_compat_pass_non_pod_arg_to_vararg : Warning< + "passing object of trivial but non-POD type %0 through variadic" + " %select{function|block|method|constructor}1 is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def warn_pass_class_arg_to_vararg : Warning< + "passing object of class type %0 through variadic " + "%select{function|block|method|constructor}1" + "%select{|; did you mean to call '%3'?}2">, + InGroup<ClassVarargs>, DefaultIgnore; +def err_cannot_pass_to_vararg : Error< + "cannot pass %select{expression of type %1|initializer list}0 to variadic " + "%select{function|block|method|constructor}2">; +def err_cannot_pass_to_vararg_format : Error< + "cannot pass %select{expression of type %1|initializer list}0 to variadic " + "%select{function|block|method|constructor}2; expected type from format " + "string was %3">; + +def err_typecheck_call_invalid_ordered_compare : Error< + "ordered compare requires two args of floating point type" + "%diff{ ($ and $)|}0,1">; +def err_typecheck_call_invalid_unary_fp : Error< + "floating point classification requires argument of floating point type " + "(passed in %0)">; +def err_typecheck_cond_expect_int_float : Error< + "used type %0 where integer or floating point type is required">; +def err_typecheck_cond_expect_scalar : Error< + "used type %0 where arithmetic or pointer type is required">; +def err_typecheck_cond_expect_nonfloat : Error< + "used type %0 where floating point type is not allowed">; +def ext_typecheck_cond_one_void : Extension< + "C99 forbids conditional expressions with only one void side">; +def err_typecheck_cast_to_incomplete : Error< + "cast to incomplete type %0">; +def ext_typecheck_cast_nonscalar : Extension< + "C99 forbids casting nonscalar type %0 to the same type">; +def ext_typecheck_cast_to_union : Extension< + "cast to union type is a GNU extension">, + InGroup<GNUUnionCast>; +def err_typecheck_cast_to_union_no_type : Error< + "cast to union type from type %0 not present in union">; +def err_cast_pointer_from_non_pointer_int : Error< + "operand of type %0 cannot be cast to a pointer type">; +def warn_cast_pointer_from_sel : Warning< + "cast of type %0 to %1 is deprecated; use sel_getName instead">, + InGroup<SelTypeCast>; +def warn_function_def_in_objc_container : Warning< + "function definition inside an Objective-C container is deprecated">, + InGroup<FunctionDefInObjCContainer>; + +def warn_bad_function_cast : Warning< + "cast from function call of type %0 to non-matching type %1">, + InGroup<BadFunctionCast>, DefaultIgnore; +def err_cast_pointer_to_non_pointer_int : Error< + "pointer cannot be cast to type %0">; +def err_typecheck_expect_scalar_operand : Error< + "operand of type %0 where arithmetic or pointer type is required">; +def err_typecheck_cond_incompatible_operands : Error< + "incompatible operand types%diff{ ($ and $)|}0,1">; +def ext_typecheck_cond_incompatible_operands_nonstandard : ExtWarn< + "incompatible operand types%diff{ ($ and $)|}0,1 use non-standard composite " + "pointer type %2">; +def err_cast_selector_expr : Error< + "cannot type cast @selector expression">; +def ext_typecheck_cond_incompatible_pointers : ExtWarn< + "pointer type mismatch%diff{ ($ and $)|}0,1">, + InGroup<DiagGroup<"pointer-type-mismatch">>; +def ext_typecheck_cond_pointer_integer_mismatch : ExtWarn< + "pointer/integer type mismatch in conditional expression" + "%diff{ ($ and $)|}0,1">, + InGroup<DiagGroup<"conditional-type-mismatch">>; +def err_typecheck_choose_expr_requires_constant : Error< + "'__builtin_choose_expr' requires a constant expression">; +def warn_unused_expr : Warning<"expression result unused">, + InGroup<UnusedValue>; +def warn_unused_voidptr : Warning< + "expression result unused; should this cast be to 'void'?">, + InGroup<UnusedValue>; +def warn_unused_property_expr : Warning< + "property access result unused - getters should not be used for side effects">, + InGroup<UnusedGetterReturnValue>; +def warn_unused_container_subscript_expr : Warning< + "container access result unused - container access should not be used for side effects">, + InGroup<UnusedValue>; +def warn_unused_call : Warning< + "ignoring return value of function declared with %0 attribute">, + InGroup<UnusedValue>; +def warn_side_effects_unevaluated_context : Warning< + "expression with side effects has no effect in an unevaluated context">, + InGroup<UnevaluatedExpression>; +def warn_side_effects_typeid : Warning< + "expression with side effects will be evaluated despite being used as an " + "operand to 'typeid'">, InGroup<PotentiallyEvaluatedExpression>; +def warn_unused_result : Warning< + "ignoring return value of function declared with warn_unused_result " + "attribute">, InGroup<DiagGroup<"unused-result">>; +def warn_unused_volatile : Warning< + "expression result unused; assign into a variable to force a volatile load">, + InGroup<DiagGroup<"unused-volatile-lvalue">>; + +def warn_unused_comparison : Warning< + "%select{%select{|in}1equality|relational}0 comparison result unused">, + InGroup<UnusedComparison>; +def note_inequality_comparison_to_or_assign : Note< + "use '|=' to turn this inequality comparison into an or-assignment">; + +def err_incomplete_type_used_in_type_trait_expr : Error< + "incomplete type %0 used in type trait expression">; + +def err_dimension_expr_not_constant_integer : Error< + "dimension expression does not evaluate to a constant unsigned int">; + +def err_typecheck_cond_incompatible_operands_null : Error< + "non-pointer operand type %0 incompatible with %select{NULL|nullptr}1">; +def ext_empty_struct_union : Extension< + "empty %select{struct|union}0 is a GNU extension">, InGroup<GNUEmptyStruct>; +def ext_no_named_members_in_struct_union : Extension< + "%select{struct|union}0 without named members is a GNU extension">, InGroup<GNUEmptyStruct>; +def warn_zero_size_struct_union_compat : Warning<"%select{|empty }0" + "%select{struct|union}1 has size 0 in C, %select{size 1|non-zero size}2 in C++">, + InGroup<CXXCompat>, DefaultIgnore; +def warn_zero_size_struct_union_in_extern_c : Warning<"%select{|empty }0" + "%select{struct|union}1 has size 0 in C, %select{size 1|non-zero size}2 in C++">, + InGroup<ExternCCompat>; +def warn_cast_qual : Warning<"cast from %0 to %1 drops %select{const and " + "volatile qualifiers|const qualifier|volatile qualifier}2">, + InGroup<CastQual>, DefaultIgnore; +def warn_cast_qual2 : Warning<"cast from %0 to %1 must have all intermediate " + "pointers const qualified to be safe">, InGroup<CastQual>, DefaultIgnore; +def warn_redefine_extname_not_applied : Warning< + "#pragma redefine_extname is applicable to external C declarations only; " + "not applied to %select{function|variable}0 %1">, + InGroup<Pragmas>; +} // End of general sema category. + +// inline asm. +let CategoryName = "Inline Assembly Issue" in { + def err_asm_invalid_lvalue_in_output : Error<"invalid lvalue in asm output">; + def err_asm_invalid_output_constraint : Error< + "invalid output constraint '%0' in asm">; + def err_asm_invalid_lvalue_in_input : Error< + "invalid lvalue in asm input for constraint '%0'">; + def err_asm_invalid_input_constraint : Error< + "invalid input constraint '%0' in asm">; + def err_asm_immediate_expected : Error<"constraint '%0' expects " + "an integer constant expression">; + def err_asm_invalid_type_in_input : Error< + "invalid type %0 in asm input for constraint '%1'">; + def err_asm_tying_incompatible_types : Error< + "unsupported inline asm: input with type " + "%diff{$ matching output with type $|}0,1">; + def err_asm_unexpected_constraint_alternatives : Error< + "asm constraint has an unexpected number of alternatives: %0 vs %1">; + def err_asm_incomplete_type : Error<"asm operand has incomplete type %0">; + def err_asm_unknown_register_name : Error<"unknown register name '%0' in asm">; + def err_asm_invalid_global_var_reg : Error<"register '%0' unsuitable for " + "global register variables on this target">; + def err_asm_register_size_mismatch : Error<"size of register '%0' does not " + "match variable size">; + def err_asm_bad_register_type : Error<"bad type for named register variable">; + def err_asm_invalid_input_size : Error< + "invalid input size for constraint '%0'">; + def err_asm_invalid_output_size : Error< + "invalid output size for constraint '%0'">; + def err_invalid_asm_cast_lvalue : Error< + "invalid use of a cast in a inline asm context requiring an l-value: " + "remove the cast or build with -fheinous-gnu-extensions">; + def err_invalid_asm_value_for_constraint + : Error <"value '%0' out of range for constraint '%1'">; + def err_asm_non_addr_value_in_memory_constraint : Error < + "reference to a %select{bit-field|vector element|global register variable}0" + " in asm %select{input|output}1 with a memory constraint '%2'">; + def err_asm_input_duplicate_match : Error< + "more than one input constraint matches the same output '%0'">; + + def warn_asm_label_on_auto_decl : Warning< + "ignored asm label '%0' on automatic variable">; + def warn_invalid_asm_cast_lvalue : Warning< + "invalid use of a cast in an inline asm context requiring an l-value: " + "accepted due to -fheinous-gnu-extensions, but clang may remove support " + "for this in the future">; + def warn_asm_mismatched_size_modifier : Warning< + "value size does not match register size specified by the constraint " + "and modifier">, + InGroup<ASMOperandWidths>; + + def note_asm_missing_constraint_modifier : Note< + "use constraint modifier \"%0\"">; + def note_asm_input_duplicate_first : Note< + "constraint '%0' is already present here">; +} + +let CategoryName = "Semantic Issue" in { + +def err_invalid_conversion_between_vectors : Error< + "invalid conversion between vector type%diff{ $ and $|}0,1 of different " + "size">; +def err_invalid_conversion_between_vector_and_integer : Error< + "invalid conversion between vector type %0 and integer type %1 " + "of different size">; + +def err_opencl_function_pointer_variable : Error< + "pointers to functions are not allowed">; + +def err_opencl_taking_function_address : Error< + "taking address of function is not allowed">; + +def err_invalid_conversion_between_vector_and_scalar : Error< + "invalid conversion between vector type %0 and scalar type %1">; + +// C++ member initializers. +def err_only_constructors_take_base_inits : Error< + "only constructors take base initializers">; + +def err_multiple_mem_initialization : Error < + "multiple initializations given for non-static member %0">; +def err_multiple_mem_union_initialization : Error < + "initializing multiple members of union">; +def err_multiple_base_initialization : Error < + "multiple initializations given for base %0">; + +def err_mem_init_not_member_or_class : Error< + "member initializer %0 does not name a non-static data member or base " + "class">; + +def warn_initializer_out_of_order : Warning< + "%select{field|base class}0 %1 will be initialized after " + "%select{field|base}2 %3">, + InGroup<Reorder>, DefaultIgnore; +def warn_abstract_vbase_init_ignored : Warning< + "initializer for virtual base class %0 of abstract class %1 " + "will never be used">, + InGroup<DiagGroup<"abstract-vbase-init">>, DefaultIgnore; + +def err_base_init_does_not_name_class : Error< + "constructor initializer %0 does not name a class">; +def err_base_init_direct_and_virtual : Error< + "base class initializer %0 names both a direct base class and an " + "inherited virtual base class">; +def err_not_direct_base_or_virtual : Error< + "type %0 is not a direct or virtual base of %1">; + +def err_in_class_initializer_non_const : Error< + "non-const static data member must be initialized out of line">; +def err_in_class_initializer_volatile : Error< + "static const volatile data member must be initialized out of line">; +def err_in_class_initializer_bad_type : Error< + "static data member of type %0 must be initialized out of line">; +def ext_in_class_initializer_float_type : ExtWarn< + "in-class initializer for static data member of type %0 is a GNU extension">, + InGroup<GNUStaticFloatInit>; +def ext_in_class_initializer_float_type_cxx11 : ExtWarn< + "in-class initializer for static data member of type %0 requires " + "'constexpr' specifier">, InGroup<StaticFloatInit>, DefaultError; +def note_in_class_initializer_float_type_cxx11 : Note<"add 'constexpr'">; +def err_in_class_initializer_literal_type : Error< + "in-class initializer for static data member of type %0 requires " + "'constexpr' specifier">; +def err_in_class_initializer_non_constant : Error< + "in-class initializer for static data member is not a constant expression">; +def err_in_class_initializer_not_yet_parsed + : Error<"cannot use defaulted default constructor of %0 within the class " + "outside of member functions because %1 has an initializer">; +def err_in_class_initializer_not_yet_parsed_outer_class + : Error<"cannot use defaulted default constructor of %0 within " + "%1 outside of member functions because %2 has an initializer">; + +def ext_in_class_initializer_non_constant : Extension< + "in-class initializer for static data member is not a constant expression; " + "folding it to a constant is a GNU extension">, InGroup<GNUFoldingConstant>; + +def err_thread_dynamic_init : Error< + "initializer for thread-local variable must be a constant expression">; +def err_thread_nontrivial_dtor : Error< + "type of thread-local variable has non-trivial destruction">; +def note_use_thread_local : Note< + "use 'thread_local' to allow this">; + +// C++ anonymous unions and GNU anonymous structs/unions +def ext_anonymous_union : Extension< + "anonymous unions are a C11 extension">, InGroup<C11>; +def ext_gnu_anonymous_struct : Extension< + "anonymous structs are a GNU extension">, InGroup<GNUAnonymousStruct>; +def ext_c11_anonymous_struct : Extension< + "anonymous structs are a C11 extension">, InGroup<C11>; +def err_anonymous_union_not_static : Error< + "anonymous unions at namespace or global scope must be declared 'static'">; +def err_anonymous_union_with_storage_spec : Error< + "anonymous union at class scope must not have a storage specifier">; +def err_anonymous_struct_not_member : Error< + "anonymous %select{structs|structs and classes}0 must be " + "%select{struct or union|class}0 members">; +def err_anonymous_record_member_redecl : Error< + "member of anonymous %select{struct|union}0 redeclares %1">; +def err_anonymous_record_with_type : Error< + "types cannot be declared in an anonymous %select{struct|union}0">; +def ext_anonymous_record_with_type : Extension< + "types declared in an anonymous %select{struct|union}0 are a Microsoft " + "extension">, InGroup<MicrosoftAnonTag>; +def ext_anonymous_record_with_anonymous_type : Extension< + "anonymous types declared in an anonymous %select{struct|union}0 " + "are an extension">, InGroup<DiagGroup<"nested-anon-types">>; +def err_anonymous_record_with_function : Error< + "functions cannot be declared in an anonymous %select{struct|union}0">; +def err_anonymous_record_with_static : Error< + "static members cannot be declared in an anonymous %select{struct|union}0">; +def err_anonymous_record_bad_member : Error< + "anonymous %select{struct|union}0 can only contain non-static data members">; +def err_anonymous_record_nonpublic_member : Error< + "anonymous %select{struct|union}0 cannot contain a " + "%select{private|protected}1 data member">; +def ext_ms_anonymous_record : ExtWarn< + "anonymous %select{structs|unions}0 are a Microsoft extension">, + InGroup<MicrosoftAnonTag>; + +// C++ local classes +def err_reference_to_local_var_in_enclosing_function : Error< + "reference to local variable %0 declared in enclosing function %1">; +def err_reference_to_local_var_in_enclosing_block : Error< + "reference to local variable %0 declared in enclosing block literal">; +def err_reference_to_local_var_in_enclosing_lambda : Error< + "reference to local variable %0 declared in enclosing lambda expression">; +def err_reference_to_local_var_in_enclosing_context : Error< + "reference to local variable %0 declared in enclosing context">; + +def err_static_data_member_not_allowed_in_local_class : Error< + "static data member %0 not allowed in local class %1">; + +// C++ derived classes +def err_base_clause_on_union : Error<"unions cannot have base classes">; +def err_base_must_be_class : Error<"base specifier must name a class">; +def err_union_as_base_class : Error<"unions cannot be base classes">; +def err_circular_inheritance : Error< + "circular inheritance between %0 and %1">; +def err_base_class_has_flexible_array_member : Error< + "base class %0 has a flexible array member">; +def err_incomplete_base_class : Error<"base class has incomplete type">; +def err_duplicate_base_class : Error< + "base class %0 specified more than once as a direct base class">; +def warn_inaccessible_base_class : Warning< + "direct base %0 is inaccessible due to ambiguity:%1">, + InGroup<DiagGroup<"inaccessible-base">>; +// FIXME: better way to display derivation? Pass entire thing into diagclient? +def err_ambiguous_derived_to_base_conv : Error< + "ambiguous conversion from derived class %0 to base class %1:%2">; +def err_ambiguous_memptr_conv : Error< + "ambiguous conversion from pointer to member of %select{base|derived}0 " + "class %1 to pointer to member of %select{derived|base}0 class %2:%3">; + +def err_memptr_conv_via_virtual : Error< + "conversion from pointer to member of class %0 to pointer to member " + "of class %1 via virtual base %2 is not allowed">; + +// C++ member name lookup +def err_ambiguous_member_multiple_subobjects : Error< + "non-static member %0 found in multiple base-class subobjects of type %1:%2">; +def err_ambiguous_member_multiple_subobject_types : Error< + "member %0 found in multiple base classes of different types">; +def note_ambiguous_member_found : Note<"member found by ambiguous name lookup">; +def err_ambiguous_reference : Error<"reference to %0 is ambiguous">; +def note_ambiguous_candidate : Note<"candidate found by name lookup is %q0">; +def err_ambiguous_tag_hiding : Error<"a type named %0 is hidden by a " + "declaration in a different namespace">; +def note_hidden_tag : Note<"type declaration hidden">; +def note_hiding_object : Note<"declaration hides type">; + +// C++ operator overloading +def err_operator_overload_needs_class_or_enum : Error< + "overloaded %0 must have at least one parameter of class " + "or enumeration type">; + +def err_operator_overload_variadic : Error<"overloaded %0 cannot be variadic">; +def err_operator_overload_static : Error< + "overloaded %0 cannot be a static member function">; +def err_operator_overload_default_arg : Error< + "parameter of overloaded %0 cannot have a default argument">; +def err_operator_overload_must_be : Error< + "overloaded %0 must be a %select{unary|binary|unary or binary}2 operator " + "(has %1 parameter%s1)">; + +def err_operator_overload_must_be_member : Error< + "overloaded %0 must be a non-static member function">; +def err_operator_overload_post_incdec_must_be_int : Error< + "parameter of overloaded post-%select{increment|decrement}1 operator must " + "have type 'int' (not %0)">; + +// C++ allocation and deallocation functions. +def err_operator_new_delete_declared_in_namespace : Error< + "%0 cannot be declared inside a namespace">; +def err_operator_new_delete_declared_static : Error< + "%0 cannot be declared static in global scope">; +def ext_operator_new_delete_declared_inline : ExtWarn< + "replacement function %0 cannot be declared 'inline'">, + InGroup<DiagGroup<"inline-new-delete">>; +def err_operator_new_delete_invalid_result_type : Error< + "%0 must return type %1">; +def err_operator_new_delete_dependent_result_type : Error< + "%0 cannot have a dependent return type; use %1 instead">; +def err_operator_new_delete_too_few_parameters : Error< + "%0 must have at least one parameter">; +def err_operator_new_delete_template_too_few_parameters : Error< + "%0 template must have at least two parameters">; +def warn_operator_new_returns_null : Warning< + "%0 should not return a null pointer unless it is declared 'throw()'" + "%select{| or 'noexcept'}1">, InGroup<OperatorNewReturnsNull>; + +def err_operator_new_dependent_param_type : Error< + "%0 cannot take a dependent type as first parameter; " + "use size_t (%1) instead">; +def err_operator_new_param_type : Error< + "%0 takes type size_t (%1) as first parameter">; +def err_operator_new_default_arg: Error< + "parameter of %0 cannot have a default argument">; +def err_operator_delete_dependent_param_type : Error< + "%0 cannot take a dependent type as first parameter; use %1 instead">; +def err_operator_delete_param_type : Error< + "first parameter of %0 must have type %1">; + +// C++ literal operators +def err_literal_operator_outside_namespace : Error< + "literal operator %0 must be in a namespace or global scope">; +def err_literal_operator_id_outside_namespace : Error< + "non-namespace scope '%0' cannot have a literal operator member">; +def err_literal_operator_default_argument : Error< + "literal operator cannot have a default argument">; +// FIXME: This diagnostic sucks +def err_literal_operator_params : Error< + "parameter declaration for literal operator %0 is not valid">; +def err_literal_operator_extern_c : Error< + "literal operator must have C++ linkage">; +def ext_string_literal_operator_template : ExtWarn< + "string literal operator templates are a GNU extension">, + InGroup<GNUStringLiteralOperatorTemplate>; +def warn_user_literal_reserved : Warning< + "user-defined literal suffixes not starting with '_' are reserved" + "%select{; no literal will invoke this operator|}0">, + InGroup<UserDefinedLiterals>; + +// C++ conversion functions +def err_conv_function_not_member : Error< + "conversion function must be a non-static member function">; +def err_conv_function_return_type : Error< + "conversion function cannot have a return type">; +def err_conv_function_with_params : Error< + "conversion function cannot have any parameters">; +def err_conv_function_variadic : Error< + "conversion function cannot be variadic">; +def err_conv_function_to_array : Error< + "conversion function cannot convert to an array type">; +def err_conv_function_to_function : Error< + "conversion function cannot convert to a function type">; +def err_conv_function_with_complex_decl : Error< + "cannot specify any part of a return type in the " + "declaration of a conversion function" + "%select{" + "; put the complete type after 'operator'|" + "; use a typedef to declare a conversion to %1|" + "; use an alias template to declare a conversion to %1|" + "}0">; +def err_conv_function_redeclared : Error< + "conversion function cannot be redeclared">; +def warn_conv_to_self_not_used : Warning< + "conversion function converting %0 to itself will never be used">; +def warn_conv_to_base_not_used : Warning< + "conversion function converting %0 to its base class %1 will never be used">; +def warn_conv_to_void_not_used : Warning< + "conversion function converting %0 to %1 will never be used">; + +def warn_not_compound_assign : Warning< + "use of unary operator that may be intended as compound assignment (%0=)">; + +// C++11 explicit conversion operators +def ext_explicit_conversion_functions : ExtWarn< + "explicit conversion functions are a C++11 extension">, InGroup<CXX11>; +def warn_cxx98_compat_explicit_conversion_functions : Warning< + "explicit conversion functions are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; + +// C++11 defaulted functions +def err_defaulted_special_member_params : Error< + "an explicitly-defaulted %select{|copy |move }0constructor cannot " + "have default arguments">; +def err_defaulted_special_member_variadic : Error< + "an explicitly-defaulted %select{|copy |move }0constructor cannot " + "be variadic">; +def err_defaulted_special_member_return_type : Error< + "explicitly-defaulted %select{copy|move}0 assignment operator must " + "return %1">; +def err_defaulted_special_member_quals : Error< + "an explicitly-defaulted %select{copy|move}0 assignment operator may not " + "have 'const'%select{, 'constexpr'|}1 or 'volatile' qualifiers">; +def err_defaulted_special_member_volatile_param : Error< + "the parameter for an explicitly-defaulted %select{<<ERROR>>|" + "copy constructor|move constructor|copy assignment operator|" + "move assignment operator|<<ERROR>>}0 may not be volatile">; +def err_defaulted_special_member_move_const_param : Error< + "the parameter for an explicitly-defaulted move " + "%select{constructor|assignment operator}0 may not be const">; +def err_defaulted_special_member_copy_const_param : Error< + "the parameter for this explicitly-defaulted copy " + "%select{constructor|assignment operator}0 is const, but a member or base " + "requires it to be non-const">; +def err_defaulted_copy_assign_not_ref : Error< + "the parameter for an explicitly-defaulted copy assignment operator must be an " + "lvalue reference type">; +def err_incorrect_defaulted_exception_spec : Error< + "exception specification of explicitly defaulted %select{default constructor|" + "copy constructor|move constructor|copy assignment operator|move assignment " + "operator|destructor}0 does not match the " + "calculated one">; +def err_incorrect_defaulted_constexpr : Error< + "defaulted definition of %select{default constructor|copy constructor|" + "move constructor|copy assignment operator|move assignment operator}0 " + "is not constexpr">; +def err_out_of_line_default_deletes : Error< + "defaulting this %select{default constructor|copy constructor|move " + "constructor|copy assignment operator|move assignment operator|destructor}0 " + "would delete it after its first declaration">; +def warn_vbase_moved_multiple_times : Warning< + "defaulted move assignment operator of %0 will move assign virtual base " + "class %1 multiple times">, InGroup<DiagGroup<"multiple-move-vbase">>; +def note_vbase_moved_here : Note< + "%select{%1 is a virtual base class of base class %2 declared here|" + "virtual base class %1 declared here}0">; + +def ext_implicit_exception_spec_mismatch : ExtWarn< + "function previously declared with an %select{explicit|implicit}0 exception " + "specification redeclared with an %select{implicit|explicit}0 exception " + "specification">, InGroup<DiagGroup<"implicit-exception-spec-mismatch">>; + +def warn_ptr_arith_precedes_bounds : Warning< + "the pointer decremented by %0 refers before the beginning of the array">, + InGroup<ArrayBoundsPointerArithmetic>, DefaultIgnore; +def warn_ptr_arith_exceeds_bounds : Warning< + "the pointer incremented by %0 refers past the end of the array (that " + "contains %1 element%s2)">, + InGroup<ArrayBoundsPointerArithmetic>, DefaultIgnore; +def warn_array_index_precedes_bounds : Warning< + "array index %0 is before the beginning of the array">, + InGroup<ArrayBounds>; +def warn_array_index_exceeds_bounds : Warning< + "array index %0 is past the end of the array (which contains %1 " + "element%s2)">, InGroup<ArrayBounds>; +def note_array_index_out_of_bounds : Note< + "array %0 declared here">; + +def warn_printf_insufficient_data_args : Warning< + "more '%%' conversions than data arguments">, InGroup<Format>; +def warn_printf_data_arg_not_used : Warning< + "data argument not used by format string">, InGroup<FormatExtraArgs>; +def warn_format_invalid_conversion : Warning< + "invalid conversion specifier '%0'">, InGroup<FormatInvalidSpecifier>; +def warn_printf_incomplete_specifier : Warning< + "incomplete format specifier">, InGroup<Format>; +def warn_missing_format_string : Warning< + "format string missing">, InGroup<Format>; +def warn_scanf_nonzero_width : Warning< + "zero field width in scanf format string is unused">, + InGroup<Format>; +def warn_format_conversion_argument_type_mismatch : Warning< + "format specifies type %0 but the argument has " + "%select{type|underlying type}2 %1">, + InGroup<Format>; +def warn_format_conversion_argument_type_mismatch_pedantic : Extension< + "format specifies type %0 but the argument has " + "%select{type|underlying type}2 %1">, + InGroup<FormatPedantic>; +def warn_format_argument_needs_cast : Warning< + "%select{values of type|enum values with underlying type}2 '%0' should not " + "be used as format arguments; add an explicit cast to %1 instead">, + InGroup<Format>; +def warn_printf_positional_arg_exceeds_data_args : Warning < + "data argument position '%0' exceeds the number of data arguments (%1)">, + InGroup<Format>; +def warn_format_zero_positional_specifier : Warning< + "position arguments in format strings start counting at 1 (not 0)">, + InGroup<Format>; +def warn_format_invalid_positional_specifier : Warning< + "invalid position specified for %select{field width|field precision}0">, + InGroup<Format>; +def warn_format_mix_positional_nonpositional_args : Warning< + "cannot mix positional and non-positional arguments in format string">, + InGroup<Format>; +def warn_static_array_too_small : Warning< + "array argument is too small; contains %0 elements, callee requires at least %1">, + InGroup<ArrayBounds>; +def note_callee_static_array : Note< + "callee declares array parameter as static here">; +def warn_empty_format_string : Warning< + "format string is empty">, InGroup<FormatZeroLength>; +def warn_format_string_is_wide_literal : Warning< + "format string should not be a wide string">, InGroup<Format>; +def warn_printf_format_string_contains_null_char : Warning< + "format string contains '\\0' within the string body">, InGroup<Format>; +def warn_printf_format_string_not_null_terminated : Warning< + "format string is not null-terminated">, InGroup<Format>; +def warn_printf_asterisk_missing_arg : Warning< + "'%select{*|.*}0' specified field %select{width|precision}0 is missing a matching 'int' argument">, + InGroup<Format>; +def warn_printf_asterisk_wrong_type : Warning< + "field %select{width|precision}0 should have type %1, but argument has type %2">, + InGroup<Format>; +def warn_printf_nonsensical_optional_amount: Warning< + "%select{field width|precision}0 used with '%1' conversion specifier, resulting in undefined behavior">, + InGroup<Format>; +def warn_printf_nonsensical_flag: Warning< + "flag '%0' results in undefined behavior with '%1' conversion specifier">, + InGroup<Format>; +def warn_format_nonsensical_length: Warning< + "length modifier '%0' results in undefined behavior or no effect with '%1' conversion specifier">, + InGroup<Format>; +def warn_format_non_standard_positional_arg: Warning< + "positional arguments are not supported by ISO C">, InGroup<FormatNonStandard>, DefaultIgnore; +def warn_format_non_standard: Warning< + "'%0' %select{length modifier|conversion specifier}1 is not supported by ISO C">, + InGroup<FormatNonStandard>, DefaultIgnore; +def warn_format_non_standard_conversion_spec: Warning< + "using length modifier '%0' with conversion specifier '%1' is not supported by ISO C">, + InGroup<FormatNonStandard>, DefaultIgnore; +def warn_printf_ignored_flag: Warning< + "flag '%0' is ignored when flag '%1' is present">, + InGroup<Format>; +def warn_printf_empty_objc_flag: Warning< + "missing object format flag">, + InGroup<Format>; +def warn_printf_ObjCflags_without_ObjCConversion: Warning< + "object format flags cannot be used with '%0' conversion specifier">, + InGroup<Format>; +def warn_printf_invalid_objc_flag: Warning< + "'%0' is not a valid object format flag">, + InGroup<Format>; +def warn_scanf_scanlist_incomplete : Warning< + "no closing ']' for '%%[' in scanf format string">, + InGroup<Format>; +def note_format_string_defined : Note<"format string is defined here">; +def note_format_fix_specifier : Note<"did you mean to use '%0'?">; +def note_printf_c_str: Note<"did you mean to call the %0 method?">; + +def warn_null_arg : Warning< + "null passed to a callee that requires a non-null argument">, + InGroup<NonNull>; +def warn_null_ret : Warning< + "null returned from %select{function|method}0 that requires a non-null return value">, + InGroup<NonNull>; + +// CHECK: returning address/reference of stack memory +def warn_ret_stack_addr_ref : Warning< + "%select{address of|reference to}0 stack memory associated with local " + "variable %1 returned">, + InGroup<ReturnStackAddress>; +def warn_ret_local_temp_addr_ref : Warning< + "returning %select{address of|reference to}0 local temporary object">, + InGroup<ReturnStackAddress>; +def warn_ret_addr_label : Warning< + "returning address of label, which is local">, + InGroup<ReturnStackAddress>; +def err_ret_local_block : Error< + "returning block that lives on the local stack">; +def note_ref_var_local_bind : Note< + "binding reference variable %0 here">; + +// Check for initializing a member variable with the address or a reference to +// a constructor parameter. +def warn_bind_ref_member_to_parameter : Warning< + "binding reference member %0 to stack allocated parameter %1">, + InGroup<DanglingField>; +def warn_init_ptr_member_to_parameter_addr : Warning< + "initializing pointer member %0 with the stack address of parameter %1">, + InGroup<DanglingField>; +def warn_bind_ref_member_to_temporary : Warning< + "binding reference %select{|subobject of }1member %0 to a temporary value">, + InGroup<DanglingField>; +def note_ref_or_ptr_member_declared_here : Note< + "%select{reference|pointer}0 member declared here">; +def note_ref_subobject_of_member_declared_here : Note< + "member with reference subobject declared here">; + +// For non-floating point, expressions of the form x == x or x != x +// should result in a warning, since these always evaluate to a constant. +// Array comparisons have similar warnings +def warn_comparison_always : Warning< + "%select{self-|array }0comparison always evaluates to %select{false|true|a constant}1">, + InGroup<TautologicalCompare>; +def warn_comparison_bitwise_always : Warning< + "bitwise comparison always evaluates to %select{false|true}0">, + InGroup<TautologicalCompare>; +def warn_tautological_overlap_comparison : Warning< + "overlapping comparisons always evaluate to %select{false|true}0">, + InGroup<TautologicalOverlapCompare>, DefaultIgnore; + +def warn_stringcompare : Warning< + "result of comparison against %select{a string literal|@encode}0 is " + "unspecified (use strncmp instead)">, + InGroup<StringCompare>; + +def warn_identity_field_assign : Warning< + "assigning %select{field|instance variable}0 to itself">, + InGroup<SelfAssignmentField>; + +// Type safety attributes +def err_type_tag_for_datatype_not_ice : Error< + "'type_tag_for_datatype' attribute requires the initializer to be " + "an %select{integer|integral}0 constant expression">; +def err_type_tag_for_datatype_too_large : Error< + "'type_tag_for_datatype' attribute requires the initializer to be " + "an %select{integer|integral}0 constant expression " + "that can be represented by a 64 bit integer">; +def warn_type_tag_for_datatype_wrong_kind : Warning< + "this type tag was not designed to be used with this function">, + InGroup<TypeSafety>; +def warn_type_safety_type_mismatch : Warning< + "argument type %0 doesn't match specified %1 type tag " + "%select{that requires %3|}2">, InGroup<TypeSafety>; +def warn_type_safety_null_pointer_required : Warning< + "specified %0 type tag requires a null pointer">, InGroup<TypeSafety>; + +// Generic selections. +def err_assoc_type_incomplete : Error< + "type %0 in generic association incomplete">; +def err_assoc_type_nonobject : Error< + "type %0 in generic association not an object type">; +def err_assoc_type_variably_modified : Error< + "type %0 in generic association is a variably modified type">; +def err_assoc_compatible_types : Error< + "type %0 in generic association compatible with previously specified type %1">; +def note_compat_assoc : Note< + "compatible type %0 specified here">; +def err_generic_sel_no_match : Error< + "controlling expression type %0 not compatible with any generic association type">; +def err_generic_sel_multi_match : Error< + "controlling expression type %0 compatible with %1 generic association types">; + + +// Blocks +def err_blocks_disable : Error<"blocks support disabled - compile with -fblocks" + " or pick a deployment target that supports them">; +def err_block_returning_array_function : Error< + "block cannot return %select{array|function}0 type %1">; + +// Builtin annotation +def err_builtin_annotation_first_arg : Error< + "first argument to __builtin_annotation must be an integer">; +def err_builtin_annotation_second_arg : Error< + "second argument to __builtin_annotation must be a non-wide string constant">; + +// CFString checking +def err_cfstring_literal_not_string_constant : Error< + "CFString literal is not a string constant">; +def warn_cfstring_truncated : Warning< + "input conversion stopped due to an input byte that does not " + "belong to the input codeset UTF-8">, + InGroup<DiagGroup<"CFString-literal">>; + +// Statements. +def err_continue_not_in_loop : Error< + "'continue' statement not in loop statement">; +def err_break_not_in_loop_or_switch : Error< + "'break' statement not in loop or switch statement">; +def warn_loop_ctrl_binds_to_inner : Warning< + "'%0' is bound to current loop, GCC binds it to the enclosing loop">, + InGroup<GccCompat>; +def warn_break_binds_to_switch : Warning< + "'break' is bound to loop, GCC binds it to switch">, + InGroup<GccCompat>; +def err_default_not_in_switch : Error< + "'default' statement not in switch statement">; +def err_case_not_in_switch : Error<"'case' statement not in switch statement">; +def warn_bool_switch_condition : Warning< + "switch condition has boolean value">, InGroup<SwitchBool>; +def warn_case_value_overflow : Warning< + "overflow converting case value to switch condition type (%0 to %1)">, + InGroup<Switch>; +def err_duplicate_case : Error<"duplicate case value '%0'">; +def err_duplicate_case_differing_expr : Error< + "duplicate case value: '%0' and '%1' both equal '%2'">; +def warn_case_empty_range : Warning<"empty case range specified">; +def warn_missing_case_for_condition : + Warning<"no case matching constant switch condition '%0'">; + +def warn_def_missing_case : Warning<"%plural{" + "1:enumeration value %1 not explicitly handled in switch|" + "2:enumeration values %1 and %2 not explicitly handled in switch|" + "3:enumeration values %1, %2, and %3 not explicitly handled in switch|" + ":%0 enumeration values not explicitly handled in switch: %1, %2, %3...}0">, + InGroup<SwitchEnum>, DefaultIgnore; + +def warn_missing_case : Warning<"%plural{" + "1:enumeration value %1 not handled in switch|" + "2:enumeration values %1 and %2 not handled in switch|" + "3:enumeration values %1, %2, and %3 not handled in switch|" + ":%0 enumeration values not handled in switch: %1, %2, %3...}0">, + InGroup<Switch>; + +def warn_unannotated_fallthrough : Warning< + "unannotated fall-through between switch labels">, + InGroup<ImplicitFallthrough>, DefaultIgnore; +def warn_unannotated_fallthrough_per_function : Warning< + "unannotated fall-through between switch labels in partly-annotated " + "function">, InGroup<ImplicitFallthroughPerFunction>, DefaultIgnore; +def note_insert_fallthrough_fixit : Note< + "insert '%0;' to silence this warning">; +def note_insert_break_fixit : Note< + "insert 'break;' to avoid fall-through">; +def err_fallthrough_attr_wrong_target : Error< + "clang::fallthrough attribute is only allowed on empty statements">; +def note_fallthrough_insert_semi_fixit : Note<"did you forget ';'?">; +def err_fallthrough_attr_outside_switch : Error< + "fallthrough annotation is outside switch statement">; +def warn_fallthrough_attr_invalid_placement : Warning< + "fallthrough annotation does not directly precede switch label">, + InGroup<ImplicitFallthrough>; +def warn_fallthrough_attr_unreachable : Warning< + "fallthrough annotation in unreachable code">, + InGroup<ImplicitFallthrough>; + +def warn_unreachable_default : Warning< + "default label in switch which covers all enumeration values">, + InGroup<CoveredSwitchDefault>, DefaultIgnore; +def warn_not_in_enum : Warning<"case value not in enumerated type %0">, + InGroup<Switch>; +def warn_not_in_enum_assignment : Warning<"integer constant not in range " + "of enumerated type %0">, InGroup<DiagGroup<"assign-enum">>, DefaultIgnore; +def err_typecheck_statement_requires_scalar : Error< + "statement requires expression of scalar type (%0 invalid)">; +def err_typecheck_statement_requires_integer : Error< + "statement requires expression of integer type (%0 invalid)">; +def err_multiple_default_labels_defined : Error< + "multiple default labels in one switch">; +def err_switch_multiple_conversions : Error< + "multiple conversions from switch condition type %0 to an integral or " + "enumeration type">; +def note_switch_conversion : Note< + "conversion to %select{integral|enumeration}0 type %1">; +def err_switch_explicit_conversion : Error< + "switch condition type %0 requires explicit conversion to %1">; +def err_switch_incomplete_class_type : Error< + "switch condition has incomplete class type %0">; + +def warn_empty_if_body : Warning< + "if statement has empty body">, InGroup<EmptyBody>; +def warn_empty_for_body : Warning< + "for loop has empty body">, InGroup<EmptyBody>; +def warn_empty_range_based_for_body : Warning< + "range-based for loop has empty body">, InGroup<EmptyBody>; +def warn_empty_while_body : Warning< + "while loop has empty body">, InGroup<EmptyBody>; +def warn_empty_switch_body : Warning< + "switch statement has empty body">, InGroup<EmptyBody>; +def note_empty_body_on_separate_line : Note< + "put the semicolon on a separate line to silence this warning">; + +def err_va_start_used_in_non_variadic_function : Error< + "'va_start' used in function with fixed args">; +def err_va_start_used_in_wrong_abi_function : Error< + "'va_start' used in %select{System V|Win64}0 ABI function">; +def err_ms_va_start_used_in_sysv_function : Error< + "'__builtin_ms_va_start' used in System V ABI function">; +def warn_second_parameter_of_va_start_not_last_named_argument : Warning< + "second parameter of 'va_start' not last named argument">, InGroup<Varargs>; +def warn_va_start_of_reference_type_is_undefined : Warning< + "'va_start' has undefined behavior with reference types">, InGroup<Varargs>; +def err_first_argument_to_va_arg_not_of_type_va_list : Error< + "first argument to 'va_arg' is of type %0 and not 'va_list'">; +def err_second_parameter_to_va_arg_incomplete: Error< + "second argument to 'va_arg' is of incomplete type %0">; +def err_second_parameter_to_va_arg_abstract: Error< + "second argument to 'va_arg' is of abstract type %0">; +def warn_second_parameter_to_va_arg_not_pod : Warning< + "second argument to 'va_arg' is of non-POD type %0">, + InGroup<NonPODVarargs>, DefaultError; +def warn_second_parameter_to_va_arg_ownership_qualified : Warning< + "second argument to 'va_arg' is of ARC ownership-qualified type %0">, + InGroup<NonPODVarargs>, DefaultError; +def warn_second_parameter_to_va_arg_never_compatible : Warning< + "second argument to 'va_arg' is of promotable type %0; this va_arg has " + "undefined behavior because arguments will be promoted to %1">, InGroup<Varargs>; + +def warn_return_missing_expr : Warning< + "non-void %select{function|method}1 %0 should return a value">, DefaultError, + InGroup<ReturnType>; +def ext_return_missing_expr : ExtWarn< + "non-void %select{function|method}1 %0 should return a value">, DefaultError, + InGroup<ReturnType>; +def ext_return_has_expr : ExtWarn< + "%select{void function|void method|constructor|destructor}1 %0 " + "should not return a value">, + DefaultError, InGroup<ReturnType>; +def ext_return_has_void_expr : Extension< + "void %select{function|method|block}1 %0 should not return void expression">; +def err_return_init_list : Error< + "%select{void function|void method|constructor|destructor}1 %0 " + "must not return a value">; +def err_ctor_dtor_returns_void : Error< + "%select{constructor|destructor}1 %0 must not return void expression">; +def warn_noreturn_function_has_return_expr : Warning< + "function %0 declared 'noreturn' should not return">, + InGroup<InvalidNoreturn>; +def warn_falloff_noreturn_function : Warning< + "function declared 'noreturn' should not return">, + InGroup<InvalidNoreturn>; +def err_noreturn_block_has_return_expr : Error< + "block declared 'noreturn' should not return">; +def err_noreturn_missing_on_first_decl : Error< + "function declared '[[noreturn]]' after its first declaration">; +def note_noreturn_missing_first_decl : Note< + "declaration missing '[[noreturn]]' attribute is here">; +def err_carries_dependency_missing_on_first_decl : Error< + "%select{function|parameter}0 declared '[[carries_dependency]]' " + "after its first declaration">; +def note_carries_dependency_missing_first_decl : Note< + "declaration missing '[[carries_dependency]]' attribute is here">; +def err_carries_dependency_param_not_function_decl : Error< + "'[[carries_dependency]]' attribute only allowed on parameter in a function " + "declaration or lambda">; +def err_block_on_nonlocal : Error< + "__block attribute not allowed, only allowed on local variables">; +def err_block_on_vm : Error< + "__block attribute not allowed on declaration with a variably modified type">; + +def err_shufflevector_non_vector : Error< + "first two arguments to __builtin_shufflevector must be vectors">; +def err_shufflevector_incompatible_vector : Error< + "first two arguments to __builtin_shufflevector must have the same type">; +def err_shufflevector_nonconstant_argument : Error< + "index for __builtin_shufflevector must be a constant integer">; +def err_shufflevector_argument_too_large : Error< + "index for __builtin_shufflevector must be less than the total number " + "of vector elements">; + +def err_convertvector_non_vector : Error< + "first argument to __builtin_convertvector must be a vector">; +def err_convertvector_non_vector_type : Error< + "second argument to __builtin_convertvector must be a vector type">; +def err_convertvector_incompatible_vector : Error< + "first two arguments to __builtin_convertvector must have the same number of elements">; + +def err_first_argument_to_cwsc_not_call : Error< + "first argument to __builtin_call_with_static_chain must be a non-member call expression">; +def err_first_argument_to_cwsc_block_call : Error< + "first argument to __builtin_call_with_static_chain must not be a block call">; +def err_first_argument_to_cwsc_builtin_call : Error< + "first argument to __builtin_call_with_static_chain must not be a builtin call">; +def err_first_argument_to_cwsc_pdtor_call : Error< + "first argument to __builtin_call_with_static_chain must not be a pseudo-destructor call">; +def err_second_argument_to_cwsc_not_pointer : Error< + "second argument to __builtin_call_with_static_chain must be of pointer type">; + +def err_vector_incorrect_num_initializers : Error< + "%select{too many|too few}0 elements in vector initialization (expected %1 elements, have %2)">; +def err_altivec_empty_initializer : Error<"expected initializer">; + +def err_invalid_neon_type_code : Error< + "incompatible constant for this __builtin_neon function">; +def err_argument_invalid_range : Error< + "argument should be a value from %0 to %1">; +def warn_neon_vector_initializer_non_portable : Warning< + "vector initializers are not compatible with NEON intrinsics in big endian " + "mode">, InGroup<DiagGroup<"nonportable-vector-initialization">>; +def note_neon_vector_initializer_non_portable : Note< + "consider using vld1_%0%1() to initialize a vector from memory, or " + "vcreate_%0%1() to initialize from an integer constant">; +def note_neon_vector_initializer_non_portable_q : Note< + "consider using vld1q_%0%1() to initialize a vector from memory, or " + "vcombine_%0%1(vcreate_%0%1(), vcreate_%0%1()) to initialize from integer " + "constants">; +def err_systemz_invalid_tabort_code : Error< + "invalid transaction abort code">; +def err_64_bit_builtin_32_bit_tgt : Error< + "this builtin is only available on 64-bit targets">; +def err_ppc_builtin_only_on_pwr7 : Error< + "this builtin is only valid on POWER7 or later CPUs">; +def err_x86_builtin_32_bit_tgt : Error< + "this builtin is only available on x86-64 targets">; + +def err_builtin_longjmp_unsupported : Error< + "__builtin_longjmp is not supported for the current target">; +def err_builtin_setjmp_unsupported : Error< + "__builtin_setjmp is not supported for the current target">; + +def err_builtin_longjmp_invalid_val : Error< + "argument to __builtin_longjmp must be a constant 1">; +def err_builtin_requires_language : Error<"'%0' is only available in %1">; + +def err_constant_integer_arg_type : Error< + "argument to %0 must be a constant integer">; + +def ext_mixed_decls_code : Extension< + "ISO C90 forbids mixing declarations and code">, + InGroup<DiagGroup<"declaration-after-statement">>; + +def err_non_local_variable_decl_in_for : Error< + "declaration of non-local variable in 'for' loop">; +def err_non_variable_decl_in_for : Error< + "non-variable declaration in 'for' loop">; +def err_toomany_element_decls : Error< + "only one element declaration is allowed">; +def err_selector_element_not_lvalue : Error< + "selector element is not a valid lvalue">; +def err_selector_element_type : Error< + "selector element type %0 is not a valid object">; +def err_selector_element_const_type : Error< + "selector element of type %0 cannot be a constant l-value expression">; +def err_collection_expr_type : Error< + "the type %0 is not a pointer to a fast-enumerable object">; +def warn_collection_expr_type : Warning< + "collection expression type %0 may not respond to %1">; + +def err_invalid_conversion_between_ext_vectors : Error< + "invalid conversion between ext-vector type %0 and %1">; + +def warn_duplicate_attribute_exact : Warning< + "attribute %0 is already applied">, InGroup<IgnoredAttributes>; + +def warn_duplicate_attribute : Warning< + "attribute %0 is already applied with different parameters">, + InGroup<IgnoredAttributes>; + +def warn_sync_fetch_and_nand_semantics_change : Warning< + "the semantics of this intrinsic changed with GCC " + "version 4.4 - the newer semantics are provided here">, + InGroup<DiagGroup<"sync-fetch-and-nand-semantics-changed">>; + +// Type +def ext_invalid_sign_spec : Extension<"'%0' cannot be signed or unsigned">; +def warn_receiver_forward_class : Warning< + "receiver %0 is a forward class and corresponding @interface may not exist">, + InGroup<ForwardClassReceiver>; +def note_method_sent_forward_class : Note<"method %0 is used for the forward class">; +def ext_missing_declspec : ExtWarn< + "declaration specifier missing, defaulting to 'int'">; +def ext_missing_type_specifier : ExtWarn< + "type specifier missing, defaults to 'int'">, + InGroup<ImplicitInt>; +def err_decimal_unsupported : Error< + "GNU decimal type extension not supported">; +def err_missing_type_specifier : Error< + "C++ requires a type specifier for all declarations">; +def err_objc_array_of_interfaces : Error< + "array of interface %0 is invalid (probably should be an array of pointers)">; +def ext_c99_array_usage : Extension< + "%select{qualifier in |static |}0array size %select{||'[*] '}0is a C99 " + "feature">, InGroup<C99>; +def err_c99_array_usage_cxx : Error< + "%select{qualifier in |static |}0array size %select{||'[*] '}0is a C99 " + "feature, not permitted in C++">; + def err_type_requires_extension : Error< + "use of type %0 requires %1 extension to be enabled">; +def err_int128_unsupported : Error< + "__int128 is not supported on this target">; +def err_nsconsumed_attribute_mismatch : Error< + "overriding method has mismatched ns_consumed attribute on its" + " parameter">; +def err_nsreturns_retained_attribute_mismatch : Error< + "overriding method has mismatched ns_returns_%select{not_retained|retained}0" + " attributes">; + +def note_getter_unavailable : Note< + "or because setter is declared here, but no getter method %0 is found">; +def err_invalid_protocol_qualifiers : Error< + "invalid protocol qualifiers on non-ObjC type">; +def warn_ivar_use_hidden : Warning< + "local declaration of %0 hides instance variable">, + InGroup<DiagGroup<"shadow-ivar">>; +def warn_direct_initialize_call : Warning< + "explicit call to +initialize results in duplicate call to +initialize">, + InGroup<ExplicitInitializeCall>; +def warn_direct_super_initialize_call : Warning< + "explicit call to [super initialize] should only be in implementation " + "of +initialize">, + InGroup<ExplicitInitializeCall>; +def error_ivar_use_in_class_method : Error< + "instance variable %0 accessed in class method">; +def error_implicit_ivar_access : Error< + "instance variable %0 cannot be accessed because 'self' has been redeclared">; +def error_private_ivar_access : Error<"instance variable %0 is private">, + AccessControl; +def error_protected_ivar_access : Error<"instance variable %0 is protected">, + AccessControl; +def warn_maynot_respond : Warning<"%0 may not respond to %1">; +def ext_typecheck_base_super : Warning< + "method parameter type " + "%diff{$ does not match super class method parameter type $|" + "does not match super class method parameter type}0,1">, + InGroup<SuperSubClassMismatch>, DefaultIgnore; +def warn_missing_method_return_type : Warning< + "method has no return type specified; defaults to 'id'">, + InGroup<MissingMethodReturnType>, DefaultIgnore; +def warn_direct_ivar_access : Warning<"instance variable %0 is being " + "directly accessed">, InGroup<DiagGroup<"direct-ivar-access">>, DefaultIgnore; + +// Spell-checking diagnostics +def err_unknown_typename : Error< + "unknown type name %0">; +def err_unknown_type_or_class_name_suggest : Error< + "unknown %select{type|class}1 name %0; did you mean %2?">; +def err_unknown_typename_suggest : Error< + "unknown type name %0; did you mean %1?">; +def err_unknown_nested_typename_suggest : Error< + "no type named %0 in %1; did you mean %select{|simply }2%3?">; +def err_no_member_suggest : Error<"no member named %0 in %1; did you mean %select{|simply }2%3?">; +def err_undeclared_use_suggest : Error< + "use of undeclared %0; did you mean %1?">; +def err_undeclared_var_use_suggest : Error< + "use of undeclared identifier %0; did you mean %1?">; +def err_no_template_suggest : Error<"no template named %0; did you mean %1?">; +def err_no_member_template_suggest : Error< + "no template named %0 in %1; did you mean %select{|simply }2%3?">; +def err_mem_init_not_member_or_class_suggest : Error< + "initializer %0 does not name a non-static data member or base " + "class; did you mean the %select{base class|member}1 %2?">; +def err_field_designator_unknown_suggest : Error< + "field designator %0 does not refer to any field in type %1; did you mean " + "%2?">; +def err_typecheck_member_reference_ivar_suggest : Error< + "%0 does not have a member named %1; did you mean %2?">; +def err_property_not_found_suggest : Error< + "property %0 not found on object of type %1; did you mean %2?">; +def err_ivar_access_using_property_syntax_suggest : Error< + "property %0 not found on object of type %1; did you mean to access instance variable %2?">; +def warn_property_access_suggest : Warning< +"property %0 not found on object of type %1; did you mean to access property %2?">, +InGroup<PropertyAccessDotSyntax>; +def err_property_found_suggest : Error< + "property %0 found on object of type %1; did you mean to access " + "it with the \".\" operator?">; +def err_undef_interface_suggest : Error< + "cannot find interface declaration for %0; did you mean %1?">; +def warn_undef_interface_suggest : Warning< + "cannot find interface declaration for %0; did you mean %1?">; +def err_undef_superclass_suggest : Error< + "cannot find interface declaration for %0, superclass of %1; did you mean " + "%2?">; +def err_undeclared_protocol_suggest : Error< + "cannot find protocol declaration for %0; did you mean %1?">; +def note_base_class_specified_here : Note< + "base class %0 specified here">; +def err_using_directive_suggest : Error< + "no namespace named %0; did you mean %1?">; +def err_using_directive_member_suggest : Error< + "no namespace named %0 in %1; did you mean %select{|simply }2%3?">; +def note_namespace_defined_here : Note<"namespace %0 defined here">; +def err_sizeof_pack_no_pack_name_suggest : Error< + "%0 does not refer to the name of a parameter pack; did you mean %1?">; +def note_parameter_pack_here : Note<"parameter pack %0 declared here">; + +def err_uncasted_use_of_unknown_any : Error< + "%0 has unknown type; cast it to its declared type to use it">; +def err_uncasted_call_of_unknown_any : Error< + "%0 has unknown return type; cast the call to its declared return type">; +def err_uncasted_send_to_unknown_any_method : Error< + "no known method %select{%objcinstance1|%objcclass1}0; cast the " + "message send to the method's return type">; +def err_unsupported_unknown_any_decl : Error< + "%0 has unknown type, which is not supported for this kind of declaration">; +def err_unsupported_unknown_any_expr : Error< + "unsupported expression with unknown type">; +def err_unsupported_unknown_any_call : Error< + "call to unsupported expression with unknown type">; +def err_unknown_any_addrof : Error< + "the address of a declaration with unknown type " + "can only be cast to a pointer type">; +def err_unknown_any_var_function_type : Error< + "variable %0 with unknown type cannot be given a function type">; +def err_unknown_any_function : Error< + "function %0 with unknown type must be given a function type">; + +def err_filter_expression_integral : Error< + "filter expression type should be an integral value not %0">; + +def err_non_asm_stmt_in_naked_function : Error< + "non-ASM statement in naked function is not supported">; +def err_asm_naked_this_ref : Error< + "'this' pointer references not allowed in naked functions">; +def err_asm_naked_parm_ref : Error< + "parameter references not allowed in naked functions">; + +def ext_deprecated_attr_is_a_cxx14_extension : ExtWarn< + "use of the 'deprecated' attribute is a C++14 extension">, InGroup<CXX14>; + +// OpenCL warnings and errors. +def err_invalid_astype_of_different_size : Error< + "invalid reinterpretation: sizes of %0 and %1 must match">; +def err_static_kernel : Error< + "kernel functions cannot be declared static">; +def err_opencl_ptrptr_kernel_param : Error< + "kernel parameter cannot be declared as a pointer to a pointer">; +def err_opencl_private_ptr_kernel_param : Error< + "kernel parameter cannot be declared as a pointer to the __private address space">; +def err_opencl_non_kernel_variable : Error< + "non-kernel function variable cannot be declared in %0 address space">; +def err_static_function_scope : Error< + "variables in function scope cannot be declared static">; +def err_opencl_bitfields : Error< + "bitfields are not supported in OpenCL">; +def err_opencl_vla : Error< + "variable length arrays are not supported in OpenCL">; +def err_bad_kernel_param_type : Error< + "%0 cannot be used as the type of a kernel parameter">; +def err_record_with_pointers_kernel_param : Error< + "%select{struct|union}0 kernel parameters may not contain pointers">; +def note_within_field_of_type : Note< + "within field of type %0 declared here">; +def note_illegal_field_declared_here : Note< + "field of illegal %select{type|pointer type}0 %1 declared here">; +def err_event_t_global_var : Error< + "the event_t type cannot be used to declare a program scope variable">; +def err_event_t_struct_field : Error< + "the event_t type cannot be used to declare a structure or union field">; +def err_event_t_addr_space_qual : Error< + "the event_t type can only be used with __private address space qualifier">; +def err_expected_kernel_void_return_type : Error< + "kernel must have void return type">; +def err_sampler_argument_required : Error< + "sampler_t variable required - got %0">; +def err_wrong_sampler_addressspace: Error< + "sampler type cannot be used with the __local and __global address space qualifiers">; +def err_opencl_global_invalid_addr_space : Error< + "program scope variable must reside in %0 address space">; +def err_opencl_no_main : Error<"%select{function|kernel}0 cannot be called 'main'">; +def err_opencl_kernel_attr : + Error<"attribute %0 can only be applied to a kernel function">; +def err_opencl_return_value_with_address_space : Error< + "return value cannot be qualified with address space">; +def err_opencl_constant_no_init : Error< + "variable in constant address space must be initialized">; +def err_atomic_init_constant : Error< + "atomic variable can only be assigned to a compile time constant" + " in the declaration statement in the program scope">; +def err_opencl_implicit_vector_conversion : Error< + "implicit conversions between vector types (%0 and %1) are not permitted">; + +// OpenCL Section 6.8.g +def err_opencl_unknown_type_specifier : Error< + "OpenCL does not support the '%0' %select{type qualifier|storage class specifier}1">; + +} // end of sema category + +let CategoryName = "OpenMP Issue" in { +// OpenMP support. +def err_omp_expected_var_arg : Error< + "%0 is not a global variable, static local variable or static data member">; +def err_omp_expected_var_arg_suggest : Error< + "%0 is not a global variable, static local variable or static data member; " + "did you mean %1">; +def err_omp_global_var_arg : Error< + "arguments of '#pragma omp %0' must have %select{global storage|static storage duration}1">; +def err_omp_ref_type_arg : Error< + "arguments of '#pragma omp %0' cannot be of reference type %1">; +def err_omp_var_scope : Error< + "'#pragma omp %0' must appear in the scope of the %q1 variable declaration">; +def err_omp_var_used : Error< + "'#pragma omp %0' must precede all references to variable %q1">; +def err_omp_var_thread_local : Error< + "variable %0 cannot be threadprivate because it is %select{thread-local|a global named register variable}1">; +def err_omp_private_incomplete_type : Error< + "a private variable with incomplete type %0">; +def err_omp_firstprivate_incomplete_type : Error< + "a firstprivate variable with incomplete type %0">; +def err_omp_lastprivate_incomplete_type : Error< + "a lastprivate variable with incomplete type %0">; +def err_omp_reduction_incomplete_type : Error< + "a reduction list item with incomplete type %0">; +def err_omp_unexpected_clause_value : Error< + "expected %0 in OpenMP clause '%1'">; +def err_omp_expected_var_name : Error< + "expected variable name">; +def err_omp_expected_var_name_or_array_item : Error< + "expected variable name, array element or array section">; +def note_omp_task_predetermined_firstprivate_here : Note< + "predetermined as a firstprivate in a task construct here">; +def err_omp_threadprivate_incomplete_type : Error< + "threadprivate variable with incomplete type %0">; +def err_omp_no_dsa_for_variable : Error< + "variable %0 must have explicitly specified data sharing attributes">; +def err_omp_wrong_dsa : Error< + "%0 variable cannot be %1">; +def err_omp_variably_modified_type_not_supported : Error< + "arguments of OpenMP clause '%0' in '#pragma omp %2' directive cannot be of variably-modified type %1">; +def note_omp_explicit_dsa : Note< + "defined as %0">; +def note_omp_predetermined_dsa : Note< + "%select{static data member is predetermined as shared|" + "variable with static storage duration is predetermined as shared|" + "loop iteration variable is predetermined as private|" + "loop iteration variable is predetermined as linear|" + "loop iteration variable is predetermined as lastprivate|" + "constant variable is predetermined as shared|" + "global variable is predetermined as shared|" + "non-shared variable in a task construct is predetermined as firstprivate|" + "variable with automatic storage duration is predetermined as private}0" + "%select{|; perhaps you forget to enclose 'omp %2' directive into a parallel or another task region?}1">; +def note_omp_implicit_dsa : Note< + "implicitly determined as %0">; +def err_omp_loop_var_dsa : Error< + "loop iteration variable in the associated loop of 'omp %1' directive may not be %0, predetermined as %2">; +def err_omp_not_for : Error< + "%select{statement after '#pragma omp %1' must be a for loop|" + "expected %2 for loops after '#pragma omp %1'%select{|, but found only %4}3}0">; +def note_omp_collapse_ordered_expr : Note< + "as specified in %select{'collapse'|'ordered'|'collapse' and 'ordered'}0 clause%select{||s}0">; +def err_omp_negative_expression_in_clause : Error< + "argument to '%0' clause must be a %select{non-negative|strictly positive}1 integer value">; +def err_omp_not_integral : Error< + "expression must have integral or unscoped enumeration " + "type, not %0">; +def err_omp_incomplete_type : Error< + "expression has incomplete class type %0">; +def err_omp_explicit_conversion : Error< + "expression requires explicit conversion from %0 to %1">; +def note_omp_conversion_here : Note< + "conversion to %select{integral|enumeration}0 type %1 declared here">; +def err_omp_ambiguous_conversion : Error< + "ambiguous conversion from type %0 to an integral or unscoped " + "enumeration type">; +def err_omp_required_access : Error< + "%0 variable must be %1">; +def err_omp_const_variable : Error< + "const-qualified variable cannot be %0">; +def err_omp_const_reduction_list_item : Error< + "const-qualified list item cannot be reduction">; +def err_omp_linear_incomplete_type : Error< + "a linear variable with incomplete type %0">; +def err_omp_linear_expected_int_or_ptr : Error< + "argument of a linear clause should be of integral or pointer " + "type, not %0">; +def warn_omp_linear_step_zero : Warning< + "zero linear step (%0 %select{|and other variables in clause }1should probably be const)">, + InGroup<OpenMPClauses>; +def warn_omp_alignment_not_power_of_two : Warning< + "aligned clause will be ignored because the requested alignment is not a power of 2">, + InGroup<OpenMPClauses>; +def err_omp_aligned_expected_array_or_ptr : Error< + "argument of aligned clause should be array" + "%select{ or pointer|, pointer, reference to array or reference to pointer}1" + ", not %0">; +def err_omp_aligned_twice : Error< + "a variable cannot appear in more than one aligned clause">; +def err_omp_local_var_in_threadprivate_init : Error< + "variable with local storage in initial value of threadprivate variable">; +def err_omp_loop_not_canonical_init : Error< + "initialization clause of OpenMP for loop is not in canonical form " + "('var = init' or 'T var = init')">; +def ext_omp_loop_not_canonical_init : ExtWarn< + "initialization clause of OpenMP for loop is not in canonical form " + "('var = init' or 'T var = init')">, InGroup<OpenMPLoopForm>; +def err_omp_loop_not_canonical_cond : Error< + "condition of OpenMP for loop must be a relational comparison " + "('<', '<=', '>', or '>=') of loop variable %0">; +def err_omp_loop_not_canonical_incr : Error< + "increment clause of OpenMP for loop must perform simple addition " + "or subtraction on loop variable %0">; +def err_omp_loop_variable_type : Error< + "variable must be of integer or %select{pointer|random access iterator}0 type">; +def err_omp_loop_incr_not_compatible : Error< + "increment expression must cause %0 to %select{decrease|increase}1 " + "on each iteration of OpenMP for loop">; +def note_omp_loop_cond_requres_compatible_incr : Note< + "loop step is expected to be %select{negative|positive}0 due to this condition">; +def err_omp_loop_diff_cxx : Error< + "could not calculate number of iterations calling 'operator-' with " + "upper and lower loop bounds">; +def err_omp_loop_cannot_use_stmt : Error< + "'%0' statement cannot be used in OpenMP for loop">; +def err_omp_simd_region_cannot_use_stmt : Error< + "'%0' statement cannot be used in OpenMP simd region">; +def warn_omp_loop_64_bit_var : Warning< + "OpenMP loop iteration variable cannot have more than 64 bits size and will be narrowed">, + InGroup<OpenMPLoopForm>; +def err_omp_unknown_reduction_identifier : Error< + "incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max'">; +def err_omp_reduction_type_array : Error< + "a reduction list item with array type %0">; +def err_omp_reduction_ref_type_arg : Error< + "argument of OpenMP clause 'reduction' must reference the same object in all threads">; +def err_omp_clause_not_arithmetic_type_arg : Error< + "arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of %select{scalar|arithmetic}0 type">; +def err_omp_clause_floating_type_arg : Error< + "arguments of OpenMP clause 'reduction' with bitwise operators cannot be of floating type">; +def err_omp_once_referenced : Error< + "variable can appear only once in OpenMP '%0' clause">; +def note_omp_referenced : Note< + "previously referenced here">; +def err_omp_reduction_in_task : Error< + "reduction variables may not be accessed in an explicit task">; +def err_omp_reduction_id_not_compatible : Error< + "list item of type %0 is not valid for specified reduction operation: unable to provide default initialization value">; +def err_omp_prohibited_region : Error< + "region cannot be%select{| closely}0 nested inside '%1' region" + "%select{|; perhaps you forget to enclose 'omp %3' directive into a parallel region?|" + "; perhaps you forget to enclose 'omp %3' directive into a for or a parallel for region with 'ordered' clause?|" + "; perhaps you forget to enclose 'omp %3' directive into a target region?|" + "; perhaps you forget to enclose 'omp %3' directive into a teams region?}2">; +def err_omp_prohibited_region_simd : Error< + "OpenMP constructs may not be nested inside a simd region">; +def err_omp_prohibited_region_atomic : Error< + "OpenMP constructs may not be nested inside an atomic region">; +def err_omp_prohibited_region_critical_same_name : Error< + "cannot nest 'critical' regions having the same name %0">; +def note_omp_previous_critical_region : Note< + "previous 'critical' region starts here">; +def err_omp_sections_not_compound_stmt : Error< + "the statement for '#pragma omp sections' must be a compound statement">; +def err_omp_parallel_sections_not_compound_stmt : Error< + "the statement for '#pragma omp parallel sections' must be a compound statement">; +def err_omp_orphaned_section_directive : Error< + "%select{orphaned 'omp section' directives are prohibited, it|'omp section' directive}0" + " must be closely nested to a sections region%select{|, not a %1 region}0">; +def err_omp_sections_substmt_not_section : Error< + "statement in 'omp sections' directive must be enclosed into a section region">; +def err_omp_parallel_sections_substmt_not_section : Error< + "statement in 'omp parallel sections' directive must be enclosed into a section region">; +def err_omp_parallel_reduction_in_task_firstprivate : Error< + "argument of a reduction clause of a %0 construct must not appear in a firstprivate clause on a task construct">; +def err_omp_atomic_read_not_expression_statement : Error< + "the statement for 'atomic read' must be an expression statement of form 'v = x;'," + " where v and x are both lvalue expressions with scalar type">; +def note_omp_atomic_read_write: Note< + "%select{expected an expression statement|expected built-in assignment operator|expected expression of scalar type|expected lvalue expression}0">; +def err_omp_atomic_write_not_expression_statement : Error< + "the statement for 'atomic write' must be an expression statement of form 'x = expr;'," + " where x is a lvalue expression with scalar type">; +def err_omp_atomic_update_not_expression_statement : Error< + "the statement for 'atomic update' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x'," + " where x is an l-value expression with scalar type">; +def err_omp_atomic_not_expression_statement : Error< + "the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x'," + " where x is an l-value expression with scalar type">; +def note_omp_atomic_update: Note< + "%select{expected an expression statement|expected built-in binary or unary operator|expected unary decrement/increment operation|" + "expected expression of scalar type|expected assignment expression|expected built-in binary operator|" + "expected one of '+', '*', '-', '/', '&', '^', '%|', '<<', or '>>' built-in operations|expected in right hand side of expression}0">; +def err_omp_atomic_capture_not_expression_statement : Error< + "the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x'," + " where x and v are both l-value expressions with scalar type">; +def err_omp_atomic_capture_not_compound_statement : Error< + "the statement for 'atomic capture' must be a compound statement of form '{v = x; x binop= expr;}', '{x binop= expr; v = x;}'," + " '{v = x; x = x binop expr;}', '{v = x; x = expr binop x;}', '{x = x binop expr; v = x;}', '{x = expr binop x; v = x;}' or '{v = x; x = expr;}'," + " '{v = x; x++;}', '{v = x; ++x;}', '{++x; v = x;}', '{x++; v = x;}', '{v = x; x--;}', '{v = x; --x;}', '{--x; v = x;}', '{x--; v = x;}'" + " where x is an l-value expression with scalar type">; +def note_omp_atomic_capture: Note< + "%select{expected assignment expression|expected compound statement|expected exactly two expression statements|expected in right hand side of the first expression}0">; +def err_omp_atomic_several_clauses : Error< + "directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update' or 'capture' clause">; +def note_omp_atomic_previous_clause : Note< + "'%0' clause used here">; +def err_omp_target_contains_not_only_teams : Error< + "target construct with nested teams region contains statements outside of the teams construct">; +def note_omp_nested_teams_construct_here : Note< + "nested teams construct here">; +def note_omp_nested_statement_here : Note< + "%select{statement|directive}0 outside teams construct here">; +def err_omp_single_copyprivate_with_nowait : Error< + "the 'copyprivate' clause must not be used with the 'nowait' clause">; +def note_omp_nowait_clause_here : Note< + "'nowait' clause is here">; +def err_omp_wrong_cancel_region : Error< + "one of 'for', 'parallel', 'sections' or 'taskgroup' is expected">; +def err_omp_parent_cancel_region_nowait : Error< + "parent region for 'omp %select{cancellation point/cancel}0' construct cannot be nowait">; +def err_omp_parent_cancel_region_ordered : Error< + "parent region for 'omp %select{cancellation point/cancel}0' construct cannot be ordered">; +def err_omp_array_section_use : Error<"OpenMP array section is not allowed here">; +def err_omp_typecheck_section_value : Error< + "subscripted value is not an array or pointer">; +def err_omp_typecheck_section_not_integer : Error< + "array section %select{lower bound|length}0 is not an integer">; +def err_omp_section_function_type : Error< + "section of pointer to function type %0">; +def warn_omp_section_is_char : Warning<"array section %select{lower bound|length}0 is of type 'char'">, + InGroup<CharSubscript>, DefaultIgnore; +def err_omp_section_incomplete_type : Error< + "section of pointer to incomplete type %0">; +def err_omp_section_negative : Error< + "section %select{lower bound|length}0 is evaluated to a negative value %1">; +def err_omp_section_length_undefined : Error< + "section length is unspecified and cannot be inferred because subscripted value is %select{not an array|an array of unknown bound}0">; +def err_omp_wrong_linear_modifier : Error< + "expected %select{'val' modifier|one of 'ref', val' or 'uval' modifiers}0">; +def err_omp_wrong_linear_modifier_non_reference : Error< + "variable of non-reference type %0 can be used only with 'val' modifier, but used with '%1'">; +def err_omp_wrong_simdlen_safelen_values : Error< + "the value of 'simdlen' parameter must be less than or equal to the value of the 'safelen' parameter">; +def err_omp_wrong_if_directive_name_modifier : Error< + "directive name modifier '%0' is not allowed for '#pragma omp %1'">; +def err_omp_no_more_if_clause : Error< + "no more 'if' clause is allowed">; +def err_omp_unnamed_if_clause : Error< + "expected %select{|one of}0 %1 directive name modifier%select{|s}0">; +def note_omp_previous_named_if_clause : Note< + "previous clause with directive name modifier specified here">; +def err_omp_ordered_directive_with_param : Error< + "'ordered' directive %select{without any clauses|with 'threads' clause}0 cannot be closely nested inside ordered region with specified parameter">; +def err_omp_ordered_directive_without_param : Error< + "'ordered' directive with 'depend' clause cannot be closely nested inside ordered region without specified parameter">; +def note_omp_ordered_param : Note< + "'ordered' clause with specified parameter">; +def err_omp_expected_base_var_name : Error< + "expected variable name as a base of the array %select{subscript|section}0">; +def err_omp_map_shared_storage : Error< + "variable already marked as mapped in current construct">; +def err_omp_not_mappable_type : Error< + "type %0 is not mappable to target">; +def note_omp_polymorphic_in_target : Note< + "mappable type cannot be polymorphic">; +def note_omp_static_member_in_target : Note< + "mappable type cannot contain static members">; +def err_omp_threadprivate_in_map : Error< + "threadprivate variables are not allowed in map clause">; +def err_omp_wrong_ordered_loop_count : Error< + "the parameter of the 'ordered' clause must be greater than or equal to the parameter of the 'collapse' clause">; +def note_collapse_loop_count : Note< + "parameter of the 'collapse' clause">; +def err_omp_grainsize_num_tasks_mutually_exclusive : Error< + "'%0' and '%1' clause are mutually exclusive and may not appear on the same directive">; +def note_omp_previous_grainsize_num_tasks : Note< + "'%0' clause is specified here">; +def err_omp_hint_clause_no_name : Error< + "the name of the construct must be specified in presence of 'hint' clause">; +def err_omp_critical_with_hint : Error< + "constructs with the same name must have a 'hint' clause with the same value">; +def note_omp_critical_hint_here : Note< + "%select{|previous }0'hint' clause with value '%1'">; +def note_omp_critical_no_hint : Note< + "%select{|previous }0directive with no 'hint' clause specified">; +def err_omp_firstprivate_distribute_private_teams : Error< + "private variable in '#pragma omp teams' cannot be firstprivate in '#pragma omp distribute'">; +def err_omp_firstprivate_and_lastprivate_in_distribute : Error< + "lastprivate variable cannot be firstprivate in '#pragma omp distribute'">; +def err_omp_firstprivate_distribute_in_teams_reduction : Error< + "reduction variable in '#pragma omp teams' cannot be firstprivate in '#pragma omp distribute'">; +def err_omp_depend_clause_thread_simd : Error< + "'depend' clauses cannot be mixed with '%0' clause">; +def err_omp_depend_sink_wrong_expr : Error< + "expected expression form x[+-d], where x is the loop iteration variable and d is a constant non-negative integer">; +def err_omp_depend_sink_expected_loop_iteration : Error< + "expected %0 loop iteration variable">; +def err_omp_depend_sink_unexpected_expr : Error< + "unexpected expression: number of expressions is larger than the number of associated loops">; +def err_omp_depend_sink_expected_plus_minus : Error< + "expected '+' or '-' operation">; +def err_omp_depend_sink_source_not_allowed : Error< + "'depend(%select{source|sink:vec}0)' clause%select{|s}0 cannot be mixed with 'depend(%select{sink:vec|source}0)' clause%select{s|}0">; +def err_omp_linear_ordered : Error< + "'linear' clause cannot be specified along with 'ordered' clause with a parameter">; +def err_omp_unexpected_schedule_modifier : Error< + "modifier '%0' cannot be used along with modifier '%1'">; +def err_omp_schedule_nonmonotonic_static : Error< + "'nonmonotonic' modifier can only be specified with 'dynamic' or 'guided' schedule kind">; +def err_omp_schedule_nonmonotonic_ordered : Error< + "'schedule' clause with 'nonmonotonic' modifier cannot be specified if an 'ordered' clause is specified">; +def err_omp_ordered_simd : Error< + "'ordered' clause with a parameter can not be specified in '#pragma omp %0' directive">; +} // end of OpenMP category + +let CategoryName = "Related Result Type Issue" in { +// Objective-C related result type compatibility +def warn_related_result_type_compatibility_class : Warning< + "method is expected to return an instance of its class type " + "%diff{$, but is declared to return $|" + ", but is declared to return different type}0,1">; +def warn_related_result_type_compatibility_protocol : Warning< + "protocol method is expected to return an instance of the implementing " + "class, but is declared to return %0">; +def note_related_result_type_family : Note< + "%select{overridden|current}0 method is part of the '%select{|alloc|copy|init|" + "mutableCopy|new|autorelease|dealloc|finalize|release|retain|retainCount|" + "self}1' method family%select{| and is expected to return an instance of its " + "class type}0">; +def note_related_result_type_overridden : Note< + "overridden method returns an instance of its class type">; +def note_related_result_type_inferred : Note< + "%select{class|instance}0 method %1 is assumed to return an instance of " + "its receiver type (%2)">; +def note_related_result_type_explicit : Note< + "%select{overridden|current}0 method is explicitly declared 'instancetype'" + "%select{| and is expected to return an instance of its class type}0">; + +} + +let CategoryName = "Modules Issue" in { +def err_module_private_specialization : Error< + "%select{template|partial|member}0 specialization cannot be " + "declared __module_private__">; +def err_module_private_local : Error< + "%select{local variable|parameter|typedef}0 %1 cannot be declared " + "__module_private__">; +def err_module_private_local_class : Error< + "local %select{struct|interface|union|class|enum}0 cannot be declared " + "__module_private__">; +def err_module_unimported_use : Error< + "%select{declaration|definition|default argument}0 of %1 must be imported " + "from module '%2' before it is required">; +def err_module_unimported_use_multiple : Error< + "%select{declaration|definition|default argument}0 of %1 must be imported " + "from one of the following modules before it is required:%2">; +def ext_module_import_in_extern_c : ExtWarn< + "import of C++ module '%0' appears within extern \"C\" language linkage " + "specification">, DefaultError, + InGroup<DiagGroup<"module-import-in-extern-c">>; +def note_module_import_in_extern_c : Note< + "extern \"C\" language linkage specification begins here">; +def err_module_import_not_at_top_level_fatal : Error< + "import of module '%0' appears within %1">, DefaultFatal; +def ext_module_import_not_at_top_level_noop : ExtWarn< + "redundant #include of module '%0' appears within %1">, DefaultError, + InGroup<DiagGroup<"modules-import-nested-redundant">>; +def note_module_import_not_at_top_level : Note<"%0 begins here">; +def err_module_self_import : Error< + "import of module '%0' appears within same top-level module '%1'">; +def err_module_import_in_implementation : Error< + "@import of module '%0' in implementation of '%1'; use #import">; + +def ext_equivalent_internal_linkage_decl_in_modules : ExtWarn< + "ambiguous use of internal linkage declaration %0 defined in multiple modules">, + InGroup<DiagGroup<"modules-ambiguous-internal-linkage">>; +def note_equivalent_internal_linkage_decl : Note< + "declared here%select{ in module '%1'|}0">; +} + +let CategoryName = "Coroutines Issue" in { +def err_return_in_coroutine : Error< + "return statement not allowed in coroutine; did you mean 'co_return'?">; +def note_declared_coroutine_here : Note< + "function is a coroutine due to use of " + "'%select{co_await|co_yield|co_return}0' here">; +def err_coroutine_objc_method : Error< + "Objective-C methods as coroutines are not yet supported">; +def err_coroutine_unevaluated_context : Error< + "'%0' cannot be used in an unevaluated context">; +def err_coroutine_outside_function : Error< + "'%0' cannot be used outside a function">; +def err_coroutine_ctor_dtor : Error< + "'%1' cannot be used in a %select{constructor|destructor}0">; +def err_coroutine_constexpr : Error< + "'%0' cannot be used in a constexpr function">; +def err_coroutine_varargs : Error< + "'%0' cannot be used in a varargs function">; +def ext_coroutine_without_co_await_co_yield : ExtWarn< + "'co_return' used in a function " + "that uses neither 'co_await' nor 'co_yield'">, + InGroup<DiagGroup<"coreturn-without-coawait">>; +def err_implied_std_coroutine_traits_not_found : Error< + "you need to include <coroutine> before defining a coroutine">; +def err_malformed_std_coroutine_traits : Error< + "'std::coroutine_traits' must be a class template">; +def err_implied_std_coroutine_traits_promise_type_not_found : Error< + "this function cannot be a coroutine: %q0 has no member named 'promise_type'">; +def err_implied_std_coroutine_traits_promise_type_not_class : Error< + "this function cannot be a coroutine: %0 is not a class">; +def err_coroutine_traits_missing_specialization : Error< + "this function cannot be a coroutine: missing definition of " + "specialization %q0">; +} + +let CategoryName = "Documentation Issue" in { +def warn_not_a_doxygen_trailing_member_comment : Warning< + "not a Doxygen trailing comment">, InGroup<Documentation>, DefaultIgnore; +} // end of documentation issue category + +let CategoryName = "Instrumentation Issue" in { +def warn_profile_data_out_of_date : Warning< + "profile data may be out of date: of %0 function%s0, %1 %plural{1:has|:have}1" + " no data and %2 %plural{1:has|:have}2 mismatched data that will be ignored">, + InGroup<ProfileInstrOutOfDate>; +def warn_profile_data_unprofiled : Warning< + "no profile data available for file \"%0\"">, + InGroup<ProfileInstrUnprofiled>; + +} // end of instrumentation issue category + +let CategoryName = "Nullability Issue" in { + +def warn_mismatched_nullability_attr : Warning< + "nullability specifier %0 conflicts with existing specifier %1">, + InGroup<Nullability>; + +def warn_nullability_declspec : Warning< + "nullability specifier %0 cannot be applied " + "to non-pointer type %1; did you mean to apply the specifier to the " + "%select{pointer|block pointer|member pointer|function pointer|" + "member function pointer}2?">, + InGroup<NullabilityDeclSpec>, + DefaultError; + +def note_nullability_here : Note<"%0 specified here">; + +def err_nullability_nonpointer : Error< + "nullability specifier %0 cannot be applied to non-pointer type %1">; + +def warn_nullability_lost : Warning< + "implicit conversion from nullable pointer %0 to non-nullable pointer " + "type %1">, + InGroup<NullableToNonNullConversion>, DefaultIgnore; + +def err_nullability_cs_multilevel : Error< + "nullability keyword %0 cannot be applied to multi-level pointer type %1">; +def note_nullability_type_specifier : Note< + "use nullability type specifier %0 to affect the innermost " + "pointer type of %1">; + +def warn_null_resettable_setter : Warning< + "synthesized setter %0 for null_resettable property %1 does not handle nil">, + InGroup<Nullability>; + +def warn_nullability_missing : Warning< + "%select{pointer|block pointer|member pointer}0 is missing a nullability " + "type specifier (_Nonnull, _Nullable, or _Null_unspecified)">, + InGroup<NullabilityCompleteness>; + +def err_objc_type_arg_explicit_nullability : Error< + "type argument %0 cannot explicitly specify nullability">; + +def err_objc_type_param_bound_explicit_nullability : Error< + "type parameter %0 bound %1 cannot explicitly specify nullability">; + +} + +let CategoryName = "Generics Issue" in { + +def err_objc_type_param_bound_nonobject : Error< + "type bound %0 for type parameter %1 is not an Objective-C pointer type">; + +def err_objc_type_param_bound_missing_pointer : Error< + "missing '*' in type bound %0 for type parameter %1">; +def err_objc_type_param_bound_qualified : Error< + "type bound %1 for type parameter %0 cannot be qualified with '%2'">; + +def err_objc_type_param_redecl : Error< + "redeclaration of type parameter %0">; + +def err_objc_type_param_arity_mismatch : Error< + "%select{forward class declaration|class definition|category|extension}0 has " + "too %select{few|many}1 type parameters (expected %2, have %3)">; + +def err_objc_type_param_bound_conflict : Error< + "type bound %0 for type parameter %1 conflicts with " + "%select{implicit|previous}2 bound %3%select{for type parameter %5|}4">; + +def err_objc_type_param_variance_conflict : Error< + "%select{in|co|contra}0variant type parameter %1 conflicts with previous " + "%select{in|co|contra}2variant type parameter %3">; + +def note_objc_type_param_here : Note<"type parameter %0 declared here">; + +def err_objc_type_param_bound_missing : Error< + "missing type bound %0 for type parameter %1 in %select{@interface|@class}2">; + +def err_objc_parameterized_category_nonclass : Error< + "%select{extension|category}0 of non-parameterized class %1 cannot have type " + "parameters">; + +def err_objc_parameterized_forward_class : Error< + "forward declaration of non-parameterized class %0 cannot have type " + "parameters">; + +def err_objc_parameterized_forward_class_first : Error< + "class %0 previously declared with type parameters">; + +def err_objc_type_arg_missing_star : Error< + "type argument %0 must be a pointer (requires a '*')">; +def err_objc_type_arg_qualified : Error< + "type argument %0 cannot be qualified with '%1'">; + +def err_objc_type_arg_missing : Error< + "no type or protocol named %0">; + +def err_objc_type_args_and_protocols : Error< + "angle brackets contain both a %select{type|protocol}0 (%1) and a " + "%select{protocol|type}0 (%2)">; + +def err_objc_type_args_non_class : Error< + "type arguments cannot be applied to non-class type %0">; + +def err_objc_type_args_non_parameterized_class : Error< + "type arguments cannot be applied to non-parameterized class %0">; + +def err_objc_type_args_specialized_class : Error< + "type arguments cannot be applied to already-specialized class type %0">; + +def err_objc_type_args_wrong_arity : Error< + "too %select{many|few}0 type arguments for class %1 (have %2, expected %3)">; +} + +def err_objc_type_arg_not_id_compatible : Error< + "type argument %0 is neither an Objective-C object nor a block type">; + +def err_objc_type_arg_does_not_match_bound : Error< + "type argument %0 does not satisfy the bound (%1) of type parameter %2">; + +def warn_objc_redundant_qualified_class_type : Warning< + "parameterized class %0 already conforms to the protocols listed; did you " + "forget a '*'?">, InGroup<ObjCProtocolQualifiers>; + +} // end of sema component. diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSerializationKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSerializationKinds.td new file mode 100644 index 0000000..16c7743 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSerializationKinds.td @@ -0,0 +1,124 @@ +//==--- DiagnosticSerializationKinds.td - serialization diagnostics -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +let Component = "Serialization" in { +let CategoryName = "AST Deserialization Issue" in { + +def err_fe_unable_to_read_pch_file : Error< + "unable to read PCH file %0: '%1'">; +def err_fe_not_a_pch_file : Error< + "input is not a PCH file: '%0'">; +def err_fe_pch_malformed : Error< + "malformed or corrupted AST file: '%0'">, DefaultFatal; +def err_fe_pch_malformed_block : Error< + "malformed block record in PCH file: '%0'">, DefaultFatal; +def err_fe_pch_file_modified : Error< + "file '%0' has been modified since the precompiled header '%1' was built">, + DefaultFatal; +def err_fe_pch_file_overridden : Error< + "file '%0' from the precompiled header has been overridden">; +def note_pch_required_by : Note<"'%0' required by '%1'">; +def note_pch_rebuild_required : Note<"please rebuild precompiled header '%0'">; +def note_module_cache_path : Note< + "after modifying system headers, please delete the module cache at '%0'">; + +def err_pch_targetopt_mismatch : Error< + "PCH file was compiled for the %0 '%1' but the current translation " + "unit is being compiled for target '%2'">; +def err_pch_targetopt_feature_mismatch : Error< + "%select{AST file|current translation unit}0 was compiled with the target " + "feature'%1' but the %select{current translation unit is|AST file was}0 " + "not">; +def err_pch_langopt_mismatch : Error<"%0 was %select{disabled|enabled}1 in " + "PCH file but is currently %select{disabled|enabled}2">; +def err_pch_langopt_value_mismatch : Error< + "%0 differs in PCH file vs. current file">; +def err_pch_diagopt_mismatch : Error<"%0 is currently enabled, but was not in " + "the PCH file">; +def err_pch_modulecache_mismatch : Error<"PCH was compiled with module cache " + "path '%0', but the path is currently '%1'">; + +def err_pch_version_too_old : Error< + "PCH file uses an older PCH format that is no longer supported">; +def err_pch_version_too_new : Error< + "PCH file uses a newer PCH format that cannot be read">; +def err_pch_different_branch : Error< + "PCH file built from a different branch (%0) than the compiler (%1)">; +def err_pch_with_compiler_errors : Error< + "PCH file contains compiler errors">; + +def err_module_file_conflict : Error< + "module '%0' is defined in both '%1' and '%2'">, DefaultFatal; +def err_module_file_not_found : Error< + "%select{PCH|module|AST}0 file '%1' not found%select{|: %3}2">, DefaultFatal; +def err_module_file_out_of_date : Error< + "%select{PCH|module|AST}0 file '%1' is out of date and " + "needs to be rebuilt%select{|: %3}2">, DefaultFatal; +def err_module_file_invalid : Error< + "file '%1' is not a valid precompiled %select{PCH|module|AST}0 file">, DefaultFatal; +def note_module_file_imported_by : Note< + "imported by %select{|module '%2' in }1'%0'">; +def err_module_file_not_module : Error< + "AST file '%0' was not built as a module">, DefaultFatal; + +def err_imported_module_not_found : Error< + "module '%0' in AST file '%1' (imported by AST file '%2') " + "is not defined in any loaded module map file; " + "maybe you need to load '%3'?">, DefaultFatal; +def err_imported_module_modmap_changed : Error< + "module '%0' imported by AST file '%1' found in a different module map file" + " (%2) than when the importing AST file was built (%3)">, DefaultFatal; +def err_imported_module_relocated : Error< + "module '%0' was built in directory '%1' but now resides in " + "directory '%2'">, DefaultFatal; +def err_module_different_modmap : Error< + "module '%0' %select{uses|does not use}1 additional module map '%2'" + "%select{| not}1 used when the module was built">; + +def err_pch_macro_def_undef : Error< + "macro '%0' was %select{defined|undef'd}1 in the precompiled header but " + "%select{undef'd|defined}1 on the command line">; +def err_pch_macro_def_conflict : Error< + "definition of macro '%0' differs between the precompiled header ('%1') " + "and the command line ('%2')">; +def err_pch_undef : Error< + "%select{command line contains|precompiled header was built with}0 " + "'-undef' but %select{precompiled header was not built with it|" + "it is not present on the command line}0">; +def err_pch_pp_detailed_record : Error< + "%select{command line contains|precompiled header was built with}0 " + "'-detailed-preprocessing-record' but %select{precompiled header was not " + "built with it|it is not present on the command line}0">; + +def err_module_odr_violation_missing_decl : Error< + "%q0 from module '%1' is not present in definition of %q2" + "%select{ in module '%4'| provided earlier}3">, NoSFINAE; +def note_module_odr_violation_no_possible_decls : Note< + "definition has no member %0">; +def note_module_odr_violation_possible_decl : Note< + "declaration of %0 does not match">; +def err_module_odr_violation_different_definitions : Error< + "%q0 has different definitions in different modules; " + "%select{definition in module '%2' is here|defined here}1">; +def note_module_odr_violation_different_definitions : Note< + "definition in module '%0' is here">; +def err_module_odr_violation_different_instantiations : Error< + "instantiation of %q0 is different in different modules">; + +def warn_module_uses_date_time : Warning< + "%select{precompiled header|module}0 uses __DATE__ or __TIME__">, + InGroup<DiagGroup<"pch-date-time">>; + +def warn_duplicate_module_file_extension : Warning< + "duplicate module file extension block name '%0'">, + InGroup<ModuleFileExtension>; + +} // let CategoryName +} // let Component + diff --git a/contrib/llvm/tools/clang/include/clang/Basic/ExceptionSpecificationType.h b/contrib/llvm/tools/clang/include/clang/Basic/ExceptionSpecificationType.h new file mode 100644 index 0000000..132b5ba --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/ExceptionSpecificationType.h @@ -0,0 +1,60 @@ +//===--- ExceptionSpecificationType.h ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the ExceptionSpecificationType enumeration and various +/// utility functions. +/// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_BASIC_EXCEPTIONSPECIFICATIONTYPE_H +#define LLVM_CLANG_BASIC_EXCEPTIONSPECIFICATIONTYPE_H + +namespace clang { + +/// \brief The various types of exception specifications that exist in C++11. +enum ExceptionSpecificationType { + EST_None, ///< no exception specification + EST_DynamicNone, ///< throw() + EST_Dynamic, ///< throw(T1, T2) + EST_MSAny, ///< Microsoft throw(...) extension + EST_BasicNoexcept, ///< noexcept + EST_ComputedNoexcept, ///< noexcept(expression) + EST_Unevaluated, ///< not evaluated yet, for special member function + EST_Uninstantiated, ///< not instantiated yet + EST_Unparsed ///< not parsed yet +}; + +inline bool isDynamicExceptionSpec(ExceptionSpecificationType ESpecType) { + return ESpecType >= EST_DynamicNone && ESpecType <= EST_MSAny; +} + +inline bool isNoexceptExceptionSpec(ExceptionSpecificationType ESpecType) { + return ESpecType == EST_BasicNoexcept || ESpecType == EST_ComputedNoexcept; +} + +inline bool isUnresolvedExceptionSpec(ExceptionSpecificationType ESpecType) { + return ESpecType == EST_Unevaluated || ESpecType == EST_Uninstantiated; +} + +/// \brief Possible results from evaluation of a noexcept expression. +enum CanThrowResult { + CT_Cannot, + CT_Dependent, + CT_Can +}; + +inline CanThrowResult mergeCanThrow(CanThrowResult CT1, CanThrowResult CT2) { + // CanThrowResult constants are ordered so that the maximum is the correct + // merge result. + return CT1 > CT2 ? CT1 : CT2; +} + +} // end namespace clang + +#endif // LLVM_CLANG_BASIC_EXCEPTIONSPECIFICATIONTYPE_H diff --git a/contrib/llvm/tools/clang/include/clang/Basic/ExpressionTraits.h b/contrib/llvm/tools/clang/include/clang/Basic/ExpressionTraits.h new file mode 100644 index 0000000..0363a1d --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/ExpressionTraits.h @@ -0,0 +1,26 @@ +//===- ExpressionTraits.h - C++ Expression Traits Support Enums -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines enumerations for expression traits intrinsics. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_EXPRESSIONTRAITS_H +#define LLVM_CLANG_BASIC_EXPRESSIONTRAITS_H + +namespace clang { + + enum ExpressionTrait { + ET_IsLValueExpr, + ET_IsRValueExpr + }; +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/FileManager.h b/contrib/llvm/tools/clang/include/clang/Basic/FileManager.h new file mode 100644 index 0000000..17758ec --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/FileManager.h @@ -0,0 +1,288 @@ +//===--- FileManager.h - File System Probing and Caching --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the clang::FileManager interface and associated types. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_FILEMANAGER_H +#define LLVM_CLANG_BASIC_FILEMANAGER_H + +#include "clang/Basic/FileSystemOptions.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/VirtualFileSystem.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Allocator.h" +#include <memory> +#include <map> + +namespace llvm { +class MemoryBuffer; +} + +namespace clang { +class FileManager; +class FileSystemStatCache; + +/// \brief Cached information about one directory (either on disk or in +/// the virtual file system). +class DirectoryEntry { + const char *Name; // Name of the directory. + friend class FileManager; +public: + DirectoryEntry() : Name(nullptr) {} + const char *getName() const { return Name; } +}; + +/// \brief Cached information about one file (either on disk +/// or in the virtual file system). +/// +/// If the 'File' member is valid, then this FileEntry has an open file +/// descriptor for the file. +class FileEntry { + const char *Name; // Name of the file. + off_t Size; // File size in bytes. + time_t ModTime; // Modification time of file. + const DirectoryEntry *Dir; // Directory file lives in. + unsigned UID; // A unique (small) ID for the file. + llvm::sys::fs::UniqueID UniqueID; + bool IsNamedPipe; + bool InPCH; + bool IsValid; // Is this \c FileEntry initialized and valid? + + /// \brief The open file, if it is owned by the \p FileEntry. + mutable std::unique_ptr<vfs::File> File; + friend class FileManager; + + void operator=(const FileEntry &) = delete; + +public: + FileEntry() + : UniqueID(0, 0), IsNamedPipe(false), InPCH(false), IsValid(false) + {} + + // FIXME: this is here to allow putting FileEntry in std::map. Once we have + // emplace, we shouldn't need a copy constructor anymore. + /// Intentionally does not copy fields that are not set in an uninitialized + /// \c FileEntry. + FileEntry(const FileEntry &FE) : UniqueID(FE.UniqueID), + IsNamedPipe(FE.IsNamedPipe), InPCH(FE.InPCH), IsValid(FE.IsValid) { + assert(!isValid() && "Cannot copy an initialized FileEntry"); + } + + const char *getName() const { return Name; } + bool isValid() const { return IsValid; } + off_t getSize() const { return Size; } + unsigned getUID() const { return UID; } + const llvm::sys::fs::UniqueID &getUniqueID() const { return UniqueID; } + bool isInPCH() const { return InPCH; } + time_t getModificationTime() const { return ModTime; } + + /// \brief Return the directory the file lives in. + const DirectoryEntry *getDir() const { return Dir; } + + bool operator<(const FileEntry &RHS) const { return UniqueID < RHS.UniqueID; } + + /// \brief Check whether the file is a named pipe (and thus can't be opened by + /// the native FileManager methods). + bool isNamedPipe() const { return IsNamedPipe; } + + void closeFile() const { + File.reset(); // rely on destructor to close File + } +}; + +struct FileData; + +/// \brief Implements support for file system lookup, file system caching, +/// and directory search management. +/// +/// This also handles more advanced properties, such as uniquing files based +/// on "inode", so that a file with two names (e.g. symlinked) will be treated +/// as a single file. +/// +class FileManager : public RefCountedBase<FileManager> { + IntrusiveRefCntPtr<vfs::FileSystem> FS; + FileSystemOptions FileSystemOpts; + + /// \brief Cache for existing real directories. + std::map<llvm::sys::fs::UniqueID, DirectoryEntry> UniqueRealDirs; + + /// \brief Cache for existing real files. + std::map<llvm::sys::fs::UniqueID, FileEntry> UniqueRealFiles; + + /// \brief The virtual directories that we have allocated. + /// + /// For each virtual file (e.g. foo/bar/baz.cpp), we add all of its parent + /// directories (foo/ and foo/bar/) here. + SmallVector<std::unique_ptr<DirectoryEntry>, 4> VirtualDirectoryEntries; + /// \brief The virtual files that we have allocated. + SmallVector<std::unique_ptr<FileEntry>, 4> VirtualFileEntries; + + /// \brief A cache that maps paths to directory entries (either real or + /// virtual) we have looked up + /// + /// The actual Entries for real directories/files are + /// owned by UniqueRealDirs/UniqueRealFiles above, while the Entries + /// for virtual directories/files are owned by + /// VirtualDirectoryEntries/VirtualFileEntries above. + /// + llvm::StringMap<DirectoryEntry*, llvm::BumpPtrAllocator> SeenDirEntries; + + /// \brief A cache that maps paths to file entries (either real or + /// virtual) we have looked up. + /// + /// \see SeenDirEntries + llvm::StringMap<FileEntry*, llvm::BumpPtrAllocator> SeenFileEntries; + + /// \brief The canonical names of directories. + llvm::DenseMap<const DirectoryEntry *, llvm::StringRef> CanonicalDirNames; + + /// \brief Storage for canonical names that we have computed. + llvm::BumpPtrAllocator CanonicalNameStorage; + + /// \brief Each FileEntry we create is assigned a unique ID #. + /// + unsigned NextFileUID; + + // Statistics. + unsigned NumDirLookups, NumFileLookups; + unsigned NumDirCacheMisses, NumFileCacheMisses; + + // Caching. + std::unique_ptr<FileSystemStatCache> StatCache; + + bool getStatValue(const char *Path, FileData &Data, bool isFile, + std::unique_ptr<vfs::File> *F); + + /// Add all ancestors of the given path (pointing to either a file + /// or a directory) as virtual directories. + void addAncestorsAsVirtualDirs(StringRef Path); + +public: + FileManager(const FileSystemOptions &FileSystemOpts, + IntrusiveRefCntPtr<vfs::FileSystem> FS = nullptr); + ~FileManager(); + + /// \brief Installs the provided FileSystemStatCache object within + /// the FileManager. + /// + /// Ownership of this object is transferred to the FileManager. + /// + /// \param statCache the new stat cache to install. Ownership of this + /// object is transferred to the FileManager. + /// + /// \param AtBeginning whether this new stat cache must be installed at the + /// beginning of the chain of stat caches. Otherwise, it will be added to + /// the end of the chain. + void addStatCache(std::unique_ptr<FileSystemStatCache> statCache, + bool AtBeginning = false); + + /// \brief Removes the specified FileSystemStatCache object from the manager. + void removeStatCache(FileSystemStatCache *statCache); + + /// \brief Removes all FileSystemStatCache objects from the manager. + void clearStatCaches(); + + /// \brief Lookup, cache, and verify the specified directory (real or + /// virtual). + /// + /// This returns NULL if the directory doesn't exist. + /// + /// \param CacheFailure If true and the file does not exist, we'll cache + /// the failure to find this file. + const DirectoryEntry *getDirectory(StringRef DirName, + bool CacheFailure = true); + + /// \brief Lookup, cache, and verify the specified file (real or + /// virtual). + /// + /// This returns NULL if the file doesn't exist. + /// + /// \param OpenFile if true and the file exists, it will be opened. + /// + /// \param CacheFailure If true and the file does not exist, we'll cache + /// the failure to find this file. + const FileEntry *getFile(StringRef Filename, bool OpenFile = false, + bool CacheFailure = true); + + /// \brief Returns the current file system options + FileSystemOptions &getFileSystemOpts() { return FileSystemOpts; } + const FileSystemOptions &getFileSystemOpts() const { return FileSystemOpts; } + + IntrusiveRefCntPtr<vfs::FileSystem> getVirtualFileSystem() const { + return FS; + } + + /// \brief Retrieve a file entry for a "virtual" file that acts as + /// if there were a file with the given name on disk. + /// + /// The file itself is not accessed. + const FileEntry *getVirtualFile(StringRef Filename, off_t Size, + time_t ModificationTime); + + /// \brief Open the specified file as a MemoryBuffer, returning a new + /// MemoryBuffer if successful, otherwise returning null. + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> + getBufferForFile(const FileEntry *Entry, bool isVolatile = false, + bool ShouldCloseOpenFile = true); + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> + getBufferForFile(StringRef Filename); + + /// \brief Get the 'stat' information for the given \p Path. + /// + /// If the path is relative, it will be resolved against the WorkingDir of the + /// FileManager's FileSystemOptions. + /// + /// \returns false on success, true on error. + bool getNoncachedStatValue(StringRef Path, + vfs::Status &Result); + + /// \brief Remove the real file \p Entry from the cache. + void invalidateCache(const FileEntry *Entry); + + /// \brief If path is not absolute and FileSystemOptions set the working + /// directory, the path is modified to be relative to the given + /// working directory. + /// \returns true if \c path changed. + bool FixupRelativePath(SmallVectorImpl<char> &path) const; + + /// Makes \c Path absolute taking into account FileSystemOptions and the + /// working directory option. + /// \returns true if \c Path changed to absolute. + bool makeAbsolutePath(SmallVectorImpl<char> &Path) const; + + /// \brief Produce an array mapping from the unique IDs assigned to each + /// file to the corresponding FileEntry pointer. + void GetUniqueIDMapping( + SmallVectorImpl<const FileEntry *> &UIDToFiles) const; + + /// \brief Modifies the size and modification time of a previously created + /// FileEntry. Use with caution. + static void modifyFileEntry(FileEntry *File, off_t Size, + time_t ModificationTime); + + /// \brief Retrieve the canonical name for a given directory. + /// + /// This is a very expensive operation, despite its results being cached, + /// and should only be used when the physical layout of the file system is + /// required, which is (almost) never. + StringRef getCanonicalName(const DirectoryEntry *Dir); + + void PrintStats() const; +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/FileSystemOptions.h b/contrib/llvm/tools/clang/include/clang/Basic/FileSystemOptions.h new file mode 100644 index 0000000..38f1346 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/FileSystemOptions.h @@ -0,0 +1,32 @@ +//===--- FileSystemOptions.h - File System Options --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the clang::FileSystemOptions interface. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_FILESYSTEMOPTIONS_H +#define LLVM_CLANG_BASIC_FILESYSTEMOPTIONS_H + +#include <string> + +namespace clang { + +/// \brief Keeps track of options that affect how file operations are performed. +class FileSystemOptions { +public: + /// \brief If set, paths are resolved as if the working directory was + /// set to the value of WorkingDir. + std::string WorkingDir; +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/FileSystemStatCache.h b/contrib/llvm/tools/clang/include/clang/Basic/FileSystemStatCache.h new file mode 100644 index 0000000..cad9189 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/FileSystemStatCache.h @@ -0,0 +1,131 @@ +//===--- FileSystemStatCache.h - Caching for 'stat' calls -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the FileSystemStatCache interface. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_FILESYSTEMSTATCACHE_H +#define LLVM_CLANG_BASIC_FILESYSTEMSTATCACHE_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/FileSystem.h" +#include <memory> + +namespace clang { + +namespace vfs { +class File; +class FileSystem; +} + +// FIXME: should probably replace this with vfs::Status +struct FileData { + std::string Name; + uint64_t Size; + time_t ModTime; + llvm::sys::fs::UniqueID UniqueID; + bool IsDirectory; + bool IsNamedPipe; + bool InPCH; + bool IsVFSMapped; // FIXME: remove this when files support multiple names + FileData() + : Size(0), ModTime(0), IsDirectory(false), IsNamedPipe(false), + InPCH(false), IsVFSMapped(false) {} +}; + +/// \brief Abstract interface for introducing a FileManager cache for 'stat' +/// system calls, which is used by precompiled and pretokenized headers to +/// improve performance. +class FileSystemStatCache { + virtual void anchor(); +protected: + std::unique_ptr<FileSystemStatCache> NextStatCache; + +public: + virtual ~FileSystemStatCache() {} + + enum LookupResult { + CacheExists, ///< We know the file exists and its cached stat data. + CacheMissing ///< We know that the file doesn't exist. + }; + + /// \brief Get the 'stat' information for the specified path, using the cache + /// to accelerate it if possible. + /// + /// \returns \c true if the path does not exist or \c false if it exists. + /// + /// If isFile is true, then this lookup should only return success for files + /// (not directories). If it is false this lookup should only return + /// success for directories (not files). On a successful file lookup, the + /// implementation can optionally fill in \p F with a valid \p File object and + /// the client guarantees that it will close it. + static bool get(const char *Path, FileData &Data, bool isFile, + std::unique_ptr<vfs::File> *F, FileSystemStatCache *Cache, + vfs::FileSystem &FS); + + /// \brief Sets the next stat call cache in the chain of stat caches. + /// Takes ownership of the given stat cache. + void setNextStatCache(std::unique_ptr<FileSystemStatCache> Cache) { + NextStatCache = std::move(Cache); + } + + /// \brief Retrieve the next stat call cache in the chain. + FileSystemStatCache *getNextStatCache() { return NextStatCache.get(); } + + /// \brief Retrieve the next stat call cache in the chain, transferring + /// ownership of this cache (and, transitively, all of the remaining caches) + /// to the caller. + std::unique_ptr<FileSystemStatCache> takeNextStatCache() { + return std::move(NextStatCache); + } + +protected: + // FIXME: The pointer here is a non-owning/optional reference to the + // unique_ptr. Optional<unique_ptr<vfs::File>&> might be nicer, but + // Optional needs some work to support references so this isn't possible yet. + virtual LookupResult getStat(const char *Path, FileData &Data, bool isFile, + std::unique_ptr<vfs::File> *F, + vfs::FileSystem &FS) = 0; + + LookupResult statChained(const char *Path, FileData &Data, bool isFile, + std::unique_ptr<vfs::File> *F, vfs::FileSystem &FS) { + if (FileSystemStatCache *Next = getNextStatCache()) + return Next->getStat(Path, Data, isFile, F, FS); + + // If we hit the end of the list of stat caches to try, just compute and + // return it without a cache. + return get(Path, Data, isFile, F, nullptr, FS) ? CacheMissing : CacheExists; + } +}; + +/// \brief A stat "cache" that can be used by FileManager to keep +/// track of the results of stat() calls that occur throughout the +/// execution of the front end. +class MemorizeStatCalls : public FileSystemStatCache { +public: + /// \brief The set of stat() calls that have been seen. + llvm::StringMap<FileData, llvm::BumpPtrAllocator> StatCalls; + + typedef llvm::StringMap<FileData, llvm::BumpPtrAllocator>::const_iterator + iterator; + + iterator begin() const { return StatCalls.begin(); } + iterator end() const { return StatCalls.end(); } + + LookupResult getStat(const char *Path, FileData &Data, bool isFile, + std::unique_ptr<vfs::File> *F, + vfs::FileSystem &FS) override; +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/IdentifierTable.h b/contrib/llvm/tools/clang/include/clang/Basic/IdentifierTable.h new file mode 100644 index 0000000..d672314 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/IdentifierTable.h @@ -0,0 +1,876 @@ +//===--- IdentifierTable.h - Hash table for identifier lookup ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the clang::IdentifierInfo, clang::IdentifierTable, and +/// clang::Selector interfaces. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_IDENTIFIERTABLE_H +#define LLVM_CLANG_BASIC_IDENTIFIERTABLE_H + +#include "clang/Basic/LLVM.h" +#include "clang/Basic/TokenKinds.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include <cassert> +#include <string> + +namespace llvm { + template <typename T> struct DenseMapInfo; +} + +namespace clang { + class LangOptions; + class IdentifierInfo; + class IdentifierTable; + class SourceLocation; + class MultiKeywordSelector; // private class used by Selector + class DeclarationName; // AST class that stores declaration names + + /// \brief A simple pair of identifier info and location. + typedef std::pair<IdentifierInfo*, SourceLocation> IdentifierLocPair; + + +/// One of these records is kept for each identifier that +/// is lexed. This contains information about whether the token was \#define'd, +/// is a language keyword, or if it is a front-end token of some sort (e.g. a +/// variable or function name). The preprocessor keeps this information in a +/// set, and all tok::identifier tokens have a pointer to one of these. +class IdentifierInfo { + unsigned TokenID : 9; // Front-end token ID or tok::identifier. + // Objective-C keyword ('protocol' in '@protocol') or builtin (__builtin_inf). + // First NUM_OBJC_KEYWORDS values are for Objective-C, the remaining values + // are for builtins. + unsigned ObjCOrBuiltinID :13; + bool HasMacro : 1; // True if there is a #define for this. + bool HadMacro : 1; // True if there was a #define for this. + bool IsExtension : 1; // True if identifier is a lang extension. + bool IsFutureCompatKeyword : 1; // True if identifier is a keyword in a + // newer Standard or proposed Standard. + bool IsPoisoned : 1; // True if identifier is poisoned. + bool IsCPPOperatorKeyword : 1; // True if ident is a C++ operator keyword. + bool NeedsHandleIdentifier : 1; // See "RecomputeNeedsHandleIdentifier". + bool IsFromAST : 1; // True if identifier was loaded (at least + // partially) from an AST file. + bool ChangedAfterLoad : 1; // True if identifier has changed from the + // definition loaded from an AST file. + bool RevertedTokenID : 1; // True if revertTokenIDToIdentifier was + // called. + bool OutOfDate : 1; // True if there may be additional + // information about this identifier + // stored externally. + bool IsModulesImport : 1; // True if this is the 'import' contextual + // keyword. + // 30 bit left in 64-bit word. + + void *FETokenInfo; // Managed by the language front-end. + llvm::StringMapEntry<IdentifierInfo*> *Entry; + + IdentifierInfo(const IdentifierInfo&) = delete; + void operator=(const IdentifierInfo&) = delete; + + friend class IdentifierTable; + +public: + IdentifierInfo(); + + + /// \brief Return true if this is the identifier for the specified string. + /// + /// This is intended to be used for string literals only: II->isStr("foo"). + template <std::size_t StrLen> + bool isStr(const char (&Str)[StrLen]) const { + return getLength() == StrLen-1 && !memcmp(getNameStart(), Str, StrLen-1); + } + + /// \brief Return the beginning of the actual null-terminated string for this + /// identifier. + /// + const char *getNameStart() const { + if (Entry) return Entry->getKeyData(); + // FIXME: This is gross. It would be best not to embed specific details + // of the PTH file format here. + // The 'this' pointer really points to a + // std::pair<IdentifierInfo, const char*>, where internal pointer + // points to the external string data. + typedef std::pair<IdentifierInfo, const char*> actualtype; + return ((const actualtype*) this)->second; + } + + /// \brief Efficiently return the length of this identifier info. + /// + unsigned getLength() const { + if (Entry) return Entry->getKeyLength(); + // FIXME: This is gross. It would be best not to embed specific details + // of the PTH file format here. + // The 'this' pointer really points to a + // std::pair<IdentifierInfo, const char*>, where internal pointer + // points to the external string data. + typedef std::pair<IdentifierInfo, const char*> actualtype; + const char* p = ((const actualtype*) this)->second - 2; + return (((unsigned) p[0]) | (((unsigned) p[1]) << 8)) - 1; + } + + /// \brief Return the actual identifier string. + StringRef getName() const { + return StringRef(getNameStart(), getLength()); + } + + /// \brief Return true if this identifier is \#defined to some other value. + /// \note The current definition may be in a module and not currently visible. + bool hasMacroDefinition() const { + return HasMacro; + } + void setHasMacroDefinition(bool Val) { + if (HasMacro == Val) return; + + HasMacro = Val; + if (Val) { + NeedsHandleIdentifier = 1; + HadMacro = true; + } else { + RecomputeNeedsHandleIdentifier(); + } + } + /// \brief Returns true if this identifier was \#defined to some value at any + /// moment. In this case there should be an entry for the identifier in the + /// macro history table in Preprocessor. + bool hadMacroDefinition() const { + return HadMacro; + } + + /// If this is a source-language token (e.g. 'for'), this API + /// can be used to cause the lexer to map identifiers to source-language + /// tokens. + tok::TokenKind getTokenID() const { return (tok::TokenKind)TokenID; } + + /// \brief True if revertTokenIDToIdentifier() was called. + bool hasRevertedTokenIDToIdentifier() const { return RevertedTokenID; } + + /// \brief Revert TokenID to tok::identifier; used for GNU libstdc++ 4.2 + /// compatibility. + /// + /// TokenID is normally read-only but there are 2 instances where we revert it + /// to tok::identifier for libstdc++ 4.2. Keep track of when this happens + /// using this method so we can inform serialization about it. + void revertTokenIDToIdentifier() { + assert(TokenID != tok::identifier && "Already at tok::identifier"); + TokenID = tok::identifier; + RevertedTokenID = true; + } + void revertIdentifierToTokenID(tok::TokenKind TK) { + assert(TokenID == tok::identifier && "Should be at tok::identifier"); + TokenID = TK; + RevertedTokenID = false; + } + + /// \brief Return the preprocessor keyword ID for this identifier. + /// + /// For example, "define" will return tok::pp_define. + tok::PPKeywordKind getPPKeywordID() const; + + /// \brief Return the Objective-C keyword ID for the this identifier. + /// + /// For example, 'class' will return tok::objc_class if ObjC is enabled. + tok::ObjCKeywordKind getObjCKeywordID() const { + if (ObjCOrBuiltinID < tok::NUM_OBJC_KEYWORDS) + return tok::ObjCKeywordKind(ObjCOrBuiltinID); + else + return tok::objc_not_keyword; + } + void setObjCKeywordID(tok::ObjCKeywordKind ID) { ObjCOrBuiltinID = ID; } + + /// \brief True if setNotBuiltin() was called. + bool hasRevertedBuiltin() const { + return ObjCOrBuiltinID == tok::NUM_OBJC_KEYWORDS; + } + + /// \brief Revert the identifier to a non-builtin identifier. We do this if + /// the name of a known builtin library function is used to declare that + /// function, but an unexpected type is specified. + void revertBuiltin() { + setBuiltinID(0); + } + + /// \brief Return a value indicating whether this is a builtin function. + /// + /// 0 is not-built-in. 1 is builtin-for-some-nonprimary-target. + /// 2+ are specific builtin functions. + unsigned getBuiltinID() const { + if (ObjCOrBuiltinID >= tok::NUM_OBJC_KEYWORDS) + return ObjCOrBuiltinID - tok::NUM_OBJC_KEYWORDS; + else + return 0; + } + void setBuiltinID(unsigned ID) { + ObjCOrBuiltinID = ID + tok::NUM_OBJC_KEYWORDS; + assert(ObjCOrBuiltinID - unsigned(tok::NUM_OBJC_KEYWORDS) == ID + && "ID too large for field!"); + } + + unsigned getObjCOrBuiltinID() const { return ObjCOrBuiltinID; } + void setObjCOrBuiltinID(unsigned ID) { ObjCOrBuiltinID = ID; } + + /// get/setExtension - Initialize information about whether or not this + /// language token is an extension. This controls extension warnings, and is + /// only valid if a custom token ID is set. + bool isExtensionToken() const { return IsExtension; } + void setIsExtensionToken(bool Val) { + IsExtension = Val; + if (Val) + NeedsHandleIdentifier = 1; + else + RecomputeNeedsHandleIdentifier(); + } + + /// is/setIsFutureCompatKeyword - Initialize information about whether or not + /// this language token is a keyword in a newer or proposed Standard. This + /// controls compatibility warnings, and is only true when not parsing the + /// corresponding Standard. Once a compatibility problem has been diagnosed + /// with this keyword, the flag will be cleared. + bool isFutureCompatKeyword() const { return IsFutureCompatKeyword; } + void setIsFutureCompatKeyword(bool Val) { + IsFutureCompatKeyword = Val; + if (Val) + NeedsHandleIdentifier = 1; + else + RecomputeNeedsHandleIdentifier(); + } + + /// setIsPoisoned - Mark this identifier as poisoned. After poisoning, the + /// Preprocessor will emit an error every time this token is used. + void setIsPoisoned(bool Value = true) { + IsPoisoned = Value; + if (Value) + NeedsHandleIdentifier = 1; + else + RecomputeNeedsHandleIdentifier(); + } + + /// \brief Return true if this token has been poisoned. + bool isPoisoned() const { return IsPoisoned; } + + /// isCPlusPlusOperatorKeyword/setIsCPlusPlusOperatorKeyword controls whether + /// this identifier is a C++ alternate representation of an operator. + void setIsCPlusPlusOperatorKeyword(bool Val = true) { + IsCPPOperatorKeyword = Val; + if (Val) + NeedsHandleIdentifier = 1; + else + RecomputeNeedsHandleIdentifier(); + } + bool isCPlusPlusOperatorKeyword() const { return IsCPPOperatorKeyword; } + + /// \brief Return true if this token is a keyword in the specified language. + bool isKeyword(const LangOptions &LangOpts); + + /// getFETokenInfo/setFETokenInfo - The language front-end is allowed to + /// associate arbitrary metadata with this token. + template<typename T> + T *getFETokenInfo() const { return static_cast<T*>(FETokenInfo); } + void setFETokenInfo(void *T) { FETokenInfo = T; } + + /// \brief Return true if the Preprocessor::HandleIdentifier must be called + /// on a token of this identifier. + /// + /// If this returns false, we know that HandleIdentifier will not affect + /// the token. + bool isHandleIdentifierCase() const { return NeedsHandleIdentifier; } + + /// \brief Return true if the identifier in its current state was loaded + /// from an AST file. + bool isFromAST() const { return IsFromAST; } + + void setIsFromAST() { IsFromAST = true; } + + /// \brief Determine whether this identifier has changed since it was loaded + /// from an AST file. + bool hasChangedSinceDeserialization() const { + return ChangedAfterLoad; + } + + /// \brief Note that this identifier has changed since it was loaded from + /// an AST file. + void setChangedSinceDeserialization() { + ChangedAfterLoad = true; + } + + /// \brief Determine whether the information for this identifier is out of + /// date with respect to the external source. + bool isOutOfDate() const { return OutOfDate; } + + /// \brief Set whether the information for this identifier is out of + /// date with respect to the external source. + void setOutOfDate(bool OOD) { + OutOfDate = OOD; + if (OOD) + NeedsHandleIdentifier = true; + else + RecomputeNeedsHandleIdentifier(); + } + + /// \brief Determine whether this is the contextual keyword \c import. + bool isModulesImport() const { return IsModulesImport; } + + /// \brief Set whether this identifier is the contextual keyword \c import. + void setModulesImport(bool I) { + IsModulesImport = I; + if (I) + NeedsHandleIdentifier = true; + else + RecomputeNeedsHandleIdentifier(); + } + + /// \brief Provide less than operator for lexicographical sorting. + bool operator<(const IdentifierInfo &RHS) const { + return getName() < RHS.getName(); + } + +private: + /// The Preprocessor::HandleIdentifier does several special (but rare) + /// things to identifiers of various sorts. For example, it changes the + /// \c for keyword token from tok::identifier to tok::for. + /// + /// This method is very tied to the definition of HandleIdentifier. Any + /// change to it should be reflected here. + void RecomputeNeedsHandleIdentifier() { + NeedsHandleIdentifier = + (isPoisoned() | hasMacroDefinition() | isCPlusPlusOperatorKeyword() | + isExtensionToken() | isFutureCompatKeyword() || isOutOfDate() || + isModulesImport()); + } +}; + +/// \brief An RAII object for [un]poisoning an identifier within a scope. +/// +/// \p II is allowed to be null, in which case objects of this type have +/// no effect. +class PoisonIdentifierRAIIObject { + IdentifierInfo *const II; + const bool OldValue; +public: + PoisonIdentifierRAIIObject(IdentifierInfo *II, bool NewValue) + : II(II), OldValue(II ? II->isPoisoned() : false) { + if(II) + II->setIsPoisoned(NewValue); + } + + ~PoisonIdentifierRAIIObject() { + if(II) + II->setIsPoisoned(OldValue); + } +}; + +/// \brief An iterator that walks over all of the known identifiers +/// in the lookup table. +/// +/// Since this iterator uses an abstract interface via virtual +/// functions, it uses an object-oriented interface rather than the +/// more standard C++ STL iterator interface. In this OO-style +/// iteration, the single function \c Next() provides dereference, +/// advance, and end-of-sequence checking in a single +/// operation. Subclasses of this iterator type will provide the +/// actual functionality. +class IdentifierIterator { +private: + IdentifierIterator(const IdentifierIterator &) = delete; + void operator=(const IdentifierIterator &) = delete; + +protected: + IdentifierIterator() { } + +public: + virtual ~IdentifierIterator(); + + /// \brief Retrieve the next string in the identifier table and + /// advances the iterator for the following string. + /// + /// \returns The next string in the identifier table. If there is + /// no such string, returns an empty \c StringRef. + virtual StringRef Next() = 0; +}; + +/// \brief Provides lookups to, and iteration over, IdentiferInfo objects. +class IdentifierInfoLookup { +public: + virtual ~IdentifierInfoLookup(); + + /// \brief Return the IdentifierInfo for the specified named identifier. + /// + /// Unlike the version in IdentifierTable, this returns a pointer instead + /// of a reference. If the pointer is null then the IdentifierInfo cannot + /// be found. + virtual IdentifierInfo* get(StringRef Name) = 0; + + /// \brief Retrieve an iterator into the set of all identifiers + /// known to this identifier lookup source. + /// + /// This routine provides access to all of the identifiers known to + /// the identifier lookup, allowing access to the contents of the + /// identifiers without introducing the overhead of constructing + /// IdentifierInfo objects for each. + /// + /// \returns A new iterator into the set of known identifiers. The + /// caller is responsible for deleting this iterator. + virtual IdentifierIterator *getIdentifiers(); +}; + +/// \brief Implements an efficient mapping from strings to IdentifierInfo nodes. +/// +/// This has no other purpose, but this is an extremely performance-critical +/// piece of the code, as each occurrence of every identifier goes through +/// here when lexed. +class IdentifierTable { + // Shark shows that using MallocAllocator is *much* slower than using this + // BumpPtrAllocator! + typedef llvm::StringMap<IdentifierInfo*, llvm::BumpPtrAllocator> HashTableTy; + HashTableTy HashTable; + + IdentifierInfoLookup* ExternalLookup; + +public: + /// \brief Create the identifier table, populating it with info about the + /// language keywords for the language specified by \p LangOpts. + IdentifierTable(const LangOptions &LangOpts, + IdentifierInfoLookup* externalLookup = nullptr); + + /// \brief Set the external identifier lookup mechanism. + void setExternalIdentifierLookup(IdentifierInfoLookup *IILookup) { + ExternalLookup = IILookup; + } + + /// \brief Retrieve the external identifier lookup object, if any. + IdentifierInfoLookup *getExternalIdentifierLookup() const { + return ExternalLookup; + } + + llvm::BumpPtrAllocator& getAllocator() { + return HashTable.getAllocator(); + } + + /// \brief Return the identifier token info for the specified named + /// identifier. + IdentifierInfo &get(StringRef Name) { + auto &Entry = *HashTable.insert(std::make_pair(Name, nullptr)).first; + + IdentifierInfo *&II = Entry.second; + if (II) return *II; + + // No entry; if we have an external lookup, look there first. + if (ExternalLookup) { + II = ExternalLookup->get(Name); + if (II) + return *II; + } + + // Lookups failed, make a new IdentifierInfo. + void *Mem = getAllocator().Allocate<IdentifierInfo>(); + II = new (Mem) IdentifierInfo(); + + // Make sure getName() knows how to find the IdentifierInfo + // contents. + II->Entry = &Entry; + + return *II; + } + + IdentifierInfo &get(StringRef Name, tok::TokenKind TokenCode) { + IdentifierInfo &II = get(Name); + II.TokenID = TokenCode; + assert(II.TokenID == (unsigned) TokenCode && "TokenCode too large"); + return II; + } + + /// \brief Gets an IdentifierInfo for the given name without consulting + /// external sources. + /// + /// This is a version of get() meant for external sources that want to + /// introduce or modify an identifier. If they called get(), they would + /// likely end up in a recursion. + IdentifierInfo &getOwn(StringRef Name) { + auto &Entry = *HashTable.insert(std::make_pair(Name, nullptr)).first; + + IdentifierInfo *&II = Entry.second; + if (II) + return *II; + + // Lookups failed, make a new IdentifierInfo. + void *Mem = getAllocator().Allocate<IdentifierInfo>(); + II = new (Mem) IdentifierInfo(); + + // Make sure getName() knows how to find the IdentifierInfo + // contents. + II->Entry = &Entry; + + // If this is the 'import' contextual keyword, mark it as such. + if (Name.equals("import")) + II->setModulesImport(true); + + return *II; + } + + typedef HashTableTy::const_iterator iterator; + typedef HashTableTy::const_iterator const_iterator; + + iterator begin() const { return HashTable.begin(); } + iterator end() const { return HashTable.end(); } + unsigned size() const { return HashTable.size(); } + + /// \brief Print some statistics to stderr that indicate how well the + /// hashing is doing. + void PrintStats() const; + + void AddKeywords(const LangOptions &LangOpts); +}; + +/// \brief A family of Objective-C methods. +/// +/// These families have no inherent meaning in the language, but are +/// nonetheless central enough in the existing implementations to +/// merit direct AST support. While, in theory, arbitrary methods can +/// be considered to form families, we focus here on the methods +/// involving allocation and retain-count management, as these are the +/// most "core" and the most likely to be useful to diverse clients +/// without extra information. +/// +/// Both selectors and actual method declarations may be classified +/// into families. Method families may impose additional restrictions +/// beyond their selector name; for example, a method called '_init' +/// that returns void is not considered to be in the 'init' family +/// (but would be if it returned 'id'). It is also possible to +/// explicitly change or remove a method's family. Therefore the +/// method's family should be considered the single source of truth. +enum ObjCMethodFamily { + /// \brief No particular method family. + OMF_None, + + // Selectors in these families may have arbitrary arity, may be + // written with arbitrary leading underscores, and may have + // additional CamelCase "words" in their first selector chunk + // following the family name. + OMF_alloc, + OMF_copy, + OMF_init, + OMF_mutableCopy, + OMF_new, + + // These families are singletons consisting only of the nullary + // selector with the given name. + OMF_autorelease, + OMF_dealloc, + OMF_finalize, + OMF_release, + OMF_retain, + OMF_retainCount, + OMF_self, + OMF_initialize, + + // performSelector families + OMF_performSelector +}; + +/// Enough bits to store any enumerator in ObjCMethodFamily or +/// InvalidObjCMethodFamily. +enum { ObjCMethodFamilyBitWidth = 4 }; + +/// \brief An invalid value of ObjCMethodFamily. +enum { InvalidObjCMethodFamily = (1 << ObjCMethodFamilyBitWidth) - 1 }; + +/// \brief A family of Objective-C methods. +/// +/// These are family of methods whose result type is initially 'id', but +/// but are candidate for the result type to be changed to 'instancetype'. +enum ObjCInstanceTypeFamily { + OIT_None, + OIT_Array, + OIT_Dictionary, + OIT_Singleton, + OIT_Init, + OIT_ReturnsSelf +}; + +enum ObjCStringFormatFamily { + SFF_None, + SFF_NSString, + SFF_CFString +}; + +/// \brief Smart pointer class that efficiently represents Objective-C method +/// names. +/// +/// This class will either point to an IdentifierInfo or a +/// MultiKeywordSelector (which is private). This enables us to optimize +/// selectors that take no arguments and selectors that take 1 argument, which +/// accounts for 78% of all selectors in Cocoa.h. +class Selector { + friend class Diagnostic; + + enum IdentifierInfoFlag { + // Empty selector = 0. + ZeroArg = 0x1, + OneArg = 0x2, + MultiArg = 0x3, + ArgFlags = ZeroArg|OneArg + }; + uintptr_t InfoPtr; // a pointer to the MultiKeywordSelector or IdentifierInfo. + + Selector(IdentifierInfo *II, unsigned nArgs) { + InfoPtr = reinterpret_cast<uintptr_t>(II); + assert((InfoPtr & ArgFlags) == 0 &&"Insufficiently aligned IdentifierInfo"); + assert(nArgs < 2 && "nArgs not equal to 0/1"); + InfoPtr |= nArgs+1; + } + Selector(MultiKeywordSelector *SI) { + InfoPtr = reinterpret_cast<uintptr_t>(SI); + assert((InfoPtr & ArgFlags) == 0 &&"Insufficiently aligned IdentifierInfo"); + InfoPtr |= MultiArg; + } + + IdentifierInfo *getAsIdentifierInfo() const { + if (getIdentifierInfoFlag() < MultiArg) + return reinterpret_cast<IdentifierInfo *>(InfoPtr & ~ArgFlags); + return nullptr; + } + MultiKeywordSelector *getMultiKeywordSelector() const { + return reinterpret_cast<MultiKeywordSelector *>(InfoPtr & ~ArgFlags); + } + + unsigned getIdentifierInfoFlag() const { + return InfoPtr & ArgFlags; + } + + static ObjCMethodFamily getMethodFamilyImpl(Selector sel); + + static ObjCStringFormatFamily getStringFormatFamilyImpl(Selector sel); + +public: + friend class SelectorTable; // only the SelectorTable can create these + friend class DeclarationName; // and the AST's DeclarationName. + + /// The default ctor should only be used when creating data structures that + /// will contain selectors. + Selector() : InfoPtr(0) {} + Selector(uintptr_t V) : InfoPtr(V) {} + + /// operator==/!= - Indicate whether the specified selectors are identical. + bool operator==(Selector RHS) const { + return InfoPtr == RHS.InfoPtr; + } + bool operator!=(Selector RHS) const { + return InfoPtr != RHS.InfoPtr; + } + void *getAsOpaquePtr() const { + return reinterpret_cast<void*>(InfoPtr); + } + + /// \brief Determine whether this is the empty selector. + bool isNull() const { return InfoPtr == 0; } + + // Predicates to identify the selector type. + bool isKeywordSelector() const { + return getIdentifierInfoFlag() != ZeroArg; + } + bool isUnarySelector() const { + return getIdentifierInfoFlag() == ZeroArg; + } + unsigned getNumArgs() const; + + + /// \brief Retrieve the identifier at a given position in the selector. + /// + /// Note that the identifier pointer returned may be NULL. Clients that only + /// care about the text of the identifier string, and not the specific, + /// uniqued identifier pointer, should use \c getNameForSlot(), which returns + /// an empty string when the identifier pointer would be NULL. + /// + /// \param argIndex The index for which we want to retrieve the identifier. + /// This index shall be less than \c getNumArgs() unless this is a keyword + /// selector, in which case 0 is the only permissible value. + /// + /// \returns the uniqued identifier for this slot, or NULL if this slot has + /// no corresponding identifier. + IdentifierInfo *getIdentifierInfoForSlot(unsigned argIndex) const; + + /// \brief Retrieve the name at a given position in the selector. + /// + /// \param argIndex The index for which we want to retrieve the name. + /// This index shall be less than \c getNumArgs() unless this is a keyword + /// selector, in which case 0 is the only permissible value. + /// + /// \returns the name for this slot, which may be the empty string if no + /// name was supplied. + StringRef getNameForSlot(unsigned argIndex) const; + + /// \brief Derive the full selector name (e.g. "foo:bar:") and return + /// it as an std::string. + std::string getAsString() const; + + /// \brief Prints the full selector name (e.g. "foo:bar:"). + void print(llvm::raw_ostream &OS) const; + + /// \brief Derive the conventional family of this method. + ObjCMethodFamily getMethodFamily() const { + return getMethodFamilyImpl(*this); + } + + ObjCStringFormatFamily getStringFormatFamily() const { + return getStringFormatFamilyImpl(*this); + } + + static Selector getEmptyMarker() { + return Selector(uintptr_t(-1)); + } + static Selector getTombstoneMarker() { + return Selector(uintptr_t(-2)); + } + + static ObjCInstanceTypeFamily getInstTypeMethodFamily(Selector sel); +}; + +/// \brief This table allows us to fully hide how we implement +/// multi-keyword caching. +class SelectorTable { + void *Impl; // Actually a SelectorTableImpl + SelectorTable(const SelectorTable &) = delete; + void operator=(const SelectorTable &) = delete; +public: + SelectorTable(); + ~SelectorTable(); + + /// \brief Can create any sort of selector. + /// + /// \p NumArgs indicates whether this is a no argument selector "foo", a + /// single argument selector "foo:" or multi-argument "foo:bar:". + Selector getSelector(unsigned NumArgs, IdentifierInfo **IIV); + + Selector getUnarySelector(IdentifierInfo *ID) { + return Selector(ID, 1); + } + Selector getNullarySelector(IdentifierInfo *ID) { + return Selector(ID, 0); + } + + /// \brief Return the total amount of memory allocated for managing selectors. + size_t getTotalMemory() const; + + /// \brief Return the default setter name for the given identifier. + /// + /// This is "set" + \p Name where the initial character of \p Name + /// has been capitalized. + static SmallString<64> constructSetterName(StringRef Name); + + /// \brief Return the default setter selector for the given identifier. + /// + /// This is "set" + \p Name where the initial character of \p Name + /// has been capitalized. + static Selector constructSetterSelector(IdentifierTable &Idents, + SelectorTable &SelTable, + const IdentifierInfo *Name); +}; + +/// DeclarationNameExtra - Common base of the MultiKeywordSelector, +/// CXXSpecialName, and CXXOperatorIdName classes, all of which are +/// private classes that describe different kinds of names. +class DeclarationNameExtra { +public: + /// ExtraKind - The kind of "extra" information stored in the + /// DeclarationName. See @c ExtraKindOrNumArgs for an explanation of + /// how these enumerator values are used. + enum ExtraKind { + CXXConstructor = 0, + CXXDestructor, + CXXConversionFunction, +#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ + CXXOperator##Name, +#include "clang/Basic/OperatorKinds.def" + CXXLiteralOperator, + CXXUsingDirective, + NUM_EXTRA_KINDS + }; + + /// ExtraKindOrNumArgs - Either the kind of C++ special name or + /// operator-id (if the value is one of the CXX* enumerators of + /// ExtraKind), in which case the DeclarationNameExtra is also a + /// CXXSpecialName, (for CXXConstructor, CXXDestructor, or + /// CXXConversionFunction) CXXOperatorIdName, or CXXLiteralOperatorName, + /// it may be also name common to C++ using-directives (CXXUsingDirective), + /// otherwise it is NUM_EXTRA_KINDS+NumArgs, where NumArgs is the number of + /// arguments in the Objective-C selector, in which case the + /// DeclarationNameExtra is also a MultiKeywordSelector. + unsigned ExtraKindOrNumArgs; +}; + +} // end namespace clang + +namespace llvm { +/// Define DenseMapInfo so that Selectors can be used as keys in DenseMap and +/// DenseSets. +template <> +struct DenseMapInfo<clang::Selector> { + static inline clang::Selector getEmptyKey() { + return clang::Selector::getEmptyMarker(); + } + static inline clang::Selector getTombstoneKey() { + return clang::Selector::getTombstoneMarker(); + } + + static unsigned getHashValue(clang::Selector S); + + static bool isEqual(clang::Selector LHS, clang::Selector RHS) { + return LHS == RHS; + } +}; + +template <> +struct isPodLike<clang::Selector> { static const bool value = true; }; + +template <typename T> class PointerLikeTypeTraits; + +template<> +class PointerLikeTypeTraits<clang::Selector> { +public: + static inline const void *getAsVoidPointer(clang::Selector P) { + return P.getAsOpaquePtr(); + } + static inline clang::Selector getFromVoidPointer(const void *P) { + return clang::Selector(reinterpret_cast<uintptr_t>(P)); + } + enum { NumLowBitsAvailable = 0 }; +}; + +// Provide PointerLikeTypeTraits for IdentifierInfo pointers, which +// are not guaranteed to be 8-byte aligned. +template<> +class PointerLikeTypeTraits<clang::IdentifierInfo*> { +public: + static inline void *getAsVoidPointer(clang::IdentifierInfo* P) { + return P; + } + static inline clang::IdentifierInfo *getFromVoidPointer(void *P) { + return static_cast<clang::IdentifierInfo*>(P); + } + enum { NumLowBitsAvailable = 1 }; +}; + +template<> +class PointerLikeTypeTraits<const clang::IdentifierInfo*> { +public: + static inline const void *getAsVoidPointer(const clang::IdentifierInfo* P) { + return P; + } + static inline const clang::IdentifierInfo *getFromVoidPointer(const void *P) { + return static_cast<const clang::IdentifierInfo*>(P); + } + enum { NumLowBitsAvailable = 1 }; +}; + +} // end namespace llvm +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/LLVM.h b/contrib/llvm/tools/clang/include/clang/Basic/LLVM.h new file mode 100644 index 0000000..0e6ff92 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/LLVM.h @@ -0,0 +1,83 @@ +//===--- LLVM.h - Import various common LLVM datatypes ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file +/// \brief Forward-declares and imports various common LLVM datatypes that +/// clang wants to use unqualified. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_LLVM_H +#define LLVM_CLANG_BASIC_LLVM_H + +// Do not proliferate #includes here, require clients to #include their +// dependencies. +// Casting.h has complex templates that cannot be easily forward declared. +#include "llvm/Support/Casting.h" +// None.h includes an enumerator that is desired & cannot be forward declared +// without a definition of NoneType. +#include "llvm/ADT/None.h" + +namespace llvm { + // ADT's. + class StringRef; + class Twine; + template<typename T> class ArrayRef; + template<typename T> class MutableArrayRef; + template<unsigned InternalLen> class SmallString; + template<typename T, unsigned N> class SmallVector; + template<typename T> class SmallVectorImpl; + template<typename T> class Optional; + + template<typename T> + struct SaveAndRestore; + + // Reference counting. + template <typename T> class IntrusiveRefCntPtr; + template <typename T> struct IntrusiveRefCntPtrInfo; + template <class Derived> class RefCountedBase; + class RefCountedBaseVPTR; + + class raw_ostream; + class raw_pwrite_stream; + // TODO: DenseMap, ... +} + + +namespace clang { + // Casting operators. + using llvm::isa; + using llvm::cast; + using llvm::dyn_cast; + using llvm::dyn_cast_or_null; + using llvm::cast_or_null; + + // ADT's. + using llvm::None; + using llvm::Optional; + using llvm::StringRef; + using llvm::Twine; + using llvm::ArrayRef; + using llvm::MutableArrayRef; + using llvm::SmallString; + using llvm::SmallVector; + using llvm::SmallVectorImpl; + using llvm::SaveAndRestore; + + // Reference counting. + using llvm::IntrusiveRefCntPtr; + using llvm::IntrusiveRefCntPtrInfo; + using llvm::RefCountedBase; + using llvm::RefCountedBaseVPTR; + + using llvm::raw_ostream; + using llvm::raw_pwrite_stream; +} // end namespace clang. + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Lambda.h b/contrib/llvm/tools/clang/include/clang/Basic/Lambda.h new file mode 100644 index 0000000..e676e72 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/Lambda.h @@ -0,0 +1,43 @@ +//===--- Lambda.h - Types for C++ Lambdas -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines several types used to describe C++ lambda expressions +/// that are shared between the parser and AST. +/// +//===----------------------------------------------------------------------===// + + +#ifndef LLVM_CLANG_BASIC_LAMBDA_H +#define LLVM_CLANG_BASIC_LAMBDA_H + +namespace clang { + +/// \brief The default, if any, capture method for a lambda expression. +enum LambdaCaptureDefault { + LCD_None, + LCD_ByCopy, + LCD_ByRef +}; + +/// \brief The different capture forms in a lambda introducer +/// +/// C++11 allows capture of \c this, or of local variables by copy or +/// by reference. C++1y also allows "init-capture", where the initializer +/// is an expression. +enum LambdaCaptureKind { + LCK_This, ///< Capturing the \c this pointer + LCK_ByCopy, ///< Capturing by copy (a.k.a., by value) + LCK_ByRef, ///< Capturing by reference + LCK_VLAType ///< Capturing variable-length array type +}; + +} // end namespace clang + +#endif // LLVM_CLANG_BASIC_LAMBDA_H diff --git a/contrib/llvm/tools/clang/include/clang/Basic/LangOptions.def b/contrib/llvm/tools/clang/include/clang/Basic/LangOptions.def new file mode 100644 index 0000000..cc70d62 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/LangOptions.def @@ -0,0 +1,246 @@ +//===--- LangOptions.def - Language option database -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the language options. Users of this file must +// define the LANGOPT macro to make use of this information. +// +// Optionally, the user may also define: +// +// BENIGN_LANGOPT: for options that don't affect the construction of the AST in +// any way (that is, the value can be different between an implicit module +// and the user of that module). +// +// COMPATIBLE_LANGOPT: for options that affect the construction of the AST in +// a way that doesn't prevent interoperability (that is, the value can be +// different between an explicit module and the user of that module). +// +// ENUM_LANGOPT: for options that have enumeration, rather than unsigned, type. +// +// VALUE_LANGOPT: for options that describe a value rather than a flag. +// +// BENIGN_ENUM_LANGOPT, COMPATIBLE_ENUM_LANGOPT: combinations of the above. +// +// FIXME: Clients should be able to more easily select whether they want +// different levels of compatibility versus how to handle different kinds +// of option. +//===----------------------------------------------------------------------===// + +#ifndef LANGOPT +# error Define the LANGOPT macro to handle language options +#endif + +#ifndef COMPATIBLE_LANGOPT +# define COMPATIBLE_LANGOPT(Name, Bits, Default, Description) \ + LANGOPT(Name, Bits, Default, Description) +#endif + +#ifndef BENIGN_LANGOPT +# define BENIGN_LANGOPT(Name, Bits, Default, Description) \ + COMPATIBLE_LANGOPT(Name, Bits, Default, Description) +#endif + +#ifndef ENUM_LANGOPT +# define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ + LANGOPT(Name, Bits, Default, Description) +#endif + +#ifndef COMPATIBLE_ENUM_LANGOPT +# define COMPATIBLE_ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ + ENUM_LANGOPT(Name, Type, Bits, Default, Description) +#endif + +#ifndef BENIGN_ENUM_LANGOPT +# define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ + COMPATIBLE_ENUM_LANGOPT(Name, Type, Bits, Default, Description) +#endif + +#ifndef VALUE_LANGOPT +# define VALUE_LANGOPT(Name, Bits, Default, Description) \ + LANGOPT(Name, Bits, Default, Description) +#endif + +// FIXME: A lot of the BENIGN_ options should be COMPATIBLE_ instead. +LANGOPT(C99 , 1, 0, "C99") +LANGOPT(C11 , 1, 0, "C11") +LANGOPT(MSVCCompat , 1, 0, "Microsoft Visual C++ full compatibility mode") +LANGOPT(MicrosoftExt , 1, 0, "Microsoft C++ extensions") +LANGOPT(AsmBlocks , 1, 0, "Microsoft inline asm blocks") +LANGOPT(Borland , 1, 0, "Borland extensions") +LANGOPT(CPlusPlus , 1, 0, "C++") +LANGOPT(CPlusPlus11 , 1, 0, "C++11") +LANGOPT(CPlusPlus14 , 1, 0, "C++14") +LANGOPT(CPlusPlus1z , 1, 0, "C++1z") +LANGOPT(ObjC1 , 1, 0, "Objective-C 1") +LANGOPT(ObjC2 , 1, 0, "Objective-C 2") +BENIGN_LANGOPT(ObjCDefaultSynthProperties , 1, 0, + "Objective-C auto-synthesized properties") +BENIGN_LANGOPT(EncodeExtendedBlockSig , 1, 0, + "Encoding extended block type signature") +BENIGN_LANGOPT(ObjCInferRelatedResultType , 1, 1, + "Objective-C related result type inference") +LANGOPT(AppExt , 1, 0, "Objective-C App Extension") +LANGOPT(Trigraphs , 1, 0,"trigraphs") +LANGOPT(LineComment , 1, 0, "'//' comments") +LANGOPT(Bool , 1, 0, "bool, true, and false keywords") +LANGOPT(Half , 1, 0, "half keyword") +LANGOPT(WChar , 1, CPlusPlus, "wchar_t keyword") +LANGOPT(DeclSpecKeyword , 1, 0, "__declspec keyword") +BENIGN_LANGOPT(DollarIdents , 1, 1, "'$' in identifiers") +BENIGN_LANGOPT(AsmPreprocessor, 1, 0, "preprocessor in asm mode") +BENIGN_LANGOPT(GNUMode , 1, 1, "GNU extensions") +LANGOPT(GNUKeywords , 1, 1, "GNU keywords") +BENIGN_LANGOPT(ImplicitInt, 1, !C99 && !CPlusPlus, "C89 implicit 'int'") +LANGOPT(Digraphs , 1, 0, "digraphs") +BENIGN_LANGOPT(HexFloats , 1, C99, "C99 hexadecimal float constants") +LANGOPT(CXXOperatorNames , 1, 0, "C++ operator name keywords") +LANGOPT(AppleKext , 1, 0, "Apple kext support") +BENIGN_LANGOPT(PascalStrings, 1, 0, "Pascal string support") +LANGOPT(WritableStrings , 1, 0, "writable string support") +LANGOPT(ConstStrings , 1, 0, "const-qualified string support") +LANGOPT(LaxVectorConversions , 1, 1, "lax vector conversions") +LANGOPT(AltiVec , 1, 0, "AltiVec-style vector initializers") +LANGOPT(ZVector , 1, 0, "System z vector extensions") +LANGOPT(Exceptions , 1, 0, "exception handling") +LANGOPT(ObjCExceptions , 1, 0, "Objective-C exceptions") +LANGOPT(CXXExceptions , 1, 0, "C++ exceptions") +LANGOPT(SjLjExceptions , 1, 0, "setjmp-longjump exception handling") +LANGOPT(TraditionalCPP , 1, 0, "traditional CPP emulation") +LANGOPT(RTTI , 1, 1, "run-time type information") +LANGOPT(RTTIData , 1, 1, "emit run-time type information data") +LANGOPT(MSBitfields , 1, 0, "Microsoft-compatible structure layout") +LANGOPT(Freestanding, 1, 0, "freestanding implementation") +LANGOPT(NoBuiltin , 1, 0, "disable builtin functions") +LANGOPT(NoMathBuiltin , 1, 0, "disable math builtin functions") +LANGOPT(GNUAsm , 1, 1, "GNU-style inline assembly") +LANGOPT(Coroutines , 1, 0, "C++ coroutines") + +BENIGN_LANGOPT(ThreadsafeStatics , 1, 1, "thread-safe static initializers") +LANGOPT(POSIXThreads , 1, 0, "POSIX thread support") +LANGOPT(Blocks , 1, 0, "blocks extension to C") +BENIGN_LANGOPT(EmitAllDecls , 1, 0, "support for emitting all declarations") +LANGOPT(MathErrno , 1, 1, "errno support for math functions") +BENIGN_LANGOPT(HeinousExtensions , 1, 0, "Extensions that we really don't like and may be ripped out at any time") +LANGOPT(Modules , 1, 0, "modules extension to C") +COMPATIBLE_LANGOPT(ModulesDeclUse , 1, 0, "require declaration of module uses") +LANGOPT(ModulesSearchAll , 1, 1, "search even non-imported modules to find unresolved references") +COMPATIBLE_LANGOPT(ModulesStrictDeclUse, 1, 0, "require declaration of module uses and all headers to be in modules") +BENIGN_LANGOPT(ModulesErrorRecovery, 1, 1, "automatically import modules as needed when performing error recovery") +BENIGN_LANGOPT(ImplicitModules, 1, 1, "build modules that are not specified via -fmodule-file") +COMPATIBLE_LANGOPT(ModulesLocalVisibility, 1, 0, "local submodule visibility") +COMPATIBLE_LANGOPT(Optimize , 1, 0, "__OPTIMIZE__ predefined macro") +COMPATIBLE_LANGOPT(OptimizeSize , 1, 0, "__OPTIMIZE_SIZE__ predefined macro") +LANGOPT(Static , 1, 0, "__STATIC__ predefined macro (as opposed to __DYNAMIC__)") +VALUE_LANGOPT(PackStruct , 32, 0, + "default struct packing maximum alignment") +VALUE_LANGOPT(MaxTypeAlign , 32, 0, + "default maximum alignment for types") +VALUE_LANGOPT(PICLevel , 2, 0, "__PIC__ level") +VALUE_LANGOPT(PIELevel , 2, 0, "__PIE__ level") +LANGOPT(GNUInline , 1, 0, "GNU inline semantics") +COMPATIBLE_LANGOPT(NoInlineDefine , 1, 0, "__NO_INLINE__ predefined macro") +COMPATIBLE_LANGOPT(Deprecated , 1, 0, "__DEPRECATED predefined macro") +LANGOPT(FastMath , 1, 0, "__FAST_MATH__ predefined macro") +LANGOPT(FiniteMathOnly , 1, 0, "__FINITE_MATH_ONLY__ predefined macro") +LANGOPT(UnsafeFPMath , 1, 0, "Unsafe Floating Point Math") + +BENIGN_LANGOPT(ObjCGCBitmapPrint , 1, 0, "printing of GC's bitmap layout for __weak/__strong ivars") + +BENIGN_LANGOPT(AccessControl , 1, 1, "C++ access control") +LANGOPT(CharIsSigned , 1, 1, "signed char") +LANGOPT(ShortWChar , 1, 0, "unsigned short wchar_t") +ENUM_LANGOPT(MSPointerToMemberRepresentationMethod, PragmaMSPointersToMembersKind, 2, PPTMK_BestCase, "member-pointer representation method") + +LANGOPT(ShortEnums , 1, 0, "short enum types") + +LANGOPT(OpenCL , 1, 0, "OpenCL") +LANGOPT(OpenCLVersion , 32, 0, "OpenCL version") +LANGOPT(NativeHalfType , 1, 0, "Native half type support") +LANGOPT(HalfArgsAndReturns, 1, 0, "half args and returns") +LANGOPT(CUDA , 1, 0, "CUDA") +LANGOPT(OpenMP , 1, 0, "OpenMP support") +LANGOPT(OpenMPUseTLS , 1, 0, "Use TLS for threadprivates or runtime calls") +LANGOPT(OpenMPIsDevice , 1, 0, "Generate code only for OpenMP target device") + +LANGOPT(CUDAIsDevice , 1, 0, "Compiling for CUDA device") +LANGOPT(CUDAAllowHostCallsFromHostDevice, 1, 0, "Allow host device functions to call host functions") +LANGOPT(CUDADisableTargetCallChecks, 1, 0, "Disable checks for call targets (host, device, etc.)") +LANGOPT(CUDATargetOverloads, 1, 0, "Enable function overloads based on CUDA target attributes") + +LANGOPT(AssumeSaneOperatorNew , 1, 1, "implicit __attribute__((malloc)) for C++'s new operators") +LANGOPT(SizedDeallocation , 1, 0, "enable sized deallocation functions") +LANGOPT(ConceptsTS , 1, 0, "enable C++ Extensions for Concepts") +BENIGN_LANGOPT(ElideConstructors , 1, 1, "C++ copy constructor elision") +BENIGN_LANGOPT(DumpRecordLayouts , 1, 0, "dumping the layout of IRgen'd records") +BENIGN_LANGOPT(DumpRecordLayoutsSimple , 1, 0, "dumping the layout of IRgen'd records in a simple form") +BENIGN_LANGOPT(DumpVTableLayouts , 1, 0, "dumping the layouts of emitted vtables") +LANGOPT(NoConstantCFStrings , 1, 0, "no constant CoreFoundation strings") +BENIGN_LANGOPT(InlineVisibilityHidden , 1, 0, "hidden default visibility for inline C++ methods") +BENIGN_LANGOPT(ParseUnknownAnytype, 1, 0, "__unknown_anytype") +BENIGN_LANGOPT(DebuggerSupport , 1, 0, "debugger support") +BENIGN_LANGOPT(DebuggerCastResultToId, 1, 0, "for 'po' in the debugger, cast the result to id if it is of unknown type") +BENIGN_LANGOPT(DebuggerObjCLiteral , 1, 0, "debugger Objective-C literals and subscripting support") + +BENIGN_LANGOPT(SpellChecking , 1, 1, "spell-checking") +LANGOPT(SinglePrecisionConstants , 1, 0, "treating double-precision floating point constants as single precision constants") +LANGOPT(FastRelaxedMath , 1, 0, "OpenCL fast relaxed math") +LANGOPT(DefaultFPContract , 1, 0, "FP_CONTRACT") +LANGOPT(NoBitFieldTypeAlign , 1, 0, "bit-field type alignment") +LANGOPT(HexagonQdsp6Compat , 1, 0, "hexagon-qdsp6 backward compatibility") +LANGOPT(ObjCAutoRefCount , 1, 0, "Objective-C automated reference counting") +LANGOPT(ObjCWeakRuntime , 1, 0, "__weak support in the ARC runtime") +LANGOPT(ObjCWeak , 1, 0, "Objective-C __weak in ARC and MRC files") +LANGOPT(ObjCSubscriptingLegacyRuntime , 1, 0, "Subscripting support in legacy ObjectiveC runtime") +LANGOPT(FakeAddressSpaceMap , 1, 0, "OpenCL fake address space map") +ENUM_LANGOPT(AddressSpaceMapMangling , AddrSpaceMapMangling, 2, ASMM_Target, "OpenCL address space map mangling mode") + +LANGOPT(MRTD , 1, 0, "-mrtd calling convention") +BENIGN_LANGOPT(DelayedTemplateParsing , 1, 0, "delayed template parsing") +LANGOPT(BlocksRuntimeOptional , 1, 0, "optional blocks runtime") + +ENUM_LANGOPT(GC, GCMode, 2, NonGC, "Objective-C Garbage Collection mode") +ENUM_LANGOPT(ValueVisibilityMode, Visibility, 3, DefaultVisibility, + "value symbol visibility") +ENUM_LANGOPT(TypeVisibilityMode, Visibility, 3, DefaultVisibility, + "type symbol visibility") +ENUM_LANGOPT(StackProtector, StackProtectorMode, 2, SSPOff, + "stack protector mode") +ENUM_LANGOPT(SignedOverflowBehavior, SignedOverflowBehaviorTy, 2, SOB_Undefined, + "signed integer overflow handling") + +BENIGN_LANGOPT(ArrowDepth, 32, 256, + "maximum number of operator->s to follow") +BENIGN_LANGOPT(InstantiationDepth, 32, 256, + "maximum template instantiation depth") +BENIGN_LANGOPT(ConstexprCallDepth, 32, 512, + "maximum constexpr call depth") +BENIGN_LANGOPT(ConstexprStepLimit, 32, 1048576, + "maximum constexpr evaluation steps") +BENIGN_LANGOPT(BracketDepth, 32, 256, + "maximum bracket nesting depth") +BENIGN_LANGOPT(NumLargeByValueCopy, 32, 0, + "if non-zero, warn about parameter or return Warn if parameter/return value is larger in bytes than this setting. 0 is no check.") +VALUE_LANGOPT(MSCompatibilityVersion, 32, 0, "Microsoft Visual C/C++ Version") +VALUE_LANGOPT(VtorDispMode, 2, 1, "How many vtordisps to insert") + +LANGOPT(ApplePragmaPack, 1, 0, "Apple gcc-compatible #pragma pack handling") + +LANGOPT(RetainCommentsFromSystemHeaders, 1, 0, "retain documentation comments from system headers in the AST") + +LANGOPT(SanitizeAddressFieldPadding, 2, 0, "controls how aggressive is ASan " + "field padding (0: none, 1:least " + "aggressive, 2: more aggressive)") + +#undef LANGOPT +#undef COMPATIBLE_LANGOPT +#undef BENIGN_LANGOPT +#undef ENUM_LANGOPT +#undef COMPATIBLE_ENUM_LANGOPT +#undef BENIGN_ENUM_LANGOPT +#undef VALUE_LANGOPT + diff --git a/contrib/llvm/tools/clang/include/clang/Basic/LangOptions.h b/contrib/llvm/tools/clang/include/clang/Basic/LangOptions.h new file mode 100644 index 0000000..736d4e0 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/LangOptions.h @@ -0,0 +1,190 @@ +//===--- LangOptions.h - C Language Family Language Options -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the clang::LangOptions interface. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_LANGOPTIONS_H +#define LLVM_CLANG_BASIC_LANGOPTIONS_H + +#include "clang/Basic/CommentOptions.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/ObjCRuntime.h" +#include "clang/Basic/Sanitizers.h" +#include "clang/Basic/Visibility.h" +#include <string> +#include <vector> + +namespace clang { + +/// Bitfields of LangOptions, split out from LangOptions in order to ensure that +/// this large collection of bitfields is a trivial class type. +class LangOptionsBase { +public: + // Define simple language options (with no accessors). +#define LANGOPT(Name, Bits, Default, Description) unsigned Name : Bits; +#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) +#include "clang/Basic/LangOptions.def" + +protected: + // Define language options of enumeration type. These are private, and will + // have accessors (below). +#define LANGOPT(Name, Bits, Default, Description) +#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ + unsigned Name : Bits; +#include "clang/Basic/LangOptions.def" +}; + +/// \brief Keeps track of the various options that can be +/// enabled, which controls the dialect of C or C++ that is accepted. +class LangOptions : public LangOptionsBase { +public: + typedef clang::Visibility Visibility; + + enum GCMode { NonGC, GCOnly, HybridGC }; + enum StackProtectorMode { SSPOff, SSPOn, SSPStrong, SSPReq }; + + enum SignedOverflowBehaviorTy { + SOB_Undefined, // Default C standard behavior. + SOB_Defined, // -fwrapv + SOB_Trapping // -ftrapv + }; + + enum PragmaMSPointersToMembersKind { + PPTMK_BestCase, + PPTMK_FullGeneralitySingleInheritance, + PPTMK_FullGeneralityMultipleInheritance, + PPTMK_FullGeneralityVirtualInheritance + }; + + enum AddrSpaceMapMangling { ASMM_Target, ASMM_On, ASMM_Off }; + + enum MSVCMajorVersion { + MSVC2010 = 16, + MSVC2012 = 17, + MSVC2013 = 18, + MSVC2015 = 19 + }; + +public: + /// \brief Set of enabled sanitizers. + SanitizerSet Sanitize; + + /// \brief Paths to blacklist files specifying which objects + /// (files, functions, variables) should not be instrumented. + std::vector<std::string> SanitizerBlacklistFiles; + + clang::ObjCRuntime ObjCRuntime; + + std::string ObjCConstantStringClass; + + /// \brief The name of the handler function to be called when -ftrapv is + /// specified. + /// + /// If none is specified, abort (GCC-compatible behaviour). + std::string OverflowHandler; + + /// \brief The name of the current module. + std::string CurrentModule; + + /// \brief The name of the module that the translation unit is an + /// implementation of. Prevents semantic imports, but does not otherwise + /// treat this as the CurrentModule. + std::string ImplementationOfModule; + + /// \brief The names of any features to enable in module 'requires' decls + /// in addition to the hard-coded list in Module.cpp and the target features. + /// + /// This list is sorted. + std::vector<std::string> ModuleFeatures; + + /// \brief Options for parsing comments. + CommentOptions CommentOpts; + + /// \brief A list of all -fno-builtin-* function names (e.g., memset). + std::vector<std::string> NoBuiltinFuncs; + + /// \brief Triples of the OpenMP targets that the host code codegen should + /// take into account in order to generate accurate offloading descriptors. + std::vector<llvm::Triple> OMPTargetTriples; + + /// \brief Name of the IR file that contains the result of the OpenMP target + /// host code generation. + std::string OMPHostIRFile; + + LangOptions(); + + // Define accessors/mutators for language options of enumeration type. +#define LANGOPT(Name, Bits, Default, Description) +#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ + Type get##Name() const { return static_cast<Type>(Name); } \ + void set##Name(Type Value) { Name = static_cast<unsigned>(Value); } +#include "clang/Basic/LangOptions.def" + + bool isSignedOverflowDefined() const { + return getSignedOverflowBehavior() == SOB_Defined; + } + + bool isSubscriptPointerArithmetic() const { + return ObjCRuntime.isSubscriptPointerArithmetic() && + !ObjCSubscriptingLegacyRuntime; + } + + bool isCompatibleWithMSVC(MSVCMajorVersion MajorVersion) const { + return MSCompatibilityVersion >= MajorVersion * 10000000U; + } + + /// \brief Reset all of the options that are not considered when building a + /// module. + void resetNonModularOptions(); + + /// \brief Is this a libc/libm function that is no longer recognized as a + /// builtin because a -fno-builtin-* option has been specified? + bool isNoBuiltinFunc(const char *Name) const; +}; + +/// \brief Floating point control options +class FPOptions { +public: + unsigned fp_contract : 1; + + FPOptions() : fp_contract(0) {} + + FPOptions(const LangOptions &LangOpts) : + fp_contract(LangOpts.DefaultFPContract) {} +}; + +/// \brief OpenCL volatile options +class OpenCLOptions { +public: +#define OPENCLEXT(nm) unsigned nm : 1; +#include "clang/Basic/OpenCLExtensions.def" + + OpenCLOptions() { +#define OPENCLEXT(nm) nm = 0; +#include "clang/Basic/OpenCLExtensions.def" + } +}; + +/// \brief Describes the kind of translation unit being processed. +enum TranslationUnitKind { + /// \brief The translation unit is a complete translation unit. + TU_Complete, + /// \brief The translation unit is a prefix to a translation unit, and is + /// not complete. + TU_Prefix, + /// \brief The translation unit is a module. + TU_Module +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Linkage.h b/contrib/llvm/tools/clang/include/clang/Basic/Linkage.h new file mode 100644 index 0000000..8b15c8e --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/Linkage.h @@ -0,0 +1,110 @@ +//===--- Linkage.h - Linkage enumeration and utilities ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the Linkage enumeration and various utility functions. +/// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_BASIC_LINKAGE_H +#define LLVM_CLANG_BASIC_LINKAGE_H + +#include <assert.h> +#include <stdint.h> +#include <utility> + +namespace clang { + +/// \brief Describes the different kinds of linkage +/// (C++ [basic.link], C99 6.2.2) that an entity may have. +enum Linkage : unsigned char { + /// \brief No linkage, which means that the entity is unique and + /// can only be referred to from within its scope. + NoLinkage = 0, + + /// \brief Internal linkage, which indicates that the entity can + /// be referred to from within the translation unit (but not other + /// translation units). + InternalLinkage, + + /// \brief External linkage within a unique namespace. + /// + /// From the language perspective, these entities have external + /// linkage. However, since they reside in an anonymous namespace, + /// their names are unique to this translation unit, which is + /// equivalent to having internal linkage from the code-generation + /// point of view. + UniqueExternalLinkage, + + /// \brief No linkage according to the standard, but is visible from other + /// translation units because of types defined in a inline function. + VisibleNoLinkage, + + /// \brief External linkage, which indicates that the entity can + /// be referred to from other translation units. + ExternalLinkage +}; + +/// \brief Describes the different kinds of language linkage +/// (C++ [dcl.link]) that an entity may have. +enum LanguageLinkage { + CLanguageLinkage, + CXXLanguageLinkage, + NoLanguageLinkage +}; + +/// \brief A more specific kind of linkage than enum Linkage. +/// +/// This is relevant to CodeGen and AST file reading. +enum GVALinkage { + GVA_Internal, + GVA_AvailableExternally, + GVA_DiscardableODR, + GVA_StrongExternal, + GVA_StrongODR +}; + +inline bool isExternallyVisible(Linkage L) { + return L == ExternalLinkage || L == VisibleNoLinkage; +} + +inline Linkage getFormalLinkage(Linkage L) { + if (L == UniqueExternalLinkage) + return ExternalLinkage; + if (L == VisibleNoLinkage) + return NoLinkage; + return L; +} + +inline bool isExternalFormalLinkage(Linkage L) { + return getFormalLinkage(L) == ExternalLinkage; +} + +/// \brief Compute the minimum linkage given two linkages. +/// +/// The linkage can be interpreted as a pair formed by the formal linkage and +/// a boolean for external visibility. This is just what getFormalLinkage and +/// isExternallyVisible return. We want the minimum of both components. The +/// Linkage enum is defined in an order that makes this simple, we just need +/// special cases for when VisibleNoLinkage would lose the visible bit and +/// become NoLinkage. +inline Linkage minLinkage(Linkage L1, Linkage L2) { + if (L2 == VisibleNoLinkage) + std::swap(L1, L2); + if (L1 == VisibleNoLinkage) { + if (L2 == InternalLinkage) + return NoLinkage; + if (L2 == UniqueExternalLinkage) + return NoLinkage; + } + return L1 < L2 ? L1 : L2; +} + +} // end namespace clang + +#endif // LLVM_CLANG_BASIC_LINKAGE_H diff --git a/contrib/llvm/tools/clang/include/clang/Basic/MacroBuilder.h b/contrib/llvm/tools/clang/include/clang/Basic/MacroBuilder.h new file mode 100644 index 0000000..9a9eaa2 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/MacroBuilder.h @@ -0,0 +1,48 @@ +//===--- MacroBuilder.h - CPP Macro building utility ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the clang::MacroBuilder utility class. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_MACROBUILDER_H +#define LLVM_CLANG_BASIC_MACROBUILDER_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/raw_ostream.h" + +namespace clang { + +class MacroBuilder { + raw_ostream &Out; +public: + MacroBuilder(raw_ostream &Output) : Out(Output) {} + + /// Append a \#define line for macro of the form "\#define Name Value\n". + void defineMacro(const Twine &Name, const Twine &Value = "1") { + Out << "#define " << Name << ' ' << Value << '\n'; + } + + /// Append a \#undef line for Name. Name should be of the form XXX + /// and we emit "\#undef XXX". + void undefineMacro(const Twine &Name) { + Out << "#undef " << Name << '\n'; + } + + /// Directly append Str and a newline to the underlying buffer. + void append(const Twine &Str) { + Out << Str << '\n'; + } +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Module.h b/contrib/llvm/tools/clang/include/clang/Basic/Module.h new file mode 100644 index 0000000..1702fb1 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/Module.h @@ -0,0 +1,569 @@ +//===--- Module.h - Describe a module ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the clang::Module class, which describes a module in the +/// source code. +/// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_BASIC_MODULE_H +#define LLVM_CLANG_BASIC_MODULE_H + +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include <string> +#include <utility> +#include <vector> + +namespace llvm { + class raw_ostream; +} + +namespace clang { + +class LangOptions; +class TargetInfo; +class IdentifierInfo; + +/// \brief Describes the name of a module. +typedef SmallVector<std::pair<std::string, SourceLocation>, 2> ModuleId; + +/// \brief Describes a module or submodule. +class Module { +public: + /// \brief The name of this module. + std::string Name; + + /// \brief The location of the module definition. + SourceLocation DefinitionLoc; + + /// \brief The parent of this module. This will be NULL for the top-level + /// module. + Module *Parent; + + /// \brief The build directory of this module. This is the directory in + /// which the module is notionally built, and relative to which its headers + /// are found. + const DirectoryEntry *Directory; + + /// \brief The umbrella header or directory. + llvm::PointerUnion<const DirectoryEntry *, const FileEntry *> Umbrella; + + /// \brief The module signature. + uint64_t Signature; + + /// \brief The name of the umbrella entry, as written in the module map. + std::string UmbrellaAsWritten; + +private: + /// \brief The submodules of this module, indexed by name. + std::vector<Module *> SubModules; + + /// \brief A mapping from the submodule name to the index into the + /// \c SubModules vector at which that submodule resides. + llvm::StringMap<unsigned> SubModuleIndex; + + /// \brief The AST file if this is a top-level module which has a + /// corresponding serialized AST file, or null otherwise. + const FileEntry *ASTFile; + + /// \brief The top-level headers associated with this module. + llvm::SmallSetVector<const FileEntry *, 2> TopHeaders; + + /// \brief top-level header filenames that aren't resolved to FileEntries yet. + std::vector<std::string> TopHeaderNames; + + /// \brief Cache of modules visible to lookup in this module. + mutable llvm::DenseSet<const Module*> VisibleModulesCache; + + /// The ID used when referencing this module within a VisibleModuleSet. + unsigned VisibilityID; + +public: + enum HeaderKind { + HK_Normal, + HK_Textual, + HK_Private, + HK_PrivateTextual, + HK_Excluded + }; + static const int NumHeaderKinds = HK_Excluded + 1; + + /// \brief Information about a header directive as found in the module map + /// file. + struct Header { + std::string NameAsWritten; + const FileEntry *Entry; + + explicit operator bool() { return Entry; } + }; + + /// \brief Information about a directory name as found in the module map + /// file. + struct DirectoryName { + std::string NameAsWritten; + const DirectoryEntry *Entry; + + explicit operator bool() { return Entry; } + }; + + /// \brief The headers that are part of this module. + SmallVector<Header, 2> Headers[5]; + + /// \brief Stored information about a header directive that was found in the + /// module map file but has not been resolved to a file. + struct UnresolvedHeaderDirective { + SourceLocation FileNameLoc; + std::string FileName; + bool IsUmbrella; + }; + + /// \brief Headers that are mentioned in the module map file but could not be + /// found on the file system. + SmallVector<UnresolvedHeaderDirective, 1> MissingHeaders; + + /// \brief An individual requirement: a feature name and a flag indicating + /// the required state of that feature. + typedef std::pair<std::string, bool> Requirement; + + /// \brief The set of language features required to use this module. + /// + /// If any of these requirements are not available, the \c IsAvailable bit + /// will be false to indicate that this (sub)module is not available. + SmallVector<Requirement, 2> Requirements; + + /// \brief Whether this module is missing a feature from \c Requirements. + unsigned IsMissingRequirement : 1; + + /// \brief Whether we tried and failed to load a module file for this module. + unsigned HasIncompatibleModuleFile : 1; + + /// \brief Whether this module is available in the current translation unit. + /// + /// If the module is missing headers or does not meet all requirements then + /// this bit will be 0. + unsigned IsAvailable : 1; + + /// \brief Whether this module was loaded from a module file. + unsigned IsFromModuleFile : 1; + + /// \brief Whether this is a framework module. + unsigned IsFramework : 1; + + /// \brief Whether this is an explicit submodule. + unsigned IsExplicit : 1; + + /// \brief Whether this is a "system" module (which assumes that all + /// headers in it are system headers). + unsigned IsSystem : 1; + + /// \brief Whether this is an 'extern "C"' module (which implicitly puts all + /// headers in it within an 'extern "C"' block, and allows the module to be + /// imported within such a block). + unsigned IsExternC : 1; + + /// \brief Whether this is an inferred submodule (module * { ... }). + unsigned IsInferred : 1; + + /// \brief Whether we should infer submodules for this module based on + /// the headers. + /// + /// Submodules can only be inferred for modules with an umbrella header. + unsigned InferSubmodules : 1; + + /// \brief Whether, when inferring submodules, the inferred submodules + /// should be explicit. + unsigned InferExplicitSubmodules : 1; + + /// \brief Whether, when inferring submodules, the inferr submodules should + /// export all modules they import (e.g., the equivalent of "export *"). + unsigned InferExportWildcard : 1; + + /// \brief Whether the set of configuration macros is exhaustive. + /// + /// When the set of configuration macros is exhaustive, meaning + /// that no identifier not in this list should affect how the module is + /// built. + unsigned ConfigMacrosExhaustive : 1; + + /// \brief Describes the visibility of the various names within a + /// particular module. + enum NameVisibilityKind { + /// \brief All of the names in this module are hidden. + Hidden, + /// \brief All of the names in this module are visible. + AllVisible + }; + + /// \brief The visibility of names within this particular module. + NameVisibilityKind NameVisibility; + + /// \brief The location of the inferred submodule. + SourceLocation InferredSubmoduleLoc; + + /// \brief The set of modules imported by this module, and on which this + /// module depends. + llvm::SmallSetVector<Module *, 2> Imports; + + /// \brief Describes an exported module. + /// + /// The pointer is the module being re-exported, while the bit will be true + /// to indicate that this is a wildcard export. + typedef llvm::PointerIntPair<Module *, 1, bool> ExportDecl; + + /// \brief The set of export declarations. + SmallVector<ExportDecl, 2> Exports; + + /// \brief Describes an exported module that has not yet been resolved + /// (perhaps because the module it refers to has not yet been loaded). + struct UnresolvedExportDecl { + /// \brief The location of the 'export' keyword in the module map file. + SourceLocation ExportLoc; + + /// \brief The name of the module. + ModuleId Id; + + /// \brief Whether this export declaration ends in a wildcard, indicating + /// that all of its submodules should be exported (rather than the named + /// module itself). + bool Wildcard; + }; + + /// \brief The set of export declarations that have yet to be resolved. + SmallVector<UnresolvedExportDecl, 2> UnresolvedExports; + + /// \brief The directly used modules. + SmallVector<Module *, 2> DirectUses; + + /// \brief The set of use declarations that have yet to be resolved. + SmallVector<ModuleId, 2> UnresolvedDirectUses; + + /// \brief A library or framework to link against when an entity from this + /// module is used. + struct LinkLibrary { + LinkLibrary() : IsFramework(false) { } + LinkLibrary(const std::string &Library, bool IsFramework) + : Library(Library), IsFramework(IsFramework) { } + + /// \brief The library to link against. + /// + /// This will typically be a library or framework name, but can also + /// be an absolute path to the library or framework. + std::string Library; + + /// \brief Whether this is a framework rather than a library. + bool IsFramework; + }; + + /// \brief The set of libraries or frameworks to link against when + /// an entity from this module is used. + llvm::SmallVector<LinkLibrary, 2> LinkLibraries; + + /// \brief The set of "configuration macros", which are macros that + /// (intentionally) change how this module is built. + std::vector<std::string> ConfigMacros; + + /// \brief An unresolved conflict with another module. + struct UnresolvedConflict { + /// \brief The (unresolved) module id. + ModuleId Id; + + /// \brief The message provided to the user when there is a conflict. + std::string Message; + }; + + /// \brief The list of conflicts for which the module-id has not yet been + /// resolved. + std::vector<UnresolvedConflict> UnresolvedConflicts; + + /// \brief A conflict between two modules. + struct Conflict { + /// \brief The module that this module conflicts with. + Module *Other; + + /// \brief The message provided to the user when there is a conflict. + std::string Message; + }; + + /// \brief The list of conflicts. + std::vector<Conflict> Conflicts; + + /// \brief Construct a new module or submodule. + Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent, + bool IsFramework, bool IsExplicit, unsigned VisibilityID); + + ~Module(); + + /// \brief Determine whether this module is available for use within the + /// current translation unit. + bool isAvailable() const { return IsAvailable; } + + /// \brief Determine whether this module is available for use within the + /// current translation unit. + /// + /// \param LangOpts The language options used for the current + /// translation unit. + /// + /// \param Target The target options used for the current translation unit. + /// + /// \param Req If this module is unavailable, this parameter + /// will be set to one of the requirements that is not met for use of + /// this module. + bool isAvailable(const LangOptions &LangOpts, + const TargetInfo &Target, + Requirement &Req, + UnresolvedHeaderDirective &MissingHeader) const; + + /// \brief Determine whether this module is a submodule. + bool isSubModule() const { return Parent != nullptr; } + + /// \brief Determine whether this module is a submodule of the given other + /// module. + bool isSubModuleOf(const Module *Other) const; + + /// \brief Determine whether this module is a part of a framework, + /// either because it is a framework module or because it is a submodule + /// of a framework module. + bool isPartOfFramework() const { + for (const Module *Mod = this; Mod; Mod = Mod->Parent) + if (Mod->IsFramework) + return true; + + return false; + } + + /// \brief Determine whether this module is a subframework of another + /// framework. + bool isSubFramework() const { + return IsFramework && Parent && Parent->isPartOfFramework(); + } + + /// \brief Retrieve the full name of this module, including the path from + /// its top-level module. + std::string getFullModuleName() const; + + /// \brief Whether the full name of this module is equal to joining + /// \p nameParts with "."s. + /// + /// This is more efficient than getFullModuleName(). + bool fullModuleNameIs(ArrayRef<StringRef> nameParts) const; + + /// \brief Retrieve the top-level module for this (sub)module, which may + /// be this module. + Module *getTopLevelModule() { + return const_cast<Module *>( + const_cast<const Module *>(this)->getTopLevelModule()); + } + + /// \brief Retrieve the top-level module for this (sub)module, which may + /// be this module. + const Module *getTopLevelModule() const; + + /// \brief Retrieve the name of the top-level module. + /// + StringRef getTopLevelModuleName() const { + return getTopLevelModule()->Name; + } + + /// \brief The serialized AST file for this module, if one was created. + const FileEntry *getASTFile() const { + return getTopLevelModule()->ASTFile; + } + + /// \brief Set the serialized AST file for the top-level module of this module. + void setASTFile(const FileEntry *File) { + assert((File == nullptr || getASTFile() == nullptr || + getASTFile() == File) && "file path changed"); + getTopLevelModule()->ASTFile = File; + } + + /// \brief Retrieve the directory for which this module serves as the + /// umbrella. + DirectoryName getUmbrellaDir() const; + + /// \brief Retrieve the header that serves as the umbrella header for this + /// module. + Header getUmbrellaHeader() const { + if (auto *E = Umbrella.dyn_cast<const FileEntry *>()) + return Header{UmbrellaAsWritten, E}; + return Header{}; + } + + /// \brief Determine whether this module has an umbrella directory that is + /// not based on an umbrella header. + bool hasUmbrellaDir() const { + return Umbrella && Umbrella.is<const DirectoryEntry *>(); + } + + /// \brief Add a top-level header associated with this module. + void addTopHeader(const FileEntry *File) { + assert(File); + TopHeaders.insert(File); + } + + /// \brief Add a top-level header filename associated with this module. + void addTopHeaderFilename(StringRef Filename) { + TopHeaderNames.push_back(Filename); + } + + /// \brief The top-level headers associated with this module. + ArrayRef<const FileEntry *> getTopHeaders(FileManager &FileMgr); + + /// \brief Determine whether this module has declared its intention to + /// directly use another module. + bool directlyUses(const Module *Requested) const; + + /// \brief Add the given feature requirement to the list of features + /// required by this module. + /// + /// \param Feature The feature that is required by this module (and + /// its submodules). + /// + /// \param RequiredState The required state of this feature: \c true + /// if it must be present, \c false if it must be absent. + /// + /// \param LangOpts The set of language options that will be used to + /// evaluate the availability of this feature. + /// + /// \param Target The target options that will be used to evaluate the + /// availability of this feature. + void addRequirement(StringRef Feature, bool RequiredState, + const LangOptions &LangOpts, + const TargetInfo &Target); + + /// \brief Mark this module and all of its submodules as unavailable. + void markUnavailable(bool MissingRequirement = false); + + /// \brief Find the submodule with the given name. + /// + /// \returns The submodule if found, or NULL otherwise. + Module *findSubmodule(StringRef Name) const; + + /// \brief Determine whether the specified module would be visible to + /// a lookup at the end of this module. + /// + /// FIXME: This may return incorrect results for (submodules of) the + /// module currently being built, if it's queried before we see all + /// of its imports. + bool isModuleVisible(const Module *M) const { + if (VisibleModulesCache.empty()) + buildVisibleModulesCache(); + return VisibleModulesCache.count(M); + } + + unsigned getVisibilityID() const { return VisibilityID; } + + typedef std::vector<Module *>::iterator submodule_iterator; + typedef std::vector<Module *>::const_iterator submodule_const_iterator; + + submodule_iterator submodule_begin() { return SubModules.begin(); } + submodule_const_iterator submodule_begin() const {return SubModules.begin();} + submodule_iterator submodule_end() { return SubModules.end(); } + submodule_const_iterator submodule_end() const { return SubModules.end(); } + + llvm::iterator_range<submodule_iterator> submodules() { + return llvm::make_range(submodule_begin(), submodule_end()); + } + llvm::iterator_range<submodule_const_iterator> submodules() const { + return llvm::make_range(submodule_begin(), submodule_end()); + } + + /// \brief Appends this module's list of exported modules to \p Exported. + /// + /// This provides a subset of immediately imported modules (the ones that are + /// directly exported), not the complete set of exported modules. + void getExportedModules(SmallVectorImpl<Module *> &Exported) const; + + static StringRef getModuleInputBufferName() { + return "<module-includes>"; + } + + /// \brief Print the module map for this module to the given stream. + /// + void print(raw_ostream &OS, unsigned Indent = 0) const; + + /// \brief Dump the contents of this module to the given output stream. + void dump() const; + +private: + void buildVisibleModulesCache() const; +}; + +/// \brief A set of visible modules. +class VisibleModuleSet { +public: + VisibleModuleSet() : Generation(0) {} + VisibleModuleSet(VisibleModuleSet &&O) + : ImportLocs(std::move(O.ImportLocs)), Generation(O.Generation ? 1 : 0) { + O.ImportLocs.clear(); + ++O.Generation; + } + + /// Move from another visible modules set. Guaranteed to leave the source + /// empty and bump the generation on both. + VisibleModuleSet &operator=(VisibleModuleSet &&O) { + ImportLocs = std::move(O.ImportLocs); + O.ImportLocs.clear(); + ++O.Generation; + ++Generation; + return *this; + } + + /// \brief Get the current visibility generation. Incremented each time the + /// set of visible modules changes in any way. + unsigned getGeneration() const { return Generation; } + + /// \brief Determine whether a module is visible. + bool isVisible(const Module *M) const { + return getImportLoc(M).isValid(); + } + + /// \brief Get the location at which the import of a module was triggered. + SourceLocation getImportLoc(const Module *M) const { + return M->getVisibilityID() < ImportLocs.size() + ? ImportLocs[M->getVisibilityID()] + : SourceLocation(); + } + + /// \brief A callback to call when a module is made visible (directly or + /// indirectly) by a call to \ref setVisible. + typedef llvm::function_ref<void(Module *M)> VisibleCallback; + /// \brief A callback to call when a module conflict is found. \p Path + /// consists of a sequence of modules from the conflicting module to the one + /// made visible, where each was exported by the next. + typedef llvm::function_ref<void(ArrayRef<Module *> Path, + Module *Conflict, StringRef Message)> + ConflictCallback; + /// \brief Make a specific module visible. + void setVisible(Module *M, SourceLocation Loc, + VisibleCallback Vis = [](Module *) {}, + ConflictCallback Cb = [](ArrayRef<Module *>, Module *, + StringRef) {}); + +private: + /// Import locations for each visible module. Indexed by the module's + /// VisibilityID. + std::vector<SourceLocation> ImportLocs; + /// Visibility generation, bumped every time the visibility state changes. + unsigned Generation; +}; + +} // end namespace clang + + +#endif // LLVM_CLANG_BASIC_MODULE_H diff --git a/contrib/llvm/tools/clang/include/clang/Basic/ObjCRuntime.h b/contrib/llvm/tools/clang/include/clang/Basic/ObjCRuntime.h new file mode 100644 index 0000000..cf51b14 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/ObjCRuntime.h @@ -0,0 +1,333 @@ +//===--- ObjCRuntime.h - Objective-C Runtime Configuration ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines types useful for describing an Objective-C runtime. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_OBJCRUNTIME_H +#define LLVM_CLANG_BASIC_OBJCRUNTIME_H + +#include "clang/Basic/VersionTuple.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/ErrorHandling.h" + +namespace clang { + +/// \brief The basic abstraction for the target Objective-C runtime. +class ObjCRuntime { +public: + /// \brief The basic Objective-C runtimes that we know about. + enum Kind { + /// 'macosx' is the Apple-provided NeXT-derived runtime on Mac OS + /// X platforms that use the non-fragile ABI; the version is a + /// release of that OS. + MacOSX, + + /// 'macosx-fragile' is the Apple-provided NeXT-derived runtime on + /// Mac OS X platforms that use the fragile ABI; the version is a + /// release of that OS. + FragileMacOSX, + + /// 'ios' is the Apple-provided NeXT-derived runtime on iOS or the iOS + /// simulator; it is always non-fragile. The version is a release + /// version of iOS. + iOS, + + /// 'watchos' is a variant of iOS for Apple's watchOS. The version + /// is a release version of watchOS. + WatchOS, + + /// 'gcc' is the Objective-C runtime shipped with GCC, implementing a + /// fragile Objective-C ABI + GCC, + + /// 'gnustep' is the modern non-fragile GNUstep runtime. + GNUstep, + + /// 'objfw' is the Objective-C runtime included in ObjFW + ObjFW + }; + +private: + Kind TheKind; + VersionTuple Version; + +public: + /// A bogus initialization of the runtime. + ObjCRuntime() : TheKind(MacOSX) {} + + ObjCRuntime(Kind kind, const VersionTuple &version) + : TheKind(kind), Version(version) {} + + void set(Kind kind, VersionTuple version) { + TheKind = kind; + Version = version; + } + + Kind getKind() const { return TheKind; } + const VersionTuple &getVersion() const { return Version; } + + /// \brief Does this runtime follow the set of implied behaviors for a + /// "non-fragile" ABI? + bool isNonFragile() const { + switch (getKind()) { + case FragileMacOSX: return false; + case GCC: return false; + case MacOSX: return true; + case GNUstep: return true; + case ObjFW: return true; + case iOS: return true; + case WatchOS: return true; + } + llvm_unreachable("bad kind"); + } + + /// The inverse of isNonFragile(): does this runtime follow the set of + /// implied behaviors for a "fragile" ABI? + bool isFragile() const { return !isNonFragile(); } + + /// The default dispatch mechanism to use for the specified architecture + bool isLegacyDispatchDefaultForArch(llvm::Triple::ArchType Arch) { + // The GNUstep runtime uses a newer dispatch method by default from + // version 1.6 onwards + if (getKind() == GNUstep && getVersion() >= VersionTuple(1, 6)) { + if (Arch == llvm::Triple::arm || + Arch == llvm::Triple::x86 || + Arch == llvm::Triple::x86_64) + return false; + } + else if ((getKind() == MacOSX) && isNonFragile() && + (getVersion() >= VersionTuple(10, 0)) && + (getVersion() < VersionTuple(10, 6))) + return Arch != llvm::Triple::x86_64; + // Except for deployment target of 10.5 or less, + // Mac runtimes use legacy dispatch everywhere now. + return true; + } + + /// \brief Is this runtime basically of the GNU family of runtimes? + bool isGNUFamily() const { + switch (getKind()) { + case FragileMacOSX: + case MacOSX: + case iOS: + case WatchOS: + return false; + case GCC: + case GNUstep: + case ObjFW: + return true; + } + llvm_unreachable("bad kind"); + } + + /// \brief Is this runtime basically of the NeXT family of runtimes? + bool isNeXTFamily() const { + // For now, this is just the inverse of isGNUFamily(), but that's + // not inherently true. + return !isGNUFamily(); + } + + /// \brief Does this runtime allow ARC at all? + bool allowsARC() const { + switch (getKind()) { + case FragileMacOSX: + // No stub library for the fragile runtime. + return getVersion() >= VersionTuple(10, 7); + case MacOSX: return true; + case iOS: return true; + case WatchOS: return true; + case GCC: return false; + case GNUstep: return true; + case ObjFW: return true; + } + llvm_unreachable("bad kind"); + } + + /// \brief Does this runtime natively provide the ARC entrypoints? + /// + /// ARC cannot be directly supported on a platform that does not provide + /// these entrypoints, although it may be supportable via a stub + /// library. + bool hasNativeARC() const { + switch (getKind()) { + case FragileMacOSX: return getVersion() >= VersionTuple(10, 7); + case MacOSX: return getVersion() >= VersionTuple(10, 7); + case iOS: return getVersion() >= VersionTuple(5); + case WatchOS: return true; + + case GCC: return false; + case GNUstep: return getVersion() >= VersionTuple(1, 6); + case ObjFW: return true; + } + llvm_unreachable("bad kind"); + } + + /// \brief Does this runtime supports optimized setter entrypoints? + bool hasOptimizedSetter() const { + switch (getKind()) { + case MacOSX: + return getVersion() >= VersionTuple(10, 8); + case iOS: + return (getVersion() >= VersionTuple(6)); + case WatchOS: + return true; + case GNUstep: + return getVersion() >= VersionTuple(1, 7); + + default: + return false; + } + } + + /// Does this runtime allow the use of __weak? + bool allowsWeak() const { + return hasNativeWeak(); + } + + /// \brief Does this runtime natively provide ARC-compliant 'weak' + /// entrypoints? + bool hasNativeWeak() const { + // Right now, this is always equivalent to whether the runtime + // natively supports ARC decision. + return hasNativeARC(); + } + + /// \brief Does this runtime directly support the subscripting methods? + /// + /// This is really a property of the library, not the runtime. + bool hasSubscripting() const { + switch (getKind()) { + case FragileMacOSX: return false; + case MacOSX: return getVersion() >= VersionTuple(10, 8); + case iOS: return getVersion() >= VersionTuple(6); + case WatchOS: return true; + + // This is really a lie, because some implementations and versions + // of the runtime do not support ARC. Probably -fgnu-runtime + // should imply a "maximal" runtime or something? + case GCC: return true; + case GNUstep: return true; + case ObjFW: return true; + } + llvm_unreachable("bad kind"); + } + + /// \brief Does this runtime allow sizeof or alignof on object types? + bool allowsSizeofAlignof() const { + return isFragile(); + } + + /// \brief Does this runtime allow pointer arithmetic on objects? + /// + /// This covers +, -, ++, --, and (if isSubscriptPointerArithmetic() + /// yields true) []. + bool allowsPointerArithmetic() const { + switch (getKind()) { + case FragileMacOSX: + case GCC: + return true; + case MacOSX: + case iOS: + case WatchOS: + case GNUstep: + case ObjFW: + return false; + } + llvm_unreachable("bad kind"); + } + + /// \brief Is subscripting pointer arithmetic? + bool isSubscriptPointerArithmetic() const { + return allowsPointerArithmetic(); + } + + /// \brief Does this runtime provide an objc_terminate function? + /// + /// This is used in handlers for exceptions during the unwind process; + /// without it, abort() must be used in pure ObjC files. + bool hasTerminate() const { + switch (getKind()) { + case FragileMacOSX: return getVersion() >= VersionTuple(10, 8); + case MacOSX: return getVersion() >= VersionTuple(10, 8); + case iOS: return getVersion() >= VersionTuple(5); + case WatchOS: return true; + case GCC: return false; + case GNUstep: return false; + case ObjFW: return false; + } + llvm_unreachable("bad kind"); + } + + /// \brief Does this runtime support weakly importing classes? + bool hasWeakClassImport() const { + switch (getKind()) { + case MacOSX: return true; + case iOS: return true; + case WatchOS: return true; + case FragileMacOSX: return false; + case GCC: return true; + case GNUstep: return true; + case ObjFW: return true; + } + llvm_unreachable("bad kind"); + } + + /// \brief Does this runtime use zero-cost exceptions? + bool hasUnwindExceptions() const { + switch (getKind()) { + case MacOSX: return true; + case iOS: return true; + case WatchOS: return true; + case FragileMacOSX: return false; + case GCC: return true; + case GNUstep: return true; + case ObjFW: return true; + } + llvm_unreachable("bad kind"); + } + + bool hasAtomicCopyHelper() const { + switch (getKind()) { + case FragileMacOSX: + case MacOSX: + case iOS: + case WatchOS: + return true; + case GNUstep: + return getVersion() >= VersionTuple(1, 7); + default: return false; + } + } + + /// \brief Try to parse an Objective-C runtime specification from the given + /// string. + /// + /// \return true on error. + bool tryParse(StringRef input); + + std::string getAsString() const; + + friend bool operator==(const ObjCRuntime &left, const ObjCRuntime &right) { + return left.getKind() == right.getKind() && + left.getVersion() == right.getVersion(); + } + + friend bool operator!=(const ObjCRuntime &left, const ObjCRuntime &right) { + return !(left == right); + } +}; + +raw_ostream &operator<<(raw_ostream &out, const ObjCRuntime &value); + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/OpenCLExtensions.def b/contrib/llvm/tools/clang/include/clang/Basic/OpenCLExtensions.def new file mode 100644 index 0000000..91fd919 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/OpenCLExtensions.def @@ -0,0 +1,35 @@ +//===--- OpenCLExtensions.def - OpenCL extension list -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the list of supported OpenCL extensions. +// +//===----------------------------------------------------------------------===// + +// OpenCL 1.1. +OPENCLEXT(cl_khr_fp64) +OPENCLEXT(cl_khr_int64_base_atomics) +OPENCLEXT(cl_khr_int64_extended_atomics) +OPENCLEXT(cl_khr_fp16) +OPENCLEXT(cl_khr_gl_sharing) +OPENCLEXT(cl_khr_gl_event) +OPENCLEXT(cl_khr_d3d10_sharing) +OPENCLEXT(cl_khr_global_int32_base_atomics) +OPENCLEXT(cl_khr_global_int32_extended_atomics) +OPENCLEXT(cl_khr_local_int32_base_atomics) +OPENCLEXT(cl_khr_local_int32_extended_atomics) +OPENCLEXT(cl_khr_byte_addressable_store) +OPENCLEXT(cl_khr_3d_image_writes) + +// OpenCL 2.0 +OPENCLEXT(cl_khr_gl_msaa_sharing) + +// Clang Extensions. +OPENCLEXT(cl_clang_storage_class_specifiers) + +#undef OPENCLEXT diff --git a/contrib/llvm/tools/clang/include/clang/Basic/OpenMPKinds.def b/contrib/llvm/tools/clang/include/clang/Basic/OpenMPKinds.def new file mode 100644 index 0000000..44f77ad --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/OpenMPKinds.def @@ -0,0 +1,451 @@ +//===--- OpenMPKinds.def - OpenMP directives and clauses list ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// \brief This file defines the list of supported OpenMP directives and +/// clauses. +/// +//===----------------------------------------------------------------------===// + +#ifndef OPENMP_DIRECTIVE +# define OPENMP_DIRECTIVE(Name) +#endif +#ifndef OPENMP_DIRECTIVE_EXT +#define OPENMP_DIRECTIVE_EXT(Name, Str) +#endif +#ifndef OPENMP_CLAUSE +# define OPENMP_CLAUSE(Name, Class) +#endif +#ifndef OPENMP_PARALLEL_CLAUSE +# define OPENMP_PARALLEL_CLAUSE(Name) +#endif +#ifndef OPENMP_SIMD_CLAUSE +# define OPENMP_SIMD_CLAUSE(Name) +#endif +#ifndef OPENMP_FOR_CLAUSE +# define OPENMP_FOR_CLAUSE(Name) +#endif +#ifndef OPENMP_FOR_SIMD_CLAUSE +# define OPENMP_FOR_SIMD_CLAUSE(Name) +#endif +#ifndef OPENMP_SECTIONS_CLAUSE +# define OPENMP_SECTIONS_CLAUSE(Name) +#endif +#ifndef OPENMP_SINGLE_CLAUSE +# define OPENMP_SINGLE_CLAUSE(Name) +#endif +#ifndef OPENMP_PARALLEL_FOR_CLAUSE +# define OPENMP_PARALLEL_FOR_CLAUSE(Name) +#endif +#ifndef OPENMP_PARALLEL_FOR_SIMD_CLAUSE +# define OPENMP_PARALLEL_FOR_SIMD_CLAUSE(Name) +#endif +#ifndef OPENMP_PARALLEL_SECTIONS_CLAUSE +# define OPENMP_PARALLEL_SECTIONS_CLAUSE(Name) +#endif +#ifndef OPENMP_TASK_CLAUSE +# define OPENMP_TASK_CLAUSE(Name) +#endif +#ifndef OPENMP_ATOMIC_CLAUSE +# define OPENMP_ATOMIC_CLAUSE(Name) +#endif +#ifndef OPENMP_TARGET_CLAUSE +# define OPENMP_TARGET_CLAUSE(Name) +#endif +#ifndef OPENMP_TARGET_DATA_CLAUSE +# define OPENMP_TARGET_DATA_CLAUSE(Name) +#endif +#ifndef OPENMP_TEAMS_CLAUSE +# define OPENMP_TEAMS_CLAUSE(Name) +#endif +#ifndef OPENMP_CANCEL_CLAUSE +# define OPENMP_CANCEL_CLAUSE(Name) +#endif +#ifndef OPENMP_ORDERED_CLAUSE +# define OPENMP_ORDERED_CLAUSE(Name) +#endif +#ifndef OPENMP_TASKLOOP_CLAUSE +# define OPENMP_TASKLOOP_CLAUSE(Name) +#endif +#ifndef OPENMP_TASKLOOP_SIMD_CLAUSE +# define OPENMP_TASKLOOP_SIMD_CLAUSE(Name) +#endif +#ifndef OPENMP_CRITICAL_CLAUSE +# define OPENMP_CRITICAL_CLAUSE(Name) +#endif +#ifndef OPENMP_DISTRIBUTE_CLAUSE +#define OPENMP_DISTRIBUTE_CLAUSE(Name) +#endif +#ifndef OPENMP_DEFAULT_KIND +# define OPENMP_DEFAULT_KIND(Name) +#endif +#ifndef OPENMP_PROC_BIND_KIND +# define OPENMP_PROC_BIND_KIND(Name) +#endif +#ifndef OPENMP_SCHEDULE_KIND +#define OPENMP_SCHEDULE_KIND(Name) +#endif +#ifndef OPENMP_SCHEDULE_MODIFIER +#define OPENMP_SCHEDULE_MODIFIER(Name) +#endif +#ifndef OPENMP_DEPEND_KIND +#define OPENMP_DEPEND_KIND(Name) +#endif +#ifndef OPENMP_LINEAR_KIND +#define OPENMP_LINEAR_KIND(Name) +#endif +#ifndef OPENMP_MAP_KIND +#define OPENMP_MAP_KIND(Name) +#endif + +// OpenMP directives. +OPENMP_DIRECTIVE(threadprivate) +OPENMP_DIRECTIVE(parallel) +OPENMP_DIRECTIVE(task) +OPENMP_DIRECTIVE(simd) +OPENMP_DIRECTIVE(for) +OPENMP_DIRECTIVE(sections) +OPENMP_DIRECTIVE(section) +OPENMP_DIRECTIVE(single) +OPENMP_DIRECTIVE(master) +OPENMP_DIRECTIVE(critical) +OPENMP_DIRECTIVE(taskyield) +OPENMP_DIRECTIVE(barrier) +OPENMP_DIRECTIVE(taskwait) +OPENMP_DIRECTIVE(taskgroup) +OPENMP_DIRECTIVE(flush) +OPENMP_DIRECTIVE(ordered) +OPENMP_DIRECTIVE(atomic) +OPENMP_DIRECTIVE(target) +OPENMP_DIRECTIVE(teams) +OPENMP_DIRECTIVE(cancel) +OPENMP_DIRECTIVE_EXT(target_data, "target data") +OPENMP_DIRECTIVE_EXT(parallel_for, "parallel for") +OPENMP_DIRECTIVE_EXT(parallel_for_simd, "parallel for simd") +OPENMP_DIRECTIVE_EXT(parallel_sections, "parallel sections") +OPENMP_DIRECTIVE_EXT(for_simd, "for simd") +OPENMP_DIRECTIVE_EXT(cancellation_point, "cancellation point") +OPENMP_DIRECTIVE(taskloop) +OPENMP_DIRECTIVE_EXT(taskloop_simd, "taskloop simd") +OPENMP_DIRECTIVE(distribute) + +// OpenMP clauses. +OPENMP_CLAUSE(if, OMPIfClause) +OPENMP_CLAUSE(final, OMPFinalClause) +OPENMP_CLAUSE(num_threads, OMPNumThreadsClause) +OPENMP_CLAUSE(safelen, OMPSafelenClause) +OPENMP_CLAUSE(simdlen, OMPSimdlenClause) +OPENMP_CLAUSE(collapse, OMPCollapseClause) +OPENMP_CLAUSE(default, OMPDefaultClause) +OPENMP_CLAUSE(private, OMPPrivateClause) +OPENMP_CLAUSE(firstprivate, OMPFirstprivateClause) +OPENMP_CLAUSE(lastprivate, OMPLastprivateClause) +OPENMP_CLAUSE(shared, OMPSharedClause) +OPENMP_CLAUSE(reduction, OMPReductionClause) +OPENMP_CLAUSE(linear, OMPLinearClause) +OPENMP_CLAUSE(aligned, OMPAlignedClause) +OPENMP_CLAUSE(copyin, OMPCopyinClause) +OPENMP_CLAUSE(copyprivate, OMPCopyprivateClause) +OPENMP_CLAUSE(proc_bind, OMPProcBindClause) +OPENMP_CLAUSE(schedule, OMPScheduleClause) +OPENMP_CLAUSE(ordered, OMPOrderedClause) +OPENMP_CLAUSE(nowait, OMPNowaitClause) +OPENMP_CLAUSE(untied, OMPUntiedClause) +OPENMP_CLAUSE(mergeable, OMPMergeableClause) +OPENMP_CLAUSE(flush, OMPFlushClause) +OPENMP_CLAUSE(read, OMPReadClause) +OPENMP_CLAUSE(write, OMPWriteClause) +OPENMP_CLAUSE(update, OMPUpdateClause) +OPENMP_CLAUSE(capture, OMPCaptureClause) +OPENMP_CLAUSE(seq_cst, OMPSeqCstClause) +OPENMP_CLAUSE(depend, OMPDependClause) +OPENMP_CLAUSE(device, OMPDeviceClause) +OPENMP_CLAUSE(threads, OMPThreadsClause) +OPENMP_CLAUSE(simd, OMPSIMDClause) +OPENMP_CLAUSE(map, OMPMapClause) +OPENMP_CLAUSE(num_teams, OMPNumTeamsClause) +OPENMP_CLAUSE(thread_limit, OMPThreadLimitClause) +OPENMP_CLAUSE(priority, OMPPriorityClause) +OPENMP_CLAUSE(grainsize, OMPGrainsizeClause) +OPENMP_CLAUSE(nogroup, OMPNogroupClause) +OPENMP_CLAUSE(num_tasks, OMPNumTasksClause) +OPENMP_CLAUSE(hint, OMPHintClause) + +// Clauses allowed for OpenMP directive 'parallel'. +OPENMP_PARALLEL_CLAUSE(if) +OPENMP_PARALLEL_CLAUSE(num_threads) +OPENMP_PARALLEL_CLAUSE(default) +OPENMP_PARALLEL_CLAUSE(proc_bind) +OPENMP_PARALLEL_CLAUSE(private) +OPENMP_PARALLEL_CLAUSE(firstprivate) +OPENMP_PARALLEL_CLAUSE(shared) +OPENMP_PARALLEL_CLAUSE(reduction) +OPENMP_PARALLEL_CLAUSE(copyin) + +// Clauses allowed for directive 'omp simd'. +OPENMP_SIMD_CLAUSE(private) +OPENMP_SIMD_CLAUSE(lastprivate) +OPENMP_SIMD_CLAUSE(linear) +OPENMP_SIMD_CLAUSE(aligned) +OPENMP_SIMD_CLAUSE(safelen) +OPENMP_SIMD_CLAUSE(simdlen) +OPENMP_SIMD_CLAUSE(collapse) +OPENMP_SIMD_CLAUSE(reduction) + +// Clauses allowed for directive 'omp for'. +OPENMP_FOR_CLAUSE(private) +OPENMP_FOR_CLAUSE(lastprivate) +OPENMP_FOR_CLAUSE(firstprivate) +OPENMP_FOR_CLAUSE(reduction) +OPENMP_FOR_CLAUSE(collapse) +OPENMP_FOR_CLAUSE(schedule) +OPENMP_FOR_CLAUSE(ordered) +OPENMP_FOR_CLAUSE(nowait) +OPENMP_FOR_CLAUSE(linear) + +// Clauses allowed for directive 'omp for simd'. +OPENMP_FOR_SIMD_CLAUSE(private) +OPENMP_FOR_SIMD_CLAUSE(firstprivate) +OPENMP_FOR_SIMD_CLAUSE(lastprivate) +OPENMP_FOR_SIMD_CLAUSE(reduction) +OPENMP_FOR_SIMD_CLAUSE(schedule) +OPENMP_FOR_SIMD_CLAUSE(collapse) +OPENMP_FOR_SIMD_CLAUSE(nowait) +OPENMP_FOR_SIMD_CLAUSE(safelen) +OPENMP_FOR_SIMD_CLAUSE(simdlen) +OPENMP_FOR_SIMD_CLAUSE(linear) +OPENMP_FOR_SIMD_CLAUSE(aligned) +OPENMP_FOR_SIMD_CLAUSE(ordered) + +// Clauses allowed for OpenMP directive 'omp sections'. +OPENMP_SECTIONS_CLAUSE(private) +OPENMP_SECTIONS_CLAUSE(lastprivate) +OPENMP_SECTIONS_CLAUSE(firstprivate) +OPENMP_SECTIONS_CLAUSE(reduction) +OPENMP_SECTIONS_CLAUSE(nowait) + +// Clauses allowed for directive 'omp single'. +OPENMP_SINGLE_CLAUSE(private) +OPENMP_SINGLE_CLAUSE(firstprivate) +OPENMP_SINGLE_CLAUSE(copyprivate) +OPENMP_SINGLE_CLAUSE(nowait) + +// Clauses allowed for OpenMP directive 'cancel'. +OPENMP_CANCEL_CLAUSE(if) + +// Static attributes for 'default' clause. +OPENMP_DEFAULT_KIND(none) +OPENMP_DEFAULT_KIND(shared) + +// Static attributes for 'proc_bind' clause. +OPENMP_PROC_BIND_KIND(master) +OPENMP_PROC_BIND_KIND(close) +OPENMP_PROC_BIND_KIND(spread) + +// Static attributes for 'schedule' clause. +OPENMP_SCHEDULE_KIND(static) +OPENMP_SCHEDULE_KIND(dynamic) +OPENMP_SCHEDULE_KIND(guided) +OPENMP_SCHEDULE_KIND(auto) +OPENMP_SCHEDULE_KIND(runtime) + +// Modifiers for 'schedule' clause. +OPENMP_SCHEDULE_MODIFIER(monotonic) +OPENMP_SCHEDULE_MODIFIER(nonmonotonic) +OPENMP_SCHEDULE_MODIFIER(simd) + +// Static attributes for 'depend' clause. +OPENMP_DEPEND_KIND(in) +OPENMP_DEPEND_KIND(out) +OPENMP_DEPEND_KIND(inout) +OPENMP_DEPEND_KIND(source) +OPENMP_DEPEND_KIND(sink) + +// Modifiers for 'linear' clause. +OPENMP_LINEAR_KIND(val) +OPENMP_LINEAR_KIND(ref) +OPENMP_LINEAR_KIND(uval) + +// Clauses allowed for OpenMP directive 'parallel for'. +OPENMP_PARALLEL_FOR_CLAUSE(if) +OPENMP_PARALLEL_FOR_CLAUSE(num_threads) +OPENMP_PARALLEL_FOR_CLAUSE(default) +OPENMP_PARALLEL_FOR_CLAUSE(proc_bind) +OPENMP_PARALLEL_FOR_CLAUSE(private) +OPENMP_PARALLEL_FOR_CLAUSE(firstprivate) +OPENMP_PARALLEL_FOR_CLAUSE(shared) +OPENMP_PARALLEL_FOR_CLAUSE(reduction) +OPENMP_PARALLEL_FOR_CLAUSE(copyin) +OPENMP_PARALLEL_FOR_CLAUSE(lastprivate) +OPENMP_PARALLEL_FOR_CLAUSE(collapse) +OPENMP_PARALLEL_FOR_CLAUSE(schedule) +OPENMP_PARALLEL_FOR_CLAUSE(ordered) +OPENMP_PARALLEL_FOR_CLAUSE(linear) + +// Clauses allowed for OpenMP directive 'parallel for simd'. +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(if) +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(num_threads) +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(default) +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(proc_bind) +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(private) +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(firstprivate) +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(shared) +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(reduction) +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(copyin) +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(lastprivate) +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(collapse) +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(schedule) +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(safelen) +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(simdlen) +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(linear) +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(aligned) +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(ordered) + +// Clauses allowed for OpenMP directive 'parallel sections'. +OPENMP_PARALLEL_SECTIONS_CLAUSE(if) +OPENMP_PARALLEL_SECTIONS_CLAUSE(num_threads) +OPENMP_PARALLEL_SECTIONS_CLAUSE(default) +OPENMP_PARALLEL_SECTIONS_CLAUSE(proc_bind) +OPENMP_PARALLEL_SECTIONS_CLAUSE(private) +OPENMP_PARALLEL_SECTIONS_CLAUSE(firstprivate) +OPENMP_PARALLEL_SECTIONS_CLAUSE(shared) +OPENMP_PARALLEL_SECTIONS_CLAUSE(reduction) +OPENMP_PARALLEL_SECTIONS_CLAUSE(copyin) +OPENMP_PARALLEL_SECTIONS_CLAUSE(lastprivate) + +// Clauses allowed for OpenMP directive 'task'. +OPENMP_TASK_CLAUSE(if) +OPENMP_TASK_CLAUSE(final) +OPENMP_TASK_CLAUSE(default) +OPENMP_TASK_CLAUSE(private) +OPENMP_TASK_CLAUSE(firstprivate) +OPENMP_TASK_CLAUSE(shared) +OPENMP_TASK_CLAUSE(untied) +OPENMP_TASK_CLAUSE(mergeable) +OPENMP_TASK_CLAUSE(depend) +OPENMP_TASK_CLAUSE(priority) + +// Clauses allowed for OpenMP directive 'atomic'. +OPENMP_ATOMIC_CLAUSE(read) +OPENMP_ATOMIC_CLAUSE(write) +OPENMP_ATOMIC_CLAUSE(update) +OPENMP_ATOMIC_CLAUSE(capture) +OPENMP_ATOMIC_CLAUSE(seq_cst) + +// Clauses allowed for OpenMP directive 'target'. +// TODO More clauses for 'target' directive. +OPENMP_TARGET_CLAUSE(if) +OPENMP_TARGET_CLAUSE(device) +OPENMP_TARGET_CLAUSE(map) + +// Clauses allowed for OpenMP directive 'target data'. +// TODO More clauses for 'target data' directive. +OPENMP_TARGET_DATA_CLAUSE(if) +OPENMP_TARGET_DATA_CLAUSE(device) +OPENMP_TARGET_DATA_CLAUSE(map) + +// Clauses allowed for OpenMP directive 'teams'. +// TODO More clauses for 'teams' directive. +OPENMP_TEAMS_CLAUSE(default) +OPENMP_TEAMS_CLAUSE(private) +OPENMP_TEAMS_CLAUSE(firstprivate) +OPENMP_TEAMS_CLAUSE(shared) +OPENMP_TEAMS_CLAUSE(reduction) +OPENMP_TEAMS_CLAUSE(num_teams) +OPENMP_TEAMS_CLAUSE(thread_limit) + +// Clauses allowed for OpenMP directive 'ordered'. +// TODO More clauses for 'ordered' directive. +OPENMP_ORDERED_CLAUSE(threads) +OPENMP_ORDERED_CLAUSE(simd) +OPENMP_ORDERED_CLAUSE(depend) + +// Map types and map type modifier for 'map' clause. +OPENMP_MAP_KIND(alloc) +OPENMP_MAP_KIND(to) +OPENMP_MAP_KIND(from) +OPENMP_MAP_KIND(tofrom) +OPENMP_MAP_KIND(delete) +OPENMP_MAP_KIND(release) +OPENMP_MAP_KIND(always) + +// Clauses allowed for OpenMP directive 'taskloop'. +OPENMP_TASKLOOP_CLAUSE(if) +OPENMP_TASKLOOP_CLAUSE(shared) +OPENMP_TASKLOOP_CLAUSE(private) +OPENMP_TASKLOOP_CLAUSE(firstprivate) +OPENMP_TASKLOOP_CLAUSE(lastprivate) +OPENMP_TASKLOOP_CLAUSE(default) +OPENMP_TASKLOOP_CLAUSE(collapse) +OPENMP_TASKLOOP_CLAUSE(final) +OPENMP_TASKLOOP_CLAUSE(untied) +OPENMP_TASKLOOP_CLAUSE(mergeable) +OPENMP_TASKLOOP_CLAUSE(priority) +OPENMP_TASKLOOP_CLAUSE(grainsize) +OPENMP_TASKLOOP_CLAUSE(nogroup) +OPENMP_TASKLOOP_CLAUSE(num_tasks) + +// Clauses allowed for OpenMP directive 'taskloop simd'. +OPENMP_TASKLOOP_SIMD_CLAUSE(if) +OPENMP_TASKLOOP_SIMD_CLAUSE(shared) +OPENMP_TASKLOOP_SIMD_CLAUSE(private) +OPENMP_TASKLOOP_SIMD_CLAUSE(firstprivate) +OPENMP_TASKLOOP_SIMD_CLAUSE(lastprivate) +OPENMP_TASKLOOP_SIMD_CLAUSE(default) +OPENMP_TASKLOOP_SIMD_CLAUSE(collapse) +OPENMP_TASKLOOP_SIMD_CLAUSE(final) +OPENMP_TASKLOOP_SIMD_CLAUSE(untied) +OPENMP_TASKLOOP_SIMD_CLAUSE(mergeable) +OPENMP_TASKLOOP_SIMD_CLAUSE(priority) +OPENMP_TASKLOOP_SIMD_CLAUSE(linear) +OPENMP_TASKLOOP_SIMD_CLAUSE(aligned) +OPENMP_TASKLOOP_SIMD_CLAUSE(safelen) +OPENMP_TASKLOOP_SIMD_CLAUSE(simdlen) +OPENMP_TASKLOOP_SIMD_CLAUSE(grainsize) +OPENMP_TASKLOOP_SIMD_CLAUSE(nogroup) +OPENMP_TASKLOOP_SIMD_CLAUSE(num_tasks) + +// Clauses allowed for OpenMP directive 'critical'. +OPENMP_CRITICAL_CLAUSE(hint) + +// Clauses allowed for OpenMP directive 'distribute' +OPENMP_DISTRIBUTE_CLAUSE(private) +OPENMP_DISTRIBUTE_CLAUSE(firstprivate) +OPENMP_DISTRIBUTE_CLAUSE(lastprivate) +OPENMP_DISTRIBUTE_CLAUSE(collapse) + +#undef OPENMP_TASKLOOP_SIMD_CLAUSE +#undef OPENMP_TASKLOOP_CLAUSE +#undef OPENMP_LINEAR_KIND +#undef OPENMP_DEPEND_KIND +#undef OPENMP_SCHEDULE_MODIFIER +#undef OPENMP_SCHEDULE_KIND +#undef OPENMP_PROC_BIND_KIND +#undef OPENMP_DEFAULT_KIND +#undef OPENMP_DIRECTIVE +#undef OPENMP_DIRECTIVE_EXT +#undef OPENMP_CLAUSE +#undef OPENMP_CRITICAL_CLAUSE +#undef OPENMP_ORDERED_CLAUSE +#undef OPENMP_CANCEL_CLAUSE +#undef OPENMP_SINGLE_CLAUSE +#undef OPENMP_SECTIONS_CLAUSE +#undef OPENMP_PARALLEL_CLAUSE +#undef OPENMP_PARALLEL_FOR_CLAUSE +#undef OPENMP_PARALLEL_FOR_SIMD_CLAUSE +#undef OPENMP_PARALLEL_SECTIONS_CLAUSE +#undef OPENMP_TASK_CLAUSE +#undef OPENMP_ATOMIC_CLAUSE +#undef OPENMP_TARGET_CLAUSE +#undef OPENMP_TARGET_DATA_CLAUSE +#undef OPENMP_TEAMS_CLAUSE +#undef OPENMP_SIMD_CLAUSE +#undef OPENMP_FOR_CLAUSE +#undef OPENMP_FOR_SIMD_CLAUSE +#undef OPENMP_MAP_KIND +#undef OPENMP_DISTRIBUTE_CLAUSE diff --git a/contrib/llvm/tools/clang/include/clang/Basic/OpenMPKinds.h b/contrib/llvm/tools/clang/include/clang/Basic/OpenMPKinds.h new file mode 100644 index 0000000..d4d3db8 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/OpenMPKinds.h @@ -0,0 +1,175 @@ +//===--- OpenMPKinds.h - OpenMP enums ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines some OpenMP-specific enums and functions. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_OPENMPKINDS_H +#define LLVM_CLANG_BASIC_OPENMPKINDS_H + +#include "llvm/ADT/StringRef.h" + +namespace clang { + +/// \brief OpenMP directives. +enum OpenMPDirectiveKind { +#define OPENMP_DIRECTIVE(Name) \ + OMPD_##Name, +#define OPENMP_DIRECTIVE_EXT(Name, Str) \ + OMPD_##Name, +#include "clang/Basic/OpenMPKinds.def" + OMPD_unknown +}; + +/// \brief OpenMP clauses. +enum OpenMPClauseKind { +#define OPENMP_CLAUSE(Name, Class) \ + OMPC_##Name, +#include "clang/Basic/OpenMPKinds.def" + OMPC_threadprivate, + OMPC_unknown +}; + +/// \brief OpenMP attributes for 'default' clause. +enum OpenMPDefaultClauseKind { +#define OPENMP_DEFAULT_KIND(Name) \ + OMPC_DEFAULT_##Name, +#include "clang/Basic/OpenMPKinds.def" + OMPC_DEFAULT_unknown +}; + +/// \brief OpenMP attributes for 'proc_bind' clause. +enum OpenMPProcBindClauseKind { +#define OPENMP_PROC_BIND_KIND(Name) \ + OMPC_PROC_BIND_##Name, +#include "clang/Basic/OpenMPKinds.def" + OMPC_PROC_BIND_unknown +}; + +/// \brief OpenMP attributes for 'schedule' clause. +enum OpenMPScheduleClauseKind { +#define OPENMP_SCHEDULE_KIND(Name) \ + OMPC_SCHEDULE_##Name, +#include "clang/Basic/OpenMPKinds.def" + OMPC_SCHEDULE_unknown +}; + +/// \brief OpenMP modifiers for 'schedule' clause. +enum OpenMPScheduleClauseModifier { + OMPC_SCHEDULE_MODIFIER_unknown = OMPC_SCHEDULE_unknown, +#define OPENMP_SCHEDULE_MODIFIER(Name) \ + OMPC_SCHEDULE_MODIFIER_##Name, +#include "clang/Basic/OpenMPKinds.def" + OMPC_SCHEDULE_MODIFIER_last +}; + +/// \brief OpenMP attributes for 'depend' clause. +enum OpenMPDependClauseKind { +#define OPENMP_DEPEND_KIND(Name) \ + OMPC_DEPEND_##Name, +#include "clang/Basic/OpenMPKinds.def" + OMPC_DEPEND_unknown +}; + +/// \brief OpenMP attributes for 'linear' clause. +enum OpenMPLinearClauseKind { +#define OPENMP_LINEAR_KIND(Name) \ + OMPC_LINEAR_##Name, +#include "clang/Basic/OpenMPKinds.def" + OMPC_LINEAR_unknown +}; + +/// \brief OpenMP mapping kind for 'map' clause. +enum OpenMPMapClauseKind { +#define OPENMP_MAP_KIND(Name) \ + OMPC_MAP_##Name, +#include "clang/Basic/OpenMPKinds.def" + OMPC_MAP_unknown +}; + +OpenMPDirectiveKind getOpenMPDirectiveKind(llvm::StringRef Str); +const char *getOpenMPDirectiveName(OpenMPDirectiveKind Kind); + +OpenMPClauseKind getOpenMPClauseKind(llvm::StringRef Str); +const char *getOpenMPClauseName(OpenMPClauseKind Kind); + +unsigned getOpenMPSimpleClauseType(OpenMPClauseKind Kind, llvm::StringRef Str); +const char *getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, unsigned Type); + +bool isAllowedClauseForDirective(OpenMPDirectiveKind DKind, + OpenMPClauseKind CKind); + +/// \brief Checks if the specified directive is a directive with an associated +/// loop construct. +/// \param DKind Specified directive. +/// \return true - the directive is a loop-associated directive like 'omp simd' +/// or 'omp for' directive, otherwise - false. +bool isOpenMPLoopDirective(OpenMPDirectiveKind DKind); + +/// \brief Checks if the specified directive is a worksharing directive. +/// \param DKind Specified directive. +/// \return true - the directive is a worksharing directive like 'omp for', +/// otherwise - false. +bool isOpenMPWorksharingDirective(OpenMPDirectiveKind DKind); + +/// \brief Checks if the specified directive is a taskloop directive. +/// \param DKind Specified directive. +/// \return true - the directive is a worksharing directive like 'omp taskloop', +/// otherwise - false. +bool isOpenMPTaskLoopDirective(OpenMPDirectiveKind DKind); + +/// \brief Checks if the specified directive is a parallel-kind directive. +/// \param DKind Specified directive. +/// \return true - the directive is a parallel-like directive like 'omp +/// parallel', otherwise - false. +bool isOpenMPParallelDirective(OpenMPDirectiveKind DKind); + +/// \brief Checks if the specified directive is a target-kind directive. +/// \param DKind Specified directive. +/// \return true - the directive is a target-like directive like 'omp target', +/// otherwise - false. +bool isOpenMPTargetDirective(OpenMPDirectiveKind DKind); + +/// \brief Checks if the specified directive is a teams-kind directive. +/// \param DKind Specified directive. +/// \return true - the directive is a teams-like directive like 'omp teams', +/// otherwise - false. +bool isOpenMPTeamsDirective(OpenMPDirectiveKind DKind); + +/// \brief Checks if the specified directive is a simd directive. +/// \param DKind Specified directive. +/// \return true - the directive is a simd directive like 'omp simd', +/// otherwise - false. +bool isOpenMPSimdDirective(OpenMPDirectiveKind DKind); + +/// \brief Checks if the specified directive is a distribute directive. +/// \param DKind Specified directive. +/// \return true - the directive is a distribute-directive like 'omp +/// distribute', +/// otherwise - false. +bool isOpenMPDistributeDirective(OpenMPDirectiveKind DKind); + +/// \brief Checks if the specified clause is one of private clauses like +/// 'private', 'firstprivate', 'reduction' etc.. +/// \param Kind Clause kind. +/// \return true - the clause is a private clause, otherwise - false. +bool isOpenMPPrivate(OpenMPClauseKind Kind); + +/// \brief Checks if the specified clause is one of threadprivate clauses like +/// 'threadprivate', 'copyin' or 'copyprivate'. +/// \param Kind Clause kind. +/// \return true - the clause is a threadprivate clause, otherwise - false. +bool isOpenMPThreadPrivate(OpenMPClauseKind Kind); + +} + +#endif + diff --git a/contrib/llvm/tools/clang/include/clang/Basic/OperatorKinds.def b/contrib/llvm/tools/clang/include/clang/Basic/OperatorKinds.def new file mode 100644 index 0000000..34ad764 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/OperatorKinds.def @@ -0,0 +1,107 @@ +//===--- OperatorKinds.def - C++ Overloaded Operator Database ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the OverloadedOperator database, which includes +// all of the overloadable C++ operators. +// +//===----------------------------------------------------------------------===// +// +/// @file OperatorKinds.def +/// +/// In this file, each of the overloadable C++ operators is enumerated +/// with either the OVERLOADED_OPERATOR or OVERLOADED_OPERATOR_MULTI +/// macro, each of which can be specified by the code including this +/// file. OVERLOADED_OPERATOR is used for single-token operators +/// (e.g., "+"), and has six arguments: +/// +/// Name: The name of the token. OO_Name will be the name of the +/// corresponding enumerator in OverloadedOperatorKind in +/// OperatorKinds.h. +/// +/// Spelling: A string that provides a canonical spelling for the +/// operator, e.g., "operator+". +/// +/// Token: The name of the token that specifies the operator, e.g., +/// "plus" for operator+ or "greatergreaterequal" for +/// "operator>>=". With a "kw_" prefix, the token name can be used as +/// an enumerator into the TokenKind enumeration. +/// +/// Unary: True if the operator can be declared as a unary operator. +/// +/// Binary: True if the operator can be declared as a binary +/// operator. Note that some operators (e.g., "operator+" and +/// "operator*") can be both unary and binary. +/// +/// MemberOnly: True if this operator can only be declared as a +/// non-static member function. False if the operator can be both a +/// non-member function and a non-static member function. +/// +/// OVERLOADED_OPERATOR_MULTI is used to enumerate the multi-token +/// overloaded operator names, e.g., "operator delete []". The macro +/// has all of the parameters of OVERLOADED_OPERATOR except Token, +/// which is omitted. + +#ifndef OVERLOADED_OPERATOR +# define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) +#endif + +#ifndef OVERLOADED_OPERATOR_MULTI +# define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly) \ + OVERLOADED_OPERATOR(Name,Spelling,unknown,Unary,Binary,MemberOnly) +#endif + +OVERLOADED_OPERATOR_MULTI(New , "new" , true , true , false) +OVERLOADED_OPERATOR_MULTI(Delete , "delete" , true , true , false) +OVERLOADED_OPERATOR_MULTI(Array_New , "new[]" , true , true , false) +OVERLOADED_OPERATOR_MULTI(Array_Delete , "delete[]" , true , true , false) +OVERLOADED_OPERATOR(Plus , "+" , plus , true , true , false) +OVERLOADED_OPERATOR(Minus , "-" , minus , true , true , false) +OVERLOADED_OPERATOR(Star , "*" , star , true , true , false) +OVERLOADED_OPERATOR(Slash , "/" , slash , false, true , false) +OVERLOADED_OPERATOR(Percent , "%" , percent , false, true , false) +OVERLOADED_OPERATOR(Caret , "^" , caret , false, true , false) +OVERLOADED_OPERATOR(Amp , "&" , amp , true , true , false) +OVERLOADED_OPERATOR(Pipe , "|" , pipe , false, true , false) +OVERLOADED_OPERATOR(Tilde , "~" , tilde , true , false, false) +OVERLOADED_OPERATOR(Exclaim , "!" , exclaim , true , false, false) +OVERLOADED_OPERATOR(Equal , "=" , equal , false, true , true) +OVERLOADED_OPERATOR(Less , "<" , less , false, true , false) +OVERLOADED_OPERATOR(Greater , ">" , greater , false, true , false) +OVERLOADED_OPERATOR(PlusEqual , "+=" , plusequal , false, true , false) +OVERLOADED_OPERATOR(MinusEqual , "-=" , minusequal , false, true , false) +OVERLOADED_OPERATOR(StarEqual , "*=" , starequal , false, true , false) +OVERLOADED_OPERATOR(SlashEqual , "/=" , slashequal , false, true , false) +OVERLOADED_OPERATOR(PercentEqual , "%=" , percentequal , false, true , false) +OVERLOADED_OPERATOR(CaretEqual , "^=" , caretequal , false, true , false) +OVERLOADED_OPERATOR(AmpEqual , "&=" , ampequal , false, true , false) +OVERLOADED_OPERATOR(PipeEqual , "|=" , pipeequal , false, true , false) +OVERLOADED_OPERATOR(LessLess , "<<" , lessless , false, true , false) +OVERLOADED_OPERATOR(GreaterGreater , ">>" , greatergreater , false, true , false) +OVERLOADED_OPERATOR(LessLessEqual , "<<=" , lesslessequal , false, true , false) +OVERLOADED_OPERATOR(GreaterGreaterEqual , ">>=" , greatergreaterequal, false, true , false) +OVERLOADED_OPERATOR(EqualEqual , "==" , equalequal , false, true , false) +OVERLOADED_OPERATOR(ExclaimEqual , "!=" , exclaimequal , false, true , false) +OVERLOADED_OPERATOR(LessEqual , "<=" , lessequal , false, true , false) +OVERLOADED_OPERATOR(GreaterEqual , ">=" , greaterequal , false, true , false) +OVERLOADED_OPERATOR(AmpAmp , "&&" , ampamp , false, true , false) +OVERLOADED_OPERATOR(PipePipe , "||" , pipepipe , false, true , false) +OVERLOADED_OPERATOR(PlusPlus , "++" , plusplus , true , true , false) +OVERLOADED_OPERATOR(MinusMinus , "--" , minusminus , true , true , false) +OVERLOADED_OPERATOR(Comma , "," , comma , false, true , false) +OVERLOADED_OPERATOR(ArrowStar , "->*" , arrowstar , false, true , false) +OVERLOADED_OPERATOR(Arrow , "->" , arrow , true , false, true) +OVERLOADED_OPERATOR_MULTI(Call , "()" , true , true , true) +OVERLOADED_OPERATOR_MULTI(Subscript , "[]" , false, true , true) +// ?: can *not* be overloaded, but we need the overload +// resolution machinery for it. +OVERLOADED_OPERATOR_MULTI(Conditional , "?" , false, true , false) +OVERLOADED_OPERATOR(Coawait , "co_await", kw_co_await , true , false, false) + +#undef OVERLOADED_OPERATOR_MULTI +#undef OVERLOADED_OPERATOR diff --git a/contrib/llvm/tools/clang/include/clang/Basic/OperatorKinds.h b/contrib/llvm/tools/clang/include/clang/Basic/OperatorKinds.h new file mode 100644 index 0000000..7120bae --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/OperatorKinds.h @@ -0,0 +1,36 @@ +//===--- OperatorKinds.h - C++ Overloaded Operators -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines an enumeration for C++ overloaded operators. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_OPERATORKINDS_H +#define LLVM_CLANG_BASIC_OPERATORKINDS_H + +namespace clang { + +/// \brief Enumeration specifying the different kinds of C++ overloaded +/// operators. +enum OverloadedOperatorKind : int { + OO_None, ///< Not an overloaded operator +#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ + OO_##Name, +#include "clang/Basic/OperatorKinds.def" + 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/contrib/llvm/tools/clang/include/clang/Basic/OperatorPrecedence.h b/contrib/llvm/tools/clang/include/clang/Basic/OperatorPrecedence.h new file mode 100644 index 0000000..640749f --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/OperatorPrecedence.h @@ -0,0 +1,52 @@ +//===--- OperatorPrecedence.h - Operator precedence levels ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines and computes precedence levels for binary/ternary operators. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_OPERATORPRECEDENCE_H +#define LLVM_CLANG_BASIC_OPERATORPRECEDENCE_H + +#include "clang/Basic/TokenKinds.h" + +namespace clang { + +/// PrecedenceLevels - These are precedences for the binary/ternary +/// operators in the C99 grammar. These have been named to relate +/// with the C99 grammar productions. Low precedences numbers bind +/// more weakly than high numbers. +namespace prec { + enum Level { + Unknown = 0, // Not binary operator. + Comma = 1, // , + Assignment = 2, // =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |= + Conditional = 3, // ? + LogicalOr = 4, // || + LogicalAnd = 5, // && + InclusiveOr = 6, // | + ExclusiveOr = 7, // ^ + And = 8, // & + Equality = 9, // ==, != + Relational = 10, // >=, <=, >, < + Shift = 11, // <<, >> + Additive = 12, // -, + + Multiplicative = 13, // *, /, % + PointerToMember = 14 // .*, ->* + }; +} + +/// \brief Return the precedence of the specified binary operator token. +prec::Level getBinOpPrecedence(tok::TokenKind Kind, bool GreaterThanIsOperator, + bool CPlusPlus11); + +} // end namespace clang + +#endif // LLVM_CLANG_OPERATOR_PRECEDENCE_H diff --git a/contrib/llvm/tools/clang/include/clang/Basic/PartialDiagnostic.h b/contrib/llvm/tools/clang/include/clang/Basic/PartialDiagnostic.h new file mode 100644 index 0000000..53ce95c --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/PartialDiagnostic.h @@ -0,0 +1,410 @@ +//===--- PartialDiagnostic.h - Diagnostic "closures" ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Implements a partial diagnostic that can be emitted anwyhere +/// in a DiagnosticBuilder stream. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_PARTIALDIAGNOSTIC_H +#define LLVM_CLANG_BASIC_PARTIALDIAGNOSTIC_H + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/DataTypes.h" +#include <cassert> + +namespace clang { + +class PartialDiagnostic { +public: + enum { + // The MaxArguments and MaxFixItHints member enum values from + // DiagnosticsEngine are private but DiagnosticsEngine declares + // PartialDiagnostic a friend. These enum values are redeclared + // here so that the nested Storage class below can access them. + MaxArguments = DiagnosticsEngine::MaxArguments + }; + + struct Storage { + Storage() : NumDiagArgs(0) { } + + enum { + /// \brief The maximum number of arguments we can hold. We + /// currently only support up to 10 arguments (%0-%9). + /// + /// A single diagnostic with more than that almost certainly has to + /// be simplified anyway. + MaxArguments = PartialDiagnostic::MaxArguments + }; + + /// \brief The number of entries in Arguments. + unsigned char NumDiagArgs; + + /// \brief Specifies for each argument whether it is in DiagArgumentsStr + /// or in DiagArguments. + unsigned char DiagArgumentsKind[MaxArguments]; + + /// \brief The values for the various substitution positions. + /// + /// This is used when the argument is not an std::string. The specific value + /// is mangled into an intptr_t and the interpretation depends on exactly + /// what sort of argument kind it is. + intptr_t DiagArgumentsVal[MaxArguments]; + + /// \brief The values for the various substitution positions that have + /// string arguments. + std::string DiagArgumentsStr[MaxArguments]; + + /// \brief The list of ranges added to this diagnostic. + SmallVector<CharSourceRange, 8> DiagRanges; + + /// \brief If valid, provides a hint with some code to insert, remove, or + /// modify at a particular position. + SmallVector<FixItHint, 6> FixItHints; + }; + + /// \brief An allocator for Storage objects, which uses a small cache to + /// objects, used to reduce malloc()/free() traffic for partial diagnostics. + class StorageAllocator { + static const unsigned NumCached = 16; + Storage Cached[NumCached]; + Storage *FreeList[NumCached]; + unsigned NumFreeListEntries; + + public: + StorageAllocator(); + ~StorageAllocator(); + + /// \brief Allocate new storage. + Storage *Allocate() { + if (NumFreeListEntries == 0) + return new Storage; + + Storage *Result = FreeList[--NumFreeListEntries]; + Result->NumDiagArgs = 0; + Result->DiagRanges.clear(); + Result->FixItHints.clear(); + return Result; + } + + /// \brief Free the given storage object. + void Deallocate(Storage *S) { + if (S >= Cached && S <= Cached + NumCached) { + FreeList[NumFreeListEntries++] = S; + return; + } + + delete S; + } + }; + +private: + // NOTE: Sema assumes that PartialDiagnostic is location-invariant + // in the sense that its bits can be safely memcpy'ed and destructed + // in the new location. + + /// \brief The diagnostic ID. + mutable unsigned DiagID; + + /// \brief Storage for args and ranges. + mutable Storage *DiagStorage; + + /// \brief Allocator used to allocate storage for this diagnostic. + StorageAllocator *Allocator; + + /// \brief Retrieve storage for this particular diagnostic. + Storage *getStorage() const { + if (DiagStorage) + return DiagStorage; + + if (Allocator) + DiagStorage = Allocator->Allocate(); + else { + assert(Allocator != reinterpret_cast<StorageAllocator *>(~uintptr_t(0))); + DiagStorage = new Storage; + } + return DiagStorage; + } + + void freeStorage() { + if (!DiagStorage) + return; + + // The hot path for PartialDiagnostic is when we just used it to wrap an ID + // (typically so we have the flexibility of passing a more complex + // diagnostic into the callee, but that does not commonly occur). + // + // Split this out into a slow function for silly compilers (*cough*) which + // can't do decent partial inlining. + freeStorageSlow(); + } + + void freeStorageSlow() { + if (Allocator) + Allocator->Deallocate(DiagStorage); + else if (Allocator != reinterpret_cast<StorageAllocator *>(~uintptr_t(0))) + delete DiagStorage; + DiagStorage = nullptr; + } + + void AddSourceRange(const CharSourceRange &R) const { + if (!DiagStorage) + DiagStorage = getStorage(); + + DiagStorage->DiagRanges.push_back(R); + } + + void AddFixItHint(const FixItHint &Hint) const { + if (Hint.isNull()) + return; + + if (!DiagStorage) + DiagStorage = getStorage(); + + DiagStorage->FixItHints.push_back(Hint); + } + +public: + struct NullDiagnostic {}; + /// \brief Create a null partial diagnostic, which cannot carry a payload, + /// and only exists to be swapped with a real partial diagnostic. + PartialDiagnostic(NullDiagnostic) + : DiagID(0), DiagStorage(nullptr), Allocator(nullptr) { } + + PartialDiagnostic(unsigned DiagID, StorageAllocator &Allocator) + : DiagID(DiagID), DiagStorage(nullptr), Allocator(&Allocator) { } + + PartialDiagnostic(const PartialDiagnostic &Other) + : DiagID(Other.DiagID), DiagStorage(nullptr), Allocator(Other.Allocator) + { + if (Other.DiagStorage) { + DiagStorage = getStorage(); + *DiagStorage = *Other.DiagStorage; + } + } + + PartialDiagnostic(PartialDiagnostic &&Other) + : DiagID(Other.DiagID), DiagStorage(Other.DiagStorage), + Allocator(Other.Allocator) { + Other.DiagStorage = nullptr; + } + + PartialDiagnostic(const PartialDiagnostic &Other, Storage *DiagStorage) + : DiagID(Other.DiagID), DiagStorage(DiagStorage), + Allocator(reinterpret_cast<StorageAllocator *>(~uintptr_t(0))) + { + if (Other.DiagStorage) + *this->DiagStorage = *Other.DiagStorage; + } + + PartialDiagnostic(const Diagnostic &Other, StorageAllocator &Allocator) + : DiagID(Other.getID()), DiagStorage(nullptr), Allocator(&Allocator) + { + // Copy arguments. + for (unsigned I = 0, N = Other.getNumArgs(); I != N; ++I) { + if (Other.getArgKind(I) == DiagnosticsEngine::ak_std_string) + AddString(Other.getArgStdStr(I)); + else + AddTaggedVal(Other.getRawArg(I), Other.getArgKind(I)); + } + + // Copy source ranges. + for (unsigned I = 0, N = Other.getNumRanges(); I != N; ++I) + AddSourceRange(Other.getRange(I)); + + // Copy fix-its. + for (unsigned I = 0, N = Other.getNumFixItHints(); I != N; ++I) + AddFixItHint(Other.getFixItHint(I)); + } + + PartialDiagnostic &operator=(const PartialDiagnostic &Other) { + DiagID = Other.DiagID; + if (Other.DiagStorage) { + if (!DiagStorage) + DiagStorage = getStorage(); + + *DiagStorage = *Other.DiagStorage; + } else { + freeStorage(); + } + + return *this; + } + + PartialDiagnostic &operator=(PartialDiagnostic &&Other) { + freeStorage(); + + DiagID = Other.DiagID; + DiagStorage = Other.DiagStorage; + Allocator = Other.Allocator; + + Other.DiagStorage = nullptr; + return *this; + } + + ~PartialDiagnostic() { + freeStorage(); + } + + void swap(PartialDiagnostic &PD) { + std::swap(DiagID, PD.DiagID); + std::swap(DiagStorage, PD.DiagStorage); + std::swap(Allocator, PD.Allocator); + } + + unsigned getDiagID() const { return DiagID; } + + void AddTaggedVal(intptr_t V, DiagnosticsEngine::ArgumentKind Kind) const { + if (!DiagStorage) + DiagStorage = getStorage(); + + assert(DiagStorage->NumDiagArgs < Storage::MaxArguments && + "Too many arguments to diagnostic!"); + DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs] = Kind; + DiagStorage->DiagArgumentsVal[DiagStorage->NumDiagArgs++] = V; + } + + void AddString(StringRef V) const { + if (!DiagStorage) + DiagStorage = getStorage(); + + assert(DiagStorage->NumDiagArgs < Storage::MaxArguments && + "Too many arguments to diagnostic!"); + DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs] + = DiagnosticsEngine::ak_std_string; + DiagStorage->DiagArgumentsStr[DiagStorage->NumDiagArgs++] = V; + } + + void Emit(const DiagnosticBuilder &DB) const { + if (!DiagStorage) + return; + + // Add all arguments. + for (unsigned i = 0, e = DiagStorage->NumDiagArgs; i != e; ++i) { + if ((DiagnosticsEngine::ArgumentKind)DiagStorage->DiagArgumentsKind[i] + == DiagnosticsEngine::ak_std_string) + DB.AddString(DiagStorage->DiagArgumentsStr[i]); + else + DB.AddTaggedVal(DiagStorage->DiagArgumentsVal[i], + (DiagnosticsEngine::ArgumentKind)DiagStorage->DiagArgumentsKind[i]); + } + + // Add all ranges. + for (const CharSourceRange &Range : DiagStorage->DiagRanges) + DB.AddSourceRange(Range); + + // Add all fix-its. + for (const FixItHint &Fix : DiagStorage->FixItHints) + DB.AddFixItHint(Fix); + } + + void EmitToString(DiagnosticsEngine &Diags, + SmallVectorImpl<char> &Buf) const { + // FIXME: It should be possible to render a diagnostic to a string without + // messing with the state of the diagnostics engine. + DiagnosticBuilder DB(Diags.Report(getDiagID())); + Emit(DB); + DB.FlushCounts(); + Diagnostic(&Diags).FormatDiagnostic(Buf); + DB.Clear(); + Diags.Clear(); + } + + /// \brief Clear out this partial diagnostic, giving it a new diagnostic ID + /// and removing all of its arguments, ranges, and fix-it hints. + void Reset(unsigned DiagID = 0) { + this->DiagID = DiagID; + freeStorage(); + } + + bool hasStorage() const { return DiagStorage != nullptr; } + + friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + unsigned I) { + PD.AddTaggedVal(I, DiagnosticsEngine::ak_uint); + return PD; + } + + friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + int I) { + PD.AddTaggedVal(I, DiagnosticsEngine::ak_sint); + return PD; + } + + friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + const char *S) { + PD.AddTaggedVal(reinterpret_cast<intptr_t>(S), + DiagnosticsEngine::ak_c_string); + return PD; + } + + friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + StringRef S) { + + PD.AddString(S); + return PD; + } + + friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + const IdentifierInfo *II) { + PD.AddTaggedVal(reinterpret_cast<intptr_t>(II), + DiagnosticsEngine::ak_identifierinfo); + return PD; + } + + // Adds a DeclContext to the diagnostic. The enable_if template magic is here + // so that we only match those arguments that are (statically) DeclContexts; + // other arguments that derive from DeclContext (e.g., RecordDecls) will not + // match. + template<typename T> + friend inline + typename std::enable_if<std::is_same<T, DeclContext>::value, + const PartialDiagnostic &>::type + operator<<(const PartialDiagnostic &PD, T *DC) { + PD.AddTaggedVal(reinterpret_cast<intptr_t>(DC), + DiagnosticsEngine::ak_declcontext); + return PD; + } + + friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + SourceRange R) { + PD.AddSourceRange(CharSourceRange::getTokenRange(R)); + return PD; + } + + friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + const CharSourceRange &R) { + PD.AddSourceRange(R); + return PD; + } + + friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + const FixItHint &Hint) { + PD.AddFixItHint(Hint); + return PD; + } + +}; + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const PartialDiagnostic &PD) { + PD.Emit(DB); + return DB; +} + +/// \brief A partial diagnostic along with the source location where this +/// diagnostic occurs. +typedef std::pair<SourceLocation, PartialDiagnostic> PartialDiagnosticAt; + +} // end namespace clang +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/PlistSupport.h b/contrib/llvm/tools/clang/include/clang/Basic/PlistSupport.h new file mode 100644 index 0000000..84dd291 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/PlistSupport.h @@ -0,0 +1,119 @@ +//===---------- PlistSupport.h - Plist Output Utilities ---------*- 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_BASIC_PLISTSUPPORT_H +#define LLVM_CLANG_BASIC_PLISTSUPPORT_H + +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/Support/raw_ostream.h" + +namespace clang { +namespace markup { +typedef llvm::DenseMap<FileID, unsigned> FIDMap; + +inline void AddFID(FIDMap &FIDs, SmallVectorImpl<FileID> &V, + const SourceManager &SM, SourceLocation L) { + FileID FID = SM.getFileID(SM.getExpansionLoc(L)); + FIDMap::iterator I = FIDs.find(FID); + if (I != FIDs.end()) + return; + FIDs[FID] = V.size(); + V.push_back(FID); +} + +inline unsigned GetFID(const FIDMap &FIDs, const SourceManager &SM, + SourceLocation L) { + FileID FID = SM.getFileID(SM.getExpansionLoc(L)); + FIDMap::const_iterator I = FIDs.find(FID); + assert(I != FIDs.end()); + return I->second; +} + +inline raw_ostream &Indent(raw_ostream &o, const unsigned indent) { + for (unsigned i = 0; i < indent; ++i) + o << ' '; + return o; +} + +inline raw_ostream &EmitPlistHeader(raw_ostream &o) { + static const char *PlistHeader = + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" " + "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" + "<plist version=\"1.0\">\n"; + return o << PlistHeader; +} + +inline raw_ostream &EmitInteger(raw_ostream &o, int64_t value) { + o << "<integer>"; + o << value; + o << "</integer>"; + return o; +} + +inline raw_ostream &EmitString(raw_ostream &o, StringRef s) { + o << "<string>"; + for (StringRef::const_iterator I = s.begin(), E = s.end(); I != E; ++I) { + char c = *I; + switch (c) { + default: + o << c; + break; + case '&': + o << "&"; + break; + case '<': + o << "<"; + break; + case '>': + o << ">"; + break; + case '\'': + o << "'"; + break; + case '\"': + o << """; + break; + } + } + o << "</string>"; + return o; +} + +inline void EmitLocation(raw_ostream &o, const SourceManager &SM, + SourceLocation L, const FIDMap &FM, unsigned indent) { + if (L.isInvalid()) return; + + FullSourceLoc Loc(SM.getExpansionLoc(L), const_cast<SourceManager &>(SM)); + + Indent(o, indent) << "<dict>\n"; + Indent(o, indent) << " <key>line</key>"; + EmitInteger(o, Loc.getExpansionLineNumber()) << '\n'; + Indent(o, indent) << " <key>col</key>"; + EmitInteger(o, Loc.getExpansionColumnNumber()) << '\n'; + Indent(o, indent) << " <key>file</key>"; + EmitInteger(o, GetFID(FM, SM, Loc)) << '\n'; + Indent(o, indent) << "</dict>\n"; +} + +inline void EmitRange(raw_ostream &o, const SourceManager &SM, + CharSourceRange R, const FIDMap &FM, unsigned indent) { + if (R.isInvalid()) return; + + assert(R.isCharRange() && "cannot handle a token range"); + Indent(o, indent) << "<array>\n"; + EmitLocation(o, SM, R.getBegin(), FM, indent + 1); + EmitLocation(o, SM, R.getEnd(), FM, indent + 1); + Indent(o, indent) << "</array>\n"; +} +} +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/PrettyStackTrace.h b/contrib/llvm/tools/clang/include/clang/Basic/PrettyStackTrace.h new file mode 100644 index 0000000..6badae5 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/PrettyStackTrace.h @@ -0,0 +1,38 @@ +//===- clang/Basic/PrettyStackTrace.h - Pretty Crash Handling --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the PrettyStackTraceEntry class, which is used to make +/// crashes give more contextual information about what the program was doing +/// when it crashed. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_PRETTYSTACKTRACE_H +#define LLVM_CLANG_BASIC_PRETTYSTACKTRACE_H + +#include "clang/Basic/SourceLocation.h" +#include "llvm/Support/PrettyStackTrace.h" + +namespace clang { + + /// If a crash happens while one of these objects are live, the message + /// is printed out along with the specified source location. + class PrettyStackTraceLoc : public llvm::PrettyStackTraceEntry { + SourceManager &SM; + SourceLocation Loc; + const char *Message; + public: + PrettyStackTraceLoc(SourceManager &sm, SourceLocation L, const char *Msg) + : SM(sm), Loc(L), Message(Msg) {} + void print(raw_ostream &OS) const override; + }; +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/SanitizerBlacklist.h b/contrib/llvm/tools/clang/include/clang/Basic/SanitizerBlacklist.h new file mode 100644 index 0000000..e651e18 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/SanitizerBlacklist.h @@ -0,0 +1,46 @@ +//===--- SanitizerBlacklist.h - Blacklist for sanitizers --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// User-provided blacklist used to disable/alter instrumentation done in +// sanitizers. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_BASIC_SANITIZERBLACKLIST_H +#define LLVM_CLANG_BASIC_SANITIZERBLACKLIST_H + +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/SpecialCaseList.h" +#include <memory> + +namespace clang { + +class SanitizerBlacklist { + std::unique_ptr<llvm::SpecialCaseList> SCL; + SourceManager &SM; + +public: + SanitizerBlacklist(const std::vector<std::string> &BlacklistPaths, + SourceManager &SM); + bool isBlacklistedGlobal(StringRef GlobalName, + StringRef Category = StringRef()) const; + bool isBlacklistedType(StringRef MangledTypeName, + StringRef Category = StringRef()) const; + bool isBlacklistedFunction(StringRef FunctionName) const; + bool isBlacklistedFile(StringRef FileName, + StringRef Category = StringRef()) const; + bool isBlacklistedLocation(SourceLocation Loc, + StringRef Category = StringRef()) const; +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Sanitizers.def b/contrib/llvm/tools/clang/include/clang/Basic/Sanitizers.def new file mode 100644 index 0000000..4b68593 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/Sanitizers.def @@ -0,0 +1,122 @@ +//===--- Sanitizers.def - Runtime sanitizer options -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the options for specifying which runtime sanitizers to +// enable. Users of this file must define the SANITIZER macro to make use of +// this information. Users of this file can also define the SANITIZER_GROUP +// macro to get information on options which refer to sets of sanitizers. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER +#error "Define SANITIZER prior to including this file!" +#endif + +// SANITIZER(NAME, ID) + +// The first value is the name of the sanitizer as a string. The sanitizer can +// be enabled by specifying -fsanitize=NAME. + +// The second value is an identifier which can be used to refer to the +// sanitizer. + + +// SANITIZER_GROUP(NAME, ID, ALIAS) + +// The first two values have the same semantics as the corresponding SANITIZER +// values. The third value is an expression ORing together the IDs of individual +// sanitizers in this group. + +#ifndef SANITIZER_GROUP +#define SANITIZER_GROUP(NAME, ID, ALIAS) +#endif + + +// AddressSanitizer +SANITIZER("address", Address) + +// Kernel AddressSanitizer (KASan) +SANITIZER("kernel-address", KernelAddress) + +// MemorySanitizer +SANITIZER("memory", Memory) + +// ThreadSanitizer +SANITIZER("thread", Thread) + +// LeakSanitizer +SANITIZER("leak", Leak) + +// UndefinedBehaviorSanitizer +SANITIZER("alignment", Alignment) +SANITIZER("array-bounds", ArrayBounds) +SANITIZER("bool", Bool) +SANITIZER("enum", Enum) +SANITIZER("float-cast-overflow", FloatCastOverflow) +SANITIZER("float-divide-by-zero", FloatDivideByZero) +SANITIZER("function", Function) +SANITIZER("integer-divide-by-zero", IntegerDivideByZero) +SANITIZER("nonnull-attribute", NonnullAttribute) +SANITIZER("null", Null) +SANITIZER("object-size", ObjectSize) +SANITIZER("return", Return) +SANITIZER("returns-nonnull-attribute", ReturnsNonnullAttribute) +SANITIZER("shift-base", ShiftBase) +SANITIZER("shift-exponent", ShiftExponent) +SANITIZER_GROUP("shift", Shift, ShiftBase | ShiftExponent) +SANITIZER("signed-integer-overflow", SignedIntegerOverflow) +SANITIZER("unreachable", Unreachable) +SANITIZER("vla-bound", VLABound) +SANITIZER("vptr", Vptr) + +// IntegerSanitizer +SANITIZER("unsigned-integer-overflow", UnsignedIntegerOverflow) + +// DataFlowSanitizer +SANITIZER("dataflow", DataFlow) + +// Control Flow Integrity +SANITIZER("cfi-cast-strict", CFICastStrict) +SANITIZER("cfi-derived-cast", CFIDerivedCast) +SANITIZER("cfi-icall", CFIICall) +SANITIZER("cfi-unrelated-cast", CFIUnrelatedCast) +SANITIZER("cfi-nvcall", CFINVCall) +SANITIZER("cfi-vcall", CFIVCall) +SANITIZER_GROUP("cfi", CFI, + CFIDerivedCast | CFIICall | CFIUnrelatedCast | CFINVCall | + CFIVCall) + +// Safe Stack +SANITIZER("safe-stack", SafeStack) + +// -fsanitize=undefined includes all the sanitizers which have low overhead, no +// ABI or address space layout implications, and only catch undefined behavior. +SANITIZER_GROUP("undefined", Undefined, + Alignment | Bool | ArrayBounds | Enum | FloatCastOverflow | + FloatDivideByZero | IntegerDivideByZero | NonnullAttribute | + Null | ObjectSize | Return | ReturnsNonnullAttribute | + Shift | SignedIntegerOverflow | Unreachable | VLABound | + Function | Vptr) + +// -fsanitize=undefined-trap is an alias for -fsanitize=undefined. +SANITIZER_GROUP("undefined-trap", UndefinedTrap, Undefined) + +SANITIZER_GROUP("integer", Integer, + SignedIntegerOverflow | UnsignedIntegerOverflow | Shift | + IntegerDivideByZero) + +SANITIZER("local-bounds", LocalBounds) +SANITIZER_GROUP("bounds", Bounds, ArrayBounds | LocalBounds) + +// Magic group, containing all sanitizers. For example, "-fno-sanitize=all" +// can be used to disable all the sanitizers. +SANITIZER_GROUP("all", All, ~0ULL) + +#undef SANITIZER +#undef SANITIZER_GROUP diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Sanitizers.h b/contrib/llvm/tools/clang/include/clang/Basic/Sanitizers.h new file mode 100644 index 0000000..98e70de --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/Sanitizers.h @@ -0,0 +1,86 @@ +//===--- Sanitizers.h - C Language Family Language Options ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the clang::SanitizerKind enum. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_SANITIZERS_H +#define LLVM_CLANG_BASIC_SANITIZERS_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/MathExtras.h" + +namespace clang { + +typedef uint64_t SanitizerMask; + +namespace SanitizerKind { + +// Assign ordinals to possible values of -fsanitize= flag, which we will use as +// bit positions. +enum SanitizerOrdinal : uint64_t { +#define SANITIZER(NAME, ID) SO_##ID, +#define SANITIZER_GROUP(NAME, ID, ALIAS) SO_##ID##Group, +#include "clang/Basic/Sanitizers.def" + SO_Count +}; + +// Define the set of sanitizer kinds, as well as the set of sanitizers each +// sanitizer group expands into. +#define SANITIZER(NAME, ID) \ + const SanitizerMask ID = 1ULL << SO_##ID; +#define SANITIZER_GROUP(NAME, ID, ALIAS) \ + const SanitizerMask ID = ALIAS; \ + const SanitizerMask ID##Group = 1ULL << SO_##ID##Group; +#include "clang/Basic/Sanitizers.def" + +} + +struct SanitizerSet { + SanitizerSet() : Mask(0) {} + + /// \brief Check if a certain (single) sanitizer is enabled. + bool has(SanitizerMask K) const { + assert(llvm::isPowerOf2_64(K)); + return Mask & K; + } + + /// \brief Check if one or more sanitizers are enabled. + bool hasOneOf(SanitizerMask K) const { return Mask & K; } + + /// \brief Enable or disable a certain (single) sanitizer. + void set(SanitizerMask K, bool Value) { + assert(llvm::isPowerOf2_64(K)); + Mask = Value ? (Mask | K) : (Mask & ~K); + } + + /// \brief Disable all sanitizers. + void clear() { Mask = 0; } + + /// \brief Returns true if at least one sanitizer is enabled. + bool empty() const { return Mask == 0; } + + /// \brief Bitmask of enabled sanitizers. + SanitizerMask Mask; +}; + +/// Parse a single value from a -fsanitize= or -fno-sanitize= value list. +/// Returns a non-zero SanitizerMask, or \c 0 if \p Value is not known. +SanitizerMask parseSanitizerValue(StringRef Value, bool AllowGroups); + +/// For each sanitizer group bit set in \p Kinds, set the bits for sanitizers +/// this group enables. +SanitizerMask expandSanitizerGroups(SanitizerMask Kinds); + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/SourceLocation.h b/contrib/llvm/tools/clang/include/clang/Basic/SourceLocation.h new file mode 100644 index 0000000..0aeba5e --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/SourceLocation.h @@ -0,0 +1,438 @@ +//===--- SourceLocation.h - Compact identifier for Source Files -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the clang::SourceLocation class and associated facilities. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_SOURCELOCATION_H +#define LLVM_CLANG_BASIC_SOURCELOCATION_H + +#include "clang/Basic/LLVM.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/PointerLikeTypeTraits.h" +#include <cassert> +#include <functional> +#include <string> +#include <utility> + +namespace llvm { + class MemoryBuffer; + template <typename T> struct DenseMapInfo; + template <typename T> struct isPodLike; +} + +namespace clang { + +class SourceManager; + +/// \brief An opaque identifier used by SourceManager which refers to a +/// source file (MemoryBuffer) along with its \#include path and \#line data. +/// +class FileID { + /// \brief A mostly-opaque identifier, where 0 is "invalid", >0 is + /// this module, and <-1 is something loaded from another module. + int ID; +public: + FileID() : ID(0) {} + + bool isValid() const { return ID != 0; } + bool isInvalid() const { return ID == 0; } + + bool operator==(const FileID &RHS) const { return ID == RHS.ID; } + bool operator<(const FileID &RHS) const { return ID < RHS.ID; } + bool operator<=(const FileID &RHS) const { return ID <= RHS.ID; } + bool operator!=(const FileID &RHS) const { return !(*this == RHS); } + bool operator>(const FileID &RHS) const { return RHS < *this; } + bool operator>=(const FileID &RHS) const { return RHS <= *this; } + + static FileID getSentinel() { return get(-1); } + unsigned getHashValue() const { return static_cast<unsigned>(ID); } + +private: + friend class SourceManager; + friend class ASTWriter; + friend class ASTReader; + + static FileID get(int V) { + FileID F; + F.ID = V; + return F; + } + int getOpaqueValue() const { return ID; } +}; + + +/// \brief Encodes a location in the source. The SourceManager can decode this +/// to get at the full include stack, line and column information. +/// +/// Technically, a source location is simply an offset into the manager's view +/// of the input source, which is all input buffers (including macro +/// expansions) concatenated in an effectively arbitrary order. The manager +/// actually maintains two blocks of input buffers. One, starting at offset +/// 0 and growing upwards, contains all buffers from this module. The other, +/// starting at the highest possible offset and growing downwards, contains +/// buffers of loaded modules. +/// +/// In addition, one bit of SourceLocation is used for quick access to the +/// information whether the location is in a file or a macro expansion. +/// +/// It is important that this type remains small. It is currently 32 bits wide. +class SourceLocation { + unsigned ID; + friend class SourceManager; + friend class ASTReader; + friend class ASTWriter; + enum : unsigned { + MacroIDBit = 1U << 31 + }; +public: + + SourceLocation() : ID(0) {} + + bool isFileID() const { return (ID & MacroIDBit) == 0; } + bool isMacroID() const { return (ID & MacroIDBit) != 0; } + + /// \brief Return true if this is a valid SourceLocation object. + /// + /// Invalid SourceLocations are often used when events have no corresponding + /// location in the source (e.g. a diagnostic is required for a command line + /// option). + bool isValid() const { return ID != 0; } + bool isInvalid() const { return ID == 0; } + +private: + /// \brief Return the offset into the manager's global input view. + unsigned getOffset() const { + return ID & ~MacroIDBit; + } + + static SourceLocation getFileLoc(unsigned ID) { + assert((ID & MacroIDBit) == 0 && "Ran out of source locations!"); + SourceLocation L; + L.ID = ID; + return L; + } + + static SourceLocation getMacroLoc(unsigned ID) { + assert((ID & MacroIDBit) == 0 && "Ran out of source locations!"); + SourceLocation L; + L.ID = MacroIDBit | ID; + return L; + } +public: + + /// \brief Return a source location with the specified offset from this + /// SourceLocation. + SourceLocation getLocWithOffset(int Offset) const { + assert(((getOffset()+Offset) & MacroIDBit) == 0 && "offset overflow"); + SourceLocation L; + L.ID = ID+Offset; + return L; + } + + /// \brief When a SourceLocation itself cannot be used, this returns + /// an (opaque) 32-bit integer encoding for it. + /// + /// This should only be passed to SourceLocation::getFromRawEncoding, it + /// should not be inspected directly. + unsigned getRawEncoding() const { return ID; } + + /// \brief Turn a raw encoding of a SourceLocation object into + /// a real SourceLocation. + /// + /// \see getRawEncoding. + static SourceLocation getFromRawEncoding(unsigned Encoding) { + SourceLocation X; + X.ID = Encoding; + return X; + } + + /// \brief When a SourceLocation itself cannot be used, this returns + /// an (opaque) pointer encoding for it. + /// + /// This should only be passed to SourceLocation::getFromPtrEncoding, it + /// should not be inspected directly. + void* getPtrEncoding() const { + // Double cast to avoid a warning "cast to pointer from integer of different + // size". + return (void*)(uintptr_t)getRawEncoding(); + } + + /// \brief Turn a pointer encoding of a SourceLocation object back + /// into a real SourceLocation. + static SourceLocation getFromPtrEncoding(const void *Encoding) { + return getFromRawEncoding((unsigned)(uintptr_t)Encoding); + } + + void print(raw_ostream &OS, const SourceManager &SM) const; + std::string printToString(const SourceManager &SM) const; + void dump(const SourceManager &SM) const; +}; + +inline bool operator==(const SourceLocation &LHS, const SourceLocation &RHS) { + return LHS.getRawEncoding() == RHS.getRawEncoding(); +} + +inline bool operator!=(const SourceLocation &LHS, const SourceLocation &RHS) { + return !(LHS == RHS); +} + +inline bool operator<(const SourceLocation &LHS, const SourceLocation &RHS) { + return LHS.getRawEncoding() < RHS.getRawEncoding(); +} + +/// \brief A trivial tuple used to represent a source range. +class SourceRange { + SourceLocation B; + SourceLocation E; +public: + SourceRange(): B(SourceLocation()), E(SourceLocation()) {} + SourceRange(SourceLocation loc) : B(loc), E(loc) {} + SourceRange(SourceLocation begin, SourceLocation end) : B(begin), E(end) {} + + SourceLocation getBegin() const { return B; } + SourceLocation getEnd() const { return E; } + + void setBegin(SourceLocation b) { B = b; } + void setEnd(SourceLocation e) { E = e; } + + bool isValid() const { return B.isValid() && E.isValid(); } + bool isInvalid() const { return !isValid(); } + + bool operator==(const SourceRange &X) const { + return B == X.B && E == X.E; + } + + bool operator!=(const SourceRange &X) const { + return B != X.B || E != X.E; + } +}; + +/// \brief Represents a character-granular source range. +/// +/// The underlying SourceRange can either specify the starting/ending character +/// of the range, or it can specify the start of the range and the start of the +/// last token of the range (a "token range"). In the token range case, the +/// size of the last token must be measured to determine the actual end of the +/// range. +class CharSourceRange { + SourceRange Range; + bool IsTokenRange; +public: + CharSourceRange() : IsTokenRange(false) {} + CharSourceRange(SourceRange R, bool ITR) : Range(R), IsTokenRange(ITR) {} + + static CharSourceRange getTokenRange(SourceRange R) { + return CharSourceRange(R, true); + } + + static CharSourceRange getCharRange(SourceRange R) { + return CharSourceRange(R, false); + } + + static CharSourceRange getTokenRange(SourceLocation B, SourceLocation E) { + return getTokenRange(SourceRange(B, E)); + } + static CharSourceRange getCharRange(SourceLocation B, SourceLocation E) { + return getCharRange(SourceRange(B, E)); + } + + /// \brief Return true if the end of this range specifies the start of + /// the last token. Return false if the end of this range specifies the last + /// character in the range. + bool isTokenRange() const { return IsTokenRange; } + bool isCharRange() const { return !IsTokenRange; } + + SourceLocation getBegin() const { return Range.getBegin(); } + SourceLocation getEnd() const { return Range.getEnd(); } + SourceRange getAsRange() const { return Range; } + + void setBegin(SourceLocation b) { Range.setBegin(b); } + void setEnd(SourceLocation e) { Range.setEnd(e); } + + bool isValid() const { return Range.isValid(); } + bool isInvalid() const { return !isValid(); } +}; + +/// \brief A SourceLocation and its associated SourceManager. +/// +/// This is useful for argument passing to functions that expect both objects. +class FullSourceLoc : public SourceLocation { + const SourceManager *SrcMgr; +public: + /// \brief Creates a FullSourceLoc where isValid() returns \c false. + explicit FullSourceLoc() : SrcMgr(nullptr) {} + + explicit FullSourceLoc(SourceLocation Loc, const SourceManager &SM) + : SourceLocation(Loc), SrcMgr(&SM) {} + + /// \pre This FullSourceLoc has an associated SourceManager. + const SourceManager &getManager() const { + assert(SrcMgr && "SourceManager is NULL."); + return *SrcMgr; + } + + FileID getFileID() const; + + FullSourceLoc getExpansionLoc() const; + FullSourceLoc getSpellingLoc() const; + + unsigned getExpansionLineNumber(bool *Invalid = nullptr) const; + unsigned getExpansionColumnNumber(bool *Invalid = nullptr) const; + + unsigned getSpellingLineNumber(bool *Invalid = nullptr) const; + unsigned getSpellingColumnNumber(bool *Invalid = nullptr) const; + + const char *getCharacterData(bool *Invalid = nullptr) const; + + + /// \brief Return a StringRef to the source buffer data for the + /// specified FileID. + StringRef getBufferData(bool *Invalid = nullptr) const; + + /// \brief Decompose the specified location into a raw FileID + Offset pair. + /// + /// The first element is the FileID, the second is the offset from the + /// start of the buffer of the location. + std::pair<FileID, unsigned> getDecomposedLoc() const; + + bool isInSystemHeader() const; + + /// \brief Determines the order of 2 source locations in the translation unit. + /// + /// \returns true if this source location comes before 'Loc', false otherwise. + bool isBeforeInTranslationUnitThan(SourceLocation Loc) const; + + /// \brief Determines the order of 2 source locations in the translation unit. + /// + /// \returns true if this source location comes before 'Loc', false otherwise. + bool isBeforeInTranslationUnitThan(FullSourceLoc Loc) const { + assert(Loc.isValid()); + assert(SrcMgr == Loc.SrcMgr && "Loc comes from another SourceManager!"); + return isBeforeInTranslationUnitThan((SourceLocation)Loc); + } + + /// \brief Comparison function class, useful for sorting FullSourceLocs. + struct BeforeThanCompare : public std::binary_function<FullSourceLoc, + FullSourceLoc, bool> { + bool operator()(const FullSourceLoc& lhs, const FullSourceLoc& rhs) const { + return lhs.isBeforeInTranslationUnitThan(rhs); + } + }; + + /// \brief Prints information about this FullSourceLoc to stderr. + /// + /// This is useful for debugging. + void dump() const; + + friend inline bool + operator==(const FullSourceLoc &LHS, const FullSourceLoc &RHS) { + return LHS.getRawEncoding() == RHS.getRawEncoding() && + LHS.SrcMgr == RHS.SrcMgr; + } + + friend inline bool + operator!=(const FullSourceLoc &LHS, const FullSourceLoc &RHS) { + return !(LHS == RHS); + } + +}; + +/// \brief Represents an unpacked "presumed" location which can be presented +/// to the user. +/// +/// A 'presumed' location can be modified by \#line and GNU line marker +/// directives and is always the expansion point of a normal location. +/// +/// You can get a PresumedLoc from a SourceLocation with SourceManager. +class PresumedLoc { + const char *Filename; + unsigned Line, Col; + SourceLocation IncludeLoc; +public: + PresumedLoc() : Filename(nullptr) {} + PresumedLoc(const char *FN, unsigned Ln, unsigned Co, SourceLocation IL) + : Filename(FN), Line(Ln), Col(Co), IncludeLoc(IL) { + } + + /// \brief Return true if this object is invalid or uninitialized. + /// + /// This occurs when created with invalid source locations or when walking + /// off the top of a \#include stack. + bool isInvalid() const { return Filename == nullptr; } + bool isValid() const { return Filename != nullptr; } + + /// \brief Return the presumed filename of this location. + /// + /// This can be affected by \#line etc. + const char *getFilename() const { return Filename; } + + /// \brief Return the presumed line number of this location. + /// + /// This can be affected by \#line etc. + unsigned getLine() const { return Line; } + + /// \brief Return the presumed column number of this location. + /// + /// This cannot be affected by \#line, but is packaged here for convenience. + unsigned getColumn() const { return Col; } + + /// \brief Return the presumed include location of this location. + /// + /// This can be affected by GNU linemarker directives. + SourceLocation getIncludeLoc() const { return IncludeLoc; } +}; + + +} // end namespace clang + +namespace llvm { + /// Define DenseMapInfo so that FileID's can be used as keys in DenseMap and + /// DenseSets. + template <> + struct DenseMapInfo<clang::FileID> { + static inline clang::FileID getEmptyKey() { + return clang::FileID(); + } + static inline clang::FileID getTombstoneKey() { + return clang::FileID::getSentinel(); + } + + static unsigned getHashValue(clang::FileID S) { + return S.getHashValue(); + } + + static bool isEqual(clang::FileID LHS, clang::FileID RHS) { + return LHS == RHS; + } + }; + + template <> + struct isPodLike<clang::SourceLocation> { static const bool value = true; }; + template <> + struct isPodLike<clang::FileID> { static const bool value = true; }; + + // Teach SmallPtrSet how to handle SourceLocation. + template<> + class PointerLikeTypeTraits<clang::SourceLocation> { + public: + static inline void *getAsVoidPointer(clang::SourceLocation L) { + return L.getPtrEncoding(); + } + static inline clang::SourceLocation getFromVoidPointer(void *P) { + return clang::SourceLocation::getFromRawEncoding((unsigned)(uintptr_t)P); + } + enum { NumLowBitsAvailable = 0 }; + }; + +} // end namespace llvm + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/SourceManager.h b/contrib/llvm/tools/clang/include/clang/Basic/SourceManager.h new file mode 100644 index 0000000..99392a0 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/SourceManager.h @@ -0,0 +1,1711 @@ +//===--- SourceManager.h - Track and cache source files ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the SourceManager interface. +/// +/// There are three different types of locations in a %file: a spelling +/// location, an expansion location, and a presumed location. +/// +/// Given an example of: +/// \code +/// #define min(x, y) x < y ? x : y +/// \endcode +/// +/// and then later on a use of min: +/// \code +/// #line 17 +/// return min(a, b); +/// \endcode +/// +/// The expansion location is the line in the source code where the macro +/// was expanded (the return statement), the spelling location is the +/// location in the source where the macro was originally defined, +/// and the presumed location is where the line directive states that +/// the line is 17, or any other line. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_SOURCEMANAGER_H +#define LLVM_CLANG_BASIC_SOURCEMANAGER_H + +#include "clang/Basic/FileManager.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/Support/AlignOf.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/MemoryBuffer.h" +#include <cassert> +#include <map> +#include <memory> +#include <vector> + +namespace clang { + +class DiagnosticsEngine; +class SourceManager; +class FileManager; +class FileEntry; +class LineTableInfo; +class LangOptions; +class ASTWriter; +class ASTReader; + +/// \brief Public enums and private classes that are part of the +/// SourceManager implementation. +/// +namespace SrcMgr { + /// \brief Indicates whether a file or directory holds normal user code, + /// system code, or system code which is implicitly 'extern "C"' in C++ mode. + /// + /// Entire directories can be tagged with this (this is maintained by + /// DirectoryLookup and friends) as can specific FileInfos when a \#pragma + /// system_header is seen or in various other cases. + /// + enum CharacteristicKind { + C_User, C_System, C_ExternCSystem + }; + + /// \brief One instance of this struct is kept for every file loaded or used. + /// + /// This object owns the MemoryBuffer object. + class LLVM_ALIGNAS(8) ContentCache { + enum CCFlags { + /// \brief Whether the buffer is invalid. + InvalidFlag = 0x01, + /// \brief Whether the buffer should not be freed on destruction. + DoNotFreeFlag = 0x02 + }; + + /// \brief The actual buffer containing the characters from the input + /// file. + /// + /// This is owned by the ContentCache object. The bits indicate + /// whether the buffer is invalid. + mutable llvm::PointerIntPair<llvm::MemoryBuffer *, 2> Buffer; + + public: + /// \brief Reference to the file entry representing this ContentCache. + /// + /// This reference does not own the FileEntry object. + /// + /// It is possible for this to be NULL if the ContentCache encapsulates + /// an imaginary text buffer. + const FileEntry *OrigEntry; + + /// \brief References the file which the contents were actually loaded from. + /// + /// Can be different from 'Entry' if we overridden the contents of one file + /// with the contents of another file. + const FileEntry *ContentsEntry; + + /// \brief A bump pointer allocated array of offsets for each source line. + /// + /// This is lazily computed. This is owned by the SourceManager + /// BumpPointerAllocator object. + unsigned *SourceLineCache; + + /// \brief The number of lines in this ContentCache. + /// + /// This is only valid if SourceLineCache is non-null. + unsigned NumLines; + + /// \brief Indicates whether the buffer itself was provided to override + /// the actual file contents. + /// + /// When true, the original entry may be a virtual file that does not + /// exist. + unsigned BufferOverridden : 1; + + /// \brief True if this content cache was initially created for a source + /// file considered as a system one. + unsigned IsSystemFile : 1; + + /// \brief True if this file may be transient, that is, if it might not + /// exist at some later point in time when this content entry is used, + /// after serialization and deserialization. + unsigned IsTransient : 1; + + ContentCache(const FileEntry *Ent = nullptr) : ContentCache(Ent, Ent) {} + + ContentCache(const FileEntry *Ent, const FileEntry *contentEnt) + : Buffer(nullptr, false), OrigEntry(Ent), ContentsEntry(contentEnt), + SourceLineCache(nullptr), NumLines(0), BufferOverridden(false), + IsSystemFile(false), IsTransient(false) {} + + ~ContentCache(); + + /// The copy ctor does not allow copies where source object has either + /// a non-NULL Buffer or SourceLineCache. Ownership of allocated memory + /// is not transferred, so this is a logical error. + ContentCache(const ContentCache &RHS) + : Buffer(nullptr, false), SourceLineCache(nullptr), + BufferOverridden(false), IsSystemFile(false), IsTransient(false) { + OrigEntry = RHS.OrigEntry; + ContentsEntry = RHS.ContentsEntry; + + assert(RHS.Buffer.getPointer() == nullptr && + RHS.SourceLineCache == nullptr && + "Passed ContentCache object cannot own a buffer."); + + NumLines = RHS.NumLines; + } + + /// \brief Returns the memory buffer for the associated content. + /// + /// \param Diag Object through which diagnostics will be emitted if the + /// buffer cannot be retrieved. + /// + /// \param Loc If specified, is the location that invalid file diagnostics + /// will be emitted at. + /// + /// \param Invalid If non-NULL, will be set \c true if an error occurred. + llvm::MemoryBuffer *getBuffer(DiagnosticsEngine &Diag, + const SourceManager &SM, + SourceLocation Loc = SourceLocation(), + bool *Invalid = nullptr) const; + + /// \brief Returns the size of the content encapsulated by this + /// ContentCache. + /// + /// This can be the size of the source file or the size of an + /// arbitrary scratch buffer. If the ContentCache encapsulates a source + /// file this size is retrieved from the file's FileEntry. + unsigned getSize() const; + + /// \brief Returns the number of bytes actually mapped for this + /// ContentCache. + /// + /// This can be 0 if the MemBuffer was not actually expanded. + unsigned getSizeBytesMapped() const; + + /// Returns the kind of memory used to back the memory buffer for + /// this content cache. This is used for performance analysis. + llvm::MemoryBuffer::BufferKind getMemoryBufferKind() const; + + void setBuffer(std::unique_ptr<llvm::MemoryBuffer> B) { + assert(!Buffer.getPointer() && "MemoryBuffer already set."); + Buffer.setPointer(B.release()); + Buffer.setInt(0); + } + + /// \brief Get the underlying buffer, returning NULL if the buffer is not + /// yet available. + llvm::MemoryBuffer *getRawBuffer() const { return Buffer.getPointer(); } + + /// \brief Replace the existing buffer (which will be deleted) + /// with the given buffer. + void replaceBuffer(llvm::MemoryBuffer *B, bool DoNotFree = false); + + /// \brief Determine whether the buffer itself is invalid. + bool isBufferInvalid() const { + return Buffer.getInt() & InvalidFlag; + } + + /// \brief Determine whether the buffer should be freed. + bool shouldFreeBuffer() const { + return (Buffer.getInt() & DoNotFreeFlag) == 0; + } + + private: + // Disable assignments. + ContentCache &operator=(const ContentCache& RHS) = delete; + }; + + // Assert that the \c ContentCache objects will always be 8-byte aligned so + // that we can pack 3 bits of integer into pointers to such objects. + static_assert(llvm::AlignOf<ContentCache>::Alignment >= 8, + "ContentCache must be 8-byte aligned."); + + /// \brief Information about a FileID, basically just the logical file + /// that it represents and include stack information. + /// + /// Each FileInfo has include stack information, indicating where it came + /// from. This information encodes the \#include chain that a token was + /// expanded from. The main include file has an invalid IncludeLoc. + /// + /// FileInfos contain a "ContentCache *", with the contents of the file. + /// + class FileInfo { + /// \brief The location of the \#include that brought in this file. + /// + /// This is an invalid SLOC for the main file (top of the \#include chain). + unsigned IncludeLoc; // Really a SourceLocation + + /// \brief Number of FileIDs (files and macros) that were created during + /// preprocessing of this \#include, including this SLocEntry. + /// + /// Zero means the preprocessor didn't provide such info for this SLocEntry. + unsigned NumCreatedFIDs; + + /// \brief Contains the ContentCache* and the bits indicating the + /// characteristic of the file and whether it has \#line info, all + /// bitmangled together. + uintptr_t Data; + + friend class clang::SourceManager; + friend class clang::ASTWriter; + friend class clang::ASTReader; + public: + /// \brief Return a FileInfo object. + static FileInfo get(SourceLocation IL, const ContentCache *Con, + CharacteristicKind FileCharacter) { + FileInfo X; + X.IncludeLoc = IL.getRawEncoding(); + X.NumCreatedFIDs = 0; + X.Data = (uintptr_t)Con; + assert((X.Data & 7) == 0 &&"ContentCache pointer insufficiently aligned"); + assert((unsigned)FileCharacter < 4 && "invalid file character"); + X.Data |= (unsigned)FileCharacter; + return X; + } + + SourceLocation getIncludeLoc() const { + return SourceLocation::getFromRawEncoding(IncludeLoc); + } + const ContentCache* getContentCache() const { + return reinterpret_cast<const ContentCache*>(Data & ~uintptr_t(7)); + } + + /// \brief Return whether this is a system header or not. + CharacteristicKind getFileCharacteristic() const { + return (CharacteristicKind)(Data & 3); + } + + /// \brief Return true if this FileID has \#line directives in it. + bool hasLineDirectives() const { return (Data & 4) != 0; } + + /// \brief Set the flag that indicates that this FileID has + /// line table entries associated with it. + void setHasLineDirectives() { + Data |= 4; + } + }; + + /// \brief Each ExpansionInfo encodes the expansion location - where + /// the token was ultimately expanded, and the SpellingLoc - where the actual + /// character data for the token came from. + class ExpansionInfo { + // Really these are all SourceLocations. + + /// \brief Where the spelling for the token can be found. + unsigned SpellingLoc; + + /// In a macro expansion, ExpansionLocStart and ExpansionLocEnd + /// indicate the start and end of the expansion. In object-like macros, + /// they will be the same. In a function-like macro expansion, the start + /// will be the identifier and the end will be the ')'. Finally, in + /// macro-argument instantiations, the end will be 'SourceLocation()', an + /// invalid location. + unsigned ExpansionLocStart, ExpansionLocEnd; + + public: + SourceLocation getSpellingLoc() const { + return SourceLocation::getFromRawEncoding(SpellingLoc); + } + SourceLocation getExpansionLocStart() const { + return SourceLocation::getFromRawEncoding(ExpansionLocStart); + } + SourceLocation getExpansionLocEnd() const { + SourceLocation EndLoc = + SourceLocation::getFromRawEncoding(ExpansionLocEnd); + return EndLoc.isInvalid() ? getExpansionLocStart() : EndLoc; + } + + std::pair<SourceLocation,SourceLocation> getExpansionLocRange() const { + return std::make_pair(getExpansionLocStart(), getExpansionLocEnd()); + } + + bool isMacroArgExpansion() const { + // Note that this needs to return false for default constructed objects. + return getExpansionLocStart().isValid() && + SourceLocation::getFromRawEncoding(ExpansionLocEnd).isInvalid(); + } + + bool isMacroBodyExpansion() const { + return getExpansionLocStart().isValid() && + SourceLocation::getFromRawEncoding(ExpansionLocEnd).isValid(); + } + + bool isFunctionMacroExpansion() const { + return getExpansionLocStart().isValid() && + getExpansionLocStart() != getExpansionLocEnd(); + } + + /// \brief Return a ExpansionInfo for an expansion. + /// + /// Start and End specify the expansion range (where the macro is + /// expanded), and SpellingLoc specifies the spelling location (where + /// the characters from the token come from). All three can refer to + /// normal File SLocs or expansion locations. + static ExpansionInfo create(SourceLocation SpellingLoc, + SourceLocation Start, SourceLocation End) { + ExpansionInfo X; + X.SpellingLoc = SpellingLoc.getRawEncoding(); + X.ExpansionLocStart = Start.getRawEncoding(); + X.ExpansionLocEnd = End.getRawEncoding(); + return X; + } + + /// \brief Return a special ExpansionInfo for the expansion of + /// a macro argument into a function-like macro's body. + /// + /// ExpansionLoc specifies the expansion location (where the macro is + /// expanded). This doesn't need to be a range because a macro is always + /// expanded at a macro parameter reference, and macro parameters are + /// always exactly one token. SpellingLoc specifies the spelling location + /// (where the characters from the token come from). ExpansionLoc and + /// SpellingLoc can both refer to normal File SLocs or expansion locations. + /// + /// Given the code: + /// \code + /// #define F(x) f(x) + /// F(42); + /// \endcode + /// + /// When expanding '\c F(42)', the '\c x' would call this with an + /// SpellingLoc pointing at '\c 42' and an ExpansionLoc pointing at its + /// location in the definition of '\c F'. + static ExpansionInfo createForMacroArg(SourceLocation SpellingLoc, + SourceLocation ExpansionLoc) { + // We store an intentionally invalid source location for the end of the + // expansion range to mark that this is a macro argument ion rather than + // a normal one. + return create(SpellingLoc, ExpansionLoc, SourceLocation()); + } + }; + + /// \brief This is a discriminated union of FileInfo and ExpansionInfo. + /// + /// SourceManager keeps an array of these objects, and they are uniquely + /// identified by the FileID datatype. + class SLocEntry { + unsigned Offset : 31; + unsigned IsExpansion : 1; + union { + FileInfo File; + ExpansionInfo Expansion; + }; + public: + unsigned getOffset() const { return Offset; } + + bool isExpansion() const { return IsExpansion; } + bool isFile() const { return !isExpansion(); } + + const FileInfo &getFile() const { + assert(isFile() && "Not a file SLocEntry!"); + return File; + } + + const ExpansionInfo &getExpansion() const { + assert(isExpansion() && "Not a macro expansion SLocEntry!"); + return Expansion; + } + + static SLocEntry get(unsigned Offset, const FileInfo &FI) { + assert(!(Offset & (1 << 31)) && "Offset is too large"); + SLocEntry E; + E.Offset = Offset; + E.IsExpansion = false; + E.File = FI; + return E; + } + + static SLocEntry get(unsigned Offset, const ExpansionInfo &Expansion) { + assert(!(Offset & (1 << 31)) && "Offset is too large"); + SLocEntry E; + E.Offset = Offset; + E.IsExpansion = true; + E.Expansion = Expansion; + return E; + } + }; +} // end SrcMgr namespace. + +/// \brief External source of source location entries. +class ExternalSLocEntrySource { +public: + virtual ~ExternalSLocEntrySource(); + + /// \brief Read the source location entry with index ID, which will always be + /// less than -1. + /// + /// \returns true if an error occurred that prevented the source-location + /// entry from being loaded. + virtual bool ReadSLocEntry(int ID) = 0; + + /// \brief Retrieve the module import location and name for the given ID, if + /// in fact it was loaded from a module (rather than, say, a precompiled + /// header). + virtual std::pair<SourceLocation, StringRef> getModuleImportLoc(int ID) = 0; +}; + + +/// \brief Holds the cache used by isBeforeInTranslationUnit. +/// +/// The cache structure is complex enough to be worth breaking out of +/// SourceManager. +class InBeforeInTUCacheEntry { + /// \brief The FileID's of the cached query. + /// + /// If these match up with a subsequent query, the result can be reused. + FileID LQueryFID, RQueryFID; + + /// \brief True if LQueryFID was created before RQueryFID. + /// + /// This is used to compare macro expansion locations. + bool IsLQFIDBeforeRQFID; + + /// \brief The file found in common between the two \#include traces, i.e., + /// the nearest common ancestor of the \#include tree. + FileID CommonFID; + + /// \brief The offset of the previous query in CommonFID. + /// + /// Usually, this represents the location of the \#include for QueryFID, but + /// if LQueryFID is a parent of RQueryFID (or vice versa) then these can be a + /// random token in the parent. + unsigned LCommonOffset, RCommonOffset; +public: + /// \brief Return true if the currently cached values match up with + /// the specified LHS/RHS query. + /// + /// If not, we can't use the cache. + bool isCacheValid(FileID LHS, FileID RHS) const { + return LQueryFID == LHS && RQueryFID == RHS; + } + + /// \brief If the cache is valid, compute the result given the + /// specified offsets in the LHS/RHS FileID's. + bool getCachedResult(unsigned LOffset, unsigned ROffset) const { + // If one of the query files is the common file, use the offset. Otherwise, + // use the #include loc in the common file. + if (LQueryFID != CommonFID) LOffset = LCommonOffset; + if (RQueryFID != CommonFID) ROffset = RCommonOffset; + + // It is common for multiple macro expansions to be "included" from the same + // location (expansion location), in which case use the order of the FileIDs + // to determine which came first. This will also take care the case where + // one of the locations points at the inclusion/expansion point of the other + // in which case its FileID will come before the other. + if (LOffset == ROffset) + return IsLQFIDBeforeRQFID; + + return LOffset < ROffset; + } + + /// \brief Set up a new query. + void setQueryFIDs(FileID LHS, FileID RHS, bool isLFIDBeforeRFID) { + assert(LHS != RHS); + LQueryFID = LHS; + RQueryFID = RHS; + IsLQFIDBeforeRQFID = isLFIDBeforeRFID; + } + + void clear() { + LQueryFID = RQueryFID = FileID(); + IsLQFIDBeforeRQFID = false; + } + + void setCommonLoc(FileID commonFID, unsigned lCommonOffset, + unsigned rCommonOffset) { + CommonFID = commonFID; + LCommonOffset = lCommonOffset; + RCommonOffset = rCommonOffset; + } + +}; + +/// \brief The stack used when building modules on demand, which is used +/// to provide a link between the source managers of the different compiler +/// instances. +typedef ArrayRef<std::pair<std::string, FullSourceLoc> > ModuleBuildStack; + +/// \brief This class handles loading and caching of source files into memory. +/// +/// This object owns the MemoryBuffer objects for all of the loaded +/// files and assigns unique FileID's for each unique \#include chain. +/// +/// The SourceManager can be queried for information about SourceLocation +/// objects, turning them into either spelling or expansion locations. Spelling +/// locations represent where the bytes corresponding to a token came from and +/// expansion locations represent where the location is in the user's view. In +/// the case of a macro expansion, for example, the spelling location indicates +/// where the expanded token came from and the expansion location specifies +/// where it was expanded. +class SourceManager : public RefCountedBase<SourceManager> { + /// \brief DiagnosticsEngine object. + DiagnosticsEngine &Diag; + + FileManager &FileMgr; + + mutable llvm::BumpPtrAllocator ContentCacheAlloc; + + /// \brief Memoized information about all of the files tracked by this + /// SourceManager. + /// + /// This map allows us to merge ContentCache entries based + /// on their FileEntry*. All ContentCache objects will thus have unique, + /// non-null, FileEntry pointers. + llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*> FileInfos; + + /// \brief True if the ContentCache for files that are overridden by other + /// files, should report the original file name. Defaults to true. + bool OverridenFilesKeepOriginalName; + + /// \brief True if non-system source files should be treated as volatile + /// (likely to change while trying to use them). Defaults to false. + bool UserFilesAreVolatile; + + /// \brief True if all files read during this compilation should be treated + /// as transient (may not be present in later compilations using a module + /// file created from this compilation). Defaults to false. + bool FilesAreTransient; + + struct OverriddenFilesInfoTy { + /// \brief Files that have been overridden with the contents from another + /// file. + llvm::DenseMap<const FileEntry *, const FileEntry *> OverriddenFiles; + /// \brief Files that were overridden with a memory buffer. + llvm::DenseSet<const FileEntry *> OverriddenFilesWithBuffer; + }; + + /// \brief Lazily create the object keeping overridden files info, since + /// it is uncommonly used. + std::unique_ptr<OverriddenFilesInfoTy> OverriddenFilesInfo; + + OverriddenFilesInfoTy &getOverriddenFilesInfo() { + if (!OverriddenFilesInfo) + OverriddenFilesInfo.reset(new OverriddenFilesInfoTy); + return *OverriddenFilesInfo; + } + + /// \brief Information about various memory buffers that we have read in. + /// + /// All FileEntry* within the stored ContentCache objects are NULL, + /// as they do not refer to a file. + std::vector<SrcMgr::ContentCache*> MemBufferInfos; + + /// \brief The table of SLocEntries that are local to this module. + /// + /// Positive FileIDs are indexes into this table. Entry 0 indicates an invalid + /// expansion. + SmallVector<SrcMgr::SLocEntry, 0> LocalSLocEntryTable; + + /// \brief The table of SLocEntries that are loaded from other modules. + /// + /// Negative FileIDs are indexes into this table. To get from ID to an index, + /// use (-ID - 2). + mutable SmallVector<SrcMgr::SLocEntry, 0> LoadedSLocEntryTable; + + /// \brief The starting offset of the next local SLocEntry. + /// + /// This is LocalSLocEntryTable.back().Offset + the size of that entry. + unsigned NextLocalOffset; + + /// \brief The starting offset of the latest batch of loaded SLocEntries. + /// + /// This is LoadedSLocEntryTable.back().Offset, except that that entry might + /// not have been loaded, so that value would be unknown. + unsigned CurrentLoadedOffset; + + /// \brief The highest possible offset is 2^31-1, so CurrentLoadedOffset + /// starts at 2^31. + static const unsigned MaxLoadedOffset = 1U << 31U; + + /// \brief A bitmap that indicates whether the entries of LoadedSLocEntryTable + /// have already been loaded from the external source. + /// + /// Same indexing as LoadedSLocEntryTable. + llvm::BitVector SLocEntryLoaded; + + /// \brief An external source for source location entries. + ExternalSLocEntrySource *ExternalSLocEntries; + + /// \brief A one-entry cache to speed up getFileID. + /// + /// LastFileIDLookup records the last FileID looked up or created, because it + /// is very common to look up many tokens from the same file. + mutable FileID LastFileIDLookup; + + /// \brief Holds information for \#line directives. + /// + /// This is referenced by indices from SLocEntryTable. + LineTableInfo *LineTable; + + /// \brief These ivars serve as a cache used in the getLineNumber + /// method which is used to speedup getLineNumber calls to nearby locations. + mutable FileID LastLineNoFileIDQuery; + mutable SrcMgr::ContentCache *LastLineNoContentCache; + mutable unsigned LastLineNoFilePos; + mutable unsigned LastLineNoResult; + + /// \brief The file ID for the main source file of the translation unit. + FileID MainFileID; + + /// \brief The file ID for the precompiled preamble there is one. + FileID PreambleFileID; + + // Statistics for -print-stats. + mutable unsigned NumLinearScans, NumBinaryProbes; + + /// \brief Associates a FileID with its "included/expanded in" decomposed + /// location. + /// + /// Used to cache results from and speed-up \c getDecomposedIncludedLoc + /// function. + mutable llvm::DenseMap<FileID, std::pair<FileID, unsigned> > IncludedLocMap; + + /// The key value into the IsBeforeInTUCache table. + typedef std::pair<FileID, FileID> IsBeforeInTUCacheKey; + + /// The IsBeforeInTranslationUnitCache is a mapping from FileID pairs + /// to cache results. + typedef llvm::DenseMap<IsBeforeInTUCacheKey, InBeforeInTUCacheEntry> + InBeforeInTUCache; + + /// Cache results for the isBeforeInTranslationUnit method. + mutable InBeforeInTUCache IBTUCache; + mutable InBeforeInTUCacheEntry IBTUCacheOverflow; + + /// Return the cache entry for comparing the given file IDs + /// for isBeforeInTranslationUnit. + InBeforeInTUCacheEntry &getInBeforeInTUCache(FileID LFID, FileID RFID) const; + + // Cache for the "fake" buffer used for error-recovery purposes. + mutable std::unique_ptr<llvm::MemoryBuffer> FakeBufferForRecovery; + + mutable std::unique_ptr<SrcMgr::ContentCache> FakeContentCacheForRecovery; + + /// \brief Lazily computed map of macro argument chunks to their expanded + /// source location. + typedef std::map<unsigned, SourceLocation> MacroArgsMap; + + mutable llvm::DenseMap<FileID, MacroArgsMap *> MacroArgsCacheMap; + + /// \brief The stack of modules being built, which is used to detect + /// cycles in the module dependency graph as modules are being built, as + /// well as to describe why we're rebuilding a particular module. + /// + /// There is no way to set this value from the command line. If we ever need + /// to do so (e.g., if on-demand module construction moves out-of-process), + /// we can add a cc1-level option to do so. + SmallVector<std::pair<std::string, FullSourceLoc>, 2> StoredModuleBuildStack; + + // SourceManager doesn't support copy construction. + explicit SourceManager(const SourceManager&) = delete; + void operator=(const SourceManager&) = delete; +public: + SourceManager(DiagnosticsEngine &Diag, FileManager &FileMgr, + bool UserFilesAreVolatile = false); + ~SourceManager(); + + void clearIDTables(); + + DiagnosticsEngine &getDiagnostics() const { return Diag; } + + FileManager &getFileManager() const { return FileMgr; } + + /// \brief Set true if the SourceManager should report the original file name + /// for contents of files that were overridden by other files. Defaults to + /// true. + void setOverridenFilesKeepOriginalName(bool value) { + OverridenFilesKeepOriginalName = value; + } + + /// \brief True if non-system source files should be treated as volatile + /// (likely to change while trying to use them). + bool userFilesAreVolatile() const { return UserFilesAreVolatile; } + + /// \brief Retrieve the module build stack. + ModuleBuildStack getModuleBuildStack() const { + return StoredModuleBuildStack; + } + + /// \brief Set the module build stack. + void setModuleBuildStack(ModuleBuildStack stack) { + StoredModuleBuildStack.clear(); + StoredModuleBuildStack.append(stack.begin(), stack.end()); + } + + /// \brief Push an entry to the module build stack. + void pushModuleBuildStack(StringRef moduleName, FullSourceLoc importLoc) { + StoredModuleBuildStack.push_back(std::make_pair(moduleName.str(),importLoc)); + } + + //===--------------------------------------------------------------------===// + // MainFileID creation and querying methods. + //===--------------------------------------------------------------------===// + + /// \brief Returns the FileID of the main source file. + FileID getMainFileID() const { return MainFileID; } + + /// \brief Set the file ID for the main source file. + void setMainFileID(FileID FID) { + MainFileID = FID; + } + + /// \brief Set the file ID for the precompiled preamble. + void setPreambleFileID(FileID Preamble) { + assert(PreambleFileID.isInvalid() && "PreambleFileID already set!"); + PreambleFileID = Preamble; + } + + /// \brief Get the file ID for the precompiled preamble if there is one. + FileID getPreambleFileID() const { return PreambleFileID; } + + //===--------------------------------------------------------------------===// + // Methods to create new FileID's and macro expansions. + //===--------------------------------------------------------------------===// + + /// \brief Create a new FileID that represents the specified file + /// being \#included from the specified IncludePosition. + /// + /// This translates NULL into standard input. + FileID createFileID(const FileEntry *SourceFile, SourceLocation IncludePos, + SrcMgr::CharacteristicKind FileCharacter, + int LoadedID = 0, unsigned LoadedOffset = 0) { + const SrcMgr::ContentCache * + IR = getOrCreateContentCache(SourceFile, + /*isSystemFile=*/FileCharacter != SrcMgr::C_User); + assert(IR && "getOrCreateContentCache() cannot return NULL"); + return createFileID(IR, IncludePos, FileCharacter, LoadedID, LoadedOffset); + } + + /// \brief Create a new FileID that represents the specified memory buffer. + /// + /// This does no caching of the buffer and takes ownership of the + /// MemoryBuffer, so only pass a MemoryBuffer to this once. + FileID createFileID(std::unique_ptr<llvm::MemoryBuffer> Buffer, + SrcMgr::CharacteristicKind FileCharacter = SrcMgr::C_User, + int LoadedID = 0, unsigned LoadedOffset = 0, + SourceLocation IncludeLoc = SourceLocation()) { + return createFileID(createMemBufferContentCache(std::move(Buffer)), + IncludeLoc, FileCharacter, LoadedID, LoadedOffset); + } + + /// \brief Return a new SourceLocation that encodes the + /// fact that a token from SpellingLoc should actually be referenced from + /// ExpansionLoc, and that it represents the expansion of a macro argument + /// into the function-like macro body. + SourceLocation createMacroArgExpansionLoc(SourceLocation Loc, + SourceLocation ExpansionLoc, + unsigned TokLength); + + /// \brief Return a new SourceLocation that encodes the fact + /// that a token from SpellingLoc should actually be referenced from + /// ExpansionLoc. + SourceLocation createExpansionLoc(SourceLocation Loc, + SourceLocation ExpansionLocStart, + SourceLocation ExpansionLocEnd, + unsigned TokLength, + int LoadedID = 0, + unsigned LoadedOffset = 0); + + /// \brief Retrieve the memory buffer associated with the given file. + /// + /// \param Invalid If non-NULL, will be set \c true if an error + /// occurs while retrieving the memory buffer. + llvm::MemoryBuffer *getMemoryBufferForFile(const FileEntry *File, + bool *Invalid = nullptr); + + /// \brief Override the contents of the given source file by providing an + /// already-allocated buffer. + /// + /// \param SourceFile the source file whose contents will be overridden. + /// + /// \param Buffer the memory buffer whose contents will be used as the + /// data in the given source file. + /// + /// \param DoNotFree If true, then the buffer will not be freed when the + /// source manager is destroyed. + void overrideFileContents(const FileEntry *SourceFile, + llvm::MemoryBuffer *Buffer, bool DoNotFree); + void overrideFileContents(const FileEntry *SourceFile, + std::unique_ptr<llvm::MemoryBuffer> Buffer) { + overrideFileContents(SourceFile, Buffer.release(), /*DoNotFree*/ false); + } + + /// \brief Override the given source file with another one. + /// + /// \param SourceFile the source file which will be overridden. + /// + /// \param NewFile the file whose contents will be used as the + /// data instead of the contents of the given source file. + void overrideFileContents(const FileEntry *SourceFile, + const FileEntry *NewFile); + + /// \brief Returns true if the file contents have been overridden. + bool isFileOverridden(const FileEntry *File) { + if (OverriddenFilesInfo) { + if (OverriddenFilesInfo->OverriddenFilesWithBuffer.count(File)) + return true; + if (OverriddenFilesInfo->OverriddenFiles.find(File) != + OverriddenFilesInfo->OverriddenFiles.end()) + return true; + } + return false; + } + + /// \brief Disable overridding the contents of a file, previously enabled + /// with #overrideFileContents. + /// + /// This should be called before parsing has begun. + void disableFileContentsOverride(const FileEntry *File); + + /// \brief Specify that a file is transient. + void setFileIsTransient(const FileEntry *SourceFile); + + /// \brief Specify that all files that are read during this compilation are + /// transient. + void setAllFilesAreTransient(bool Transient) { + FilesAreTransient = Transient; + } + + //===--------------------------------------------------------------------===// + // FileID manipulation methods. + //===--------------------------------------------------------------------===// + + /// \brief Return the buffer for the specified FileID. + /// + /// If there is an error opening this buffer the first time, this + /// manufactures a temporary buffer and returns a non-empty error string. + llvm::MemoryBuffer *getBuffer(FileID FID, SourceLocation Loc, + bool *Invalid = nullptr) const { + bool MyInvalid = false; + const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &MyInvalid); + if (MyInvalid || !Entry.isFile()) { + if (Invalid) + *Invalid = true; + + return getFakeBufferForRecovery(); + } + + return Entry.getFile().getContentCache()->getBuffer(Diag, *this, Loc, + Invalid); + } + + llvm::MemoryBuffer *getBuffer(FileID FID, bool *Invalid = nullptr) const { + bool MyInvalid = false; + const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &MyInvalid); + if (MyInvalid || !Entry.isFile()) { + if (Invalid) + *Invalid = true; + + return getFakeBufferForRecovery(); + } + + return Entry.getFile().getContentCache()->getBuffer(Diag, *this, + SourceLocation(), + Invalid); + } + + /// \brief Returns the FileEntry record for the provided FileID. + const FileEntry *getFileEntryForID(FileID FID) const { + bool MyInvalid = false; + const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &MyInvalid); + if (MyInvalid || !Entry.isFile()) + return nullptr; + + const SrcMgr::ContentCache *Content = Entry.getFile().getContentCache(); + if (!Content) + return nullptr; + return Content->OrigEntry; + } + + /// \brief Returns the FileEntry record for the provided SLocEntry. + const FileEntry *getFileEntryForSLocEntry(const SrcMgr::SLocEntry &sloc) const + { + const SrcMgr::ContentCache *Content = sloc.getFile().getContentCache(); + if (!Content) + return nullptr; + return Content->OrigEntry; + } + + /// \brief Return a StringRef to the source buffer data for the + /// specified FileID. + /// + /// \param FID The file ID whose contents will be returned. + /// \param Invalid If non-NULL, will be set true if an error occurred. + StringRef getBufferData(FileID FID, bool *Invalid = nullptr) const; + + /// \brief Get the number of FileIDs (files and macros) that were created + /// during preprocessing of \p FID, including it. + unsigned getNumCreatedFIDsForFileID(FileID FID) const { + bool Invalid = false; + const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid); + if (Invalid || !Entry.isFile()) + return 0; + + return Entry.getFile().NumCreatedFIDs; + } + + /// \brief Set the number of FileIDs (files and macros) that were created + /// during preprocessing of \p FID, including it. + void setNumCreatedFIDsForFileID(FileID FID, unsigned NumFIDs) const { + bool Invalid = false; + const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid); + if (Invalid || !Entry.isFile()) + return; + + assert(Entry.getFile().NumCreatedFIDs == 0 && "Already set!"); + const_cast<SrcMgr::FileInfo &>(Entry.getFile()).NumCreatedFIDs = NumFIDs; + } + + //===--------------------------------------------------------------------===// + // SourceLocation manipulation methods. + //===--------------------------------------------------------------------===// + + /// \brief Return the FileID for a SourceLocation. + /// + /// This is a very hot method that is used for all SourceManager queries + /// that start with a SourceLocation object. It is responsible for finding + /// the entry in SLocEntryTable which contains the specified location. + /// + FileID getFileID(SourceLocation SpellingLoc) const { + unsigned SLocOffset = SpellingLoc.getOffset(); + + // If our one-entry cache covers this offset, just return it. + if (isOffsetInFileID(LastFileIDLookup, SLocOffset)) + return LastFileIDLookup; + + return getFileIDSlow(SLocOffset); + } + + /// \brief Return the filename of the file containing a SourceLocation. + StringRef getFilename(SourceLocation SpellingLoc) const { + if (const FileEntry *F = getFileEntryForID(getFileID(SpellingLoc))) + return F->getName(); + return StringRef(); + } + + /// \brief Return the source location corresponding to the first byte of + /// the specified file. + SourceLocation getLocForStartOfFile(FileID FID) const { + bool Invalid = false; + const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid); + if (Invalid || !Entry.isFile()) + return SourceLocation(); + + unsigned FileOffset = Entry.getOffset(); + return SourceLocation::getFileLoc(FileOffset); + } + + /// \brief Return the source location corresponding to the last byte of the + /// specified file. + SourceLocation getLocForEndOfFile(FileID FID) const { + bool Invalid = false; + const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid); + if (Invalid || !Entry.isFile()) + return SourceLocation(); + + unsigned FileOffset = Entry.getOffset(); + return SourceLocation::getFileLoc(FileOffset + getFileIDSize(FID)); + } + + /// \brief Returns the include location if \p FID is a \#include'd file + /// otherwise it returns an invalid location. + SourceLocation getIncludeLoc(FileID FID) const { + bool Invalid = false; + const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid); + if (Invalid || !Entry.isFile()) + return SourceLocation(); + + return Entry.getFile().getIncludeLoc(); + } + + // \brief Returns the import location if the given source location is + // located within a module, or an invalid location if the source location + // is within the current translation unit. + std::pair<SourceLocation, StringRef> + getModuleImportLoc(SourceLocation Loc) const { + FileID FID = getFileID(Loc); + + // Positive file IDs are in the current translation unit, and -1 is a + // placeholder. + if (FID.ID >= -1) + return std::make_pair(SourceLocation(), ""); + + return ExternalSLocEntries->getModuleImportLoc(FID.ID); + } + + /// \brief Given a SourceLocation object \p Loc, return the expansion + /// location referenced by the ID. + SourceLocation getExpansionLoc(SourceLocation Loc) const { + // Handle the non-mapped case inline, defer to out of line code to handle + // expansions. + if (Loc.isFileID()) return Loc; + return getExpansionLocSlowCase(Loc); + } + + /// \brief Given \p Loc, if it is a macro location return the expansion + /// location or the spelling location, depending on if it comes from a + /// macro argument or not. + SourceLocation getFileLoc(SourceLocation Loc) const { + if (Loc.isFileID()) return Loc; + return getFileLocSlowCase(Loc); + } + + /// \brief Return the start/end of the expansion information for an + /// expansion location. + /// + /// \pre \p Loc is required to be an expansion location. + std::pair<SourceLocation,SourceLocation> + getImmediateExpansionRange(SourceLocation Loc) const; + + /// \brief Given a SourceLocation object, return the range of + /// tokens covered by the expansion in the ultimate file. + std::pair<SourceLocation,SourceLocation> + getExpansionRange(SourceLocation Loc) const; + + /// \brief Given a SourceRange object, return the range of + /// tokens covered by the expansion in the ultimate file. + SourceRange getExpansionRange(SourceRange Range) const { + return SourceRange(getExpansionRange(Range.getBegin()).first, + getExpansionRange(Range.getEnd()).second); + } + + /// \brief Given a SourceLocation object, return the spelling + /// location referenced by the ID. + /// + /// This is the place where the characters that make up the lexed token + /// can be found. + SourceLocation getSpellingLoc(SourceLocation Loc) const { + // Handle the non-mapped case inline, defer to out of line code to handle + // expansions. + if (Loc.isFileID()) return Loc; + return getSpellingLocSlowCase(Loc); + } + + /// \brief Given a SourceLocation object, return the spelling location + /// referenced by the ID. + /// + /// This is the first level down towards the place where the characters + /// that make up the lexed token can be found. This should not generally + /// be used by clients. + SourceLocation getImmediateSpellingLoc(SourceLocation Loc) const; + + /// \brief Decompose the specified location into a raw FileID + Offset pair. + /// + /// The first element is the FileID, the second is the offset from the + /// start of the buffer of the location. + std::pair<FileID, unsigned> getDecomposedLoc(SourceLocation Loc) const { + FileID FID = getFileID(Loc); + bool Invalid = false; + const SrcMgr::SLocEntry &E = getSLocEntry(FID, &Invalid); + if (Invalid) + return std::make_pair(FileID(), 0); + return std::make_pair(FID, Loc.getOffset()-E.getOffset()); + } + + /// \brief Decompose the specified location into a raw FileID + Offset pair. + /// + /// If the location is an expansion record, walk through it until we find + /// the final location expanded. + std::pair<FileID, unsigned> + getDecomposedExpansionLoc(SourceLocation Loc) const { + FileID FID = getFileID(Loc); + bool Invalid = false; + const SrcMgr::SLocEntry *E = &getSLocEntry(FID, &Invalid); + if (Invalid) + return std::make_pair(FileID(), 0); + + unsigned Offset = Loc.getOffset()-E->getOffset(); + if (Loc.isFileID()) + return std::make_pair(FID, Offset); + + return getDecomposedExpansionLocSlowCase(E); + } + + /// \brief Decompose the specified location into a raw FileID + Offset pair. + /// + /// If the location is an expansion record, walk through it until we find + /// its spelling record. + std::pair<FileID, unsigned> + getDecomposedSpellingLoc(SourceLocation Loc) const { + FileID FID = getFileID(Loc); + bool Invalid = false; + const SrcMgr::SLocEntry *E = &getSLocEntry(FID, &Invalid); + if (Invalid) + return std::make_pair(FileID(), 0); + + unsigned Offset = Loc.getOffset()-E->getOffset(); + if (Loc.isFileID()) + return std::make_pair(FID, Offset); + return getDecomposedSpellingLocSlowCase(E, Offset); + } + + /// \brief Returns the "included/expanded in" decomposed location of the given + /// FileID. + std::pair<FileID, unsigned> getDecomposedIncludedLoc(FileID FID) const; + + /// \brief Returns the offset from the start of the file that the + /// specified SourceLocation represents. + /// + /// This is not very meaningful for a macro ID. + unsigned getFileOffset(SourceLocation SpellingLoc) const { + return getDecomposedLoc(SpellingLoc).second; + } + + /// \brief Tests whether the given source location represents a macro + /// argument's expansion into the function-like macro definition. + /// + /// \param StartLoc If non-null and function returns true, it is set to the + /// start location of the macro argument expansion. + /// + /// Such source locations only appear inside of the expansion + /// locations representing where a particular function-like macro was + /// expanded. + bool isMacroArgExpansion(SourceLocation Loc, + SourceLocation *StartLoc = nullptr) const; + + /// \brief Tests whether the given source location represents the expansion of + /// a macro body. + /// + /// This is equivalent to testing whether the location is part of a macro + /// expansion but not the expansion of an argument to a function-like macro. + bool isMacroBodyExpansion(SourceLocation Loc) const; + + /// \brief Returns true if the given MacroID location points at the beginning + /// of the immediate macro expansion. + /// + /// \param MacroBegin If non-null and function returns true, it is set to the + /// begin location of the immediate macro expansion. + bool isAtStartOfImmediateMacroExpansion(SourceLocation Loc, + SourceLocation *MacroBegin = nullptr) const; + + /// \brief Returns true if the given MacroID location points at the character + /// end of the immediate macro expansion. + /// + /// \param MacroEnd If non-null and function returns true, it is set to the + /// character end location of the immediate macro expansion. + bool + isAtEndOfImmediateMacroExpansion(SourceLocation Loc, + SourceLocation *MacroEnd = nullptr) const; + + /// \brief Returns true if \p Loc is inside the [\p Start, +\p Length) + /// chunk of the source location address space. + /// + /// If it's true and \p RelativeOffset is non-null, it will be set to the + /// relative offset of \p Loc inside the chunk. + bool isInSLocAddrSpace(SourceLocation Loc, + SourceLocation Start, unsigned Length, + unsigned *RelativeOffset = nullptr) const { + assert(((Start.getOffset() < NextLocalOffset && + Start.getOffset()+Length <= NextLocalOffset) || + (Start.getOffset() >= CurrentLoadedOffset && + Start.getOffset()+Length < MaxLoadedOffset)) && + "Chunk is not valid SLoc address space"); + unsigned LocOffs = Loc.getOffset(); + unsigned BeginOffs = Start.getOffset(); + unsigned EndOffs = BeginOffs + Length; + if (LocOffs >= BeginOffs && LocOffs < EndOffs) { + if (RelativeOffset) + *RelativeOffset = LocOffs - BeginOffs; + return true; + } + + return false; + } + + /// \brief Return true if both \p LHS and \p RHS are in the local source + /// location address space or the loaded one. + /// + /// If it's true and \p RelativeOffset is non-null, it will be set to the + /// offset of \p RHS relative to \p LHS. + bool isInSameSLocAddrSpace(SourceLocation LHS, SourceLocation RHS, + int *RelativeOffset) const { + unsigned LHSOffs = LHS.getOffset(), RHSOffs = RHS.getOffset(); + bool LHSLoaded = LHSOffs >= CurrentLoadedOffset; + bool RHSLoaded = RHSOffs >= CurrentLoadedOffset; + + if (LHSLoaded == RHSLoaded) { + if (RelativeOffset) + *RelativeOffset = RHSOffs - LHSOffs; + return true; + } + + return false; + } + + //===--------------------------------------------------------------------===// + // Queries about the code at a SourceLocation. + //===--------------------------------------------------------------------===// + + /// \brief Return a pointer to the start of the specified location + /// in the appropriate spelling MemoryBuffer. + /// + /// \param Invalid If non-NULL, will be set \c true if an error occurs. + const char *getCharacterData(SourceLocation SL, + bool *Invalid = nullptr) const; + + /// \brief Return the column # for the specified file position. + /// + /// This is significantly cheaper to compute than the line number. This + /// returns zero if the column number isn't known. This may only be called + /// on a file sloc, so you must choose a spelling or expansion location + /// before calling this method. + unsigned getColumnNumber(FileID FID, unsigned FilePos, + bool *Invalid = nullptr) const; + unsigned getSpellingColumnNumber(SourceLocation Loc, + bool *Invalid = nullptr) const; + unsigned getExpansionColumnNumber(SourceLocation Loc, + bool *Invalid = nullptr) const; + unsigned getPresumedColumnNumber(SourceLocation Loc, + bool *Invalid = nullptr) const; + + /// \brief Given a SourceLocation, return the spelling line number + /// for the position indicated. + /// + /// This requires building and caching a table of line offsets for the + /// MemoryBuffer, so this is not cheap: use only when about to emit a + /// diagnostic. + unsigned getLineNumber(FileID FID, unsigned FilePos, bool *Invalid = nullptr) const; + unsigned getSpellingLineNumber(SourceLocation Loc, bool *Invalid = nullptr) const; + unsigned getExpansionLineNumber(SourceLocation Loc, bool *Invalid = nullptr) const; + unsigned getPresumedLineNumber(SourceLocation Loc, bool *Invalid = nullptr) const; + + /// \brief Return the filename or buffer identifier of the buffer the + /// location is in. + /// + /// Note that this name does not respect \#line directives. Use + /// getPresumedLoc for normal clients. + const char *getBufferName(SourceLocation Loc, bool *Invalid = nullptr) const; + + /// \brief Return the file characteristic of the specified source + /// location, indicating whether this is a normal file, a system + /// header, or an "implicit extern C" system header. + /// + /// This state can be modified with flags on GNU linemarker directives like: + /// \code + /// # 4 "foo.h" 3 + /// \endcode + /// which changes all source locations in the current file after that to be + /// considered to be from a system header. + SrcMgr::CharacteristicKind getFileCharacteristic(SourceLocation Loc) const; + + /// \brief Returns the "presumed" location of a SourceLocation specifies. + /// + /// A "presumed location" can be modified by \#line or GNU line marker + /// directives. This provides a view on the data that a user should see + /// in diagnostics, for example. + /// + /// Note that a presumed location is always given as the expansion point of + /// an expansion location, not at the spelling location. + /// + /// \returns The presumed location of the specified SourceLocation. If the + /// presumed location cannot be calculated (e.g., because \p Loc is invalid + /// or the file containing \p Loc has changed on disk), returns an invalid + /// presumed location. + PresumedLoc getPresumedLoc(SourceLocation Loc, + bool UseLineDirectives = true) const; + + /// \brief Returns whether the PresumedLoc for a given SourceLocation is + /// in the main file. + /// + /// This computes the "presumed" location for a SourceLocation, then checks + /// whether it came from a file other than the main file. This is different + /// from isWrittenInMainFile() because it takes line marker directives into + /// account. + bool isInMainFile(SourceLocation Loc) const; + + /// \brief Returns true if the spelling locations for both SourceLocations + /// are part of the same file buffer. + /// + /// This check ignores line marker directives. + bool isWrittenInSameFile(SourceLocation Loc1, SourceLocation Loc2) const { + return getFileID(Loc1) == getFileID(Loc2); + } + + /// \brief Returns true if the spelling location for the given location + /// is in the main file buffer. + /// + /// This check ignores line marker directives. + bool isWrittenInMainFile(SourceLocation Loc) const { + return getFileID(Loc) == getMainFileID(); + } + + /// \brief Returns if a SourceLocation is in a system header. + bool isInSystemHeader(SourceLocation Loc) const { + return getFileCharacteristic(Loc) != SrcMgr::C_User; + } + + /// \brief Returns if a SourceLocation is in an "extern C" system header. + bool isInExternCSystemHeader(SourceLocation Loc) const { + return getFileCharacteristic(Loc) == SrcMgr::C_ExternCSystem; + } + + /// \brief Returns whether \p Loc is expanded from a macro in a system header. + bool isInSystemMacro(SourceLocation loc) { + return loc.isMacroID() && isInSystemHeader(getSpellingLoc(loc)); + } + + /// \brief The size of the SLocEntry that \p FID represents. + unsigned getFileIDSize(FileID FID) const; + + /// \brief Given a specific FileID, returns true if \p Loc is inside that + /// FileID chunk and sets relative offset (offset of \p Loc from beginning + /// of FileID) to \p relativeOffset. + bool isInFileID(SourceLocation Loc, FileID FID, + unsigned *RelativeOffset = nullptr) const { + unsigned Offs = Loc.getOffset(); + if (isOffsetInFileID(FID, Offs)) { + if (RelativeOffset) + *RelativeOffset = Offs - getSLocEntry(FID).getOffset(); + return true; + } + + return false; + } + + //===--------------------------------------------------------------------===// + // Line Table Manipulation Routines + //===--------------------------------------------------------------------===// + + /// \brief Return the uniqued ID for the specified filename. + /// + unsigned getLineTableFilenameID(StringRef Str); + + /// \brief Add a line note to the line table for the FileID and offset + /// specified by Loc. + /// + /// If FilenameID is -1, it is considered to be unspecified. + void AddLineNote(SourceLocation Loc, unsigned LineNo, int FilenameID); + void AddLineNote(SourceLocation Loc, unsigned LineNo, int FilenameID, + bool IsFileEntry, bool IsFileExit, + bool IsSystemHeader, bool IsExternCHeader); + + /// \brief Determine if the source manager has a line table. + bool hasLineTable() const { return LineTable != nullptr; } + + /// \brief Retrieve the stored line table. + LineTableInfo &getLineTable(); + + //===--------------------------------------------------------------------===// + // Queries for performance analysis. + //===--------------------------------------------------------------------===// + + /// \brief Return the total amount of physical memory allocated by the + /// ContentCache allocator. + size_t getContentCacheSize() const { + return ContentCacheAlloc.getTotalMemory(); + } + + struct MemoryBufferSizes { + const size_t malloc_bytes; + const size_t mmap_bytes; + + MemoryBufferSizes(size_t malloc_bytes, size_t mmap_bytes) + : malloc_bytes(malloc_bytes), mmap_bytes(mmap_bytes) {} + }; + + /// \brief Return the amount of memory used by memory buffers, breaking down + /// by heap-backed versus mmap'ed memory. + MemoryBufferSizes getMemoryBufferSizes() const; + + /// \brief Return the amount of memory used for various side tables and + /// data structures in the SourceManager. + size_t getDataStructureSizes() const; + + //===--------------------------------------------------------------------===// + // Other miscellaneous methods. + //===--------------------------------------------------------------------===// + + /// \brief Get the source location for the given file:line:col triplet. + /// + /// If the source file is included multiple times, the source location will + /// be based upon the first inclusion. + SourceLocation translateFileLineCol(const FileEntry *SourceFile, + unsigned Line, unsigned Col) const; + + /// \brief Get the FileID for the given file. + /// + /// If the source file is included multiple times, the FileID will be the + /// first inclusion. + FileID translateFile(const FileEntry *SourceFile) const; + + /// \brief Get the source location in \p FID for the given line:col. + /// Returns null location if \p FID is not a file SLocEntry. + SourceLocation translateLineCol(FileID FID, + unsigned Line, unsigned Col) const; + + /// \brief If \p Loc points inside a function macro argument, the returned + /// location will be the macro location in which the argument was expanded. + /// If a macro argument is used multiple times, the expanded location will + /// be at the first expansion of the argument. + /// e.g. + /// MY_MACRO(foo); + /// ^ + /// Passing a file location pointing at 'foo', will yield a macro location + /// where 'foo' was expanded into. + SourceLocation getMacroArgExpandedLocation(SourceLocation Loc) const; + + /// \brief Determines the order of 2 source locations in the translation unit. + /// + /// \returns true if LHS source location comes before RHS, false otherwise. + bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const; + + /// \brief Determines the order of 2 source locations in the "source location + /// address space". + bool isBeforeInSLocAddrSpace(SourceLocation LHS, SourceLocation RHS) const { + return isBeforeInSLocAddrSpace(LHS, RHS.getOffset()); + } + + /// \brief Determines the order of a source location and a source location + /// offset in the "source location address space". + /// + /// Note that we always consider source locations loaded from + bool isBeforeInSLocAddrSpace(SourceLocation LHS, unsigned RHS) const { + unsigned LHSOffset = LHS.getOffset(); + bool LHSLoaded = LHSOffset >= CurrentLoadedOffset; + bool RHSLoaded = RHS >= CurrentLoadedOffset; + if (LHSLoaded == RHSLoaded) + return LHSOffset < RHS; + + return LHSLoaded; + } + + // Iterators over FileInfos. + typedef llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*> + ::const_iterator fileinfo_iterator; + fileinfo_iterator fileinfo_begin() const { return FileInfos.begin(); } + fileinfo_iterator fileinfo_end() const { return FileInfos.end(); } + bool hasFileInfo(const FileEntry *File) const { + return FileInfos.find(File) != FileInfos.end(); + } + + /// \brief Print statistics to stderr. + /// + void PrintStats() const; + + void dump() const; + + /// \brief Get the number of local SLocEntries we have. + unsigned local_sloc_entry_size() const { return LocalSLocEntryTable.size(); } + + /// \brief Get a local SLocEntry. This is exposed for indexing. + const SrcMgr::SLocEntry &getLocalSLocEntry(unsigned Index, + bool *Invalid = nullptr) const { + assert(Index < LocalSLocEntryTable.size() && "Invalid index"); + return LocalSLocEntryTable[Index]; + } + + /// \brief Get the number of loaded SLocEntries we have. + unsigned loaded_sloc_entry_size() const { return LoadedSLocEntryTable.size();} + + /// \brief Get a loaded SLocEntry. This is exposed for indexing. + const SrcMgr::SLocEntry &getLoadedSLocEntry(unsigned Index, + bool *Invalid = nullptr) const { + assert(Index < LoadedSLocEntryTable.size() && "Invalid index"); + if (SLocEntryLoaded[Index]) + return LoadedSLocEntryTable[Index]; + return loadSLocEntry(Index, Invalid); + } + + const SrcMgr::SLocEntry &getSLocEntry(FileID FID, + bool *Invalid = nullptr) const { + if (FID.ID == 0 || FID.ID == -1) { + if (Invalid) *Invalid = true; + return LocalSLocEntryTable[0]; + } + return getSLocEntryByID(FID.ID, Invalid); + } + + unsigned getNextLocalOffset() const { return NextLocalOffset; } + + void setExternalSLocEntrySource(ExternalSLocEntrySource *Source) { + assert(LoadedSLocEntryTable.empty() && + "Invalidating existing loaded entries"); + ExternalSLocEntries = Source; + } + + /// \brief Allocate a number of loaded SLocEntries, which will be actually + /// loaded on demand from the external source. + /// + /// NumSLocEntries will be allocated, which occupy a total of TotalSize space + /// in the global source view. The lowest ID and the base offset of the + /// entries will be returned. + std::pair<int, unsigned> + AllocateLoadedSLocEntries(unsigned NumSLocEntries, unsigned TotalSize); + + /// \brief Returns true if \p Loc came from a PCH/Module. + bool isLoadedSourceLocation(SourceLocation Loc) const { + return Loc.getOffset() >= CurrentLoadedOffset; + } + + /// \brief Returns true if \p Loc did not come from a PCH/Module. + bool isLocalSourceLocation(SourceLocation Loc) const { + return Loc.getOffset() < NextLocalOffset; + } + + /// \brief Returns true if \p FID came from a PCH/Module. + bool isLoadedFileID(FileID FID) const { + assert(FID.ID != -1 && "Using FileID sentinel value"); + return FID.ID < 0; + } + + /// \brief Returns true if \p FID did not come from a PCH/Module. + bool isLocalFileID(FileID FID) const { + return !isLoadedFileID(FID); + } + + /// Gets the location of the immediate macro caller, one level up the stack + /// toward the initial macro typed into the source. + SourceLocation getImmediateMacroCallerLoc(SourceLocation Loc) const { + if (!Loc.isMacroID()) return Loc; + + // When we have the location of (part of) an expanded parameter, its + // spelling location points to the argument as expanded in the macro call, + // and therefore is used to locate the macro caller. + if (isMacroArgExpansion(Loc)) + return getImmediateSpellingLoc(Loc); + + // Otherwise, the caller of the macro is located where this macro is + // expanded (while the spelling is part of the macro definition). + return getImmediateExpansionRange(Loc).first; + } + +private: + llvm::MemoryBuffer *getFakeBufferForRecovery() const; + const SrcMgr::ContentCache *getFakeContentCacheForRecovery() const; + + const SrcMgr::SLocEntry &loadSLocEntry(unsigned Index, bool *Invalid) const; + + /// \brief Get the entry with the given unwrapped FileID. + const SrcMgr::SLocEntry &getSLocEntryByID(int ID, + bool *Invalid = nullptr) const { + assert(ID != -1 && "Using FileID sentinel value"); + if (ID < 0) + return getLoadedSLocEntryByID(ID, Invalid); + return getLocalSLocEntry(static_cast<unsigned>(ID), Invalid); + } + + const SrcMgr::SLocEntry & + getLoadedSLocEntryByID(int ID, bool *Invalid = nullptr) const { + return getLoadedSLocEntry(static_cast<unsigned>(-ID - 2), Invalid); + } + + /// Implements the common elements of storing an expansion info struct into + /// the SLocEntry table and producing a source location that refers to it. + SourceLocation createExpansionLocImpl(const SrcMgr::ExpansionInfo &Expansion, + unsigned TokLength, + int LoadedID = 0, + unsigned LoadedOffset = 0); + + /// \brief Return true if the specified FileID contains the + /// specified SourceLocation offset. This is a very hot method. + inline bool isOffsetInFileID(FileID FID, unsigned SLocOffset) const { + const SrcMgr::SLocEntry &Entry = getSLocEntry(FID); + // If the entry is after the offset, it can't contain it. + if (SLocOffset < Entry.getOffset()) return false; + + // If this is the very last entry then it does. + if (FID.ID == -2) + return true; + + // If it is the last local entry, then it does if the location is local. + if (FID.ID+1 == static_cast<int>(LocalSLocEntryTable.size())) + return SLocOffset < NextLocalOffset; + + // Otherwise, the entry after it has to not include it. This works for both + // local and loaded entries. + return SLocOffset < getSLocEntryByID(FID.ID+1).getOffset(); + } + + /// \brief Returns the previous in-order FileID or an invalid FileID if there + /// is no previous one. + FileID getPreviousFileID(FileID FID) const; + + /// \brief Returns the next in-order FileID or an invalid FileID if there is + /// no next one. + FileID getNextFileID(FileID FID) const; + + /// \brief Create a new fileID for the specified ContentCache and + /// include position. + /// + /// This works regardless of whether the ContentCache corresponds to a + /// file or some other input source. + FileID createFileID(const SrcMgr::ContentCache* File, + SourceLocation IncludePos, + SrcMgr::CharacteristicKind DirCharacter, + int LoadedID, unsigned LoadedOffset); + + const SrcMgr::ContentCache * + getOrCreateContentCache(const FileEntry *SourceFile, + bool isSystemFile = false); + + /// \brief Create a new ContentCache for the specified memory buffer. + const SrcMgr::ContentCache * + createMemBufferContentCache(std::unique_ptr<llvm::MemoryBuffer> Buf); + + FileID getFileIDSlow(unsigned SLocOffset) const; + FileID getFileIDLocal(unsigned SLocOffset) const; + FileID getFileIDLoaded(unsigned SLocOffset) const; + + SourceLocation getExpansionLocSlowCase(SourceLocation Loc) const; + SourceLocation getSpellingLocSlowCase(SourceLocation Loc) const; + SourceLocation getFileLocSlowCase(SourceLocation Loc) const; + + std::pair<FileID, unsigned> + getDecomposedExpansionLocSlowCase(const SrcMgr::SLocEntry *E) const; + std::pair<FileID, unsigned> + getDecomposedSpellingLocSlowCase(const SrcMgr::SLocEntry *E, + unsigned Offset) const; + void computeMacroArgsCache(MacroArgsMap *&MacroArgsCache, FileID FID) const; + void associateFileChunkWithMacroArgExp(MacroArgsMap &MacroArgsCache, + FileID FID, + SourceLocation SpellLoc, + SourceLocation ExpansionLoc, + unsigned ExpansionLength) const; + friend class ASTReader; + friend class ASTWriter; +}; + +/// \brief Comparison function object. +template<typename T> +class BeforeThanCompare; + +/// \brief Compare two source locations. +template<> +class BeforeThanCompare<SourceLocation> { + SourceManager &SM; + +public: + explicit BeforeThanCompare(SourceManager &SM) : SM(SM) { } + + bool operator()(SourceLocation LHS, SourceLocation RHS) const { + return SM.isBeforeInTranslationUnit(LHS, RHS); + } +}; + +/// \brief Compare two non-overlapping source ranges. +template<> +class BeforeThanCompare<SourceRange> { + SourceManager &SM; + +public: + explicit BeforeThanCompare(SourceManager &SM) : SM(SM) { } + + bool operator()(SourceRange LHS, SourceRange RHS) const { + return SM.isBeforeInTranslationUnit(LHS.getBegin(), RHS.getBegin()); + } +}; + +} // end namespace clang + + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/SourceManagerInternals.h b/contrib/llvm/tools/clang/include/clang/Basic/SourceManagerInternals.h new file mode 100644 index 0000000..27dea9f --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/SourceManagerInternals.h @@ -0,0 +1,128 @@ +//===--- SourceManagerInternals.h - SourceManager Internals -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines implementation details of the clang::SourceManager class. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_SOURCEMANAGERINTERNALS_H +#define LLVM_CLANG_BASIC_SOURCEMANAGERINTERNALS_H + +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/ADT/StringMap.h" +#include <map> + +namespace clang { + +//===----------------------------------------------------------------------===// +// Line Table Implementation +//===----------------------------------------------------------------------===// + +struct LineEntry { + /// \brief The offset in this file that the line entry occurs at. + unsigned FileOffset; + + /// \brief The presumed line number of this line entry: \#line 4. + unsigned LineNo; + + /// \brief The ID of the filename identified by this line entry: + /// \#line 4 "foo.c". This is -1 if not specified. + int FilenameID; + + /// \brief Set the 0 if no flags, 1 if a system header, + SrcMgr::CharacteristicKind FileKind; + + /// \brief The offset of the virtual include stack location, + /// which is manipulated by GNU linemarker directives. + /// + /// If this is 0 then there is no virtual \#includer. + unsigned IncludeOffset; + + static LineEntry get(unsigned Offs, unsigned Line, int Filename, + SrcMgr::CharacteristicKind FileKind, + unsigned IncludeOffset) { + LineEntry E; + E.FileOffset = Offs; + E.LineNo = Line; + E.FilenameID = Filename; + E.FileKind = FileKind; + E.IncludeOffset = IncludeOffset; + return E; + } +}; + +// needed for FindNearestLineEntry (upper_bound of LineEntry) +inline bool operator<(const LineEntry &lhs, const LineEntry &rhs) { + // FIXME: should check the other field? + return lhs.FileOffset < rhs.FileOffset; +} + +inline bool operator<(const LineEntry &E, unsigned Offset) { + return E.FileOffset < Offset; +} + +inline bool operator<(unsigned Offset, const LineEntry &E) { + return Offset < E.FileOffset; +} + +/// \brief Used to hold and unique data used to represent \#line information. +class LineTableInfo { + /// \brief Map used to assign unique IDs to filenames in \#line directives. + /// + /// This allows us to unique the filenames that + /// frequently reoccur and reference them with indices. FilenameIDs holds + /// the mapping from string -> ID, and FilenamesByID holds the mapping of ID + /// to string. + llvm::StringMap<unsigned, llvm::BumpPtrAllocator> FilenameIDs; + std::vector<llvm::StringMapEntry<unsigned>*> FilenamesByID; + + /// \brief Map from FileIDs to a list of line entries (sorted by the offset + /// at which they occur in the file). + std::map<FileID, std::vector<LineEntry> > LineEntries; +public: + void clear() { + FilenameIDs.clear(); + FilenamesByID.clear(); + LineEntries.clear(); + } + + unsigned getLineTableFilenameID(StringRef Str); + const char *getFilename(unsigned ID) const { + assert(ID < FilenamesByID.size() && "Invalid FilenameID"); + return FilenamesByID[ID]->getKeyData(); + } + unsigned getNumFilenames() const { return FilenamesByID.size(); } + + void AddLineNote(FileID FID, unsigned Offset, + unsigned LineNo, int FilenameID); + void AddLineNote(FileID FID, unsigned Offset, + unsigned LineNo, int FilenameID, + unsigned EntryExit, SrcMgr::CharacteristicKind FileKind); + + + /// \brief Find the line entry nearest to FID that is before it. + /// + /// If there is no line entry before \p Offset in \p FID, returns null. + const LineEntry *FindNearestLineEntry(FileID FID, unsigned Offset); + + // Low-level access + typedef std::map<FileID, std::vector<LineEntry> >::iterator iterator; + iterator begin() { return LineEntries.begin(); } + iterator end() { return LineEntries.end(); } + + /// \brief Add a new line entry that has already been encoded into + /// the internal representation of the line table. + void AddEntry(FileID FID, const std::vector<LineEntry> &Entries); +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Specifiers.h b/contrib/llvm/tools/clang/include/clang/Basic/Specifiers.h new file mode 100644 index 0000000..1d59d64 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/Specifiers.h @@ -0,0 +1,283 @@ +//===--- Specifiers.h - Declaration and Type Specifiers ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines various enumerations that describe declaration and +/// type specifiers. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_SPECIFIERS_H +#define LLVM_CLANG_BASIC_SPECIFIERS_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/ErrorHandling.h" + +namespace clang { + /// \brief Specifies the width of a type, e.g., short, long, or long long. + enum TypeSpecifierWidth { + TSW_unspecified, + TSW_short, + TSW_long, + TSW_longlong + }; + + /// \brief Specifies the signedness of a type, e.g., signed or unsigned. + enum TypeSpecifierSign { + TSS_unspecified, + TSS_signed, + TSS_unsigned + }; + + /// \brief Specifies the kind of type. + enum TypeSpecifierType { + TST_unspecified, + TST_void, + TST_char, + TST_wchar, // C++ wchar_t + TST_char16, // C++11 char16_t + TST_char32, // C++11 char32_t + TST_int, + TST_int128, + TST_half, // OpenCL half, ARM NEON __fp16 + TST_float, + TST_double, + TST_bool, // _Bool + TST_decimal32, // _Decimal32 + TST_decimal64, // _Decimal64 + TST_decimal128, // _Decimal128 + TST_enum, + TST_union, + TST_struct, + TST_class, // C++ class type + TST_interface, // C++ (Microsoft-specific) __interface type + TST_typename, // Typedef, C++ class-name or enum name, etc. + TST_typeofType, + TST_typeofExpr, + TST_decltype, // C++11 decltype + TST_underlyingType, // __underlying_type for C++11 + TST_auto, // C++11 auto + TST_decltype_auto, // C++1y decltype(auto) + TST_auto_type, // __auto_type extension + TST_unknown_anytype, // __unknown_anytype extension + TST_atomic, // C11 _Atomic + TST_error // erroneous type + }; + + /// \brief Structure that packs information about the type specifiers that + /// were written in a particular type specifier sequence. + struct WrittenBuiltinSpecs { + /*DeclSpec::TST*/ unsigned Type : 5; + /*DeclSpec::TSS*/ unsigned Sign : 2; + /*DeclSpec::TSW*/ unsigned Width : 2; + bool ModeAttr : 1; + }; + + /// \brief A C++ access specifier (public, private, protected), plus the + /// special value "none" which means different things in different contexts. + enum AccessSpecifier { + AS_public, + AS_protected, + AS_private, + AS_none + }; + + /// \brief The categorization of expression values, currently following the + /// C++11 scheme. + enum ExprValueKind { + /// \brief An r-value expression (a pr-value in the C++11 taxonomy) + /// produces a temporary value. + VK_RValue, + + /// \brief An l-value expression is a reference to an object with + /// independent storage. + VK_LValue, + + /// \brief An x-value expression is a reference to an object with + /// independent storage but which can be "moved", i.e. + /// efficiently cannibalized for its resources. + VK_XValue + }; + + /// \brief A further classification of the kind of object referenced by an + /// l-value or x-value. + enum ExprObjectKind { + /// An ordinary object is located at an address in memory. + OK_Ordinary, + + /// A bitfield object is a bitfield on a C or C++ record. + OK_BitField, + + /// A vector component is an element or range of elements on a vector. + OK_VectorComponent, + + /// An Objective-C property is a logical field of an Objective-C + /// object which is read and written via Objective-C method calls. + OK_ObjCProperty, + + /// An Objective-C array/dictionary subscripting which reads an + /// object or writes at the subscripted array/dictionary element via + /// Objective-C method calls. + OK_ObjCSubscript + }; + + /// \brief Describes the kind of template specialization that a + /// particular template specialization declaration represents. + enum TemplateSpecializationKind { + /// This template specialization was formed from a template-id but + /// has not yet been declared, defined, or instantiated. + TSK_Undeclared = 0, + /// This template specialization was implicitly instantiated from a + /// template. (C++ [temp.inst]). + TSK_ImplicitInstantiation, + /// This template specialization was declared or defined by an + /// explicit specialization (C++ [temp.expl.spec]) or partial + /// specialization (C++ [temp.class.spec]). + TSK_ExplicitSpecialization, + /// This template specialization was instantiated from a template + /// due to an explicit instantiation declaration request + /// (C++11 [temp.explicit]). + TSK_ExplicitInstantiationDeclaration, + /// This template specialization was instantiated from a template + /// due to an explicit instantiation definition request + /// (C++ [temp.explicit]). + TSK_ExplicitInstantiationDefinition + }; + + /// \brief Determine whether this template specialization kind refers + /// to an instantiation of an entity (as opposed to a non-template or + /// an explicit specialization). + inline bool isTemplateInstantiation(TemplateSpecializationKind Kind) { + return Kind != TSK_Undeclared && Kind != TSK_ExplicitSpecialization; + } + + /// \brief True if this template specialization kind is an explicit + /// specialization, explicit instantiation declaration, or explicit + /// instantiation definition. + inline bool isTemplateExplicitInstantiationOrSpecialization( + TemplateSpecializationKind Kind) { + switch (Kind) { + case TSK_ExplicitSpecialization: + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + return true; + + case TSK_Undeclared: + case TSK_ImplicitInstantiation: + return false; + } + llvm_unreachable("bad template specialization kind"); + } + + /// \brief Thread storage-class-specifier. + enum ThreadStorageClassSpecifier { + TSCS_unspecified, + /// GNU __thread. + TSCS___thread, + /// C++11 thread_local. Implies 'static' at block scope, but not at + /// class scope. + TSCS_thread_local, + /// C11 _Thread_local. Must be combined with either 'static' or 'extern' + /// if used at block scope. + TSCS__Thread_local + }; + + /// \brief Storage classes. + enum StorageClass { + // These are legal on both functions and variables. + SC_None, + SC_Extern, + SC_Static, + SC_PrivateExtern, + + // These are only legal on variables. + SC_Auto, + SC_Register + }; + + /// \brief Checks whether the given storage class is legal for functions. + inline bool isLegalForFunction(StorageClass SC) { + return SC <= SC_PrivateExtern; + } + + /// \brief Checks whether the given storage class is legal for variables. + inline bool isLegalForVariable(StorageClass SC) { + return true; + } + + /// \brief In-class initialization styles for non-static data members. + enum InClassInitStyle { + ICIS_NoInit, ///< No in-class initializer. + ICIS_CopyInit, ///< Copy initialization. + ICIS_ListInit ///< Direct list-initialization. + }; + + /// \brief CallingConv - Specifies the calling convention that a function uses. + enum CallingConv { + CC_C, // __attribute__((cdecl)) + CC_X86StdCall, // __attribute__((stdcall)) + CC_X86FastCall, // __attribute__((fastcall)) + CC_X86ThisCall, // __attribute__((thiscall)) + CC_X86VectorCall, // __attribute__((vectorcall)) + CC_X86Pascal, // __attribute__((pascal)) + CC_X86_64Win64, // __attribute__((ms_abi)) + CC_X86_64SysV, // __attribute__((sysv_abi)) + CC_AAPCS, // __attribute__((pcs("aapcs"))) + CC_AAPCS_VFP, // __attribute__((pcs("aapcs-vfp"))) + CC_IntelOclBicc, // __attribute__((intel_ocl_bicc)) + CC_SpirFunction, // default for OpenCL functions on SPIR target + CC_SpirKernel // inferred for OpenCL kernels on SPIR target + }; + + /// \brief Checks whether the given calling convention supports variadic + /// calls. Unprototyped calls also use the variadic call rules. + inline bool supportsVariadicCall(CallingConv CC) { + switch (CC) { + case CC_X86StdCall: + case CC_X86FastCall: + case CC_X86ThisCall: + case CC_X86Pascal: + case CC_X86VectorCall: + case CC_SpirFunction: + case CC_SpirKernel: + return false; + default: + return true; + } + } + + /// \brief The storage duration for an object (per C++ [basic.stc]). + enum StorageDuration { + SD_FullExpression, ///< Full-expression storage duration (for temporaries). + SD_Automatic, ///< Automatic storage duration (most local variables). + SD_Thread, ///< Thread storage duration. + SD_Static, ///< Static storage duration. + SD_Dynamic ///< Dynamic storage duration. + }; + + /// Describes the nullability of a particular type. + enum class NullabilityKind : uint8_t { + /// Values of this type can never be null. + NonNull = 0, + /// Values of this type can be null. + Nullable, + /// Whether values of this type can be null is (explicitly) + /// unspecified. This captures a (fairly rare) case where we + /// can't conclude anything about the nullability of the type even + /// though it has been considered. + Unspecified + }; + + /// Retrieve the spelling of the given nullability kind. + llvm::StringRef getNullabilitySpelling(NullabilityKind kind, + bool isContextSensitive = false); +} // end namespace clang + +#endif // LLVM_CLANG_BASIC_SPECIFIERS_H diff --git a/contrib/llvm/tools/clang/include/clang/Basic/StmtNodes.td b/contrib/llvm/tools/clang/include/clang/Basic/StmtNodes.td new file mode 100644 index 0000000..36519ea --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/StmtNodes.td @@ -0,0 +1,224 @@ +class AttrSubject; + +class Stmt<bit abstract = 0> : AttrSubject { + bit Abstract = abstract; +} + +class DStmt<Stmt base, bit abstract = 0> : Stmt<abstract> { + Stmt Base = base; +} + +// Statements +def NullStmt : Stmt; +def CompoundStmt : Stmt; +def LabelStmt : Stmt; +def AttributedStmt : Stmt; +def IfStmt : Stmt; +def SwitchStmt : Stmt; +def WhileStmt : Stmt; +def DoStmt : Stmt; +def ForStmt : Stmt; +def GotoStmt : Stmt; +def IndirectGotoStmt : Stmt; +def ContinueStmt : Stmt; +def BreakStmt : Stmt; +def ReturnStmt : Stmt; +def DeclStmt : Stmt; +def SwitchCase : Stmt<1>; +def CaseStmt : DStmt<SwitchCase>; +def DefaultStmt : DStmt<SwitchCase>; +def CapturedStmt : Stmt; + +// Asm statements +def AsmStmt : Stmt<1>; +def GCCAsmStmt : DStmt<AsmStmt>; +def MSAsmStmt : DStmt<AsmStmt>; + +// Obj-C statements +def ObjCAtTryStmt : Stmt; +def ObjCAtCatchStmt : Stmt; +def ObjCAtFinallyStmt : Stmt; +def ObjCAtThrowStmt : Stmt; +def ObjCAtSynchronizedStmt : Stmt; +def ObjCForCollectionStmt : Stmt; +def ObjCAutoreleasePoolStmt : Stmt; + +// C++ statments +def CXXCatchStmt : Stmt; +def CXXTryStmt : Stmt; +def CXXForRangeStmt : Stmt; + +// C++ Coroutines TS statements +def CoroutineBodyStmt : Stmt; +def CoreturnStmt : Stmt; + +// Expressions +def Expr : Stmt<1>; +def PredefinedExpr : DStmt<Expr>; +def DeclRefExpr : DStmt<Expr>; +def IntegerLiteral : DStmt<Expr>; +def FloatingLiteral : DStmt<Expr>; +def ImaginaryLiteral : DStmt<Expr>; +def StringLiteral : DStmt<Expr>; +def CharacterLiteral : DStmt<Expr>; +def ParenExpr : DStmt<Expr>; +def UnaryOperator : DStmt<Expr>; +def OffsetOfExpr : DStmt<Expr>; +def UnaryExprOrTypeTraitExpr : DStmt<Expr>; +def ArraySubscriptExpr : DStmt<Expr>; +def OMPArraySectionExpr : DStmt<Expr>; +def CallExpr : DStmt<Expr>; +def MemberExpr : DStmt<Expr>; +def CastExpr : DStmt<Expr, 1>; +def BinaryOperator : DStmt<Expr>; +def CompoundAssignOperator : DStmt<BinaryOperator>; +def AbstractConditionalOperator : DStmt<Expr, 1>; +def ConditionalOperator : DStmt<AbstractConditionalOperator>; +def BinaryConditionalOperator : DStmt<AbstractConditionalOperator>; +def ImplicitCastExpr : DStmt<CastExpr>; +def ExplicitCastExpr : DStmt<CastExpr, 1>; +def CStyleCastExpr : DStmt<ExplicitCastExpr>; +def CompoundLiteralExpr : DStmt<Expr>; +def ExtVectorElementExpr : DStmt<Expr>; +def InitListExpr : DStmt<Expr>; +def DesignatedInitExpr : DStmt<Expr>; +def DesignatedInitUpdateExpr : DStmt<Expr>; +def ImplicitValueInitExpr : DStmt<Expr>; +def NoInitExpr : DStmt<Expr>; +def ParenListExpr : DStmt<Expr>; +def VAArgExpr : DStmt<Expr>; +def GenericSelectionExpr : DStmt<Expr>; +def PseudoObjectExpr : DStmt<Expr>; + +// Atomic expressions +def AtomicExpr : DStmt<Expr>; + +// GNU Extensions. +def AddrLabelExpr : DStmt<Expr>; +def StmtExpr : DStmt<Expr>; +def ChooseExpr : DStmt<Expr>; +def GNUNullExpr : DStmt<Expr>; + +// C++ Expressions. +def CXXOperatorCallExpr : DStmt<CallExpr>; +def CXXMemberCallExpr : DStmt<CallExpr>; +def CXXNamedCastExpr : DStmt<ExplicitCastExpr, 1>; +def CXXStaticCastExpr : DStmt<CXXNamedCastExpr>; +def CXXDynamicCastExpr : DStmt<CXXNamedCastExpr>; +def CXXReinterpretCastExpr : DStmt<CXXNamedCastExpr>; +def CXXConstCastExpr : DStmt<CXXNamedCastExpr>; +def CXXFunctionalCastExpr : DStmt<ExplicitCastExpr>; +def CXXTypeidExpr : DStmt<Expr>; +def UserDefinedLiteral : DStmt<CallExpr>; +def CXXBoolLiteralExpr : DStmt<Expr>; +def CXXNullPtrLiteralExpr : DStmt<Expr>; +def CXXThisExpr : DStmt<Expr>; +def CXXThrowExpr : DStmt<Expr>; +def CXXDefaultArgExpr : DStmt<Expr>; +def CXXDefaultInitExpr : DStmt<Expr>; +def CXXScalarValueInitExpr : DStmt<Expr>; +def CXXStdInitializerListExpr : DStmt<Expr>; +def CXXNewExpr : DStmt<Expr>; +def CXXDeleteExpr : DStmt<Expr>; +def CXXPseudoDestructorExpr : DStmt<Expr>; +def TypeTraitExpr : DStmt<Expr>; +def ArrayTypeTraitExpr : DStmt<Expr>; +def ExpressionTraitExpr : DStmt<Expr>; +def DependentScopeDeclRefExpr : DStmt<Expr>; +def CXXConstructExpr : DStmt<Expr>; +def CXXBindTemporaryExpr : DStmt<Expr>; +def ExprWithCleanups : DStmt<Expr>; +def CXXTemporaryObjectExpr : DStmt<CXXConstructExpr>; +def CXXUnresolvedConstructExpr : DStmt<Expr>; +def CXXDependentScopeMemberExpr : DStmt<Expr>; +def OverloadExpr : DStmt<Expr, 1>; +def UnresolvedLookupExpr : DStmt<OverloadExpr>; +def UnresolvedMemberExpr : DStmt<OverloadExpr>; +def CXXNoexceptExpr : DStmt<Expr>; +def PackExpansionExpr : DStmt<Expr>; +def SizeOfPackExpr : DStmt<Expr>; +def SubstNonTypeTemplateParmExpr : DStmt<Expr>; +def SubstNonTypeTemplateParmPackExpr : DStmt<Expr>; +def FunctionParmPackExpr : DStmt<Expr>; +def MaterializeTemporaryExpr : DStmt<Expr>; +def LambdaExpr : DStmt<Expr>; +def CXXFoldExpr : DStmt<Expr>; + +// C++ Coroutines TS expressions +def CoroutineSuspendExpr : DStmt<Expr, 1>; +def CoawaitExpr : DStmt<CoroutineSuspendExpr>; +def CoyieldExpr : DStmt<CoroutineSuspendExpr>; + +// Obj-C Expressions. +def ObjCStringLiteral : DStmt<Expr>; +def ObjCBoxedExpr : DStmt<Expr>; +def ObjCArrayLiteral : DStmt<Expr>; +def ObjCDictionaryLiteral : DStmt<Expr>; +def ObjCEncodeExpr : DStmt<Expr>; +def ObjCMessageExpr : DStmt<Expr>; +def ObjCSelectorExpr : DStmt<Expr>; +def ObjCProtocolExpr : DStmt<Expr>; +def ObjCIvarRefExpr : DStmt<Expr>; +def ObjCPropertyRefExpr : DStmt<Expr>; +def ObjCIsaExpr : DStmt<Expr>; +def ObjCIndirectCopyRestoreExpr : DStmt<Expr>; +def ObjCBoolLiteralExpr : DStmt<Expr>; +def ObjCSubscriptRefExpr : DStmt<Expr>; + +// Obj-C ARC Expressions. +def ObjCBridgedCastExpr : DStmt<ExplicitCastExpr>; + +// CUDA Expressions. +def CUDAKernelCallExpr : DStmt<CallExpr>; + +// Clang Extensions. +def ShuffleVectorExpr : DStmt<Expr>; +def ConvertVectorExpr : DStmt<Expr>; +def BlockExpr : DStmt<Expr>; +def OpaqueValueExpr : DStmt<Expr>; +def TypoExpr : DStmt<Expr>; + +// Microsoft Extensions. +def MSPropertyRefExpr : DStmt<Expr>; +def MSPropertySubscriptExpr : DStmt<Expr>; +def CXXUuidofExpr : DStmt<Expr>; +def SEHTryStmt : Stmt; +def SEHExceptStmt : Stmt; +def SEHFinallyStmt : Stmt; +def SEHLeaveStmt : Stmt; +def MSDependentExistsStmt : Stmt; + +// OpenCL Extensions. +def AsTypeExpr : DStmt<Expr>; + +// OpenMP Directives. +def OMPExecutableDirective : Stmt<1>; +def OMPLoopDirective : DStmt<OMPExecutableDirective, 1>; +def OMPParallelDirective : DStmt<OMPExecutableDirective>; +def OMPSimdDirective : DStmt<OMPLoopDirective>; +def OMPForDirective : DStmt<OMPLoopDirective>; +def OMPForSimdDirective : DStmt<OMPLoopDirective>; +def OMPSectionsDirective : DStmt<OMPExecutableDirective>; +def OMPSectionDirective : DStmt<OMPExecutableDirective>; +def OMPSingleDirective : DStmt<OMPExecutableDirective>; +def OMPMasterDirective : DStmt<OMPExecutableDirective>; +def OMPCriticalDirective : DStmt<OMPExecutableDirective>; +def OMPParallelForDirective : DStmt<OMPLoopDirective>; +def OMPParallelForSimdDirective : DStmt<OMPLoopDirective>; +def OMPParallelSectionsDirective : DStmt<OMPExecutableDirective>; +def OMPTaskDirective : DStmt<OMPExecutableDirective>; +def OMPTaskyieldDirective : DStmt<OMPExecutableDirective>; +def OMPBarrierDirective : DStmt<OMPExecutableDirective>; +def OMPTaskwaitDirective : DStmt<OMPExecutableDirective>; +def OMPTaskgroupDirective : DStmt<OMPExecutableDirective>; +def OMPFlushDirective : DStmt<OMPExecutableDirective>; +def OMPOrderedDirective : DStmt<OMPExecutableDirective>; +def OMPAtomicDirective : DStmt<OMPExecutableDirective>; +def OMPTargetDirective : DStmt<OMPExecutableDirective>; +def OMPTargetDataDirective : DStmt<OMPExecutableDirective>; +def OMPTeamsDirective : DStmt<OMPExecutableDirective>; +def OMPCancellationPointDirective : DStmt<OMPExecutableDirective>; +def OMPCancelDirective : DStmt<OMPExecutableDirective>; +def OMPTaskLoopDirective : DStmt<OMPLoopDirective>; +def OMPTaskLoopSimdDirective : DStmt<OMPLoopDirective>; +def OMPDistributeDirective : DStmt<OMPLoopDirective>; diff --git a/contrib/llvm/tools/clang/include/clang/Basic/TargetBuiltins.h b/contrib/llvm/tools/clang/include/clang/Basic/TargetBuiltins.h new file mode 100644 index 0000000..623c0b6 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/TargetBuiltins.h @@ -0,0 +1,201 @@ +//===--- TargetBuiltins.h - Target specific builtin IDs ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Enumerates target-specific builtins in their own namespaces within +/// namespace ::clang. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_TARGETBUILTINS_H +#define LLVM_CLANG_BASIC_TARGETBUILTINS_H + +#include <stdint.h> +#include "clang/Basic/Builtins.h" +#undef PPC + +namespace clang { + + namespace NEON { + enum { + LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, +#define BUILTIN(ID, TYPE, ATTRS) BI##ID, +#include "clang/Basic/BuiltinsNEON.def" + FirstTSBuiltin + }; + } + + /// \brief ARM builtins + namespace ARM { + enum { + LastTIBuiltin = clang::Builtin::FirstTSBuiltin-1, + LastNEONBuiltin = NEON::FirstTSBuiltin - 1, +#define BUILTIN(ID, TYPE, ATTRS) BI##ID, +#include "clang/Basic/BuiltinsARM.def" + LastTSBuiltin + }; + } + + /// \brief AArch64 builtins + namespace AArch64 { + enum { + LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, + LastNEONBuiltin = NEON::FirstTSBuiltin - 1, + #define BUILTIN(ID, TYPE, ATTRS) BI##ID, + #include "clang/Basic/BuiltinsAArch64.def" + LastTSBuiltin + }; + } + + /// \brief PPC builtins + namespace PPC { + enum { + LastTIBuiltin = clang::Builtin::FirstTSBuiltin-1, +#define BUILTIN(ID, TYPE, ATTRS) BI##ID, +#include "clang/Basic/BuiltinsPPC.def" + LastTSBuiltin + }; + } + + /// \brief NVPTX builtins + namespace NVPTX { + enum { + LastTIBuiltin = clang::Builtin::FirstTSBuiltin-1, +#define BUILTIN(ID, TYPE, ATTRS) BI##ID, +#include "clang/Basic/BuiltinsNVPTX.def" + LastTSBuiltin + }; + } + + /// \brief AMDGPU builtins + namespace AMDGPU { + enum { + LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, + #define BUILTIN(ID, TYPE, ATTRS) BI##ID, + #include "clang/Basic/BuiltinsAMDGPU.def" + LastTSBuiltin + }; + } + + /// \brief X86 builtins + namespace X86 { + enum { + LastTIBuiltin = clang::Builtin::FirstTSBuiltin-1, +#define BUILTIN(ID, TYPE, ATTRS) BI##ID, +#include "clang/Basic/BuiltinsX86.def" + LastTSBuiltin + }; + } + + /// \brief Flags to identify the types for overloaded Neon builtins. + /// + /// These must be kept in sync with the flags in utils/TableGen/NeonEmitter.h. + class NeonTypeFlags { + enum { + EltTypeMask = 0xf, + UnsignedFlag = 0x10, + QuadFlag = 0x20 + }; + uint32_t Flags; + + public: + enum EltType { + Int8, + Int16, + Int32, + Int64, + Poly8, + Poly16, + Poly64, + Poly128, + Float16, + Float32, + Float64 + }; + + NeonTypeFlags(unsigned F) : Flags(F) {} + NeonTypeFlags(EltType ET, bool IsUnsigned, bool IsQuad) : Flags(ET) { + if (IsUnsigned) + Flags |= UnsignedFlag; + if (IsQuad) + Flags |= QuadFlag; + } + + EltType getEltType() const { return (EltType)(Flags & EltTypeMask); } + bool isPoly() const { + EltType ET = getEltType(); + return ET == Poly8 || ET == Poly16; + } + bool isUnsigned() const { return (Flags & UnsignedFlag) != 0; } + bool isQuad() const { return (Flags & QuadFlag) != 0; } + }; + + /// \brief Hexagon builtins + namespace Hexagon { + enum { + LastTIBuiltin = clang::Builtin::FirstTSBuiltin-1, +#define BUILTIN(ID, TYPE, ATTRS) BI##ID, +#include "clang/Basic/BuiltinsHexagon.def" + LastTSBuiltin + }; + } + + /// \brief MIPS builtins + namespace Mips { + enum { + LastTIBuiltin = clang::Builtin::FirstTSBuiltin-1, +#define BUILTIN(ID, TYPE, ATTRS) BI##ID, +#include "clang/Basic/BuiltinsMips.def" + LastTSBuiltin + }; + } + + /// \brief XCore builtins + namespace XCore { + enum { + LastTIBuiltin = clang::Builtin::FirstTSBuiltin-1, +#define BUILTIN(ID, TYPE, ATTRS) BI##ID, +#include "clang/Basic/BuiltinsXCore.def" + LastTSBuiltin + }; + } + + /// \brief Le64 builtins + namespace Le64 { + enum { + LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, + #define BUILTIN(ID, TYPE, ATTRS) BI##ID, + #include "clang/Basic/BuiltinsLe64.def" + LastTSBuiltin + }; + } + + /// \brief SystemZ builtins + namespace SystemZ { + enum { + LastTIBuiltin = clang::Builtin::FirstTSBuiltin-1, +#define BUILTIN(ID, TYPE, ATTRS) BI##ID, +#include "clang/Basic/BuiltinsSystemZ.def" + LastTSBuiltin + }; + } + + /// \brief WebAssembly builtins + namespace WebAssembly { + enum { + LastTIBuiltin = clang::Builtin::FirstTSBuiltin-1, +#define BUILTIN(ID, TYPE, ATTRS) BI##ID, +#include "clang/Basic/BuiltinsWebAssembly.def" + LastTSBuiltin + }; + } + +} // end namespace clang. + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/TargetCXXABI.h b/contrib/llvm/tools/clang/include/clang/Basic/TargetCXXABI.h new file mode 100644 index 0000000..67247ea --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/TargetCXXABI.h @@ -0,0 +1,354 @@ +//===--- TargetCXXABI.h - C++ ABI Target Configuration ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the TargetCXXABI class, which abstracts details of the +/// C++ ABI that we're targeting. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_TARGETCXXABI_H +#define LLVM_CLANG_BASIC_TARGETCXXABI_H + +#include "llvm/ADT/Triple.h" +#include "llvm/Support/ErrorHandling.h" + +namespace clang { + +/// \brief The basic abstraction for the target C++ ABI. +class TargetCXXABI { +public: + /// \brief The basic C++ ABI kind. + enum Kind { + /// The generic Itanium ABI is the standard ABI of most open-source + /// and Unix-like platforms. It is the primary ABI targeted by + /// many compilers, including Clang and GCC. + /// + /// It is documented here: + /// http://www.codesourcery.com/public/cxx-abi/ + GenericItanium, + + /// The generic ARM ABI is a modified version of the Itanium ABI + /// proposed by ARM for use on ARM-based platforms. + /// + /// These changes include: + /// - the representation of member function pointers is adjusted + /// to not conflict with the 'thumb' bit of ARM function pointers; + /// - constructors and destructors return 'this'; + /// - guard variables are smaller; + /// - inline functions are never key functions; + /// - array cookies have a slightly different layout; + /// - additional convenience functions are specified; + /// - and more! + /// + /// It is documented here: + /// http://infocenter.arm.com + /// /help/topic/com.arm.doc.ihi0041c/IHI0041C_cppabi.pdf + GenericARM, + + /// The iOS ABI is a partial implementation of the ARM ABI. + /// Several of the features of the ARM ABI were not fully implemented + /// in the compilers that iOS was launched with. + /// + /// Essentially, the iOS ABI includes the ARM changes to: + /// - member function pointers, + /// - guard variables, + /// - array cookies, and + /// - constructor/destructor signatures. + iOS, + + /// The iOS 64-bit ABI is follows ARM's published 64-bit ABI more + /// closely, but we don't guarantee to follow it perfectly. + /// + /// It is documented here: + /// http://infocenter.arm.com + /// /help/topic/com.arm.doc.ihi0059a/IHI0059A_cppabi64.pdf + iOS64, + + /// WatchOS is a modernisation of the iOS ABI, which roughly means it's + /// the iOS64 ABI ported to 32-bits. The primary difference from iOS64 is + /// that RTTI objects must still be unique at the moment. + WatchOS, + + /// The generic AArch64 ABI is also a modified version of the Itanium ABI, + /// but it has fewer divergences than the 32-bit ARM ABI. + /// + /// The relevant changes from the generic ABI in this case are: + /// - representation of member function pointers adjusted as in ARM. + /// - guard variables are smaller. + GenericAArch64, + + /// The generic Mips ABI is a modified version of the Itanium ABI. + /// + /// At the moment, only change from the generic ABI in this case is: + /// - representation of member function pointers adjusted as in ARM. + GenericMIPS, + + /// The WebAssembly ABI is a modified version of the Itanium ABI. + /// + /// The changes from the Itanium ABI are: + /// - representation of member function pointers is adjusted, as in ARM; + /// - member functions are not specially aligned; + /// - constructors and destructors return 'this', as in ARM; + /// - guard variables are 32-bit on wasm32, as in ARM; + /// - unused bits of guard variables are reserved, as in ARM; + /// - inline functions are never key functions, as in ARM; + /// - C++11 POD rules are used for tail padding, as in iOS64. + /// + /// TODO: At present the WebAssembly ABI is not considered stable, so none + /// of these details is necessarily final yet. + WebAssembly, + + /// The Microsoft ABI is the ABI used by Microsoft Visual Studio (and + /// compatible compilers). + /// + /// FIXME: should this be split into Win32 and Win64 variants? + /// + /// Only scattered and incomplete official documentation exists. + Microsoft + }; + +private: + // Right now, this class is passed around as a cheap value type. + // If you add more members, especially non-POD members, please + // audit the users to pass it by reference instead. + Kind TheKind; + +public: + /// A bogus initialization of the platform ABI. + TargetCXXABI() : TheKind(GenericItanium) {} + + TargetCXXABI(Kind kind) : TheKind(kind) {} + + void set(Kind kind) { + TheKind = kind; + } + + Kind getKind() const { return TheKind; } + + /// \brief Does this ABI generally fall into the Itanium family of ABIs? + bool isItaniumFamily() const { + switch (getKind()) { + case GenericAArch64: + case GenericItanium: + case GenericARM: + case iOS: + case iOS64: + case WatchOS: + case GenericMIPS: + case WebAssembly: + return true; + + case Microsoft: + return false; + } + llvm_unreachable("bad ABI kind"); + } + + /// \brief Is this ABI an MSVC-compatible ABI? + bool isMicrosoft() const { + switch (getKind()) { + case GenericAArch64: + case GenericItanium: + case GenericARM: + case iOS: + case iOS64: + case WatchOS: + case GenericMIPS: + case WebAssembly: + return false; + + case Microsoft: + return true; + } + llvm_unreachable("bad ABI kind"); + } + + /// \brief Are member functions differently aligned? + /// + /// Many Itanium-style C++ ABIs require member functions to be aligned, so + /// that a pointer to such a function is guaranteed to have a zero in the + /// least significant bit, so that pointers to member functions can use that + /// bit to distinguish between virtual and non-virtual functions. However, + /// some Itanium-style C++ ABIs differentiate between virtual and non-virtual + /// functions via other means, and consequently don't require that member + /// functions be aligned. + bool areMemberFunctionsAligned() const { + switch (getKind()) { + case WebAssembly: + // WebAssembly doesn't require any special alignment for member functions. + return false; + case GenericARM: + case GenericAArch64: + case GenericMIPS: + // TODO: ARM-style pointers to member functions put the discriminator in + // the this adjustment, so they don't require functions to have any + // special alignment and could therefore also return false. + case GenericItanium: + case iOS: + case iOS64: + case WatchOS: + case Microsoft: + return true; + } + llvm_unreachable("bad ABI kind"); + } + + /// \brief Is the default C++ member function calling convention + /// the same as the default calling convention? + bool isMemberFunctionCCDefault() const { + // Right now, this is always false for Microsoft. + return !isMicrosoft(); + } + + /// Are arguments to a call destroyed left to right in the callee? + /// This is a fundamental language change, since it implies that objects + /// passed by value do *not* live to the end of the full expression. + /// Temporaries passed to a function taking a const reference live to the end + /// of the full expression as usual. Both the caller and the callee must + /// have access to the destructor, while only the caller needs the + /// destructor if this is false. + bool areArgsDestroyedLeftToRightInCallee() const { + return isMicrosoft(); + } + + /// \brief Does this ABI have different entrypoints for complete-object + /// and base-subobject constructors? + bool hasConstructorVariants() const { + return isItaniumFamily(); + } + + /// \brief Does this ABI allow virtual bases to be primary base classes? + bool hasPrimaryVBases() const { + return isItaniumFamily(); + } + + /// \brief Does this ABI use key functions? If so, class data such as the + /// vtable is emitted with strong linkage by the TU containing the key + /// function. + bool hasKeyFunctions() const { + return isItaniumFamily(); + } + + /// \brief Can an out-of-line inline function serve as a key function? + /// + /// This flag is only useful in ABIs where type data (for example, + /// v-tables and type_info objects) are emitted only after processing + /// the definition of a special "key" virtual function. (This is safe + /// because the ODR requires that every virtual function be defined + /// somewhere in a program.) This usually permits such data to be + /// emitted in only a single object file, as opposed to redundantly + /// in every object file that requires it. + /// + /// One simple and common definition of "key function" is the first + /// virtual function in the class definition which is not defined there. + /// This rule works very well when that function has a non-inline + /// definition in some non-header file. Unfortunately, when that + /// function is defined inline, this rule requires the type data + /// to be emitted weakly, as if there were no key function. + /// + /// The ARM ABI observes that the ODR provides an additional guarantee: + /// a virtual function is always ODR-used, so if it is defined inline, + /// that definition must appear in every translation unit that defines + /// the class. Therefore, there is no reason to allow such functions + /// to serve as key functions. + /// + /// Because this changes the rules for emitting type data, + /// it can cause type data to be emitted with both weak and strong + /// linkage, which is not allowed on all platforms. Therefore, + /// exploiting this observation requires an ABI break and cannot be + /// done on a generic Itanium platform. + bool canKeyFunctionBeInline() const { + switch (getKind()) { + case GenericARM: + case iOS64: + case WebAssembly: + case WatchOS: + return false; + + case GenericAArch64: + case GenericItanium: + case iOS: // old iOS compilers did not follow this rule + case Microsoft: + case GenericMIPS: + return true; + } + llvm_unreachable("bad ABI kind"); + } + + /// When is record layout allowed to allocate objects in the tail + /// padding of a base class? + /// + /// This decision cannot be changed without breaking platform ABI + /// compatibility, and yet it is tied to language guarantees which + /// the committee has so far seen fit to strengthen no less than + /// three separate times: + /// - originally, there were no restrictions at all; + /// - C++98 declared that objects could not be allocated in the + /// tail padding of a POD type; + /// - C++03 extended the definition of POD to include classes + /// containing member pointers; and + /// - C++11 greatly broadened the definition of POD to include + /// all trivial standard-layout classes. + /// Each of these changes technically took several existing + /// platforms and made them permanently non-conformant. + enum TailPaddingUseRules { + /// The tail-padding of a base class is always theoretically + /// available, even if it's POD. This is not strictly conforming + /// in any language mode. + AlwaysUseTailPadding, + + /// Only allocate objects in the tail padding of a base class if + /// the base class is not POD according to the rules of C++ TR1. + /// This is non-strictly conforming in C++11 mode. + UseTailPaddingUnlessPOD03, + + /// Only allocate objects in the tail padding of a base class if + /// the base class is not POD according to the rules of C++11. + UseTailPaddingUnlessPOD11 + }; + TailPaddingUseRules getTailPaddingUseRules() const { + switch (getKind()) { + // To preserve binary compatibility, the generic Itanium ABI has + // permanently locked the definition of POD to the rules of C++ TR1, + // and that trickles down to derived ABIs. + case GenericItanium: + case GenericAArch64: + case GenericARM: + case iOS: + case GenericMIPS: + return UseTailPaddingUnlessPOD03; + + // iOS on ARM64 and WebAssembly use the C++11 POD rules. They do not honor + // the Itanium exception about classes with over-large bitfields. + case iOS64: + case WebAssembly: + case WatchOS: + return UseTailPaddingUnlessPOD11; + + // MSVC always allocates fields in the tail-padding of a base class + // subobject, even if they're POD. + case Microsoft: + return AlwaysUseTailPadding; + } + llvm_unreachable("bad ABI kind"); + } + + friend bool operator==(const TargetCXXABI &left, const TargetCXXABI &right) { + return left.getKind() == right.getKind(); + } + + friend bool operator!=(const TargetCXXABI &left, const TargetCXXABI &right) { + return !(left == right); + } +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/TargetInfo.h b/contrib/llvm/tools/clang/include/clang/Basic/TargetInfo.h new file mode 100644 index 0000000..f1d8338 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/TargetInfo.h @@ -0,0 +1,953 @@ +//===--- TargetInfo.h - Expose information about the target -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the clang::TargetInfo interface. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_TARGETINFO_H +#define LLVM_CLANG_BASIC_TARGETINFO_H + +#include "clang/Basic/AddressSpaces.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/Specifiers.h" +#include "clang/Basic/TargetCXXABI.h" +#include "clang/Basic/TargetOptions.h" +#include "clang/Basic/VersionTuple.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/DataTypes.h" +#include <cassert> +#include <string> +#include <vector> + +namespace llvm { +struct fltSemantics; +} + +namespace clang { +class DiagnosticsEngine; +class LangOptions; +class MacroBuilder; +class SourceLocation; +class SourceManager; + +namespace Builtin { struct Info; } + +/// \brief Exposes information about the current target. +/// +class TargetInfo : public RefCountedBase<TargetInfo> { + std::shared_ptr<TargetOptions> TargetOpts; + llvm::Triple Triple; +protected: + // Target values set by the ctor of the actual target implementation. Default + // values are specified by the TargetInfo constructor. + bool BigEndian; + bool TLSSupported; + bool NoAsmVariants; // True if {|} are normal characters. + unsigned char PointerWidth, PointerAlign; + unsigned char BoolWidth, BoolAlign; + unsigned char IntWidth, IntAlign; + unsigned char HalfWidth, HalfAlign; + unsigned char FloatWidth, FloatAlign; + unsigned char DoubleWidth, DoubleAlign; + unsigned char LongDoubleWidth, LongDoubleAlign; + unsigned char LargeArrayMinWidth, LargeArrayAlign; + unsigned char LongWidth, LongAlign; + unsigned char LongLongWidth, LongLongAlign; + unsigned char SuitableAlign; + unsigned char DefaultAlignForAttributeAligned; + unsigned char MinGlobalAlign; + unsigned char MaxAtomicPromoteWidth, MaxAtomicInlineWidth; + unsigned short MaxVectorAlign; + unsigned short MaxTLSAlign; + unsigned short SimdDefaultAlign; + const char *DataLayoutString; + const char *UserLabelPrefix; + const char *MCountName; + const llvm::fltSemantics *HalfFormat, *FloatFormat, *DoubleFormat, + *LongDoubleFormat; + unsigned char RegParmMax, SSERegParmMax; + TargetCXXABI TheCXXABI; + const LangAS::Map *AddrSpaceMap; + + mutable StringRef PlatformName; + mutable VersionTuple PlatformMinVersion; + + unsigned HasAlignMac68kSupport : 1; + unsigned RealTypeUsesObjCFPRet : 3; + unsigned ComplexLongDoubleUsesFP2Ret : 1; + + unsigned HasBuiltinMSVaList : 1; + + // TargetInfo Constructor. Default initializes all fields. + TargetInfo(const llvm::Triple &T); + +public: + /// \brief Construct a target for the given options. + /// + /// \param Opts - The options to use to initialize the target. The target may + /// modify the options to canonicalize the target feature information to match + /// what the backend expects. + static TargetInfo * + CreateTargetInfo(DiagnosticsEngine &Diags, + const std::shared_ptr<TargetOptions> &Opts); + + virtual ~TargetInfo(); + + /// \brief Retrieve the target options. + TargetOptions &getTargetOpts() const { + assert(TargetOpts && "Missing target options"); + return *TargetOpts; + } + + ///===---- Target Data Type Query Methods -------------------------------===// + enum IntType { + NoInt = 0, + SignedChar, + UnsignedChar, + SignedShort, + UnsignedShort, + SignedInt, + UnsignedInt, + SignedLong, + UnsignedLong, + SignedLongLong, + UnsignedLongLong + }; + + enum RealType { + NoFloat = 255, + Float = 0, + Double, + LongDouble + }; + + /// \brief The different kinds of __builtin_va_list types defined by + /// the target implementation. + enum BuiltinVaListKind { + /// typedef char* __builtin_va_list; + CharPtrBuiltinVaList = 0, + + /// typedef void* __builtin_va_list; + VoidPtrBuiltinVaList, + + /// __builtin_va_list as defind by the AArch64 ABI + /// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055a/IHI0055A_aapcs64.pdf + AArch64ABIBuiltinVaList, + + /// __builtin_va_list as defined by the PNaCl ABI: + /// http://www.chromium.org/nativeclient/pnacl/bitcode-abi#TOC-Machine-Types + PNaClABIBuiltinVaList, + + /// __builtin_va_list as defined by the Power ABI: + /// https://www.power.org + /// /resources/downloads/Power-Arch-32-bit-ABI-supp-1.0-Embedded.pdf + PowerABIBuiltinVaList, + + /// __builtin_va_list as defined by the x86-64 ABI: + /// http://www.x86-64.org/documentation/abi.pdf + X86_64ABIBuiltinVaList, + + /// __builtin_va_list as defined by ARM AAPCS ABI + /// http://infocenter.arm.com + // /help/topic/com.arm.doc.ihi0042d/IHI0042D_aapcs.pdf + AAPCSABIBuiltinVaList, + + // typedef struct __va_list_tag + // { + // long __gpr; + // long __fpr; + // void *__overflow_arg_area; + // void *__reg_save_area; + // } va_list[1]; + SystemZBuiltinVaList + }; + +protected: + IntType SizeType, IntMaxType, PtrDiffType, IntPtrType, WCharType, + WIntType, Char16Type, Char32Type, Int64Type, SigAtomicType, + ProcessIDType; + + /// \brief Whether Objective-C's built-in boolean type should be signed char. + /// + /// Otherwise, when this flag is not set, the normal built-in boolean type is + /// used. + unsigned UseSignedCharForObjCBool : 1; + + /// Control whether the alignment of bit-field types is respected when laying + /// out structures. If true, then the alignment of the bit-field type will be + /// used to (a) impact the alignment of the containing structure, and (b) + /// ensure that the individual bit-field will not straddle an alignment + /// boundary. + unsigned UseBitFieldTypeAlignment : 1; + + /// \brief Whether zero length bitfields (e.g., int : 0;) force alignment of + /// the next bitfield. + /// + /// If the alignment of the zero length bitfield is greater than the member + /// that follows it, `bar', `bar' will be aligned as the type of the + /// zero-length bitfield. + unsigned UseZeroLengthBitfieldAlignment : 1; + + /// If non-zero, specifies a fixed alignment value for bitfields that follow + /// zero length bitfield, regardless of the zero length bitfield type. + unsigned ZeroLengthBitfieldBoundary; + + /// \brief Specify if mangling based on address space map should be used or + /// not for language specific address spaces + bool UseAddrSpaceMapMangling; + +public: + IntType getSizeType() const { return SizeType; } + IntType getIntMaxType() const { return IntMaxType; } + IntType getUIntMaxType() const { + return getCorrespondingUnsignedType(IntMaxType); + } + IntType getPtrDiffType(unsigned AddrSpace) const { + return AddrSpace == 0 ? PtrDiffType : getPtrDiffTypeV(AddrSpace); + } + IntType getIntPtrType() const { return IntPtrType; } + IntType getUIntPtrType() const { + return getCorrespondingUnsignedType(IntPtrType); + } + IntType getWCharType() const { return WCharType; } + IntType getWIntType() const { return WIntType; } + IntType getChar16Type() const { return Char16Type; } + IntType getChar32Type() const { return Char32Type; } + IntType getInt64Type() const { return Int64Type; } + IntType getUInt64Type() const { + return getCorrespondingUnsignedType(Int64Type); + } + IntType getSigAtomicType() const { return SigAtomicType; } + IntType getProcessIDType() const { return ProcessIDType; } + + static IntType getCorrespondingUnsignedType(IntType T) { + switch (T) { + case SignedChar: + return UnsignedChar; + case SignedShort: + return UnsignedShort; + case SignedInt: + return UnsignedInt; + case SignedLong: + return UnsignedLong; + case SignedLongLong: + return UnsignedLongLong; + default: + llvm_unreachable("Unexpected signed integer type"); + } + } + + /// \brief Return the width (in bits) of the specified integer type enum. + /// + /// For example, SignedInt -> getIntWidth(). + unsigned getTypeWidth(IntType T) const; + + /// \brief Return integer type with specified width. + virtual IntType getIntTypeByWidth(unsigned BitWidth, bool IsSigned) const; + + /// \brief Return the smallest integer type with at least the specified width. + virtual IntType getLeastIntTypeByWidth(unsigned BitWidth, + bool IsSigned) const; + + /// \brief Return floating point type with specified width. + RealType getRealTypeByWidth(unsigned BitWidth) const; + + /// \brief Return the alignment (in bits) of the specified integer type enum. + /// + /// For example, SignedInt -> getIntAlign(). + unsigned getTypeAlign(IntType T) const; + + /// \brief Returns true if the type is signed; false otherwise. + static bool isTypeSigned(IntType T); + + /// \brief Return the width of pointers on this target, for the + /// specified address space. + uint64_t getPointerWidth(unsigned AddrSpace) const { + return AddrSpace == 0 ? PointerWidth : getPointerWidthV(AddrSpace); + } + uint64_t getPointerAlign(unsigned AddrSpace) const { + return AddrSpace == 0 ? PointerAlign : getPointerAlignV(AddrSpace); + } + + /// \brief Return the size of '_Bool' and C++ 'bool' for this target, in bits. + unsigned getBoolWidth() const { return BoolWidth; } + + /// \brief Return the alignment of '_Bool' and C++ 'bool' for this target. + unsigned getBoolAlign() const { return BoolAlign; } + + unsigned getCharWidth() const { return 8; } // FIXME + unsigned getCharAlign() const { return 8; } // FIXME + + /// \brief Return the size of 'signed short' and 'unsigned short' for this + /// target, in bits. + unsigned getShortWidth() const { return 16; } // FIXME + + /// \brief Return the alignment of 'signed short' and 'unsigned short' for + /// this target. + unsigned getShortAlign() const { return 16; } // FIXME + + /// getIntWidth/Align - Return the size of 'signed int' and 'unsigned int' for + /// this target, in bits. + unsigned getIntWidth() const { return IntWidth; } + unsigned getIntAlign() const { return IntAlign; } + + /// getLongWidth/Align - Return the size of 'signed long' and 'unsigned long' + /// for this target, in bits. + unsigned getLongWidth() const { return LongWidth; } + unsigned getLongAlign() const { return LongAlign; } + + /// getLongLongWidth/Align - Return the size of 'signed long long' and + /// 'unsigned long long' for this target, in bits. + unsigned getLongLongWidth() const { return LongLongWidth; } + unsigned getLongLongAlign() const { return LongLongAlign; } + + /// \brief Determine whether the __int128 type is supported on this target. + virtual bool hasInt128Type() const { + return getPointerWidth(0) >= 64; + } // FIXME + + /// \brief Return the alignment that is suitable for storing any + /// object with a fundamental alignment requirement. + unsigned getSuitableAlign() const { return SuitableAlign; } + + /// \brief Return the default alignment for __attribute__((aligned)) on + /// this target, to be used if no alignment value is specified. + unsigned getDefaultAlignForAttributeAligned() const { + return DefaultAlignForAttributeAligned; + } + + /// getMinGlobalAlign - Return the minimum alignment of a global variable, + /// unless its alignment is explicitly reduced via attributes. + unsigned getMinGlobalAlign() const { return MinGlobalAlign; } + + /// getWCharWidth/Align - Return the size of 'wchar_t' for this target, in + /// bits. + unsigned getWCharWidth() const { return getTypeWidth(WCharType); } + unsigned getWCharAlign() const { return getTypeAlign(WCharType); } + + /// getChar16Width/Align - Return the size of 'char16_t' for this target, in + /// bits. + unsigned getChar16Width() const { return getTypeWidth(Char16Type); } + unsigned getChar16Align() const { return getTypeAlign(Char16Type); } + + /// getChar32Width/Align - Return the size of 'char32_t' for this target, in + /// bits. + unsigned getChar32Width() const { return getTypeWidth(Char32Type); } + unsigned getChar32Align() const { return getTypeAlign(Char32Type); } + + /// getHalfWidth/Align/Format - Return the size/align/format of 'half'. + unsigned getHalfWidth() const { return HalfWidth; } + unsigned getHalfAlign() const { return HalfAlign; } + const llvm::fltSemantics &getHalfFormat() const { return *HalfFormat; } + + /// getFloatWidth/Align/Format - Return the size/align/format of 'float'. + unsigned getFloatWidth() const { return FloatWidth; } + unsigned getFloatAlign() const { return FloatAlign; } + const llvm::fltSemantics &getFloatFormat() const { return *FloatFormat; } + + /// getDoubleWidth/Align/Format - Return the size/align/format of 'double'. + unsigned getDoubleWidth() const { return DoubleWidth; } + unsigned getDoubleAlign() const { return DoubleAlign; } + const llvm::fltSemantics &getDoubleFormat() const { return *DoubleFormat; } + + /// getLongDoubleWidth/Align/Format - Return the size/align/format of 'long + /// double'. + unsigned getLongDoubleWidth() const { return LongDoubleWidth; } + unsigned getLongDoubleAlign() const { return LongDoubleAlign; } + const llvm::fltSemantics &getLongDoubleFormat() const { + return *LongDoubleFormat; + } + + /// \brief Return true if the 'long double' type should be mangled like + /// __float128. + virtual bool useFloat128ManglingForLongDouble() const { return false; } + + /// \brief Return the value for the C99 FLT_EVAL_METHOD macro. + virtual unsigned getFloatEvalMethod() const { return 0; } + + // getLargeArrayMinWidth/Align - Return the minimum array size that is + // 'large' and its alignment. + unsigned getLargeArrayMinWidth() const { return LargeArrayMinWidth; } + unsigned getLargeArrayAlign() const { return LargeArrayAlign; } + + /// \brief Return the maximum width lock-free atomic operation which will + /// ever be supported for the given target + unsigned getMaxAtomicPromoteWidth() const { return MaxAtomicPromoteWidth; } + /// \brief Return the maximum width lock-free atomic operation which can be + /// inlined given the supported features of the given target. + unsigned getMaxAtomicInlineWidth() const { return MaxAtomicInlineWidth; } + /// \brief Returns true if the given target supports lock-free atomic + /// operations at the specified width and alignment. + virtual bool hasBuiltinAtomic(uint64_t AtomicSizeInBits, + uint64_t AlignmentInBits) const { + return AtomicSizeInBits <= AlignmentInBits && + AtomicSizeInBits <= getMaxAtomicInlineWidth() && + (AtomicSizeInBits <= getCharWidth() || + llvm::isPowerOf2_64(AtomicSizeInBits / getCharWidth())); + } + + /// \brief Return the maximum vector alignment supported for the given target. + unsigned getMaxVectorAlign() const { return MaxVectorAlign; } + /// \brief Return default simd alignment for the given target. Generally, this + /// value is type-specific, but this alignment can be used for most of the + /// types for the given target. + unsigned getSimdDefaultAlign() const { return SimdDefaultAlign; } + + /// \brief Return the size of intmax_t and uintmax_t for this target, in bits. + unsigned getIntMaxTWidth() const { + return getTypeWidth(IntMaxType); + } + + // Return the size of unwind_word for this target. + unsigned getUnwindWordWidth() const { return getPointerWidth(0); } + + /// \brief Return the "preferred" register width on this target. + unsigned getRegisterWidth() const { + // Currently we assume the register width on the target matches the pointer + // width, we can introduce a new variable for this if/when some target wants + // it. + return PointerWidth; + } + + /// \brief Returns the default value of the __USER_LABEL_PREFIX__ macro, + /// which is the prefix given to user symbols by default. + /// + /// On most platforms this is "_", but it is "" on some, and "." on others. + const char *getUserLabelPrefix() const { + return UserLabelPrefix; + } + + /// \brief Returns the name of the mcount instrumentation function. + const char *getMCountName() const { + return MCountName; + } + + /// \brief Check if the Objective-C built-in boolean type should be signed + /// char. + /// + /// Otherwise, if this returns false, the normal built-in boolean type + /// should also be used for Objective-C. + bool useSignedCharForObjCBool() const { + return UseSignedCharForObjCBool; + } + void noSignedCharForObjCBool() { + UseSignedCharForObjCBool = false; + } + + /// \brief Check whether the alignment of bit-field types is respected + /// when laying out structures. + bool useBitFieldTypeAlignment() const { + return UseBitFieldTypeAlignment; + } + + /// \brief Check whether zero length bitfields should force alignment of + /// the next member. + bool useZeroLengthBitfieldAlignment() const { + return UseZeroLengthBitfieldAlignment; + } + + /// \brief Get the fixed alignment value in bits for a member that follows + /// a zero length bitfield. + unsigned getZeroLengthBitfieldBoundary() const { + return ZeroLengthBitfieldBoundary; + } + + /// \brief Check whether this target support '\#pragma options align=mac68k'. + bool hasAlignMac68kSupport() const { + return HasAlignMac68kSupport; + } + + /// \brief Return the user string for the specified integer type enum. + /// + /// For example, SignedShort -> "short". + static const char *getTypeName(IntType T); + + /// \brief Return the constant suffix for the specified integer type enum. + /// + /// For example, SignedLong -> "L". + const char *getTypeConstantSuffix(IntType T) const; + + /// \brief Return the printf format modifier for the specified + /// integer type enum. + /// + /// For example, SignedLong -> "l". + static const char *getTypeFormatModifier(IntType T); + + /// \brief Check whether the given real type should use the "fpret" flavor of + /// Objective-C message passing on this target. + bool useObjCFPRetForRealType(RealType T) const { + return RealTypeUsesObjCFPRet & (1 << T); + } + + /// \brief Check whether _Complex long double should use the "fp2ret" flavor + /// of Objective-C message passing on this target. + bool useObjCFP2RetForComplexLongDouble() const { + return ComplexLongDoubleUsesFP2Ret; + } + + /// \brief Specify if mangling based on address space map should be used or + /// not for language specific address spaces + bool useAddressSpaceMapMangling() const { + return UseAddrSpaceMapMangling; + } + + ///===---- Other target property query methods --------------------------===// + + /// \brief Appends the target-specific \#define values for this + /// target set to the specified buffer. + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const = 0; + + + /// Return information about target-specific builtins for + /// the current primary target, and info about which builtins are non-portable + /// across the current set of primary and secondary targets. + virtual ArrayRef<Builtin::Info> getTargetBuiltins() const = 0; + + /// The __builtin_clz* and __builtin_ctz* built-in + /// functions are specified to have undefined results for zero inputs, but + /// on targets that support these operations in a way that provides + /// well-defined results for zero without loss of performance, it is a good + /// idea to avoid optimizing based on that undef behavior. + virtual bool isCLZForZeroUndef() const { return true; } + + /// \brief Returns the kind of __builtin_va_list type that should be used + /// with this target. + virtual BuiltinVaListKind getBuiltinVaListKind() const = 0; + + /// Returns whether or not type \c __builtin_ms_va_list type is + /// available on this target. + bool hasBuiltinMSVaList() const { return HasBuiltinMSVaList; } + + /// \brief Returns whether the passed in string is a valid clobber in an + /// inline asm statement. + /// + /// This is used by Sema. + bool isValidClobber(StringRef Name) const; + + /// \brief Returns whether the passed in string is a valid register name + /// according to GCC. + /// + /// This is used by Sema for inline asm statements. + bool isValidGCCRegisterName(StringRef Name) const; + + /// \brief Returns the "normalized" GCC register name. + /// + /// For example, on x86 it will return "ax" when "eax" is passed in. + StringRef getNormalizedGCCRegisterName(StringRef Name) const; + + struct ConstraintInfo { + enum { + CI_None = 0x00, + CI_AllowsMemory = 0x01, + CI_AllowsRegister = 0x02, + CI_ReadWrite = 0x04, // "+r" output constraint (read and write). + CI_HasMatchingInput = 0x08, // This output operand has a matching input. + CI_ImmediateConstant = 0x10, // This operand must be an immediate constant + CI_EarlyClobber = 0x20, // "&" output constraint (early clobber). + }; + unsigned Flags; + int TiedOperand; + struct { + int Min; + int Max; + } ImmRange; + llvm::SmallSet<int, 4> ImmSet; + + std::string ConstraintStr; // constraint: "=rm" + std::string Name; // Operand name: [foo] with no []'s. + public: + ConstraintInfo(StringRef ConstraintStr, StringRef Name) + : Flags(0), TiedOperand(-1), ConstraintStr(ConstraintStr.str()), + Name(Name.str()) { + ImmRange.Min = ImmRange.Max = 0; + } + + const std::string &getConstraintStr() const { return ConstraintStr; } + const std::string &getName() const { return Name; } + bool isReadWrite() const { return (Flags & CI_ReadWrite) != 0; } + bool earlyClobber() { return (Flags & CI_EarlyClobber) != 0; } + bool allowsRegister() const { return (Flags & CI_AllowsRegister) != 0; } + bool allowsMemory() const { return (Flags & CI_AllowsMemory) != 0; } + + /// \brief Return true if this output operand has a matching + /// (tied) input operand. + bool hasMatchingInput() const { return (Flags & CI_HasMatchingInput) != 0; } + + /// \brief Return true if this input operand is a matching + /// constraint that ties it to an output operand. + /// + /// If this returns true then getTiedOperand will indicate which output + /// operand this is tied to. + bool hasTiedOperand() const { return TiedOperand != -1; } + unsigned getTiedOperand() const { + assert(hasTiedOperand() && "Has no tied operand!"); + return (unsigned)TiedOperand; + } + + bool requiresImmediateConstant() const { + return (Flags & CI_ImmediateConstant) != 0; + } + bool isValidAsmImmediate(const llvm::APInt &Value) const { + return (Value.sge(ImmRange.Min) && Value.sle(ImmRange.Max)) || + ImmSet.count(Value.getZExtValue()) != 0; + } + + void setIsReadWrite() { Flags |= CI_ReadWrite; } + void setEarlyClobber() { Flags |= CI_EarlyClobber; } + void setAllowsMemory() { Flags |= CI_AllowsMemory; } + void setAllowsRegister() { Flags |= CI_AllowsRegister; } + void setHasMatchingInput() { Flags |= CI_HasMatchingInput; } + void setRequiresImmediate(int Min, int Max) { + Flags |= CI_ImmediateConstant; + ImmRange.Min = Min; + ImmRange.Max = Max; + } + void setRequiresImmediate(llvm::ArrayRef<int> Exacts) { + Flags |= CI_ImmediateConstant; + for (int Exact : Exacts) + ImmSet.insert(Exact); + } + void setRequiresImmediate(int Exact) { + Flags |= CI_ImmediateConstant; + ImmSet.insert(Exact); + } + void setRequiresImmediate() { + Flags |= CI_ImmediateConstant; + ImmRange.Min = INT_MIN; + ImmRange.Max = INT_MAX; + } + + /// \brief Indicate that this is an input operand that is tied to + /// the specified output operand. + /// + /// Copy over the various constraint information from the output. + void setTiedOperand(unsigned N, ConstraintInfo &Output) { + Output.setHasMatchingInput(); + Flags = Output.Flags; + TiedOperand = N; + // Don't copy Name or constraint string. + } + }; + + /// \brief Validate register name used for global register variables. + /// + /// This function returns true if the register passed in RegName can be used + /// for global register variables on this target. In addition, it returns + /// true in HasSizeMismatch if the size of the register doesn't match the + /// variable size passed in RegSize. + virtual bool validateGlobalRegisterVariable(StringRef RegName, + unsigned RegSize, + bool &HasSizeMismatch) const { + HasSizeMismatch = false; + return true; + } + + // validateOutputConstraint, validateInputConstraint - Checks that + // a constraint is valid and provides information about it. + // FIXME: These should return a real error instead of just true/false. + bool validateOutputConstraint(ConstraintInfo &Info) const; + bool validateInputConstraint(MutableArrayRef<ConstraintInfo> OutputConstraints, + ConstraintInfo &info) const; + + virtual bool validateOutputSize(StringRef /*Constraint*/, + unsigned /*Size*/) const { + return true; + } + + virtual bool validateInputSize(StringRef /*Constraint*/, + unsigned /*Size*/) const { + return true; + } + virtual bool + validateConstraintModifier(StringRef /*Constraint*/, + char /*Modifier*/, + unsigned /*Size*/, + std::string &/*SuggestedModifier*/) const { + return true; + } + virtual bool + validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const = 0; + + bool resolveSymbolicName(const char *&Name, + ArrayRef<ConstraintInfo> OutputConstraints, + unsigned &Index) const; + + // Constraint parm will be left pointing at the last character of + // the constraint. In practice, it won't be changed unless the + // constraint is longer than one character. + virtual std::string convertConstraint(const char *&Constraint) const { + // 'p' defaults to 'r', but can be overridden by targets. + if (*Constraint == 'p') + return std::string("r"); + return std::string(1, *Constraint); + } + + /// \brief Returns a string of target-specific clobbers, in LLVM format. + virtual const char *getClobbers() const = 0; + + /// \brief Returns true if NaN encoding is IEEE 754-2008. + /// Only MIPS allows a different encoding. + virtual bool isNan2008() const { + return true; + } + + /// \brief Returns the target triple of the primary target. + const llvm::Triple &getTriple() const { + return Triple; + } + + const char *getDataLayoutString() const { + assert(DataLayoutString && "Uninitialized DataLayoutString!"); + return DataLayoutString; + } + + struct GCCRegAlias { + const char * const Aliases[5]; + const char * const Register; + }; + + struct AddlRegName { + const char * const Names[5]; + const unsigned RegNum; + }; + + /// \brief Does this target support "protected" visibility? + /// + /// Any target which dynamic libraries will naturally support + /// something like "default" (meaning that the symbol is visible + /// outside this shared object) and "hidden" (meaning that it isn't) + /// visibilities, but "protected" is really an ELF-specific concept + /// with weird semantics designed around the convenience of dynamic + /// linker implementations. Which is not to suggest that there's + /// consistent target-independent semantics for "default" visibility + /// either; the entire thing is pretty badly mangled. + virtual bool hasProtectedVisibility() const { return true; } + + /// \brief An optional hook that targets can implement to perform semantic + /// checking on attribute((section("foo"))) specifiers. + /// + /// In this case, "foo" is passed in to be checked. If the section + /// specifier is invalid, the backend should return a non-empty string + /// that indicates the problem. + /// + /// This hook is a simple quality of implementation feature to catch errors + /// and give good diagnostics in cases when the assembler or code generator + /// would otherwise reject the section specifier. + /// + virtual std::string isValidSectionSpecifier(StringRef SR) const { + return ""; + } + + /// \brief Set forced language options. + /// + /// Apply changes to the target information with respect to certain + /// language options which change the target configuration. + virtual void adjust(const LangOptions &Opts); + + /// \brief Initialize the map with the default set of target features for the + /// CPU this should include all legal feature strings on the target. + /// + /// \return False on error (invalid features). + virtual bool initFeatureMap(llvm::StringMap<bool> &Features, + DiagnosticsEngine &Diags, StringRef CPU, + const std::vector<std::string> &FeatureVec) const; + + /// \brief Get the ABI currently in use. + virtual StringRef getABI() const { return StringRef(); } + + /// \brief Get the C++ ABI currently in use. + TargetCXXABI getCXXABI() const { + return TheCXXABI; + } + + /// \brief Target the specified CPU. + /// + /// \return False on error (invalid CPU name). + virtual bool setCPU(const std::string &Name) { + return false; + } + + /// \brief Use the specified ABI. + /// + /// \return False on error (invalid ABI name). + virtual bool setABI(const std::string &Name) { + return false; + } + + /// \brief Use the specified unit for FP math. + /// + /// \return False on error (invalid unit name). + virtual bool setFPMath(StringRef Name) { + return false; + } + + /// \brief Enable or disable a specific target feature; + /// the feature name must be valid. + virtual void setFeatureEnabled(llvm::StringMap<bool> &Features, + StringRef Name, + bool Enabled) const { + Features[Name] = Enabled; + } + + /// \brief Perform initialization based on the user configured + /// set of features (e.g., +sse4). + /// + /// The list is guaranteed to have at most one entry per feature. + /// + /// The target may modify the features list, to change which options are + /// passed onwards to the backend. + /// FIXME: This part should be fixed so that we can change handleTargetFeatures + /// to merely a TargetInfo initialization routine. + /// + /// \return False on error. + virtual bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) { + return true; + } + + /// \brief Determine whether the given target has the given feature. + virtual bool hasFeature(StringRef Feature) const { + return false; + } + + // \brief Validate the contents of the __builtin_cpu_supports(const char*) + // argument. + virtual bool validateCpuSupports(StringRef Name) const { return false; } + + // \brief Returns maximal number of args passed in registers. + unsigned getRegParmMax() const { + assert(RegParmMax < 7 && "RegParmMax value is larger than AST can handle"); + return RegParmMax; + } + + /// \brief Whether the target supports thread-local storage. + bool isTLSSupported() const { + return TLSSupported; + } + + /// \brief Return the maximum alignment (in bits) of a TLS variable + /// + /// Gets the maximum alignment (in bits) of a TLS variable on this target. + /// Returns zero if there is no such constraint. + unsigned short getMaxTLSAlign() const { + return MaxTLSAlign; + } + + /// \brief Whether the target supports SEH __try. + bool isSEHTrySupported() const { + return getTriple().isOSWindows() && + (getTriple().getArch() == llvm::Triple::x86 || + getTriple().getArch() == llvm::Triple::x86_64); + } + + /// \brief Return true if {|} are normal characters in the asm string. + /// + /// If this returns false (the default), then {abc|xyz} is syntax + /// that says that when compiling for asm variant #0, "abc" should be + /// generated, but when compiling for asm variant #1, "xyz" should be + /// generated. + bool hasNoAsmVariants() const { + return NoAsmVariants; + } + + /// \brief Return the register number that __builtin_eh_return_regno would + /// return with the specified argument. + virtual int getEHDataRegisterNumber(unsigned RegNo) const { + return -1; + } + + /// \brief Return the section to use for C++ static initialization functions. + virtual const char *getStaticInitSectionSpecifier() const { + return nullptr; + } + + const LangAS::Map &getAddressSpaceMap() const { + return *AddrSpaceMap; + } + + /// \brief Retrieve the name of the platform as it is used in the + /// availability attribute. + StringRef getPlatformName() const { return PlatformName; } + + /// \brief Retrieve the minimum desired version of the platform, to + /// which the program should be compiled. + VersionTuple getPlatformMinVersion() const { return PlatformMinVersion; } + + bool isBigEndian() const { return BigEndian; } + + enum CallingConvMethodType { + CCMT_Unknown, + CCMT_Member, + CCMT_NonMember + }; + + /// \brief Gets the default calling convention for the given target and + /// declaration context. + virtual CallingConv getDefaultCallingConv(CallingConvMethodType MT) const { + // Not all targets will specify an explicit calling convention that we can + // express. This will always do the right thing, even though it's not + // an explicit calling convention. + return CC_C; + } + + enum CallingConvCheckResult { + CCCR_OK, + CCCR_Warning, + CCCR_Ignore, + }; + + /// \brief Determines whether a given calling convention is valid for the + /// target. A calling convention can either be accepted, produce a warning + /// and be substituted with the default calling convention, or (someday) + /// produce an error (such as using thiscall on a non-instance function). + virtual CallingConvCheckResult checkCallingConvention(CallingConv CC) const { + switch (CC) { + default: + return CCCR_Warning; + case CC_C: + return CCCR_OK; + } + } + + /// Controls if __builtin_longjmp / __builtin_setjmp can be lowered to + /// llvm.eh.sjlj.longjmp / llvm.eh.sjlj.setjmp. + virtual bool hasSjLjLowering() const { + return false; + } + +protected: + virtual uint64_t getPointerWidthV(unsigned AddrSpace) const { + return PointerWidth; + } + virtual uint64_t getPointerAlignV(unsigned AddrSpace) const { + return PointerAlign; + } + virtual enum IntType getPtrDiffTypeV(unsigned AddrSpace) const { + return PtrDiffType; + } + virtual ArrayRef<const char *> getGCCRegNames() const = 0; + virtual ArrayRef<GCCRegAlias> getGCCRegAliases() const = 0; + virtual ArrayRef<AddlRegName> getGCCAddlRegNames() const { + return None; + } +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/TargetOptions.h b/contrib/llvm/tools/clang/include/clang/Basic/TargetOptions.h new file mode 100644 index 0000000..ca0cca7 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/TargetOptions.h @@ -0,0 +1,54 @@ +//===--- TargetOptions.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the clang::TargetOptions class. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_TARGETOPTIONS_H +#define LLVM_CLANG_BASIC_TARGETOPTIONS_H + +#include <string> +#include <vector> + +namespace clang { + +/// \brief Options for controlling the target. +class TargetOptions { +public: + /// If given, the name of the target triple to compile for. If not given the + /// target will be selected to match the host. + std::string Triple; + + /// If given, the name of the target CPU to generate code for. + std::string CPU; + + /// If given, the unit to use for floating point math. + std::string FPMath; + + /// If given, the name of the target ABI to use. + std::string ABI; + + /// If given, the version string of the linker in use. + std::string LinkerVersion; + + /// \brief The list of target specific features to enable or disable, as written on the command line. + std::vector<std::string> FeaturesAsWritten; + + /// The list of target specific features to enable or disable -- this should + /// be a list of strings starting with by '+' or '-'. + std::vector<std::string> Features; + + std::vector<std::string> Reciprocals; +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/TemplateKinds.h b/contrib/llvm/tools/clang/include/clang/Basic/TemplateKinds.h new file mode 100644 index 0000000..aed287b --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/TemplateKinds.h @@ -0,0 +1,44 @@ +//===--- TemplateKinds.h - Enum values for C++ Template Kinds ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the clang::TemplateNameKind enum. +/// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_BASIC_TEMPLATEKINDS_H +#define LLVM_CLANG_BASIC_TEMPLATEKINDS_H + +namespace clang { + +/// \brief Specifies the kind of template name that an identifier refers to. +/// Be careful when changing this: this enumeration is used in diagnostics. +enum TemplateNameKind { + /// The name does not refer to a template. + TNK_Non_template = 0, + /// The name refers to a function template or a set of overloaded + /// functions that includes at least one function template. + TNK_Function_template, + /// The name refers to a template whose specialization produces a + /// type. The template itself could be a class template, template + /// template parameter, or C++0x template alias. + TNK_Type_template, + /// The name refers to a variable template whose specialization produces a + /// variable. + TNK_Var_template, + /// The name refers to a dependent template name. Whether the + /// template name is assumed to refer to a type template or a + /// function template depends on the context in which the template + /// name occurs. + TNK_Dependent_template_name +}; + +} +#endif + + diff --git a/contrib/llvm/tools/clang/include/clang/Basic/TokenKinds.def b/contrib/llvm/tools/clang/include/clang/Basic/TokenKinds.def new file mode 100644 index 0000000..9252d99 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/TokenKinds.def @@ -0,0 +1,781 @@ +//===--- TokenKinds.def - C Family Token Kind Database ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TokenKind database. This includes normal tokens like +// tok::ampamp (corresponding to the && token) as well as keywords for various +// languages. Users of this file must optionally #define the TOK, KEYWORD, +// CXX11_KEYWORD, CONCEPTS_KEYWORD, ALIAS, or PPKEYWORD macros to make use of +// this file. +// +//===----------------------------------------------------------------------===// + +#ifndef TOK +#define TOK(X) +#endif +#ifndef PUNCTUATOR +#define PUNCTUATOR(X,Y) TOK(X) +#endif +#ifndef KEYWORD +#define KEYWORD(X,Y) TOK(kw_ ## X) +#endif +#ifndef CXX11_KEYWORD +#define CXX11_KEYWORD(X,Y) KEYWORD(X,KEYCXX11|(Y)) +#endif +#ifndef CONCEPTS_KEYWORD +#define CONCEPTS_KEYWORD(X) KEYWORD(X,KEYCONCEPTS) +#endif +#ifndef TYPE_TRAIT +#define TYPE_TRAIT(N,I,K) KEYWORD(I,K) +#endif +#ifndef TYPE_TRAIT_1 +#define TYPE_TRAIT_1(I,E,K) TYPE_TRAIT(1,I,K) +#endif +#ifndef TYPE_TRAIT_2 +#define TYPE_TRAIT_2(I,E,K) TYPE_TRAIT(2,I,K) +#endif +#ifndef TYPE_TRAIT_N +#define TYPE_TRAIT_N(I,E,K) TYPE_TRAIT(0,I,K) +#endif +#ifndef ALIAS +#define ALIAS(X,Y,Z) +#endif +#ifndef PPKEYWORD +#define PPKEYWORD(X) +#endif +#ifndef CXX_KEYWORD_OPERATOR +#define CXX_KEYWORD_OPERATOR(X,Y) +#endif +#ifndef OBJC1_AT_KEYWORD +#define OBJC1_AT_KEYWORD(X) +#endif +#ifndef OBJC2_AT_KEYWORD +#define OBJC2_AT_KEYWORD(X) +#endif +#ifndef TESTING_KEYWORD +#define TESTING_KEYWORD(X, L) KEYWORD(X, L) +#endif +#ifndef ANNOTATION +#define ANNOTATION(X) TOK(annot_ ## X) +#endif + +//===----------------------------------------------------------------------===// +// Preprocessor keywords. +//===----------------------------------------------------------------------===// + +// These have meaning after a '#' at the start of a line. These define enums in +// the tok::pp_* namespace. Note that IdentifierInfo::getPPKeywordID must be +// manually updated if something is added here. +PPKEYWORD(not_keyword) + +// C99 6.10.1 - Conditional Inclusion. +PPKEYWORD(if) +PPKEYWORD(ifdef) +PPKEYWORD(ifndef) +PPKEYWORD(elif) +PPKEYWORD(else) +PPKEYWORD(endif) +PPKEYWORD(defined) + +// C99 6.10.2 - Source File Inclusion. +PPKEYWORD(include) +PPKEYWORD(__include_macros) + +// C99 6.10.3 - Macro Replacement. +PPKEYWORD(define) +PPKEYWORD(undef) + +// C99 6.10.4 - Line Control. +PPKEYWORD(line) + +// C99 6.10.5 - Error Directive. +PPKEYWORD(error) + +// C99 6.10.6 - Pragma Directive. +PPKEYWORD(pragma) + +// GNU Extensions. +PPKEYWORD(import) +PPKEYWORD(include_next) +PPKEYWORD(warning) +PPKEYWORD(ident) +PPKEYWORD(sccs) +PPKEYWORD(assert) +PPKEYWORD(unassert) + +// Clang extensions +PPKEYWORD(__public_macro) +PPKEYWORD(__private_macro) + +//===----------------------------------------------------------------------===// +// Language keywords. +//===----------------------------------------------------------------------===// + +// These define members of the tok::* namespace. + +TOK(unknown) // Not a token. +TOK(eof) // End of file. +TOK(eod) // End of preprocessing directive (end of line inside a + // directive). +TOK(code_completion) // Code completion marker + +// C99 6.4.9: Comments. +TOK(comment) // Comment (only in -E -C[C] mode) + +// C99 6.4.2: Identifiers. +TOK(identifier) // abcde123 +TOK(raw_identifier) // Used only in raw lexing mode. + +// C99 6.4.4.1: Integer Constants +// C99 6.4.4.2: Floating Constants +TOK(numeric_constant) // 0x123 + +// C99 6.4.4: Character Constants +TOK(char_constant) // 'a' +TOK(wide_char_constant) // L'b' + +// C++1z Character Constants +TOK(utf8_char_constant) // u8'a' + +// C++11 Character Constants +TOK(utf16_char_constant) // u'a' +TOK(utf32_char_constant) // U'a' + +// C99 6.4.5: String Literals. +TOK(string_literal) // "foo" +TOK(wide_string_literal) // L"foo" +TOK(angle_string_literal)// <foo> + +// C++11 String Literals. +TOK(utf8_string_literal) // u8"foo" +TOK(utf16_string_literal)// u"foo" +TOK(utf32_string_literal)// U"foo" + +// C99 6.4.6: Punctuators. +PUNCTUATOR(l_square, "[") +PUNCTUATOR(r_square, "]") +PUNCTUATOR(l_paren, "(") +PUNCTUATOR(r_paren, ")") +PUNCTUATOR(l_brace, "{") +PUNCTUATOR(r_brace, "}") +PUNCTUATOR(period, ".") +PUNCTUATOR(ellipsis, "...") +PUNCTUATOR(amp, "&") +PUNCTUATOR(ampamp, "&&") +PUNCTUATOR(ampequal, "&=") +PUNCTUATOR(star, "*") +PUNCTUATOR(starequal, "*=") +PUNCTUATOR(plus, "+") +PUNCTUATOR(plusplus, "++") +PUNCTUATOR(plusequal, "+=") +PUNCTUATOR(minus, "-") +PUNCTUATOR(arrow, "->") +PUNCTUATOR(minusminus, "--") +PUNCTUATOR(minusequal, "-=") +PUNCTUATOR(tilde, "~") +PUNCTUATOR(exclaim, "!") +PUNCTUATOR(exclaimequal, "!=") +PUNCTUATOR(slash, "/") +PUNCTUATOR(slashequal, "/=") +PUNCTUATOR(percent, "%") +PUNCTUATOR(percentequal, "%=") +PUNCTUATOR(less, "<") +PUNCTUATOR(lessless, "<<") +PUNCTUATOR(lessequal, "<=") +PUNCTUATOR(lesslessequal, "<<=") +PUNCTUATOR(greater, ">") +PUNCTUATOR(greatergreater, ">>") +PUNCTUATOR(greaterequal, ">=") +PUNCTUATOR(greatergreaterequal, ">>=") +PUNCTUATOR(caret, "^") +PUNCTUATOR(caretequal, "^=") +PUNCTUATOR(pipe, "|") +PUNCTUATOR(pipepipe, "||") +PUNCTUATOR(pipeequal, "|=") +PUNCTUATOR(question, "?") +PUNCTUATOR(colon, ":") +PUNCTUATOR(semi, ";") +PUNCTUATOR(equal, "=") +PUNCTUATOR(equalequal, "==") +PUNCTUATOR(comma, ",") +PUNCTUATOR(hash, "#") +PUNCTUATOR(hashhash, "##") +PUNCTUATOR(hashat, "#@") + +// C++ Support +PUNCTUATOR(periodstar, ".*") +PUNCTUATOR(arrowstar, "->*") +PUNCTUATOR(coloncolon, "::") + +// Objective C support. +PUNCTUATOR(at, "@") + +// CUDA support. +PUNCTUATOR(lesslessless, "<<<") +PUNCTUATOR(greatergreatergreater, ">>>") + +// C99 6.4.1: Keywords. These turn into kw_* tokens. +// Flags allowed: +// KEYALL - This is a keyword in all variants of C and C++, or it +// is a keyword in the implementation namespace that should +// always be treated as a keyword +// KEYC99 - This is a keyword introduced to C in C99 +// KEYC11 - This is a keyword introduced to C in C11 +// KEYCXX - This is a C++ keyword, or a C++-specific keyword in the +// implementation namespace +// KEYNOCXX - This is a keyword in every non-C++ dialect. +// KEYCXX11 - This is a C++ keyword introduced to C++ in C++11 +// KEYCONCEPTS - This is a keyword if the C++ extensions for concepts +// are enabled. +// KEYGNU - This is a keyword if GNU extensions are enabled +// KEYMS - This is a keyword if Microsoft extensions are enabled +// KEYNOMS18 - This is a keyword that must never be enabled under +// MSVC <= v18. +// KEYOPENCL - This is a keyword in OpenCL +// KEYNOOPENCL - This is a keyword that is not supported in OpenCL +// KEYALTIVEC - This is a keyword in AltiVec +// KEYZVECTOR - This is a keyword for the System z vector extensions, +// which are heavily based on AltiVec +// KEYBORLAND - This is a keyword if Borland extensions are enabled +// KEYCOROUTINES - This is a keyword if support for the C++ coroutines +// TS is enabled +// BOOLSUPPORT - This is a keyword if 'bool' is a built-in type +// HALFSUPPORT - This is a keyword if 'half' is a built-in type +// WCHARSUPPORT - This is a keyword if 'wchar_t' is a built-in type +// +KEYWORD(auto , KEYALL) +KEYWORD(break , KEYALL) +KEYWORD(case , KEYALL) +KEYWORD(char , KEYALL) +KEYWORD(const , KEYALL) +KEYWORD(continue , KEYALL) +KEYWORD(default , KEYALL) +KEYWORD(do , KEYALL) +KEYWORD(double , KEYALL) +KEYWORD(else , KEYALL) +KEYWORD(enum , KEYALL) +KEYWORD(extern , KEYALL) +KEYWORD(float , KEYALL) +KEYWORD(for , KEYALL) +KEYWORD(goto , KEYALL) +KEYWORD(if , KEYALL) +KEYWORD(inline , KEYC99|KEYCXX|KEYGNU) +KEYWORD(int , KEYALL) +KEYWORD(long , KEYALL) +KEYWORD(register , KEYALL) +KEYWORD(restrict , KEYC99) +KEYWORD(return , KEYALL) +KEYWORD(short , KEYALL) +KEYWORD(signed , KEYALL) +KEYWORD(sizeof , KEYALL) +KEYWORD(static , KEYALL) +KEYWORD(struct , KEYALL) +KEYWORD(switch , KEYALL) +KEYWORD(typedef , KEYALL) +KEYWORD(union , KEYALL) +KEYWORD(unsigned , KEYALL) +KEYWORD(void , KEYALL) +KEYWORD(volatile , KEYALL) +KEYWORD(while , KEYALL) +KEYWORD(_Alignas , KEYALL) +KEYWORD(_Alignof , KEYALL) +KEYWORD(_Atomic , KEYALL|KEYNOOPENCL) +KEYWORD(_Bool , KEYNOCXX) +KEYWORD(_Complex , KEYALL) +KEYWORD(_Generic , KEYALL) +KEYWORD(_Imaginary , KEYALL) +KEYWORD(_Noreturn , KEYALL) +KEYWORD(_Static_assert , KEYALL) +KEYWORD(_Thread_local , KEYALL) +KEYWORD(__func__ , KEYALL) +KEYWORD(__objc_yes , KEYALL) +KEYWORD(__objc_no , KEYALL) + + +// C++ 2.11p1: Keywords. +KEYWORD(asm , KEYCXX|KEYGNU) +KEYWORD(bool , BOOLSUPPORT) +KEYWORD(catch , KEYCXX) +KEYWORD(class , KEYCXX) +KEYWORD(const_cast , KEYCXX) +KEYWORD(delete , KEYCXX) +KEYWORD(dynamic_cast , KEYCXX) +KEYWORD(explicit , KEYCXX) +KEYWORD(export , KEYCXX) +KEYWORD(false , BOOLSUPPORT) +KEYWORD(friend , KEYCXX) +KEYWORD(mutable , KEYCXX) +KEYWORD(namespace , KEYCXX) +KEYWORD(new , KEYCXX) +KEYWORD(operator , KEYCXX) +KEYWORD(private , KEYCXX) +KEYWORD(protected , KEYCXX) +KEYWORD(public , KEYCXX) +KEYWORD(reinterpret_cast , KEYCXX) +KEYWORD(static_cast , KEYCXX) +KEYWORD(template , KEYCXX) +KEYWORD(this , KEYCXX) +KEYWORD(throw , KEYCXX) +KEYWORD(true , BOOLSUPPORT) +KEYWORD(try , KEYCXX) +KEYWORD(typename , KEYCXX) +KEYWORD(typeid , KEYCXX) +KEYWORD(using , KEYCXX) +KEYWORD(virtual , KEYCXX) +KEYWORD(wchar_t , WCHARSUPPORT) + +// C++ 2.5p2: Alternative Representations. +CXX_KEYWORD_OPERATOR(and , ampamp) +CXX_KEYWORD_OPERATOR(and_eq , ampequal) +CXX_KEYWORD_OPERATOR(bitand , amp) +CXX_KEYWORD_OPERATOR(bitor , pipe) +CXX_KEYWORD_OPERATOR(compl , tilde) +CXX_KEYWORD_OPERATOR(not , exclaim) +CXX_KEYWORD_OPERATOR(not_eq , exclaimequal) +CXX_KEYWORD_OPERATOR(or , pipepipe) +CXX_KEYWORD_OPERATOR(or_eq , pipeequal) +CXX_KEYWORD_OPERATOR(xor , caret) +CXX_KEYWORD_OPERATOR(xor_eq , caretequal) + +// C++11 keywords +CXX11_KEYWORD(alignas , 0) +CXX11_KEYWORD(alignof , 0) +CXX11_KEYWORD(char16_t , KEYNOMS18) +CXX11_KEYWORD(char32_t , KEYNOMS18) +CXX11_KEYWORD(constexpr , 0) +CXX11_KEYWORD(decltype , 0) +CXX11_KEYWORD(noexcept , 0) +CXX11_KEYWORD(nullptr , 0) +CXX11_KEYWORD(static_assert , 0) +CXX11_KEYWORD(thread_local , 0) + +// C++ concepts TS keywords +CONCEPTS_KEYWORD(concept) +CONCEPTS_KEYWORD(requires) + +// C++ coroutines TS keywords +KEYWORD(co_await , KEYCOROUTINES) +KEYWORD(co_return , KEYCOROUTINES) +KEYWORD(co_yield , KEYCOROUTINES) + +// GNU Extensions (in impl-reserved namespace) +KEYWORD(_Decimal32 , KEYALL) +KEYWORD(_Decimal64 , KEYALL) +KEYWORD(_Decimal128 , KEYALL) +KEYWORD(__null , KEYCXX) +KEYWORD(__alignof , KEYALL) +KEYWORD(__attribute , KEYALL) +KEYWORD(__builtin_choose_expr , KEYALL) +KEYWORD(__builtin_offsetof , KEYALL) +// __builtin_types_compatible_p is a GNU C extension that we handle like a C++ +// type trait. +TYPE_TRAIT_2(__builtin_types_compatible_p, TypeCompatible, KEYNOCXX) +KEYWORD(__builtin_va_arg , KEYALL) +KEYWORD(__extension__ , KEYALL) +KEYWORD(__imag , KEYALL) +KEYWORD(__int128 , KEYALL) +KEYWORD(__label__ , KEYALL) +KEYWORD(__real , KEYALL) +KEYWORD(__thread , KEYALL) +KEYWORD(__FUNCTION__ , KEYALL) +KEYWORD(__PRETTY_FUNCTION__ , KEYALL) +KEYWORD(__auto_type , KEYALL) + +// GNU Extensions (outside impl-reserved namespace) +KEYWORD(typeof , KEYGNU) + +// MS Extensions +KEYWORD(__FUNCDNAME__ , KEYMS) +KEYWORD(__FUNCSIG__ , KEYMS) +KEYWORD(L__FUNCTION__ , KEYMS) +TYPE_TRAIT_1(__is_interface_class, IsInterfaceClass, KEYMS) +TYPE_TRAIT_1(__is_sealed, IsSealed, KEYMS) + +// MSVC12.0 / VS2013 Type Traits +TYPE_TRAIT_1(__is_destructible, IsDestructible, KEYMS) +TYPE_TRAIT_1(__is_nothrow_destructible, IsNothrowDestructible, KEYMS) +TYPE_TRAIT_2(__is_nothrow_assignable, IsNothrowAssignable, KEYCXX) +TYPE_TRAIT_N(__is_constructible, IsConstructible, KEYCXX) +TYPE_TRAIT_N(__is_nothrow_constructible, IsNothrowConstructible, KEYCXX) + +// GNU and MS Type Traits +TYPE_TRAIT_1(__has_nothrow_assign, HasNothrowAssign, KEYCXX) +TYPE_TRAIT_1(__has_nothrow_move_assign, HasNothrowMoveAssign, KEYCXX) +TYPE_TRAIT_1(__has_nothrow_copy, HasNothrowCopy, KEYCXX) +TYPE_TRAIT_1(__has_nothrow_constructor, HasNothrowConstructor, KEYCXX) +TYPE_TRAIT_1(__has_trivial_assign, HasTrivialAssign, KEYCXX) +TYPE_TRAIT_1(__has_trivial_move_assign, HasTrivialMoveAssign, KEYCXX) +TYPE_TRAIT_1(__has_trivial_copy, HasTrivialCopy, KEYCXX) +TYPE_TRAIT_1(__has_trivial_constructor, HasTrivialDefaultConstructor, KEYCXX) +TYPE_TRAIT_1(__has_trivial_move_constructor, HasTrivialMoveConstructor, KEYCXX) +TYPE_TRAIT_1(__has_trivial_destructor, HasTrivialDestructor, KEYCXX) +TYPE_TRAIT_1(__has_virtual_destructor, HasVirtualDestructor, KEYCXX) +TYPE_TRAIT_1(__is_abstract, IsAbstract, KEYCXX) +TYPE_TRAIT_2(__is_base_of, IsBaseOf, KEYCXX) +TYPE_TRAIT_1(__is_class, IsClass, KEYCXX) +TYPE_TRAIT_2(__is_convertible_to, IsConvertibleTo, KEYCXX) +TYPE_TRAIT_1(__is_empty, IsEmpty, KEYCXX) +TYPE_TRAIT_1(__is_enum, IsEnum, KEYCXX) +TYPE_TRAIT_1(__is_final, IsFinal, KEYCXX) +// Tentative name - there's no implementation of std::is_literal_type yet. +TYPE_TRAIT_1(__is_literal, IsLiteral, KEYCXX) +// Name for GCC 4.6 compatibility - people have already written libraries using +// this name unfortunately. +ALIAS("__is_literal_type", __is_literal, KEYCXX) +TYPE_TRAIT_1(__is_pod, IsPOD, KEYCXX) +TYPE_TRAIT_1(__is_polymorphic, IsPolymorphic, KEYCXX) +TYPE_TRAIT_1(__is_trivial, IsTrivial, KEYCXX) +TYPE_TRAIT_1(__is_union, IsUnion, KEYCXX) + +// Clang-only C++ Type Traits +TYPE_TRAIT_N(__is_trivially_constructible, IsTriviallyConstructible, KEYCXX) +TYPE_TRAIT_1(__is_trivially_copyable, IsTriviallyCopyable, KEYCXX) +TYPE_TRAIT_2(__is_trivially_assignable, IsTriviallyAssignable, KEYCXX) +KEYWORD(__underlying_type , KEYCXX) + +// Embarcadero Expression Traits +KEYWORD(__is_lvalue_expr , KEYCXX) +KEYWORD(__is_rvalue_expr , KEYCXX) + +// Embarcadero Unary Type Traits +TYPE_TRAIT_1(__is_arithmetic, IsArithmetic, KEYCXX) +TYPE_TRAIT_1(__is_floating_point, IsFloatingPoint, KEYCXX) +TYPE_TRAIT_1(__is_integral, IsIntegral, KEYCXX) +TYPE_TRAIT_1(__is_complete_type, IsCompleteType, KEYCXX) +TYPE_TRAIT_1(__is_void, IsVoid, KEYCXX) +TYPE_TRAIT_1(__is_array, IsArray, KEYCXX) +TYPE_TRAIT_1(__is_function, IsFunction, KEYCXX) +TYPE_TRAIT_1(__is_reference, IsReference, KEYCXX) +TYPE_TRAIT_1(__is_lvalue_reference, IsLvalueReference, KEYCXX) +TYPE_TRAIT_1(__is_rvalue_reference, IsRvalueReference, KEYCXX) +TYPE_TRAIT_1(__is_fundamental, IsFundamental, KEYCXX) +TYPE_TRAIT_1(__is_object, IsObject, KEYCXX) +TYPE_TRAIT_1(__is_scalar, IsScalar, KEYCXX) +TYPE_TRAIT_1(__is_compound, IsCompound, KEYCXX) +TYPE_TRAIT_1(__is_pointer, IsPointer, KEYCXX) +TYPE_TRAIT_1(__is_member_object_pointer, IsMemberObjectPointer, KEYCXX) +TYPE_TRAIT_1(__is_member_function_pointer, IsMemberFunctionPointer, KEYCXX) +TYPE_TRAIT_1(__is_member_pointer, IsMemberPointer, KEYCXX) +TYPE_TRAIT_1(__is_const, IsConst, KEYCXX) +TYPE_TRAIT_1(__is_volatile, IsVolatile, KEYCXX) +TYPE_TRAIT_1(__is_standard_layout, IsStandardLayout, KEYCXX) +TYPE_TRAIT_1(__is_signed, IsSigned, KEYCXX) +TYPE_TRAIT_1(__is_unsigned, IsUnsigned, KEYCXX) + +// Embarcadero Binary Type Traits +TYPE_TRAIT_2(__is_same, IsSame, KEYCXX) +TYPE_TRAIT_2(__is_convertible, IsConvertible, KEYCXX) +KEYWORD(__array_rank , KEYCXX) +KEYWORD(__array_extent , KEYCXX) + +// Apple Extension. +KEYWORD(__private_extern__ , KEYALL) +KEYWORD(__module_private__ , KEYALL) + +// Extension that will be enabled for Microsoft, Borland and PS4, but can be +// disabled via '-fno-declspec'. +KEYWORD(__declspec , 0) + +// Microsoft Extension. +KEYWORD(__cdecl , KEYALL) +KEYWORD(__stdcall , KEYALL) +KEYWORD(__fastcall , KEYALL) +KEYWORD(__thiscall , KEYALL) +KEYWORD(__vectorcall , KEYALL) +KEYWORD(__forceinline , KEYMS) +KEYWORD(__unaligned , KEYMS) +KEYWORD(__super , KEYMS) + +// OpenCL address space qualifiers +KEYWORD(__global , KEYOPENCL) +KEYWORD(__local , KEYOPENCL) +KEYWORD(__constant , KEYOPENCL) +KEYWORD(__private , KEYOPENCL) +KEYWORD(__generic , KEYOPENCL) +ALIAS("global", __global , KEYOPENCL) +ALIAS("local", __local , KEYOPENCL) +ALIAS("constant", __constant , KEYOPENCL) +ALIAS("private", __private , KEYOPENCL) +ALIAS("generic", __generic , KEYOPENCL) +// OpenCL function qualifiers +KEYWORD(__kernel , KEYOPENCL) +ALIAS("kernel", __kernel , KEYOPENCL) +// OpenCL access qualifiers +KEYWORD(__read_only , KEYOPENCL) +KEYWORD(__write_only , KEYOPENCL) +KEYWORD(__read_write , KEYOPENCL) +ALIAS("read_only", __read_only , KEYOPENCL) +ALIAS("write_only", __write_only , KEYOPENCL) +ALIAS("read_write", __read_write , KEYOPENCL) +// OpenCL builtins +KEYWORD(__builtin_astype , KEYOPENCL) +KEYWORD(vec_step , KEYOPENCL|KEYALTIVEC|KEYZVECTOR) + +// OpenMP Type Traits +KEYWORD(__builtin_omp_required_simd_align, KEYALL) + +// Borland Extensions. +KEYWORD(__pascal , KEYALL) + +// Altivec Extension. +KEYWORD(__vector , KEYALTIVEC|KEYZVECTOR) +KEYWORD(__pixel , KEYALTIVEC) +KEYWORD(__bool , KEYALTIVEC|KEYZVECTOR) + +// ARM NEON extensions. +ALIAS("__fp16", half , KEYALL) + +// OpenCL Extension. +KEYWORD(half , HALFSUPPORT) + +// Objective-C ARC keywords. +KEYWORD(__bridge , KEYARC) +KEYWORD(__bridge_transfer , KEYARC) +KEYWORD(__bridge_retained , KEYARC) +KEYWORD(__bridge_retain , KEYARC) + +// Objective-C keywords. +KEYWORD(__covariant , KEYOBJC2) +KEYWORD(__contravariant , KEYOBJC2) +KEYWORD(__kindof , KEYOBJC2) + +// Alternate spelling for various tokens. There are GCC extensions in all +// languages, but should not be disabled in strict conformance mode. +ALIAS("__alignof__" , __alignof , KEYALL) +ALIAS("__asm" , asm , KEYALL) +ALIAS("__asm__" , asm , KEYALL) +ALIAS("__attribute__", __attribute, KEYALL) +ALIAS("__complex" , _Complex , KEYALL) +ALIAS("__complex__" , _Complex , KEYALL) +ALIAS("__const" , const , KEYALL) +ALIAS("__const__" , const , KEYALL) +ALIAS("__decltype" , decltype , KEYCXX) +ALIAS("__imag__" , __imag , KEYALL) +ALIAS("__inline" , inline , KEYALL) +ALIAS("__inline__" , inline , KEYALL) +ALIAS("__nullptr" , nullptr , KEYCXX) +ALIAS("__real__" , __real , KEYALL) +ALIAS("__restrict" , restrict , KEYALL) +ALIAS("__restrict__" , restrict , KEYALL) +ALIAS("__signed" , signed , KEYALL) +ALIAS("__signed__" , signed , KEYALL) +ALIAS("__typeof" , typeof , KEYALL) +ALIAS("__typeof__" , typeof , KEYALL) +ALIAS("__volatile" , volatile , KEYALL) +ALIAS("__volatile__" , volatile , KEYALL) + +// Type nullability. +KEYWORD(_Nonnull , KEYALL) +KEYWORD(_Nullable , KEYALL) +KEYWORD(_Null_unspecified , KEYALL) + +// Microsoft extensions which should be disabled in strict conformance mode +KEYWORD(__ptr64 , KEYMS) +KEYWORD(__ptr32 , KEYMS) +KEYWORD(__sptr , KEYMS) +KEYWORD(__uptr , KEYMS) +KEYWORD(__w64 , KEYMS) +KEYWORD(__uuidof , KEYMS | KEYBORLAND) +KEYWORD(__try , KEYMS | KEYBORLAND) +KEYWORD(__finally , KEYMS | KEYBORLAND) +KEYWORD(__leave , KEYMS | KEYBORLAND) +KEYWORD(__int64 , KEYMS) +KEYWORD(__if_exists , KEYMS) +KEYWORD(__if_not_exists , KEYMS) +KEYWORD(__single_inheritance , KEYMS) +KEYWORD(__multiple_inheritance , KEYMS) +KEYWORD(__virtual_inheritance , KEYMS) +KEYWORD(__interface , KEYMS) +ALIAS("__int8" , char , KEYMS) +ALIAS("_int8" , char , KEYMS) +ALIAS("__int16" , short , KEYMS) +ALIAS("_int16" , short , KEYMS) +ALIAS("__int32" , int , KEYMS) +ALIAS("_int32" , int , KEYMS) +ALIAS("_int64" , __int64 , KEYMS) +ALIAS("__wchar_t" , wchar_t , KEYMS) +ALIAS("_asm" , asm , KEYMS) +ALIAS("_alignof" , __alignof , KEYMS) +ALIAS("__builtin_alignof", __alignof , KEYMS) +ALIAS("_cdecl" , __cdecl , KEYMS | KEYBORLAND) +ALIAS("_fastcall" , __fastcall , KEYMS | KEYBORLAND) +ALIAS("_stdcall" , __stdcall , KEYMS | KEYBORLAND) +ALIAS("_thiscall" , __thiscall , KEYMS) +ALIAS("_vectorcall" , __vectorcall, KEYMS) +ALIAS("_uuidof" , __uuidof , KEYMS | KEYBORLAND) +ALIAS("_inline" , inline , KEYMS) +ALIAS("_declspec" , __declspec , KEYMS) + +// Borland Extensions which should be disabled in strict conformance mode. +ALIAS("_pascal" , __pascal , KEYBORLAND) + +// Clang Extensions. +KEYWORD(__builtin_convertvector , KEYALL) +ALIAS("__char16_t" , char16_t , KEYCXX) +ALIAS("__char32_t" , char32_t , KEYCXX) + +// Clang-specific keywords enabled only in testing. +TESTING_KEYWORD(__unknown_anytype , KEYALL) + + +//===----------------------------------------------------------------------===// +// Objective-C @-preceded keywords. +//===----------------------------------------------------------------------===// + +// These have meaning after an '@' in Objective-C mode. These define enums in +// the tok::objc_* namespace. + +OBJC1_AT_KEYWORD(not_keyword) +OBJC1_AT_KEYWORD(class) +OBJC1_AT_KEYWORD(compatibility_alias) +OBJC1_AT_KEYWORD(defs) +OBJC1_AT_KEYWORD(encode) +OBJC1_AT_KEYWORD(end) +OBJC1_AT_KEYWORD(implementation) +OBJC1_AT_KEYWORD(interface) +OBJC1_AT_KEYWORD(private) +OBJC1_AT_KEYWORD(protected) +OBJC1_AT_KEYWORD(protocol) +OBJC1_AT_KEYWORD(public) +OBJC1_AT_KEYWORD(selector) +OBJC1_AT_KEYWORD(throw) +OBJC1_AT_KEYWORD(try) +OBJC1_AT_KEYWORD(catch) +OBJC1_AT_KEYWORD(finally) +OBJC1_AT_KEYWORD(synchronized) +OBJC1_AT_KEYWORD(autoreleasepool) + +OBJC2_AT_KEYWORD(property) +OBJC2_AT_KEYWORD(package) +OBJC2_AT_KEYWORD(required) +OBJC2_AT_KEYWORD(optional) +OBJC2_AT_KEYWORD(synthesize) +OBJC2_AT_KEYWORD(dynamic) +OBJC2_AT_KEYWORD(import) + +// TODO: What to do about context-sensitive keywords like: +// bycopy/byref/in/inout/oneway/out? + +ANNOTATION(cxxscope) // annotation for a C++ scope spec, e.g. "::foo::bar::" +ANNOTATION(typename) // annotation for a C typedef name, a C++ (possibly + // qualified) typename, e.g. "foo::MyClass", or + // template-id that names a type ("std::vector<int>") +ANNOTATION(template_id) // annotation for a C++ template-id that names a + // function template specialization (not a type), + // e.g., "std::swap<int>" +ANNOTATION(primary_expr) // annotation for a primary expression +ANNOTATION(decltype) // annotation for a decltype expression, + // e.g., "decltype(foo.bar())" + +// Annotation for #pragma unused(...) +// For each argument inside the parentheses the pragma handler will produce +// one 'pragma_unused' annotation token followed by the argument token. +ANNOTATION(pragma_unused) + +// Annotation for #pragma GCC visibility... +// The lexer produces these so that they only take effect when the parser +// handles them. +ANNOTATION(pragma_vis) + +// Annotation for #pragma pack... +// The lexer produces these so that they only take effect when the parser +// handles them. +ANNOTATION(pragma_pack) + +// Annotation for #pragma clang __debug parser_crash... +// The lexer produces these so that they only take effect when the parser +// handles them. +ANNOTATION(pragma_parser_crash) + +// Annotation for #pragma clang __debug captured... +// The lexer produces these so that they only take effect when the parser +// handles them. +ANNOTATION(pragma_captured) + +// Annotation for #pragma ms_struct... +// The lexer produces these so that they only take effect when the parser +// handles them. +ANNOTATION(pragma_msstruct) + +// Annotation for #pragma align... +// The lexer produces these so that they only take effect when the parser +// handles them. +ANNOTATION(pragma_align) + +// Annotation for #pragma weak id +// The lexer produces these so that they only take effect when the parser +// handles them. +ANNOTATION(pragma_weak) + +// Annotation for #pragma weak id = id +// The lexer produces these so that they only take effect when the parser +// handles them. +ANNOTATION(pragma_weakalias) + +// Annotation for #pragma redefine_extname... +// The lexer produces these so that they only take effect when the parser +// handles them. +ANNOTATION(pragma_redefine_extname) + +// Annotation for #pragma STDC FP_CONTRACT... +// The lexer produces these so that they only take effect when the parser +// handles them. +ANNOTATION(pragma_fp_contract) + +// Annotation for #pragma pointers_to_members... +// The lexer produces these so that they only take effect when the parser +// handles them. +ANNOTATION(pragma_ms_pointers_to_members) + +// Annotation for #pragma vtordisp... +// The lexer produces these so that they only take effect when the parser +// handles them. +ANNOTATION(pragma_ms_vtordisp) + +// Annotation for all microsoft #pragmas... +// The lexer produces these so that they only take effect when the parser +// handles them. +ANNOTATION(pragma_ms_pragma) + +// Annotation for #pragma OPENCL EXTENSION... +// The lexer produces these so that they only take effect when the parser +// handles them. +ANNOTATION(pragma_opencl_extension) + +// Annotations for OpenMP pragma directives - #pragma omp ... +// The lexer produces these so that they only take effect when the parser +// handles #pragma omp ... directives. +ANNOTATION(pragma_openmp) +ANNOTATION(pragma_openmp_end) + +// Annotations for loop pragma directives #pragma clang loop ... +// The lexer produces these so that they only take effect when the parser +// handles #pragma loop ... directives. +ANNOTATION(pragma_loop_hint) + +// Annotations for module import translated from #include etc. +ANNOTATION(module_include) +ANNOTATION(module_begin) +ANNOTATION(module_end) + +#undef ANNOTATION +#undef TESTING_KEYWORD +#undef OBJC2_AT_KEYWORD +#undef OBJC1_AT_KEYWORD +#undef CXX_KEYWORD_OPERATOR +#undef PPKEYWORD +#undef ALIAS +#undef TYPE_TRAIT_N +#undef TYPE_TRAIT_2 +#undef TYPE_TRAIT_1 +#undef TYPE_TRAIT +#undef CONCEPTS_KEYWORD +#undef CXX11_KEYWORD +#undef KEYWORD +#undef PUNCTUATOR +#undef TOK diff --git a/contrib/llvm/tools/clang/include/clang/Basic/TokenKinds.h b/contrib/llvm/tools/clang/include/clang/Basic/TokenKinds.h new file mode 100644 index 0000000..f4ecb3e --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/TokenKinds.h @@ -0,0 +1,106 @@ +//===--- TokenKinds.h - Enum values for C Token Kinds -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the clang::TokenKind enum and support functions. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_TOKENKINDS_H +#define LLVM_CLANG_BASIC_TOKENKINDS_H + +#include "llvm/Support/Compiler.h" + +namespace clang { + +namespace tok { + +/// \brief Provides a simple uniform namespace for tokens from all C languages. +enum TokenKind : unsigned short { +#define TOK(X) X, +#include "clang/Basic/TokenKinds.def" + NUM_TOKENS +}; + +/// \brief Provides a namespace for preprocessor keywords which start with a +/// '#' at the beginning of the line. +enum PPKeywordKind { +#define PPKEYWORD(X) pp_##X, +#include "clang/Basic/TokenKinds.def" + NUM_PP_KEYWORDS +}; + +/// \brief Provides a namespace for Objective-C keywords which start with +/// an '@'. +enum ObjCKeywordKind { +#define OBJC1_AT_KEYWORD(X) objc_##X, +#define OBJC2_AT_KEYWORD(X) objc_##X, +#include "clang/Basic/TokenKinds.def" + NUM_OBJC_KEYWORDS +}; + +/// \brief Defines the possible values of an on-off-switch (C99 6.10.6p2). +enum OnOffSwitch { + OOS_ON, OOS_OFF, OOS_DEFAULT +}; + +/// \brief Determines the name of a token as used within the front end. +/// +/// The name of a token will be an internal name (such as "l_square") +/// and should not be used as part of diagnostic messages. +const char *getTokenName(TokenKind Kind) LLVM_READNONE; + +/// \brief Determines the spelling of simple punctuation tokens like +/// '!' or '%', and returns NULL for literal and annotation tokens. +/// +/// This routine only retrieves the "simple" spelling of the token, +/// and will not produce any alternative spellings (e.g., a +/// digraph). For the actual spelling of a given Token, use +/// Preprocessor::getSpelling(). +const char *getPunctuatorSpelling(TokenKind Kind) LLVM_READNONE; + +/// \brief Determines the spelling of simple keyword and contextual keyword +/// tokens like 'int' and 'dynamic_cast'. Returns NULL for other token kinds. +const char *getKeywordSpelling(TokenKind Kind) LLVM_READNONE; + +/// \brief Return true if this is a raw identifier or an identifier kind. +inline bool isAnyIdentifier(TokenKind K) { + return (K == tok::identifier) || (K == tok::raw_identifier); +} + +/// \brief Return true if this is a C or C++ string-literal (or +/// C++11 user-defined-string-literal) token. +inline bool isStringLiteral(TokenKind K) { + return K == tok::string_literal || K == tok::wide_string_literal || + K == tok::utf8_string_literal || K == tok::utf16_string_literal || + K == tok::utf32_string_literal; +} + +/// \brief Return true if this is a "literal" kind, like a numeric +/// constant, string, etc. +inline bool isLiteral(TokenKind K) { + return K == tok::numeric_constant || K == tok::char_constant || + K == tok::wide_char_constant || K == tok::utf8_char_constant || + K == tok::utf16_char_constant || K == tok::utf32_char_constant || + isStringLiteral(K) || K == tok::angle_string_literal; +} + +/// \brief Return true if this is any of tok::annot_* kinds. +inline bool isAnnotation(TokenKind K) { +#define ANNOTATION(NAME) \ + if (K == tok::annot_##NAME) \ + return true; +#include "clang/Basic/TokenKinds.def" + return false; +} + +} // end namespace tok +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/TypeTraits.h b/contrib/llvm/tools/clang/include/clang/Basic/TypeTraits.h new file mode 100644 index 0000000..765246b --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/TypeTraits.h @@ -0,0 +1,100 @@ +//===--- TypeTraits.h - C++ Type Traits Support Enumerations ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines enumerations for the type traits support. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_TYPETRAITS_H +#define LLVM_CLANG_BASIC_TYPETRAITS_H + +namespace clang { + + /// \brief Names for traits that operate specifically on types. + enum TypeTrait { + UTT_HasNothrowAssign, + UTT_HasNothrowMoveAssign, + UTT_HasNothrowCopy, + UTT_HasNothrowConstructor, + UTT_HasTrivialAssign, + UTT_HasTrivialMoveAssign, + UTT_HasTrivialCopy, + UTT_HasTrivialDefaultConstructor, + UTT_HasTrivialMoveConstructor, + UTT_HasTrivialDestructor, + UTT_HasVirtualDestructor, + UTT_IsAbstract, + UTT_IsArithmetic, + UTT_IsArray, + UTT_IsClass, + UTT_IsCompleteType, + UTT_IsCompound, + UTT_IsConst, + UTT_IsDestructible, + UTT_IsEmpty, + UTT_IsEnum, + UTT_IsFinal, + UTT_IsFloatingPoint, + UTT_IsFunction, + UTT_IsFundamental, + UTT_IsIntegral, + UTT_IsInterfaceClass, + UTT_IsLiteral, + UTT_IsLvalueReference, + UTT_IsMemberFunctionPointer, + UTT_IsMemberObjectPointer, + UTT_IsMemberPointer, + UTT_IsNothrowDestructible, + UTT_IsObject, + UTT_IsPOD, + UTT_IsPointer, + UTT_IsPolymorphic, + UTT_IsReference, + UTT_IsRvalueReference, + UTT_IsScalar, + UTT_IsSealed, + UTT_IsSigned, + UTT_IsStandardLayout, + UTT_IsTrivial, + UTT_IsTriviallyCopyable, + UTT_IsUnion, + UTT_IsUnsigned, + UTT_IsVoid, + UTT_IsVolatile, + UTT_Last = UTT_IsVolatile, + BTT_IsBaseOf, + BTT_IsConvertible, + BTT_IsConvertibleTo, + BTT_IsSame, + BTT_TypeCompatible, + BTT_IsNothrowAssignable, + BTT_IsTriviallyAssignable, + BTT_Last = BTT_IsTriviallyAssignable, + TT_IsConstructible, + TT_IsNothrowConstructible, + TT_IsTriviallyConstructible + }; + + /// \brief Names for the array type traits. + enum ArrayTypeTrait { + ATT_ArrayRank, + ATT_ArrayExtent + }; + + /// \brief Names for the "expression or type" traits. + enum UnaryExprOrTypeTrait { + UETT_SizeOf, + UETT_AlignOf, + UETT_VecStep, + UETT_OpenMPRequiredSimdAlign, + }; +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Version.h b/contrib/llvm/tools/clang/include/clang/Basic/Version.h new file mode 100644 index 0000000..02da432 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/Version.h @@ -0,0 +1,82 @@ +//===- Version.h - Clang Version Number -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines version macros and version-related utility functions +/// for Clang. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_VERSION_H +#define LLVM_CLANG_BASIC_VERSION_H + +#include "clang/Basic/Version.inc" +#include "llvm/ADT/StringRef.h" + +/// \brief Helper macro for CLANG_VERSION_STRING. +#define CLANG_MAKE_VERSION_STRING2(X) #X + +#ifdef CLANG_VERSION_PATCHLEVEL +/// \brief Helper macro for CLANG_VERSION_STRING. +#define CLANG_MAKE_VERSION_STRING(X,Y,Z) CLANG_MAKE_VERSION_STRING2(X.Y.Z) + +/// \brief A string that describes the Clang version number, e.g., "1.0". +#define CLANG_VERSION_STRING \ + CLANG_MAKE_VERSION_STRING(CLANG_VERSION_MAJOR,CLANG_VERSION_MINOR, \ + CLANG_VERSION_PATCHLEVEL) +#else +/// \brief Helper macro for CLANG_VERSION_STRING. +#define CLANG_MAKE_VERSION_STRING(X,Y) CLANG_MAKE_VERSION_STRING2(X.Y) + +/// \brief A string that describes the Clang version number, e.g., "1.0". +#define CLANG_VERSION_STRING \ + CLANG_MAKE_VERSION_STRING(CLANG_VERSION_MAJOR,CLANG_VERSION_MINOR) +#endif + +namespace clang { + /// \brief Retrieves the repository path (e.g., Subversion path) that + /// identifies the particular Clang branch, tag, or trunk from which this + /// Clang was built. + std::string getClangRepositoryPath(); + + /// \brief Retrieves the repository path from which LLVM was built. + /// + /// This supports LLVM residing in a separate repository from clang. + std::string getLLVMRepositoryPath(); + + /// \brief Retrieves the repository revision number (or identifer) from which + /// this Clang was built. + std::string getClangRevision(); + + /// \brief Retrieves the repository revision number (or identifer) from which + /// LLVM was built. + /// + /// If Clang and LLVM are in the same repository, this returns the same + /// string as getClangRevision. + std::string getLLVMRevision(); + + /// \brief Retrieves the full repository version that is an amalgamation of + /// the information in getClangRepositoryPath() and getClangRevision(). + std::string getClangFullRepositoryVersion(); + + /// \brief Retrieves a string representing the complete clang version, + /// which includes the clang version number, the repository version, + /// and the vendor tag. + std::string getClangFullVersion(); + + /// \brief Like getClangFullVersion(), but with a custom tool name. + std::string getClangToolFullVersion(llvm::StringRef ToolName); + + /// \brief Retrieves a string representing the complete clang version suitable + /// for use in the CPP __VERSION__ macro, which includes the clang version + /// number, the repository version, and the vendor tag. + std::string getClangFullCPPVersion(); +} + +#endif // LLVM_CLANG_BASIC_VERSION_H diff --git a/contrib/llvm/tools/clang/include/clang/Basic/VersionTuple.h b/contrib/llvm/tools/clang/include/clang/Basic/VersionTuple.h new file mode 100644 index 0000000..784f3f3 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/VersionTuple.h @@ -0,0 +1,163 @@ +//===- VersionTuple.h - Version Number Handling -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the clang::VersionTuple class, which represents a version in +/// the form major[.minor[.subminor]]. +/// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_BASIC_VERSIONTUPLE_H +#define LLVM_CLANG_BASIC_VERSIONTUPLE_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/Optional.h" +#include <string> +#include <tuple> + +namespace clang { + +/// \brief Represents a version number in the form major[.minor[.subminor[.build]]]. +class VersionTuple { + unsigned Major : 31; + unsigned Minor : 31; + unsigned Subminor : 31; + unsigned Build : 31; + unsigned HasMinor : 1; + unsigned HasSubminor : 1; + unsigned HasBuild : 1; + unsigned UsesUnderscores : 1; + +public: + VersionTuple() + : Major(0), Minor(0), Subminor(0), Build(0), HasMinor(false), + HasSubminor(false), HasBuild(false), UsesUnderscores(false) {} + + explicit VersionTuple(unsigned Major) + : Major(Major), Minor(0), Subminor(0), Build(0), HasMinor(false), + HasSubminor(false), HasBuild(false), UsesUnderscores(false) {} + + explicit VersionTuple(unsigned Major, unsigned Minor, + bool UsesUnderscores = false) + : Major(Major), Minor(Minor), Subminor(0), Build(0), HasMinor(true), + HasSubminor(false), HasBuild(false), UsesUnderscores(UsesUnderscores) {} + + explicit VersionTuple(unsigned Major, unsigned Minor, unsigned Subminor, + bool UsesUnderscores = false) + : Major(Major), Minor(Minor), Subminor(Subminor), Build(0), + HasMinor(true), HasSubminor(true), HasBuild(false), + UsesUnderscores(UsesUnderscores) {} + + explicit VersionTuple(unsigned Major, unsigned Minor, unsigned Subminor, + unsigned Build, bool UsesUnderscores = false) + : Major(Major), Minor(Minor), Subminor(Subminor), Build(Build), + HasMinor(true), HasSubminor(true), HasBuild(true), + UsesUnderscores(UsesUnderscores) {} + + /// \brief Determine whether this version information is empty + /// (e.g., all version components are zero). + bool empty() const { + return Major == 0 && Minor == 0 && Subminor == 0 && Build == 0; + } + + /// \brief Retrieve the major version number. + unsigned getMajor() const { return Major; } + + /// \brief Retrieve the minor version number, if provided. + Optional<unsigned> getMinor() const { + if (!HasMinor) + return None; + return Minor; + } + + /// \brief Retrieve the subminor version number, if provided. + Optional<unsigned> getSubminor() const { + if (!HasSubminor) + return None; + return Subminor; + } + + /// \brief Retrieve the build version number, if provided. + Optional<unsigned> getBuild() const { + if (!HasBuild) + return None; + return Build; + } + + bool usesUnderscores() const { + return UsesUnderscores; + } + + void UseDotAsSeparator() { + UsesUnderscores = false; + } + + /// \brief Determine if two version numbers are equivalent. If not + /// provided, minor and subminor version numbers are considered to be zero. + friend bool operator==(const VersionTuple& X, const VersionTuple &Y) { + return X.Major == Y.Major && X.Minor == Y.Minor && + X.Subminor == Y.Subminor && X.Build == Y.Build; + } + + /// \brief Determine if two version numbers are not equivalent. + /// + /// If not provided, minor and subminor version numbers are considered to be + /// zero. + friend bool operator!=(const VersionTuple &X, const VersionTuple &Y) { + return !(X == Y); + } + + /// \brief Determine whether one version number precedes another. + /// + /// If not provided, minor and subminor version numbers are considered to be + /// zero. + friend bool operator<(const VersionTuple &X, const VersionTuple &Y) { + return std::tie(X.Major, X.Minor, X.Subminor, X.Build) < + std::tie(Y.Major, Y.Minor, Y.Subminor, Y.Build); + } + + /// \brief Determine whether one version number follows another. + /// + /// If not provided, minor and subminor version numbers are considered to be + /// zero. + friend bool operator>(const VersionTuple &X, const VersionTuple &Y) { + return Y < X; + } + + /// \brief Determine whether one version number precedes or is + /// equivalent to another. + /// + /// If not provided, minor and subminor version numbers are considered to be + /// zero. + friend bool operator<=(const VersionTuple &X, const VersionTuple &Y) { + return !(Y < X); + } + + /// \brief Determine whether one version number follows or is + /// equivalent to another. + /// + /// If not provided, minor and subminor version numbers are considered to be + /// zero. + friend bool operator>=(const VersionTuple &X, const VersionTuple &Y) { + return !(X < Y); + } + + /// \brief Retrieve a string representation of the version number. + std::string getAsString() const; + + /// \brief Try to parse the given string as a version number. + /// \returns \c true if the string does not match the regular expression + /// [0-9]+(\.[0-9]+){0,3} + bool tryParse(StringRef string); +}; + +/// \brief Print a version number. +raw_ostream& operator<<(raw_ostream &Out, const VersionTuple &V); + +} // end namespace clang +#endif // LLVM_CLANG_BASIC_VERSIONTUPLE_H diff --git a/contrib/llvm/tools/clang/include/clang/Basic/VirtualFileSystem.h b/contrib/llvm/tools/clang/include/clang/Basic/VirtualFileSystem.h new file mode 100644 index 0000000..1df4947 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/VirtualFileSystem.h @@ -0,0 +1,341 @@ +//===- VirtualFileSystem.h - Virtual File System Layer ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// \brief Defines the virtual file system interface vfs::FileSystem. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_VIRTUALFILESYSTEM_H +#define LLVM_CLANG_BASIC_VIRTUALFILESYSTEM_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/Optional.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { +class MemoryBuffer; +} + +namespace clang { +namespace vfs { + +/// \brief The result of a \p status operation. +class Status { + std::string Name; + llvm::sys::fs::UniqueID UID; + llvm::sys::TimeValue MTime; + uint32_t User; + uint32_t Group; + uint64_t Size; + llvm::sys::fs::file_type Type; + llvm::sys::fs::perms Perms; + +public: + bool IsVFSMapped; // FIXME: remove when files support multiple names + +public: + Status() : Type(llvm::sys::fs::file_type::status_error) {} + Status(const llvm::sys::fs::file_status &Status); + Status(StringRef Name, llvm::sys::fs::UniqueID UID, + llvm::sys::TimeValue MTime, uint32_t User, uint32_t Group, + uint64_t Size, llvm::sys::fs::file_type Type, + llvm::sys::fs::perms Perms); + + /// Get a copy of a Status with a different name. + static Status copyWithNewName(const Status &In, StringRef NewName); + static Status copyWithNewName(const llvm::sys::fs::file_status &In, + StringRef NewName); + + /// \brief Returns the name that should be used for this file or directory. + StringRef getName() const { return Name; } + + /// @name Status interface from llvm::sys::fs + /// @{ + llvm::sys::fs::file_type getType() const { return Type; } + llvm::sys::fs::perms getPermissions() const { return Perms; } + llvm::sys::TimeValue getLastModificationTime() const { return MTime; } + llvm::sys::fs::UniqueID getUniqueID() const { return UID; } + uint32_t getUser() const { return User; } + uint32_t getGroup() const { return Group; } + uint64_t getSize() const { return Size; } + /// @} + /// @name Status queries + /// These are static queries in llvm::sys::fs. + /// @{ + bool equivalent(const Status &Other) const; + bool isDirectory() const; + bool isRegularFile() const; + bool isOther() const; + bool isSymlink() const; + bool isStatusKnown() const; + bool exists() const; + /// @} +}; + +/// \brief Represents an open file. +class File { +public: + /// \brief Destroy the file after closing it (if open). + /// Sub-classes should generally call close() inside their destructors. We + /// cannot do that from the base class, since close is virtual. + virtual ~File(); + /// \brief Get the status of the file. + virtual llvm::ErrorOr<Status> status() = 0; + /// \brief Get the contents of the file as a \p MemoryBuffer. + virtual llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> + getBuffer(const Twine &Name, int64_t FileSize = -1, + bool RequiresNullTerminator = true, bool IsVolatile = false) = 0; + /// \brief Closes the file. + virtual std::error_code close() = 0; +}; + +namespace detail { +/// \brief An interface for virtual file systems to provide an iterator over the +/// (non-recursive) contents of a directory. +struct DirIterImpl { + virtual ~DirIterImpl(); + /// \brief Sets \c CurrentEntry to the next entry in the directory on success, + /// or returns a system-defined \c error_code. + virtual std::error_code increment() = 0; + Status CurrentEntry; +}; +} // end namespace detail + +/// \brief An input iterator over the entries in a virtual path, similar to +/// llvm::sys::fs::directory_iterator. +class directory_iterator { + std::shared_ptr<detail::DirIterImpl> Impl; // Input iterator semantics on copy + +public: + directory_iterator(std::shared_ptr<detail::DirIterImpl> I) : Impl(I) { + assert(Impl.get() != nullptr && "requires non-null implementation"); + if (!Impl->CurrentEntry.isStatusKnown()) + Impl.reset(); // Normalize the end iterator to Impl == nullptr. + } + + /// \brief Construct an 'end' iterator. + directory_iterator() { } + + /// \brief Equivalent to operator++, with an error code. + directory_iterator &increment(std::error_code &EC) { + assert(Impl && "attempting to increment past end"); + EC = Impl->increment(); + if (EC || !Impl->CurrentEntry.isStatusKnown()) + Impl.reset(); // Normalize the end iterator to Impl == nullptr. + return *this; + } + + const Status &operator*() const { return Impl->CurrentEntry; } + const Status *operator->() const { return &Impl->CurrentEntry; } + + bool operator==(const directory_iterator &RHS) const { + if (Impl && RHS.Impl) + return Impl->CurrentEntry.equivalent(RHS.Impl->CurrentEntry); + return !Impl && !RHS.Impl; + } + bool operator!=(const directory_iterator &RHS) const { + return !(*this == RHS); + } +}; + +class FileSystem; + +/// \brief An input iterator over the recursive contents of a virtual path, +/// similar to llvm::sys::fs::recursive_directory_iterator. +class recursive_directory_iterator { + typedef std::stack<directory_iterator, std::vector<directory_iterator>> + IterState; + + FileSystem *FS; + std::shared_ptr<IterState> State; // Input iterator semantics on copy. + +public: + recursive_directory_iterator(FileSystem &FS, const Twine &Path, + std::error_code &EC); + /// \brief Construct an 'end' iterator. + recursive_directory_iterator() { } + + /// \brief Equivalent to operator++, with an error code. + recursive_directory_iterator &increment(std::error_code &EC); + + const Status &operator*() const { return *State->top(); } + const Status *operator->() const { return &*State->top(); } + + bool operator==(const recursive_directory_iterator &Other) const { + return State == Other.State; // identity + } + bool operator!=(const recursive_directory_iterator &RHS) const { + return !(*this == RHS); + } +}; + +/// \brief The virtual file system interface. +class FileSystem : public llvm::ThreadSafeRefCountedBase<FileSystem> { +public: + virtual ~FileSystem(); + + /// \brief Get the status of the entry at \p Path, if one exists. + virtual llvm::ErrorOr<Status> status(const Twine &Path) = 0; + /// \brief Get a \p File object for the file at \p Path, if one exists. + virtual llvm::ErrorOr<std::unique_ptr<File>> + openFileForRead(const Twine &Path) = 0; + + /// This is a convenience method that opens a file, gets its content and then + /// closes the file. + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> + getBufferForFile(const Twine &Name, int64_t FileSize = -1, + bool RequiresNullTerminator = true, bool IsVolatile = false); + + /// \brief Get a directory_iterator for \p Dir. + /// \note The 'end' iterator is directory_iterator(). + virtual directory_iterator dir_begin(const Twine &Dir, + std::error_code &EC) = 0; + + /// Set the working directory. This will affect all following operations on + /// this file system and may propagate down for nested file systems. + virtual std::error_code setCurrentWorkingDirectory(const Twine &Path) = 0; + /// Get the working directory of this file system. + virtual llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const = 0; + + /// Check whether a file exists. Provided for convenience. + bool exists(const Twine &Path); + + /// Make \a Path an absolute path. + /// + /// Makes \a Path absolute using the current directory if it is not already. + /// An empty \a Path will result in the current directory. + /// + /// /absolute/path => /absolute/path + /// relative/../path => <current-directory>/relative/../path + /// + /// \param Path A path that is modified to be an absolute path. + /// \returns success if \a path has been made absolute, otherwise a + /// platform-specific error_code. + std::error_code makeAbsolute(SmallVectorImpl<char> &Path) const; +}; + +/// \brief Gets an \p vfs::FileSystem for the 'real' file system, as seen by +/// the operating system. +IntrusiveRefCntPtr<FileSystem> getRealFileSystem(); + +/// \brief A file system that allows overlaying one \p AbstractFileSystem on top +/// of another. +/// +/// Consists of a stack of >=1 \p FileSystem objects, which are treated as being +/// one merged file system. When there is a directory that exists in more than +/// one file system, the \p OverlayFileSystem contains a directory containing +/// the union of their contents. The attributes (permissions, etc.) of the +/// top-most (most recently added) directory are used. When there is a file +/// that exists in more than one file system, the file in the top-most file +/// system overrides the other(s). +class OverlayFileSystem : public FileSystem { + typedef SmallVector<IntrusiveRefCntPtr<FileSystem>, 1> FileSystemList; + /// \brief The stack of file systems, implemented as a list in order of + /// their addition. + FileSystemList FSList; + +public: + OverlayFileSystem(IntrusiveRefCntPtr<FileSystem> Base); + /// \brief Pushes a file system on top of the stack. + void pushOverlay(IntrusiveRefCntPtr<FileSystem> FS); + + llvm::ErrorOr<Status> status(const Twine &Path) override; + llvm::ErrorOr<std::unique_ptr<File>> + openFileForRead(const Twine &Path) override; + directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override; + llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override; + std::error_code setCurrentWorkingDirectory(const Twine &Path) override; + + typedef FileSystemList::reverse_iterator iterator; + + /// \brief Get an iterator pointing to the most recently added file system. + iterator overlays_begin() { return FSList.rbegin(); } + + /// \brief Get an iterator pointing one-past the least recently added file + /// system. + iterator overlays_end() { return FSList.rend(); } +}; + +namespace detail { +class InMemoryDirectory; +} // end namespace detail + +/// An in-memory file system. +class InMemoryFileSystem : public FileSystem { + std::unique_ptr<detail::InMemoryDirectory> Root; + std::string WorkingDirectory; + bool UseNormalizedPaths = true; + +public: + explicit InMemoryFileSystem(bool UseNormalizedPaths = true); + ~InMemoryFileSystem() override; + /// Add a buffer to the VFS with a path. The VFS owns the buffer. + /// \return true if the file was successfully added, false if the file already + /// exists in the file system with different contents. + bool addFile(const Twine &Path, time_t ModificationTime, + std::unique_ptr<llvm::MemoryBuffer> Buffer); + /// Add a buffer to the VFS with a path. The VFS does not own the buffer. + /// \return true if the file was successfully added, false if the file already + /// exists in the file system with different contents. + bool addFileNoOwn(const Twine &Path, time_t ModificationTime, + llvm::MemoryBuffer *Buffer); + std::string toString() const; + /// Return true if this file system normalizes . and .. in paths. + bool useNormalizedPaths() const { return UseNormalizedPaths; } + + llvm::ErrorOr<Status> status(const Twine &Path) override; + llvm::ErrorOr<std::unique_ptr<File>> + openFileForRead(const Twine &Path) override; + directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override; + llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override { + return WorkingDirectory; + } + std::error_code setCurrentWorkingDirectory(const Twine &Path) override { + WorkingDirectory = Path.str(); + return std::error_code(); + } +}; + +/// \brief Get a globally unique ID for a virtual file or directory. +llvm::sys::fs::UniqueID getNextVirtualUniqueID(); + +/// \brief Gets a \p FileSystem for a virtual file system described in YAML +/// format. +IntrusiveRefCntPtr<FileSystem> +getVFSFromYAML(std::unique_ptr<llvm::MemoryBuffer> Buffer, + llvm::SourceMgr::DiagHandlerTy DiagHandler, + void *DiagContext = nullptr, + IntrusiveRefCntPtr<FileSystem> ExternalFS = getRealFileSystem()); + +struct YAMLVFSEntry { + template <typename T1, typename T2> YAMLVFSEntry(T1 &&VPath, T2 &&RPath) + : VPath(std::forward<T1>(VPath)), RPath(std::forward<T2>(RPath)) {} + std::string VPath; + std::string RPath; +}; + +class YAMLVFSWriter { + std::vector<YAMLVFSEntry> Mappings; + Optional<bool> IsCaseSensitive; + +public: + YAMLVFSWriter() {} + void addFileMapping(StringRef VirtualPath, StringRef RealPath); + void setCaseSensitivity(bool CaseSensitive) { + IsCaseSensitive = CaseSensitive; + } + void write(llvm::raw_ostream &OS); +}; + +} // end namespace vfs +} // end namespace clang +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Visibility.h b/contrib/llvm/tools/clang/include/clang/Basic/Visibility.h new file mode 100644 index 0000000..6ac52ed --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/Visibility.h @@ -0,0 +1,141 @@ +//===--- Visibility.h - Visibility enumeration and utilities ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the clang::Visibility enumeration and various utility +/// functions. +/// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_BASIC_VISIBILITY_H +#define LLVM_CLANG_BASIC_VISIBILITY_H + +#include "clang/Basic/Linkage.h" + +namespace clang { + +/// \brief Describes the different kinds of visibility that a declaration +/// may have. +/// +/// Visibility determines how a declaration interacts with the dynamic +/// linker. It may also affect whether the symbol can be found by runtime +/// symbol lookup APIs. +/// +/// Visibility is not described in any language standard and +/// (nonetheless) sometimes has odd behavior. Not all platforms +/// support all visibility kinds. +enum Visibility { + /// Objects with "hidden" visibility are not seen by the dynamic + /// linker. + HiddenVisibility, + + /// Objects with "protected" visibility are seen by the dynamic + /// linker but always dynamically resolve to an object within this + /// shared object. + ProtectedVisibility, + + /// Objects with "default" visibility are seen by the dynamic linker + /// and act like normal objects. + DefaultVisibility +}; + +inline Visibility minVisibility(Visibility L, Visibility R) { + return L < R ? L : R; +} + +class LinkageInfo { + uint8_t linkage_ : 3; + uint8_t visibility_ : 2; + uint8_t explicit_ : 1; + + void setVisibility(Visibility V, bool E) { visibility_ = V; explicit_ = E; } +public: + LinkageInfo() : linkage_(ExternalLinkage), visibility_(DefaultVisibility), + explicit_(false) {} + LinkageInfo(Linkage L, Visibility V, bool E) + : linkage_(L), visibility_(V), explicit_(E) { + assert(getLinkage() == L && getVisibility() == V && + isVisibilityExplicit() == E && "Enum truncated!"); + } + + static LinkageInfo external() { + return LinkageInfo(); + } + static LinkageInfo internal() { + return LinkageInfo(InternalLinkage, DefaultVisibility, false); + } + static LinkageInfo uniqueExternal() { + return LinkageInfo(UniqueExternalLinkage, DefaultVisibility, false); + } + static LinkageInfo none() { + return LinkageInfo(NoLinkage, DefaultVisibility, false); + } + + Linkage getLinkage() const { return (Linkage)linkage_; } + Visibility getVisibility() const { return (Visibility)visibility_; } + bool isVisibilityExplicit() const { return explicit_; } + + void setLinkage(Linkage L) { linkage_ = L; } + + void mergeLinkage(Linkage L) { + setLinkage(minLinkage(getLinkage(), L)); + } + void mergeLinkage(LinkageInfo other) { + mergeLinkage(other.getLinkage()); + } + + void mergeExternalVisibility(Linkage L) { + Linkage ThisL = getLinkage(); + if (!isExternallyVisible(L)) { + if (ThisL == VisibleNoLinkage) + ThisL = NoLinkage; + else if (ThisL == ExternalLinkage) + ThisL = UniqueExternalLinkage; + } + setLinkage(ThisL); + } + void mergeExternalVisibility(LinkageInfo Other) { + mergeExternalVisibility(Other.getLinkage()); + } + + /// Merge in the visibility 'newVis'. + void mergeVisibility(Visibility newVis, bool newExplicit) { + Visibility oldVis = getVisibility(); + + // Never increase visibility. + if (oldVis < newVis) + return; + + // If the new visibility is the same as the old and the new + // visibility isn't explicit, we have nothing to add. + if (oldVis == newVis && !newExplicit) + return; + + // Otherwise, we're either decreasing visibility or making our + // existing visibility explicit. + setVisibility(newVis, newExplicit); + } + void mergeVisibility(LinkageInfo other) { + mergeVisibility(other.getVisibility(), other.isVisibilityExplicit()); + } + + /// Merge both linkage and visibility. + void merge(LinkageInfo other) { + mergeLinkage(other); + mergeVisibility(other); + } + + /// Merge linkage and conditionally merge visibility. + void mergeMaybeWithVisibility(LinkageInfo other, bool withVis) { + mergeLinkage(other); + if (withVis) mergeVisibility(other); + } +}; +} + +#endif // LLVM_CLANG_BASIC_VISIBILITY_H diff --git a/contrib/llvm/tools/clang/include/clang/Basic/arm_neon.td b/contrib/llvm/tools/clang/include/clang/Basic/arm_neon.td new file mode 100644 index 0000000..6d95c1e --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/arm_neon.td @@ -0,0 +1,1657 @@ +//===--- arm_neon.td - ARM NEON compiler interface ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TableGen definitions from which the ARM NEON header +// file will be generated. See ARM document DUI0348B. +// +//===----------------------------------------------------------------------===// +// +// Each intrinsic is a subclass of the Inst class. An intrinsic can either +// generate a __builtin_* call or it can expand to a set of generic operations. +// +// The operations are subclasses of Operation providing a list of DAGs, the +// last of which is the return value. The available DAG nodes are documented +// below. +// +//===----------------------------------------------------------------------===// + +// The base Operation class. All operations must subclass this. +class Operation<list<dag> ops=[]> { + list<dag> Ops = ops; + bit Unavailable = 0; +} +// An operation that only contains a single DAG. +class Op<dag op> : Operation<[op]>; +// A shorter version of Operation - takes a list of DAGs. The last of these will +// be the return value. +class LOp<list<dag> ops> : Operation<ops>; + +// These defs and classes are used internally to implement the SetTheory +// expansion and should be ignored. +foreach Index = 0-63 in + def sv##Index; +class MaskExpand; + +//===----------------------------------------------------------------------===// +// Available operations +//===----------------------------------------------------------------------===// + +// DAG arguments can either be operations (documented below) or variables. +// Variables are prefixed with '$'. There are variables for each input argument, +// with the name $pN, where N starts at zero. So the zero'th argument will be +// $p0, the first $p1 etc. + +// op - Binary or unary operator, depending on the number of arguments. The +// operator itself is just treated as a raw string and is not checked. +// example: (op "+", $p0, $p1) -> "__p0 + __p1". +// (op "-", $p0) -> "-__p0" +def op; +// call - Invoke another intrinsic. The input types are type checked and +// disambiguated. If there is no intrinsic defined that takes +// the given types (or if there is a type ambiguity) an error is +// generated at tblgen time. The name of the intrinsic is the raw +// name as given to the Inst class (not mangled). +// example: (call "vget_high", $p0) -> "vgetq_high_s16(__p0)" +// (assuming $p0 has type int16x8_t). +def call; +// cast - Perform a cast to a different type. This gets emitted as a static +// C-style cast. For a pure reinterpret cast (T x = *(T*)&y), use +// "bitcast". +// +// The syntax is (cast MOD* VAL). The last argument is the value to +// cast, preceded by a sequence of type modifiers. The target type +// starts off as the type of VAL, and is modified by MOD in sequence. +// The available modifiers are: +// - $X - Take the type of parameter/variable X. For example: +// (cast $p0, $p1) would cast $p1 to the type of $p0. +// - "R" - The type of the return type. +// - A typedef string - A NEON or stdint.h type that is then parsed. +// for example: (cast "uint32x4_t", $p0). +// - "U" - Make the type unsigned. +// - "S" - Make the type signed. +// - "H" - Halve the number of lanes in the type. +// - "D" - Double the number of lanes in the type. +// - "8" - Convert type to an equivalent vector of 8-bit signed +// integers. +// example: (cast "R", "U", $p0) -> "(uint32x4_t)__p0" (assuming the return +// value is of type "int32x4_t". +// (cast $p0, "D", "8", $p1) -> "(int8x16_t)__p1" (assuming __p0 +// has type float64x1_t or any other vector type of 64 bits). +// (cast "int32_t", $p2) -> "(int32_t)__p2" +def cast; +// bitcast - Same as "cast", except a reinterpret-cast is produced: +// (bitcast "T", $p0) -> "*(T*)&__p0". +// The VAL argument is saved to a temporary so it can be used +// as an l-value. +def bitcast; +// dup - Take a scalar argument and create a vector by duplicating it into +// all lanes. The type of the vector is the base type of the intrinsic. +// example: (dup $p1) -> "(uint32x2_t) {__p1, __p1}" (assuming the base type +// is uint32x2_t). +def dup; +// splat - Take a vector and a lane index, and return a vector of the same type +// containing repeated instances of the source vector at the lane index. +// example: (splat $p0, $p1) -> +// "__builtin_shufflevector(__p0, __p0, __p1, __p1, __p1, __p1)" +// (assuming __p0 has four elements). +def splat; +// save_temp - Create a temporary (local) variable. The variable takes a name +// based on the zero'th parameter and can be referenced using +// using that name in subsequent DAGs in the same +// operation. The scope of a temp is the operation. If a variable +// with the given name already exists, an error will be given at +// tblgen time. +// example: [(save_temp $var, (call "foo", $p0)), +// (op "+", $var, $p1)] -> +// "int32x2_t __var = foo(__p0); return __var + __p1;" +def save_temp; +// name_replace - Return the name of the current intrinsic with the first +// argument replaced by the second argument. Raises an error if +// the first argument does not exist in the intrinsic name. +// example: (call (name_replace "_high_", "_"), $p0) (to call the non-high +// version of this intrinsic). +def name_replace; +// literal - Create a literal piece of code. The code is treated as a raw +// string, and must be given a type. The type is a stdint.h or +// NEON intrinsic type as given to (cast). +// example: (literal "int32_t", "0") +def literal; +// shuffle - Create a vector shuffle. The syntax is (shuffle ARG0, ARG1, MASK). +// The MASK argument is a set of elements. The elements are generated +// from the two special defs "mask0" and "mask1". "mask0" expands to +// the lane indices in sequence for ARG0, and "mask1" expands to +// the lane indices in sequence for ARG1. They can be used as-is, e.g. +// +// (shuffle $p0, $p1, mask0) -> $p0 +// (shuffle $p0, $p1, mask1) -> $p1 +// +// or, more usefully, they can be manipulated using the SetTheory +// operators plus some extra operators defined in the NEON emitter. +// The operators are described below. +// example: (shuffle $p0, $p1, (add (highhalf mask0), (highhalf mask1))) -> +// A concatenation of the high halves of the input vectors. +def shuffle; + +// add, interleave, decimate: These set operators are vanilla SetTheory +// operators and take their normal definition. +def add; +def interleave; +def decimate; +// rotl - Rotate set left by a number of elements. +// example: (rotl mask0, 3) -> [3, 4, 5, 6, 0, 1, 2] +def rotl; +// rotl - Rotate set right by a number of elements. +// example: (rotr mask0, 3) -> [4, 5, 6, 0, 1, 2, 3] +def rotr; +// highhalf - Take only the high half of the input. +// example: (highhalf mask0) -> [4, 5, 6, 7] (assuming mask0 had 8 elements) +def highhalf; +// highhalf - Take only the low half of the input. +// example: (lowhalf mask0) -> [0, 1, 2, 3] (assuming mask0 had 8 elements) +def lowhalf; +// rev - Perform a variable-width reversal of the elements. The zero'th argument +// is a width in bits to reverse. The lanes this maps to is determined +// based on the element width of the underlying type. +// example: (rev 32, mask0) -> [3, 2, 1, 0, 7, 6, 5, 4] (if 8-bit elements) +// example: (rev 32, mask0) -> [1, 0, 3, 2] (if 16-bit elements) +def rev; +// mask0 - The initial sequence of lanes for shuffle ARG0 +def mask0 : MaskExpand; +// mask0 - The initial sequence of lanes for shuffle ARG1 +def mask1 : MaskExpand; + +def OP_NONE : Operation; +def OP_UNAVAILABLE : Operation { + let Unavailable = 1; +} + +//===----------------------------------------------------------------------===// +// Instruction definitions +//===----------------------------------------------------------------------===// + +// Every intrinsic subclasses "Inst". An intrinsic has a name, a prototype and +// a sequence of typespecs. +// +// The name is the base name of the intrinsic, for example "vget_lane". This is +// then mangled by the tblgen backend to add type information ("vget_lane_s16"). +// +// A typespec is a sequence of uppercase characters (modifiers) followed by one +// lowercase character. A typespec encodes a particular "base type" of the +// intrinsic. +// +// An example typespec is "Qs" - quad-size short - uint16x8_t. The available +// typespec codes are given below. +// +// The string given to an Inst class is a sequence of typespecs. The intrinsic +// is instantiated for every typespec in the sequence. For example "sdQsQd". +// +// The prototype is a string that defines the return type of the intrinsic +// and the type of each argument. The return type and every argument gets a +// "modifier" that can change in some way the "base type" of the intrinsic. +// +// The modifier 'd' means "default" and does not modify the base type in any +// way. The available modifiers are given below. +// +// Typespecs +// --------- +// c: char +// s: short +// i: int +// l: long +// k: 128-bit long +// f: float +// h: half-float +// d: double +// +// Typespec modifiers +// ------------------ +// S: scalar, only used for function mangling. +// U: unsigned +// Q: 128b +// H: 128b without mangling 'q' +// P: polynomial +// +// Prototype modifiers +// ------------------- +// prototype: return (arg, arg, ...) +// +// v: void +// t: best-fit integer (int/poly args) +// x: signed integer (int/float args) +// u: unsigned integer (int/float args) +// f: float (int args) +// F: double (int args) +// d: default +// g: default, ignore 'Q' size modifier. +// j: default, force 'Q' size modifier. +// w: double width elements, same num elts +// n: double width elements, half num elts +// h: half width elements, double num elts +// q: half width elements, quad num elts +// e: half width elements, double num elts, unsigned +// m: half width elements, same num elts +// i: constant int +// l: constant uint64 +// s: scalar of element type +// z: scalar of half width element type, signed +// r: scalar of double width element type, signed +// a: scalar of element type (splat to vector type) +// b: scalar of unsigned integer/long type (int/float args) +// $: scalar of signed integer/long type (int/float args) +// y: scalar of float +// o: scalar of double +// k: default elt width, double num elts +// 2,3,4: array of default vectors +// B,C,D: array of default elts, force 'Q' size modifier. +// p: pointer type +// c: const pointer type + +// Every intrinsic subclasses Inst. +class Inst <string n, string p, string t, Operation o> { + string Name = n; + string Prototype = p; + string Types = t; + string ArchGuard = ""; + + Operation Operation = o; + bit CartesianProductOfTypes = 0; + bit BigEndianSafe = 0; + bit isShift = 0; + bit isScalarShift = 0; + bit isScalarNarrowShift = 0; + bit isVCVT_N = 0; + // For immediate checks: the immediate will be assumed to specify the lane of + // a Q register. Only used for intrinsics which end up calling polymorphic + // builtins. + bit isLaneQ = 0; + + // Certain intrinsics have different names than their representative + // instructions. This field allows us to handle this correctly when we + // are generating tests. + string InstName = ""; + + // Certain intrinsics even though they are not a WOpInst or LOpInst, + // generate a WOpInst/LOpInst instruction (see below for definition + // of a WOpInst/LOpInst). For testing purposes we need to know + // this. Ex: vset_lane which outputs vmov instructions. + bit isHiddenWInst = 0; + bit isHiddenLInst = 0; +} + +// The following instruction classes are implemented via builtins. +// These declarations are used to generate Builtins.def: +// +// SInst: Instruction with signed/unsigned suffix (e.g., "s8", "u8", "p8") +// IInst: Instruction with generic integer suffix (e.g., "i8") +// WInst: Instruction with only bit size suffix (e.g., "8") +class SInst<string n, string p, string t> : Inst<n, p, t, OP_NONE> {} +class IInst<string n, string p, string t> : Inst<n, p, t, OP_NONE> {} +class WInst<string n, string p, string t> : Inst<n, p, t, OP_NONE> {} + +// The following instruction classes are implemented via operators +// instead of builtins. As such these declarations are only used for +// the purpose of generating tests. +// +// SOpInst: Instruction with signed/unsigned suffix (e.g., "s8", +// "u8", "p8"). +// IOpInst: Instruction with generic integer suffix (e.g., "i8"). +// WOpInst: Instruction with bit size only suffix (e.g., "8"). +// LOpInst: Logical instruction with no bit size suffix. +// NoTestOpInst: Intrinsic that has no corresponding instruction. +class SOpInst<string n, string p, string t, Operation o> : Inst<n, p, t, o> {} +class IOpInst<string n, string p, string t, Operation o> : Inst<n, p, t, o> {} +class WOpInst<string n, string p, string t, Operation o> : Inst<n, p, t, o> {} +class LOpInst<string n, string p, string t, Operation o> : Inst<n, p, t, o> {} +class NoTestOpInst<string n, string p, string t, Operation o> : Inst<n, p, t, o> {} + +//===----------------------------------------------------------------------===// +// Operations +//===----------------------------------------------------------------------===// + +def OP_ADD : Op<(op "+", $p0, $p1)>; +def OP_ADDL : Op<(op "+", (call "vmovl", $p0), (call "vmovl", $p1))>; +def OP_ADDLHi : Op<(op "+", (call "vmovl_high", $p0), + (call "vmovl_high", $p1))>; +def OP_ADDW : Op<(op "+", $p0, (call "vmovl", $p1))>; +def OP_ADDWHi : Op<(op "+", $p0, (call "vmovl_high", $p1))>; +def OP_SUB : Op<(op "-", $p0, $p1)>; +def OP_SUBL : Op<(op "-", (call "vmovl", $p0), (call "vmovl", $p1))>; +def OP_SUBLHi : Op<(op "-", (call "vmovl_high", $p0), + (call "vmovl_high", $p1))>; +def OP_SUBW : Op<(op "-", $p0, (call "vmovl", $p1))>; +def OP_SUBWHi : Op<(op "-", $p0, (call "vmovl_high", $p1))>; +def OP_MUL : Op<(op "*", $p0, $p1)>; +def OP_MLA : Op<(op "+", $p0, (op "*", $p1, $p2))>; +def OP_MLAL : Op<(op "+", $p0, (call "vmull", $p1, $p2))>; +def OP_MULLHi : Op<(call "vmull", (call "vget_high", $p0), + (call "vget_high", $p1))>; +def OP_MULLHi_P64 : Op<(call "vmull", + (cast "poly64_t", (call "vget_high", $p0)), + (cast "poly64_t", (call "vget_high", $p1)))>; +def OP_MULLHi_N : Op<(call "vmull_n", (call "vget_high", $p0), $p1)>; +def OP_MLALHi : Op<(call "vmlal", $p0, (call "vget_high", $p1), + (call "vget_high", $p2))>; +def OP_MLALHi_N : Op<(call "vmlal_n", $p0, (call "vget_high", $p1), $p2)>; +def OP_MLS : Op<(op "-", $p0, (op "*", $p1, $p2))>; +def OP_MLSL : Op<(op "-", $p0, (call "vmull", $p1, $p2))>; +def OP_MLSLHi : Op<(call "vmlsl", $p0, (call "vget_high", $p1), + (call "vget_high", $p2))>; +def OP_MLSLHi_N : Op<(call "vmlsl_n", $p0, (call "vget_high", $p1), $p2)>; +def OP_MUL_N : Op<(op "*", $p0, (dup $p1))>; +def OP_MLA_N : Op<(op "+", $p0, (op "*", $p1, (dup $p2)))>; +def OP_MLS_N : Op<(op "-", $p0, (op "*", $p1, (dup $p2)))>; +def OP_FMLA_N : Op<(call "vfma", $p0, $p1, (dup $p2))>; +def OP_FMLS_N : Op<(call "vfms", $p0, $p1, (dup $p2))>; +def OP_MLAL_N : Op<(op "+", $p0, (call "vmull", $p1, (dup $p2)))>; +def OP_MLSL_N : Op<(op "-", $p0, (call "vmull", $p1, (dup $p2)))>; +def OP_MUL_LN : Op<(op "*", $p0, (splat $p1, $p2))>; +def OP_MULX_LN : Op<(call "vmulx", $p0, (splat $p1, $p2))>; +def OP_MULL_LN : Op<(call "vmull", $p0, (splat $p1, $p2))>; +def OP_MULLHi_LN: Op<(call "vmull", (call "vget_high", $p0), (splat $p1, $p2))>; +def OP_MLA_LN : Op<(op "+", $p0, (op "*", $p1, (splat $p2, $p3)))>; +def OP_MLS_LN : Op<(op "-", $p0, (op "*", $p1, (splat $p2, $p3)))>; +def OP_MLAL_LN : Op<(op "+", $p0, (call "vmull", $p1, (splat $p2, $p3)))>; +def OP_MLALHi_LN: Op<(op "+", $p0, (call "vmull", (call "vget_high", $p1), + (splat $p2, $p3)))>; +def OP_MLSL_LN : Op<(op "-", $p0, (call "vmull", $p1, (splat $p2, $p3)))>; +def OP_MLSLHi_LN : Op<(op "-", $p0, (call "vmull", (call "vget_high", $p1), + (splat $p2, $p3)))>; +def OP_QDMULL_LN : Op<(call "vqdmull", $p0, (splat $p1, $p2))>; +def OP_QDMULLHi_LN : Op<(call "vqdmull", (call "vget_high", $p0), + (splat $p1, $p2))>; +def OP_QDMLAL_LN : Op<(call "vqdmlal", $p0, $p1, (splat $p2, $p3))>; +def OP_QDMLALHi_LN : Op<(call "vqdmlal", $p0, (call "vget_high", $p1), + (splat $p2, $p3))>; +def OP_QDMLSL_LN : Op<(call "vqdmlsl", $p0, $p1, (splat $p2, $p3))>; +def OP_QDMLSLHi_LN : Op<(call "vqdmlsl", $p0, (call "vget_high", $p1), + (splat $p2, $p3))>; +def OP_QDMULH_LN : Op<(call "vqdmulh", $p0, (splat $p1, $p2))>; +def OP_QRDMULH_LN : Op<(call "vqrdmulh", $p0, (splat $p1, $p2))>; +def OP_QRDMLAH : Op<(call "vqadd", $p0, (call "vqrdmulh", $p1, $p2))>; +def OP_QRDMLSH : Op<(call "vqsub", $p0, (call "vqrdmulh", $p1, $p2))>; +def OP_QRDMLAH_LN : Op<(call "vqadd", $p0, (call "vqrdmulh", $p1, (splat $p2, $p3)))>; +def OP_QRDMLSH_LN : Op<(call "vqsub", $p0, (call "vqrdmulh", $p1, (splat $p2, $p3)))>; +def OP_FMS_LN : Op<(call "vfma_lane", $p0, $p1, (op "-", $p2), $p3)>; +def OP_FMS_LNQ : Op<(call "vfma_laneq", $p0, $p1, (op "-", $p2), $p3)>; +def OP_TRN1 : Op<(shuffle $p0, $p1, (interleave (decimate mask0, 2), + (decimate mask1, 2)))>; +def OP_ZIP1 : Op<(shuffle $p0, $p1, (lowhalf (interleave mask0, mask1)))>; +def OP_UZP1 : Op<(shuffle $p0, $p1, (add (decimate mask0, 2), + (decimate mask1, 2)))>; +def OP_TRN2 : Op<(shuffle $p0, $p1, (interleave + (decimate (rotl mask0, 1), 2), + (decimate (rotl mask1, 1), 2)))>; +def OP_ZIP2 : Op<(shuffle $p0, $p1, (highhalf (interleave mask0, mask1)))>; +def OP_UZP2 : Op<(shuffle $p0, $p1, (add (decimate (rotl mask0, 1), 2), + (decimate (rotl mask1, 1), 2)))>; +def OP_EQ : Op<(cast "R", (op "==", $p0, $p1))>; +def OP_GE : Op<(cast "R", (op ">=", $p0, $p1))>; +def OP_LE : Op<(cast "R", (op "<=", $p0, $p1))>; +def OP_GT : Op<(cast "R", (op ">", $p0, $p1))>; +def OP_LT : Op<(cast "R", (op "<", $p0, $p1))>; +def OP_NEG : Op<(op "-", $p0)>; +def OP_NOT : Op<(op "~", $p0)>; +def OP_AND : Op<(op "&", $p0, $p1)>; +def OP_OR : Op<(op "|", $p0, $p1)>; +def OP_XOR : Op<(op "^", $p0, $p1)>; +def OP_ANDN : Op<(op "&", $p0, (op "~", $p1))>; +def OP_ORN : Op<(op "|", $p0, (op "~", $p1))>; +def OP_CAST : Op<(cast "R", $p0)>; +def OP_HI : Op<(shuffle $p0, $p0, (highhalf mask0))>; +def OP_LO : Op<(shuffle $p0, $p0, (lowhalf mask0))>; +def OP_CONC : Op<(shuffle $p0, $p1, (add mask0, mask1))>; +def OP_DUP : Op<(dup $p0)>; +def OP_DUP_LN : Op<(splat $p0, $p1)>; +def OP_SEL : Op<(cast "R", (op "|", + (op "&", $p0, (cast $p0, $p1)), + (op "&", (op "~", $p0), (cast $p0, $p2))))>; +def OP_REV16 : Op<(shuffle $p0, $p0, (rev 16, mask0))>; +def OP_REV32 : Op<(shuffle $p0, $p0, (rev 32, mask0))>; +def OP_REV64 : Op<(shuffle $p0, $p0, (rev 64, mask0))>; +def OP_XTN : Op<(call "vcombine", $p0, (call "vmovn", $p1))>; +def OP_SQXTUN : Op<(call "vcombine", (cast $p0, "U", $p0), + (call "vqmovun", $p1))>; +def OP_QXTN : Op<(call "vcombine", $p0, (call "vqmovn", $p1))>; +def OP_VCVT_NA_HI_F16 : Op<(call "vcombine", $p0, (call "vcvt_f16_f32", $p1))>; +def OP_VCVT_NA_HI_F32 : Op<(call "vcombine", $p0, (call "vcvt_f32_f64", $p1))>; +def OP_VCVT_EX_HI_F32 : Op<(call "vcvt_f32_f16", (call "vget_high", $p0))>; +def OP_VCVT_EX_HI_F64 : Op<(call "vcvt_f64_f32", (call "vget_high", $p0))>; +def OP_VCVTX_HI : Op<(call "vcombine", $p0, (call "vcvtx_f32", $p1))>; +def OP_REINT : Op<(cast "R", $p0)>; +def OP_ADDHNHi : Op<(call "vcombine", $p0, (call "vaddhn", $p1, $p2))>; +def OP_RADDHNHi : Op<(call "vcombine", $p0, (call "vraddhn", $p1, $p2))>; +def OP_SUBHNHi : Op<(call "vcombine", $p0, (call "vsubhn", $p1, $p2))>; +def OP_RSUBHNHi : Op<(call "vcombine", $p0, (call "vrsubhn", $p1, $p2))>; +def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", + (call "vabd", $p0, $p1))))>; +def OP_ABDLHi : Op<(call "vabdl", (call "vget_high", $p0), + (call "vget_high", $p1))>; +def OP_ABA : Op<(op "+", $p0, (call "vabd", $p1, $p2))>; +def OP_ABAL : Op<(op "+", $p0, (call "vabdl", $p1, $p2))>; +def OP_ABALHi : Op<(call "vabal", $p0, (call "vget_high", $p1), + (call "vget_high", $p2))>; +def OP_QDMULLHi : Op<(call "vqdmull", (call "vget_high", $p0), + (call "vget_high", $p1))>; +def OP_QDMULLHi_N : Op<(call "vqdmull_n", (call "vget_high", $p0), $p1)>; +def OP_QDMLALHi : Op<(call "vqdmlal", $p0, (call "vget_high", $p1), + (call "vget_high", $p2))>; +def OP_QDMLALHi_N : Op<(call "vqdmlal_n", $p0, (call "vget_high", $p1), $p2)>; +def OP_QDMLSLHi : Op<(call "vqdmlsl", $p0, (call "vget_high", $p1), + (call "vget_high", $p2))>; +def OP_QDMLSLHi_N : Op<(call "vqdmlsl_n", $p0, (call "vget_high", $p1), $p2)>; +def OP_DIV : Op<(op "/", $p0, $p1)>; +def OP_LONG_HI : Op<(cast "R", (call (name_replace "_high_", "_"), + (call "vget_high", $p0), $p1))>; +def OP_NARROW_HI : Op<(cast "R", (call "vcombine", + (cast "R", "H", $p0), + (cast "R", "H", + (call (name_replace "_high_", "_"), + $p1, $p2))))>; +def OP_MOVL_HI : LOp<[(save_temp $a1, (call "vget_high", $p0)), + (cast "R", + (call "vshll_n", $a1, (literal "int32_t", "0")))]>; +def OP_COPY_LN : Op<(call "vset_lane", (call "vget_lane", $p2, $p3), $p0, $p1)>; +def OP_SCALAR_MUL_LN : Op<(op "*", $p0, (call "vget_lane", $p1, $p2))>; +def OP_SCALAR_MULX_LN : Op<(call "vmulx", $p0, (call "vget_lane", $p1, $p2))>; +def OP_SCALAR_VMULX_LN : LOp<[(save_temp $x, (call "vget_lane", $p0, + (literal "int32_t", "0"))), + (save_temp $y, (call "vget_lane", $p1, $p2)), + (save_temp $z, (call "vmulx", $x, $y)), + (call "vset_lane", $z, $p0, $p2)]>; +def OP_SCALAR_VMULX_LNQ : LOp<[(save_temp $x, (call "vget_lane", $p0, + (literal "int32_t", "0"))), + (save_temp $y, (call "vget_lane", $p1, $p2)), + (save_temp $z, (call "vmulx", $x, $y)), + (call "vset_lane", $z, $p0, (literal "int32_t", + "0"))]>; +class ScalarMulOp<string opname> : + Op<(call opname, $p0, (call "vget_lane", $p1, $p2))>; + +def OP_SCALAR_QDMULL_LN : ScalarMulOp<"vqdmull">; +def OP_SCALAR_QDMULH_LN : ScalarMulOp<"vqdmulh">; +def OP_SCALAR_QRDMULH_LN : ScalarMulOp<"vqrdmulh">; + +def OP_SCALAR_QRDMLAH_LN : Op<(call "vqadd", $p0, (call "vqrdmulh", $p1, + (call "vget_lane", $p2, $p3)))>; +def OP_SCALAR_QRDMLSH_LN : Op<(call "vqsub", $p0, (call "vqrdmulh", $p1, + (call "vget_lane", $p2, $p3)))>; + +def OP_SCALAR_HALF_GET_LN : Op<(bitcast "float16_t", + (call "vget_lane", + (bitcast "int16x4_t", $p0), $p1))>; +def OP_SCALAR_HALF_GET_LNQ : Op<(bitcast "float16_t", + (call "vget_lane", + (bitcast "int16x8_t", $p0), $p1))>; +def OP_SCALAR_HALF_SET_LN : Op<(bitcast "float16x4_t", + (call "vset_lane", + (bitcast "int16_t", $p0), + (bitcast "int16x4_t", $p1), $p2))>; +def OP_SCALAR_HALF_SET_LNQ : Op<(bitcast "float16x8_t", + (call "vset_lane", + (bitcast "int16_t", $p0), + (bitcast "int16x8_t", $p1), $p2))>; + +//===----------------------------------------------------------------------===// +// Instructions +//===----------------------------------------------------------------------===// + +//////////////////////////////////////////////////////////////////////////////// +// E.3.1 Addition +def VADD : IOpInst<"vadd", "ddd", + "csilfUcUsUiUlQcQsQiQlQfQUcQUsQUiQUl", OP_ADD>; +def VADDL : SOpInst<"vaddl", "wdd", "csiUcUsUi", OP_ADDL>; +def VADDW : SOpInst<"vaddw", "wwd", "csiUcUsUi", OP_ADDW>; +def VHADD : SInst<"vhadd", "ddd", "csiUcUsUiQcQsQiQUcQUsQUi">; +def VRHADD : SInst<"vrhadd", "ddd", "csiUcUsUiQcQsQiQUcQUsQUi">; +def VQADD : SInst<"vqadd", "ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VADDHN : IInst<"vaddhn", "hkk", "silUsUiUl">; +def VRADDHN : IInst<"vraddhn", "hkk", "silUsUiUl">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.2 Multiplication +def VMUL : IOpInst<"vmul", "ddd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_MUL>; +def VMULP : SInst<"vmul", "ddd", "PcQPc">; +def VMLA : IOpInst<"vmla", "dddd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_MLA>; +def VMLAL : SOpInst<"vmlal", "wwdd", "csiUcUsUi", OP_MLAL>; +def VMLS : IOpInst<"vmls", "dddd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_MLS>; +def VMLSL : SOpInst<"vmlsl", "wwdd", "csiUcUsUi", OP_MLSL>; +def VQDMULH : SInst<"vqdmulh", "ddd", "siQsQi">; +def VQRDMULH : SInst<"vqrdmulh", "ddd", "siQsQi">; + +let ArchGuard = "defined(__ARM_FEATURE_QRDMX)" in { +def VQRDMLAH : SOpInst<"vqrdmlah", "dddd", "siQsQi", OP_QRDMLAH>; +def VQRDMLSH : SOpInst<"vqrdmlsh", "dddd", "siQsQi", OP_QRDMLSH>; +} + +def VQDMLAL : SInst<"vqdmlal", "wwdd", "si">; +def VQDMLSL : SInst<"vqdmlsl", "wwdd", "si">; +def VMULL : SInst<"vmull", "wdd", "csiUcUsUiPc">; +def VQDMULL : SInst<"vqdmull", "wdd", "si">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.3 Subtraction +def VSUB : IOpInst<"vsub", "ddd", + "csilfUcUsUiUlQcQsQiQlQfQUcQUsQUiQUl", OP_SUB>; +def VSUBL : SOpInst<"vsubl", "wdd", "csiUcUsUi", OP_SUBL>; +def VSUBW : SOpInst<"vsubw", "wwd", "csiUcUsUi", OP_SUBW>; +def VQSUB : SInst<"vqsub", "ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VHSUB : SInst<"vhsub", "ddd", "csiUcUsUiQcQsQiQUcQUsQUi">; +def VSUBHN : IInst<"vsubhn", "hkk", "silUsUiUl">; +def VRSUBHN : IInst<"vrsubhn", "hkk", "silUsUiUl">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.4 Comparison +def VCEQ : IOpInst<"vceq", "udd", "csifUcUsUiPcQcQsQiQfQUcQUsQUiQPc", OP_EQ>; +def VCGE : SOpInst<"vcge", "udd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_GE>; +let InstName = "vcge" in +def VCLE : SOpInst<"vcle", "udd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_LE>; +def VCGT : SOpInst<"vcgt", "udd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_GT>; +let InstName = "vcgt" in +def VCLT : SOpInst<"vclt", "udd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_LT>; +let InstName = "vacge" in { +def VCAGE : IInst<"vcage", "udd", "fQf">; +def VCALE : IInst<"vcale", "udd", "fQf">; +} +let InstName = "vacgt" in { +def VCAGT : IInst<"vcagt", "udd", "fQf">; +def VCALT : IInst<"vcalt", "udd", "fQf">; +} +def VTST : WInst<"vtst", "udd", "csiUcUsUiPcPsQcQsQiQUcQUsQUiQPcQPs">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.5 Absolute Difference +def VABD : SInst<"vabd", "ddd", "csiUcUsUifQcQsQiQUcQUsQUiQf">; +def VABDL : SOpInst<"vabdl", "wdd", "csiUcUsUi", OP_ABDL>; +def VABA : SOpInst<"vaba", "dddd", "csiUcUsUiQcQsQiQUcQUsQUi", OP_ABA>; +def VABAL : SOpInst<"vabal", "wwdd", "csiUcUsUi", OP_ABAL>; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.6 Max/Min +def VMAX : SInst<"vmax", "ddd", "csiUcUsUifQcQsQiQUcQUsQUiQf">; +def VMIN : SInst<"vmin", "ddd", "csiUcUsUifQcQsQiQUcQUsQUiQf">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.7 Pairwise Addition +def VPADD : IInst<"vpadd", "ddd", "csiUcUsUif">; +def VPADDL : SInst<"vpaddl", "nd", "csiUcUsUiQcQsQiQUcQUsQUi">; +def VPADAL : SInst<"vpadal", "nnd", "csiUcUsUiQcQsQiQUcQUsQUi">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.8-9 Folding Max/Min +def VPMAX : SInst<"vpmax", "ddd", "csiUcUsUif">; +def VPMIN : SInst<"vpmin", "ddd", "csiUcUsUif">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.10 Reciprocal/Sqrt +def VRECPS : IInst<"vrecps", "ddd", "fQf">; +def VRSQRTS : IInst<"vrsqrts", "ddd", "fQf">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.11 Shifts by signed variable +def VSHL : SInst<"vshl", "ddx", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VQSHL : SInst<"vqshl", "ddx", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VRSHL : SInst<"vrshl", "ddx", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VQRSHL : SInst<"vqrshl", "ddx", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.12 Shifts by constant +let isShift = 1 in { +def VSHR_N : SInst<"vshr_n", "ddi", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VSHL_N : IInst<"vshl_n", "ddi", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VRSHR_N : SInst<"vrshr_n", "ddi", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VSRA_N : SInst<"vsra_n", "dddi", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VRSRA_N : SInst<"vrsra_n", "dddi", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VQSHL_N : SInst<"vqshl_n", "ddi", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VQSHLU_N : SInst<"vqshlu_n", "udi", "csilQcQsQiQl">; +def VSHRN_N : IInst<"vshrn_n", "hki", "silUsUiUl">; +def VQSHRUN_N : SInst<"vqshrun_n", "eki", "sil">; +def VQRSHRUN_N : SInst<"vqrshrun_n", "eki", "sil">; +def VQSHRN_N : SInst<"vqshrn_n", "hki", "silUsUiUl">; +def VRSHRN_N : IInst<"vrshrn_n", "hki", "silUsUiUl">; +def VQRSHRN_N : SInst<"vqrshrn_n", "hki", "silUsUiUl">; +def VSHLL_N : SInst<"vshll_n", "wdi", "csiUcUsUi">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.13 Shifts with insert +def VSRI_N : WInst<"vsri_n", "dddi", + "csilUcUsUiUlPcPsQcQsQiQlQUcQUsQUiQUlQPcQPs">; +def VSLI_N : WInst<"vsli_n", "dddi", + "csilUcUsUiUlPcPsQcQsQiQlQUcQUsQUiQUlQPcQPs">; +} + +//////////////////////////////////////////////////////////////////////////////// +// E.3.14 Loads and stores of a single vector +def VLD1 : WInst<"vld1", "dc", + "QUcQUsQUiQUlQcQsQiQlQhQfQPcQPsUcUsUiUlcsilhfPcPs">; +def VLD1_LANE : WInst<"vld1_lane", "dcdi", + "QUcQUsQUiQUlQcQsQiQlQhQfQPcQPsUcUsUiUlcsilhfPcPs">; +def VLD1_DUP : WInst<"vld1_dup", "dc", + "QUcQUsQUiQUlQcQsQiQlQhQfQPcQPsUcUsUiUlcsilhfPcPs">; +def VST1 : WInst<"vst1", "vpd", + "QUcQUsQUiQUlQcQsQiQlQhQfQPcQPsUcUsUiUlcsilhfPcPs">; +def VST1_LANE : WInst<"vst1_lane", "vpdi", + "QUcQUsQUiQUlQcQsQiQlQhQfQPcQPsUcUsUiUlcsilhfPcPs">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.15 Loads and stores of an N-element structure +def VLD2 : WInst<"vld2", "2c", "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPs">; +def VLD3 : WInst<"vld3", "3c", "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPs">; +def VLD4 : WInst<"vld4", "4c", "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPs">; +def VLD2_DUP : WInst<"vld2_dup", "2c", "UcUsUiUlcsilhfPcPs">; +def VLD3_DUP : WInst<"vld3_dup", "3c", "UcUsUiUlcsilhfPcPs">; +def VLD4_DUP : WInst<"vld4_dup", "4c", "UcUsUiUlcsilhfPcPs">; +def VLD2_LANE : WInst<"vld2_lane", "2c2i", "QUsQUiQsQiQhQfQPsUcUsUicsihfPcPs">; +def VLD3_LANE : WInst<"vld3_lane", "3c3i", "QUsQUiQsQiQhQfQPsUcUsUicsihfPcPs">; +def VLD4_LANE : WInst<"vld4_lane", "4c4i", "QUsQUiQsQiQhQfQPsUcUsUicsihfPcPs">; +def VST2 : WInst<"vst2", "vp2", "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPs">; +def VST3 : WInst<"vst3", "vp3", "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPs">; +def VST4 : WInst<"vst4", "vp4", "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPs">; +def VST2_LANE : WInst<"vst2_lane", "vp2i", "QUsQUiQsQiQhQfQPsUcUsUicsihfPcPs">; +def VST3_LANE : WInst<"vst3_lane", "vp3i", "QUsQUiQsQiQhQfQPsUcUsUicsihfPcPs">; +def VST4_LANE : WInst<"vst4_lane", "vp4i", "QUsQUiQsQiQhQfQPsUcUsUicsihfPcPs">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.16 Extract lanes from a vector +let InstName = "vmov" in +def VGET_LANE : IInst<"vget_lane", "sdi", + "UcUsUicsiPcPsfQUcQUsQUiQcQsQiQPcQPsQflUlQlQUl">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.17 Set lanes within a vector +let InstName = "vmov" in +def VSET_LANE : IInst<"vset_lane", "dsdi", + "UcUsUicsiPcPsfQUcQUsQUiQcQsQiQPcQPsQflUlQlQUl">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.18 Initialize a vector from bit pattern +def VCREATE : NoTestOpInst<"vcreate", "dl", "csihfUcUsUiUlPcPsl", OP_CAST> { + let BigEndianSafe = 1; +} + +//////////////////////////////////////////////////////////////////////////////// +// E.3.19 Set all lanes to same value +let InstName = "vmov" in { +def VDUP_N : WOpInst<"vdup_n", "ds", + "UcUsUicsiPcPshfQUcQUsQUiQcQsQiQPcQPsQhQflUlQlQUl", + OP_DUP>; +def VMOV_N : WOpInst<"vmov_n", "ds", + "UcUsUicsiPcPshfQUcQUsQUiQcQsQiQPcQPsQhQflUlQlQUl", + OP_DUP>; +} +let InstName = "" in +def VDUP_LANE: WOpInst<"vdup_lane", "dgi", + "UcUsUicsiPcPsfQUcQUsQUiQcQsQiQPcQPsQflUlQlQUl", + OP_DUP_LN>; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.20 Combining vectors +def VCOMBINE : NoTestOpInst<"vcombine", "kdd", "csilhfUcUsUiUlPcPs", OP_CONC>; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.21 Splitting vectors +let InstName = "vmov" in { +def VGET_HIGH : NoTestOpInst<"vget_high", "dk", "csilhfUcUsUiUlPcPs", OP_HI>; +def VGET_LOW : NoTestOpInst<"vget_low", "dk", "csilhfUcUsUiUlPcPs", OP_LO>; +} + +//////////////////////////////////////////////////////////////////////////////// +// E.3.22 Converting vectors + +def VCVT_F16_F32 : SInst<"vcvt_f16_f32", "md", "Hf">; +def VCVT_F32_F16 : SInst<"vcvt_f32_f16", "wd", "h">; + +def VCVT_S32 : SInst<"vcvt_s32", "xd", "fQf">; +def VCVT_U32 : SInst<"vcvt_u32", "ud", "fQf">; +def VCVT_F32 : SInst<"vcvt_f32", "fd", "iUiQiQUi">; +let isVCVT_N = 1 in { +def VCVT_N_S32 : SInst<"vcvt_n_s32", "xdi", "fQf">; +def VCVT_N_U32 : SInst<"vcvt_n_u32", "udi", "fQf">; +def VCVT_N_F32 : SInst<"vcvt_n_f32", "fdi", "iUiQiQUi">; +} + +def VMOVN : IInst<"vmovn", "hk", "silUsUiUl">; +def VMOVL : SInst<"vmovl", "wd", "csiUcUsUi">; +def VQMOVN : SInst<"vqmovn", "hk", "silUsUiUl">; +def VQMOVUN : SInst<"vqmovun", "ek", "sil">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.23-24 Table lookup, Extended table lookup +let InstName = "vtbl" in { +def VTBL1 : WInst<"vtbl1", "ddt", "UccPc">; +def VTBL2 : WInst<"vtbl2", "d2t", "UccPc">; +def VTBL3 : WInst<"vtbl3", "d3t", "UccPc">; +def VTBL4 : WInst<"vtbl4", "d4t", "UccPc">; +} +let InstName = "vtbx" in { +def VTBX1 : WInst<"vtbx1", "dddt", "UccPc">; +def VTBX2 : WInst<"vtbx2", "dd2t", "UccPc">; +def VTBX3 : WInst<"vtbx3", "dd3t", "UccPc">; +def VTBX4 : WInst<"vtbx4", "dd4t", "UccPc">; +} + +//////////////////////////////////////////////////////////////////////////////// +// E.3.25 Operations with a scalar value +def VMLA_LANE : IOpInst<"vmla_lane", "dddgi", + "siUsUifQsQiQUsQUiQf", OP_MLA_LN>; +def VMLAL_LANE : SOpInst<"vmlal_lane", "wwddi", "siUsUi", OP_MLAL_LN>; +def VQDMLAL_LANE : SOpInst<"vqdmlal_lane", "wwddi", "si", OP_QDMLAL_LN>; +def VMLS_LANE : IOpInst<"vmls_lane", "dddgi", + "siUsUifQsQiQUsQUiQf", OP_MLS_LN>; +def VMLSL_LANE : SOpInst<"vmlsl_lane", "wwddi", "siUsUi", OP_MLSL_LN>; +def VQDMLSL_LANE : SOpInst<"vqdmlsl_lane", "wwddi", "si", OP_QDMLSL_LN>; +def VMUL_N : IOpInst<"vmul_n", "dds", "sifUsUiQsQiQfQUsQUi", OP_MUL_N>; +def VMUL_LANE : IOpInst<"vmul_lane", "ddgi", + "sifUsUiQsQiQfQUsQUi", OP_MUL_LN>; +def VMULL_N : SInst<"vmull_n", "wda", "siUsUi">; +def VMULL_LANE : SOpInst<"vmull_lane", "wddi", "siUsUi", OP_MULL_LN>; +def VQDMULL_N : SInst<"vqdmull_n", "wda", "si">; +def VQDMULL_LANE : SOpInst<"vqdmull_lane", "wddi", "si", OP_QDMULL_LN>; +def VQDMULH_N : SInst<"vqdmulh_n", "dda", "siQsQi">; +def VQDMULH_LANE : SOpInst<"vqdmulh_lane", "ddgi", "siQsQi", OP_QDMULH_LN>; +def VQRDMULH_N : SInst<"vqrdmulh_n", "dda", "siQsQi">; +def VQRDMULH_LANE : SOpInst<"vqrdmulh_lane", "ddgi", "siQsQi", OP_QRDMULH_LN>; + +let ArchGuard = "defined(__ARM_FEATURE_QRDMX)" in { +def VQRDMLAH_LANE : SOpInst<"vqrdmlah_lane", "dddgi", "siQsQi", OP_QRDMLAH_LN>; +def VQRDMLSH_LANE : SOpInst<"vqrdmlsh_lane", "dddgi", "siQsQi", OP_QRDMLSH_LN>; +} + +def VMLA_N : IOpInst<"vmla_n", "ddda", "siUsUifQsQiQUsQUiQf", OP_MLA_N>; +def VMLAL_N : SOpInst<"vmlal_n", "wwda", "siUsUi", OP_MLAL_N>; +def VQDMLAL_N : SInst<"vqdmlal_n", "wwda", "si">; +def VMLS_N : IOpInst<"vmls_n", "ddds", "siUsUifQsQiQUsQUiQf", OP_MLS_N>; +def VMLSL_N : SOpInst<"vmlsl_n", "wwda", "siUsUi", OP_MLSL_N>; +def VQDMLSL_N : SInst<"vqdmlsl_n", "wwda", "si">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.26 Vector Extract +def VEXT : WInst<"vext", "dddi", + "cUcPcsUsPsiUilUlfQcQUcQPcQsQUsQPsQiQUiQlQUlQf">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.27 Reverse vector elements +def VREV64 : WOpInst<"vrev64", "dd", "csiUcUsUiPcPsfQcQsQiQUcQUsQUiQPcQPsQf", + OP_REV64>; +def VREV32 : WOpInst<"vrev32", "dd", "csUcUsPcPsQcQsQUcQUsQPcQPs", OP_REV32>; +def VREV16 : WOpInst<"vrev16", "dd", "cUcPcQcQUcQPc", OP_REV16>; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.28 Other single operand arithmetic +def VABS : SInst<"vabs", "dd", "csifQcQsQiQf">; +def VQABS : SInst<"vqabs", "dd", "csiQcQsQi">; +def VNEG : SOpInst<"vneg", "dd", "csifQcQsQiQf", OP_NEG>; +def VQNEG : SInst<"vqneg", "dd", "csiQcQsQi">; +def VCLS : SInst<"vcls", "dd", "csiQcQsQi">; +def VCLZ : IInst<"vclz", "dd", "csiUcUsUiQcQsQiQUcQUsQUi">; +def VCNT : WInst<"vcnt", "dd", "UccPcQUcQcQPc">; +def VRECPE : SInst<"vrecpe", "dd", "fUiQfQUi">; +def VRSQRTE : SInst<"vrsqrte", "dd", "fUiQfQUi">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.29 Logical operations +def VMVN : LOpInst<"vmvn", "dd", "csiUcUsUiPcQcQsQiQUcQUsQUiQPc", OP_NOT>; +def VAND : LOpInst<"vand", "ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl", OP_AND>; +def VORR : LOpInst<"vorr", "ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl", OP_OR>; +def VEOR : LOpInst<"veor", "ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl", OP_XOR>; +def VBIC : LOpInst<"vbic", "ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl", OP_ANDN>; +def VORN : LOpInst<"vorn", "ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl", OP_ORN>; +let isHiddenLInst = 1 in +def VBSL : SInst<"vbsl", "dudd", + "csilUcUsUiUlfPcPsQcQsQiQlQUcQUsQUiQUlQfQPcQPs">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.30 Transposition operations +def VTRN : WInst<"vtrn", "2dd", "csiUcUsUifPcPsQcQsQiQUcQUsQUiQfQPcQPs">; +def VZIP : WInst<"vzip", "2dd", "csiUcUsUifPcPsQcQsQiQUcQUsQUiQfQPcQPs">; +def VUZP : WInst<"vuzp", "2dd", "csiUcUsUifPcPsQcQsQiQUcQUsQUiQfQPcQPs">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.31 Vector reinterpret cast operations +def VREINTERPRET + : NoTestOpInst<"vreinterpret", "dd", + "csilUcUsUiUlhfPcPsQcQsQiQlQUcQUsQUiQUlQhQfQPcQPs", OP_REINT> { + let CartesianProductOfTypes = 1; + let ArchGuard = "!defined(__aarch64__)"; + let BigEndianSafe = 1; +} + +//////////////////////////////////////////////////////////////////////////////// +// Vector fused multiply-add operations + +def VFMA : SInst<"vfma", "dddd", "fQf">; + +//////////////////////////////////////////////////////////////////////////////// +// fp16 vector operations +def SCALAR_HALF_GET_LANE : IOpInst<"vget_lane", "sdi", "h", OP_SCALAR_HALF_GET_LN>; +def SCALAR_HALF_SET_LANE : IOpInst<"vset_lane", "dsdi", "h", OP_SCALAR_HALF_SET_LN>; +def SCALAR_HALF_GET_LANEQ : IOpInst<"vget_lane", "sdi", "Qh", OP_SCALAR_HALF_GET_LNQ>; +def SCALAR_HALF_SET_LANEQ : IOpInst<"vset_lane", "dsdi", "Qh", OP_SCALAR_HALF_SET_LNQ>; + +//////////////////////////////////////////////////////////////////////////////// +// AArch64 Intrinsics + +let ArchGuard = "defined(__aarch64__)" in { + +//////////////////////////////////////////////////////////////////////////////// +// Load/Store +def LD1 : WInst<"vld1", "dc", "dQdPlQPl">; +def LD2 : WInst<"vld2", "2c", "QUlQldQdPlQPl">; +def LD3 : WInst<"vld3", "3c", "QUlQldQdPlQPl">; +def LD4 : WInst<"vld4", "4c", "QUlQldQdPlQPl">; +def ST1 : WInst<"vst1", "vpd", "dQdPlQPl">; +def ST2 : WInst<"vst2", "vp2", "QUlQldQdPlQPl">; +def ST3 : WInst<"vst3", "vp3", "QUlQldQdPlQPl">; +def ST4 : WInst<"vst4", "vp4", "QUlQldQdPlQPl">; + +def LD1_X2 : WInst<"vld1_x2", "2c", + "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPsQUlQldQdPlQPl">; +def LD3_x3 : WInst<"vld1_x3", "3c", + "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPsQUlQldQdPlQPl">; +def LD4_x4 : WInst<"vld1_x4", "4c", + "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPsQUlQldQdPlQPl">; + +def ST1_X2 : WInst<"vst1_x2", "vp2", + "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPsQUlQldQdPlQPl">; +def ST1_X3 : WInst<"vst1_x3", "vp3", + "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPsQUlQldQdPlQPl">; +def ST1_X4 : WInst<"vst1_x4", "vp4", + "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPsQUlQldQdPlQPl">; + +def LD1_LANE : WInst<"vld1_lane", "dcdi", "dQdPlQPl">; +def LD2_LANE : WInst<"vld2_lane", "2c2i", "lUlQcQUcQPcQlQUldQdPlQPl">; +def LD3_LANE : WInst<"vld3_lane", "3c3i", "lUlQcQUcQPcQlQUldQdPlQPl">; +def LD4_LANE : WInst<"vld4_lane", "4c4i", "lUlQcQUcQPcQlQUldQdPlQPl">; +def ST1_LANE : WInst<"vst1_lane", "vpdi", "dQdPlQPl">; +def ST2_LANE : WInst<"vst2_lane", "vp2i", "lUlQcQUcQPcQlQUldQdPlQPl">; +def ST3_LANE : WInst<"vst3_lane", "vp3i", "lUlQcQUcQPcQlQUldQdPlQPl">; +def ST4_LANE : WInst<"vst4_lane", "vp4i", "lUlQcQUcQPcQlQUldQdPlQPl">; + +def LD1_DUP : WInst<"vld1_dup", "dc", "dQdPlQPl">; +def LD2_DUP : WInst<"vld2_dup", "2c", + "QUcQUsQUiQUlQcQsQiQlQhQfQdQPcQPsQPldPl">; +def LD3_DUP : WInst<"vld3_dup", "3c", + "QUcQUsQUiQUlQcQsQiQlQhQfQdQPcQPsQPldPl">; +def LD4_DUP : WInst<"vld4_dup", "4c", + "QUcQUsQUiQUlQcQsQiQlQhQfQdQPcQPsQPldPl">; + +def VLDRQ : WInst<"vldrq", "sc", "Pk">; +def VSTRQ : WInst<"vstrq", "vps", "Pk">; + +//////////////////////////////////////////////////////////////////////////////// +// Addition +def ADD : IOpInst<"vadd", "ddd", "dQd", OP_ADD>; + +//////////////////////////////////////////////////////////////////////////////// +// Subtraction +def SUB : IOpInst<"vsub", "ddd", "dQd", OP_SUB>; + +//////////////////////////////////////////////////////////////////////////////// +// Multiplication +def MUL : IOpInst<"vmul", "ddd", "dQd", OP_MUL>; +def MLA : IOpInst<"vmla", "dddd", "dQd", OP_MLA>; +def MLS : IOpInst<"vmls", "dddd", "dQd", OP_MLS>; + +//////////////////////////////////////////////////////////////////////////////// +// Multiplication Extended +def MULX : SInst<"vmulx", "ddd", "fdQfQd">; + +//////////////////////////////////////////////////////////////////////////////// +// Division +def FDIV : IOpInst<"vdiv", "ddd", "fdQfQd", OP_DIV>; + +//////////////////////////////////////////////////////////////////////////////// +// Vector fused multiply-add operations +def FMLA : SInst<"vfma", "dddd", "dQd">; +def FMLS : SInst<"vfms", "dddd", "fdQfQd">; + +//////////////////////////////////////////////////////////////////////////////// +// MUL, MLA, MLS, FMA, FMS definitions with scalar argument +def VMUL_N_A64 : IOpInst<"vmul_n", "dds", "Qd", OP_MUL_N>; + +def FMLA_N : SOpInst<"vfma_n", "ddds", "fQfQd", OP_FMLA_N>; +def FMLS_N : SOpInst<"vfms_n", "ddds", "fQfQd", OP_FMLS_N>; + +def MLA_N : SOpInst<"vmla_n", "ddds", "Qd", OP_MLA_N>; +def MLS_N : SOpInst<"vmls_n", "ddds", "Qd", OP_MLS_N>; + +//////////////////////////////////////////////////////////////////////////////// +// Logical operations +def BSL : SInst<"vbsl", "dudd", "dPlQdQPl">; + +//////////////////////////////////////////////////////////////////////////////// +// Absolute Difference +def ABD : SInst<"vabd", "ddd", "dQd">; + +//////////////////////////////////////////////////////////////////////////////// +// saturating absolute/negate +def ABS : SInst<"vabs", "dd", "dQdlQl">; +def QABS : SInst<"vqabs", "dd", "lQl">; +def NEG : SOpInst<"vneg", "dd", "dlQdQl", OP_NEG>; +def QNEG : SInst<"vqneg", "dd", "lQl">; + +//////////////////////////////////////////////////////////////////////////////// +// Signed Saturating Accumulated of Unsigned Value +def SUQADD : SInst<"vuqadd", "ddd", "csilQcQsQiQl">; + +//////////////////////////////////////////////////////////////////////////////// +// Unsigned Saturating Accumulated of Signed Value +def USQADD : SInst<"vsqadd", "ddd", "UcUsUiUlQUcQUsQUiQUl">; + +//////////////////////////////////////////////////////////////////////////////// +// Reciprocal/Sqrt +def FRECPS : IInst<"vrecps", "ddd", "dQd">; +def FRSQRTS : IInst<"vrsqrts", "ddd", "dQd">; +def FRECPE : SInst<"vrecpe", "dd", "dQd">; +def FRSQRTE : SInst<"vrsqrte", "dd", "dQd">; +def FSQRT : SInst<"vsqrt", "dd", "fdQfQd">; + +//////////////////////////////////////////////////////////////////////////////// +// bitwise reverse +def RBIT : IInst<"vrbit", "dd", "cUcPcQcQUcQPc">; + +//////////////////////////////////////////////////////////////////////////////// +// Integer extract and narrow to high +def XTN2 : SOpInst<"vmovn_high", "qhk", "silUsUiUl", OP_XTN>; + +//////////////////////////////////////////////////////////////////////////////// +// Signed integer saturating extract and unsigned narrow to high +def SQXTUN2 : SOpInst<"vqmovun_high", "qhk", "sil", OP_SQXTUN>; + +//////////////////////////////////////////////////////////////////////////////// +// Integer saturating extract and narrow to high +def QXTN2 : SOpInst<"vqmovn_high", "qhk", "silUsUiUl", OP_QXTN>; + +//////////////////////////////////////////////////////////////////////////////// +// Converting vectors + +def VCVT_F32_F64 : SInst<"vcvt_f32_f64", "md", "Qd">; +def VCVT_F64_F32 : SInst<"vcvt_f64_f32", "wd", "f">; + +def VCVT_S64 : SInst<"vcvt_s64", "xd", "dQd">; +def VCVT_U64 : SInst<"vcvt_u64", "ud", "dQd">; +def VCVT_F64 : SInst<"vcvt_f64", "Fd", "lUlQlQUl">; + +def VCVT_HIGH_F16_F32 : SOpInst<"vcvt_high_f16", "hmj", "Hf", OP_VCVT_NA_HI_F16>; +def VCVT_HIGH_F32_F16 : SOpInst<"vcvt_high_f32", "wk", "h", OP_VCVT_EX_HI_F32>; +def VCVT_HIGH_F32_F64 : SOpInst<"vcvt_high_f32", "qfj", "d", OP_VCVT_NA_HI_F32>; +def VCVT_HIGH_F64_F32 : SOpInst<"vcvt_high_f64", "wj", "f", OP_VCVT_EX_HI_F64>; + +def VCVTX_F32_F64 : SInst<"vcvtx_f32", "fj", "d">; +def VCVTX_HIGH_F32_F64 : SOpInst<"vcvtx_high_f32", "qfj", "d", OP_VCVTX_HI>; + +//////////////////////////////////////////////////////////////////////////////// +// Comparison +def FCAGE : IInst<"vcage", "udd", "dQd">; +def FCAGT : IInst<"vcagt", "udd", "dQd">; +def FCALE : IInst<"vcale", "udd", "dQd">; +def FCALT : IInst<"vcalt", "udd", "dQd">; +def CMTST : WInst<"vtst", "udd", "lUlPlQlQUlQPl">; +def CFMEQ : SOpInst<"vceq", "udd", "lUldQdQlQUlPlQPl", OP_EQ>; +def CFMGE : SOpInst<"vcge", "udd", "lUldQdQlQUl", OP_GE>; +def CFMLE : SOpInst<"vcle", "udd", "lUldQdQlQUl", OP_LE>; +def CFMGT : SOpInst<"vcgt", "udd", "lUldQdQlQUl", OP_GT>; +def CFMLT : SOpInst<"vclt", "udd", "lUldQdQlQUl", OP_LT>; + +def CMEQ : SInst<"vceqz", "ud", + "csilfUcUsUiUlPcPsPlQcQsQiQlQfQUcQUsQUiQUlQPcQPsdQdQPl">; +def CMGE : SInst<"vcgez", "ud", "csilfdQcQsQiQlQfQd">; +def CMLE : SInst<"vclez", "ud", "csilfdQcQsQiQlQfQd">; +def CMGT : SInst<"vcgtz", "ud", "csilfdQcQsQiQlQfQd">; +def CMLT : SInst<"vcltz", "ud", "csilfdQcQsQiQlQfQd">; + +//////////////////////////////////////////////////////////////////////////////// +// Max/Min Integer +def MAX : SInst<"vmax", "ddd", "dQd">; +def MIN : SInst<"vmin", "ddd", "dQd">; + +//////////////////////////////////////////////////////////////////////////////// +// Pairwise Max/Min +def MAXP : SInst<"vpmax", "ddd", "QcQsQiQUcQUsQUiQfQd">; +def MINP : SInst<"vpmin", "ddd", "QcQsQiQUcQUsQUiQfQd">; + +//////////////////////////////////////////////////////////////////////////////// +// Pairwise MaxNum/MinNum Floating Point +def FMAXNMP : SInst<"vpmaxnm", "ddd", "fQfQd">; +def FMINNMP : SInst<"vpminnm", "ddd", "fQfQd">; + +//////////////////////////////////////////////////////////////////////////////// +// Pairwise Addition +def ADDP : IInst<"vpadd", "ddd", "QcQsQiQlQUcQUsQUiQUlQfQd">; + +//////////////////////////////////////////////////////////////////////////////// +// Shifts by constant +let isShift = 1 in { +// Left shift long high +def SHLL_HIGH_N : SOpInst<"vshll_high_n", "ndi", "HcHsHiHUcHUsHUi", + OP_LONG_HI>; + +//////////////////////////////////////////////////////////////////////////////// +def SRI_N : WInst<"vsri_n", "dddi", "PlQPl">; +def SLI_N : WInst<"vsli_n", "dddi", "PlQPl">; + +// Right shift narrow high +def SHRN_HIGH_N : IOpInst<"vshrn_high_n", "hmdi", + "HsHiHlHUsHUiHUl", OP_NARROW_HI>; +def QSHRUN_HIGH_N : SOpInst<"vqshrun_high_n", "hmdi", + "HsHiHl", OP_NARROW_HI>; +def RSHRN_HIGH_N : IOpInst<"vrshrn_high_n", "hmdi", + "HsHiHlHUsHUiHUl", OP_NARROW_HI>; +def QRSHRUN_HIGH_N : SOpInst<"vqrshrun_high_n", "hmdi", + "HsHiHl", OP_NARROW_HI>; +def QSHRN_HIGH_N : SOpInst<"vqshrn_high_n", "hmdi", + "HsHiHlHUsHUiHUl", OP_NARROW_HI>; +def QRSHRN_HIGH_N : SOpInst<"vqrshrn_high_n", "hmdi", + "HsHiHlHUsHUiHUl", OP_NARROW_HI>; +} + +//////////////////////////////////////////////////////////////////////////////// +// Converting vectors +def VMOVL_HIGH : SOpInst<"vmovl_high", "nd", "HcHsHiHUcHUsHUi", OP_MOVL_HI>; + +let isVCVT_N = 1 in { +def CVTF_N_F64 : SInst<"vcvt_n_f64", "Fdi", "lUlQlQUl">; +def FCVTZS_N_S64 : SInst<"vcvt_n_s64", "xdi", "dQd">; +def FCVTZS_N_U64 : SInst<"vcvt_n_u64", "udi", "dQd">; +} + +//////////////////////////////////////////////////////////////////////////////// +// 3VDiff class using high 64-bit in operands +def VADDL_HIGH : SOpInst<"vaddl_high", "wkk", "csiUcUsUi", OP_ADDLHi>; +def VADDW_HIGH : SOpInst<"vaddw_high", "wwk", "csiUcUsUi", OP_ADDWHi>; +def VSUBL_HIGH : SOpInst<"vsubl_high", "wkk", "csiUcUsUi", OP_SUBLHi>; +def VSUBW_HIGH : SOpInst<"vsubw_high", "wwk", "csiUcUsUi", OP_SUBWHi>; + +def VABDL_HIGH : SOpInst<"vabdl_high", "wkk", "csiUcUsUi", OP_ABDLHi>; +def VABAL_HIGH : SOpInst<"vabal_high", "wwkk", "csiUcUsUi", OP_ABALHi>; + +def VMULL_HIGH : SOpInst<"vmull_high", "wkk", "csiUcUsUiPc", OP_MULLHi>; +def VMULL_HIGH_N : SOpInst<"vmull_high_n", "wks", "siUsUi", OP_MULLHi_N>; +def VMLAL_HIGH : SOpInst<"vmlal_high", "wwkk", "csiUcUsUi", OP_MLALHi>; +def VMLAL_HIGH_N : SOpInst<"vmlal_high_n", "wwks", "siUsUi", OP_MLALHi_N>; +def VMLSL_HIGH : SOpInst<"vmlsl_high", "wwkk", "csiUcUsUi", OP_MLSLHi>; +def VMLSL_HIGH_N : SOpInst<"vmlsl_high_n", "wwks", "siUsUi", OP_MLSLHi_N>; + +def VADDHN_HIGH : SOpInst<"vaddhn_high", "qhkk", "silUsUiUl", OP_ADDHNHi>; +def VRADDHN_HIGH : SOpInst<"vraddhn_high", "qhkk", "silUsUiUl", OP_RADDHNHi>; +def VSUBHN_HIGH : SOpInst<"vsubhn_high", "qhkk", "silUsUiUl", OP_SUBHNHi>; +def VRSUBHN_HIGH : SOpInst<"vrsubhn_high", "qhkk", "silUsUiUl", OP_RSUBHNHi>; + +def VQDMULL_HIGH : SOpInst<"vqdmull_high", "wkk", "si", OP_QDMULLHi>; +def VQDMULL_HIGH_N : SOpInst<"vqdmull_high_n", "wks", "si", OP_QDMULLHi_N>; +def VQDMLAL_HIGH : SOpInst<"vqdmlal_high", "wwkk", "si", OP_QDMLALHi>; +def VQDMLAL_HIGH_N : SOpInst<"vqdmlal_high_n", "wwks", "si", OP_QDMLALHi_N>; +def VQDMLSL_HIGH : SOpInst<"vqdmlsl_high", "wwkk", "si", OP_QDMLSLHi>; +def VQDMLSL_HIGH_N : SOpInst<"vqdmlsl_high_n", "wwks", "si", OP_QDMLSLHi_N>; +def VMULL_P64 : SInst<"vmull", "rss", "Pl">; +def VMULL_HIGH_P64 : SOpInst<"vmull_high", "rdd", "HPl", OP_MULLHi_P64>; + + +//////////////////////////////////////////////////////////////////////////////// +// Extract or insert element from vector +def GET_LANE : IInst<"vget_lane", "sdi", "dQdPlQPl">; +def SET_LANE : IInst<"vset_lane", "dsdi", "dQdPlQPl">; +def COPY_LANE : IOpInst<"vcopy_lane", "ddidi", + "csilUcUsUiUlPcPsPlfd", OP_COPY_LN>; +def COPYQ_LANE : IOpInst<"vcopy_lane", "ddigi", + "QcQsQiQlQUcQUsQUiQUlQPcQPsQfQdQPl", OP_COPY_LN>; +def COPY_LANEQ : IOpInst<"vcopy_laneq", "ddiki", + "csilPcPsPlUcUsUiUlfd", OP_COPY_LN>; +def COPYQ_LANEQ : IOpInst<"vcopy_laneq", "ddidi", + "QcQsQiQlQUcQUsQUiQUlQPcQPsQfQdQPl", OP_COPY_LN>; + +//////////////////////////////////////////////////////////////////////////////// +// Set all lanes to same value +def VDUP_LANE1: WOpInst<"vdup_lane", "dgi", "hdQhQdPlQPl", OP_DUP_LN>; +def VDUP_LANE2: WOpInst<"vdup_laneq", "dji", + "csilUcUsUiUlPcPshfdQcQsQiQlQPcQPsQUcQUsQUiQUlQhQfQdPlQPl", + OP_DUP_LN>; +def DUP_N : WOpInst<"vdup_n", "ds", "dQdPlQPl", OP_DUP>; +def MOV_N : WOpInst<"vmov_n", "ds", "dQdPlQPl", OP_DUP>; + +//////////////////////////////////////////////////////////////////////////////// +def COMBINE : NoTestOpInst<"vcombine", "kdd", "dPl", OP_CONC>; + +//////////////////////////////////////////////////////////////////////////////// +//Initialize a vector from bit pattern +def CREATE : NoTestOpInst<"vcreate", "dl", "dPl", OP_CAST> { + let BigEndianSafe = 1; +} + +//////////////////////////////////////////////////////////////////////////////// + +def VMLA_LANEQ : IOpInst<"vmla_laneq", "dddji", + "siUsUifQsQiQUsQUiQf", OP_MLA_LN>; +def VMLS_LANEQ : IOpInst<"vmls_laneq", "dddji", + "siUsUifQsQiQUsQUiQf", OP_MLS_LN>; + +def VFMA_LANE : IInst<"vfma_lane", "dddgi", "fdQfQd">; +def VFMA_LANEQ : IInst<"vfma_laneq", "dddji", "fdQfQd"> { + let isLaneQ = 1; +} +def VFMS_LANE : IOpInst<"vfms_lane", "dddgi", "fdQfQd", OP_FMS_LN>; +def VFMS_LANEQ : IOpInst<"vfms_laneq", "dddji", "fdQfQd", OP_FMS_LNQ>; + +def VMLAL_LANEQ : SOpInst<"vmlal_laneq", "wwdki", "siUsUi", OP_MLAL_LN>; +def VMLAL_HIGH_LANE : SOpInst<"vmlal_high_lane", "wwkdi", "siUsUi", + OP_MLALHi_LN>; +def VMLAL_HIGH_LANEQ : SOpInst<"vmlal_high_laneq", "wwkki", "siUsUi", + OP_MLALHi_LN>; +def VMLSL_LANEQ : SOpInst<"vmlsl_laneq", "wwdki", "siUsUi", OP_MLSL_LN>; +def VMLSL_HIGH_LANE : SOpInst<"vmlsl_high_lane", "wwkdi", "siUsUi", + OP_MLSLHi_LN>; +def VMLSL_HIGH_LANEQ : SOpInst<"vmlsl_high_laneq", "wwkki", "siUsUi", + OP_MLSLHi_LN>; + +def VQDMLAL_LANEQ : SOpInst<"vqdmlal_laneq", "wwdki", "si", OP_QDMLAL_LN>; +def VQDMLAL_HIGH_LANE : SOpInst<"vqdmlal_high_lane", "wwkdi", "si", + OP_QDMLALHi_LN>; +def VQDMLAL_HIGH_LANEQ : SOpInst<"vqdmlal_high_laneq", "wwkki", "si", + OP_QDMLALHi_LN>; +def VQDMLSL_LANEQ : SOpInst<"vqdmlsl_laneq", "wwdki", "si", OP_QDMLSL_LN>; +def VQDMLSL_HIGH_LANE : SOpInst<"vqdmlsl_high_lane", "wwkdi", "si", + OP_QDMLSLHi_LN>; +def VQDMLSL_HIGH_LANEQ : SOpInst<"vqdmlsl_high_laneq", "wwkki", "si", + OP_QDMLSLHi_LN>; + +// Newly add double parameter for vmul_lane in aarch64 +// Note: d type is handled by SCALAR_VMUL_LANE +def VMUL_LANE_A64 : IOpInst<"vmul_lane", "ddgi", "Qd", OP_MUL_LN>; + +// Note: d type is handled by SCALAR_VMUL_LANEQ +def VMUL_LANEQ : IOpInst<"vmul_laneq", "ddji", + "sifUsUiQsQiQUsQUiQfQd", OP_MUL_LN>; +def VMULL_LANEQ : SOpInst<"vmull_laneq", "wdki", "siUsUi", OP_MULL_LN>; +def VMULL_HIGH_LANE : SOpInst<"vmull_high_lane", "wkdi", "siUsUi", + OP_MULLHi_LN>; +def VMULL_HIGH_LANEQ : SOpInst<"vmull_high_laneq", "wkki", "siUsUi", + OP_MULLHi_LN>; + +def VQDMULL_LANEQ : SOpInst<"vqdmull_laneq", "wdki", "si", OP_QDMULL_LN>; +def VQDMULL_HIGH_LANE : SOpInst<"vqdmull_high_lane", "wkdi", "si", + OP_QDMULLHi_LN>; +def VQDMULL_HIGH_LANEQ : SOpInst<"vqdmull_high_laneq", "wkki", "si", + OP_QDMULLHi_LN>; + +def VQDMULH_LANEQ : SOpInst<"vqdmulh_laneq", "ddji", "siQsQi", OP_QDMULH_LN>; +def VQRDMULH_LANEQ : SOpInst<"vqrdmulh_laneq", "ddji", "siQsQi", OP_QRDMULH_LN>; + +let ArchGuard = "defined(__ARM_FEATURE_QRDMX) && defined(__aarch64__)" in { +def VQRDMLAH_LANEQ : SOpInst<"vqrdmlah_laneq", "dddji", "siQsQi", OP_QRDMLAH_LN>; +def VQRDMLSH_LANEQ : SOpInst<"vqrdmlsh_laneq", "dddji", "siQsQi", OP_QRDMLSH_LN>; +} + +// Note: d type implemented by SCALAR_VMULX_LANE +def VMULX_LANE : IOpInst<"vmulx_lane", "ddgi", "fQfQd", OP_MULX_LN>; +// Note: d type is implemented by SCALAR_VMULX_LANEQ +def VMULX_LANEQ : IOpInst<"vmulx_laneq", "ddji", "fQfQd", OP_MULX_LN>; + +//////////////////////////////////////////////////////////////////////////////// +// Across vectors class +def VADDLV : SInst<"vaddlv", "rd", "csiUcUsUiQcQsQiQUcQUsQUi">; +def VMAXV : SInst<"vmaxv", "sd", "csifUcUsUiQcQsQiQUcQUsQUiQfQd">; +def VMINV : SInst<"vminv", "sd", "csifUcUsUiQcQsQiQUcQUsQUiQfQd">; +def VADDV : SInst<"vaddv", "sd", "csifUcUsUiQcQsQiQUcQUsQUiQfQdQlQUl">; +def FMAXNMV : SInst<"vmaxnmv", "sd", "fQfQd">; +def FMINNMV : SInst<"vminnmv", "sd", "fQfQd">; + +//////////////////////////////////////////////////////////////////////////////// +// Newly added Vector Extract for f64 +def VEXT_A64 : WInst<"vext", "dddi", "dQdPlQPl">; + +//////////////////////////////////////////////////////////////////////////////// +// Crypto +let ArchGuard = "__ARM_FEATURE_CRYPTO" in { +def AESE : SInst<"vaese", "ddd", "QUc">; +def AESD : SInst<"vaesd", "ddd", "QUc">; +def AESMC : SInst<"vaesmc", "dd", "QUc">; +def AESIMC : SInst<"vaesimc", "dd", "QUc">; + +def SHA1H : SInst<"vsha1h", "ss", "Ui">; +def SHA1SU1 : SInst<"vsha1su1", "ddd", "QUi">; +def SHA256SU0 : SInst<"vsha256su0", "ddd", "QUi">; + +def SHA1C : SInst<"vsha1c", "ddsd", "QUi">; +def SHA1P : SInst<"vsha1p", "ddsd", "QUi">; +def SHA1M : SInst<"vsha1m", "ddsd", "QUi">; +def SHA1SU0 : SInst<"vsha1su0", "dddd", "QUi">; +def SHA256H : SInst<"vsha256h", "dddd", "QUi">; +def SHA256H2 : SInst<"vsha256h2", "dddd", "QUi">; +def SHA256SU1 : SInst<"vsha256su1", "dddd", "QUi">; +} + +//////////////////////////////////////////////////////////////////////////////// +// Float -> Int conversions with explicit rounding mode + +let ArchGuard = "__ARM_ARCH >= 8" in { +def FCVTNS_S32 : SInst<"vcvtn_s32", "xd", "fQf">; +def FCVTNU_S32 : SInst<"vcvtn_u32", "ud", "fQf">; +def FCVTPS_S32 : SInst<"vcvtp_s32", "xd", "fQf">; +def FCVTPU_S32 : SInst<"vcvtp_u32", "ud", "fQf">; +def FCVTMS_S32 : SInst<"vcvtm_s32", "xd", "fQf">; +def FCVTMU_S32 : SInst<"vcvtm_u32", "ud", "fQf">; +def FCVTAS_S32 : SInst<"vcvta_s32", "xd", "fQf">; +def FCVTAU_S32 : SInst<"vcvta_u32", "ud", "fQf">; +} + +let ArchGuard = "__ARM_ARCH >= 8 && defined(__aarch64__)" in { +def FCVTNS_S64 : SInst<"vcvtn_s64", "xd", "dQd">; +def FCVTNU_S64 : SInst<"vcvtn_u64", "ud", "dQd">; +def FCVTPS_S64 : SInst<"vcvtp_s64", "xd", "dQd">; +def FCVTPU_S64 : SInst<"vcvtp_u64", "ud", "dQd">; +def FCVTMS_S64 : SInst<"vcvtm_s64", "xd", "dQd">; +def FCVTMU_S64 : SInst<"vcvtm_u64", "ud", "dQd">; +def FCVTAS_S64 : SInst<"vcvta_s64", "xd", "dQd">; +def FCVTAU_S64 : SInst<"vcvta_u64", "ud", "dQd">; +} + +//////////////////////////////////////////////////////////////////////////////// +// Round to Integral + +let ArchGuard = "__ARM_ARCH >= 8 && defined(__ARM_FEATURE_DIRECTED_ROUNDING)" in { +def FRINTN_S32 : SInst<"vrndn", "dd", "fQf">; +def FRINTA_S32 : SInst<"vrnda", "dd", "fQf">; +def FRINTP_S32 : SInst<"vrndp", "dd", "fQf">; +def FRINTM_S32 : SInst<"vrndm", "dd", "fQf">; +def FRINTX_S32 : SInst<"vrndx", "dd", "fQf">; +def FRINTZ_S32 : SInst<"vrnd", "dd", "fQf">; +} + +let ArchGuard = "__ARM_ARCH >= 8 && defined(__aarch64__) && defined(__ARM_FEATURE_DIRECTED_ROUNDING)" in { +def FRINTN_S64 : SInst<"vrndn", "dd", "dQd">; +def FRINTA_S64 : SInst<"vrnda", "dd", "dQd">; +def FRINTP_S64 : SInst<"vrndp", "dd", "dQd">; +def FRINTM_S64 : SInst<"vrndm", "dd", "dQd">; +def FRINTX_S64 : SInst<"vrndx", "dd", "dQd">; +def FRINTZ_S64 : SInst<"vrnd", "dd", "dQd">; +def FRINTI_S64 : SInst<"vrndi", "dd", "fdQfQd">; +} + +//////////////////////////////////////////////////////////////////////////////// +// MaxNum/MinNum Floating Point + +let ArchGuard = "__ARM_ARCH >= 8 && defined(__ARM_FEATURE_NUMERIC_MAXMIN)" in { +def FMAXNM_S32 : SInst<"vmaxnm", "ddd", "fQf">; +def FMINNM_S32 : SInst<"vminnm", "ddd", "fQf">; +} + +let ArchGuard = "__ARM_ARCH >= 8 && defined(__aarch64__) && defined(__ARM_FEATURE_NUMERIC_MAXMIN)" in { +def FMAXNM_S64 : SInst<"vmaxnm", "ddd", "dQd">; +def FMINNM_S64 : SInst<"vminnm", "ddd", "dQd">; +} + +//////////////////////////////////////////////////////////////////////////////// +// Permutation +def VTRN1 : SOpInst<"vtrn1", "ddd", + "csiUcUsUifPcPsQcQsQiQlQUcQUsQUiQUlQfQdQPcQPsQPl", OP_TRN1>; +def VZIP1 : SOpInst<"vzip1", "ddd", + "csiUcUsUifPcPsQcQsQiQlQUcQUsQUiQUlQfQdQPcQPsQPl", OP_ZIP1>; +def VUZP1 : SOpInst<"vuzp1", "ddd", + "csiUcUsUifPcPsQcQsQiQlQUcQUsQUiQUlQfQdQPcQPsQPl", OP_UZP1>; +def VTRN2 : SOpInst<"vtrn2", "ddd", + "csiUcUsUifPcPsQcQsQiQlQUcQUsQUiQUlQfQdQPcQPsQPl", OP_TRN2>; +def VZIP2 : SOpInst<"vzip2", "ddd", + "csiUcUsUifPcPsQcQsQiQlQUcQUsQUiQUlQfQdQPcQPsQPl", OP_ZIP2>; +def VUZP2 : SOpInst<"vuzp2", "ddd", + "csiUcUsUifPcPsQcQsQiQlQUcQUsQUiQUlQfQdQPcQPsQPl", OP_UZP2>; + +//////////////////////////////////////////////////////////////////////////////// +// Table lookup +let InstName = "vtbl" in { +def VQTBL1_A64 : WInst<"vqtbl1", "djt", "UccPcQUcQcQPc">; +def VQTBL2_A64 : WInst<"vqtbl2", "dBt", "UccPcQUcQcQPc">; +def VQTBL3_A64 : WInst<"vqtbl3", "dCt", "UccPcQUcQcQPc">; +def VQTBL4_A64 : WInst<"vqtbl4", "dDt", "UccPcQUcQcQPc">; +} +let InstName = "vtbx" in { +def VQTBX1_A64 : WInst<"vqtbx1", "ddjt", "UccPcQUcQcQPc">; +def VQTBX2_A64 : WInst<"vqtbx2", "ddBt", "UccPcQUcQcQPc">; +def VQTBX3_A64 : WInst<"vqtbx3", "ddCt", "UccPcQUcQcQPc">; +def VQTBX4_A64 : WInst<"vqtbx4", "ddDt", "UccPcQUcQcQPc">; +} + +//////////////////////////////////////////////////////////////////////////////// +// Vector reinterpret cast operations + +// NeonEmitter implicitly takes the cartesian product of the type string with +// itself during generation so, unlike all other intrinsics, this one should +// include *all* types, not just additional ones. +def VVREINTERPRET + : NoTestOpInst<"vreinterpret", "dd", + "csilUcUsUiUlhfdPcPsPlQcQsQiQlQUcQUsQUiQUlQhQfQdQPcQPsQPlQPk", OP_REINT> { + let CartesianProductOfTypes = 1; + let BigEndianSafe = 1; + let ArchGuard = "__ARM_ARCH >= 8 && defined(__aarch64__)"; +} + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Intrinsics +// Scalar Arithmetic + +// Scalar Addition +def SCALAR_ADD : SInst<"vadd", "sss", "SlSUl">; +// Scalar Saturating Add +def SCALAR_QADD : SInst<"vqadd", "sss", "ScSsSiSlSUcSUsSUiSUl">; + +// Scalar Subtraction +def SCALAR_SUB : SInst<"vsub", "sss", "SlSUl">; +// Scalar Saturating Sub +def SCALAR_QSUB : SInst<"vqsub", "sss", "ScSsSiSlSUcSUsSUiSUl">; + +let InstName = "vmov" in { +def VGET_HIGH_A64 : NoTestOpInst<"vget_high", "dk", "dPl", OP_HI>; +def VGET_LOW_A64 : NoTestOpInst<"vget_low", "dk", "dPl", OP_LO>; +} + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Shift +// Scalar Shift Left +def SCALAR_SHL: SInst<"vshl", "sss", "SlSUl">; +// Scalar Saturating Shift Left +def SCALAR_QSHL: SInst<"vqshl", "sss", "ScSsSiSlSUcSUsSUiSUl">; +// Scalar Saturating Rounding Shift Left +def SCALAR_QRSHL: SInst<"vqrshl", "sss", "ScSsSiSlSUcSUsSUiSUl">; +// Scalar Shift Rouding Left +def SCALAR_RSHL: SInst<"vrshl", "sss", "SlSUl">; + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Shift (Immediate) +let isScalarShift = 1 in { +// Signed/Unsigned Shift Right (Immediate) +def SCALAR_SSHR_N: SInst<"vshr_n", "ssi", "SlSUl">; +// Signed/Unsigned Rounding Shift Right (Immediate) +def SCALAR_SRSHR_N: SInst<"vrshr_n", "ssi", "SlSUl">; + +// Signed/Unsigned Shift Right and Accumulate (Immediate) +def SCALAR_SSRA_N: SInst<"vsra_n", "sssi", "SlSUl">; +// Signed/Unsigned Rounding Shift Right and Accumulate (Immediate) +def SCALAR_SRSRA_N: SInst<"vrsra_n", "sssi", "SlSUl">; + +// Shift Left (Immediate) +def SCALAR_SHL_N: SInst<"vshl_n", "ssi", "SlSUl">; +// Signed/Unsigned Saturating Shift Left (Immediate) +def SCALAR_SQSHL_N: SInst<"vqshl_n", "ssi", "ScSsSiSlSUcSUsSUiSUl">; +// Signed Saturating Shift Left Unsigned (Immediate) +def SCALAR_SQSHLU_N: SInst<"vqshlu_n", "ssi", "ScSsSiSl">; + +// Shift Right And Insert (Immediate) +def SCALAR_SRI_N: SInst<"vsri_n", "sssi", "SlSUl">; +// Shift Left And Insert (Immediate) +def SCALAR_SLI_N: SInst<"vsli_n", "sssi", "SlSUl">; + +let isScalarNarrowShift = 1 in { + // Signed/Unsigned Saturating Shift Right Narrow (Immediate) + def SCALAR_SQSHRN_N: SInst<"vqshrn_n", "zsi", "SsSiSlSUsSUiSUl">; + // Signed/Unsigned Saturating Rounded Shift Right Narrow (Immediate) + def SCALAR_SQRSHRN_N: SInst<"vqrshrn_n", "zsi", "SsSiSlSUsSUiSUl">; + // Signed Saturating Shift Right Unsigned Narrow (Immediate) + def SCALAR_SQSHRUN_N: SInst<"vqshrun_n", "zsi", "SsSiSl">; + // Signed Saturating Rounded Shift Right Unsigned Narrow (Immediate) + def SCALAR_SQRSHRUN_N: SInst<"vqrshrun_n", "zsi", "SsSiSl">; +} + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Signed/Unsigned Fixed-point Convert To Floating-Point (Immediate) +def SCALAR_SCVTF_N_F32: SInst<"vcvt_n_f32", "ysi", "SiSUi">; +def SCALAR_SCVTF_N_F64: SInst<"vcvt_n_f64", "osi", "SlSUl">; + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Floating-point Convert To Signed/Unsigned Fixed-point (Immediate) +def SCALAR_FCVTZS_N_S32 : SInst<"vcvt_n_s32", "$si", "Sf">; +def SCALAR_FCVTZU_N_U32 : SInst<"vcvt_n_u32", "bsi", "Sf">; +def SCALAR_FCVTZS_N_S64 : SInst<"vcvt_n_s64", "$si", "Sd">; +def SCALAR_FCVTZU_N_U64 : SInst<"vcvt_n_u64", "bsi", "Sd">; +} + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Reduce Pairwise Addition (Scalar and Floating Point) +def SCALAR_ADDP : SInst<"vpadd", "sd", "SfSHlSHdSHUl">; + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Reduce Floating Point Pairwise Max/Min +def SCALAR_FMAXP : SInst<"vpmax", "sd", "SfSQd">; + +def SCALAR_FMINP : SInst<"vpmin", "sd", "SfSQd">; + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Reduce Floating Point Pairwise maxNum/minNum +def SCALAR_FMAXNMP : SInst<"vpmaxnm", "sd", "SfSQd">; +def SCALAR_FMINNMP : SInst<"vpminnm", "sd", "SfSQd">; + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Integer Saturating Doubling Multiply Half High +def SCALAR_SQDMULH : SInst<"vqdmulh", "sss", "SsSi">; + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Integer Saturating Rounding Doubling Multiply Half High +def SCALAR_SQRDMULH : SInst<"vqrdmulh", "sss", "SsSi">; + +let ArchGuard = "defined(__ARM_FEATURE_QRDMX) && defined(__aarch64__)" in { +//////////////////////////////////////////////////////////////////////////////// +// Signed Saturating Rounding Doubling Multiply Accumulate Returning High Half +def SCALAR_SQRDMLAH : SOpInst<"vqrdmlah", "ssss", "SsSi", OP_QRDMLAH>; + +//////////////////////////////////////////////////////////////////////////////// +// Signed Saturating Rounding Doubling Multiply Subtract Returning High Half +def SCALAR_SQRDMLSH : SOpInst<"vqrdmlsh", "ssss", "SsSi", OP_QRDMLSH>; +} + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Floating-point Multiply Extended +def SCALAR_FMULX : IInst<"vmulx", "sss", "SfSd">; + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Floating-point Reciprocal Step +def SCALAR_FRECPS : IInst<"vrecps", "sss", "SfSd">; + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Floating-point Reciprocal Square Root Step +def SCALAR_FRSQRTS : IInst<"vrsqrts", "sss", "SfSd">; + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Signed Integer Convert To Floating-point +def SCALAR_SCVTFS : SInst<"vcvt_f32", "ys", "Si">; +def SCALAR_SCVTFD : SInst<"vcvt_f64", "os", "Sl">; + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Unsigned Integer Convert To Floating-point +def SCALAR_UCVTFS : SInst<"vcvt_f32", "ys", "SUi">; +def SCALAR_UCVTFD : SInst<"vcvt_f64", "os", "SUl">; + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Floating-point Converts +def SCALAR_FCVTXN : IInst<"vcvtx_f32", "ys", "Sd">; +def SCALAR_FCVTNSS : SInst<"vcvtn_s32", "$s", "Sf">; +def SCALAR_FCVTNUS : SInst<"vcvtn_u32", "bs", "Sf">; +def SCALAR_FCVTNSD : SInst<"vcvtn_s64", "$s", "Sd">; +def SCALAR_FCVTNUD : SInst<"vcvtn_u64", "bs", "Sd">; +def SCALAR_FCVTMSS : SInst<"vcvtm_s32", "$s", "Sf">; +def SCALAR_FCVTMUS : SInst<"vcvtm_u32", "bs", "Sf">; +def SCALAR_FCVTMSD : SInst<"vcvtm_s64", "$s", "Sd">; +def SCALAR_FCVTMUD : SInst<"vcvtm_u64", "bs", "Sd">; +def SCALAR_FCVTASS : SInst<"vcvta_s32", "$s", "Sf">; +def SCALAR_FCVTAUS : SInst<"vcvta_u32", "bs", "Sf">; +def SCALAR_FCVTASD : SInst<"vcvta_s64", "$s", "Sd">; +def SCALAR_FCVTAUD : SInst<"vcvta_u64", "bs", "Sd">; +def SCALAR_FCVTPSS : SInst<"vcvtp_s32", "$s", "Sf">; +def SCALAR_FCVTPUS : SInst<"vcvtp_u32", "bs", "Sf">; +def SCALAR_FCVTPSD : SInst<"vcvtp_s64", "$s", "Sd">; +def SCALAR_FCVTPUD : SInst<"vcvtp_u64", "bs", "Sd">; +def SCALAR_FCVTZSS : SInst<"vcvt_s32", "$s", "Sf">; +def SCALAR_FCVTZUS : SInst<"vcvt_u32", "bs", "Sf">; +def SCALAR_FCVTZSD : SInst<"vcvt_s64", "$s", "Sd">; +def SCALAR_FCVTZUD : SInst<"vcvt_u64", "bs", "Sd">; + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Floating-point Reciprocal Estimate +def SCALAR_FRECPE : IInst<"vrecpe", "ss", "SfSd">; + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Floating-point Reciprocal Exponent +def SCALAR_FRECPX : IInst<"vrecpx", "ss", "SfSd">; + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Floating-point Reciprocal Square Root Estimate +def SCALAR_FRSQRTE : IInst<"vrsqrte", "ss", "SfSd">; + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Integer Comparison +def SCALAR_CMEQ : SInst<"vceq", "sss", "SlSUl">; +def SCALAR_CMEQZ : SInst<"vceqz", "ss", "SlSUl">; +def SCALAR_CMGE : SInst<"vcge", "sss", "Sl">; +def SCALAR_CMGEZ : SInst<"vcgez", "ss", "Sl">; +def SCALAR_CMHS : SInst<"vcge", "sss", "SUl">; +def SCALAR_CMLE : SInst<"vcle", "sss", "SlSUl">; +def SCALAR_CMLEZ : SInst<"vclez", "ss", "Sl">; +def SCALAR_CMLT : SInst<"vclt", "sss", "SlSUl">; +def SCALAR_CMLTZ : SInst<"vcltz", "ss", "Sl">; +def SCALAR_CMGT : SInst<"vcgt", "sss", "Sl">; +def SCALAR_CMGTZ : SInst<"vcgtz", "ss", "Sl">; +def SCALAR_CMHI : SInst<"vcgt", "sss", "SUl">; +def SCALAR_CMTST : SInst<"vtst", "sss", "SlSUl">; + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Floating-point Comparison +def SCALAR_FCMEQ : IInst<"vceq", "bss", "SfSd">; +def SCALAR_FCMEQZ : IInst<"vceqz", "bs", "SfSd">; +def SCALAR_FCMGE : IInst<"vcge", "bss", "SfSd">; +def SCALAR_FCMGEZ : IInst<"vcgez", "bs", "SfSd">; +def SCALAR_FCMGT : IInst<"vcgt", "bss", "SfSd">; +def SCALAR_FCMGTZ : IInst<"vcgtz", "bs", "SfSd">; +def SCALAR_FCMLE : IInst<"vcle", "bss", "SfSd">; +def SCALAR_FCMLEZ : IInst<"vclez", "bs", "SfSd">; +def SCALAR_FCMLT : IInst<"vclt", "bss", "SfSd">; +def SCALAR_FCMLTZ : IInst<"vcltz", "bs", "SfSd">; + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Floating-point Absolute Compare Mask Greater Than Or Equal +def SCALAR_FACGE : IInst<"vcage", "bss", "SfSd">; +def SCALAR_FACLE : IInst<"vcale", "bss", "SfSd">; + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Floating-point Absolute Compare Mask Greater Than +def SCALAR_FACGT : IInst<"vcagt", "bss", "SfSd">; +def SCALAR_FACLT : IInst<"vcalt", "bss", "SfSd">; + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Absolute Value +def SCALAR_ABS : SInst<"vabs", "ss", "Sl">; + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Absolute Difference +def SCALAR_ABD : IInst<"vabd", "sss", "SfSd">; + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Signed Saturating Absolute Value +def SCALAR_SQABS : SInst<"vqabs", "ss", "ScSsSiSl">; + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Negate +def SCALAR_NEG : SInst<"vneg", "ss", "Sl">; + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Signed Saturating Negate +def SCALAR_SQNEG : SInst<"vqneg", "ss", "ScSsSiSl">; + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Signed Saturating Accumulated of Unsigned Value +def SCALAR_SUQADD : SInst<"vuqadd", "sss", "ScSsSiSl">; + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Unsigned Saturating Accumulated of Signed Value +def SCALAR_USQADD : SInst<"vsqadd", "sss", "SUcSUsSUiSUl">; + +//////////////////////////////////////////////////////////////////////////////// +// Signed Saturating Doubling Multiply-Add Long +def SCALAR_SQDMLAL : SInst<"vqdmlal", "rrss", "SsSi">; + +//////////////////////////////////////////////////////////////////////////////// +// Signed Saturating Doubling Multiply-Subtract Long +def SCALAR_SQDMLSL : SInst<"vqdmlsl", "rrss", "SsSi">; + +//////////////////////////////////////////////////////////////////////////////// +// Signed Saturating Doubling Multiply Long +def SCALAR_SQDMULL : SInst<"vqdmull", "rss", "SsSi">; + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Signed Saturating Extract Unsigned Narrow +def SCALAR_SQXTUN : SInst<"vqmovun", "zs", "SsSiSl">; + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Signed Saturating Extract Narrow +def SCALAR_SQXTN : SInst<"vqmovn", "zs", "SsSiSl">; + +//////////////////////////////////////////////////////////////////////////////// +// Scalar Unsigned Saturating Extract Narrow +def SCALAR_UQXTN : SInst<"vqmovn", "zs", "SUsSUiSUl">; + +// Scalar Floating Point multiply (scalar, by element) +def SCALAR_FMUL_LANE : IOpInst<"vmul_lane", "ssdi", "SfSd", OP_SCALAR_MUL_LN>; +def SCALAR_FMUL_LANEQ : IOpInst<"vmul_laneq", "ssji", "SfSd", OP_SCALAR_MUL_LN>; + +// Scalar Floating Point multiply extended (scalar, by element) +def SCALAR_FMULX_LANE : IOpInst<"vmulx_lane", "ssdi", "SfSd", OP_SCALAR_MULX_LN>; +def SCALAR_FMULX_LANEQ : IOpInst<"vmulx_laneq", "ssji", "SfSd", OP_SCALAR_MULX_LN>; + +def SCALAR_VMUL_N : IInst<"vmul_n", "dds", "d">; + +// VMUL_LANE_A64 d type implemented using scalar mul lane +def SCALAR_VMUL_LANE : IInst<"vmul_lane", "ddgi", "d">; + +// VMUL_LANEQ d type implemented using scalar mul lane +def SCALAR_VMUL_LANEQ : IInst<"vmul_laneq", "ddji", "d"> { + let isLaneQ = 1; +} + +// VMULX_LANE d type implemented using scalar vmulx_lane +def SCALAR_VMULX_LANE : IOpInst<"vmulx_lane", "ddgi", "d", OP_SCALAR_VMULX_LN>; + +// VMULX_LANEQ d type implemented using scalar vmulx_laneq +def SCALAR_VMULX_LANEQ : IOpInst<"vmulx_laneq", "ddji", "d", OP_SCALAR_VMULX_LNQ>; + +// Scalar Floating Point fused multiply-add (scalar, by element) +def SCALAR_FMLA_LANE : IInst<"vfma_lane", "sssdi", "SfSd">; +def SCALAR_FMLA_LANEQ : IInst<"vfma_laneq", "sssji", "SfSd">; + +// Scalar Floating Point fused multiply-subtract (scalar, by element) +def SCALAR_FMLS_LANE : IOpInst<"vfms_lane", "sssdi", "SfSd", OP_FMS_LN>; +def SCALAR_FMLS_LANEQ : IOpInst<"vfms_laneq", "sssji", "SfSd", OP_FMS_LNQ>; + +// Signed Saturating Doubling Multiply Long (scalar by element) +def SCALAR_SQDMULL_LANE : SOpInst<"vqdmull_lane", "rsdi", "SsSi", OP_SCALAR_QDMULL_LN>; +def SCALAR_SQDMULL_LANEQ : SOpInst<"vqdmull_laneq", "rsji", "SsSi", OP_SCALAR_QDMULL_LN>; + +// Signed Saturating Doubling Multiply-Add Long (scalar by element) +def SCALAR_SQDMLAL_LANE : SInst<"vqdmlal_lane", "rrsdi", "SsSi">; +def SCALAR_SQDMLAL_LANEQ : SInst<"vqdmlal_laneq", "rrsji", "SsSi">; + +// Signed Saturating Doubling Multiply-Subtract Long (scalar by element) +def SCALAR_SQDMLS_LANE : SInst<"vqdmlsl_lane", "rrsdi", "SsSi">; +def SCALAR_SQDMLS_LANEQ : SInst<"vqdmlsl_laneq", "rrsji", "SsSi">; + +// Scalar Integer Saturating Doubling Multiply Half High (scalar by element) +def SCALAR_SQDMULH_LANE : SOpInst<"vqdmulh_lane", "ssdi", "SsSi", OP_SCALAR_QDMULH_LN>; +def SCALAR_SQDMULH_LANEQ : SOpInst<"vqdmulh_laneq", "ssji", "SsSi", OP_SCALAR_QDMULH_LN>; + +// Scalar Integer Saturating Rounding Doubling Multiply Half High +def SCALAR_SQRDMULH_LANE : SOpInst<"vqrdmulh_lane", "ssdi", "SsSi", OP_SCALAR_QRDMULH_LN>; +def SCALAR_SQRDMULH_LANEQ : SOpInst<"vqrdmulh_laneq", "ssji", "SsSi", OP_SCALAR_QRDMULH_LN>; + +let ArchGuard = "defined(__ARM_FEATURE_QRDMX) && defined(__aarch64__)" in { +// Signed Saturating Rounding Doubling Multiply Accumulate Returning High Half +def SCALAR_SQRDMLAH_LANE : SOpInst<"vqrdmlah_lane", "sssdi", "SsSi", OP_SCALAR_QRDMLAH_LN>; +def SCALAR_SQRDMLAH_LANEQ : SOpInst<"vqrdmlah_laneq", "sssji", "SsSi", OP_SCALAR_QRDMLAH_LN>; + +// Signed Saturating Rounding Doubling Multiply Subtract Returning High Half +def SCALAR_SQRDMLSH_LANE : SOpInst<"vqrdmlsh_lane", "sssdi", "SsSi", OP_SCALAR_QRDMLSH_LN>; +def SCALAR_SQRDMLSH_LANEQ : SOpInst<"vqrdmlsh_laneq", "sssji", "SsSi", OP_SCALAR_QRDMLSH_LN>; +} + +def SCALAR_VDUP_LANE : IInst<"vdup_lane", "sdi", "ScSsSiSlSfSdSUcSUsSUiSUlSPcSPs">; +def SCALAR_VDUP_LANEQ : IInst<"vdup_laneq", "sji", "ScSsSiSlSfSdSUcSUsSUiSUlSPcSPs">; +} diff --git a/contrib/llvm/tools/clang/include/clang/CodeGen/BackendUtil.h b/contrib/llvm/tools/clang/include/clang/CodeGen/BackendUtil.h new file mode 100644 index 0000000..ba5dc39 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/CodeGen/BackendUtil.h @@ -0,0 +1,44 @@ +//===--- BackendUtil.h - LLVM Backend Utilities -----------------*- 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_CODEGEN_BACKENDUTIL_H +#define LLVM_CLANG_CODEGEN_BACKENDUTIL_H + +#include "clang/Basic/LLVM.h" +#include "llvm/IR/FunctionInfo.h" +#include <memory> + +namespace llvm { + class Module; +} + +namespace clang { + class DiagnosticsEngine; + class CodeGenOptions; + class TargetOptions; + class LangOptions; + + enum BackendAction { + Backend_EmitAssembly, ///< Emit native assembly files + Backend_EmitBC, ///< Emit LLVM bitcode files + Backend_EmitLL, ///< Emit human-readable LLVM assembly + Backend_EmitNothing, ///< Don't emit anything (benchmarking mode) + Backend_EmitMCNull, ///< Run CodeGen, but don't emit anything + Backend_EmitObj ///< Emit native object files + }; + + void + EmitBackendOutput(DiagnosticsEngine &Diags, const CodeGenOptions &CGOpts, + const TargetOptions &TOpts, const LangOptions &LOpts, + StringRef TDesc, llvm::Module *M, BackendAction Action, + raw_pwrite_stream *OS, + std::unique_ptr<llvm::FunctionInfoIndex> Index = nullptr); +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/CodeGen/CGFunctionInfo.h b/contrib/llvm/tools/clang/include/clang/CodeGen/CGFunctionInfo.h new file mode 100644 index 0000000..bb6ceb4 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/CodeGen/CGFunctionInfo.h @@ -0,0 +1,538 @@ +//==-- CGFunctionInfo.h - Representation of function argument/return types -==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Defines CGFunctionInfo and associated types used in representing the +// LLVM source types and ABI-coerced types for function arguments and +// return values. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CODEGEN_CGFUNCTIONINFO_H +#define LLVM_CLANG_CODEGEN_CGFUNCTIONINFO_H + +#include "clang/AST/CanonicalType.h" +#include "clang/AST/CharUnits.h" +#include "clang/AST/Type.h" +#include "llvm/ADT/FoldingSet.h" +#include <cassert> + +namespace llvm { + class Type; + class StructType; +} + +namespace clang { +class Decl; + +namespace CodeGen { + +/// ABIArgInfo - Helper class to encapsulate information about how a +/// specific C type should be passed to or returned from a function. +class ABIArgInfo { +public: + enum Kind : uint8_t { + /// Direct - Pass the argument directly using the normal converted LLVM + /// type, or by coercing to another specified type stored in + /// 'CoerceToType'). If an offset is specified (in UIntData), then the + /// argument passed is offset by some number of bytes in the memory + /// representation. A dummy argument is emitted before the real argument + /// if the specified type stored in "PaddingType" is not zero. + Direct, + + /// Extend - Valid only for integer argument types. Same as 'direct' + /// but also emit a zero/sign extension attribute. + Extend, + + /// Indirect - Pass the argument indirectly via a hidden pointer + /// with the specified alignment (0 indicates default alignment). + Indirect, + + /// Ignore - Ignore the argument (treat as void). Useful for void and + /// empty structs. + Ignore, + + /// Expand - Only valid for aggregate argument types. The structure should + /// be expanded into consecutive arguments for its constituent fields. + /// Currently expand is only allowed on structures whose fields + /// are all scalar types or are themselves expandable types. + Expand, + + /// InAlloca - Pass the argument directly using the LLVM inalloca attribute. + /// This is similar to indirect with byval, except it only applies to + /// arguments stored in memory and forbids any implicit copies. When + /// applied to a return type, it means the value is returned indirectly via + /// an implicit sret parameter stored in the argument struct. + InAlloca, + KindFirst = Direct, + KindLast = InAlloca + }; + +private: + llvm::Type *TypeData; // isDirect() || isExtend() + llvm::Type *PaddingType; + union { + unsigned DirectOffset; // isDirect() || isExtend() + unsigned IndirectAlign; // isIndirect() + unsigned AllocaFieldIndex; // isInAlloca() + }; + Kind TheKind; + bool PaddingInReg : 1; + bool InAllocaSRet : 1; // isInAlloca() + bool IndirectByVal : 1; // isIndirect() + bool IndirectRealign : 1; // isIndirect() + bool SRetAfterThis : 1; // isIndirect() + bool InReg : 1; // isDirect() || isExtend() || isIndirect() + bool CanBeFlattened: 1; // isDirect() + + ABIArgInfo(Kind K) + : PaddingType(nullptr), TheKind(K), PaddingInReg(false), InReg(false) {} + +public: + ABIArgInfo() + : TypeData(nullptr), PaddingType(nullptr), DirectOffset(0), + TheKind(Direct), PaddingInReg(false), InReg(false) {} + + static ABIArgInfo getDirect(llvm::Type *T = nullptr, unsigned Offset = 0, + llvm::Type *Padding = nullptr, + bool CanBeFlattened = true) { + auto AI = ABIArgInfo(Direct); + AI.setCoerceToType(T); + AI.setDirectOffset(Offset); + AI.setPaddingType(Padding); + AI.setCanBeFlattened(CanBeFlattened); + return AI; + } + static ABIArgInfo getDirectInReg(llvm::Type *T = nullptr) { + auto AI = getDirect(T); + AI.setInReg(true); + return AI; + } + static ABIArgInfo getExtend(llvm::Type *T = nullptr) { + auto AI = ABIArgInfo(Extend); + AI.setCoerceToType(T); + AI.setDirectOffset(0); + return AI; + } + static ABIArgInfo getExtendInReg(llvm::Type *T = nullptr) { + auto AI = getExtend(T); + AI.setInReg(true); + return AI; + } + static ABIArgInfo getIgnore() { + return ABIArgInfo(Ignore); + } + static ABIArgInfo getIndirect(CharUnits Alignment, bool ByVal = true, + bool Realign = false, + llvm::Type *Padding = nullptr) { + auto AI = ABIArgInfo(Indirect); + AI.setIndirectAlign(Alignment); + AI.setIndirectByVal(ByVal); + AI.setIndirectRealign(Realign); + AI.setSRetAfterThis(false); + AI.setPaddingType(Padding); + return AI; + } + static ABIArgInfo getIndirectInReg(CharUnits Alignment, bool ByVal = true, + bool Realign = false) { + auto AI = getIndirect(Alignment, ByVal, Realign); + AI.setInReg(true); + return AI; + } + static ABIArgInfo getInAlloca(unsigned FieldIndex) { + auto AI = ABIArgInfo(InAlloca); + AI.setInAllocaFieldIndex(FieldIndex); + return AI; + } + static ABIArgInfo getExpand() { + return ABIArgInfo(Expand); + } + static ABIArgInfo getExpandWithPadding(bool PaddingInReg, + llvm::Type *Padding) { + auto AI = getExpand(); + AI.setPaddingInReg(PaddingInReg); + AI.setPaddingType(Padding); + return AI; + } + + Kind getKind() const { return TheKind; } + bool isDirect() const { return TheKind == Direct; } + bool isInAlloca() const { return TheKind == InAlloca; } + bool isExtend() const { return TheKind == Extend; } + bool isIgnore() const { return TheKind == Ignore; } + bool isIndirect() const { return TheKind == Indirect; } + bool isExpand() const { return TheKind == Expand; } + + bool canHaveCoerceToType() const { return isDirect() || isExtend(); } + + // Direct/Extend accessors + unsigned getDirectOffset() const { + assert((isDirect() || isExtend()) && "Not a direct or extend kind"); + return DirectOffset; + } + void setDirectOffset(unsigned Offset) { + assert((isDirect() || isExtend()) && "Not a direct or extend kind"); + DirectOffset = Offset; + } + + llvm::Type *getPaddingType() const { return PaddingType; } + + void setPaddingType(llvm::Type *T) { PaddingType = T; } + + bool getPaddingInReg() const { + return PaddingInReg; + } + void setPaddingInReg(bool PIR) { + PaddingInReg = PIR; + } + + llvm::Type *getCoerceToType() const { + assert(canHaveCoerceToType() && "Invalid kind!"); + return TypeData; + } + + void setCoerceToType(llvm::Type *T) { + assert(canHaveCoerceToType() && "Invalid kind!"); + TypeData = T; + } + + bool getInReg() const { + assert((isDirect() || isExtend() || isIndirect()) && "Invalid kind!"); + return InReg; + } + + void setInReg(bool IR) { + assert((isDirect() || isExtend() || isIndirect()) && "Invalid kind!"); + InReg = IR; + } + + // Indirect accessors + CharUnits getIndirectAlign() const { + assert(isIndirect() && "Invalid kind!"); + return CharUnits::fromQuantity(IndirectAlign); + } + void setIndirectAlign(CharUnits IA) { + assert(isIndirect() && "Invalid kind!"); + IndirectAlign = IA.getQuantity(); + } + + bool getIndirectByVal() const { + assert(isIndirect() && "Invalid kind!"); + return IndirectByVal; + } + void setIndirectByVal(bool IBV) { + assert(isIndirect() && "Invalid kind!"); + IndirectByVal = IBV; + } + + bool getIndirectRealign() const { + assert(isIndirect() && "Invalid kind!"); + return IndirectRealign; + } + void setIndirectRealign(bool IR) { + assert(isIndirect() && "Invalid kind!"); + IndirectRealign = IR; + } + + bool isSRetAfterThis() const { + assert(isIndirect() && "Invalid kind!"); + return SRetAfterThis; + } + void setSRetAfterThis(bool AfterThis) { + assert(isIndirect() && "Invalid kind!"); + SRetAfterThis = AfterThis; + } + + unsigned getInAllocaFieldIndex() const { + assert(isInAlloca() && "Invalid kind!"); + return AllocaFieldIndex; + } + void setInAllocaFieldIndex(unsigned FieldIndex) { + assert(isInAlloca() && "Invalid kind!"); + AllocaFieldIndex = FieldIndex; + } + + /// \brief Return true if this field of an inalloca struct should be returned + /// to implement a struct return calling convention. + bool getInAllocaSRet() const { + assert(isInAlloca() && "Invalid kind!"); + return InAllocaSRet; + } + + void setInAllocaSRet(bool SRet) { + assert(isInAlloca() && "Invalid kind!"); + InAllocaSRet = SRet; + } + + bool getCanBeFlattened() const { + assert(isDirect() && "Invalid kind!"); + return CanBeFlattened; + } + + void setCanBeFlattened(bool Flatten) { + assert(isDirect() && "Invalid kind!"); + CanBeFlattened = Flatten; + } + + void dump() const; +}; + +/// A class for recording the number of arguments that a function +/// signature requires. +class RequiredArgs { + /// The number of required arguments, or ~0 if the signature does + /// not permit optional arguments. + unsigned NumRequired; +public: + enum All_t { All }; + + RequiredArgs(All_t _) : NumRequired(~0U) {} + explicit RequiredArgs(unsigned n) : NumRequired(n) { + assert(n != ~0U); + } + + /// Compute the arguments required by the given formal prototype, + /// given that there may be some additional, non-formal arguments + /// in play. + static RequiredArgs forPrototypePlus(const FunctionProtoType *prototype, + unsigned additional) { + if (!prototype->isVariadic()) return All; + return RequiredArgs(prototype->getNumParams() + additional); + } + + static RequiredArgs forPrototype(const FunctionProtoType *prototype) { + return forPrototypePlus(prototype, 0); + } + + static RequiredArgs forPrototype(CanQual<FunctionProtoType> prototype) { + return forPrototype(prototype.getTypePtr()); + } + + static RequiredArgs forPrototypePlus(CanQual<FunctionProtoType> prototype, + unsigned additional) { + return forPrototypePlus(prototype.getTypePtr(), additional); + } + + bool allowsOptionalArgs() const { return NumRequired != ~0U; } + unsigned getNumRequiredArgs() const { + assert(allowsOptionalArgs()); + return NumRequired; + } + + unsigned getOpaqueData() const { return NumRequired; } + static RequiredArgs getFromOpaqueData(unsigned value) { + if (value == ~0U) return All; + return RequiredArgs(value); + } +}; + +/// CGFunctionInfo - Class to encapsulate the information about a +/// function definition. +class CGFunctionInfo : public llvm::FoldingSetNode { + struct ArgInfo { + CanQualType type; + ABIArgInfo info; + }; + + /// The LLVM::CallingConv to use for this function (as specified by the + /// user). + unsigned CallingConvention : 8; + + /// The LLVM::CallingConv to actually use for this function, which may + /// depend on the ABI. + unsigned EffectiveCallingConvention : 8; + + /// The clang::CallingConv that this was originally created with. + unsigned ASTCallingConvention : 8; + + /// Whether this is an instance method. + unsigned InstanceMethod : 1; + + /// Whether this is a chain call. + unsigned ChainCall : 1; + + /// Whether this function is noreturn. + unsigned NoReturn : 1; + + /// Whether this function is returns-retained. + unsigned ReturnsRetained : 1; + + /// How many arguments to pass inreg. + unsigned HasRegParm : 1; + unsigned RegParm : 3; + + RequiredArgs Required; + + /// The struct representing all arguments passed in memory. Only used when + /// passing non-trivial types with inalloca. Not part of the profile. + llvm::StructType *ArgStruct; + unsigned ArgStructAlign; + + unsigned NumArgs; + ArgInfo *getArgsBuffer() { + return reinterpret_cast<ArgInfo*>(this+1); + } + const ArgInfo *getArgsBuffer() const { + return reinterpret_cast<const ArgInfo*>(this + 1); + } + + CGFunctionInfo() : Required(RequiredArgs::All) {} + +public: + static CGFunctionInfo *create(unsigned llvmCC, + bool instanceMethod, + bool chainCall, + const FunctionType::ExtInfo &extInfo, + CanQualType resultType, + ArrayRef<CanQualType> argTypes, + RequiredArgs required); + + typedef const ArgInfo *const_arg_iterator; + typedef ArgInfo *arg_iterator; + + typedef llvm::iterator_range<arg_iterator> arg_range; + typedef llvm::iterator_range<const_arg_iterator> arg_const_range; + + arg_range arguments() { return arg_range(arg_begin(), arg_end()); } + arg_const_range arguments() const { + return arg_const_range(arg_begin(), arg_end()); + } + + const_arg_iterator arg_begin() const { return getArgsBuffer() + 1; } + const_arg_iterator arg_end() const { return getArgsBuffer() + 1 + NumArgs; } + arg_iterator arg_begin() { return getArgsBuffer() + 1; } + arg_iterator arg_end() { return getArgsBuffer() + 1 + NumArgs; } + + unsigned arg_size() const { return NumArgs; } + + bool isVariadic() const { return Required.allowsOptionalArgs(); } + RequiredArgs getRequiredArgs() const { return Required; } + unsigned getNumRequiredArgs() const { + return isVariadic() ? getRequiredArgs().getNumRequiredArgs() : arg_size(); + } + + bool isInstanceMethod() const { return InstanceMethod; } + + bool isChainCall() const { return ChainCall; } + + bool isNoReturn() const { return NoReturn; } + + /// In ARC, whether this function retains its return value. This + /// is not always reliable for call sites. + bool isReturnsRetained() const { return ReturnsRetained; } + + /// getASTCallingConvention() - Return the AST-specified calling + /// convention. + CallingConv getASTCallingConvention() const { + return CallingConv(ASTCallingConvention); + } + + /// getCallingConvention - Return the user specified calling + /// convention, which has been translated into an LLVM CC. + unsigned getCallingConvention() const { return CallingConvention; } + + /// getEffectiveCallingConvention - Return the actual calling convention to + /// use, which may depend on the ABI. + unsigned getEffectiveCallingConvention() const { + return EffectiveCallingConvention; + } + void setEffectiveCallingConvention(unsigned Value) { + EffectiveCallingConvention = Value; + } + + bool getHasRegParm() const { return HasRegParm; } + unsigned getRegParm() const { return RegParm; } + + FunctionType::ExtInfo getExtInfo() const { + return FunctionType::ExtInfo(isNoReturn(), + getHasRegParm(), getRegParm(), + getASTCallingConvention(), + isReturnsRetained()); + } + + CanQualType getReturnType() const { return getArgsBuffer()[0].type; } + + ABIArgInfo &getReturnInfo() { return getArgsBuffer()[0].info; } + const ABIArgInfo &getReturnInfo() const { return getArgsBuffer()[0].info; } + + /// \brief Return true if this function uses inalloca arguments. + bool usesInAlloca() const { return ArgStruct; } + + /// \brief Get the struct type used to represent all the arguments in memory. + llvm::StructType *getArgStruct() const { return ArgStruct; } + CharUnits getArgStructAlignment() const { + return CharUnits::fromQuantity(ArgStructAlign); + } + void setArgStruct(llvm::StructType *Ty, CharUnits Align) { + ArgStruct = Ty; + ArgStructAlign = Align.getQuantity(); + } + + void Profile(llvm::FoldingSetNodeID &ID) { + ID.AddInteger(getASTCallingConvention()); + ID.AddBoolean(InstanceMethod); + ID.AddBoolean(ChainCall); + ID.AddBoolean(NoReturn); + ID.AddBoolean(ReturnsRetained); + ID.AddBoolean(HasRegParm); + ID.AddInteger(RegParm); + ID.AddInteger(Required.getOpaqueData()); + getReturnType().Profile(ID); + for (const auto &I : arguments()) + I.type.Profile(ID); + } + static void Profile(llvm::FoldingSetNodeID &ID, + bool InstanceMethod, + bool ChainCall, + const FunctionType::ExtInfo &info, + RequiredArgs required, + CanQualType resultType, + ArrayRef<CanQualType> argTypes) { + ID.AddInteger(info.getCC()); + ID.AddBoolean(InstanceMethod); + ID.AddBoolean(ChainCall); + ID.AddBoolean(info.getNoReturn()); + ID.AddBoolean(info.getProducesResult()); + ID.AddBoolean(info.getHasRegParm()); + ID.AddInteger(info.getRegParm()); + ID.AddInteger(required.getOpaqueData()); + resultType.Profile(ID); + for (ArrayRef<CanQualType>::iterator + i = argTypes.begin(), e = argTypes.end(); i != e; ++i) { + i->Profile(ID); + } + } +}; + +/// CGCalleeInfo - Class to encapsulate the information about a callee to be +/// used during the generation of call/invoke instructions. +class CGCalleeInfo { + /// \brief The function proto type of the callee. + const FunctionProtoType *CalleeProtoTy; + /// \brief The function declaration of the callee. + const Decl *CalleeDecl; + +public: + explicit CGCalleeInfo() : CalleeProtoTy(nullptr), CalleeDecl(nullptr) {} + CGCalleeInfo(const FunctionProtoType *calleeProtoTy, const Decl *calleeDecl) + : CalleeProtoTy(calleeProtoTy), CalleeDecl(calleeDecl) {} + CGCalleeInfo(const FunctionProtoType *calleeProtoTy) + : CalleeProtoTy(calleeProtoTy), CalleeDecl(nullptr) {} + CGCalleeInfo(const Decl *calleeDecl) + : CalleeProtoTy(nullptr), CalleeDecl(calleeDecl) {} + + const FunctionProtoType *getCalleeFunctionProtoType() { + return CalleeProtoTy; + } + const Decl *getCalleeDecl() { return CalleeDecl; } +}; + +} // end namespace CodeGen +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/CodeGen/CodeGenABITypes.h b/contrib/llvm/tools/clang/include/clang/CodeGen/CodeGenABITypes.h new file mode 100644 index 0000000..9d9504a --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/CodeGen/CodeGenABITypes.h @@ -0,0 +1,91 @@ +//==---- CodeGenABITypes.h - Convert Clang types to LLVM types for ABI -----==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// CodeGenABITypes is a simple interface for getting LLVM types for +// the parameters and the return value of a function given the Clang +// types. +// +// The class is implemented as a public wrapper around the private +// CodeGenTypes class in lib/CodeGen. +// +// It allows other clients, like LLDB, to determine the LLVM types that are +// actually used in function calls, which makes it possible to then determine +// the acutal ABI locations (e.g. registers, stack locations, etc.) that +// these parameters are stored in. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CODEGEN_CODEGENABITYPES_H +#define LLVM_CLANG_CODEGEN_CODEGENABITYPES_H + +#include "clang/AST/CanonicalType.h" +#include "clang/AST/Type.h" +#include "clang/CodeGen/CGFunctionInfo.h" + +namespace llvm { + class DataLayout; + class Module; +} + +namespace clang { +class ASTContext; +class CXXRecordDecl; +class CXXMethodDecl; +class CodeGenOptions; +class CoverageSourceInfo; +class DiagnosticsEngine; +class HeaderSearchOptions; +class ObjCMethodDecl; +class PreprocessorOptions; + +namespace CodeGen { +class CGFunctionInfo; +class CodeGenModule; + +class CodeGenABITypes +{ +public: + CodeGenABITypes(ASTContext &C, llvm::Module &M, + CoverageSourceInfo *CoverageInfo = nullptr); + ~CodeGenABITypes(); + + /// These methods all forward to methods in the private implementation class + /// CodeGenTypes. + + const CGFunctionInfo &arrangeObjCMessageSendSignature( + const ObjCMethodDecl *MD, + QualType receiverType); + const CGFunctionInfo &arrangeFreeFunctionType(CanQual<FunctionProtoType> Ty, + const FunctionDecl *FD); + const CGFunctionInfo &arrangeFreeFunctionType( + CanQual<FunctionNoProtoType> Ty); + const CGFunctionInfo &arrangeCXXMethodType(const CXXRecordDecl *RD, + const FunctionProtoType *FTP, + const CXXMethodDecl *MD); + const CGFunctionInfo &arrangeFreeFunctionCall(CanQualType returnType, + ArrayRef<CanQualType> argTypes, + FunctionType::ExtInfo info, + RequiredArgs args); + +private: + /// Default CodeGenOptions object used to initialize the + /// CodeGenModule and otherwise not used. More specifically, it is + /// not used in ABI type generation, so none of the options matter. + std::unique_ptr<CodeGenOptions> CGO; + std::unique_ptr<HeaderSearchOptions> HSO; + std::unique_ptr<PreprocessorOptions> PPO; + + /// The CodeGenModule we use get to the CodeGenTypes object. + std::unique_ptr<CodeGen::CodeGenModule> CGM; +}; + +} // end namespace CodeGen +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/CodeGen/CodeGenAction.h b/contrib/llvm/tools/clang/include/clang/CodeGen/CodeGenAction.h new file mode 100644 index 0000000..cc38e24 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/CodeGen/CodeGenAction.h @@ -0,0 +1,107 @@ +//===--- CodeGenAction.h - LLVM Code Generation Frontend Action -*- 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_CODEGEN_CODEGENACTION_H +#define LLVM_CLANG_CODEGEN_CODEGENACTION_H + +#include "clang/Frontend/FrontendAction.h" +#include <memory> + +namespace llvm { + class LLVMContext; + class Module; +} + +namespace clang { +class BackendConsumer; + +class CodeGenAction : public ASTFrontendAction { +private: + unsigned Act; + std::unique_ptr<llvm::Module> TheModule; + // Vector of {Linker::Flags, Module*} pairs to specify bitcode + // modules to link in using corresponding linker flags. + SmallVector<std::pair<unsigned, llvm::Module *>, 4> LinkModules; + llvm::LLVMContext *VMContext; + bool OwnsVMContext; + +protected: + /// Create a new code generation action. If the optional \p _VMContext + /// parameter is supplied, the action uses it without taking ownership, + /// otherwise it creates a fresh LLVM context and takes ownership. + CodeGenAction(unsigned _Act, llvm::LLVMContext *_VMContext = nullptr); + + bool hasIRSupport() const override; + + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override; + + void ExecuteAction() override; + + void EndSourceFileAction() override; + +public: + ~CodeGenAction() override; + + /// setLinkModule - Set the link module to be used by this action. If a link + /// module is not provided, and CodeGenOptions::LinkBitcodeFile is non-empty, + /// the action will load it from the specified file. + void addLinkModule(llvm::Module *Mod, unsigned LinkFlags) { + LinkModules.push_back(std::make_pair(LinkFlags, Mod)); + } + + /// Take the generated LLVM module, for use after the action has been run. + /// The result may be null on failure. + std::unique_ptr<llvm::Module> takeModule(); + + /// Take the LLVM context used by this action. + llvm::LLVMContext *takeLLVMContext(); + + BackendConsumer *BEConsumer; +}; + +class EmitAssemblyAction : public CodeGenAction { + virtual void anchor(); +public: + EmitAssemblyAction(llvm::LLVMContext *_VMContext = nullptr); +}; + +class EmitBCAction : public CodeGenAction { + virtual void anchor(); +public: + EmitBCAction(llvm::LLVMContext *_VMContext = nullptr); +}; + +class EmitLLVMAction : public CodeGenAction { + virtual void anchor(); +public: + EmitLLVMAction(llvm::LLVMContext *_VMContext = nullptr); +}; + +class EmitLLVMOnlyAction : public CodeGenAction { + virtual void anchor(); +public: + EmitLLVMOnlyAction(llvm::LLVMContext *_VMContext = nullptr); +}; + +class EmitCodeGenOnlyAction : public CodeGenAction { + virtual void anchor(); +public: + EmitCodeGenOnlyAction(llvm::LLVMContext *_VMContext = nullptr); +}; + +class EmitObjAction : public CodeGenAction { + virtual void anchor(); +public: + EmitObjAction(llvm::LLVMContext *_VMContext = nullptr); +}; + +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/CodeGen/ModuleBuilder.h b/contrib/llvm/tools/clang/include/clang/CodeGen/ModuleBuilder.h new file mode 100644 index 0000000..52497d9 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/CodeGen/ModuleBuilder.h @@ -0,0 +1,54 @@ +//===--- CodeGen/ModuleBuilder.h - Build LLVM from ASTs ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ModuleBuilder interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CODEGEN_MODULEBUILDER_H +#define LLVM_CLANG_CODEGEN_MODULEBUILDER_H + +#include "clang/AST/ASTConsumer.h" +#include <string> + +namespace llvm { + class LLVMContext; + class Module; +} + +namespace clang { + class DiagnosticsEngine; + class CoverageSourceInfo; + class LangOptions; + class HeaderSearchOptions; + class PreprocessorOptions; + class CodeGenOptions; + class Decl; + + class CodeGenerator : public ASTConsumer { + virtual void anchor(); + public: + virtual llvm::Module* GetModule() = 0; + virtual llvm::Module* ReleaseModule() = 0; + virtual const Decl *GetDeclForMangledName(llvm::StringRef MangledName) = 0; + }; + + /// CreateLLVMCodeGen - Create a CodeGenerator instance. + /// It is the responsibility of the caller to call delete on + /// the allocated CodeGenerator instance. + CodeGenerator *CreateLLVMCodeGen(DiagnosticsEngine &Diags, + const std::string &ModuleName, + const HeaderSearchOptions &HeaderSearchOpts, + const PreprocessorOptions &PreprocessorOpts, + const CodeGenOptions &CGO, + llvm::LLVMContext& C, + CoverageSourceInfo *CoverageInfo = nullptr); +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/CodeGen/ObjectFilePCHContainerOperations.h b/contrib/llvm/tools/clang/include/clang/CodeGen/ObjectFilePCHContainerOperations.h new file mode 100644 index 0000000..15132ac --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/CodeGen/ObjectFilePCHContainerOperations.h @@ -0,0 +1,43 @@ +//===-- CodeGen/ObjectFilePCHContainerOperations.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_CODEGEN_OBJECT_FILE_PCH_CONTAINER_OPERATIONS_H +#define LLVM_CLANG_CODEGEN_OBJECT_FILE_PCH_CONTAINER_OPERATIONS_H + +#include "clang/Frontend/PCHContainerOperations.h" + +namespace clang { + +/// A PCHContainerWriter implementation that uses LLVM to +/// wraps Clang modules inside a COFF, ELF, or Mach-O container. +class ObjectFilePCHContainerWriter : public PCHContainerWriter { + StringRef getFormat() const override { return "obj"; } + + /// Return an ASTConsumer that can be chained with a + /// PCHGenerator that produces a wrapper file format + /// that also contains full debug info for the module. + std::unique_ptr<ASTConsumer> CreatePCHContainerGenerator( + CompilerInstance &CI, const std::string &MainFileName, + const std::string &OutputFileName, llvm::raw_pwrite_stream *OS, + std::shared_ptr<PCHBuffer> Buffer) const override; +}; + +/// A PCHContainerReader implementation that uses LLVM to +/// wraps Clang modules inside a COFF, ELF, or Mach-O container. +class ObjectFilePCHContainerReader : public PCHContainerReader { + StringRef getFormat() const override { return "obj"; } + + /// Initialize an llvm::BitstreamReader with the serialized + /// AST inside the PCH container Buffer. + void ExtractPCH(llvm::MemoryBufferRef Buffer, + llvm::BitstreamReader &StreamFile) const override; +}; +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Driver/Action.h b/contrib/llvm/tools/clang/include/clang/Driver/Action.h new file mode 100644 index 0000000..fc31d4b --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Driver/Action.h @@ -0,0 +1,317 @@ +//===--- Action.h - Abstract compilation steps ------------------*- 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_DRIVER_ACTION_H +#define LLVM_CLANG_DRIVER_ACTION_H + +#include "clang/Driver/Types.h" +#include "clang/Driver/Util.h" +#include "llvm/ADT/SmallVector.h" + +namespace llvm { +namespace opt { + class Arg; +} +} + +namespace clang { +namespace driver { + +/// Action - Represent an abstract compilation step to perform. +/// +/// An action represents an edge in the compilation graph; typically +/// it is a job to transform an input using some tool. +/// +/// The current driver is hard wired to expect actions which produce a +/// single primary output, at least in terms of controlling the +/// compilation. Actions can produce auxiliary files, but can only +/// produce a single output to feed into subsequent actions. +class Action { +public: + typedef ActionList::size_type size_type; + typedef ActionList::iterator iterator; + typedef ActionList::const_iterator const_iterator; + + enum ActionClass { + InputClass = 0, + BindArchClass, + CudaDeviceClass, + CudaHostClass, + PreprocessJobClass, + PrecompileJobClass, + AnalyzeJobClass, + MigrateJobClass, + CompileJobClass, + BackendJobClass, + AssembleJobClass, + LinkJobClass, + LipoJobClass, + DsymutilJobClass, + VerifyDebugInfoJobClass, + VerifyPCHJobClass, + + JobClassFirst=PreprocessJobClass, + JobClassLast=VerifyPCHJobClass + }; + + static const char *getClassName(ActionClass AC); + +private: + ActionClass Kind; + + /// The output type of this action. + types::ID Type; + + ActionList Inputs; + + unsigned OwnsInputs : 1; + +protected: + Action(ActionClass Kind, types::ID Type) + : Kind(Kind), Type(Type), OwnsInputs(true) {} + Action(ActionClass Kind, std::unique_ptr<Action> Input, types::ID Type) + : Kind(Kind), Type(Type), Inputs(1, Input.release()), OwnsInputs(true) { + } + Action(ActionClass Kind, std::unique_ptr<Action> Input) + : Kind(Kind), Type(Input->getType()), Inputs(1, Input.release()), + OwnsInputs(true) {} + Action(ActionClass Kind, const ActionList &Inputs, types::ID Type) + : Kind(Kind), Type(Type), Inputs(Inputs), OwnsInputs(true) {} +public: + virtual ~Action(); + + const char *getClassName() const { return Action::getClassName(getKind()); } + + bool getOwnsInputs() { return OwnsInputs; } + void setOwnsInputs(bool Value) { OwnsInputs = Value; } + + ActionClass getKind() const { return Kind; } + types::ID getType() const { return Type; } + + ActionList &getInputs() { return Inputs; } + const ActionList &getInputs() const { return Inputs; } + + size_type size() const { return Inputs.size(); } + + iterator begin() { return Inputs.begin(); } + iterator end() { return Inputs.end(); } + const_iterator begin() const { return Inputs.begin(); } + const_iterator end() const { return Inputs.end(); } +}; + +class InputAction : public Action { + virtual void anchor(); + const llvm::opt::Arg &Input; + +public: + InputAction(const llvm::opt::Arg &Input, types::ID Type); + + const llvm::opt::Arg &getInputArg() const { return Input; } + + static bool classof(const Action *A) { + return A->getKind() == InputClass; + } +}; + +class BindArchAction : public Action { + virtual void anchor(); + /// The architecture to bind, or 0 if the default architecture + /// should be bound. + const char *ArchName; + +public: + BindArchAction(std::unique_ptr<Action> Input, const char *ArchName); + + const char *getArchName() const { return ArchName; } + + static bool classof(const Action *A) { + return A->getKind() == BindArchClass; + } +}; + +class CudaDeviceAction : public Action { + virtual void anchor(); + /// GPU architecture to bind -- e.g 'sm_35'. + const char *GpuArchName; + /// True when action results are not consumed by the host action (e.g when + /// -fsyntax-only or --cuda-device-only options are used). + bool AtTopLevel; + +public: + CudaDeviceAction(std::unique_ptr<Action> Input, const char *ArchName, + bool AtTopLevel); + + const char *getGpuArchName() const { return GpuArchName; } + bool isAtTopLevel() const { return AtTopLevel; } + + static bool classof(const Action *A) { + return A->getKind() == CudaDeviceClass; + } +}; + +class CudaHostAction : public Action { + virtual void anchor(); + ActionList DeviceActions; + +public: + CudaHostAction(std::unique_ptr<Action> Input, + const ActionList &DeviceActions); + ~CudaHostAction() override; + + const ActionList &getDeviceActions() const { return DeviceActions; } + + static bool classof(const Action *A) { return A->getKind() == CudaHostClass; } +}; + +class JobAction : public Action { + virtual void anchor(); +protected: + JobAction(ActionClass Kind, std::unique_ptr<Action> Input, types::ID Type); + JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type); + +public: + static bool classof(const Action *A) { + return (A->getKind() >= JobClassFirst && + A->getKind() <= JobClassLast); + } +}; + +class PreprocessJobAction : public JobAction { + void anchor() override; +public: + PreprocessJobAction(std::unique_ptr<Action> Input, types::ID OutputType); + + static bool classof(const Action *A) { + return A->getKind() == PreprocessJobClass; + } +}; + +class PrecompileJobAction : public JobAction { + void anchor() override; +public: + PrecompileJobAction(std::unique_ptr<Action> Input, types::ID OutputType); + + static bool classof(const Action *A) { + return A->getKind() == PrecompileJobClass; + } +}; + +class AnalyzeJobAction : public JobAction { + void anchor() override; +public: + AnalyzeJobAction(std::unique_ptr<Action> Input, types::ID OutputType); + + static bool classof(const Action *A) { + return A->getKind() == AnalyzeJobClass; + } +}; + +class MigrateJobAction : public JobAction { + void anchor() override; +public: + MigrateJobAction(std::unique_ptr<Action> Input, types::ID OutputType); + + static bool classof(const Action *A) { + return A->getKind() == MigrateJobClass; + } +}; + +class CompileJobAction : public JobAction { + void anchor() override; +public: + CompileJobAction(std::unique_ptr<Action> Input, types::ID OutputType); + + static bool classof(const Action *A) { + return A->getKind() == CompileJobClass; + } +}; + +class BackendJobAction : public JobAction { + void anchor() override; +public: + BackendJobAction(std::unique_ptr<Action> Input, types::ID OutputType); + + static bool classof(const Action *A) { + return A->getKind() == BackendJobClass; + } +}; + +class AssembleJobAction : public JobAction { + void anchor() override; +public: + AssembleJobAction(std::unique_ptr<Action> Input, types::ID OutputType); + + static bool classof(const Action *A) { + return A->getKind() == AssembleJobClass; + } +}; + +class LinkJobAction : public JobAction { + void anchor() override; +public: + LinkJobAction(ActionList &Inputs, types::ID Type); + + static bool classof(const Action *A) { + return A->getKind() == LinkJobClass; + } +}; + +class LipoJobAction : public JobAction { + void anchor() override; +public: + LipoJobAction(ActionList &Inputs, types::ID Type); + + static bool classof(const Action *A) { + return A->getKind() == LipoJobClass; + } +}; + +class DsymutilJobAction : public JobAction { + void anchor() override; +public: + DsymutilJobAction(ActionList &Inputs, types::ID Type); + + static bool classof(const Action *A) { + return A->getKind() == DsymutilJobClass; + } +}; + +class VerifyJobAction : public JobAction { + void anchor() override; +public: + VerifyJobAction(ActionClass Kind, std::unique_ptr<Action> Input, + types::ID Type); + static bool classof(const Action *A) { + return A->getKind() == VerifyDebugInfoJobClass || + A->getKind() == VerifyPCHJobClass; + } +}; + +class VerifyDebugInfoJobAction : public VerifyJobAction { + void anchor() override; +public: + VerifyDebugInfoJobAction(std::unique_ptr<Action> Input, types::ID Type); + static bool classof(const Action *A) { + return A->getKind() == VerifyDebugInfoJobClass; + } +}; + +class VerifyPCHJobAction : public VerifyJobAction { + void anchor() override; +public: + VerifyPCHJobAction(std::unique_ptr<Action> Input, types::ID Type); + static bool classof(const Action *A) { + return A->getKind() == VerifyPCHJobClass; + } +}; + +} // end namespace driver +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Driver/CC1Options.td b/contrib/llvm/tools/clang/include/clang/Driver/CC1Options.td new file mode 100644 index 0000000..051f903 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Driver/CC1Options.td @@ -0,0 +1,718 @@ +//===--- CC1Options.td - Options for clang -cc1 ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the options accepted by clang -cc1 and clang -cc1as. +// +//===----------------------------------------------------------------------===// + +let Flags = [CC1Option, NoDriverOption] in { + +//===----------------------------------------------------------------------===// +// Target Options +//===----------------------------------------------------------------------===// + +let Flags = [CC1Option, CC1AsOption, NoDriverOption] in { + +def target_cpu : Separate<["-"], "target-cpu">, + HelpText<"Target a specific cpu type">; +def target_feature : Separate<["-"], "target-feature">, + HelpText<"Target specific attributes">; +def triple : Separate<["-"], "triple">, + HelpText<"Specify target triple (e.g. i686-apple-darwin9)">; +def target_abi : Separate<["-"], "target-abi">, + HelpText<"Target a particular ABI type">; + +} + +def target_linker_version : Separate<["-"], "target-linker-version">, + HelpText<"Target linker version">; +def triple_EQ : Joined<["-"], "triple=">, Alias<triple>; +def mfpmath : Separate<["-"], "mfpmath">, + HelpText<"Which unit to use for fp math">; + +//===----------------------------------------------------------------------===// +// Analyzer Options +//===----------------------------------------------------------------------===// + +def analysis_UnoptimizedCFG : Flag<["-"], "unoptimized-cfg">, + HelpText<"Generate unoptimized CFGs for all analyses">; +def analysis_CFGAddImplicitDtors : Flag<["-"], "cfg-add-implicit-dtors">, + HelpText<"Add C++ implicit destructors to CFGs for all analyses">; + +def analyzer_store : Separate<["-"], "analyzer-store">, + HelpText<"Source Code Analysis - Abstract Memory Store Models">; +def analyzer_store_EQ : Joined<["-"], "analyzer-store=">, Alias<analyzer_store>; + +def analyzer_constraints : Separate<["-"], "analyzer-constraints">, + HelpText<"Source Code Analysis - Symbolic Constraint Engines">; +def analyzer_constraints_EQ : Joined<["-"], "analyzer-constraints=">, + Alias<analyzer_constraints>; + +def analyzer_output : Separate<["-"], "analyzer-output">, + HelpText<"Source Code Analysis - Output Options">; +def analyzer_output_EQ : Joined<["-"], "analyzer-output=">, + Alias<analyzer_output>; + +def analyzer_purge : Separate<["-"], "analyzer-purge">, + HelpText<"Source Code Analysis - Dead Symbol Removal Frequency">; +def analyzer_purge_EQ : Joined<["-"], "analyzer-purge=">, Alias<analyzer_purge>; + +def analyzer_opt_analyze_headers : Flag<["-"], "analyzer-opt-analyze-headers">, + HelpText<"Force the static analyzer to analyze functions defined in header files">; +def analyzer_opt_analyze_nested_blocks : Flag<["-"], "analyzer-opt-analyze-nested-blocks">, + HelpText<"Analyze the definitions of blocks in addition to functions">; +def analyzer_display_progress : Flag<["-"], "analyzer-display-progress">, + HelpText<"Emit verbose output about the analyzer's progress">; +def analyze_function : Separate<["-"], "analyze-function">, + HelpText<"Run analysis on specific function">; +def analyze_function_EQ : Joined<["-"], "analyze-function=">, Alias<analyze_function>; +def analyzer_eagerly_assume : Flag<["-"], "analyzer-eagerly-assume">, + HelpText<"Eagerly assume the truth/falseness of some symbolic constraints">; +def trim_egraph : Flag<["-"], "trim-egraph">, + HelpText<"Only show error-related paths in the analysis graph">; +def analyzer_viz_egraph_graphviz : Flag<["-"], "analyzer-viz-egraph-graphviz">, + HelpText<"Display exploded graph using GraphViz">; +def analyzer_viz_egraph_ubigraph : Flag<["-"], "analyzer-viz-egraph-ubigraph">, + HelpText<"Display exploded graph using Ubigraph">; + +def analyzer_inline_max_stack_depth : Separate<["-"], "analyzer-inline-max-stack-depth">, + HelpText<"Bound on stack depth while inlining (4 by default)">; +def analyzer_inline_max_stack_depth_EQ : Joined<["-"], "analyzer-inline-max-stack-depth=">, + Alias<analyzer_inline_max_stack_depth>; + +def analyzer_inlining_mode : Separate<["-"], "analyzer-inlining-mode">, + HelpText<"Specify the function selection heuristic used during inlining">; +def analyzer_inlining_mode_EQ : Joined<["-"], "analyzer-inlining-mode=">, Alias<analyzer_inlining_mode>; + +def analyzer_disable_retry_exhausted : Flag<["-"], "analyzer-disable-retry-exhausted">, + HelpText<"Do not re-analyze paths leading to exhausted nodes with a different strategy (may decrease code coverage)">; + +def analyzer_max_loop : Separate<["-"], "analyzer-max-loop">, + HelpText<"The maximum number of times the analyzer will go through a loop">; +def analyzer_stats : Flag<["-"], "analyzer-stats">, + HelpText<"Print internal analyzer statistics.">; + +def analyzer_checker : Separate<["-"], "analyzer-checker">, + HelpText<"Choose analyzer checkers to enable">; +def analyzer_checker_EQ : Joined<["-"], "analyzer-checker=">, + Alias<analyzer_checker>; + +def analyzer_disable_checker : Separate<["-"], "analyzer-disable-checker">, + HelpText<"Choose analyzer checkers to disable">; +def analyzer_disable_checker_EQ : Joined<["-"], "analyzer-disable-checker=">, + Alias<analyzer_disable_checker>; + +def analyzer_disable_all_checks : Flag<["-"], "analyzer-disable-all-checks">, + HelpText<"Disable all static analyzer checks">; + +def analyzer_checker_help : Flag<["-"], "analyzer-checker-help">, + HelpText<"Display the list of analyzer checkers that are available">; + +def analyzer_config : Separate<["-"], "analyzer-config">, + HelpText<"Choose analyzer options to enable">; + +//===----------------------------------------------------------------------===// +// Migrator Options +//===----------------------------------------------------------------------===// +def migrator_no_nsalloc_error : Flag<["-"], "no-ns-alloc-error">, + HelpText<"Do not error on use of NSAllocateCollectable/NSReallocateCollectable">; + +def migrator_no_finalize_removal : Flag<["-"], "no-finalize-removal">, + HelpText<"Do not remove finalize method in gc mode">; + +//===----------------------------------------------------------------------===// +// CodeGen Options +//===----------------------------------------------------------------------===// + +let Flags = [CC1Option, CC1AsOption, NoDriverOption] in { + +def debug_info_kind_EQ : Joined<["-"], "debug-info-kind=">; +def dwarf_version_EQ : Joined<["-"], "dwarf-version=">; +def debugger_tuning_EQ : Joined<["-"], "debugger-tuning=">; +def fdebug_compilation_dir : Separate<["-"], "fdebug-compilation-dir">, + HelpText<"The compilation directory to embed in the debug info.">; +def dwarf_debug_flags : Separate<["-"], "dwarf-debug-flags">, + HelpText<"The string to embed in the Dwarf debug flags record.">; +def mno_exec_stack : Flag<["-"], "mnoexecstack">, + HelpText<"Mark the file as not needing an executable stack">; +def massembler_fatal_warnings : Flag<["-"], "massembler-fatal-warnings">, + HelpText<"Make assembler warnings fatal">; +def compress_debug_sections : Flag<["-"], "compress-debug-sections">, + HelpText<"Compress DWARF debug sections using zlib">; +def msave_temp_labels : Flag<["-"], "msave-temp-labels">, + HelpText<"Save temporary labels in the symbol table. " + "Note this may change .s semantics and shouldn't generally be used " + "on compiler-generated code.">; +def mrelocation_model : Separate<["-"], "mrelocation-model">, + HelpText<"The relocation model to use">; +} + +def disable_llvm_optzns : Flag<["-"], "disable-llvm-optzns">, + HelpText<"Don't run LLVM optimization passes">; +def disable_llvm_verifier : Flag<["-"], "disable-llvm-verifier">, + HelpText<"Don't run the LLVM IR verifier pass">; +def disable_llvm_passes : Flag<["-"], "disable-llvm-passes">, + HelpText<"Use together with -emit-llvm to get pristine LLVM IR from the " + "frontend by not running any LLVM passes at all">; +def disable_red_zone : Flag<["-"], "disable-red-zone">, + HelpText<"Do not emit code that uses the red zone.">; +def dwarf_column_info : Flag<["-"], "dwarf-column-info">, + HelpText<"Turn on column location information.">; +def split_dwarf : Flag<["-"], "split-dwarf">, + HelpText<"Split out the dwarf .dwo sections">; +def gnu_pubnames : Flag<["-"], "gnu-pubnames">, + HelpText<"Emit newer GNU style pubnames">; +def arange_sections : Flag<["-"], "arange_sections">, + HelpText<"Emit DWARF .debug_arange sections">; +def dwarf_ext_refs : Flag<["-"], "dwarf-ext-refs">, + HelpText<"Generate debug info with external references to clang modules" + " or precompiled headers">; +def fforbid_guard_variables : Flag<["-"], "fforbid-guard-variables">, + HelpText<"Emit an error if a C++ static local initializer would need a guard variable">; +def no_implicit_float : Flag<["-"], "no-implicit-float">, + HelpText<"Don't generate implicit floating point instructions">; +def fdump_vtable_layouts : Flag<["-"], "fdump-vtable-layouts">, + HelpText<"Dump the layouts of all vtables that will be emitted in a translation unit">; +def fmerge_functions : Flag<["-"], "fmerge-functions">, + HelpText<"Permit merging of identical functions when optimizing.">; +def femit_coverage_notes : Flag<["-"], "femit-coverage-notes">, + HelpText<"Emit a gcov coverage notes file when compiling.">; +def femit_coverage_data: Flag<["-"], "femit-coverage-data">, + HelpText<"Instrument the program to emit gcov coverage data when run.">; +def coverage_file : Separate<["-"], "coverage-file">, + HelpText<"Emit coverage data to this filename. The extension will be replaced.">; +def coverage_file_EQ : Joined<["-"], "coverage-file=">, Alias<coverage_file>; +def coverage_cfg_checksum : Flag<["-"], "coverage-cfg-checksum">, + HelpText<"Emit CFG checksum for functions in .gcno files.">; +def coverage_no_function_names_in_data : Flag<["-"], "coverage-no-function-names-in-data">, + HelpText<"Emit function names in .gcda files.">; +def coverage_exit_block_before_body : Flag<["-"], "coverage-exit-block-before-body">, + HelpText<"Emit the exit block before the body blocks in .gcno files.">; +def coverage_version_EQ : Joined<["-"], "coverage-version=">, + HelpText<"Four-byte version string for gcov files.">; +def test_coverage : Flag<["-"], "test-coverage">, + HelpText<"Do not generate coverage files or remove coverage changes from IR">; +def dump_coverage_mapping : Flag<["-"], "dump-coverage-mapping">, + HelpText<"Dump the coverage mapping records, for testing">; +def fuse_register_sized_bitfield_access: Flag<["-"], "fuse-register-sized-bitfield-access">, + HelpText<"Use register sized accesses to bit-fields, when possible.">; +def relaxed_aliasing : Flag<["-"], "relaxed-aliasing">, + HelpText<"Turn off Type Based Alias Analysis">; +def no_struct_path_tbaa : Flag<["-"], "no-struct-path-tbaa">, + HelpText<"Turn off struct-path aware Type Based Alias Analysis">; +def masm_verbose : Flag<["-"], "masm-verbose">, + HelpText<"Generate verbose assembly output">; +def mcode_model : Separate<["-"], "mcode-model">, + HelpText<"The code model to use">; +def mdebug_pass : Separate<["-"], "mdebug-pass">, + HelpText<"Enable additional debug output">; +def mdisable_fp_elim : Flag<["-"], "mdisable-fp-elim">, + HelpText<"Disable frame pointer elimination optimization">; +def mdisable_tail_calls : Flag<["-"], "mdisable-tail-calls">, + HelpText<"Disable tail call optimization, keeping the call stack accurate">; +def menable_no_infinities : Flag<["-"], "menable-no-infs">, + HelpText<"Allow optimization to assume there are no infinities.">; +def menable_no_nans : Flag<["-"], "menable-no-nans">, + HelpText<"Allow optimization to assume there are no NaNs.">; +def menable_unsafe_fp_math : Flag<["-"], "menable-unsafe-fp-math">, + HelpText<"Allow unsafe floating-point math optimizations which may decrease " + "precision">; +def mfloat_abi : Separate<["-"], "mfloat-abi">, + HelpText<"The float ABI to use">; +def mlimit_float_precision : Separate<["-"], "mlimit-float-precision">, + HelpText<"Limit float precision to the given value">; +def split_stacks : Flag<["-"], "split-stacks">, + HelpText<"Try to use a split stack if possible.">; +def mno_zero_initialized_in_bss : Flag<["-"], "mno-zero-initialized-in-bss">, + HelpText<"Do not put zero initialized data in the BSS">; +def backend_option : Separate<["-"], "backend-option">, + HelpText<"Additional arguments to forward to LLVM backend (during code gen)">; +def mregparm : Separate<["-"], "mregparm">, + HelpText<"Limit the number of registers available for integer arguments">; +def munwind_tables : Flag<["-"], "munwind-tables">, + HelpText<"Generate unwinding tables for all functions">; +def mconstructor_aliases : Flag<["-"], "mconstructor-aliases">, + HelpText<"Emit complete constructors and destructors as aliases when possible">; +def mlink_bitcode_file : Separate<["-"], "mlink-bitcode-file">, + HelpText<"Link the given bitcode file before performing optimizations.">; +def mlink_cuda_bitcode : Separate<["-"], "mlink-cuda-bitcode">, + HelpText<"Link and internalize needed symbols from the given bitcode file " + "before performing optimizations.">; +def vectorize_loops : Flag<["-"], "vectorize-loops">, + HelpText<"Run the Loop vectorization passes">; +def vectorize_slp : Flag<["-"], "vectorize-slp">, + HelpText<"Run the SLP vectorization passes">; +def vectorize_slp_aggressive : Flag<["-"], "vectorize-slp-aggressive">, + HelpText<"Run the BB vectorization passes">; +def dependent_lib : Joined<["--"], "dependent-lib=">, + HelpText<"Add dependent library">; +def fsanitize_coverage_type : Joined<["-"], "fsanitize-coverage-type=">, + HelpText<"Sanitizer coverage type">; +def fsanitize_coverage_indirect_calls + : Flag<["-"], "fsanitize-coverage-indirect-calls">, + HelpText<"Enable sanitizer coverage for indirect calls">; +def fsanitize_coverage_trace_bb + : Flag<["-"], "fsanitize-coverage-trace-bb">, + HelpText<"Enable basic block tracing in sanitizer coverage">; +def fsanitize_coverage_trace_cmp + : Flag<["-"], "fsanitize-coverage-trace-cmp">, + HelpText<"Enable cmp instruction tracing in sanitizer coverage">; +def fsanitize_coverage_8bit_counters + : Flag<["-"], "fsanitize-coverage-8bit-counters">, + HelpText<"Enable frequency counters in sanitizer coverage">; + +//===----------------------------------------------------------------------===// +// Dependency Output Options +//===----------------------------------------------------------------------===// + +def sys_header_deps : Flag<["-"], "sys-header-deps">, + HelpText<"Include system headers in dependency output">; +def module_file_deps : Flag<["-"], "module-file-deps">, + HelpText<"Include module files in dependency output">; +def header_include_file : Separate<["-"], "header-include-file">, + HelpText<"Filename (or -) to write header include output to">; +def show_includes : Flag<["--"], "show-includes">, + HelpText<"Print cl.exe style /showIncludes to stdout">; + +//===----------------------------------------------------------------------===// +// Diagnostic Options +//===----------------------------------------------------------------------===// + +def diagnostic_log_file : Separate<["-"], "diagnostic-log-file">, + HelpText<"Filename (or -) to log diagnostics to">; +def diagnostic_serialized_file : Separate<["-"], "serialize-diagnostic-file">, + MetaVarName<"<filename>">, + HelpText<"File for serializing diagnostics in a binary format">; + +def fdiagnostics_format : Separate<["-"], "fdiagnostics-format">, + HelpText<"Change diagnostic formatting to match IDE and command line tools">; +def fdiagnostics_show_category : Separate<["-"], "fdiagnostics-show-category">, + HelpText<"Print diagnostic category">; +def fno_diagnostics_use_presumed_location : Flag<["-"], "fno-diagnostics-use-presumed-location">, + HelpText<"Ignore #line directives when displaying diagnostic locations">; +def ftabstop : Separate<["-"], "ftabstop">, MetaVarName<"<N>">, + HelpText<"Set the tab stop distance.">; +def ferror_limit : Separate<["-"], "ferror-limit">, MetaVarName<"<N>">, + HelpText<"Set the maximum number of errors to emit before stopping (0 = no limit).">; +def fmacro_backtrace_limit : Separate<["-"], "fmacro-backtrace-limit">, MetaVarName<"<N>">, + HelpText<"Set the maximum number of entries to print in a macro expansion backtrace (0 = no limit).">; +def ftemplate_backtrace_limit : Separate<["-"], "ftemplate-backtrace-limit">, MetaVarName<"<N>">, + HelpText<"Set the maximum number of entries to print in a template instantiation backtrace (0 = no limit).">; +def fconstexpr_backtrace_limit : Separate<["-"], "fconstexpr-backtrace-limit">, MetaVarName<"<N>">, + HelpText<"Set the maximum number of entries to print in a constexpr evaluation backtrace (0 = no limit).">; +def fspell_checking_limit : Separate<["-"], "fspell-checking-limit">, MetaVarName<"<N>">, + HelpText<"Set the maximum number of times to perform spell checking on unrecognized identifiers (0 = no limit).">; +def fmessage_length : Separate<["-"], "fmessage-length">, MetaVarName<"<N>">, + HelpText<"Format message diagnostics so that they fit within N columns or fewer, when possible.">; +def verify : Flag<["-"], "verify">, + HelpText<"Verify diagnostic output using comment directives">; +def verify_ignore_unexpected : Flag<["-"], "verify-ignore-unexpected">, + HelpText<"Ignore unexpected diagnostic messages">; +def verify_ignore_unexpected_EQ : CommaJoined<["-"], "verify-ignore-unexpected=">, + HelpText<"Ignore unexpected diagnostic messages">; +def Wno_rewrite_macros : Flag<["-"], "Wno-rewrite-macros">, + HelpText<"Silence ObjC rewriting warnings">; + +//===----------------------------------------------------------------------===// +// Frontend Options +//===----------------------------------------------------------------------===// + +// This isn't normally used, it is just here so we can parse a +// CompilerInvocation out of a driver-derived argument vector. +def cc1 : Flag<["-"], "cc1">; +def cc1as : Flag<["-"], "cc1as">; + +def ast_merge : Separate<["-"], "ast-merge">, + MetaVarName<"<ast file>">, + HelpText<"Merge the given AST file into the translation unit being compiled.">; +def aux_triple : Separate<["-"], "aux-triple">, + HelpText<"Auxiliary target triple.">; +def code_completion_at : Separate<["-"], "code-completion-at">, + MetaVarName<"<file>:<line>:<column>">, + HelpText<"Dump code-completion information at a location">; +def remap_file : Separate<["-"], "remap-file">, + MetaVarName<"<from>;<to>">, + HelpText<"Replace the contents of the <from> file with the contents of the <to> file">; +def code_completion_at_EQ : Joined<["-"], "code-completion-at=">, + Alias<code_completion_at>; +def code_completion_macros : Flag<["-"], "code-completion-macros">, + HelpText<"Include macros in code-completion results">; +def code_completion_patterns : Flag<["-"], "code-completion-patterns">, + HelpText<"Include code patterns in code-completion results">; +def no_code_completion_globals : Flag<["-"], "no-code-completion-globals">, + HelpText<"Do not include global declarations in code-completion results.">; +def code_completion_brief_comments : Flag<["-"], "code-completion-brief-comments">, + HelpText<"Include brief documentation comments in code-completion results.">; +def disable_free : Flag<["-"], "disable-free">, + HelpText<"Disable freeing of memory on exit">; +def load : Separate<["-"], "load">, MetaVarName<"<dsopath>">, + HelpText<"Load the named plugin (dynamic shared object)">; +def plugin : Separate<["-"], "plugin">, MetaVarName<"<name>">, + HelpText<"Use the named plugin action instead of the default action (use \"help\" to list available options)">; +def plugin_arg : JoinedAndSeparate<["-"], "plugin-arg-">, + MetaVarName<"<name> <arg>">, + HelpText<"Pass <arg> to plugin <name>">; +def add_plugin : Separate<["-"], "add-plugin">, MetaVarName<"<name>">, + HelpText<"Use the named plugin action in addition to the default action">; +def ast_dump_filter : Separate<["-"], "ast-dump-filter">, + MetaVarName<"<dump_filter>">, + HelpText<"Use with -ast-dump or -ast-print to dump/print only AST declaration" + " nodes having a certain substring in a qualified name. Use" + " -ast-list to list all filterable declaration node names.">; +def fno_modules_global_index : Flag<["-"], "fno-modules-global-index">, + HelpText<"Do not automatically generate or update the global module index">; +def fno_modules_error_recovery : Flag<["-"], "fno-modules-error-recovery">, + HelpText<"Do not automatically import modules for error recovery">; +def fmodule_implementation_of : Separate<["-"], "fmodule-implementation-of">, + MetaVarName<"<name>">, + HelpText<"Specify the name of the module whose implementation file this is">; +def fmodule_map_file_home_is_cwd : Flag<["-"], "fmodule-map-file-home-is-cwd">, + HelpText<"Use the current working directory as the home directory of " + "module maps specified by -fmodule-map-file=<FILE>">; +def fmodule_feature : Separate<["-"], "fmodule-feature">, + MetaVarName<"<feature>">, + HelpText<"Enable <feature> in module map requires declarations">; +def fmodules_embed_file_EQ : Joined<["-"], "fmodules-embed-file=">, + MetaVarName<"<file>">, + HelpText<"Embed the contents of the specified file into the module file " + "being compiled.">; +def fmodules_embed_all_files : Joined<["-"], "fmodules-embed-all-files">, + HelpText<"Embed the contents of all files read by this compilation into " + "the produced module file.">; +def fmodules_local_submodule_visibility : + Flag<["-"], "fmodules-local-submodule-visibility">, + HelpText<"Enforce name visibility rules across submodules of the same " + "top-level module.">; +def fmodule_format_EQ : Joined<["-"], "fmodule-format=">, + HelpText<"Select the container format for clang modules and PCH. " + "Supported options are 'raw' and 'obj'.">; +def ftest_module_file_extension_EQ : + Joined<["-"], "ftest-module-file-extension=">, + HelpText<"introduce a module file extension for testing purposes. " + "The argument is parsed as blockname:major:minor:hashed:user info">; +def fconcepts_ts : Flag<["-"], "fconcepts-ts">, + HelpText<"Enable C++ Extensions for Concepts.">; + +let Group = Action_Group in { + +def Eonly : Flag<["-"], "Eonly">, + HelpText<"Just run preprocessor, no output (for timings)">; +def dump_raw_tokens : Flag<["-"], "dump-raw-tokens">, + HelpText<"Lex file in raw mode and dump raw tokens">; +def analyze : Flag<["-"], "analyze">, + HelpText<"Run static analysis engine">; +def dump_tokens : Flag<["-"], "dump-tokens">, + HelpText<"Run preprocessor, dump internal rep of tokens">; +def init_only : Flag<["-"], "init-only">, + HelpText<"Only execute frontend initialization">; +def fixit : Flag<["-"], "fixit">, + HelpText<"Apply fix-it advice to the input source">; +def fixit_EQ : Joined<["-"], "fixit=">, + HelpText<"Apply fix-it advice creating a file with the given suffix">; +def print_preamble : Flag<["-"], "print-preamble">, + HelpText<"Print the \"preamble\" of a file, which is a candidate for implicit" + " precompiled headers.">; +def emit_html : Flag<["-"], "emit-html">, + HelpText<"Output input source as HTML">; +def ast_print : Flag<["-"], "ast-print">, + HelpText<"Build ASTs and then pretty-print them">; +def ast_list : Flag<["-"], "ast-list">, + HelpText<"Build ASTs and print the list of declaration node qualified names">; +def ast_dump : Flag<["-"], "ast-dump">, + HelpText<"Build ASTs and then debug dump them">; +def ast_dump_lookups : Flag<["-"], "ast-dump-lookups">, + HelpText<"Build ASTs and then debug dump their name lookup tables">; +def ast_view : Flag<["-"], "ast-view">, + HelpText<"Build ASTs and view them with GraphViz">; +def print_decl_contexts : Flag<["-"], "print-decl-contexts">, + HelpText<"Print DeclContexts and their Decls">; +def emit_module : Flag<["-"], "emit-module">, + HelpText<"Generate pre-compiled module file from a module map">; +def emit_pth : Flag<["-"], "emit-pth">, + HelpText<"Generate pre-tokenized header file">; +def emit_pch : Flag<["-"], "emit-pch">, + HelpText<"Generate pre-compiled header file">; +def emit_llvm_bc : Flag<["-"], "emit-llvm-bc">, + HelpText<"Build ASTs then convert to LLVM, emit .bc file">; +def emit_llvm_only : Flag<["-"], "emit-llvm-only">, + HelpText<"Build ASTs and convert to LLVM, discarding output">; +def emit_codegen_only : Flag<["-"], "emit-codegen-only">, + HelpText<"Generate machine code, but discard output">; +def emit_obj : Flag<["-"], "emit-obj">, + HelpText<"Emit native object files">; +def rewrite_test : Flag<["-"], "rewrite-test">, + HelpText<"Rewriter playground">; +def rewrite_macros : Flag<["-"], "rewrite-macros">, + HelpText<"Expand macros without full preprocessing">; +def migrate : Flag<["-"], "migrate">, + HelpText<"Migrate source code">; +} + +def emit_llvm_uselists : Flag<["-"], "emit-llvm-uselists">, + HelpText<"Preserve order of LLVM use-lists when serializing">; +def no_emit_llvm_uselists : Flag<["-"], "no-emit-llvm-uselists">, + HelpText<"Don't preserve order of LLVM use-lists when serializing">; + +def mt_migrate_directory : Separate<["-"], "mt-migrate-directory">, + HelpText<"Directory for temporary files produced during ARC or ObjC migration">; +def arcmt_check : Flag<["-"], "arcmt-check">, + HelpText<"Check for ARC migration issues that need manual handling">; +def arcmt_modify : Flag<["-"], "arcmt-modify">, + HelpText<"Apply modifications to files to conform to ARC">; +def arcmt_migrate : Flag<["-"], "arcmt-migrate">, + HelpText<"Apply modifications and produces temporary files that conform to ARC">; + +def print_stats : Flag<["-"], "print-stats">, + HelpText<"Print performance metrics and statistics">; +def fdump_record_layouts : Flag<["-"], "fdump-record-layouts">, + HelpText<"Dump record layout information">; +def fdump_record_layouts_simple : Flag<["-"], "fdump-record-layouts-simple">, + HelpText<"Dump record layout information in a simple form used for testing">; +def fix_what_you_can : Flag<["-"], "fix-what-you-can">, + HelpText<"Apply fix-it advice even in the presence of unfixable errors">; +def fix_only_warnings : Flag<["-"], "fix-only-warnings">, + HelpText<"Apply fix-it advice only for warnings, not errors">; +def fixit_recompile : Flag<["-"], "fixit-recompile">, + HelpText<"Apply fix-it changes and recompile">; +def fixit_to_temp : Flag<["-"], "fixit-to-temporary">, + HelpText<"Apply fix-it changes to temporary files">; + +def foverride_record_layout_EQ : Joined<["-"], "foverride-record-layout=">, + HelpText<"Override record layouts with those in the given file">; + +//===----------------------------------------------------------------------===// +// Language Options +//===----------------------------------------------------------------------===// + +let Flags = [CC1Option, CC1AsOption, NoDriverOption] in { + +def version : Flag<["-"], "version">, + HelpText<"Print the compiler version">; +def main_file_name : Separate<["-"], "main-file-name">, + HelpText<"Main file name to use for debug info">; + +} + +def fblocks_runtime_optional : Flag<["-"], "fblocks-runtime-optional">, + HelpText<"Weakly link in the blocks runtime">; +def fsjlj_exceptions : Flag<["-"], "fsjlj-exceptions">, + HelpText<"Use SjLj style exceptions">; +def fnew_ms_eh: Flag<["-"], "fnew-ms-eh">, + HelpText<"Use the new IR representation for MS exceptions">; +def split_dwarf_file : Separate<["-"], "split-dwarf-file">, + HelpText<"File name to use for split dwarf debug info output">; +def fno_wchar : Flag<["-"], "fno-wchar">, + HelpText<"Disable C++ builtin type wchar_t">; +def fconstant_string_class : Separate<["-"], "fconstant-string-class">, + MetaVarName<"<class name>">, + HelpText<"Specify the class to use for constant Objective-C string objects.">; +def fobjc_arc_cxxlib_EQ : Joined<["-"], "fobjc-arc-cxxlib=">, + HelpText<"Objective-C++ Automatic Reference Counting standard library kind">; +def fobjc_runtime_has_weak : Flag<["-"], "fobjc-runtime-has-weak">, + HelpText<"The target Objective-C runtime supports ARC weak operations">; +def fobjc_dispatch_method_EQ : Joined<["-"], "fobjc-dispatch-method=">, + HelpText<"Objective-C dispatch method to use">; +def disable_objc_default_synthesize_properties : Flag<["-"], "disable-objc-default-synthesize-properties">, + HelpText<"disable the default synthesis of Objective-C properties">; +def fencode_extended_block_signature : Flag<["-"], "fencode-extended-block-signature">, + HelpText<"enable extended encoding of block type signature">; +def pic_level : Separate<["-"], "pic-level">, + HelpText<"Value for __PIC__">; +def pie_level : Separate<["-"], "pie-level">, + HelpText<"Value for __PIE__">; +def fno_validate_pch : Flag<["-"], "fno-validate-pch">, + HelpText<"Disable validation of precompiled headers">; +def dump_deserialized_pch_decls : Flag<["-"], "dump-deserialized-decls">, + HelpText<"Dump declarations that are deserialized from PCH, for testing">; +def error_on_deserialized_pch_decl : Separate<["-"], "error-on-deserialized-decl">, + HelpText<"Emit error if a specific declaration is deserialized from PCH, for testing">; +def error_on_deserialized_pch_decl_EQ : Joined<["-"], "error-on-deserialized-decl=">, + Alias<error_on_deserialized_pch_decl>; +def static_define : Flag<["-"], "static-define">, + HelpText<"Should __STATIC__ be defined">; +def stack_protector : Separate<["-"], "stack-protector">, + HelpText<"Enable stack protectors">; +def stack_protector_buffer_size : Separate<["-"], "stack-protector-buffer-size">, + HelpText<"Lower bound for a buffer to be considered for stack protection">; +def fvisibility : Separate<["-"], "fvisibility">, + HelpText<"Default type and symbol visibility">; +def ftype_visibility : Separate<["-"], "ftype-visibility">, + HelpText<"Default type visibility">; +def ftemplate_depth : Separate<["-"], "ftemplate-depth">, + HelpText<"Maximum depth of recursive template instantiation">; +def foperator_arrow_depth : Separate<["-"], "foperator-arrow-depth">, + HelpText<"Maximum number of 'operator->'s to call for a member access">; +def fconstexpr_depth : Separate<["-"], "fconstexpr-depth">, + HelpText<"Maximum depth of recursive constexpr function calls">; +def fconstexpr_steps : Separate<["-"], "fconstexpr-steps">, + HelpText<"Maximum number of steps in constexpr function evaluation">; +def fbracket_depth : Separate<["-"], "fbracket-depth">, + HelpText<"Maximum nesting level for parentheses, brackets, and braces">; +def fconst_strings : Flag<["-"], "fconst-strings">, + HelpText<"Use a const qualified type for string literals in C and ObjC">; +def fno_const_strings : Flag<["-"], "fno-const-strings">, + HelpText<"Don't use a const qualified type for string literals in C and ObjC">; +def fno_bitfield_type_align : Flag<["-"], "fno-bitfield-type-align">, + HelpText<"Ignore bit-field types when aligning structures">; +def ffake_address_space_map : Flag<["-"], "ffake-address-space-map">, + HelpText<"Use a fake address space map; OpenCL testing purposes only">; +def faddress_space_map_mangling_EQ : Joined<["-"], "faddress-space-map-mangling=">, MetaVarName<"<yes|no|target>">, + HelpText<"Set the mode for address space map based mangling; OpenCL testing purposes only">; +def funknown_anytype : Flag<["-"], "funknown-anytype">, + HelpText<"Enable parser support for the __unknown_anytype type; for testing purposes only">; +def fdebugger_support : Flag<["-"], "fdebugger-support">, + HelpText<"Enable special debugger support behavior">; +def fdebugger_cast_result_to_id : Flag<["-"], "fdebugger-cast-result-to-id">, + HelpText<"Enable casting unknown expression results to id">; +def fdebugger_objc_literal : Flag<["-"], "fdebugger-objc-literal">, + HelpText<"Enable special debugger support for Objective-C subscripting and literals">; +def fdeprecated_macro : Flag<["-"], "fdeprecated-macro">, + HelpText<"Defines the __DEPRECATED macro">; +def fno_deprecated_macro : Flag<["-"], "fno-deprecated-macro">, + HelpText<"Undefines the __DEPRECATED macro">; +def fobjc_subscripting_legacy_runtime : Flag<["-"], "fobjc-subscripting-legacy-runtime">, + HelpText<"Allow Objective-C array and dictionary subscripting in legacy runtime">; +def vtordisp_mode_EQ : Joined<["-"], "vtordisp-mode=">, + HelpText<"Control vtordisp placement on win32 targets">; +def fno_rtti_data : Flag<["-"], "fno-rtti-data">, + HelpText<"Control emission of RTTI data">; +def fnative_half_type: Flag<["-"], "fnative-half-type">, + HelpText<"Use the native half type for __fp16 instead of promoting to float">; +def fallow_half_arguments_and_returns : Flag<["-"], "fallow-half-arguments-and-returns">, + HelpText<"Allow function arguments and returns of type half">; + +// C++ TSes. +def fcoroutines : Flag<["-"], "fcoroutines">, + HelpText<"Enable support for the C++ Coroutines TS">; + +//===----------------------------------------------------------------------===// +// Header Search Options +//===----------------------------------------------------------------------===// + +def nostdsysteminc : Flag<["-"], "nostdsysteminc">, + HelpText<"Disable standard system #include directories">; +def fdisable_module_hash : Flag<["-"], "fdisable-module-hash">, + HelpText<"Disable the module hash">; +def c_isystem : JoinedOrSeparate<["-"], "c-isystem">, MetaVarName<"<directory>">, + HelpText<"Add directory to the C SYSTEM include search path">; +def objc_isystem : JoinedOrSeparate<["-"], "objc-isystem">, + MetaVarName<"<directory>">, + HelpText<"Add directory to the ObjC SYSTEM include search path">; +def objcxx_isystem : JoinedOrSeparate<["-"], "objcxx-isystem">, + MetaVarName<"<directory>">, + HelpText<"Add directory to the ObjC++ SYSTEM include search path">; +def internal_isystem : JoinedOrSeparate<["-"], "internal-isystem">, + MetaVarName<"<directory>">, + HelpText<"Add directory to the internal system include search path; these " + "are assumed to not be user-provided and are used to model system " + "and standard headers' paths.">; +def internal_externc_isystem : JoinedOrSeparate<["-"], "internal-externc-isystem">, + MetaVarName<"<directory>">, + HelpText<"Add directory to the internal system include search path with " + "implicit extern \"C\" semantics; these are assumed to not be " + "user-provided and are used to model system and standard headers' " + "paths.">; + +//===----------------------------------------------------------------------===// +// Preprocessor Options +//===----------------------------------------------------------------------===// + +def include_pth : Separate<["-"], "include-pth">, MetaVarName<"<file>">, + HelpText<"Include file before parsing">; +def chain_include : Separate<["-"], "chain-include">, MetaVarName<"<file>">, + HelpText<"Include and chain a header file after turning it into PCH">; +def preamble_bytes_EQ : Joined<["-"], "preamble-bytes=">, + HelpText<"Assume that the precompiled header is a precompiled preamble " + "covering the first N bytes of the main file">; +def token_cache : Separate<["-"], "token-cache">, MetaVarName<"<path>">, + HelpText<"Use specified token cache file">; +def detailed_preprocessing_record : Flag<["-"], "detailed-preprocessing-record">, + HelpText<"include a detailed record of preprocessing actions">; + +//===----------------------------------------------------------------------===// +// OpenCL Options +//===----------------------------------------------------------------------===// + +def cl_opt_disable : Flag<["-"], "cl-opt-disable">, + HelpText<"OpenCL only. This option disables all optimizations. The default is optimizations are enabled.">; +def cl_strict_aliasing : Flag<["-"], "cl-strict-aliasing">, + HelpText<"OpenCL only. This option does nothing and is for compatibility with OpenCL 1.0">; +def cl_single_precision_constant : Flag<["-"], "cl-single-precision-constant">, + HelpText<"OpenCL only. Treat double precision floating-point constant as single precision constant.">; +def cl_finite_math_only : Flag<["-"], "cl-finite-math-only">, + HelpText<"OpenCL only. Allow floating-point optimizations that assume arguments and results are not NaNs or +-Inf.">; +def cl_kernel_arg_info : Flag<["-"], "cl-kernel-arg-info">, + HelpText<"OpenCL only. Generate kernel argument metadata.">; +def cl_unsafe_math_optimizations : Flag<["-"], "cl-unsafe-math-optimizations">, + HelpText<"OpenCL only. Allow unsafe floating-point optimizations. Also implies -cl-no-signed-zeros and -cl-mad-enable">; +def cl_fast_relaxed_math : Flag<["-"], "cl-fast-relaxed-math">, + HelpText<"OpenCL only. Sets -cl-finite-math-only and -cl-unsafe-math-optimizations, and defines __FAST_RELAXED_MATH__">; +def cl_mad_enable : Flag<["-"], "cl-mad-enable">, + HelpText<"OpenCL only. Enable less precise MAD instructions to be generated.">; +def cl_std_EQ : Joined<["-"], "cl-std=">, + HelpText<"OpenCL language standard to compile for">; +def cl_denorms_are_zero : Flag<["-"], "cl-denorms-are-zero">, + HelpText<"OpenCL only. Allow denormals to be flushed to zero">; + +//===----------------------------------------------------------------------===// +// CUDA Options +//===----------------------------------------------------------------------===// + +def fcuda_is_device : Flag<["-"], "fcuda-is-device">, + HelpText<"Generate code for CUDA device">; +def fcuda_allow_host_calls_from_host_device : Flag<["-"], + "fcuda-allow-host-calls-from-host-device">, + HelpText<"Allow host device functions to call host functions">; +def fcuda_disable_target_call_checks : Flag<["-"], + "fcuda-disable-target-call-checks">, + HelpText<"Disable all cross-target (host, device, etc.) call checks in CUDA">; +def fcuda_include_gpubinary : Separate<["-"], "fcuda-include-gpubinary">, + HelpText<"Incorporate CUDA device-side binary into host object file.">; +def fcuda_target_overloads : Flag<["-"], "fcuda-target-overloads">, + HelpText<"Enable function overloads based on CUDA target attributes.">; + +//===----------------------------------------------------------------------===// +// OpenMP Options +//===----------------------------------------------------------------------===// + +def fopenmp_is_device : Flag<["-"], "fopenmp-is-device">, + HelpText<"Generate code only for an OpenMP target device.">; +def omp_host_ir_file_path : Separate<["-"], "omp-host-ir-file-path">, + HelpText<"Path to the IR file produced by the frontend for the host.">; + +} // let Flags = [CC1Option] + + +//===----------------------------------------------------------------------===// +// cc1as-only Options +//===----------------------------------------------------------------------===// + +let Flags = [CC1AsOption, NoDriverOption] in { + +// Language Options +def n : Flag<["-"], "n">, + HelpText<"Don't automatically start assembly file with a text section">; + +// Frontend Options +def filetype : Separate<["-"], "filetype">, + HelpText<"Specify the output file type ('asm', 'null', or 'obj')">; + +// Transliterate Options +def output_asm_variant : Separate<["-"], "output-asm-variant">, + HelpText<"Select the asm variant index to use for output">; +def show_encoding : Flag<["-"], "show-encoding">, + HelpText<"Show instruction encoding information in transliterate mode">; +def show_inst : Flag<["-"], "show-inst">, + HelpText<"Show internal instruction representation in transliterate mode">; + +// Assemble Options +def dwarf_debug_producer : Separate<["-"], "dwarf-debug-producer">, + HelpText<"The string to embed in the Dwarf debug AT_producer record.">; + +} // let Flags = [CC1AsOption] diff --git a/contrib/llvm/tools/clang/include/clang/Driver/CLCompatOptions.td b/contrib/llvm/tools/clang/include/clang/Driver/CLCompatOptions.td new file mode 100644 index 0000000..16a5b72 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Driver/CLCompatOptions.td @@ -0,0 +1,342 @@ +//===--- CLCompatOptions.td - Options for clang-cl ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the options accepted by clang-cl. +// +//===----------------------------------------------------------------------===// + +def cl_Group : OptionGroup<"<clang-cl options>">, + HelpText<"CL.EXE COMPATIBILITY OPTIONS">; + +def cl_compile_Group : OptionGroup<"<clang-cl compile-only options>">, + Group<cl_Group>; + +def cl_ignored_Group : OptionGroup<"<clang-cl ignored options>">, + Group<cl_Group>; + +class CLFlag<string name> : Option<["/", "-"], name, KIND_FLAG>, + Group<cl_Group>, Flags<[CLOption, DriverOption]>; + +class CLCompileFlag<string name> : Option<["/", "-"], name, KIND_FLAG>, + Group<cl_compile_Group>, Flags<[CLOption, DriverOption]>; + +class CLIgnoredFlag<string name> : Option<["/", "-"], name, KIND_FLAG>, + Group<cl_ignored_Group>, Flags<[CLOption, DriverOption, HelpHidden]>; + +class CLJoined<string name> : Option<["/", "-"], name, KIND_JOINED>, + Group<cl_Group>, Flags<[CLOption, DriverOption]>; + +class CLCompileJoined<string name> : Option<["/", "-"], name, KIND_JOINED>, + Group<cl_compile_Group>, Flags<[CLOption, DriverOption]>; + +class CLIgnoredJoined<string name> : Option<["/", "-"], name, KIND_JOINED>, + Group<cl_ignored_Group>, Flags<[CLOption, DriverOption, HelpHidden]>; + +class CLJoinedOrSeparate<string name> : Option<["/", "-"], name, + KIND_JOINED_OR_SEPARATE>, Group<cl_Group>, Flags<[CLOption, DriverOption]>; + +class CLCompileJoinedOrSeparate<string name> : Option<["/", "-"], name, + KIND_JOINED_OR_SEPARATE>, Group<cl_compile_Group>, + Flags<[CLOption, DriverOption]>; + +class CLRemainingArgs<string name> : Option<["/", "-"], name, + KIND_REMAINING_ARGS>, Group<cl_Group>, Flags<[CLOption, DriverOption]>; + +// Aliases: +// (We don't put any of these in cl_compile_Group as the options they alias are +// already in the right group.) + +def _SLASH_Brepro : CLFlag<"Brepro">, + HelpText<"Emit an object file which can be reproduced over time">, + Alias<mincremental_linker_compatible>; +def _SLASH_Brepro_ : CLFlag<"Brepro-">, + HelpText<"Emit an object file which cannot be reproduced over time">, + Alias<mno_incremental_linker_compatible>; +def _SLASH_C : CLFlag<"C">, + HelpText<"Don't discard comments when preprocessing">, Alias<C>; +def _SLASH_c : CLFlag<"c">, HelpText<"Compile only">, Alias<c>; +def _SLASH_D : CLJoinedOrSeparate<"D">, HelpText<"Define macro">, + MetaVarName<"<macro[=value]>">, Alias<D>; +def _SLASH_E : CLFlag<"E">, HelpText<"Preprocess to stdout">, Alias<E>; +def _SLASH_fp_except : CLFlag<"fp:except">, HelpText<"">, Alias<ftrapping_math>; +def _SLASH_fp_except_ : CLFlag<"fp:except-">, + HelpText<"">, Alias<fno_trapping_math>; +def _SLASH_fp_fast : CLFlag<"fp:fast">, HelpText<"">, Alias<ffast_math>; +def _SLASH_fp_precise : CLFlag<"fp:precise">, + HelpText<"">, Alias<fno_fast_math>; +def _SLASH_fp_strict : CLFlag<"fp:strict">, HelpText<"">, Alias<fno_fast_math>; +def _SLASH_GA : CLFlag<"GA">, Alias<ftlsmodel_EQ>, AliasArgs<["local-exec"]>, + HelpText<"Assume thread-local variables are defined in the executable">; +def _SLASH_GR : CLFlag<"GR">, HelpText<"Enable emission of RTTI data">; +def _SLASH_GR_ : CLFlag<"GR-">, HelpText<"Disable emission of RTTI data">; +def _SLASH_GF_ : CLFlag<"GF-">, HelpText<"Disable string pooling">, + Alias<fwritable_strings>; +def _SLASH_Gs : CLJoined<"Gs">, HelpText<"Set stack probe size">, + Alias<mstack_probe_size>; +def _SLASH_Gy : CLFlag<"Gy">, HelpText<"Put each function in its own section">, + Alias<ffunction_sections>; +def _SLASH_Gy_ : CLFlag<"Gy-">, + HelpText<"Don't put each function in its own section">, + Alias<fno_function_sections>; +def _SLASH_Gw : CLFlag<"Gw">, HelpText<"Put each data item in its own section">, + Alias<fdata_sections>; +def _SLASH_Gw_ : CLFlag<"Gw-">, + HelpText<"Don't put each data item in its own section">, + Alias<fno_data_sections>; +def _SLASH_help : CLFlag<"help">, Alias<help>, + HelpText<"Display available options">; +def _SLASH_HELP : CLFlag<"HELP">, Alias<help>; +def _SLASH_I : CLJoinedOrSeparate<"I">, + HelpText<"Add directory to include search path">, MetaVarName<"<dir>">, + Alias<I>; +def _SLASH_J : CLFlag<"J">, HelpText<"Make char type unsigned">, + Alias<funsigned_char>; +def _SLASH_O0 : CLFlag<"O0">, Alias<O0>; +def _SLASH_O : CLJoined<"O">, HelpText<"Optimization level">; +def _SLASH_Ob0 : CLFlag<"Ob0">, HelpText<"Disable inlining">, + Alias<fno_inline>; +def _SLASH_Od : CLFlag<"Od">, HelpText<"Disable optimization">, Alias<O0>; +def _SLASH_Oi : CLFlag<"Oi">, HelpText<"Enable use of builtin functions">, + Alias<fbuiltin>; +def _SLASH_Oi_ : CLFlag<"Oi-">, HelpText<"Disable use of builtin functions">, + Alias<fno_builtin>; +def _SLASH_Os : CLFlag<"Os">, HelpText<"Optimize for size">, Alias<O>, + AliasArgs<["s"]>; +def _SLASH_Ot : CLFlag<"Ot">, HelpText<"Optimize for speed">, Alias<O>, + AliasArgs<["2"]>; +def _SLASH_QUESTION : CLFlag<"?">, Alias<help>, + HelpText<"Display available options">; +def _SLASH_Qvec : CLFlag<"Qvec">, + HelpText<"Enable the loop vectorization passes">, Alias<fvectorize>; +def _SLASH_Qvec_ : CLFlag<"Qvec-">, + HelpText<"Disable the loop vectorization passes">, Alias<fno_vectorize>; +def _SLASH_showIncludes : CLFlag<"showIncludes">, + HelpText<"Print info about included files to stderr">, + Alias<show_includes>; +def _SLASH_U : CLJoinedOrSeparate<"U">, HelpText<"Undefine macro">, + MetaVarName<"<macro>">, Alias<U>; +def _SLASH_W0 : CLFlag<"W0">, HelpText<"Disable all warnings">, Alias<w>; +def _SLASH_W1 : CLFlag<"W1">, HelpText<"Enable -Wall">, Alias<Wall>; +def _SLASH_W2 : CLFlag<"W2">, HelpText<"Enable -Wall">, Alias<Wall>; +def _SLASH_W3 : CLFlag<"W3">, HelpText<"Enable -Wall">, Alias<Wall>; +def _SLASH_W4 : CLFlag<"W4">, HelpText<"Enable -Wall and -Wextra">, Alias<WCL4>; +def _SLASH_Wall : CLFlag<"Wall">, HelpText<"Enable -Wall and -Wextra">, Alias<WCL4>; +def _SLASH_WX : CLFlag<"WX">, HelpText<"Treat warnings as errors">, + Alias<W_Joined>, AliasArgs<["error"]>; +def _SLASH_WX_ : CLFlag<"WX-">, HelpText<"Do not treat warnings as errors">, + Alias<W_Joined>, AliasArgs<["no-error"]>; +def _SLASH_w_flag : CLFlag<"w">, HelpText<"Disable all warnings">, Alias<w>; +def _SLASH_wd4005 : CLFlag<"wd4005">, Alias<W_Joined>, + AliasArgs<["no-macro-redefined"]>; +def _SLASH_wd4100 : CLFlag<"wd4100">, Alias<W_Joined>, + AliasArgs<["no-unused-parameter"]>; +def _SLASH_wd4910 : CLFlag<"wd4910">, Alias<W_Joined>, + AliasArgs<["no-dllexport-explicit-instantiation-decl"]>; +def _SLASH_wd4996 : CLFlag<"wd4996">, Alias<W_Joined>, + AliasArgs<["no-deprecated-declarations"]>; +def _SLASH_vd : CLJoined<"vd">, HelpText<"Control vtordisp placement">, + Alias<vtordisp_mode_EQ>; +def _SLASH_Zc_sizedDealloc : CLFlag<"Zc:sizedDealloc">, + HelpText<"Enable C++14 sized global deallocation functions">, + Alias<fsized_deallocation>; +def _SLASH_Zc_sizedDealloc_ : CLFlag<"Zc:sizedDealloc-">, + HelpText<"Disable C++14 sized global deallocation functions">, + Alias<fno_sized_deallocation>; +def _SLASH_Zc_strictStrings : CLFlag<"Zc:strictStrings">, + HelpText<"Treat string literals as const">, Alias<W_Joined>, + AliasArgs<["error=c++11-compat-deprecated-writable-strings"]>; +def _SLASH_Zc_threadSafeInit : CLFlag<"Zc:threadSafeInit">, + HelpText<"Enable thread-safe initialization of static variables">, + Alias<fthreadsafe_statics>; +def _SLASH_Zc_threadSafeInit_ : CLFlag<"Zc:threadSafeInit-">, + HelpText<"Disable thread-safe initialization of static variables">, + Alias<fno_threadsafe_statics>; +def _SLASH_Zc_trigraphs : CLFlag<"Zc:trigraphs">, + HelpText<"Enable trigraphs">, Alias<ftrigraphs>; +def _SLASH_Zc_trigraphs_off : CLFlag<"Zc:trigraphs-">, + HelpText<"Disable trigraphs (default)">, Alias<fno_trigraphs>; +def _SLASH_Z7 : CLFlag<"Z7">, + HelpText<"Enable CodeView debug information in object files">; +def _SLASH_Zi : CLFlag<"Zi">, Alias<_SLASH_Z7>, + HelpText<"Alias for /Z7. Does not produce PDBs.">; +def _SLASH_Zp : CLJoined<"Zp">, + HelpText<"Specify the default maximum struct packing alignment">, + Alias<fpack_struct_EQ>; +def _SLASH_Zp_flag : CLFlag<"Zp">, + HelpText<"Set the default maximum struct packing alignment to 1">, + Alias<fpack_struct_EQ>, AliasArgs<["1"]>; +def _SLASH_Zs : CLFlag<"Zs">, HelpText<"Syntax-check only">, + Alias<fsyntax_only>; + + +// Non-aliases: + +def _SLASH_arch : CLCompileJoined<"arch:">, + HelpText<"Set architecture for code generation">; + +def _SLASH_M_Group : OptionGroup<"</M group>">, Group<cl_compile_Group>; +def _SLASH_volatile_Group : OptionGroup<"</volatile group>">, + Group<cl_compile_Group>; + +def _SLASH_EH : CLJoined<"EH">, HelpText<"Exception handling model">; +def _SLASH_EP : CLFlag<"EP">, + HelpText<"Disable linemarker output and preprocess to stdout">; +def _SLASH_FA : CLFlag<"FA">, + HelpText<"Output assembly code file during compilation">; +def _SLASH_Fa : CLJoined<"Fa">, + HelpText<"Output assembly code to this file during compilation (with /FA)">, + MetaVarName<"<file or directory>">; +def _SLASH_fallback : CLCompileFlag<"fallback">, + HelpText<"Fall back to cl.exe if clang-cl fails to compile">; +def _SLASH_FI : CLJoinedOrSeparate<"FI">, + HelpText<"Include file before parsing">, Alias<include_>; +def _SLASH_Fe : CLJoined<"Fe">, + HelpText<"Set output executable file or directory (ends in / or \\)">, + MetaVarName<"<file or directory>">; +def _SLASH_Fi : CLCompileJoined<"Fi">, + HelpText<"Set preprocess output file name (with /P)">, + MetaVarName<"<file>">; +def _SLASH_Fo : CLCompileJoined<"Fo">, + HelpText<"Set output object file, or directory (ends in / or \\) (with /c)">, + MetaVarName<"<file or directory>">; +def _SLASH_LD : CLFlag<"LD">, HelpText<"Create DLL">; +def _SLASH_LDd : CLFlag<"LDd">, HelpText<"Create debug DLL">; +def _SLASH_link : CLRemainingArgs<"link">, + HelpText<"Forward options to the linker">, MetaVarName<"<options>">; +def _SLASH_MD : Option<["/", "-"], "MD", KIND_FLAG>, Group<_SLASH_M_Group>, + Flags<[CLOption, DriverOption]>, HelpText<"Use DLL run-time">; +def _SLASH_MDd : Option<["/", "-"], "MDd", KIND_FLAG>, Group<_SLASH_M_Group>, + Flags<[CLOption, DriverOption]>, HelpText<"Use DLL debug run-time">; +def _SLASH_MT : Option<["/", "-"], "MT", KIND_FLAG>, Group<_SLASH_M_Group>, + Flags<[CLOption, DriverOption]>, HelpText<"Use static run-time">; +def _SLASH_MTd : Option<["/", "-"], "MTd", KIND_FLAG>, Group<_SLASH_M_Group>, + Flags<[CLOption, DriverOption]>, HelpText<"Use static debug run-time">; +def _SLASH_o : CLJoinedOrSeparate<"o">, + HelpText<"Set output file or directory (ends in / or \\)">, + MetaVarName<"<file or directory>">; +def _SLASH_P : CLFlag<"P">, HelpText<"Preprocess to file">; +def _SLASH_Tc : CLCompileJoinedOrSeparate<"Tc">, + HelpText<"Specify a C source file">, MetaVarName<"<filename>">; +def _SLASH_TC : CLCompileFlag<"TC">, HelpText<"Treat all source files as C">; +def _SLASH_Tp : CLCompileJoinedOrSeparate<"Tp">, + HelpText<"Specify a C++ source file">, MetaVarName<"<filename>">; +def _SLASH_TP : CLCompileFlag<"TP">, HelpText<"Treat all source files as C++">; +def _SLASH_volatile_iso : Option<["/", "-"], "volatile:iso", KIND_FLAG>, + Group<_SLASH_volatile_Group>, Flags<[CLOption, DriverOption]>, + HelpText<"Volatile loads and stores have standard semantics">; +def _SLASH_vmb : CLFlag<"vmb">, + HelpText<"Use a best-case representation method for member pointers">; +def _SLASH_vmg : CLFlag<"vmg">, + HelpText<"Use a most-general representation for member pointers">; +def _SLASH_vms : CLFlag<"vms">, + HelpText<"Set the default most-general representation to single inheritance">; +def _SLASH_vmm : CLFlag<"vmm">, + HelpText<"Set the default most-general representation to " + "multiple inheritance">; +def _SLASH_vmv : CLFlag<"vmv">, + HelpText<"Set the default most-general representation to " + "virtual inheritance">; +def _SLASH_volatile_ms : Option<["/", "-"], "volatile:ms", KIND_FLAG>, + Group<_SLASH_volatile_Group>, Flags<[CLOption, DriverOption]>, + HelpText<"Volatile loads and stores have acquire and release semantics">; +def _SLASH_Zl : CLFlag<"Zl">, + HelpText<"Don't mention any default libraries in the object file">; + +// Ignored: + +def _SLASH_analyze_ : CLIgnoredFlag<"analyze-">; +def _SLASH_bigobj : CLIgnoredFlag<"bigobj">; +def _SLASH_cgthreads : CLIgnoredJoined<"cgthreads">; +def _SLASH_d2Zi_PLUS : CLIgnoredFlag<"d2Zi+">; +def _SLASH_errorReport : CLIgnoredJoined<"errorReport">; +def _SLASH_Fd : CLIgnoredJoined<"Fd">; +def _SLASH_FS : CLIgnoredFlag<"FS">, HelpText<"Force synchronous PDB writes">; +def _SLASH_Gd : CLIgnoredFlag<"Gd">; +def _SLASH_GF : CLIgnoredFlag<"GF">; +def _SLASH_GS_ : CLIgnoredFlag<"GS-">; +def _SLASH_kernel_ : CLIgnoredFlag<"kernel-">; +def _SLASH_nologo : CLIgnoredFlag<"nologo">; +def _SLASH_Ob1 : CLIgnoredFlag<"Ob1">; +def _SLASH_Ob2 : CLIgnoredFlag<"Ob2">; +def _SLASH_Og : CLIgnoredFlag<"Og">; +def _SLASH_openmp_ : CLIgnoredFlag<"openmp-">; +def _SLASH_RTC : CLIgnoredJoined<"RTC">; +def _SLASH_sdl : CLIgnoredFlag<"sdl">; +def _SLASH_sdl_ : CLIgnoredFlag<"sdl-">; +def _SLASH_w : CLIgnoredJoined<"w">; +def _SLASH_Zc_auto : CLIgnoredFlag<"Zc:auto">; +def _SLASH_Zc_forScope : CLIgnoredFlag<"Zc:forScope">; +def _SLASH_Zc_inline : CLIgnoredFlag<"Zc:inline">; +def _SLASH_Zc_rvalueCast : CLIgnoredFlag<"Zc:rvalueCast">; +def _SLASH_Zc_wchar_t : CLIgnoredFlag<"Zc:wchar_t">; +def _SLASH_Zm : CLIgnoredJoined<"Zm">; +def _SLASH_Zo : CLIgnoredFlag<"Zo">; +def _SLASH_Zo_ : CLIgnoredFlag<"Zo-">; + + +// Unsupported: + +def _SLASH_AI : CLJoined<"AI">; +def _SLASH_clr : CLJoined<"clr">; +def _SLASH_doc : CLJoined<"doc">; +def _SLASH_FA_joined : CLJoined<"FA">; +def _SLASH_favor : CLJoined<"favor">; +def _SLASH_FC : CLFlag<"FC">; +def _SLASH_F : CLFlag<"F">; +def _SLASH_Fm : CLJoined<"Fm">; +def _SLASH_Fp : CLJoined<"Fp">; +def _SLASH_Fr : CLJoined<"Fr">; +def _SLASH_FR : CLJoined<"FR">; +def _SLASH_FU : CLJoinedOrSeparate<"FU">; +def _SLASH_Fx : CLFlag<"Fx">; +def _SLASH_G1 : CLFlag<"G1">; +def _SLASH_G2 : CLFlag<"G2">; +def _SLASH_Ge : CLFlag<"Ge">; +def _SLASH_Gh : CLFlag<"Gh">; +def _SLASH_GH : CLFlag<"GH">; +def _SLASH_GL : CLFlag<"GL">; +def _SLASH_GL_ : CLFlag<"GL-">; +def _SLASH_Gm : CLFlag<"Gm">; +def _SLASH_Gm_ : CLFlag<"Gm-">; +def _SLASH_Gr : CLFlag<"Gr">; +def _SLASH_GS : CLFlag<"GS">; +def _SLASH_GT : CLFlag<"GT">; +def _SLASH_Guard : CLJoined<"guard:">; +def _SLASH_GX : CLFlag<"GX">; +def _SLASH_Gv : CLFlag<"Gv">; +def _SLASH_Gz : CLFlag<"Gz">; +def _SLASH_GZ : CLFlag<"GZ">; +def _SLASH_H : CLFlag<"H">; +def _SLASH_homeparams : CLFlag<"homeparams">; +def _SLASH_hotpatch : CLFlag<"hotpatch">; +def _SLASH_kernel : CLFlag<"kernel">; +def _SLASH_LN : CLFlag<"LN">; +def _SLASH_MP : CLJoined<"MP">; +def _SLASH_openmp : CLFlag<"openmp">; +def _SLASH_Qfast_transcendentals : CLFlag<"Qfast_transcendentals">; +def _SLASH_QIfist : CLFlag<"QIfist">; +def _SLASH_Qimprecise_fwaits : CLFlag<"Qimprecise_fwaits">; +def _SLASH_Qpar : CLFlag<"Qpar">; +def _SLASH_Qvec_report : CLJoined<"Qvec-report">; +def _SLASH_u : CLFlag<"u">; +def _SLASH_V : CLFlag<"V">; +def _SLASH_WL : CLFlag<"WL">; +def _SLASH_Wp64 : CLFlag<"Wp64">; +def _SLASH_X : CLFlag<"X">; +def _SLASH_Yc : CLJoined<"Yc">; +def _SLASH_Y_ : CLFlag<"Y-">; +def _SLASH_Yd : CLFlag<"Yd">; +def _SLASH_Yl : CLJoined<"Yl">; +def _SLASH_Yu : CLJoined<"Yu">; +def _SLASH_Za : CLFlag<"Za">; +def _SLASH_Zc : CLJoined<"Zc:">; +def _SLASH_Ze : CLFlag<"Ze">; +def _SLASH_Zg : CLFlag<"Zg">; +def _SLASH_ZI : CLFlag<"ZI">; +def _SLASH_ZW : CLJoined<"ZW">; diff --git a/contrib/llvm/tools/clang/include/clang/Driver/Compilation.h b/contrib/llvm/tools/clang/include/clang/Driver/Compilation.h new file mode 100644 index 0000000..12ff068 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Driver/Compilation.h @@ -0,0 +1,202 @@ +//===--- Compilation.h - Compilation Task Data Structure --------*- 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_DRIVER_COMPILATION_H +#define LLVM_CLANG_DRIVER_COMPILATION_H + +#include "clang/Driver/Action.h" +#include "clang/Driver/Job.h" +#include "clang/Driver/Util.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/Support/Path.h" + +namespace llvm { +namespace opt { + class DerivedArgList; + class InputArgList; +} +} + +namespace clang { +namespace driver { + class Driver; + class JobList; + class ToolChain; + +/// Compilation - A set of tasks to perform for a single driver +/// invocation. +class Compilation { + /// The driver we were created by. + const Driver &TheDriver; + + /// The default tool chain. + const ToolChain &DefaultToolChain; + + const ToolChain *CudaHostToolChain; + const ToolChain *CudaDeviceToolChain; + + /// The original (untranslated) input argument list. + llvm::opt::InputArgList *Args; + + /// The driver translated arguments. Note that toolchains may perform their + /// own argument translation. + llvm::opt::DerivedArgList *TranslatedArgs; + + /// The list of actions. + ActionList Actions; + + /// The root list of jobs. + JobList Jobs; + + /// Cache of translated arguments for a particular tool chain and bound + /// architecture. + llvm::DenseMap<std::pair<const ToolChain *, const char *>, + llvm::opt::DerivedArgList *> TCArgs; + + /// Temporary files which should be removed on exit. + llvm::opt::ArgStringList TempFiles; + + /// Result files which should be removed on failure. + ArgStringMap ResultFiles; + + /// Result files which are generated correctly on failure, and which should + /// only be removed if we crash. + ArgStringMap FailureResultFiles; + + /// Redirection for stdout, stderr, etc. + const StringRef **Redirects; + + /// Whether we're compiling for diagnostic purposes. + bool ForDiagnostics; + +public: + Compilation(const Driver &D, const ToolChain &DefaultToolChain, + llvm::opt::InputArgList *Args, + llvm::opt::DerivedArgList *TranslatedArgs); + ~Compilation(); + + const Driver &getDriver() const { return TheDriver; } + + const ToolChain &getDefaultToolChain() const { return DefaultToolChain; } + const ToolChain *getCudaHostToolChain() const { return CudaHostToolChain; } + const ToolChain *getCudaDeviceToolChain() const { + return CudaDeviceToolChain; + } + + void setCudaHostToolChain(const ToolChain *HostToolChain) { + CudaHostToolChain = HostToolChain; + } + void setCudaDeviceToolChain(const ToolChain *DeviceToolChain) { + CudaDeviceToolChain = DeviceToolChain; + } + + const llvm::opt::InputArgList &getInputArgs() const { return *Args; } + + const llvm::opt::DerivedArgList &getArgs() const { return *TranslatedArgs; } + + llvm::opt::DerivedArgList &getArgs() { return *TranslatedArgs; } + + ActionList &getActions() { return Actions; } + const ActionList &getActions() const { return Actions; } + + JobList &getJobs() { return Jobs; } + const JobList &getJobs() const { return Jobs; } + + void addCommand(std::unique_ptr<Command> C) { Jobs.addJob(std::move(C)); } + + const llvm::opt::ArgStringList &getTempFiles() const { return TempFiles; } + + const ArgStringMap &getResultFiles() const { return ResultFiles; } + + const ArgStringMap &getFailureResultFiles() const { + return FailureResultFiles; + } + + /// Returns the sysroot path. + StringRef getSysRoot() const; + + /// getArgsForToolChain - Return the derived argument list for the + /// tool chain \p TC (or the default tool chain, if TC is not specified). + /// + /// \param BoundArch - The bound architecture name, or 0. + const llvm::opt::DerivedArgList &getArgsForToolChain(const ToolChain *TC, + const char *BoundArch); + + /// addTempFile - Add a file to remove on exit, and returns its + /// argument. + const char *addTempFile(const char *Name) { + TempFiles.push_back(Name); + return Name; + } + + /// addResultFile - Add a file to remove on failure, and returns its + /// argument. + const char *addResultFile(const char *Name, const JobAction *JA) { + ResultFiles[JA] = Name; + return Name; + } + + /// addFailureResultFile - Add a file to remove if we crash, and returns its + /// argument. + const char *addFailureResultFile(const char *Name, const JobAction *JA) { + FailureResultFiles[JA] = Name; + return Name; + } + + /// CleanupFile - Delete a given file. + /// + /// \param IssueErrors - Report failures as errors. + /// \return Whether the file was removed successfully. + bool CleanupFile(const char *File, bool IssueErrors = false) const; + + /// CleanupFileList - Remove the files in the given list. + /// + /// \param IssueErrors - Report failures as errors. + /// \return Whether all files were removed successfully. + bool CleanupFileList(const llvm::opt::ArgStringList &Files, + bool IssueErrors = false) const; + + /// CleanupFileMap - Remove the files in the given map. + /// + /// \param JA - If specified, only delete the files associated with this + /// JobAction. Otherwise, delete all files in the map. + /// \param IssueErrors - Report failures as errors. + /// \return Whether all files were removed successfully. + bool CleanupFileMap(const ArgStringMap &Files, + const JobAction *JA, + bool IssueErrors = false) const; + + /// ExecuteCommand - Execute an actual command. + /// + /// \param FailingCommand - For non-zero results, this will be set to the + /// Command which failed, if any. + /// \return The result code of the subprocess. + int ExecuteCommand(const Command &C, const Command *&FailingCommand) const; + + /// ExecuteJob - Execute a single job. + /// + /// \param FailingCommands - For non-zero results, this will be a vector of + /// failing commands and their associated result code. + void ExecuteJobs( + const JobList &Jobs, + SmallVectorImpl<std::pair<int, const Command *>> &FailingCommands) const; + + /// initCompilationForDiagnostics - Remove stale state and suppress output + /// so compilation can be reexecuted to generate additional diagnostic + /// information (e.g., preprocessed source(s)). + void initCompilationForDiagnostics(); + + /// Return true if we're compiling for diagnostics. + bool isForDiagnostics() const { return ForDiagnostics; } +}; + +} // end namespace driver +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Driver/Driver.h b/contrib/llvm/tools/clang/include/clang/Driver/Driver.h new file mode 100644 index 0000000..c9940ba --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Driver/Driver.h @@ -0,0 +1,468 @@ +//===--- Driver.h - Clang GCC Compatible Driver -----------------*- 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_DRIVER_DRIVER_H +#define LLVM_CLANG_DRIVER_DRIVER_H + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/LLVM.h" +#include "clang/Driver/Phases.h" +#include "clang/Driver/Types.h" +#include "clang/Driver/Util.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Path.h" // FIXME: Kill when CompilationInfo +#include <memory> + // lands. +#include <list> +#include <set> +#include <string> + +namespace llvm { +namespace opt { + class Arg; + class ArgList; + class DerivedArgList; + class InputArgList; + class OptTable; +} +} + +namespace clang { + +namespace vfs { +class FileSystem; +} + +namespace driver { + + class Action; + class Command; + class Compilation; + class InputInfo; + class JobList; + class JobAction; + class SanitizerArgs; + class ToolChain; + +/// Describes the kind of LTO mode selected via -f(no-)?lto(=.*)? options. +enum LTOKind { + LTOK_None, + LTOK_Full, + LTOK_Thin, + LTOK_Unknown +}; + +/// Driver - Encapsulate logic for constructing compilation processes +/// from a set of gcc-driver-like command line arguments. +class Driver { + llvm::opt::OptTable *Opts; + + DiagnosticsEngine &Diags; + + IntrusiveRefCntPtr<vfs::FileSystem> VFS; + + enum DriverMode { + GCCMode, + GXXMode, + CPPMode, + CLMode + } Mode; + + enum SaveTempsMode { + SaveTempsNone, + SaveTempsCwd, + SaveTempsObj + } SaveTemps; + + /// LTO mode selected via -f(no-)?lto(=.*)? options. + LTOKind LTOMode; + +public: + // Diag - Forwarding function for diagnostics. + DiagnosticBuilder Diag(unsigned DiagID) const { + return Diags.Report(DiagID); + } + + // FIXME: Privatize once interface is stable. +public: + /// The name the driver was invoked as. + std::string Name; + + /// The path the driver executable was in, as invoked from the + /// command line. + std::string Dir; + + /// The original path to the clang executable. + std::string ClangExecutable; + + /// The path to the installed clang directory, if any. + std::string InstalledDir; + + /// The path to the compiler resource directory. + std::string ResourceDir; + + /// A prefix directory used to emulate a limited subset of GCC's '-Bprefix' + /// functionality. + /// FIXME: This type of customization should be removed in favor of the + /// universal driver when it is ready. + typedef SmallVector<std::string, 4> prefix_list; + prefix_list PrefixDirs; + + /// sysroot, if present + std::string SysRoot; + + /// Dynamic loader prefix, if present + std::string DyldPrefix; + + /// If the standard library is used + bool UseStdLib; + + /// Default target triple. + std::string DefaultTargetTriple; + + /// Driver title to use with help. + std::string DriverTitle; + + /// Information about the host which can be overridden by the user. + std::string HostBits, HostMachine, HostSystem, HostRelease; + + /// The file to log CC_PRINT_OPTIONS output to, if enabled. + const char *CCPrintOptionsFilename; + + /// The file to log CC_PRINT_HEADERS output to, if enabled. + const char *CCPrintHeadersFilename; + + /// The file to log CC_LOG_DIAGNOSTICS output to, if enabled. + const char *CCLogDiagnosticsFilename; + + /// A list of inputs and their types for the given arguments. + typedef SmallVector<std::pair<types::ID, const llvm::opt::Arg *>, 16> + InputList; + + /// Whether the driver should follow g++ like behavior. + bool CCCIsCXX() const { return Mode == GXXMode; } + + /// Whether the driver is just the preprocessor. + bool CCCIsCPP() const { return Mode == CPPMode; } + + /// Whether the driver should follow cl.exe like behavior. + bool IsCLMode() const { return Mode == CLMode; } + + /// Only print tool bindings, don't build any jobs. + unsigned CCCPrintBindings : 1; + + /// Set CC_PRINT_OPTIONS mode, which is like -v but logs the commands to + /// CCPrintOptionsFilename or to stderr. + unsigned CCPrintOptions : 1; + + /// Set CC_PRINT_HEADERS mode, which causes the frontend to log header include + /// information to CCPrintHeadersFilename or to stderr. + unsigned CCPrintHeaders : 1; + + /// Set CC_LOG_DIAGNOSTICS mode, which causes the frontend to log diagnostics + /// to CCLogDiagnosticsFilename or to stderr, in a stable machine readable + /// format. + unsigned CCLogDiagnostics : 1; + + /// Whether the driver is generating diagnostics for debugging purposes. + unsigned CCGenDiagnostics : 1; + +private: + /// Name to use when invoking gcc/g++. + std::string CCCGenericGCCName; + + /// Whether to check that input files exist when constructing compilation + /// jobs. + unsigned CheckInputsExist : 1; + +public: + /// Use lazy precompiled headers for PCH support. + unsigned CCCUsePCH : 1; + +private: + /// Certain options suppress the 'no input files' warning. + bool SuppressMissingInputWarning : 1; + + std::list<std::string> TempFiles; + std::list<std::string> ResultFiles; + + /// \brief Cache of all the ToolChains in use by the driver. + /// + /// This maps from the string representation of a triple to a ToolChain + /// created targeting that triple. The driver owns all the ToolChain objects + /// stored in it, and will clean them up when torn down. + mutable llvm::StringMap<ToolChain *> ToolChains; + +private: + /// TranslateInputArgs - Create a new derived argument list from the input + /// arguments, after applying the standard argument translations. + llvm::opt::DerivedArgList * + TranslateInputArgs(const llvm::opt::InputArgList &Args) const; + + // getFinalPhase - Determine which compilation mode we are in and record + // which option we used to determine the final phase. + phases::ID getFinalPhase(const llvm::opt::DerivedArgList &DAL, + llvm::opt::Arg **FinalPhaseArg = nullptr) const; + + // Before executing jobs, sets up response files for commands that need them. + void setUpResponseFiles(Compilation &C, Command &Cmd); + + void generatePrefixedToolNames(const char *Tool, const ToolChain &TC, + SmallVectorImpl<std::string> &Names) const; + +public: + Driver(StringRef ClangExecutable, StringRef DefaultTargetTriple, + DiagnosticsEngine &Diags, + IntrusiveRefCntPtr<vfs::FileSystem> VFS = nullptr); + ~Driver(); + + /// @name Accessors + /// @{ + + /// Name to use when invoking gcc/g++. + const std::string &getCCCGenericGCCName() const { return CCCGenericGCCName; } + + const llvm::opt::OptTable &getOpts() const { return *Opts; } + + const DiagnosticsEngine &getDiags() const { return Diags; } + + vfs::FileSystem &getVFS() const { return *VFS; } + + bool getCheckInputsExist() const { return CheckInputsExist; } + + void setCheckInputsExist(bool Value) { CheckInputsExist = Value; } + + const std::string &getTitle() { return DriverTitle; } + void setTitle(std::string Value) { DriverTitle = Value; } + + /// \brief Get the path to the main clang executable. + const char *getClangProgramPath() const { + return ClangExecutable.c_str(); + } + + /// \brief Get the path to where the clang executable was installed. + const char *getInstalledDir() const { + if (!InstalledDir.empty()) + return InstalledDir.c_str(); + return Dir.c_str(); + } + void setInstalledDir(StringRef Value) { + InstalledDir = Value; + } + + bool isSaveTempsEnabled() const { return SaveTemps != SaveTempsNone; } + bool isSaveTempsObj() const { return SaveTemps == SaveTempsObj; } + + /// @} + /// @name Primary Functionality + /// @{ + + /// BuildCompilation - Construct a compilation object for a command + /// line argument vector. + /// + /// \return A compilation, or 0 if none was built for the given + /// argument vector. A null return value does not necessarily + /// indicate an error condition, the diagnostics should be queried + /// to determine if an error occurred. + Compilation *BuildCompilation(ArrayRef<const char *> Args); + + /// @name Driver Steps + /// @{ + + /// ParseDriverMode - Look for and handle the driver mode option in Args. + void ParseDriverMode(ArrayRef<const char *> Args); + + /// ParseArgStrings - Parse the given list of strings into an + /// ArgList. + llvm::opt::InputArgList ParseArgStrings(ArrayRef<const char *> Args); + + /// BuildInputs - Construct the list of inputs and their types from + /// the given arguments. + /// + /// \param TC - The default host tool chain. + /// \param Args - The input arguments. + /// \param Inputs - The list to store the resulting compilation + /// inputs onto. + void BuildInputs(const ToolChain &TC, llvm::opt::DerivedArgList &Args, + InputList &Inputs) const; + + /// BuildActions - Construct the list of actions to perform for the + /// given arguments, which are only done for a single architecture. + /// + /// \param C - The compilation that is being built. + /// \param TC - The default host tool chain. + /// \param Args - The input arguments. + /// \param Actions - The list to store the resulting actions onto. + void BuildActions(Compilation &C, const ToolChain &TC, + llvm::opt::DerivedArgList &Args, const InputList &Inputs, + ActionList &Actions) const; + + /// BuildUniversalActions - Construct the list of actions to perform + /// for the given arguments, which may require a universal build. + /// + /// \param C - The compilation that is being built. + /// \param TC - The default host tool chain. + void BuildUniversalActions(Compilation &C, const ToolChain &TC, + const InputList &BAInputs) const; + + /// BuildJobs - Bind actions to concrete tools and translate + /// arguments to form the list of jobs to run. + /// + /// \param C - The compilation that is being built. + void BuildJobs(Compilation &C) const; + + /// ExecuteCompilation - Execute the compilation according to the command line + /// arguments and return an appropriate exit code. + /// + /// This routine handles additional processing that must be done in addition + /// to just running the subprocesses, for example reporting errors, setting + /// up response files, removing temporary files, etc. + int ExecuteCompilation(Compilation &C, + SmallVectorImpl< std::pair<int, const Command *> > &FailingCommands); + + /// generateCompilationDiagnostics - Generate diagnostics information + /// including preprocessed source file(s). + /// + void generateCompilationDiagnostics(Compilation &C, + const Command &FailingCommand); + + /// @} + /// @name Helper Methods + /// @{ + + /// PrintActions - Print the list of actions. + void PrintActions(const Compilation &C) const; + + /// PrintHelp - Print the help text. + /// + /// \param ShowHidden - Show hidden options. + void PrintHelp(bool ShowHidden) const; + + /// PrintVersion - Print the driver version. + void PrintVersion(const Compilation &C, raw_ostream &OS) const; + + /// GetFilePath - Lookup \p Name in the list of file search paths. + /// + /// \param TC - The tool chain for additional information on + /// directories to search. + // + // FIXME: This should be in CompilationInfo. + std::string GetFilePath(const char *Name, const ToolChain &TC) const; + + /// GetProgramPath - Lookup \p Name in the list of program search paths. + /// + /// \param TC - The provided tool chain for additional information on + /// directories to search. + // + // FIXME: This should be in CompilationInfo. + std::string GetProgramPath(const char *Name, const ToolChain &TC) const; + + /// HandleImmediateArgs - Handle any arguments which should be + /// treated before building actions or binding tools. + /// + /// \return Whether any compilation should be built for this + /// invocation. + bool HandleImmediateArgs(const Compilation &C); + + /// ConstructAction - Construct the appropriate action to do for + /// \p Phase on the \p Input, taking in to account arguments + /// like -fsyntax-only or --analyze. + std::unique_ptr<Action> + ConstructPhaseAction(const ToolChain &TC, const llvm::opt::ArgList &Args, + phases::ID Phase, std::unique_ptr<Action> Input) const; + + /// BuildJobsForAction - Construct the jobs to perform for the + /// action \p A. + void BuildJobsForAction(Compilation &C, + const Action *A, + const ToolChain *TC, + const char *BoundArch, + bool AtTopLevel, + bool MultipleArchs, + const char *LinkingOutput, + InputInfo &Result) const; + + /// Returns the default name for linked images (e.g., "a.out"). + const char *getDefaultImageName() const; + + /// GetNamedOutputPath - Return the name to use for the output of + /// the action \p JA. The result is appended to the compilation's + /// list of temporary or result files, as appropriate. + /// + /// \param C - The compilation. + /// \param JA - The action of interest. + /// \param BaseInput - The original input file that this action was + /// triggered by. + /// \param BoundArch - The bound architecture. + /// \param AtTopLevel - Whether this is a "top-level" action. + /// \param MultipleArchs - Whether multiple -arch options were supplied. + const char *GetNamedOutputPath(Compilation &C, + const JobAction &JA, + const char *BaseInput, + const char *BoundArch, + bool AtTopLevel, + bool MultipleArchs) const; + + /// GetTemporaryPath - Return the pathname of a temporary file to use + /// as part of compilation; the file will have the given prefix and suffix. + /// + /// GCC goes to extra lengths here to be a bit more robust. + std::string GetTemporaryPath(StringRef Prefix, const char *Suffix) const; + + /// ShouldUseClangCompiler - Should the clang compiler be used to + /// handle this action. + bool ShouldUseClangCompiler(const JobAction &JA) const; + + /// Returns true if we are performing any kind of LTO. + bool isUsingLTO() const { return LTOMode != LTOK_None; } + + /// Get the specific kind of LTO being performed. + LTOKind getLTOMode() const { return LTOMode; } + +private: + /// Parse the \p Args list for LTO options and record the type of LTO + /// compilation based on which -f(no-)?lto(=.*)? option occurs last. + void setLTOMode(const llvm::opt::ArgList &Args); + + /// \brief Retrieves a ToolChain for a particular \p Target triple. + /// + /// Will cache ToolChains for the life of the driver object, and create them + /// on-demand. + const ToolChain &getToolChain(const llvm::opt::ArgList &Args, + const llvm::Triple &Target) const; + + /// @} + + /// \brief Get bitmasks for which option flags to include and exclude based on + /// the driver mode. + std::pair<unsigned, unsigned> getIncludeExcludeOptionFlagMasks() const; + +public: + /// GetReleaseVersion - Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and + /// return the grouped values as integers. Numbers which are not + /// provided are set to 0. + /// + /// \return True if the entire string was parsed (9.2), or all + /// groups were parsed (10.3.5extrastuff). HadExtra is true if all + /// groups were parsed but extra characters remain at the end. + static bool GetReleaseVersion(const char *Str, unsigned &Major, + unsigned &Minor, unsigned &Micro, + bool &HadExtra); +}; + +/// \return True if the last defined optimization level is -Ofast. +/// And False otherwise. +bool isOptimizationLevelFast(const llvm::opt::ArgList &Args); + +} // end namespace driver +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Driver/DriverDiagnostic.h b/contrib/llvm/tools/clang/include/clang/Driver/DriverDiagnostic.h new file mode 100644 index 0000000..680338a --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Driver/DriverDiagnostic.h @@ -0,0 +1,28 @@ +//===--- DiagnosticDriver.h - Diagnostics for libdriver ---------*- 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_DRIVER_DRIVERDIAGNOSTIC_H +#define LLVM_CLANG_DRIVER_DRIVERDIAGNOSTIC_H + +#include "clang/Basic/Diagnostic.h" + +namespace clang { + namespace diag { + enum { +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\ + SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM, +#define DRIVERSTART +#include "clang/Basic/DiagnosticDriverKinds.inc" +#undef DIAG + NUM_BUILTIN_DRIVER_DIAGNOSTICS + }; + } // end namespace diag +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Driver/Job.h b/contrib/llvm/tools/clang/include/clang/Driver/Job.h new file mode 100644 index 0000000..263356f --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Driver/Job.h @@ -0,0 +1,174 @@ +//===--- Job.h - Commands to Execute ----------------------------*- 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_DRIVER_JOB_H +#define LLVM_CLANG_DRIVER_JOB_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/iterator.h" +#include "llvm/Option/Option.h" +#include <memory> + +namespace llvm { + class raw_ostream; +} + +namespace clang { +namespace driver { +class Action; +class Command; +class Tool; +class InputInfo; + +// Re-export this as clang::driver::ArgStringList. +using llvm::opt::ArgStringList; + +struct CrashReportInfo { + StringRef Filename; + StringRef VFSPath; + + CrashReportInfo(StringRef Filename, StringRef VFSPath) + : Filename(Filename), VFSPath(VFSPath) {} +}; + +/// Command - An executable path/name and argument vector to +/// execute. +class Command { + /// Source - The action which caused the creation of this job. + const Action &Source; + + /// Tool - The tool which caused the creation of this job. + const Tool &Creator; + + /// The executable to run. + const char *Executable; + + /// The list of program arguments (not including the implicit first + /// argument, which will be the executable). + llvm::opt::ArgStringList Arguments; + + /// The list of program arguments which are inputs. + llvm::opt::ArgStringList InputFilenames; + + /// Response file name, if this command is set to use one, or nullptr + /// otherwise + const char *ResponseFile; + + /// The input file list in case we need to emit a file list instead of a + /// proper response file + llvm::opt::ArgStringList InputFileList; + + /// String storage if we need to create a new argument to specify a response + /// file + std::string ResponseFileFlag; + + /// When a response file is needed, we try to put most arguments in an + /// exclusive file, while others remains as regular command line arguments. + /// This functions fills a vector with the regular command line arguments, + /// argv, excluding the ones passed in a response file. + void buildArgvForResponseFile(llvm::SmallVectorImpl<const char *> &Out) const; + + /// Encodes an array of C strings into a single string separated by whitespace. + /// This function will also put in quotes arguments that have whitespaces and + /// will escape the regular backslashes (used in Windows paths) and quotes. + /// The results are the contents of a response file, written into a raw_ostream. + void writeResponseFile(raw_ostream &OS) const; + +public: + Command(const Action &Source, const Tool &Creator, const char *Executable, + const llvm::opt::ArgStringList &Arguments, + ArrayRef<InputInfo> Inputs); + // FIXME: This really shouldn't be copyable, but is currently copied in some + // error handling in Driver::generateCompilationDiagnostics. + Command(const Command &) = default; + virtual ~Command() {} + + virtual void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote, + CrashReportInfo *CrashInfo = nullptr) const; + + virtual int Execute(const StringRef **Redirects, std::string *ErrMsg, + bool *ExecutionFailed) const; + + /// getSource - Return the Action which caused the creation of this job. + const Action &getSource() const { return Source; } + + /// getCreator - Return the Tool which caused the creation of this job. + const Tool &getCreator() const { return Creator; } + + /// Set to pass arguments via a response file when launching the command + void setResponseFile(const char *FileName); + + /// Set an input file list, necessary if we need to use a response file but + /// the tool being called only supports input files lists. + void setInputFileList(llvm::opt::ArgStringList List) { + InputFileList = std::move(List); + } + + const char *getExecutable() const { return Executable; } + + const llvm::opt::ArgStringList &getArguments() const { return Arguments; } + + /// Print a command argument, and optionally quote it. + static void printArg(llvm::raw_ostream &OS, const char *Arg, bool Quote); +}; + +/// Like Command, but with a fallback which is executed in case +/// the primary command crashes. +class FallbackCommand : public Command { +public: + FallbackCommand(const Action &Source_, const Tool &Creator_, + const char *Executable_, const ArgStringList &Arguments_, + ArrayRef<InputInfo> Inputs, + std::unique_ptr<Command> Fallback_); + + void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote, + CrashReportInfo *CrashInfo = nullptr) const override; + + int Execute(const StringRef **Redirects, std::string *ErrMsg, + bool *ExecutionFailed) const override; + +private: + std::unique_ptr<Command> Fallback; +}; + +/// JobList - A sequence of jobs to perform. +class JobList { +public: + typedef SmallVector<std::unique_ptr<Command>, 4> list_type; + typedef list_type::size_type size_type; + typedef llvm::pointee_iterator<list_type::iterator> iterator; + typedef llvm::pointee_iterator<list_type::const_iterator> const_iterator; + +private: + list_type Jobs; + +public: + void Print(llvm::raw_ostream &OS, const char *Terminator, + bool Quote, CrashReportInfo *CrashInfo = nullptr) const; + + /// Add a job to the list (taking ownership). + void addJob(std::unique_ptr<Command> J) { Jobs.push_back(std::move(J)); } + + /// Clear the job list. + void clear(); + + const list_type &getJobs() const { return Jobs; } + + size_type size() const { return Jobs.size(); } + iterator begin() { return Jobs.begin(); } + const_iterator begin() const { return Jobs.begin(); } + iterator end() { return Jobs.end(); } + const_iterator end() const { return Jobs.end(); } +}; + +} // end namespace driver +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Driver/Multilib.h b/contrib/llvm/tools/clang/include/clang/Driver/Multilib.h new file mode 100644 index 0000000..20bb80d --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Driver/Multilib.h @@ -0,0 +1,175 @@ +//===--- Multilib.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_DRIVER_MULTILIB_H +#define LLVM_CLANG_DRIVER_MULTILIB_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Option/Option.h" +#include <functional> +#include <string> +#include <vector> + +namespace clang { +namespace driver { + +/// This corresponds to a single GCC Multilib, or a segment of one controlled +/// by a command line flag +class Multilib { +public: + typedef std::vector<std::string> flags_list; + +private: + std::string GCCSuffix; + std::string OSSuffix; + std::string IncludeSuffix; + flags_list Flags; + +public: + Multilib(StringRef GCCSuffix = "", StringRef OSSuffix = "", + StringRef IncludeSuffix = ""); + + /// \brief Get the detected GCC installation path suffix for the multi-arch + /// target variant. Always starts with a '/', unless empty + const std::string &gccSuffix() const { + assert(GCCSuffix.empty() || + (StringRef(GCCSuffix).front() == '/' && GCCSuffix.size() > 1)); + return GCCSuffix; + } + /// Set the GCC installation path suffix. + Multilib &gccSuffix(StringRef S); + + /// \brief Get the detected os path suffix for the multi-arch + /// target variant. Always starts with a '/', unless empty + const std::string &osSuffix() const { + assert(OSSuffix.empty() || + (StringRef(OSSuffix).front() == '/' && OSSuffix.size() > 1)); + return OSSuffix; + } + /// Set the os path suffix. + Multilib &osSuffix(StringRef S); + + /// \brief Get the include directory suffix. Always starts with a '/', unless + /// empty + const std::string &includeSuffix() const { + assert(IncludeSuffix.empty() || + (StringRef(IncludeSuffix).front() == '/' && IncludeSuffix.size() > 1)); + return IncludeSuffix; + } + /// Set the include directory suffix + Multilib &includeSuffix(StringRef S); + + /// \brief Get the flags that indicate or contraindicate this multilib's use + /// All elements begin with either '+' or '-' + const flags_list &flags() const { return Flags; } + flags_list &flags() { return Flags; } + /// Add a flag to the flags list + Multilib &flag(StringRef F) { + assert(F.front() == '+' || F.front() == '-'); + Flags.push_back(F); + return *this; + } + + /// \brief print summary of the Multilib + void print(raw_ostream &OS) const; + + /// Check whether any of the 'against' flags contradict the 'for' flags. + bool isValid() const; + + /// Check whether the default is selected + bool isDefault() const + { return GCCSuffix.empty() && OSSuffix.empty() && IncludeSuffix.empty(); } + + bool operator==(const Multilib &Other) const; +}; + +raw_ostream &operator<<(raw_ostream &OS, const Multilib &M); + +class MultilibSet { +public: + typedef std::vector<Multilib> multilib_list; + typedef multilib_list::iterator iterator; + typedef multilib_list::const_iterator const_iterator; + + typedef std::function<std::vector<std::string>( + StringRef InstallDir, StringRef Triple, const Multilib &M)> + IncludeDirsFunc; + + typedef llvm::function_ref<bool(const Multilib &)> FilterCallback; + +private: + multilib_list Multilibs; + IncludeDirsFunc IncludeCallback; + +public: + MultilibSet() {} + + /// Add an optional Multilib segment + MultilibSet &Maybe(const Multilib &M); + + /// Add a set of mutually incompatible Multilib segments + MultilibSet &Either(const Multilib &M1, const Multilib &M2); + MultilibSet &Either(const Multilib &M1, const Multilib &M2, + const Multilib &M3); + MultilibSet &Either(const Multilib &M1, const Multilib &M2, + const Multilib &M3, const Multilib &M4); + MultilibSet &Either(const Multilib &M1, const Multilib &M2, + const Multilib &M3, const Multilib &M4, + const Multilib &M5); + MultilibSet &Either(ArrayRef<Multilib> Ms); + + /// Filter out some subset of the Multilibs using a user defined callback + MultilibSet &FilterOut(FilterCallback F); + /// Filter out those Multilibs whose gccSuffix matches the given expression + MultilibSet &FilterOut(const char *Regex); + + /// Add a completed Multilib to the set + void push_back(const Multilib &M); + + /// Union this set of multilibs with another + void combineWith(const MultilibSet &MS); + + /// Remove all of thie multilibs from the set + void clear() { Multilibs.clear(); } + + iterator begin() { return Multilibs.begin(); } + const_iterator begin() const { return Multilibs.begin(); } + + iterator end() { return Multilibs.end(); } + const_iterator end() const { return Multilibs.end(); } + + /// Pick the best multilib in the set, \returns false if none are compatible + bool select(const Multilib::flags_list &Flags, Multilib &M) const; + + unsigned size() const { return Multilibs.size(); } + + void print(raw_ostream &OS) const; + + MultilibSet &setIncludeDirsCallback(IncludeDirsFunc F) { + IncludeCallback = std::move(F); + return *this; + } + const IncludeDirsFunc &includeDirsCallback() const { return IncludeCallback; } + +private: + /// Apply the filter to Multilibs and return the subset that remains + static multilib_list filterCopy(FilterCallback F, const multilib_list &Ms); + + /// Apply the filter to the multilib_list, removing those that don't match + static void filterInPlace(FilterCallback F, multilib_list &Ms); +}; + +raw_ostream &operator<<(raw_ostream &OS, const MultilibSet &MS); +} +} + +#endif + diff --git a/contrib/llvm/tools/clang/include/clang/Driver/Options.h b/contrib/llvm/tools/clang/include/clang/Driver/Options.h new file mode 100644 index 0000000..2716fa9 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Driver/Options.h @@ -0,0 +1,51 @@ +//===--- Options.h - Option info & table ------------------------*- 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_DRIVER_OPTIONS_H +#define LLVM_CLANG_DRIVER_OPTIONS_H + +namespace llvm { +namespace opt { +class OptTable; +} +} + +namespace clang { +namespace driver { + +namespace options { +/// Flags specifically for clang options. Must not overlap with +/// llvm::opt::DriverFlag. +enum ClangFlags { + DriverOption = (1 << 4), + LinkerInput = (1 << 5), + NoArgumentUnused = (1 << 6), + Unsupported = (1 << 7), + CoreOption = (1 << 8), + CLOption = (1 << 9), + CC1Option = (1 << 10), + CC1AsOption = (1 << 11), + NoDriverOption = (1 << 12) +}; + +enum ID { + OPT_INVALID = 0, // This is not an option ID. +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR) OPT_##ID, +#include "clang/Driver/Options.inc" + LastOption +#undef OPTION + }; +} + +llvm::opt::OptTable *createDriverOptTable(); +} +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Driver/Options.td b/contrib/llvm/tools/clang/include/clang/Driver/Options.td new file mode 100644 index 0000000..e219a9b --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Driver/Options.td @@ -0,0 +1,2133 @@ +//===--- Options.td - Options for clang -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the options accepted by clang. +// +//===----------------------------------------------------------------------===// + +// Include the common option parsing interfaces. +include "llvm/Option/OptParser.td" + +///////// +// Flags + +// DriverOption - The option is a "driver" option, and should not be forwarded +// to other tools. +def DriverOption : OptionFlag; + +// LinkerInput - The option is a linker input. +def LinkerInput : OptionFlag; + +// NoArgumentUnused - Don't report argument unused warnings for this option; this +// is useful for options like -static or -dynamic which a user may always end up +// passing, even if the platform defaults to (or only supports) that option. +def NoArgumentUnused : OptionFlag; + +// Unsupported - The option is unsupported, and the driver will reject command +// lines that use it. +def Unsupported : OptionFlag; + +// CoreOption - This is considered a "core" Clang option, available in both +// clang and clang-cl modes. +def CoreOption : OptionFlag; + +// CLOption - This is a cl.exe compatibility option. Options with this flag +// are made available when the driver is running in CL compatibility mode. +def CLOption : OptionFlag; + +// CC1Option - This option should be accepted by clang -cc1. +def CC1Option : OptionFlag; + +// CC1AsOption - This option should be accepted by clang -cc1as. +def CC1AsOption : OptionFlag; + +// NoDriverOption - This option should not be accepted by the driver. +def NoDriverOption : OptionFlag; + +///////// +// Groups + +// Meta-group for options which are only used for compilation, +// and not linking etc. +def CompileOnly_Group : OptionGroup<"<CompileOnly group>">; + +def Action_Group : OptionGroup<"<action group>">; + +def I_Group : OptionGroup<"<I group>">, Group<CompileOnly_Group>; +def M_Group : OptionGroup<"<M group>">, Group<CompileOnly_Group>; +def T_Group : OptionGroup<"<T group>">; +def O_Group : OptionGroup<"<O group>">, Group<CompileOnly_Group>; +def R_Group : OptionGroup<"<R group>">, Group<CompileOnly_Group>; +def R_value_Group : OptionGroup<"<R (with value) group>">, Group<R_Group>; +def W_Group : OptionGroup<"<W group>">, Group<CompileOnly_Group>; +def W_value_Group : OptionGroup<"<W (with value) group>">, Group<W_Group>; +def d_Group : OptionGroup<"<d group>">; +def f_Group : OptionGroup<"<f group>">, Group<CompileOnly_Group>; +def f_clang_Group : OptionGroup<"<f (clang-only) group>">, Group<CompileOnly_Group>; +def g_Group : OptionGroup<"<g group>">; +def gN_Group : OptionGroup<"<gN group>">, Group<g_Group>; +def ggdbN_Group : OptionGroup<"<ggdbN group>">, Group<gN_Group>; +def gTune_Group : OptionGroup<"<gTune group>">, Group<g_Group>; +def g_flags_Group : OptionGroup<"<g flags group>">; +def i_Group : OptionGroup<"<i group>">, Group<CompileOnly_Group>; +def clang_i_Group : OptionGroup<"<clang i group>">, Group<i_Group>; +def m_Group : OptionGroup<"<m group>">, Group<CompileOnly_Group>; + +// Feature groups - these take command line options that correspond directly to +// target specific features and can be translated directly from command line +// options. +def m_x86_Features_Group : OptionGroup<"<x86 features group>">, + Group<m_Group>, + Flags<[CoreOption]>; +def m_hexagon_Features_Group : OptionGroup<"<hexagon features group>">, + Group<m_Group>; +def m_arm_Features_Group : OptionGroup<"<arm features group>">, + Group<m_Group>; +def m_aarch64_Features_Group : OptionGroup<"<aarch64 features group>">, + Group<m_Group>; +def m_ppc_Features_Group : OptionGroup<"<ppc features group>">, + Group<m_Group>; +def m_wasm_Features_Group : OptionGroup<"<wasm features group>">, + Group<m_Group>; + +def m_libc_Group : OptionGroup<"<m libc group>">, Group<m_Group>; +def u_Group : OptionGroup<"<u group>">; + +def pedantic_Group : OptionGroup<"<pedantic group>">, + Group<CompileOnly_Group>; +def reserved_lib_Group : OptionGroup<"<reserved libs group>">; + +// Temporary groups for clang options which we know we don't support, +// but don't want to verbosely warn the user about. +def clang_ignored_f_Group : OptionGroup<"<clang ignored f group>">, + Group<f_Group>; +def clang_ignored_m_Group : OptionGroup<"<clang ignored m group>">, + Group<m_Group>; + +// Group that ignores all gcc optimizations that won't be implemented +def clang_ignored_gcc_optimization_f_Group : OptionGroup< + "<clang_ignored_gcc_optimization_f_Group>">, Group<f_Group>; + +///////// +// Options + +// The internal option ID must be a valid C++ identifier and results in a +// clang::driver::options::OPT_XX enum constant for XX. +// +// We want to unambiguously be able to refer to options from the driver source +// code, for this reason the option name is mangled into an ID. This mangling +// isn't guaranteed to have an inverse, but for practical purposes it does. +// +// The mangling scheme is to ignore the leading '-', and perform the following +// substitutions: +// _ => __ +// - => _ +// / => _SLASH +// # => _HASH +// ? => _QUESTION +// , => _COMMA +// = => _EQ +// C++ => CXX +// . => _ + +// Developer Driver Options + +def internal_Group : OptionGroup<"<clang internal options>">; +def internal_driver_Group : OptionGroup<"<clang driver internal options>">, + Group<internal_Group>, HelpText<"DRIVER OPTIONS">; +def internal_debug_Group : + OptionGroup<"<clang debug/development internal options>">, + Group<internal_Group>, HelpText<"DEBUG/DEVELOPMENT OPTIONS">; + +class InternalDriverOpt : Group<internal_driver_Group>, + Flags<[DriverOption, HelpHidden]>; +def driver_mode : Joined<["--"], "driver-mode=">, Group<internal_driver_Group>, + Flags<[CoreOption, DriverOption, HelpHidden]>, + HelpText<"Set the driver mode to either 'gcc', 'g++', 'cpp', or 'cl'">; +def ccc_gcc_name : Separate<["-"], "ccc-gcc-name">, InternalDriverOpt, + HelpText<"Name for native GCC compiler">, + MetaVarName<"<gcc-path>">; +def ccc_pch_is_pch : Flag<["-"], "ccc-pch-is-pch">, InternalDriverOpt, + HelpText<"Use lazy PCH for precompiled headers">; +def ccc_pch_is_pth : Flag<["-"], "ccc-pch-is-pth">, InternalDriverOpt, + HelpText<"Use pretokenized headers for precompiled headers">; + +class InternalDebugOpt : Group<internal_debug_Group>, + Flags<[DriverOption, HelpHidden, CoreOption]>; +def ccc_install_dir : Separate<["-"], "ccc-install-dir">, InternalDebugOpt, + HelpText<"Simulate installation in the given directory">; +def ccc_print_phases : Flag<["-"], "ccc-print-phases">, InternalDebugOpt, + HelpText<"Dump list of actions to perform">; +def ccc_print_bindings : Flag<["-"], "ccc-print-bindings">, InternalDebugOpt, + HelpText<"Show bindings of tools to actions">; + +def ccc_arcmt_check : Flag<["-"], "ccc-arcmt-check">, InternalDriverOpt, + HelpText<"Check for ARC migration issues that need manual handling">; +def ccc_arcmt_modify : Flag<["-"], "ccc-arcmt-modify">, InternalDriverOpt, + HelpText<"Apply modifications to files to conform to ARC">; +def ccc_arcmt_migrate : Separate<["-"], "ccc-arcmt-migrate">, InternalDriverOpt, + HelpText<"Apply modifications and produces temporary files that conform to ARC">; +def arcmt_migrate_report_output : Separate<["-"], "arcmt-migrate-report-output">, + HelpText<"Output path for the plist report">, Flags<[CC1Option]>; +def arcmt_migrate_emit_arc_errors : Flag<["-"], "arcmt-migrate-emit-errors">, + HelpText<"Emit ARC errors even if the migrator can fix them">, + Flags<[CC1Option]>; + +def _migrate : Flag<["--"], "migrate">, Flags<[DriverOption]>, + HelpText<"Run the migrator">; +def ccc_objcmt_migrate : Separate<["-"], "ccc-objcmt-migrate">, + InternalDriverOpt, + HelpText<"Apply modifications and produces temporary files to migrate to " + "modern ObjC syntax">; +def objcmt_migrate_literals : Flag<["-"], "objcmt-migrate-literals">, Flags<[CC1Option]>, + HelpText<"Enable migration to modern ObjC literals">; +def objcmt_migrate_subscripting : Flag<["-"], "objcmt-migrate-subscripting">, Flags<[CC1Option]>, + HelpText<"Enable migration to modern ObjC subscripting">; +def objcmt_migrate_property : Flag<["-"], "objcmt-migrate-property">, Flags<[CC1Option]>, + HelpText<"Enable migration to modern ObjC property">; +def objcmt_migrate_all : Flag<["-"], "objcmt-migrate-all">, Flags<[CC1Option]>, + HelpText<"Enable migration to modern ObjC">; +def objcmt_migrate_readonly_property : Flag<["-"], "objcmt-migrate-readonly-property">, Flags<[CC1Option]>, + HelpText<"Enable migration to modern ObjC readonly property">; +def objcmt_migrate_readwrite_property : Flag<["-"], "objcmt-migrate-readwrite-property">, Flags<[CC1Option]>, + HelpText<"Enable migration to modern ObjC readwrite property">; +def objcmt_migrate_property_dot_syntax : Flag<["-"], "objcmt-migrate-property-dot-syntax">, Flags<[CC1Option]>, + HelpText<"Enable migration of setter/getter messages to property-dot syntax">; +def objcmt_migrate_annotation : Flag<["-"], "objcmt-migrate-annotation">, Flags<[CC1Option]>, + HelpText<"Enable migration to property and method annotations">; +def objcmt_migrate_instancetype : Flag<["-"], "objcmt-migrate-instancetype">, Flags<[CC1Option]>, + HelpText<"Enable migration to infer instancetype for method result type">; +def objcmt_migrate_nsmacros : Flag<["-"], "objcmt-migrate-ns-macros">, Flags<[CC1Option]>, + HelpText<"Enable migration to NS_ENUM/NS_OPTIONS macros">; +def objcmt_migrate_protocol_conformance : Flag<["-"], "objcmt-migrate-protocol-conformance">, Flags<[CC1Option]>, + HelpText<"Enable migration to add protocol conformance on classes">; +def objcmt_atomic_property : Flag<["-"], "objcmt-atomic-property">, Flags<[CC1Option]>, + HelpText<"Make migration to 'atomic' properties">; +def objcmt_returns_innerpointer_property : Flag<["-"], "objcmt-returns-innerpointer-property">, Flags<[CC1Option]>, + HelpText<"Enable migration to annotate property with NS_RETURNS_INNER_POINTER">; +def objcmt_ns_nonatomic_iosonly: Flag<["-"], "objcmt-ns-nonatomic-iosonly">, Flags<[CC1Option]>, + HelpText<"Enable migration to use NS_NONATOMIC_IOSONLY macro for setting property's 'atomic' attribute">; +def objcmt_migrate_designated_init : Flag<["-"], "objcmt-migrate-designated-init">, Flags<[CC1Option]>, + HelpText<"Enable migration to infer NS_DESIGNATED_INITIALIZER for initializer methods">; +def objcmt_whitelist_dir_path: Joined<["-"], "objcmt-whitelist-dir-path=">, Flags<[CC1Option]>, + HelpText<"Only modify files with a filename contained in the provided directory path">; +// The misspelt "white-list" [sic] alias is due for removal. +def : Joined<["-"], "objcmt-white-list-dir-path=">, Flags<[CC1Option]>, + Alias<objcmt_whitelist_dir_path>; + +// Make sure all other -ccc- options are rejected. +def ccc_ : Joined<["-"], "ccc-">, Group<internal_Group>, Flags<[Unsupported]>; + +// Standard Options + +def _HASH_HASH_HASH : Flag<["-"], "###">, Flags<[DriverOption, CoreOption]>, + HelpText<"Print (but do not run) the commands to run for this compilation">; +def _DASH_DASH : Option<["--"], "", KIND_REMAINING_ARGS>, + Flags<[DriverOption, CoreOption]>; +def A : JoinedOrSeparate<["-"], "A">, Flags<[RenderJoined]>; +def B : JoinedOrSeparate<["-"], "B">; +def CC : Flag<["-"], "CC">, Flags<[CC1Option]>; +def C : Flag<["-"], "C">, Flags<[CC1Option]>; +def D : JoinedOrSeparate<["-"], "D">, Group<CompileOnly_Group>, Flags<[CC1Option]>; +def E : Flag<["-"], "E">, Flags<[DriverOption,CC1Option]>, Group<Action_Group>, + HelpText<"Only run the preprocessor">; +def F : JoinedOrSeparate<["-"], "F">, Flags<[RenderJoined,CC1Option]>, + HelpText<"Add directory to framework include search path">; +def G : JoinedOrSeparate<["-"], "G">, Flags<[DriverOption]>; +def G_EQ : Joined<["-"], "G=">, Flags<[DriverOption]>; +def H : Flag<["-"], "H">, Flags<[CC1Option]>, + HelpText<"Show header includes and nesting depth">; +def I_ : Flag<["-"], "I-">, Group<I_Group>; +def I : JoinedOrSeparate<["-"], "I">, Group<I_Group>, Flags<[CC1Option,CC1AsOption]>, + HelpText<"Add directory to include search path">; +def L : JoinedOrSeparate<["-"], "L">, Flags<[RenderJoined]>; +def MD : Flag<["-"], "MD">, Group<M_Group>, + HelpText<"Write a depfile containing user and system headers">; +def MMD : Flag<["-"], "MMD">, Group<M_Group>, + HelpText<"Write a depfile containing user headers">; +def M : Flag<["-"], "M">, Group<M_Group>, + HelpText<"Like -MD, but also implies -E and writes to stdout by default">; +def MM : Flag<["-"], "MM">, Group<M_Group>, + HelpText<"Like -MMD, but also implies -E and writes to stdout by default">; +def MF : JoinedOrSeparate<["-"], "MF">, Group<M_Group>, + HelpText<"Write depfile output from -MMD, -MD, -MM, or -M to <file>">, + MetaVarName<"<file>">; +def MG : Flag<["-"], "MG">, Group<M_Group>, Flags<[CC1Option]>, + HelpText<"Add missing headers to depfile">; +def MP : Flag<["-"], "MP">, Group<M_Group>, Flags<[CC1Option]>, + HelpText<"Create phony target for each dependency (other than main file)">; +def MQ : JoinedOrSeparate<["-"], "MQ">, Group<M_Group>, Flags<[CC1Option]>, + HelpText<"Specify name of main file output to quote in depfile">; +def MT : JoinedOrSeparate<["-"], "MT">, Group<M_Group>, Flags<[CC1Option]>, + HelpText<"Specify name of main file output in depfile">; +def MV : Flag<["-"], "MV">, Group<M_Group>, Flags<[CC1Option]>, + HelpText<"Use NMake/Jom format for the depfile">; +def Mach : Flag<["-"], "Mach">; +def O0 : Flag<["-"], "O0">, Group<O_Group>, Flags<[CC1Option]>; +def O4 : Flag<["-"], "O4">, Group<O_Group>, Flags<[CC1Option]>; +def ObjCXX : Flag<["-"], "ObjC++">, Flags<[DriverOption]>, + HelpText<"Treat source input files as Objective-C++ inputs">; +def ObjC : Flag<["-"], "ObjC">, Flags<[DriverOption]>, + HelpText<"Treat source input files as Objective-C inputs">; +def O : Joined<["-"], "O">, Group<O_Group>, Flags<[CC1Option]>; +def O_flag : Flag<["-"], "O">, Flags<[CC1Option]>, Alias<O>, AliasArgs<["2"]>; +def Ofast : Joined<["-"], "Ofast">, Group<O_Group>, Flags<[CC1Option]>; +def P : Flag<["-"], "P">, Flags<[CC1Option]>, + HelpText<"Disable linemarker output in -E mode">; +def Qn : Flag<["-"], "Qn">; +def Qunused_arguments : Flag<["-"], "Qunused-arguments">, Flags<[DriverOption, CoreOption]>, + HelpText<"Don't emit warning for unused driver arguments">; +def Q : Flag<["-"], "Q">; +def Rpass_EQ : Joined<["-"], "Rpass=">, Group<R_value_Group>, Flags<[CC1Option]>, + HelpText<"Report transformations performed by optimization passes whose " + "name matches the given POSIX regular expression">; +def Rpass_missed_EQ : Joined<["-"], "Rpass-missed=">, Group<R_value_Group>, + Flags<[CC1Option]>, + HelpText<"Report missed transformations by optimization passes whose " + "name matches the given POSIX regular expression">; +def Rpass_analysis_EQ : Joined<["-"], "Rpass-analysis=">, Group<R_value_Group>, + Flags<[CC1Option]>, + HelpText<"Report transformation analysis from optimization passes whose " + "name matches the given POSIX regular expression">; +def R_Joined : Joined<["-"], "R">, Group<R_Group>, Flags<[CC1Option, CoreOption]>, + MetaVarName<"<remark>">, HelpText<"Enable the specified remark">; +def S : Flag<["-"], "S">, Flags<[DriverOption,CC1Option]>, Group<Action_Group>, + HelpText<"Only run preprocess and compilation steps">; +def Tbss : JoinedOrSeparate<["-"], "Tbss">, Group<T_Group>; +def Tdata : JoinedOrSeparate<["-"], "Tdata">, Group<T_Group>; +def Ttext : JoinedOrSeparate<["-"], "Ttext">, Group<T_Group>; +def T : JoinedOrSeparate<["-"], "T">, Group<T_Group>; +def U : JoinedOrSeparate<["-"], "U">, Group<CompileOnly_Group>, Flags<[CC1Option]>; +def V : JoinedOrSeparate<["-"], "V">, Flags<[DriverOption, Unsupported]>; +def Wa_COMMA : CommaJoined<["-"], "Wa,">, + HelpText<"Pass the comma separated arguments in <arg> to the assembler">, + MetaVarName<"<arg>">; +def Wall : Flag<["-"], "Wall">, Group<W_Group>, Flags<[CC1Option]>; +def WCL4 : Flag<["-"], "WCL4">, Group<W_Group>, Flags<[CC1Option]>; +def Wdeprecated : Flag<["-"], "Wdeprecated">, Group<W_Group>, Flags<[CC1Option]>; +def Wno_deprecated : Flag<["-"], "Wno-deprecated">, Group<W_Group>, Flags<[CC1Option]>; +def Wextra : Flag<["-"], "Wextra">, Group<W_Group>, Flags<[CC1Option]>; +def Wl_COMMA : CommaJoined<["-"], "Wl,">, Flags<[LinkerInput, RenderAsInput]>, + HelpText<"Pass the comma separated arguments in <arg> to the linker">, + MetaVarName<"<arg>">; +// FIXME: This is broken; these should not be Joined arguments. +def Wno_nonportable_cfstrings : Joined<["-"], "Wno-nonportable-cfstrings">, Group<W_Group>, + Flags<[CC1Option]>; +def Wnonportable_cfstrings : Joined<["-"], "Wnonportable-cfstrings">, Group<W_Group>, + Flags<[CC1Option]>; +def Wp_COMMA : CommaJoined<["-"], "Wp,">, + HelpText<"Pass the comma separated arguments in <arg> to the preprocessor">, + MetaVarName<"<arg>">; +def Wwrite_strings : Flag<["-"], "Wwrite-strings">, Group<W_Group>, Flags<[CC1Option]>; +def Wno_write_strings : Flag<["-"], "Wno-write-strings">, Group<W_Group>, Flags<[CC1Option]>; +def W_Joined : Joined<["-"], "W">, Group<W_Group>, Flags<[CC1Option, CoreOption]>, + MetaVarName<"<warning>">, HelpText<"Enable the specified warning">; +def Xanalyzer : Separate<["-"], "Xanalyzer">, + HelpText<"Pass <arg> to the static analyzer">, MetaVarName<"<arg>">; +def Xarch__ : JoinedAndSeparate<["-"], "Xarch_">, Flags<[DriverOption]>; +def Xassembler : Separate<["-"], "Xassembler">, + HelpText<"Pass <arg> to the assembler">, MetaVarName<"<arg>">; +def Xclang : Separate<["-"], "Xclang">, + HelpText<"Pass <arg> to the clang compiler">, MetaVarName<"<arg>">, + Flags<[DriverOption, CoreOption]>; +def z : Separate<["-"], "z">, Flags<[LinkerInput, RenderAsInput]>, + HelpText<"Pass -z <arg> to the linker">, MetaVarName<"<arg>">; +def Xlinker : Separate<["-"], "Xlinker">, Flags<[LinkerInput, RenderAsInput]>, + HelpText<"Pass <arg> to the linker">, MetaVarName<"<arg>">; +def Xpreprocessor : Separate<["-"], "Xpreprocessor">, + HelpText<"Pass <arg> to the preprocessor">, MetaVarName<"<arg>">; +def X_Flag : Flag<["-"], "X">; +def X_Joined : Joined<["-"], "X">; +def Z_Flag : Flag<["-"], "Z">; +def Z_Joined : Joined<["-"], "Z">; +def all__load : Flag<["-"], "all_load">; +def allowable__client : Separate<["-"], "allowable_client">; +def ansi : Flag<["-", "--"], "ansi">; +def arch__errors__fatal : Flag<["-"], "arch_errors_fatal">; +def arch : Separate<["-"], "arch">, Flags<[DriverOption]>; +def arch__only : Separate<["-"], "arch_only">; +def a : Joined<["-"], "a">; +def bind__at__load : Flag<["-"], "bind_at_load">; +def bundle__loader : Separate<["-"], "bundle_loader">; +def bundle : Flag<["-"], "bundle">; +def b : JoinedOrSeparate<["-"], "b">, Flags<[Unsupported]>; +def client__name : JoinedOrSeparate<["-"], "client_name">; +def combine : Flag<["-", "--"], "combine">, Flags<[DriverOption, Unsupported]>; +def compatibility__version : JoinedOrSeparate<["-"], "compatibility_version">; +def coverage : Flag<["-", "--"], "coverage">; +def cpp_precomp : Flag<["-"], "cpp-precomp">, Group<clang_ignored_f_Group>; +def current__version : JoinedOrSeparate<["-"], "current_version">; +def cxx_isystem : JoinedOrSeparate<["-"], "cxx-isystem">, Group<clang_i_Group>, + HelpText<"Add directory to the C++ SYSTEM include search path">, Flags<[CC1Option]>, + MetaVarName<"<directory>">; +def c : Flag<["-"], "c">, Flags<[DriverOption]>, + HelpText<"Only run preprocess, compile, and assemble steps">; +def cuda_device_only : Flag<["--"], "cuda-device-only">, + HelpText<"Do device-side CUDA compilation only">; +def cuda_gpu_arch_EQ : Joined<["--"], "cuda-gpu-arch=">, + Flags<[DriverOption, HelpHidden]>, HelpText<"CUDA GPU architecture">; +def cuda_host_only : Flag<["--"], "cuda-host-only">, + HelpText<"Do host-side CUDA compilation only">; +def cuda_path_EQ : Joined<["--"], "cuda-path=">, Group<i_Group>, + HelpText<"CUDA installation path">; +def dA : Flag<["-"], "dA">, Group<d_Group>; +def dD : Flag<["-"], "dD">, Group<d_Group>, Flags<[CC1Option]>, + HelpText<"Print macro definitions in -E mode in addition to normal output">; +def dM : Flag<["-"], "dM">, Group<d_Group>, Flags<[CC1Option]>, + HelpText<"Print macro definitions in -E mode instead of normal output">; +def dead__strip : Flag<["-"], "dead_strip">; +def dependency_file : Separate<["-"], "dependency-file">, Flags<[CC1Option]>, + HelpText<"Filename (or -) to write dependency output to">; +def dependency_dot : Separate<["-"], "dependency-dot">, Flags<[CC1Option]>, + HelpText<"Filename to write DOT-formatted header dependencies to">; +def module_dependency_dir : Separate<["-"], "module-dependency-dir">, + Flags<[CC1Option]>, HelpText<"Directory to dump module dependencies to">; +def dumpmachine : Flag<["-"], "dumpmachine">; +def dumpspecs : Flag<["-"], "dumpspecs">, Flags<[Unsupported]>; +def dumpversion : Flag<["-"], "dumpversion">; +def dylib__file : Separate<["-"], "dylib_file">; +def dylinker__install__name : JoinedOrSeparate<["-"], "dylinker_install_name">; +def dylinker : Flag<["-"], "dylinker">; +def dynamiclib : Flag<["-"], "dynamiclib">; +def dynamic : Flag<["-"], "dynamic">, Flags<[NoArgumentUnused]>; +def d_Flag : Flag<["-"], "d">, Group<d_Group>; +def d_Joined : Joined<["-"], "d">, Group<d_Group>; +def emit_ast : Flag<["-"], "emit-ast">, + HelpText<"Emit Clang AST files for source inputs">; +def emit_llvm : Flag<["-"], "emit-llvm">, Flags<[CC1Option]>, Group<Action_Group>, + HelpText<"Use the LLVM representation for assembler and object files">; +def exported__symbols__list : Separate<["-"], "exported_symbols_list">; +def e : JoinedOrSeparate<["-"], "e">; +def fPIC : Flag<["-"], "fPIC">, Group<f_Group>; +def fno_PIC : Flag<["-"], "fno-PIC">, Group<f_Group>; +def fPIE : Flag<["-"], "fPIE">, Group<f_Group>; +def fno_PIE : Flag<["-"], "fno-PIE">, Group<f_Group>; +def faccess_control : Flag<["-"], "faccess-control">, Group<f_Group>; +def fallow_unsupported : Flag<["-"], "fallow-unsupported">, Group<f_Group>; +def fapple_kext : Flag<["-"], "fapple-kext">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Use Apple's kernel extensions ABI">; +def fapple_pragma_pack : Flag<["-"], "fapple-pragma-pack">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Enable Apple gcc-compatible #pragma pack handling">; +def shared_libasan : Flag<["-"], "shared-libasan">; +def fasm : Flag<["-"], "fasm">, Group<f_Group>; + +def fasm_blocks : Flag<["-"], "fasm-blocks">, Group<f_Group>, Flags<[CC1Option]>; +def fno_asm_blocks : Flag<["-"], "fno-asm-blocks">, Group<f_Group>; + +def fassume_sane_operator_new : Flag<["-"], "fassume-sane-operator-new">, Group<f_Group>; +def fastcp : Flag<["-"], "fastcp">, Group<f_Group>; +def fastf : Flag<["-"], "fastf">, Group<f_Group>; +def fast : Flag<["-"], "fast">, Group<f_Group>; +def fasynchronous_unwind_tables : Flag<["-"], "fasynchronous-unwind-tables">, Group<f_Group>; + +def fautolink : Flag <["-"], "fautolink">, Group<f_Group>; +def fno_autolink : Flag <["-"], "fno-autolink">, Group<f_Group>, + Flags<[DriverOption, CC1Option]>, + HelpText<"Disable generation of linker directives for automatic library linking">; + +def fgnu_inline_asm : Flag<["-"], "fgnu-inline-asm">, Group<f_Group>, Flags<[DriverOption]>; +def fno_gnu_inline_asm : Flag<["-"], "fno-gnu-inline-asm">, Group<f_Group>, + Flags<[DriverOption, CC1Option]>, + HelpText<"Disable GNU style inline asm">; + +def fprofile_sample_use_EQ : Joined<["-"], "fprofile-sample-use=">, + Group<f_Group>, Flags<[DriverOption, CC1Option]>, + HelpText<"Enable sample-based profile guided optimizations">; +def fauto_profile_EQ : Joined<["-"], "fauto-profile=">, + Alias<fprofile_sample_use_EQ>; +def fprofile_instr_generate : Flag<["-"], "fprofile-instr-generate">, + Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Generate instrumented code to collect execution counts into default.profraw file (overriden by '=' form of option or LLVM_PROFILE_FILE env var)">; +def fprofile_instr_generate_EQ : Joined<["-"], "fprofile-instr-generate=">, + Group<f_Group>, Flags<[CC1Option]>, MetaVarName<"<file>">, + HelpText<"Generate instrumented code to collect execution counts into <file> (overridden by LLVM_PROFILE_FILE env var)">; +def fprofile_instr_use : Flag<["-"], "fprofile-instr-use">, Group<f_Group>, + Flags<[DriverOption]>; +def fprofile_instr_use_EQ : Joined<["-"], "fprofile-instr-use=">, + Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Use instrumentation data for profile-guided optimization">; +def fcoverage_mapping : Flag<["-"], "fcoverage-mapping">, + Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Generate coverage mapping to enable code coverage analysis">; +def fno_coverage_mapping : Flag<["-"], "fno-coverage-mapping">, + Group<f_Group>, Flags<[DriverOption]>, + HelpText<"Disable code coverage analysis">; +def fprofile_generate : Flag<["-"], "fprofile-generate">, + Alias<fprofile_instr_generate>; +def fprofile_generate_EQ : Joined<["-"], "fprofile-generate=">, + Group<f_Group>, Flags<[DriverOption]>, MetaVarName<"<directory>">, + HelpText<"Generate instrumented code to collect execution counts into <directory>/default.profraw (overridden by LLVM_PROFILE_FILE env var)">; +def fprofile_use : Flag<["-"], "fprofile-use">, Group<f_Group>, + Alias<fprofile_instr_use>; +def fprofile_use_EQ : Joined<["-"], "fprofile-use=">, + Group<f_Group>, Flags<[DriverOption]>, MetaVarName<"<pathname>">, + HelpText<"Use instrumentation data for profile-guided optimization. If pathname is a directory, it reads from <pathname>/default.profdata. Otherwise, it reads from file <pathname>.">; +def fno_profile_instr_generate : Flag<["-"], "fno-profile-instr-generate">, + Group<f_Group>, Flags<[DriverOption]>, + HelpText<"Disable generation of profile instrumentation.">; +def fno_profile_generate : Flag<["-"], "fno-profile-generate">, + Alias<fno_profile_instr_generate>; +def fno_profile_instr_use : Flag<["-"], "fno-profile-instr-use">, + Group<f_Group>, Flags<[DriverOption]>, + HelpText<"Disable using instrumentation data for profile-guided optimization">; +def fno_profile_use : Flag<["-"], "fno-profile-use">, + Alias<fno_profile_instr_use>; + +def fblocks : Flag<["-"], "fblocks">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Enable the 'blocks' language feature">; +def fbootclasspath_EQ : Joined<["-"], "fbootclasspath=">, Group<f_Group>; +def fborland_extensions : Flag<["-"], "fborland-extensions">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Accept non-standard constructs supported by the Borland compiler">; +def fbuiltin : Flag<["-"], "fbuiltin">, Group<f_Group>; +def fcaret_diagnostics : Flag<["-"], "fcaret-diagnostics">, Group<f_Group>; +def fclasspath_EQ : Joined<["-"], "fclasspath=">, Group<f_Group>; +def fcolor_diagnostics : Flag<["-"], "fcolor-diagnostics">, Group<f_Group>, + Flags<[CoreOption, CC1Option]>, HelpText<"Use colors in diagnostics">; +def fdiagnostics_color : Flag<["-"], "fdiagnostics-color">, Group<f_Group>, + Flags<[CoreOption, DriverOption]>; +def fdiagnostics_color_EQ : Joined<["-"], "fdiagnostics-color=">, Group<f_Group>; +def fansi_escape_codes : Flag<["-"], "fansi-escape-codes">, Group<f_Group>, + Flags<[CoreOption, CC1Option]>, HelpText<"Use ANSI escape codes for diagnostics">; +def fcomment_block_commands : CommaJoined<["-"], "fcomment-block-commands=">, Group<f_clang_Group>, Flags<[CC1Option]>, + HelpText<"Treat each comma separated argument in <arg> as a documentation comment block command">, + MetaVarName<"<arg>">; +def fparse_all_comments : Flag<["-"], "fparse-all-comments">, Group<f_clang_Group>, Flags<[CC1Option]>; +def fcommon : Flag<["-"], "fcommon">, Group<f_Group>; +def fcompile_resource_EQ : Joined<["-"], "fcompile-resource=">, Group<f_Group>; +def fconstant_cfstrings : Flag<["-"], "fconstant-cfstrings">, Group<f_Group>; +def fconstant_string_class_EQ : Joined<["-"], "fconstant-string-class=">, Group<f_Group>; +def fconstexpr_depth_EQ : Joined<["-"], "fconstexpr-depth=">, Group<f_Group>; +def fconstexpr_steps_EQ : Joined<["-"], "fconstexpr-steps=">, Group<f_Group>; +def fconstexpr_backtrace_limit_EQ : Joined<["-"], "fconstexpr-backtrace-limit=">, + Group<f_Group>; +def fno_crash_diagnostics : Flag<["-"], "fno-crash-diagnostics">, Group<f_clang_Group>, Flags<[NoArgumentUnused]>; +def fcreate_profile : Flag<["-"], "fcreate-profile">, Group<f_Group>; +def fcxx_exceptions: Flag<["-"], "fcxx-exceptions">, Group<f_Group>, + HelpText<"Enable C++ exceptions">, Flags<[CC1Option]>; +def fcxx_modules : Flag <["-"], "fcxx-modules">, Group<f_Group>, + Flags<[DriverOption]>; +def fdebug_pass_arguments : Flag<["-"], "fdebug-pass-arguments">, Group<f_Group>; +def fdebug_pass_structure : Flag<["-"], "fdebug-pass-structure">, Group<f_Group>; +def fdepfile_entry : Joined<["-"], "fdepfile-entry=">, + Group<f_clang_Group>, Flags<[CC1Option]>; +def fdiagnostics_fixit_info : Flag<["-"], "fdiagnostics-fixit-info">, Group<f_clang_Group>; +def fdiagnostics_parseable_fixits : Flag<["-"], "fdiagnostics-parseable-fixits">, Group<f_clang_Group>, + Flags<[CoreOption, CC1Option]>, HelpText<"Print fix-its in machine parseable form">; +def fdiagnostics_print_source_range_info : Flag<["-"], "fdiagnostics-print-source-range-info">, + Group<f_clang_Group>, Flags<[CC1Option]>, + HelpText<"Print source range spans in numeric form">; +def fdiagnostics_show_option : Flag<["-"], "fdiagnostics-show-option">, Group<f_Group>, + Flags<[CC1Option]>, HelpText<"Print option name with mappable diagnostics">; +def fdiagnostics_show_note_include_stack : Flag<["-"], "fdiagnostics-show-note-include-stack">, + Group<f_Group>, Flags<[CC1Option]>, HelpText<"Display include stacks for diagnostic notes">; +def fdiagnostics_format_EQ : Joined<["-"], "fdiagnostics-format=">, Group<f_clang_Group>; +def fdiagnostics_show_category_EQ : Joined<["-"], "fdiagnostics-show-category=">, Group<f_clang_Group>; +def fdiagnostics_show_template_tree : Flag<["-"], "fdiagnostics-show-template-tree">, + Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Print a template comparison tree for differing templates">; +def fdeclspec : Flag<["-"], "fdeclspec">, Group<f_clang_Group>, + HelpText<"Allow __declspec as a keyword">, Flags<[CC1Option]>; +def fdollars_in_identifiers : Flag<["-"], "fdollars-in-identifiers">, Group<f_Group>, + HelpText<"Allow '$' in identifiers">, Flags<[CC1Option]>; +def fdwarf2_cfi_asm : Flag<["-"], "fdwarf2-cfi-asm">, Group<clang_ignored_f_Group>; +def fno_dwarf2_cfi_asm : Flag<["-"], "fno-dwarf2-cfi-asm">, Group<clang_ignored_f_Group>; +def fdwarf_directory_asm : Flag<["-"], "fdwarf-directory-asm">, Group<f_Group>; +def fno_dwarf_directory_asm : Flag<["-"], "fno-dwarf-directory-asm">, Group<f_Group>, Flags<[CC1Option]>; +def felide_constructors : Flag<["-"], "felide-constructors">, Group<f_Group>; +def fno_elide_type : Flag<["-"], "fno-elide-type">, Group<f_Group>, + Flags<[CC1Option]>, + HelpText<"Do not elide types when printing diagnostics">; +def feliminate_unused_debug_symbols : Flag<["-"], "feliminate-unused-debug-symbols">, Group<f_Group>; +def femit_all_decls : Flag<["-"], "femit-all-decls">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Emit all declarations, even if unused">; +def femulated_tls : Flag<["-"], "femulated-tls">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Use emutls functions to access thread_local variables">; +def fno_emulated_tls : Flag<["-"], "fno-emulated-tls">, Group<f_Group>; +def fencoding_EQ : Joined<["-"], "fencoding=">, Group<f_Group>; +def ferror_limit_EQ : Joined<["-"], "ferror-limit=">, Group<f_Group>, Flags<[CoreOption]>; +def fexceptions : Flag<["-"], "fexceptions">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Enable support for exception handling">; +def fexcess_precision_EQ : Joined<["-"], "fexcess-precision=">, + Group<clang_ignored_gcc_optimization_f_Group>; +def : Flag<["-"], "fexpensive-optimizations">, Group<clang_ignored_gcc_optimization_f_Group>; +def : Flag<["-"], "fno-expensive-optimizations">, Group<clang_ignored_gcc_optimization_f_Group>; +def fextdirs_EQ : Joined<["-"], "fextdirs=">, Group<f_Group>; +def : Flag<["-"], "fdefer-pop">, Group<clang_ignored_gcc_optimization_f_Group>; +def : Flag<["-"], "fno-defer-pop">, Group<clang_ignored_gcc_optimization_f_Group>; +def : Flag<["-"], "fextended-identifiers">, Group<clang_ignored_f_Group>; +def : Flag<["-"], "fno-extended-identifiers">, Group<f_Group>, Flags<[Unsupported]>; +def fhosted : Flag<["-"], "fhosted">, Group<f_Group>; +def ffast_math : Flag<["-"], "ffast-math">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Enable the *frontend*'s 'fast-math' mode. This has no effect on " + "optimizations, but provides a preprocessor macro __FAST_MATH__ the " + "same as GCC's -ffast-math flag">; +def fno_fast_math : Flag<["-"], "fno-fast-math">, Group<f_Group>; +def fmath_errno : Flag<["-"], "fmath-errno">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Require math functions to indicate errors by setting errno">; +def fno_math_errno : Flag<["-"], "fno-math-errno">, Group<f_Group>; +def fbracket_depth_EQ : Joined<["-"], "fbracket-depth=">, Group<f_Group>; +def fsignaling_math : Flag<["-"], "fsignaling-math">, Group<f_Group>; +def fno_signaling_math : Flag<["-"], "fno-signaling-math">, Group<f_Group>; +def fsanitize_EQ : CommaJoined<["-"], "fsanitize=">, Group<f_clang_Group>, + Flags<[CC1Option, CoreOption]>, MetaVarName<"<check>">, + HelpText<"Turn on runtime checks for various forms of undefined " + "or suspicious behavior. See user manual for available checks">; +def fno_sanitize_EQ : CommaJoined<["-"], "fno-sanitize=">, Group<f_clang_Group>, + Flags<[CoreOption]>; +def fsanitize_blacklist : Joined<["-"], "fsanitize-blacklist=">, + Group<f_clang_Group>, Flags<[CC1Option, CoreOption]>, + HelpText<"Path to blacklist file for sanitizers">; +def fno_sanitize_blacklist : Flag<["-"], "fno-sanitize-blacklist">, + Group<f_clang_Group>, + HelpText<"Don't use blacklist file for sanitizers">; +def fsanitize_coverage + : CommaJoined<["-"], "fsanitize-coverage=">, + Group<f_clang_Group>, Flags<[CoreOption]>, + HelpText<"Specify the type of coverage instrumentation for Sanitizers">; +def fno_sanitize_coverage + : CommaJoined<["-"], "fno-sanitize-coverage=">, + Group<f_clang_Group>, Flags<[CoreOption]>, + HelpText<"Disable specified features of coverage instrumentation for " + "Sanitizers">; +def fsanitize_memory_track_origins_EQ : Joined<["-"], "fsanitize-memory-track-origins=">, + Group<f_clang_Group>, Flags<[CC1Option]>, + HelpText<"Enable origins tracking in MemorySanitizer">; +def fsanitize_memory_track_origins : Flag<["-"], "fsanitize-memory-track-origins">, + Group<f_clang_Group>, Flags<[CC1Option]>, + HelpText<"Enable origins tracking in MemorySanitizer">; +def fno_sanitize_memory_track_origins : Flag<["-"], "fno-sanitize-memory-track-origins">, + Group<f_clang_Group>, Flags<[CC1Option]>, + HelpText<"Disable origins tracking in MemorySanitizer">; +def fsanitize_memory_use_after_dtor : Flag<["-"], "fsanitize-memory-use-after-dtor">, + Group<f_clang_Group>, Flags<[CC1Option]>, + HelpText<"Enable use-after-destroy detection in MemorySanitizer">; +def fsanitize_address_field_padding : Joined<["-"], "fsanitize-address-field-padding=">, + Group<f_clang_Group>, Flags<[CC1Option]>, + HelpText<"Level of field padding for AddressSanitizer">; +def fsanitize_recover : Flag<["-"], "fsanitize-recover">, Group<f_clang_Group>, + Flags<[CoreOption]>; +def fno_sanitize_recover : Flag<["-"], "fno-sanitize-recover">, + Group<f_clang_Group>, Flags<[CoreOption]>; +def fsanitize_recover_EQ : CommaJoined<["-"], "fsanitize-recover=">, + Group<f_clang_Group>, + Flags<[CC1Option, CoreOption]>, + HelpText<"Enable recovery for specified sanitizers">; +def fno_sanitize_recover_EQ + : CommaJoined<["-"], "fno-sanitize-recover=">, + Group<f_clang_Group>, Flags<[CoreOption]>, + HelpText<"Disable recovery for specified sanitizers">; +def fsanitize_trap_EQ : CommaJoined<["-"], "fsanitize-trap=">, Group<f_clang_Group>, + Flags<[CC1Option, CoreOption]>, + HelpText<"Enable trapping for specified sanitizers">; +def fno_sanitize_trap_EQ : CommaJoined<["-"], "fno-sanitize-trap=">, Group<f_clang_Group>, + Flags<[CoreOption]>, + HelpText<"Disable trapping for specified sanitizers">; +def fsanitize_undefined_trap_on_error : Flag<["-"], "fsanitize-undefined-trap-on-error">, + Group<f_clang_Group>; +def fno_sanitize_undefined_trap_on_error : Flag<["-"], "fno-sanitize-undefined-trap-on-error">, + Group<f_clang_Group>; +def fsanitize_link_cxx_runtime : Flag<["-"], "fsanitize-link-c++-runtime">, + Group<f_clang_Group>; +def fsanitize_cfi_cross_dso : Flag<["-"], "fsanitize-cfi-cross-dso">, + Group<f_clang_Group>, Flags<[CC1Option]>, + HelpText<"Enable control flow integrity (CFI) checks for cross-DSO calls.">; +def fno_sanitize_cfi_cross_dso : Flag<["-"], "fno-sanitize-cfi-cross-dso">, + Group<f_clang_Group>, Flags<[CC1Option]>, + HelpText<"Disable control flow integrity (CFI) checks for cross-DSO calls.">; +def funsafe_math_optimizations : Flag<["-"], "funsafe-math-optimizations">, + Group<f_Group>; +def fno_unsafe_math_optimizations : Flag<["-"], "fno-unsafe-math-optimizations">, + Group<f_Group>; +def fassociative_math : Flag<["-"], "fassociative-math">, Group<f_Group>; +def fno_associative_math : Flag<["-"], "fno-associative-math">, Group<f_Group>; +def freciprocal_math : + Flag<["-"], "freciprocal-math">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Allow division operations to be reassociated">; +def fno_reciprocal_math : Flag<["-"], "fno-reciprocal-math">, Group<f_Group>; +def ffinite_math_only : Flag<["-"], "ffinite-math-only">, Group<f_Group>, Flags<[CC1Option]>; +def fno_finite_math_only : Flag<["-"], "fno-finite-math-only">, Group<f_Group>; +def fsigned_zeros : Flag<["-"], "fsigned-zeros">, Group<f_Group>; +def fno_signed_zeros : + Flag<["-"], "fno-signed-zeros">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Allow optimizations that ignore the sign of floating point zeros">; +def fhonor_nans : Flag<["-"], "fhonor-nans">, Group<f_Group>; +def fno_honor_nans : Flag<["-"], "fno-honor-nans">, Group<f_Group>; +def fhonor_infinities : Flag<["-"], "fhonor-infinities">, Group<f_Group>; +def fno_honor_infinities : Flag<["-"], "fno-honor-infinities">, Group<f_Group>; +// This option was originally misspelt "infinites" [sic]. +def : Flag<["-"], "fhonor-infinites">, Alias<fhonor_infinities>; +def : Flag<["-"], "fno-honor-infinites">, Alias<fno_honor_infinities>; +def ftrapping_math : Flag<["-"], "ftrapping-math">, Group<f_Group>; +def fno_trapping_math : Flag<["-"], "fno-trapping-math">, Group<f_Group>; +def ffp_contract : Joined<["-"], "ffp-contract=">, Group<f_Group>, + Flags<[CC1Option]>, HelpText<"Form fused FP ops (e.g. FMAs): fast (everywhere)" + " | on (according to FP_CONTRACT pragma, default) | off (never fuse)">; + +def ffor_scope : Flag<["-"], "ffor-scope">, Group<f_Group>; +def fno_for_scope : Flag<["-"], "fno-for-scope">, Group<f_Group>; + +def frewrite_includes : Flag<["-"], "frewrite-includes">, Group<f_Group>, + Flags<[CC1Option]>; +def fno_rewrite_includes : Flag<["-"], "fno-rewrite-includes">, Group<f_Group>; + +def frewrite_map_file : Separate<["-"], "frewrite-map-file">, + Group<f_Group>, + Flags<[ DriverOption, CC1Option ]>; +def frewrite_map_file_EQ : Joined<["-"], "frewrite-map-file=">, + Group<f_Group>, + Flags<[DriverOption]>; + +def fuse_line_directives : Flag<["-"], "fuse-line-directives">, Group<f_Group>, + Flags<[CC1Option]>; +def fno_use_line_directives : Flag<["-"], "fno-use-line-directives">, Group<f_Group>; + +def ffreestanding : Flag<["-"], "ffreestanding">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Assert that the compilation takes place in a freestanding environment">; +def fgnu_keywords : Flag<["-"], "fgnu-keywords">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Allow GNU-extension keywords regardless of language standard">; +def fgnu89_inline : Flag<["-"], "fgnu89-inline">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Use the gnu89 inline semantics">; +def fno_gnu89_inline : Flag<["-"], "fno-gnu89-inline">, Group<f_Group>; +def fgnu_runtime : Flag<["-"], "fgnu-runtime">, Group<f_Group>, + HelpText<"Generate output compatible with the standard GNU Objective-C runtime">; +def fheinous_gnu_extensions : Flag<["-"], "fheinous-gnu-extensions">, Flags<[CC1Option]>; +def filelist : Separate<["-"], "filelist">, Flags<[LinkerInput]>; +def : Flag<["-"], "findirect-virtual-calls">, Alias<fapple_kext>; +def finline_functions : Flag<["-"], "finline-functions">, Group<clang_ignored_gcc_optimization_f_Group>; +def finline : Flag<["-"], "finline">, Group<clang_ignored_f_Group>; +def finput_charset_EQ : Joined<["-"], "finput-charset=">, Group<f_Group>; +def fexec_charset_EQ : Joined<["-"], "fexec-charset=">, Group<f_Group>; +def finstrument_functions : Flag<["-"], "finstrument-functions">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Generate calls to instrument function entry and exit">; +def flat__namespace : Flag<["-"], "flat_namespace">; +def flax_vector_conversions : Flag<["-"], "flax-vector-conversions">, Group<f_Group>; +def flimited_precision_EQ : Joined<["-"], "flimited-precision=">, Group<f_Group>; +def flto_EQ : Joined<["-"], "flto=">, Flags<[CC1Option]>, Group<f_Group>, + HelpText<"Set LTO mode to either 'full' or 'thin'">; +def flto : Flag<["-"], "flto">, Flags<[CC1Option]>, Group<f_Group>, + HelpText<"Enable LTO in 'full' mode">; +def fno_lto : Flag<["-"], "fno-lto">, Group<f_Group>, + HelpText<"Disable LTO mode (default)">; +def fthinlto_index_EQ : Joined<["-"], "fthinlto-index=">, + Flags<[CC1Option]>, Group<f_Group>, + HelpText<"Perform ThinLTO importing using provided function summary index">; +def fmacro_backtrace_limit_EQ : Joined<["-"], "fmacro-backtrace-limit=">, + Group<f_Group>, Flags<[DriverOption, CoreOption]>; +def fmerge_all_constants : Flag<["-"], "fmerge-all-constants">, Group<f_Group>; +def fmessage_length_EQ : Joined<["-"], "fmessage-length=">, Group<f_Group>; +def fms_extensions : Flag<["-"], "fms-extensions">, Group<f_Group>, Flags<[CC1Option, CoreOption]>, + HelpText<"Accept some non-standard constructs supported by the Microsoft compiler">; +def fms_compatibility : Flag<["-"], "fms-compatibility">, Group<f_Group>, Flags<[CC1Option, CoreOption]>, + HelpText<"Enable full Microsoft Visual C++ compatibility">; +def fms_volatile : Joined<["-"], "fms-volatile">, Group<f_Group>, Flags<[CC1Option]>; +def fmsc_version : Joined<["-"], "fmsc-version=">, Group<f_Group>, Flags<[DriverOption, CoreOption]>, + HelpText<"Microsoft compiler version number to report in _MSC_VER (0 = don't define it (default))">; +def fms_compatibility_version + : Joined<["-"], "fms-compatibility-version=">, + Group<f_Group>, + Flags<[ CC1Option, CoreOption ]>, + HelpText<"Dot-separated value representing the Microsoft compiler " + "version number to report in _MSC_VER (0 = don't define it " + "(default))">; +def fdelayed_template_parsing : Flag<["-"], "fdelayed-template-parsing">, Group<f_Group>, + HelpText<"Parse templated function definitions at the end of the " + "translation unit">, Flags<[CC1Option]>; +def fms_memptr_rep_EQ : Joined<["-"], "fms-memptr-rep=">, Group<f_Group>, Flags<[CC1Option]>; +def fmodules_cache_path : Joined<["-"], "fmodules-cache-path=">, Group<i_Group>, + Flags<[DriverOption, CC1Option]>, MetaVarName<"<directory>">, + HelpText<"Specify the module cache path">; +def fmodules_user_build_path : Separate<["-"], "fmodules-user-build-path">, Group<i_Group>, + Flags<[DriverOption, CC1Option]>, MetaVarName<"<directory>">, + HelpText<"Specify the module user build path">; +def fmodules_prune_interval : Joined<["-"], "fmodules-prune-interval=">, Group<i_Group>, + Flags<[CC1Option]>, MetaVarName<"<seconds>">, + HelpText<"Specify the interval (in seconds) between attempts to prune the module cache">; +def fmodules_prune_after : Joined<["-"], "fmodules-prune-after=">, Group<i_Group>, + Flags<[CC1Option]>, MetaVarName<"<seconds>">, + HelpText<"Specify the interval (in seconds) after which a module file will be considered unused">; +def fmodules_search_all : Flag <["-"], "fmodules-search-all">, Group<f_Group>, + Flags<[DriverOption, CC1Option]>, + HelpText<"Search even non-imported modules to resolve references">; +def fbuild_session_timestamp : Joined<["-"], "fbuild-session-timestamp=">, + Group<i_Group>, Flags<[CC1Option]>, MetaVarName<"<time since Epoch in seconds>">, + HelpText<"Time when the current build session started">; +def fbuild_session_file : Joined<["-"], "fbuild-session-file=">, + Group<i_Group>, MetaVarName<"<file>">, + HelpText<"Use the last modification time of <file> as the build session timestamp">; +def fmodules_validate_once_per_build_session : Flag<["-"], "fmodules-validate-once-per-build-session">, + Group<i_Group>, Flags<[CC1Option]>, + HelpText<"Don't verify input files for the modules if the module has been " + "successfully validated or loaded during this build session">; +def fmodules_validate_system_headers : Flag<["-"], "fmodules-validate-system-headers">, + Group<i_Group>, Flags<[CC1Option]>, + HelpText<"Validate the system headers that a module depends on when loading the module">; +def fmodules : Flag <["-"], "fmodules">, Group<f_Group>, + Flags<[DriverOption, CC1Option]>, + HelpText<"Enable the 'modules' language feature">; +def fimplicit_module_maps : Flag <["-"], "fimplicit-module-maps">, Group<f_Group>, + Flags<[DriverOption, CC1Option]>, + HelpText<"Implicitly search the file system for module map files.">; +def fmodule_maps : Flag <["-"], "fmodule-maps">, Alias<fimplicit_module_maps>; +def fmodule_name : JoinedOrSeparate<["-"], "fmodule-name=">, Group<f_Group>, + Flags<[DriverOption,CC1Option]>, MetaVarName<"<name>">, + HelpText<"Specify the name of the module to build">; +def fmodule_map_file : Joined<["-"], "fmodule-map-file=">, + Group<f_Group>, Flags<[DriverOption,CC1Option]>, MetaVarName<"<file>">, + HelpText<"Load this module map file">; +def fmodule_file : Joined<["-"], "fmodule-file=">, + Group<f_Group>, Flags<[DriverOption,CC1Option]>, + HelpText<"Load this precompiled module file">, MetaVarName<"<file>">; +def fmodules_ignore_macro : Joined<["-"], "fmodules-ignore-macro=">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Ignore the definition of the given macro when building and loading modules">; +def fmodules_decluse : Flag <["-"], "fmodules-decluse">, Group<f_Group>, + Flags<[DriverOption,CC1Option]>, + HelpText<"Require declaration of modules used within a module">; +def fmodules_strict_decluse : Flag <["-"], "fmodules-strict-decluse">, Group<f_Group>, + Flags<[DriverOption,CC1Option]>, + HelpText<"Like -fmodules-decluse but requires all headers to be in modules">; +def fno_modules_search_all : Flag <["-"], "fno-modules-search-all">, Group<f_Group>, + Flags<[DriverOption, CC1Option]>; +def fno_implicit_modules : + Flag <["-"], "fno-implicit-modules">, + Group<f_Group>, Flags<[DriverOption, CC1Option]>; +def fretain_comments_from_system_headers : Flag<["-"], "fretain-comments-from-system-headers">, Group<f_Group>, Flags<[CC1Option]>; + +def fmudflapth : Flag<["-"], "fmudflapth">, Group<f_Group>; +def fmudflap : Flag<["-"], "fmudflap">, Group<f_Group>; +def fnested_functions : Flag<["-"], "fnested-functions">, Group<f_Group>; +def fnext_runtime : Flag<["-"], "fnext-runtime">, Group<f_Group>; +def fno_access_control : Flag<["-"], "fno-access-control">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Disable C++ access control">; +def fno_apple_pragma_pack : Flag<["-"], "fno-apple-pragma-pack">, Group<f_Group>; +def fno_asm : Flag<["-"], "fno-asm">, Group<f_Group>; +def fno_asynchronous_unwind_tables : Flag<["-"], "fno-asynchronous-unwind-tables">, Group<f_Group>; +def fno_assume_sane_operator_new : Flag<["-"], "fno-assume-sane-operator-new">, Group<f_Group>, + HelpText<"Don't assume that C++'s global operator new can't alias any pointer">, + Flags<[CC1Option]>; +def fno_blocks : Flag<["-"], "fno-blocks">, Group<f_Group>; +def fno_borland_extensions : Flag<["-"], "fno-borland-extensions">, Group<f_Group>; +def fno_builtin : Flag<["-"], "fno-builtin">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Disable implicit builtin knowledge of functions">; +def fno_builtin_ : Joined<["-"], "fno-builtin-">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Disable implicit builtin knowledge of a specific function">; +def fno_math_builtin : Flag<["-"], "fno-math-builtin">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Disable implicit builtin knowledge of math functions">; +def fno_caret_diagnostics : Flag<["-"], "fno-caret-diagnostics">, Group<f_Group>, + Flags<[CC1Option]>; +def fno_color_diagnostics : Flag<["-"], "fno-color-diagnostics">, Group<f_Group>, + Flags<[CoreOption, CC1Option]>; +def fno_diagnostics_color : Flag<["-"], "fno-diagnostics-color">, Group<f_Group>, + Flags<[CoreOption, DriverOption]>; +def fno_common : Flag<["-"], "fno-common">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Compile common globals like normal definitions">; +def fno_constant_cfstrings : Flag<["-"], "fno-constant-cfstrings">, Group<f_Group>, + Flags<[CC1Option]>, + HelpText<"Disable creation of CodeFoundation-type constant strings">; +def fno_cxx_exceptions: Flag<["-"], "fno-cxx-exceptions">, Group<f_Group>; +def fno_cxx_modules : Flag <["-"], "fno-cxx-modules">, Group<f_Group>, + Flags<[DriverOption]>; +def fno_diagnostics_fixit_info : Flag<["-"], "fno-diagnostics-fixit-info">, Group<f_Group>, + Flags<[CC1Option]>, HelpText<"Do not include fixit information in diagnostics">; +def fno_diagnostics_show_option : Flag<["-"], "fno-diagnostics-show-option">, Group<f_Group>; +def fno_diagnostics_show_note_include_stack : Flag<["-"], "fno-diagnostics-show-note-include-stack">, + Flags<[CC1Option]>, Group<f_Group>; +def fno_declspec : Flag<["-"], "fno-declspec">, Group<f_clang_Group>, + HelpText<"Disallow __declspec as a keyword">, Flags<[CC1Option]>; +def fno_dollars_in_identifiers : Flag<["-"], "fno-dollars-in-identifiers">, Group<f_Group>, + HelpText<"Disallow '$' in identifiers">, Flags<[CC1Option]>; +def fno_elide_constructors : Flag<["-"], "fno-elide-constructors">, Group<f_Group>, + HelpText<"Disable C++ copy constructor elision">, Flags<[CC1Option]>; +def fno_eliminate_unused_debug_symbols : Flag<["-"], "fno-eliminate-unused-debug-symbols">, Group<f_Group>; +def fno_exceptions : Flag<["-"], "fno-exceptions">, Group<f_Group>; +def fno_gnu_keywords : Flag<["-"], "fno-gnu-keywords">, Group<f_Group>, Flags<[CC1Option]>; +def fno_inline_functions : Flag<["-"], "fno-inline-functions">, Group<f_clang_Group>, Flags<[CC1Option]>; +def fno_inline : Flag<["-"], "fno-inline">, Group<f_clang_Group>, Flags<[CC1Option]>; +def fveclib : Joined<["-"], "fveclib=">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Use the given vector functions library">; +def fno_lax_vector_conversions : Flag<["-"], "fno-lax-vector-conversions">, Group<f_Group>, + HelpText<"Disallow implicit conversions between vectors with a different number of elements or different element types">, Flags<[CC1Option]>; +def fno_merge_all_constants : Flag<["-"], "fno-merge-all-constants">, Group<f_Group>, + Flags<[CC1Option]>, HelpText<"Disallow merging of constants">; +def fno_modules : Flag <["-"], "fno-modules">, Group<f_Group>, + Flags<[DriverOption]>; +def fno_implicit_module_maps : Flag <["-"], "fno-implicit-module-maps">, Group<f_Group>, + Flags<[DriverOption]>; +def fno_module_maps : Flag <["-"], "fno-module-maps">, Alias<fno_implicit_module_maps>; +def fno_modules_decluse : Flag <["-"], "fno-modules-decluse">, Group<f_Group>, + Flags<[DriverOption]>; +def fno_modules_strict_decluse : Flag <["-"], "fno-strict-modules-decluse">, Group<f_Group>, + Flags<[DriverOption]>; +def fimplicit_modules : Flag <["-"], "fimplicit-modules">, Group<f_Group>, + Flags<[DriverOption]>; +def fmodule_file_deps : Flag <["-"], "fmodule-file-deps">, Group<f_Group>, + Flags<[DriverOption]>; +def fno_module_file_deps : Flag <["-"], "fno-module-file-deps">, Group<f_Group>, + Flags<[DriverOption]>; +def fno_ms_extensions : Flag<["-"], "fno-ms-extensions">, Group<f_Group>, + Flags<[CoreOption]>; +def fno_ms_compatibility : Flag<["-"], "fno-ms-compatibility">, Group<f_Group>, + Flags<[CoreOption]>; +def fno_delayed_template_parsing : Flag<["-"], "fno-delayed-template-parsing">, Group<f_Group>; +def fno_objc_exceptions: Flag<["-"], "fno-objc-exceptions">, Group<f_Group>; +def fno_objc_legacy_dispatch : Flag<["-"], "fno-objc-legacy-dispatch">, Group<f_Group>; +def fno_objc_weak : Flag<["-"], "fno-objc-weak">, Group<f_Group>, Flags<[CC1Option]>; +def fno_omit_frame_pointer : Flag<["-"], "fno-omit-frame-pointer">, Group<f_Group>; +def fno_operator_names : Flag<["-"], "fno-operator-names">, Group<f_Group>, + HelpText<"Do not treat C++ operator name keywords as synonyms for operators">, + Flags<[CC1Option]>; +def fno_pascal_strings : Flag<["-"], "fno-pascal-strings">, Group<f_Group>; +def fno_rtti : Flag<["-"], "fno-rtti">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Disable generation of rtti information">; +def fno_short_enums : Flag<["-"], "fno-short-enums">, Group<f_Group>; +def fno_show_column : Flag<["-"], "fno-show-column">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Do not include column number on diagnostics">; +def fno_show_source_location : Flag<["-"], "fno-show-source-location">, Group<f_Group>, + Flags<[CC1Option]>, HelpText<"Do not include source location information with diagnostics">; +def fno_spell_checking : Flag<["-"], "fno-spell-checking">, Group<f_Group>, + Flags<[CC1Option]>, HelpText<"Disable spell-checking">; +def fno_stack_protector : Flag<["-"], "fno-stack-protector">, Group<f_Group>, + HelpText<"Disable the use of stack protectors">; +def fno_strict_aliasing : Flag<["-"], "fno-strict-aliasing">, Group<f_Group>, + Flags<[DriverOption, CoreOption]>; +def fstruct_path_tbaa : Flag<["-"], "fstruct-path-tbaa">, Group<f_Group>; +def fno_struct_path_tbaa : Flag<["-"], "fno-struct-path-tbaa">, Group<f_Group>; +def fno_strict_enums : Flag<["-"], "fno-strict-enums">, Group<f_Group>; +def fno_strict_vtable_pointers: Flag<["-"], "fno-strict-vtable-pointers">, + Group<f_Group>; +def fno_strict_overflow : Flag<["-"], "fno-strict-overflow">, Group<f_Group>; +def fno_threadsafe_statics : Flag<["-"], "fno-threadsafe-statics">, Group<f_Group>, + Flags<[CC1Option]>, HelpText<"Do not emit code to make initialization of local statics thread safe">; +def fno_use_cxa_atexit : Flag<["-"], "fno-use-cxa-atexit">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Don't use __cxa_atexit for calling destructors">; +def fno_use_init_array : Flag<["-"], "fno-use-init-array">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Don't use .init_array instead of .ctors">; +def fno_unit_at_a_time : Flag<["-"], "fno-unit-at-a-time">, Group<f_Group>; +def fno_unwind_tables : Flag<["-"], "fno-unwind-tables">, Group<f_Group>; +def fno_verbose_asm : Flag<["-"], "fno-verbose-asm">, Group<f_Group>; +def fno_working_directory : Flag<["-"], "fno-working-directory">, Group<f_Group>; +def fno_wrapv : Flag<["-"], "fno-wrapv">, Group<f_Group>; +def fno_zero_initialized_in_bss : Flag<["-"], "fno-zero-initialized-in-bss">, Group<f_Group>; +def fobjc_arc : Flag<["-"], "fobjc-arc">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Synthesize retain and release calls for Objective-C pointers">; +def fno_objc_arc : Flag<["-"], "fno-objc-arc">, Group<f_Group>; +def fobjc_arc_exceptions : Flag<["-"], "fobjc-arc-exceptions">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Use EH-safe code when synthesizing retains and releases in -fobjc-arc">; +def fno_objc_arc_exceptions : Flag<["-"], "fno-objc-arc-exceptions">, Group<f_Group>; +def fobjc_atdefs : Flag<["-"], "fobjc-atdefs">, Group<clang_ignored_f_Group>; +def fobjc_call_cxx_cdtors : Flag<["-"], "fobjc-call-cxx-cdtors">, Group<clang_ignored_f_Group>; +def fobjc_exceptions: Flag<["-"], "fobjc-exceptions">, Group<f_Group>, + HelpText<"Enable Objective-C exceptions">, Flags<[CC1Option]>; +def fapplication_extension : Flag<["-"], "fapplication-extension">, + Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Restrict code to those available for App Extensions">; +def fno_application_extension : Flag<["-"], "fno-application-extension">, + Group<f_Group>; +def fsized_deallocation : Flag<["-"], "fsized-deallocation">, Flags<[CC1Option]>, + HelpText<"Enable C++14 sized global deallocation functions">, Group<f_Group>; +def fno_sized_deallocation: Flag<["-"], "fno-sized-deallocation">, Group<f_Group>; + +def fobjc_gc_only : Flag<["-"], "fobjc-gc-only">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Use GC exclusively for Objective-C related memory management">; +def fobjc_gc : Flag<["-"], "fobjc-gc">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Enable Objective-C garbage collection">; +def fobjc_legacy_dispatch : Flag<["-"], "fobjc-legacy-dispatch">, Group<f_Group>; +def fobjc_new_property : Flag<["-"], "fobjc-new-property">, Group<clang_ignored_f_Group>; +def fobjc_infer_related_result_type : Flag<["-"], "fobjc-infer-related-result-type">, + Group<f_Group>; +def fno_objc_infer_related_result_type : Flag<["-"], + "fno-objc-infer-related-result-type">, Group<f_Group>, + HelpText< + "do not infer Objective-C related result type based on method family">, + Flags<[CC1Option]>; +def fobjc_link_runtime: Flag<["-"], "fobjc-link-runtime">, Group<f_Group>; +def fobjc_weak : Flag<["-"], "fobjc-weak">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Enable ARC-style weak references in Objective-C">; + +// Objective-C ABI options. +def fobjc_runtime_EQ : Joined<["-"], "fobjc-runtime=">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Specify the target Objective-C runtime kind and version">; +def fobjc_abi_version_EQ : Joined<["-"], "fobjc-abi-version=">, Group<f_Group>; +def fobjc_nonfragile_abi_version_EQ : Joined<["-"], "fobjc-nonfragile-abi-version=">, Group<f_Group>; +def fobjc_nonfragile_abi : Flag<["-"], "fobjc-nonfragile-abi">, Group<f_Group>; +def fno_objc_nonfragile_abi : Flag<["-"], "fno-objc-nonfragile-abi">, Group<f_Group>; + +def fobjc_sender_dependent_dispatch : Flag<["-"], "fobjc-sender-dependent-dispatch">, Group<f_Group>; +def fomit_frame_pointer : Flag<["-"], "fomit-frame-pointer">, Group<f_Group>; +def fopenmp : Flag<["-"], "fopenmp">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>; +def fno_openmp : Flag<["-"], "fno-openmp">, Group<f_Group>, Flags<[NoArgumentUnused]>; +def fopenmp_EQ : Joined<["-"], "fopenmp=">, Group<f_Group>; +def fopenmp_use_tls : Flag<["-"], "fopenmp-use-tls">, Group<f_Group>, Flags<[NoArgumentUnused]>; +def fnoopenmp_use_tls : Flag<["-"], "fnoopenmp-use-tls">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>; +def fno_optimize_sibling_calls : Flag<["-"], "fno-optimize-sibling-calls">, Group<f_Group>; +def foptimize_sibling_calls : Flag<["-"], "foptimize-sibling-calls">, Group<f_Group>; +def force__cpusubtype__ALL : Flag<["-"], "force_cpusubtype_ALL">; +def force__flat__namespace : Flag<["-"], "force_flat_namespace">; +def force__load : Separate<["-"], "force_load">; +def force_addr : Joined<["-"], "fforce-addr">, Group<clang_ignored_f_Group>; +def foutput_class_dir_EQ : Joined<["-"], "foutput-class-dir=">, Group<f_Group>; +def fpack_struct : Flag<["-"], "fpack-struct">, Group<f_Group>; +def fno_pack_struct : Flag<["-"], "fno-pack-struct">, Group<f_Group>; +def fpack_struct_EQ : Joined<["-"], "fpack-struct=">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Specify the default maximum struct packing alignment">; +def fmax_type_align_EQ : Joined<["-"], "fmax-type-align=">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Specify the maximum alignment to enforce on pointers lacking an explicit alignment">; +def fno_max_type_align : Flag<["-"], "fno-max-type-align">, Group<f_Group>; +def fpascal_strings : Flag<["-"], "fpascal-strings">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Recognize and construct Pascal-style string literals">; +def fpcc_struct_return : Flag<["-"], "fpcc-struct-return">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Override the default ABI to return all structs on the stack">; +def fpch_preprocess : Flag<["-"], "fpch-preprocess">, Group<f_Group>; +def fpic : Flag<["-"], "fpic">, Group<f_Group>; +def fno_pic : Flag<["-"], "fno-pic">, Group<f_Group>; +def fpie : Flag<["-"], "fpie">, Group<f_Group>; +def fno_pie : Flag<["-"], "fno-pie">, Group<f_Group>; +def fplugin_EQ : Joined<["-"], "fplugin=">, Group<f_Group>, Flags<[DriverOption]>, MetaVarName<"<dsopath>">, + HelpText<"Load the named plugin (dynamic shared object)">; +def fprofile_arcs : Flag<["-"], "fprofile-arcs">, Group<f_Group>; +def fno_profile_arcs : Flag<["-"], "fno-profile-arcs">, Group<f_Group>; +def framework : Separate<["-"], "framework">, Flags<[LinkerInput]>; +def frandom_seed_EQ : Joined<["-"], "frandom-seed=">, Group<clang_ignored_f_Group>; +def freg_struct_return : Flag<["-"], "freg-struct-return">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Override the default ABI to return small structs in registers">; +def frtti : Flag<["-"], "frtti">, Group<f_Group>; +def : Flag<["-"], "fsched-interblock">, Group<clang_ignored_f_Group>; +def fshort_enums : Flag<["-"], "fshort-enums">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Allocate to an enum type only as many bytes as it needs for the declared range of possible values">; +def fshort_wchar : Flag<["-"], "fshort-wchar">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Force wchar_t to be a short unsigned int">; +def fno_short_wchar : Flag<["-"], "fno-short-wchar">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Force wchar_t to be an unsigned int">; +def fshow_overloads_EQ : Joined<["-"], "fshow-overloads=">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Which overload candidates to show when overload resolution fails: " + "best|all; defaults to all">; +def fshow_column : Flag<["-"], "fshow-column">, Group<f_Group>, Flags<[CC1Option]>; +def fshow_source_location : Flag<["-"], "fshow-source-location">, Group<f_Group>; +def fspell_checking : Flag<["-"], "fspell-checking">, Group<f_Group>; +def fspell_checking_limit_EQ : Joined<["-"], "fspell-checking-limit=">, Group<f_Group>; +def fsigned_bitfields : Flag<["-"], "fsigned-bitfields">, Group<f_Group>; +def fsigned_char : Flag<["-"], "fsigned-char">, Group<f_Group>; +def fno_signed_char : Flag<["-"], "fno-signed-char">, Group<f_Group>, + Flags<[CC1Option]>, HelpText<"Char is unsigned">; +def fsplit_stack : Flag<["-"], "fsplit-stack">, Group<f_Group>; +def fstack_protector_all : Flag<["-"], "fstack-protector-all">, Group<f_Group>, + HelpText<"Force the usage of stack protectors for all functions">; +def fstack_protector_strong : Flag<["-"], "fstack-protector-strong">, Group<f_Group>, + HelpText<"Use a strong heuristic to apply stack protectors to functions">; +def fstack_protector : Flag<["-"], "fstack-protector">, Group<f_Group>, + HelpText<"Enable stack protectors for functions potentially vulnerable to stack smashing">; +def fstandalone_debug : Flag<["-"], "fstandalone-debug">, Group<f_Group>, + HelpText<"Emit full debug info for all types used by the program">; +def fno_standalone_debug : Flag<["-"], "fno-standalone-debug">, Group<f_Group>, + HelpText<"Limit debug information produced to reduce size of debug binary">; +def flimit_debug_info : Flag<["-"], "flimit-debug-info">, Alias<fno_standalone_debug>; +def fno_limit_debug_info : Flag<["-"], "fno-limit-debug-info">, Alias<fstandalone_debug>; +def fstrict_aliasing : Flag<["-"], "fstrict-aliasing">, Group<f_Group>, + Flags<[DriverOption, CoreOption]>; +def fstrict_enums : Flag<["-"], "fstrict-enums">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Enable optimizations based on the strict definition of an enum's " + "value range">; +def fstrict_vtable_pointers: Flag<["-"], "fstrict-vtable-pointers">, + Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Enable optimizations based on the strict rules for overwriting " + "polymorphic C++ objects">; +def fstrict_overflow : Flag<["-"], "fstrict-overflow">, Group<f_Group>; +def fsyntax_only : Flag<["-"], "fsyntax-only">, + Flags<[DriverOption,CoreOption,CC1Option]>, Group<Action_Group>; +def ftabstop_EQ : Joined<["-"], "ftabstop=">, Group<f_Group>; +def ftemplate_depth_EQ : Joined<["-"], "ftemplate-depth=">, Group<f_Group>; +def ftemplate_depth_ : Joined<["-"], "ftemplate-depth-">, Group<f_Group>; +def ftemplate_backtrace_limit_EQ : Joined<["-"], "ftemplate-backtrace-limit=">, + Group<f_Group>; +def foperator_arrow_depth_EQ : Joined<["-"], "foperator-arrow-depth=">, + Group<f_Group>; +def ftest_coverage : Flag<["-"], "ftest-coverage">, Group<f_Group>; +def fvectorize : Flag<["-"], "fvectorize">, Group<f_Group>, + HelpText<"Enable the loop vectorization passes">; +def fno_vectorize : Flag<["-"], "fno-vectorize">, Group<f_Group>; +def : Flag<["-"], "ftree-vectorize">, Alias<fvectorize>; +def : Flag<["-"], "fno-tree-vectorize">, Alias<fno_vectorize>; +def fslp_vectorize : Flag<["-"], "fslp-vectorize">, Group<f_Group>, + HelpText<"Enable the superword-level parallelism vectorization passes">; +def fno_slp_vectorize : Flag<["-"], "fno-slp-vectorize">, Group<f_Group>; +def fslp_vectorize_aggressive : Flag<["-"], "fslp-vectorize-aggressive">, Group<f_Group>, + HelpText<"Enable the BB vectorization passes">; +def fno_slp_vectorize_aggressive : Flag<["-"], "fno-slp-vectorize-aggressive">, Group<f_Group>; +def : Flag<["-"], "ftree-slp-vectorize">, Alias<fslp_vectorize>; +def : Flag<["-"], "fno-tree-slp-vectorize">, Alias<fno_slp_vectorize>; +def Wlarge_by_value_copy_def : Flag<["-"], "Wlarge-by-value-copy">, + HelpText<"Warn if a function definition returns or accepts an object larger " + "in bytes than a given value">, Flags<[HelpHidden]>; +def Wlarge_by_value_copy_EQ : Joined<["-"], "Wlarge-by-value-copy=">, Flags<[CC1Option]>; + +// These "special" warning flags are effectively processed as f_Group flags by the driver: +// Just silence warnings about -Wlarger-than for now. +def Wlarger_than_EQ : Joined<["-"], "Wlarger-than=">, Group<clang_ignored_f_Group>; +def Wlarger_than_ : Joined<["-"], "Wlarger-than-">, Alias<Wlarger_than_EQ>; +def Wframe_larger_than_EQ : Joined<["-"], "Wframe-larger-than=">, Group<f_Group>, Flags<[DriverOption]>; + +def : Flag<["-"], "fterminated-vtables">, Alias<fapple_kext>; +def fthreadsafe_statics : Flag<["-"], "fthreadsafe-statics">, Group<f_Group>; +def ftime_report : Flag<["-"], "ftime-report">, Group<f_Group>, Flags<[CC1Option]>; +def ftlsmodel_EQ : Joined<["-"], "ftls-model=">, Group<f_Group>, Flags<[CC1Option]>; +def ftrapv : Flag<["-"], "ftrapv">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Trap on integer overflow">; +def ftrapv_handler_EQ : Joined<["-"], "ftrapv-handler=">, Group<f_Group>, + MetaVarName<"<function name>">, + HelpText<"Specify the function to be called on overflow">; +def ftrapv_handler : Separate<["-"], "ftrapv-handler">, Group<f_Group>, Flags<[CC1Option]>; +def ftrap_function_EQ : Joined<["-"], "ftrap-function=">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Issue call to specified function rather than a trap instruction">; +def funit_at_a_time : Flag<["-"], "funit-at-a-time">, Group<f_Group>; +def funroll_loops : Flag<["-"], "funroll-loops">, Group<f_Group>, + HelpText<"Turn on loop unroller">, Flags<[CC1Option]>; +def fno_unroll_loops : Flag<["-"], "fno-unroll-loops">, Group<f_Group>, + HelpText<"Turn off loop unroller">, Flags<[CC1Option]>; +def freroll_loops : Flag<["-"], "freroll-loops">, Group<f_Group>, + HelpText<"Turn on loop reroller">, Flags<[CC1Option]>; +def fno_reroll_loops : Flag<["-"], "fno-reroll-loops">, Group<f_Group>, + HelpText<"Turn off loop reroller">; +def ftrigraphs : Flag<["-"], "ftrigraphs">, Group<f_Group>, + HelpText<"Process trigraph sequences">, Flags<[CC1Option]>; +def fno_trigraphs : Flag<["-"], "fno-trigraphs">, Group<f_Group>, + HelpText<"Do not process trigraph sequences">, Flags<[CC1Option]>; +def funsigned_bitfields : Flag<["-"], "funsigned-bitfields">, Group<f_Group>; +def funsigned_char : Flag<["-"], "funsigned-char">, Group<f_Group>; +def fno_unsigned_char : Flag<["-"], "fno-unsigned-char">; +def funwind_tables : Flag<["-"], "funwind-tables">, Group<f_Group>; +def fuse_cxa_atexit : Flag<["-"], "fuse-cxa-atexit">, Group<f_Group>; +def fuse_init_array : Flag<["-"], "fuse-init-array">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Use .init_array instead of .ctors">; +def fno_var_tracking : Flag<["-"], "fno-var-tracking">, Group<clang_ignored_f_Group>; +def fverbose_asm : Flag<["-"], "fverbose-asm">, Group<f_Group>; +def fvisibility_EQ : Joined<["-"], "fvisibility=">, Group<f_Group>, + HelpText<"Set the default symbol visibility for all global declarations">; +def fvisibility_inlines_hidden : Flag<["-"], "fvisibility-inlines-hidden">, Group<f_Group>, + HelpText<"Give inline C++ member functions default visibility by default">, + Flags<[CC1Option]>; +def fvisibility_ms_compat : Flag<["-"], "fvisibility-ms-compat">, Group<f_Group>, + HelpText<"Give global types 'default' visibility and global functions and " + "variables 'hidden' visibility by default">; +def fwrapv : Flag<["-"], "fwrapv">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Treat signed integer overflow as two's complement">; +def fwritable_strings : Flag<["-"], "fwritable-strings">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Store string literals as writable data">; +def fzero_initialized_in_bss : Flag<["-"], "fzero-initialized-in-bss">, Group<f_Group>; +def ffunction_sections : Flag<["-"], "ffunction-sections">, Group<f_Group>, + Flags<[CC1Option]>, + HelpText<"Place each function in its own section (ELF Only)">; +def fno_function_sections : Flag<["-"], "fno-function-sections">, + Group<f_Group>, Flags<[CC1Option]>; +def fdata_sections : Flag <["-"], "fdata-sections">, Group<f_Group>, + Flags<[CC1Option]>, HelpText<"Place each data in its own section (ELF Only)">; +def fno_data_sections : Flag <["-"], "fno-data-sections">, Group<f_Group>, + Flags<[CC1Option]>; + +def funique_section_names : Flag <["-"], "funique-section-names">, + Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Use unique names for text and data sections (ELF Only)">; +def fno_unique_section_names : Flag <["-"], "fno-unique-section-names">, + Group<f_Group>, Flags<[CC1Option]>; + + +def fdebug_types_section: Flag <["-"], "fdebug-types-section">, Group<f_Group>, + Flags<[CC1Option]>, HelpText<"Place debug types in their own section (ELF Only)">; +def fno_debug_types_section: Flag<["-"], "fno-debug-types-section">, Group<f_Group>, + Flags<[CC1Option]>; +def fdebug_prefix_map_EQ + : Joined<["-"], "fdebug-prefix-map=">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"remap file source paths in debug info">; +def g_Flag : Flag<["-"], "g">, Group<g_Group>, + HelpText<"Generate source-level debug information">; +def gline_tables_only : Flag<["-"], "gline-tables-only">, Group<gN_Group>, + HelpText<"Emit debug line number tables only">; +def gmlt : Flag<["-"], "gmlt">, Alias<gline_tables_only>; +def g0 : Flag<["-"], "g0">, Group<gN_Group>; +def g1 : Flag<["-"], "g1">, Group<gN_Group>, Alias<gline_tables_only>; +def g2 : Flag<["-"], "g2">, Group<gN_Group>; +def g3 : Flag<["-"], "g3">, Group<gN_Group>; +def ggdb : Flag<["-"], "ggdb">, Group<gTune_Group>; +def ggdb0 : Flag<["-"], "ggdb0">, Group<ggdbN_Group>; +def ggdb1 : Flag<["-"], "ggdb1">, Group<ggdbN_Group>; +def ggdb2 : Flag<["-"], "ggdb2">, Group<ggdbN_Group>; +def ggdb3 : Flag<["-"], "ggdb3">, Group<ggdbN_Group>; +def glldb : Flag<["-"], "glldb">, Group<gTune_Group>; +def gsce : Flag<["-"], "gsce">, Group<gTune_Group>; +def gdwarf_2 : Flag<["-"], "gdwarf-2">, Group<g_Group>, + HelpText<"Generate source-level debug information with dwarf version 2">; +def gdwarf_3 : Flag<["-"], "gdwarf-3">, Group<g_Group>, + HelpText<"Generate source-level debug information with dwarf version 3">; +def gdwarf_4 : Flag<["-"], "gdwarf-4">, Group<g_Group>, + HelpText<"Generate source-level debug information with dwarf version 4">; +def gdwarf_5 : Flag<["-"], "gdwarf-5">, Group<g_Group>, + HelpText<"Generate source-level debug information with dwarf version 5">; +def gcodeview : Flag<["-"], "gcodeview">, + HelpText<"Generate CodeView debug information">, + Flags<[CC1Option, CC1AsOption, CoreOption]>; +// Equivalent to our default dwarf version. Forces usual dwarf emission when +// CodeView is enabled. +def gdwarf : Flag<["-"], "gdwarf">, Alias<gdwarf_4>, Flags<[CoreOption]>; + +def gfull : Flag<["-"], "gfull">, Group<g_Group>; +def gused : Flag<["-"], "gused">, Group<g_Group>; +def gstabs : Joined<["-"], "gstabs">, Group<g_Group>, Flags<[Unsupported]>; +def gcoff : Joined<["-"], "gcoff">, Group<g_Group>, Flags<[Unsupported]>; +def gxcoff : Joined<["-"], "gxcoff">, Group<g_Group>, Flags<[Unsupported]>; +def gvms : Joined<["-"], "gvms">, Group<g_Group>, Flags<[Unsupported]>; +def gtoggle : Flag<["-"], "gtoggle">, Group<g_flags_Group>, Flags<[Unsupported]>; +def grecord_gcc_switches : Flag<["-"], "grecord-gcc-switches">, Group<g_flags_Group>; +def gno_record_gcc_switches : Flag<["-"], "gno-record-gcc-switches">, + Group<g_flags_Group>; +def gstrict_dwarf : Flag<["-"], "gstrict-dwarf">, Group<g_flags_Group>; +def gno_strict_dwarf : Flag<["-"], "gno-strict-dwarf">, Group<g_flags_Group>; +def gcolumn_info : Flag<["-"], "gcolumn-info">, Group<g_flags_Group>; +def gno_column_info : Flag<["-"], "gno-column-info">, Group<g_flags_Group>; +def gsplit_dwarf : Flag<["-"], "gsplit-dwarf">, Group<g_flags_Group>; +def ggnu_pubnames : Flag<["-"], "ggnu-pubnames">, Group<g_flags_Group>; +def gdwarf_aranges : Flag<["-"], "gdwarf-aranges">, Group<g_flags_Group>; +def gmodules : Flag <["-"], "gmodules">, Group<f_Group>, + HelpText<"Generate debug info with external references to clang modules" + " or precompiled headers">; +def headerpad__max__install__names : Joined<["-"], "headerpad_max_install_names">; +def help : Flag<["-", "--"], "help">, Flags<[CC1Option,CC1AsOption]>, + HelpText<"Display available options">; +def index_header_map : Flag<["-"], "index-header-map">, Flags<[CC1Option]>, + HelpText<"Make the next included directory (-I or -F) an indexer header map">; +def idirafter : JoinedOrSeparate<["-"], "idirafter">, Group<clang_i_Group>, Flags<[CC1Option]>, + HelpText<"Add directory to AFTER include search path">; +def iframework : JoinedOrSeparate<["-"], "iframework">, Group<clang_i_Group>, Flags<[CC1Option]>, + HelpText<"Add directory to SYSTEM framework search path">; +def imacros : JoinedOrSeparate<["-", "--"], "imacros">, Group<clang_i_Group>, Flags<[CC1Option]>, + HelpText<"Include macros from file before parsing">, MetaVarName<"<file>">; +def image__base : Separate<["-"], "image_base">; +def include_ : JoinedOrSeparate<["-", "--"], "include">, Group<clang_i_Group>, EnumName<"include">, + MetaVarName<"<file>">, HelpText<"Include file before parsing">, Flags<[CC1Option]>; +def include_pch : Separate<["-"], "include-pch">, Group<clang_i_Group>, Flags<[CC1Option]>, + HelpText<"Include precompiled header file">, MetaVarName<"<file>">; +def relocatable_pch : Flag<["-", "--"], "relocatable-pch">, Flags<[CC1Option]>, + HelpText<"Whether to build a relocatable precompiled header">; +def verify_pch : Flag<["-"], "verify-pch">, Group<Action_Group>, Flags<[CC1Option]>, + HelpText<"Load and verify that a pre-compiled header file is not stale">; +def init : Separate<["-"], "init">; +def install__name : Separate<["-"], "install_name">; +def iprefix : JoinedOrSeparate<["-"], "iprefix">, Group<clang_i_Group>, Flags<[CC1Option]>, + HelpText<"Set the -iwithprefix/-iwithprefixbefore prefix">, MetaVarName<"<dir>">; +def iquote : JoinedOrSeparate<["-"], "iquote">, Group<clang_i_Group>, Flags<[CC1Option]>, + HelpText<"Add directory to QUOTE include search path">, MetaVarName<"<directory>">; +def isysroot : JoinedOrSeparate<["-"], "isysroot">, Group<clang_i_Group>, Flags<[CC1Option]>, + HelpText<"Set the system root directory (usually /)">, MetaVarName<"<dir>">; +def isystem : JoinedOrSeparate<["-"], "isystem">, Group<clang_i_Group>, Flags<[CC1Option]>, + HelpText<"Add directory to SYSTEM include search path">, MetaVarName<"<directory>">; +def iwithprefixbefore : JoinedOrSeparate<["-"], "iwithprefixbefore">, Group<clang_i_Group>, + HelpText<"Set directory to include search path with prefix">, MetaVarName<"<dir>">, + Flags<[CC1Option]>; +def iwithprefix : JoinedOrSeparate<["-"], "iwithprefix">, Group<clang_i_Group>, Flags<[CC1Option]>, + HelpText<"Set directory to SYSTEM include search path with prefix">, MetaVarName<"<dir>">; +def iwithsysroot : JoinedOrSeparate<["-"], "iwithsysroot">, Group<clang_i_Group>, + HelpText<"Add directory to SYSTEM include search path, " + "absolute paths are relative to -isysroot">, MetaVarName<"<directory>">, + Flags<[CC1Option]>; +def ivfsoverlay : JoinedOrSeparate<["-"], "ivfsoverlay">, Group<clang_i_Group>, Flags<[CC1Option]>, + HelpText<"Overlay the virtual filesystem described by file over the real file system">; +def i : Joined<["-"], "i">, Group<i_Group>; +def keep__private__externs : Flag<["-"], "keep_private_externs">; +def l : JoinedOrSeparate<["-"], "l">, Flags<[LinkerInput, RenderJoined]>; +def lazy__framework : Separate<["-"], "lazy_framework">, Flags<[LinkerInput]>; +def lazy__library : Separate<["-"], "lazy_library">, Flags<[LinkerInput]>; +def mlittle_endian : Flag<["-"], "mlittle-endian">, Flags<[DriverOption]>; +def EL : Flag<["-"], "EL">, Alias<mlittle_endian>; +def mbig_endian : Flag<["-"], "mbig-endian">, Flags<[DriverOption]>; +def EB : Flag<["-"], "EB">, Alias<mbig_endian>; +def m16 : Flag<["-"], "m16">, Group<m_Group>, Flags<[DriverOption, CoreOption]>; +def m32 : Flag<["-"], "m32">, Group<m_Group>, Flags<[DriverOption, CoreOption]>; +def mqdsp6_compat : Flag<["-"], "mqdsp6-compat">, Group<m_Group>, Flags<[DriverOption,CC1Option]>, + HelpText<"Enable hexagon-qdsp6 backward compatibility">; +def m3dnowa : Flag<["-"], "m3dnowa">, Group<m_x86_Features_Group>; +def m3dnow : Flag<["-"], "m3dnow">, Group<m_x86_Features_Group>; +def m64 : Flag<["-"], "m64">, Group<m_Group>, Flags<[DriverOption, CoreOption]>; +def mx32 : Flag<["-"], "mx32">, Group<m_Group>, Flags<[DriverOption, CoreOption]>; +def mabi_EQ : Joined<["-"], "mabi=">, Group<m_Group>; +def malign_functions_EQ : Joined<["-"], "malign-functions=">, Group<clang_ignored_m_Group>; +def malign_loops_EQ : Joined<["-"], "malign-loops=">, Group<clang_ignored_m_Group>; +def malign_jumps_EQ : Joined<["-"], "malign-jumps=">, Group<clang_ignored_m_Group>; +def mfancy_math_387 : Flag<["-"], "mfancy-math-387">, Group<clang_ignored_m_Group>; +def mtvos_version_min_EQ : Joined<["-"], "mtvos-version-min=">, Group<m_Group>; +def mappletvos_version_min_EQ : Joined<["-"], "mappletvos-version-min=">, Alias<mtvos_version_min_EQ>; +def mtvos_simulator_version_min_EQ : Joined<["-"], "mtvos-simulator-version-min=">, Alias<mtvos_version_min_EQ>; +def mappletvsimulator_version_min_EQ : Joined<["-"], "mappletvsimulator-version-min=">, Alias<mtvos_version_min_EQ>; +def mwatchos_version_min_EQ : Joined<["-"], "mwatchos-version-min=">, Group<m_Group>; +def mwatchos_simulator_version_min_EQ : Joined<["-"], "mwatchos-simulator-version-min=">, Alias<mwatchos_version_min_EQ>; +def mwatchsimulator_version_min_EQ : Joined<["-"], "mwatchsimulator-version-min=">, Alias<mwatchos_version_min_EQ>; +def march_EQ : Joined<["-"], "march=">, Group<m_Group>; +def masm_EQ : Joined<["-"], "masm=">, Group<m_Group>, Flags<[DriverOption]>; +def mcmodel_EQ : Joined<["-"], "mcmodel=">, Group<m_Group>; +def mconstant_cfstrings : Flag<["-"], "mconstant-cfstrings">, Group<clang_ignored_m_Group>; +def mconsole : Joined<["-"], "mconsole">, Group<m_Group>, Flags<[DriverOption]>; +def mwindows : Joined<["-"], "mwindows">, Group<m_Group>, Flags<[DriverOption]>; +def mdll : Joined<["-"], "mdll">, Group<m_Group>, Flags<[DriverOption]>; +def municode : Joined<["-"], "municode">, Group<m_Group>, Flags<[DriverOption]>; +def mthreads : Joined<["-"], "mthreads">, Group<m_Group>, Flags<[DriverOption]>; +def mcpu_EQ : Joined<["-"], "mcpu=">, Group<m_Group>; +def mdynamic_no_pic : Joined<["-"], "mdynamic-no-pic">, Group<m_Group>; +def mfix_and_continue : Flag<["-"], "mfix-and-continue">, Group<clang_ignored_m_Group>; +def mieee_fp : Flag<["-"], "mieee-fp">, Group<clang_ignored_m_Group>; +def minline_all_stringops : Flag<["-"], "minline-all-stringops">, Group<clang_ignored_m_Group>; +def mno_inline_all_stringops : Flag<["-"], "mno-inline-all-stringops">, Group<clang_ignored_m_Group>; +def mfloat_abi_EQ : Joined<["-"], "mfloat-abi=">, Group<m_Group>; +def mfpmath_EQ : Joined<["-"], "mfpmath=">, Group<m_Group>; +def mfpu_EQ : Joined<["-"], "mfpu=">, Group<m_Group>; +def mhwdiv_EQ : Joined<["-"], "mhwdiv=">, Group<m_Group>; +def mglobal_merge : Flag<["-"], "mglobal-merge">, Group<m_Group>, Flags<[CC1Option]>, + HelpText<"Enable merging of globals">; +def mhard_float : Flag<["-"], "mhard-float">, Group<m_Group>; +def miphoneos_version_min_EQ : Joined<["-"], "miphoneos-version-min=">, Group<m_Group>; +def mios_version_min_EQ : Joined<["-"], "mios-version-min=">, + Alias<miphoneos_version_min_EQ>, HelpText<"Set iOS deployment target">; +def mios_simulator_version_min_EQ : Joined<["-"], "mios-simulator-version-min=">, Alias<miphoneos_version_min_EQ>; +def miphonesimulator_version_min_EQ : Joined<["-"], "miphonesimulator-version-min=">, Alias<miphoneos_version_min_EQ>; +def mkernel : Flag<["-"], "mkernel">, Group<m_Group>; +def mlinker_version_EQ : Joined<["-"], "mlinker-version=">, + Flags<[DriverOption]>; +def mllvm : Separate<["-"], "mllvm">, Flags<[CC1Option,CC1AsOption,CoreOption]>, + HelpText<"Additional arguments to forward to LLVM's option processing">; +def mmacosx_version_min_EQ : Joined<["-"], "mmacosx-version-min=">, + Group<m_Group>, HelpText<"Set Mac OS X deployment target">; +def mms_bitfields : Flag<["-"], "mms-bitfields">, Group<m_Group>, Flags<[CC1Option]>, + HelpText<"Set the default structure layout to be compatible with the Microsoft compiler standard">; +def mno_ms_bitfields : Flag<["-"], "mno-ms-bitfields">, Group<m_Group>, + HelpText<"Do not set the default structure layout to be compatible with the Microsoft compiler standard">; +def mstackrealign : Flag<["-"], "mstackrealign">, Group<m_Group>, Flags<[CC1Option]>, + HelpText<"Force realign the stack at entry to every function">; +def mstack_alignment : Joined<["-"], "mstack-alignment=">, Group<m_Group>, Flags<[CC1Option]>, + HelpText<"Set the stack alignment">; +def mstack_probe_size : Joined<["-"], "mstack-probe-size=">, Group<m_Group>, Flags<[CC1Option]>, + HelpText<"Set the stack probe size">; +def mthread_model : Separate<["-"], "mthread-model">, Group<m_Group>, Flags<[CC1Option]>, + HelpText<"The thread model to use, e.g. posix, single (posix by default)">; +def meabi : Separate<["-"], "meabi">, Group<m_Group>, Flags<[CC1Option]>, + HelpText<"Set EABI type, e.g. 4, 5 or gnu (default depends on triple)">; + +def mmmx : Flag<["-"], "mmmx">, Group<m_x86_Features_Group>; +def mno_3dnowa : Flag<["-"], "mno-3dnowa">, Group<m_x86_Features_Group>; +def mno_3dnow : Flag<["-"], "mno-3dnow">, Group<m_x86_Features_Group>; +def mno_constant_cfstrings : Flag<["-"], "mno-constant-cfstrings">, Group<m_Group>; +def mno_global_merge : Flag<["-"], "mno-global-merge">, Group<m_Group>, Flags<[CC1Option]>, + HelpText<"Disable merging of globals">; +def mno_mmx : Flag<["-"], "mno-mmx">, Group<m_x86_Features_Group>; +def mno_pascal_strings : Flag<["-"], "mno-pascal-strings">, + Alias<fno_pascal_strings>; +def mno_red_zone : Flag<["-"], "mno-red-zone">, Group<m_Group>; +def mno_relax_all : Flag<["-"], "mno-relax-all">, Group<m_Group>; +def mno_rtd: Flag<["-"], "mno-rtd">, Group<m_Group>; +def mno_soft_float : Flag<["-"], "mno-soft-float">, Group<m_Group>; +def mno_stackrealign : Flag<["-"], "mno-stackrealign">, Group<m_Group>; +def mno_sse2 : Flag<["-"], "mno-sse2">, Group<m_x86_Features_Group>; +def mno_sse3 : Flag<["-"], "mno-sse3">, Group<m_x86_Features_Group>; +def mno_sse4a : Flag<["-"], "mno-sse4a">, Group<m_x86_Features_Group>; +def mno_sse4_1 : Flag<["-"], "mno-sse4.1">, Group<m_x86_Features_Group>; +def mno_sse4_2 : Flag<["-"], "mno-sse4.2">, Group<m_x86_Features_Group>; +// -mno-sse4 turns off sse4.1 which has the effect of turning off everything +// later than 4.1. -msse4 turns on 4.2 which has the effect of turning on +// everything earlier than 4.2. +def mno_sse4 : Flag<["-"], "mno-sse4">, Alias<mno_sse4_1>; +def mno_sse : Flag<["-"], "mno-sse">, Group<m_x86_Features_Group>; +def mno_ssse3 : Flag<["-"], "mno-ssse3">, Group<m_x86_Features_Group>; +def mno_aes : Flag<["-"], "mno-aes">, Group<m_x86_Features_Group>; +def mno_avx : Flag<["-"], "mno-avx">, Group<m_x86_Features_Group>; +def mno_avx2 : Flag<["-"], "mno-avx2">, Group<m_x86_Features_Group>; +def mno_avx512f : Flag<["-"], "mno-avx512f">, Group<m_x86_Features_Group>; +def mno_avx512cd : Flag<["-"], "mno-avx512cd">, Group<m_x86_Features_Group>; +def mno_avx512er : Flag<["-"], "mno-avx512er">, Group<m_x86_Features_Group>; +def mno_avx512pf : Flag<["-"], "mno-avx512pf">, Group<m_x86_Features_Group>; +def mno_avx512dq : Flag<["-"], "mno-avx512dq">, Group<m_x86_Features_Group>; +def mno_avx512bw : Flag<["-"], "mno-avx512bw">, Group<m_x86_Features_Group>; +def mno_avx512vl : Flag<["-"], "mno-avx512vl">, Group<m_x86_Features_Group>; +def mno_pclmul : Flag<["-"], "mno-pclmul">, Group<m_x86_Features_Group>; +def mno_lzcnt : Flag<["-"], "mno-lzcnt">, Group<m_x86_Features_Group>; +def mno_rdrnd : Flag<["-"], "mno-rdrnd">, Group<m_x86_Features_Group>; +def mno_fsgsbase : Flag<["-"], "mno-fsgsbase">, Group<m_x86_Features_Group>; +def mno_bmi : Flag<["-"], "mno-bmi">, Group<m_x86_Features_Group>; +def mno_bmi2 : Flag<["-"], "mno-bmi2">, Group<m_x86_Features_Group>; +def mno_popcnt : Flag<["-"], "mno-popcnt">, Group<m_x86_Features_Group>; +def mno_tbm : Flag<["-"], "mno-tbm">, Group<m_x86_Features_Group>; +def mno_fma4 : Flag<["-"], "mno-fma4">, Group<m_x86_Features_Group>; +def mno_fma : Flag<["-"], "mno-fma">, Group<m_x86_Features_Group>; +def mno_xop : Flag<["-"], "mno-xop">, Group<m_x86_Features_Group>; +def mno_f16c : Flag<["-"], "mno-f16c">, Group<m_x86_Features_Group>; +def mno_rtm : Flag<["-"], "mno-rtm">, Group<m_x86_Features_Group>; +def mno_prfchw : Flag<["-"], "mno-prfchw">, Group<m_x86_Features_Group>; +def mno_rdseed : Flag<["-"], "mno-rdseed">, Group<m_x86_Features_Group>; +def mno_adx : Flag<["-"], "mno-adx">, Group<m_x86_Features_Group>; +def mno_sha : Flag<["-"], "mno-sha">, Group<m_x86_Features_Group>; +def mno_fxsr : Flag<["-"], "mno-fxsr">, Group<m_x86_Features_Group>; +def mno_xsave : Flag<["-"], "mno-xsave">, Group<m_x86_Features_Group>; +def mno_xsaveopt : Flag<["-"], "mno-xsaveopt">, Group<m_x86_Features_Group>; +def mno_xsavec : Flag<["-"], "mno-xsavec">, Group<m_x86_Features_Group>; +def mno_xsaves : Flag<["-"], "mno-xsaves">, Group<m_x86_Features_Group>; +def mno_pku : Flag<["-"], "mno-pku">, Group<m_x86_Features_Group>; + +def munaligned_access : Flag<["-"], "munaligned-access">, Group<m_arm_Features_Group>, + HelpText<"Allow memory accesses to be unaligned (AArch32/AArch64 only)">; +def mno_unaligned_access : Flag<["-"], "mno-unaligned-access">, Group<m_arm_Features_Group>, + HelpText<"Force all memory accesses to be aligned (AArch32/AArch64 only)">; +def mstrict_align : Flag<["-"], "mstrict-align">, Alias<mno_unaligned_access>, Flags<[CC1Option,HelpHidden]>, + HelpText<"Force all memory accesses to be aligned (same as mno-unaligned-access)">; +def mno_thumb : Flag<["-"], "mno-thumb">, Group<m_arm_Features_Group>; +def mrestrict_it: Flag<["-"], "mrestrict-it">, Group<m_arm_Features_Group>, + HelpText<"Disallow generation of deprecated IT blocks for ARMv8. It is on by default for ARMv8 Thumb mode.">; +def mno_restrict_it: Flag<["-"], "mno-restrict-it">, Group<m_arm_Features_Group>, + HelpText<"Allow generation of deprecated IT blocks for ARMv8. It is off by default for ARMv8 Thumb mode">; +def marm : Flag<["-"], "marm">, Alias<mno_thumb>; +def ffixed_r9 : Flag<["-"], "ffixed-r9">, Group<m_arm_Features_Group>, + HelpText<"Reserve the r9 register (ARM only)">; +def mno_movt : Flag<["-"], "mno-movt">, Group<m_arm_Features_Group>, + HelpText<"Disallow use of movt/movw pairs (ARM only)">; +def mcrc : Flag<["-"], "mcrc">, Group<m_arm_Features_Group>, + HelpText<"Allow use of CRC instructions (ARM only)">; +def mnocrc : Flag<["-"], "mnocrc">, Group<m_arm_Features_Group>, + HelpText<"Disallow use of CRC instructions (ARM only)">; +def mlong_calls : Flag<["-"], "mlong-calls">, Group<m_arm_Features_Group>, + HelpText<"Generate an indirect jump to enable jumps further than 64M">; +def mno_long_calls : Flag<["-"], "mno-long-calls">, Group<m_arm_Features_Group>, + HelpText<"Restore the default behaviour of not generating long calls">; + +def mgeneral_regs_only : Flag<["-"], "mgeneral-regs-only">, Group<m_aarch64_Features_Group>, + HelpText<"Generate code which only uses the general purpose registers (AArch64 only)">; + +def mfix_cortex_a53_835769 : Flag<["-"], "mfix-cortex-a53-835769">, + Group<m_aarch64_Features_Group>, + HelpText<"Workaround Cortex-A53 erratum 835769 (AArch64 only)">; +def mno_fix_cortex_a53_835769 : Flag<["-"], "mno-fix-cortex-a53-835769">, + Group<m_aarch64_Features_Group>, + HelpText<"Don't workaround Cortex-A53 erratum 835769 (AArch64 only)">; +def ffixed_x18 : Flag<["-"], "ffixed-x18">, Group<m_aarch64_Features_Group>, + HelpText<"Reserve the x18 register (AArch64 only)">; + +def msimd128 : Flag<["-"], "msimd128">, Group<m_wasm_Features_Group>; +def mno_simd128 : Flag<["-"], "mno-simd128">, Group<m_wasm_Features_Group>; + +def mvsx : Flag<["-"], "mvsx">, Group<m_ppc_Features_Group>; +def mno_vsx : Flag<["-"], "mno-vsx">, Group<m_ppc_Features_Group>; +def mpower8_vector : Flag<["-"], "mpower8-vector">, + Group<m_ppc_Features_Group>; +def mno_power8_vector : Flag<["-"], "mno-power8-vector">, + Group<m_ppc_Features_Group>; +def mpower8_crypto : Flag<["-"], "mcrypto">, + Group<m_ppc_Features_Group>; +def mnopower8_crypto : Flag<["-"], "mno-crypto">, + Group<m_ppc_Features_Group>; +def mdirect_move : Flag<["-"], "mdirect-move">, + Group<m_ppc_Features_Group>; +def mnodirect_move : Flag<["-"], "mno-direct-move">, + Group<m_ppc_Features_Group>; +def mhtm : Flag<["-"], "mhtm">, Group<m_ppc_Features_Group>; +def mno_htm : Flag<["-"], "mno-htm">, Group<m_ppc_Features_Group>; +def mfprnd : Flag<["-"], "mfprnd">, Group<m_ppc_Features_Group>; +def mno_fprnd : Flag<["-"], "mno-fprnd">, Group<m_ppc_Features_Group>; +def mcmpb : Flag<["-"], "mcmpb">, Group<m_ppc_Features_Group>; +def mno_cmpb : Flag<["-"], "mno-cmpb">, Group<m_ppc_Features_Group>; +def misel : Flag<["-"], "misel">, Group<m_ppc_Features_Group>; +def mno_isel : Flag<["-"], "mno-isel">, Group<m_ppc_Features_Group>; +def mmfocrf : Flag<["-"], "mmfocrf">, Group<m_ppc_Features_Group>; +def mmfcrf : Flag<["-"], "mmfcrf">, Alias<mmfocrf>; +def mno_mfocrf : Flag<["-"], "mno-mfocrf">, Group<m_ppc_Features_Group>; +def mno_mfcrf : Flag<["-"], "mno-mfcrf">, Alias<mno_mfocrf>; +def mpopcntd : Flag<["-"], "mpopcntd">, Group<m_ppc_Features_Group>; +def mno_popcntd : Flag<["-"], "mno-popcntd">, Group<m_ppc_Features_Group>; +def mqpx : Flag<["-"], "mqpx">, Group<m_ppc_Features_Group>; +def mno_qpx : Flag<["-"], "mno-qpx">, Group<m_ppc_Features_Group>; +def mcrbits : Flag<["-"], "mcrbits">, Group<m_ppc_Features_Group>; +def mno_crbits : Flag<["-"], "mno-crbits">, Group<m_ppc_Features_Group>; +def minvariant_function_descriptors : + Flag<["-"], "minvariant-function-descriptors">, Group<m_ppc_Features_Group>; +def mno_invariant_function_descriptors : + Flag<["-"], "mno-invariant-function-descriptors">, + Group<m_ppc_Features_Group>; + +def faltivec : Flag<["-"], "faltivec">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Enable AltiVec vector initializer syntax">; +def fno_altivec : Flag<["-"], "fno-altivec">, Group<f_Group>, Flags<[CC1Option]>; +def maltivec : Flag<["-"], "maltivec">, Alias<faltivec>; +def mno_altivec : Flag<["-"], "mno-altivec">, Alias<fno_altivec>; + +def mvx : Flag<["-"], "mvx">, Group<m_Group>; +def mno_vx : Flag<["-"], "mno-vx">, Group<m_Group>; + +def fzvector : Flag<["-"], "fzvector">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Enable System z vector language extension">; +def fno_zvector : Flag<["-"], "fno-zvector">, Group<f_Group>, + Flags<[CC1Option]>; +def mzvector : Flag<["-"], "mzvector">, Alias<fzvector>; +def mno_zvector : Flag<["-"], "mno-zvector">, Alias<fno_zvector>; + +def mno_warn_nonportable_cfstrings : Flag<["-"], "mno-warn-nonportable-cfstrings">, Group<m_Group>; +def mno_omit_leaf_frame_pointer : Flag<["-"], "mno-omit-leaf-frame-pointer">, Group<m_Group>; +def momit_leaf_frame_pointer : Flag<["-"], "momit-leaf-frame-pointer">, Group<m_Group>, + HelpText<"Omit frame pointer setup for leaf functions">, Flags<[CC1Option]>; +def moslib_EQ : Joined<["-"], "moslib=">, Group<m_Group>; +def mpascal_strings : Flag<["-"], "mpascal-strings">, Alias<fpascal_strings>; +def mred_zone : Flag<["-"], "mred-zone">, Group<m_Group>; +def mregparm_EQ : Joined<["-"], "mregparm=">, Group<m_Group>; +def mrelax_all : Flag<["-"], "mrelax-all">, Group<m_Group>, Flags<[CC1Option,CC1AsOption]>, + HelpText<"(integrated-as) Relax all machine instructions">; +def mincremental_linker_compatible : Flag<["-"], "mincremental-linker-compatible">, Group<m_Group>, + Flags<[CC1Option,CC1AsOption]>, + HelpText<"(integrated-as) Emit an object file which can be used with an incremental linker">; +def mno_incremental_linker_compatible : Flag<["-"], "mno-incremental-linker-compatible">, Group<m_Group>, + HelpText<"(integrated-as) Emit an object file which cannot be used with an incremental linker">; +def mrtd : Flag<["-"], "mrtd">, Group<m_Group>, Flags<[CC1Option]>, + HelpText<"Make StdCall calling convention the default">; +def msmall_data_threshold_EQ : Joined <["-"], "msmall-data-threshold=">, Group<m_Group>; +def msoft_float : Flag<["-"], "msoft-float">, Group<m_Group>, Flags<[CC1Option]>, + HelpText<"Use software floating point">; +def mno_implicit_float : Flag<["-"], "mno-implicit-float">, Group<m_Group>, + HelpText<"Don't generate implicit floating point instructions">; +def mimplicit_float : Flag<["-"], "mimplicit-float">, Group<m_Group>; +def mrecip : Flag<["-"], "mrecip">, Group<m_Group>; +def mrecip_EQ : CommaJoined<["-"], "mrecip=">, Group<m_Group>, Flags<[CC1Option]>; +def msse2 : Flag<["-"], "msse2">, Group<m_x86_Features_Group>; +def msse3 : Flag<["-"], "msse3">, Group<m_x86_Features_Group>; +def msse4a : Flag<["-"], "msse4a">, Group<m_x86_Features_Group>; +def msse4_1 : Flag<["-"], "msse4.1">, Group<m_x86_Features_Group>; +def msse4_2 : Flag<["-"], "msse4.2">, Group<m_x86_Features_Group>; +def msse4 : Flag<["-"], "msse4">, Alias<msse4_2>; +def msse : Flag<["-"], "msse">, Group<m_x86_Features_Group>; +def mssse3 : Flag<["-"], "mssse3">, Group<m_x86_Features_Group>; +def maes : Flag<["-"], "maes">, Group<m_x86_Features_Group>; +def mavx : Flag<["-"], "mavx">, Group<m_x86_Features_Group>; +def mavx2 : Flag<["-"], "mavx2">, Group<m_x86_Features_Group>; +def mavx512f : Flag<["-"], "mavx512f">, Group<m_x86_Features_Group>; +def mavx512cd : Flag<["-"], "mavx512cd">, Group<m_x86_Features_Group>; +def mavx512er : Flag<["-"], "mavx512er">, Group<m_x86_Features_Group>; +def mavx512pf : Flag<["-"], "mavx512pf">, Group<m_x86_Features_Group>; +def mavx512dq : Flag<["-"], "mavx512dq">, Group<m_x86_Features_Group>; +def mavx512bw : Flag<["-"], "mavx512bw">, Group<m_x86_Features_Group>; +def mavx512vl : Flag<["-"], "mavx512vl">, Group<m_x86_Features_Group>; +def mpclmul : Flag<["-"], "mpclmul">, Group<m_x86_Features_Group>; +def mlzcnt : Flag<["-"], "mlzcnt">, Group<m_x86_Features_Group>; +def mrdrnd : Flag<["-"], "mrdrnd">, Group<m_x86_Features_Group>; +def mfsgsbase : Flag<["-"], "mfsgsbase">, Group<m_x86_Features_Group>; +def mbmi : Flag<["-"], "mbmi">, Group<m_x86_Features_Group>; +def mbmi2 : Flag<["-"], "mbmi2">, Group<m_x86_Features_Group>; +def mpopcnt : Flag<["-"], "mpopcnt">, Group<m_x86_Features_Group>; +def mtbm : Flag<["-"], "mtbm">, Group<m_x86_Features_Group>; +def mfma4 : Flag<["-"], "mfma4">, Group<m_x86_Features_Group>; +def mfma : Flag<["-"], "mfma">, Group<m_x86_Features_Group>; +def mxop : Flag<["-"], "mxop">, Group<m_x86_Features_Group>; +def mf16c : Flag<["-"], "mf16c">, Group<m_x86_Features_Group>; +def mrtm : Flag<["-"], "mrtm">, Group<m_x86_Features_Group>; +def mprfchw : Flag<["-"], "mprfchw">, Group<m_x86_Features_Group>; +def mrdseed : Flag<["-"], "mrdseed">, Group<m_x86_Features_Group>; +def mpku : Flag<["-"], "mpku">, Group<m_x86_Features_Group>; +def madx : Flag<["-"], "madx">, Group<m_x86_Features_Group>; +def msha : Flag<["-"], "msha">, Group<m_x86_Features_Group>; +def mcx16 : Flag<["-"], "mcx16">, Group<m_x86_Features_Group>; +def mfxsr : Flag<["-"], "mfxsr">, Group<m_x86_Features_Group>; +def mxsave : Flag<["-"], "mxsave">, Group<m_x86_Features_Group>; +def mxsaveopt : Flag<["-"], "mxsaveopt">, Group<m_x86_Features_Group>; +def mxsavec : Flag<["-"], "mxsavec">, Group<m_x86_Features_Group>; +def mxsaves : Flag<["-"], "mxsaves">, Group<m_x86_Features_Group>; +def mips16 : Flag<["-"], "mips16">, Group<m_Group>; +def mno_mips16 : Flag<["-"], "mno-mips16">, Group<m_Group>; +def mmicromips : Flag<["-"], "mmicromips">, Group<m_Group>; +def mno_micromips : Flag<["-"], "mno-micromips">, Group<m_Group>; +def mxgot : Flag<["-"], "mxgot">, Group<m_Group>; +def mno_xgot : Flag<["-"], "mno-xgot">, Group<m_Group>; +def mldc1_sdc1 : Flag<["-"], "mldc1-sdc1">, Group<m_Group>; +def mno_ldc1_sdc1 : Flag<["-"], "mno-ldc1-sdc1">, Group<m_Group>; +def mcheck_zero_division : Flag<["-"], "mcheck-zero-division">, Group<m_Group>; +def mno_check_zero_division : Flag<["-"], "mno-check-zero-division">, + Group<m_Group>; +def mdsp : Flag<["-"], "mdsp">, Group<m_Group>; +def mno_dsp : Flag<["-"], "mno-dsp">, Group<m_Group>; +def mdspr2 : Flag<["-"], "mdspr2">, Group<m_Group>; +def mno_dspr2 : Flag<["-"], "mno-dspr2">, Group<m_Group>; +def msingle_float : Flag<["-"], "msingle-float">, Group<m_Group>; +def mdouble_float : Flag<["-"], "mdouble-float">, Group<m_Group>; +def mmsa : Flag<["-"], "mmsa">, Group<m_Group>, + HelpText<"Enable MSA ASE (MIPS only)">; +def mno_msa : Flag<["-"], "mno-msa">, Group<m_Group>, + HelpText<"Disable MSA ASE (MIPS only)">; +def mfp64 : Flag<["-"], "mfp64">, Group<m_Group>, + HelpText<"Use 64-bit floating point registers (MIPS only)">; +def mfp32 : Flag<["-"], "mfp32">, Group<m_Group>, + HelpText<"Use 32-bit floating point registers (MIPS only)">; +def mnan_EQ : Joined<["-"], "mnan=">, Group<m_Group>; +def mabicalls : Flag<["-"], "mabicalls">, Group<m_Group>, + HelpText<"Enable SVR4-style position-independent code (Mips only)">; +def mno_abicalls : Flag<["-"], "mno-abicalls">, Group<m_Group>, + HelpText<"Disable SVR4-style position-independent code (Mips only)">; +def mips1 : Flag<["-"], "mips1">, + Alias<march_EQ>, AliasArgs<["mips1"]>, + HelpText<"Equivalent to -march=mips1">, Flags<[HelpHidden]>; +def mips2 : Flag<["-"], "mips2">, + Alias<march_EQ>, AliasArgs<["mips2"]>, + HelpText<"Equivalent to -march=mips2">, Flags<[HelpHidden]>; +def mips3 : Flag<["-"], "mips3">, + Alias<march_EQ>, AliasArgs<["mips3"]>, + HelpText<"Equivalent to -march=mips3">, Flags<[HelpHidden]>; +def mips4 : Flag<["-"], "mips4">, + Alias<march_EQ>, AliasArgs<["mips4"]>, + HelpText<"Equivalent to -march=mips4">, Flags<[HelpHidden]>; +def mips5 : Flag<["-"], "mips5">, + Alias<march_EQ>, AliasArgs<["mips5"]>, + HelpText<"Equivalent to -march=mips5">, Flags<[HelpHidden]>; +def mips32 : Flag<["-"], "mips32">, + Alias<march_EQ>, AliasArgs<["mips32"]>, + HelpText<"Equivalent to -march=mips32">, Flags<[HelpHidden]>; +def mips32r2 : Flag<["-"], "mips32r2">, + Alias<march_EQ>, AliasArgs<["mips32r2"]>, + HelpText<"Equivalent to -march=mips32r2">, Flags<[HelpHidden]>; +def mips32r3 : Flag<["-"], "mips32r3">, + Alias<march_EQ>, AliasArgs<["mips32r3"]>, + HelpText<"Equivalent to -march=mips32r3">, Flags<[HelpHidden]>; +def mips32r5 : Flag<["-"], "mips32r5">, + Alias<march_EQ>, AliasArgs<["mips32r5"]>, + HelpText<"Equivalent to -march=mips32r5">, Flags<[HelpHidden]>; +def mips32r6 : Flag<["-"], "mips32r6">, + Alias<march_EQ>, AliasArgs<["mips32r6"]>, + HelpText<"Equivalent to -march=mips32r6">, Flags<[HelpHidden]>; +def mips64 : Flag<["-"], "mips64">, + Alias<march_EQ>, AliasArgs<["mips64"]>, + HelpText<"Equivalent to -march=mips64">, Flags<[HelpHidden]>; +def mips64r2 : Flag<["-"], "mips64r2">, + Alias<march_EQ>, AliasArgs<["mips64r2"]>, + HelpText<"Equivalent to -march=mips64r2">, Flags<[HelpHidden]>; +def mips64r3 : Flag<["-"], "mips64r3">, + Alias<march_EQ>, AliasArgs<["mips64r3"]>, + HelpText<"Equivalent to -march=mips64r3">, Flags<[HelpHidden]>; +def mips64r5 : Flag<["-"], "mips64r5">, + Alias<march_EQ>, AliasArgs<["mips64r5"]>, + HelpText<"Equivalent to -march=mips64r5">, Flags<[HelpHidden]>; +def mips64r6 : Flag<["-"], "mips64r6">, + Alias<march_EQ>, AliasArgs<["mips64r6"]>, + HelpText<"Equivalent to -march=mips64r6">, Flags<[HelpHidden]>; +def mfpxx : Flag<["-"], "mfpxx">, Group<m_Group>, + HelpText<"Avoid FPU mode dependent operations when used with the O32 ABI">, + Flags<[HelpHidden]>; +def modd_spreg : Flag<["-"], "modd-spreg">, Group<m_Group>, + HelpText<"Enable odd single-precision floating point registers">, + Flags<[HelpHidden]>; +def mno_odd_spreg : Flag<["-"], "mno-odd-spreg">, Group<m_Group>, + HelpText<"Disable odd single-precision floating point registers">, + Flags<[HelpHidden]>; +def mglibc : Flag<["-"], "mglibc">, Group<m_libc_Group>, Flags<[HelpHidden]>; +def muclibc : Flag<["-"], "muclibc">, Group<m_libc_Group>, Flags<[HelpHidden]>; +def module_file_info : Flag<["-"], "module-file-info">, Flags<[DriverOption,CC1Option]>, Group<Action_Group>; +def mthumb : Flag<["-"], "mthumb">, Group<m_Group>; +def mtune_EQ : Joined<["-"], "mtune=">, Group<m_Group>; +def multi__module : Flag<["-"], "multi_module">; +def multiply__defined__unused : Separate<["-"], "multiply_defined_unused">; +def multiply__defined : Separate<["-"], "multiply_defined">; +def mwarn_nonportable_cfstrings : Flag<["-"], "mwarn-nonportable-cfstrings">, Group<m_Group>; +def no_canonical_prefixes : Flag<["-"], "no-canonical-prefixes">, Flags<[HelpHidden]>, + HelpText<"Use relative instead of canonical paths">; +def no_cpp_precomp : Flag<["-"], "no-cpp-precomp">, Group<clang_ignored_f_Group>; +def no_integrated_cpp : Flag<["-", "--"], "no-integrated-cpp">, Flags<[DriverOption]>; +def no_pedantic : Flag<["-", "--"], "no-pedantic">, Group<pedantic_Group>; +def no__dead__strip__inits__and__terms : Flag<["-"], "no_dead_strip_inits_and_terms">; +def nobuiltininc : Flag<["-"], "nobuiltininc">, Flags<[CC1Option]>, + HelpText<"Disable builtin #include directories">; +def nocudainc : Flag<["-"], "nocudainc">; +def nocudalib : Flag<["-"], "nocudalib">; +def nodefaultlibs : Flag<["-"], "nodefaultlibs">; +def nofixprebinding : Flag<["-"], "nofixprebinding">; +def nolibc : Flag<["-"], "nolibc">; +def nomultidefs : Flag<["-"], "nomultidefs">; +def nopie : Flag<["-"], "nopie">; +def noprebind : Flag<["-"], "noprebind">; +def noseglinkedit : Flag<["-"], "noseglinkedit">; +def nostartfiles : Flag<["-"], "nostartfiles">; +def nostdinc : Flag<["-"], "nostdinc">; +def nostdlibinc : Flag<["-"], "nostdlibinc">; +def nostdincxx : Flag<["-"], "nostdinc++">, Flags<[CC1Option]>, + HelpText<"Disable standard #include directories for the C++ standard library">; +def nostdlib : Flag<["-"], "nostdlib">; +def object : Flag<["-"], "object">; +def o : JoinedOrSeparate<["-"], "o">, Flags<[DriverOption, RenderAsInput, CC1Option, CC1AsOption]>, + HelpText<"Write output to <file>">, MetaVarName<"<file>">; +def omptargets_EQ : CommaJoined<["-"], "omptargets=">, Flags<[DriverOption, CC1Option]>, + HelpText<"Specify comma-separated list of triples OpenMP offloading targets to be supported">; +def pagezero__size : JoinedOrSeparate<["-"], "pagezero_size">; +def pass_exit_codes : Flag<["-", "--"], "pass-exit-codes">, Flags<[Unsupported]>; +def pedantic_errors : Flag<["-", "--"], "pedantic-errors">, Group<pedantic_Group>, Flags<[CC1Option]>; +def pedantic : Flag<["-", "--"], "pedantic">, Group<pedantic_Group>, Flags<[CC1Option]>; +def pg : Flag<["-"], "pg">, HelpText<"Enable mcount instrumentation">, Flags<[CC1Option]>; +def pipe : Flag<["-", "--"], "pipe">, + HelpText<"Use pipes between commands, when possible">; +def prebind__all__twolevel__modules : Flag<["-"], "prebind_all_twolevel_modules">; +def prebind : Flag<["-"], "prebind">; +def preload : Flag<["-"], "preload">; +def print_file_name_EQ : Joined<["-", "--"], "print-file-name=">, + HelpText<"Print the full library path of <file>">, MetaVarName<"<file>">; +def print_ivar_layout : Flag<["-"], "print-ivar-layout">, Flags<[CC1Option]>, + HelpText<"Enable Objective-C Ivar layout bitmap print trace">; +def print_libgcc_file_name : Flag<["-", "--"], "print-libgcc-file-name">, + HelpText<"Print the library path for \"libgcc.a\"">; +def print_multi_directory : Flag<["-", "--"], "print-multi-directory">; +def print_multi_lib : Flag<["-", "--"], "print-multi-lib">; +def print_multi_os_directory : Flag<["-", "--"], "print-multi-os-directory">, + Flags<[Unsupported]>; +def print_prog_name_EQ : Joined<["-", "--"], "print-prog-name=">, + HelpText<"Print the full program path of <name>">, MetaVarName<"<name>">; +def print_search_dirs : Flag<["-", "--"], "print-search-dirs">, + HelpText<"Print the paths used for finding libraries and programs">; +def private__bundle : Flag<["-"], "private_bundle">; +def pthreads : Flag<["-"], "pthreads">; +def pthread : Flag<["-"], "pthread">, Flags<[CC1Option]>, + HelpText<"Support POSIX threads in generated code">; +def no_pthread : Flag<["-"], "no-pthread">, Flags<[CC1Option]>; +def p : Flag<["-"], "p">; +def pie : Flag<["-"], "pie">; +def read__only__relocs : Separate<["-"], "read_only_relocs">; +def remap : Flag<["-"], "remap">; +def rewrite_objc : Flag<["-"], "rewrite-objc">, Flags<[DriverOption,CC1Option]>, + HelpText<"Rewrite Objective-C source to C++">, Group<Action_Group>; +def rewrite_legacy_objc : Flag<["-"], "rewrite-legacy-objc">, Flags<[DriverOption]>, + HelpText<"Rewrite Legacy Objective-C source to C++">; +def rdynamic : Flag<["-"], "rdynamic">; +def resource_dir : Separate<["-"], "resource-dir">, + Flags<[DriverOption, CC1Option, HelpHidden]>, + HelpText<"The directory which holds the compiler resource files">; +def resource_dir_EQ : Joined<["-"], "resource-dir=">, Flags<[DriverOption]>, + Alias<resource_dir>; +def rpath : Separate<["-"], "rpath">, Flags<[LinkerInput]>; +def rtlib_EQ : Joined<["-", "--"], "rtlib=">; +def r : Flag<["-"], "r">, Flags<[LinkerInput,NoArgumentUnused]>; +def save_temps_EQ : Joined<["-", "--"], "save-temps=">, Flags<[DriverOption]>, + HelpText<"Save intermediate compilation results.">; +def save_temps : Flag<["-", "--"], "save-temps">, Flags<[DriverOption]>, + Alias<save_temps_EQ>, AliasArgs<["cwd"]>, + HelpText<"Save intermediate compilation results">; +def via_file_asm : Flag<["-", "--"], "via-file-asm">, InternalDebugOpt, + HelpText<"Write assembly to file for input to assemble jobs">; +def sectalign : MultiArg<["-"], "sectalign", 3>; +def sectcreate : MultiArg<["-"], "sectcreate", 3>; +def sectobjectsymbols : MultiArg<["-"], "sectobjectsymbols", 2>; +def sectorder : MultiArg<["-"], "sectorder", 3>; +def seg1addr : JoinedOrSeparate<["-"], "seg1addr">; +def seg__addr__table__filename : Separate<["-"], "seg_addr_table_filename">; +def seg__addr__table : Separate<["-"], "seg_addr_table">; +def segaddr : MultiArg<["-"], "segaddr", 2>; +def segcreate : MultiArg<["-"], "segcreate", 3>; +def seglinkedit : Flag<["-"], "seglinkedit">; +def segprot : MultiArg<["-"], "segprot", 3>; +def segs__read__only__addr : Separate<["-"], "segs_read_only_addr">; +def segs__read__write__addr : Separate<["-"], "segs_read_write_addr">; +def segs__read__ : Joined<["-"], "segs_read_">; +def shared_libgcc : Flag<["-"], "shared-libgcc">; +def shared : Flag<["-", "--"], "shared">; +def single__module : Flag<["-"], "single_module">; +def specs_EQ : Joined<["-", "--"], "specs=">; +def specs : Separate<["-", "--"], "specs">, Flags<[Unsupported]>; +def static_libgcc : Flag<["-"], "static-libgcc">; +def static_libstdcxx : Flag<["-"], "static-libstdc++">; +def static : Flag<["-", "--"], "static">, Flags<[NoArgumentUnused]>; +def std_default_EQ : Joined<["-"], "std-default=">; +def std_EQ : Joined<["-", "--"], "std=">, Flags<[CC1Option]>, + Group<CompileOnly_Group>, HelpText<"Language standard to compile for">; +def stdlib_EQ : Joined<["-", "--"], "stdlib=">, Flags<[CC1Option]>, + HelpText<"C++ standard library to use">; +def sub__library : JoinedOrSeparate<["-"], "sub_library">; +def sub__umbrella : JoinedOrSeparate<["-"], "sub_umbrella">; +def system_header_prefix : Joined<["--"], "system-header-prefix=">, + Group<clang_i_Group>, Flags<[CC1Option]>, MetaVarName<"<prefix>">, + HelpText<"Treat all #include paths starting with <prefix> as including a " + "system header.">; +def : Separate<["--"], "system-header-prefix">, Alias<system_header_prefix>; +def no_system_header_prefix : Joined<["--"], "no-system-header-prefix=">, + Group<clang_i_Group>, Flags<[CC1Option]>, MetaVarName<"<prefix>">, + HelpText<"Treat all #include paths starting with <prefix> as not including a " + "system header.">; +def : Separate<["--"], "no-system-header-prefix">, Alias<no_system_header_prefix>; +def s : Flag<["-"], "s">; +def target : Joined<["--"], "target=">, Flags<[DriverOption, CoreOption]>, + HelpText<"Generate code for the given target">; +def gcc_toolchain : Joined<["--"], "gcc-toolchain=">, Flags<[DriverOption]>, + HelpText<"Use the gcc toolchain at the given directory">; +def time : Flag<["-"], "time">, + HelpText<"Time individual commands">; +def traditional_cpp : Flag<["-", "--"], "traditional-cpp">, Flags<[CC1Option]>, + HelpText<"Enable some traditional CPP emulation">; +def traditional : Flag<["-", "--"], "traditional">; +def trigraphs : Flag<["-", "--"], "trigraphs">, Alias<ftrigraphs>, + HelpText<"Process trigraph sequences">; +def twolevel__namespace__hints : Flag<["-"], "twolevel_namespace_hints">; +def twolevel__namespace : Flag<["-"], "twolevel_namespace">; +def t : Flag<["-"], "t">; +def umbrella : Separate<["-"], "umbrella">; +def undefined : JoinedOrSeparate<["-"], "undefined">, Group<u_Group>; +def undef : Flag<["-"], "undef">, Group<u_Group>, Flags<[CC1Option]>, + HelpText<"undef all system defines">; +def unexported__symbols__list : Separate<["-"], "unexported_symbols_list">; +def u : JoinedOrSeparate<["-"], "u">, Group<u_Group>; +def v : Flag<["-"], "v">, Flags<[CC1Option, CoreOption]>, + HelpText<"Show commands to run and use verbose output">; +def verify_debug_info : Flag<["--"], "verify-debug-info">, Flags<[DriverOption]>, + HelpText<"Verify the binary representation of debug output">; +def weak_l : Joined<["-"], "weak-l">, Flags<[LinkerInput]>; +def weak__framework : Separate<["-"], "weak_framework">, Flags<[LinkerInput]>; +def weak__library : Separate<["-"], "weak_library">, Flags<[LinkerInput]>; +def weak__reference__mismatches : Separate<["-"], "weak_reference_mismatches">; +def whatsloaded : Flag<["-"], "whatsloaded">; +def whyload : Flag<["-"], "whyload">; +def w : Flag<["-"], "w">, HelpText<"Suppress all warnings">, Flags<[CC1Option]>; +def x : JoinedOrSeparate<["-"], "x">, Flags<[DriverOption,CC1Option]>, + HelpText<"Treat subsequent input files as having type <language>">, + MetaVarName<"<language>">; +def y : Joined<["-"], "y">; + +def fintegrated_as : Flag<["-"], "fintegrated-as">, Flags<[DriverOption]>, + Group<f_Group>, HelpText<"Enable the integrated assembler">; +def fno_integrated_as : Flag<["-"], "fno-integrated-as">, + Flags<[CC1Option, DriverOption]>, Group<f_Group>, + HelpText<"Disable the integrated assembler">; +def : Flag<["-"], "integrated-as">, Alias<fintegrated_as>, Flags<[DriverOption]>; +def : Flag<["-"], "no-integrated-as">, Alias<fno_integrated_as>, + Flags<[CC1Option, DriverOption]>; + +def working_directory : JoinedOrSeparate<["-"], "working-directory">, Flags<[CC1Option]>, + HelpText<"Resolve file paths relative to the specified directory">; +def working_directory_EQ : Joined<["-"], "working-directory=">, Flags<[CC1Option]>, + Alias<working_directory>; + +// Double dash options, which are usually an alias for one of the previous +// options. + +def _mhwdiv_EQ : Joined<["--"], "mhwdiv=">, Alias<mhwdiv_EQ>; +def _mhwdiv : Separate<["--"], "mhwdiv">, Alias<mhwdiv_EQ>; +def _CLASSPATH_EQ : Joined<["--"], "CLASSPATH=">, Alias<fclasspath_EQ>; +def _CLASSPATH : Separate<["--"], "CLASSPATH">, Alias<fclasspath_EQ>; +def _all_warnings : Flag<["--"], "all-warnings">, Alias<Wall>; +def _analyze_auto : Flag<["--"], "analyze-auto">, Flags<[DriverOption]>; +def _analyzer_no_default_checks : Flag<["--"], "analyzer-no-default-checks">, Flags<[DriverOption]>; +def _analyzer_output : JoinedOrSeparate<["--"], "analyzer-output">, Flags<[DriverOption]>; +def _analyze : Flag<["--"], "analyze">, Flags<[DriverOption, CoreOption]>, + HelpText<"Run the static analyzer">; +def _assemble : Flag<["--"], "assemble">, Alias<S>; +def _assert_EQ : Joined<["--"], "assert=">, Alias<A>; +def _assert : Separate<["--"], "assert">, Alias<A>; +def _bootclasspath_EQ : Joined<["--"], "bootclasspath=">, Alias<fbootclasspath_EQ>; +def _bootclasspath : Separate<["--"], "bootclasspath">, Alias<fbootclasspath_EQ>; +def _classpath_EQ : Joined<["--"], "classpath=">, Alias<fclasspath_EQ>; +def _classpath : Separate<["--"], "classpath">, Alias<fclasspath_EQ>; +def _comments_in_macros : Flag<["--"], "comments-in-macros">, Alias<CC>; +def _comments : Flag<["--"], "comments">, Alias<C>; +def _compile : Flag<["--"], "compile">, Alias<c>; +def _constant_cfstrings : Flag<["--"], "constant-cfstrings">; +def _debug_EQ : Joined<["--"], "debug=">, Alias<g_Flag>; +def _debug : Flag<["--"], "debug">, Alias<g_Flag>; +def _define_macro_EQ : Joined<["--"], "define-macro=">, Alias<D>; +def _define_macro : Separate<["--"], "define-macro">, Alias<D>; +def _dependencies : Flag<["--"], "dependencies">, Alias<M>; +def _dyld_prefix_EQ : Joined<["--"], "dyld-prefix=">; +def _dyld_prefix : Separate<["--"], "dyld-prefix">, Alias<_dyld_prefix_EQ>; +def _encoding_EQ : Joined<["--"], "encoding=">, Alias<fencoding_EQ>; +def _encoding : Separate<["--"], "encoding">, Alias<fencoding_EQ>; +def _entry : Flag<["--"], "entry">, Alias<e>; +def _extdirs_EQ : Joined<["--"], "extdirs=">, Alias<fextdirs_EQ>; +def _extdirs : Separate<["--"], "extdirs">, Alias<fextdirs_EQ>; +def _extra_warnings : Flag<["--"], "extra-warnings">, Alias<W_Joined>; +def _for_linker_EQ : Joined<["--"], "for-linker=">, Alias<Xlinker>; +def _for_linker : Separate<["--"], "for-linker">, Alias<Xlinker>; +def _force_link_EQ : Joined<["--"], "force-link=">, Alias<u>; +def _force_link : Separate<["--"], "force-link">, Alias<u>; +def _help_hidden : Flag<["--"], "help-hidden">; +def _imacros_EQ : Joined<["--"], "imacros=">, Alias<imacros>; +def _include_barrier : Flag<["--"], "include-barrier">, Alias<I_>; +def _include_directory_after_EQ : Joined<["--"], "include-directory-after=">, Alias<idirafter>; +def _include_directory_after : Separate<["--"], "include-directory-after">, Alias<idirafter>; +def _include_directory_EQ : Joined<["--"], "include-directory=">, Alias<I>; +def _include_directory : Separate<["--"], "include-directory">, Alias<I>; +def _include_prefix_EQ : Joined<["--"], "include-prefix=">, Alias<iprefix>; +def _include_prefix : Separate<["--"], "include-prefix">, Alias<iprefix>; +def _include_with_prefix_after_EQ : Joined<["--"], "include-with-prefix-after=">, Alias<iwithprefix>; +def _include_with_prefix_after : Separate<["--"], "include-with-prefix-after">, Alias<iwithprefix>; +def _include_with_prefix_before_EQ : Joined<["--"], "include-with-prefix-before=">, Alias<iwithprefixbefore>; +def _include_with_prefix_before : Separate<["--"], "include-with-prefix-before">, Alias<iwithprefixbefore>; +def _include_with_prefix_EQ : Joined<["--"], "include-with-prefix=">, Alias<iwithprefix>; +def _include_with_prefix : Separate<["--"], "include-with-prefix">, Alias<iwithprefix>; +def _include_EQ : Joined<["--"], "include=">, Alias<include_>; +def _language_EQ : Joined<["--"], "language=">, Alias<x>; +def _language : Separate<["--"], "language">, Alias<x>; +def _library_directory_EQ : Joined<["--"], "library-directory=">, Alias<L>; +def _library_directory : Separate<["--"], "library-directory">, Alias<L>; +def _no_line_commands : Flag<["--"], "no-line-commands">, Alias<P>; +def _no_standard_includes : Flag<["--"], "no-standard-includes">, Alias<nostdinc>; +def _no_standard_libraries : Flag<["--"], "no-standard-libraries">, Alias<nostdlib>; +def _no_undefined : Flag<["--"], "no-undefined">, Flags<[LinkerInput]>; +def _no_warnings : Flag<["--"], "no-warnings">, Alias<w>; +def _optimize_EQ : Joined<["--"], "optimize=">, Alias<O>; +def _optimize : Flag<["--"], "optimize">, Alias<O>; +def _output_class_directory_EQ : Joined<["--"], "output-class-directory=">, Alias<foutput_class_dir_EQ>; +def _output_class_directory : Separate<["--"], "output-class-directory">, Alias<foutput_class_dir_EQ>; +def _output_EQ : Joined<["--"], "output=">, Alias<o>; +def _output : Separate<["--"], "output">, Alias<o>; +def _param : Separate<["--"], "param">, Group<CompileOnly_Group>; +def _param_EQ : Joined<["--"], "param=">, Alias<_param>; +def _prefix_EQ : Joined<["--"], "prefix=">, Alias<B>; +def _prefix : Separate<["--"], "prefix">, Alias<B>; +def _preprocess : Flag<["--"], "preprocess">, Alias<E>; +def _print_diagnostic_categories : Flag<["--"], "print-diagnostic-categories">; +def _print_file_name : Separate<["--"], "print-file-name">, Alias<print_file_name_EQ>; +def _print_missing_file_dependencies : Flag<["--"], "print-missing-file-dependencies">, Alias<MG>; +def _print_prog_name : Separate<["--"], "print-prog-name">, Alias<print_prog_name_EQ>; +def _profile_blocks : Flag<["--"], "profile-blocks">, Alias<a>; +def _profile : Flag<["--"], "profile">, Alias<p>; +def _resource_EQ : Joined<["--"], "resource=">, Alias<fcompile_resource_EQ>; +def _resource : Separate<["--"], "resource">, Alias<fcompile_resource_EQ>; +def _rtlib : Separate<["--"], "rtlib">, Alias<rtlib_EQ>; +def _serialize_diags : Separate<["-", "--"], "serialize-diagnostics">, Flags<[DriverOption]>, + HelpText<"Serialize compiler diagnostics to a file">; +// We give --version different semantics from -version. +def _version : Flag<["--"], "version">, Flags<[CC1Option]>; +def _signed_char : Flag<["--"], "signed-char">, Alias<fsigned_char>; +def _std : Separate<["--"], "std">, Alias<std_EQ>; +def _stdlib : Separate<["--"], "stdlib">, Alias<stdlib_EQ>; +def _sysroot_EQ : Joined<["--"], "sysroot=">; +def _sysroot : Separate<["--"], "sysroot">, Alias<_sysroot_EQ>; +def _target_help : Flag<["--"], "target-help">; +def _trace_includes : Flag<["--"], "trace-includes">, Alias<H>; +def _undefine_macro_EQ : Joined<["--"], "undefine-macro=">, Alias<U>; +def _undefine_macro : Separate<["--"], "undefine-macro">, Alias<U>; +def _unsigned_char : Flag<["--"], "unsigned-char">, Alias<funsigned_char>; +def _user_dependencies : Flag<["--"], "user-dependencies">, Alias<MM>; +def _verbose : Flag<["--"], "verbose">, Alias<v>; +def _warn__EQ : Joined<["--"], "warn-=">, Alias<W_Joined>; +def _warn_ : Joined<["--"], "warn-">, Alias<W_Joined>; +def _write_dependencies : Flag<["--"], "write-dependencies">, Alias<MD>; +def _write_user_dependencies : Flag<["--"], "write-user-dependencies">, Alias<MMD>; +def _ : Joined<["--"], "">, Flags<[Unsupported]>; + +def mieee_rnd_near : Flag<["-"], "mieee-rnd-near">, Group<m_hexagon_Features_Group>; +def mv4 : Flag<["-"], "mv4">, Group<m_hexagon_Features_Group>, + Alias<mcpu_EQ>, AliasArgs<["v4"]>; +def mv5 : Flag<["-"], "mv5">, Group<m_hexagon_Features_Group>, Alias<mcpu_EQ>, + AliasArgs<["v5"]>; +def mv55 : Flag<["-"], "mv55">, Group<m_hexagon_Features_Group>, + Alias<mcpu_EQ>, AliasArgs<["v55"]>; +def mv60 : Flag<["-"], "mv60">, Group<m_hexagon_Features_Group>, + Alias<mcpu_EQ>, AliasArgs<["v60"]>; +def mhexagon_hvx : Flag<["-"], "mhvx">, Group<m_hexagon_Features_Group>, + Flags<[CC1Option]>, HelpText<"Enable Hexagon Vector eXtensions">; +def mno_hexagon_hvx : Flag<["-"], "mno-hvx">, Group<m_hexagon_Features_Group>, + Flags<[CC1Option]>, HelpText<"Disable Hexagon Vector eXtensions">; +def mhexagon_hvx_double : Flag<["-"], "mhvx-double">, Group<m_hexagon_Features_Group>, + Flags<[CC1Option]>, HelpText<"Enable Hexagon Double Vector eXtensions">; +def mno_hexagon_hvx_double : Flag<["-"], "mno-hvx-double">, Group<m_hexagon_Features_Group>, + Flags<[CC1Option]>, HelpText<"Disable Hexagon Double Vector eXtensions">; + +// These are legacy user-facing driver-level option spellings. They are always +// aliases for options that are spelled using the more common Unix / GNU flag +// style of double-dash and equals-joined flags. +def gcc_toolchain_legacy_spelling : Separate<["-"], "gcc-toolchain">, Alias<gcc_toolchain>; +def target_legacy_spelling : Separate<["-"], "target">, Alias<target>; + +// Special internal option to handle -Xlinker --no-demangle. +def Z_Xlinker__no_demangle : Flag<["-"], "Z-Xlinker-no-demangle">, + Flags<[Unsupported, NoArgumentUnused]>; + +// Special internal option to allow forwarding arbitrary arguments to linker. +def Zlinker_input : Separate<["-"], "Zlinker-input">, + Flags<[Unsupported, NoArgumentUnused]>; + +// Reserved library options. +def Z_reserved_lib_stdcxx : Flag<["-"], "Z-reserved-lib-stdc++">, + Flags<[LinkerInput, NoArgumentUnused, Unsupported]>, Group<reserved_lib_Group>; +def Z_reserved_lib_cckext : Flag<["-"], "Z-reserved-lib-cckext">, + Flags<[LinkerInput, NoArgumentUnused, Unsupported]>, Group<reserved_lib_Group>; + +// Ignored options +// FIXME: multiclasess produce suffixes, not prefixes. This is fine for now +// since it is only used in ignored options. +multiclass BooleanFFlag<string name> { + def _f : Flag<["-"], "f"#name>; + def _fno : Flag<["-"], "fno-"#name>; +} + +defm : BooleanFFlag<"keep-inline-functions">, Group<clang_ignored_gcc_optimization_f_Group>; + +def fprofile_dir : Joined<["-"], "fprofile-dir=">, Group<clang_ignored_gcc_optimization_f_Group>; + +def fuse_ld_EQ : Joined<["-"], "fuse-ld=">, Group<f_Group>; + +defm align_functions : BooleanFFlag<"align-functions">, Group<clang_ignored_gcc_optimization_f_Group>; +def falign_functions_EQ : Joined<["-"], "falign-functions=">, Group<clang_ignored_gcc_optimization_f_Group>; +defm align_labels : BooleanFFlag<"align-labels">, Group<clang_ignored_gcc_optimization_f_Group>; +def falign_labels_EQ : Joined<["-"], "falign-labels=">, Group<clang_ignored_gcc_optimization_f_Group>; +defm align_loops : BooleanFFlag<"align-loops">, Group<clang_ignored_gcc_optimization_f_Group>; +def falign_loops_EQ : Joined<["-"], "falign-loops=">, Group<clang_ignored_gcc_optimization_f_Group>; +defm align_jumps : BooleanFFlag<"align-jumps">, Group<clang_ignored_gcc_optimization_f_Group>; +def falign_jumps_EQ : Joined<["-"], "falign-jumps=">, Group<clang_ignored_gcc_optimization_f_Group>; + +// FIXME: This option should be supported and wired up to our diognostics, but +// ignore it for now to avoid breaking builds that use it. +def fdiagnostics_show_location_EQ : Joined<["-"], "fdiagnostics-show-location=">, Group<clang_ignored_f_Group>; + +defm fcheck_new : BooleanFFlag<"check-new">, Group<clang_ignored_f_Group>; +defm caller_saves : BooleanFFlag<"caller-saves">, Group<clang_ignored_gcc_optimization_f_Group>; +defm reorder_blocks : BooleanFFlag<"reorder-blocks">, Group<clang_ignored_gcc_optimization_f_Group>; +defm eliminate_unused_debug_types : BooleanFFlag<"eliminate-unused-debug-types">, Group<clang_ignored_f_Group>; +defm branch_count_reg : BooleanFFlag<"branch-count-reg">, Group<clang_ignored_gcc_optimization_f_Group>; +defm default_inline : BooleanFFlag<"default-inline">, Group<clang_ignored_gcc_optimization_f_Group>; +defm delete_null_pointer_checks : BooleanFFlag<"delete-null-pointer-checks">, + Group<clang_ignored_gcc_optimization_f_Group>; +defm fat_lto_objects : BooleanFFlag<"fat-lto-objects">, Group<clang_ignored_gcc_optimization_f_Group>; +defm float_store : BooleanFFlag<"float-store">, Group<clang_ignored_gcc_optimization_f_Group>; +defm friend_injection : BooleanFFlag<"friend-injection">, Group<clang_ignored_f_Group>; +defm function_attribute_list : BooleanFFlag<"function-attribute-list">, Group<clang_ignored_f_Group>; +defm gcse : BooleanFFlag<"gcse">, Group<clang_ignored_gcc_optimization_f_Group>; +defm gcse_after_reload: BooleanFFlag<"gcse-after-reload">, Group<clang_ignored_gcc_optimization_f_Group>; +defm gcse_las: BooleanFFlag<"gcse-las">, Group<clang_ignored_gcc_optimization_f_Group>; +defm gcse_sm: BooleanFFlag<"gcse-sm">, Group<clang_ignored_gcc_optimization_f_Group>; +defm gnu : BooleanFFlag<"gnu">, Group<clang_ignored_f_Group>; +defm ident : BooleanFFlag<"ident">, Group<clang_ignored_f_Group>; +defm implicit_templates : BooleanFFlag<"implicit-templates">, Group<clang_ignored_f_Group>; +defm implement_inlines : BooleanFFlag<"implement-inlines">, Group<clang_ignored_f_Group>; +defm merge_constants : BooleanFFlag<"merge-constants">, Group<clang_ignored_gcc_optimization_f_Group>; +defm modulo_sched : BooleanFFlag<"modulo-sched">, Group<clang_ignored_gcc_optimization_f_Group>; +defm modulo_sched_allow_regmoves : BooleanFFlag<"modulo-sched-allow-regmoves">, + Group<clang_ignored_gcc_optimization_f_Group>; +defm inline_functions_called_once : BooleanFFlag<"inline-functions-called-once">, + Group<clang_ignored_gcc_optimization_f_Group>; +def finline_limit_EQ : Joined<["-"], "finline-limit=">, Group<clang_ignored_gcc_optimization_f_Group>; +defm finline_limit : BooleanFFlag<"inline-limit">, Group<clang_ignored_gcc_optimization_f_Group>; +defm inline_small_functions : BooleanFFlag<"inline-small-functions">, + Group<clang_ignored_gcc_optimization_f_Group>; +defm ipa_cp : BooleanFFlag<"ipa-cp">, + Group<clang_ignored_gcc_optimization_f_Group>; +defm ivopts : BooleanFFlag<"ivopts">, Group<clang_ignored_gcc_optimization_f_Group>; +defm non_call_exceptions : BooleanFFlag<"non-call-exceptions">, Group<clang_ignored_f_Group>; +defm peel_loops : BooleanFFlag<"peel-loops">, Group<clang_ignored_gcc_optimization_f_Group>; +defm permissive : BooleanFFlag<"permissive">, Group<clang_ignored_f_Group>; +defm prefetch_loop_arrays : BooleanFFlag<"prefetch-loop-arrays">, Group<clang_ignored_gcc_optimization_f_Group>; +defm printf : BooleanFFlag<"printf">, Group<clang_ignored_f_Group>; +defm profile : BooleanFFlag<"profile">, Group<clang_ignored_f_Group>; +defm profile_correction : BooleanFFlag<"profile-correction">, Group<clang_ignored_gcc_optimization_f_Group>; +defm profile_generate_sampling : BooleanFFlag<"profile-generate-sampling">, Group<clang_ignored_f_Group>; +defm profile_reusedist : BooleanFFlag<"profile-reusedist">, Group<clang_ignored_f_Group>; +defm profile_values : BooleanFFlag<"profile-values">, Group<clang_ignored_gcc_optimization_f_Group>; +defm regs_graph : BooleanFFlag<"regs-graph">, Group<clang_ignored_f_Group>; +defm rename_registers : BooleanFFlag<"rename-registers">, Group<clang_ignored_gcc_optimization_f_Group>; +defm ripa : BooleanFFlag<"ripa">, Group<clang_ignored_f_Group>; +defm rounding_math : BooleanFFlag<"rounding-math">, Group<clang_ignored_gcc_optimization_f_Group>; +defm schedule_insns : BooleanFFlag<"schedule-insns">, Group<clang_ignored_gcc_optimization_f_Group>; +defm schedule_insns2 : BooleanFFlag<"schedule-insns2">, Group<clang_ignored_gcc_optimization_f_Group>; +defm see : BooleanFFlag<"see">, Group<clang_ignored_f_Group>; +defm signaling_nans : BooleanFFlag<"signaling-nans">, Group<clang_ignored_gcc_optimization_f_Group>; +defm single_precision_constant : BooleanFFlag<"single-precision-constant">, + Group<clang_ignored_gcc_optimization_f_Group>; +defm spec_constr_count : BooleanFFlag<"spec-constr-count">, Group<clang_ignored_f_Group>; +defm stack_check : BooleanFFlag<"stack-check">, Group<clang_ignored_f_Group>; +defm strength_reduce : + BooleanFFlag<"strength-reduce">, Group<clang_ignored_gcc_optimization_f_Group>; +defm tls_model : BooleanFFlag<"tls-model">, Group<clang_ignored_f_Group>; +defm tracer : BooleanFFlag<"tracer">, Group<clang_ignored_gcc_optimization_f_Group>; +defm tree_dce : BooleanFFlag<"tree-dce">, Group<clang_ignored_gcc_optimization_f_Group>; +defm tree_loop_im : BooleanFFlag<"tree_loop_im">, Group<clang_ignored_gcc_optimization_f_Group>; +defm tree_loop_ivcanon : BooleanFFlag<"tree_loop_ivcanon">, Group<clang_ignored_gcc_optimization_f_Group>; +defm tree_loop_linear : BooleanFFlag<"tree_loop_linear">, Group<clang_ignored_gcc_optimization_f_Group>; +defm tree_salias : BooleanFFlag<"tree-salias">, Group<clang_ignored_f_Group>; +defm tree_ter : BooleanFFlag<"tree-ter">, Group<clang_ignored_gcc_optimization_f_Group>; +defm tree_vectorizer_verbose : BooleanFFlag<"tree-vectorizer-verbose">, Group<clang_ignored_f_Group>; +defm tree_vrp : BooleanFFlag<"tree-vrp">, Group<clang_ignored_gcc_optimization_f_Group>; +defm unroll_all_loops : BooleanFFlag<"unroll-all-loops">, Group<clang_ignored_gcc_optimization_f_Group>; +defm unsafe_loop_optimizations : BooleanFFlag<"unsafe-loop-optimizations">, + Group<clang_ignored_gcc_optimization_f_Group>; +defm unswitch_loops : BooleanFFlag<"unswitch-loops">, Group<clang_ignored_gcc_optimization_f_Group>; +defm use_linker_plugin : BooleanFFlag<"use-linker-plugin">, Group<clang_ignored_gcc_optimization_f_Group>; +defm vect_cost_model : BooleanFFlag<"vect-cost-model">, Group<clang_ignored_gcc_optimization_f_Group>; +defm variable_expansion_in_unroller : BooleanFFlag<"variable-expansion-in-unroller">, + Group<clang_ignored_gcc_optimization_f_Group>; +defm web : BooleanFFlag<"web">, Group<clang_ignored_gcc_optimization_f_Group>; +defm whole_program : BooleanFFlag<"whole-program">, Group<clang_ignored_gcc_optimization_f_Group>; +defm devirtualize : BooleanFFlag<"devirtualize">, Group<clang_ignored_gcc_optimization_f_Group>; +defm devirtualize_speculatively : BooleanFFlag<"devirtualize-speculatively">, + Group<clang_ignored_gcc_optimization_f_Group>; + +// gfortran options that we recognize in the driver and pass along when +// invoking GCC to compile Fortran code. +def gfortran_Group : OptionGroup<"gfortran Group">; + +// Generic gfortran options. +def A_DASH : Joined<["-"], "A-">, Group<gfortran_Group>; +def J : JoinedOrSeparate<["-"], "J">, Flags<[RenderJoined]>, Group<gfortran_Group>; +def cpp : Flag<["-"], "cpp">, Group<gfortran_Group>; +def nocpp : Flag<["-"], "nocpp">, Group<gfortran_Group>; +def static_libgfortran : Flag<["-"], "static-libgfortran">, Group<gfortran_Group>; + +// "f" options with values for gfortran. +def fblas_matmul_limit_EQ : Joined<["-"], "fblas-matmul-limit=">, Group<gfortran_Group>; +def fcheck_EQ : Joined<["-"], "fcheck=">, Group<gfortran_Group>; +def fcoarray_EQ : Joined<["-"], "fcoarray=">, Group<gfortran_Group>; +def fconvert_EQ : Joined<["-"], "fconvert=">, Group<gfortran_Group>; +def ffixed_line_length_VALUE : Joined<["-"], "ffixed-line-length-">, Group<gfortran_Group>; +def ffpe_trap_EQ : Joined<["-"], "ffpe-trap=">, Group<gfortran_Group>; +def ffree_line_length_VALUE : Joined<["-"], "ffree-line-length-">, Group<gfortran_Group>; +def finit_character_EQ : Joined<["-"], "finit-character=">, Group<gfortran_Group>; +def finit_integer_EQ : Joined<["-"], "finit-integer=">, Group<gfortran_Group>; +def finit_logical_EQ : Joined<["-"], "finit-logical=">, Group<gfortran_Group>; +def finit_real_EQ : Joined<["-"], "finit-real=">, Group<gfortran_Group>; +def fmax_array_constructor_EQ : Joined<["-"], "fmax-array-constructor=">, Group<gfortran_Group>; +def fmax_errors_EQ : Joined<["-"], "fmax-errors=">, Group<gfortran_Group>; +def fmax_stack_var_size_EQ : Joined<["-"], "fmax-stack-var-size=">, Group<gfortran_Group>; +def fmax_subrecord_length_EQ : Joined<["-"], "fmax-subrecord-length=">, Group<gfortran_Group>; +def frecord_marker_EQ : Joined<["-"], "frecord-marker=">, Group<gfortran_Group>; + +// "f" flags for gfortran. +defm aggressive_function_elimination : BooleanFFlag<"aggressive-function-elimination">, Group<gfortran_Group>; +defm align_commons : BooleanFFlag<"align-commons">, Group<gfortran_Group>; +defm all_intrinsics : BooleanFFlag<"all-intrinsics">, Group<gfortran_Group>; +defm automatic : BooleanFFlag<"automatic">, Group<gfortran_Group>; +defm backslash : BooleanFFlag<"backslash">, Group<gfortran_Group>; +defm backtrace : BooleanFFlag<"backtrace">, Group<gfortran_Group>; +defm bounds_check : BooleanFFlag<"bounds-check">, Group<gfortran_Group>; +defm check_array_temporaries : BooleanFFlag<"check-array-temporaries">, Group<gfortran_Group>; +defm cray_pointer : BooleanFFlag<"cray-pointer">, Group<gfortran_Group>; +defm d_lines_as_code : BooleanFFlag<"d-lines-as-code">, Group<gfortran_Group>; +defm d_lines_as_comments : BooleanFFlag<"d-lines-as-comments">, Group<gfortran_Group>; +defm default_double_8 : BooleanFFlag<"default-double-8">, Group<gfortran_Group>; +defm default_integer_8 : BooleanFFlag<"default-integer-8">, Group<gfortran_Group>; +defm default_real_8 : BooleanFFlag<"default-real-8">, Group<gfortran_Group>; +defm dollar_ok : BooleanFFlag<"dollar-ok">, Group<gfortran_Group>; +defm dump_fortran_optimized : BooleanFFlag<"dump-fortran-optimized">, Group<gfortran_Group>; +defm dump_fortran_original : BooleanFFlag<"dump-fortran-original">, Group<gfortran_Group>; +defm dump_parse_tree : BooleanFFlag<"dump-parse-tree">, Group<gfortran_Group>; +defm external_blas : BooleanFFlag<"external-blas">, Group<gfortran_Group>; +defm f2c : BooleanFFlag<"f2c">, Group<gfortran_Group>; +defm fixed_form : BooleanFFlag<"fixed-form">, Group<gfortran_Group>; +defm free_form : BooleanFFlag<"free-form">, Group<gfortran_Group>; +defm frontend_optimize : BooleanFFlag<"frontend-optimize">, Group<gfortran_Group>; +defm implicit_none : BooleanFFlag<"implicit-none">, Group<gfortran_Group>; +defm init_local_zero : BooleanFFlag<"init-local-zero">, Group<gfortran_Group>; +defm integer_4_integer_8 : BooleanFFlag<"integer-4-integer-8">, Group<gfortran_Group>; +defm intrinsic_modules_path : BooleanFFlag<"intrinsic-modules-path">, Group<gfortran_Group>; +defm max_identifier_length : BooleanFFlag<"max-identifier-length">, Group<gfortran_Group>; +defm module_private : BooleanFFlag<"module-private">, Group<gfortran_Group>; +defm pack_derived : BooleanFFlag<"pack-derived">, Group<gfortran_Group>; +defm protect_parens : BooleanFFlag<"protect-parens">, Group<gfortran_Group>; +defm range_check : BooleanFFlag<"range-check">, Group<gfortran_Group>; +defm real_4_real_10 : BooleanFFlag<"real-4-real-10">, Group<gfortran_Group>; +defm real_4_real_16 : BooleanFFlag<"real-4-real-16">, Group<gfortran_Group>; +defm real_4_real_8 : BooleanFFlag<"real-4-real-8">, Group<gfortran_Group>; +defm real_8_real_10 : BooleanFFlag<"real-8-real-10">, Group<gfortran_Group>; +defm real_8_real_16 : BooleanFFlag<"real-8-real-16">, Group<gfortran_Group>; +defm real_8_real_4 : BooleanFFlag<"real-8-real-4">, Group<gfortran_Group>; +defm realloc_lhs : BooleanFFlag<"realloc-lhs">, Group<gfortran_Group>; +defm recursive : BooleanFFlag<"recursive">, Group<gfortran_Group>; +defm repack_arrays : BooleanFFlag<"repack-arrays">, Group<gfortran_Group>; +defm second_underscore : BooleanFFlag<"second-underscore">, Group<gfortran_Group>; +defm sign_zero : BooleanFFlag<"sign-zero">, Group<gfortran_Group>; +defm stack_arrays : BooleanFFlag<"stack-arrays">, Group<gfortran_Group>; +defm underscoring : BooleanFFlag<"underscoring">, Group<gfortran_Group>; +defm whole_file : BooleanFFlag<"whole-file">, Group<gfortran_Group>; + + +include "CC1Options.td" + +include "CLCompatOptions.td" diff --git a/contrib/llvm/tools/clang/include/clang/Driver/Phases.h b/contrib/llvm/tools/clang/include/clang/Driver/Phases.h new file mode 100644 index 0000000..cd6b5b5 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Driver/Phases.h @@ -0,0 +1,37 @@ +//===--- Phases.h - Transformations on Driver Types -------------*- 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_DRIVER_PHASES_H +#define LLVM_CLANG_DRIVER_PHASES_H + +namespace clang { +namespace driver { +namespace phases { + /// ID - Ordered values for successive stages in the + /// compilation process which interact with user options. + enum ID { + Preprocess, + Precompile, + Compile, + Backend, + Assemble, + Link + }; + + enum { + MaxNumberOfPhases = Link + 1 + }; + + const char *getPhaseName(ID Id); + +} // end namespace phases +} // end namespace driver +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Driver/SanitizerArgs.h b/contrib/llvm/tools/clang/include/clang/Driver/SanitizerArgs.h new file mode 100644 index 0000000..c2611b5 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Driver/SanitizerArgs.h @@ -0,0 +1,73 @@ +//===--- SanitizerArgs.h - Arguments for sanitizer tools -------*- 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_DRIVER_SANITIZERARGS_H +#define LLVM_CLANG_DRIVER_SANITIZERARGS_H + +#include "clang/Basic/Sanitizers.h" +#include "clang/Driver/Types.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include <string> +#include <vector> + +namespace clang { +namespace driver { + +class ToolChain; + +class SanitizerArgs { + SanitizerSet Sanitizers; + SanitizerSet RecoverableSanitizers; + SanitizerSet TrapSanitizers; + + std::vector<std::string> BlacklistFiles; + std::vector<std::string> ExtraDeps; + int CoverageFeatures; + int MsanTrackOrigins; + bool MsanUseAfterDtor; + bool CfiCrossDso; + int AsanFieldPadding; + bool AsanSharedRuntime; + bool LinkCXXRuntimes; + bool NeedPIE; + + public: + /// Parses the sanitizer arguments from an argument list. + SanitizerArgs(const ToolChain &TC, const llvm::opt::ArgList &Args); + + bool needsAsanRt() const { return Sanitizers.has(SanitizerKind::Address); } + bool needsSharedAsanRt() const { return AsanSharedRuntime; } + bool needsTsanRt() const { return Sanitizers.has(SanitizerKind::Thread); } + bool needsMsanRt() const { return Sanitizers.has(SanitizerKind::Memory); } + bool needsLsanRt() const { + return Sanitizers.has(SanitizerKind::Leak) && + !Sanitizers.has(SanitizerKind::Address); + } + bool needsUbsanRt() const; + bool needsDfsanRt() const { return Sanitizers.has(SanitizerKind::DataFlow); } + bool needsSafeStackRt() const { + return Sanitizers.has(SanitizerKind::SafeStack); + } + bool needsCfiRt() const; + bool needsCfiDiagRt() const; + + bool requiresPIE() const; + bool needsUnwindTables() const; + bool linkCXXRuntimes() const { return LinkCXXRuntimes; } + void addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, types::ID InputType) const; + + private: + void clear(); +}; + +} // namespace driver +} // namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Driver/Tool.h b/contrib/llvm/tools/clang/include/clang/Driver/Tool.h new file mode 100644 index 0000000..b9eac1c --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Driver/Tool.h @@ -0,0 +1,137 @@ +//===--- Tool.h - Compilation Tools -----------------------------*- 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_DRIVER_TOOL_H +#define LLVM_CLANG_DRIVER_TOOL_H + +#include "clang/Basic/LLVM.h" +#include "llvm/Support/Program.h" + +namespace llvm { +namespace opt { + class ArgList; +} +} + +namespace clang { +namespace driver { + + class Compilation; + class InputInfo; + class Job; + class JobAction; + class ToolChain; + + typedef SmallVector<InputInfo, 4> InputInfoList; + +/// Tool - Information on a specific compilation tool. +class Tool { +public: + // Documents the level of support for response files in this tool. + // Response files are necessary if the command line gets too large, + // requiring the arguments to be transfered to a file. + enum ResponseFileSupport { + // Provides full support for response files, which means we can transfer + // all tool input arguments to a file. E.g.: clang, gcc, binutils and MSVC + // tools. + RF_Full, + // Input file names can live in a file, but flags can't. E.g.: ld64 (Mac + // OS X linker). + RF_FileList, + // Does not support response files: all arguments must be passed via + // command line. + RF_None + }; + +private: + /// The tool name (for debugging). + const char *Name; + + /// The human readable name for the tool, for use in diagnostics. + const char *ShortName; + + /// The tool chain this tool is a part of. + const ToolChain &TheToolChain; + + /// The level of support for response files seen in this tool + const ResponseFileSupport ResponseSupport; + + /// The encoding to use when writing response files for this tool on Windows + const llvm::sys::WindowsEncodingMethod ResponseEncoding; + + /// The flag used to pass a response file via command line to this tool + const char *const ResponseFlag; + +public: + Tool(const char *Name, const char *ShortName, const ToolChain &TC, + ResponseFileSupport ResponseSupport = RF_None, + llvm::sys::WindowsEncodingMethod ResponseEncoding = llvm::sys::WEM_UTF8, + const char *ResponseFlag = "@"); + +public: + virtual ~Tool(); + + const char *getName() const { return Name; } + + const char *getShortName() const { return ShortName; } + + const ToolChain &getToolChain() const { return TheToolChain; } + + virtual bool hasIntegratedAssembler() const { return false; } + virtual bool canEmitIR() const { return false; } + virtual bool hasIntegratedCPP() const = 0; + virtual bool isLinkJob() const { return false; } + virtual bool isDsymutilJob() const { return false; } + /// \brief Returns the level of support for response files of this tool, + /// whether it accepts arguments to be passed via a file on disk. + ResponseFileSupport getResponseFilesSupport() const { + return ResponseSupport; + } + /// \brief Returns which encoding the response file should use. This is only + /// relevant on Windows platforms where there are different encodings being + /// accepted for different tools. On UNIX, UTF8 is universal. + /// + /// Windows use cases: - GCC and Binutils on mingw only accept ANSI response + /// files encoded with the system current code page. + /// - MSVC's CL.exe and LINK.exe accept UTF16 on Windows. + /// - Clang accepts both UTF8 and UTF16. + /// + /// FIXME: When GNU tools learn how to parse UTF16 on Windows, we should + /// always use UTF16 for Windows, which is the Windows official encoding for + /// international characters. + llvm::sys::WindowsEncodingMethod getResponseFileEncoding() const { + return ResponseEncoding; + } + /// \brief Returns which prefix to use when passing the name of a response + /// file as a parameter to this tool. + const char *getResponseFileFlag() const { return ResponseFlag; } + + /// \brief Does this tool have "good" standardized diagnostics, or should the + /// driver add an additional "command failed" diagnostic on failures. + virtual bool hasGoodDiagnostics() const { return false; } + + /// ConstructJob - Construct jobs to perform the action \p JA, + /// writing to \p Output and with \p Inputs, and add the jobs to + /// \p C. + /// + /// \param TCArgs - The argument list for this toolchain, with any + /// tool chain specific translations applied. + /// \param LinkingOutput - If this output will eventually feed the + /// linker, then this is the final output name of the linked image. + virtual void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const = 0; +}; + +} // end namespace driver +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Driver/ToolChain.h b/contrib/llvm/tools/clang/include/clang/Driver/ToolChain.h new file mode 100644 index 0000000..ed73107 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Driver/ToolChain.h @@ -0,0 +1,418 @@ +//===--- ToolChain.h - Collections of tools for one platform ----*- 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_DRIVER_TOOLCHAIN_H +#define LLVM_CLANG_DRIVER_TOOLCHAIN_H + +#include "clang/Basic/Sanitizers.h" +#include "clang/Driver/Action.h" +#include "clang/Driver/Multilib.h" +#include "clang/Driver/Types.h" +#include "clang/Driver/Util.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Path.h" +#include "llvm/Target/TargetOptions.h" +#include <memory> +#include <string> + +namespace llvm { +namespace opt { + class ArgList; + class DerivedArgList; + class InputArgList; +} +} + +namespace clang { +class ObjCRuntime; +namespace vfs { +class FileSystem; +} + +namespace driver { + class Compilation; + class Driver; + class JobAction; + class SanitizerArgs; + class Tool; + +/// ToolChain - Access to tools for a single platform. +class ToolChain { +public: + typedef SmallVector<std::string, 16> path_list; + + enum CXXStdlibType { + CST_Libcxx, + CST_Libstdcxx + }; + + enum RuntimeLibType { + RLT_CompilerRT, + RLT_Libgcc + }; + + enum RTTIMode { + RM_EnabledExplicitly, + RM_EnabledImplicitly, + RM_DisabledExplicitly, + RM_DisabledImplicitly + }; + +private: + const Driver &D; + const llvm::Triple Triple; + const llvm::opt::ArgList &Args; + // We need to initialize CachedRTTIArg before CachedRTTIMode + const llvm::opt::Arg *const CachedRTTIArg; + const RTTIMode CachedRTTIMode; + + /// The list of toolchain specific path prefixes to search for + /// files. + path_list FilePaths; + + /// The list of toolchain specific path prefixes to search for + /// programs. + path_list ProgramPaths; + + mutable std::unique_ptr<Tool> Clang; + mutable std::unique_ptr<Tool> Assemble; + mutable std::unique_ptr<Tool> Link; + Tool *getClang() const; + Tool *getAssemble() const; + Tool *getLink() const; + Tool *getClangAs() const; + + mutable std::unique_ptr<SanitizerArgs> SanitizerArguments; + +protected: + MultilibSet Multilibs; + const char *DefaultLinker = "ld"; + + ToolChain(const Driver &D, const llvm::Triple &T, + const llvm::opt::ArgList &Args); + + virtual Tool *buildAssembler() const; + virtual Tool *buildLinker() const; + virtual Tool *getTool(Action::ActionClass AC) const; + + /// \name Utilities for implementing subclasses. + ///@{ + static void addSystemInclude(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + const Twine &Path); + static void addExternCSystemInclude(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + const Twine &Path); + static void + addExternCSystemIncludeIfExists(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + const Twine &Path); + static void addSystemIncludes(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + ArrayRef<StringRef> Paths); + ///@} + +public: + virtual ~ToolChain(); + + // Accessors + + const Driver &getDriver() const { return D; } + vfs::FileSystem &getVFS() const; + const llvm::Triple &getTriple() const { return Triple; } + + llvm::Triple::ArchType getArch() const { return Triple.getArch(); } + StringRef getArchName() const { return Triple.getArchName(); } + StringRef getPlatform() const { return Triple.getVendorName(); } + StringRef getOS() const { return Triple.getOSName(); } + + /// \brief Provide the default architecture name (as expected by -arch) for + /// this toolchain. Note t + StringRef getDefaultUniversalArchName() const; + + std::string getTripleString() const { + return Triple.getTriple(); + } + + path_list &getFilePaths() { return FilePaths; } + const path_list &getFilePaths() const { return FilePaths; } + + path_list &getProgramPaths() { return ProgramPaths; } + const path_list &getProgramPaths() const { return ProgramPaths; } + + const MultilibSet &getMultilibs() const { return Multilibs; } + + const SanitizerArgs& getSanitizerArgs() const; + + // Returns the Arg * that explicitly turned on/off rtti, or nullptr. + const llvm::opt::Arg *getRTTIArg() const { return CachedRTTIArg; } + + // Returns the RTTIMode for the toolchain with the current arguments. + RTTIMode getRTTIMode() const { return CachedRTTIMode; } + + /// \brief Return any implicit target and/or mode flag for an invocation of + /// the compiler driver as `ProgName`. + /// + /// For example, when called with i686-linux-android-g++, the first element + /// of the return value will be set to `"i686-linux-android"` and the second + /// will be set to "--driver-mode=g++"`. + /// + /// \pre `llvm::InitializeAllTargets()` has been called. + /// \param ProgName The name the Clang driver was invoked with (from, + /// e.g., argv[0]) + /// \return A pair of (`target`, `mode-flag`), where one or both may be empty. + static std::pair<std::string, std::string> + getTargetAndModeFromProgramName(StringRef ProgName); + + // Tool access. + + /// TranslateArgs - Create a new derived argument list for any argument + /// translations this ToolChain may wish to perform, or 0 if no tool chain + /// specific translations are needed. + /// + /// \param BoundArch - The bound architecture name, or 0. + virtual llvm::opt::DerivedArgList * + TranslateArgs(const llvm::opt::DerivedArgList &Args, + const char *BoundArch) const { + return nullptr; + } + + /// Choose a tool to use to handle the action \p JA. + /// + /// This can be overridden when a particular ToolChain needs to use + /// a compiler other than Clang. + virtual Tool *SelectTool(const JobAction &JA) const; + + // Helper methods + + std::string GetFilePath(const char *Name) const; + std::string GetProgramPath(const char *Name) const; + + /// Returns the linker path, respecting the -fuse-ld= argument to determine + /// the linker suffix or name. + std::string GetLinkerPath() const; + + /// \brief Dispatch to the specific toolchain for verbose printing. + /// + /// This is used when handling the verbose option to print detailed, + /// toolchain-specific information useful for understanding the behavior of + /// the driver on a specific platform. + virtual void printVerboseInfo(raw_ostream &OS) const {} + + // Platform defaults information + + /// \brief Returns true if the toolchain is targeting a non-native + /// architecture. + virtual bool isCrossCompiling() const; + + /// HasNativeLTOLinker - Check whether the linker and related tools have + /// native LLVM support. + virtual bool HasNativeLLVMSupport() const; + + /// LookupTypeForExtension - Return the default language type to use for the + /// given extension. + virtual types::ID LookupTypeForExtension(const char *Ext) const; + + /// IsBlocksDefault - Does this tool chain enable -fblocks by default. + virtual bool IsBlocksDefault() const { return false; } + + /// IsIntegratedAssemblerDefault - Does this tool chain enable -integrated-as + /// by default. + virtual bool IsIntegratedAssemblerDefault() const { return false; } + + /// \brief Check if the toolchain should use the integrated assembler. + bool useIntegratedAs() const; + + /// IsMathErrnoDefault - Does this tool chain use -fmath-errno by default. + virtual bool IsMathErrnoDefault() const { return true; } + + /// IsEncodeExtendedBlockSignatureDefault - Does this tool chain enable + /// -fencode-extended-block-signature by default. + virtual bool IsEncodeExtendedBlockSignatureDefault() const { return false; } + + /// IsObjCNonFragileABIDefault - Does this tool chain set + /// -fobjc-nonfragile-abi by default. + virtual bool IsObjCNonFragileABIDefault() const { return false; } + + /// UseObjCMixedDispatchDefault - When using non-legacy dispatch, should the + /// mixed dispatch method be used? + virtual bool UseObjCMixedDispatch() const { return false; } + + /// GetDefaultStackProtectorLevel - Get the default stack protector level for + /// this tool chain (0=off, 1=on, 2=strong, 3=all). + virtual unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const { + return 0; + } + + /// GetDefaultRuntimeLibType - Get the default runtime library variant to use. + virtual RuntimeLibType GetDefaultRuntimeLibType() const { + return ToolChain::RLT_Libgcc; + } + + virtual std::string getCompilerRT(const llvm::opt::ArgList &Args, + StringRef Component, + bool Shared = false) const; + + const char *getCompilerRTArgString(const llvm::opt::ArgList &Args, + StringRef Component, + bool Shared = false) const; + /// needsProfileRT - returns true if instrumentation profile is on. + static bool needsProfileRT(const llvm::opt::ArgList &Args); + + /// IsUnwindTablesDefault - Does this tool chain use -funwind-tables + /// by default. + virtual bool IsUnwindTablesDefault() const; + + /// \brief Test whether this toolchain defaults to PIC. + virtual bool isPICDefault() const = 0; + + /// \brief Test whether this toolchain defaults to PIE. + virtual bool isPIEDefault() const = 0; + + /// \brief Tests whether this toolchain forces its default for PIC, PIE or + /// non-PIC. If this returns true, any PIC related flags should be ignored + /// and instead the results of \c isPICDefault() and \c isPIEDefault() are + /// used exclusively. + virtual bool isPICDefaultForced() const = 0; + + /// SupportsProfiling - Does this tool chain support -pg. + virtual bool SupportsProfiling() const { return true; } + + /// Does this tool chain support Objective-C garbage collection. + virtual bool SupportsObjCGC() const { return true; } + + /// Complain if this tool chain doesn't support Objective-C ARC. + virtual void CheckObjCARC() const {} + + /// UseDwarfDebugFlags - Embed the compile options to clang into the Dwarf + /// compile unit information. + virtual bool UseDwarfDebugFlags() const { return false; } + + // Return the DWARF version to emit, in the absence of arguments + // to the contrary. + virtual unsigned GetDefaultDwarfVersion() const { return 4; } + + // True if the driver should assume "-fstandalone-debug" + // in the absence of an option specifying otherwise, + // provided that debugging was requested in the first place. + // i.e. a value of 'true' does not imply that debugging is wanted. + virtual bool GetDefaultStandaloneDebug() const { return false; } + + // Return the default debugger "tuning." + virtual llvm::DebuggerKind getDefaultDebuggerTuning() const { + return llvm::DebuggerKind::GDB; + } + + /// UseSjLjExceptions - Does this tool chain use SjLj exceptions. + virtual bool UseSjLjExceptions(const llvm::opt::ArgList &Args) const { + return false; + } + + /// getThreadModel() - Which thread model does this target use? + virtual std::string getThreadModel() const { return "posix"; } + + /// isThreadModelSupported() - Does this target support a thread model? + virtual bool isThreadModelSupported(const StringRef Model) const; + + /// ComputeLLVMTriple - Return the LLVM target triple to use, after taking + /// command line arguments into account. + virtual std::string + ComputeLLVMTriple(const llvm::opt::ArgList &Args, + types::ID InputType = types::TY_INVALID) const; + + /// ComputeEffectiveClangTriple - Return the Clang triple to use for this + /// target, which may take into account the command line arguments. For + /// example, on Darwin the -mmacosx-version-min= command line argument (which + /// sets the deployment target) determines the version in the triple passed to + /// Clang. + virtual std::string ComputeEffectiveClangTriple( + const llvm::opt::ArgList &Args, + types::ID InputType = types::TY_INVALID) const; + + /// getDefaultObjCRuntime - Return the default Objective-C runtime + /// for this platform. + /// + /// FIXME: this really belongs on some sort of DeploymentTarget abstraction + virtual ObjCRuntime getDefaultObjCRuntime(bool isNonFragile) const; + + /// hasBlocksRuntime - Given that the user is compiling with + /// -fblocks, does this tool chain guarantee the existence of a + /// blocks runtime? + /// + /// FIXME: this really belongs on some sort of DeploymentTarget abstraction + virtual bool hasBlocksRuntime() const { return true; } + + /// \brief Add the clang cc1 arguments for system include paths. + /// + /// This routine is responsible for adding the necessary cc1 arguments to + /// include headers from standard system header directories. + virtual void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + + /// \brief Add options that need to be passed to cc1 for this target. + virtual void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + + /// \brief Add warning options that need to be passed to cc1 for this target. + virtual void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const; + + // GetRuntimeLibType - Determine the runtime library type to use with the + // given compilation arguments. + virtual RuntimeLibType + GetRuntimeLibType(const llvm::opt::ArgList &Args) const; + + // GetCXXStdlibType - Determine the C++ standard library type to use with the + // given compilation arguments. + virtual CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const; + + /// AddClangCXXStdlibIncludeArgs - Add the clang -cc1 level arguments to set + /// the include paths to use for the given C++ standard library type. + virtual void + AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + + /// AddCXXStdlibLibArgs - Add the system specific linker arguments to use + /// for the given C++ standard library type. + virtual void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + + /// AddFilePathLibArgs - Add each thing in getFilePaths() as a "-L" option. + void AddFilePathLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + + /// AddCCKextLibArgs - Add the system specific linker arguments to use + /// for kernel extensions (Darwin-specific). + virtual void AddCCKextLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + + /// AddFastMathRuntimeIfAvailable - If a runtime library exists that sets + /// global flags for unsafe floating point math, add it and return true. + /// + /// This checks for presence of the -Ofast, -ffast-math or -funsafe-math flags. + virtual bool AddFastMathRuntimeIfAvailable( + const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; + /// addProfileRTLibs - When -fprofile-instr-profile is specified, try to pass + /// a suitable profile runtime library to the linker. + virtual void addProfileRTLibs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + + /// \brief Add arguments to use system-specific CUDA includes. + virtual void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + + /// \brief Return sanitizers which are available in this toolchain. + virtual SanitizerMask getSupportedSanitizers() const; +}; + +} // end namespace driver +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Driver/Types.def b/contrib/llvm/tools/clang/include/clang/Driver/Types.def new file mode 100644 index 0000000..d1b6915 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Driver/Types.def @@ -0,0 +1,96 @@ +//===--- Types.def - Driver Type info ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the driver type information. Users of this file +// must define the TYPE macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +#ifndef TYPE +#error "Define TYPE prior to including this file!" +#endif + +// TYPE(NAME, ID, PP_TYPE, TEMP_SUFFIX, FLAGS) + +// The first value is the type name as a string; for types which can +// be user specified this should be the equivalent -x option. + +// The second value is the type id, which will result in a +// clang::driver::types::TY_XX enum constant. + +// The third value is that id of the type for preprocessed inputs of +// this type, or INVALID if this type is not preprocessed. + +// The fourth value is the suffix to use when creating temporary files +// of this type, or null if unspecified. + +// The fifth value is a string containing option flags. Valid values: +// a - The type should only be assembled. +// p - The type should only be precompiled. +// u - The type can be user specified (with -x). +// A - The type's temporary suffix should be appended when generating +// outputs of this type. + + +// C family source language (with and without preprocessing). +TYPE("cpp-output", PP_C, INVALID, "i", "u") +TYPE("c", C, PP_C, "c", "u") +TYPE("cl", CL, PP_C, "cl", "u") +TYPE("cuda-cpp-output", PP_CUDA, INVALID, "cui", "u") +TYPE("cuda", CUDA, PP_CUDA, "cu", "u") +TYPE("cuda", CUDA_DEVICE, PP_CUDA, "cu", "") +TYPE("objective-c-cpp-output", PP_ObjC, INVALID, "mi", "u") +TYPE("objc-cpp-output", PP_ObjC_Alias, INVALID, "mi", "u") +TYPE("objective-c", ObjC, PP_ObjC, "m", "u") +TYPE("c++-cpp-output", PP_CXX, INVALID, "ii", "u") +TYPE("c++", CXX, PP_CXX, "cpp", "u") +TYPE("objective-c++-cpp-output", PP_ObjCXX, INVALID, "mii", "u") +TYPE("objc++-cpp-output", PP_ObjCXX_Alias, INVALID, "mii", "u") +TYPE("objective-c++", ObjCXX, PP_ObjCXX, "mm", "u") + +// C family input files to precompile. +TYPE("c-header-cpp-output", PP_CHeader, INVALID, "i", "p") +TYPE("c-header", CHeader, PP_CHeader, "h", "pu") +TYPE("cl-header", CLHeader, PP_CHeader, "h", "pu") +TYPE("objective-c-header-cpp-output", PP_ObjCHeader, INVALID, "mi", "p") +TYPE("objective-c-header", ObjCHeader, PP_ObjCHeader, "h", "pu") +TYPE("c++-header-cpp-output", PP_CXXHeader, INVALID, "ii", "p") +TYPE("c++-header", CXXHeader, PP_CXXHeader, "hh", "pu") +TYPE("objective-c++-header-cpp-output", PP_ObjCXXHeader, INVALID, "mii", "p") +TYPE("objective-c++-header", ObjCXXHeader, PP_ObjCXXHeader, "h", "pu") + +// Other languages. +TYPE("ada", Ada, INVALID, nullptr, "u") +TYPE("assembler", PP_Asm, INVALID, "s", "au") +TYPE("assembler-with-cpp", Asm, PP_Asm, "S", "au") +TYPE("f95", PP_Fortran, INVALID, nullptr, "u") +TYPE("f95-cpp-input", Fortran, PP_Fortran, nullptr, "u") +TYPE("java", Java, INVALID, nullptr, "u") + +// LLVM IR/LTO types. We define separate types for IR and LTO because LTO +// outputs should use the standard suffixes. +TYPE("ir", LLVM_IR, INVALID, "ll", "u") +TYPE("ir", LLVM_BC, INVALID, "bc", "u") +TYPE("lto-ir", LTO_IR, INVALID, "s", "") +TYPE("lto-bc", LTO_BC, INVALID, "o", "") + +// Misc. +TYPE("ast", AST, INVALID, "ast", "u") +TYPE("pcm", ModuleFile, INVALID, "pcm", "u") +TYPE("plist", Plist, INVALID, "plist", "") +TYPE("rewritten-objc", RewrittenObjC,INVALID, "cpp", "") +TYPE("rewritten-legacy-objc", RewrittenLegacyObjC,INVALID, "cpp", "") +TYPE("remap", Remap, INVALID, "remap", "") +TYPE("precompiled-header", PCH, INVALID, "gch", "A") +TYPE("object", Object, INVALID, "o", "") +TYPE("treelang", Treelang, INVALID, nullptr, "u") +TYPE("image", Image, INVALID, "out", "") +TYPE("dSYM", dSYM, INVALID, "dSYM", "A") +TYPE("dependencies", Dependencies, INVALID, "d", "") +TYPE("none", Nothing, INVALID, nullptr, "u") diff --git a/contrib/llvm/tools/clang/include/clang/Driver/Types.h b/contrib/llvm/tools/clang/include/clang/Driver/Types.h new file mode 100644 index 0000000..22122c7 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Driver/Types.h @@ -0,0 +1,97 @@ +//===--- Types.h - Input & Temporary Driver Types ---------------*- 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_DRIVER_TYPES_H +#define LLVM_CLANG_DRIVER_TYPES_H + +#include "clang/Driver/Phases.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { +namespace driver { +namespace types { + enum ID { + TY_INVALID, +#define TYPE(NAME, ID, PP_TYPE, TEMP_SUFFIX, FLAGS) TY_##ID, +#include "clang/Driver/Types.def" +#undef TYPE + TY_LAST + }; + + /// getTypeName - Return the name of the type for \p Id. + const char *getTypeName(ID Id); + + /// getPreprocessedType - Get the ID of the type for this input when + /// it has been preprocessed, or INVALID if this input is not + /// preprocessed. + ID getPreprocessedType(ID Id); + + /// getTypeTempSuffix - Return the suffix to use when creating a + /// temp file of this type, or null if unspecified. + const char *getTypeTempSuffix(ID Id, bool CLMode = false); + + /// onlyAssembleType - Should this type only be assembled. + bool onlyAssembleType(ID Id); + + /// onlyPrecompileType - Should this type only be precompiled. + bool onlyPrecompileType(ID Id); + + /// canTypeBeUserSpecified - Can this type be specified on the + /// command line (by the type name); this is used when forwarding + /// commands to gcc. + bool canTypeBeUserSpecified(ID Id); + + /// appendSuffixForType - When generating outputs of this type, + /// should the suffix be appended (instead of replacing the existing + /// suffix). + bool appendSuffixForType(ID Id); + + /// canLipoType - Is this type acceptable as the output of a + /// universal build (currently, just the Nothing, Image, and Object + /// types). + bool canLipoType(ID Id); + + /// isAcceptedByClang - Can clang handle this input type. + bool isAcceptedByClang(ID Id); + + /// isCXX - Is this a "C++" input (C++ and Obj-C++ sources and headers). + bool isCXX(ID Id); + + /// Is this LLVM IR. + bool isLLVMIR(ID Id); + + /// isCuda - Is this a CUDA input. + bool isCuda(ID Id); + + /// isObjC - Is this an "ObjC" input (Obj-C and Obj-C++ sources and headers). + bool isObjC(ID Id); + + /// lookupTypeForExtension - Lookup the type to use for the file + /// extension \p Ext. + ID lookupTypeForExtension(const char *Ext); + + /// lookupTypeForTypSpecifier - Lookup the type to use for a user + /// specified type name. + ID lookupTypeForTypeSpecifier(const char *Name); + + /// getCompilationPhases - Get the list of compilation phases ('Phases') to be + /// done for type 'Id'. + void getCompilationPhases( + ID Id, + llvm::SmallVectorImpl<phases::ID> &Phases); + + /// lookupCXXTypeForCType - Lookup CXX input type that corresponds to given + /// C type (used for clang++ emulation of g++ behaviour) + ID lookupCXXTypeForCType(ID Id); + +} // end namespace types +} // end namespace driver +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Driver/Util.h b/contrib/llvm/tools/clang/include/clang/Driver/Util.h new file mode 100644 index 0000000..07495a1 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Driver/Util.h @@ -0,0 +1,32 @@ +//===--- Util.h - Common Driver Utilities -----------------------*- 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_DRIVER_UTIL_H +#define LLVM_CLANG_DRIVER_UTIL_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/DenseMap.h" + +namespace clang { +class DiagnosticsEngine; + +namespace driver { + class Action; + class JobAction; + + /// ArgStringMap - Type used to map a JobAction to its result file. + typedef llvm::DenseMap<const JobAction*, const char*> ArgStringMap; + + /// ActionList - Type used for lists of actions. + typedef SmallVector<Action*, 3> ActionList; + +} // end namespace driver +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Edit/Commit.h b/contrib/llvm/tools/clang/include/clang/Edit/Commit.h new file mode 100644 index 0000000..ac4bb47 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Edit/Commit.h @@ -0,0 +1,143 @@ +//===----- Commit.h - A unit of edits ---------------------------*- 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_EDIT_COMMIT_H +#define LLVM_CLANG_EDIT_COMMIT_H + +#include "clang/Edit/FileOffset.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Allocator.h" + +namespace clang { + class LangOptions; + class PPConditionalDirectiveRecord; + +namespace edit { + class EditedSource; + +class Commit { +public: + enum EditKind { + Act_Insert, + Act_InsertFromRange, + Act_Remove + }; + + struct Edit { + EditKind Kind; + StringRef Text; + SourceLocation OrigLoc; + FileOffset Offset; + FileOffset InsertFromRangeOffs; + unsigned Length; + bool BeforePrev; + + SourceLocation getFileLocation(SourceManager &SM) const; + CharSourceRange getFileRange(SourceManager &SM) const; + CharSourceRange getInsertFromRange(SourceManager &SM) const; + }; + +private: + const SourceManager &SourceMgr; + const LangOptions &LangOpts; + const PPConditionalDirectiveRecord *PPRec; + EditedSource *Editor; + + bool IsCommitable; + SmallVector<Edit, 8> CachedEdits; + + llvm::BumpPtrAllocator StrAlloc; + +public: + explicit Commit(EditedSource &Editor); + Commit(const SourceManager &SM, const LangOptions &LangOpts, + const PPConditionalDirectiveRecord *PPRec = nullptr) + : SourceMgr(SM), LangOpts(LangOpts), PPRec(PPRec), Editor(nullptr), + IsCommitable(true) { } + + bool isCommitable() const { return IsCommitable; } + + bool insert(SourceLocation loc, StringRef text, bool afterToken = false, + bool beforePreviousInsertions = false); + bool insertAfterToken(SourceLocation loc, StringRef text, + bool beforePreviousInsertions = false) { + return insert(loc, text, /*afterToken=*/true, beforePreviousInsertions); + } + bool insertBefore(SourceLocation loc, StringRef text) { + return insert(loc, text, /*afterToken=*/false, + /*beforePreviousInsertions=*/true); + } + bool insertFromRange(SourceLocation loc, CharSourceRange range, + bool afterToken = false, + bool beforePreviousInsertions = false); + bool insertWrap(StringRef before, CharSourceRange range, StringRef after); + + bool remove(CharSourceRange range); + + bool replace(CharSourceRange range, StringRef text); + bool replaceWithInner(CharSourceRange range, CharSourceRange innerRange); + bool replaceText(SourceLocation loc, StringRef text, + StringRef replacementText); + + bool insertFromRange(SourceLocation loc, SourceRange TokenRange, + bool afterToken = false, + bool beforePreviousInsertions = false) { + return insertFromRange(loc, CharSourceRange::getTokenRange(TokenRange), + afterToken, beforePreviousInsertions); + } + bool insertWrap(StringRef before, SourceRange TokenRange, StringRef after) { + return insertWrap(before, CharSourceRange::getTokenRange(TokenRange), after); + } + bool remove(SourceRange TokenRange) { + return remove(CharSourceRange::getTokenRange(TokenRange)); + } + bool replace(SourceRange TokenRange, StringRef text) { + return replace(CharSourceRange::getTokenRange(TokenRange), text); + } + bool replaceWithInner(SourceRange TokenRange, SourceRange TokenInnerRange) { + return replaceWithInner(CharSourceRange::getTokenRange(TokenRange), + CharSourceRange::getTokenRange(TokenInnerRange)); + } + + typedef SmallVectorImpl<Edit>::const_iterator edit_iterator; + edit_iterator edit_begin() const { return CachedEdits.begin(); } + edit_iterator edit_end() const { return CachedEdits.end(); } + +private: + void addInsert(SourceLocation OrigLoc, + FileOffset Offs, StringRef text, bool beforePreviousInsertions); + void addInsertFromRange(SourceLocation OrigLoc, FileOffset Offs, + FileOffset RangeOffs, unsigned RangeLen, + bool beforePreviousInsertions); + void addRemove(SourceLocation OrigLoc, FileOffset Offs, unsigned Len); + + bool canInsert(SourceLocation loc, FileOffset &Offset); + bool canInsertAfterToken(SourceLocation loc, FileOffset &Offset, + SourceLocation &AfterLoc); + bool canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs); + bool canRemoveRange(CharSourceRange range, FileOffset &Offs, unsigned &Len); + bool canReplaceText(SourceLocation loc, StringRef text, + FileOffset &Offs, unsigned &Len); + + void commitInsert(FileOffset offset, StringRef text, + bool beforePreviousInsertions); + void commitRemove(FileOffset offset, unsigned length); + + bool isAtStartOfMacroExpansion(SourceLocation loc, + SourceLocation *MacroBegin = nullptr) const; + bool isAtEndOfMacroExpansion(SourceLocation loc, + SourceLocation *MacroEnd = nullptr) const; +}; + +} + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Edit/EditedSource.h b/contrib/llvm/tools/clang/include/clang/Edit/EditedSource.h new file mode 100644 index 0000000..b6ec8b8 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Edit/EditedSource.h @@ -0,0 +1,97 @@ +//===----- EditedSource.h - Collection of source edits ----------*- 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_EDIT_EDITEDSOURCE_H +#define LLVM_CLANG_EDIT_EDITEDSOURCE_H + +#include "clang/Basic/IdentifierTable.h" +#include "clang/Edit/FileOffset.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/TinyPtrVector.h" +#include "llvm/Support/Allocator.h" +#include <map> + +namespace clang { + class LangOptions; + class PPConditionalDirectiveRecord; + +namespace edit { + class Commit; + class EditsReceiver; + +class EditedSource { + const SourceManager &SourceMgr; + const LangOptions &LangOpts; + const PPConditionalDirectiveRecord *PPRec; + + struct FileEdit { + StringRef Text; + unsigned RemoveLen; + + FileEdit() : RemoveLen(0) {} + }; + + typedef std::map<FileOffset, FileEdit> FileEditsTy; + FileEditsTy FileEdits; + + llvm::DenseMap<unsigned, llvm::TinyPtrVector<IdentifierInfo*>> + ExpansionToArgMap; + SmallVector<std::pair<SourceLocation, IdentifierInfo*>, 2> + CurrCommitMacroArgExps; + + IdentifierTable IdentTable; + llvm::BumpPtrAllocator StrAlloc; + +public: + EditedSource(const SourceManager &SM, const LangOptions &LangOpts, + const PPConditionalDirectiveRecord *PPRec = nullptr) + : SourceMgr(SM), LangOpts(LangOpts), PPRec(PPRec), IdentTable(LangOpts), + StrAlloc() { } + + const SourceManager &getSourceManager() const { return SourceMgr; } + const LangOptions &getLangOpts() const { return LangOpts; } + const PPConditionalDirectiveRecord *getPPCondDirectiveRecord() const { + return PPRec; + } + + bool canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs); + + bool commit(const Commit &commit); + + void applyRewrites(EditsReceiver &receiver); + void clearRewrites(); + + StringRef copyString(StringRef str) { return str.copy(StrAlloc); } + StringRef copyString(const Twine &twine); + +private: + bool commitInsert(SourceLocation OrigLoc, FileOffset Offs, StringRef text, + bool beforePreviousInsertions); + bool commitInsertFromRange(SourceLocation OrigLoc, FileOffset Offs, + FileOffset InsertFromRangeOffs, unsigned Len, + bool beforePreviousInsertions); + void commitRemove(SourceLocation OrigLoc, FileOffset BeginOffs, unsigned Len); + + StringRef getSourceText(FileOffset BeginOffs, FileOffset EndOffs, + bool &Invalid); + FileEditsTy::iterator getActionForOffset(FileOffset Offs); + void deconstructMacroArgLoc(SourceLocation Loc, + SourceLocation &ExpansionLoc, + IdentifierInfo *&II); + + void startingCommit(); + void finishedCommit(); +}; + +} + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Edit/EditsReceiver.h b/contrib/llvm/tools/clang/include/clang/Edit/EditsReceiver.h new file mode 100644 index 0000000..600ac28 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Edit/EditsReceiver.h @@ -0,0 +1,35 @@ +//===----- EditedSource.h - Collection of source edits ----------*- 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_EDIT_EDITSRECEIVER_H +#define LLVM_CLANG_EDIT_EDITSRECEIVER_H + +#include "clang/Basic/LLVM.h" + +namespace clang { + class SourceLocation; + class CharSourceRange; + +namespace edit { + +class EditsReceiver { +public: + virtual ~EditsReceiver() { } + + virtual void insert(SourceLocation loc, StringRef text) = 0; + virtual void replace(CharSourceRange range, StringRef text) = 0; + /// \brief By default it calls replace with an empty string. + virtual void remove(CharSourceRange range); +}; + +} + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Edit/FileOffset.h b/contrib/llvm/tools/clang/include/clang/Edit/FileOffset.h new file mode 100644 index 0000000..0c1e72b --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Edit/FileOffset.h @@ -0,0 +1,61 @@ +//===----- FileOffset.h - Offset in a file ----------------------*- 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_EDIT_FILEOFFSET_H +#define LLVM_CLANG_EDIT_FILEOFFSET_H + +#include "clang/Basic/SourceLocation.h" + +namespace clang { + +namespace edit { + +class FileOffset { + FileID FID; + unsigned Offs; +public: + FileOffset() : Offs(0) { } + FileOffset(FileID fid, unsigned offs) : FID(fid), Offs(offs) { } + + bool isInvalid() const { return FID.isInvalid(); } + + FileID getFID() const { return FID; } + unsigned getOffset() const { return Offs; } + + FileOffset getWithOffset(unsigned offset) const { + FileOffset NewOffs = *this; + NewOffs.Offs += offset; + return NewOffs; + } + + friend bool operator==(FileOffset LHS, FileOffset RHS) { + return LHS.FID == RHS.FID && LHS.Offs == RHS.Offs; + } + friend bool operator!=(FileOffset LHS, FileOffset RHS) { + return !(LHS == RHS); + } + friend bool operator<(FileOffset LHS, FileOffset RHS) { + return std::tie(LHS.FID, LHS.Offs) < std::tie(RHS.FID, RHS.Offs); + } + friend bool operator>(FileOffset LHS, FileOffset RHS) { + return RHS < LHS; + } + friend bool operator>=(FileOffset LHS, FileOffset RHS) { + return !(LHS < RHS); + } + friend bool operator<=(FileOffset LHS, FileOffset RHS) { + return !(RHS < LHS); + } +}; + +} + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Edit/Rewriters.h b/contrib/llvm/tools/clang/include/clang/Edit/Rewriters.h new file mode 100644 index 0000000..5e3425f --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Edit/Rewriters.h @@ -0,0 +1,41 @@ +//===--- Rewriters.h - Rewritings ---------------------------*- 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_EDIT_REWRITERS_H +#define LLVM_CLANG_EDIT_REWRITERS_H +#include "llvm/ADT/SmallVector.h" + +namespace clang { + class ObjCMessageExpr; + class ObjCMethodDecl; + class ObjCInterfaceDecl; + class ObjCProtocolDecl; + class NSAPI; + class EnumDecl; + class TypedefDecl; + class ParentMap; + +namespace edit { + class Commit; + +bool rewriteObjCRedundantCallWithLiteral(const ObjCMessageExpr *Msg, + const NSAPI &NS, Commit &commit); + +bool rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg, + const NSAPI &NS, Commit &commit, + const ParentMap *PMap); + +bool rewriteToObjCSubscriptSyntax(const ObjCMessageExpr *Msg, + const NSAPI &NS, Commit &commit); + +} + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Format/Format.h b/contrib/llvm/tools/clang/include/clang/Format/Format.h new file mode 100644 index 0000000..6d051e0 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Format/Format.h @@ -0,0 +1,792 @@ +//===--- Format.h - Format C++ code -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Various functions to configurably format source code. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FORMAT_FORMAT_H +#define LLVM_CLANG_FORMAT_FORMAT_H + +#include "clang/Basic/LangOptions.h" +#include "clang/Tooling/Core/Replacement.h" +#include "llvm/ADT/ArrayRef.h" +#include <system_error> + +namespace clang { + +class Lexer; +class SourceManager; +class DiagnosticConsumer; + +namespace format { + +enum class ParseError { Success = 0, Error, Unsuitable }; +class ParseErrorCategory final : public std::error_category { +public: + const char *name() const LLVM_NOEXCEPT override; + std::string message(int EV) const override; +}; +const std::error_category &getParseCategory(); +std::error_code make_error_code(ParseError e); + +/// \brief The \c FormatStyle is used to configure the formatting to follow +/// specific guidelines. +struct FormatStyle { + /// \brief The extra indent or outdent of access modifiers, e.g. \c public:. + int AccessModifierOffset; + + /// \brief Different styles for aligning after open brackets. + enum BracketAlignmentStyle { + /// \brief Align parameters on the open bracket, e.g.: + /// \code + /// someLongFunction(argument1, + /// argument2); + /// \endcode + BAS_Align, + /// \brief Don't align, instead use \c ContinuationIndentWidth, e.g.: + /// \code + /// someLongFunction(argument1, + /// argument2); + /// \endcode + BAS_DontAlign, + /// \brief Always break after an open bracket, if the parameters don't fit + /// on a single line, e.g.: + /// \code + /// someLongFunction( + /// argument1, argument2); + /// \endcode + BAS_AlwaysBreak, + }; + + /// \brief If \c true, horizontally aligns arguments after an open bracket. + /// + /// This applies to round brackets (parentheses), angle brackets and square + /// brackets. + BracketAlignmentStyle AlignAfterOpenBracket; + + /// \brief If \c true, aligns consecutive assignments. + /// + /// This will align the assignment operators of consecutive lines. This + /// will result in formattings like + /// \code + /// int aaaa = 12; + /// int b = 23; + /// int ccc = 23; + /// \endcode + bool AlignConsecutiveAssignments; + + /// \brief If \c true, aligns consecutive declarations. + /// + /// This will align the declaration names of consecutive lines. This + /// will result in formattings like + /// \code + /// int aaaa = 12; + /// float b = 23; + /// std::string ccc = 23; + /// \endcode + bool AlignConsecutiveDeclarations; + + /// \brief If \c true, aligns escaped newlines as far left as possible. + /// Otherwise puts them into the right-most column. + bool AlignEscapedNewlinesLeft; + + /// \brief If \c true, horizontally align operands of binary and ternary + /// expressions. + /// + /// Specifically, this aligns operands of a single expression that needs to be + /// split over multiple lines, e.g.: + /// \code + /// int aaa = bbbbbbbbbbbbbbb + + /// ccccccccccccccc; + /// \endcode + bool AlignOperands; + + /// \brief If \c true, aligns trailing comments. + bool AlignTrailingComments; + + /// \brief Allow putting all parameters of a function declaration onto + /// the next line even if \c BinPackParameters is \c false. + bool AllowAllParametersOfDeclarationOnNextLine; + + /// \brief Allows contracting simple braced statements to a single line. + /// + /// E.g., this allows <tt>if (a) { return; }</tt> to be put on a single line. + bool AllowShortBlocksOnASingleLine; + + /// \brief If \c true, short case labels will be contracted to a single line. + bool AllowShortCaseLabelsOnASingleLine; + + /// \brief Different styles for merging short functions containing at most one + /// statement. + enum ShortFunctionStyle { + /// \brief Never merge functions into a single line. + SFS_None, + /// \brief Only merge empty functions. + SFS_Empty, + /// \brief Only merge functions defined inside a class. Implies "empty". + SFS_Inline, + /// \brief Merge all functions fitting on a single line. + SFS_All, + }; + + /// \brief Dependent on the value, <tt>int f() { return 0; }</tt> can be put + /// on a single line. + ShortFunctionStyle AllowShortFunctionsOnASingleLine; + + /// \brief If \c true, <tt>if (a) return;</tt> can be put on a single + /// line. + bool AllowShortIfStatementsOnASingleLine; + + /// \brief If \c true, <tt>while (true) continue;</tt> can be put on a + /// single line. + bool AllowShortLoopsOnASingleLine; + + /// \brief Different ways to break after the function definition return type. + enum DefinitionReturnTypeBreakingStyle { + /// Break after return type automatically. + /// \c PenaltyReturnTypeOnItsOwnLine is taken into account. + DRTBS_None, + /// Always break after the return type. + DRTBS_All, + /// Always break after the return types of top-level functions. + DRTBS_TopLevel, + }; + + /// \brief Different ways to break after the function definition or + /// declaration return type. + enum ReturnTypeBreakingStyle { + /// Break after return type automatically. + /// \c PenaltyReturnTypeOnItsOwnLine is taken into account. + RTBS_None, + /// Always break after the return type. + RTBS_All, + /// Always break after the return types of top-level functions. + RTBS_TopLevel, + /// Always break after the return type of function definitions. + RTBS_AllDefinitions, + /// Always break after the return type of top-level definitions. + RTBS_TopLevelDefinitions, + }; + + /// \brief The function definition return type breaking style to use. This + /// option is deprecated and is retained for backwards compatibility. + DefinitionReturnTypeBreakingStyle AlwaysBreakAfterDefinitionReturnType; + + /// \brief The function declaration return type breaking style to use. + ReturnTypeBreakingStyle AlwaysBreakAfterReturnType; + + /// \brief If \c true, always break before multiline string literals. + /// + /// This flag is mean to make cases where there are multiple multiline strings + /// in a file look more consistent. Thus, it will only take effect if wrapping + /// the string at that point leads to it being indented + /// \c ContinuationIndentWidth spaces from the start of the line. + bool AlwaysBreakBeforeMultilineStrings; + + /// \brief If \c true, always break after the <tt>template<...></tt> of a + /// template declaration. + bool AlwaysBreakTemplateDeclarations; + + /// \brief If \c false, a function call's arguments will either be all on the + /// same line or will have one line each. + bool BinPackArguments; + + /// \brief If \c false, a function declaration's or function definition's + /// parameters will either all be on the same line or will have one line each. + bool BinPackParameters; + + /// \brief The style of breaking before or after binary operators. + enum BinaryOperatorStyle { + /// Break after operators. + BOS_None, + /// Break before operators that aren't assignments. + BOS_NonAssignment, + /// Break before operators. + BOS_All, + }; + + /// \brief The way to wrap binary operators. + BinaryOperatorStyle BreakBeforeBinaryOperators; + + /// \brief Different ways to attach braces to their surrounding context. + enum BraceBreakingStyle { + /// Always attach braces to surrounding context. + BS_Attach, + /// Like \c Attach, but break before braces on function, namespace and + /// class definitions. + BS_Linux, + /// Like ``Attach``, but break before braces on enum, function, and record + /// definitions. + BS_Mozilla, + /// Like \c Attach, but break before function definitions, 'catch', and 'else'. + BS_Stroustrup, + /// Always break before braces. + BS_Allman, + /// Always break before braces and add an extra level of indentation to + /// braces of control statements, not to those of class, function + /// or other definitions. + BS_GNU, + /// Like ``Attach``, but break before functions. + BS_WebKit, + /// Configure each individual brace in \c BraceWrapping. + BS_Custom + }; + + /// \brief The brace breaking style to use. + BraceBreakingStyle BreakBeforeBraces; + + /// \brief Precise control over the wrapping of braces. + struct BraceWrappingFlags { + /// \brief Wrap class definitions. + bool AfterClass; + /// \brief Wrap control statements (if/for/while/switch/..). + bool AfterControlStatement; + /// \brief Wrap enum definitions. + bool AfterEnum; + /// \brief Wrap function definitions. + bool AfterFunction; + /// \brief Wrap namespace definitions. + bool AfterNamespace; + /// \brief Wrap ObjC definitions (@autoreleasepool, interfaces, ..). + bool AfterObjCDeclaration; + /// \brief Wrap struct definitions. + bool AfterStruct; + /// \brief Wrap union definitions. + bool AfterUnion; + /// \brief Wrap before \c catch. + bool BeforeCatch; + /// \brief Wrap before \c else. + bool BeforeElse; + /// \brief Indent the wrapped braces themselves. + bool IndentBraces; + }; + + /// \brief Control of individual brace wrapping cases. + /// + /// If \c BreakBeforeBraces is set to \c custom, use this to specify how each + /// individual brace case should be handled. Otherwise, this is ignored. + BraceWrappingFlags BraceWrapping; + + /// \brief If \c true, ternary operators will be placed after line breaks. + bool BreakBeforeTernaryOperators; + + /// \brief Always break constructor initializers before commas and align + /// the commas with the colon. + bool BreakConstructorInitializersBeforeComma; + + /// \brief Break after each annotation on a field in Java files. + bool BreakAfterJavaFieldAnnotations; + + /// \brief The column limit. + /// + /// A column limit of \c 0 means that there is no column limit. In this case, + /// clang-format will respect the input's line breaking decisions within + /// statements unless they contradict other rules. + unsigned ColumnLimit; + + /// \brief A regular expression that describes comments with special meaning, + /// which should not be split into lines or otherwise changed. + std::string CommentPragmas; + + /// \brief If the constructor initializers don't fit on a line, put each + /// initializer on its own line. + bool ConstructorInitializerAllOnOneLineOrOnePerLine; + + /// \brief The number of characters to use for indentation of constructor + /// initializer lists. + unsigned ConstructorInitializerIndentWidth; + + /// \brief Indent width for line continuations. + unsigned ContinuationIndentWidth; + + /// \brief If \c true, format braced lists as best suited for C++11 braced + /// lists. + /// + /// Important differences: + /// - No spaces inside the braced list. + /// - No line break before the closing brace. + /// - Indentation with the continuation indent, not with the block indent. + /// + /// Fundamentally, C++11 braced lists are formatted exactly like function + /// calls would be formatted in their place. If the braced list follows a name + /// (e.g. a type or variable name), clang-format formats as if the \c {} were + /// the parentheses of a function call with that name. If there is no name, + /// a zero-length name is assumed. + bool Cpp11BracedListStyle; + + /// \brief If \c true, analyze the formatted file for the most common + /// alignment of & and *. \c PointerAlignment is then used only as fallback. + bool DerivePointerAlignment; + + /// \brief Disables formatting completely. + bool DisableFormat; + + /// \brief If \c true, clang-format detects whether function calls and + /// definitions are formatted with one parameter per line. + /// + /// Each call can be bin-packed, one-per-line or inconclusive. If it is + /// inconclusive, e.g. completely on one line, but a decision needs to be + /// made, clang-format analyzes whether there are other bin-packed cases in + /// the input file and act accordingly. + /// + /// NOTE: This is an experimental flag, that might go away or be renamed. Do + /// not use this in config files, etc. Use at your own risk. + bool ExperimentalAutoDetectBinPacking; + + /// \brief A vector of macros that should be interpreted as foreach loops + /// instead of as function calls. + /// + /// These are expected to be macros of the form: + /// \code + /// FOREACH(<variable-declaration>, ...) + /// <loop-body> + /// \endcode + /// + /// In the .clang-format configuration file, this can be configured like: + /// \code + /// ForEachMacros: ['RANGES_FOR', 'FOREACH'] + /// \endcode + /// + /// For example: BOOST_FOREACH. + std::vector<std::string> ForEachMacros; + + /// \brief See documentation of \c IncludeCategories. + struct IncludeCategory { + /// \brief The regular expression that this category matches. + std::string Regex; + /// \brief The priority to assign to this category. + int Priority; + bool operator==(const IncludeCategory &Other) const { + return Regex == Other.Regex && Priority == Other.Priority; + } + }; + + /// \brief Regular expressions denoting the different #include categories used + /// for ordering #includes. + /// + /// These regular expressions are matched against the filename of an include + /// (including the <> or "") in order. The value belonging to the first + /// matching regular expression is assigned and #includes are sorted first + /// according to increasing category number and then alphabetically within + /// each category. + /// + /// If none of the regular expressions match, INT_MAX is assigned as + /// category. The main header for a source file automatically gets category 0. + /// so that it is generally kept at the beginning of the #includes + /// (http://llvm.org/docs/CodingStandards.html#include-style). However, you + /// can also assign negative priorities if you have certain headers that + /// always need to be first. + /// + /// To configure this in the .clang-format file, use: + /// \code + /// IncludeCategories: + /// - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + /// Priority: 2 + /// - Regex: '^(<|"(gtest|isl|json)/)' + /// Priority: 3 + /// - Regex: '.*' + /// Priority: 1 + /// \endcode + std::vector<IncludeCategory> IncludeCategories; + + /// \brief Indent case labels one level from the switch statement. + /// + /// When \c false, use the same indentation level as for the switch statement. + /// Switch statement body is always indented one level more than case labels. + bool IndentCaseLabels; + + /// \brief The number of columns to use for indentation. + unsigned IndentWidth; + + /// \brief Indent if a function definition or declaration is wrapped after the + /// type. + bool IndentWrappedFunctionNames; + + /// \brief If true, empty lines at the start of blocks are kept. + bool KeepEmptyLinesAtTheStartOfBlocks; + + /// \brief Supported languages. When stored in a configuration file, specifies + /// the language, that the configuration targets. When passed to the + /// reformat() function, enables syntax features specific to the language. + enum LanguageKind { + /// Do not use. + LK_None, + /// Should be used for C, C++, ObjectiveC, ObjectiveC++. + LK_Cpp, + /// Should be used for Java. + LK_Java, + /// Should be used for JavaScript. + LK_JavaScript, + /// Should be used for Protocol Buffers + /// (https://developers.google.com/protocol-buffers/). + LK_Proto, + /// Should be used for TableGen code. + LK_TableGen + }; + + /// \brief Language, this format style is targeted at. + LanguageKind Language; + + /// \brief A regular expression matching macros that start a block. + std::string MacroBlockBegin; + + /// \brief A regular expression matching macros that end a block. + std::string MacroBlockEnd; + + /// \brief The maximum number of consecutive empty lines to keep. + unsigned MaxEmptyLinesToKeep; + + /// \brief Different ways to indent namespace contents. + enum NamespaceIndentationKind { + /// Don't indent in namespaces. + NI_None, + /// Indent only in inner namespaces (nested in other namespaces). + NI_Inner, + /// Indent in all namespaces. + NI_All + }; + + /// \brief The indentation used for namespaces. + NamespaceIndentationKind NamespaceIndentation; + + /// \brief The number of characters to use for indentation of ObjC blocks. + unsigned ObjCBlockIndentWidth; + + /// \brief Add a space after \c @property in Objective-C, i.e. use + /// <tt>\@property (readonly)</tt> instead of <tt>\@property(readonly)</tt>. + bool ObjCSpaceAfterProperty; + + /// \brief Add a space in front of an Objective-C protocol list, i.e. use + /// <tt>Foo <Protocol></tt> instead of \c Foo<Protocol>. + bool ObjCSpaceBeforeProtocolList; + + /// \brief The penalty for breaking a function call after "call(". + unsigned PenaltyBreakBeforeFirstCallParameter; + + /// \brief The penalty for each line break introduced inside a comment. + unsigned PenaltyBreakComment; + + /// \brief The penalty for breaking before the first \c <<. + unsigned PenaltyBreakFirstLessLess; + + /// \brief The penalty for each line break introduced inside a string literal. + unsigned PenaltyBreakString; + + /// \brief The penalty for each character outside of the column limit. + unsigned PenaltyExcessCharacter; + + /// \brief Penalty for putting the return type of a function onto its own + /// line. + unsigned PenaltyReturnTypeOnItsOwnLine; + + /// \brief The & and * alignment style. + enum PointerAlignmentStyle { + /// Align pointer to the left. + PAS_Left, + /// Align pointer to the right. + PAS_Right, + /// Align pointer in the middle. + PAS_Middle + }; + + /// \brief Pointer and reference alignment style. + PointerAlignmentStyle PointerAlignment; + + /// \brief If true, clang-format will attempt to re-flow comments. + bool ReflowComments; + + /// \brief If true, clang-format will sort #includes. + bool SortIncludes; + + /// \brief If \c true, a space may be inserted after C style casts. + bool SpaceAfterCStyleCast; + + /// \brief If \c false, spaces will be removed before assignment operators. + bool SpaceBeforeAssignmentOperators; + + /// \brief Different ways to put a space before opening parentheses. + enum SpaceBeforeParensOptions { + /// Never put a space before opening parentheses. + SBPO_Never, + /// Put a space before opening parentheses only after control statement + /// keywords (<tt>for/if/while...</tt>). + SBPO_ControlStatements, + /// Always put a space before opening parentheses, except when it's + /// prohibited by the syntax rules (in function-like macro definitions) or + /// when determined by other style rules (after unary operators, opening + /// parentheses, etc.) + SBPO_Always + }; + + /// \brief Defines in which cases to put a space before opening parentheses. + SpaceBeforeParensOptions SpaceBeforeParens; + + /// \brief If \c true, spaces may be inserted into '()'. + bool SpaceInEmptyParentheses; + + /// \brief The number of spaces before trailing line comments + /// (\c // - comments). + /// + /// This does not affect trailing block comments (\c /**/ - comments) as those + /// commonly have different usage patterns and a number of special cases. + unsigned SpacesBeforeTrailingComments; + + /// \brief If \c true, spaces will be inserted after '<' and before '>' in + /// template argument lists + bool SpacesInAngles; + + /// \brief If \c true, spaces are inserted inside container literals (e.g. + /// ObjC and Javascript array and dict literals). + bool SpacesInContainerLiterals; + + /// \brief If \c true, spaces may be inserted into C style casts. + bool SpacesInCStyleCastParentheses; + + /// \brief If \c true, spaces will be inserted after '(' and before ')'. + bool SpacesInParentheses; + + /// \brief If \c true, spaces will be inserted after '[' and before ']'. + bool SpacesInSquareBrackets; + + /// \brief Supported language standards. + enum LanguageStandard { + /// Use C++03-compatible syntax. + LS_Cpp03, + /// Use features of C++11 (e.g. \c A<A<int>> instead of + /// <tt>A<A<int> ></tt>). + LS_Cpp11, + /// Automatic detection based on the input. + LS_Auto + }; + + /// \brief Format compatible with this standard, e.g. use + /// <tt>A<A<int> ></tt> instead of \c A<A<int>> for LS_Cpp03. + LanguageStandard Standard; + + /// \brief The number of columns used for tab stops. + unsigned TabWidth; + + /// \brief Different ways to use tab in formatting. + enum UseTabStyle { + /// Never use tab. + UT_Never, + /// Use tabs only for indentation. + UT_ForIndentation, + /// Use tabs whenever we need to fill whitespace that spans at least from + /// one tab stop to the next one. + UT_Always + }; + + /// \brief The way to use tab characters in the resulting file. + UseTabStyle UseTab; + + bool operator==(const FormatStyle &R) const { + return AccessModifierOffset == R.AccessModifierOffset && + AlignAfterOpenBracket == R.AlignAfterOpenBracket && + AlignConsecutiveAssignments == R.AlignConsecutiveAssignments && + AlignConsecutiveDeclarations == R.AlignConsecutiveDeclarations && + AlignEscapedNewlinesLeft == R.AlignEscapedNewlinesLeft && + AlignOperands == R.AlignOperands && + AlignTrailingComments == R.AlignTrailingComments && + AllowAllParametersOfDeclarationOnNextLine == + R.AllowAllParametersOfDeclarationOnNextLine && + AllowShortBlocksOnASingleLine == R.AllowShortBlocksOnASingleLine && + AllowShortCaseLabelsOnASingleLine == + R.AllowShortCaseLabelsOnASingleLine && + AllowShortFunctionsOnASingleLine == + R.AllowShortFunctionsOnASingleLine && + AllowShortIfStatementsOnASingleLine == + R.AllowShortIfStatementsOnASingleLine && + AllowShortLoopsOnASingleLine == R.AllowShortLoopsOnASingleLine && + AlwaysBreakAfterReturnType == R.AlwaysBreakAfterReturnType && + AlwaysBreakBeforeMultilineStrings == + R.AlwaysBreakBeforeMultilineStrings && + AlwaysBreakTemplateDeclarations == + R.AlwaysBreakTemplateDeclarations && + BinPackArguments == R.BinPackArguments && + BinPackParameters == R.BinPackParameters && + BreakBeforeBinaryOperators == R.BreakBeforeBinaryOperators && + BreakBeforeBraces == R.BreakBeforeBraces && + BreakBeforeTernaryOperators == R.BreakBeforeTernaryOperators && + BreakConstructorInitializersBeforeComma == + R.BreakConstructorInitializersBeforeComma && + BreakAfterJavaFieldAnnotations == R.BreakAfterJavaFieldAnnotations && + ColumnLimit == R.ColumnLimit && CommentPragmas == R.CommentPragmas && + ConstructorInitializerAllOnOneLineOrOnePerLine == + R.ConstructorInitializerAllOnOneLineOrOnePerLine && + ConstructorInitializerIndentWidth == + R.ConstructorInitializerIndentWidth && + ContinuationIndentWidth == R.ContinuationIndentWidth && + Cpp11BracedListStyle == R.Cpp11BracedListStyle && + DerivePointerAlignment == R.DerivePointerAlignment && + DisableFormat == R.DisableFormat && + ExperimentalAutoDetectBinPacking == + R.ExperimentalAutoDetectBinPacking && + ForEachMacros == R.ForEachMacros && + IncludeCategories == R.IncludeCategories && + IndentCaseLabels == R.IndentCaseLabels && + IndentWidth == R.IndentWidth && Language == R.Language && + IndentWrappedFunctionNames == R.IndentWrappedFunctionNames && + KeepEmptyLinesAtTheStartOfBlocks == + R.KeepEmptyLinesAtTheStartOfBlocks && + MacroBlockBegin == R.MacroBlockBegin && + MacroBlockEnd == R.MacroBlockEnd && + MaxEmptyLinesToKeep == R.MaxEmptyLinesToKeep && + NamespaceIndentation == R.NamespaceIndentation && + ObjCBlockIndentWidth == R.ObjCBlockIndentWidth && + ObjCSpaceAfterProperty == R.ObjCSpaceAfterProperty && + ObjCSpaceBeforeProtocolList == R.ObjCSpaceBeforeProtocolList && + PenaltyBreakBeforeFirstCallParameter == + R.PenaltyBreakBeforeFirstCallParameter && + PenaltyBreakComment == R.PenaltyBreakComment && + PenaltyBreakFirstLessLess == R.PenaltyBreakFirstLessLess && + PenaltyBreakString == R.PenaltyBreakString && + PenaltyExcessCharacter == R.PenaltyExcessCharacter && + PenaltyReturnTypeOnItsOwnLine == R.PenaltyReturnTypeOnItsOwnLine && + PointerAlignment == R.PointerAlignment && + SpaceAfterCStyleCast == R.SpaceAfterCStyleCast && + SpaceBeforeAssignmentOperators == R.SpaceBeforeAssignmentOperators && + SpaceBeforeParens == R.SpaceBeforeParens && + SpaceInEmptyParentheses == R.SpaceInEmptyParentheses && + SpacesBeforeTrailingComments == R.SpacesBeforeTrailingComments && + SpacesInAngles == R.SpacesInAngles && + SpacesInContainerLiterals == R.SpacesInContainerLiterals && + SpacesInCStyleCastParentheses == R.SpacesInCStyleCastParentheses && + SpacesInParentheses == R.SpacesInParentheses && + SpacesInSquareBrackets == R.SpacesInSquareBrackets && + Standard == R.Standard && TabWidth == R.TabWidth && + UseTab == R.UseTab; + } +}; + +/// \brief Returns a format style complying with the LLVM coding standards: +/// http://llvm.org/docs/CodingStandards.html. +FormatStyle getLLVMStyle(); + +/// \brief Returns a format style complying with one of Google's style guides: +/// http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml. +/// http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml. +/// https://developers.google.com/protocol-buffers/docs/style. +FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language); + +/// \brief Returns a format style complying with Chromium's style guide: +/// http://www.chromium.org/developers/coding-style. +FormatStyle getChromiumStyle(FormatStyle::LanguageKind Language); + +/// \brief Returns a format style complying with Mozilla's style guide: +/// https://developer.mozilla.org/en-US/docs/Developer_Guide/Coding_Style. +FormatStyle getMozillaStyle(); + +/// \brief Returns a format style complying with Webkit's style guide: +/// http://www.webkit.org/coding/coding-style.html +FormatStyle getWebKitStyle(); + +/// \brief Returns a format style complying with GNU Coding Standards: +/// http://www.gnu.org/prep/standards/standards.html +FormatStyle getGNUStyle(); + +/// \brief Returns style indicating formatting should be not applied at all. +FormatStyle getNoStyle(); + +/// \brief Gets a predefined style for the specified language by name. +/// +/// Currently supported names: LLVM, Google, Chromium, Mozilla. Names are +/// compared case-insensitively. +/// +/// Returns \c true if the Style has been set. +bool getPredefinedStyle(StringRef Name, FormatStyle::LanguageKind Language, + FormatStyle *Style); + +/// \brief Parse configuration from YAML-formatted text. +/// +/// Style->Language is used to get the base style, if the \c BasedOnStyle +/// option is present. +/// +/// When \c BasedOnStyle is not present, options not present in the YAML +/// document, are retained in \p Style. +std::error_code parseConfiguration(StringRef Text, FormatStyle *Style); + +/// \brief Gets configuration in a YAML string. +std::string configurationAsText(const FormatStyle &Style); + +/// \brief Returns the replacements necessary to sort all #include blocks that +/// are affected by 'Ranges'. +tooling::Replacements sortIncludes(const FormatStyle &Style, StringRef Code, + ArrayRef<tooling::Range> Ranges, + StringRef FileName, + unsigned *Cursor = nullptr); + +/// \brief Reformats the given \p Ranges in the file \p ID. +/// +/// Each range is extended on either end to its next bigger logic unit, i.e. +/// everything that might influence its formatting or might be influenced by its +/// formatting. +/// +/// Returns the \c Replacements necessary to make all \p Ranges comply with +/// \p Style. +/// +/// If \c IncompleteFormat is non-null, its value will be set to true if any +/// of the affected ranges were not formatted due to a non-recoverable syntax +/// error. +tooling::Replacements reformat(const FormatStyle &Style, + SourceManager &SourceMgr, FileID ID, + ArrayRef<CharSourceRange> Ranges, + bool *IncompleteFormat = nullptr); + +/// \brief Reformats the given \p Ranges in \p Code. +/// +/// Otherwise identical to the reformat() function using a file ID. +tooling::Replacements reformat(const FormatStyle &Style, StringRef Code, + ArrayRef<tooling::Range> Ranges, + StringRef FileName = "<stdin>", + bool *IncompleteFormat = nullptr); + +/// \brief Returns the \c LangOpts that the formatter expects you to set. +/// +/// \param Style determines specific settings for lexing mode. +LangOptions getFormattingLangOpts(const FormatStyle &Style = getLLVMStyle()); + +/// \brief Description to be used for help text for a llvm::cl option for +/// specifying format style. The description is closely related to the operation +/// of getStyle(). +extern const char *StyleOptionHelpDescription; + +/// \brief Construct a FormatStyle based on \c StyleName. +/// +/// \c StyleName can take several forms: +/// \li "{<key>: <value>, ...}" - Set specic style parameters. +/// \li "<style name>" - One of the style names supported by +/// getPredefinedStyle(). +/// \li "file" - Load style configuration from a file called '.clang-format' +/// located in one of the parent directories of \c FileName or the current +/// directory if \c FileName is empty. +/// +/// \param[in] StyleName Style name to interpret according to the description +/// above. +/// \param[in] FileName Path to start search for .clang-format if \c StyleName +/// == "file". +/// \param[in] FallbackStyle The name of a predefined style used to fallback to +/// in case the style can't be determined from \p StyleName. +/// +/// \returns FormatStyle as specified by \c StyleName. If no style could be +/// determined, the default is LLVM Style (see getLLVMStyle()). +FormatStyle getStyle(StringRef StyleName, StringRef FileName, + StringRef FallbackStyle); + +} // end namespace format +} // end namespace clang + +namespace std { +template <> +struct is_error_code_enum<clang::format::ParseError> : std::true_type {}; +} + +#endif // LLVM_CLANG_FORMAT_FORMAT_H diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/ASTConsumers.h b/contrib/llvm/tools/clang/include/clang/Frontend/ASTConsumers.h new file mode 100644 index 0000000..757fcae --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Frontend/ASTConsumers.h @@ -0,0 +1,58 @@ +//===--- ASTConsumers.h - ASTConsumer implementations -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// AST Consumers. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_ASTCONSUMERS_H +#define LLVM_CLANG_FRONTEND_ASTCONSUMERS_H + +#include "clang/Basic/LLVM.h" +#include <memory> + +namespace clang { + +class ASTConsumer; +class CodeGenOptions; +class DiagnosticsEngine; +class FileManager; +class LangOptions; +class Preprocessor; +class TargetOptions; + +// AST pretty-printer: prints out the AST in a format that is close to the +// original C code. The output is intended to be in a format such that +// clang could re-parse the output back into the same AST, but the +// implementation is still incomplete. +std::unique_ptr<ASTConsumer> CreateASTPrinter(raw_ostream *OS, + StringRef FilterString); + +// AST dumper: dumps the raw AST in human-readable form to stderr; this is +// intended for debugging. +std::unique_ptr<ASTConsumer> CreateASTDumper(StringRef FilterString, + bool DumpDecls, + bool DumpLookups); + +// AST Decl node lister: prints qualified names of all filterable AST Decl +// nodes. +std::unique_ptr<ASTConsumer> CreateASTDeclNodeLister(); + +// Graphical AST viewer: for each function definition, creates a graph of +// the AST and displays it with the graph viewer "dotty". Also outputs +// function declarations to stderr. +std::unique_ptr<ASTConsumer> CreateASTViewer(); + +// DeclContext printer: prints out the DeclContext tree in human-readable form +// to stderr; this is intended for debugging. +std::unique_ptr<ASTConsumer> CreateDeclContextPrinter(); + +} // end clang namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/ASTUnit.h b/contrib/llvm/tools/clang/include/clang/Frontend/ASTUnit.h new file mode 100644 index 0000000..a5f7af5 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Frontend/ASTUnit.h @@ -0,0 +1,924 @@ +//===--- ASTUnit.h - ASTUnit utility ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// ASTUnit utility class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_ASTUNIT_H +#define LLVM_CLANG_FRONTEND_ASTUNIT_H + +#include "clang-c/Index.h" +#include "clang/AST/ASTContext.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/FileSystemOptions.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetOptions.h" +#include "clang/Lex/HeaderSearchOptions.h" +#include "clang/Lex/ModuleLoader.h" +#include "clang/Lex/PreprocessingRecord.h" +#include "clang/Sema/CodeCompleteConsumer.h" +#include "clang/Serialization/ASTBitCodes.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/MD5.h" +#include "llvm/Support/Path.h" +#include <cassert> +#include <map> +#include <memory> +#include <string> +#include <sys/types.h> +#include <utility> +#include <vector> + +namespace llvm { + class MemoryBuffer; +} + +namespace clang { +class Sema; +class ASTContext; +class ASTReader; +class CodeCompleteConsumer; +class CompilerInvocation; +class CompilerInstance; +class Decl; +class DiagnosticsEngine; +class FileEntry; +class FileManager; +class HeaderSearch; +class Preprocessor; +class PCHContainerOperations; +class PCHContainerReader; +class SourceManager; +class TargetInfo; +class ASTFrontendAction; +class ASTDeserializationListener; + +/// \brief Utility class for loading a ASTContext from an AST file. +/// +class ASTUnit : public ModuleLoader { +public: + struct StandaloneFixIt { + std::pair<unsigned, unsigned> RemoveRange; + std::pair<unsigned, unsigned> InsertFromRange; + std::string CodeToInsert; + bool BeforePreviousInsertions; + }; + + struct StandaloneDiagnostic { + unsigned ID; + DiagnosticsEngine::Level Level; + std::string Message; + std::string Filename; + unsigned LocOffset; + std::vector<std::pair<unsigned, unsigned> > Ranges; + std::vector<StandaloneFixIt> FixIts; + }; + +private: + std::shared_ptr<LangOptions> LangOpts; + IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics; + IntrusiveRefCntPtr<FileManager> FileMgr; + IntrusiveRefCntPtr<SourceManager> SourceMgr; + std::unique_ptr<HeaderSearch> HeaderInfo; + IntrusiveRefCntPtr<TargetInfo> Target; + IntrusiveRefCntPtr<Preprocessor> PP; + IntrusiveRefCntPtr<ASTContext> Ctx; + std::shared_ptr<TargetOptions> TargetOpts; + IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts; + IntrusiveRefCntPtr<ASTReader> Reader; + bool HadModuleLoaderFatalFailure; + + struct ASTWriterData; + std::unique_ptr<ASTWriterData> WriterData; + + FileSystemOptions FileSystemOpts; + + /// \brief The AST consumer that received information about the translation + /// unit as it was parsed or loaded. + std::unique_ptr<ASTConsumer> Consumer; + + /// \brief The semantic analysis object used to type-check the translation + /// unit. + std::unique_ptr<Sema> TheSema; + + /// Optional owned invocation, just used to make the invocation used in + /// LoadFromCommandLine available. + IntrusiveRefCntPtr<CompilerInvocation> Invocation; + + // OnlyLocalDecls - when true, walking this AST should only visit declarations + // that come from the AST itself, not from included precompiled headers. + // FIXME: This is temporary; eventually, CIndex will always do this. + bool OnlyLocalDecls; + + /// \brief Whether to capture any diagnostics produced. + bool CaptureDiagnostics; + + /// \brief Track whether the main file was loaded from an AST or not. + bool MainFileIsAST; + + /// \brief What kind of translation unit this AST represents. + TranslationUnitKind TUKind; + + /// \brief Whether we should time each operation. + bool WantTiming; + + /// \brief Whether the ASTUnit should delete the remapped buffers. + bool OwnsRemappedFileBuffers; + + /// Track the top-level decls which appeared in an ASTUnit which was loaded + /// from a source file. + // + // FIXME: This is just an optimization hack to avoid deserializing large parts + // of a PCH file when using the Index library on an ASTUnit loaded from + // source. In the long term we should make the Index library use efficient and + // more scalable search mechanisms. + std::vector<Decl*> TopLevelDecls; + + /// \brief Sorted (by file offset) vector of pairs of file offset/Decl. + typedef SmallVector<std::pair<unsigned, Decl *>, 64> LocDeclsTy; + typedef llvm::DenseMap<FileID, LocDeclsTy *> FileDeclsTy; + + /// \brief Map from FileID to the file-level declarations that it contains. + /// The files and decls are only local (and non-preamble) ones. + FileDeclsTy FileDecls; + + /// The name of the original source file used to generate this ASTUnit. + std::string OriginalSourceFile; + + /// \brief The set of diagnostics produced when creating the preamble. + SmallVector<StandaloneDiagnostic, 4> PreambleDiagnostics; + + /// \brief The set of diagnostics produced when creating this + /// translation unit. + SmallVector<StoredDiagnostic, 4> StoredDiagnostics; + + /// \brief The set of diagnostics produced when failing to parse, e.g. due + /// to failure to load the PCH. + SmallVector<StoredDiagnostic, 4> FailedParseDiagnostics; + + /// \brief The number of stored diagnostics that come from the driver + /// itself. + /// + /// Diagnostics that come from the driver are retained from one parse to + /// the next. + unsigned NumStoredDiagnosticsFromDriver; + + /// \brief Counter that determines when we want to try building a + /// precompiled preamble. + /// + /// If zero, we will never build a precompiled preamble. Otherwise, + /// it's treated as a counter that decrements each time we reparse + /// without the benefit of a precompiled preamble. When it hits 1, + /// we'll attempt to rebuild the precompiled header. This way, if + /// building the precompiled preamble fails, we won't try again for + /// some number of calls. + unsigned PreambleRebuildCounter; + +public: + class PreambleData { + const FileEntry *File; + std::vector<char> Buffer; + mutable unsigned NumLines; + + public: + PreambleData() : File(nullptr), NumLines(0) { } + + void assign(const FileEntry *F, const char *begin, const char *end) { + File = F; + Buffer.assign(begin, end); + NumLines = 0; + } + + void clear() { Buffer.clear(); File = nullptr; NumLines = 0; } + + size_t size() const { return Buffer.size(); } + bool empty() const { return Buffer.empty(); } + + const char *getBufferStart() const { return &Buffer[0]; } + + unsigned getNumLines() const { + if (NumLines) + return NumLines; + countLines(); + return NumLines; + } + + SourceRange getSourceRange(const SourceManager &SM) const { + SourceLocation FileLoc = SM.getLocForStartOfFile(SM.getPreambleFileID()); + return SourceRange(FileLoc, FileLoc.getLocWithOffset(size()-1)); + } + + private: + void countLines() const; + }; + + const PreambleData &getPreambleData() const { + return Preamble; + } + + /// Data used to determine if a file used in the preamble has been changed. + struct PreambleFileHash { + /// All files have size set. + off_t Size; + + /// Modification time is set for files that are on disk. For memory + /// buffers it is zero. + time_t ModTime; + + /// Memory buffers have MD5 instead of modification time. We don't + /// compute MD5 for on-disk files because we hope that modification time is + /// enough to tell if the file was changed. + llvm::MD5::MD5Result MD5; + + static PreambleFileHash createForFile(off_t Size, time_t ModTime); + static PreambleFileHash + createForMemoryBuffer(const llvm::MemoryBuffer *Buffer); + + friend bool operator==(const PreambleFileHash &LHS, + const PreambleFileHash &RHS); + + friend bool operator!=(const PreambleFileHash &LHS, + const PreambleFileHash &RHS) { + return !(LHS == RHS); + } + }; + +private: + /// \brief The contents of the preamble that has been precompiled to + /// \c PreambleFile. + PreambleData Preamble; + + /// \brief Whether the preamble ends at the start of a new line. + /// + /// Used to inform the lexer as to whether it's starting at the beginning of + /// a line after skipping the preamble. + bool PreambleEndsAtStartOfLine; + + /// \brief Keeps track of the files that were used when computing the + /// preamble, with both their buffer size and their modification time. + /// + /// If any of the files have changed from one compile to the next, + /// the preamble must be thrown away. + llvm::StringMap<PreambleFileHash> FilesInPreamble; + + /// \brief When non-NULL, this is the buffer used to store the contents of + /// the main file when it has been padded for use with the precompiled + /// preamble. + std::unique_ptr<llvm::MemoryBuffer> SavedMainFileBuffer; + + /// \brief When non-NULL, this is the buffer used to store the + /// contents of the preamble when it has been padded to build the + /// precompiled preamble. + std::unique_ptr<llvm::MemoryBuffer> PreambleBuffer; + + /// \brief The number of warnings that occurred while parsing the preamble. + /// + /// This value will be used to restore the state of the \c DiagnosticsEngine + /// object when re-using the precompiled preamble. Note that only the + /// number of warnings matters, since we will not save the preamble + /// when any errors are present. + unsigned NumWarningsInPreamble; + + /// \brief A list of the serialization ID numbers for each of the top-level + /// declarations parsed within the precompiled preamble. + std::vector<serialization::DeclID> TopLevelDeclsInPreamble; + + /// \brief Whether we should be caching code-completion results. + bool ShouldCacheCodeCompletionResults : 1; + + /// \brief Whether to include brief documentation within the set of code + /// completions cached. + bool IncludeBriefCommentsInCodeCompletion : 1; + + /// \brief True if non-system source files should be treated as volatile + /// (likely to change while trying to use them). + bool UserFilesAreVolatile : 1; + + /// \brief The language options used when we load an AST file. + LangOptions ASTFileLangOpts; + + static void ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> Diags, + ASTUnit &AST, bool CaptureDiagnostics); + + void TranslateStoredDiagnostics(FileManager &FileMgr, + SourceManager &SrcMan, + const SmallVectorImpl<StandaloneDiagnostic> &Diags, + SmallVectorImpl<StoredDiagnostic> &Out); + + void clearFileLevelDecls(); + +public: + /// \brief A cached code-completion result, which may be introduced in one of + /// many different contexts. + struct CachedCodeCompletionResult { + /// \brief The code-completion string corresponding to this completion + /// result. + CodeCompletionString *Completion; + + /// \brief A bitmask that indicates which code-completion contexts should + /// contain this completion result. + /// + /// The bits in the bitmask correspond to the values of + /// CodeCompleteContext::Kind. To map from a completion context kind to a + /// bit, shift 1 by that number of bits. Many completions can occur in + /// several different contexts. + uint64_t ShowInContexts; + + /// \brief The priority given to this code-completion result. + unsigned Priority; + + /// \brief The libclang cursor kind corresponding to this code-completion + /// result. + CXCursorKind Kind; + + /// \brief The availability of this code-completion result. + CXAvailabilityKind Availability; + + /// \brief The simplified type class for a non-macro completion result. + SimplifiedTypeClass TypeClass; + + /// \brief The type of a non-macro completion result, stored as a unique + /// integer used by the string map of cached completion types. + /// + /// This value will be zero if the type is not known, or a unique value + /// determined by the formatted type string. Se \c CachedCompletionTypes + /// for more information. + unsigned Type; + }; + + /// \brief Retrieve the mapping from formatted type names to unique type + /// identifiers. + llvm::StringMap<unsigned> &getCachedCompletionTypes() { + return CachedCompletionTypes; + } + + /// \brief Retrieve the allocator used to cache global code completions. + IntrusiveRefCntPtr<GlobalCodeCompletionAllocator> + getCachedCompletionAllocator() { + return CachedCompletionAllocator; + } + + CodeCompletionTUInfo &getCodeCompletionTUInfo() { + if (!CCTUInfo) + CCTUInfo.reset(new CodeCompletionTUInfo( + new GlobalCodeCompletionAllocator)); + return *CCTUInfo; + } + +private: + /// \brief Allocator used to store cached code completions. + IntrusiveRefCntPtr<GlobalCodeCompletionAllocator> + CachedCompletionAllocator; + + std::unique_ptr<CodeCompletionTUInfo> CCTUInfo; + + /// \brief The set of cached code-completion results. + std::vector<CachedCodeCompletionResult> CachedCompletionResults; + + /// \brief A mapping from the formatted type name to a unique number for that + /// type, which is used for type equality comparisons. + llvm::StringMap<unsigned> CachedCompletionTypes; + + /// \brief A string hash of the top-level declaration and macro definition + /// names processed the last time that we reparsed the file. + /// + /// This hash value is used to determine when we need to refresh the + /// global code-completion cache. + unsigned CompletionCacheTopLevelHashValue; + + /// \brief A string hash of the top-level declaration and macro definition + /// names processed the last time that we reparsed the precompiled preamble. + /// + /// This hash value is used to determine when we need to refresh the + /// global code-completion cache after a rebuild of the precompiled preamble. + unsigned PreambleTopLevelHashValue; + + /// \brief The current hash value for the top-level declaration and macro + /// definition names + unsigned CurrentTopLevelHashValue; + + /// \brief Bit used by CIndex to mark when a translation unit may be in an + /// inconsistent state, and is not safe to free. + unsigned UnsafeToFree : 1; + + /// \brief Cache any "global" code-completion results, so that we can avoid + /// recomputing them with each completion. + void CacheCodeCompletionResults(); + + /// \brief Clear out and deallocate + void ClearCachedCompletionResults(); + + ASTUnit(const ASTUnit &) = delete; + void operator=(const ASTUnit &) = delete; + + explicit ASTUnit(bool MainFileIsAST); + + void CleanTemporaryFiles(); + bool Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps, + std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer); + + struct ComputedPreamble { + llvm::MemoryBuffer *Buffer; + std::unique_ptr<llvm::MemoryBuffer> Owner; + unsigned Size; + bool PreambleEndsAtStartOfLine; + ComputedPreamble(llvm::MemoryBuffer *Buffer, + std::unique_ptr<llvm::MemoryBuffer> Owner, unsigned Size, + bool PreambleEndsAtStartOfLine) + : Buffer(Buffer), Owner(std::move(Owner)), Size(Size), + PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {} + ComputedPreamble(ComputedPreamble &&C) + : Buffer(C.Buffer), Owner(std::move(C.Owner)), Size(C.Size), + PreambleEndsAtStartOfLine(C.PreambleEndsAtStartOfLine) {} + }; + ComputedPreamble ComputePreamble(CompilerInvocation &Invocation, + unsigned MaxLines); + + std::unique_ptr<llvm::MemoryBuffer> getMainBufferWithPrecompiledPreamble( + std::shared_ptr<PCHContainerOperations> PCHContainerOps, + const CompilerInvocation &PreambleInvocationIn, bool AllowRebuild = true, + unsigned MaxLines = 0); + void RealizeTopLevelDeclsFromPreamble(); + + /// \brief Transfers ownership of the objects (like SourceManager) from + /// \param CI to this ASTUnit. + void transferASTDataFromCompilerInstance(CompilerInstance &CI); + + /// \brief Allows us to assert that ASTUnit is not being used concurrently, + /// which is not supported. + /// + /// Clients should create instances of the ConcurrencyCheck class whenever + /// using the ASTUnit in a way that isn't intended to be concurrent, which is + /// just about any usage. + /// Becomes a noop in release mode; only useful for debug mode checking. + class ConcurrencyState { + void *Mutex; // a llvm::sys::MutexImpl in debug; + + public: + ConcurrencyState(); + ~ConcurrencyState(); + + void start(); + void finish(); + }; + ConcurrencyState ConcurrencyCheckValue; + +public: + class ConcurrencyCheck { + ASTUnit &Self; + + public: + explicit ConcurrencyCheck(ASTUnit &Self) + : Self(Self) + { + Self.ConcurrencyCheckValue.start(); + } + ~ConcurrencyCheck() { + Self.ConcurrencyCheckValue.finish(); + } + }; + friend class ConcurrencyCheck; + + ~ASTUnit() override; + + bool isMainFileAST() const { return MainFileIsAST; } + + bool isUnsafeToFree() const { return UnsafeToFree; } + void setUnsafeToFree(bool Value) { UnsafeToFree = Value; } + + const DiagnosticsEngine &getDiagnostics() const { return *Diagnostics; } + DiagnosticsEngine &getDiagnostics() { return *Diagnostics; } + + const SourceManager &getSourceManager() const { return *SourceMgr; } + SourceManager &getSourceManager() { return *SourceMgr; } + + const Preprocessor &getPreprocessor() const { return *PP; } + Preprocessor &getPreprocessor() { return *PP; } + + const ASTContext &getASTContext() const { return *Ctx; } + ASTContext &getASTContext() { return *Ctx; } + + void setASTContext(ASTContext *ctx) { Ctx = ctx; } + void setPreprocessor(Preprocessor *pp); + + bool hasSema() const { return (bool)TheSema; } + Sema &getSema() const { + assert(TheSema && "ASTUnit does not have a Sema object!"); + return *TheSema; + } + + const LangOptions &getLangOpts() const { + assert(LangOpts && " ASTUnit does not have language options"); + return *LangOpts; + } + + const FileManager &getFileManager() const { return *FileMgr; } + FileManager &getFileManager() { return *FileMgr; } + + const FileSystemOptions &getFileSystemOpts() const { return FileSystemOpts; } + + StringRef getOriginalSourceFileName() { + return OriginalSourceFile; + } + + ASTMutationListener *getASTMutationListener(); + ASTDeserializationListener *getDeserializationListener(); + + /// \brief Add a temporary file that the ASTUnit depends on. + /// + /// This file will be erased when the ASTUnit is destroyed. + void addTemporaryFile(StringRef TempFile); + + bool getOnlyLocalDecls() const { return OnlyLocalDecls; } + + bool getOwnsRemappedFileBuffers() const { return OwnsRemappedFileBuffers; } + void setOwnsRemappedFileBuffers(bool val) { OwnsRemappedFileBuffers = val; } + + StringRef getMainFileName() const; + + /// \brief If this ASTUnit came from an AST file, returns the filename for it. + StringRef getASTFileName() const; + + typedef std::vector<Decl *>::iterator top_level_iterator; + + top_level_iterator top_level_begin() { + assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!"); + if (!TopLevelDeclsInPreamble.empty()) + RealizeTopLevelDeclsFromPreamble(); + return TopLevelDecls.begin(); + } + + top_level_iterator top_level_end() { + assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!"); + if (!TopLevelDeclsInPreamble.empty()) + RealizeTopLevelDeclsFromPreamble(); + return TopLevelDecls.end(); + } + + std::size_t top_level_size() const { + assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!"); + return TopLevelDeclsInPreamble.size() + TopLevelDecls.size(); + } + + bool top_level_empty() const { + assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!"); + return TopLevelDeclsInPreamble.empty() && TopLevelDecls.empty(); + } + + /// \brief Add a new top-level declaration. + void addTopLevelDecl(Decl *D) { + TopLevelDecls.push_back(D); + } + + /// \brief Add a new local file-level declaration. + void addFileLevelDecl(Decl *D); + + /// \brief Get the decls that are contained in a file in the Offset/Length + /// range. \p Length can be 0 to indicate a point at \p Offset instead of + /// a range. + void findFileRegionDecls(FileID File, unsigned Offset, unsigned Length, + SmallVectorImpl<Decl *> &Decls); + + /// \brief Add a new top-level declaration, identified by its ID in + /// the precompiled preamble. + void addTopLevelDeclFromPreamble(serialization::DeclID D) { + TopLevelDeclsInPreamble.push_back(D); + } + + /// \brief Retrieve a reference to the current top-level name hash value. + /// + /// Note: This is used internally by the top-level tracking action + unsigned &getCurrentTopLevelHashValue() { return CurrentTopLevelHashValue; } + + /// \brief Get the source location for the given file:line:col triplet. + /// + /// The difference with SourceManager::getLocation is that this method checks + /// whether the requested location points inside the precompiled preamble + /// in which case the returned source location will be a "loaded" one. + SourceLocation getLocation(const FileEntry *File, + unsigned Line, unsigned Col) const; + + /// \brief Get the source location for the given file:offset pair. + SourceLocation getLocation(const FileEntry *File, unsigned Offset) const; + + /// \brief If \p Loc is a loaded location from the preamble, returns + /// the corresponding local location of the main file, otherwise it returns + /// \p Loc. + SourceLocation mapLocationFromPreamble(SourceLocation Loc); + + /// \brief If \p Loc is a local location of the main file but inside the + /// preamble chunk, returns the corresponding loaded location from the + /// preamble, otherwise it returns \p Loc. + SourceLocation mapLocationToPreamble(SourceLocation Loc); + + bool isInPreambleFileID(SourceLocation Loc); + bool isInMainFileID(SourceLocation Loc); + SourceLocation getStartOfMainFileID(); + SourceLocation getEndOfPreambleFileID(); + + /// \see mapLocationFromPreamble. + SourceRange mapRangeFromPreamble(SourceRange R) { + return SourceRange(mapLocationFromPreamble(R.getBegin()), + mapLocationFromPreamble(R.getEnd())); + } + + /// \see mapLocationToPreamble. + SourceRange mapRangeToPreamble(SourceRange R) { + return SourceRange(mapLocationToPreamble(R.getBegin()), + mapLocationToPreamble(R.getEnd())); + } + + // Retrieve the diagnostics associated with this AST + typedef StoredDiagnostic *stored_diag_iterator; + typedef const StoredDiagnostic *stored_diag_const_iterator; + stored_diag_const_iterator stored_diag_begin() const { + return StoredDiagnostics.begin(); + } + stored_diag_iterator stored_diag_begin() { + return StoredDiagnostics.begin(); + } + stored_diag_const_iterator stored_diag_end() const { + return StoredDiagnostics.end(); + } + stored_diag_iterator stored_diag_end() { + return StoredDiagnostics.end(); + } + unsigned stored_diag_size() const { return StoredDiagnostics.size(); } + + stored_diag_iterator stored_diag_afterDriver_begin() { + if (NumStoredDiagnosticsFromDriver > StoredDiagnostics.size()) + NumStoredDiagnosticsFromDriver = 0; + return StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver; + } + + typedef std::vector<CachedCodeCompletionResult>::iterator + cached_completion_iterator; + + cached_completion_iterator cached_completion_begin() { + return CachedCompletionResults.begin(); + } + + cached_completion_iterator cached_completion_end() { + return CachedCompletionResults.end(); + } + + unsigned cached_completion_size() const { + return CachedCompletionResults.size(); + } + + /// \brief Returns an iterator range for the local preprocessing entities + /// of the local Preprocessor, if this is a parsed source file, or the loaded + /// preprocessing entities of the primary module if this is an AST file. + llvm::iterator_range<PreprocessingRecord::iterator> + getLocalPreprocessingEntities() const; + + /// \brief Type for a function iterating over a number of declarations. + /// \returns true to continue iteration and false to abort. + typedef bool (*DeclVisitorFn)(void *context, const Decl *D); + + /// \brief Iterate over local declarations (locally parsed if this is a parsed + /// source file or the loaded declarations of the primary module if this is an + /// AST file). + /// \returns true if the iteration was complete or false if it was aborted. + bool visitLocalTopLevelDecls(void *context, DeclVisitorFn Fn); + + /// \brief Get the PCH file if one was included. + const FileEntry *getPCHFile(); + + /// \brief Returns true if the ASTUnit was constructed from a serialized + /// module file. + bool isModuleFile(); + + std::unique_ptr<llvm::MemoryBuffer> + getBufferForFile(StringRef Filename, std::string *ErrorStr = nullptr); + + /// \brief Determine what kind of translation unit this AST represents. + TranslationUnitKind getTranslationUnitKind() const { return TUKind; } + + /// \brief A mapping from a file name to the memory buffer that stores the + /// remapped contents of that file. + typedef std::pair<std::string, llvm::MemoryBuffer *> RemappedFile; + + /// \brief Create a ASTUnit. Gets ownership of the passed CompilerInvocation. + static ASTUnit *create(CompilerInvocation *CI, + IntrusiveRefCntPtr<DiagnosticsEngine> Diags, + bool CaptureDiagnostics, + bool UserFilesAreVolatile); + + /// \brief Create a ASTUnit from an AST file. + /// + /// \param Filename - The AST file to load. + /// + /// \param PCHContainerRdr - The PCHContainerOperations to use for loading and + /// creating modules. + /// \param Diags - The diagnostics engine to use for reporting errors; its + /// lifetime is expected to extend past that of the returned ASTUnit. + /// + /// \returns - The initialized ASTUnit or null if the AST failed to load. + static std::unique_ptr<ASTUnit> LoadFromASTFile( + const std::string &Filename, const PCHContainerReader &PCHContainerRdr, + IntrusiveRefCntPtr<DiagnosticsEngine> Diags, + const FileSystemOptions &FileSystemOpts, bool UseDebugInfo = false, + bool OnlyLocalDecls = false, ArrayRef<RemappedFile> RemappedFiles = None, + bool CaptureDiagnostics = false, bool AllowPCHWithCompilerErrors = false, + bool UserFilesAreVolatile = false); + +private: + /// \brief Helper function for \c LoadFromCompilerInvocation() and + /// \c LoadFromCommandLine(), which loads an AST from a compiler invocation. + /// + /// \param PrecompilePreambleAfterNParses After how many parses the preamble + /// of this translation unit should be precompiled, to improve the performance + /// of reparsing. Set to zero to disable preambles. + /// + /// \returns \c true if a catastrophic failure occurred (which means that the + /// \c ASTUnit itself is invalid), or \c false otherwise. + bool LoadFromCompilerInvocation( + std::shared_ptr<PCHContainerOperations> PCHContainerOps, + unsigned PrecompilePreambleAfterNParses); + +public: + + /// \brief Create an ASTUnit from a source file, via a CompilerInvocation + /// object, by invoking the optionally provided ASTFrontendAction. + /// + /// \param CI - The compiler invocation to use; it must have exactly one input + /// source file. The ASTUnit takes ownership of the CompilerInvocation object. + /// + /// \param PCHContainerOps - The PCHContainerOperations to use for loading and + /// creating modules. + /// + /// \param Diags - The diagnostics engine to use for reporting errors; its + /// lifetime is expected to extend past that of the returned ASTUnit. + /// + /// \param Action - The ASTFrontendAction to invoke. Its ownership is not + /// transferred. + /// + /// \param Unit - optionally an already created ASTUnit. Its ownership is not + /// transferred. + /// + /// \param Persistent - if true the returned ASTUnit will be complete. + /// false means the caller is only interested in getting info through the + /// provided \see Action. + /// + /// \param ErrAST - If non-null and parsing failed without any AST to return + /// (e.g. because the PCH could not be loaded), this accepts the ASTUnit + /// mainly to allow the caller to see the diagnostics. + /// This will only receive an ASTUnit if a new one was created. If an already + /// created ASTUnit was passed in \p Unit then the caller can check that. + /// + static ASTUnit *LoadFromCompilerInvocationAction( + CompilerInvocation *CI, + std::shared_ptr<PCHContainerOperations> PCHContainerOps, + IntrusiveRefCntPtr<DiagnosticsEngine> Diags, + ASTFrontendAction *Action = nullptr, ASTUnit *Unit = nullptr, + bool Persistent = true, StringRef ResourceFilesPath = StringRef(), + bool OnlyLocalDecls = false, bool CaptureDiagnostics = false, + unsigned PrecompilePreambleAfterNParses = 0, + bool CacheCodeCompletionResults = false, + bool IncludeBriefCommentsInCodeCompletion = false, + bool UserFilesAreVolatile = false, + std::unique_ptr<ASTUnit> *ErrAST = nullptr); + + /// LoadFromCompilerInvocation - Create an ASTUnit from a source file, via a + /// CompilerInvocation object. + /// + /// \param CI - The compiler invocation to use; it must have exactly one input + /// source file. The ASTUnit takes ownership of the CompilerInvocation object. + /// + /// \param PCHContainerOps - The PCHContainerOperations to use for loading and + /// creating modules. + /// + /// \param Diags - The diagnostics engine to use for reporting errors; its + /// lifetime is expected to extend past that of the returned ASTUnit. + // + // FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we + // shouldn't need to specify them at construction time. + static std::unique_ptr<ASTUnit> LoadFromCompilerInvocation( + CompilerInvocation *CI, + std::shared_ptr<PCHContainerOperations> PCHContainerOps, + IntrusiveRefCntPtr<DiagnosticsEngine> Diags, FileManager *FileMgr, + bool OnlyLocalDecls = false, bool CaptureDiagnostics = false, + unsigned PrecompilePreambleAfterNParses = 0, + TranslationUnitKind TUKind = TU_Complete, + bool CacheCodeCompletionResults = false, + bool IncludeBriefCommentsInCodeCompletion = false, + bool UserFilesAreVolatile = false); + + /// LoadFromCommandLine - Create an ASTUnit from a vector of command line + /// arguments, which must specify exactly one source file. + /// + /// \param ArgBegin - The beginning of the argument vector. + /// + /// \param ArgEnd - The end of the argument vector. + /// + /// \param PCHContainerOps - The PCHContainerOperations to use for loading and + /// creating modules. + /// + /// \param Diags - The diagnostics engine to use for reporting errors; its + /// lifetime is expected to extend past that of the returned ASTUnit. + /// + /// \param ResourceFilesPath - The path to the compiler resource files. + /// + /// \param ModuleFormat - If provided, uses the specific module format. + /// + /// \param ErrAST - If non-null and parsing failed without any AST to return + /// (e.g. because the PCH could not be loaded), this accepts the ASTUnit + /// mainly to allow the caller to see the diagnostics. + /// + // FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we + // shouldn't need to specify them at construction time. + static ASTUnit *LoadFromCommandLine( + const char **ArgBegin, const char **ArgEnd, + std::shared_ptr<PCHContainerOperations> PCHContainerOps, + IntrusiveRefCntPtr<DiagnosticsEngine> Diags, StringRef ResourceFilesPath, + bool OnlyLocalDecls = false, bool CaptureDiagnostics = false, + ArrayRef<RemappedFile> RemappedFiles = None, + bool RemappedFilesKeepOriginalName = true, + unsigned PrecompilePreambleAfterNParses = 0, + TranslationUnitKind TUKind = TU_Complete, + bool CacheCodeCompletionResults = false, + bool IncludeBriefCommentsInCodeCompletion = false, + bool AllowPCHWithCompilerErrors = false, bool SkipFunctionBodies = false, + bool UserFilesAreVolatile = false, bool ForSerialization = false, + llvm::Optional<StringRef> ModuleFormat = llvm::None, + std::unique_ptr<ASTUnit> *ErrAST = nullptr); + + /// \brief Reparse the source files using the same command-line options that + /// were originally used to produce this translation unit. + /// + /// \returns True if a failure occurred that causes the ASTUnit not to + /// contain any translation-unit information, false otherwise. + bool Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps, + ArrayRef<RemappedFile> RemappedFiles = None); + + /// \brief Perform code completion at the given file, line, and + /// column within this translation unit. + /// + /// \param File The file in which code completion will occur. + /// + /// \param Line The line at which code completion will occur. + /// + /// \param Column The column at which code completion will occur. + /// + /// \param IncludeMacros Whether to include macros in the code-completion + /// results. + /// + /// \param IncludeCodePatterns Whether to include code patterns (such as a + /// for loop) in the code-completion results. + /// + /// \param IncludeBriefComments Whether to include brief documentation within + /// the set of code completions returned. + /// + /// FIXME: The Diag, LangOpts, SourceMgr, FileMgr, StoredDiagnostics, and + /// OwnedBuffers parameters are all disgusting hacks. They will go away. + void CodeComplete(StringRef File, unsigned Line, unsigned Column, + ArrayRef<RemappedFile> RemappedFiles, bool IncludeMacros, + bool IncludeCodePatterns, bool IncludeBriefComments, + CodeCompleteConsumer &Consumer, + std::shared_ptr<PCHContainerOperations> PCHContainerOps, + DiagnosticsEngine &Diag, LangOptions &LangOpts, + SourceManager &SourceMgr, FileManager &FileMgr, + SmallVectorImpl<StoredDiagnostic> &StoredDiagnostics, + SmallVectorImpl<const llvm::MemoryBuffer *> &OwnedBuffers); + + /// \brief Save this translation unit to a file with the given name. + /// + /// \returns true if there was a file error or false if the save was + /// successful. + bool Save(StringRef File); + + /// \brief Serialize this translation unit with the given output stream. + /// + /// \returns True if an error occurred, false otherwise. + bool serialize(raw_ostream &OS); + + ModuleLoadResult loadModule(SourceLocation ImportLoc, ModuleIdPath Path, + Module::NameVisibilityKind Visibility, + bool IsInclusionDirective) override { + // ASTUnit doesn't know how to load modules (not that this matters). + return ModuleLoadResult(); + } + + void makeModuleVisible(Module *Mod, Module::NameVisibilityKind Visibility, + SourceLocation ImportLoc) override {} + + GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override + { return nullptr; } + bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override + { return 0; } +}; + +} // namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/ChainedDiagnosticConsumer.h b/contrib/llvm/tools/clang/include/clang/Frontend/ChainedDiagnosticConsumer.h new file mode 100644 index 0000000..eb33273 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Frontend/ChainedDiagnosticConsumer.h @@ -0,0 +1,72 @@ +//===- ChainedDiagnosticConsumer.h - Chain Diagnostic Clients ---*- 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_CHAINEDDIAGNOSTICCONSUMER_H +#define LLVM_CLANG_FRONTEND_CHAINEDDIAGNOSTICCONSUMER_H + +#include "clang/Basic/Diagnostic.h" +#include <memory> + +namespace clang { +class LangOptions; + +/// ChainedDiagnosticConsumer - Chain two diagnostic clients so that diagnostics +/// go to the first client and then the second. The first diagnostic client +/// should be the "primary" client, and will be used for computing whether the +/// diagnostics should be included in counts. +class ChainedDiagnosticConsumer : public DiagnosticConsumer { + virtual void anchor(); + std::unique_ptr<DiagnosticConsumer> OwningPrimary; + DiagnosticConsumer *Primary; + std::unique_ptr<DiagnosticConsumer> Secondary; + +public: + ChainedDiagnosticConsumer(std::unique_ptr<DiagnosticConsumer> Primary, + std::unique_ptr<DiagnosticConsumer> Secondary) + : OwningPrimary(std::move(Primary)), Primary(OwningPrimary.get()), + Secondary(std::move(Secondary)) {} + + /// \brief Construct without taking ownership of \c Primary. + ChainedDiagnosticConsumer(DiagnosticConsumer *Primary, + std::unique_ptr<DiagnosticConsumer> Secondary) + : Primary(Primary), Secondary(std::move(Secondary)) {} + + void BeginSourceFile(const LangOptions &LO, + const Preprocessor *PP) override { + Primary->BeginSourceFile(LO, PP); + Secondary->BeginSourceFile(LO, PP); + } + + void EndSourceFile() override { + Secondary->EndSourceFile(); + Primary->EndSourceFile(); + } + + void finish() override { + Secondary->finish(); + Primary->finish(); + } + + bool IncludeInDiagnosticCounts() const override { + return Primary->IncludeInDiagnosticCounts(); + } + + void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, + const Diagnostic &Info) override { + // Default implementation (Warnings/errors count). + DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info); + + Primary->HandleDiagnostic(DiagLevel, Info); + Secondary->HandleDiagnostic(DiagLevel, Info); + } +}; + +} // end namspace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.def b/contrib/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.def new file mode 100644 index 0000000..d9f6ab7 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.def @@ -0,0 +1,212 @@ +//===--- CodeGenOptions.def - Code generation option database ------ C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the code generation options. Users of this file +// must define the CODEGENOPT macro to make use of this information. +// Optionally, the user may also define ENUM_CODEGENOPT (for options +// that have enumeration type and VALUE_CODEGENOPT is a code +// generation option that describes a value rather than a flag. +// +//===----------------------------------------------------------------------===// +#ifndef CODEGENOPT +# error Define the CODEGENOPT macro to handle language options +#endif + +#ifndef VALUE_CODEGENOPT +# define VALUE_CODEGENOPT(Name, Bits, Default) \ +CODEGENOPT(Name, Bits, Default) +#endif + +#ifndef ENUM_CODEGENOPT +# define ENUM_CODEGENOPT(Name, Type, Bits, Default) \ +CODEGENOPT(Name, Bits, Default) +#endif + +CODEGENOPT(DisableIntegratedAS, 1, 0) ///< -no-integrated-as +CODEGENOPT(CompressDebugSections, 1, 0) ///< -Wa,-compress-debug-sections +CODEGENOPT(Autolink , 1, 1) ///< -fno-autolink +CODEGENOPT(AsmVerbose , 1, 0) ///< -dA, -fverbose-asm. +CODEGENOPT(ObjCAutoRefCountExceptions , 1, 0) ///< Whether ARC should be EH-safe. +CODEGENOPT(CoverageExtraChecksum, 1, 0) ///< Whether we need a second checksum for functions in GCNO files. +CODEGENOPT(CoverageNoFunctionNamesInData, 1, 0) ///< Do not include function names in GCDA files. +CODEGENOPT(CoverageExitBlockBeforeBody, 1, 0) ///< Whether to emit the exit block before the body blocks in GCNO files. +CODEGENOPT(CXAAtExit , 1, 1) ///< Use __cxa_atexit for calling destructors. +CODEGENOPT(CXXCtorDtorAliases, 1, 0) ///< Emit complete ctors/dtors as linker + ///< aliases to base ctors when possible. +CODEGENOPT(DataSections , 1, 0) ///< Set when -fdata-sections is enabled. +CODEGENOPT(UniqueSectionNames, 1, 1) ///< Set for -funique-section-names. +CODEGENOPT(DisableFPElim , 1, 0) ///< Set when -fomit-frame-pointer is enabled. +CODEGENOPT(DisableFree , 1, 0) ///< Don't free memory. +CODEGENOPT(DisableGCov , 1, 0) ///< Don't run the GCov pass, for testing. +CODEGENOPT(DisableLLVMOpts , 1, 0) ///< Don't run any optimizations, for use in + ///< getting .bc files that correspond to the + ///< internal state before optimizations are + ///< done. +CODEGENOPT(DisableLLVMPasses , 1, 0) ///< Don't run any LLVM IR passes to get + ///< the pristine IR generated by the + ///< frontend. +CODEGENOPT(DisableRedZone , 1, 0) ///< Set when -mno-red-zone is enabled. +CODEGENOPT(DisableTailCalls , 1, 0) ///< Do not emit tail calls. +CODEGENOPT(EmitDeclMetadata , 1, 0) ///< Emit special metadata indicating what + ///< Decl* various IR entities came from. + ///< Only useful when running CodeGen as a + ///< subroutine. +CODEGENOPT(EmitGcovArcs , 1, 0) ///< Emit coverage data files, aka. GCDA. +CODEGENOPT(EmitGcovNotes , 1, 0) ///< Emit coverage "notes" files, aka GCNO. +CODEGENOPT(EmitOpenCLArgMetadata , 1, 0) ///< Emit OpenCL kernel arg metadata. +CODEGENOPT(EmulatedTLS , 1, 0) ///< Set when -femulated-tls is enabled. +/// \brief FP_CONTRACT mode (on/off/fast). +ENUM_CODEGENOPT(FPContractMode, FPContractModeKind, 2, FPC_On) +CODEGENOPT(ForbidGuardVariables , 1, 0) ///< Issue errors if C++ guard variables + ///< are required. +CODEGENOPT(FunctionSections , 1, 0) ///< Set when -ffunction-sections is enabled. +CODEGENOPT(InstrumentFunctions , 1, 0) ///< Set when -finstrument-functions is + ///< enabled. +CODEGENOPT(InstrumentForProfiling , 1, 0) ///< Set when -pg is enabled. +CODEGENOPT(LessPreciseFPMAD , 1, 0) ///< Enable less precise MAD instructions to + ///< be generated. +CODEGENOPT(PrepareForLTO , 1, 0) ///< Set when -flto is enabled on the + ///< compile step. +CODEGENOPT(EmitFunctionSummary, 1, 0) ///< Set when -flto=thin is enabled on the + ///< compile step. +CODEGENOPT(IncrementalLinkerCompatible, 1, 0) ///< Emit an object file which can + ///< be used with an incremental + ///< linker. +CODEGENOPT(MergeAllConstants , 1, 1) ///< Merge identical constants. +CODEGENOPT(MergeFunctions , 1, 0) ///< Set when -fmerge-functions is enabled. +CODEGENOPT(MSVolatile , 1, 0) ///< Set when /volatile:ms is enabled. +CODEGENOPT(NoCommon , 1, 0) ///< Set when -fno-common or C++ is enabled. +CODEGENOPT(NoDwarfDirectoryAsm , 1, 0) ///< Set when -fno-dwarf-directory-asm is + ///< enabled. +CODEGENOPT(NoExecStack , 1, 0) ///< Set when -Wa,--noexecstack is enabled. +CODEGENOPT(FatalWarnings , 1, 0) ///< Set when -Wa,--fatal-warnings is + ///< enabled. +CODEGENOPT(EnableSegmentedStacks , 1, 0) ///< Set when -fsplit-stack is enabled. +CODEGENOPT(NoImplicitFloat , 1, 0) ///< Set when -mno-implicit-float is enabled. +CODEGENOPT(NoInfsFPMath , 1, 0) ///< Assume FP arguments, results not +-Inf. +CODEGENOPT(NoSignedZeros , 1, 0) ///< Allow ignoring the signedness of FP zero +CODEGENOPT(ReciprocalMath , 1, 0) ///< Allow FP divisions to be reassociated. +CODEGENOPT(NoInline , 1, 0) ///< Set when -fno-inline is enabled. + ///< Disables use of the inline keyword. +CODEGENOPT(NoNaNsFPMath , 1, 0) ///< Assume FP arguments, results not NaN. +CODEGENOPT(NoZeroInitializedInBSS , 1, 0) ///< -fno-zero-initialized-in-bss. +/// \brief Method of Objective-C dispatch to use. +ENUM_CODEGENOPT(ObjCDispatchMethod, ObjCDispatchMethodKind, 2, Legacy) +CODEGENOPT(OmitLeafFramePointer , 1, 0) ///< Set when -momit-leaf-frame-pointer is + ///< enabled. +VALUE_CODEGENOPT(OptimizationLevel, 2, 0) ///< The -O[0-3] option specified. +VALUE_CODEGENOPT(OptimizeSize, 2, 0) ///< If -Os (==1) or -Oz (==2) is specified. + +CODEGENOPT(ProfileInstrGenerate , 1, 0) ///< Instrument code to generate + ///< execution counts to use with PGO. +CODEGENOPT(CoverageMapping , 1, 0) ///< Generate coverage mapping regions to + ///< enable code coverage analysis. +CODEGENOPT(DumpCoverageMapping , 1, 0) ///< Dump the generated coverage mapping + ///< regions. + + /// If -fpcc-struct-return or -freg-struct-return is specified. +ENUM_CODEGENOPT(StructReturnConvention, StructReturnConventionKind, 2, SRCK_Default) + +CODEGENOPT(RelaxAll , 1, 0) ///< Relax all machine code instructions. +CODEGENOPT(RelaxedAliasing , 1, 0) ///< Set when -fno-strict-aliasing is enabled. +CODEGENOPT(StructPathTBAA , 1, 0) ///< Whether or not to use struct-path TBAA. +CODEGENOPT(SaveTempLabels , 1, 0) ///< Save temporary labels. +CODEGENOPT(SanitizeAddressZeroBaseShadow , 1, 0) ///< Map shadow memory at zero + ///< offset in AddressSanitizer. +CODEGENOPT(SanitizeMemoryTrackOrigins, 2, 0) ///< Enable tracking origins in + ///< MemorySanitizer +CODEGENOPT(SanitizeMemoryUseAfterDtor, 1, 0) ///< Enable use-after-delete detection + ///< in MemorySanitizer +CODEGENOPT(SanitizeCfiCrossDso, 1, 0) ///< Enable cross-dso support in CFI. +CODEGENOPT(SanitizeCoverageType, 2, 0) ///< Type of sanitizer coverage + ///< instrumentation. +CODEGENOPT(SanitizeCoverageIndirectCalls, 1, 0) ///< Enable sanitizer coverage + ///< for indirect calls. +CODEGENOPT(SanitizeCoverageTraceBB, 1, 0) ///< Enable basic block tracing in + ///< in sanitizer coverage. +CODEGENOPT(SanitizeCoverageTraceCmp, 1, 0) ///< Enable cmp instruction tracing + ///< in sanitizer coverage. +CODEGENOPT(SanitizeCoverage8bitCounters, 1, 0) ///< Use 8-bit frequency counters + ///< in sanitizer coverage. +CODEGENOPT(SimplifyLibCalls , 1, 1) ///< Set when -fbuiltin is enabled. +CODEGENOPT(SoftFloat , 1, 0) ///< -soft-float. +CODEGENOPT(StrictEnums , 1, 0) ///< Optimize based on strict enum definition. +CODEGENOPT(StrictVTablePointers, 1, 0) ///< Optimize based on the strict vtable pointers +CODEGENOPT(TimePasses , 1, 0) ///< Set when -ftime-report is enabled. +CODEGENOPT(UnitAtATime , 1, 1) ///< Unused. For mirroring GCC optimization + ///< selection. +CODEGENOPT(UnrollLoops , 1, 0) ///< Control whether loops are unrolled. +CODEGENOPT(RerollLoops , 1, 0) ///< Control whether loops are rerolled. +CODEGENOPT(UnsafeFPMath , 1, 0) ///< Allow unsafe floating point optzns. +CODEGENOPT(UnwindTables , 1, 0) ///< Emit unwind tables. +CODEGENOPT(VectorizeBB , 1, 0) ///< Run basic block vectorizer. +CODEGENOPT(VectorizeLoop , 1, 0) ///< Run loop vectorizer. +CODEGENOPT(VectorizeSLP , 1, 0) ///< Run SLP vectorizer. + + /// Attempt to use register sized accesses to bit-fields in structures, when + /// possible. +CODEGENOPT(UseRegisterSizedBitfieldAccess , 1, 0) + +CODEGENOPT(VerifyModule , 1, 1) ///< Control whether the module should be run + ///< through the LLVM Verifier. + +CODEGENOPT(StackRealignment , 1, 0) ///< Control whether to force stack + ///< realignment. +CODEGENOPT(UseInitArray , 1, 0) ///< Control whether to use .init_array or + ///< .ctors. +VALUE_CODEGENOPT(StackAlignment , 32, 0) ///< Overrides default stack + ///< alignment, if not 0. +VALUE_CODEGENOPT(StackProbeSize , 32, 4096) ///< Overrides default stack + ///< probe size, even if 0. +CODEGENOPT(DebugColumnInfo, 1, 0) ///< Whether or not to use column information + ///< in debug info. + +CODEGENOPT(DebugTypeExtRefs, 1, 0) ///< Whether or not debug info should contain + ///< external references to a PCH or module. + +CODEGENOPT(DebugExplicitImport, 1, 0) ///< Whether or not debug info should + ///< contain explicit imports for + ///< anonymous namespaces + +CODEGENOPT(EmitLLVMUseLists, 1, 0) ///< Control whether to serialize use-lists. + +/// The user specified number of registers to be used for integral arguments, +/// or 0 if unspecified. +VALUE_CODEGENOPT(NumRegisterParameters, 32, 0) + +/// The lower bound for a buffer to be considered for stack protection. +VALUE_CODEGENOPT(SSPBufferSize, 32, 0) + +/// The kind of generated debug info. +ENUM_CODEGENOPT(DebugInfo, DebugInfoKind, 3, NoDebugInfo) + +/// Tune the debug info for this debugger. +ENUM_CODEGENOPT(DebuggerTuning, DebuggerKind, 2, DebuggerKindDefault) + +/// Dwarf version. Version zero indicates to LLVM that no DWARF should be +/// emitted. +VALUE_CODEGENOPT(DwarfVersion, 3, 0) + +/// Whether we should emit CodeView debug information. It's possible to emit +/// CodeView and DWARF into the same object. +CODEGENOPT(EmitCodeView, 1, 0) + +/// The kind of inlining to perform. +ENUM_CODEGENOPT(Inlining, InliningMethod, 2, NoInlining) + +// Vector functions library to use. +ENUM_CODEGENOPT(VecLib, VectorLibrary, 1, NoLibrary) + +/// The default TLS model to use. +ENUM_CODEGENOPT(DefaultTLSModel, TLSModel, 2, GeneralDynamicTLSModel) + +#undef CODEGENOPT +#undef ENUM_CODEGENOPT +#undef VALUE_CODEGENOPT + diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.h b/contrib/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.h new file mode 100644 index 0000000..7550e6f --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.h @@ -0,0 +1,245 @@ +//===--- CodeGenOptions.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the CodeGenOptions interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_CODEGENOPTIONS_H +#define LLVM_CLANG_FRONTEND_CODEGENOPTIONS_H + +#include "clang/Basic/Sanitizers.h" +#include "llvm/Support/Regex.h" +#include <map> +#include <memory> +#include <string> +#include <vector> + +namespace clang { + +/// \brief Bitfields of CodeGenOptions, split out from CodeGenOptions to ensure +/// that this large collection of bitfields is a trivial class type. +class CodeGenOptionsBase { +public: +#define CODEGENOPT(Name, Bits, Default) unsigned Name : Bits; +#define ENUM_CODEGENOPT(Name, Type, Bits, Default) +#include "clang/Frontend/CodeGenOptions.def" + +protected: +#define CODEGENOPT(Name, Bits, Default) +#define ENUM_CODEGENOPT(Name, Type, Bits, Default) unsigned Name : Bits; +#include "clang/Frontend/CodeGenOptions.def" +}; + +/// CodeGenOptions - Track various options which control how the code +/// is optimized and passed to the backend. +class CodeGenOptions : public CodeGenOptionsBase { +public: + enum InliningMethod { + NoInlining, // Perform no inlining whatsoever. + NormalInlining, // Use the standard function inlining pass. + OnlyAlwaysInlining // Only run the always inlining pass. + }; + + enum VectorLibrary { + NoLibrary, // Don't use any vector library. + Accelerate // Use the Accelerate framework. + }; + + enum ObjCDispatchMethodKind { + Legacy = 0, + NonLegacy = 1, + Mixed = 2 + }; + + enum DebugInfoKind { + NoDebugInfo, /// Don't generate debug info. + + LocTrackingOnly, /// Emit location information but do not generate + /// debug info in the output. This is useful in + /// cases where the backend wants to track source + /// locations for instructions without actually + /// emitting debug info for them (e.g., when -Rpass + /// is used). + + DebugLineTablesOnly, /// Emit only debug info necessary for generating + /// line number tables (-gline-tables-only). + + LimitedDebugInfo, /// Limit generated debug info to reduce size + /// (-fno-standalone-debug). This emits + /// forward decls for types that could be + /// replaced with forward decls in the source + /// code. For dynamic C++ classes type info + /// is only emitted int the module that + /// contains the classe's vtable. + + FullDebugInfo /// Generate complete debug info. + }; + + enum DebuggerKind { + DebuggerKindDefault, + DebuggerKindGDB, + DebuggerKindLLDB, + DebuggerKindSCE + }; + + enum TLSModel { + GeneralDynamicTLSModel, + LocalDynamicTLSModel, + InitialExecTLSModel, + LocalExecTLSModel + }; + + enum FPContractModeKind { + FPC_Off, // Form fused FP ops only where result will not be affected. + FPC_On, // Form fused FP ops according to FP_CONTRACT rules. + FPC_Fast // Aggressively fuse FP ops (E.g. FMA). + }; + + enum StructReturnConventionKind { + SRCK_Default, // No special option was passed. + SRCK_OnStack, // Small structs on the stack (-fpcc-struct-return). + SRCK_InRegs // Small structs in registers (-freg-struct-return). + }; + + /// The code model to use (-mcmodel). + std::string CodeModel; + + /// The filename with path we use for coverage files. The extension will be + /// replaced. + std::string CoverageFile; + + /// The version string to put into coverage files. + char CoverageVersion[4]; + + /// Enable additional debugging information. + std::string DebugPass; + + /// The string to embed in debug information as the current working directory. + std::string DebugCompilationDir; + + /// The string to embed in the debug information for the compile unit, if + /// non-empty. + std::string DwarfDebugFlags; + + std::map<std::string, std::string> DebugPrefixMap; + + /// The ABI to use for passing floating point arguments. + std::string FloatABI; + + /// The float precision limit to use, if non-empty. + std::string LimitFloatPrecision; + + /// The name of the bitcode file to link before optzns. + std::vector<std::pair<unsigned, std::string>> LinkBitcodeFiles; + + /// The user provided name for the "main file", if non-empty. This is useful + /// in situations where the input file name does not match the original input + /// file, for example with -save-temps. + std::string MainFileName; + + /// The name for the split debug info file that we'll break out. This is used + /// in the backend for setting the name in the skeleton cu. + std::string SplitDwarfFile; + + /// The name of the relocation model to use. + std::string RelocationModel; + + /// The thread model to use + std::string ThreadModel; + + /// If not an empty string, trap intrinsics are lowered to calls to this + /// function instead of to trap instructions. + std::string TrapFuncName; + + /// A list of command-line options to forward to the LLVM backend. + std::vector<std::string> BackendOptions; + + /// A list of dependent libraries. + std::vector<std::string> DependentLibraries; + + /// Name of the profile file to use as output for -fprofile-instr-generate + /// and -fprofile-generate. + std::string InstrProfileOutput; + + /// Name of the profile file to use with -fprofile-sample-use. + std::string SampleProfileFile; + + /// Name of the profile file to use as input for -fprofile-instr-use + std::string InstrProfileInput; + + /// Name of the function summary index file to use for ThinLTO function + /// importing. + std::string ThinLTOIndexFile; + + /// The EABI version to use + std::string EABIVersion; + + /// A list of file names passed with -fcuda-include-gpubinary options to + /// forward to CUDA runtime back-end for incorporating them into host-side + /// object file. + std::vector<std::string> CudaGpuBinaryFileNames; + + /// Regular expression to select optimizations for which we should enable + /// optimization remarks. Transformation passes whose name matches this + /// expression (and support this feature), will emit a diagnostic + /// whenever they perform a transformation. This is enabled by the + /// -Rpass=regexp flag. + std::shared_ptr<llvm::Regex> OptimizationRemarkPattern; + + /// Regular expression to select optimizations for which we should enable + /// missed optimization remarks. Transformation passes whose name matches this + /// expression (and support this feature), will emit a diagnostic + /// whenever they tried but failed to perform a transformation. This is + /// enabled by the -Rpass-missed=regexp flag. + std::shared_ptr<llvm::Regex> OptimizationRemarkMissedPattern; + + /// Regular expression to select optimizations for which we should enable + /// optimization analyses. Transformation passes whose name matches this + /// expression (and support this feature), will emit a diagnostic + /// whenever they want to explain why they decided to apply or not apply + /// a given transformation. This is enabled by the -Rpass-analysis=regexp + /// flag. + std::shared_ptr<llvm::Regex> OptimizationRemarkAnalysisPattern; + + /// Set of files definining the rules for the symbol rewriting. + std::vector<std::string> RewriteMapFiles; + + /// Set of sanitizer checks that are non-fatal (i.e. execution should be + /// continued when possible). + SanitizerSet SanitizeRecover; + + /// Set of sanitizer checks that trap rather than diagnose. + SanitizerSet SanitizeTrap; + + /// \brief A list of all -fno-builtin-* function names (e.g., memset). + std::vector<std::string> NoBuiltinFuncs; + +public: + // Define accessors/mutators for code generation options of enumeration type. +#define CODEGENOPT(Name, Bits, Default) +#define ENUM_CODEGENOPT(Name, Type, Bits, Default) \ + Type get##Name() const { return static_cast<Type>(Name); } \ + void set##Name(Type Value) { Name = static_cast<unsigned>(Value); } +#include "clang/Frontend/CodeGenOptions.def" + + CodeGenOptions(); + + /// \brief Is this a libc/libm function that is no longer recognized as a + /// builtin because a -fno-builtin-* option has been specified? + bool isNoBuiltinFunc(const char *Name) const; + + const std::vector<std::string> &getNoBuiltinFuncs() const { + return NoBuiltinFuncs; + } +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/CommandLineSourceLoc.h b/contrib/llvm/tools/clang/include/clang/Frontend/CommandLineSourceLoc.h new file mode 100644 index 0000000..a78c96d --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Frontend/CommandLineSourceLoc.h @@ -0,0 +1,87 @@ + +//===--- CommandLineSourceLoc.h - Parsing for source locations-*- C++ -*---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Command line parsing for source locations. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_COMMANDLINESOURCELOC_H +#define LLVM_CLANG_FRONTEND_COMMANDLINESOURCELOC_H + +#include "clang/Basic/LLVM.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/raw_ostream.h" + +namespace clang { + +/// \brief A source location that has been parsed on the command line. +struct ParsedSourceLocation { + std::string FileName; + unsigned Line; + unsigned Column; + +public: + /// Construct a parsed source location from a string; the Filename is empty on + /// error. + static ParsedSourceLocation FromString(StringRef Str) { + ParsedSourceLocation PSL; + std::pair<StringRef, StringRef> ColSplit = Str.rsplit(':'); + std::pair<StringRef, StringRef> LineSplit = + ColSplit.first.rsplit(':'); + + // If both tail splits were valid integers, return success. + if (!ColSplit.second.getAsInteger(10, PSL.Column) && + !LineSplit.second.getAsInteger(10, PSL.Line)) { + PSL.FileName = LineSplit.first; + + // On the command-line, stdin may be specified via "-". Inside the + // compiler, stdin is called "<stdin>". + if (PSL.FileName == "-") + PSL.FileName = "<stdin>"; + } + + return PSL; + } +}; + +} + +namespace llvm { + namespace cl { + /// \brief Command-line option parser that parses source locations. + /// + /// Source locations are of the form filename:line:column. + template<> + class parser<clang::ParsedSourceLocation> final + : public basic_parser<clang::ParsedSourceLocation> { + public: + inline bool parse(Option &O, StringRef ArgName, StringRef ArgValue, + clang::ParsedSourceLocation &Val); + }; + + bool + parser<clang::ParsedSourceLocation>:: + parse(Option &O, StringRef ArgName, StringRef ArgValue, + clang::ParsedSourceLocation &Val) { + using namespace clang; + + Val = ParsedSourceLocation::FromString(ArgValue); + if (Val.FileName.empty()) { + errs() << "error: " + << "source location must be of the form filename:line:column\n"; + return true; + } + + return false; + } + } +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/CompilerInstance.h b/contrib/llvm/tools/clang/include/clang/Frontend/CompilerInstance.h new file mode 100644 index 0000000..83eed2c --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Frontend/CompilerInstance.h @@ -0,0 +1,785 @@ +//===-- CompilerInstance.h - Clang Compiler Instance ------------*- 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_COMPILERINSTANCE_H_ +#define LLVM_CLANG_FRONTEND_COMPILERINSTANCE_H_ + +#include "clang/AST/ASTConsumer.h" +#include "clang/Frontend/PCHContainerOperations.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Frontend/CompilerInvocation.h" +#include "clang/Frontend/Utils.h" +#include "clang/Lex/ModuleLoader.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/StringRef.h" +#include <cassert> +#include <list> +#include <memory> +#include <string> +#include <utility> + +namespace llvm { +class raw_fd_ostream; +class Timer; +class TimerGroup; +} + +namespace clang { +class ASTContext; +class ASTConsumer; +class ASTReader; +class CodeCompleteConsumer; +class DiagnosticsEngine; +class DiagnosticConsumer; +class ExternalASTSource; +class FileEntry; +class FileManager; +class FrontendAction; +class Module; +class Preprocessor; +class Sema; +class SourceManager; +class TargetInfo; + +/// CompilerInstance - Helper class for managing a single instance of the Clang +/// compiler. +/// +/// The CompilerInstance serves two purposes: +/// (1) It manages the various objects which are necessary to run the compiler, +/// for example the preprocessor, the target information, and the AST +/// context. +/// (2) It provides utility routines for constructing and manipulating the +/// common Clang objects. +/// +/// The compiler instance generally owns the instance of all the objects that it +/// manages. However, clients can still share objects by manually setting the +/// object and retaking ownership prior to destroying the CompilerInstance. +/// +/// The compiler instance is intended to simplify clients, but not to lock them +/// in to the compiler instance for everything. When possible, utility functions +/// come in two forms; a short form that reuses the CompilerInstance objects, +/// and a long form that takes explicit instances of any required objects. +class CompilerInstance : public ModuleLoader { + /// The options used in this compiler instance. + IntrusiveRefCntPtr<CompilerInvocation> Invocation; + + /// The diagnostics engine instance. + IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics; + + /// The target being compiled for. + IntrusiveRefCntPtr<TargetInfo> Target; + + /// Auxiliary Target info. + IntrusiveRefCntPtr<TargetInfo> AuxTarget; + + /// The virtual file system. + IntrusiveRefCntPtr<vfs::FileSystem> VirtualFileSystem; + + /// The file manager. + IntrusiveRefCntPtr<FileManager> FileMgr; + + /// The source manager. + IntrusiveRefCntPtr<SourceManager> SourceMgr; + + /// The preprocessor. + IntrusiveRefCntPtr<Preprocessor> PP; + + /// The AST context. + IntrusiveRefCntPtr<ASTContext> Context; + + /// The AST consumer. + std::unique_ptr<ASTConsumer> Consumer; + + /// The code completion consumer. + std::unique_ptr<CodeCompleteConsumer> CompletionConsumer; + + /// \brief The semantic analysis object. + std::unique_ptr<Sema> TheSema; + + /// \brief The frontend timer group. + std::unique_ptr<llvm::TimerGroup> FrontendTimerGroup; + + /// \brief The frontend timer. + std::unique_ptr<llvm::Timer> FrontendTimer; + + /// \brief The ASTReader, if one exists. + IntrusiveRefCntPtr<ASTReader> ModuleManager; + + /// \brief The module dependency collector for crashdumps + std::shared_ptr<ModuleDependencyCollector> ModuleDepCollector; + + /// \brief The module provider. + std::shared_ptr<PCHContainerOperations> ThePCHContainerOperations; + + /// \brief The dependency file generator. + std::unique_ptr<DependencyFileGenerator> TheDependencyFileGenerator; + + std::vector<std::shared_ptr<DependencyCollector>> DependencyCollectors; + + /// \brief The set of top-level modules that has already been loaded, + /// along with the module map + llvm::DenseMap<const IdentifierInfo *, Module *> KnownModules; + + /// \brief The location of the module-import keyword for the last module + /// import. + SourceLocation LastModuleImportLoc; + + /// \brief The result of the last module import. + /// + ModuleLoadResult LastModuleImportResult; + + /// \brief Whether we should (re)build the global module index once we + /// have finished with this translation unit. + bool BuildGlobalModuleIndex; + + /// \brief We have a full global module index, with all modules. + bool HaveFullGlobalModuleIndex; + + /// \brief One or more modules failed to build. + bool ModuleBuildFailed; + + /// \brief Holds information about the output file. + /// + /// If TempFilename is not empty we must rename it to Filename at the end. + /// TempFilename may be empty and Filename non-empty if creating the temporary + /// failed. + struct OutputFile { + std::string Filename; + std::string TempFilename; + std::unique_ptr<raw_ostream> OS; + + OutputFile(std::string filename, std::string tempFilename, + std::unique_ptr<raw_ostream> OS) + : Filename(std::move(filename)), TempFilename(std::move(tempFilename)), + OS(std::move(OS)) {} + OutputFile(OutputFile &&O) + : Filename(std::move(O.Filename)), + TempFilename(std::move(O.TempFilename)), OS(std::move(O.OS)) {} + }; + + /// If the output doesn't support seeking (terminal, pipe). we switch + /// the stream to a buffer_ostream. These are the buffer and the original + /// stream. + std::unique_ptr<llvm::raw_fd_ostream> NonSeekStream; + + /// The list of active output files. + std::list<OutputFile> OutputFiles; + + CompilerInstance(const CompilerInstance &) = delete; + void operator=(const CompilerInstance &) = delete; +public: + explicit CompilerInstance( + std::shared_ptr<PCHContainerOperations> PCHContainerOps = + std::make_shared<PCHContainerOperations>(), + bool BuildingModule = false); + ~CompilerInstance() override; + + /// @name High-Level Operations + /// { + + /// ExecuteAction - Execute the provided action against the compiler's + /// CompilerInvocation object. + /// + /// This function makes the following assumptions: + /// + /// - The invocation options should be initialized. This function does not + /// handle the '-help' or '-version' options, clients should handle those + /// directly. + /// + /// - The diagnostics engine should have already been created by the client. + /// + /// - No other CompilerInstance state should have been initialized (this is + /// an unchecked error). + /// + /// - Clients should have initialized any LLVM target features that may be + /// required. + /// + /// - Clients should eventually call llvm_shutdown() upon the completion of + /// this routine to ensure that any managed objects are properly destroyed. + /// + /// Note that this routine may write output to 'stderr'. + /// + /// \param Act - The action to execute. + /// \return - True on success. + // + // FIXME: This function should take the stream to write any debugging / + // verbose output to as an argument. + // + // FIXME: Eliminate the llvm_shutdown requirement, that should either be part + // of the context or else not CompilerInstance specific. + bool ExecuteAction(FrontendAction &Act); + + /// } + /// @name Compiler Invocation and Options + /// { + + bool hasInvocation() const { return Invocation != nullptr; } + + CompilerInvocation &getInvocation() { + assert(Invocation && "Compiler instance has no invocation!"); + return *Invocation; + } + + /// setInvocation - Replace the current invocation. + void setInvocation(CompilerInvocation *Value); + + /// \brief Indicates whether we should (re)build the global module index. + bool shouldBuildGlobalModuleIndex() const; + + /// \brief Set the flag indicating whether we should (re)build the global + /// module index. + void setBuildGlobalModuleIndex(bool Build) { + BuildGlobalModuleIndex = Build; + } + + /// } + /// @name Forwarding Methods + /// { + + AnalyzerOptionsRef getAnalyzerOpts() { + return Invocation->getAnalyzerOpts(); + } + + CodeGenOptions &getCodeGenOpts() { + return Invocation->getCodeGenOpts(); + } + const CodeGenOptions &getCodeGenOpts() const { + return Invocation->getCodeGenOpts(); + } + + DependencyOutputOptions &getDependencyOutputOpts() { + return Invocation->getDependencyOutputOpts(); + } + const DependencyOutputOptions &getDependencyOutputOpts() const { + return Invocation->getDependencyOutputOpts(); + } + + DiagnosticOptions &getDiagnosticOpts() { + return Invocation->getDiagnosticOpts(); + } + const DiagnosticOptions &getDiagnosticOpts() const { + return Invocation->getDiagnosticOpts(); + } + + FileSystemOptions &getFileSystemOpts() { + return Invocation->getFileSystemOpts(); + } + const FileSystemOptions &getFileSystemOpts() const { + return Invocation->getFileSystemOpts(); + } + + FrontendOptions &getFrontendOpts() { + return Invocation->getFrontendOpts(); + } + const FrontendOptions &getFrontendOpts() const { + return Invocation->getFrontendOpts(); + } + + HeaderSearchOptions &getHeaderSearchOpts() { + return Invocation->getHeaderSearchOpts(); + } + const HeaderSearchOptions &getHeaderSearchOpts() const { + return Invocation->getHeaderSearchOpts(); + } + + LangOptions &getLangOpts() { + return *Invocation->getLangOpts(); + } + const LangOptions &getLangOpts() const { + return *Invocation->getLangOpts(); + } + + PreprocessorOptions &getPreprocessorOpts() { + return Invocation->getPreprocessorOpts(); + } + const PreprocessorOptions &getPreprocessorOpts() const { + return Invocation->getPreprocessorOpts(); + } + + PreprocessorOutputOptions &getPreprocessorOutputOpts() { + return Invocation->getPreprocessorOutputOpts(); + } + const PreprocessorOutputOptions &getPreprocessorOutputOpts() const { + return Invocation->getPreprocessorOutputOpts(); + } + + TargetOptions &getTargetOpts() { + return Invocation->getTargetOpts(); + } + const TargetOptions &getTargetOpts() const { + return Invocation->getTargetOpts(); + } + + /// } + /// @name Diagnostics Engine + /// { + + bool hasDiagnostics() const { return Diagnostics != nullptr; } + + /// Get the current diagnostics engine. + DiagnosticsEngine &getDiagnostics() const { + assert(Diagnostics && "Compiler instance has no diagnostics!"); + return *Diagnostics; + } + + /// setDiagnostics - Replace the current diagnostics engine. + void setDiagnostics(DiagnosticsEngine *Value); + + DiagnosticConsumer &getDiagnosticClient() const { + assert(Diagnostics && Diagnostics->getClient() && + "Compiler instance has no diagnostic client!"); + return *Diagnostics->getClient(); + } + + /// } + /// @name Target Info + /// { + + bool hasTarget() const { return Target != nullptr; } + + TargetInfo &getTarget() const { + assert(Target && "Compiler instance has no target!"); + return *Target; + } + + /// Replace the current Target. + void setTarget(TargetInfo *Value); + + /// } + /// @name AuxTarget Info + /// { + + TargetInfo *getAuxTarget() const { return AuxTarget.get(); } + + /// Replace the current AuxTarget. + void setAuxTarget(TargetInfo *Value); + + /// } + /// @name Virtual File System + /// { + + bool hasVirtualFileSystem() const { return VirtualFileSystem != nullptr; } + + vfs::FileSystem &getVirtualFileSystem() const { + assert(hasVirtualFileSystem() && + "Compiler instance has no virtual file system"); + return *VirtualFileSystem; + } + + /// \brief Replace the current virtual file system. + /// + /// \note Most clients should use setFileManager, which will implicitly reset + /// the virtual file system to the one contained in the file manager. + void setVirtualFileSystem(IntrusiveRefCntPtr<vfs::FileSystem> FS) { + VirtualFileSystem = FS; + } + + /// } + /// @name File Manager + /// { + + bool hasFileManager() const { return FileMgr != nullptr; } + + /// Return the current file manager to the caller. + FileManager &getFileManager() const { + assert(FileMgr && "Compiler instance has no file manager!"); + return *FileMgr; + } + + void resetAndLeakFileManager() { + BuryPointer(FileMgr.get()); + FileMgr.resetWithoutRelease(); + } + + /// \brief Replace the current file manager and virtual file system. + void setFileManager(FileManager *Value); + + /// } + /// @name Source Manager + /// { + + bool hasSourceManager() const { return SourceMgr != nullptr; } + + /// Return the current source manager. + SourceManager &getSourceManager() const { + assert(SourceMgr && "Compiler instance has no source manager!"); + return *SourceMgr; + } + + void resetAndLeakSourceManager() { + BuryPointer(SourceMgr.get()); + SourceMgr.resetWithoutRelease(); + } + + /// setSourceManager - Replace the current source manager. + void setSourceManager(SourceManager *Value); + + /// } + /// @name Preprocessor + /// { + + bool hasPreprocessor() const { return PP != nullptr; } + + /// Return the current preprocessor. + Preprocessor &getPreprocessor() const { + assert(PP && "Compiler instance has no preprocessor!"); + return *PP; + } + + void resetAndLeakPreprocessor() { + BuryPointer(PP.get()); + PP.resetWithoutRelease(); + } + + /// Replace the current preprocessor. + void setPreprocessor(Preprocessor *Value); + + /// } + /// @name ASTContext + /// { + + bool hasASTContext() const { return Context != nullptr; } + + ASTContext &getASTContext() const { + assert(Context && "Compiler instance has no AST context!"); + return *Context; + } + + void resetAndLeakASTContext() { + BuryPointer(Context.get()); + Context.resetWithoutRelease(); + } + + /// setASTContext - Replace the current AST context. + void setASTContext(ASTContext *Value); + + /// \brief Replace the current Sema; the compiler instance takes ownership + /// of S. + void setSema(Sema *S); + + /// } + /// @name ASTConsumer + /// { + + bool hasASTConsumer() const { return (bool)Consumer; } + + ASTConsumer &getASTConsumer() const { + assert(Consumer && "Compiler instance has no AST consumer!"); + return *Consumer; + } + + /// takeASTConsumer - Remove the current AST consumer and give ownership to + /// the caller. + std::unique_ptr<ASTConsumer> takeASTConsumer() { return std::move(Consumer); } + + /// setASTConsumer - Replace the current AST consumer; the compiler instance + /// takes ownership of \p Value. + void setASTConsumer(std::unique_ptr<ASTConsumer> Value); + + /// } + /// @name Semantic analysis + /// { + bool hasSema() const { return (bool)TheSema; } + + Sema &getSema() const { + assert(TheSema && "Compiler instance has no Sema object!"); + return *TheSema; + } + + std::unique_ptr<Sema> takeSema(); + void resetAndLeakSema(); + + /// } + /// @name Module Management + /// { + + IntrusiveRefCntPtr<ASTReader> getModuleManager() const; + void setModuleManager(IntrusiveRefCntPtr<ASTReader> Reader); + + std::shared_ptr<ModuleDependencyCollector> getModuleDepCollector() const; + void setModuleDepCollector( + std::shared_ptr<ModuleDependencyCollector> Collector); + + std::shared_ptr<PCHContainerOperations> getPCHContainerOperations() const { + return ThePCHContainerOperations; + } + + /// Return the appropriate PCHContainerWriter depending on the + /// current CodeGenOptions. + const PCHContainerWriter &getPCHContainerWriter() const { + assert(Invocation && "cannot determine module format without invocation"); + StringRef Format = getHeaderSearchOpts().ModuleFormat; + auto *Writer = ThePCHContainerOperations->getWriterOrNull(Format); + if (!Writer) { + if (Diagnostics) + Diagnostics->Report(diag::err_module_format_unhandled) << Format; + llvm::report_fatal_error("unknown module format"); + } + return *Writer; + } + + /// Return the appropriate PCHContainerReader depending on the + /// current CodeGenOptions. + const PCHContainerReader &getPCHContainerReader() const { + assert(Invocation && "cannot determine module format without invocation"); + StringRef Format = getHeaderSearchOpts().ModuleFormat; + auto *Reader = ThePCHContainerOperations->getReaderOrNull(Format); + if (!Reader) { + if (Diagnostics) + Diagnostics->Report(diag::err_module_format_unhandled) << Format; + llvm::report_fatal_error("unknown module format"); + } + return *Reader; + } + + /// } + /// @name Code Completion + /// { + + bool hasCodeCompletionConsumer() const { return (bool)CompletionConsumer; } + + CodeCompleteConsumer &getCodeCompletionConsumer() const { + assert(CompletionConsumer && + "Compiler instance has no code completion consumer!"); + return *CompletionConsumer; + } + + /// setCodeCompletionConsumer - Replace the current code completion consumer; + /// the compiler instance takes ownership of \p Value. + void setCodeCompletionConsumer(CodeCompleteConsumer *Value); + + /// } + /// @name Frontend timer + /// { + + bool hasFrontendTimer() const { return (bool)FrontendTimer; } + + llvm::Timer &getFrontendTimer() const { + assert(FrontendTimer && "Compiler instance has no frontend timer!"); + return *FrontendTimer; + } + + /// } + /// @name Output Files + /// { + + /// addOutputFile - Add an output file onto the list of tracked output files. + /// + /// \param OutFile - The output file info. + void addOutputFile(OutputFile &&OutFile); + + /// clearOutputFiles - Clear the output file list, destroying the contained + /// output streams. + /// + /// \param EraseFiles - If true, attempt to erase the files from disk. + void clearOutputFiles(bool EraseFiles); + + /// } + /// @name Construction Utility Methods + /// { + + /// Create the diagnostics engine using the invocation's diagnostic options + /// and replace any existing one with it. + /// + /// Note that this routine also replaces the diagnostic client, + /// allocating one if one is not provided. + /// + /// \param Client If non-NULL, a diagnostic client that will be + /// attached to (and, then, owned by) the DiagnosticsEngine inside this AST + /// unit. + /// + /// \param ShouldOwnClient If Client is non-NULL, specifies whether + /// the diagnostic object should take ownership of the client. + void createDiagnostics(DiagnosticConsumer *Client = nullptr, + bool ShouldOwnClient = true); + + /// Create a DiagnosticsEngine object with a the TextDiagnosticPrinter. + /// + /// If no diagnostic client is provided, this creates a + /// DiagnosticConsumer that is owned by the returned diagnostic + /// object, if using directly the caller is responsible for + /// releasing the returned DiagnosticsEngine's client eventually. + /// + /// \param Opts - The diagnostic options; note that the created text + /// diagnostic object contains a reference to these options. + /// + /// \param Client If non-NULL, a diagnostic client that will be + /// attached to (and, then, owned by) the returned DiagnosticsEngine + /// object. + /// + /// \param CodeGenOpts If non-NULL, the code gen options in use, which may be + /// used by some diagnostics printers (for logging purposes only). + /// + /// \return The new object on success, or null on failure. + static IntrusiveRefCntPtr<DiagnosticsEngine> + createDiagnostics(DiagnosticOptions *Opts, + DiagnosticConsumer *Client = nullptr, + bool ShouldOwnClient = true, + const CodeGenOptions *CodeGenOpts = nullptr); + + /// Create the file manager and replace any existing one with it. + void createFileManager(); + + /// Create the source manager and replace any existing one with it. + void createSourceManager(FileManager &FileMgr); + + /// Create the preprocessor, using the invocation, file, and source managers, + /// and replace any existing one with it. + void createPreprocessor(TranslationUnitKind TUKind); + + std::string getSpecificModuleCachePath(); + + /// Create the AST context. + void createASTContext(); + + /// Create an external AST source to read a PCH file and attach it to the AST + /// context. + void createPCHExternalASTSource(StringRef Path, bool DisablePCHValidation, + bool AllowPCHWithCompilerErrors, + void *DeserializationListener, + bool OwnDeserializationListener); + + /// Create an external AST source to read a PCH file. + /// + /// \return - The new object on success, or null on failure. + static IntrusiveRefCntPtr<ASTReader> createPCHExternalASTSource( + StringRef Path, StringRef Sysroot, bool DisablePCHValidation, + bool AllowPCHWithCompilerErrors, Preprocessor &PP, ASTContext &Context, + const PCHContainerReader &PCHContainerRdr, + ArrayRef<IntrusiveRefCntPtr<ModuleFileExtension>> Extensions, + void *DeserializationListener, bool OwnDeserializationListener, + bool Preamble, bool UseGlobalModuleIndex); + + /// Create a code completion consumer using the invocation; note that this + /// will cause the source manager to truncate the input source file at the + /// completion point. + void createCodeCompletionConsumer(); + + /// Create a code completion consumer to print code completion results, at + /// \p Filename, \p Line, and \p Column, to the given output stream \p OS. + static CodeCompleteConsumer *createCodeCompletionConsumer( + Preprocessor &PP, StringRef Filename, unsigned Line, unsigned Column, + const CodeCompleteOptions &Opts, raw_ostream &OS); + + /// \brief Create the Sema object to be used for parsing. + void createSema(TranslationUnitKind TUKind, + CodeCompleteConsumer *CompletionConsumer); + + /// Create the frontend timer and replace any existing one with it. + void createFrontendTimer(); + + /// Create the default output file (from the invocation's options) and add it + /// to the list of tracked output files. + /// + /// The files created by this function always use temporary files to write to + /// their result (that is, the data is written to a temporary file which will + /// atomically replace the target output on success). + /// + /// \return - Null on error. + raw_pwrite_stream *createDefaultOutputFile(bool Binary = true, + StringRef BaseInput = "", + StringRef Extension = ""); + + /// Create a new output file and add it to the list of tracked output files, + /// optionally deriving the output path name. + /// + /// \return - Null on error. + raw_pwrite_stream *createOutputFile(StringRef OutputPath, bool Binary, + bool RemoveFileOnSignal, + StringRef BaseInput, StringRef Extension, + bool UseTemporary, + bool CreateMissingDirectories = false); + + /// Create a new output file, optionally deriving the output path name. + /// + /// If \p OutputPath is empty, then createOutputFile will derive an output + /// path location as \p BaseInput, with any suffix removed, and \p Extension + /// appended. If \p OutputPath is not stdout and \p UseTemporary + /// is true, createOutputFile will create a new temporary file that must be + /// renamed to \p OutputPath in the end. + /// + /// \param OutputPath - If given, the path to the output file. + /// \param Error [out] - On failure, the error. + /// \param BaseInput - If \p OutputPath is empty, the input path name to use + /// for deriving the output path. + /// \param Extension - The extension to use for derived output names. + /// \param Binary - The mode to open the file in. + /// \param RemoveFileOnSignal - Whether the file should be registered with + /// llvm::sys::RemoveFileOnSignal. Note that this is not safe for + /// multithreaded use, as the underlying signal mechanism is not reentrant + /// \param UseTemporary - Create a new temporary file that must be renamed to + /// OutputPath in the end. + /// \param CreateMissingDirectories - When \p UseTemporary is true, create + /// missing directories in the output path. + /// \param ResultPathName [out] - If given, the result path name will be + /// stored here on success. + /// \param TempPathName [out] - If given, the temporary file path name + /// will be stored here on success. + std::unique_ptr<raw_pwrite_stream> + createOutputFile(StringRef OutputPath, std::error_code &Error, bool Binary, + bool RemoveFileOnSignal, StringRef BaseInput, + StringRef Extension, bool UseTemporary, + bool CreateMissingDirectories, std::string *ResultPathName, + std::string *TempPathName); + + llvm::raw_null_ostream *createNullOutputFile(); + + /// } + /// @name Initialization Utility Methods + /// { + + /// InitializeSourceManager - Initialize the source manager to set InputFile + /// as the main file. + /// + /// \return True on success. + bool InitializeSourceManager(const FrontendInputFile &Input); + + /// InitializeSourceManager - Initialize the source manager to set InputFile + /// as the main file. + /// + /// \return True on success. + static bool InitializeSourceManager(const FrontendInputFile &Input, + DiagnosticsEngine &Diags, + FileManager &FileMgr, + SourceManager &SourceMgr, + const FrontendOptions &Opts); + + /// } + + // Create module manager. + void createModuleManager(); + + bool loadModuleFile(StringRef FileName); + + ModuleLoadResult loadModule(SourceLocation ImportLoc, ModuleIdPath Path, + Module::NameVisibilityKind Visibility, + bool IsInclusionDirective) override; + + void makeModuleVisible(Module *Mod, Module::NameVisibilityKind Visibility, + SourceLocation ImportLoc) override; + + bool hadModuleLoaderFatalFailure() const { + return ModuleLoader::HadFatalFailure; + } + + GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override; + + bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override; + + void addDependencyCollector(std::shared_ptr<DependencyCollector> Listener) { + DependencyCollectors.push_back(std::move(Listener)); + } +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/CompilerInvocation.h b/contrib/llvm/tools/clang/include/clang/Frontend/CompilerInvocation.h new file mode 100644 index 0000000..0b4a1e5 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Frontend/CompilerInvocation.h @@ -0,0 +1,219 @@ +//===-- CompilerInvocation.h - Compiler Invocation Helper Data --*- 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_COMPILERINVOCATION_H_ +#define LLVM_CLANG_FRONTEND_COMPILERINVOCATION_H_ + +#include "clang/Basic/DiagnosticOptions.h" +#include "clang/Basic/FileSystemOptions.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/TargetOptions.h" +#include "clang/Frontend/CodeGenOptions.h" +#include "clang/Frontend/DependencyOutputOptions.h" +#include "clang/Frontend/FrontendOptions.h" +#include "clang/Frontend/LangStandard.h" +#include "clang/Frontend/MigratorOptions.h" +#include "clang/Frontend/PreprocessorOutputOptions.h" +#include "clang/Lex/HeaderSearchOptions.h" +#include "clang/Lex/PreprocessorOptions.h" +#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include <string> +#include <vector> + +namespace llvm { +namespace opt { +class ArgList; +} +} + +namespace clang { +class CompilerInvocation; +class DiagnosticsEngine; + +/// \brief Fill out Opts based on the options given in Args. +/// +/// Args must have been created from the OptTable returned by +/// createCC1OptTable(). +/// +/// When errors are encountered, return false and, if Diags is non-null, +/// report the error(s). +bool ParseDiagnosticArgs(DiagnosticOptions &Opts, llvm::opt::ArgList &Args, + DiagnosticsEngine *Diags = nullptr); + +class CompilerInvocationBase : public RefCountedBase<CompilerInvocation> { + void operator=(const CompilerInvocationBase &) = delete; + +public: + /// Options controlling the language variant. + std::shared_ptr<LangOptions> LangOpts; + + /// Options controlling the target. + std::shared_ptr<TargetOptions> TargetOpts; + + /// Options controlling the diagnostic engine. + IntrusiveRefCntPtr<DiagnosticOptions> DiagnosticOpts; + + /// Options controlling the \#include directive. + IntrusiveRefCntPtr<HeaderSearchOptions> HeaderSearchOpts; + + /// Options controlling the preprocessor (aside from \#include handling). + IntrusiveRefCntPtr<PreprocessorOptions> PreprocessorOpts; + + CompilerInvocationBase(); + ~CompilerInvocationBase(); + + CompilerInvocationBase(const CompilerInvocationBase &X); + + LangOptions *getLangOpts() { return LangOpts.get(); } + const LangOptions *getLangOpts() const { return LangOpts.get(); } + + TargetOptions &getTargetOpts() { return *TargetOpts.get(); } + const TargetOptions &getTargetOpts() const { + return *TargetOpts.get(); + } + + DiagnosticOptions &getDiagnosticOpts() const { return *DiagnosticOpts; } + + HeaderSearchOptions &getHeaderSearchOpts() { return *HeaderSearchOpts; } + const HeaderSearchOptions &getHeaderSearchOpts() const { + return *HeaderSearchOpts; + } + + PreprocessorOptions &getPreprocessorOpts() { return *PreprocessorOpts; } + const PreprocessorOptions &getPreprocessorOpts() const { + return *PreprocessorOpts; + } +}; + +/// \brief Helper class for holding the data necessary to invoke the compiler. +/// +/// This class is designed to represent an abstract "invocation" of the +/// compiler, including data such as the include paths, the code generation +/// options, the warning flags, and so on. +class CompilerInvocation : public CompilerInvocationBase { + /// Options controlling the static analyzer. + AnalyzerOptionsRef AnalyzerOpts; + + MigratorOptions MigratorOpts; + + /// Options controlling IRgen and the backend. + CodeGenOptions CodeGenOpts; + + /// Options controlling dependency output. + DependencyOutputOptions DependencyOutputOpts; + + /// Options controlling file system operations. + FileSystemOptions FileSystemOpts; + + /// Options controlling the frontend itself. + FrontendOptions FrontendOpts; + + /// Options controlling preprocessed output. + PreprocessorOutputOptions PreprocessorOutputOpts; + +public: + CompilerInvocation() : AnalyzerOpts(new AnalyzerOptions()) {} + + /// @name Utility Methods + /// @{ + + /// \brief Create a compiler invocation from a list of input options. + /// \returns true on success. + /// + /// \param [out] Res - The resulting invocation. + /// \param ArgBegin - The first element in the argument vector. + /// \param ArgEnd - The last element in the argument vector. + /// \param Diags - The diagnostic engine to use for errors. + static bool CreateFromArgs(CompilerInvocation &Res, + const char* const *ArgBegin, + const char* const *ArgEnd, + DiagnosticsEngine &Diags); + + /// \brief Get the directory where the compiler headers + /// reside, relative to the compiler binary (found by the passed in + /// arguments). + /// + /// \param Argv0 - The program path (from argv[0]), for finding the builtin + /// compiler path. + /// \param MainAddr - The address of main (or some other function in the main + /// executable), for finding the builtin compiler path. + static std::string GetResourcesPath(const char *Argv0, void *MainAddr); + + /// \brief Set language defaults for the given input language and + /// language standard in the given LangOptions object. + /// + /// \param Opts - The LangOptions object to set up. + /// \param IK - The input language. + /// \param LangStd - The input language standard. + static void setLangDefaults(LangOptions &Opts, InputKind IK, + LangStandard::Kind LangStd = LangStandard::lang_unspecified); + + /// \brief Retrieve a module hash string that is suitable for uniquely + /// identifying the conditions under which the module was built. + std::string getModuleHash() const; + + /// @} + /// @name Option Subgroups + /// @{ + + AnalyzerOptionsRef getAnalyzerOpts() const { + return AnalyzerOpts; + } + + MigratorOptions &getMigratorOpts() { return MigratorOpts; } + const MigratorOptions &getMigratorOpts() const { + return MigratorOpts; + } + + CodeGenOptions &getCodeGenOpts() { return CodeGenOpts; } + const CodeGenOptions &getCodeGenOpts() const { + return CodeGenOpts; + } + + DependencyOutputOptions &getDependencyOutputOpts() { + return DependencyOutputOpts; + } + const DependencyOutputOptions &getDependencyOutputOpts() const { + return DependencyOutputOpts; + } + + FileSystemOptions &getFileSystemOpts() { return FileSystemOpts; } + const FileSystemOptions &getFileSystemOpts() const { + return FileSystemOpts; + } + + FrontendOptions &getFrontendOpts() { return FrontendOpts; } + const FrontendOptions &getFrontendOpts() const { + return FrontendOpts; + } + + PreprocessorOutputOptions &getPreprocessorOutputOpts() { + return PreprocessorOutputOpts; + } + const PreprocessorOutputOptions &getPreprocessorOutputOpts() const { + return PreprocessorOutputOpts; + } + + /// @} +}; + +namespace vfs { + class FileSystem; +} + +IntrusiveRefCntPtr<vfs::FileSystem> +createVFSFromCompilerInvocation(const CompilerInvocation &CI, + DiagnosticsEngine &Diags); + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/DependencyOutputOptions.h b/contrib/llvm/tools/clang/include/clang/Frontend/DependencyOutputOptions.h new file mode 100644 index 0000000..129b534 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Frontend/DependencyOutputOptions.h @@ -0,0 +1,73 @@ +//===--- DependencyOutputOptions.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_DEPENDENCYOUTPUTOPTIONS_H +#define LLVM_CLANG_FRONTEND_DEPENDENCYOUTPUTOPTIONS_H + +#include <string> +#include <vector> + +namespace clang { + +/// DependencyOutputFormat - Format for the compiler dependency file. +enum class DependencyOutputFormat { Make, NMake }; + +/// DependencyOutputOptions - Options for controlling the compiler dependency +/// file generation. +class DependencyOutputOptions { +public: + unsigned IncludeSystemHeaders : 1; ///< Include system header dependencies. + unsigned ShowHeaderIncludes : 1; ///< Show header inclusions (-H). + unsigned UsePhonyTargets : 1; ///< Include phony targets for each + /// dependency, which can avoid some 'make' + /// problems. + unsigned AddMissingHeaderDeps : 1; ///< Add missing headers to dependency list + unsigned PrintShowIncludes : 1; ///< Print cl.exe style /showIncludes info. + unsigned IncludeModuleFiles : 1; ///< Include module file dependencies. + + /// The format for the dependency file. + DependencyOutputFormat OutputFormat; + + /// The file to write dependency output to. + std::string OutputFile; + + /// The file to write header include output to. This is orthogonal to + /// ShowHeaderIncludes (-H) and will include headers mentioned in the + /// predefines buffer. If the output file is "-", output will be sent to + /// stderr. + std::string HeaderIncludeOutputFile; + + /// A list of names to use as the targets in the dependency file; this list + /// must contain at least one entry. + std::vector<std::string> Targets; + + /// A list of filenames to be used as extra dependencies for every target. + std::vector<std::string> ExtraDeps; + + /// \brief The file to write GraphViz-formatted header dependencies to. + std::string DOTOutputFile; + + /// \brief The directory to copy module dependencies to when collecting them. + std::string ModuleDependencyOutputDir; + +public: + DependencyOutputOptions() { + IncludeSystemHeaders = 0; + ShowHeaderIncludes = 0; + UsePhonyTargets = 0; + AddMissingHeaderDeps = 0; + PrintShowIncludes = 0; + IncludeModuleFiles = 0; + OutputFormat = DependencyOutputFormat::Make; + } +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/DiagnosticRenderer.h b/contrib/llvm/tools/clang/include/clang/Frontend/DiagnosticRenderer.h new file mode 100644 index 0000000..c372fdd --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Frontend/DiagnosticRenderer.h @@ -0,0 +1,178 @@ +//===--- DiagnosticRenderer.h - Diagnostic Pretty-Printing ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a utility class that provides support for pretty-printing of +// diagnostics. It is used to implement the different code paths which require +// such functionality in a consistent way. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_DIAGNOSTICRENDERER_H +#define LLVM_CLANG_FRONTEND_DIAGNOSTICRENDERER_H + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/PointerUnion.h" + +namespace clang { + +class DiagnosticOptions; +class LangOptions; +class SourceManager; + +typedef llvm::PointerUnion<const Diagnostic *, + const StoredDiagnostic *> DiagOrStoredDiag; + +/// \brief Class to encapsulate the logic for formatting a diagnostic message. +/// +/// Actual "printing" logic is implemented by subclasses. +/// +/// This class provides an interface for building and emitting +/// diagnostic, including all of the macro backtraces, caret diagnostics, FixIt +/// Hints, and code snippets. In the presence of macros this involves +/// a recursive process, synthesizing notes for each macro expansion. +/// +/// A brief worklist: +/// FIXME: Sink the recursive printing of template instantiations into this +/// class. +class DiagnosticRenderer { +protected: + const LangOptions &LangOpts; + IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts; + + /// \brief The location of the previous diagnostic if known. + /// + /// This will be invalid in cases where there is no (known) previous + /// diagnostic location, or that location itself is invalid or comes from + /// a different source manager than SM. + SourceLocation LastLoc; + + /// \brief The location of the last include whose stack was printed if known. + /// + /// Same restriction as LastLoc essentially, but tracking include stack + /// root locations rather than diagnostic locations. + SourceLocation LastIncludeLoc; + + /// \brief The level of the last diagnostic emitted. + /// + /// The level of the last diagnostic emitted. Used to detect level changes + /// which change the amount of information displayed. + DiagnosticsEngine::Level LastLevel; + + DiagnosticRenderer(const LangOptions &LangOpts, + DiagnosticOptions *DiagOpts); + + virtual ~DiagnosticRenderer(); + + virtual void emitDiagnosticMessage(SourceLocation Loc, PresumedLoc PLoc, + DiagnosticsEngine::Level Level, + StringRef Message, + ArrayRef<CharSourceRange> Ranges, + const SourceManager *SM, + DiagOrStoredDiag Info) = 0; + + virtual void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, + DiagnosticsEngine::Level Level, + ArrayRef<CharSourceRange> Ranges, + const SourceManager &SM) = 0; + + virtual void emitCodeContext(SourceLocation Loc, + DiagnosticsEngine::Level Level, + SmallVectorImpl<CharSourceRange>& Ranges, + ArrayRef<FixItHint> Hints, + const SourceManager &SM) = 0; + + virtual void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc, + const SourceManager &SM) = 0; + virtual void emitImportLocation(SourceLocation Loc, PresumedLoc PLoc, + StringRef ModuleName, + const SourceManager &SM) = 0; + virtual void emitBuildingModuleLocation(SourceLocation Loc, PresumedLoc PLoc, + StringRef ModuleName, + const SourceManager &SM) = 0; + + virtual void beginDiagnostic(DiagOrStoredDiag D, + DiagnosticsEngine::Level Level) {} + virtual void endDiagnostic(DiagOrStoredDiag D, + DiagnosticsEngine::Level Level) {} + + +private: + void emitBasicNote(StringRef Message); + void emitIncludeStack(SourceLocation Loc, PresumedLoc PLoc, + DiagnosticsEngine::Level Level, const SourceManager &SM); + void emitIncludeStackRecursively(SourceLocation Loc, const SourceManager &SM); + void emitImportStack(SourceLocation Loc, const SourceManager &SM); + void emitImportStackRecursively(SourceLocation Loc, StringRef ModuleName, + const SourceManager &SM); + void emitModuleBuildStack(const SourceManager &SM); + void emitCaret(SourceLocation Loc, DiagnosticsEngine::Level Level, + ArrayRef<CharSourceRange> Ranges, ArrayRef<FixItHint> Hints, + const SourceManager &SM); + void emitSingleMacroExpansion(SourceLocation Loc, + DiagnosticsEngine::Level Level, + ArrayRef<CharSourceRange> Ranges, + const SourceManager &SM); + void emitMacroExpansions(SourceLocation Loc, + DiagnosticsEngine::Level Level, + ArrayRef<CharSourceRange> Ranges, + ArrayRef<FixItHint> Hints, + const SourceManager &SM); +public: + /// \brief Emit a diagnostic. + /// + /// This is the primary entry point for emitting diagnostic messages. + /// It handles formatting and rendering the message as well as any ancillary + /// information needed based on macros whose expansions impact the + /// diagnostic. + /// + /// \param Loc The location for this caret. + /// \param Level The level of the diagnostic to be emitted. + /// \param Message The diagnostic message to emit. + /// \param Ranges The underlined ranges for this code snippet. + /// \param FixItHints The FixIt hints active for this diagnostic. + /// \param SM The SourceManager; will be null if the diagnostic came from the + /// frontend, thus \p Loc will be invalid. + void emitDiagnostic(SourceLocation Loc, DiagnosticsEngine::Level Level, + StringRef Message, ArrayRef<CharSourceRange> Ranges, + ArrayRef<FixItHint> FixItHints, + const SourceManager *SM, + DiagOrStoredDiag D = (Diagnostic *)nullptr); + + void emitStoredDiagnostic(StoredDiagnostic &Diag); +}; + +/// Subclass of DiagnosticRender that turns all subdiagostics into explicit +/// notes. It is up to subclasses to further define the behavior. +class DiagnosticNoteRenderer : public DiagnosticRenderer { +public: + DiagnosticNoteRenderer(const LangOptions &LangOpts, + DiagnosticOptions *DiagOpts) + : DiagnosticRenderer(LangOpts, DiagOpts) {} + + ~DiagnosticNoteRenderer() override; + + void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc, + const SourceManager &SM) override; + + void emitImportLocation(SourceLocation Loc, PresumedLoc PLoc, + StringRef ModuleName, + const SourceManager &SM) override; + + void emitBuildingModuleLocation(SourceLocation Loc, PresumedLoc PLoc, + StringRef ModuleName, + const SourceManager &SM) override; + + virtual void emitNote(SourceLocation Loc, StringRef Message, + const SourceManager *SM) = 0; +}; +} // end clang namespace +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/FrontendAction.h b/contrib/llvm/tools/clang/include/clang/Frontend/FrontendAction.h new file mode 100644 index 0000000..c407ff8 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Frontend/FrontendAction.h @@ -0,0 +1,298 @@ +//===-- FrontendAction.h - Generic Frontend Action Interface ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the clang::FrontendAction interface and various convenience +/// abstract classes (clang::ASTFrontendAction, clang::PluginASTAction, +/// clang::PreprocessorFrontendAction, and clang::WrapperFrontendAction) +/// derived from it. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_FRONTENDACTION_H +#define LLVM_CLANG_FRONTEND_FRONTENDACTION_H + +#include "clang/AST/ASTConsumer.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/Frontend/FrontendOptions.h" +#include "llvm/ADT/StringRef.h" +#include <memory> +#include <string> +#include <vector> + +namespace clang { +class ASTMergeAction; +class CompilerInstance; + +/// Abstract base class for actions which can be performed by the frontend. +class FrontendAction { + FrontendInputFile CurrentInput; + std::unique_ptr<ASTUnit> CurrentASTUnit; + CompilerInstance *Instance; + friend class ASTMergeAction; + friend class WrapperFrontendAction; + +private: + std::unique_ptr<ASTConsumer> CreateWrappedASTConsumer(CompilerInstance &CI, + StringRef InFile); + +protected: + /// @name Implementation Action Interface + /// @{ + + /// \brief Create the AST consumer object for this action, if supported. + /// + /// This routine is called as part of BeginSourceFile(), which will + /// fail if the AST consumer cannot be created. This will not be called if the + /// action has indicated that it only uses the preprocessor. + /// + /// \param CI - The current compiler instance, provided as a convenience, see + /// getCompilerInstance(). + /// + /// \param InFile - The current input file, provided as a convenience, see + /// getCurrentFile(). + /// + /// \return The new AST consumer, or null on failure. + virtual std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) = 0; + + /// \brief Callback before starting processing a single input, giving the + /// opportunity to modify the CompilerInvocation or do some other action + /// before BeginSourceFileAction is called. + /// + /// \return True on success; on failure BeginSourceFileAction(), + /// ExecuteAction() and EndSourceFileAction() will not be called. + virtual bool BeginInvocation(CompilerInstance &CI) { return true; } + + /// \brief Callback at the start of processing a single input. + /// + /// \return True on success; on failure ExecutionAction() and + /// EndSourceFileAction() will not be called. + virtual bool BeginSourceFileAction(CompilerInstance &CI, + StringRef Filename) { + return true; + } + + /// \brief Callback to run the program action, using the initialized + /// compiler instance. + /// + /// This is guaranteed to only be called between BeginSourceFileAction() + /// and EndSourceFileAction(). + virtual void ExecuteAction() = 0; + + /// \brief Callback at the end of processing a single input. + /// + /// This is guaranteed to only be called following a successful call to + /// BeginSourceFileAction (and BeginSourceFile). + virtual void EndSourceFileAction() {} + + /// \brief Callback at the end of processing a single input, to determine + /// if the output files should be erased or not. + /// + /// By default it returns true if a compiler error occurred. + /// This is guaranteed to only be called following a successful call to + /// BeginSourceFileAction (and BeginSourceFile). + virtual bool shouldEraseOutputFiles(); + + /// @} + +public: + FrontendAction(); + virtual ~FrontendAction(); + + /// @name Compiler Instance Access + /// @{ + + CompilerInstance &getCompilerInstance() const { + assert(Instance && "Compiler instance not registered!"); + return *Instance; + } + + void setCompilerInstance(CompilerInstance *Value) { Instance = Value; } + + /// @} + /// @name Current File Information + /// @{ + + bool isCurrentFileAST() const { + assert(!CurrentInput.isEmpty() && "No current file!"); + return (bool)CurrentASTUnit; + } + + const FrontendInputFile &getCurrentInput() const { + return CurrentInput; + } + + const StringRef getCurrentFile() const { + assert(!CurrentInput.isEmpty() && "No current file!"); + return CurrentInput.getFile(); + } + + InputKind getCurrentFileKind() const { + assert(!CurrentInput.isEmpty() && "No current file!"); + return CurrentInput.getKind(); + } + + ASTUnit &getCurrentASTUnit() const { + assert(CurrentASTUnit && "No current AST unit!"); + return *CurrentASTUnit; + } + + std::unique_ptr<ASTUnit> takeCurrentASTUnit() { + return std::move(CurrentASTUnit); + } + + void setCurrentInput(const FrontendInputFile &CurrentInput, + std::unique_ptr<ASTUnit> AST = nullptr); + + /// @} + /// @name Supported Modes + /// @{ + + /// \brief Is this action invoked on a model file? + /// + /// Model files are incomplete translation units that relies on type + /// information from another translation unit. Check ParseModelFileAction for + /// details. + virtual bool isModelParsingAction() const { return false; } + + /// \brief Does this action only use the preprocessor? + /// + /// If so no AST context will be created and this action will be invalid + /// with AST file inputs. + virtual bool usesPreprocessorOnly() const = 0; + + /// \brief For AST-based actions, the kind of translation unit we're handling. + virtual TranslationUnitKind getTranslationUnitKind() { return TU_Complete; } + + /// \brief Does this action support use with PCH? + virtual bool hasPCHSupport() const { return !usesPreprocessorOnly(); } + + /// \brief Does this action support use with AST files? + virtual bool hasASTFileSupport() const { return !usesPreprocessorOnly(); } + + /// \brief Does this action support use with IR files? + virtual bool hasIRSupport() const { return false; } + + /// \brief Does this action support use with code completion? + virtual bool hasCodeCompletionSupport() const { return false; } + + /// @} + /// @name Public Action Interface + /// @{ + + /// \brief Prepare the action for processing the input file \p Input. + /// + /// This is run after the options and frontend have been initialized, + /// but prior to executing any per-file processing. + /// + /// \param CI - The compiler instance this action is being run from. The + /// action may store and use this object up until the matching EndSourceFile + /// action. + /// + /// \param Input - The input filename and kind. Some input kinds are handled + /// specially, for example AST inputs, since the AST file itself contains + /// several objects which would normally be owned by the + /// CompilerInstance. When processing AST input files, these objects should + /// generally not be initialized in the CompilerInstance -- they will + /// automatically be shared with the AST file in between + /// BeginSourceFile() and EndSourceFile(). + /// + /// \return True on success; on failure the compilation of this file should + /// be aborted and neither Execute() nor EndSourceFile() should be called. + bool BeginSourceFile(CompilerInstance &CI, const FrontendInputFile &Input); + + /// \brief Set the source manager's main input file, and run the action. + bool Execute(); + + /// \brief Perform any per-file post processing, deallocate per-file + /// objects, and run statistics and output file cleanup code. + void EndSourceFile(); + + /// @} +}; + +/// \brief Abstract base class to use for AST consumer-based frontend actions. +class ASTFrontendAction : public FrontendAction { +protected: + /// \brief Implement the ExecuteAction interface by running Sema on + /// the already-initialized AST consumer. + /// + /// This will also take care of instantiating a code completion consumer if + /// the user requested it and the action supports it. + void ExecuteAction() override; + +public: + ASTFrontendAction() {} + bool usesPreprocessorOnly() const override { return false; } +}; + +class PluginASTAction : public ASTFrontendAction { + virtual void anchor(); +public: + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override = 0; + + /// \brief Parse the given plugin command line arguments. + /// + /// \param CI - The compiler instance, for use in reporting diagnostics. + /// \return True if the parsing succeeded; otherwise the plugin will be + /// destroyed and no action run. The plugin is responsible for using the + /// CompilerInstance's Diagnostic object to report errors. + virtual bool ParseArgs(const CompilerInstance &CI, + const std::vector<std::string> &arg) = 0; +}; + +/// \brief Abstract base class to use for preprocessor-based frontend actions. +class PreprocessorFrontendAction : public FrontendAction { +protected: + /// \brief Provide a default implementation which returns aborts; + /// this method should never be called by FrontendAction clients. + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override; + +public: + bool usesPreprocessorOnly() const override { return true; } +}; + +/// \brief A frontend action which simply wraps some other runtime-specified +/// frontend action. +/// +/// Deriving from this class allows an action to inject custom logic around +/// some existing action's behavior. It implements every virtual method in +/// the FrontendAction interface by forwarding to the wrapped action. +class WrapperFrontendAction : public FrontendAction { + std::unique_ptr<FrontendAction> WrappedAction; + +protected: + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override; + bool BeginInvocation(CompilerInstance &CI) override; + bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) override; + void ExecuteAction() override; + void EndSourceFileAction() override; + +public: + /// Construct a WrapperFrontendAction from an existing action, taking + /// ownership of it. + WrapperFrontendAction(FrontendAction *WrappedAction); + + bool usesPreprocessorOnly() const override; + TranslationUnitKind getTranslationUnitKind() override; + bool hasPCHSupport() const override; + bool hasASTFileSupport() const override; + bool hasIRSupport() const override; + bool hasCodeCompletionSupport() const override; +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/FrontendActions.h b/contrib/llvm/tools/clang/include/clang/Frontend/FrontendActions.h new file mode 100644 index 0000000..f61775f --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Frontend/FrontendActions.h @@ -0,0 +1,241 @@ +//===-- FrontendActions.h - Useful Frontend Actions -------------*- 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_FRONTENDACTIONS_H +#define LLVM_CLANG_FRONTEND_FRONTENDACTIONS_H + +#include "clang/Frontend/FrontendAction.h" +#include <string> +#include <vector> + +namespace clang { + +class Module; +class FileEntry; + +//===----------------------------------------------------------------------===// +// Custom Consumer Actions +//===----------------------------------------------------------------------===// + +class InitOnlyAction : public FrontendAction { + void ExecuteAction() override; + + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override; + +public: + // Don't claim to only use the preprocessor, we want to follow the AST path, + // but do nothing. + bool usesPreprocessorOnly() const override { return false; } +}; + +//===----------------------------------------------------------------------===// +// AST Consumer Actions +//===----------------------------------------------------------------------===// + +class ASTPrintAction : public ASTFrontendAction { +protected: + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override; +}; + +class ASTDumpAction : public ASTFrontendAction { +protected: + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override; +}; + +class ASTDeclListAction : public ASTFrontendAction { +protected: + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override; +}; + +class ASTViewAction : public ASTFrontendAction { +protected: + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override; +}; + +class DeclContextPrintAction : public ASTFrontendAction { +protected: + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override; +}; + +class GeneratePCHAction : public ASTFrontendAction { +protected: + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override; + + TranslationUnitKind getTranslationUnitKind() override { + return TU_Prefix; + } + + bool hasASTFileSupport() const override { return false; } + +public: + /// \brief Compute the AST consumer arguments that will be used to + /// create the PCHGenerator instance returned by CreateASTConsumer. + /// + /// \returns true if an error occurred, false otherwise. + static raw_pwrite_stream * + ComputeASTConsumerArguments(CompilerInstance &CI, StringRef InFile, + std::string &Sysroot, std::string &OutputFile); +}; + +class GenerateModuleAction : public ASTFrontendAction { + clang::Module *Module; + const FileEntry *ModuleMapForUniquing; + bool IsSystem; + +protected: + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override; + + TranslationUnitKind getTranslationUnitKind() override { + return TU_Module; + } + + bool hasASTFileSupport() const override { return false; } + +public: + GenerateModuleAction(const FileEntry *ModuleMap = nullptr, + bool IsSystem = false) + : ASTFrontendAction(), ModuleMapForUniquing(ModuleMap), IsSystem(IsSystem) + { } + + bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) override; + + /// \brief Compute the AST consumer arguments that will be used to + /// create the PCHGenerator instance returned by CreateASTConsumer. + /// + /// \returns true if an error occurred, false otherwise. + raw_pwrite_stream *ComputeASTConsumerArguments(CompilerInstance &CI, + StringRef InFile, + std::string &Sysroot, + std::string &OutputFile); +}; + +class SyntaxOnlyAction : public ASTFrontendAction { +protected: + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override; + +public: + bool hasCodeCompletionSupport() const override { return true; } +}; + +/// \brief Dump information about the given module file, to be used for +/// basic debugging and discovery. +class DumpModuleInfoAction : public ASTFrontendAction { +protected: + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override; + void ExecuteAction() override; + +public: + bool hasPCHSupport() const override { return false; } + bool hasASTFileSupport() const override { return true; } + bool hasIRSupport() const override { return false; } + bool hasCodeCompletionSupport() const override { return false; } +}; + +class VerifyPCHAction : public ASTFrontendAction { +protected: + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override; + + void ExecuteAction() override; + +public: + bool hasCodeCompletionSupport() const override { return false; } +}; + +/** + * \brief Frontend action adaptor that merges ASTs together. + * + * This action takes an existing AST file and "merges" it into the AST + * context, producing a merged context. This action is an action + * adaptor, which forwards most of its calls to another action that + * will consume the merged context. + */ +class ASTMergeAction : public FrontendAction { + /// \brief The action that the merge action adapts. + FrontendAction *AdaptedAction; + + /// \brief The set of AST files to merge. + std::vector<std::string> ASTFiles; + +protected: + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override; + + bool BeginSourceFileAction(CompilerInstance &CI, + StringRef Filename) override; + + void ExecuteAction() override; + void EndSourceFileAction() override; + +public: + ASTMergeAction(FrontendAction *AdaptedAction, ArrayRef<std::string> ASTFiles); + ~ASTMergeAction() override; + + bool usesPreprocessorOnly() const override; + TranslationUnitKind getTranslationUnitKind() override; + bool hasPCHSupport() const override; + bool hasASTFileSupport() const override; + bool hasCodeCompletionSupport() const override; +}; + +class PrintPreambleAction : public FrontendAction { +protected: + void ExecuteAction() override; + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &, + StringRef) override { + return nullptr; + } + + bool usesPreprocessorOnly() const override { return true; } +}; + +//===----------------------------------------------------------------------===// +// Preprocessor Actions +//===----------------------------------------------------------------------===// + +class DumpRawTokensAction : public PreprocessorFrontendAction { +protected: + void ExecuteAction() override; +}; + +class DumpTokensAction : public PreprocessorFrontendAction { +protected: + void ExecuteAction() override; +}; + +class GeneratePTHAction : public PreprocessorFrontendAction { +protected: + void ExecuteAction() override; +}; + +class PreprocessOnlyAction : public PreprocessorFrontendAction { +protected: + void ExecuteAction() override; +}; + +class PrintPreprocessedAction : public PreprocessorFrontendAction { +protected: + void ExecuteAction() override; + + bool hasPCHSupport() const override { return true; } +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/FrontendDiagnostic.h b/contrib/llvm/tools/clang/include/clang/Frontend/FrontendDiagnostic.h new file mode 100644 index 0000000..0f37b7e --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Frontend/FrontendDiagnostic.h @@ -0,0 +1,28 @@ +//===--- DiagnosticFrontend.h - Diagnostics for frontend --------*- 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_FRONTENDDIAGNOSTIC_H +#define LLVM_CLANG_FRONTEND_FRONTENDDIAGNOSTIC_H + +#include "clang/Basic/Diagnostic.h" + +namespace clang { + namespace diag { + enum { +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\ + SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM, +#define FRONTENDSTART +#include "clang/Basic/DiagnosticFrontendKinds.inc" +#undef DIAG + NUM_BUILTIN_FRONTEND_DIAGNOSTICS + }; + } // end namespace diag +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/FrontendOptions.h b/contrib/llvm/tools/clang/include/clang/Frontend/FrontendOptions.h new file mode 100644 index 0000000..c800a51 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Frontend/FrontendOptions.h @@ -0,0 +1,292 @@ +//===--- FrontendOptions.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_FRONTENDOPTIONS_H +#define LLVM_CLANG_FRONTEND_FRONTENDOPTIONS_H + +#include "clang/Frontend/CommandLineSourceLoc.h" +#include "clang/Serialization/ModuleFileExtension.h" +#include "clang/Sema/CodeCompleteOptions.h" +#include "llvm/ADT/StringRef.h" +#include <string> +#include <vector> + +namespace llvm { +class MemoryBuffer; +} + +namespace clang { + +namespace frontend { + enum ActionKind { + ASTDeclList, ///< Parse ASTs and list Decl nodes. + ASTDump, ///< Parse ASTs and dump them. + ASTPrint, ///< Parse ASTs and print them. + ASTView, ///< Parse ASTs and view them in Graphviz. + DumpRawTokens, ///< Dump out raw tokens. + DumpTokens, ///< Dump out preprocessed tokens. + EmitAssembly, ///< Emit a .s file. + EmitBC, ///< Emit a .bc file. + EmitHTML, ///< Translate input source into HTML. + EmitLLVM, ///< Emit a .ll file. + EmitLLVMOnly, ///< Generate LLVM IR, but do not emit anything. + EmitCodeGenOnly, ///< Generate machine code, but don't emit anything. + EmitObj, ///< Emit a .o file. + FixIt, ///< Parse and apply any fixits to the source. + GenerateModule, ///< Generate pre-compiled module. + GeneratePCH, ///< Generate pre-compiled header. + GeneratePTH, ///< Generate pre-tokenized header. + InitOnly, ///< Only execute frontend initialization. + ModuleFileInfo, ///< Dump information about a module file. + VerifyPCH, ///< Load and verify that a PCH file is usable. + ParseSyntaxOnly, ///< Parse and perform semantic analysis. + PluginAction, ///< Run a plugin action, \see ActionName. + PrintDeclContext, ///< Print DeclContext and their Decls. + PrintPreamble, ///< Print the "preamble" of the input file + PrintPreprocessedInput, ///< -E mode. + RewriteMacros, ///< Expand macros but not \#includes. + RewriteObjC, ///< ObjC->C Rewriter. + RewriteTest, ///< Rewriter playground + RunAnalysis, ///< Run one or more source code analyses. + MigrateSource, ///< Run migrator. + RunPreprocessorOnly ///< Just lex, no output. + }; +} + +enum InputKind { + IK_None, + IK_Asm, + IK_C, + IK_CXX, + IK_ObjC, + IK_ObjCXX, + IK_PreprocessedC, + IK_PreprocessedCXX, + IK_PreprocessedObjC, + IK_PreprocessedObjCXX, + IK_OpenCL, + IK_CUDA, + IK_PreprocessedCuda, + IK_AST, + IK_LLVM_IR +}; + + +/// \brief An input file for the front end. +class FrontendInputFile { + /// \brief The file name, or "-" to read from standard input. + std::string File; + + llvm::MemoryBuffer *Buffer; + + /// \brief The kind of input, e.g., C source, AST file, LLVM IR. + InputKind Kind; + + /// \brief Whether we're dealing with a 'system' input (vs. a 'user' input). + bool IsSystem; + +public: + FrontendInputFile() : Buffer(nullptr), Kind(IK_None), IsSystem(false) { } + FrontendInputFile(StringRef File, InputKind Kind, bool IsSystem = false) + : File(File.str()), Buffer(nullptr), Kind(Kind), IsSystem(IsSystem) { } + FrontendInputFile(llvm::MemoryBuffer *buffer, InputKind Kind, + bool IsSystem = false) + : Buffer(buffer), Kind(Kind), IsSystem(IsSystem) { } + + InputKind getKind() const { return Kind; } + bool isSystem() const { return IsSystem; } + + bool isEmpty() const { return File.empty() && Buffer == nullptr; } + bool isFile() const { return !isBuffer(); } + bool isBuffer() const { return Buffer != nullptr; } + + StringRef getFile() const { + assert(isFile()); + return File; + } + llvm::MemoryBuffer *getBuffer() const { + assert(isBuffer()); + return Buffer; + } +}; + +/// FrontendOptions - Options for controlling the behavior of the frontend. +class FrontendOptions { +public: + unsigned DisableFree : 1; ///< Disable memory freeing on exit. + unsigned RelocatablePCH : 1; ///< When generating PCH files, + /// instruct the AST writer to create + /// relocatable PCH files. + unsigned ShowHelp : 1; ///< Show the -help text. + unsigned ShowStats : 1; ///< Show frontend performance + /// metrics and statistics. + unsigned ShowTimers : 1; ///< Show timers for individual + /// actions. + unsigned ShowVersion : 1; ///< Show the -version text. + unsigned FixWhatYouCan : 1; ///< Apply fixes even if there are + /// unfixable errors. + unsigned FixOnlyWarnings : 1; ///< Apply fixes only for warnings. + unsigned FixAndRecompile : 1; ///< Apply fixes and recompile. + unsigned FixToTemporaries : 1; ///< Apply fixes to temporary files. + unsigned ARCMTMigrateEmitARCErrors : 1; /// Emit ARC errors even if the + /// migrator can fix them + unsigned SkipFunctionBodies : 1; ///< Skip over function bodies to + /// speed up parsing in cases you do + /// not need them (e.g. with code + /// completion). + unsigned UseGlobalModuleIndex : 1; ///< Whether we can use the + ///< global module index if available. + unsigned GenerateGlobalModuleIndex : 1; ///< Whether we can generate the + ///< global module index if needed. + unsigned ASTDumpDecls : 1; ///< Whether we include declaration + ///< dumps in AST dumps. + unsigned ASTDumpLookups : 1; ///< Whether we include lookup table + ///< dumps in AST dumps. + unsigned BuildingImplicitModule : 1; ///< Whether we are performing an + ///< implicit module build. + unsigned ModulesEmbedAllFiles : 1; ///< Whether we should embed all used + ///< files into the PCM file. + + CodeCompleteOptions CodeCompleteOpts; + + enum { + ARCMT_None, + ARCMT_Check, + ARCMT_Modify, + ARCMT_Migrate + } ARCMTAction; + + enum { + ObjCMT_None = 0, + /// \brief Enable migration to modern ObjC literals. + ObjCMT_Literals = 0x1, + /// \brief Enable migration to modern ObjC subscripting. + ObjCMT_Subscripting = 0x2, + /// \brief Enable migration to modern ObjC readonly property. + ObjCMT_ReadonlyProperty = 0x4, + /// \brief Enable migration to modern ObjC readwrite property. + ObjCMT_ReadwriteProperty = 0x8, + /// \brief Enable migration to modern ObjC property. + ObjCMT_Property = (ObjCMT_ReadonlyProperty | ObjCMT_ReadwriteProperty), + /// \brief Enable annotation of ObjCMethods of all kinds. + ObjCMT_Annotation = 0x10, + /// \brief Enable migration of ObjC methods to 'instancetype'. + ObjCMT_Instancetype = 0x20, + /// \brief Enable migration to NS_ENUM/NS_OPTIONS macros. + ObjCMT_NsMacros = 0x40, + /// \brief Enable migration to add conforming protocols. + ObjCMT_ProtocolConformance = 0x80, + /// \brief prefer 'atomic' property over 'nonatomic'. + ObjCMT_AtomicProperty = 0x100, + /// \brief annotate property with NS_RETURNS_INNER_POINTER + ObjCMT_ReturnsInnerPointerProperty = 0x200, + /// \brief use NS_NONATOMIC_IOSONLY for property 'atomic' attribute + ObjCMT_NsAtomicIOSOnlyProperty = 0x400, + /// \brief Enable inferring NS_DESIGNATED_INITIALIZER for ObjC methods. + ObjCMT_DesignatedInitializer = 0x800, + /// \brief Enable converting setter/getter expressions to property-dot syntx. + ObjCMT_PropertyDotSyntax = 0x1000, + ObjCMT_MigrateDecls = (ObjCMT_ReadonlyProperty | ObjCMT_ReadwriteProperty | + ObjCMT_Annotation | ObjCMT_Instancetype | + ObjCMT_NsMacros | ObjCMT_ProtocolConformance | + ObjCMT_NsAtomicIOSOnlyProperty | + ObjCMT_DesignatedInitializer), + ObjCMT_MigrateAll = (ObjCMT_Literals | ObjCMT_Subscripting | + ObjCMT_MigrateDecls | ObjCMT_PropertyDotSyntax) + }; + unsigned ObjCMTAction; + std::string ObjCMTWhiteListPath; + + std::string MTMigrateDir; + std::string ARCMTMigrateReportOut; + + /// The input files and their types. + std::vector<FrontendInputFile> Inputs; + + /// The output file, if any. + std::string OutputFile; + + /// If given, the new suffix for fix-it rewritten files. + std::string FixItSuffix; + + /// If given, filter dumped AST Decl nodes by this substring. + std::string ASTDumpFilter; + + /// If given, enable code completion at the provided location. + ParsedSourceLocation CodeCompletionAt; + + /// The frontend action to perform. + frontend::ActionKind ProgramAction; + + /// The name of the action to run when using a plugin action. + std::string ActionName; + + /// Args to pass to the plugin + std::vector<std::string> PluginArgs; + + /// The list of plugin actions to run in addition to the normal action. + std::vector<std::string> AddPluginActions; + + /// Args to pass to the additional plugins + std::vector<std::vector<std::string> > AddPluginArgs; + + /// The list of plugins to load. + std::vector<std::string> Plugins; + + /// The list of module file extensions. + std::vector<IntrusiveRefCntPtr<ModuleFileExtension>> ModuleFileExtensions; + + /// \brief The list of module map files to load before processing the input. + std::vector<std::string> ModuleMapFiles; + + /// \brief The list of additional prebuilt module files to load before + /// processing the input. + std::vector<std::string> ModuleFiles; + + /// \brief The list of files to embed into the compiled module file. + std::vector<std::string> ModulesEmbedFiles; + + /// \brief The list of AST files to merge. + std::vector<std::string> ASTMergeFiles; + + /// \brief A list of arguments to forward to LLVM's option processing; this + /// should only be used for debugging and experimental features. + std::vector<std::string> LLVMArgs; + + /// \brief File name of the file that will provide record layouts + /// (in the format produced by -fdump-record-layouts). + std::string OverrideRecordLayoutsFile; + + /// \brief Auxiliary triple for CUDA compilation. + std::string AuxTriple; + +public: + FrontendOptions() : + DisableFree(false), RelocatablePCH(false), ShowHelp(false), + ShowStats(false), ShowTimers(false), ShowVersion(false), + FixWhatYouCan(false), FixOnlyWarnings(false), FixAndRecompile(false), + FixToTemporaries(false), ARCMTMigrateEmitARCErrors(false), + SkipFunctionBodies(false), UseGlobalModuleIndex(true), + GenerateGlobalModuleIndex(true), ASTDumpDecls(false), ASTDumpLookups(false), + BuildingImplicitModule(false), ModulesEmbedAllFiles(false), + ARCMTAction(ARCMT_None), ObjCMTAction(ObjCMT_None), + ProgramAction(frontend::ParseSyntaxOnly) + {} + + /// getInputKindForExtension - Return the appropriate input kind for a file + /// extension. For example, "c" would return IK_C. + /// + /// \return The input kind for the extension, or IK_None if the extension is + /// not recognized. + static InputKind getInputKindForExtension(StringRef Extension); +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/FrontendPluginRegistry.h b/contrib/llvm/tools/clang/include/clang/Frontend/FrontendPluginRegistry.h new file mode 100644 index 0000000..ecab630 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Frontend/FrontendPluginRegistry.h @@ -0,0 +1,26 @@ +//===-- FrontendAction.h - Pluggable Frontend Action Interface --*- 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_FRONTENDPLUGINREGISTRY_H +#define LLVM_CLANG_FRONTEND_FRONTENDPLUGINREGISTRY_H + +#include "clang/Frontend/FrontendAction.h" +#include "llvm/Support/Registry.h" + +// Instantiated in FrontendAction.cpp. +extern template class llvm::Registry<clang::PluginASTAction>; + +namespace clang { + +/// The frontend plugin registry. +typedef llvm::Registry<PluginASTAction> FrontendPluginRegistry; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/LangStandard.h b/contrib/llvm/tools/clang/include/clang/Frontend/LangStandard.h new file mode 100644 index 0000000..8021d08 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Frontend/LangStandard.h @@ -0,0 +1,100 @@ +//===--- LangStandard.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_LANGSTANDARD_H +#define LLVM_CLANG_FRONTEND_LANGSTANDARD_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { + +namespace frontend { + +enum LangFeatures { + LineComment = (1 << 0), + C89 = (1 << 1), + C99 = (1 << 2), + C11 = (1 << 3), + CPlusPlus = (1 << 4), + CPlusPlus11 = (1 << 5), + CPlusPlus14 = (1 << 6), + CPlusPlus1z = (1 << 7), + Digraphs = (1 << 8), + GNUMode = (1 << 9), + HexFloat = (1 << 10), + ImplicitInt = (1 << 11) +}; + +} + +/// LangStandard - Information about the properties of a particular language +/// standard. +struct LangStandard { + enum Kind { +#define LANGSTANDARD(id, name, desc, features) \ + lang_##id, +#include "clang/Frontend/LangStandards.def" + lang_unspecified + }; + + const char *ShortName; + const char *Description; + unsigned Flags; + +public: + /// getName - Get the name of this standard. + const char *getName() const { return ShortName; } + + /// getDescription - Get the description of this standard. + const char *getDescription() const { return Description; } + + /// Language supports '//' comments. + bool hasLineComments() const { return Flags & frontend::LineComment; } + + /// isC89 - Language is a superset of C89. + bool isC89() const { return Flags & frontend::C89; } + + /// isC99 - Language is a superset of C99. + bool isC99() const { return Flags & frontend::C99; } + + /// isC11 - Language is a superset of C11. + bool isC11() const { return Flags & frontend::C11; } + + /// isCPlusPlus - Language is a C++ variant. + bool isCPlusPlus() const { return Flags & frontend::CPlusPlus; } + + /// isCPlusPlus11 - Language is a C++11 variant (or later). + bool isCPlusPlus11() const { return Flags & frontend::CPlusPlus11; } + + /// isCPlusPlus14 - Language is a C++14 variant (or later). + bool isCPlusPlus14() const { return Flags & frontend::CPlusPlus14; } + + /// isCPlusPlus1z - Language is a C++17 variant (or later). + bool isCPlusPlus1z() const { return Flags & frontend::CPlusPlus1z; } + + /// hasDigraphs - Language supports digraphs. + bool hasDigraphs() const { return Flags & frontend::Digraphs; } + + /// isGNUMode - Language includes GNU extensions. + bool isGNUMode() const { return Flags & frontend::GNUMode; } + + /// hasHexFloats - Language supports hexadecimal float constants. + bool hasHexFloats() const { return Flags & frontend::HexFloat; } + + /// hasImplicitInt - Language allows variables to be typed as int implicitly. + bool hasImplicitInt() const { return Flags & frontend::ImplicitInt; } + + static const LangStandard &getLangStandardForKind(Kind K); + static const LangStandard *getLangStandardForName(StringRef Name); +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/LangStandards.def b/contrib/llvm/tools/clang/include/clang/Frontend/LangStandards.def new file mode 100644 index 0000000..cac9c3c --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Frontend/LangStandards.def @@ -0,0 +1,153 @@ +//===-- LangStandards.def - Language Standard Data --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LANGSTANDARD +#error "LANGSTANDARD must be defined before including this file" +#endif + +/// LANGSTANDARD(IDENT, NAME, DESC, FEATURES) +/// +/// \param IDENT - The name of the standard as a C++ identifier. +/// \param NAME - The name of the standard. +/// \param DESC - A short description of the standard. +/// \param FEATURES - The standard features as flags, these are enums from the +/// clang::frontend namespace, which is assumed to be be available. + +// C89-ish modes. +LANGSTANDARD(c89, "c89", + "ISO C 1990", + C89 | ImplicitInt) +LANGSTANDARD(c90, "c90", + "ISO C 1990", + C89 | ImplicitInt) +LANGSTANDARD(iso9899_1990, "iso9899:1990", + "ISO C 1990", + C89 | ImplicitInt) + +LANGSTANDARD(c94, "iso9899:199409", + "ISO C 1990 with amendment 1", + C89 | Digraphs | ImplicitInt) + +LANGSTANDARD(gnu89, "gnu89", + "ISO C 1990 with GNU extensions", + LineComment | C89 | Digraphs | GNUMode | ImplicitInt) +LANGSTANDARD(gnu90, "gnu90", + "ISO C 1990 with GNU extensions", + LineComment | C89 | Digraphs | GNUMode | ImplicitInt) + +// C99-ish modes +LANGSTANDARD(c99, "c99", + "ISO C 1999", + LineComment | C99 | Digraphs | HexFloat) +LANGSTANDARD(c9x, "c9x", + "ISO C 1999", + LineComment | C99 | Digraphs | HexFloat) +LANGSTANDARD(iso9899_1999, + "iso9899:1999", "ISO C 1999", + LineComment | C99 | Digraphs | HexFloat) +LANGSTANDARD(iso9899_199x, + "iso9899:199x", "ISO C 1999", + LineComment | C99 | Digraphs | HexFloat) + +LANGSTANDARD(gnu99, "gnu99", + "ISO C 1999 with GNU extensions", + LineComment | C99 | Digraphs | GNUMode | HexFloat) +LANGSTANDARD(gnu9x, "gnu9x", + "ISO C 1999 with GNU extensions", + LineComment | C99 | Digraphs | GNUMode | HexFloat) + +// C11 modes +LANGSTANDARD(c11, "c11", + "ISO C 2011", + LineComment | C99 | C11 | Digraphs | HexFloat) +LANGSTANDARD(c1x, "c1x", + "ISO C 2011", + LineComment | C99 | C11 | Digraphs | HexFloat) +LANGSTANDARD(iso9899_2011, + "iso9899:2011", "ISO C 2011", + LineComment | C99 | C11 | Digraphs | HexFloat) +LANGSTANDARD(iso9899_201x, + "iso9899:2011", "ISO C 2011", + LineComment | C99 | C11 | Digraphs | HexFloat) + +LANGSTANDARD(gnu11, "gnu11", + "ISO C 2011 with GNU extensions", + LineComment | C99 | C11 | Digraphs | GNUMode | HexFloat) +LANGSTANDARD(gnu1x, "gnu1x", + "ISO C 2011 with GNU extensions", + LineComment | C99 | C11 | Digraphs | GNUMode | HexFloat) + +// C++ modes +LANGSTANDARD(cxx98, "c++98", + "ISO C++ 1998 with amendments", + LineComment | CPlusPlus | Digraphs) +LANGSTANDARD(cxx03, "c++03", + "ISO C++ 1998 with amendments", + LineComment | CPlusPlus | Digraphs) +LANGSTANDARD(gnucxx98, "gnu++98", + "ISO C++ 1998 with amendments and GNU extensions", + LineComment | CPlusPlus | Digraphs | GNUMode) + +LANGSTANDARD(cxx0x, "c++0x", + "ISO C++ 2011 with amendments", + LineComment | CPlusPlus | CPlusPlus11 | Digraphs) +LANGSTANDARD(cxx11, "c++11", + "ISO C++ 2011 with amendments", + LineComment | CPlusPlus | CPlusPlus11 | Digraphs) +LANGSTANDARD(gnucxx0x, "gnu++0x", + "ISO C++ 2011 with amendments and GNU extensions", + LineComment | CPlusPlus | CPlusPlus11 | Digraphs | GNUMode) +LANGSTANDARD(gnucxx11, "gnu++11", + "ISO C++ 2011 with amendments and GNU extensions", + LineComment | CPlusPlus | CPlusPlus11 | Digraphs | GNUMode) + +LANGSTANDARD(cxx1y, "c++1y", + "ISO C++ 2014 with amendments", + LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs) +LANGSTANDARD(cxx14, "c++14", + "ISO C++ 2014 with amendments", + LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs) +LANGSTANDARD(gnucxx1y, "gnu++1y", + "ISO C++ 2014 with amendments and GNU extensions", + LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs | + GNUMode) +LANGSTANDARD(gnucxx14, "gnu++14", + "ISO C++ 2014 with amendments and GNU extensions", + LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs | + GNUMode) + +LANGSTANDARD(cxx1z, "c++1z", + "Working draft for ISO C++ 2017", + LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus1z | + Digraphs) +LANGSTANDARD(gnucxx1z, "gnu++1z", + "Working draft for ISO C++ 2017 with GNU extensions", + LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus1z | + Digraphs | GNUMode) + +// OpenCL +LANGSTANDARD(opencl, "cl", + "OpenCL 1.0", + LineComment | C99 | Digraphs | HexFloat) +LANGSTANDARD(opencl11, "CL1.1", + "OpenCL 1.1", + LineComment | C99 | Digraphs | HexFloat) +LANGSTANDARD(opencl12, "CL1.2", + "OpenCL 1.2", + LineComment | C99 | Digraphs | HexFloat) +LANGSTANDARD(opencl20, "CL2.0", + "OpenCL 2.0", + LineComment | C99 | Digraphs | HexFloat) + +// CUDA +LANGSTANDARD(cuda, "cuda", + "NVIDIA CUDA(tm)", + LineComment | CPlusPlus | Digraphs) + +#undef LANGSTANDARD diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/LayoutOverrideSource.h b/contrib/llvm/tools/clang/include/clang/Frontend/LayoutOverrideSource.h new file mode 100644 index 0000000..16d032b --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Frontend/LayoutOverrideSource.h @@ -0,0 +1,63 @@ +//===--- LayoutOverrideSource.h --Override Record Layouts -----------------===// +// +// 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_LAYOUTOVERRIDESOURCE_H +#define LLVM_CLANG_FRONTEND_LAYOUTOVERRIDESOURCE_H + +#include "clang/AST/ExternalASTSource.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { + /// \brief An external AST source that overrides the layout of + /// a specified set of record types. + /// + /// This class is used only for testing the ability of external AST sources + /// to override the layout of record types. Its input is the output format + /// of the command-line argument -fdump-record-layouts. + class LayoutOverrideSource : public ExternalASTSource { + /// \brief The layout of a given record. + struct Layout { + /// \brief The size of the record. + uint64_t Size; + + /// \brief The alignment of the record. + uint64_t Align; + + /// \brief The offsets of the fields, in source order. + SmallVector<uint64_t, 8> FieldOffsets; + }; + + /// \brief The set of layouts that will be overridden. + llvm::StringMap<Layout> Layouts; + + public: + /// \brief Create a new AST source that overrides the layout of some + /// set of record types. + /// + /// The file is the result of passing -fdump-record-layouts to a file. + explicit LayoutOverrideSource(StringRef Filename); + + /// \brief If this particular record type has an overridden layout, + /// return that layout. + bool + layoutRecordType(const RecordDecl *Record, + uint64_t &Size, uint64_t &Alignment, + llvm::DenseMap<const FieldDecl *, uint64_t> &FieldOffsets, + llvm::DenseMap<const CXXRecordDecl *, CharUnits> &BaseOffsets, + llvm::DenseMap<const CXXRecordDecl *, + CharUnits> &VirtualBaseOffsets) override; + + /// \brief Dump the overridden layouts. + void dump(); + }; +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/LogDiagnosticPrinter.h b/contrib/llvm/tools/clang/include/clang/Frontend/LogDiagnosticPrinter.h new file mode 100644 index 0000000..98adf65 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Frontend/LogDiagnosticPrinter.h @@ -0,0 +1,85 @@ +//===--- LogDiagnosticPrinter.h - Log Diagnostic Client ---------*- 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_LOGDIAGNOSTICPRINTER_H +#define LLVM_CLANG_FRONTEND_LOGDIAGNOSTICPRINTER_H + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { +class DiagnosticOptions; +class LangOptions; + +class LogDiagnosticPrinter : public DiagnosticConsumer { + struct DiagEntry { + /// The primary message line of the diagnostic. + std::string Message; + + /// The source file name, if available. + std::string Filename; + + /// The source file line number, if available. + unsigned Line; + + /// The source file column number, if available. + unsigned Column; + + /// The ID of the diagnostic. + unsigned DiagnosticID; + + /// The Option Flag for the diagnostic + std::string WarningOption; + + /// The level of the diagnostic. + DiagnosticsEngine::Level DiagnosticLevel; + }; + + void EmitDiagEntry(llvm::raw_ostream &OS, + const LogDiagnosticPrinter::DiagEntry &DE); + + // Conditional ownership (when StreamOwner is non-null, it's keeping OS + // alive). We might want to replace this with a wrapper for conditional + // ownership eventually - it seems to pop up often enough. + raw_ostream &OS; + std::unique_ptr<raw_ostream> StreamOwner; + const LangOptions *LangOpts; + IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts; + + SourceLocation LastWarningLoc; + FullSourceLoc LastLoc; + + SmallVector<DiagEntry, 8> Entries; + + std::string MainFilename; + std::string DwarfDebugFlags; + +public: + LogDiagnosticPrinter(raw_ostream &OS, DiagnosticOptions *Diags, + std::unique_ptr<raw_ostream> StreamOwner); + + void setDwarfDebugFlags(StringRef Value) { + DwarfDebugFlags = Value; + } + + void BeginSourceFile(const LangOptions &LO, const Preprocessor *PP) override { + LangOpts = &LO; + } + + void EndSourceFile() override; + + void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, + const Diagnostic &Info) override; +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/MigratorOptions.h b/contrib/llvm/tools/clang/include/clang/Frontend/MigratorOptions.h new file mode 100644 index 0000000..8eb71b1 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Frontend/MigratorOptions.h @@ -0,0 +1,31 @@ +//===--- MigratorOptions.h - MigratorOptions Options ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header contains the structures necessary for a front-end to specify +// various migration analysis. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_MIGRATOROPTIONS_H +#define LLVM_CLANG_FRONTEND_MIGRATOROPTIONS_H + +namespace clang { + +class MigratorOptions { +public: + unsigned NoNSAllocReallocError : 1; + unsigned NoFinalizeRemoval : 1; + MigratorOptions() { + NoNSAllocReallocError = 0; + NoFinalizeRemoval = 0; + } +}; + +} +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/MultiplexConsumer.h b/contrib/llvm/tools/clang/include/clang/Frontend/MultiplexConsumer.h new file mode 100644 index 0000000..873af03 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Frontend/MultiplexConsumer.h @@ -0,0 +1,69 @@ +//===-- MultiplexConsumer.h - AST Consumer for PCH Generation ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the MultiplexConsumer class, which can be used to +// multiplex ASTConsumer and SemaConsumer messages to many consumers. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_MULTIPLEXCONSUMER_H +#define LLVM_CLANG_FRONTEND_MULTIPLEXCONSUMER_H + +#include "clang/Basic/LLVM.h" +#include "clang/Sema/SemaConsumer.h" +#include <memory> +#include <vector> + +namespace clang { + +class MultiplexASTMutationListener; +class MultiplexASTDeserializationListener; + +// Has a list of ASTConsumers and calls each of them. Owns its children. +class MultiplexConsumer : public SemaConsumer { +public: + // Takes ownership of the pointers in C. + MultiplexConsumer(std::vector<std::unique_ptr<ASTConsumer>> C); + ~MultiplexConsumer() override; + + // ASTConsumer + void Initialize(ASTContext &Context) override; + void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) override; + bool HandleTopLevelDecl(DeclGroupRef D) override; + void HandleInlineMethodDefinition(CXXMethodDecl *D) override; + void HandleInterestingDecl(DeclGroupRef D) override; + void HandleTranslationUnit(ASTContext &Ctx) override; + void HandleTagDeclDefinition(TagDecl *D) override; + void HandleTagDeclRequiredDefinition(const TagDecl *D) override; + void HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) override; + void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) override; + void HandleImplicitImportDecl(ImportDecl *D) override; + void HandleLinkerOptionPragma(llvm::StringRef Opts) override; + void HandleDetectMismatch(llvm::StringRef Name, + llvm::StringRef Value) override; + void HandleDependentLibrary(llvm::StringRef Lib) override; + void CompleteTentativeDefinition(VarDecl *D) override; + void HandleVTable(CXXRecordDecl *RD) override; + ASTMutationListener *GetASTMutationListener() override; + ASTDeserializationListener *GetASTDeserializationListener() override; + void PrintStats() override; + + // SemaConsumer + void InitializeSema(Sema &S) override; + void ForgetSema() override; + +private: + std::vector<std::unique_ptr<ASTConsumer>> Consumers; // Owns these. + std::unique_ptr<MultiplexASTMutationListener> MutationListener; + std::unique_ptr<MultiplexASTDeserializationListener> DeserializationListener; +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/PCHContainerOperations.h b/contrib/llvm/tools/clang/include/clang/Frontend/PCHContainerOperations.h new file mode 100644 index 0000000..67c36cf --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Frontend/PCHContainerOperations.h @@ -0,0 +1,118 @@ +//===--- Frontend/PCHContainerOperations.h - PCH Containers -----*- 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_PCH_CONTAINER_OPERATIONS_H +#define LLVM_CLANG_PCH_CONTAINER_OPERATIONS_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/MemoryBuffer.h" +#include <memory> + +namespace llvm { +class raw_pwrite_stream; +class BitstreamReader; +} + +using llvm::StringRef; + +namespace clang { + +class ASTConsumer; +class CodeGenOptions; +class DiagnosticsEngine; +class CompilerInstance; + +struct PCHBuffer { + uint64_t Signature; + llvm::SmallVector<char, 0> Data; + bool IsComplete; +}; + +/// This abstract interface provides operations for creating +/// containers for serialized ASTs (precompiled headers and clang +/// modules). +class PCHContainerWriter { +public: + virtual ~PCHContainerWriter() = 0; + virtual StringRef getFormat() const = 0; + + /// Return an ASTConsumer that can be chained with a + /// PCHGenerator that produces a wrapper file format containing a + /// serialized AST bitstream. + virtual std::unique_ptr<ASTConsumer> CreatePCHContainerGenerator( + CompilerInstance &CI, const std::string &MainFileName, + const std::string &OutputFileName, llvm::raw_pwrite_stream *OS, + std::shared_ptr<PCHBuffer> Buffer) const = 0; +}; + +/// This abstract interface provides operations for unwrapping +/// containers for serialized ASTs (precompiled headers and clang +/// modules). +class PCHContainerReader { +public: + virtual ~PCHContainerReader() = 0; + /// Equivalent to the format passed to -fmodule-format= + virtual StringRef getFormat() const = 0; + + /// Initialize an llvm::BitstreamReader with the serialized AST inside + /// the PCH container Buffer. + virtual void ExtractPCH(llvm::MemoryBufferRef Buffer, + llvm::BitstreamReader &StreamFile) const = 0; +}; + +/// Implements write operations for a raw pass-through PCH container. +class RawPCHContainerWriter : public PCHContainerWriter { + StringRef getFormat() const override { return "raw"; } + + /// Return an ASTConsumer that can be chained with a + /// PCHGenerator that writes the module to a flat file. + std::unique_ptr<ASTConsumer> CreatePCHContainerGenerator( + CompilerInstance &CI, const std::string &MainFileName, + const std::string &OutputFileName, llvm::raw_pwrite_stream *OS, + std::shared_ptr<PCHBuffer> Buffer) const override; +}; + +/// Implements read operations for a raw pass-through PCH container. +class RawPCHContainerReader : public PCHContainerReader { + StringRef getFormat() const override { return "raw"; } + + /// Initialize an llvm::BitstreamReader with Buffer. + void ExtractPCH(llvm::MemoryBufferRef Buffer, + llvm::BitstreamReader &StreamFile) const override; +}; + +/// A registry of PCHContainerWriter and -Reader objects for different formats. +class PCHContainerOperations { + llvm::StringMap<std::unique_ptr<PCHContainerWriter>> Writers; + llvm::StringMap<std::unique_ptr<PCHContainerReader>> Readers; +public: + /// Automatically registers a RawPCHContainerWriter and + /// RawPCHContainerReader. + PCHContainerOperations(); + void registerWriter(std::unique_ptr<PCHContainerWriter> Writer) { + Writers[Writer->getFormat()] = std::move(Writer); + } + void registerReader(std::unique_ptr<PCHContainerReader> Reader) { + Readers[Reader->getFormat()] = std::move(Reader); + } + const PCHContainerWriter *getWriterOrNull(StringRef Format) { + return Writers[Format].get(); + } + const PCHContainerReader *getReaderOrNull(StringRef Format) { + return Readers[Format].get(); + } + const PCHContainerReader &getRawReader() { + return *getReaderOrNull("raw"); + } +}; + +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/PreprocessorOutputOptions.h b/contrib/llvm/tools/clang/include/clang/Frontend/PreprocessorOutputOptions.h new file mode 100644 index 0000000..f86c490 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Frontend/PreprocessorOutputOptions.h @@ -0,0 +1,41 @@ +//===--- PreprocessorOutputOptions.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_PREPROCESSOROUTPUTOPTIONS_H +#define LLVM_CLANG_FRONTEND_PREPROCESSOROUTPUTOPTIONS_H + +namespace clang { + +/// PreprocessorOutputOptions - Options for controlling the C preprocessor +/// output (e.g., -E). +class PreprocessorOutputOptions { +public: + unsigned ShowCPP : 1; ///< Print normal preprocessed output. + unsigned ShowComments : 1; ///< Show comments. + unsigned ShowLineMarkers : 1; ///< Show \#line markers. + unsigned UseLineDirectives : 1; ///< Use \#line instead of GCC-style \# N. + unsigned ShowMacroComments : 1; ///< Show comments, even in macros. + unsigned ShowMacros : 1; ///< Print macro definitions. + unsigned RewriteIncludes : 1; ///< Preprocess include directives only. + +public: + PreprocessorOutputOptions() { + ShowCPP = 0; + ShowComments = 0; + ShowLineMarkers = 1; + UseLineDirectives = 0; + ShowMacroComments = 0; + ShowMacros = 0; + RewriteIncludes = 0; + } +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/SerializedDiagnosticPrinter.h b/contrib/llvm/tools/clang/include/clang/Frontend/SerializedDiagnosticPrinter.h new file mode 100644 index 0000000..4c57e9d --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Frontend/SerializedDiagnosticPrinter.h @@ -0,0 +1,43 @@ +//===--- SerializedDiagnosticPrinter.h - Serializer for diagnostics -------===// +// +// 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_SERIALIZEDDIAGNOSTICPRINTER_H +#define LLVM_CLANG_FRONTEND_SERIALIZEDDIAGNOSTICPRINTER_H + +#include "clang/Basic/LLVM.h" +#include "clang/Frontend/SerializedDiagnostics.h" +#include "llvm/Bitcode/BitstreamWriter.h" + +namespace llvm { +class raw_ostream; +} + +namespace clang { +class DiagnosticConsumer; +class DiagnosticsEngine; +class DiagnosticOptions; + +namespace serialized_diags { + +/// \brief Returns a DiagnosticConsumer that serializes diagnostics to +/// a bitcode file. +/// +/// The created DiagnosticConsumer is designed for quick and lightweight +/// transfer of of diagnostics to the enclosing build system (e.g., an IDE). +/// This allows wrapper tools for Clang to get diagnostics from Clang +/// (via libclang) without needing to parse Clang's command line output. +/// +std::unique_ptr<DiagnosticConsumer> create(StringRef OutputFile, + DiagnosticOptions *Diags, + bool MergeChildRecords = false); + +} // end serialized_diags namespace +} // end clang namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/SerializedDiagnosticReader.h b/contrib/llvm/tools/clang/include/clang/Frontend/SerializedDiagnosticReader.h new file mode 100644 index 0000000..3db362b --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Frontend/SerializedDiagnosticReader.h @@ -0,0 +1,131 @@ +//===--- SerializedDiagnosticReader.h - Reads diagnostics -------*- 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_SERIALIZED_DIAGNOSTIC_READER_H_ +#define LLVM_CLANG_FRONTEND_SERIALIZED_DIAGNOSTIC_READER_H_ + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Support/ErrorOr.h" + +namespace clang { +namespace serialized_diags { + +enum class SDError { + CouldNotLoad = 1, + InvalidSignature, + InvalidDiagnostics, + MalformedTopLevelBlock, + MalformedSubBlock, + MalformedBlockInfoBlock, + MalformedMetadataBlock, + MalformedDiagnosticBlock, + MalformedDiagnosticRecord, + MissingVersion, + VersionMismatch, + UnsupportedConstruct, + /// A generic error for subclass handlers that don't want or need to define + /// their own error_category. + HandlerFailed +}; + +const std::error_category &SDErrorCategory(); + +inline std::error_code make_error_code(SDError E) { + return std::error_code(static_cast<int>(E), SDErrorCategory()); +} + +/// \brief A location that is represented in the serialized diagnostics. +struct Location { + unsigned FileID; + unsigned Line; + unsigned Col; + unsigned Offset; + Location(unsigned FileID, unsigned Line, unsigned Col, unsigned Offset) + : FileID(FileID), Line(Line), Col(Col), Offset(Offset) {} +}; + +/// \brief A base class that handles reading serialized diagnostics from a file. +/// +/// Subclasses should override the visit* methods with their logic for handling +/// the various constructs that are found in serialized diagnostics. +class SerializedDiagnosticReader { +public: + SerializedDiagnosticReader() {} + virtual ~SerializedDiagnosticReader() {} + + /// \brief Read the diagnostics in \c File + std::error_code readDiagnostics(StringRef File); + +private: + enum class Cursor; + + /// \brief Read to the next record or block to process. + llvm::ErrorOr<Cursor> skipUntilRecordOrBlock(llvm::BitstreamCursor &Stream, + unsigned &BlockOrRecordId); + + /// \brief Read a metadata block from \c Stream. + std::error_code readMetaBlock(llvm::BitstreamCursor &Stream); + + /// \brief Read a diagnostic block from \c Stream. + std::error_code readDiagnosticBlock(llvm::BitstreamCursor &Stream); + +protected: + /// \brief Visit the start of a diagnostic block. + virtual std::error_code visitStartOfDiagnostic() { + return std::error_code(); + } + /// \brief Visit the end of a diagnostic block. + virtual std::error_code visitEndOfDiagnostic() { return std::error_code(); } + /// \brief Visit a category. This associates the category \c ID to a \c Name. + virtual std::error_code visitCategoryRecord(unsigned ID, StringRef Name) { + return std::error_code(); + } + /// \brief Visit a flag. This associates the flag's \c ID to a \c Name. + virtual std::error_code visitDiagFlagRecord(unsigned ID, StringRef Name) { + return std::error_code(); + } + /// \brief Visit a diagnostic. + virtual std::error_code + visitDiagnosticRecord(unsigned Severity, const Location &Location, + unsigned Category, unsigned Flag, StringRef Message) { + return std::error_code(); + } + /// \brief Visit a filename. This associates the file's \c ID to a \c Name. + virtual std::error_code visitFilenameRecord(unsigned ID, unsigned Size, + unsigned Timestamp, + StringRef Name) { + return std::error_code(); + } + /// \brief Visit a fixit hint. + virtual std::error_code + visitFixitRecord(const Location &Start, const Location &End, StringRef Text) { + return std::error_code(); + } + /// \brief Visit a source range. + virtual std::error_code visitSourceRangeRecord(const Location &Start, + const Location &End) { + return std::error_code(); + } + /// \brief Visit the version of the set of diagnostics. + virtual std::error_code visitVersionRecord(unsigned Version) { + return std::error_code(); + } +}; + +} // end serialized_diags namespace +} // end clang namespace + +namespace std { +template <> +struct is_error_code_enum<clang::serialized_diags::SDError> : std::true_type {}; +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/SerializedDiagnostics.h b/contrib/llvm/tools/clang/include/clang/Frontend/SerializedDiagnostics.h new file mode 100644 index 0000000..2032cd3 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Frontend/SerializedDiagnostics.h @@ -0,0 +1,59 @@ +//===--- SerializedDiagnostics.h - Common data for serialized diagnostics -===// +// +// 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_SERIALIZE_DIAGNOSTICS_H_ +#define LLVM_CLANG_FRONTEND_SERIALIZE_DIAGNOSTICS_H_ + +#include "llvm/Bitcode/BitCodes.h" + +namespace clang { +namespace serialized_diags { + +enum BlockIDs { + /// \brief A top-level block which represents any meta data associated + /// with the diagostics, including versioning of the format. + BLOCK_META = llvm::bitc::FIRST_APPLICATION_BLOCKID, + + /// \brief The this block acts as a container for all the information + /// for a specific diagnostic. + BLOCK_DIAG +}; + +enum RecordIDs { + RECORD_VERSION = 1, + RECORD_DIAG, + RECORD_SOURCE_RANGE, + RECORD_DIAG_FLAG, + RECORD_CATEGORY, + RECORD_FILENAME, + RECORD_FIXIT, + RECORD_FIRST = RECORD_VERSION, + RECORD_LAST = RECORD_FIXIT +}; + +/// \brief A stable version of DiagnosticIDs::Level. +/// +/// Do not change the order of values in this enum, and please increment the +/// serialized diagnostics version number when you add to it. +enum Level { + Ignored = 0, + Note, + Warning, + Error, + Fatal, + Remark +}; + +/// \brief The serialized diagnostics version number. +enum { VersionNumber = 2 }; + +} // end serialized_diags namespace +} // end clang namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/TextDiagnostic.h b/contrib/llvm/tools/clang/include/clang/Frontend/TextDiagnostic.h new file mode 100644 index 0000000..d41f15a --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Frontend/TextDiagnostic.h @@ -0,0 +1,122 @@ +//===--- TextDiagnostic.h - Text Diagnostic Pretty-Printing -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a utility class that provides support for textual pretty-printing of +// diagnostics. It is used to implement the different code paths which require +// such functionality in a consistent way. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_TEXTDIAGNOSTIC_H +#define LLVM_CLANG_FRONTEND_TEXTDIAGNOSTIC_H + +#include "clang/Frontend/DiagnosticRenderer.h" + +namespace clang { + +/// \brief Class to encapsulate the logic for formatting and printing a textual +/// diagnostic message. +/// +/// This class provides an interface for building and emitting a textual +/// diagnostic, including all of the macro backtraces, caret diagnostics, FixIt +/// Hints, and code snippets. In the presence of macros this involves +/// a recursive process, synthesizing notes for each macro expansion. +/// +/// The purpose of this class is to isolate the implementation of printing +/// beautiful text diagnostics from any particular interfaces. The Clang +/// DiagnosticClient is implemented through this class as is diagnostic +/// printing coming out of libclang. +class TextDiagnostic : public DiagnosticRenderer { + raw_ostream &OS; + +public: + TextDiagnostic(raw_ostream &OS, + const LangOptions &LangOpts, + DiagnosticOptions *DiagOpts); + + ~TextDiagnostic() override; + + /// \brief Print the diagonstic level to a raw_ostream. + /// + /// This is a static helper that handles colorizing the level and formatting + /// it into an arbitrary output stream. This is used internally by the + /// TextDiagnostic emission code, but it can also be used directly by + /// consumers that don't have a source manager or other state that the full + /// TextDiagnostic logic requires. + static void printDiagnosticLevel(raw_ostream &OS, + DiagnosticsEngine::Level Level, + bool ShowColors, + bool CLFallbackMode = false); + + /// \brief Pretty-print a diagnostic message to a raw_ostream. + /// + /// This is a static helper to handle the line wrapping, colorizing, and + /// rendering of a diagnostic message to a particular ostream. It is + /// publicly visible so that clients which do not have sufficient state to + /// build a complete TextDiagnostic object can still get consistent + /// formatting of their diagnostic messages. + /// + /// \param OS Where the message is printed + /// \param IsSupplemental true if this is a continuation note diagnostic + /// \param Message The text actually printed + /// \param CurrentColumn The starting column of the first line, accounting + /// for any prefix. + /// \param Columns The number of columns to use in line-wrapping, 0 disables + /// all line-wrapping. + /// \param ShowColors Enable colorizing of the message. + static void printDiagnosticMessage(raw_ostream &OS, bool IsSupplemental, + StringRef Message, unsigned CurrentColumn, + unsigned Columns, bool ShowColors); + +protected: + void emitDiagnosticMessage(SourceLocation Loc,PresumedLoc PLoc, + DiagnosticsEngine::Level Level, + StringRef Message, + ArrayRef<CharSourceRange> Ranges, + const SourceManager *SM, + DiagOrStoredDiag D) override; + + void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, + DiagnosticsEngine::Level Level, + ArrayRef<CharSourceRange> Ranges, + const SourceManager &SM) override; + + void emitCodeContext(SourceLocation Loc, + DiagnosticsEngine::Level Level, + SmallVectorImpl<CharSourceRange>& Ranges, + ArrayRef<FixItHint> Hints, + const SourceManager &SM) override { + emitSnippetAndCaret(Loc, Level, Ranges, Hints, SM); + } + + void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc, + const SourceManager &SM) override; + + void emitImportLocation(SourceLocation Loc, PresumedLoc PLoc, + StringRef ModuleName, + const SourceManager &SM) override; + + void emitBuildingModuleLocation(SourceLocation Loc, PresumedLoc PLoc, + StringRef ModuleName, + const SourceManager &SM) override; + +private: + void emitSnippetAndCaret(SourceLocation Loc, DiagnosticsEngine::Level Level, + SmallVectorImpl<CharSourceRange>& Ranges, + ArrayRef<FixItHint> Hints, + const SourceManager &SM); + + void emitSnippet(StringRef SourceLine); + + void emitParseableFixits(ArrayRef<FixItHint> Hints, const SourceManager &SM); +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/TextDiagnosticBuffer.h b/contrib/llvm/tools/clang/include/clang/Frontend/TextDiagnosticBuffer.h new file mode 100644 index 0000000..3bcf824 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Frontend/TextDiagnosticBuffer.h @@ -0,0 +1,55 @@ +//===--- TextDiagnosticBuffer.h - Buffer Text Diagnostics -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a concrete diagnostic client, which buffers the diagnostic messages. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_TEXTDIAGNOSTICBUFFER_H +#define LLVM_CLANG_FRONTEND_TEXTDIAGNOSTICBUFFER_H + +#include "clang/Basic/Diagnostic.h" +#include <vector> + +namespace clang { + +class Preprocessor; +class SourceManager; + +class TextDiagnosticBuffer : public DiagnosticConsumer { +public: + typedef std::vector<std::pair<SourceLocation, std::string> > DiagList; + typedef DiagList::iterator iterator; + typedef DiagList::const_iterator const_iterator; +private: + DiagList Errors, Warnings, Remarks, Notes; +public: + const_iterator err_begin() const { return Errors.begin(); } + const_iterator err_end() const { return Errors.end(); } + + const_iterator warn_begin() const { return Warnings.begin(); } + const_iterator warn_end() const { return Warnings.end(); } + + const_iterator remark_begin() const { return Remarks.begin(); } + const_iterator remark_end() const { return Remarks.end(); } + + const_iterator note_begin() const { return Notes.begin(); } + const_iterator note_end() const { return Notes.end(); } + + void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, + const Diagnostic &Info) override; + + /// FlushDiagnostics - Flush the buffered diagnostics to an given + /// diagnostic engine. + void FlushDiagnostics(DiagnosticsEngine &Diags) const; +}; + +} // end namspace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/TextDiagnosticPrinter.h b/contrib/llvm/tools/clang/include/clang/Frontend/TextDiagnosticPrinter.h new file mode 100644 index 0000000..04a5705 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Frontend/TextDiagnosticPrinter.h @@ -0,0 +1,58 @@ +//===--- TextDiagnosticPrinter.h - Text Diagnostic Client -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a concrete diagnostic client, which prints the diagnostics to +// standard error. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_TEXTDIAGNOSTICPRINTER_H +#define LLVM_CLANG_FRONTEND_TEXTDIAGNOSTICPRINTER_H + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include <memory> + +namespace clang { +class DiagnosticOptions; +class LangOptions; +class TextDiagnostic; + +class TextDiagnosticPrinter : public DiagnosticConsumer { + raw_ostream &OS; + IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts; + + /// \brief Handle to the currently active text diagnostic emitter. + std::unique_ptr<TextDiagnostic> TextDiag; + + /// A string to prefix to error messages. + std::string Prefix; + + unsigned OwnsOutputStream : 1; + +public: + TextDiagnosticPrinter(raw_ostream &os, DiagnosticOptions *diags, + bool OwnsOutputStream = false); + ~TextDiagnosticPrinter() override; + + /// setPrefix - Set the diagnostic printer prefix string, which will be + /// printed at the start of any diagnostics. If empty, no prefix string is + /// used. + void setPrefix(std::string Value) { Prefix = Value; } + + void BeginSourceFile(const LangOptions &LO, const Preprocessor *PP) override; + void EndSourceFile() override; + void HandleDiagnostic(DiagnosticsEngine::Level Level, + const Diagnostic &Info) override; +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/Utils.h b/contrib/llvm/tools/clang/include/clang/Frontend/Utils.h new file mode 100644 index 0000000..a5f667e --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Frontend/Utils.h @@ -0,0 +1,220 @@ +//===--- Utils.h - Misc utilities for the front-end -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header contains miscellaneous utilities for various front-end actions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_UTILS_H +#define LLVM_CLANG_FRONTEND_UTILS_H + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/VirtualFileSystem.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/Option/OptSpecifier.h" + +namespace llvm { +class raw_fd_ostream; +class Triple; + +namespace opt { +class ArgList; +} +} + +namespace clang { +class ASTConsumer; +class ASTReader; +class CompilerInstance; +class CompilerInvocation; +class Decl; +class DependencyOutputOptions; +class DiagnosticsEngine; +class DiagnosticOptions; +class ExternalSemaSource; +class FileManager; +class HeaderSearch; +class HeaderSearchOptions; +class IdentifierTable; +class LangOptions; +class PCHContainerReader; +class Preprocessor; +class PreprocessorOptions; +class PreprocessorOutputOptions; +class SourceManager; +class Stmt; +class TargetInfo; +class FrontendOptions; + +/// Apply the header search options to get given HeaderSearch object. +void ApplyHeaderSearchOptions(HeaderSearch &HS, + const HeaderSearchOptions &HSOpts, + const LangOptions &Lang, + const llvm::Triple &triple); + +/// InitializePreprocessor - Initialize the preprocessor getting it and the +/// environment ready to process a single file. +void InitializePreprocessor(Preprocessor &PP, const PreprocessorOptions &PPOpts, + const PCHContainerReader &PCHContainerRdr, + const FrontendOptions &FEOpts); + +/// DoPrintPreprocessedInput - Implement -E mode. +void DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream* OS, + const PreprocessorOutputOptions &Opts); + +/// An interface for collecting the dependencies of a compilation. Users should +/// use \c attachToPreprocessor and \c attachToASTReader to get all of the +/// dependencies. +// FIXME: Migrate DependencyFileGen, DependencyGraphGen, ModuleDepCollectory to +// use this interface. +class DependencyCollector { +public: + void attachToPreprocessor(Preprocessor &PP); + void attachToASTReader(ASTReader &R); + llvm::ArrayRef<std::string> getDependencies() const { return Dependencies; } + + /// Called when a new file is seen. Return true if \p Filename should be added + /// to the list of dependencies. + /// + /// The default implementation ignores <built-in> and system files. + virtual bool sawDependency(StringRef Filename, bool FromModule, + bool IsSystem, bool IsModuleFile, bool IsMissing); + /// Called when the end of the main file is reached. + virtual void finishedMainFile() { } + /// Return true if system files should be passed to sawDependency(). + virtual bool needSystemDependencies() { return false; } + virtual ~DependencyCollector(); + +public: // implementation detail + /// Add a dependency \p Filename if it has not been seen before and + /// sawDependency() returns true. + void maybeAddDependency(StringRef Filename, bool FromModule, bool IsSystem, + bool IsModuleFile, bool IsMissing); +private: + llvm::StringSet<> Seen; + std::vector<std::string> Dependencies; +}; + +/// Builds a depdenency file when attached to a Preprocessor (for includes) and +/// ASTReader (for module imports), and writes it out at the end of processing +/// a source file. Users should attach to the ast reader whenever a module is +/// loaded. +class DependencyFileGenerator { + void *Impl; // Opaque implementation + DependencyFileGenerator(void *Impl); +public: + static DependencyFileGenerator *CreateAndAttachToPreprocessor( + Preprocessor &PP, const DependencyOutputOptions &Opts); + void AttachToASTReader(ASTReader &R); +}; + +/// Collects the dependencies for imported modules into a directory. Users +/// should attach to the AST reader whenever a module is loaded. +class ModuleDependencyCollector { + std::string DestDir; + bool HasErrors; + llvm::StringSet<> Seen; + vfs::YAMLVFSWriter VFSWriter; + +public: + StringRef getDest() { return DestDir; } + bool insertSeen(StringRef Filename) { return Seen.insert(Filename).second; } + void setHasErrors() { HasErrors = true; } + void addFileMapping(StringRef VPath, StringRef RPath) { + VFSWriter.addFileMapping(VPath, RPath); + } + + void attachToASTReader(ASTReader &R); + void writeFileMap(); + bool hasErrors() { return HasErrors; } + ModuleDependencyCollector(std::string DestDir) + : DestDir(DestDir), HasErrors(false) {} + ~ModuleDependencyCollector() { writeFileMap(); } +}; + +/// AttachDependencyGraphGen - Create a dependency graph generator, and attach +/// it to the given preprocessor. + void AttachDependencyGraphGen(Preprocessor &PP, StringRef OutputFile, + StringRef SysRoot); + +/// AttachHeaderIncludeGen - Create a header include list generator, and attach +/// it to the given preprocessor. +/// +/// \param ExtraHeaders - If not empty, will write the header filenames, just +/// like they were included during a regular preprocessing. Useful for +/// implicit include dependencies, like sanitizer blacklists. +/// \param ShowAllHeaders - If true, show all header information instead of just +/// headers following the predefines buffer. This is useful for making sure +/// includes mentioned on the command line are also reported, but differs from +/// the default behavior used by -H. +/// \param OutputPath - If non-empty, a path to write the header include +/// information to, instead of writing to stderr. +/// \param ShowDepth - Whether to indent to show the nesting of the includes. +/// \param MSStyle - Whether to print in cl.exe /showIncludes style. +void AttachHeaderIncludeGen(Preprocessor &PP, + const std::vector<std::string> &ExtraHeaders, + bool ShowAllHeaders = false, + StringRef OutputPath = "", + bool ShowDepth = true, bool MSStyle = false); + +/// Cache tokens for use with PCH. Note that this requires a seekable stream. +void CacheTokens(Preprocessor &PP, raw_pwrite_stream *OS); + +/// The ChainedIncludesSource class converts headers to chained PCHs in +/// memory, mainly for testing. +IntrusiveRefCntPtr<ExternalSemaSource> +createChainedIncludesSource(CompilerInstance &CI, + IntrusiveRefCntPtr<ExternalSemaSource> &Reader); + +/// createInvocationFromCommandLine - Construct a compiler invocation object for +/// a command line argument vector. +/// +/// \return A CompilerInvocation, or 0 if none was built for the given +/// argument vector. +CompilerInvocation * +createInvocationFromCommandLine(ArrayRef<const char *> Args, + IntrusiveRefCntPtr<DiagnosticsEngine> Diags = + IntrusiveRefCntPtr<DiagnosticsEngine>()); + +/// Return the value of the last argument as an integer, or a default. If Diags +/// is non-null, emits an error if the argument is given, but non-integral. +int getLastArgIntValue(const llvm::opt::ArgList &Args, + llvm::opt::OptSpecifier Id, int Default, + DiagnosticsEngine *Diags = nullptr); + +inline int getLastArgIntValue(const llvm::opt::ArgList &Args, + llvm::opt::OptSpecifier Id, int Default, + DiagnosticsEngine &Diags) { + return getLastArgIntValue(Args, Id, Default, &Diags); +} + +uint64_t getLastArgUInt64Value(const llvm::opt::ArgList &Args, + llvm::opt::OptSpecifier Id, uint64_t Default, + DiagnosticsEngine *Diags = nullptr); + +inline uint64_t getLastArgUInt64Value(const llvm::opt::ArgList &Args, + llvm::opt::OptSpecifier Id, + uint64_t Default, + DiagnosticsEngine &Diags) { + return getLastArgUInt64Value(Args, Id, Default, &Diags); +} + +// When Clang->getFrontendOpts().DisableFree is set we don't delete some of the +// global objects, but we don't want LeakDetectors to complain, so we bury them +// in a globally visible array. +void BuryPointer(const void *Ptr); +template <typename T> void BuryPointer(std::unique_ptr<T> Ptr) { + BuryPointer(Ptr.release()); +} + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h b/contrib/llvm/tools/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h new file mode 100644 index 0000000..475f07f --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h @@ -0,0 +1,278 @@ +//===- VerifyDiagnosticConsumer.h - Verifying Diagnostic Client -*- 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_VERIFYDIAGNOSTICCONSUMER_H +#define LLVM_CLANG_FRONTEND_VERIFYDIAGNOSTICCONSUMER_H + +#include "clang/Basic/Diagnostic.h" +#include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/STLExtras.h" +#include <climits> +#include <memory> + +namespace clang { + +class DiagnosticsEngine; +class TextDiagnosticBuffer; +class FileEntry; + +/// VerifyDiagnosticConsumer - Create a diagnostic client which will use +/// markers in the input source to check that all the emitted diagnostics match +/// those expected. +/// +/// USING THE DIAGNOSTIC CHECKER: +/// +/// Indicating that a line expects an error or a warning is simple. Put a +/// comment on the line that has the diagnostic, use: +/// +/// \code +/// expected-{error,warning,remark,note} +/// \endcode +/// +/// to tag if it's an expected error, remark or warning, and place the expected +/// text between {{ and }} markers. The full text doesn't have to be included, +/// only enough to ensure that the correct diagnostic was emitted. +/// +/// Here's an example: +/// +/// \code +/// int A = B; // expected-error {{use of undeclared identifier 'B'}} +/// \endcode +/// +/// You can place as many diagnostics on one line as you wish. To make the code +/// more readable, you can use slash-newline to separate out the diagnostics. +/// +/// Alternatively, it is possible to specify the line on which the diagnostic +/// should appear by appending "@<line>" to "expected-<type>", for example: +/// +/// \code +/// #warning some text +/// // expected-warning@10 {{some text}} +/// \endcode +/// +/// The line number may be absolute (as above), or relative to the current +/// line by prefixing the number with either '+' or '-'. +/// +/// If the diagnostic is generated in a separate file, for example in a shared +/// header file, it may be beneficial to be able to declare the file in which +/// the diagnostic will appear, rather than placing the expected-* directive in +/// the actual file itself. This can be done using the following syntax: +/// +/// \code +/// // expected-error@path/include.h:15 {{error message}} +/// \endcode +/// +/// The path can be absolute or relative and the same search paths will be used +/// as for #include directives. The line number in an external file may be +/// substituted with '*' meaning that any line number will match (useful where +/// the included file is, for example, a system header where the actual line +/// number may change and is not critical). +/// +/// The simple syntax above allows each specification to match exactly one +/// error. You can use the extended syntax to customize this. The extended +/// syntax is "expected-<type> <n> {{diag text}}", where \<type> is one of +/// "error", "warning" or "note", and \<n> is a positive integer. This allows +/// the diagnostic to appear as many times as specified. Example: +/// +/// \code +/// void f(); // expected-note 2 {{previous declaration is here}} +/// \endcode +/// +/// Where the diagnostic is expected to occur a minimum number of times, this +/// can be specified by appending a '+' to the number. Example: +/// +/// \code +/// void f(); // expected-note 0+ {{previous declaration is here}} +/// void g(); // expected-note 1+ {{previous declaration is here}} +/// \endcode +/// +/// In the first example, the diagnostic becomes optional, i.e. it will be +/// swallowed if it occurs, but will not generate an error if it does not +/// occur. In the second example, the diagnostic must occur at least once. +/// As a short-hand, "one or more" can be specified simply by '+'. Example: +/// +/// \code +/// void g(); // expected-note + {{previous declaration is here}} +/// \endcode +/// +/// A range can also be specified by "<n>-<m>". Example: +/// +/// \code +/// void f(); // expected-note 0-1 {{previous declaration is here}} +/// \endcode +/// +/// In this example, the diagnostic may appear only once, if at all. +/// +/// Regex matching mode may be selected by appending '-re' to type and +/// including regexes wrapped in double curly braces in the directive, such as: +/// +/// \code +/// expected-error-re {{format specifies type 'wchar_t **' (aka '{{.+}}')}} +/// \endcode +/// +/// Examples matching error: "variable has incomplete type 'struct s'" +/// +/// \code +/// // expected-error {{variable has incomplete type 'struct s'}} +/// // expected-error {{variable has incomplete type}} +/// +/// // expected-error-re {{variable has type 'struct {{.}}'}} +/// // expected-error-re {{variable has type 'struct {{.*}}'}} +/// // expected-error-re {{variable has type 'struct {{(.*)}}'}} +/// // expected-error-re {{variable has type 'struct{{[[:space:]](.*)}}'}} +/// \endcode +/// +/// VerifyDiagnosticConsumer expects at least one expected-* directive to +/// be found inside the source code. If no diagnostics are expected the +/// following directive can be used to indicate this: +/// +/// \code +/// // expected-no-diagnostics +/// \endcode +/// +class VerifyDiagnosticConsumer: public DiagnosticConsumer, + public CommentHandler { +public: + /// Directive - Abstract class representing a parsed verify directive. + /// + class Directive { + public: + static std::unique_ptr<Directive> create(bool RegexKind, + SourceLocation DirectiveLoc, + SourceLocation DiagnosticLoc, + bool MatchAnyLine, StringRef Text, + unsigned Min, unsigned Max); + + public: + /// Constant representing n or more matches. + static const unsigned MaxCount = UINT_MAX; + + SourceLocation DirectiveLoc; + SourceLocation DiagnosticLoc; + const std::string Text; + unsigned Min, Max; + bool MatchAnyLine; + + virtual ~Directive() { } + + // Returns true if directive text is valid. + // Otherwise returns false and populates E. + virtual bool isValid(std::string &Error) = 0; + + // Returns true on match. + virtual bool match(StringRef S) = 0; + + protected: + Directive(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc, + bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max) + : DirectiveLoc(DirectiveLoc), DiagnosticLoc(DiagnosticLoc), + Text(Text), Min(Min), Max(Max), MatchAnyLine(MatchAnyLine) { + assert(!DirectiveLoc.isInvalid() && "DirectiveLoc is invalid!"); + assert(!DiagnosticLoc.isInvalid() && "DiagnosticLoc is invalid!"); + } + + private: + Directive(const Directive &) = delete; + void operator=(const Directive &) = delete; + }; + + typedef std::vector<std::unique_ptr<Directive>> DirectiveList; + + /// ExpectedData - owns directive objects and deletes on destructor. + /// + struct ExpectedData { + DirectiveList Errors; + DirectiveList Warnings; + DirectiveList Remarks; + DirectiveList Notes; + + void Reset() { + Errors.clear(); + Warnings.clear(); + Remarks.clear(); + Notes.clear(); + } + }; + + enum DirectiveStatus { + HasNoDirectives, + HasNoDirectivesReported, + HasExpectedNoDiagnostics, + HasOtherExpectedDirectives + }; + +private: + DiagnosticsEngine &Diags; + DiagnosticConsumer *PrimaryClient; + std::unique_ptr<DiagnosticConsumer> PrimaryClientOwner; + std::unique_ptr<TextDiagnosticBuffer> Buffer; + const Preprocessor *CurrentPreprocessor; + const LangOptions *LangOpts; + SourceManager *SrcManager; + unsigned ActiveSourceFiles; + DirectiveStatus Status; + ExpectedData ED; + + void CheckDiagnostics(); + void setSourceManager(SourceManager &SM) { + assert((!SrcManager || SrcManager == &SM) && "SourceManager changed!"); + SrcManager = &SM; + } + + // These facilities are used for validation in debug builds. + class UnparsedFileStatus { + llvm::PointerIntPair<const FileEntry *, 1, bool> Data; + public: + UnparsedFileStatus(const FileEntry *File, bool FoundDirectives) + : Data(File, FoundDirectives) {} + const FileEntry *getFile() const { return Data.getPointer(); } + bool foundDirectives() const { return Data.getInt(); } + }; + typedef llvm::DenseMap<FileID, const FileEntry *> ParsedFilesMap; + typedef llvm::DenseMap<FileID, UnparsedFileStatus> UnparsedFilesMap; + ParsedFilesMap ParsedFiles; + UnparsedFilesMap UnparsedFiles; + +public: + /// Create a new verifying diagnostic client, which will issue errors to + /// the currently-attached diagnostic client when a diagnostic does not match + /// what is expected (as indicated in the source file). + VerifyDiagnosticConsumer(DiagnosticsEngine &Diags); + ~VerifyDiagnosticConsumer() override; + + void BeginSourceFile(const LangOptions &LangOpts, + const Preprocessor *PP) override; + + void EndSourceFile() override; + + enum ParsedStatus { + /// File has been processed via HandleComment. + IsParsed, + + /// File has diagnostics and may have directives. + IsUnparsed, + + /// File has diagnostics but guaranteed no directives. + IsUnparsedNoDirectives + }; + + /// \brief Update lists of parsed and unparsed files. + void UpdateParsedFileStatus(SourceManager &SM, FileID FID, ParsedStatus PS); + + bool HandleComment(Preprocessor &PP, SourceRange Comment) override; + + void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, + const Diagnostic &Info) override; +}; + +} // end namspace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/FrontendTool/Utils.h b/contrib/llvm/tools/clang/include/clang/FrontendTool/Utils.h new file mode 100644 index 0000000..031ee7d --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/FrontendTool/Utils.h @@ -0,0 +1,30 @@ +//===--- Utils.h - Misc utilities for the front-end -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header contains miscellaneous utilities for various front-end actions +// which were split from Frontend to minimise Frontend's dependencies. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTENDTOOL_UTILS_H +#define LLVM_CLANG_FRONTENDTOOL_UTILS_H + +namespace clang { + +class CompilerInstance; + +/// ExecuteCompilerInvocation - Execute the given actions described by the +/// compiler invocation object in the given compiler instance. +/// +/// \return - True on success. +bool ExecuteCompilerInvocation(CompilerInstance *Clang); + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Index/CommentToXML.h b/contrib/llvm/tools/clang/include/clang/Index/CommentToXML.h new file mode 100644 index 0000000..bb7b71a --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Index/CommentToXML.h @@ -0,0 +1,52 @@ +//===--- CommentToXML.h - Convert comments to XML representation ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INDEX_COMMENTTOXML_H +#define LLVM_CLANG_INDEX_COMMENTTOXML_H + +#include "clang/Basic/LLVM.h" +#include <memory> + +namespace clang { +class ASTContext; + +namespace comments { +class FullComment; +class HTMLTagComment; +} + +namespace index { +class SimpleFormatContext; + +class CommentToXMLConverter { + std::unique_ptr<SimpleFormatContext> FormatContext; + unsigned FormatInMemoryUniqueId; + +public: + CommentToXMLConverter(); + ~CommentToXMLConverter(); + + void convertCommentToHTML(const comments::FullComment *FC, + SmallVectorImpl<char> &HTML, + const ASTContext &Context); + + void convertHTMLTagNodeToText(const comments::HTMLTagComment *HTC, + SmallVectorImpl<char> &Text, + const ASTContext &Context); + + void convertCommentToXML(const comments::FullComment *FC, + SmallVectorImpl<char> &XML, + const ASTContext &Context); +}; + +} // namespace index +} // namespace clang + +#endif // LLVM_CLANG_INDEX_COMMENTTOXML_H + diff --git a/contrib/llvm/tools/clang/include/clang/Index/USRGeneration.h b/contrib/llvm/tools/clang/include/clang/Index/USRGeneration.h new file mode 100644 index 0000000..55e35cc --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Index/USRGeneration.h @@ -0,0 +1,62 @@ +//===- USRGeneration.h - Routines for USR generation ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INDEX_USRGENERATION_H +#define LLVM_CLANG_INDEX_USRGENERATION_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { +class Decl; +class MacroDefinitionRecord; +class SourceManager; + +namespace index { + +static inline StringRef getUSRSpacePrefix() { + return "c:"; +} + +/// \brief Generate a USR for a Decl, including the USR prefix. +/// \returns true if the results should be ignored, false otherwise. +bool generateUSRForDecl(const Decl *D, SmallVectorImpl<char> &Buf); + +/// \brief Generate a USR fragment for an Objective-C class. +void generateUSRForObjCClass(StringRef Cls, raw_ostream &OS); + +/// \brief Generate a USR fragment for an Objective-C class category. +void generateUSRForObjCCategory(StringRef Cls, StringRef Cat, raw_ostream &OS); + +/// \brief Generate a USR fragment for an Objective-C instance variable. The +/// complete USR can be created by concatenating the USR for the +/// encompassing class with this USR fragment. +void generateUSRForObjCIvar(StringRef Ivar, raw_ostream &OS); + +/// \brief Generate a USR fragment for an Objective-C method. +void generateUSRForObjCMethod(StringRef Sel, bool IsInstanceMethod, + raw_ostream &OS); + +/// \brief Generate a USR fragment for an Objective-C property. +void generateUSRForObjCProperty(StringRef Prop, raw_ostream &OS); + +/// \brief Generate a USR fragment for an Objective-C protocol. +void generateUSRForObjCProtocol(StringRef Prot, raw_ostream &OS); + +/// \brief Generate a USR for a macro, including the USR prefix. +/// +/// \returns true on error, false on success. +bool generateUSRForMacro(const MacroDefinitionRecord *MD, + const SourceManager &SM, SmallVectorImpl<char> &Buf); + +} // namespace index +} // namespace clang + +#endif // LLVM_CLANG_IDE_USRGENERATION_H + diff --git a/contrib/llvm/tools/clang/include/clang/Lex/CodeCompletionHandler.h b/contrib/llvm/tools/clang/include/clang/Lex/CodeCompletionHandler.h new file mode 100644 index 0000000..91c3b78 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Lex/CodeCompletionHandler.h @@ -0,0 +1,71 @@ +//===--- CodeCompletionHandler.h - Preprocessor code completion -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the CodeCompletionHandler interface, which provides +// code-completion callbacks for the preprocessor. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_LEX_CODECOMPLETIONHANDLER_H +#define LLVM_CLANG_LEX_CODECOMPLETIONHANDLER_H + +namespace clang { + +class IdentifierInfo; +class MacroInfo; + +/// \brief Callback handler that receives notifications when performing code +/// completion within the preprocessor. +class CodeCompletionHandler { +public: + virtual ~CodeCompletionHandler(); + + /// \brief Callback invoked when performing code completion for a preprocessor + /// directive. + /// + /// This callback will be invoked when the preprocessor processes a '#' at the + /// start of a line, followed by the code-completion token. + /// + /// \param InConditional Whether we're inside a preprocessor conditional + /// already. + virtual void CodeCompleteDirective(bool InConditional) { } + + /// \brief Callback invoked when performing code completion within a block of + /// code that was excluded due to preprocessor conditionals. + virtual void CodeCompleteInConditionalExclusion() { } + + /// \brief Callback invoked when performing code completion in a context + /// where the name of a macro is expected. + /// + /// \param IsDefinition Whether this is the definition of a macro, e.g., + /// in a \#define. + virtual void CodeCompleteMacroName(bool IsDefinition) { } + + /// \brief Callback invoked when performing code completion in a preprocessor + /// expression, such as the condition of an \#if or \#elif directive. + virtual void CodeCompletePreprocessorExpression() { } + + /// \brief Callback invoked when performing code completion inside a + /// function-like macro argument. + /// + /// There will be another callback invocation after the macro arguments are + /// parsed, so this callback should generally be used to note that the next + /// callback is invoked inside a macro argument. + virtual void CodeCompleteMacroArgument(IdentifierInfo *Macro, + MacroInfo *MacroInfo, + unsigned ArgumentIndex) { } + + /// \brief Callback invoked when performing code completion in a part of the + /// file where we expect natural language, e.g., a comment, string, or + /// \#error directive. + virtual void CodeCompleteNaturalLanguage() { } +}; + +} + +#endif // LLVM_CLANG_LEX_CODECOMPLETIONHANDLER_H diff --git a/contrib/llvm/tools/clang/include/clang/Lex/DirectoryLookup.h b/contrib/llvm/tools/clang/include/clang/Lex/DirectoryLookup.h new file mode 100644 index 0000000..20c4bb0 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Lex/DirectoryLookup.h @@ -0,0 +1,196 @@ +//===--- DirectoryLookup.h - Info for searching for headers -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the DirectoryLookup interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_DIRECTORYLOOKUP_H +#define LLVM_CLANG_LEX_DIRECTORYLOOKUP_H + +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Lex/ModuleMap.h" + +namespace clang { +class HeaderMap; +class DirectoryEntry; +class FileEntry; +class HeaderSearch; +class Module; + +/// DirectoryLookup - This class represents one entry in the search list that +/// specifies the search order for directories in \#include directives. It +/// represents either a directory, a framework, or a headermap. +/// +class DirectoryLookup { +public: + enum LookupType_t { + LT_NormalDir, + LT_Framework, + LT_HeaderMap + }; +private: + union { // This union is discriminated by isHeaderMap. + /// Dir - This is the actual directory that we're referring to for a normal + /// directory or a framework. + const DirectoryEntry *Dir; + + /// Map - This is the HeaderMap if this is a headermap lookup. + /// + const HeaderMap *Map; + } u; + + /// DirCharacteristic - The type of directory this is: this is an instance of + /// SrcMgr::CharacteristicKind. + unsigned DirCharacteristic : 2; + + /// LookupType - This indicates whether this DirectoryLookup object is a + /// normal directory, a framework, or a headermap. + unsigned LookupType : 2; + + /// \brief Whether this is a header map used when building a framework. + unsigned IsIndexHeaderMap : 1; + + /// \brief Whether we've performed an exhaustive search for module maps + /// within the subdirectories of this directory. + unsigned SearchedAllModuleMaps : 1; + +public: + /// DirectoryLookup ctor - Note that this ctor *does not take ownership* of + /// 'dir'. + DirectoryLookup(const DirectoryEntry *dir, SrcMgr::CharacteristicKind DT, + bool isFramework) + : DirCharacteristic(DT), + LookupType(isFramework ? LT_Framework : LT_NormalDir), + IsIndexHeaderMap(false), SearchedAllModuleMaps(false) { + u.Dir = dir; + } + + /// DirectoryLookup ctor - Note that this ctor *does not take ownership* of + /// 'map'. + DirectoryLookup(const HeaderMap *map, SrcMgr::CharacteristicKind DT, + bool isIndexHeaderMap) + : DirCharacteristic(DT), LookupType(LT_HeaderMap), + IsIndexHeaderMap(isIndexHeaderMap), SearchedAllModuleMaps(false) { + u.Map = map; + } + + /// getLookupType - Return the kind of directory lookup that this is: either a + /// normal directory, a framework path, or a HeaderMap. + LookupType_t getLookupType() const { return (LookupType_t)LookupType; } + + /// getName - Return the directory or filename corresponding to this lookup + /// object. + const char *getName() const; + + /// getDir - Return the directory that this entry refers to. + /// + const DirectoryEntry *getDir() const { + return isNormalDir() ? u.Dir : nullptr; + } + + /// getFrameworkDir - Return the directory that this framework refers to. + /// + const DirectoryEntry *getFrameworkDir() const { + return isFramework() ? u.Dir : nullptr; + } + + /// getHeaderMap - Return the directory that this entry refers to. + /// + const HeaderMap *getHeaderMap() const { + return isHeaderMap() ? u.Map : nullptr; + } + + /// isNormalDir - Return true if this is a normal directory, not a header map. + bool isNormalDir() const { return getLookupType() == LT_NormalDir; } + + /// isFramework - True if this is a framework directory. + /// + bool isFramework() const { return getLookupType() == LT_Framework; } + + /// isHeaderMap - Return true if this is a header map, not a normal directory. + bool isHeaderMap() const { return getLookupType() == LT_HeaderMap; } + + /// \brief Determine whether we have already searched this entire + /// directory for module maps. + bool haveSearchedAllModuleMaps() const { return SearchedAllModuleMaps; } + + /// \brief Specify whether we have already searched all of the subdirectories + /// for module maps. + void setSearchedAllModuleMaps(bool SAMM) { + SearchedAllModuleMaps = SAMM; + } + + /// DirCharacteristic - The type of directory this is, one of the DirType enum + /// values. + SrcMgr::CharacteristicKind getDirCharacteristic() const { + return (SrcMgr::CharacteristicKind)DirCharacteristic; + } + + /// \brief Whether this describes a system header directory. + bool isSystemHeaderDirectory() const { + return getDirCharacteristic() != SrcMgr::C_User; + } + + /// \brief Whether this header map is building a framework or not. + bool isIndexHeaderMap() const { + return isHeaderMap() && IsIndexHeaderMap; + } + + /// LookupFile - Lookup the specified file in this search path, returning it + /// if it exists or returning null if not. + /// + /// \param Filename The file to look up relative to the search paths. + /// + /// \param HS The header search instance to search with. + /// + /// \param SearchPath If not NULL, will be set to the search path relative + /// to which the file was found. + /// + /// \param RelativePath If not NULL, will be set to the path relative to + /// SearchPath at which the file was found. This only differs from the + /// Filename for framework includes. + /// + /// \param RequestingModule The module in which the lookup was performed. + /// + /// \param SuggestedModule If non-null, and the file found is semantically + /// part of a known module, this will be set to the module that should + /// be imported instead of preprocessing/parsing the file found. + /// + /// \param [out] InUserSpecifiedSystemFramework If the file is found, + /// set to true if the file is located in a framework that has been + /// user-specified to be treated as a system framework. + /// + /// \param [out] MappedName if this is a headermap which maps the filename to + /// a framework include ("Foo.h" -> "Foo/Foo.h"), set the new name to this + /// vector and point Filename to it. + const FileEntry *LookupFile(StringRef &Filename, HeaderSearch &HS, + SmallVectorImpl<char> *SearchPath, + SmallVectorImpl<char> *RelativePath, + Module *RequestingModule, + ModuleMap::KnownHeader *SuggestedModule, + bool &InUserSpecifiedSystemFramework, + bool &HasBeenMapped, + SmallVectorImpl<char> &MappedName) const; + +private: + const FileEntry *DoFrameworkLookup( + StringRef Filename, HeaderSearch &HS, + SmallVectorImpl<char> *SearchPath, + SmallVectorImpl<char> *RelativePath, + Module *RequestingModule, + ModuleMap::KnownHeader *SuggestedModule, + bool &InUserSpecifiedSystemHeader) const; + +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Lex/ExternalPreprocessorSource.h b/contrib/llvm/tools/clang/include/clang/Lex/ExternalPreprocessorSource.h new file mode 100644 index 0000000..adf8e71 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Lex/ExternalPreprocessorSource.h @@ -0,0 +1,48 @@ +//===- ExternalPreprocessorSource.h - Abstract Macro Interface --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ExternalPreprocessorSource interface, which enables +// construction of macro definitions from some external source. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_LEX_EXTERNALPREPROCESSORSOURCE_H +#define LLVM_CLANG_LEX_EXTERNALPREPROCESSORSOURCE_H + +namespace clang { + +class IdentifierInfo; +class Module; + +/// \brief Abstract interface for external sources of preprocessor +/// information. +/// +/// This abstract class allows an external sources (such as the \c ASTReader) +/// to provide additional preprocessing information. +class ExternalPreprocessorSource { +public: + virtual ~ExternalPreprocessorSource(); + + /// \brief Read the set of macros defined by this external macro source. + virtual void ReadDefinedMacros() = 0; + + /// \brief Update an out-of-date identifier. + virtual void updateOutOfDateIdentifier(IdentifierInfo &II) = 0; + + /// \brief Return the identifier associated with the given ID number. + /// + /// The ID 0 is associated with the NULL identifier. + virtual IdentifierInfo *GetIdentifier(unsigned ID) = 0; + + /// \brief Map a module ID to a module. + virtual Module *getModule(unsigned ModuleID) = 0; +}; + +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Lex/HeaderMap.h b/contrib/llvm/tools/clang/include/clang/Lex/HeaderMap.h new file mode 100644 index 0000000..183361e --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Lex/HeaderMap.h @@ -0,0 +1,76 @@ +//===--- HeaderMap.h - A file that acts like dir of symlinks ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the HeaderMap interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_HEADERMAP_H +#define LLVM_CLANG_LEX_HEADERMAP_H + +#include "clang/Basic/LLVM.h" +#include "llvm/Support/Compiler.h" +#include <memory> + +namespace llvm { + class MemoryBuffer; +} +namespace clang { + class FileEntry; + class FileManager; + struct HMapBucket; + struct HMapHeader; + +/// This class represents an Apple concept known as a 'header map'. To the +/// \#include file resolution process, it basically acts like a directory of +/// symlinks to files. Its advantages are that it is dense and more efficient +/// to create and process than a directory of symlinks. +class HeaderMap { + HeaderMap(const HeaderMap &) = delete; + void operator=(const HeaderMap &) = delete; + + std::unique_ptr<const llvm::MemoryBuffer> FileBuffer; + bool NeedsBSwap; + + HeaderMap(std::unique_ptr<const llvm::MemoryBuffer> File, bool BSwap) + : FileBuffer(std::move(File)), NeedsBSwap(BSwap) {} +public: + /// HeaderMap::Create - This attempts to load the specified file as a header + /// map. If it doesn't look like a HeaderMap, it gives up and returns null. + static const HeaderMap *Create(const FileEntry *FE, FileManager &FM); + + /// LookupFile - Check to see if the specified relative filename is located in + /// this HeaderMap. If so, open it and return its FileEntry. + /// If RawPath is not NULL and the file is found, RawPath will be set to the + /// raw path at which the file was found in the file system. For example, + /// for a search path ".." and a filename "../file.h" this would be + /// "../../file.h". + const FileEntry *LookupFile(StringRef Filename, FileManager &FM) const; + + /// If the specified relative filename is located in this HeaderMap return + /// the filename it is mapped to, otherwise return an empty StringRef. + StringRef lookupFilename(StringRef Filename, + SmallVectorImpl<char> &DestPath) const; + + /// getFileName - Return the filename of the headermap. + const char *getFileName() const; + + /// dump - Print the contents of this headermap to stderr. + void dump() const; + +private: + unsigned getEndianAdjustedWord(unsigned X) const; + const HMapHeader &getHeader() const; + HMapBucket getBucket(unsigned BucketNo) const; + const char *getString(unsigned StrTabIdx) const; +}; + +} // end namespace clang. + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Lex/HeaderSearch.h b/contrib/llvm/tools/clang/include/clang/Lex/HeaderSearch.h new file mode 100644 index 0000000..6d592e1 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Lex/HeaderSearch.h @@ -0,0 +1,688 @@ +//===--- HeaderSearch.h - Resolve Header File Locations ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the HeaderSearch interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_HEADERSEARCH_H +#define LLVM_CLANG_LEX_HEADERSEARCH_H + +#include "clang/Lex/DirectoryLookup.h" +#include "clang/Lex/ModuleMap.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/Support/Allocator.h" +#include <memory> +#include <vector> + +namespace clang { + +class DiagnosticsEngine; +class ExternalPreprocessorSource; +class FileEntry; +class FileManager; +class HeaderSearchOptions; +class IdentifierInfo; +class Preprocessor; + +/// \brief The preprocessor keeps track of this information for each +/// file that is \#included. +struct HeaderFileInfo { + /// \brief True if this is a \#import'd or \#pragma once file. + unsigned isImport : 1; + + /// \brief True if this is a \#pragma once file. + unsigned isPragmaOnce : 1; + + /// DirInfo - Keep track of whether this is a system header, and if so, + /// whether it is C++ clean or not. This can be set by the include paths or + /// by \#pragma gcc system_header. This is an instance of + /// SrcMgr::CharacteristicKind. + unsigned DirInfo : 2; + + /// \brief Whether this header file info was supplied by an external source, + /// and has not changed since. + unsigned External : 1; + + /// \brief Whether this header is part of a module. + unsigned isModuleHeader : 1; + + /// \brief Whether this header is part of the module that we are building. + unsigned isCompilingModuleHeader : 1; + + /// \brief Whether this structure is considered to already have been + /// "resolved", meaning that it was loaded from the external source. + unsigned Resolved : 1; + + /// \brief Whether this is a header inside a framework that is currently + /// being built. + /// + /// When a framework is being built, the headers have not yet been placed + /// into the appropriate framework subdirectories, and therefore are + /// provided via a header map. This bit indicates when this is one of + /// those framework headers. + unsigned IndexHeaderMapHeader : 1; + + /// \brief Whether this file has been looked up as a header. + unsigned IsValid : 1; + + /// \brief The number of times the file has been included already. + unsigned short NumIncludes; + + /// \brief The ID number of the controlling macro. + /// + /// This ID number will be non-zero when there is a controlling + /// macro whose IdentifierInfo may not yet have been loaded from + /// external storage. + unsigned ControllingMacroID; + + /// If this file has a \#ifndef XXX (or equivalent) guard that + /// protects the entire contents of the file, this is the identifier + /// for the macro that controls whether or not it has any effect. + /// + /// Note: Most clients should use getControllingMacro() to access + /// the controlling macro of this header, since + /// getControllingMacro() is able to load a controlling macro from + /// external storage. + const IdentifierInfo *ControllingMacro; + + /// \brief If this header came from a framework include, this is the name + /// of the framework. + StringRef Framework; + + HeaderFileInfo() + : isImport(false), isPragmaOnce(false), DirInfo(SrcMgr::C_User), + External(false), isModuleHeader(false), isCompilingModuleHeader(false), + Resolved(false), IndexHeaderMapHeader(false), IsValid(0), + NumIncludes(0), ControllingMacroID(0), ControllingMacro(nullptr) {} + + /// \brief Retrieve the controlling macro for this header file, if + /// any. + const IdentifierInfo * + getControllingMacro(ExternalPreprocessorSource *External); + + /// \brief Determine whether this is a non-default header file info, e.g., + /// it corresponds to an actual header we've included or tried to include. + bool isNonDefault() const { + return isImport || isPragmaOnce || NumIncludes || ControllingMacro || + ControllingMacroID; + } +}; + +/// \brief An external source of header file information, which may supply +/// information about header files already included. +class ExternalHeaderFileInfoSource { +public: + virtual ~ExternalHeaderFileInfoSource(); + + /// \brief Retrieve the header file information for the given file entry. + /// + /// \returns Header file information for the given file entry, with the + /// \c External bit set. If the file entry is not known, return a + /// default-constructed \c HeaderFileInfo. + virtual HeaderFileInfo GetHeaderFileInfo(const FileEntry *FE) = 0; +}; + +/// \brief Encapsulates the information needed to find the file referenced +/// by a \#include or \#include_next, (sub-)framework lookup, etc. +class HeaderSearch { + /// This structure is used to record entries in our framework cache. + struct FrameworkCacheEntry { + /// The directory entry which should be used for the cached framework. + const DirectoryEntry *Directory; + + /// Whether this framework has been "user-specified" to be treated as if it + /// were a system framework (even if it was found outside a system framework + /// directory). + bool IsUserSpecifiedSystemFramework; + }; + + /// \brief Header-search options used to initialize this header search. + IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts; + + DiagnosticsEngine &Diags; + FileManager &FileMgr; + /// \#include search path information. Requests for \#include "x" search the + /// directory of the \#including file first, then each directory in SearchDirs + /// consecutively. Requests for <x> search the current dir first, then each + /// directory in SearchDirs, starting at AngledDirIdx, consecutively. If + /// NoCurDirSearch is true, then the check for the file in the current + /// directory is suppressed. + std::vector<DirectoryLookup> SearchDirs; + unsigned AngledDirIdx; + unsigned SystemDirIdx; + bool NoCurDirSearch; + + /// \brief \#include prefixes for which the 'system header' property is + /// overridden. + /// + /// For a \#include "x" or \#include \<x> directive, the last string in this + /// list which is a prefix of 'x' determines whether the file is treated as + /// a system header. + std::vector<std::pair<std::string, bool> > SystemHeaderPrefixes; + + /// \brief The path to the module cache. + std::string ModuleCachePath; + + /// \brief All of the preprocessor-specific data about files that are + /// included, indexed by the FileEntry's UID. + mutable std::vector<HeaderFileInfo> FileInfo; + + /// Keeps track of each lookup performed by LookupFile. + struct LookupFileCacheInfo { + /// Starting index in SearchDirs that the cached search was performed from. + /// If there is a hit and this value doesn't match the current query, the + /// cache has to be ignored. + unsigned StartIdx; + /// The entry in SearchDirs that satisfied the query. + unsigned HitIdx; + /// This is non-null if the original filename was mapped to a framework + /// include via a headermap. + const char *MappedName; + + /// Default constructor -- Initialize all members with zero. + LookupFileCacheInfo(): StartIdx(0), HitIdx(0), MappedName(nullptr) {} + + void reset(unsigned StartIdx) { + this->StartIdx = StartIdx; + this->MappedName = nullptr; + } + }; + llvm::StringMap<LookupFileCacheInfo, llvm::BumpPtrAllocator> LookupFileCache; + + /// \brief Collection mapping a framework or subframework + /// name like "Carbon" to the Carbon.framework directory. + llvm::StringMap<FrameworkCacheEntry, llvm::BumpPtrAllocator> FrameworkMap; + + /// IncludeAliases - maps include file names (including the quotes or + /// angle brackets) to other include file names. This is used to support the + /// include_alias pragma for Microsoft compatibility. + typedef llvm::StringMap<std::string, llvm::BumpPtrAllocator> + IncludeAliasMap; + std::unique_ptr<IncludeAliasMap> IncludeAliases; + + /// HeaderMaps - This is a mapping from FileEntry -> HeaderMap, uniquing + /// headermaps. This vector owns the headermap. + std::vector<std::pair<const FileEntry*, const HeaderMap*> > HeaderMaps; + + /// \brief The mapping between modules and headers. + mutable ModuleMap ModMap; + + /// \brief Describes whether a given directory has a module map in it. + llvm::DenseMap<const DirectoryEntry *, bool> DirectoryHasModuleMap; + + /// \brief Set of module map files we've already loaded, and a flag indicating + /// whether they were valid or not. + llvm::DenseMap<const FileEntry *, bool> LoadedModuleMaps; + + /// \brief Uniqued set of framework names, which is used to track which + /// headers were included as framework headers. + llvm::StringSet<llvm::BumpPtrAllocator> FrameworkNames; + + /// \brief Entity used to resolve the identifier IDs of controlling + /// macros into IdentifierInfo pointers, and keep the identifire up to date, + /// as needed. + ExternalPreprocessorSource *ExternalLookup; + + /// \brief Entity used to look up stored header file information. + ExternalHeaderFileInfoSource *ExternalSource; + + // Various statistics we track for performance analysis. + unsigned NumIncluded; + unsigned NumMultiIncludeFileOptzn; + unsigned NumFrameworkLookups, NumSubFrameworkLookups; + + const LangOptions &LangOpts; + + // HeaderSearch doesn't support default or copy construction. + HeaderSearch(const HeaderSearch&) = delete; + void operator=(const HeaderSearch&) = delete; + + friend class DirectoryLookup; + +public: + HeaderSearch(IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts, + SourceManager &SourceMgr, DiagnosticsEngine &Diags, + const LangOptions &LangOpts, const TargetInfo *Target); + ~HeaderSearch(); + + /// \brief Retrieve the header-search options with which this header search + /// was initialized. + HeaderSearchOptions &getHeaderSearchOpts() const { return *HSOpts; } + + FileManager &getFileMgr() const { return FileMgr; } + + /// \brief Interface for setting the file search paths. + void SetSearchPaths(const std::vector<DirectoryLookup> &dirs, + unsigned angledDirIdx, unsigned systemDirIdx, + bool noCurDirSearch) { + assert(angledDirIdx <= systemDirIdx && systemDirIdx <= dirs.size() && + "Directory indicies are unordered"); + SearchDirs = dirs; + AngledDirIdx = angledDirIdx; + SystemDirIdx = systemDirIdx; + NoCurDirSearch = noCurDirSearch; + //LookupFileCache.clear(); + } + + /// \brief Add an additional search path. + void AddSearchPath(const DirectoryLookup &dir, bool isAngled) { + unsigned idx = isAngled ? SystemDirIdx : AngledDirIdx; + SearchDirs.insert(SearchDirs.begin() + idx, dir); + if (!isAngled) + AngledDirIdx++; + SystemDirIdx++; + } + + /// \brief Set the list of system header prefixes. + void SetSystemHeaderPrefixes(ArrayRef<std::pair<std::string, bool> > P) { + SystemHeaderPrefixes.assign(P.begin(), P.end()); + } + + /// \brief Checks whether the map exists or not. + bool HasIncludeAliasMap() const { return (bool)IncludeAliases; } + + /// \brief Map the source include name to the dest include name. + /// + /// The Source should include the angle brackets or quotes, the dest + /// should not. This allows for distinction between <> and "" headers. + void AddIncludeAlias(StringRef Source, StringRef Dest) { + if (!IncludeAliases) + IncludeAliases.reset(new IncludeAliasMap); + (*IncludeAliases)[Source] = Dest; + } + + /// MapHeaderToIncludeAlias - Maps one header file name to a different header + /// file name, for use with the include_alias pragma. Note that the source + /// file name should include the angle brackets or quotes. Returns StringRef + /// as null if the header cannot be mapped. + StringRef MapHeaderToIncludeAlias(StringRef Source) { + assert(IncludeAliases && "Trying to map headers when there's no map"); + + // Do any filename replacements before anything else + IncludeAliasMap::const_iterator Iter = IncludeAliases->find(Source); + if (Iter != IncludeAliases->end()) + return Iter->second; + return StringRef(); + } + + /// \brief Set the path to the module cache. + void setModuleCachePath(StringRef CachePath) { + ModuleCachePath = CachePath; + } + + /// \brief Retrieve the path to the module cache. + StringRef getModuleCachePath() const { return ModuleCachePath; } + + /// \brief Consider modules when including files from this directory. + void setDirectoryHasModuleMap(const DirectoryEntry* Dir) { + DirectoryHasModuleMap[Dir] = true; + } + + /// \brief Forget everything we know about headers so far. + void ClearFileInfo() { + FileInfo.clear(); + } + + void SetExternalLookup(ExternalPreprocessorSource *EPS) { + ExternalLookup = EPS; + } + + ExternalPreprocessorSource *getExternalLookup() const { + return ExternalLookup; + } + + /// \brief Set the external source of header information. + void SetExternalSource(ExternalHeaderFileInfoSource *ES) { + ExternalSource = ES; + } + + /// \brief Set the target information for the header search, if not + /// already known. + void setTarget(const TargetInfo &Target); + + /// \brief Given a "foo" or \<foo> reference, look up the indicated file, + /// return null on failure. + /// + /// \returns If successful, this returns 'UsedDir', the DirectoryLookup member + /// the file was found in, or null if not applicable. + /// + /// \param IncludeLoc Used for diagnostics if valid. + /// + /// \param isAngled indicates whether the file reference is a <> reference. + /// + /// \param CurDir If non-null, the file was found in the specified directory + /// search location. This is used to implement \#include_next. + /// + /// \param Includers Indicates where the \#including file(s) are, in case + /// relative searches are needed. In reverse order of inclusion. + /// + /// \param SearchPath If non-null, will be set to the search path relative + /// to which the file was found. If the include path is absolute, SearchPath + /// will be set to an empty string. + /// + /// \param RelativePath If non-null, will be set to the path relative to + /// SearchPath at which the file was found. This only differs from the + /// Filename for framework includes. + /// + /// \param SuggestedModule If non-null, and the file found is semantically + /// part of a known module, this will be set to the module that should + /// be imported instead of preprocessing/parsing the file found. + const FileEntry *LookupFile( + StringRef Filename, SourceLocation IncludeLoc, bool isAngled, + const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir, + ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>> Includers, + SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath, + Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule, + bool SkipCache = false); + + /// \brief Look up a subframework for the specified \#include file. + /// + /// For example, if \#include'ing <HIToolbox/HIToolbox.h> from + /// within ".../Carbon.framework/Headers/Carbon.h", check to see if + /// HIToolbox is a subframework within Carbon.framework. If so, return + /// the FileEntry for the designated file, otherwise return null. + const FileEntry *LookupSubframeworkHeader( + StringRef Filename, const FileEntry *RelativeFileEnt, + SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath, + Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule); + + /// \brief Look up the specified framework name in our framework cache. + /// \returns The DirectoryEntry it is in if we know, null otherwise. + FrameworkCacheEntry &LookupFrameworkCache(StringRef FWName) { + return FrameworkMap[FWName]; + } + + /// \brief Mark the specified file as a target of of a \#include, + /// \#include_next, or \#import directive. + /// + /// \return false if \#including the file will have no effect or true + /// if we should include it. + bool ShouldEnterIncludeFile(Preprocessor &PP, const FileEntry *File, + bool isImport, Module *CorrespondingModule); + + /// \brief Return whether the specified file is a normal header, + /// a system header, or a C++ friendly system header. + SrcMgr::CharacteristicKind getFileDirFlavor(const FileEntry *File) { + return (SrcMgr::CharacteristicKind)getFileInfo(File).DirInfo; + } + + /// \brief Mark the specified file as a "once only" file, e.g. due to + /// \#pragma once. + void MarkFileIncludeOnce(const FileEntry *File) { + HeaderFileInfo &FI = getFileInfo(File); + FI.isImport = true; + FI.isPragmaOnce = true; + } + + /// \brief Mark the specified file as a system header, e.g. due to + /// \#pragma GCC system_header. + void MarkFileSystemHeader(const FileEntry *File) { + getFileInfo(File).DirInfo = SrcMgr::C_System; + } + + /// \brief Mark the specified file as part of a module. + void MarkFileModuleHeader(const FileEntry *File, + ModuleMap::ModuleHeaderRole Role, + bool IsCompiledModuleHeader); + + /// \brief Increment the count for the number of times the specified + /// FileEntry has been entered. + void IncrementIncludeCount(const FileEntry *File) { + ++getFileInfo(File).NumIncludes; + } + + /// \brief Mark the specified file as having a controlling macro. + /// + /// This is used by the multiple-include optimization to eliminate + /// no-op \#includes. + void SetFileControllingMacro(const FileEntry *File, + const IdentifierInfo *ControllingMacro) { + getFileInfo(File).ControllingMacro = ControllingMacro; + } + + /// \brief Return true if this is the first time encountering this header. + bool FirstTimeLexingFile(const FileEntry *File) { + return getFileInfo(File).NumIncludes == 1; + } + + /// \brief Determine whether this file is intended to be safe from + /// multiple inclusions, e.g., it has \#pragma once or a controlling + /// macro. + /// + /// This routine does not consider the effect of \#import + bool isFileMultipleIncludeGuarded(const FileEntry *File); + + /// CreateHeaderMap - This method returns a HeaderMap for the specified + /// FileEntry, uniquing them through the 'HeaderMaps' datastructure. + const HeaderMap *CreateHeaderMap(const FileEntry *FE); + + /// \brief Retrieve the name of the module file that should be used to + /// load the given module. + /// + /// \param Module The module whose module file name will be returned. + /// + /// \returns The name of the module file that corresponds to this module, + /// or an empty string if this module does not correspond to any module file. + std::string getModuleFileName(Module *Module); + + /// \brief Retrieve the name of the module file that should be used to + /// load a module with the given name. + /// + /// \param ModuleName The module whose module file name will be returned. + /// + /// \param ModuleMapPath A path that when combined with \c ModuleName + /// uniquely identifies this module. See Module::ModuleMap. + /// + /// \returns The name of the module file that corresponds to this module, + /// or an empty string if this module does not correspond to any module file. + std::string getModuleFileName(StringRef ModuleName, StringRef ModuleMapPath); + + /// \brief Lookup a module Search for a module with the given name. + /// + /// \param ModuleName The name of the module we're looking for. + /// + /// \param AllowSearch Whether we are allowed to search in the various + /// search directories to produce a module definition. If not, this lookup + /// will only return an already-known module. + /// + /// \returns The module with the given name. + Module *lookupModule(StringRef ModuleName, bool AllowSearch = true); + + /// \brief Try to find a module map file in the given directory, returning + /// \c nullptr if none is found. + const FileEntry *lookupModuleMapFile(const DirectoryEntry *Dir, + bool IsFramework); + + void IncrementFrameworkLookupCount() { ++NumFrameworkLookups; } + + /// \brief Determine whether there is a module map that may map the header + /// with the given file name to a (sub)module. + /// Always returns false if modules are disabled. + /// + /// \param Filename The name of the file. + /// + /// \param Root The "root" directory, at which we should stop looking for + /// module maps. + /// + /// \param IsSystem Whether the directories we're looking at are system + /// header directories. + bool hasModuleMap(StringRef Filename, const DirectoryEntry *Root, + bool IsSystem); + + /// \brief Retrieve the module that corresponds to the given file, if any. + /// + /// \param File The header that we wish to map to a module. + ModuleMap::KnownHeader findModuleForHeader(const FileEntry *File) const; + + /// \brief Read the contents of the given module map file. + /// + /// \param File The module map file. + /// \param IsSystem Whether this file is in a system header directory. + /// + /// \returns true if an error occurred, false otherwise. + bool loadModuleMapFile(const FileEntry *File, bool IsSystem); + + /// \brief Collect the set of all known, top-level modules. + /// + /// \param Modules Will be filled with the set of known, top-level modules. + void collectAllModules(SmallVectorImpl<Module *> &Modules); + + /// \brief Load all known, top-level system modules. + void loadTopLevelSystemModules(); + +private: + /// \brief Retrieve a module with the given name, which may be part of the + /// given framework. + /// + /// \param Name The name of the module to retrieve. + /// + /// \param Dir The framework directory (e.g., ModuleName.framework). + /// + /// \param IsSystem Whether the framework directory is part of the system + /// frameworks. + /// + /// \returns The module, if found; otherwise, null. + Module *loadFrameworkModule(StringRef Name, + const DirectoryEntry *Dir, + bool IsSystem); + + /// \brief Load all of the module maps within the immediate subdirectories + /// of the given search directory. + void loadSubdirectoryModuleMaps(DirectoryLookup &SearchDir); + + /// \brief Find and suggest a usable module for the given file. + /// + /// \return \c true if the file can be used, \c false if we are not permitted to + /// find this file due to requirements from \p RequestingModule. + bool findUsableModuleForHeader(const FileEntry *File, + const DirectoryEntry *Root, + Module *RequestingModule, + ModuleMap::KnownHeader *SuggestedModule, + bool IsSystemHeaderDir); + + /// \brief Find and suggest a usable module for the given file, which is part of + /// the specified framework. + /// + /// \return \c true if the file can be used, \c false if we are not permitted to + /// find this file due to requirements from \p RequestingModule. + bool findUsableModuleForFrameworkHeader( + const FileEntry *File, StringRef FrameworkDir, Module *RequestingModule, + ModuleMap::KnownHeader *SuggestedModule, bool IsSystemFramework); + + /// \brief Look up the file with the specified name and determine its owning + /// module. + const FileEntry * + getFileAndSuggestModule(StringRef FileName, const DirectoryEntry *Dir, + bool IsSystemHeaderDir, Module *RequestingModule, + ModuleMap::KnownHeader *SuggestedModule); + +public: + /// \brief Retrieve the module map. + ModuleMap &getModuleMap() { return ModMap; } + + /// \brief Retrieve the module map. + const ModuleMap &getModuleMap() const { return ModMap; } + + unsigned header_file_size() const { return FileInfo.size(); } + + /// \brief Return the HeaderFileInfo structure for the specified FileEntry, + /// in preparation for updating it in some way. + HeaderFileInfo &getFileInfo(const FileEntry *FE); + + /// \brief Return the HeaderFileInfo structure for the specified FileEntry, + /// if it has ever been filled in. + /// \param WantExternal Whether the caller wants purely-external header file + /// info (where \p External is true). + const HeaderFileInfo *getExistingFileInfo(const FileEntry *FE, + bool WantExternal = true) const; + + // Used by external tools + typedef std::vector<DirectoryLookup>::const_iterator search_dir_iterator; + search_dir_iterator search_dir_begin() const { return SearchDirs.begin(); } + search_dir_iterator search_dir_end() const { return SearchDirs.end(); } + unsigned search_dir_size() const { return SearchDirs.size(); } + + search_dir_iterator quoted_dir_begin() const { + return SearchDirs.begin(); + } + search_dir_iterator quoted_dir_end() const { + return SearchDirs.begin() + AngledDirIdx; + } + + search_dir_iterator angled_dir_begin() const { + return SearchDirs.begin() + AngledDirIdx; + } + search_dir_iterator angled_dir_end() const { + return SearchDirs.begin() + SystemDirIdx; + } + + search_dir_iterator system_dir_begin() const { + return SearchDirs.begin() + SystemDirIdx; + } + search_dir_iterator system_dir_end() const { return SearchDirs.end(); } + + /// \brief Retrieve a uniqued framework name. + StringRef getUniqueFrameworkName(StringRef Framework); + + void PrintStats(); + + size_t getTotalMemory() const; + + static std::string NormalizeDashIncludePath(StringRef File, + FileManager &FileMgr); + +private: + /// \brief Describes what happened when we tried to load a module map file. + enum LoadModuleMapResult { + /// \brief The module map file had already been loaded. + LMM_AlreadyLoaded, + /// \brief The module map file was loaded by this invocation. + LMM_NewlyLoaded, + /// \brief There is was directory with the given name. + LMM_NoDirectory, + /// \brief There was either no module map file or the module map file was + /// invalid. + LMM_InvalidModuleMap + }; + + LoadModuleMapResult loadModuleMapFileImpl(const FileEntry *File, + bool IsSystem, + const DirectoryEntry *Dir); + + /// \brief Try to load the module map file in the given directory. + /// + /// \param DirName The name of the directory where we will look for a module + /// map file. + /// \param IsSystem Whether this is a system header directory. + /// \param IsFramework Whether this is a framework directory. + /// + /// \returns The result of attempting to load the module map file from the + /// named directory. + LoadModuleMapResult loadModuleMapFile(StringRef DirName, bool IsSystem, + bool IsFramework); + + /// \brief Try to load the module map file in the given directory. + /// + /// \param Dir The directory where we will look for a module map file. + /// \param IsSystem Whether this is a system header directory. + /// \param IsFramework Whether this is a framework directory. + /// + /// \returns The result of attempting to load the module map file from the + /// named directory. + LoadModuleMapResult loadModuleMapFile(const DirectoryEntry *Dir, + bool IsSystem, bool IsFramework); +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Lex/HeaderSearchOptions.h b/contrib/llvm/tools/clang/include/clang/Lex/HeaderSearchOptions.h new file mode 100644 index 0000000..915dbf7 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Lex/HeaderSearchOptions.h @@ -0,0 +1,206 @@ +//===--- HeaderSearchOptions.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_LEX_HEADERSEARCHOPTIONS_H +#define LLVM_CLANG_LEX_HEADERSEARCHOPTIONS_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/StringRef.h" +#include <string> +#include <vector> + +namespace clang { + +namespace frontend { + /// IncludeDirGroup - Identifies the group an include Entry belongs to, + /// representing its relative positive in the search list. + /// \#include directives whose paths are enclosed by string quotes ("") + /// start searching at the Quoted group (specified by '-iquote'), + /// then search the Angled group, then the System group, etc. + enum IncludeDirGroup { + Quoted = 0, ///< '\#include ""' paths, added by 'gcc -iquote'. + Angled, ///< Paths for '\#include <>' added by '-I'. + IndexHeaderMap, ///< Like Angled, but marks header maps used when + /// building frameworks. + System, ///< Like Angled, but marks system directories. + ExternCSystem, ///< Like System, but headers are implicitly wrapped in + /// extern "C". + CSystem, ///< Like System, but only used for C. + CXXSystem, ///< Like System, but only used for C++. + ObjCSystem, ///< Like System, but only used for ObjC. + ObjCXXSystem, ///< Like System, but only used for ObjC++. + After ///< Like System, but searched after the system directories. + }; +} + +/// HeaderSearchOptions - Helper class for storing options related to the +/// initialization of the HeaderSearch object. +class HeaderSearchOptions : public RefCountedBase<HeaderSearchOptions> { +public: + struct Entry { + std::string Path; + frontend::IncludeDirGroup Group; + unsigned IsFramework : 1; + + /// IgnoreSysRoot - This is false if an absolute path should be treated + /// relative to the sysroot, or true if it should always be the absolute + /// path. + unsigned IgnoreSysRoot : 1; + + Entry(StringRef path, frontend::IncludeDirGroup group, bool isFramework, + bool ignoreSysRoot) + : Path(path), Group(group), IsFramework(isFramework), + IgnoreSysRoot(ignoreSysRoot) {} + }; + + struct SystemHeaderPrefix { + /// A prefix to be matched against paths in \#include directives. + std::string Prefix; + + /// True if paths beginning with this prefix should be treated as system + /// headers. + bool IsSystemHeader; + + SystemHeaderPrefix(StringRef Prefix, bool IsSystemHeader) + : Prefix(Prefix), IsSystemHeader(IsSystemHeader) {} + }; + + /// If non-empty, the directory to use as a "virtual system root" for include + /// paths. + std::string Sysroot; + + /// User specified include entries. + std::vector<Entry> UserEntries; + + /// User-specified system header prefixes. + std::vector<SystemHeaderPrefix> SystemHeaderPrefixes; + + /// The directory which holds the compiler resource files (builtin includes, + /// etc.). + std::string ResourceDir; + + /// \brief The directory used for the module cache. + std::string ModuleCachePath; + + /// \brief The directory used for a user build. + std::string ModuleUserBuildPath; + + /// The module/pch container format. + std::string ModuleFormat; + + /// \brief Whether we should disable the use of the hash string within the + /// module cache. + /// + /// Note: Only used for testing! + unsigned DisableModuleHash : 1; + + /// \brief Implicit module maps. This option is enabld by default when + /// modules is enabled. + unsigned ImplicitModuleMaps : 1; + + /// \brief Set the 'home directory' of a module map file to the current + /// working directory (or the home directory of the module map file that + /// contained the 'extern module' directive importing this module map file + /// if any) rather than the directory containing the module map file. + // + /// The home directory is where we look for files named in the module map + /// file. + unsigned ModuleMapFileHomeIsCwd : 1; + + /// \brief The interval (in seconds) between pruning operations. + /// + /// This operation is expensive, because it requires Clang to walk through + /// the directory structure of the module cache, stat()'ing and removing + /// files. + /// + /// The default value is large, e.g., the operation runs once a week. + unsigned ModuleCachePruneInterval; + + /// \brief The time (in seconds) after which an unused module file will be + /// considered unused and will, therefore, be pruned. + /// + /// When the module cache is pruned, any module file that has not been + /// accessed in this many seconds will be removed. The default value is + /// large, e.g., a month, to avoid forcing infrequently-used modules to be + /// regenerated often. + unsigned ModuleCachePruneAfter; + + /// \brief The time in seconds when the build session started. + /// + /// This time is used by other optimizations in header search and module + /// loading. + uint64_t BuildSessionTimestamp; + + /// \brief The set of macro names that should be ignored for the purposes + /// of computing the module hash. + llvm::SmallSetVector<std::string, 16> ModulesIgnoreMacros; + + /// \brief The set of user-provided virtual filesystem overlay files. + std::vector<std::string> VFSOverlayFiles; + + /// Include the compiler builtin includes. + unsigned UseBuiltinIncludes : 1; + + /// Include the system standard include search directories. + unsigned UseStandardSystemIncludes : 1; + + /// Include the system standard C++ library include search directories. + unsigned UseStandardCXXIncludes : 1; + + /// Use libc++ instead of the default libstdc++. + unsigned UseLibcxx : 1; + + /// Whether header search information should be output as for -v. + unsigned Verbose : 1; + + /// \brief If true, skip verifying input files used by modules if the + /// module was already verified during this build session (see + /// \c BuildSessionTimestamp). + unsigned ModulesValidateOncePerBuildSession : 1; + + /// \brief Whether to validate system input files when a module is loaded. + unsigned ModulesValidateSystemHeaders : 1; + + /// Whether the module includes debug information (-gmodules). + unsigned UseDebugInfo : 1; + + HeaderSearchOptions(StringRef _Sysroot = "/") + : Sysroot(_Sysroot), ModuleFormat("raw"), DisableModuleHash(0), + ImplicitModuleMaps(0), ModuleMapFileHomeIsCwd(0), + ModuleCachePruneInterval(7 * 24 * 60 * 60), + ModuleCachePruneAfter(31 * 24 * 60 * 60), BuildSessionTimestamp(0), + UseBuiltinIncludes(true), UseStandardSystemIncludes(true), + UseStandardCXXIncludes(true), UseLibcxx(false), Verbose(false), + ModulesValidateOncePerBuildSession(false), + ModulesValidateSystemHeaders(false), + UseDebugInfo(false) {} + + /// AddPath - Add the \p Path path to the specified \p Group list. + void AddPath(StringRef Path, frontend::IncludeDirGroup Group, + bool IsFramework, bool IgnoreSysRoot) { + UserEntries.emplace_back(Path, Group, IsFramework, IgnoreSysRoot); + } + + /// AddSystemHeaderPrefix - Override whether \#include directives naming a + /// path starting with \p Prefix should be considered as naming a system + /// header. + void AddSystemHeaderPrefix(StringRef Prefix, bool IsSystemHeader) { + SystemHeaderPrefixes.emplace_back(Prefix, IsSystemHeader); + } + + void AddVFSOverlayFile(StringRef Name) { + VFSOverlayFiles.push_back(Name); + } +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Lex/LexDiagnostic.h b/contrib/llvm/tools/clang/include/clang/Lex/LexDiagnostic.h new file mode 100644 index 0000000..5d724c0 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Lex/LexDiagnostic.h @@ -0,0 +1,28 @@ +//===--- DiagnosticLex.h - Diagnostics for liblex ---------------*- 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_LEX_LEXDIAGNOSTIC_H +#define LLVM_CLANG_LEX_LEXDIAGNOSTIC_H + +#include "clang/Basic/Diagnostic.h" + +namespace clang { + namespace diag { + enum { +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\ + SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM, +#define LEXSTART +#include "clang/Basic/DiagnosticLexKinds.inc" +#undef DIAG + NUM_BUILTIN_LEX_DIAGNOSTICS + }; + } // end namespace diag +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Lex/Lexer.h b/contrib/llvm/tools/clang/include/clang/Lex/Lexer.h new file mode 100644 index 0000000..12565d0 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Lex/Lexer.h @@ -0,0 +1,665 @@ +//===--- Lexer.h - C Language Family Lexer ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Lexer interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_LEXER_H +#define LLVM_CLANG_LEX_LEXER_H + +#include "clang/Basic/LangOptions.h" +#include "clang/Lex/PreprocessorLexer.h" +#include "llvm/ADT/SmallVector.h" +#include <cassert> +#include <string> + +namespace clang { +class DiagnosticsEngine; +class SourceManager; +class Preprocessor; +class DiagnosticBuilder; + +/// ConflictMarkerKind - Kinds of conflict marker which the lexer might be +/// recovering from. +enum ConflictMarkerKind { + /// Not within a conflict marker. + CMK_None, + /// A normal or diff3 conflict marker, initiated by at least 7 "<"s, + /// separated by at least 7 "="s or "|"s, and terminated by at least 7 ">"s. + CMK_Normal, + /// A Perforce-style conflict marker, initiated by 4 ">"s, + /// separated by 4 "="s, and terminated by 4 "<"s. + CMK_Perforce +}; + +/// Lexer - This provides a simple interface that turns a text buffer into a +/// stream of tokens. This provides no support for file reading or buffering, +/// or buffering/seeking of tokens, only forward lexing is supported. It relies +/// on the specified Preprocessor object to handle preprocessor directives, etc. +class Lexer : public PreprocessorLexer { + void anchor() override; + + //===--------------------------------------------------------------------===// + // Constant configuration values for this lexer. + const char *BufferStart; // Start of the buffer. + const char *BufferEnd; // End of the buffer. + SourceLocation FileLoc; // Location for start of file. + LangOptions LangOpts; // LangOpts enabled by this language (cache). + bool Is_PragmaLexer; // True if lexer for _Pragma handling. + + //===--------------------------------------------------------------------===// + // Context-specific lexing flags set by the preprocessor. + // + + /// ExtendedTokenMode - The lexer can optionally keep comments and whitespace + /// and return them as tokens. This is used for -C and -CC modes, and + /// whitespace preservation can be useful for some clients that want to lex + /// the file in raw mode and get every character from the file. + /// + /// When this is set to 2 it returns comments and whitespace. When set to 1 + /// it returns comments, when it is set to 0 it returns normal tokens only. + unsigned char ExtendedTokenMode; + + //===--------------------------------------------------------------------===// + // Context that changes as the file is lexed. + // NOTE: any state that mutates when in raw mode must have save/restore code + // in Lexer::isNextPPTokenLParen. + + // BufferPtr - Current pointer into the buffer. This is the next character + // to be lexed. + const char *BufferPtr; + + // IsAtStartOfLine - True if the next lexed token should get the "start of + // line" flag set on it. + bool IsAtStartOfLine; + + bool IsAtPhysicalStartOfLine; + + bool HasLeadingSpace; + + bool HasLeadingEmptyMacro; + + // CurrentConflictMarkerState - The kind of conflict marker we are handling. + ConflictMarkerKind CurrentConflictMarkerState; + + Lexer(const Lexer &) = delete; + void operator=(const Lexer &) = delete; + friend class Preprocessor; + + void InitLexer(const char *BufStart, const char *BufPtr, const char *BufEnd); +public: + + /// Lexer constructor - Create a new lexer object for the specified buffer + /// with the specified preprocessor managing the lexing process. This lexer + /// assumes that the associated file buffer and Preprocessor objects will + /// outlive it, so it doesn't take ownership of either of them. + Lexer(FileID FID, const llvm::MemoryBuffer *InputBuffer, Preprocessor &PP); + + /// Lexer constructor - Create a new raw lexer object. This object is only + /// suitable for calls to 'LexFromRawLexer'. This lexer assumes that the + /// text range will outlive it, so it doesn't take ownership of it. + Lexer(SourceLocation FileLoc, const LangOptions &LangOpts, + const char *BufStart, const char *BufPtr, const char *BufEnd); + + /// Lexer constructor - Create a new raw lexer object. This object is only + /// suitable for calls to 'LexFromRawLexer'. This lexer assumes that the + /// text range will outlive it, so it doesn't take ownership of it. + Lexer(FileID FID, const llvm::MemoryBuffer *InputBuffer, + const SourceManager &SM, const LangOptions &LangOpts); + + /// Create_PragmaLexer: Lexer constructor - Create a new lexer object for + /// _Pragma expansion. This has a variety of magic semantics that this method + /// sets up. It returns a new'd Lexer that must be delete'd when done. + static Lexer *Create_PragmaLexer(SourceLocation SpellingLoc, + SourceLocation ExpansionLocStart, + SourceLocation ExpansionLocEnd, + unsigned TokLen, Preprocessor &PP); + + + /// getLangOpts - Return the language features currently enabled. + /// NOTE: this lexer modifies features as a file is parsed! + const LangOptions &getLangOpts() const { return LangOpts; } + + /// getFileLoc - Return the File Location for the file we are lexing out of. + /// The physical location encodes the location where the characters come from, + /// the virtual location encodes where we should *claim* the characters came + /// from. Currently this is only used by _Pragma handling. + SourceLocation getFileLoc() const { return FileLoc; } + +private: + /// Lex - Return the next token in the file. If this is the end of file, it + /// return the tok::eof token. This implicitly involves the preprocessor. + bool Lex(Token &Result); + +public: + /// isPragmaLexer - Returns true if this Lexer is being used to lex a pragma. + bool isPragmaLexer() const { return Is_PragmaLexer; } + +private: + /// IndirectLex - An indirect call to 'Lex' that can be invoked via + /// the PreprocessorLexer interface. + void IndirectLex(Token &Result) override { Lex(Result); } + +public: + /// LexFromRawLexer - Lex a token from a designated raw lexer (one with no + /// associated preprocessor object. Return true if the 'next character to + /// read' pointer points at the end of the lexer buffer, false otherwise. + bool LexFromRawLexer(Token &Result) { + assert(LexingRawMode && "Not already in raw mode!"); + Lex(Result); + // Note that lexing to the end of the buffer doesn't implicitly delete the + // lexer when in raw mode. + return BufferPtr == BufferEnd; + } + + /// isKeepWhitespaceMode - Return true if the lexer should return tokens for + /// every character in the file, including whitespace and comments. This + /// should only be used in raw mode, as the preprocessor is not prepared to + /// deal with the excess tokens. + bool isKeepWhitespaceMode() const { + return ExtendedTokenMode > 1; + } + + /// SetKeepWhitespaceMode - This method lets clients enable or disable + /// whitespace retention mode. + void SetKeepWhitespaceMode(bool Val) { + assert((!Val || LexingRawMode || LangOpts.TraditionalCPP) && + "Can only retain whitespace in raw mode or -traditional-cpp"); + ExtendedTokenMode = Val ? 2 : 0; + } + + /// inKeepCommentMode - Return true if the lexer should return comments as + /// tokens. + bool inKeepCommentMode() const { + return ExtendedTokenMode > 0; + } + + /// SetCommentRetentionMode - Change the comment retention mode of the lexer + /// to the specified mode. This is really only useful when lexing in raw + /// mode, because otherwise the lexer needs to manage this. + void SetCommentRetentionState(bool Mode) { + assert(!isKeepWhitespaceMode() && + "Can't play with comment retention state when retaining whitespace"); + ExtendedTokenMode = Mode ? 1 : 0; + } + + /// Sets the extended token mode back to its initial value, according to the + /// language options and preprocessor. This controls whether the lexer + /// produces comment and whitespace tokens. + /// + /// This requires the lexer to have an associated preprocessor. A standalone + /// lexer has nothing to reset to. + void resetExtendedTokenMode(); + + /// Gets source code buffer. + StringRef getBuffer() const { + return StringRef(BufferStart, BufferEnd - BufferStart); + } + + /// ReadToEndOfLine - Read the rest of the current preprocessor line as an + /// uninterpreted string. This switches the lexer out of directive mode. + void ReadToEndOfLine(SmallVectorImpl<char> *Result = nullptr); + + + /// Diag - Forwarding function for diagnostics. This translate a source + /// position in the current buffer into a SourceLocation object for rendering. + DiagnosticBuilder Diag(const char *Loc, unsigned DiagID) const; + + /// getSourceLocation - Return a source location identifier for the specified + /// offset in the current file. + SourceLocation getSourceLocation(const char *Loc, unsigned TokLen = 1) const; + + /// getSourceLocation - Return a source location for the next character in + /// the current file. + SourceLocation getSourceLocation() override { + return getSourceLocation(BufferPtr); + } + + /// \brief Return the current location in the buffer. + const char *getBufferLocation() const { return BufferPtr; } + + /// Stringify - Convert the specified string into a C string by escaping '\' + /// and " characters. This does not add surrounding ""'s to the string. + /// If Charify is true, this escapes the ' character instead of ". + static std::string Stringify(StringRef Str, bool Charify = false); + + /// Stringify - Convert the specified string into a C string by escaping '\' + /// and " characters. This does not add surrounding ""'s to the string. + static void Stringify(SmallVectorImpl<char> &Str); + + + /// getSpelling - This method is used to get the spelling of a token into a + /// preallocated buffer, instead of as an std::string. The caller is required + /// to allocate enough space for the token, which is guaranteed to be at least + /// Tok.getLength() bytes long. The length of the actual result is returned. + /// + /// Note that this method may do two possible things: it may either fill in + /// the buffer specified with characters, or it may *change the input pointer* + /// to point to a constant buffer with the data already in it (avoiding a + /// copy). The caller is not allowed to modify the returned buffer pointer + /// if an internal buffer is returned. + static unsigned getSpelling(const Token &Tok, const char *&Buffer, + const SourceManager &SourceMgr, + const LangOptions &LangOpts, + bool *Invalid = nullptr); + + /// getSpelling() - Return the 'spelling' of the Tok token. The spelling of a + /// token is the characters used to represent the token in the source file + /// after trigraph expansion and escaped-newline folding. In particular, this + /// wants to get the true, uncanonicalized, spelling of things like digraphs + /// UCNs, etc. + static std::string getSpelling(const Token &Tok, + const SourceManager &SourceMgr, + const LangOptions &LangOpts, + bool *Invalid = nullptr); + + /// getSpelling - This method is used to get the spelling of the + /// token at the given source location. If, as is usually true, it + /// is not necessary to copy any data, then the returned string may + /// not point into the provided buffer. + /// + /// This method lexes at the expansion depth of the given + /// location and does not jump to the expansion or spelling + /// location. + static StringRef getSpelling(SourceLocation loc, + SmallVectorImpl<char> &buffer, + const SourceManager &SourceMgr, + const LangOptions &LangOpts, + bool *invalid = nullptr); + + /// MeasureTokenLength - Relex the token at the specified location and return + /// its length in bytes in the input file. If the token needs cleaning (e.g. + /// includes a trigraph or an escaped newline) then this count includes bytes + /// that are part of that. + static unsigned MeasureTokenLength(SourceLocation Loc, + const SourceManager &SM, + const LangOptions &LangOpts); + + /// \brief Relex the token at the specified location. + /// \returns true if there was a failure, false on success. + static bool getRawToken(SourceLocation Loc, Token &Result, + const SourceManager &SM, + const LangOptions &LangOpts, + bool IgnoreWhiteSpace = false); + + /// \brief Given a location any where in a source buffer, find the location + /// that corresponds to the beginning of the token in which the original + /// source location lands. + static SourceLocation GetBeginningOfToken(SourceLocation Loc, + const SourceManager &SM, + const LangOptions &LangOpts); + + /// AdvanceToTokenCharacter - If the current SourceLocation specifies a + /// location at the start of a token, return a new location that specifies a + /// character within the token. This handles trigraphs and escaped newlines. + static SourceLocation AdvanceToTokenCharacter(SourceLocation TokStart, + unsigned Character, + const SourceManager &SM, + const LangOptions &LangOpts); + + /// \brief Computes the source location just past the end of the + /// token at this source location. + /// + /// This routine can be used to produce a source location that + /// points just past the end of the token referenced by \p Loc, and + /// is generally used when a diagnostic needs to point just after a + /// token where it expected something different that it received. If + /// the returned source location would not be meaningful (e.g., if + /// it points into a macro), this routine returns an invalid + /// source location. + /// + /// \param Offset an offset from the end of the token, where the source + /// location should refer to. The default offset (0) produces a source + /// location pointing just past the end of the token; an offset of 1 produces + /// a source location pointing to the last character in the token, etc. + static SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset, + const SourceManager &SM, + const LangOptions &LangOpts); + + /// \brief Given a token range, produce a corresponding CharSourceRange that + /// is not a token range. This allows the source range to be used by + /// components that don't have access to the lexer and thus can't find the + /// end of the range for themselves. + static CharSourceRange getAsCharRange(SourceRange Range, + const SourceManager &SM, + const LangOptions &LangOpts) { + SourceLocation End = getLocForEndOfToken(Range.getEnd(), 0, SM, LangOpts); + return End.isInvalid() ? CharSourceRange() + : CharSourceRange::getCharRange( + Range.getBegin(), End.getLocWithOffset(-1)); + } + static CharSourceRange getAsCharRange(CharSourceRange Range, + const SourceManager &SM, + const LangOptions &LangOpts) { + return Range.isTokenRange() + ? getAsCharRange(Range.getAsRange(), SM, LangOpts) + : Range; + } + + /// \brief Returns true if the given MacroID location points at the first + /// token of the macro expansion. + /// + /// \param MacroBegin If non-null and function returns true, it is set to + /// begin location of the macro. + static bool isAtStartOfMacroExpansion(SourceLocation loc, + const SourceManager &SM, + const LangOptions &LangOpts, + SourceLocation *MacroBegin = nullptr); + + /// \brief Returns true if the given MacroID location points at the last + /// token of the macro expansion. + /// + /// \param MacroEnd If non-null and function returns true, it is set to + /// end location of the macro. + static bool isAtEndOfMacroExpansion(SourceLocation loc, + const SourceManager &SM, + const LangOptions &LangOpts, + SourceLocation *MacroEnd = nullptr); + + /// \brief Accepts a range and returns a character range with file locations. + /// + /// Returns a null range if a part of the range resides inside a macro + /// expansion or the range does not reside on the same FileID. + /// + /// This function is trying to deal with macros and return a range based on + /// file locations. The cases where it can successfully handle macros are: + /// + /// -begin or end range lies at the start or end of a macro expansion, in + /// which case the location will be set to the expansion point, e.g: + /// \#define M 1 2 + /// a M + /// If you have a range [a, 2] (where 2 came from the macro), the function + /// will return a range for "a M" + /// if you have range [a, 1], the function will fail because the range + /// overlaps with only a part of the macro + /// + /// -The macro is a function macro and the range can be mapped to the macro + /// arguments, e.g: + /// \#define M 1 2 + /// \#define FM(x) x + /// FM(a b M) + /// if you have range [b, 2], the function will return the file range "b M" + /// inside the macro arguments. + /// if you have range [a, 2], the function will return the file range + /// "FM(a b M)" since the range includes all of the macro expansion. + static CharSourceRange makeFileCharRange(CharSourceRange Range, + const SourceManager &SM, + const LangOptions &LangOpts); + + /// \brief Returns a string for the source that the range encompasses. + static StringRef getSourceText(CharSourceRange Range, + const SourceManager &SM, + const LangOptions &LangOpts, + bool *Invalid = nullptr); + + /// \brief Retrieve the name of the immediate macro expansion. + /// + /// This routine starts from a source location, and finds the name of the macro + /// responsible for its immediate expansion. It looks through any intervening + /// macro argument expansions to compute this. It returns a StringRef which + /// refers to the SourceManager-owned buffer of the source where that macro + /// name is spelled. Thus, the result shouldn't out-live that SourceManager. + static StringRef getImmediateMacroName(SourceLocation Loc, + const SourceManager &SM, + const LangOptions &LangOpts); + + /// \brief Compute the preamble of the given file. + /// + /// The preamble of a file contains the initial comments, include directives, + /// and other preprocessor directives that occur before the code in this + /// particular file actually begins. The preamble of the main source file is + /// a potential prefix header. + /// + /// \param Buffer The memory buffer containing the file's contents. + /// + /// \param MaxLines If non-zero, restrict the length of the preamble + /// to fewer than this number of lines. + /// + /// \returns The offset into the file where the preamble ends and the rest + /// of the file begins along with a boolean value indicating whether + /// the preamble ends at the beginning of a new line. + static std::pair<unsigned, bool> ComputePreamble(StringRef Buffer, + const LangOptions &LangOpts, + unsigned MaxLines = 0); + + /// \brief Checks that the given token is the first token that occurs after + /// the given location (this excludes comments and whitespace). Returns the + /// location immediately after the specified token. If the token is not found + /// or the location is inside a macro, the returned source location will be + /// invalid. + static SourceLocation findLocationAfterToken(SourceLocation loc, + tok::TokenKind TKind, + const SourceManager &SM, + const LangOptions &LangOpts, + bool SkipTrailingWhitespaceAndNewLine); + + /// \brief Returns true if the given character could appear in an identifier. + static bool isIdentifierBodyChar(char c, const LangOptions &LangOpts); + + /// getCharAndSizeNoWarn - Like the getCharAndSize method, but does not ever + /// emit a warning. + static inline char getCharAndSizeNoWarn(const char *Ptr, unsigned &Size, + const LangOptions &LangOpts) { + // If this is not a trigraph and not a UCN or escaped newline, return + // quickly. + if (isObviouslySimpleCharacter(Ptr[0])) { + Size = 1; + return *Ptr; + } + + Size = 0; + return getCharAndSizeSlowNoWarn(Ptr, Size, LangOpts); + } + + //===--------------------------------------------------------------------===// + // Internal implementation interfaces. +private: + + /// LexTokenInternal - Internal interface to lex a preprocessing token. Called + /// by Lex. + /// + bool LexTokenInternal(Token &Result, bool TokAtPhysicalStartOfLine); + + bool CheckUnicodeWhitespace(Token &Result, uint32_t C, const char *CurPtr); + + /// Given that a token begins with the Unicode character \p C, figure out + /// what kind of token it is and dispatch to the appropriate lexing helper + /// function. + bool LexUnicode(Token &Result, uint32_t C, const char *CurPtr); + + /// FormTokenWithChars - When we lex a token, we have identified a span + /// starting at BufferPtr, going to TokEnd that forms the token. This method + /// takes that range and assigns it to the token as its location and size. In + /// addition, since tokens cannot overlap, this also updates BufferPtr to be + /// TokEnd. + void FormTokenWithChars(Token &Result, const char *TokEnd, + tok::TokenKind Kind) { + unsigned TokLen = TokEnd-BufferPtr; + Result.setLength(TokLen); + Result.setLocation(getSourceLocation(BufferPtr, TokLen)); + Result.setKind(Kind); + BufferPtr = TokEnd; + } + + /// isNextPPTokenLParen - Return 1 if the next unexpanded token will return a + /// tok::l_paren token, 0 if it is something else and 2 if there are no more + /// tokens in the buffer controlled by this lexer. + unsigned isNextPPTokenLParen(); + + //===--------------------------------------------------------------------===// + // Lexer character reading interfaces. + + // This lexer is built on two interfaces for reading characters, both of which + // automatically provide phase 1/2 translation. getAndAdvanceChar is used + // when we know that we will be reading a character from the input buffer and + // that this character will be part of the result token. This occurs in (f.e.) + // string processing, because we know we need to read until we find the + // closing '"' character. + // + // The second interface is the combination of getCharAndSize with + // ConsumeChar. getCharAndSize reads a phase 1/2 translated character, + // returning it and its size. If the lexer decides that this character is + // part of the current token, it calls ConsumeChar on it. This two stage + // approach allows us to emit diagnostics for characters (e.g. warnings about + // trigraphs), knowing that they only are emitted if the character is + // consumed. + + /// isObviouslySimpleCharacter - Return true if the specified character is + /// obviously the same in translation phase 1 and translation phase 3. This + /// can return false for characters that end up being the same, but it will + /// never return true for something that needs to be mapped. + static bool isObviouslySimpleCharacter(char C) { + return C != '?' && C != '\\'; + } + + /// getAndAdvanceChar - Read a single 'character' from the specified buffer, + /// advance over it, and return it. This is tricky in several cases. Here we + /// just handle the trivial case and fall-back to the non-inlined + /// getCharAndSizeSlow method to handle the hard case. + inline char getAndAdvanceChar(const char *&Ptr, Token &Tok) { + // If this is not a trigraph and not a UCN or escaped newline, return + // quickly. + if (isObviouslySimpleCharacter(Ptr[0])) return *Ptr++; + + unsigned Size = 0; + char C = getCharAndSizeSlow(Ptr, Size, &Tok); + Ptr += Size; + return C; + } + + /// ConsumeChar - When a character (identified by getCharAndSize) is consumed + /// and added to a given token, check to see if there are diagnostics that + /// need to be emitted or flags that need to be set on the token. If so, do + /// it. + const char *ConsumeChar(const char *Ptr, unsigned Size, Token &Tok) { + // Normal case, we consumed exactly one token. Just return it. + if (Size == 1) + return Ptr+Size; + + // Otherwise, re-lex the character with a current token, allowing + // diagnostics to be emitted and flags to be set. + Size = 0; + getCharAndSizeSlow(Ptr, Size, &Tok); + return Ptr+Size; + } + + /// getCharAndSize - Peek a single 'character' from the specified buffer, + /// get its size, and return it. This is tricky in several cases. Here we + /// just handle the trivial case and fall-back to the non-inlined + /// getCharAndSizeSlow method to handle the hard case. + inline char getCharAndSize(const char *Ptr, unsigned &Size) { + // If this is not a trigraph and not a UCN or escaped newline, return + // quickly. + if (isObviouslySimpleCharacter(Ptr[0])) { + Size = 1; + return *Ptr; + } + + Size = 0; + return getCharAndSizeSlow(Ptr, Size); + } + + /// getCharAndSizeSlow - Handle the slow/uncommon case of the getCharAndSize + /// method. + char getCharAndSizeSlow(const char *Ptr, unsigned &Size, + Token *Tok = nullptr); + + /// getEscapedNewLineSize - Return the size of the specified escaped newline, + /// or 0 if it is not an escaped newline. P[-1] is known to be a "\" on entry + /// to this function. + static unsigned getEscapedNewLineSize(const char *P); + + /// SkipEscapedNewLines - If P points to an escaped newline (or a series of + /// them), skip over them and return the first non-escaped-newline found, + /// otherwise return P. + static const char *SkipEscapedNewLines(const char *P); + + /// getCharAndSizeSlowNoWarn - Same as getCharAndSizeSlow, but never emits a + /// diagnostic. + static char getCharAndSizeSlowNoWarn(const char *Ptr, unsigned &Size, + const LangOptions &LangOpts); + + //===--------------------------------------------------------------------===// + // Other lexer functions. + + void SkipBytes(unsigned Bytes, bool StartOfLine); + + void PropagateLineStartLeadingSpaceInfo(Token &Result); + + const char *LexUDSuffix(Token &Result, const char *CurPtr, + bool IsStringLiteral); + + // Helper functions to lex the remainder of a token of the specific type. + bool LexIdentifier (Token &Result, const char *CurPtr); + bool LexNumericConstant (Token &Result, const char *CurPtr); + bool LexStringLiteral (Token &Result, const char *CurPtr, + tok::TokenKind Kind); + bool LexRawStringLiteral (Token &Result, const char *CurPtr, + tok::TokenKind Kind); + bool LexAngledStringLiteral(Token &Result, const char *CurPtr); + bool LexCharConstant (Token &Result, const char *CurPtr, + tok::TokenKind Kind); + bool LexEndOfFile (Token &Result, const char *CurPtr); + bool SkipWhitespace (Token &Result, const char *CurPtr, + bool &TokAtPhysicalStartOfLine); + bool SkipLineComment (Token &Result, const char *CurPtr, + bool &TokAtPhysicalStartOfLine); + bool SkipBlockComment (Token &Result, const char *CurPtr, + bool &TokAtPhysicalStartOfLine); + bool SaveLineComment (Token &Result, const char *CurPtr); + + bool IsStartOfConflictMarker(const char *CurPtr); + bool HandleEndOfConflictMarker(const char *CurPtr); + + bool isCodeCompletionPoint(const char *CurPtr) const; + void cutOffLexing() { BufferPtr = BufferEnd; } + + bool isHexaLiteral(const char *Start, const LangOptions &LangOpts); + + + /// Read a universal character name. + /// + /// \param CurPtr The position in the source buffer after the initial '\'. + /// If the UCN is syntactically well-formed (but not necessarily + /// valid), this parameter will be updated to point to the + /// character after the UCN. + /// \param SlashLoc The position in the source buffer of the '\'. + /// \param Tok The token being formed. Pass \c NULL to suppress diagnostics + /// and handle token formation in the caller. + /// + /// \return The Unicode codepoint specified by the UCN, or 0 if the UCN is + /// invalid. + uint32_t tryReadUCN(const char *&CurPtr, const char *SlashLoc, Token *Tok); + + /// \brief Try to consume a UCN as part of an identifier at the current + /// location. + /// \param CurPtr Initially points to the range of characters in the source + /// buffer containing the '\'. Updated to point past the end of + /// the UCN on success. + /// \param Size The number of characters occupied by the '\' (including + /// trigraphs and escaped newlines). + /// \param Result The token being produced. Marked as containing a UCN on + /// success. + /// \return \c true if a UCN was lexed and it produced an acceptable + /// identifier character, \c false otherwise. + bool tryConsumeIdentifierUCN(const char *&CurPtr, unsigned Size, + Token &Result); + + /// \brief Try to consume an identifier character encoded in UTF-8. + /// \param CurPtr Points to the start of the (potential) UTF-8 code unit + /// sequence. On success, updated to point past the end of it. + /// \return \c true if a UTF-8 sequence mapping to an acceptable identifier + /// character was lexed, \c false otherwise. + bool tryConsumeIdentifierUTF8Char(const char *&CurPtr); +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Lex/LiteralSupport.h b/contrib/llvm/tools/clang/include/clang/Lex/LiteralSupport.h new file mode 100644 index 0000000..5210e3f --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Lex/LiteralSupport.h @@ -0,0 +1,260 @@ +//===--- LiteralSupport.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the NumericLiteralParser, CharLiteralParser, and +// StringLiteralParser interfaces. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_LITERALSUPPORT_H +#define LLVM_CLANG_LEX_LITERALSUPPORT_H + +#include "clang/Basic/CharInfo.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/TokenKinds.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/DataTypes.h" + +namespace clang { + +class DiagnosticsEngine; +class Preprocessor; +class Token; +class SourceLocation; +class TargetInfo; +class SourceManager; +class LangOptions; + +/// Copy characters from Input to Buf, expanding any UCNs. +void expandUCNs(SmallVectorImpl<char> &Buf, StringRef Input); + +/// NumericLiteralParser - This performs strict semantic analysis of the content +/// of a ppnumber, classifying it as either integer, floating, or erroneous, +/// determines the radix of the value and can convert it to a useful value. +class NumericLiteralParser { + Preprocessor &PP; // needed for diagnostics + + const char *const ThisTokBegin; + const char *const ThisTokEnd; + const char *DigitsBegin, *SuffixBegin; // markers + const char *s; // cursor + + unsigned radix; + + bool saw_exponent, saw_period, saw_ud_suffix; + + SmallString<32> UDSuffixBuf; + +public: + NumericLiteralParser(StringRef TokSpelling, + SourceLocation TokLoc, + Preprocessor &PP); + bool hadError : 1; + bool isUnsigned : 1; + bool isLong : 1; // This is *not* set for long long. + bool isLongLong : 1; + bool isFloat : 1; // 1.0f + bool isImaginary : 1; // 1.0i + uint8_t MicrosoftInteger; // Microsoft suffix extension i8, i16, i32, or i64. + + bool isIntegerLiteral() const { + return !saw_period && !saw_exponent; + } + bool isFloatingLiteral() const { + return saw_period || saw_exponent; + } + + bool hasUDSuffix() const { + return saw_ud_suffix; + } + StringRef getUDSuffix() const { + assert(saw_ud_suffix); + return UDSuffixBuf; + } + unsigned getUDSuffixOffset() const { + assert(saw_ud_suffix); + return SuffixBegin - ThisTokBegin; + } + + static bool isValidUDSuffix(const LangOptions &LangOpts, StringRef Suffix); + + unsigned getRadix() const { return radix; } + + /// GetIntegerValue - Convert this numeric literal value to an APInt that + /// matches Val's input width. If there is an overflow (i.e., if the unsigned + /// value read is larger than the APInt's bits will hold), set Val to the low + /// bits of the result and return true. Otherwise, return false. + bool GetIntegerValue(llvm::APInt &Val); + + /// GetFloatValue - Convert this numeric literal to a floating value, using + /// the specified APFloat fltSemantics (specifying float, double, etc). + /// The optional bool isExact (passed-by-reference) has its value + /// set to true if the returned APFloat can represent the number in the + /// literal exactly, and false otherwise. + llvm::APFloat::opStatus GetFloatValue(llvm::APFloat &Result); + +private: + + void ParseNumberStartingWithZero(SourceLocation TokLoc); + + static bool isDigitSeparator(char C) { return C == '\''; } + + enum CheckSeparatorKind { CSK_BeforeDigits, CSK_AfterDigits }; + + /// \brief Ensure that we don't have a digit separator here. + void checkSeparator(SourceLocation TokLoc, const char *Pos, + CheckSeparatorKind IsAfterDigits); + + /// SkipHexDigits - Read and skip over any hex digits, up to End. + /// Return a pointer to the first non-hex digit or End. + const char *SkipHexDigits(const char *ptr) { + while (ptr != ThisTokEnd && (isHexDigit(*ptr) || isDigitSeparator(*ptr))) + ptr++; + return ptr; + } + + /// SkipOctalDigits - Read and skip over any octal digits, up to End. + /// Return a pointer to the first non-hex digit or End. + const char *SkipOctalDigits(const char *ptr) { + while (ptr != ThisTokEnd && + ((*ptr >= '0' && *ptr <= '7') || isDigitSeparator(*ptr))) + ptr++; + return ptr; + } + + /// SkipDigits - Read and skip over any digits, up to End. + /// Return a pointer to the first non-hex digit or End. + const char *SkipDigits(const char *ptr) { + while (ptr != ThisTokEnd && (isDigit(*ptr) || isDigitSeparator(*ptr))) + ptr++; + return ptr; + } + + /// SkipBinaryDigits - Read and skip over any binary digits, up to End. + /// Return a pointer to the first non-binary digit or End. + const char *SkipBinaryDigits(const char *ptr) { + while (ptr != ThisTokEnd && + (*ptr == '0' || *ptr == '1' || isDigitSeparator(*ptr))) + ptr++; + return ptr; + } + +}; + +/// CharLiteralParser - Perform interpretation and semantic analysis of a +/// character literal. +class CharLiteralParser { + uint64_t Value; + tok::TokenKind Kind; + bool IsMultiChar; + bool HadError; + SmallString<32> UDSuffixBuf; + unsigned UDSuffixOffset; +public: + CharLiteralParser(const char *begin, const char *end, + SourceLocation Loc, Preprocessor &PP, + tok::TokenKind kind); + + bool hadError() const { return HadError; } + bool isAscii() const { return Kind == tok::char_constant; } + bool isWide() const { return Kind == tok::wide_char_constant; } + bool isUTF16() const { return Kind == tok::utf16_char_constant; } + bool isUTF32() const { return Kind == tok::utf32_char_constant; } + bool isMultiChar() const { return IsMultiChar; } + uint64_t getValue() const { return Value; } + StringRef getUDSuffix() const { return UDSuffixBuf; } + unsigned getUDSuffixOffset() const { + assert(!UDSuffixBuf.empty() && "no ud-suffix"); + return UDSuffixOffset; + } +}; + +/// StringLiteralParser - This decodes string escape characters and performs +/// wide string analysis and Translation Phase #6 (concatenation of string +/// literals) (C99 5.1.1.2p1). +class StringLiteralParser { + const SourceManager &SM; + const LangOptions &Features; + const TargetInfo &Target; + DiagnosticsEngine *Diags; + + unsigned MaxTokenLength; + unsigned SizeBound; + unsigned CharByteWidth; + tok::TokenKind Kind; + SmallString<512> ResultBuf; + char *ResultPtr; // cursor + SmallString<32> UDSuffixBuf; + unsigned UDSuffixToken; + unsigned UDSuffixOffset; +public: + StringLiteralParser(ArrayRef<Token> StringToks, + Preprocessor &PP, bool Complain = true); + StringLiteralParser(ArrayRef<Token> StringToks, + const SourceManager &sm, const LangOptions &features, + const TargetInfo &target, + DiagnosticsEngine *diags = nullptr) + : SM(sm), Features(features), Target(target), Diags(diags), + MaxTokenLength(0), SizeBound(0), CharByteWidth(0), Kind(tok::unknown), + ResultPtr(ResultBuf.data()), hadError(false), Pascal(false) { + init(StringToks); + } + + + bool hadError; + bool Pascal; + + StringRef GetString() const { + return StringRef(ResultBuf.data(), GetStringLength()); + } + unsigned GetStringLength() const { return ResultPtr-ResultBuf.data(); } + + unsigned GetNumStringChars() const { + return GetStringLength() / CharByteWidth; + } + /// getOffsetOfStringByte - This function returns the offset of the + /// specified byte of the string data represented by Token. This handles + /// advancing over escape sequences in the string. + /// + /// If the Diagnostics pointer is non-null, then this will do semantic + /// checking of the string literal and emit errors and warnings. + unsigned getOffsetOfStringByte(const Token &TheTok, unsigned ByteNo) const; + + bool isAscii() const { return Kind == tok::string_literal; } + bool isWide() const { return Kind == tok::wide_string_literal; } + bool isUTF8() const { return Kind == tok::utf8_string_literal; } + bool isUTF16() const { return Kind == tok::utf16_string_literal; } + bool isUTF32() const { return Kind == tok::utf32_string_literal; } + bool isPascal() const { return Pascal; } + + StringRef getUDSuffix() const { return UDSuffixBuf; } + + /// Get the index of a token containing a ud-suffix. + unsigned getUDSuffixToken() const { + assert(!UDSuffixBuf.empty() && "no ud-suffix"); + return UDSuffixToken; + } + /// Get the spelling offset of the first byte of the ud-suffix. + unsigned getUDSuffixOffset() const { + assert(!UDSuffixBuf.empty() && "no ud-suffix"); + return UDSuffixOffset; + } + +private: + void init(ArrayRef<Token> StringToks); + bool CopyStringFragment(const Token &Tok, const char *TokBegin, + StringRef Fragment); + void DiagnoseLexingError(SourceLocation Loc); +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Lex/MacroArgs.h b/contrib/llvm/tools/clang/include/clang/Lex/MacroArgs.h new file mode 100644 index 0000000..243b143 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Lex/MacroArgs.h @@ -0,0 +1,127 @@ +//===--- MacroArgs.h - Formal argument info for Macros ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the MacroArgs interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_MACROARGS_H +#define LLVM_CLANG_LEX_MACROARGS_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" +#include <vector> + +namespace clang { + class MacroInfo; + class Preprocessor; + class Token; + class SourceLocation; + +/// MacroArgs - An instance of this class captures information about +/// the formal arguments specified to a function-like macro invocation. +class MacroArgs { + /// NumUnexpArgTokens - The number of raw, unexpanded tokens for the + /// arguments. All of the actual argument tokens are allocated immediately + /// after the MacroArgs object in memory. This is all of the arguments + /// concatenated together, with 'EOF' markers at the end of each argument. + unsigned NumUnexpArgTokens; + + /// VarargsElided - True if this is a C99 style varargs macro invocation and + /// there was no argument specified for the "..." argument. If the argument + /// was specified (even empty) or this isn't a C99 style varargs function, or + /// if in strict mode and the C99 varargs macro had only a ... argument, this + /// is false. + bool VarargsElided; + + /// PreExpArgTokens - Pre-expanded tokens for arguments that need them. Empty + /// if not yet computed. This includes the EOF marker at the end of the + /// stream. + std::vector<std::vector<Token> > PreExpArgTokens; + + /// StringifiedArgs - This contains arguments in 'stringified' form. If the + /// stringified form of an argument has not yet been computed, this is empty. + std::vector<Token> StringifiedArgs; + + /// ArgCache - This is a linked list of MacroArgs objects that the + /// Preprocessor owns which we use to avoid thrashing malloc/free. + MacroArgs *ArgCache; + + MacroArgs(unsigned NumToks, bool varargsElided) + : NumUnexpArgTokens(NumToks), VarargsElided(varargsElided), + ArgCache(nullptr) {} + ~MacroArgs() = default; + +public: + /// MacroArgs ctor function - Create a new MacroArgs object with the specified + /// macro and argument info. + static MacroArgs *create(const MacroInfo *MI, + ArrayRef<Token> UnexpArgTokens, + bool VarargsElided, Preprocessor &PP); + + /// destroy - Destroy and deallocate the memory for this object. + /// + void destroy(Preprocessor &PP); + + /// ArgNeedsPreexpansion - If we can prove that the argument won't be affected + /// by pre-expansion, return false. Otherwise, conservatively return true. + bool ArgNeedsPreexpansion(const Token *ArgTok, Preprocessor &PP) const; + + /// getUnexpArgument - Return a pointer to the first token of the unexpanded + /// token list for the specified formal. + /// + const Token *getUnexpArgument(unsigned Arg) const; + + /// getArgLength - Given a pointer to an expanded or unexpanded argument, + /// return the number of tokens, not counting the EOF, that make up the + /// argument. + static unsigned getArgLength(const Token *ArgPtr); + + /// getPreExpArgument - Return the pre-expanded form of the specified + /// argument. + const std::vector<Token> & + getPreExpArgument(unsigned Arg, const MacroInfo *MI, Preprocessor &PP); + + /// getStringifiedArgument - Compute, cache, and return the specified argument + /// that has been 'stringified' as required by the # operator. + const Token &getStringifiedArgument(unsigned ArgNo, Preprocessor &PP, + SourceLocation ExpansionLocStart, + SourceLocation ExpansionLocEnd); + + /// getNumArguments - Return the number of arguments passed into this macro + /// invocation. + unsigned getNumArguments() const { return NumUnexpArgTokens; } + + + /// isVarargsElidedUse - Return true if this is a C99 style varargs macro + /// invocation and there was no argument specified for the "..." argument. If + /// the argument was specified (even empty) or this isn't a C99 style varargs + /// function, or if in strict mode and the C99 varargs macro had only a ... + /// argument, this returns false. + bool isVarargsElidedUse() const { return VarargsElided; } + + /// StringifyArgument - Implement C99 6.10.3.2p2, converting a sequence of + /// tokens into the literal string token that should be produced by the C # + /// preprocessor operator. If Charify is true, then it should be turned into + /// a character literal for the Microsoft charize (#@) extension. + /// + static Token StringifyArgument(const Token *ArgToks, + Preprocessor &PP, bool Charify, + SourceLocation ExpansionLocStart, + SourceLocation ExpansionLocEnd); + + + /// deallocate - This should only be called by the Preprocessor when managing + /// its freelist. + MacroArgs *deallocate(); +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Lex/MacroInfo.h b/contrib/llvm/tools/clang/include/clang/Lex/MacroInfo.h new file mode 100644 index 0000000..320645e --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Lex/MacroInfo.h @@ -0,0 +1,609 @@ +//===--- MacroInfo.h - Information about #defined identifiers ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the clang::MacroInfo and clang::MacroDirective classes. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_MACROINFO_H +#define LLVM_CLANG_LEX_MACROINFO_H + +#include "clang/Lex/Token.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Allocator.h" +#include <cassert> + +namespace clang { +class Module; +class ModuleMacro; +class Preprocessor; + +/// \brief Encapsulates the data about a macro definition (e.g. its tokens). +/// +/// There's an instance of this class for every #define. +class MacroInfo { + //===--------------------------------------------------------------------===// + // State set when the macro is defined. + + /// \brief The location the macro is defined. + SourceLocation Location; + /// \brief The location of the last token in the macro. + SourceLocation EndLocation; + + /// \brief The list of arguments for a function-like macro. + /// + /// ArgumentList points to the first of NumArguments pointers. + /// + /// This can be empty, for, e.g. "#define X()". In a C99-style variadic + /// macro, this includes the \c __VA_ARGS__ identifier on the list. + IdentifierInfo **ArgumentList; + + /// \see ArgumentList + unsigned NumArguments; + + /// \brief This is the list of tokens that the macro is defined to. + SmallVector<Token, 8> ReplacementTokens; + + /// \brief Length in characters of the macro definition. + mutable unsigned DefinitionLength; + mutable bool IsDefinitionLengthCached : 1; + + /// \brief True if this macro is function-like, false if it is object-like. + bool IsFunctionLike : 1; + + /// \brief True if this macro is of the form "#define X(...)" or + /// "#define X(Y,Z,...)". + /// + /// The __VA_ARGS__ token should be replaced with the contents of "..." in an + /// invocation. + bool IsC99Varargs : 1; + + /// \brief True if this macro is of the form "#define X(a...)". + /// + /// The "a" identifier in the replacement list will be replaced with all + /// arguments of the macro starting with the specified one. + bool IsGNUVarargs : 1; + + /// \brief True if this macro requires processing before expansion. + /// + /// This is the case for builtin macros such as __LINE__, so long as they have + /// not been redefined, but not for regular predefined macros from the + /// "<built-in>" memory buffer (see Preprocessing::getPredefinesFileID). + bool IsBuiltinMacro : 1; + + /// \brief Whether this macro contains the sequence ", ## __VA_ARGS__" + bool HasCommaPasting : 1; + + //===--------------------------------------------------------------------===// + // State that changes as the macro is used. + + /// \brief True if we have started an expansion of this macro already. + /// + /// This disables recursive expansion, which would be quite bad for things + /// like \#define A A. + bool IsDisabled : 1; + + /// \brief True if this macro is either defined in the main file and has + /// been used, or if it is not defined in the main file. + /// + /// This is used to emit -Wunused-macros diagnostics. + bool IsUsed : 1; + + /// \brief True if this macro can be redefined without emitting a warning. + bool IsAllowRedefinitionsWithoutWarning : 1; + + /// \brief Must warn if the macro is unused at the end of translation unit. + bool IsWarnIfUnused : 1; + + /// \brief Whether this macro info was loaded from an AST file. + unsigned FromASTFile : 1; + + /// \brief Whether this macro was used as header guard. + bool UsedForHeaderGuard : 1; + + // Only the Preprocessor gets to create and destroy these. + MacroInfo(SourceLocation DefLoc); + ~MacroInfo() = default; + +public: + /// \brief Return the location that the macro was defined at. + SourceLocation getDefinitionLoc() const { return Location; } + + /// \brief Set the location of the last token in the macro. + void setDefinitionEndLoc(SourceLocation EndLoc) { EndLocation = EndLoc; } + + /// \brief Return the location of the last token in the macro. + SourceLocation getDefinitionEndLoc() const { return EndLocation; } + + /// \brief Get length in characters of the macro definition. + unsigned getDefinitionLength(SourceManager &SM) const { + if (IsDefinitionLengthCached) + return DefinitionLength; + return getDefinitionLengthSlow(SM); + } + + /// \brief Return true if the specified macro definition is equal to + /// this macro in spelling, arguments, and whitespace. + /// + /// \param Syntactically if true, the macro definitions can be identical even + /// if they use different identifiers for the function macro parameters. + /// Otherwise the comparison is lexical and this implements the rules in + /// C99 6.10.3. + bool isIdenticalTo(const MacroInfo &Other, Preprocessor &PP, + bool Syntactically) const; + + /// \brief Set or clear the isBuiltinMacro flag. + void setIsBuiltinMacro(bool Val = true) { IsBuiltinMacro = Val; } + + /// \brief Set the value of the IsUsed flag. + void setIsUsed(bool Val) { IsUsed = Val; } + + /// \brief Set the value of the IsAllowRedefinitionsWithoutWarning flag. + void setIsAllowRedefinitionsWithoutWarning(bool Val) { + IsAllowRedefinitionsWithoutWarning = Val; + } + + /// \brief Set the value of the IsWarnIfUnused flag. + void setIsWarnIfUnused(bool val) { IsWarnIfUnused = val; } + + /// \brief Set the specified list of identifiers as the argument list for + /// this macro. + void setArgumentList(ArrayRef<IdentifierInfo *> List, + llvm::BumpPtrAllocator &PPAllocator) { + assert(ArgumentList == nullptr && NumArguments == 0 && + "Argument list already set!"); + if (List.empty()) + return; + + NumArguments = List.size(); + ArgumentList = PPAllocator.Allocate<IdentifierInfo *>(List.size()); + std::copy(List.begin(), List.end(), ArgumentList); + } + + /// Arguments - The list of arguments for a function-like macro. This can be + /// empty, for, e.g. "#define X()". + typedef IdentifierInfo *const *arg_iterator; + bool arg_empty() const { return NumArguments == 0; } + arg_iterator arg_begin() const { return ArgumentList; } + arg_iterator arg_end() const { return ArgumentList + NumArguments; } + unsigned getNumArgs() const { return NumArguments; } + ArrayRef<const IdentifierInfo *> args() const { + return ArrayRef<const IdentifierInfo *>(ArgumentList, NumArguments); + } + + /// \brief Return the argument number of the specified identifier, + /// or -1 if the identifier is not a formal argument identifier. + int getArgumentNum(const IdentifierInfo *Arg) const { + for (arg_iterator I = arg_begin(), E = arg_end(); I != E; ++I) + if (*I == Arg) + return I - arg_begin(); + return -1; + } + + /// Function/Object-likeness. Keep track of whether this macro has formal + /// parameters. + void setIsFunctionLike() { IsFunctionLike = true; } + bool isFunctionLike() const { return IsFunctionLike; } + bool isObjectLike() const { return !IsFunctionLike; } + + /// Varargs querying methods. This can only be set for function-like macros. + void setIsC99Varargs() { IsC99Varargs = true; } + void setIsGNUVarargs() { IsGNUVarargs = true; } + bool isC99Varargs() const { return IsC99Varargs; } + bool isGNUVarargs() const { return IsGNUVarargs; } + bool isVariadic() const { return IsC99Varargs | IsGNUVarargs; } + + /// \brief Return true if this macro requires processing before expansion. + /// + /// This is true only for builtin macro, such as \__LINE__, whose values + /// are not given by fixed textual expansions. Regular predefined macros + /// from the "<built-in>" buffer are not reported as builtins by this + /// function. + bool isBuiltinMacro() const { return IsBuiltinMacro; } + + bool hasCommaPasting() const { return HasCommaPasting; } + void setHasCommaPasting() { HasCommaPasting = true; } + + /// \brief Return false if this macro is defined in the main file and has + /// not yet been used. + bool isUsed() const { return IsUsed; } + + /// \brief Return true if this macro can be redefined without warning. + bool isAllowRedefinitionsWithoutWarning() const { + return IsAllowRedefinitionsWithoutWarning; + } + + /// \brief Return true if we should emit a warning if the macro is unused. + bool isWarnIfUnused() const { return IsWarnIfUnused; } + + /// \brief Return the number of tokens that this macro expands to. + /// + unsigned getNumTokens() const { return ReplacementTokens.size(); } + + const Token &getReplacementToken(unsigned Tok) const { + assert(Tok < ReplacementTokens.size() && "Invalid token #"); + return ReplacementTokens[Tok]; + } + + typedef SmallVectorImpl<Token>::const_iterator tokens_iterator; + tokens_iterator tokens_begin() const { return ReplacementTokens.begin(); } + tokens_iterator tokens_end() const { return ReplacementTokens.end(); } + bool tokens_empty() const { return ReplacementTokens.empty(); } + ArrayRef<Token> tokens() const { return ReplacementTokens; } + + /// \brief Add the specified token to the replacement text for the macro. + void AddTokenToBody(const Token &Tok) { + assert( + !IsDefinitionLengthCached && + "Changing replacement tokens after definition length got calculated"); + ReplacementTokens.push_back(Tok); + } + + /// \brief Return true if this macro is enabled. + /// + /// In other words, that we are not currently in an expansion of this macro. + bool isEnabled() const { return !IsDisabled; } + + void EnableMacro() { + assert(IsDisabled && "Cannot enable an already-enabled macro!"); + IsDisabled = false; + } + + void DisableMacro() { + assert(!IsDisabled && "Cannot disable an already-disabled macro!"); + IsDisabled = true; + } + + /// \brief Determine whether this macro info came from an AST file (such as + /// a precompiled header or module) rather than having been parsed. + bool isFromASTFile() const { return FromASTFile; } + + /// \brief Determine whether this macro was used for a header guard. + bool isUsedForHeaderGuard() const { return UsedForHeaderGuard; } + + void setUsedForHeaderGuard(bool Val) { UsedForHeaderGuard = Val; } + + /// \brief Retrieve the global ID of the module that owns this particular + /// macro info. + unsigned getOwningModuleID() const { + if (isFromASTFile()) + return *(const unsigned *)(this + 1); + + return 0; + } + + void dump() const; + +private: + unsigned getDefinitionLengthSlow(SourceManager &SM) const; + + void setOwningModuleID(unsigned ID) { + assert(isFromASTFile()); + *(unsigned *)(this + 1) = ID; + } + + friend class Preprocessor; +}; + +class DefMacroDirective; + +/// \brief Encapsulates changes to the "macros namespace" (the location where +/// the macro name became active, the location where it was undefined, etc.). +/// +/// MacroDirectives, associated with an identifier, are used to model the macro +/// history. Usually a macro definition (MacroInfo) is where a macro name +/// becomes active (MacroDirective) but #pragma push_macro / pop_macro can +/// create additional DefMacroDirectives for the same MacroInfo. +class MacroDirective { +public: + enum Kind { MD_Define, MD_Undefine, MD_Visibility }; + +protected: + /// \brief Previous macro directive for the same identifier, or NULL. + MacroDirective *Previous; + + SourceLocation Loc; + + /// \brief MacroDirective kind. + unsigned MDKind : 2; + + /// \brief True if the macro directive was loaded from a PCH file. + bool IsFromPCH : 1; + + // Used by VisibilityMacroDirective ----------------------------------------// + + /// \brief Whether the macro has public visibility (when described in a + /// module). + bool IsPublic : 1; + + MacroDirective(Kind K, SourceLocation Loc) + : Previous(nullptr), Loc(Loc), MDKind(K), IsFromPCH(false), + IsPublic(true) {} + +public: + Kind getKind() const { return Kind(MDKind); } + + SourceLocation getLocation() const { return Loc; } + + /// \brief Set previous definition of the macro with the same name. + void setPrevious(MacroDirective *Prev) { Previous = Prev; } + + /// \brief Get previous definition of the macro with the same name. + const MacroDirective *getPrevious() const { return Previous; } + + /// \brief Get previous definition of the macro with the same name. + MacroDirective *getPrevious() { return Previous; } + + /// \brief Return true if the macro directive was loaded from a PCH file. + bool isFromPCH() const { return IsFromPCH; } + + void setIsFromPCH() { IsFromPCH = true; } + + class DefInfo { + DefMacroDirective *DefDirective; + SourceLocation UndefLoc; + bool IsPublic; + + public: + DefInfo() : DefDirective(nullptr), IsPublic(true) {} + + DefInfo(DefMacroDirective *DefDirective, SourceLocation UndefLoc, + bool isPublic) + : DefDirective(DefDirective), UndefLoc(UndefLoc), IsPublic(isPublic) {} + + const DefMacroDirective *getDirective() const { return DefDirective; } + DefMacroDirective *getDirective() { return DefDirective; } + + inline SourceLocation getLocation() const; + inline MacroInfo *getMacroInfo(); + const MacroInfo *getMacroInfo() const { + return const_cast<DefInfo *>(this)->getMacroInfo(); + } + + SourceLocation getUndefLocation() const { return UndefLoc; } + bool isUndefined() const { return UndefLoc.isValid(); } + + bool isPublic() const { return IsPublic; } + + bool isValid() const { return DefDirective != nullptr; } + bool isInvalid() const { return !isValid(); } + + explicit operator bool() const { return isValid(); } + + inline DefInfo getPreviousDefinition(); + const DefInfo getPreviousDefinition() const { + return const_cast<DefInfo *>(this)->getPreviousDefinition(); + } + }; + + /// \brief Traverses the macro directives history and returns the next + /// macro definition directive along with info about its undefined location + /// (if there is one) and if it is public or private. + DefInfo getDefinition(); + const DefInfo getDefinition() const { + return const_cast<MacroDirective *>(this)->getDefinition(); + } + + bool isDefined() const { + if (const DefInfo Def = getDefinition()) + return !Def.isUndefined(); + return false; + } + + const MacroInfo *getMacroInfo() const { + return getDefinition().getMacroInfo(); + } + MacroInfo *getMacroInfo() { return getDefinition().getMacroInfo(); } + + /// \brief Find macro definition active in the specified source location. If + /// this macro was not defined there, return NULL. + const DefInfo findDirectiveAtLoc(SourceLocation L, SourceManager &SM) const; + + void dump() const; + + static bool classof(const MacroDirective *) { return true; } +}; + +/// \brief A directive for a defined macro or a macro imported from a module. +class DefMacroDirective : public MacroDirective { + MacroInfo *Info; + +public: + DefMacroDirective(MacroInfo *MI, SourceLocation Loc) + : MacroDirective(MD_Define, Loc), Info(MI) { + assert(MI && "MacroInfo is null"); + } + explicit DefMacroDirective(MacroInfo *MI) + : DefMacroDirective(MI, MI->getDefinitionLoc()) {} + + /// \brief The data for the macro definition. + const MacroInfo *getInfo() const { return Info; } + MacroInfo *getInfo() { return Info; } + + static bool classof(const MacroDirective *MD) { + return MD->getKind() == MD_Define; + } + static bool classof(const DefMacroDirective *) { return true; } +}; + +/// \brief A directive for an undefined macro. +class UndefMacroDirective : public MacroDirective { +public: + explicit UndefMacroDirective(SourceLocation UndefLoc) + : MacroDirective(MD_Undefine, UndefLoc) { + assert(UndefLoc.isValid() && "Invalid UndefLoc!"); + } + + static bool classof(const MacroDirective *MD) { + return MD->getKind() == MD_Undefine; + } + static bool classof(const UndefMacroDirective *) { return true; } +}; + +/// \brief A directive for setting the module visibility of a macro. +class VisibilityMacroDirective : public MacroDirective { +public: + explicit VisibilityMacroDirective(SourceLocation Loc, bool Public) + : MacroDirective(MD_Visibility, Loc) { + IsPublic = Public; + } + + /// \brief Determine whether this macro is part of the public API of its + /// module. + bool isPublic() const { return IsPublic; } + + static bool classof(const MacroDirective *MD) { + return MD->getKind() == MD_Visibility; + } + static bool classof(const VisibilityMacroDirective *) { return true; } +}; + +inline SourceLocation MacroDirective::DefInfo::getLocation() const { + if (isInvalid()) + return SourceLocation(); + return DefDirective->getLocation(); +} + +inline MacroInfo *MacroDirective::DefInfo::getMacroInfo() { + if (isInvalid()) + return nullptr; + return DefDirective->getInfo(); +} + +inline MacroDirective::DefInfo +MacroDirective::DefInfo::getPreviousDefinition() { + if (isInvalid() || DefDirective->getPrevious() == nullptr) + return DefInfo(); + return DefDirective->getPrevious()->getDefinition(); +} + +/// \brief Represents a macro directive exported by a module. +/// +/// There's an instance of this class for every macro #define or #undef that is +/// the final directive for a macro name within a module. These entities also +/// represent the macro override graph. +/// +/// These are stored in a FoldingSet in the preprocessor. +class ModuleMacro : public llvm::FoldingSetNode { + /// The name defined by the macro. + IdentifierInfo *II; + /// The body of the #define, or nullptr if this is a #undef. + MacroInfo *Macro; + /// The module that exports this macro. + Module *OwningModule; + /// The number of module macros that override this one. + unsigned NumOverriddenBy; + /// The number of modules whose macros are directly overridden by this one. + unsigned NumOverrides; + // ModuleMacro *OverriddenMacros[NumOverrides]; + + friend class Preprocessor; + + ModuleMacro(Module *OwningModule, IdentifierInfo *II, MacroInfo *Macro, + ArrayRef<ModuleMacro *> Overrides) + : II(II), Macro(Macro), OwningModule(OwningModule), NumOverriddenBy(0), + NumOverrides(Overrides.size()) { + std::copy(Overrides.begin(), Overrides.end(), + reinterpret_cast<ModuleMacro **>(this + 1)); + } + +public: + static ModuleMacro *create(Preprocessor &PP, Module *OwningModule, + IdentifierInfo *II, MacroInfo *Macro, + ArrayRef<ModuleMacro *> Overrides); + + void Profile(llvm::FoldingSetNodeID &ID) const { + return Profile(ID, OwningModule, II); + } + static void Profile(llvm::FoldingSetNodeID &ID, Module *OwningModule, + IdentifierInfo *II) { + ID.AddPointer(OwningModule); + ID.AddPointer(II); + } + + /// Get the ID of the module that exports this macro. + Module *getOwningModule() const { return OwningModule; } + + /// Get definition for this exported #define, or nullptr if this + /// represents a #undef. + MacroInfo *getMacroInfo() const { return Macro; } + + /// Iterators over the overridden module IDs. + /// \{ + typedef ModuleMacro *const *overrides_iterator; + overrides_iterator overrides_begin() const { + return reinterpret_cast<overrides_iterator>(this + 1); + } + overrides_iterator overrides_end() const { + return overrides_begin() + NumOverrides; + } + ArrayRef<ModuleMacro *> overrides() const { + return llvm::makeArrayRef(overrides_begin(), overrides_end()); + } + /// \} + + /// Get the number of macros that override this one. + unsigned getNumOverridingMacros() const { return NumOverriddenBy; } +}; + +/// \brief A description of the current definition of a macro. +/// +/// The definition of a macro comprises a set of (at least one) defining +/// entities, which are either local MacroDirectives or imported ModuleMacros. +class MacroDefinition { + llvm::PointerIntPair<DefMacroDirective *, 1, bool> LatestLocalAndAmbiguous; + ArrayRef<ModuleMacro *> ModuleMacros; + +public: + MacroDefinition() : LatestLocalAndAmbiguous(), ModuleMacros() {} + MacroDefinition(DefMacroDirective *MD, ArrayRef<ModuleMacro *> MMs, + bool IsAmbiguous) + : LatestLocalAndAmbiguous(MD, IsAmbiguous), ModuleMacros(MMs) {} + + /// \brief Determine whether there is a definition of this macro. + explicit operator bool() const { + return getLocalDirective() || !ModuleMacros.empty(); + } + + /// \brief Get the MacroInfo that should be used for this definition. + MacroInfo *getMacroInfo() const { + if (!ModuleMacros.empty()) + return ModuleMacros.back()->getMacroInfo(); + if (auto *MD = getLocalDirective()) + return MD->getMacroInfo(); + return nullptr; + } + + /// \brief \c true if the definition is ambiguous, \c false otherwise. + bool isAmbiguous() const { return LatestLocalAndAmbiguous.getInt(); } + + /// \brief Get the latest non-imported, non-\#undef'd macro definition + /// for this macro. + DefMacroDirective *getLocalDirective() const { + return LatestLocalAndAmbiguous.getPointer(); + } + + /// \brief Get the active module macros for this macro. + ArrayRef<ModuleMacro *> getModuleMacros() const { return ModuleMacros; } + + template <typename Fn> void forAllDefinitions(Fn F) const { + if (auto *MD = getLocalDirective()) + F(MD->getMacroInfo()); + for (auto *MM : getModuleMacros()) + F(MM->getMacroInfo()); + } +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Lex/ModuleLoader.h b/contrib/llvm/tools/clang/include/clang/Lex/ModuleLoader.h new file mode 100644 index 0000000..ae79650 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Lex/ModuleLoader.h @@ -0,0 +1,129 @@ +//===--- ModuleLoader.h - Module Loader Interface ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ModuleLoader interface, which is responsible for +// loading named modules. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_LEX_MODULELOADER_H +#define LLVM_CLANG_LEX_MODULELOADER_H + +#include "clang/Basic/Module.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/PointerIntPair.h" + +namespace clang { + +class GlobalModuleIndex; +class IdentifierInfo; +class Module; + +/// \brief A sequence of identifier/location pairs used to describe a particular +/// module or submodule, e.g., std.vector. +typedef ArrayRef<std::pair<IdentifierInfo *, SourceLocation> > ModuleIdPath; + +/// \brief Describes the result of attempting to load a module. +class ModuleLoadResult { + llvm::PointerIntPair<Module *, 1, bool> Storage; + +public: + ModuleLoadResult() : Storage() { } + + ModuleLoadResult(Module *module, bool missingExpected) + : Storage(module, missingExpected) { } + + operator Module *() const { return Storage.getPointer(); } + + /// \brief Determines whether the module, which failed to load, was + /// actually a submodule that we expected to see (based on implying the + /// submodule from header structure), but didn't materialize in the actual + /// module. + bool isMissingExpected() const { return Storage.getInt(); } +}; + +/// \brief Abstract interface for a module loader. +/// +/// This abstract interface describes a module loader, which is responsible +/// for resolving a module name (e.g., "std") to an actual module file, and +/// then loading that module. +class ModuleLoader { + // Building a module if true. + bool BuildingModule; +public: + explicit ModuleLoader(bool BuildingModule = false) : + BuildingModule(BuildingModule), + HadFatalFailure(false) {} + + virtual ~ModuleLoader(); + + /// \brief Returns true if this instance is building a module. + bool buildingModule() const { + return BuildingModule; + } + /// \brief Flag indicating whether this instance is building a module. + void setBuildingModule(bool BuildingModuleFlag) { + BuildingModule = BuildingModuleFlag; + } + + /// \brief Attempt to load the given module. + /// + /// This routine attempts to load the module described by the given + /// parameters. + /// + /// \param ImportLoc The location of the 'import' keyword. + /// + /// \param Path The identifiers (and their locations) of the module + /// "path", e.g., "std.vector" would be split into "std" and "vector". + /// + /// \param Visibility The visibility provided for the names in the loaded + /// module. + /// + /// \param IsInclusionDirective Indicates that this module is being loaded + /// implicitly, due to the presence of an inclusion directive. Otherwise, + /// it is being loaded due to an import declaration. + /// + /// \returns If successful, returns the loaded module. Otherwise, returns + /// NULL to indicate that the module could not be loaded. + virtual ModuleLoadResult loadModule(SourceLocation ImportLoc, + ModuleIdPath Path, + Module::NameVisibilityKind Visibility, + bool IsInclusionDirective) = 0; + + /// \brief Make the given module visible. + virtual void makeModuleVisible(Module *Mod, + Module::NameVisibilityKind Visibility, + SourceLocation ImportLoc) = 0; + + /// \brief Load, create, or return global module. + /// This function returns an existing global module index, if one + /// had already been loaded or created, or loads one if it + /// exists, or creates one if it doesn't exist. + /// Also, importantly, if the index doesn't cover all the modules + /// in the module map, it will be update to do so here, because + /// of its use in searching for needed module imports and + /// associated fixit messages. + /// \param TriggerLoc The location for what triggered the load. + /// \returns Returns null if load failed. + virtual GlobalModuleIndex *loadGlobalModuleIndex( + SourceLocation TriggerLoc) = 0; + + /// Check global module index for missing imports. + /// \param Name The symbol name to look for. + /// \param TriggerLoc The location for what triggered the load. + /// \returns Returns true if any modules with that symbol found. + virtual bool lookupMissingImports(StringRef Name, + SourceLocation TriggerLoc) = 0; + + bool HadFatalFailure; +}; + +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Lex/ModuleMap.h b/contrib/llvm/tools/clang/include/clang/Lex/ModuleMap.h new file mode 100644 index 0000000..155943e --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Lex/ModuleMap.h @@ -0,0 +1,514 @@ +//===--- ModuleMap.h - Describe the layout of modules -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ModuleMap interface, which describes the layout of a +// module as it relates to headers. +// +//===----------------------------------------------------------------------===// + + +#ifndef LLVM_CLANG_LEX_MODULEMAP_H +#define LLVM_CLANG_LEX_MODULEMAP_H + +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/Module.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include <string> + +namespace clang { + +class DirectoryEntry; +class FileEntry; +class FileManager; +class DiagnosticConsumer; +class DiagnosticsEngine; +class HeaderSearch; +class ModuleMapParser; + +/// \brief A mechanism to observe the actions of the module map parser as it +/// reads module map files. +class ModuleMapCallbacks { +public: + virtual ~ModuleMapCallbacks() {} + + /// \brief Called when a module map file has been read. + /// + /// \param FileStart A SourceLocation referring to the start of the file's + /// contents. + /// \param File The file itself. + /// \param IsSystem Whether this is a module map from a system include path. + virtual void moduleMapFileRead(SourceLocation FileStart, + const FileEntry &File, bool IsSystem) {} +}; + +class ModuleMap { + SourceManager &SourceMgr; + DiagnosticsEngine &Diags; + const LangOptions &LangOpts; + const TargetInfo *Target; + HeaderSearch &HeaderInfo; + + llvm::SmallVector<std::unique_ptr<ModuleMapCallbacks>, 1> Callbacks; + + /// \brief The directory used for Clang-supplied, builtin include headers, + /// such as "stdint.h". + const DirectoryEntry *BuiltinIncludeDir; + + /// \brief Language options used to parse the module map itself. + /// + /// These are always simple C language options. + LangOptions MMapLangOpts; + + // The module that we are building; related to \c LangOptions::CurrentModule. + Module *CompilingModule; + +public: + // The module that the .cc source file is associated with. + Module *SourceModule; + std::string SourceModuleName; + +private: + /// \brief The top-level modules that are known. + llvm::StringMap<Module *> Modules; + + /// \brief The number of modules we have created in total. + unsigned NumCreatedModules; + +public: + /// \brief Flags describing the role of a module header. + enum ModuleHeaderRole { + /// \brief This header is normally included in the module. + NormalHeader = 0x0, + /// \brief This header is included but private. + PrivateHeader = 0x1, + /// \brief This header is part of the module (for layering purposes) but + /// should be textually included. + TextualHeader = 0x2, + // Caution: Adding an enumerator needs other changes. + // Adjust the number of bits for KnownHeader::Storage. + // Adjust the bitfield HeaderFileInfo::HeaderRole size. + // Adjust the HeaderFileInfoTrait::ReadData streaming. + // Adjust the HeaderFileInfoTrait::EmitData streaming. + // Adjust ModuleMap::addHeader. + }; + + /// \brief A header that is known to reside within a given module, + /// whether it was included or excluded. + class KnownHeader { + llvm::PointerIntPair<Module *, 2, ModuleHeaderRole> Storage; + + public: + KnownHeader() : Storage(nullptr, NormalHeader) { } + KnownHeader(Module *M, ModuleHeaderRole Role) : Storage(M, Role) { } + + friend bool operator==(const KnownHeader &A, const KnownHeader &B) { + return A.Storage == B.Storage; + } + friend bool operator!=(const KnownHeader &A, const KnownHeader &B) { + return A.Storage != B.Storage; + } + + /// \brief Retrieve the module the header is stored in. + Module *getModule() const { return Storage.getPointer(); } + + /// \brief The role of this header within the module. + ModuleHeaderRole getRole() const { return Storage.getInt(); } + + /// \brief Whether this header is available in the module. + bool isAvailable() const { + return getModule()->isAvailable(); + } + + // \brief Whether this known header is valid (i.e., it has an + // associated module). + explicit operator bool() const { + return Storage.getPointer() != nullptr; + } + }; + + typedef llvm::SmallPtrSet<const FileEntry *, 1> AdditionalModMapsSet; + +private: + typedef llvm::DenseMap<const FileEntry *, SmallVector<KnownHeader, 1> > + HeadersMap; + + /// \brief Mapping from each header to the module that owns the contents of + /// that header. + HeadersMap Headers; + + /// \brief Mapping from directories with umbrella headers to the module + /// that is generated from the umbrella header. + /// + /// This mapping is used to map headers that haven't explicitly been named + /// in the module map over to the module that includes them via its umbrella + /// header. + llvm::DenseMap<const DirectoryEntry *, Module *> UmbrellaDirs; + + /// \brief The set of attributes that can be attached to a module. + struct Attributes { + Attributes() : IsSystem(), IsExternC(), IsExhaustive() {} + + /// \brief Whether this is a system module. + unsigned IsSystem : 1; + + /// \brief Whether this is an extern "C" module. + unsigned IsExternC : 1; + + /// \brief Whether this is an exhaustive set of configuration macros. + unsigned IsExhaustive : 1; + }; + + /// \brief A directory for which framework modules can be inferred. + struct InferredDirectory { + InferredDirectory() : InferModules() {} + + /// \brief Whether to infer modules from this directory. + unsigned InferModules : 1; + + /// \brief The attributes to use for inferred modules. + Attributes Attrs; + + /// \brief If \c InferModules is non-zero, the module map file that allowed + /// inferred modules. Otherwise, nullptr. + const FileEntry *ModuleMapFile; + + /// \brief The names of modules that cannot be inferred within this + /// directory. + SmallVector<std::string, 2> ExcludedModules; + }; + + /// \brief A mapping from directories to information about inferring + /// framework modules from within those directories. + llvm::DenseMap<const DirectoryEntry *, InferredDirectory> InferredDirectories; + + /// A mapping from an inferred module to the module map that allowed the + /// inference. + llvm::DenseMap<const Module *, const FileEntry *> InferredModuleAllowedBy; + + llvm::DenseMap<const Module *, AdditionalModMapsSet> AdditionalModMaps; + + /// \brief Describes whether we haved parsed a particular file as a module + /// map. + llvm::DenseMap<const FileEntry *, bool> ParsedModuleMap; + + friend class ModuleMapParser; + + /// \brief Resolve the given export declaration into an actual export + /// declaration. + /// + /// \param Mod The module in which we're resolving the export declaration. + /// + /// \param Unresolved The export declaration to resolve. + /// + /// \param Complain Whether this routine should complain about unresolvable + /// exports. + /// + /// \returns The resolved export declaration, which will have a NULL pointer + /// if the export could not be resolved. + Module::ExportDecl + resolveExport(Module *Mod, const Module::UnresolvedExportDecl &Unresolved, + bool Complain) const; + + /// \brief Resolve the given module id to an actual module. + /// + /// \param Id The module-id to resolve. + /// + /// \param Mod The module in which we're resolving the module-id. + /// + /// \param Complain Whether this routine should complain about unresolvable + /// module-ids. + /// + /// \returns The resolved module, or null if the module-id could not be + /// resolved. + Module *resolveModuleId(const ModuleId &Id, Module *Mod, bool Complain) const; + + /// \brief Looks up the modules that \p File corresponds to. + /// + /// If \p File represents a builtin header within Clang's builtin include + /// directory, this also loads all of the module maps to see if it will get + /// associated with a specific module (e.g. in /usr/include). + HeadersMap::iterator findKnownHeader(const FileEntry *File); + + /// \brief Searches for a module whose umbrella directory contains \p File. + /// + /// \param File The header to search for. + /// + /// \param IntermediateDirs On success, contains the set of directories + /// searched before finding \p File. + KnownHeader findHeaderInUmbrellaDirs(const FileEntry *File, + SmallVectorImpl<const DirectoryEntry *> &IntermediateDirs); + + /// \brief Given that \p File is not in the Headers map, look it up within + /// umbrella directories and find or create a module for it. + KnownHeader findOrCreateModuleForHeaderInUmbrellaDir(const FileEntry *File); + + /// \brief A convenience method to determine if \p File is (possibly nested) + /// in an umbrella directory. + bool isHeaderInUmbrellaDirs(const FileEntry *File) { + SmallVector<const DirectoryEntry *, 2> IntermediateDirs; + return static_cast<bool>(findHeaderInUmbrellaDirs(File, IntermediateDirs)); + } + + Module *inferFrameworkModule(const DirectoryEntry *FrameworkDir, + Attributes Attrs, Module *Parent); + +public: + /// \brief Construct a new module map. + /// + /// \param SourceMgr The source manager used to find module files and headers. + /// This source manager should be shared with the header-search mechanism, + /// since they will refer to the same headers. + /// + /// \param Diags A diagnostic engine used for diagnostics. + /// + /// \param LangOpts Language options for this translation unit. + /// + /// \param Target The target for this translation unit. + ModuleMap(SourceManager &SourceMgr, DiagnosticsEngine &Diags, + const LangOptions &LangOpts, const TargetInfo *Target, + HeaderSearch &HeaderInfo); + + /// \brief Destroy the module map. + /// + ~ModuleMap(); + + /// \brief Set the target information. + void setTarget(const TargetInfo &Target); + + /// \brief Set the directory that contains Clang-supplied include + /// files, such as our stdarg.h or tgmath.h. + void setBuiltinIncludeDir(const DirectoryEntry *Dir) { + BuiltinIncludeDir = Dir; + } + + /// \brief Add a module map callback. + void addModuleMapCallbacks(std::unique_ptr<ModuleMapCallbacks> Callback) { + Callbacks.push_back(std::move(Callback)); + } + + /// \brief Retrieve the module that owns the given header file, if any. + /// + /// \param File The header file that is likely to be included. + /// + /// \returns The module KnownHeader, which provides the module that owns the + /// given header file. The KnownHeader is default constructed to indicate + /// that no module owns this header file. + KnownHeader findModuleForHeader(const FileEntry *File); + + /// \brief Retrieve all the modules that contain the given header file. This + /// may not include umbrella modules, nor information from external sources, + /// if they have not yet been inferred / loaded. + /// + /// Typically, \ref findModuleForHeader should be used instead, as it picks + /// the preferred module for the header. + ArrayRef<KnownHeader> findAllModulesForHeader(const FileEntry *File) const; + + /// \brief Reports errors if a module must not include a specific file. + /// + /// \param RequestingModule The module including a file. + /// + /// \param FilenameLoc The location of the inclusion's filename. + /// + /// \param Filename The included filename as written. + /// + /// \param File The included file. + void diagnoseHeaderInclusion(Module *RequestingModule, + SourceLocation FilenameLoc, StringRef Filename, + const FileEntry *File); + + /// \brief Determine whether the given header is part of a module + /// marked 'unavailable'. + bool isHeaderInUnavailableModule(const FileEntry *Header) const; + + /// \brief Determine whether the given header is unavailable as part + /// of the specified module. + bool isHeaderUnavailableInModule(const FileEntry *Header, + const Module *RequestingModule) const; + + /// \brief Retrieve a module with the given name. + /// + /// \param Name The name of the module to look up. + /// + /// \returns The named module, if known; otherwise, returns null. + Module *findModule(StringRef Name) const; + + /// \brief Retrieve a module with the given name using lexical name lookup, + /// starting at the given context. + /// + /// \param Name The name of the module to look up. + /// + /// \param Context The module context, from which we will perform lexical + /// name lookup. + /// + /// \returns The named module, if known; otherwise, returns null. + Module *lookupModuleUnqualified(StringRef Name, Module *Context) const; + + /// \brief Retrieve a module with the given name within the given context, + /// using direct (qualified) name lookup. + /// + /// \param Name The name of the module to look up. + /// + /// \param Context The module for which we will look for a submodule. If + /// null, we will look for a top-level module. + /// + /// \returns The named submodule, if known; otherwose, returns null. + Module *lookupModuleQualified(StringRef Name, Module *Context) const; + + /// \brief Find a new module or submodule, or create it if it does not already + /// exist. + /// + /// \param Name The name of the module to find or create. + /// + /// \param Parent The module that will act as the parent of this submodule, + /// or NULL to indicate that this is a top-level module. + /// + /// \param IsFramework Whether this is a framework module. + /// + /// \param IsExplicit Whether this is an explicit submodule. + /// + /// \returns The found or newly-created module, along with a boolean value + /// that will be true if the module is newly-created. + std::pair<Module *, bool> findOrCreateModule(StringRef Name, Module *Parent, + bool IsFramework, + bool IsExplicit); + + /// \brief Infer the contents of a framework module map from the given + /// framework directory. + Module *inferFrameworkModule(const DirectoryEntry *FrameworkDir, + bool IsSystem, Module *Parent); + + /// \brief Retrieve the module map file containing the definition of the given + /// module. + /// + /// \param Module The module whose module map file will be returned, if known. + /// + /// \returns The file entry for the module map file containing the given + /// module, or NULL if the module definition was inferred. + const FileEntry *getContainingModuleMapFile(const Module *Module) const; + + /// \brief Get the module map file that (along with the module name) uniquely + /// identifies this module. + /// + /// The particular module that \c Name refers to may depend on how the module + /// was found in header search. However, the combination of \c Name and + /// this module map will be globally unique for top-level modules. In the case + /// of inferred modules, returns the module map that allowed the inference + /// (e.g. contained 'module *'). Otherwise, returns + /// getContainingModuleMapFile(). + const FileEntry *getModuleMapFileForUniquing(const Module *M) const; + + void setInferredModuleAllowedBy(Module *M, const FileEntry *ModuleMap); + + /// \brief Get any module map files other than getModuleMapFileForUniquing(M) + /// that define submodules of a top-level module \p M. This is cheaper than + /// getting the module map file for each submodule individually, since the + /// expected number of results is very small. + AdditionalModMapsSet *getAdditionalModuleMapFiles(const Module *M) { + auto I = AdditionalModMaps.find(M); + if (I == AdditionalModMaps.end()) + return nullptr; + return &I->second; + } + + void addAdditionalModuleMapFile(const Module *M, const FileEntry *ModuleMap) { + AdditionalModMaps[M].insert(ModuleMap); + } + + /// \brief Resolve all of the unresolved exports in the given module. + /// + /// \param Mod The module whose exports should be resolved. + /// + /// \param Complain Whether to emit diagnostics for failures. + /// + /// \returns true if any errors were encountered while resolving exports, + /// false otherwise. + bool resolveExports(Module *Mod, bool Complain); + + /// \brief Resolve all of the unresolved uses in the given module. + /// + /// \param Mod The module whose uses should be resolved. + /// + /// \param Complain Whether to emit diagnostics for failures. + /// + /// \returns true if any errors were encountered while resolving uses, + /// false otherwise. + bool resolveUses(Module *Mod, bool Complain); + + /// \brief Resolve all of the unresolved conflicts in the given module. + /// + /// \param Mod The module whose conflicts should be resolved. + /// + /// \param Complain Whether to emit diagnostics for failures. + /// + /// \returns true if any errors were encountered while resolving conflicts, + /// false otherwise. + bool resolveConflicts(Module *Mod, bool Complain); + + /// \brief Infers the (sub)module based on the given source location and + /// source manager. + /// + /// \param Loc The location within the source that we are querying, along + /// with its source manager. + /// + /// \returns The module that owns this source location, or null if no + /// module owns this source location. + Module *inferModuleFromLocation(FullSourceLoc Loc); + + /// \brief Sets the umbrella header of the given module to the given + /// header. + void setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader, + Twine NameAsWritten); + + /// \brief Sets the umbrella directory of the given module to the given + /// directory. + void setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir, + Twine NameAsWritten); + + /// \brief Adds this header to the given module. + /// \param Role The role of the header wrt the module. + void addHeader(Module *Mod, Module::Header Header, + ModuleHeaderRole Role, bool Imported = false); + + /// \brief Marks this header as being excluded from the given module. + void excludeHeader(Module *Mod, Module::Header Header); + + /// \brief Parse the given module map file, and record any modules we + /// encounter. + /// + /// \param File The file to be parsed. + /// + /// \param IsSystem Whether this module map file is in a system header + /// directory, and therefore should be considered a system module. + /// + /// \param HomeDir The directory in which relative paths within this module + /// map file will be resolved. + /// + /// \param ExternModuleLoc The location of the "extern module" declaration + /// that caused us to load this module map file, if any. + /// + /// \returns true if an error occurred, false otherwise. + bool parseModuleMapFile(const FileEntry *File, bool IsSystem, + const DirectoryEntry *HomeDir, + SourceLocation ExternModuleLoc = SourceLocation()); + + /// \brief Dump the contents of the module map, for debugging purposes. + void dump(); + + typedef llvm::StringMap<Module *>::const_iterator module_iterator; + module_iterator module_begin() const { return Modules.begin(); } + module_iterator module_end() const { return Modules.end(); } +}; + +} +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Lex/MultipleIncludeOpt.h b/contrib/llvm/tools/clang/include/clang/Lex/MultipleIncludeOpt.h new file mode 100644 index 0000000..83e6f99 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Lex/MultipleIncludeOpt.h @@ -0,0 +1,181 @@ +//===--- MultipleIncludeOpt.h - Header Multiple-Include Optzn ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the MultipleIncludeOpt interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_MULTIPLEINCLUDEOPT_H +#define LLVM_CLANG_LEX_MULTIPLEINCLUDEOPT_H + +#include "clang/Basic/SourceLocation.h" + +namespace clang { +class IdentifierInfo; + +/// \brief Implements the simple state machine that the Lexer class uses to +/// detect files subject to the 'multiple-include' optimization. +/// +/// The public methods in this class are triggered by various +/// events that occur when a file is lexed, and after the entire file is lexed, +/// information about which macro (if any) controls the header is returned. +class MultipleIncludeOpt { + /// ReadAnyTokens - This is set to false when a file is first opened and true + /// any time a token is returned to the client or a (non-multiple-include) + /// directive is parsed. When the final \#endif is parsed this is reset back + /// to false, that way any tokens before the first \#ifdef or after the last + /// \#endif can be easily detected. + bool ReadAnyTokens; + + /// ImmediatelyAfterTopLevelIfndef - This is true when the only tokens + /// processed in the file so far is an #ifndef and an identifier. Used in + /// the detection of header guards in a file. + bool ImmediatelyAfterTopLevelIfndef; + + /// ReadAnyTokens - This is set to false when a file is first opened and true + /// any time a token is returned to the client or a (non-multiple-include) + /// directive is parsed. When the final #endif is parsed this is reset back + /// to false, that way any tokens before the first #ifdef or after the last + /// #endif can be easily detected. + bool DidMacroExpansion; + + /// TheMacro - The controlling macro for a file, if valid. + /// + const IdentifierInfo *TheMacro; + + /// DefinedMacro - The macro defined right after TheMacro, if any. + const IdentifierInfo *DefinedMacro; + + SourceLocation MacroLoc; + SourceLocation DefinedLoc; +public: + MultipleIncludeOpt() { + ReadAnyTokens = false; + ImmediatelyAfterTopLevelIfndef = false; + DidMacroExpansion = false; + TheMacro = nullptr; + DefinedMacro = nullptr; + } + + SourceLocation GetMacroLocation() const { + return MacroLoc; + } + + SourceLocation GetDefinedLocation() const { + return DefinedLoc; + } + + void resetImmediatelyAfterTopLevelIfndef() { + ImmediatelyAfterTopLevelIfndef = false; + } + + void SetDefinedMacro(IdentifierInfo *M, SourceLocation Loc) { + DefinedMacro = M; + DefinedLoc = Loc; + } + + /// Invalidate - Permanently mark this file as not being suitable for the + /// include-file optimization. + void Invalidate() { + // If we have read tokens but have no controlling macro, the state-machine + // below can never "accept". + ReadAnyTokens = true; + ImmediatelyAfterTopLevelIfndef = false; + DefinedMacro = nullptr; + TheMacro = nullptr; + } + + /// getHasReadAnyTokensVal - This is used for the \#ifndef hande-shake at the + /// top of the file when reading preprocessor directives. Otherwise, reading + /// the "ifndef x" would count as reading tokens. + bool getHasReadAnyTokensVal() const { return ReadAnyTokens; } + + /// getImmediatelyAfterTopLevelIfndef - returns true if the last directive + /// was an #ifndef at the beginning of the file. + bool getImmediatelyAfterTopLevelIfndef() const { + return ImmediatelyAfterTopLevelIfndef; + } + + // If a token is read, remember that we have seen a side-effect in this file. + void ReadToken() { + ReadAnyTokens = true; + ImmediatelyAfterTopLevelIfndef = false; + } + + /// ExpandedMacro - When a macro is expanded with this lexer as the current + /// buffer, this method is called to disable the MIOpt if needed. + void ExpandedMacro() { DidMacroExpansion = true; } + + /// \brief Called when entering a top-level \#ifndef directive (or the + /// "\#if !defined" equivalent) without any preceding tokens. + /// + /// Note, we don't care about the input value of 'ReadAnyTokens'. The caller + /// ensures that this is only called if there are no tokens read before the + /// \#ifndef. The caller is required to do this, because reading the \#if + /// line obviously reads in in tokens. + void EnterTopLevelIfndef(const IdentifierInfo *M, SourceLocation Loc) { + // If the macro is already set, this is after the top-level #endif. + if (TheMacro) + return Invalidate(); + + // If we have already expanded a macro by the end of the #ifndef line, then + // there is a macro expansion *in* the #ifndef line. This means that the + // condition could evaluate differently when subsequently #included. Reject + // this. + if (DidMacroExpansion) + return Invalidate(); + + // Remember that we're in the #if and that we have the macro. + ReadAnyTokens = true; + ImmediatelyAfterTopLevelIfndef = true; + TheMacro = M; + MacroLoc = Loc; + } + + /// \brief Invoked when a top level conditional (except \#ifndef) is found. + void EnterTopLevelConditional() { + // If a conditional directive (except #ifndef) is found at the top level, + // there is a chunk of the file not guarded by the controlling macro. + Invalidate(); + } + + /// \brief Called when the lexer exits the top-level conditional. + void ExitTopLevelConditional() { + // If we have a macro, that means the top of the file was ok. Set our state + // back to "not having read any tokens" so we can detect anything after the + // #endif. + if (!TheMacro) return Invalidate(); + + // At this point, we haven't "read any tokens" but we do have a controlling + // macro. + ReadAnyTokens = false; + ImmediatelyAfterTopLevelIfndef = false; + } + + /// \brief Once the entire file has been lexed, if there is a controlling + /// macro, return it. + const IdentifierInfo *GetControllingMacroAtEndOfFile() const { + // If we haven't read any tokens after the #endif, return the controlling + // macro if it's valid (if it isn't, it will be null). + if (!ReadAnyTokens) + return TheMacro; + return nullptr; + } + + /// \brief If the ControllingMacro is followed by a macro definition, return + /// the macro that was defined. + const IdentifierInfo *GetDefinedMacro() const { + return DefinedMacro; + } +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Lex/PPCallbacks.h b/contrib/llvm/tools/clang/include/clang/Lex/PPCallbacks.h new file mode 100644 index 0000000..68b8f1c --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Lex/PPCallbacks.h @@ -0,0 +1,509 @@ +//===--- PPCallbacks.h - Callbacks for Preprocessor actions -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the PPCallbacks interface. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_PPCALLBACKS_H +#define LLVM_CLANG_LEX_PPCALLBACKS_H + +#include "clang/Basic/DiagnosticIDs.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/DirectoryLookup.h" +#include "clang/Lex/ModuleLoader.h" +#include "clang/Lex/Pragma.h" +#include "llvm/ADT/StringRef.h" +#include <string> + +namespace clang { + class SourceLocation; + class Token; + class IdentifierInfo; + class MacroDefinition; + class MacroDirective; + class MacroArgs; + +/// \brief This interface provides a way to observe the actions of the +/// preprocessor as it does its thing. +/// +/// Clients can define their hooks here to implement preprocessor level tools. +class PPCallbacks { +public: + virtual ~PPCallbacks(); + + enum FileChangeReason { + EnterFile, ExitFile, SystemHeaderPragma, RenameFile + }; + + /// \brief Callback invoked whenever a source file is entered or exited. + /// + /// \param Loc Indicates the new location. + /// \param PrevFID the file that was exited if \p Reason is ExitFile. + virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType, + FileID PrevFID = FileID()) { + } + + /// \brief Callback invoked whenever a source file is skipped as the result + /// of header guard optimization. + /// + /// \param SkippedFile The file that is skipped instead of entering \#include + /// + /// \param FilenameTok The file name token in \#include "FileName" directive + /// or macro expanded file name token from \#include MACRO(PARAMS) directive. + /// Note that FilenameTok contains corresponding quotes/angles symbols. + virtual void FileSkipped(const FileEntry &SkippedFile, + const Token &FilenameTok, + SrcMgr::CharacteristicKind FileType) { + } + + /// \brief Callback invoked whenever an inclusion directive results in a + /// file-not-found error. + /// + /// \param FileName The name of the file being included, as written in the + /// source code. + /// + /// \param RecoveryPath If this client indicates that it can recover from + /// this missing file, the client should set this as an additional header + /// search patch. + /// + /// \returns true to indicate that the preprocessor should attempt to recover + /// by adding \p RecoveryPath as a header search path. + virtual bool FileNotFound(StringRef FileName, + SmallVectorImpl<char> &RecoveryPath) { + return false; + } + + /// \brief Callback invoked whenever an inclusion directive of + /// any kind (\c \#include, \c \#import, etc.) has been processed, regardless + /// of whether the inclusion will actually result in an inclusion. + /// + /// \param HashLoc The location of the '#' that starts the inclusion + /// directive. + /// + /// \param IncludeTok The token that indicates the kind of inclusion + /// directive, e.g., 'include' or 'import'. + /// + /// \param FileName The name of the file being included, as written in the + /// source code. + /// + /// \param IsAngled Whether the file name was enclosed in angle brackets; + /// otherwise, it was enclosed in quotes. + /// + /// \param FilenameRange The character range of the quotes or angle brackets + /// for the written file name. + /// + /// \param File The actual file that may be included by this inclusion + /// directive. + /// + /// \param SearchPath Contains the search path which was used to find the file + /// in the file system. If the file was found via an absolute include path, + /// SearchPath will be empty. For framework includes, the SearchPath and + /// RelativePath will be split up. For example, if an include of "Some/Some.h" + /// is found via the framework path + /// "path/to/Frameworks/Some.framework/Headers/Some.h", SearchPath will be + /// "path/to/Frameworks/Some.framework/Headers" and RelativePath will be + /// "Some.h". + /// + /// \param RelativePath The path relative to SearchPath, at which the include + /// file was found. This is equal to FileName except for framework includes. + /// + /// \param Imported The module, whenever an inclusion directive was + /// automatically turned into a module import or null otherwise. + /// + virtual void InclusionDirective(SourceLocation HashLoc, + const Token &IncludeTok, + StringRef FileName, + bool IsAngled, + CharSourceRange FilenameRange, + const FileEntry *File, + StringRef SearchPath, + StringRef RelativePath, + const Module *Imported) { + } + + /// \brief Callback invoked whenever there was an explicit module-import + /// syntax. + /// + /// \param ImportLoc The location of import directive token. + /// + /// \param Path The identifiers (and their locations) of the module + /// "path", e.g., "std.vector" would be split into "std" and "vector". + /// + /// \param Imported The imported module; can be null if importing failed. + /// + virtual void moduleImport(SourceLocation ImportLoc, + ModuleIdPath Path, + const Module *Imported) { + } + + /// \brief Callback invoked when the end of the main file is reached. + /// + /// No subsequent callbacks will be made. + virtual void EndOfMainFile() { + } + + /// \brief Callback invoked when a \#ident or \#sccs directive is read. + /// \param Loc The location of the directive. + /// \param str The text of the directive. + /// + virtual void Ident(SourceLocation Loc, StringRef str) { + } + + /// \brief Callback invoked when start reading any pragma directive. + virtual void PragmaDirective(SourceLocation Loc, + PragmaIntroducerKind Introducer) { + } + + /// \brief Callback invoked when a \#pragma comment directive is read. + virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind, + StringRef Str) { + } + + /// \brief Callback invoked when a \#pragma detect_mismatch directive is + /// read. + virtual void PragmaDetectMismatch(SourceLocation Loc, StringRef Name, + StringRef Value) { + } + + /// \brief Callback invoked when a \#pragma clang __debug directive is read. + /// \param Loc The location of the debug directive. + /// \param DebugType The identifier following __debug. + virtual void PragmaDebug(SourceLocation Loc, StringRef DebugType) { + } + + /// \brief Determines the kind of \#pragma invoking a call to PragmaMessage. + enum PragmaMessageKind { + /// \brief \#pragma message has been invoked. + PMK_Message, + + /// \brief \#pragma GCC warning has been invoked. + PMK_Warning, + + /// \brief \#pragma GCC error has been invoked. + PMK_Error + }; + + /// \brief Callback invoked when a \#pragma message directive is read. + /// \param Loc The location of the message directive. + /// \param Namespace The namespace of the message directive. + /// \param Kind The type of the message directive. + /// \param Str The text of the message directive. + virtual void PragmaMessage(SourceLocation Loc, StringRef Namespace, + PragmaMessageKind Kind, StringRef Str) { + } + + /// \brief Callback invoked when a \#pragma gcc diagnostic push directive + /// is read. + virtual void PragmaDiagnosticPush(SourceLocation Loc, + StringRef Namespace) { + } + + /// \brief Callback invoked when a \#pragma gcc diagnostic pop directive + /// is read. + virtual void PragmaDiagnosticPop(SourceLocation Loc, + StringRef Namespace) { + } + + /// \brief Callback invoked when a \#pragma gcc diagnostic directive is read. + virtual void PragmaDiagnostic(SourceLocation Loc, StringRef Namespace, + diag::Severity mapping, StringRef Str) {} + + /// \brief Called when an OpenCL extension is either disabled or + /// enabled with a pragma. + virtual void PragmaOpenCLExtension(SourceLocation NameLoc, + const IdentifierInfo *Name, + SourceLocation StateLoc, unsigned State) { + } + + /// \brief Callback invoked when a \#pragma warning directive is read. + virtual void PragmaWarning(SourceLocation Loc, StringRef WarningSpec, + ArrayRef<int> Ids) { + } + + /// \brief Callback invoked when a \#pragma warning(push) directive is read. + virtual void PragmaWarningPush(SourceLocation Loc, int Level) { + } + + /// \brief Callback invoked when a \#pragma warning(pop) directive is read. + virtual void PragmaWarningPop(SourceLocation Loc) { + } + + /// \brief Called by Preprocessor::HandleMacroExpandedIdentifier when a + /// macro invocation is found. + virtual void MacroExpands(const Token &MacroNameTok, + const MacroDefinition &MD, SourceRange Range, + const MacroArgs *Args) {} + + /// \brief Hook called whenever a macro definition is seen. + virtual void MacroDefined(const Token &MacroNameTok, + const MacroDirective *MD) { + } + + /// \brief Hook called whenever a macro \#undef is seen. + /// + /// MD is released immediately following this callback. + virtual void MacroUndefined(const Token &MacroNameTok, + const MacroDefinition &MD) { + } + + /// \brief Hook called whenever the 'defined' operator is seen. + /// \param MD The MacroDirective if the name was a macro, null otherwise. + virtual void Defined(const Token &MacroNameTok, const MacroDefinition &MD, + SourceRange Range) { + } + + /// \brief Hook called when a source range is skipped. + /// \param Range The SourceRange that was skipped. The range begins at the + /// \#if/\#else directive and ends after the \#endif/\#else directive. + virtual void SourceRangeSkipped(SourceRange Range) { + } + + enum ConditionValueKind { + CVK_NotEvaluated, CVK_False, CVK_True + }; + + /// \brief Hook called whenever an \#if is seen. + /// \param Loc the source location of the directive. + /// \param ConditionRange The SourceRange of the expression being tested. + /// \param ConditionValue The evaluated value of the condition. + /// + // FIXME: better to pass in a list (or tree!) of Tokens. + virtual void If(SourceLocation Loc, SourceRange ConditionRange, + ConditionValueKind ConditionValue) { + } + + /// \brief Hook called whenever an \#elif is seen. + /// \param Loc the source location of the directive. + /// \param ConditionRange The SourceRange of the expression being tested. + /// \param ConditionValue The evaluated value of the condition. + /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive. + // FIXME: better to pass in a list (or tree!) of Tokens. + virtual void Elif(SourceLocation Loc, SourceRange ConditionRange, + ConditionValueKind ConditionValue, SourceLocation IfLoc) { + } + + /// \brief Hook called whenever an \#ifdef is seen. + /// \param Loc the source location of the directive. + /// \param MacroNameTok Information on the token being tested. + /// \param MD The MacroDefinition if the name was a macro, null otherwise. + virtual void Ifdef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) { + } + + /// \brief Hook called whenever an \#ifndef is seen. + /// \param Loc the source location of the directive. + /// \param MacroNameTok Information on the token being tested. + /// \param MD The MacroDefiniton if the name was a macro, null otherwise. + virtual void Ifndef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) { + } + + /// \brief Hook called whenever an \#else is seen. + /// \param Loc the source location of the directive. + /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive. + virtual void Else(SourceLocation Loc, SourceLocation IfLoc) { + } + + /// \brief Hook called whenever an \#endif is seen. + /// \param Loc the source location of the directive. + /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive. + virtual void Endif(SourceLocation Loc, SourceLocation IfLoc) { + } +}; + +/// \brief Simple wrapper class for chaining callbacks. +class PPChainedCallbacks : public PPCallbacks { + virtual void anchor(); + std::unique_ptr<PPCallbacks> First, Second; + +public: + PPChainedCallbacks(std::unique_ptr<PPCallbacks> _First, + std::unique_ptr<PPCallbacks> _Second) + : First(std::move(_First)), Second(std::move(_Second)) {} + + void FileChanged(SourceLocation Loc, FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType, + FileID PrevFID) override { + First->FileChanged(Loc, Reason, FileType, PrevFID); + Second->FileChanged(Loc, Reason, FileType, PrevFID); + } + + void FileSkipped(const FileEntry &SkippedFile, + const Token &FilenameTok, + SrcMgr::CharacteristicKind FileType) override { + First->FileSkipped(SkippedFile, FilenameTok, FileType); + Second->FileSkipped(SkippedFile, FilenameTok, FileType); + } + + bool FileNotFound(StringRef FileName, + SmallVectorImpl<char> &RecoveryPath) override { + return First->FileNotFound(FileName, RecoveryPath) || + Second->FileNotFound(FileName, RecoveryPath); + } + + void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, + StringRef FileName, bool IsAngled, + CharSourceRange FilenameRange, const FileEntry *File, + StringRef SearchPath, StringRef RelativePath, + const Module *Imported) override { + First->InclusionDirective(HashLoc, IncludeTok, FileName, IsAngled, + FilenameRange, File, SearchPath, RelativePath, + Imported); + Second->InclusionDirective(HashLoc, IncludeTok, FileName, IsAngled, + FilenameRange, File, SearchPath, RelativePath, + Imported); + } + + void moduleImport(SourceLocation ImportLoc, ModuleIdPath Path, + const Module *Imported) override { + First->moduleImport(ImportLoc, Path, Imported); + Second->moduleImport(ImportLoc, Path, Imported); + } + + void EndOfMainFile() override { + First->EndOfMainFile(); + Second->EndOfMainFile(); + } + + void Ident(SourceLocation Loc, StringRef str) override { + First->Ident(Loc, str); + Second->Ident(Loc, str); + } + + void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind, + StringRef Str) override { + First->PragmaComment(Loc, Kind, Str); + Second->PragmaComment(Loc, Kind, Str); + } + + void PragmaDetectMismatch(SourceLocation Loc, StringRef Name, + StringRef Value) override { + First->PragmaDetectMismatch(Loc, Name, Value); + Second->PragmaDetectMismatch(Loc, Name, Value); + } + + void PragmaMessage(SourceLocation Loc, StringRef Namespace, + PragmaMessageKind Kind, StringRef Str) override { + First->PragmaMessage(Loc, Namespace, Kind, Str); + Second->PragmaMessage(Loc, Namespace, Kind, Str); + } + + void PragmaDiagnosticPush(SourceLocation Loc, StringRef Namespace) override { + First->PragmaDiagnosticPush(Loc, Namespace); + Second->PragmaDiagnosticPush(Loc, Namespace); + } + + void PragmaDiagnosticPop(SourceLocation Loc, StringRef Namespace) override { + First->PragmaDiagnosticPop(Loc, Namespace); + Second->PragmaDiagnosticPop(Loc, Namespace); + } + + void PragmaDiagnostic(SourceLocation Loc, StringRef Namespace, + diag::Severity mapping, StringRef Str) override { + First->PragmaDiagnostic(Loc, Namespace, mapping, Str); + Second->PragmaDiagnostic(Loc, Namespace, mapping, Str); + } + + void PragmaOpenCLExtension(SourceLocation NameLoc, const IdentifierInfo *Name, + SourceLocation StateLoc, unsigned State) override { + First->PragmaOpenCLExtension(NameLoc, Name, StateLoc, State); + Second->PragmaOpenCLExtension(NameLoc, Name, StateLoc, State); + } + + void PragmaWarning(SourceLocation Loc, StringRef WarningSpec, + ArrayRef<int> Ids) override { + First->PragmaWarning(Loc, WarningSpec, Ids); + Second->PragmaWarning(Loc, WarningSpec, Ids); + } + + void PragmaWarningPush(SourceLocation Loc, int Level) override { + First->PragmaWarningPush(Loc, Level); + Second->PragmaWarningPush(Loc, Level); + } + + void PragmaWarningPop(SourceLocation Loc) override { + First->PragmaWarningPop(Loc); + Second->PragmaWarningPop(Loc); + } + + void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, + SourceRange Range, const MacroArgs *Args) override { + First->MacroExpands(MacroNameTok, MD, Range, Args); + Second->MacroExpands(MacroNameTok, MD, Range, Args); + } + + void MacroDefined(const Token &MacroNameTok, const MacroDirective *MD) override { + First->MacroDefined(MacroNameTok, MD); + Second->MacroDefined(MacroNameTok, MD); + } + + void MacroUndefined(const Token &MacroNameTok, + const MacroDefinition &MD) override { + First->MacroUndefined(MacroNameTok, MD); + Second->MacroUndefined(MacroNameTok, MD); + } + + void Defined(const Token &MacroNameTok, const MacroDefinition &MD, + SourceRange Range) override { + First->Defined(MacroNameTok, MD, Range); + Second->Defined(MacroNameTok, MD, Range); + } + + void SourceRangeSkipped(SourceRange Range) override { + First->SourceRangeSkipped(Range); + Second->SourceRangeSkipped(Range); + } + + /// \brief Hook called whenever an \#if is seen. + void If(SourceLocation Loc, SourceRange ConditionRange, + ConditionValueKind ConditionValue) override { + First->If(Loc, ConditionRange, ConditionValue); + Second->If(Loc, ConditionRange, ConditionValue); + } + + /// \brief Hook called whenever an \#elif is seen. + void Elif(SourceLocation Loc, SourceRange ConditionRange, + ConditionValueKind ConditionValue, SourceLocation IfLoc) override { + First->Elif(Loc, ConditionRange, ConditionValue, IfLoc); + Second->Elif(Loc, ConditionRange, ConditionValue, IfLoc); + } + + /// \brief Hook called whenever an \#ifdef is seen. + void Ifdef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) override { + First->Ifdef(Loc, MacroNameTok, MD); + Second->Ifdef(Loc, MacroNameTok, MD); + } + + /// \brief Hook called whenever an \#ifndef is seen. + void Ifndef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) override { + First->Ifndef(Loc, MacroNameTok, MD); + Second->Ifndef(Loc, MacroNameTok, MD); + } + + /// \brief Hook called whenever an \#else is seen. + void Else(SourceLocation Loc, SourceLocation IfLoc) override { + First->Else(Loc, IfLoc); + Second->Else(Loc, IfLoc); + } + + /// \brief Hook called whenever an \#endif is seen. + void Endif(SourceLocation Loc, SourceLocation IfLoc) override { + First->Endif(Loc, IfLoc); + Second->Endif(Loc, IfLoc); + } +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Lex/PPConditionalDirectiveRecord.h b/contrib/llvm/tools/clang/include/clang/Lex/PPConditionalDirectiveRecord.h new file mode 100644 index 0000000..8c52275 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Lex/PPConditionalDirectiveRecord.h @@ -0,0 +1,103 @@ +//===--- PPConditionalDirectiveRecord.h - Preprocessing Directives-*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the PPConditionalDirectiveRecord class, which maintains +// a record of conditional directive regions. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_LEX_PPCONDITIONALDIRECTIVERECORD_H +#define LLVM_CLANG_LEX_PPCONDITIONALDIRECTIVERECORD_H + +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/PPCallbacks.h" +#include "llvm/ADT/SmallVector.h" +#include <vector> + +namespace clang { + +/// \brief Records preprocessor conditional directive regions and allows +/// querying in which region source locations belong to. +class PPConditionalDirectiveRecord : public PPCallbacks { + SourceManager &SourceMgr; + + SmallVector<SourceLocation, 6> CondDirectiveStack; + + class CondDirectiveLoc { + SourceLocation Loc; + SourceLocation RegionLoc; + + public: + CondDirectiveLoc(SourceLocation Loc, SourceLocation RegionLoc) + : Loc(Loc), RegionLoc(RegionLoc) {} + + SourceLocation getLoc() const { return Loc; } + SourceLocation getRegionLoc() const { return RegionLoc; } + + class Comp { + SourceManager &SM; + public: + explicit Comp(SourceManager &SM) : SM(SM) {} + bool operator()(const CondDirectiveLoc &LHS, + const CondDirectiveLoc &RHS) { + return SM.isBeforeInTranslationUnit(LHS.getLoc(), RHS.getLoc()); + } + bool operator()(const CondDirectiveLoc &LHS, SourceLocation RHS) { + return SM.isBeforeInTranslationUnit(LHS.getLoc(), RHS); + } + bool operator()(SourceLocation LHS, const CondDirectiveLoc &RHS) { + return SM.isBeforeInTranslationUnit(LHS, RHS.getLoc()); + } + }; + }; + + typedef std::vector<CondDirectiveLoc> CondDirectiveLocsTy; + /// \brief The locations of conditional directives in source order. + CondDirectiveLocsTy CondDirectiveLocs; + + void addCondDirectiveLoc(CondDirectiveLoc DirLoc); + +public: + /// \brief Construct a new preprocessing record. + explicit PPConditionalDirectiveRecord(SourceManager &SM); + + size_t getTotalMemory() const; + + SourceManager &getSourceManager() const { return SourceMgr; } + + /// \brief Returns true if the given range intersects with a conditional + /// directive. if a \#if/\#endif block is fully contained within the range, + /// this function will return false. + bool rangeIntersectsConditionalDirective(SourceRange Range) const; + + /// \brief Returns true if the given locations are in different regions, + /// separated by conditional directive blocks. + bool areInDifferentConditionalDirectiveRegion(SourceLocation LHS, + SourceLocation RHS) const { + return findConditionalDirectiveRegionLoc(LHS) != + findConditionalDirectiveRegionLoc(RHS); + } + + SourceLocation findConditionalDirectiveRegionLoc(SourceLocation Loc) const; + +private: + void If(SourceLocation Loc, SourceRange ConditionRange, + ConditionValueKind ConditionValue) override; + void Elif(SourceLocation Loc, SourceRange ConditionRange, + ConditionValueKind ConditionValue, SourceLocation IfLoc) override; + void Ifdef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) override; + void Ifndef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) override; + void Else(SourceLocation Loc, SourceLocation IfLoc) override; + void Endif(SourceLocation Loc, SourceLocation IfLoc) override; +}; + +} // end namespace clang + +#endif // LLVM_CLANG_LEX_PPCONDITIONALDIRECTIVERECORD_H diff --git a/contrib/llvm/tools/clang/include/clang/Lex/PTHLexer.h b/contrib/llvm/tools/clang/include/clang/Lex/PTHLexer.h new file mode 100644 index 0000000..904be79 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Lex/PTHLexer.h @@ -0,0 +1,104 @@ +//===--- PTHLexer.h - Lexer based on Pre-tokenized input --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the PTHLexer interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_PTHLEXER_H +#define LLVM_CLANG_LEX_PTHLEXER_H + +#include "clang/Lex/PreprocessorLexer.h" + +namespace clang { + +class PTHManager; +class PTHSpellingSearch; + +class PTHLexer : public PreprocessorLexer { + SourceLocation FileStartLoc; + + /// TokBuf - Buffer from PTH file containing raw token data. + const unsigned char* TokBuf; + + /// CurPtr - Pointer into current offset of the token buffer where + /// the next token will be read. + const unsigned char* CurPtr; + + /// LastHashTokPtr - Pointer into TokBuf of the last processed '#' + /// token that appears at the start of a line. + const unsigned char* LastHashTokPtr; + + /// PPCond - Pointer to a side table in the PTH file that provides a + /// a consise summary of the preproccessor conditional block structure. + /// This is used to perform quick skipping of conditional blocks. + const unsigned char* PPCond; + + /// CurPPCondPtr - Pointer inside PPCond that refers to the next entry + /// to process when doing quick skipping of preprocessor blocks. + const unsigned char* CurPPCondPtr; + + PTHLexer(const PTHLexer &) = delete; + void operator=(const PTHLexer &) = delete; + + /// ReadToken - Used by PTHLexer to read tokens TokBuf. + void ReadToken(Token& T); + + bool LexEndOfFile(Token &Result); + + /// PTHMgr - The PTHManager object that created this PTHLexer. + PTHManager& PTHMgr; + + Token EofToken; + +protected: + friend class PTHManager; + + /// Create a PTHLexer for the specified token stream. + PTHLexer(Preprocessor& pp, FileID FID, const unsigned char *D, + const unsigned char* ppcond, PTHManager &PM); +public: + ~PTHLexer() override {} + + /// Lex - Return the next token. + bool Lex(Token &Tok); + + void getEOF(Token &Tok); + + /// DiscardToEndOfLine - Read the rest of the current preprocessor line as an + /// uninterpreted string. This switches the lexer out of directive mode. + void DiscardToEndOfLine(); + + /// isNextPPTokenLParen - Return 1 if the next unexpanded token will return a + /// tok::l_paren token, 0 if it is something else and 2 if there are no more + /// tokens controlled by this lexer. + unsigned isNextPPTokenLParen() { + // isNextPPTokenLParen is not on the hot path, and all we care about is + // whether or not we are at a token with kind tok::eof or tok::l_paren. + // Just read the first byte from the current token pointer to determine + // its kind. + tok::TokenKind x = (tok::TokenKind)*CurPtr; + return x == tok::eof ? 2 : x == tok::l_paren; + } + + /// IndirectLex - An indirect call to 'Lex' that can be invoked via + /// the PreprocessorLexer interface. + void IndirectLex(Token &Result) override { Lex(Result); } + + /// getSourceLocation - Return a source location for the token in + /// the current file. + SourceLocation getSourceLocation() override; + + /// SkipBlock - Used by Preprocessor to skip the current conditional block. + bool SkipBlock(); +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Lex/PTHManager.h b/contrib/llvm/tools/clang/include/clang/Lex/PTHManager.h new file mode 100644 index 0000000..26178ed --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Lex/PTHManager.h @@ -0,0 +1,150 @@ +//===--- PTHManager.h - Manager object for PTH processing -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the PTHManager interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_PTHMANAGER_H +#define LLVM_CLANG_LEX_PTHMANAGER_H + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Lex/PTHLexer.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/OnDiskHashTable.h" +#include <string> + +namespace llvm { + class MemoryBuffer; +} + +namespace clang { + +class FileEntry; +class PTHLexer; +class DiagnosticsEngine; +class FileSystemStatCache; + +class PTHManager : public IdentifierInfoLookup { + friend class PTHLexer; + + friend class PTHStatCache; + + class PTHStringLookupTrait; + class PTHFileLookupTrait; + typedef llvm::OnDiskChainedHashTable<PTHStringLookupTrait> PTHStringIdLookup; + typedef llvm::OnDiskChainedHashTable<PTHFileLookupTrait> PTHFileLookup; + + /// The memory mapped PTH file. + std::unique_ptr<const llvm::MemoryBuffer> Buf; + + /// Alloc - Allocator used for IdentifierInfo objects. + llvm::BumpPtrAllocator Alloc; + + /// IdMap - A lazily generated cache mapping from persistent identifiers to + /// IdentifierInfo*. + std::unique_ptr<IdentifierInfo *[], llvm::FreeDeleter> PerIDCache; + + /// FileLookup - Abstract data structure used for mapping between files + /// and token data in the PTH file. + std::unique_ptr<PTHFileLookup> FileLookup; + + /// IdDataTable - Array representing the mapping from persistent IDs to the + /// data offset within the PTH file containing the information to + /// reconsitute an IdentifierInfo. + const unsigned char* const IdDataTable; + + /// SortedIdTable - Abstract data structure mapping from strings to + /// persistent IDs. This is used by get(). + std::unique_ptr<PTHStringIdLookup> StringIdLookup; + + /// NumIds - The number of identifiers in the PTH file. + const unsigned NumIds; + + /// PP - The Preprocessor object that will use this PTHManager to create + /// PTHLexer objects. + Preprocessor* PP; + + /// SpellingBase - The base offset within the PTH memory buffer that + /// contains the cached spellings for literals. + const unsigned char* const SpellingBase; + + /// OriginalSourceFile - A null-terminated C-string that specifies the name + /// if the file (if any) that was to used to generate the PTH cache. + const char* OriginalSourceFile; + + /// This constructor is intended to only be called by the static 'Create' + /// method. + PTHManager(std::unique_ptr<const llvm::MemoryBuffer> buf, + std::unique_ptr<PTHFileLookup> fileLookup, + const unsigned char *idDataTable, + std::unique_ptr<IdentifierInfo *[], llvm::FreeDeleter> perIDCache, + std::unique_ptr<PTHStringIdLookup> stringIdLookup, unsigned numIds, + const unsigned char *spellingBase, const char *originalSourceFile); + + PTHManager(const PTHManager &) = delete; + void operator=(const PTHManager &) = delete; + + /// getSpellingAtPTHOffset - Used by PTHLexer classes to get the cached + /// spelling for a token. + unsigned getSpellingAtPTHOffset(unsigned PTHOffset, const char*& Buffer); + + /// GetIdentifierInfo - Used to reconstruct IdentifierInfo objects from the + /// PTH file. + inline IdentifierInfo* GetIdentifierInfo(unsigned PersistentID) { + // Check if the IdentifierInfo has already been resolved. + if (IdentifierInfo* II = PerIDCache[PersistentID]) + return II; + return LazilyCreateIdentifierInfo(PersistentID); + } + IdentifierInfo* LazilyCreateIdentifierInfo(unsigned PersistentID); + +public: + // The current PTH version. + enum { Version = 10 }; + + ~PTHManager() override; + + /// getOriginalSourceFile - Return the full path to the original header + /// file name that was used to generate the PTH cache. + const char* getOriginalSourceFile() const { + return OriginalSourceFile; + } + + /// get - Return the identifier token info for the specified named identifier. + /// Unlike the version in IdentifierTable, this returns a pointer instead + /// of a reference. If the pointer is NULL then the IdentifierInfo cannot + /// be found. + IdentifierInfo *get(StringRef Name) override; + + /// Create - This method creates PTHManager objects. The 'file' argument + /// is the name of the PTH file. This method returns NULL upon failure. + static PTHManager *Create(StringRef file, DiagnosticsEngine &Diags); + + void setPreprocessor(Preprocessor *pp) { PP = pp; } + + /// CreateLexer - Return a PTHLexer that "lexes" the cached tokens for the + /// specified file. This method returns NULL if no cached tokens exist. + /// It is the responsibility of the caller to 'delete' the returned object. + PTHLexer *CreateLexer(FileID FID); + + /// createStatCache - Returns a FileSystemStatCache object for use with + /// FileManager objects. These objects use the PTH data to speed up + /// calls to stat by memoizing their results from when the PTH file + /// was generated. + std::unique_ptr<FileSystemStatCache> createStatCache(); +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Lex/Pragma.h b/contrib/llvm/tools/clang/include/clang/Lex/Pragma.h new file mode 100644 index 0000000..274f0da --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Lex/Pragma.h @@ -0,0 +1,126 @@ +//===--- Pragma.h - Pragma registration and handling ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the PragmaHandler and PragmaTable interfaces. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_PRAGMA_H +#define LLVM_CLANG_LEX_PRAGMA_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include <cassert> + +namespace clang { + class Preprocessor; + class Token; + class IdentifierInfo; + class PragmaNamespace; + + /** + * \brief Describes how the pragma was introduced, e.g., with \#pragma, + * _Pragma, or __pragma. + */ + enum PragmaIntroducerKind { + /** + * \brief The pragma was introduced via \#pragma. + */ + PIK_HashPragma, + + /** + * \brief The pragma was introduced via the C99 _Pragma(string-literal). + */ + PIK__Pragma, + + /** + * \brief The pragma was introduced via the Microsoft + * __pragma(token-string). + */ + PIK___pragma + }; + +/// PragmaHandler - Instances of this interface defined to handle the various +/// pragmas that the language front-end uses. Each handler optionally has a +/// name (e.g. "pack") and the HandlePragma method is invoked when a pragma with +/// that identifier is found. If a handler does not match any of the declared +/// pragmas the handler with a null identifier is invoked, if it exists. +/// +/// Note that the PragmaNamespace class can be used to subdivide pragmas, e.g. +/// we treat "\#pragma STDC" and "\#pragma GCC" as namespaces that contain other +/// pragmas. +class PragmaHandler { + std::string Name; +public: + explicit PragmaHandler(StringRef name) : Name(name) {} + PragmaHandler() {} + virtual ~PragmaHandler(); + + StringRef getName() const { return Name; } + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken) = 0; + + /// getIfNamespace - If this is a namespace, return it. This is equivalent to + /// using a dynamic_cast, but doesn't require RTTI. + virtual PragmaNamespace *getIfNamespace() { return nullptr; } +}; + +/// EmptyPragmaHandler - A pragma handler which takes no action, which can be +/// used to ignore particular pragmas. +class EmptyPragmaHandler : public PragmaHandler { +public: + explicit EmptyPragmaHandler(StringRef Name = StringRef()); + + void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken) override; +}; + +/// PragmaNamespace - This PragmaHandler subdivides the namespace of pragmas, +/// allowing hierarchical pragmas to be defined. Common examples of namespaces +/// are "\#pragma GCC", "\#pragma STDC", and "\#pragma omp", but any namespaces +/// may be (potentially recursively) defined. +class PragmaNamespace : public PragmaHandler { + /// Handlers - This is a map of the handlers in this namespace with their name + /// as key. + /// + llvm::StringMap<PragmaHandler*> Handlers; +public: + explicit PragmaNamespace(StringRef Name) : PragmaHandler(Name) {} + ~PragmaNamespace() override; + + /// FindHandler - Check to see if there is already a handler for the + /// specified name. If not, return the handler for the null name if it + /// exists, otherwise return null. If IgnoreNull is true (the default) then + /// the null handler isn't returned on failure to match. + PragmaHandler *FindHandler(StringRef Name, + bool IgnoreNull = true) const; + + /// AddPragma - Add a pragma to this namespace. + /// + void AddPragma(PragmaHandler *Handler); + + /// RemovePragmaHandler - Remove the given handler from the + /// namespace. + void RemovePragmaHandler(PragmaHandler *Handler); + + bool IsEmpty() { + return Handlers.empty(); + } + + void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken) override; + + PragmaNamespace *getIfNamespace() override { return this; } +}; + + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Lex/PreprocessingRecord.h b/contrib/llvm/tools/clang/include/clang/Lex/PreprocessingRecord.h new file mode 100644 index 0000000..87b8ce1 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Lex/PreprocessingRecord.h @@ -0,0 +1,536 @@ +//===--- PreprocessingRecord.h - Record of Preprocessing --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the PreprocessingRecord class, which maintains a record +// of what occurred during preprocessing. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_LEX_PREPROCESSINGRECORD_H +#define LLVM_CLANG_LEX_PREPROCESSINGRECORD_H + +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/PPCallbacks.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/iterator.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Compiler.h" +#include <vector> + +namespace clang { + class IdentifierInfo; + class MacroInfo; + class PreprocessingRecord; +} + +/// \brief Allocates memory within a Clang preprocessing record. +void *operator new(size_t bytes, clang::PreprocessingRecord &PR, + unsigned alignment = 8) LLVM_NOEXCEPT; + +/// \brief Frees memory allocated in a Clang preprocessing record. +void operator delete(void *ptr, clang::PreprocessingRecord &PR, + unsigned) LLVM_NOEXCEPT; + +namespace clang { + class MacroDefinitionRecord; + class FileEntry; + + /// \brief Base class that describes a preprocessed entity, which may be a + /// preprocessor directive or macro expansion. + class PreprocessedEntity { + public: + /// \brief The kind of preprocessed entity an object describes. + enum EntityKind { + /// \brief Indicates a problem trying to load the preprocessed entity. + InvalidKind, + + /// \brief A macro expansion. + MacroExpansionKind, + + /// \defgroup Preprocessing directives + /// @{ + + /// \brief A macro definition. + MacroDefinitionKind, + + /// \brief An inclusion directive, such as \c \#include, \c + /// \#import, or \c \#include_next. + InclusionDirectiveKind, + + /// @} + + FirstPreprocessingDirective = MacroDefinitionKind, + LastPreprocessingDirective = InclusionDirectiveKind + }; + + private: + /// \brief The kind of preprocessed entity that this object describes. + EntityKind Kind; + + /// \brief The source range that covers this preprocessed entity. + SourceRange Range; + + protected: + PreprocessedEntity(EntityKind Kind, SourceRange Range) + : Kind(Kind), Range(Range) { } + + friend class PreprocessingRecord; + + public: + /// \brief Retrieve the kind of preprocessed entity stored in this object. + EntityKind getKind() const { return Kind; } + + /// \brief Retrieve the source range that covers this entire preprocessed + /// entity. + SourceRange getSourceRange() const LLVM_READONLY { return Range; } + + /// \brief Returns true if there was a problem loading the preprocessed + /// entity. + bool isInvalid() const { return Kind == InvalidKind; } + + // Only allow allocation of preprocessed entities using the allocator + // in PreprocessingRecord or by doing a placement new. + void *operator new(size_t bytes, PreprocessingRecord &PR, + unsigned alignment = 8) LLVM_NOEXCEPT { + return ::operator new(bytes, PR, alignment); + } + + void *operator new(size_t bytes, void *mem) LLVM_NOEXCEPT { return mem; } + + void operator delete(void *ptr, PreprocessingRecord &PR, + unsigned alignment) LLVM_NOEXCEPT { + return ::operator delete(ptr, PR, alignment); + } + + void operator delete(void *, std::size_t) LLVM_NOEXCEPT {} + void operator delete(void *, void *) LLVM_NOEXCEPT {} + + private: + // Make vanilla 'new' and 'delete' illegal for preprocessed entities. + void *operator new(size_t bytes) LLVM_NOEXCEPT; + void operator delete(void *data) LLVM_NOEXCEPT; + }; + + /// \brief Records the presence of a preprocessor directive. + class PreprocessingDirective : public PreprocessedEntity { + public: + PreprocessingDirective(EntityKind Kind, SourceRange Range) + : PreprocessedEntity(Kind, Range) { } + + // Implement isa/cast/dyncast/etc. + static bool classof(const PreprocessedEntity *PD) { + return PD->getKind() >= FirstPreprocessingDirective && + PD->getKind() <= LastPreprocessingDirective; + } + }; + + /// \brief Record the location of a macro definition. + class MacroDefinitionRecord : public PreprocessingDirective { + /// \brief The name of the macro being defined. + const IdentifierInfo *Name; + + public: + explicit MacroDefinitionRecord(const IdentifierInfo *Name, + SourceRange Range) + : PreprocessingDirective(MacroDefinitionKind, Range), Name(Name) {} + + /// \brief Retrieve the name of the macro being defined. + const IdentifierInfo *getName() const { return Name; } + + /// \brief Retrieve the location of the macro name in the definition. + SourceLocation getLocation() const { return getSourceRange().getBegin(); } + + // Implement isa/cast/dyncast/etc. + static bool classof(const PreprocessedEntity *PE) { + return PE->getKind() == MacroDefinitionKind; + } + }; + + /// \brief Records the location of a macro expansion. + class MacroExpansion : public PreprocessedEntity { + /// \brief The definition of this macro or the name of the macro if it is + /// a builtin macro. + llvm::PointerUnion<IdentifierInfo *, MacroDefinitionRecord *> NameOrDef; + + public: + MacroExpansion(IdentifierInfo *BuiltinName, SourceRange Range) + : PreprocessedEntity(MacroExpansionKind, Range), + NameOrDef(BuiltinName) {} + + MacroExpansion(MacroDefinitionRecord *Definition, SourceRange Range) + : PreprocessedEntity(MacroExpansionKind, Range), NameOrDef(Definition) { + } + + /// \brief True if it is a builtin macro. + bool isBuiltinMacro() const { return NameOrDef.is<IdentifierInfo *>(); } + + /// \brief The name of the macro being expanded. + const IdentifierInfo *getName() const { + if (MacroDefinitionRecord *Def = getDefinition()) + return Def->getName(); + return NameOrDef.get<IdentifierInfo *>(); + } + + /// \brief The definition of the macro being expanded. May return null if + /// this is a builtin macro. + MacroDefinitionRecord *getDefinition() const { + return NameOrDef.dyn_cast<MacroDefinitionRecord *>(); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const PreprocessedEntity *PE) { + return PE->getKind() == MacroExpansionKind; + } + }; + + /// \brief Record the location of an inclusion directive, such as an + /// \c \#include or \c \#import statement. + class InclusionDirective : public PreprocessingDirective { + public: + /// \brief The kind of inclusion directives known to the + /// preprocessor. + enum InclusionKind { + /// \brief An \c \#include directive. + Include, + /// \brief An Objective-C \c \#import directive. + Import, + /// \brief A GNU \c \#include_next directive. + IncludeNext, + /// \brief A Clang \c \#__include_macros directive. + IncludeMacros + }; + + private: + /// \brief The name of the file that was included, as written in + /// the source. + StringRef FileName; + + /// \brief Whether the file name was in quotation marks; otherwise, it was + /// in angle brackets. + unsigned InQuotes : 1; + + /// \brief The kind of inclusion directive we have. + /// + /// This is a value of type InclusionKind. + unsigned Kind : 2; + + /// \brief Whether the inclusion directive was automatically turned into + /// a module import. + unsigned ImportedModule : 1; + + /// \brief The file that was included. + const FileEntry *File; + + public: + InclusionDirective(PreprocessingRecord &PPRec, + InclusionKind Kind, StringRef FileName, + bool InQuotes, bool ImportedModule, + const FileEntry *File, SourceRange Range); + + /// \brief Determine what kind of inclusion directive this is. + InclusionKind getKind() const { return static_cast<InclusionKind>(Kind); } + + /// \brief Retrieve the included file name as it was written in the source. + StringRef getFileName() const { return FileName; } + + /// \brief Determine whether the included file name was written in quotes; + /// otherwise, it was written in angle brackets. + bool wasInQuotes() const { return InQuotes; } + + /// \brief Determine whether the inclusion directive was automatically + /// turned into a module import. + bool importedModule() const { return ImportedModule; } + + /// \brief Retrieve the file entry for the actual file that was included + /// by this directive. + const FileEntry *getFile() const { return File; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const PreprocessedEntity *PE) { + return PE->getKind() == InclusionDirectiveKind; + } + }; + + /// \brief An abstract class that should be subclassed by any external source + /// of preprocessing record entries. + class ExternalPreprocessingRecordSource { + public: + virtual ~ExternalPreprocessingRecordSource(); + + /// \brief Read a preallocated preprocessed entity from the external source. + /// + /// \returns null if an error occurred that prevented the preprocessed + /// entity from being loaded. + virtual PreprocessedEntity *ReadPreprocessedEntity(unsigned Index) = 0; + + /// \brief Returns a pair of [Begin, End) indices of preallocated + /// preprocessed entities that \p Range encompasses. + virtual std::pair<unsigned, unsigned> + findPreprocessedEntitiesInRange(SourceRange Range) = 0; + + /// \brief Optionally returns true or false if the preallocated preprocessed + /// entity with index \p Index came from file \p FID. + virtual Optional<bool> isPreprocessedEntityInFileID(unsigned Index, + FileID FID) { + return None; + } + }; + + /// \brief A record of the steps taken while preprocessing a source file, + /// including the various preprocessing directives processed, macros + /// expanded, etc. + class PreprocessingRecord : public PPCallbacks { + SourceManager &SourceMgr; + + /// \brief Allocator used to store preprocessing objects. + llvm::BumpPtrAllocator BumpAlloc; + + /// \brief The set of preprocessed entities in this record, in order they + /// were seen. + std::vector<PreprocessedEntity *> PreprocessedEntities; + + /// \brief The set of preprocessed entities in this record that have been + /// loaded from external sources. + /// + /// The entries in this vector are loaded lazily from the external source, + /// and are referenced by the iterator using negative indices. + std::vector<PreprocessedEntity *> LoadedPreprocessedEntities; + + /// \brief The set of ranges that were skipped by the preprocessor, + std::vector<SourceRange> SkippedRanges; + + /// \brief Global (loaded or local) ID for a preprocessed entity. + /// Negative values are used to indicate preprocessed entities + /// loaded from the external source while non-negative values are used to + /// indicate preprocessed entities introduced by the current preprocessor. + /// Value -1 corresponds to element 0 in the loaded entities vector, + /// value -2 corresponds to element 1 in the loaded entities vector, etc. + /// Value 0 is an invalid value, the index to local entities is 1-based, + /// value 1 corresponds to element 0 in the local entities vector, + /// value 2 corresponds to element 1 in the local entities vector, etc. + class PPEntityID { + int ID; + explicit PPEntityID(int ID) : ID(ID) {} + friend class PreprocessingRecord; + public: + PPEntityID() : ID(0) {} + }; + + static PPEntityID getPPEntityID(unsigned Index, bool isLoaded) { + return isLoaded ? PPEntityID(-int(Index)-1) : PPEntityID(Index+1); + } + + /// \brief Mapping from MacroInfo structures to their definitions. + llvm::DenseMap<const MacroInfo *, MacroDefinitionRecord *> MacroDefinitions; + + /// \brief External source of preprocessed entities. + ExternalPreprocessingRecordSource *ExternalSource; + + /// \brief Retrieve the preprocessed entity at the given ID. + PreprocessedEntity *getPreprocessedEntity(PPEntityID PPID); + + /// \brief Retrieve the loaded preprocessed entity at the given index. + PreprocessedEntity *getLoadedPreprocessedEntity(unsigned Index); + + /// \brief Determine the number of preprocessed entities that were + /// loaded (or can be loaded) from an external source. + unsigned getNumLoadedPreprocessedEntities() const { + return LoadedPreprocessedEntities.size(); + } + + /// \brief Returns a pair of [Begin, End) indices of local preprocessed + /// entities that \p Range encompasses. + std::pair<unsigned, unsigned> + findLocalPreprocessedEntitiesInRange(SourceRange Range) const; + unsigned findBeginLocalPreprocessedEntity(SourceLocation Loc) const; + unsigned findEndLocalPreprocessedEntity(SourceLocation Loc) const; + + /// \brief Allocate space for a new set of loaded preprocessed entities. + /// + /// \returns The index into the set of loaded preprocessed entities, which + /// corresponds to the first newly-allocated entity. + unsigned allocateLoadedEntities(unsigned NumEntities); + + /// \brief Register a new macro definition. + void RegisterMacroDefinition(MacroInfo *Macro, MacroDefinitionRecord *Def); + + public: + /// \brief Construct a new preprocessing record. + explicit PreprocessingRecord(SourceManager &SM); + + /// \brief Allocate memory in the preprocessing record. + void *Allocate(unsigned Size, unsigned Align = 8) { + return BumpAlloc.Allocate(Size, Align); + } + + /// \brief Deallocate memory in the preprocessing record. + void Deallocate(void *Ptr) { } + + size_t getTotalMemory() const; + + SourceManager &getSourceManager() const { return SourceMgr; } + + /// Iteration over the preprocessed entities. + /// + /// In a complete iteration, the iterator walks the range [-M, N), + /// where negative values are used to indicate preprocessed entities + /// loaded from the external source while non-negative values are used to + /// indicate preprocessed entities introduced by the current preprocessor. + /// However, to provide iteration in source order (for, e.g., chained + /// precompiled headers), dereferencing the iterator flips the negative + /// values (corresponding to loaded entities), so that position -M + /// corresponds to element 0 in the loaded entities vector, position -M+1 + /// corresponds to element 1 in the loaded entities vector, etc. This + /// gives us a reasonably efficient, source-order walk. + /// + /// We define this as a wrapping iterator around an int. The + /// iterator_adaptor_base class forwards the iterator methods to basic + /// integer arithmetic. + class iterator : public llvm::iterator_adaptor_base< + iterator, int, std::random_access_iterator_tag, + PreprocessedEntity *, int, PreprocessedEntity *, + PreprocessedEntity *> { + PreprocessingRecord *Self; + + iterator(PreprocessingRecord *Self, int Position) + : iterator::iterator_adaptor_base(Position), Self(Self) {} + friend class PreprocessingRecord; + + public: + iterator() : iterator(nullptr, 0) {} + + PreprocessedEntity *operator*() const { + bool isLoaded = this->I < 0; + unsigned Index = isLoaded ? + Self->LoadedPreprocessedEntities.size() + this->I : this->I; + PPEntityID ID = Self->getPPEntityID(Index, isLoaded); + return Self->getPreprocessedEntity(ID); + } + PreprocessedEntity *operator->() const { return **this; } + }; + + /// \brief Begin iterator for all preprocessed entities. + iterator begin() { + return iterator(this, -(int)LoadedPreprocessedEntities.size()); + } + + /// \brief End iterator for all preprocessed entities. + iterator end() { + return iterator(this, PreprocessedEntities.size()); + } + + /// \brief Begin iterator for local, non-loaded, preprocessed entities. + iterator local_begin() { + return iterator(this, 0); + } + + /// \brief End iterator for local, non-loaded, preprocessed entities. + iterator local_end() { + return iterator(this, PreprocessedEntities.size()); + } + + /// \brief iterator range for the given range of loaded + /// preprocessed entities. + llvm::iterator_range<iterator> getIteratorsForLoadedRange(unsigned start, + unsigned count) { + unsigned end = start + count; + assert(end <= LoadedPreprocessedEntities.size()); + return llvm::make_range( + iterator(this, int(start) - LoadedPreprocessedEntities.size()), + iterator(this, int(end) - LoadedPreprocessedEntities.size())); + } + + /// \brief Returns a range of preprocessed entities that source range \p R + /// encompasses. + /// + /// \param R the range to look for preprocessed entities. + /// + llvm::iterator_range<iterator> + getPreprocessedEntitiesInRange(SourceRange R); + + /// \brief Returns true if the preprocessed entity that \p PPEI iterator + /// points to is coming from the file \p FID. + /// + /// Can be used to avoid implicit deserializations of preallocated + /// preprocessed entities if we only care about entities of a specific file + /// and not from files \#included in the range given at + /// \see getPreprocessedEntitiesInRange. + bool isEntityInFileID(iterator PPEI, FileID FID); + + /// \brief Add a new preprocessed entity to this record. + PPEntityID addPreprocessedEntity(PreprocessedEntity *Entity); + + /// \brief Set the external source for preprocessed entities. + void SetExternalSource(ExternalPreprocessingRecordSource &Source); + + /// \brief Retrieve the external source for preprocessed entities. + ExternalPreprocessingRecordSource *getExternalSource() const { + return ExternalSource; + } + + /// \brief Retrieve the macro definition that corresponds to the given + /// \c MacroInfo. + MacroDefinitionRecord *findMacroDefinition(const MacroInfo *MI); + + /// \brief Retrieve all ranges that got skipped while preprocessing. + const std::vector<SourceRange> &getSkippedRanges() const { + return SkippedRanges; + } + + private: + void MacroExpands(const Token &Id, const MacroDefinition &MD, + SourceRange Range, const MacroArgs *Args) override; + void MacroDefined(const Token &Id, const MacroDirective *MD) override; + void MacroUndefined(const Token &Id, const MacroDefinition &MD) override; + void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, + StringRef FileName, bool IsAngled, + CharSourceRange FilenameRange, + const FileEntry *File, StringRef SearchPath, + StringRef RelativePath, + const Module *Imported) override; + void Ifdef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) override; + void Ifndef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) override; + /// \brief Hook called whenever the 'defined' operator is seen. + void Defined(const Token &MacroNameTok, const MacroDefinition &MD, + SourceRange Range) override; + + void SourceRangeSkipped(SourceRange Range) override; + + void addMacroExpansion(const Token &Id, const MacroInfo *MI, + SourceRange Range); + + /// \brief Cached result of the last \see getPreprocessedEntitiesInRange + /// query. + struct { + SourceRange Range; + std::pair<int, int> Result; + } CachedRangeQuery; + + std::pair<int, int> getPreprocessedEntitiesInRangeSlow(SourceRange R); + + friend class ASTReader; + friend class ASTWriter; + }; +} // end namespace clang + +inline void *operator new(size_t bytes, clang::PreprocessingRecord &PR, + unsigned alignment) LLVM_NOEXCEPT { + return PR.Allocate(bytes, alignment); +} + +inline void operator delete(void *ptr, clang::PreprocessingRecord &PR, + unsigned) LLVM_NOEXCEPT { + PR.Deallocate(ptr); +} + +#endif // LLVM_CLANG_LEX_PREPROCESSINGRECORD_H diff --git a/contrib/llvm/tools/clang/include/clang/Lex/Preprocessor.h b/contrib/llvm/tools/clang/include/clang/Lex/Preprocessor.h new file mode 100644 index 0000000..f6154b6 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Lex/Preprocessor.h @@ -0,0 +1,1911 @@ +//===--- Preprocessor.h - C Language Family Preprocessor --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the clang::Preprocessor interface. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_PREPROCESSOR_H +#define LLVM_CLANG_LEX_PREPROCESSOR_H + +#include "clang/Basic/Builtins.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Lex/MacroInfo.h" +#include "clang/Lex/ModuleMap.h" +#include "clang/Lex/PPCallbacks.h" +#include "clang/Lex/PTHLexer.h" +#include "clang/Lex/TokenLexer.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/TinyPtrVector.h" +#include "llvm/Support/Allocator.h" +#include <memory> +#include <vector> + +namespace llvm { + template<unsigned InternalLen> class SmallString; +} + +namespace clang { + +class SourceManager; +class ExternalPreprocessorSource; +class FileManager; +class FileEntry; +class HeaderSearch; +class PragmaNamespace; +class PragmaHandler; +class CommentHandler; +class ScratchBuffer; +class TargetInfo; +class PPCallbacks; +class CodeCompletionHandler; +class DirectoryLookup; +class PreprocessingRecord; +class ModuleLoader; +class PTHManager; +class PreprocessorOptions; + +/// \brief Stores token information for comparing actual tokens with +/// predefined values. Only handles simple tokens and identifiers. +class TokenValue { + tok::TokenKind Kind; + IdentifierInfo *II; + +public: + TokenValue(tok::TokenKind Kind) : Kind(Kind), II(nullptr) { + assert(Kind != tok::raw_identifier && "Raw identifiers are not supported."); + assert(Kind != tok::identifier && + "Identifiers should be created by TokenValue(IdentifierInfo *)"); + assert(!tok::isLiteral(Kind) && "Literals are not supported."); + assert(!tok::isAnnotation(Kind) && "Annotations are not supported."); + } + TokenValue(IdentifierInfo *II) : Kind(tok::identifier), II(II) {} + bool operator==(const Token &Tok) const { + return Tok.getKind() == Kind && + (!II || II == Tok.getIdentifierInfo()); + } +}; + +/// \brief Context in which macro name is used. +enum MacroUse { + MU_Other = 0, // other than #define or #undef + MU_Define = 1, // macro name specified in #define + MU_Undef = 2 // macro name specified in #undef +}; + +/// \brief Engages in a tight little dance with the lexer to efficiently +/// preprocess tokens. +/// +/// Lexers know only about tokens within a single source file, and don't +/// know anything about preprocessor-level issues like the \#include stack, +/// token expansion, etc. +class Preprocessor : public RefCountedBase<Preprocessor> { + IntrusiveRefCntPtr<PreprocessorOptions> PPOpts; + DiagnosticsEngine *Diags; + LangOptions &LangOpts; + const TargetInfo *Target; + const TargetInfo *AuxTarget; + FileManager &FileMgr; + SourceManager &SourceMgr; + std::unique_ptr<ScratchBuffer> ScratchBuf; + HeaderSearch &HeaderInfo; + ModuleLoader &TheModuleLoader; + + /// \brief External source of macros. + ExternalPreprocessorSource *ExternalSource; + + + /// An optional PTHManager object used for getting tokens from + /// a token cache rather than lexing the original source file. + std::unique_ptr<PTHManager> PTH; + + /// A BumpPtrAllocator object used to quickly allocate and release + /// objects internal to the Preprocessor. + llvm::BumpPtrAllocator BP; + + /// Identifiers for builtin macros and other builtins. + IdentifierInfo *Ident__LINE__, *Ident__FILE__; // __LINE__, __FILE__ + IdentifierInfo *Ident__DATE__, *Ident__TIME__; // __DATE__, __TIME__ + IdentifierInfo *Ident__INCLUDE_LEVEL__; // __INCLUDE_LEVEL__ + IdentifierInfo *Ident__BASE_FILE__; // __BASE_FILE__ + IdentifierInfo *Ident__TIMESTAMP__; // __TIMESTAMP__ + IdentifierInfo *Ident__COUNTER__; // __COUNTER__ + IdentifierInfo *Ident_Pragma, *Ident__pragma; // _Pragma, __pragma + IdentifierInfo *Ident__identifier; // __identifier + IdentifierInfo *Ident__VA_ARGS__; // __VA_ARGS__ + IdentifierInfo *Ident__has_feature; // __has_feature + IdentifierInfo *Ident__has_extension; // __has_extension + IdentifierInfo *Ident__has_builtin; // __has_builtin + IdentifierInfo *Ident__has_attribute; // __has_attribute + IdentifierInfo *Ident__has_include; // __has_include + IdentifierInfo *Ident__has_include_next; // __has_include_next + IdentifierInfo *Ident__has_warning; // __has_warning + IdentifierInfo *Ident__is_identifier; // __is_identifier + IdentifierInfo *Ident__building_module; // __building_module + IdentifierInfo *Ident__MODULE__; // __MODULE__ + IdentifierInfo *Ident__has_cpp_attribute; // __has_cpp_attribute + IdentifierInfo *Ident__has_declspec; // __has_declspec_attribute + + SourceLocation DATELoc, TIMELoc; + unsigned CounterValue; // Next __COUNTER__ value. + + enum { + /// \brief Maximum depth of \#includes. + MaxAllowedIncludeStackDepth = 200 + }; + + // State that is set before the preprocessor begins. + bool KeepComments : 1; + bool KeepMacroComments : 1; + bool SuppressIncludeNotFoundError : 1; + + // State that changes while the preprocessor runs: + bool InMacroArgs : 1; // True if parsing fn macro invocation args. + + /// Whether the preprocessor owns the header search object. + bool OwnsHeaderSearch : 1; + + /// True if macro expansion is disabled. + bool DisableMacroExpansion : 1; + + /// Temporarily disables DisableMacroExpansion (i.e. enables expansion) + /// when parsing preprocessor directives. + bool MacroExpansionInDirectivesOverride : 1; + + class ResetMacroExpansionHelper; + + /// \brief Whether we have already loaded macros from the external source. + mutable bool ReadMacrosFromExternalSource : 1; + + /// \brief True if pragmas are enabled. + bool PragmasEnabled : 1; + + /// \brief True if the current build action is a preprocessing action. + bool PreprocessedOutput : 1; + + /// \brief True if we are currently preprocessing a #if or #elif directive + bool ParsingIfOrElifDirective; + + /// \brief True if we are pre-expanding macro arguments. + bool InMacroArgPreExpansion; + + /// \brief Mapping/lookup information for all identifiers in + /// the program, including program keywords. + mutable IdentifierTable Identifiers; + + /// \brief This table contains all the selectors in the program. + /// + /// Unlike IdentifierTable above, this table *isn't* populated by the + /// preprocessor. It is declared/expanded here because its role/lifetime is + /// conceptually similar to the IdentifierTable. In addition, the current + /// control flow (in clang::ParseAST()), make it convenient to put here. + /// + /// FIXME: Make sure the lifetime of Identifiers/Selectors *isn't* tied to + /// the lifetime of the preprocessor. + SelectorTable Selectors; + + /// \brief Information about builtins. + Builtin::Context BuiltinInfo; + + /// \brief Tracks all of the pragmas that the client registered + /// with this preprocessor. + std::unique_ptr<PragmaNamespace> PragmaHandlers; + + /// \brief Pragma handlers of the original source is stored here during the + /// parsing of a model file. + std::unique_ptr<PragmaNamespace> PragmaHandlersBackup; + + /// \brief Tracks all of the comment handlers that the client registered + /// with this preprocessor. + std::vector<CommentHandler *> CommentHandlers; + + /// \brief True if we want to ignore EOF token and continue later on (thus + /// avoid tearing the Lexer and etc. down). + bool IncrementalProcessing; + + /// The kind of translation unit we are processing. + TranslationUnitKind TUKind; + + /// \brief The code-completion handler. + CodeCompletionHandler *CodeComplete; + + /// \brief The file that we're performing code-completion for, if any. + const FileEntry *CodeCompletionFile; + + /// \brief The offset in file for the code-completion point. + unsigned CodeCompletionOffset; + + /// \brief The location for the code-completion point. This gets instantiated + /// when the CodeCompletionFile gets \#include'ed for preprocessing. + SourceLocation CodeCompletionLoc; + + /// \brief The start location for the file of the code-completion point. + /// + /// This gets instantiated when the CodeCompletionFile gets \#include'ed + /// for preprocessing. + SourceLocation CodeCompletionFileLoc; + + /// \brief The source location of the \c import contextual keyword we just + /// lexed, if any. + SourceLocation ModuleImportLoc; + + /// \brief The module import path that we're currently processing. + SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> ModuleImportPath; + + /// \brief Whether the last token we lexed was an '@'. + bool LastTokenWasAt; + + /// \brief Whether the module import expects an identifier next. Otherwise, + /// it expects a '.' or ';'. + bool ModuleImportExpectsIdentifier; + + /// \brief The source location of the currently-active + /// \#pragma clang arc_cf_code_audited begin. + SourceLocation PragmaARCCFCodeAuditedLoc; + + /// \brief The source location of the currently-active + /// \#pragma clang assume_nonnull begin. + SourceLocation PragmaAssumeNonNullLoc; + + /// \brief True if we hit the code-completion point. + bool CodeCompletionReached; + + /// \brief The directory that the main file should be considered to occupy, + /// if it does not correspond to a real file (as happens when building a + /// module). + const DirectoryEntry *MainFileDir; + + /// \brief The number of bytes that we will initially skip when entering the + /// main file, along with a flag that indicates whether skipping this number + /// of bytes will place the lexer at the start of a line. + /// + /// This is used when loading a precompiled preamble. + std::pair<int, bool> SkipMainFilePreamble; + + /// \brief The current top of the stack that we're lexing from if + /// not expanding a macro and we are lexing directly from source code. + /// + /// Only one of CurLexer, CurPTHLexer, or CurTokenLexer will be non-null. + std::unique_ptr<Lexer> CurLexer; + + /// \brief The current top of stack that we're lexing from if + /// not expanding from a macro and we are lexing from a PTH cache. + /// + /// Only one of CurLexer, CurPTHLexer, or CurTokenLexer will be non-null. + std::unique_ptr<PTHLexer> CurPTHLexer; + + /// \brief The current top of the stack what we're lexing from + /// if not expanding a macro. + /// + /// This is an alias for either CurLexer or CurPTHLexer. + PreprocessorLexer *CurPPLexer; + + /// \brief 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 *CurDirLookup; + + /// \brief The current macro we are expanding, if we are expanding a macro. + /// + /// One of CurLexer and CurTokenLexer must be null. + std::unique_ptr<TokenLexer> CurTokenLexer; + + /// \brief The kind of lexer we're currently working with. + enum CurLexerKind { + CLK_Lexer, + CLK_PTHLexer, + CLK_TokenLexer, + CLK_CachingLexer, + CLK_LexAfterModuleImport + } CurLexerKind; + + /// \brief If the current lexer is for a submodule that is being built, this + /// is that submodule. + Module *CurSubmodule; + + /// \brief Keeps track of the stack of files currently + /// \#included, and macros currently being expanded from, not counting + /// CurLexer/CurTokenLexer. + struct IncludeStackInfo { + enum CurLexerKind CurLexerKind; + Module *TheSubmodule; + std::unique_ptr<Lexer> TheLexer; + std::unique_ptr<PTHLexer> ThePTHLexer; + PreprocessorLexer *ThePPLexer; + std::unique_ptr<TokenLexer> TheTokenLexer; + const DirectoryLookup *TheDirLookup; + + // The following constructors are completely useless copies of the default + // versions, only needed to pacify MSVC. + IncludeStackInfo(enum CurLexerKind CurLexerKind, Module *TheSubmodule, + std::unique_ptr<Lexer> &&TheLexer, + std::unique_ptr<PTHLexer> &&ThePTHLexer, + PreprocessorLexer *ThePPLexer, + std::unique_ptr<TokenLexer> &&TheTokenLexer, + const DirectoryLookup *TheDirLookup) + : CurLexerKind(std::move(CurLexerKind)), + TheSubmodule(std::move(TheSubmodule)), TheLexer(std::move(TheLexer)), + ThePTHLexer(std::move(ThePTHLexer)), + ThePPLexer(std::move(ThePPLexer)), + TheTokenLexer(std::move(TheTokenLexer)), + TheDirLookup(std::move(TheDirLookup)) {} + IncludeStackInfo(IncludeStackInfo &&RHS) + : CurLexerKind(std::move(RHS.CurLexerKind)), + TheSubmodule(std::move(RHS.TheSubmodule)), + TheLexer(std::move(RHS.TheLexer)), + ThePTHLexer(std::move(RHS.ThePTHLexer)), + ThePPLexer(std::move(RHS.ThePPLexer)), + TheTokenLexer(std::move(RHS.TheTokenLexer)), + TheDirLookup(std::move(RHS.TheDirLookup)) {} + }; + std::vector<IncludeStackInfo> IncludeMacroStack; + + /// \brief Actions invoked when some preprocessor activity is + /// encountered (e.g. a file is \#included, etc). + std::unique_ptr<PPCallbacks> Callbacks; + + struct MacroExpandsInfo { + Token Tok; + MacroDefinition MD; + SourceRange Range; + MacroExpandsInfo(Token Tok, MacroDefinition MD, SourceRange Range) + : Tok(Tok), MD(MD), Range(Range) { } + }; + SmallVector<MacroExpandsInfo, 2> DelayedMacroExpandsCallbacks; + + /// Information about a name that has been used to define a module macro. + struct ModuleMacroInfo { + ModuleMacroInfo(MacroDirective *MD) + : MD(MD), ActiveModuleMacrosGeneration(0), IsAmbiguous(false) {} + + /// The most recent macro directive for this identifier. + MacroDirective *MD; + /// The active module macros for this identifier. + llvm::TinyPtrVector<ModuleMacro*> ActiveModuleMacros; + /// The generation number at which we last updated ActiveModuleMacros. + /// \see Preprocessor::VisibleModules. + unsigned ActiveModuleMacrosGeneration; + /// Whether this macro name is ambiguous. + bool IsAmbiguous; + /// The module macros that are overridden by this macro. + llvm::TinyPtrVector<ModuleMacro*> OverriddenMacros; + }; + + /// The state of a macro for an identifier. + class MacroState { + mutable llvm::PointerUnion<MacroDirective *, ModuleMacroInfo *> State; + + ModuleMacroInfo *getModuleInfo(Preprocessor &PP, + const IdentifierInfo *II) const { + // FIXME: Find a spare bit on IdentifierInfo and store a + // HasModuleMacros flag. + if (!II->hasMacroDefinition() || + (!PP.getLangOpts().Modules && + !PP.getLangOpts().ModulesLocalVisibility) || + !PP.CurSubmoduleState->VisibleModules.getGeneration()) + return nullptr; + + auto *Info = State.dyn_cast<ModuleMacroInfo*>(); + if (!Info) { + Info = new (PP.getPreprocessorAllocator()) + ModuleMacroInfo(State.get<MacroDirective *>()); + State = Info; + } + + if (PP.CurSubmoduleState->VisibleModules.getGeneration() != + Info->ActiveModuleMacrosGeneration) + PP.updateModuleMacroInfo(II, *Info); + return Info; + } + + public: + MacroState() : MacroState(nullptr) {} + MacroState(MacroDirective *MD) : State(MD) {} + MacroState(MacroState &&O) LLVM_NOEXCEPT : State(O.State) { + O.State = (MacroDirective *)nullptr; + } + MacroState &operator=(MacroState &&O) LLVM_NOEXCEPT { + auto S = O.State; + O.State = (MacroDirective *)nullptr; + State = S; + return *this; + } + ~MacroState() { + if (auto *Info = State.dyn_cast<ModuleMacroInfo*>()) + Info->~ModuleMacroInfo(); + } + + MacroDirective *getLatest() const { + if (auto *Info = State.dyn_cast<ModuleMacroInfo*>()) + return Info->MD; + return State.get<MacroDirective*>(); + } + void setLatest(MacroDirective *MD) { + if (auto *Info = State.dyn_cast<ModuleMacroInfo*>()) + Info->MD = MD; + else + State = MD; + } + + bool isAmbiguous(Preprocessor &PP, const IdentifierInfo *II) const { + auto *Info = getModuleInfo(PP, II); + return Info ? Info->IsAmbiguous : false; + } + ArrayRef<ModuleMacro *> + getActiveModuleMacros(Preprocessor &PP, const IdentifierInfo *II) const { + if (auto *Info = getModuleInfo(PP, II)) + return Info->ActiveModuleMacros; + return None; + } + + MacroDirective::DefInfo findDirectiveAtLoc(SourceLocation Loc, + SourceManager &SourceMgr) const { + // FIXME: Incorporate module macros into the result of this. + if (auto *Latest = getLatest()) + return Latest->findDirectiveAtLoc(Loc, SourceMgr); + return MacroDirective::DefInfo(); + } + + void overrideActiveModuleMacros(Preprocessor &PP, IdentifierInfo *II) { + if (auto *Info = getModuleInfo(PP, II)) { + Info->OverriddenMacros.insert(Info->OverriddenMacros.end(), + Info->ActiveModuleMacros.begin(), + Info->ActiveModuleMacros.end()); + Info->ActiveModuleMacros.clear(); + Info->IsAmbiguous = false; + } + } + ArrayRef<ModuleMacro*> getOverriddenMacros() const { + if (auto *Info = State.dyn_cast<ModuleMacroInfo*>()) + return Info->OverriddenMacros; + return None; + } + void setOverriddenMacros(Preprocessor &PP, + ArrayRef<ModuleMacro *> Overrides) { + auto *Info = State.dyn_cast<ModuleMacroInfo*>(); + if (!Info) { + if (Overrides.empty()) + return; + Info = new (PP.getPreprocessorAllocator()) + ModuleMacroInfo(State.get<MacroDirective *>()); + State = Info; + } + Info->OverriddenMacros.clear(); + Info->OverriddenMacros.insert(Info->OverriddenMacros.end(), + Overrides.begin(), Overrides.end()); + Info->ActiveModuleMacrosGeneration = 0; + } + }; + + /// For each IdentifierInfo that was associated with a macro, we + /// keep a mapping to the history of all macro definitions and #undefs in + /// the reverse order (the latest one is in the head of the list). + /// + /// This mapping lives within the \p CurSubmoduleState. + typedef llvm::DenseMap<const IdentifierInfo *, MacroState> MacroMap; + + friend class ASTReader; + + struct SubmoduleState; + + /// \brief Information about a submodule that we're currently building. + struct BuildingSubmoduleInfo { + BuildingSubmoduleInfo(Module *M, SourceLocation ImportLoc, + SubmoduleState *OuterSubmoduleState) + : M(M), ImportLoc(ImportLoc), OuterSubmoduleState(OuterSubmoduleState) { + } + + /// The module that we are building. + Module *M; + /// The location at which the module was included. + SourceLocation ImportLoc; + /// The previous SubmoduleState. + SubmoduleState *OuterSubmoduleState; + }; + SmallVector<BuildingSubmoduleInfo, 8> BuildingSubmoduleStack; + + /// \brief Information about a submodule's preprocessor state. + struct SubmoduleState { + /// The macros for the submodule. + MacroMap Macros; + /// The set of modules that are visible within the submodule. + VisibleModuleSet VisibleModules; + // FIXME: CounterValue? + // FIXME: PragmaPushMacroInfo? + }; + std::map<Module*, SubmoduleState> Submodules; + + /// The preprocessor state for preprocessing outside of any submodule. + SubmoduleState NullSubmoduleState; + + /// The current submodule state. Will be \p NullSubmoduleState if we're not + /// in a submodule. + SubmoduleState *CurSubmoduleState; + + /// The set of known macros exported from modules. + llvm::FoldingSet<ModuleMacro> ModuleMacros; + + /// The list of module macros, for each identifier, that are not overridden by + /// any other module macro. + llvm::DenseMap<const IdentifierInfo *, llvm::TinyPtrVector<ModuleMacro*>> + LeafModuleMacros; + + /// \brief Macros that we want to warn because they are not used at the end + /// of the translation unit. + /// + /// We store just their SourceLocations instead of + /// something like MacroInfo*. The benefit of this is that when we are + /// deserializing from PCH, we don't need to deserialize identifier & macros + /// just so that we can report that they are unused, we just warn using + /// the SourceLocations of this set (that will be filled by the ASTReader). + /// We are using SmallPtrSet instead of a vector for faster removal. + typedef llvm::SmallPtrSet<SourceLocation, 32> WarnUnusedMacroLocsTy; + WarnUnusedMacroLocsTy WarnUnusedMacroLocs; + + /// \brief A "freelist" of MacroArg objects that can be + /// reused for quick allocation. + MacroArgs *MacroArgCache; + friend class MacroArgs; + + /// For each IdentifierInfo used in a \#pragma push_macro directive, + /// we keep a MacroInfo stack used to restore the previous macro value. + llvm::DenseMap<IdentifierInfo*, std::vector<MacroInfo*> > PragmaPushMacroInfo; + + // Various statistics we track for performance analysis. + unsigned NumDirectives, NumDefined, NumUndefined, NumPragma; + unsigned NumIf, NumElse, NumEndif; + unsigned NumEnteredSourceFiles, MaxIncludeStackDepth; + unsigned NumMacroExpanded, NumFnMacroExpanded, NumBuiltinMacroExpanded; + unsigned NumFastMacroExpanded, NumTokenPaste, NumFastTokenPaste; + unsigned NumSkipped; + + /// \brief The predefined macros that preprocessor should use from the + /// command line etc. + std::string Predefines; + + /// \brief The file ID for the preprocessor predefines. + FileID PredefinesFileID; + + /// \{ + /// \brief Cache of macro expanders to reduce malloc traffic. + enum { TokenLexerCacheSize = 8 }; + unsigned NumCachedTokenLexers; + std::unique_ptr<TokenLexer> TokenLexerCache[TokenLexerCacheSize]; + /// \} + + /// \brief Keeps macro expanded tokens for TokenLexers. + // + /// Works like a stack; a TokenLexer adds the macro expanded tokens that is + /// going to lex in the cache and when it finishes the tokens are removed + /// from the end of the cache. + SmallVector<Token, 16> MacroExpandedTokens; + std::vector<std::pair<TokenLexer *, size_t> > MacroExpandingLexersStack; + + /// \brief A record of the macro definitions and expansions that + /// occurred during preprocessing. + /// + /// This is an optional side structure that can be enabled with + /// \c createPreprocessingRecord() prior to preprocessing. + PreprocessingRecord *Record; + + /// Cached tokens state. + typedef SmallVector<Token, 1> CachedTokensTy; + + /// \brief Cached tokens are stored here when we do backtracking or + /// lookahead. They are "lexed" by the CachingLex() method. + CachedTokensTy CachedTokens; + + /// \brief The position of the cached token that CachingLex() should + /// "lex" next. + /// + /// If it points beyond the CachedTokens vector, it means that a normal + /// Lex() should be invoked. + CachedTokensTy::size_type CachedLexPos; + + /// \brief Stack of backtrack positions, allowing nested backtracks. + /// + /// The EnableBacktrackAtThisPos() method pushes a position to + /// indicate where CachedLexPos should be set when the BackTrack() method is + /// invoked (at which point the last position is popped). + std::vector<CachedTokensTy::size_type> BacktrackPositions; + + struct MacroInfoChain { + MacroInfo MI; + MacroInfoChain *Next; + }; + + /// MacroInfos are managed as a chain for easy disposal. This is the head + /// of that list. + MacroInfoChain *MIChainHead; + + struct DeserializedMacroInfoChain { + MacroInfo MI; + unsigned OwningModuleID; // MUST be immediately after the MacroInfo object + // so it can be accessed by MacroInfo::getOwningModuleID(). + DeserializedMacroInfoChain *Next; + }; + DeserializedMacroInfoChain *DeserialMIChainHead; + +public: + Preprocessor(IntrusiveRefCntPtr<PreprocessorOptions> PPOpts, + DiagnosticsEngine &diags, LangOptions &opts, + SourceManager &SM, HeaderSearch &Headers, + ModuleLoader &TheModuleLoader, + IdentifierInfoLookup *IILookup = nullptr, + bool OwnsHeaderSearch = false, + TranslationUnitKind TUKind = TU_Complete); + + ~Preprocessor(); + + /// \brief Initialize the preprocessor using information about the target. + /// + /// \param Target is owned by the caller and must remain valid for the + /// lifetime of the preprocessor. + /// \param AuxTarget is owned by the caller and must remain valid for + /// the lifetime of the preprocessor. + void Initialize(const TargetInfo &Target, + const TargetInfo *AuxTarget = nullptr); + + /// \brief Initialize the preprocessor to parse a model file + /// + /// To parse model files the preprocessor of the original source is reused to + /// preserver the identifier table. However to avoid some duplicate + /// information in the preprocessor some cleanup is needed before it is used + /// to parse model files. This method does that cleanup. + void InitializeForModelFile(); + + /// \brief Cleanup after model file parsing + void FinalizeForModelFile(); + + /// \brief Retrieve the preprocessor options used to initialize this + /// preprocessor. + PreprocessorOptions &getPreprocessorOpts() const { return *PPOpts; } + + DiagnosticsEngine &getDiagnostics() const { return *Diags; } + void setDiagnostics(DiagnosticsEngine &D) { Diags = &D; } + + const LangOptions &getLangOpts() const { return LangOpts; } + const TargetInfo &getTargetInfo() const { return *Target; } + const TargetInfo *getAuxTargetInfo() const { return AuxTarget; } + FileManager &getFileManager() const { return FileMgr; } + SourceManager &getSourceManager() const { return SourceMgr; } + HeaderSearch &getHeaderSearchInfo() const { return HeaderInfo; } + + IdentifierTable &getIdentifierTable() { return Identifiers; } + const IdentifierTable &getIdentifierTable() const { return Identifiers; } + SelectorTable &getSelectorTable() { return Selectors; } + Builtin::Context &getBuiltinInfo() { return BuiltinInfo; } + llvm::BumpPtrAllocator &getPreprocessorAllocator() { return BP; } + + void setPTHManager(PTHManager* pm); + + PTHManager *getPTHManager() { return PTH.get(); } + + void setExternalSource(ExternalPreprocessorSource *Source) { + ExternalSource = Source; + } + + ExternalPreprocessorSource *getExternalSource() const { + return ExternalSource; + } + + /// \brief Retrieve the module loader associated with this preprocessor. + ModuleLoader &getModuleLoader() const { return TheModuleLoader; } + + bool hadModuleLoaderFatalFailure() const { + return TheModuleLoader.HadFatalFailure; + } + + /// \brief True if we are currently preprocessing a #if or #elif directive + bool isParsingIfOrElifDirective() const { + return ParsingIfOrElifDirective; + } + + /// \brief Control whether the preprocessor retains comments in output. + void SetCommentRetentionState(bool KeepComments, bool KeepMacroComments) { + this->KeepComments = KeepComments | KeepMacroComments; + this->KeepMacroComments = KeepMacroComments; + } + + bool getCommentRetentionState() const { return KeepComments; } + + void setPragmasEnabled(bool Enabled) { PragmasEnabled = Enabled; } + bool getPragmasEnabled() const { return PragmasEnabled; } + + void SetSuppressIncludeNotFoundError(bool Suppress) { + SuppressIncludeNotFoundError = Suppress; + } + + bool GetSuppressIncludeNotFoundError() { + return SuppressIncludeNotFoundError; + } + + /// Sets whether the preprocessor is responsible for producing output or if + /// it is producing tokens to be consumed by Parse and Sema. + void setPreprocessedOutput(bool IsPreprocessedOutput) { + PreprocessedOutput = IsPreprocessedOutput; + } + + /// Returns true if the preprocessor is responsible for generating output, + /// false if it is producing tokens to be consumed by Parse and Sema. + bool isPreprocessedOutput() const { return PreprocessedOutput; } + + /// \brief Return true if we are lexing directly from the specified lexer. + bool isCurrentLexer(const PreprocessorLexer *L) const { + return CurPPLexer == L; + } + + /// \brief 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; } + + /// \brief 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; + + /// \brief Return the submodule owning the file being lexed. + Module *getCurrentSubmodule() const { return CurSubmodule; } + + /// \brief Returns the FileID for the preprocessor predefines. + FileID getPredefinesFileID() const { return PredefinesFileID; } + + /// \{ + /// \brief Accessors for preprocessor callbacks. + /// + /// Note that this class takes ownership of any PPCallbacks object given to + /// it. + PPCallbacks *getPPCallbacks() const { return Callbacks.get(); } + void addPPCallbacks(std::unique_ptr<PPCallbacks> C) { + if (Callbacks) + C = llvm::make_unique<PPChainedCallbacks>(std::move(C), + std::move(Callbacks)); + Callbacks = std::move(C); + } + /// \} + + bool isMacroDefined(StringRef Id) { + return isMacroDefined(&Identifiers.get(Id)); + } + bool isMacroDefined(const IdentifierInfo *II) { + return II->hasMacroDefinition() && + (!getLangOpts().Modules || (bool)getMacroDefinition(II)); + } + + /// \brief Determine whether II is defined as a macro within the module M, + /// if that is a module that we've already preprocessed. Does not check for + /// macros imported into M. + bool isMacroDefinedInLocalModule(const IdentifierInfo *II, Module *M) { + if (!II->hasMacroDefinition()) + return false; + auto I = Submodules.find(M); + if (I == Submodules.end()) + return false; + auto J = I->second.Macros.find(II); + if (J == I->second.Macros.end()) + return false; + auto *MD = J->second.getLatest(); + return MD && MD->isDefined(); + } + + MacroDefinition getMacroDefinition(const IdentifierInfo *II) { + if (!II->hasMacroDefinition()) + return MacroDefinition(); + + MacroState &S = CurSubmoduleState->Macros[II]; + auto *MD = S.getLatest(); + while (MD && isa<VisibilityMacroDirective>(MD)) + MD = MD->getPrevious(); + return MacroDefinition(dyn_cast_or_null<DefMacroDirective>(MD), + S.getActiveModuleMacros(*this, II), + S.isAmbiguous(*this, II)); + } + + MacroDefinition getMacroDefinitionAtLoc(const IdentifierInfo *II, + SourceLocation Loc) { + if (!II->hadMacroDefinition()) + return MacroDefinition(); + + MacroState &S = CurSubmoduleState->Macros[II]; + MacroDirective::DefInfo DI; + if (auto *MD = S.getLatest()) + DI = MD->findDirectiveAtLoc(Loc, getSourceManager()); + // FIXME: Compute the set of active module macros at the specified location. + return MacroDefinition(DI.getDirective(), + S.getActiveModuleMacros(*this, II), + S.isAmbiguous(*this, II)); + } + + /// \brief Given an identifier, return its latest non-imported MacroDirective + /// if it is \#define'd and not \#undef'd, or null if it isn't \#define'd. + MacroDirective *getLocalMacroDirective(const IdentifierInfo *II) const { + if (!II->hasMacroDefinition()) + return nullptr; + + auto *MD = getLocalMacroDirectiveHistory(II); + if (!MD || MD->getDefinition().isUndefined()) + return nullptr; + + return MD; + } + + const MacroInfo *getMacroInfo(const IdentifierInfo *II) const { + return const_cast<Preprocessor*>(this)->getMacroInfo(II); + } + + MacroInfo *getMacroInfo(const IdentifierInfo *II) { + if (!II->hasMacroDefinition()) + return nullptr; + if (auto MD = getMacroDefinition(II)) + return MD.getMacroInfo(); + return nullptr; + } + + /// \brief Given an identifier, return the latest non-imported macro + /// directive for that identifier. + /// + /// One can iterate over all previous macro directives from the most recent + /// one. + MacroDirective *getLocalMacroDirectiveHistory(const IdentifierInfo *II) const; + + /// \brief Add a directive to the macro directive history for this identifier. + void appendMacroDirective(IdentifierInfo *II, MacroDirective *MD); + DefMacroDirective *appendDefMacroDirective(IdentifierInfo *II, MacroInfo *MI, + SourceLocation Loc) { + DefMacroDirective *MD = AllocateDefMacroDirective(MI, Loc); + appendMacroDirective(II, MD); + return MD; + } + DefMacroDirective *appendDefMacroDirective(IdentifierInfo *II, + MacroInfo *MI) { + return appendDefMacroDirective(II, MI, MI->getDefinitionLoc()); + } + /// \brief Set a MacroDirective that was loaded from a PCH file. + void setLoadedMacroDirective(IdentifierInfo *II, MacroDirective *MD); + + /// \brief Register an exported macro for a module and identifier. + ModuleMacro *addModuleMacro(Module *Mod, IdentifierInfo *II, MacroInfo *Macro, + ArrayRef<ModuleMacro *> Overrides, bool &IsNew); + ModuleMacro *getModuleMacro(Module *Mod, IdentifierInfo *II); + + /// \brief Get the list of leaf (non-overridden) module macros for a name. + ArrayRef<ModuleMacro*> getLeafModuleMacros(const IdentifierInfo *II) const { + auto I = LeafModuleMacros.find(II); + if (I != LeafModuleMacros.end()) + return I->second; + return None; + } + + /// \{ + /// Iterators for the macro history table. Currently defined macros have + /// IdentifierInfo::hasMacroDefinition() set and an empty + /// MacroInfo::getUndefLoc() at the head of the list. + typedef MacroMap::const_iterator macro_iterator; + macro_iterator macro_begin(bool IncludeExternalMacros = true) const; + macro_iterator macro_end(bool IncludeExternalMacros = true) const; + llvm::iterator_range<macro_iterator> + macros(bool IncludeExternalMacros = true) const { + return llvm::make_range(macro_begin(IncludeExternalMacros), + macro_end(IncludeExternalMacros)); + } + /// \} + + /// \brief Return the name of the macro defined before \p Loc that has + /// spelling \p Tokens. If there are multiple macros with same spelling, + /// return the last one defined. + StringRef getLastMacroWithSpelling(SourceLocation Loc, + ArrayRef<TokenValue> Tokens) const; + + const std::string &getPredefines() const { return Predefines; } + /// \brief Set the predefines for this Preprocessor. + /// + /// These predefines are automatically injected when parsing the main file. + void setPredefines(const char *P) { Predefines = P; } + void setPredefines(StringRef P) { Predefines = P; } + + /// Return information about the specified preprocessor + /// identifier token. + IdentifierInfo *getIdentifierInfo(StringRef Name) const { + return &Identifiers.get(Name); + } + + /// \brief Add the specified pragma handler to this preprocessor. + /// + /// If \p Namespace is non-null, then it is a token required to exist on the + /// pragma line before the pragma string starts, e.g. "STDC" or "GCC". + void AddPragmaHandler(StringRef Namespace, PragmaHandler *Handler); + void AddPragmaHandler(PragmaHandler *Handler) { + AddPragmaHandler(StringRef(), Handler); + } + + /// \brief Remove the specific pragma handler from this preprocessor. + /// + /// If \p Namespace is non-null, then it should be the namespace that + /// \p Handler was added to. It is an error to remove a handler that + /// has not been registered. + void RemovePragmaHandler(StringRef Namespace, PragmaHandler *Handler); + void RemovePragmaHandler(PragmaHandler *Handler) { + RemovePragmaHandler(StringRef(), Handler); + } + + /// Install empty handlers for all pragmas (making them ignored). + void IgnorePragmas(); + + /// \brief Add the specified comment handler to the preprocessor. + void addCommentHandler(CommentHandler *Handler); + + /// \brief Remove the specified comment handler. + /// + /// It is an error to remove a handler that has not been registered. + void removeCommentHandler(CommentHandler *Handler); + + /// \brief Set the code completion handler to the given object. + void setCodeCompletionHandler(CodeCompletionHandler &Handler) { + CodeComplete = &Handler; + } + + /// \brief Retrieve the current code-completion handler. + CodeCompletionHandler *getCodeCompletionHandler() const { + return CodeComplete; + } + + /// \brief Clear out the code completion handler. + void clearCodeCompletionHandler() { + CodeComplete = nullptr; + } + + /// \brief Hook used by the lexer to invoke the "natural language" code + /// completion point. + void CodeCompleteNaturalLanguage(); + + /// \brief Retrieve the preprocessing record, or NULL if there is no + /// preprocessing record. + PreprocessingRecord *getPreprocessingRecord() const { return Record; } + + /// \brief Create a new preprocessing record, which will keep track of + /// all macro expansions, macro definitions, etc. + void createPreprocessingRecord(); + + /// \brief Enter the specified FileID as the main source file, + /// which implicitly adds the builtin defines etc. + void EnterMainSourceFile(); + + /// \brief Inform the preprocessor callbacks that processing is complete. + void EndSourceFile(); + + /// \brief Add a source file to the top of the include stack and + /// start lexing tokens from it instead of the current buffer. + /// + /// Emits a diagnostic, doesn't enter the file, and returns true on error. + bool EnterSourceFile(FileID CurFileID, const DirectoryLookup *Dir, + SourceLocation Loc); + + /// \brief Add a Macro to the top of the include stack and start lexing + /// tokens from it instead of the current buffer. + /// + /// \param Args specifies the tokens input to a function-like macro. + /// \param ILEnd specifies the location of the ')' for a function-like macro + /// or the identifier for an object-like macro. + void EnterMacro(Token &Identifier, SourceLocation ILEnd, MacroInfo *Macro, + MacroArgs *Args); + + /// \brief Add a "macro" context to the top of the include stack, + /// which will cause the lexer to start returning the specified tokens. + /// + /// If \p DisableMacroExpansion is true, tokens lexed from the token stream + /// will not be subject to further macro expansion. Otherwise, these tokens + /// will be re-macro-expanded when/if expansion is enabled. + /// + /// If \p OwnsTokens is false, this method assumes that the specified stream + /// of tokens has a permanent owner somewhere, so they do not need to be + /// copied. If it is true, it assumes the array of tokens is allocated with + /// \c new[] and must be freed. + void EnterTokenStream(const Token *Toks, unsigned NumToks, + bool DisableMacroExpansion, bool OwnsTokens); + + /// \brief Pop the current lexer/macro exp off the top of the lexer stack. + /// + /// This should only be used in situations where the current state of the + /// top-of-stack lexer is known. + void RemoveTopOfLexerStack(); + + /// From the point that this method is called, and until + /// CommitBacktrackedTokens() or Backtrack() is called, the Preprocessor + /// keeps track of the lexed tokens so that a subsequent Backtrack() call will + /// make the Preprocessor re-lex the same tokens. + /// + /// Nested backtracks are allowed, meaning that EnableBacktrackAtThisPos can + /// be called multiple times and CommitBacktrackedTokens/Backtrack calls will + /// be combined with the EnableBacktrackAtThisPos calls in reverse order. + /// + /// NOTE: *DO NOT* forget to call either CommitBacktrackedTokens or Backtrack + /// at some point after EnableBacktrackAtThisPos. If you don't, caching of + /// tokens will continue indefinitely. + /// + void EnableBacktrackAtThisPos(); + + /// \brief Disable the last EnableBacktrackAtThisPos call. + void CommitBacktrackedTokens(); + + /// \brief Make Preprocessor re-lex the tokens that were lexed since + /// EnableBacktrackAtThisPos() was previously called. + void Backtrack(); + + /// \brief True if EnableBacktrackAtThisPos() was called and + /// caching of tokens is on. + bool isBacktrackEnabled() const { return !BacktrackPositions.empty(); } + + /// \brief Lex the next token for this preprocessor. + void Lex(Token &Result); + + void LexAfterModuleImport(Token &Result); + + void makeModuleVisible(Module *M, SourceLocation Loc); + + SourceLocation getModuleImportLoc(Module *M) const { + return CurSubmoduleState->VisibleModules.getImportLoc(M); + } + + /// \brief Lex a string literal, which may be the concatenation of multiple + /// string literals and may even come from macro expansion. + /// \returns true on success, false if a error diagnostic has been generated. + bool LexStringLiteral(Token &Result, std::string &String, + const char *DiagnosticTag, bool AllowMacroExpansion) { + if (AllowMacroExpansion) + Lex(Result); + else + LexUnexpandedToken(Result); + return FinishLexStringLiteral(Result, String, DiagnosticTag, + AllowMacroExpansion); + } + + /// \brief Complete the lexing of a string literal where the first token has + /// already been lexed (see LexStringLiteral). + bool FinishLexStringLiteral(Token &Result, std::string &String, + const char *DiagnosticTag, + bool AllowMacroExpansion); + + /// \brief Lex a token. If it's a comment, keep lexing until we get + /// something not a comment. + /// + /// This is useful in -E -C mode where comments would foul up preprocessor + /// directive handling. + void LexNonComment(Token &Result) { + do + Lex(Result); + while (Result.getKind() == tok::comment); + } + + /// \brief Just like Lex, but disables macro expansion of identifier tokens. + void LexUnexpandedToken(Token &Result) { + // Disable macro expansion. + bool OldVal = DisableMacroExpansion; + DisableMacroExpansion = true; + // Lex the token. + Lex(Result); + + // Reenable it. + DisableMacroExpansion = OldVal; + } + + /// \brief Like LexNonComment, but this disables macro expansion of + /// identifier tokens. + void LexUnexpandedNonComment(Token &Result) { + do + LexUnexpandedToken(Result); + while (Result.getKind() == tok::comment); + } + + /// \brief Parses a simple integer literal to get its numeric value. Floating + /// point literals and user defined literals are rejected. Used primarily to + /// handle pragmas that accept integer arguments. + bool parseSimpleIntegerLiteral(Token &Tok, uint64_t &Value); + + /// Disables macro expansion everywhere except for preprocessor directives. + void SetMacroExpansionOnlyInDirectives() { + DisableMacroExpansion = true; + MacroExpansionInDirectivesOverride = true; + } + + /// \brief Peeks ahead N tokens and returns that token without consuming any + /// tokens. + /// + /// LookAhead(0) returns the next token that would be returned by Lex(), + /// LookAhead(1) returns the token after it, etc. This returns normal + /// tokens after phase 5. As such, it is equivalent to using + /// 'Lex', not 'LexUnexpandedToken'. + const Token &LookAhead(unsigned N) { + if (CachedLexPos + N < CachedTokens.size()) + return CachedTokens[CachedLexPos+N]; + else + return PeekAhead(N+1); + } + + /// \brief When backtracking is enabled and tokens are cached, + /// this allows to revert a specific number of tokens. + /// + /// Note that the number of tokens being reverted should be up to the last + /// backtrack position, not more. + void RevertCachedTokens(unsigned N) { + assert(isBacktrackEnabled() && + "Should only be called when tokens are cached for backtracking"); + assert(signed(CachedLexPos) - signed(N) >= signed(BacktrackPositions.back()) + && "Should revert tokens up to the last backtrack position, not more"); + assert(signed(CachedLexPos) - signed(N) >= 0 && + "Corrupted backtrack positions ?"); + CachedLexPos -= N; + } + + /// \brief Enters a token in the token stream to be lexed next. + /// + /// If BackTrack() is called afterwards, the token will remain at the + /// insertion point. + void EnterToken(const Token &Tok) { + EnterCachingLexMode(); + CachedTokens.insert(CachedTokens.begin()+CachedLexPos, Tok); + } + + /// We notify the Preprocessor that if it is caching tokens (because + /// backtrack is enabled) it should replace the most recent cached tokens + /// with the given annotation token. This function has no effect if + /// backtracking is not enabled. + /// + /// Note that the use of this function is just for optimization, so that the + /// cached tokens doesn't get re-parsed and re-resolved after a backtrack is + /// invoked. + void AnnotateCachedTokens(const Token &Tok) { + assert(Tok.isAnnotation() && "Expected annotation token"); + if (CachedLexPos != 0 && isBacktrackEnabled()) + AnnotatePreviousCachedTokens(Tok); + } + + /// Get the location of the last cached token, suitable for setting the end + /// location of an annotation token. + SourceLocation getLastCachedTokenLocation() const { + assert(CachedLexPos != 0); + return CachedTokens[CachedLexPos-1].getLastLoc(); + } + + /// \brief Replace the last token with an annotation token. + /// + /// Like AnnotateCachedTokens(), this routine replaces an + /// already-parsed (and resolved) token with an annotation + /// token. However, this routine only replaces the last token with + /// the annotation token; it does not affect any other cached + /// tokens. This function has no effect if backtracking is not + /// enabled. + void ReplaceLastTokenWithAnnotation(const Token &Tok) { + assert(Tok.isAnnotation() && "Expected annotation token"); + if (CachedLexPos != 0 && isBacktrackEnabled()) + CachedTokens[CachedLexPos-1] = Tok; + } + + /// Update the current token to represent the provided + /// identifier, in order to cache an action performed by typo correction. + void TypoCorrectToken(const Token &Tok) { + assert(Tok.getIdentifierInfo() && "Expected identifier token"); + if (CachedLexPos != 0 && isBacktrackEnabled()) + CachedTokens[CachedLexPos-1] = Tok; + } + + /// \brief Recompute the current lexer kind based on the CurLexer/CurPTHLexer/ + /// CurTokenLexer pointers. + void recomputeCurLexerKind(); + + /// \brief Returns true if incremental processing is enabled + bool isIncrementalProcessingEnabled() const { return IncrementalProcessing; } + + /// \brief Enables the incremental processing + void enableIncrementalProcessing(bool value = true) { + IncrementalProcessing = value; + } + + /// \brief Specify the point at which code-completion will be performed. + /// + /// \param File the file in which code completion should occur. If + /// this file is included multiple times, code-completion will + /// perform completion the first time it is included. If NULL, this + /// function clears out the code-completion point. + /// + /// \param Line the line at which code completion should occur + /// (1-based). + /// + /// \param Column the column at which code completion should occur + /// (1-based). + /// + /// \returns true if an error occurred, false otherwise. + bool SetCodeCompletionPoint(const FileEntry *File, + unsigned Line, unsigned Column); + + /// \brief Determine if we are performing code completion. + bool isCodeCompletionEnabled() const { return CodeCompletionFile != nullptr; } + + /// \brief Returns the location of the code-completion point. + /// + /// Returns an invalid location if code-completion is not enabled or the file + /// containing the code-completion point has not been lexed yet. + SourceLocation getCodeCompletionLoc() const { return CodeCompletionLoc; } + + /// \brief Returns the start location of the file of code-completion point. + /// + /// Returns an invalid location if code-completion is not enabled or the file + /// containing the code-completion point has not been lexed yet. + SourceLocation getCodeCompletionFileLoc() const { + return CodeCompletionFileLoc; + } + + /// \brief Returns true if code-completion is enabled and we have hit the + /// code-completion point. + bool isCodeCompletionReached() const { return CodeCompletionReached; } + + /// \brief Note that we hit the code-completion point. + void setCodeCompletionReached() { + assert(isCodeCompletionEnabled() && "Code-completion not enabled!"); + CodeCompletionReached = true; + // Silence any diagnostics that occur after we hit the code-completion. + getDiagnostics().setSuppressAllDiagnostics(true); + } + + /// \brief The location of the currently-active \#pragma clang + /// arc_cf_code_audited begin. + /// + /// Returns an invalid location if there is no such pragma active. + SourceLocation getPragmaARCCFCodeAuditedLoc() const { + return PragmaARCCFCodeAuditedLoc; + } + + /// \brief Set the location of the currently-active \#pragma clang + /// arc_cf_code_audited begin. An invalid location ends the pragma. + void setPragmaARCCFCodeAuditedLoc(SourceLocation Loc) { + PragmaARCCFCodeAuditedLoc = Loc; + } + + /// \brief The location of the currently-active \#pragma clang + /// assume_nonnull begin. + /// + /// Returns an invalid location if there is no such pragma active. + SourceLocation getPragmaAssumeNonNullLoc() const { + return PragmaAssumeNonNullLoc; + } + + /// \brief Set the location of the currently-active \#pragma clang + /// assume_nonnull begin. An invalid location ends the pragma. + void setPragmaAssumeNonNullLoc(SourceLocation Loc) { + PragmaAssumeNonNullLoc = Loc; + } + + /// \brief Set the directory in which the main file should be considered + /// to have been found, if it is not a real file. + void setMainFileDir(const DirectoryEntry *Dir) { + MainFileDir = Dir; + } + + /// \brief Instruct the preprocessor to skip part of the main source file. + /// + /// \param Bytes The number of bytes in the preamble to skip. + /// + /// \param StartOfLine Whether skipping these bytes puts the lexer at the + /// start of a line. + void setSkipMainFilePreamble(unsigned Bytes, bool StartOfLine) { + SkipMainFilePreamble.first = Bytes; + SkipMainFilePreamble.second = StartOfLine; + } + + /// Forwarding function for diagnostics. This emits a diagnostic at + /// the specified Token's location, translating the token's start + /// position in the current buffer into a SourcePosition object for rendering. + DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) const { + return Diags->Report(Loc, DiagID); + } + + DiagnosticBuilder Diag(const Token &Tok, unsigned DiagID) const { + return Diags->Report(Tok.getLocation(), DiagID); + } + + /// Return the 'spelling' of the token at the given + /// location; does not go up to the spelling location or down to the + /// expansion location. + /// + /// \param buffer A buffer which will be used only if the token requires + /// "cleaning", e.g. if it contains trigraphs or escaped newlines + /// \param invalid If non-null, will be set \c true if an error occurs. + StringRef getSpelling(SourceLocation loc, + SmallVectorImpl<char> &buffer, + bool *invalid = nullptr) const { + return Lexer::getSpelling(loc, buffer, SourceMgr, LangOpts, invalid); + } + + /// \brief Return the 'spelling' of the Tok token. + /// + /// The spelling of a token is the characters used to represent the token in + /// the source file after trigraph expansion and escaped-newline folding. In + /// particular, this wants to get the true, uncanonicalized, spelling of + /// things like digraphs, UCNs, etc. + /// + /// \param Invalid If non-null, will be set \c true if an error occurs. + std::string getSpelling(const Token &Tok, bool *Invalid = nullptr) const { + return Lexer::getSpelling(Tok, SourceMgr, LangOpts, Invalid); + } + + /// \brief Get the spelling of a token into a preallocated buffer, instead + /// of as an std::string. + /// + /// The caller is required to allocate enough space for the token, which is + /// guaranteed to be at least Tok.getLength() bytes long. The length of the + /// actual result is returned. + /// + /// Note that this method may do two possible things: it may either fill in + /// the buffer specified with characters, or it may *change the input pointer* + /// to point to a constant buffer with the data already in it (avoiding a + /// copy). The caller is not allowed to modify the returned buffer pointer + /// if an internal buffer is returned. + unsigned getSpelling(const Token &Tok, const char *&Buffer, + bool *Invalid = nullptr) const { + return Lexer::getSpelling(Tok, Buffer, SourceMgr, LangOpts, Invalid); + } + + /// \brief Get the spelling of a token into a SmallVector. + /// + /// Note that the returned StringRef may not point to the + /// supplied buffer if a copy can be avoided. + StringRef getSpelling(const Token &Tok, + SmallVectorImpl<char> &Buffer, + bool *Invalid = nullptr) const; + + /// \brief Relex the token at the specified location. + /// \returns true if there was a failure, false on success. + bool getRawToken(SourceLocation Loc, Token &Result, + bool IgnoreWhiteSpace = false) { + return Lexer::getRawToken(Loc, Result, SourceMgr, LangOpts, IgnoreWhiteSpace); + } + + /// \brief Given a Token \p Tok that is a numeric constant with length 1, + /// return the character. + char + getSpellingOfSingleCharacterNumericConstant(const Token &Tok, + bool *Invalid = nullptr) const { + assert(Tok.is(tok::numeric_constant) && + Tok.getLength() == 1 && "Called on unsupported token"); + assert(!Tok.needsCleaning() && "Token can't need cleaning with length 1"); + + // If the token is carrying a literal data pointer, just use it. + if (const char *D = Tok.getLiteralData()) + return *D; + + // Otherwise, fall back on getCharacterData, which is slower, but always + // works. + return *SourceMgr.getCharacterData(Tok.getLocation(), Invalid); + } + + /// \brief Retrieve the name of the immediate macro expansion. + /// + /// This routine starts from a source location, and finds the name of the + /// macro responsible for its immediate expansion. It looks through any + /// intervening macro argument expansions to compute this. It returns a + /// StringRef that refers to the SourceManager-owned buffer of the source + /// where that macro name is spelled. Thus, the result shouldn't out-live + /// the SourceManager. + StringRef getImmediateMacroName(SourceLocation Loc) { + return Lexer::getImmediateMacroName(Loc, SourceMgr, getLangOpts()); + } + + /// \brief Plop the specified string into a scratch buffer and set the + /// specified token's location and length to it. + /// + /// If specified, the source location provides a location of the expansion + /// point of the token. + void CreateString(StringRef Str, Token &Tok, + SourceLocation ExpansionLocStart = SourceLocation(), + SourceLocation ExpansionLocEnd = SourceLocation()); + + /// \brief Computes the source location just past the end of the + /// token at this source location. + /// + /// This routine can be used to produce a source location that + /// points just past the end of the token referenced by \p Loc, and + /// is generally used when a diagnostic needs to point just after a + /// token where it expected something different that it received. If + /// the returned source location would not be meaningful (e.g., if + /// it points into a macro), this routine returns an invalid + /// source location. + /// + /// \param Offset an offset from the end of the token, where the source + /// location should refer to. The default offset (0) produces a source + /// location pointing just past the end of the token; an offset of 1 produces + /// a source location pointing to the last character in the token, etc. + SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset = 0) { + return Lexer::getLocForEndOfToken(Loc, Offset, SourceMgr, LangOpts); + } + + /// \brief Returns true if the given MacroID location points at the first + /// token of the macro expansion. + /// + /// \param MacroBegin If non-null and function returns true, it is set to + /// begin location of the macro. + bool isAtStartOfMacroExpansion(SourceLocation loc, + SourceLocation *MacroBegin = nullptr) const { + return Lexer::isAtStartOfMacroExpansion(loc, SourceMgr, LangOpts, + MacroBegin); + } + + /// \brief Returns true if the given MacroID location points at the last + /// token of the macro expansion. + /// + /// \param MacroEnd If non-null and function returns true, it is set to + /// end location of the macro. + bool isAtEndOfMacroExpansion(SourceLocation loc, + SourceLocation *MacroEnd = nullptr) const { + return Lexer::isAtEndOfMacroExpansion(loc, SourceMgr, LangOpts, MacroEnd); + } + + /// \brief Print the token to stderr, used for debugging. + void DumpToken(const Token &Tok, bool DumpFlags = false) const; + void DumpLocation(SourceLocation Loc) const; + void DumpMacro(const MacroInfo &MI) const; + void dumpMacroInfo(const IdentifierInfo *II); + + /// \brief Given a location that specifies the start of a + /// token, return a new location that specifies a character within the token. + SourceLocation AdvanceToTokenCharacter(SourceLocation TokStart, + unsigned Char) const { + return Lexer::AdvanceToTokenCharacter(TokStart, Char, SourceMgr, LangOpts); + } + + /// \brief Increment the counters for the number of token paste operations + /// performed. + /// + /// If fast was specified, this is a 'fast paste' case we handled. + void IncrementPasteCounter(bool isFast) { + if (isFast) + ++NumFastTokenPaste; + else + ++NumTokenPaste; + } + + void PrintStats(); + + size_t getTotalMemory() const; + + /// When the macro expander pastes together a comment (/##/) in Microsoft + /// mode, this method handles updating the current state, returning the + /// token on the next source line. + void HandleMicrosoftCommentPaste(Token &Tok); + + //===--------------------------------------------------------------------===// + // Preprocessor callback methods. These are invoked by a lexer as various + // directives and events are found. + + /// Given a tok::raw_identifier token, look up the + /// identifier information for the token and install it into the token, + /// updating the token kind accordingly. + IdentifierInfo *LookUpIdentifierInfo(Token &Identifier) const; + +private: + llvm::DenseMap<IdentifierInfo*,unsigned> PoisonReasons; + +public: + + /// \brief Specifies the reason for poisoning an identifier. + /// + /// If that identifier is accessed while poisoned, then this reason will be + /// used instead of the default "poisoned" diagnostic. + void SetPoisonReason(IdentifierInfo *II, unsigned DiagID); + + /// \brief Display reason for poisoned identifier. + void HandlePoisonedIdentifier(Token & Tok); + + void MaybeHandlePoisonedIdentifier(Token & Identifier) { + if(IdentifierInfo * II = Identifier.getIdentifierInfo()) { + if(II->isPoisoned()) { + HandlePoisonedIdentifier(Identifier); + } + } + } + +private: + /// Identifiers used for SEH handling in Borland. These are only + /// allowed in particular circumstances + // __except block + IdentifierInfo *Ident__exception_code, + *Ident___exception_code, + *Ident_GetExceptionCode; + // __except filter expression + IdentifierInfo *Ident__exception_info, + *Ident___exception_info, + *Ident_GetExceptionInfo; + // __finally + IdentifierInfo *Ident__abnormal_termination, + *Ident___abnormal_termination, + *Ident_AbnormalTermination; + + const char *getCurLexerEndPos(); + +public: + void PoisonSEHIdentifiers(bool Poison = true); // Borland + + /// \brief Callback invoked when the lexer reads an identifier and has + /// filled in the tokens IdentifierInfo member. + /// + /// This callback potentially macro expands it or turns it into a named + /// token (like 'for'). + /// + /// \returns true if we actually computed a token, false if we need to + /// lex again. + bool HandleIdentifier(Token &Identifier); + + + /// \brief Callback invoked when the lexer hits the end of the current file. + /// + /// This either returns the EOF token and returns true, or + /// pops a level off the include stack and returns false, at which point the + /// client should call lex again. + bool HandleEndOfFile(Token &Result, bool isEndOfMacro = false); + + /// \brief Callback invoked when the current TokenLexer hits the end of its + /// token stream. + bool HandleEndOfTokenLexer(Token &Result); + + /// \brief Callback invoked when the lexer sees a # token at the start of a + /// line. + /// + /// This consumes the directive, modifies the lexer/preprocessor state, and + /// advances the lexer(s) so that the next token read is the correct one. + void HandleDirective(Token &Result); + + /// \brief Ensure that the next token is a tok::eod token. + /// + /// If not, emit a diagnostic and consume up until the eod. + /// If \p EnableMacros is true, then we consider macros that expand to zero + /// tokens as being ok. + void CheckEndOfDirective(const char *Directive, bool EnableMacros = false); + + /// \brief Read and discard all tokens remaining on the current line until + /// the tok::eod token is found. + void DiscardUntilEndOfDirective(); + + /// \brief Returns true if the preprocessor has seen a use of + /// __DATE__ or __TIME__ in the file so far. + bool SawDateOrTime() const { + return DATELoc != SourceLocation() || TIMELoc != SourceLocation(); + } + unsigned getCounterValue() const { return CounterValue; } + void setCounterValue(unsigned V) { CounterValue = V; } + + /// \brief Retrieves the module that we're currently building, if any. + Module *getCurrentModule(); + + /// \brief Allocate a new MacroInfo object with the provided SourceLocation. + MacroInfo *AllocateMacroInfo(SourceLocation L); + + /// \brief Allocate a new MacroInfo object loaded from an AST file. + MacroInfo *AllocateDeserializedMacroInfo(SourceLocation L, + unsigned SubModuleID); + + /// \brief Turn the specified lexer token into a fully checked and spelled + /// filename, e.g. as an operand of \#include. + /// + /// 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. + /// + /// \returns true if the input filename was in <>'s or false if it was + /// in ""'s. + bool GetIncludeFilenameSpelling(SourceLocation Loc,StringRef &Filename); + + /// \brief Given a "foo" or \<foo> reference, look up the indicated file. + /// + /// Returns null on failure. \p isAngled indicates whether the file + /// reference is for system \#include's or not (i.e. using <> instead of ""). + const FileEntry *LookupFile(SourceLocation FilenameLoc, StringRef Filename, + bool isAngled, const DirectoryLookup *FromDir, + const FileEntry *FromFile, + const DirectoryLookup *&CurDir, + SmallVectorImpl<char> *SearchPath, + SmallVectorImpl<char> *RelativePath, + ModuleMap::KnownHeader *SuggestedModule, + bool SkipCache = false); + + /// \brief Get 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; } + + /// \brief Return true if we're in the top-level file, not in a \#include. + bool isInPrimaryFile() const; + + /// \brief 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: + /// \code + /// \#define FOO <x/y.h> + /// \#include FOO + /// \endcode + /// because in this case, "<x/y.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 EOD marker. + bool ConcatenateIncludeName(SmallString<128> &FilenameBuffer, + SourceLocation &End); + + /// \brief Lex an on-off-switch (C99 6.10.6p2) and verify that it is + /// followed by EOD. Return true if the token is not a valid on-off-switch. + bool LexOnOffSwitch(tok::OnOffSwitch &OOS); + + bool CheckMacroName(Token &MacroNameTok, MacroUse isDefineUndef, + bool *ShadowFlag = nullptr); + +private: + + void PushIncludeMacroStack() { + assert(CurLexerKind != CLK_CachingLexer && "cannot push a caching lexer"); + IncludeMacroStack.emplace_back( + CurLexerKind, CurSubmodule, std::move(CurLexer), std::move(CurPTHLexer), + CurPPLexer, std::move(CurTokenLexer), CurDirLookup); + CurPPLexer = nullptr; + } + + void PopIncludeMacroStack() { + CurLexer = std::move(IncludeMacroStack.back().TheLexer); + CurPTHLexer = std::move(IncludeMacroStack.back().ThePTHLexer); + CurPPLexer = IncludeMacroStack.back().ThePPLexer; + CurTokenLexer = std::move(IncludeMacroStack.back().TheTokenLexer); + CurDirLookup = IncludeMacroStack.back().TheDirLookup; + CurSubmodule = IncludeMacroStack.back().TheSubmodule; + CurLexerKind = IncludeMacroStack.back().CurLexerKind; + IncludeMacroStack.pop_back(); + } + + void PropagateLineStartLeadingSpaceInfo(Token &Result); + + void EnterSubmodule(Module *M, SourceLocation ImportLoc); + void LeaveSubmodule(); + + /// Update the set of active module macros and ambiguity flag for a module + /// macro name. + void updateModuleMacroInfo(const IdentifierInfo *II, ModuleMacroInfo &Info); + + /// \brief Allocate a new MacroInfo object. + MacroInfo *AllocateMacroInfo(); + + DefMacroDirective *AllocateDefMacroDirective(MacroInfo *MI, + SourceLocation Loc); + UndefMacroDirective *AllocateUndefMacroDirective(SourceLocation UndefLoc); + VisibilityMacroDirective *AllocateVisibilityMacroDirective(SourceLocation Loc, + bool isPublic); + + /// \brief Lex and validate a macro name, which occurs after a + /// \#define or \#undef. + /// + /// \param MacroNameTok Token that represents the name defined or undefined. + /// \param IsDefineUndef Kind if preprocessor directive. + /// \param ShadowFlag Points to flag that is set if macro name shadows + /// a keyword. + /// + /// This emits a diagnostic, sets the token kind to eod, + /// and discards the rest of the macro line if the macro name is invalid. + void ReadMacroName(Token &MacroNameTok, MacroUse IsDefineUndef = MU_Other, + bool *ShadowFlag = nullptr); + + /// The ( starting an argument list of a macro definition has just been read. + /// Lex the rest of the arguments and the closing ), updating \p MI with + /// what we learn and saving in \p LastTok the last token read. + /// Return true if an error occurs parsing the arg list. + bool ReadMacroDefinitionArgList(MacroInfo *MI, Token& LastTok); + + /// We just read a \#if or related directive and decided that the + /// subsequent tokens are in the \#if'd out portion of the + /// file. Lex the rest of the file, until we see an \#endif. If \p + /// FoundNonSkipPortion is true, then we have already emitted code for part of + /// this \#if directive, so \#else/\#elif blocks should never be entered. If + /// \p FoundElse is false, then \#else directives are ok, if not, then we have + /// already seen one so a \#else directive is a duplicate. When this returns, + /// the caller can lex the first valid token. + void SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, + bool FoundNonSkipPortion, bool FoundElse, + SourceLocation ElseLoc = SourceLocation()); + + /// \brief A fast PTH version of SkipExcludedConditionalBlock. + void PTHSkipExcludedConditionalBlock(); + + /// \brief Evaluate an integer constant expression that may occur after a + /// \#if or \#elif directive and return it as a bool. + /// + /// If the expression is equivalent to "!defined(X)" return X in IfNDefMacro. + bool EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro); + + /// \brief Install the standard preprocessor pragmas: + /// \#pragma GCC poison/system_header/dependency and \#pragma once. + void RegisterBuiltinPragmas(); + + /// \brief Register builtin macros such as __LINE__ with the identifier table. + void RegisterBuiltinMacros(); + + /// If an identifier token is read that is to be expanded as a macro, handle + /// it and return the next token as 'Tok'. If we lexed a token, return true; + /// otherwise the caller should lex again. + bool HandleMacroExpandedIdentifier(Token &Tok, const MacroDefinition &MD); + + /// \brief Cache macro expanded tokens for TokenLexers. + // + /// Works like a stack; a TokenLexer adds the macro expanded tokens that is + /// going to lex in the cache and when it finishes the tokens are removed + /// from the end of the cache. + Token *cacheMacroExpandedTokens(TokenLexer *tokLexer, + ArrayRef<Token> tokens); + void removeCachedMacroExpandedTokensOfLastLexer(); + friend void TokenLexer::ExpandFunctionArguments(); + + /// Determine whether the next preprocessor token to be + /// lexed is a '('. If so, consume the token and return true, if not, this + /// method should have no observable side-effect on the lexed tokens. + bool isNextPPTokenLParen(); + + /// After reading "MACRO(", this method is invoked to read all of the formal + /// arguments specified for the macro invocation. Returns null on error. + MacroArgs *ReadFunctionLikeMacroArgs(Token &MacroName, MacroInfo *MI, + SourceLocation &ExpansionEnd); + + /// \brief If an identifier token is read that is to be expanded + /// as a builtin macro, handle it and return the next token as 'Tok'. + void ExpandBuiltinMacro(Token &Tok); + + /// \brief Read a \c _Pragma directive, slice it up, process it, then + /// return the first token after the directive. + /// This assumes that the \c _Pragma token has just been read into \p Tok. + void Handle_Pragma(Token &Tok); + + /// \brief Like Handle_Pragma except the pragma text is not enclosed within + /// a string literal. + void HandleMicrosoft__pragma(Token &Tok); + + /// \brief Add a lexer to the top of the include stack and + /// start lexing tokens from it instead of the current buffer. + void EnterSourceFileWithLexer(Lexer *TheLexer, const DirectoryLookup *Dir); + + /// \brief Add a lexer to the top of the include stack and + /// start getting tokens from it using the PTH cache. + void EnterSourceFileWithPTH(PTHLexer *PL, const DirectoryLookup *Dir); + + /// \brief Set the FileID for the preprocessor predefines. + void setPredefinesFileID(FileID FID) { + assert(PredefinesFileID.isInvalid() && "PredefinesFileID already set!"); + PredefinesFileID = FID; + } + + /// \brief 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) { + return L ? !L->isPragmaLexer() : P != nullptr; + } + + static bool IsFileLexer(const IncludeStackInfo& I) { + return IsFileLexer(I.TheLexer.get(), I.ThePPLexer); + } + + bool IsFileLexer() const { + return IsFileLexer(CurLexer.get(), CurPPLexer); + } + + //===--------------------------------------------------------------------===// + // Caching stuff. + void CachingLex(Token &Result); + bool InCachingLexMode() const { + // If the Lexer pointers are 0 and IncludeMacroStack is empty, it means + // that we are past EOF, not that we are in CachingLex mode. + return !CurPPLexer && !CurTokenLexer && !CurPTHLexer && + !IncludeMacroStack.empty(); + } + void EnterCachingLexMode(); + void ExitCachingLexMode() { + if (InCachingLexMode()) + RemoveTopOfLexerStack(); + } + const Token &PeekAhead(unsigned N); + void AnnotatePreviousCachedTokens(const Token &Tok); + + //===--------------------------------------------------------------------===// + /// Handle*Directive - implement the various preprocessor directives. These + /// should side-effect the current preprocessor object so that the next call + /// to Lex() will return the appropriate token next. + void HandleLineDirective(Token &Tok); + void HandleDigitDirective(Token &Tok); + void HandleUserDiagnosticDirective(Token &Tok, bool isWarning); + void HandleIdentSCCSDirective(Token &Tok); + void HandleMacroPublicDirective(Token &Tok); + void HandleMacroPrivateDirective(Token &Tok); + + // File inclusion. + void HandleIncludeDirective(SourceLocation HashLoc, + Token &Tok, + const DirectoryLookup *LookupFrom = nullptr, + const FileEntry *LookupFromFile = nullptr, + bool isImport = false); + void HandleIncludeNextDirective(SourceLocation HashLoc, Token &Tok); + void HandleIncludeMacrosDirective(SourceLocation HashLoc, Token &Tok); + void HandleImportDirective(SourceLocation HashLoc, Token &Tok); + void HandleMicrosoftImportDirective(Token &Tok); + +public: + // Module inclusion testing. + /// \brief Find the module that owns the source or header file that + /// \p Loc points to. If the location is in a file that was included + /// into a module, or is outside any module, returns nullptr. + Module *getModuleForLocation(SourceLocation Loc); + + /// \brief Find the module that contains the specified location, either + /// directly or indirectly. + Module *getModuleContainingLocation(SourceLocation Loc); + +private: + // Macro handling. + void HandleDefineDirective(Token &Tok, bool ImmediatelyAfterTopLevelIfndef); + void HandleUndefDirective(Token &Tok); + + // Conditional Inclusion. + void HandleIfdefDirective(Token &Tok, bool isIfndef, + bool ReadAnyTokensBeforeDirective); + void HandleIfDirective(Token &Tok, bool ReadAnyTokensBeforeDirective); + void HandleEndifDirective(Token &Tok); + void HandleElseDirective(Token &Tok); + void HandleElifDirective(Token &Tok); + + // Pragmas. + void HandlePragmaDirective(SourceLocation IntroducerLoc, + PragmaIntroducerKind Introducer); +public: + void HandlePragmaOnce(Token &OnceTok); + void HandlePragmaMark(); + void HandlePragmaPoison(Token &PoisonTok); + void HandlePragmaSystemHeader(Token &SysHeaderTok); + void HandlePragmaDependency(Token &DependencyTok); + void HandlePragmaPushMacro(Token &Tok); + void HandlePragmaPopMacro(Token &Tok); + void HandlePragmaIncludeAlias(Token &Tok); + IdentifierInfo *ParsePragmaPushOrPopMacro(Token &Tok); + + // Return true and store the first token only if any CommentHandler + // has inserted some tokens and getCommentRetentionState() is false. + bool HandleComment(Token &Token, SourceRange Comment); + + /// \brief A macro is used, update information about macros that need unused + /// warnings. + void markMacroAsUsed(MacroInfo *MI); +}; + +/// \brief Abstract base class that describes a handler that will receive +/// source ranges for each of the comments encountered in the source file. +class CommentHandler { +public: + virtual ~CommentHandler(); + + // The handler shall return true if it has pushed any tokens + // to be read using e.g. EnterToken or EnterTokenStream. + virtual bool HandleComment(Preprocessor &PP, SourceRange Comment) = 0; +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Lex/PreprocessorLexer.h b/contrib/llvm/tools/clang/include/clang/Lex/PreprocessorLexer.h new file mode 100644 index 0000000..6d6cf05 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Lex/PreprocessorLexer.h @@ -0,0 +1,183 @@ +//===--- PreprocessorLexer.h - C Language Family Lexer ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the PreprocessorLexer interface. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_PREPROCESSORLEXER_H +#define LLVM_CLANG_LEX_PREPROCESSORLEXER_H + +#include "clang/Lex/MultipleIncludeOpt.h" +#include "clang/Lex/Token.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { + +class FileEntry; +class Preprocessor; + +class PreprocessorLexer { + virtual void anchor(); +protected: + Preprocessor *PP; // Preprocessor object controlling lexing. + + /// The SourceManager FileID corresponding to the file being lexed. + const FileID FID; + + /// \brief Number of SLocEntries before lexing the file. + unsigned InitialNumSLocEntries; + + //===--------------------------------------------------------------------===// + // Context-specific lexing flags set by the preprocessor. + //===--------------------------------------------------------------------===// + + /// \brief True when parsing \#XXX; turns '\\n' into a tok::eod token. + bool ParsingPreprocessorDirective; + + /// \brief True after \#include; turns \<xx> into a tok::angle_string_literal + /// token. + bool ParsingFilename; + + /// \brief True if in raw mode. + /// + /// Raw mode disables interpretation of tokens and is a far faster mode to + /// lex in than non-raw-mode. This flag: + /// 1. If EOF of the current lexer is found, the include stack isn't popped. + /// 2. Identifier information is not looked up for identifier tokens. As an + /// effect of this, implicit macro expansion is naturally disabled. + /// 3. "#" tokens at the start of a line are treated as normal tokens, not + /// implicitly transformed by the lexer. + /// 4. All diagnostic messages are disabled. + /// 5. No callbacks are made into the preprocessor. + /// + /// Note that in raw mode that the PP pointer may be null. + bool LexingRawMode; + + /// \brief A state machine that detects the \#ifndef-wrapping a file + /// idiom for the multiple-include optimization. + MultipleIncludeOpt MIOpt; + + /// \brief Information about the set of \#if/\#ifdef/\#ifndef blocks + /// we are currently in. + SmallVector<PPConditionalInfo, 4> ConditionalStack; + + PreprocessorLexer(const PreprocessorLexer &) = delete; + void operator=(const PreprocessorLexer &) = delete; + friend class Preprocessor; + + PreprocessorLexer(Preprocessor *pp, FileID fid); + + PreprocessorLexer() + : PP(nullptr), InitialNumSLocEntries(0), + ParsingPreprocessorDirective(false), + ParsingFilename(false), + LexingRawMode(false) {} + + virtual ~PreprocessorLexer() {} + + virtual void IndirectLex(Token& Result) = 0; + + /// \brief Return the source location for the next observable location. + virtual SourceLocation getSourceLocation() = 0; + + //===--------------------------------------------------------------------===// + // #if directive handling. + + /// pushConditionalLevel - When we enter a \#if directive, this keeps track of + /// what we are currently in for diagnostic emission (e.g. \#if with missing + /// \#endif). + void pushConditionalLevel(SourceLocation DirectiveStart, bool WasSkipping, + bool FoundNonSkip, bool FoundElse) { + PPConditionalInfo CI; + CI.IfLoc = DirectiveStart; + CI.WasSkipping = WasSkipping; + CI.FoundNonSkip = FoundNonSkip; + CI.FoundElse = FoundElse; + ConditionalStack.push_back(CI); + } + void pushConditionalLevel(const PPConditionalInfo &CI) { + ConditionalStack.push_back(CI); + } + + /// popConditionalLevel - Remove an entry off the top of the conditional + /// stack, returning information about it. If the conditional stack is empty, + /// this returns true and does not fill in the arguments. + bool popConditionalLevel(PPConditionalInfo &CI) { + if (ConditionalStack.empty()) + return true; + CI = ConditionalStack.pop_back_val(); + return false; + } + + /// \brief Return the top of the conditional stack. + /// \pre This requires that there be a conditional active. + PPConditionalInfo &peekConditionalLevel() { + assert(!ConditionalStack.empty() && "No conditionals active!"); + return ConditionalStack.back(); + } + + unsigned getConditionalStackDepth() const { return ConditionalStack.size(); } + +public: + + //===--------------------------------------------------------------------===// + // Misc. lexing methods. + + /// \brief After the preprocessor has parsed a \#include, lex and + /// (potentially) macro expand the filename. + /// + /// If the sequence parsed is not lexically legal, emit a diagnostic and + /// return a result EOD token. + void LexIncludeFilename(Token &Result); + + /// \brief Inform the lexer whether or not we are currently lexing a + /// preprocessor directive. + void setParsingPreprocessorDirective(bool f) { + ParsingPreprocessorDirective = f; + } + + /// \brief Return true if this lexer is in raw mode or not. + bool isLexingRawMode() const { return LexingRawMode; } + + /// \brief Return the preprocessor object for this lexer. + Preprocessor *getPP() const { return PP; } + + FileID getFileID() const { + assert(PP && + "PreprocessorLexer::getFileID() should only be used with a Preprocessor"); + return FID; + } + + /// \brief Number of SLocEntries before lexing the file. + unsigned getInitialNumSLocEntries() const { + return InitialNumSLocEntries; + } + + /// getFileEntry - Return the FileEntry corresponding to this FileID. Like + /// getFileID(), this only works for lexers with attached preprocessors. + const FileEntry *getFileEntry() const; + + /// \brief Iterator that traverses the current stack of preprocessor + /// conditional directives (\#if/\#ifdef/\#ifndef). + typedef SmallVectorImpl<PPConditionalInfo>::const_iterator + conditional_iterator; + + conditional_iterator conditional_begin() const { + return ConditionalStack.begin(); + } + conditional_iterator conditional_end() const { + return ConditionalStack.end(); + } +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Lex/PreprocessorOptions.h b/contrib/llvm/tools/clang/include/clang/Lex/PreprocessorOptions.h new file mode 100644 index 0000000..963d95d --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Lex/PreprocessorOptions.h @@ -0,0 +1,185 @@ +//===--- PreprocessorOptions.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_LEX_PREPROCESSOROPTIONS_H_ +#define LLVM_CLANG_LEX_PREPROCESSOROPTIONS_H_ + +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSet.h" +#include <cassert> +#include <set> +#include <string> +#include <utility> +#include <vector> + +namespace llvm { + class MemoryBuffer; +} + +namespace clang { + +class Preprocessor; +class LangOptions; + +/// \brief Enumerate the kinds of standard library that +enum ObjCXXARCStandardLibraryKind { + ARCXX_nolib, + /// \brief libc++ + ARCXX_libcxx, + /// \brief libstdc++ + ARCXX_libstdcxx +}; + +/// PreprocessorOptions - This class is used for passing the various options +/// used in preprocessor initialization to InitializePreprocessor(). +class PreprocessorOptions : public RefCountedBase<PreprocessorOptions> { +public: + std::vector<std::pair<std::string, bool/*isUndef*/> > Macros; + std::vector<std::string> Includes; + std::vector<std::string> MacroIncludes; + + /// \brief Initialize the preprocessor with the compiler and target specific + /// predefines. + unsigned UsePredefines : 1; + + /// \brief Whether we should maintain a detailed record of all macro + /// definitions and expansions. + unsigned DetailedRecord : 1; + + /// The implicit PCH included at the start of the translation unit, or empty. + std::string ImplicitPCHInclude; + + /// \brief Headers that will be converted to chained PCHs in memory. + std::vector<std::string> ChainedIncludes; + + /// \brief When true, disables most of the normal validation performed on + /// precompiled headers. + bool DisablePCHValidation; + + /// \brief When true, a PCH with compiler errors will not be rejected. + bool AllowPCHWithCompilerErrors; + + /// \brief Dump declarations that are deserialized from PCH, for testing. + bool DumpDeserializedPCHDecls; + + /// \brief This is a set of names for decls that we do not want to be + /// deserialized, and we emit an error if they are; for testing purposes. + std::set<std::string> DeserializedPCHDeclsToErrorOn; + + /// \brief If non-zero, the implicit PCH include is actually a precompiled + /// preamble that covers this number of bytes in the main source file. + /// + /// The boolean indicates whether the preamble ends at the start of a new + /// line. + std::pair<unsigned, bool> PrecompiledPreambleBytes; + + /// The implicit PTH input included at the start of the translation unit, or + /// empty. + std::string ImplicitPTHInclude; + + /// If given, a PTH cache file to use for speeding up header parsing. + std::string TokenCache; + + /// \brief True if the SourceManager should report the original file name for + /// contents of files that were remapped to other files. Defaults to true. + bool RemappedFilesKeepOriginalName; + + /// \brief The set of file remappings, which take existing files on + /// the system (the first part of each pair) and gives them the + /// contents of other files on the system (the second part of each + /// pair). + std::vector<std::pair<std::string, std::string>> RemappedFiles; + + /// \brief The set of file-to-buffer remappings, which take existing files + /// on the system (the first part of each pair) and gives them the contents + /// of the specified memory buffer (the second part of each pair). + std::vector<std::pair<std::string, llvm::MemoryBuffer *>> RemappedFileBuffers; + + /// \brief Whether the compiler instance should retain (i.e., not free) + /// the buffers associated with remapped files. + /// + /// This flag defaults to false; it can be set true only through direct + /// manipulation of the compiler invocation object, in cases where the + /// compiler invocation and its buffers will be reused. + bool RetainRemappedFileBuffers; + + /// \brief The Objective-C++ ARC standard library that we should support, + /// by providing appropriate definitions to retrofit the standard library + /// with support for lifetime-qualified pointers. + ObjCXXARCStandardLibraryKind ObjCXXARCStandardLibrary; + + /// \brief Records the set of modules + class FailedModulesSet : public RefCountedBase<FailedModulesSet> { + llvm::StringSet<> Failed; + + public: + bool hasAlreadyFailed(StringRef module) { + return Failed.count(module) > 0; + } + + void addFailed(StringRef module) { + Failed.insert(module); + } + }; + + /// \brief The set of modules that failed to build. + /// + /// This pointer will be shared among all of the compiler instances created + /// to (re)build modules, so that once a module fails to build anywhere, + /// other instances will see that the module has failed and won't try to + /// build it again. + IntrusiveRefCntPtr<FailedModulesSet> FailedModules; + +public: + PreprocessorOptions() : UsePredefines(true), DetailedRecord(false), + DisablePCHValidation(false), + AllowPCHWithCompilerErrors(false), + DumpDeserializedPCHDecls(false), + PrecompiledPreambleBytes(0, true), + RemappedFilesKeepOriginalName(true), + RetainRemappedFileBuffers(false), + ObjCXXARCStandardLibrary(ARCXX_nolib) { } + + void addMacroDef(StringRef Name) { Macros.emplace_back(Name, false); } + void addMacroUndef(StringRef Name) { Macros.emplace_back(Name, true); } + void addRemappedFile(StringRef From, StringRef To) { + RemappedFiles.emplace_back(From, To); + } + + void addRemappedFile(StringRef From, llvm::MemoryBuffer *To) { + RemappedFileBuffers.emplace_back(From, To); + } + + void clearRemappedFiles() { + RemappedFiles.clear(); + RemappedFileBuffers.clear(); + } + + /// \brief Reset any options that are not considered when building a + /// module. + void resetNonModularOptions() { + Includes.clear(); + MacroIncludes.clear(); + ChainedIncludes.clear(); + DumpDeserializedPCHDecls = false; + ImplicitPCHInclude.clear(); + ImplicitPTHInclude.clear(); + TokenCache.clear(); + RetainRemappedFileBuffers = true; + PrecompiledPreambleBytes.first = 0; + PrecompiledPreambleBytes.second = 0; + } +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Lex/ScratchBuffer.h b/contrib/llvm/tools/clang/include/clang/Lex/ScratchBuffer.h new file mode 100644 index 0000000..a3d6096 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Lex/ScratchBuffer.h @@ -0,0 +1,45 @@ +//===--- ScratchBuffer.h - Scratch space for forming tokens -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ScratchBuffer interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_SCRATCHBUFFER_H +#define LLVM_CLANG_LEX_SCRATCHBUFFER_H + +#include "clang/Basic/SourceLocation.h" + +namespace clang { + class SourceManager; + +/// ScratchBuffer - This class exposes a simple interface for the dynamic +/// construction of tokens. This is used for builtin macros (e.g. __LINE__) as +/// well as token pasting, etc. +class ScratchBuffer { + SourceManager &SourceMgr; + char *CurBuffer; + SourceLocation BufferStartLoc; + unsigned BytesUsed; +public: + ScratchBuffer(SourceManager &SM); + + /// getToken - Splat the specified text into a temporary MemoryBuffer and + /// return a SourceLocation that refers to the token. This is just like the + /// previous method, but returns a location that indicates the physloc of the + /// token. + SourceLocation getToken(const char *Buf, unsigned Len, const char *&DestPtr); + +private: + void AllocScratchBuffer(unsigned RequestLen); +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Lex/Token.h b/contrib/llvm/tools/clang/include/clang/Lex/Token.h new file mode 100644 index 0000000..7ba22b2 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Lex/Token.h @@ -0,0 +1,328 @@ +//===--- Token.h - Token interface ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Token interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_TOKEN_H +#define LLVM_CLANG_LEX_TOKEN_H + +#include "clang/Basic/OperatorKinds.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/TemplateKinds.h" +#include "clang/Basic/TokenKinds.h" +#include "llvm/ADT/StringRef.h" +#include <cstdlib> + +namespace clang { + +class IdentifierInfo; + +/// Token - This structure provides full information about a lexed token. +/// It is not intended to be space efficient, it is intended to return as much +/// information as possible about each returned token. This is expected to be +/// compressed into a smaller form if memory footprint is important. +/// +/// The parser can create a special "annotation token" representing a stream of +/// tokens that were parsed and semantically resolved, e.g.: "foo::MyClass<int>" +/// can be represented by a single typename annotation token that carries +/// information about the SourceRange of the tokens and the type object. +class Token { + /// The location of the token. This is actually a SourceLocation. + unsigned Loc; + + // Conceptually these next two fields could be in a union. However, this + // causes gcc 4.2 to pessimize LexTokenInternal, a very performance critical + // routine. Keeping as separate members with casts until a more beautiful fix + // presents itself. + + /// UintData - This holds either the length of the token text, when + /// a normal token, or the end of the SourceRange when an annotation + /// token. + unsigned UintData; + + /// PtrData - This is a union of four different pointer types, which depends + /// on what type of token this is: + /// Identifiers, keywords, etc: + /// This is an IdentifierInfo*, which contains the uniqued identifier + /// spelling. + /// Literals: isLiteral() returns true. + /// This is a pointer to the start of the token in a text buffer, which + /// may be dirty (have trigraphs / escaped newlines). + /// Annotations (resolved type names, C++ scopes, etc): isAnnotation(). + /// This is a pointer to sema-specific data for the annotation token. + /// Eof: + // This is a pointer to a Decl. + /// Other: + /// This is null. + void *PtrData; + + /// Kind - The actual flavor of token this is. + tok::TokenKind Kind; + + /// Flags - Bits we track about this token, members of the TokenFlags enum. + unsigned short Flags; +public: + + // Various flags set per token: + enum TokenFlags { + StartOfLine = 0x01, // At start of line or only after whitespace + // (considering the line after macro expansion). + LeadingSpace = 0x02, // Whitespace exists before this token (considering + // whitespace after macro expansion). + DisableExpand = 0x04, // This identifier may never be macro expanded. + NeedsCleaning = 0x08, // Contained an escaped newline or trigraph. + LeadingEmptyMacro = 0x10, // Empty macro exists before this token. + HasUDSuffix = 0x20, // This string or character literal has a ud-suffix. + HasUCN = 0x40, // This identifier contains a UCN. + IgnoredComma = 0x80, // This comma is not a macro argument separator (MS). + StringifiedInMacro = 0x100, // This string or character literal is formed by + // macro stringizing or charizing operator. + }; + + tok::TokenKind getKind() const { return Kind; } + void setKind(tok::TokenKind K) { Kind = K; } + + /// is/isNot - Predicates to check if this token is a specific kind, as in + /// "if (Tok.is(tok::l_brace)) {...}". + bool is(tok::TokenKind K) const { return Kind == K; } + bool isNot(tok::TokenKind K) const { return Kind != K; } + bool isOneOf(tok::TokenKind K1, tok::TokenKind K2) const { + return is(K1) || is(K2); + } + template <typename... Ts> + bool isOneOf(tok::TokenKind K1, tok::TokenKind K2, Ts... Ks) const { + return is(K1) || isOneOf(K2, Ks...); + } + + /// \brief Return true if this is a raw identifier (when lexing + /// in raw mode) or a non-keyword identifier (when lexing in non-raw mode). + bool isAnyIdentifier() const { + return tok::isAnyIdentifier(getKind()); + } + + /// \brief Return true if this is a "literal", like a numeric + /// constant, string, etc. + bool isLiteral() const { + return tok::isLiteral(getKind()); + } + + /// \brief Return true if this is any of tok::annot_* kind tokens. + bool isAnnotation() const { + return tok::isAnnotation(getKind()); + } + + /// \brief Return a source location identifier for the specified + /// offset in the current file. + SourceLocation getLocation() const { + return SourceLocation::getFromRawEncoding(Loc); + } + unsigned getLength() const { + assert(!isAnnotation() && "Annotation tokens have no length field"); + return UintData; + } + + void setLocation(SourceLocation L) { Loc = L.getRawEncoding(); } + void setLength(unsigned Len) { + assert(!isAnnotation() && "Annotation tokens have no length field"); + UintData = Len; + } + + SourceLocation getAnnotationEndLoc() const { + assert(isAnnotation() && "Used AnnotEndLocID on non-annotation token"); + return SourceLocation::getFromRawEncoding(UintData ? UintData : Loc); + } + void setAnnotationEndLoc(SourceLocation L) { + assert(isAnnotation() && "Used AnnotEndLocID on non-annotation token"); + UintData = L.getRawEncoding(); + } + + SourceLocation getLastLoc() const { + return isAnnotation() ? getAnnotationEndLoc() : getLocation(); + } + + SourceLocation getEndLoc() const { + return isAnnotation() ? getAnnotationEndLoc() + : getLocation().getLocWithOffset(getLength()); + } + + /// \brief SourceRange of the group of tokens that this annotation token + /// represents. + SourceRange getAnnotationRange() const { + return SourceRange(getLocation(), getAnnotationEndLoc()); + } + void setAnnotationRange(SourceRange R) { + setLocation(R.getBegin()); + setAnnotationEndLoc(R.getEnd()); + } + + const char *getName() const { return tok::getTokenName(Kind); } + + /// \brief Reset all flags to cleared. + void startToken() { + Kind = tok::unknown; + Flags = 0; + PtrData = nullptr; + UintData = 0; + Loc = SourceLocation().getRawEncoding(); + } + + IdentifierInfo *getIdentifierInfo() const { + assert(isNot(tok::raw_identifier) && + "getIdentifierInfo() on a tok::raw_identifier token!"); + assert(!isAnnotation() && + "getIdentifierInfo() on an annotation token!"); + if (isLiteral()) return nullptr; + if (is(tok::eof)) return nullptr; + return (IdentifierInfo*) PtrData; + } + void setIdentifierInfo(IdentifierInfo *II) { + PtrData = (void*) II; + } + + const void *getEofData() const { + assert(is(tok::eof)); + return reinterpret_cast<const void *>(PtrData); + } + void setEofData(const void *D) { + assert(is(tok::eof)); + assert(!PtrData); + PtrData = const_cast<void *>(D); + } + + /// getRawIdentifier - For a raw identifier token (i.e., an identifier + /// lexed in raw mode), returns a reference to the text substring in the + /// buffer if known. + StringRef getRawIdentifier() const { + assert(is(tok::raw_identifier)); + return StringRef(reinterpret_cast<const char *>(PtrData), getLength()); + } + void setRawIdentifierData(const char *Ptr) { + assert(is(tok::raw_identifier)); + PtrData = const_cast<char*>(Ptr); + } + + /// getLiteralData - For a literal token (numeric constant, string, etc), this + /// returns a pointer to the start of it in the text buffer if known, null + /// otherwise. + const char *getLiteralData() const { + assert(isLiteral() && "Cannot get literal data of non-literal"); + return reinterpret_cast<const char*>(PtrData); + } + void setLiteralData(const char *Ptr) { + assert(isLiteral() && "Cannot set literal data of non-literal"); + PtrData = const_cast<char*>(Ptr); + } + + void *getAnnotationValue() const { + assert(isAnnotation() && "Used AnnotVal on non-annotation token"); + return PtrData; + } + void setAnnotationValue(void *val) { + assert(isAnnotation() && "Used AnnotVal on non-annotation token"); + PtrData = val; + } + + /// \brief Set the specified flag. + void setFlag(TokenFlags Flag) { + Flags |= Flag; + } + + /// \brief Unset the specified flag. + void clearFlag(TokenFlags Flag) { + Flags &= ~Flag; + } + + /// \brief Return the internal represtation of the flags. + /// + /// This is only intended for low-level operations such as writing tokens to + /// disk. + unsigned getFlags() const { + return Flags; + } + + /// \brief Set a flag to either true or false. + void setFlagValue(TokenFlags Flag, bool Val) { + if (Val) + setFlag(Flag); + else + clearFlag(Flag); + } + + /// isAtStartOfLine - Return true if this token is at the start of a line. + /// + bool isAtStartOfLine() const { return (Flags & StartOfLine) ? true : false; } + + /// \brief Return true if this token has whitespace before it. + /// + bool hasLeadingSpace() const { return (Flags & LeadingSpace) ? true : false; } + + /// \brief Return true if this identifier token should never + /// be expanded in the future, due to C99 6.10.3.4p2. + bool isExpandDisabled() const { + return (Flags & DisableExpand) ? true : false; + } + + /// \brief Return true if we have an ObjC keyword identifier. + bool isObjCAtKeyword(tok::ObjCKeywordKind objcKey) const; + + /// \brief Return the ObjC keyword kind. + tok::ObjCKeywordKind getObjCKeywordID() const; + + /// \brief Return true if this token has trigraphs or escaped newlines in it. + bool needsCleaning() const { return (Flags & NeedsCleaning) ? true : false; } + + /// \brief Return true if this token has an empty macro before it. + /// + bool hasLeadingEmptyMacro() const { + return (Flags & LeadingEmptyMacro) ? true : false; + } + + /// \brief Return true if this token is a string or character literal which + /// has a ud-suffix. + bool hasUDSuffix() const { return (Flags & HasUDSuffix) ? true : false; } + + /// Returns true if this token contains a universal character name. + bool hasUCN() const { return (Flags & HasUCN) ? true : false; } + + /// Returns true if this token is formed by macro by stringizing or charizing + /// operator. + bool stringifiedInMacro() const { + return (Flags & StringifiedInMacro) ? true : false; + } +}; + +/// \brief Information about the conditional stack (\#if directives) +/// currently active. +struct PPConditionalInfo { + /// \brief Location where the conditional started. + SourceLocation IfLoc; + + /// \brief True if this was contained in a skipping directive, e.g., + /// in a "\#if 0" block. + bool WasSkipping; + + /// \brief True if we have emitted tokens already, and now we're in + /// an \#else block or something. Only useful in Skipping blocks. + bool FoundNonSkip; + + /// \brief True if we've seen a \#else in this block. If so, + /// \#elif/\#else directives are not allowed. + bool FoundElse; +}; + +} // end namespace clang + +namespace llvm { + template <> + struct isPodLike<clang::Token> { static const bool value = true; }; +} // end namespace llvm + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Lex/TokenConcatenation.h b/contrib/llvm/tools/clang/include/clang/Lex/TokenConcatenation.h new file mode 100644 index 0000000..a2d98b0 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Lex/TokenConcatenation.h @@ -0,0 +1,72 @@ +//===--- TokenConcatenation.h - Token Concatenation Avoidance ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TokenConcatenation class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_TOKENCONCATENATION_H +#define LLVM_CLANG_LEX_TOKENCONCATENATION_H + +#include "clang/Basic/TokenKinds.h" + +namespace clang { + class Preprocessor; + class Token; + + /// TokenConcatenation class, which answers the question of + /// "Is it safe to emit two tokens without a whitespace between them, or + /// would that cause implicit concatenation of the tokens?" + /// + /// For example, it emitting two identifiers "foo" and "bar" next to each + /// other would cause the lexer to produce one "foobar" token. Emitting "1" + /// and ")" next to each other is safe. + /// + class TokenConcatenation { + Preprocessor &PP; + + enum AvoidConcatInfo { + /// By default, a token never needs to avoid concatenation. Most tokens + /// (e.g. ',', ')', etc) don't cause a problem when concatenated. + aci_never_avoid_concat = 0, + + /// aci_custom_firstchar - AvoidConcat contains custom code to handle this + /// token's requirements, and it needs to know the first character of the + /// token. + aci_custom_firstchar = 1, + + /// aci_custom - AvoidConcat contains custom code to handle this token's + /// requirements, but it doesn't need to know the first character of the + /// token. + aci_custom = 2, + + /// aci_avoid_equal - Many tokens cannot be safely followed by an '=' + /// character. For example, "<<" turns into "<<=" when followed by an =. + aci_avoid_equal = 4 + }; + + /// TokenInfo - This array contains information for each token on what + /// action to take when avoiding concatenation of tokens in the AvoidConcat + /// method. + char TokenInfo[tok::NUM_TOKENS]; + public: + TokenConcatenation(Preprocessor &PP); + + bool AvoidConcat(const Token &PrevPrevTok, + const Token &PrevTok, + const Token &Tok) const; + + private: + /// IsIdentifierStringPrefix - Return true if the spelling of the token + /// is literally 'L', 'u', 'U', or 'u8'. + bool IsIdentifierStringPrefix(const Token &Tok) const; + }; + } // end clang namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Lex/TokenLexer.h b/contrib/llvm/tools/clang/include/clang/Lex/TokenLexer.h new file mode 100644 index 0000000..fdeed44 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Lex/TokenLexer.h @@ -0,0 +1,205 @@ +//===--- TokenLexer.h - Lex from a token buffer -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TokenLexer interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_TOKENLEXER_H +#define LLVM_CLANG_LEX_TOKENLEXER_H + +#include "clang/Basic/SourceLocation.h" + +namespace clang { + class MacroInfo; + class Preprocessor; + class Token; + class MacroArgs; + +/// TokenLexer - This implements a lexer that returns tokens from a macro body +/// or token stream instead of lexing from a character buffer. This is used for +/// macro expansion and _Pragma handling, for example. +/// +class TokenLexer { + /// Macro - The macro we are expanding from. This is null if expanding a + /// token stream. + /// + MacroInfo *Macro; + + /// ActualArgs - The actual arguments specified for a function-like macro, or + /// null. The TokenLexer owns the pointed-to object. + MacroArgs *ActualArgs; + + /// PP - The current preprocessor object we are expanding for. + /// + Preprocessor &PP; + + /// Tokens - This is the pointer to an array of tokens that the macro is + /// defined to, with arguments expanded for function-like macros. If this is + /// a token stream, these are the tokens we are returning. This points into + /// the macro definition we are lexing from, a cache buffer that is owned by + /// the preprocessor, or some other buffer that we may or may not own + /// (depending on OwnsTokens). + /// Note that if it points into Preprocessor's cache buffer, the Preprocessor + /// may update the pointer as needed. + const Token *Tokens; + friend class Preprocessor; + + /// NumTokens - This is the length of the Tokens array. + /// + unsigned NumTokens; + + /// CurToken - This is the next token that Lex will return. + /// + unsigned CurToken; + + /// ExpandLocStart/End - The source location range where this macro was + /// expanded. + SourceLocation ExpandLocStart, ExpandLocEnd; + + /// \brief Source location pointing at the source location entry chunk that + /// was reserved for the current macro expansion. + SourceLocation MacroExpansionStart; + + /// \brief The offset of the macro expansion in the + /// "source location address space". + unsigned MacroStartSLocOffset; + + /// \brief Location of the macro definition. + SourceLocation MacroDefStart; + /// \brief Length of the macro definition. + unsigned MacroDefLength; + + /// Lexical information about the expansion point of the macro: the identifier + /// that the macro expanded from had these properties. + bool AtStartOfLine : 1; + bool HasLeadingSpace : 1; + + // NextTokGetsSpace - When this is true, the next token appended to the + // output list during function argument expansion will get a leading space, + // regardless of whether it had one to begin with or not. This is used for + // placemarker support. If still true after function argument expansion, the + // leading space will be applied to the first token following the macro + // expansion. + bool NextTokGetsSpace : 1; + + /// OwnsTokens - This is true if this TokenLexer allocated the Tokens + /// array, and thus needs to free it when destroyed. For simple object-like + /// macros (for example) we just point into the token buffer of the macro + /// definition, we don't make a copy of it. + bool OwnsTokens : 1; + + /// DisableMacroExpansion - This is true when tokens lexed from the TokenLexer + /// should not be subject to further macro expansion. + bool DisableMacroExpansion : 1; + + TokenLexer(const TokenLexer &) = delete; + void operator=(const TokenLexer &) = delete; +public: + /// Create a TokenLexer for the specified macro with the specified actual + /// arguments. Note that this ctor takes ownership of the ActualArgs pointer. + /// ILEnd specifies the location of the ')' for a function-like macro or the + /// identifier for an object-like macro. + TokenLexer(Token &Tok, SourceLocation ILEnd, MacroInfo *MI, + MacroArgs *ActualArgs, Preprocessor &pp) + : Macro(nullptr), ActualArgs(nullptr), PP(pp), OwnsTokens(false) { + Init(Tok, ILEnd, MI, ActualArgs); + } + + /// Init - Initialize this TokenLexer to expand from the specified macro + /// with the specified argument information. Note that this ctor takes + /// ownership of the ActualArgs pointer. ILEnd specifies the location of the + /// ')' for a function-like macro or the identifier for an object-like macro. + void Init(Token &Tok, SourceLocation ILEnd, MacroInfo *MI, + MacroArgs *ActualArgs); + + /// Create a TokenLexer for the specified token stream. If 'OwnsTokens' is + /// specified, this takes ownership of the tokens and delete[]'s them when + /// the token lexer is empty. + TokenLexer(const Token *TokArray, unsigned NumToks, bool DisableExpansion, + bool ownsTokens, Preprocessor &pp) + : Macro(nullptr), ActualArgs(nullptr), PP(pp), OwnsTokens(false) { + Init(TokArray, NumToks, DisableExpansion, ownsTokens); + } + + /// Init - Initialize this TokenLexer with the specified token stream. + /// This does not take ownership of the specified token vector. + /// + /// DisableExpansion is true when macro expansion of tokens lexed from this + /// stream should be disabled. + void Init(const Token *TokArray, unsigned NumToks, + bool DisableMacroExpansion, bool OwnsTokens); + + ~TokenLexer() { destroy(); } + + /// isNextTokenLParen - If the next token lexed will pop this macro off the + /// expansion stack, return 2. If the next unexpanded token is a '(', return + /// 1, otherwise return 0. + unsigned isNextTokenLParen() const; + + /// Lex - Lex and return a token from this macro stream. + bool Lex(Token &Tok); + + /// isParsingPreprocessorDirective - Return true if we are in the middle of a + /// preprocessor directive. + bool isParsingPreprocessorDirective() const; + +private: + void destroy(); + + /// isAtEnd - Return true if the next lex call will pop this macro off the + /// include stack. + bool isAtEnd() const { + return CurToken == NumTokens; + } + + /// PasteTokens - Tok is the LHS of a ## operator, and CurToken is the ## + /// operator. Read the ## and RHS, and paste the LHS/RHS together. If there + /// are is another ## after it, chomp it iteratively. Return the result as + /// Tok. If this returns true, the caller should immediately return the + /// token. + bool PasteTokens(Token &Tok); + + /// Expand the arguments of a function-like macro so that we can quickly + /// return preexpanded tokens from Tokens. + void ExpandFunctionArguments(); + + /// HandleMicrosoftCommentPaste - In microsoft compatibility mode, /##/ pastes + /// together to form a comment that comments out everything in the current + /// macro, other active macros, and anything left on the current physical + /// source line of the expanded buffer. Handle this by returning the + /// first token on the next line. + void HandleMicrosoftCommentPaste(Token &Tok, SourceLocation OpLoc); + + /// \brief If \p loc is a FileID and points inside the current macro + /// definition, returns the appropriate source location pointing at the + /// macro expansion source location entry. + SourceLocation getExpansionLocForMacroDefLoc(SourceLocation loc) const; + + /// \brief Creates SLocEntries and updates the locations of macro argument + /// tokens to their new expanded locations. + /// + /// \param ArgIdSpellLoc the location of the macro argument id inside the + /// macro definition. + void updateLocForMacroArgTokens(SourceLocation ArgIdSpellLoc, + Token *begin_tokens, Token *end_tokens); + + /// Remove comma ahead of __VA_ARGS__, if present, according to compiler + /// dialect settings. Returns true if the comma is removed. + bool MaybeRemoveCommaBeforeVaArgs(SmallVectorImpl<Token> &ResultToks, + bool HasPasteOperator, + MacroInfo *Macro, unsigned MacroArgNo, + Preprocessor &PP); + + void PropagateLineStartLeadingSpaceInfo(Token &Result); +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Parse/ParseAST.h b/contrib/llvm/tools/clang/include/clang/Parse/ParseAST.h new file mode 100644 index 0000000..21f9701 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Parse/ParseAST.h @@ -0,0 +1,49 @@ +//===--- ParseAST.h - Define the ParseAST method ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the clang::ParseAST method. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PARSE_PARSEAST_H +#define LLVM_CLANG_PARSE_PARSEAST_H + +#include "clang/Basic/LangOptions.h" + +namespace clang { + class Preprocessor; + class ASTConsumer; + class ASTContext; + class CodeCompleteConsumer; + class Sema; + + /// \brief Parse the entire file specified, notifying the ASTConsumer as + /// the file is parsed. + /// + /// This operation inserts the parsed decls into the translation + /// unit held by Ctx. + /// + /// \param TUKind The kind of translation unit being parsed. + /// + /// \param CompletionConsumer If given, an object to consume code completion + /// results. + void ParseAST(Preprocessor &pp, ASTConsumer *C, + ASTContext &Ctx, bool PrintStats = false, + TranslationUnitKind TUKind = TU_Complete, + CodeCompleteConsumer *CompletionConsumer = nullptr, + bool SkipFunctionBodies = false); + + /// \brief Parse the main file known to the preprocessor, producing an + /// abstract syntax tree. + void ParseAST(Sema &S, bool PrintStats = false, + bool SkipFunctionBodies = false); + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Parse/ParseDiagnostic.h b/contrib/llvm/tools/clang/include/clang/Parse/ParseDiagnostic.h new file mode 100644 index 0000000..f3a7f3b --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Parse/ParseDiagnostic.h @@ -0,0 +1,28 @@ +//===--- DiagnosticParse.h - Diagnostics for libparse -----------*- 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_PARSE_PARSEDIAGNOSTIC_H +#define LLVM_CLANG_PARSE_PARSEDIAGNOSTIC_H + +#include "clang/Basic/Diagnostic.h" + +namespace clang { + namespace diag { + enum { +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\ + SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM, +#define PARSESTART +#include "clang/Basic/DiagnosticParseKinds.inc" +#undef DIAG + NUM_BUILTIN_PARSE_DIAGNOSTICS + }; + } // end namespace diag +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Parse/Parser.h b/contrib/llvm/tools/clang/include/clang/Parse/Parser.h new file mode 100644 index 0000000..82b7798 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Parse/Parser.h @@ -0,0 +1,2593 @@ +//===--- Parser.h - C Language Parser ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Parser interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PARSE_PARSER_H +#define LLVM_CLANG_PARSE_PARSER_H + +#include "clang/Basic/OpenMPKinds.h" +#include "clang/Basic/OperatorPrecedence.h" +#include "clang/Basic/Specifiers.h" +#include "clang/Lex/CodeCompletionHandler.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/LoopHint.h" +#include "clang/Sema/Sema.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/SaveAndRestore.h" +#include <memory> +#include <stack> + +namespace clang { + class PragmaHandler; + class Scope; + class BalancedDelimiterTracker; + class CorrectionCandidateCallback; + class DeclGroupRef; + class DiagnosticBuilder; + class Parser; + class ParsingDeclRAIIObject; + class ParsingDeclSpec; + class ParsingDeclarator; + class ParsingFieldDeclarator; + class ColonProtectionRAIIObject; + class InMessageExpressionRAIIObject; + class PoisonSEHIdentifiersRAIIObject; + class VersionTuple; + class OMPClause; + class ObjCTypeParamList; + class ObjCTypeParameter; + +/// Parser - This implements a parser for the C family of languages. After +/// parsing units of the grammar, productions are invoked to handle whatever has +/// been read. +/// +class Parser : public CodeCompletionHandler { + friend class ColonProtectionRAIIObject; + friend class InMessageExpressionRAIIObject; + friend class PoisonSEHIdentifiersRAIIObject; + friend class ObjCDeclContextSwitch; + friend class ParenBraceBracketBalancer; + friend class BalancedDelimiterTracker; + + Preprocessor &PP; + + /// Tok - The current token we are peeking ahead. All parsing methods assume + /// that this is valid. + Token Tok; + + // PrevTokLocation - The location of the token we previously + // consumed. This token is used for diagnostics where we expected to + // see a token following another token (e.g., the ';' at the end of + // a statement). + SourceLocation PrevTokLocation; + + unsigned short ParenCount, BracketCount, BraceCount; + + /// Actions - These are the callbacks we invoke as we parse various constructs + /// in the file. + Sema &Actions; + + DiagnosticsEngine &Diags; + + /// ScopeCache - Cache scopes to reduce malloc traffic. + enum { ScopeCacheSize = 16 }; + unsigned NumCachedScopes; + Scope *ScopeCache[ScopeCacheSize]; + + /// Identifiers used for SEH handling in Borland. These are only + /// allowed in particular circumstances + // __except block + IdentifierInfo *Ident__exception_code, + *Ident___exception_code, + *Ident_GetExceptionCode; + // __except filter expression + IdentifierInfo *Ident__exception_info, + *Ident___exception_info, + *Ident_GetExceptionInfo; + // __finally + IdentifierInfo *Ident__abnormal_termination, + *Ident___abnormal_termination, + *Ident_AbnormalTermination; + + /// Contextual keywords for Microsoft extensions. + IdentifierInfo *Ident__except; + mutable IdentifierInfo *Ident_sealed; + + /// Ident_super - IdentifierInfo for "super", to support fast + /// comparison. + IdentifierInfo *Ident_super; + /// Ident_vector, Ident_bool - cached IdentifierInfos for "vector" and + /// "bool" fast comparison. Only present if AltiVec or ZVector are enabled. + IdentifierInfo *Ident_vector; + IdentifierInfo *Ident_bool; + /// Ident_pixel - cached IdentifierInfos for "pixel" fast comparison. + /// Only present if AltiVec enabled. + IdentifierInfo *Ident_pixel; + + /// Objective-C contextual keywords. + mutable IdentifierInfo *Ident_instancetype; + + /// \brief Identifier for "introduced". + IdentifierInfo *Ident_introduced; + + /// \brief Identifier for "deprecated". + IdentifierInfo *Ident_deprecated; + + /// \brief Identifier for "obsoleted". + IdentifierInfo *Ident_obsoleted; + + /// \brief Identifier for "unavailable". + IdentifierInfo *Ident_unavailable; + + /// \brief Identifier for "message". + IdentifierInfo *Ident_message; + + /// C++0x contextual keywords. + mutable IdentifierInfo *Ident_final; + mutable IdentifierInfo *Ident_override; + + // C++ type trait keywords that can be reverted to identifiers and still be + // used as type traits. + llvm::SmallDenseMap<IdentifierInfo *, tok::TokenKind> RevertibleTypeTraits; + + std::unique_ptr<PragmaHandler> AlignHandler; + std::unique_ptr<PragmaHandler> GCCVisibilityHandler; + std::unique_ptr<PragmaHandler> OptionsHandler; + std::unique_ptr<PragmaHandler> PackHandler; + std::unique_ptr<PragmaHandler> MSStructHandler; + std::unique_ptr<PragmaHandler> UnusedHandler; + std::unique_ptr<PragmaHandler> WeakHandler; + std::unique_ptr<PragmaHandler> RedefineExtnameHandler; + std::unique_ptr<PragmaHandler> FPContractHandler; + std::unique_ptr<PragmaHandler> OpenCLExtensionHandler; + std::unique_ptr<PragmaHandler> OpenMPHandler; + std::unique_ptr<PragmaHandler> MSCommentHandler; + std::unique_ptr<PragmaHandler> MSDetectMismatchHandler; + std::unique_ptr<PragmaHandler> MSPointersToMembers; + std::unique_ptr<PragmaHandler> MSVtorDisp; + std::unique_ptr<PragmaHandler> MSInitSeg; + std::unique_ptr<PragmaHandler> MSDataSeg; + std::unique_ptr<PragmaHandler> MSBSSSeg; + std::unique_ptr<PragmaHandler> MSConstSeg; + std::unique_ptr<PragmaHandler> MSCodeSeg; + std::unique_ptr<PragmaHandler> MSSection; + std::unique_ptr<PragmaHandler> MSRuntimeChecks; + std::unique_ptr<PragmaHandler> OptimizeHandler; + std::unique_ptr<PragmaHandler> LoopHintHandler; + std::unique_ptr<PragmaHandler> UnrollHintHandler; + std::unique_ptr<PragmaHandler> NoUnrollHintHandler; + + std::unique_ptr<CommentHandler> CommentSemaHandler; + + /// Whether the '>' token acts as an operator or not. This will be + /// true except when we are parsing an expression within a C++ + /// template argument list, where the '>' closes the template + /// argument list. + bool GreaterThanIsOperator; + + /// ColonIsSacred - When this is false, we aggressively try to recover from + /// code like "foo : bar" as if it were a typo for "foo :: bar". This is not + /// safe in case statements and a few other things. This is managed by the + /// ColonProtectionRAIIObject RAII object. + bool ColonIsSacred; + + /// \brief When true, we are directly inside an Objective-C message + /// send expression. + /// + /// This is managed by the \c InMessageExpressionRAIIObject class, and + /// should not be set directly. + bool InMessageExpression; + + /// The "depth" of the template parameters currently being parsed. + unsigned TemplateParameterDepth; + + /// \brief RAII class that manages the template parameter depth. + class TemplateParameterDepthRAII { + unsigned &Depth; + unsigned AddedLevels; + public: + explicit TemplateParameterDepthRAII(unsigned &Depth) + : Depth(Depth), AddedLevels(0) {} + + ~TemplateParameterDepthRAII() { + Depth -= AddedLevels; + } + + void operator++() { + ++Depth; + ++AddedLevels; + } + void addDepth(unsigned D) { + Depth += D; + AddedLevels += D; + } + unsigned getDepth() const { return Depth; } + }; + + /// Factory object for creating AttributeList objects. + AttributeFactory AttrFactory; + + /// \brief Gathers and cleans up TemplateIdAnnotations when parsing of a + /// top-level declaration is finished. + SmallVector<TemplateIdAnnotation *, 16> TemplateIds; + + /// \brief Identifiers which have been declared within a tentative parse. + SmallVector<IdentifierInfo *, 8> TentativelyDeclaredIdentifiers; + + IdentifierInfo *getSEHExceptKeyword(); + + /// True if we are within an Objective-C container while parsing C-like decls. + /// + /// This is necessary because Sema thinks we have left the container + /// to parse the C-like decls, meaning Actions.getObjCDeclContext() will + /// be NULL. + bool ParsingInObjCContainer; + + bool SkipFunctionBodies; + +public: + Parser(Preprocessor &PP, Sema &Actions, bool SkipFunctionBodies); + ~Parser() override; + + const LangOptions &getLangOpts() const { return PP.getLangOpts(); } + const TargetInfo &getTargetInfo() const { return PP.getTargetInfo(); } + Preprocessor &getPreprocessor() const { return PP; } + Sema &getActions() const { return Actions; } + AttributeFactory &getAttrFactory() { return AttrFactory; } + + const Token &getCurToken() const { return Tok; } + Scope *getCurScope() const { return Actions.getCurScope(); } + void incrementMSManglingNumber() const { + return Actions.incrementMSManglingNumber(); + } + + Decl *getObjCDeclContext() const { return Actions.getObjCDeclContext(); } + + // Type forwarding. All of these are statically 'void*', but they may all be + // different actual classes based on the actions in place. + typedef OpaquePtr<DeclGroupRef> DeclGroupPtrTy; + typedef OpaquePtr<TemplateName> TemplateTy; + + typedef SmallVector<TemplateParameterList *, 4> TemplateParameterLists; + + typedef Sema::FullExprArg FullExprArg; + + // Parsing methods. + + /// Initialize - Warm up the parser. + /// + void Initialize(); + + /// ParseTopLevelDecl - Parse one top-level declaration. Returns true if + /// the EOF was encountered. + bool ParseTopLevelDecl(DeclGroupPtrTy &Result); + bool ParseTopLevelDecl() { + DeclGroupPtrTy Result; + return ParseTopLevelDecl(Result); + } + + /// ConsumeToken - Consume the current 'peek token' and lex the next one. + /// This does not work with special tokens: string literals, code completion + /// and balanced tokens must be handled using the specific consume methods. + /// Returns the location of the consumed token. + SourceLocation ConsumeToken() { + assert(!isTokenSpecial() && + "Should consume special tokens with Consume*Token"); + PrevTokLocation = Tok.getLocation(); + PP.Lex(Tok); + return PrevTokLocation; + } + + bool TryConsumeToken(tok::TokenKind Expected) { + if (Tok.isNot(Expected)) + return false; + assert(!isTokenSpecial() && + "Should consume special tokens with Consume*Token"); + PrevTokLocation = Tok.getLocation(); + PP.Lex(Tok); + return true; + } + + bool TryConsumeToken(tok::TokenKind Expected, SourceLocation &Loc) { + if (!TryConsumeToken(Expected)) + return false; + Loc = PrevTokLocation; + return true; + } + + /// Retrieve the underscored keyword (_Nonnull, _Nullable) that corresponds + /// to the given nullability kind. + IdentifierInfo *getNullabilityKeyword(NullabilityKind nullability) { + return Actions.getNullabilityKeyword(nullability); + } + +private: + //===--------------------------------------------------------------------===// + // Low-Level token peeking and consumption methods. + // + + /// isTokenParen - Return true if the cur token is '(' or ')'. + bool isTokenParen() const { + return Tok.getKind() == tok::l_paren || Tok.getKind() == tok::r_paren; + } + /// isTokenBracket - Return true if the cur token is '[' or ']'. + bool isTokenBracket() const { + return Tok.getKind() == tok::l_square || Tok.getKind() == tok::r_square; + } + /// isTokenBrace - Return true if the cur token is '{' or '}'. + bool isTokenBrace() const { + return Tok.getKind() == tok::l_brace || Tok.getKind() == tok::r_brace; + } + /// isTokenStringLiteral - True if this token is a string-literal. + bool isTokenStringLiteral() const { + return tok::isStringLiteral(Tok.getKind()); + } + /// isTokenSpecial - True if this token requires special consumption methods. + bool isTokenSpecial() const { + return isTokenStringLiteral() || isTokenParen() || isTokenBracket() || + isTokenBrace() || Tok.is(tok::code_completion); + } + + /// \brief Returns true if the current token is '=' or is a type of '='. + /// For typos, give a fixit to '=' + bool isTokenEqualOrEqualTypo(); + + /// \brief Return the current token to the token stream and make the given + /// token the current token. + void UnconsumeToken(Token &Consumed) { + Token Next = Tok; + PP.EnterToken(Consumed); + PP.Lex(Tok); + PP.EnterToken(Next); + } + + /// ConsumeAnyToken - Dispatch to the right Consume* method based on the + /// current token type. This should only be used in cases where the type of + /// the token really isn't known, e.g. in error recovery. + SourceLocation ConsumeAnyToken(bool ConsumeCodeCompletionTok = false) { + if (isTokenParen()) + return ConsumeParen(); + if (isTokenBracket()) + return ConsumeBracket(); + if (isTokenBrace()) + return ConsumeBrace(); + if (isTokenStringLiteral()) + return ConsumeStringToken(); + if (Tok.is(tok::code_completion)) + return ConsumeCodeCompletionTok ? ConsumeCodeCompletionToken() + : handleUnexpectedCodeCompletionToken(); + return ConsumeToken(); + } + + /// ConsumeParen - This consume method keeps the paren count up-to-date. + /// + SourceLocation ConsumeParen() { + assert(isTokenParen() && "wrong consume method"); + if (Tok.getKind() == tok::l_paren) + ++ParenCount; + else if (ParenCount) + --ParenCount; // Don't let unbalanced )'s drive the count negative. + PrevTokLocation = Tok.getLocation(); + PP.Lex(Tok); + return PrevTokLocation; + } + + /// ConsumeBracket - This consume method keeps the bracket count up-to-date. + /// + SourceLocation ConsumeBracket() { + assert(isTokenBracket() && "wrong consume method"); + if (Tok.getKind() == tok::l_square) + ++BracketCount; + else if (BracketCount) + --BracketCount; // Don't let unbalanced ]'s drive the count negative. + + PrevTokLocation = Tok.getLocation(); + PP.Lex(Tok); + return PrevTokLocation; + } + + /// ConsumeBrace - This consume method keeps the brace count up-to-date. + /// + SourceLocation ConsumeBrace() { + assert(isTokenBrace() && "wrong consume method"); + if (Tok.getKind() == tok::l_brace) + ++BraceCount; + else if (BraceCount) + --BraceCount; // Don't let unbalanced }'s drive the count negative. + + PrevTokLocation = Tok.getLocation(); + PP.Lex(Tok); + return PrevTokLocation; + } + + /// ConsumeStringToken - Consume the current 'peek token', lexing a new one + /// and returning the token kind. This method is specific to strings, as it + /// handles string literal concatenation, as per C99 5.1.1.2, translation + /// phase #6. + SourceLocation ConsumeStringToken() { + assert(isTokenStringLiteral() && + "Should only consume string literals with this method"); + PrevTokLocation = Tok.getLocation(); + PP.Lex(Tok); + return PrevTokLocation; + } + + /// \brief Consume the current code-completion token. + /// + /// This routine can be called to consume the code-completion token and + /// continue processing in special cases where \c cutOffParsing() isn't + /// desired, such as token caching or completion with lookahead. + SourceLocation ConsumeCodeCompletionToken() { + assert(Tok.is(tok::code_completion)); + PrevTokLocation = Tok.getLocation(); + PP.Lex(Tok); + return PrevTokLocation; + } + + ///\ brief When we are consuming a code-completion token without having + /// matched specific position in the grammar, provide code-completion results + /// based on context. + /// + /// \returns the source location of the code-completion token. + SourceLocation handleUnexpectedCodeCompletionToken(); + + /// \brief Abruptly cut off parsing; mainly used when we have reached the + /// code-completion point. + void cutOffParsing() { + if (PP.isCodeCompletionEnabled()) + PP.setCodeCompletionReached(); + // Cut off parsing by acting as if we reached the end-of-file. + Tok.setKind(tok::eof); + } + + /// \brief Determine if we're at the end of the file or at a transition + /// between modules. + bool isEofOrEom() { + tok::TokenKind Kind = Tok.getKind(); + return Kind == tok::eof || Kind == tok::annot_module_begin || + Kind == tok::annot_module_end || Kind == tok::annot_module_include; + } + + /// \brief Initialize all pragma handlers. + void initializePragmaHandlers(); + + /// \brief Destroy and reset all pragma handlers. + void resetPragmaHandlers(); + + /// \brief Handle the annotation token produced for #pragma unused(...) + void HandlePragmaUnused(); + + /// \brief Handle the annotation token produced for + /// #pragma GCC visibility... + void HandlePragmaVisibility(); + + /// \brief Handle the annotation token produced for + /// #pragma pack... + void HandlePragmaPack(); + + /// \brief Handle the annotation token produced for + /// #pragma ms_struct... + void HandlePragmaMSStruct(); + + /// \brief Handle the annotation token produced for + /// #pragma comment... + void HandlePragmaMSComment(); + + void HandlePragmaMSPointersToMembers(); + + void HandlePragmaMSVtorDisp(); + + void HandlePragmaMSPragma(); + bool HandlePragmaMSSection(StringRef PragmaName, + SourceLocation PragmaLocation); + bool HandlePragmaMSSegment(StringRef PragmaName, + SourceLocation PragmaLocation); + bool HandlePragmaMSInitSeg(StringRef PragmaName, + SourceLocation PragmaLocation); + + /// \brief Handle the annotation token produced for + /// #pragma align... + void HandlePragmaAlign(); + + /// \brief Handle the annotation token produced for + /// #pragma weak id... + void HandlePragmaWeak(); + + /// \brief Handle the annotation token produced for + /// #pragma weak id = id... + void HandlePragmaWeakAlias(); + + /// \brief Handle the annotation token produced for + /// #pragma redefine_extname... + void HandlePragmaRedefineExtname(); + + /// \brief Handle the annotation token produced for + /// #pragma STDC FP_CONTRACT... + void HandlePragmaFPContract(); + + /// \brief Handle the annotation token produced for + /// #pragma OPENCL EXTENSION... + void HandlePragmaOpenCLExtension(); + + /// \brief Handle the annotation token produced for + /// #pragma clang __debug captured + StmtResult HandlePragmaCaptured(); + + /// \brief Handle the annotation token produced for + /// #pragma clang loop and #pragma unroll. + bool HandlePragmaLoopHint(LoopHint &Hint); + + /// GetLookAheadToken - This peeks ahead N tokens and returns that token + /// without consuming any tokens. LookAhead(0) returns 'Tok', LookAhead(1) + /// returns the token after Tok, etc. + /// + /// Note that this differs from the Preprocessor's LookAhead method, because + /// the Parser always has one token lexed that the preprocessor doesn't. + /// + const Token &GetLookAheadToken(unsigned N) { + if (N == 0 || Tok.is(tok::eof)) return Tok; + return PP.LookAhead(N-1); + } + +public: + /// NextToken - This peeks ahead one token and returns it without + /// consuming it. + const Token &NextToken() { + return PP.LookAhead(0); + } + + /// getTypeAnnotation - Read a parsed type out of an annotation token. + static ParsedType getTypeAnnotation(Token &Tok) { + return ParsedType::getFromOpaquePtr(Tok.getAnnotationValue()); + } + +private: + static void setTypeAnnotation(Token &Tok, ParsedType T) { + Tok.setAnnotationValue(T.getAsOpaquePtr()); + } + + /// \brief Read an already-translated primary expression out of an annotation + /// token. + static ExprResult getExprAnnotation(Token &Tok) { + return ExprResult::getFromOpaquePointer(Tok.getAnnotationValue()); + } + + /// \brief Set the primary expression corresponding to the given annotation + /// token. + static void setExprAnnotation(Token &Tok, ExprResult ER) { + Tok.setAnnotationValue(ER.getAsOpaquePointer()); + } + +public: + // If NeedType is true, then TryAnnotateTypeOrScopeToken will try harder to + // find a type name by attempting typo correction. + bool TryAnnotateTypeOrScopeToken(bool EnteringContext = false, + bool NeedType = false); + bool TryAnnotateTypeOrScopeTokenAfterScopeSpec(bool EnteringContext, + bool NeedType, + CXXScopeSpec &SS, + bool IsNewScope); + bool TryAnnotateCXXScopeToken(bool EnteringContext = false); + +private: + enum AnnotatedNameKind { + /// Annotation has failed and emitted an error. + ANK_Error, + /// The identifier is a tentatively-declared name. + ANK_TentativeDecl, + /// The identifier is a template name. FIXME: Add an annotation for that. + ANK_TemplateName, + /// The identifier can't be resolved. + ANK_Unresolved, + /// Annotation was successful. + ANK_Success + }; + AnnotatedNameKind + TryAnnotateName(bool IsAddressOfOperand, + std::unique_ptr<CorrectionCandidateCallback> CCC = nullptr); + + /// Push a tok::annot_cxxscope token onto the token stream. + void AnnotateScopeToken(CXXScopeSpec &SS, bool IsNewAnnotation); + + /// TryAltiVecToken - Check for context-sensitive AltiVec identifier tokens, + /// replacing them with the non-context-sensitive keywords. This returns + /// true if the token was replaced. + bool TryAltiVecToken(DeclSpec &DS, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID, + bool &isInvalid) { + if (!getLangOpts().AltiVec && !getLangOpts().ZVector) + return false; + + if (Tok.getIdentifierInfo() != Ident_vector && + Tok.getIdentifierInfo() != Ident_bool && + (!getLangOpts().AltiVec || Tok.getIdentifierInfo() != Ident_pixel)) + return false; + + return TryAltiVecTokenOutOfLine(DS, Loc, PrevSpec, DiagID, isInvalid); + } + + /// TryAltiVecVectorToken - Check for context-sensitive AltiVec vector + /// identifier token, replacing it with the non-context-sensitive __vector. + /// This returns true if the token was replaced. + bool TryAltiVecVectorToken() { + if ((!getLangOpts().AltiVec && !getLangOpts().ZVector) || + Tok.getIdentifierInfo() != Ident_vector) return false; + return TryAltiVecVectorTokenOutOfLine(); + } + + bool TryAltiVecVectorTokenOutOfLine(); + bool TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID, + bool &isInvalid); + + /// Returns true if the current token is the identifier 'instancetype'. + /// + /// Should only be used in Objective-C language modes. + bool isObjCInstancetype() { + assert(getLangOpts().ObjC1); + if (!Ident_instancetype) + Ident_instancetype = PP.getIdentifierInfo("instancetype"); + return Tok.getIdentifierInfo() == Ident_instancetype; + } + + /// TryKeywordIdentFallback - For compatibility with system headers using + /// keywords as identifiers, attempt to convert the current token to an + /// identifier and optionally disable the keyword for the remainder of the + /// translation unit. This returns false if the token was not replaced, + /// otherwise emits a diagnostic and returns true. + bool TryKeywordIdentFallback(bool DisableKeyword); + + /// \brief Get the TemplateIdAnnotation from the token. + TemplateIdAnnotation *takeTemplateIdAnnotation(const Token &tok); + + /// TentativeParsingAction - An object that is used as a kind of "tentative + /// parsing transaction". It gets instantiated to mark the token position and + /// after the token consumption is done, Commit() or Revert() is called to + /// either "commit the consumed tokens" or revert to the previously marked + /// token position. Example: + /// + /// TentativeParsingAction TPA(*this); + /// ConsumeToken(); + /// .... + /// TPA.Revert(); + /// + class TentativeParsingAction { + Parser &P; + Token PrevTok; + size_t PrevTentativelyDeclaredIdentifierCount; + unsigned short PrevParenCount, PrevBracketCount, PrevBraceCount; + bool isActive; + + public: + explicit TentativeParsingAction(Parser& p) : P(p) { + PrevTok = P.Tok; + PrevTentativelyDeclaredIdentifierCount = + P.TentativelyDeclaredIdentifiers.size(); + PrevParenCount = P.ParenCount; + PrevBracketCount = P.BracketCount; + PrevBraceCount = P.BraceCount; + P.PP.EnableBacktrackAtThisPos(); + isActive = true; + } + void Commit() { + assert(isActive && "Parsing action was finished!"); + P.TentativelyDeclaredIdentifiers.resize( + PrevTentativelyDeclaredIdentifierCount); + P.PP.CommitBacktrackedTokens(); + isActive = false; + } + void Revert() { + assert(isActive && "Parsing action was finished!"); + P.PP.Backtrack(); + P.Tok = PrevTok; + P.TentativelyDeclaredIdentifiers.resize( + PrevTentativelyDeclaredIdentifierCount); + P.ParenCount = PrevParenCount; + P.BracketCount = PrevBracketCount; + P.BraceCount = PrevBraceCount; + isActive = false; + } + ~TentativeParsingAction() { + assert(!isActive && "Forgot to call Commit or Revert!"); + } + }; + class UnannotatedTentativeParsingAction; + + /// ObjCDeclContextSwitch - An object used to switch context from + /// an objective-c decl context to its enclosing decl context and + /// back. + class ObjCDeclContextSwitch { + Parser &P; + Decl *DC; + SaveAndRestore<bool> WithinObjCContainer; + public: + explicit ObjCDeclContextSwitch(Parser &p) + : P(p), DC(p.getObjCDeclContext()), + WithinObjCContainer(P.ParsingInObjCContainer, DC != nullptr) { + if (DC) + P.Actions.ActOnObjCTemporaryExitContainerContext(cast<DeclContext>(DC)); + } + ~ObjCDeclContextSwitch() { + if (DC) + P.Actions.ActOnObjCReenterContainerContext(cast<DeclContext>(DC)); + } + }; + + /// ExpectAndConsume - The parser expects that 'ExpectedTok' is next in the + /// input. If so, it is consumed and false is returned. + /// + /// If a trivial punctuator misspelling is encountered, a FixIt error + /// diagnostic is issued and false is returned after recovery. + /// + /// If the input is malformed, this emits the specified diagnostic and true is + /// returned. + bool ExpectAndConsume(tok::TokenKind ExpectedTok, + unsigned Diag = diag::err_expected, + StringRef DiagMsg = ""); + + /// \brief The parser expects a semicolon and, if present, will consume it. + /// + /// If the next token is not a semicolon, this emits the specified diagnostic, + /// or, if there's just some closing-delimiter noise (e.g., ')' or ']') prior + /// to the semicolon, consumes that extra token. + bool ExpectAndConsumeSemi(unsigned DiagID); + + /// \brief The kind of extra semi diagnostic to emit. + enum ExtraSemiKind { + OutsideFunction = 0, + InsideStruct = 1, + InstanceVariableList = 2, + AfterMemberFunctionDefinition = 3 + }; + + /// \brief Consume any extra semi-colons until the end of the line. + void ConsumeExtraSemi(ExtraSemiKind Kind, unsigned TST = TST_unspecified); + +public: + //===--------------------------------------------------------------------===// + // Scope manipulation + + /// ParseScope - Introduces a new scope for parsing. The kind of + /// scope is determined by ScopeFlags. Objects of this type should + /// be created on the stack to coincide with the position where the + /// parser enters the new scope, and this object's constructor will + /// create that new scope. Similarly, once the object is destroyed + /// the parser will exit the scope. + class ParseScope { + Parser *Self; + ParseScope(const ParseScope &) = delete; + void operator=(const ParseScope &) = delete; + + public: + // ParseScope - Construct a new object to manage a scope in the + // parser Self where the new Scope is created with the flags + // ScopeFlags, but only when we aren't about to enter a compound statement. + ParseScope(Parser *Self, unsigned ScopeFlags, bool EnteredScope = true, + bool BeforeCompoundStmt = false) + : Self(Self) { + if (EnteredScope && !BeforeCompoundStmt) + Self->EnterScope(ScopeFlags); + else { + if (BeforeCompoundStmt) + Self->incrementMSManglingNumber(); + + this->Self = nullptr; + } + } + + // Exit - Exit the scope associated with this object now, rather + // than waiting until the object is destroyed. + void Exit() { + if (Self) { + Self->ExitScope(); + Self = nullptr; + } + } + + ~ParseScope() { + Exit(); + } + }; + + /// EnterScope - Start a new scope. + void EnterScope(unsigned ScopeFlags); + + /// ExitScope - Pop a scope off the scope stack. + void ExitScope(); + +private: + /// \brief RAII object used to modify the scope flags for the current scope. + class ParseScopeFlags { + Scope *CurScope; + unsigned OldFlags; + ParseScopeFlags(const ParseScopeFlags &) = delete; + void operator=(const ParseScopeFlags &) = delete; + + public: + ParseScopeFlags(Parser *Self, unsigned ScopeFlags, bool ManageFlags = true); + ~ParseScopeFlags(); + }; + + //===--------------------------------------------------------------------===// + // Diagnostic Emission and Error recovery. + +public: + DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID); + DiagnosticBuilder Diag(const Token &Tok, unsigned DiagID); + DiagnosticBuilder Diag(unsigned DiagID) { + return Diag(Tok, DiagID); + } + +private: + void SuggestParentheses(SourceLocation Loc, unsigned DK, + SourceRange ParenRange); + void CheckNestedObjCContexts(SourceLocation AtLoc); + +public: + + /// \brief Control flags for SkipUntil functions. + enum SkipUntilFlags { + StopAtSemi = 1 << 0, ///< Stop skipping at semicolon + /// \brief Stop skipping at specified token, but don't skip the token itself + StopBeforeMatch = 1 << 1, + StopAtCodeCompletion = 1 << 2 ///< Stop at code completion + }; + + friend LLVM_CONSTEXPR SkipUntilFlags operator|(SkipUntilFlags L, + SkipUntilFlags R) { + return static_cast<SkipUntilFlags>(static_cast<unsigned>(L) | + static_cast<unsigned>(R)); + } + + /// SkipUntil - Read tokens until we get to the specified token, then consume + /// it (unless StopBeforeMatch is specified). Because we cannot guarantee + /// that the token will ever occur, this skips to the next token, or to some + /// likely good stopping point. If Flags has StopAtSemi flag, skipping will + /// stop at a ';' character. + /// + /// If SkipUntil finds the specified token, it returns true, otherwise it + /// returns false. + bool SkipUntil(tok::TokenKind T, + SkipUntilFlags Flags = static_cast<SkipUntilFlags>(0)) { + return SkipUntil(llvm::makeArrayRef(T), Flags); + } + bool SkipUntil(tok::TokenKind T1, tok::TokenKind T2, + SkipUntilFlags Flags = static_cast<SkipUntilFlags>(0)) { + tok::TokenKind TokArray[] = {T1, T2}; + return SkipUntil(TokArray, Flags); + } + bool SkipUntil(tok::TokenKind T1, tok::TokenKind T2, tok::TokenKind T3, + SkipUntilFlags Flags = static_cast<SkipUntilFlags>(0)) { + tok::TokenKind TokArray[] = {T1, T2, T3}; + return SkipUntil(TokArray, Flags); + } + bool SkipUntil(ArrayRef<tok::TokenKind> Toks, + SkipUntilFlags Flags = static_cast<SkipUntilFlags>(0)); + + /// SkipMalformedDecl - Read tokens until we get to some likely good stopping + /// point for skipping past a simple-declaration. + void SkipMalformedDecl(); + +private: + //===--------------------------------------------------------------------===// + // Lexing and parsing of C++ inline methods. + + struct ParsingClass; + + /// [class.mem]p1: "... the class is regarded as complete within + /// - function bodies + /// - default arguments + /// - exception-specifications (TODO: C++0x) + /// - and brace-or-equal-initializers for non-static data members + /// (including such things in nested classes)." + /// LateParsedDeclarations build the tree of those elements so they can + /// be parsed after parsing the top-level class. + class LateParsedDeclaration { + public: + virtual ~LateParsedDeclaration(); + + virtual void ParseLexedMethodDeclarations(); + virtual void ParseLexedMemberInitializers(); + virtual void ParseLexedMethodDefs(); + virtual void ParseLexedAttributes(); + }; + + /// Inner node of the LateParsedDeclaration tree that parses + /// all its members recursively. + class LateParsedClass : public LateParsedDeclaration { + public: + LateParsedClass(Parser *P, ParsingClass *C); + ~LateParsedClass() override; + + void ParseLexedMethodDeclarations() override; + void ParseLexedMemberInitializers() override; + void ParseLexedMethodDefs() override; + void ParseLexedAttributes() override; + + private: + Parser *Self; + ParsingClass *Class; + }; + + /// Contains the lexed tokens of an attribute with arguments that + /// may reference member variables and so need to be parsed at the + /// end of the class declaration after parsing all other member + /// member declarations. + /// FIXME: Perhaps we should change the name of LateParsedDeclaration to + /// LateParsedTokens. + struct LateParsedAttribute : public LateParsedDeclaration { + Parser *Self; + CachedTokens Toks; + IdentifierInfo &AttrName; + SourceLocation AttrNameLoc; + SmallVector<Decl*, 2> Decls; + + explicit LateParsedAttribute(Parser *P, IdentifierInfo &Name, + SourceLocation Loc) + : Self(P), AttrName(Name), AttrNameLoc(Loc) {} + + void ParseLexedAttributes() override; + + void addDecl(Decl *D) { Decls.push_back(D); } + }; + + // A list of late-parsed attributes. Used by ParseGNUAttributes. + class LateParsedAttrList: public SmallVector<LateParsedAttribute *, 2> { + public: + LateParsedAttrList(bool PSoon = false) : ParseSoon(PSoon) { } + + bool parseSoon() { return ParseSoon; } + + private: + bool ParseSoon; // Are we planning to parse these shortly after creation? + }; + + /// Contains the lexed tokens of a member function definition + /// which needs to be parsed at the end of the class declaration + /// after parsing all other member declarations. + struct LexedMethod : public LateParsedDeclaration { + Parser *Self; + Decl *D; + CachedTokens Toks; + + /// \brief Whether this member function had an associated template + /// scope. When true, D is a template declaration. + /// otherwise, it is a member function declaration. + bool TemplateScope; + + explicit LexedMethod(Parser* P, Decl *MD) + : Self(P), D(MD), TemplateScope(false) {} + + void ParseLexedMethodDefs() override; + }; + + /// LateParsedDefaultArgument - Keeps track of a parameter that may + /// have a default argument that cannot be parsed yet because it + /// occurs within a member function declaration inside the class + /// (C++ [class.mem]p2). + struct LateParsedDefaultArgument { + explicit LateParsedDefaultArgument(Decl *P, + CachedTokens *Toks = nullptr) + : Param(P), Toks(Toks) { } + + /// Param - The parameter declaration for this parameter. + Decl *Param; + + /// Toks - The sequence of tokens that comprises the default + /// argument expression, not including the '=' or the terminating + /// ')' or ','. This will be NULL for parameters that have no + /// default argument. + CachedTokens *Toks; + }; + + /// LateParsedMethodDeclaration - A method declaration inside a class that + /// contains at least one entity whose parsing needs to be delayed + /// until the class itself is completely-defined, such as a default + /// argument (C++ [class.mem]p2). + struct LateParsedMethodDeclaration : public LateParsedDeclaration { + explicit LateParsedMethodDeclaration(Parser *P, Decl *M) + : Self(P), Method(M), TemplateScope(false), + ExceptionSpecTokens(nullptr) {} + + void ParseLexedMethodDeclarations() override; + + Parser* Self; + + /// Method - The method declaration. + Decl *Method; + + /// \brief Whether this member function had an associated template + /// scope. When true, D is a template declaration. + /// othewise, it is a member function declaration. + bool TemplateScope; + + /// DefaultArgs - Contains the parameters of the function and + /// their default arguments. At least one of the parameters will + /// have a default argument, but all of the parameters of the + /// method will be stored so that they can be reintroduced into + /// scope at the appropriate times. + SmallVector<LateParsedDefaultArgument, 8> DefaultArgs; + + /// \brief The set of tokens that make up an exception-specification that + /// has not yet been parsed. + CachedTokens *ExceptionSpecTokens; + }; + + /// LateParsedMemberInitializer - An initializer for a non-static class data + /// member whose parsing must to be delayed until the class is completely + /// defined (C++11 [class.mem]p2). + struct LateParsedMemberInitializer : public LateParsedDeclaration { + LateParsedMemberInitializer(Parser *P, Decl *FD) + : Self(P), Field(FD) { } + + void ParseLexedMemberInitializers() override; + + Parser *Self; + + /// Field - The field declaration. + Decl *Field; + + /// CachedTokens - The sequence of tokens that comprises the initializer, + /// including any leading '='. + CachedTokens Toks; + }; + + /// LateParsedDeclarationsContainer - During parsing of a top (non-nested) + /// C++ class, its method declarations that contain parts that won't be + /// parsed until after the definition is completed (C++ [class.mem]p2), + /// the method declarations and possibly attached inline definitions + /// will be stored here with the tokens that will be parsed to create those + /// entities. + typedef SmallVector<LateParsedDeclaration*,2> LateParsedDeclarationsContainer; + + /// \brief Representation of a class that has been parsed, including + /// any member function declarations or definitions that need to be + /// parsed after the corresponding top-level class is complete. + struct ParsingClass { + ParsingClass(Decl *TagOrTemplate, bool TopLevelClass, bool IsInterface) + : TopLevelClass(TopLevelClass), TemplateScope(false), + IsInterface(IsInterface), TagOrTemplate(TagOrTemplate) { } + + /// \brief Whether this is a "top-level" class, meaning that it is + /// not nested within another class. + bool TopLevelClass : 1; + + /// \brief Whether this class had an associated template + /// scope. When true, TagOrTemplate is a template declaration; + /// othewise, it is a tag declaration. + bool TemplateScope : 1; + + /// \brief Whether this class is an __interface. + bool IsInterface : 1; + + /// \brief The class or class template whose definition we are parsing. + Decl *TagOrTemplate; + + /// LateParsedDeclarations - Method declarations, inline definitions and + /// nested classes that contain pieces whose parsing will be delayed until + /// the top-level class is fully defined. + LateParsedDeclarationsContainer LateParsedDeclarations; + }; + + /// \brief The stack of classes that is currently being + /// parsed. Nested and local classes will be pushed onto this stack + /// when they are parsed, and removed afterward. + std::stack<ParsingClass *> ClassStack; + + ParsingClass &getCurrentClass() { + assert(!ClassStack.empty() && "No lexed method stacks!"); + return *ClassStack.top(); + } + + /// \brief RAII object used to manage the parsing of a class definition. + class ParsingClassDefinition { + Parser &P; + bool Popped; + Sema::ParsingClassState State; + + public: + ParsingClassDefinition(Parser &P, Decl *TagOrTemplate, bool TopLevelClass, + bool IsInterface) + : P(P), Popped(false), + State(P.PushParsingClass(TagOrTemplate, TopLevelClass, IsInterface)) { + } + + /// \brief Pop this class of the stack. + void Pop() { + assert(!Popped && "Nested class has already been popped"); + Popped = true; + P.PopParsingClass(State); + } + + ~ParsingClassDefinition() { + if (!Popped) + P.PopParsingClass(State); + } + }; + + /// \brief Contains information about any template-specific + /// information that has been parsed prior to parsing declaration + /// specifiers. + struct ParsedTemplateInfo { + ParsedTemplateInfo() + : Kind(NonTemplate), TemplateParams(nullptr), TemplateLoc() { } + + ParsedTemplateInfo(TemplateParameterLists *TemplateParams, + bool isSpecialization, + bool lastParameterListWasEmpty = false) + : Kind(isSpecialization? ExplicitSpecialization : Template), + TemplateParams(TemplateParams), + LastParameterListWasEmpty(lastParameterListWasEmpty) { } + + explicit ParsedTemplateInfo(SourceLocation ExternLoc, + SourceLocation TemplateLoc) + : Kind(ExplicitInstantiation), TemplateParams(nullptr), + ExternLoc(ExternLoc), TemplateLoc(TemplateLoc), + LastParameterListWasEmpty(false){ } + + /// \brief The kind of template we are parsing. + enum { + /// \brief We are not parsing a template at all. + NonTemplate = 0, + /// \brief We are parsing a template declaration. + Template, + /// \brief We are parsing an explicit specialization. + ExplicitSpecialization, + /// \brief We are parsing an explicit instantiation. + ExplicitInstantiation + } Kind; + + /// \brief The template parameter lists, for template declarations + /// and explicit specializations. + TemplateParameterLists *TemplateParams; + + /// \brief The location of the 'extern' keyword, if any, for an explicit + /// instantiation + SourceLocation ExternLoc; + + /// \brief The location of the 'template' keyword, for an explicit + /// instantiation. + SourceLocation TemplateLoc; + + /// \brief Whether the last template parameter list was empty. + bool LastParameterListWasEmpty; + + SourceRange getSourceRange() const LLVM_READONLY; + }; + + void LexTemplateFunctionForLateParsing(CachedTokens &Toks); + void ParseLateTemplatedFuncDef(LateParsedTemplate &LPT); + + static void LateTemplateParserCallback(void *P, LateParsedTemplate &LPT); + static void LateTemplateParserCleanupCallback(void *P); + + Sema::ParsingClassState + PushParsingClass(Decl *TagOrTemplate, bool TopLevelClass, bool IsInterface); + void DeallocateParsedClasses(ParsingClass *Class); + void PopParsingClass(Sema::ParsingClassState); + + enum CachedInitKind { + CIK_DefaultArgument, + CIK_DefaultInitializer + }; + + NamedDecl *ParseCXXInlineMethodDef(AccessSpecifier AS, + AttributeList *AccessAttrs, + ParsingDeclarator &D, + const ParsedTemplateInfo &TemplateInfo, + const VirtSpecifiers& VS, + SourceLocation PureSpecLoc); + void ParseCXXNonStaticMemberInitializer(Decl *VarD); + void ParseLexedAttributes(ParsingClass &Class); + void ParseLexedAttributeList(LateParsedAttrList &LAs, Decl *D, + bool EnterScope, bool OnDefinition); + void ParseLexedAttribute(LateParsedAttribute &LA, + bool EnterScope, bool OnDefinition); + void ParseLexedMethodDeclarations(ParsingClass &Class); + void ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM); + void ParseLexedMethodDefs(ParsingClass &Class); + void ParseLexedMethodDef(LexedMethod &LM); + void ParseLexedMemberInitializers(ParsingClass &Class); + void ParseLexedMemberInitializer(LateParsedMemberInitializer &MI); + void ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod); + bool ConsumeAndStoreFunctionPrologue(CachedTokens &Toks); + bool ConsumeAndStoreInitializer(CachedTokens &Toks, CachedInitKind CIK); + bool ConsumeAndStoreConditional(CachedTokens &Toks); + bool ConsumeAndStoreUntil(tok::TokenKind T1, + CachedTokens &Toks, + bool StopAtSemi = true, + bool ConsumeFinalToken = true) { + return ConsumeAndStoreUntil(T1, T1, Toks, StopAtSemi, ConsumeFinalToken); + } + bool ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2, + CachedTokens &Toks, + bool StopAtSemi = true, + bool ConsumeFinalToken = true); + + //===--------------------------------------------------------------------===// + // C99 6.9: External Definitions. + struct ParsedAttributesWithRange : ParsedAttributes { + ParsedAttributesWithRange(AttributeFactory &factory) + : ParsedAttributes(factory) {} + + SourceRange Range; + }; + + DeclGroupPtrTy ParseExternalDeclaration(ParsedAttributesWithRange &attrs, + ParsingDeclSpec *DS = nullptr); + bool isDeclarationAfterDeclarator(); + bool isStartOfFunctionDefinition(const ParsingDeclarator &Declarator); + DeclGroupPtrTy ParseDeclarationOrFunctionDefinition( + ParsedAttributesWithRange &attrs, + ParsingDeclSpec *DS = nullptr, + AccessSpecifier AS = AS_none); + DeclGroupPtrTy ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs, + ParsingDeclSpec &DS, + AccessSpecifier AS); + + void SkipFunctionBody(); + Decl *ParseFunctionDefinition(ParsingDeclarator &D, + const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), + LateParsedAttrList *LateParsedAttrs = nullptr); + void ParseKNRParamDeclarations(Declarator &D); + // EndLoc, if non-NULL, is filled with the location of the last token of + // the simple-asm. + ExprResult ParseSimpleAsm(SourceLocation *EndLoc = nullptr); + ExprResult ParseAsmStringLiteral(); + + // Objective-C External Declarations + void MaybeSkipAttributes(tok::ObjCKeywordKind Kind); + DeclGroupPtrTy ParseObjCAtDirectives(); + DeclGroupPtrTy ParseObjCAtClassDeclaration(SourceLocation atLoc); + Decl *ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, + ParsedAttributes &prefixAttrs); + class ObjCTypeParamListScope; + ObjCTypeParamList *parseObjCTypeParamList(); + ObjCTypeParamList *parseObjCTypeParamListOrProtocolRefs( + ObjCTypeParamListScope &Scope, SourceLocation &lAngleLoc, + SmallVectorImpl<IdentifierLocPair> &protocolIdents, + SourceLocation &rAngleLoc, bool mayBeProtocolList = true); + + void HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocation atLoc, + BalancedDelimiterTracker &T, + SmallVectorImpl<Decl *> &AllIvarDecls, + bool RBraceMissing); + void ParseObjCClassInstanceVariables(Decl *interfaceDecl, + tok::ObjCKeywordKind visibility, + SourceLocation atLoc); + bool ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &P, + SmallVectorImpl<SourceLocation> &PLocs, + bool WarnOnDeclarations, + bool ForObjCContainer, + SourceLocation &LAngleLoc, + SourceLocation &EndProtoLoc, + bool consumeLastToken); + + /// Parse the first angle-bracket-delimited clause for an + /// Objective-C object or object pointer type, which may be either + /// type arguments or protocol qualifiers. + void parseObjCTypeArgsOrProtocolQualifiers( + ParsedType baseType, + SourceLocation &typeArgsLAngleLoc, + SmallVectorImpl<ParsedType> &typeArgs, + SourceLocation &typeArgsRAngleLoc, + SourceLocation &protocolLAngleLoc, + SmallVectorImpl<Decl *> &protocols, + SmallVectorImpl<SourceLocation> &protocolLocs, + SourceLocation &protocolRAngleLoc, + bool consumeLastToken, + bool warnOnIncompleteProtocols); + + /// Parse either Objective-C type arguments or protocol qualifiers; if the + /// former, also parse protocol qualifiers afterward. + void parseObjCTypeArgsAndProtocolQualifiers( + ParsedType baseType, + SourceLocation &typeArgsLAngleLoc, + SmallVectorImpl<ParsedType> &typeArgs, + SourceLocation &typeArgsRAngleLoc, + SourceLocation &protocolLAngleLoc, + SmallVectorImpl<Decl *> &protocols, + SmallVectorImpl<SourceLocation> &protocolLocs, + SourceLocation &protocolRAngleLoc, + bool consumeLastToken); + + /// Parse a protocol qualifier type such as '<NSCopying>', which is + /// an anachronistic way of writing 'id<NSCopying>'. + TypeResult parseObjCProtocolQualifierType(SourceLocation &rAngleLoc); + + /// Parse Objective-C type arguments and protocol qualifiers, extending the + /// current type with the parsed result. + TypeResult parseObjCTypeArgsAndProtocolQualifiers(SourceLocation loc, + ParsedType type, + bool consumeLastToken, + SourceLocation &endLoc); + + void ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, + Decl *CDecl); + DeclGroupPtrTy ParseObjCAtProtocolDeclaration(SourceLocation atLoc, + ParsedAttributes &prefixAttrs); + + struct ObjCImplParsingDataRAII { + Parser &P; + Decl *Dcl; + bool HasCFunction; + typedef SmallVector<LexedMethod*, 8> LateParsedObjCMethodContainer; + LateParsedObjCMethodContainer LateParsedObjCMethods; + + ObjCImplParsingDataRAII(Parser &parser, Decl *D) + : P(parser), Dcl(D), HasCFunction(false) { + P.CurParsedObjCImpl = this; + Finished = false; + } + ~ObjCImplParsingDataRAII(); + + void finish(SourceRange AtEnd); + bool isFinished() const { return Finished; } + + private: + bool Finished; + }; + ObjCImplParsingDataRAII *CurParsedObjCImpl; + void StashAwayMethodOrFunctionBodyTokens(Decl *MDecl); + + DeclGroupPtrTy ParseObjCAtImplementationDeclaration(SourceLocation AtLoc); + DeclGroupPtrTy ParseObjCAtEndDeclaration(SourceRange atEnd); + Decl *ParseObjCAtAliasDeclaration(SourceLocation atLoc); + Decl *ParseObjCPropertySynthesize(SourceLocation atLoc); + Decl *ParseObjCPropertyDynamic(SourceLocation atLoc); + + IdentifierInfo *ParseObjCSelectorPiece(SourceLocation &MethodLocation); + // Definitions for Objective-c context sensitive keywords recognition. + enum ObjCTypeQual { + objc_in=0, objc_out, objc_inout, objc_oneway, objc_bycopy, objc_byref, + objc_nonnull, objc_nullable, objc_null_unspecified, + objc_NumQuals + }; + IdentifierInfo *ObjCTypeQuals[objc_NumQuals]; + + bool isTokIdentifier_in() const; + + ParsedType ParseObjCTypeName(ObjCDeclSpec &DS, Declarator::TheContext Ctx, + ParsedAttributes *ParamAttrs); + void ParseObjCMethodRequirement(); + Decl *ParseObjCMethodPrototype( + tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword, + bool MethodDefinition = true); + Decl *ParseObjCMethodDecl(SourceLocation mLoc, tok::TokenKind mType, + tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword, + bool MethodDefinition=true); + void ParseObjCPropertyAttribute(ObjCDeclSpec &DS); + + Decl *ParseObjCMethodDefinition(); + +public: + //===--------------------------------------------------------------------===// + // C99 6.5: Expressions. + + /// TypeCastState - State whether an expression is or may be a type cast. + enum TypeCastState { + NotTypeCast = 0, + MaybeTypeCast, + IsTypeCast + }; + + ExprResult ParseExpression(TypeCastState isTypeCast = NotTypeCast); + ExprResult ParseConstantExpression(TypeCastState isTypeCast = NotTypeCast); + ExprResult ParseConstraintExpression(); + // Expr that doesn't include commas. + ExprResult ParseAssignmentExpression(TypeCastState isTypeCast = NotTypeCast); + + ExprResult ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks, + unsigned &NumLineToksConsumed, + void *Info, + bool IsUnevaluated); + +private: + ExprResult ParseExpressionWithLeadingAt(SourceLocation AtLoc); + + ExprResult ParseExpressionWithLeadingExtension(SourceLocation ExtLoc); + + ExprResult ParseRHSOfBinaryExpression(ExprResult LHS, + prec::Level MinPrec); + ExprResult ParseCastExpression(bool isUnaryExpression, + bool isAddressOfOperand, + bool &NotCastExpr, + TypeCastState isTypeCast); + ExprResult ParseCastExpression(bool isUnaryExpression, + bool isAddressOfOperand = false, + TypeCastState isTypeCast = NotTypeCast); + + /// Returns true if the next token cannot start an expression. + bool isNotExpressionStart(); + + /// Returns true if the next token would start a postfix-expression + /// suffix. + bool isPostfixExpressionSuffixStart() { + tok::TokenKind K = Tok.getKind(); + return (K == tok::l_square || K == tok::l_paren || + K == tok::period || K == tok::arrow || + K == tok::plusplus || K == tok::minusminus); + } + + ExprResult ParsePostfixExpressionSuffix(ExprResult LHS); + ExprResult ParseUnaryExprOrTypeTraitExpression(); + ExprResult ParseBuiltinPrimaryExpression(); + + ExprResult ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, + bool &isCastExpr, + ParsedType &CastTy, + SourceRange &CastRange); + + typedef SmallVector<Expr*, 20> ExprListTy; + typedef SmallVector<SourceLocation, 20> CommaLocsTy; + + /// ParseExpressionList - Used for C/C++ (argument-)expression-list. + bool ParseExpressionList(SmallVectorImpl<Expr *> &Exprs, + SmallVectorImpl<SourceLocation> &CommaLocs, + std::function<void()> Completer = nullptr); + + /// ParseSimpleExpressionList - A simple comma-separated list of expressions, + /// used for misc language extensions. + bool ParseSimpleExpressionList(SmallVectorImpl<Expr*> &Exprs, + SmallVectorImpl<SourceLocation> &CommaLocs); + + + /// ParenParseOption - Control what ParseParenExpression will parse. + enum ParenParseOption { + SimpleExpr, // Only parse '(' expression ')' + CompoundStmt, // Also allow '(' compound-statement ')' + CompoundLiteral, // Also allow '(' type-name ')' '{' ... '}' + CastExpr // Also allow '(' type-name ')' <anything> + }; + ExprResult ParseParenExpression(ParenParseOption &ExprType, + bool stopIfCastExpr, + bool isTypeCast, + ParsedType &CastTy, + SourceLocation &RParenLoc); + + ExprResult ParseCXXAmbiguousParenExpression( + ParenParseOption &ExprType, ParsedType &CastTy, + BalancedDelimiterTracker &Tracker, ColonProtectionRAIIObject &ColonProt); + ExprResult ParseCompoundLiteralExpression(ParsedType Ty, + SourceLocation LParenLoc, + SourceLocation RParenLoc); + + ExprResult ParseStringLiteralExpression(bool AllowUserDefinedLiteral = false); + + ExprResult ParseGenericSelectionExpression(); + + ExprResult ParseObjCBoolLiteral(); + + ExprResult ParseFoldExpression(ExprResult LHS, BalancedDelimiterTracker &T); + + //===--------------------------------------------------------------------===// + // C++ Expressions + ExprResult tryParseCXXIdExpression(CXXScopeSpec &SS, bool isAddressOfOperand, + Token &Replacement); + ExprResult ParseCXXIdExpression(bool isAddressOfOperand = false); + + bool areTokensAdjacent(const Token &A, const Token &B); + + void CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectTypePtr, + bool EnteringContext, IdentifierInfo &II, + CXXScopeSpec &SS); + + bool ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, + ParsedType ObjectType, + bool EnteringContext, + bool *MayBePseudoDestructor = nullptr, + bool IsTypename = false, + IdentifierInfo **LastII = nullptr); + + void CheckForLParenAfterColonColon(); + + //===--------------------------------------------------------------------===// + // C++0x 5.1.2: Lambda expressions + + // [...] () -> type {...} + ExprResult ParseLambdaExpression(); + ExprResult TryParseLambdaExpression(); + Optional<unsigned> ParseLambdaIntroducer(LambdaIntroducer &Intro, + bool *SkippedInits = nullptr); + bool TryParseLambdaIntroducer(LambdaIntroducer &Intro); + ExprResult ParseLambdaExpressionAfterIntroducer( + LambdaIntroducer &Intro); + + //===--------------------------------------------------------------------===// + // C++ 5.2p1: C++ Casts + ExprResult ParseCXXCasts(); + + //===--------------------------------------------------------------------===// + // C++ 5.2p1: C++ Type Identification + ExprResult ParseCXXTypeid(); + + //===--------------------------------------------------------------------===// + // C++ : Microsoft __uuidof Expression + ExprResult ParseCXXUuidof(); + + //===--------------------------------------------------------------------===// + // C++ 5.2.4: C++ Pseudo-Destructor Expressions + ExprResult ParseCXXPseudoDestructor(Expr *Base, SourceLocation OpLoc, + tok::TokenKind OpKind, + CXXScopeSpec &SS, + ParsedType ObjectType); + + //===--------------------------------------------------------------------===// + // C++ 9.3.2: C++ 'this' pointer + ExprResult ParseCXXThis(); + + //===--------------------------------------------------------------------===// + // C++ 15: C++ Throw Expression + ExprResult ParseThrowExpression(); + + ExceptionSpecificationType tryParseExceptionSpecification( + bool Delayed, + SourceRange &SpecificationRange, + SmallVectorImpl<ParsedType> &DynamicExceptions, + SmallVectorImpl<SourceRange> &DynamicExceptionRanges, + ExprResult &NoexceptExpr, + CachedTokens *&ExceptionSpecTokens); + + // EndLoc is filled with the location of the last token of the specification. + ExceptionSpecificationType ParseDynamicExceptionSpecification( + SourceRange &SpecificationRange, + SmallVectorImpl<ParsedType> &Exceptions, + SmallVectorImpl<SourceRange> &Ranges); + + //===--------------------------------------------------------------------===// + // C++0x 8: Function declaration trailing-return-type + TypeResult ParseTrailingReturnType(SourceRange &Range); + + //===--------------------------------------------------------------------===// + // C++ 2.13.5: C++ Boolean Literals + ExprResult ParseCXXBoolLiteral(); + + //===--------------------------------------------------------------------===// + // C++ 5.2.3: Explicit type conversion (functional notation) + ExprResult ParseCXXTypeConstructExpression(const DeclSpec &DS); + + /// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers. + /// This should only be called when the current token is known to be part of + /// simple-type-specifier. + void ParseCXXSimpleTypeSpecifier(DeclSpec &DS); + + bool ParseCXXTypeSpecifierSeq(DeclSpec &DS); + + //===--------------------------------------------------------------------===// + // C++ 5.3.4 and 5.3.5: C++ new and delete + bool ParseExpressionListOrTypeId(SmallVectorImpl<Expr*> &Exprs, + Declarator &D); + void ParseDirectNewDeclarator(Declarator &D); + ExprResult ParseCXXNewExpression(bool UseGlobal, SourceLocation Start); + ExprResult ParseCXXDeleteExpression(bool UseGlobal, + SourceLocation Start); + + //===--------------------------------------------------------------------===// + // C++ if/switch/while condition expression. + bool ParseCXXCondition(ExprResult &ExprResult, Decl *&DeclResult, + SourceLocation Loc, bool ConvertToBoolean); + + //===--------------------------------------------------------------------===// + // C++ Coroutines + + ExprResult ParseCoyieldExpression(); + + //===--------------------------------------------------------------------===// + // C99 6.7.8: Initialization. + + /// ParseInitializer + /// initializer: [C99 6.7.8] + /// assignment-expression + /// '{' ... + ExprResult ParseInitializer() { + if (Tok.isNot(tok::l_brace)) + return ParseAssignmentExpression(); + return ParseBraceInitializer(); + } + bool MayBeDesignationStart(); + ExprResult ParseBraceInitializer(); + ExprResult ParseInitializerWithPotentialDesignator(); + + //===--------------------------------------------------------------------===// + // clang Expressions + + ExprResult ParseBlockLiteralExpression(); // ^{...} + + //===--------------------------------------------------------------------===// + // Objective-C Expressions + ExprResult ParseObjCAtExpression(SourceLocation AtLocation); + ExprResult ParseObjCStringLiteral(SourceLocation AtLoc); + ExprResult ParseObjCCharacterLiteral(SourceLocation AtLoc); + ExprResult ParseObjCNumericLiteral(SourceLocation AtLoc); + ExprResult ParseObjCBooleanLiteral(SourceLocation AtLoc, bool ArgValue); + ExprResult ParseObjCArrayLiteral(SourceLocation AtLoc); + ExprResult ParseObjCDictionaryLiteral(SourceLocation AtLoc); + ExprResult ParseObjCBoxedExpr(SourceLocation AtLoc); + ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc); + ExprResult ParseObjCSelectorExpression(SourceLocation AtLoc); + ExprResult ParseObjCProtocolExpression(SourceLocation AtLoc); + bool isSimpleObjCMessageExpression(); + ExprResult ParseObjCMessageExpression(); + ExprResult ParseObjCMessageExpressionBody(SourceLocation LBracloc, + SourceLocation SuperLoc, + ParsedType ReceiverType, + Expr *ReceiverExpr); + ExprResult ParseAssignmentExprWithObjCMessageExprStart( + SourceLocation LBracloc, SourceLocation SuperLoc, + ParsedType ReceiverType, Expr *ReceiverExpr); + bool ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr); + + //===--------------------------------------------------------------------===// + // C99 6.8: Statements and Blocks. + + /// A SmallVector of statements, with stack size 32 (as that is the only one + /// used.) + typedef SmallVector<Stmt*, 32> StmtVector; + /// A SmallVector of expressions, with stack size 12 (the maximum used.) + typedef SmallVector<Expr*, 12> ExprVector; + /// A SmallVector of types. + typedef SmallVector<ParsedType, 12> TypeVector; + + StmtResult ParseStatement(SourceLocation *TrailingElseLoc = nullptr); + StmtResult + ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement, + SourceLocation *TrailingElseLoc = nullptr); + StmtResult ParseStatementOrDeclarationAfterAttributes( + StmtVector &Stmts, + bool OnlyStatement, + SourceLocation *TrailingElseLoc, + ParsedAttributesWithRange &Attrs); + StmtResult ParseExprStatement(); + StmtResult ParseLabeledStatement(ParsedAttributesWithRange &attrs); + StmtResult ParseCaseStatement(bool MissingCase = false, + ExprResult Expr = ExprResult()); + StmtResult ParseDefaultStatement(); + StmtResult ParseCompoundStatement(bool isStmtExpr = false); + StmtResult ParseCompoundStatement(bool isStmtExpr, + unsigned ScopeFlags); + void ParseCompoundStatementLeadingPragmas(); + StmtResult ParseCompoundStatementBody(bool isStmtExpr = false); + bool ParseParenExprOrCondition(ExprResult &ExprResult, + Decl *&DeclResult, + SourceLocation Loc, + bool ConvertToBoolean); + StmtResult ParseIfStatement(SourceLocation *TrailingElseLoc); + StmtResult ParseSwitchStatement(SourceLocation *TrailingElseLoc); + StmtResult ParseWhileStatement(SourceLocation *TrailingElseLoc); + StmtResult ParseDoStatement(); + StmtResult ParseForStatement(SourceLocation *TrailingElseLoc); + StmtResult ParseGotoStatement(); + StmtResult ParseContinueStatement(); + StmtResult ParseBreakStatement(); + StmtResult ParseReturnStatement(); + StmtResult ParseAsmStatement(bool &msAsm); + StmtResult ParseMicrosoftAsmStatement(SourceLocation AsmLoc); + StmtResult ParsePragmaLoopHint(StmtVector &Stmts, bool OnlyStatement, + SourceLocation *TrailingElseLoc, + ParsedAttributesWithRange &Attrs); + + /// \brief Describes the behavior that should be taken for an __if_exists + /// block. + enum IfExistsBehavior { + /// \brief Parse the block; this code is always used. + IEB_Parse, + /// \brief Skip the block entirely; this code is never used. + IEB_Skip, + /// \brief Parse the block as a dependent block, which may be used in + /// some template instantiations but not others. + IEB_Dependent + }; + + /// \brief Describes the condition of a Microsoft __if_exists or + /// __if_not_exists block. + struct IfExistsCondition { + /// \brief The location of the initial keyword. + SourceLocation KeywordLoc; + /// \brief Whether this is an __if_exists block (rather than an + /// __if_not_exists block). + bool IsIfExists; + + /// \brief Nested-name-specifier preceding the name. + CXXScopeSpec SS; + + /// \brief The name we're looking for. + UnqualifiedId Name; + + /// \brief The behavior of this __if_exists or __if_not_exists block + /// should. + IfExistsBehavior Behavior; + }; + + bool ParseMicrosoftIfExistsCondition(IfExistsCondition& Result); + void ParseMicrosoftIfExistsStatement(StmtVector &Stmts); + void ParseMicrosoftIfExistsExternalDeclaration(); + void ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType, + AccessSpecifier& CurAS); + bool ParseMicrosoftIfExistsBraceInitializer(ExprVector &InitExprs, + bool &InitExprsOk); + bool ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names, + SmallVectorImpl<Expr *> &Constraints, + SmallVectorImpl<Expr *> &Exprs); + + //===--------------------------------------------------------------------===// + // C++ 6: Statements and Blocks + + StmtResult ParseCXXTryBlock(); + StmtResult ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry = false); + StmtResult ParseCXXCatchBlock(bool FnCatch = false); + + //===--------------------------------------------------------------------===// + // MS: SEH Statements and Blocks + + StmtResult ParseSEHTryBlock(); + StmtResult ParseSEHExceptBlock(SourceLocation Loc); + StmtResult ParseSEHFinallyBlock(SourceLocation Loc); + StmtResult ParseSEHLeaveStatement(); + + //===--------------------------------------------------------------------===// + // Objective-C Statements + + StmtResult ParseObjCAtStatement(SourceLocation atLoc); + StmtResult ParseObjCTryStmt(SourceLocation atLoc); + StmtResult ParseObjCThrowStmt(SourceLocation atLoc); + StmtResult ParseObjCSynchronizedStmt(SourceLocation atLoc); + StmtResult ParseObjCAutoreleasePoolStmt(SourceLocation atLoc); + + + //===--------------------------------------------------------------------===// + // C99 6.7: Declarations. + + /// A context for parsing declaration specifiers. TODO: flesh this + /// out, there are other significant restrictions on specifiers than + /// would be best implemented in the parser. + enum DeclSpecContext { + DSC_normal, // normal context + DSC_class, // class context, enables 'friend' + DSC_type_specifier, // C++ type-specifier-seq or C specifier-qualifier-list + DSC_trailing, // C++11 trailing-type-specifier in a trailing return type + DSC_alias_declaration, // C++11 type-specifier-seq in an alias-declaration + DSC_top_level, // top-level/namespace declaration context + DSC_template_type_arg, // template type argument context + DSC_objc_method_result, // ObjC method result context, enables 'instancetype' + DSC_condition // condition declaration context + }; + + /// Is this a context in which we are parsing just a type-specifier (or + /// trailing-type-specifier)? + static bool isTypeSpecifier(DeclSpecContext DSC) { + switch (DSC) { + case DSC_normal: + case DSC_class: + case DSC_top_level: + case DSC_objc_method_result: + case DSC_condition: + return false; + + case DSC_template_type_arg: + case DSC_type_specifier: + case DSC_trailing: + case DSC_alias_declaration: + return true; + } + llvm_unreachable("Missing DeclSpecContext case"); + } + + /// Information on a C++0x for-range-initializer found while parsing a + /// declaration which turns out to be a for-range-declaration. + struct ForRangeInit { + SourceLocation ColonLoc; + ExprResult RangeExpr; + + bool ParsedForRangeDecl() { return !ColonLoc.isInvalid(); } + }; + + DeclGroupPtrTy ParseDeclaration(unsigned Context, SourceLocation &DeclEnd, + ParsedAttributesWithRange &attrs); + DeclGroupPtrTy ParseSimpleDeclaration(unsigned Context, + SourceLocation &DeclEnd, + ParsedAttributesWithRange &attrs, + bool RequireSemi, + ForRangeInit *FRI = nullptr); + bool MightBeDeclarator(unsigned Context); + DeclGroupPtrTy ParseDeclGroup(ParsingDeclSpec &DS, unsigned Context, + SourceLocation *DeclEnd = nullptr, + ForRangeInit *FRI = nullptr); + Decl *ParseDeclarationAfterDeclarator(Declarator &D, + const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo()); + bool ParseAsmAttributesAfterDeclarator(Declarator &D); + Decl *ParseDeclarationAfterDeclaratorAndAttributes( + Declarator &D, + const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), + ForRangeInit *FRI = nullptr); + Decl *ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope); + Decl *ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope); + + /// \brief When in code-completion, skip parsing of the function/method body + /// unless the body contains the code-completion point. + /// + /// \returns true if the function body was skipped. + bool trySkippingFunctionBody(); + + bool ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, + const ParsedTemplateInfo &TemplateInfo, + AccessSpecifier AS, DeclSpecContext DSC, + ParsedAttributesWithRange &Attrs); + DeclSpecContext getDeclSpecContextFromDeclaratorContext(unsigned Context); + void ParseDeclarationSpecifiers(DeclSpec &DS, + const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), + AccessSpecifier AS = AS_none, + DeclSpecContext DSC = DSC_normal, + LateParsedAttrList *LateAttrs = nullptr); + bool DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS, + DeclSpecContext DSContext, + LateParsedAttrList *LateAttrs = nullptr); + + void ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS = AS_none, + DeclSpecContext DSC = DSC_normal); + + void ParseObjCTypeQualifierList(ObjCDeclSpec &DS, + Declarator::TheContext Context); + + void ParseEnumSpecifier(SourceLocation TagLoc, DeclSpec &DS, + const ParsedTemplateInfo &TemplateInfo, + AccessSpecifier AS, DeclSpecContext DSC); + void ParseEnumBody(SourceLocation StartLoc, Decl *TagDecl); + void ParseStructUnionBody(SourceLocation StartLoc, unsigned TagType, + Decl *TagDecl); + + void ParseStructDeclaration( + ParsingDeclSpec &DS, + llvm::function_ref<void(ParsingFieldDeclarator &)> FieldsCallback); + + bool isDeclarationSpecifier(bool DisambiguatingWithExpression = false); + bool isTypeSpecifierQualifier(); + bool isTypeQualifier() const; + + /// isKnownToBeTypeSpecifier - Return true if we know that the specified token + /// is definitely a type-specifier. Return false if it isn't part of a type + /// specifier or if we're not sure. + bool isKnownToBeTypeSpecifier(const Token &Tok) const; + + /// \brief Return true if we know that we are definitely looking at a + /// decl-specifier, and isn't part of an expression such as a function-style + /// cast. Return false if it's no a decl-specifier, or we're not sure. + bool isKnownToBeDeclarationSpecifier() { + if (getLangOpts().CPlusPlus) + return isCXXDeclarationSpecifier() == TPResult::True; + return isDeclarationSpecifier(true); + } + + /// isDeclarationStatement - Disambiguates between a declaration or an + /// expression statement, when parsing function bodies. + /// Returns true for declaration, false for expression. + bool isDeclarationStatement() { + if (getLangOpts().CPlusPlus) + return isCXXDeclarationStatement(); + return isDeclarationSpecifier(true); + } + + /// isForInitDeclaration - Disambiguates between a declaration or an + /// expression in the context of the C 'clause-1' or the C++ + // 'for-init-statement' part of a 'for' statement. + /// Returns true for declaration, false for expression. + bool isForInitDeclaration() { + if (getLangOpts().CPlusPlus) + return isCXXSimpleDeclaration(/*AllowForRangeDecl=*/true); + return isDeclarationSpecifier(true); + } + + /// \brief Determine whether this is a C++1z for-range-identifier. + bool isForRangeIdentifier(); + + /// \brief Determine whether we are currently at the start of an Objective-C + /// class message that appears to be missing the open bracket '['. + bool isStartOfObjCClassMessageMissingOpenBracket(); + + /// \brief Starting with a scope specifier, identifier, or + /// template-id that refers to the current class, determine whether + /// this is a constructor declarator. + bool isConstructorDeclarator(bool Unqualified); + + /// \brief Specifies the context in which type-id/expression + /// disambiguation will occur. + enum TentativeCXXTypeIdContext { + TypeIdInParens, + TypeIdUnambiguous, + TypeIdAsTemplateArgument + }; + + + /// isTypeIdInParens - Assumes that a '(' was parsed and now we want to know + /// whether the parens contain an expression or a type-id. + /// Returns true for a type-id and false for an expression. + bool isTypeIdInParens(bool &isAmbiguous) { + if (getLangOpts().CPlusPlus) + return isCXXTypeId(TypeIdInParens, isAmbiguous); + isAmbiguous = false; + return isTypeSpecifierQualifier(); + } + bool isTypeIdInParens() { + bool isAmbiguous; + return isTypeIdInParens(isAmbiguous); + } + + /// \brief Checks if the current tokens form type-id or expression. + /// It is similar to isTypeIdInParens but does not suppose that type-id + /// is in parenthesis. + bool isTypeIdUnambiguously() { + bool IsAmbiguous; + if (getLangOpts().CPlusPlus) + return isCXXTypeId(TypeIdUnambiguous, IsAmbiguous); + return isTypeSpecifierQualifier(); + } + + /// isCXXDeclarationStatement - C++-specialized function that disambiguates + /// between a declaration or an expression statement, when parsing function + /// bodies. Returns true for declaration, false for expression. + bool isCXXDeclarationStatement(); + + /// isCXXSimpleDeclaration - C++-specialized function that disambiguates + /// between a simple-declaration or an expression-statement. + /// If during the disambiguation process a parsing error is encountered, + /// the function returns true to let the declaration parsing code handle it. + /// Returns false if the statement is disambiguated as expression. + bool isCXXSimpleDeclaration(bool AllowForRangeDecl); + + /// isCXXFunctionDeclarator - Disambiguates between a function declarator or + /// a constructor-style initializer, when parsing declaration statements. + /// Returns true for function declarator and false for constructor-style + /// initializer. Sets 'IsAmbiguous' to true to indicate that this declaration + /// might be a constructor-style initializer. + /// If during the disambiguation process a parsing error is encountered, + /// the function returns true to let the declaration parsing code handle it. + bool isCXXFunctionDeclarator(bool *IsAmbiguous = nullptr); + + /// isCXXConditionDeclaration - Disambiguates between a declaration or an + /// expression for a condition of a if/switch/while/for statement. + /// If during the disambiguation process a parsing error is encountered, + /// the function returns true to let the declaration parsing code handle it. + bool isCXXConditionDeclaration(); + + bool isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous); + bool isCXXTypeId(TentativeCXXTypeIdContext Context) { + bool isAmbiguous; + return isCXXTypeId(Context, isAmbiguous); + } + + /// TPResult - Used as the result value for functions whose purpose is to + /// disambiguate C++ constructs by "tentatively parsing" them. + enum class TPResult { + True, False, Ambiguous, Error + }; + + /// \brief Based only on the given token kind, determine whether we know that + /// we're at the start of an expression or a type-specifier-seq (which may + /// be an expression, in C++). + /// + /// This routine does not attempt to resolve any of the trick cases, e.g., + /// those involving lookup of identifiers. + /// + /// \returns \c TPR_true if this token starts an expression, \c TPR_false if + /// this token starts a type-specifier-seq, or \c TPR_ambiguous if it cannot + /// tell. + TPResult isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind); + + /// isCXXDeclarationSpecifier - Returns TPResult::True if it is a + /// declaration specifier, TPResult::False if it is not, + /// TPResult::Ambiguous if it could be either a decl-specifier or a + /// function-style cast, and TPResult::Error if a parsing error was + /// encountered. If it could be a braced C++11 function-style cast, returns + /// BracedCastResult. + /// Doesn't consume tokens. + TPResult + isCXXDeclarationSpecifier(TPResult BracedCastResult = TPResult::False, + bool *HasMissingTypename = nullptr); + + /// Given that isCXXDeclarationSpecifier returns \c TPResult::True or + /// \c TPResult::Ambiguous, determine whether the decl-specifier would be + /// a type-specifier other than a cv-qualifier. + bool isCXXDeclarationSpecifierAType(); + + /// \brief Determine whether an identifier has been tentatively declared as a + /// non-type. Such tentative declarations should not be found to name a type + /// during a tentative parse, but also should not be annotated as a non-type. + bool isTentativelyDeclared(IdentifierInfo *II); + + // "Tentative parsing" functions, used for disambiguation. If a parsing error + // is encountered they will return TPResult::Error. + // Returning TPResult::True/False indicates that the ambiguity was + // resolved and tentative parsing may stop. TPResult::Ambiguous indicates + // that more tentative parsing is necessary for disambiguation. + // They all consume tokens, so backtracking should be used after calling them. + + TPResult TryParseSimpleDeclaration(bool AllowForRangeDecl); + TPResult TryParseTypeofSpecifier(); + TPResult TryParseProtocolQualifiers(); + TPResult TryParsePtrOperatorSeq(); + TPResult TryParseOperatorId(); + TPResult TryParseInitDeclaratorList(); + TPResult TryParseDeclarator(bool mayBeAbstract, bool mayHaveIdentifier=true); + TPResult + TryParseParameterDeclarationClause(bool *InvalidAsDeclaration = nullptr, + bool VersusTemplateArg = false); + TPResult TryParseFunctionDeclarator(); + TPResult TryParseBracketDeclarator(); + TPResult TryConsumeDeclarationSpecifier(); + +public: + TypeResult ParseTypeName(SourceRange *Range = nullptr, + Declarator::TheContext Context + = Declarator::TypeNameContext, + AccessSpecifier AS = AS_none, + Decl **OwnedType = nullptr, + ParsedAttributes *Attrs = nullptr); + +private: + void ParseBlockId(SourceLocation CaretLoc); + + // Check for the start of a C++11 attribute-specifier-seq in a context where + // an attribute is not allowed. + bool CheckProhibitedCXX11Attribute() { + assert(Tok.is(tok::l_square)); + if (!getLangOpts().CPlusPlus11 || NextToken().isNot(tok::l_square)) + return false; + return DiagnoseProhibitedCXX11Attribute(); + } + bool DiagnoseProhibitedCXX11Attribute(); + void CheckMisplacedCXX11Attribute(ParsedAttributesWithRange &Attrs, + SourceLocation CorrectLocation) { + if (!getLangOpts().CPlusPlus11) + return; + if ((Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square)) && + Tok.isNot(tok::kw_alignas)) + return; + DiagnoseMisplacedCXX11Attribute(Attrs, CorrectLocation); + } + void DiagnoseMisplacedCXX11Attribute(ParsedAttributesWithRange &Attrs, + SourceLocation CorrectLocation); + + void handleDeclspecAlignBeforeClassKey(ParsedAttributesWithRange &Attrs, + DeclSpec &DS, Sema::TagUseKind TUK); + + void ProhibitAttributes(ParsedAttributesWithRange &attrs) { + if (!attrs.Range.isValid()) return; + DiagnoseProhibitedAttributes(attrs); + attrs.clear(); + } + void DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs); + + // Forbid C++11 attributes that appear on certain syntactic + // locations which standard permits but we don't supported yet, + // for example, attributes appertain to decl specifiers. + void ProhibitCXX11Attributes(ParsedAttributesWithRange &attrs); + + /// \brief Skip C++11 attributes and return the end location of the last one. + /// \returns SourceLocation() if there are no attributes. + SourceLocation SkipCXX11Attributes(); + + /// \brief Diagnose and skip C++11 attributes that appear in syntactic + /// locations where attributes are not allowed. + void DiagnoseAndSkipCXX11Attributes(); + + /// \brief Parses syntax-generic attribute arguments for attributes which are + /// known to the implementation, and adds them to the given ParsedAttributes + /// list with the given attribute syntax. Returns the number of arguments + /// parsed for the attribute. + unsigned + ParseAttributeArgsCommon(IdentifierInfo *AttrName, SourceLocation AttrNameLoc, + ParsedAttributes &Attrs, SourceLocation *EndLoc, + IdentifierInfo *ScopeName, SourceLocation ScopeLoc, + AttributeList::Syntax Syntax); + + void MaybeParseGNUAttributes(Declarator &D, + LateParsedAttrList *LateAttrs = nullptr) { + if (Tok.is(tok::kw___attribute)) { + ParsedAttributes attrs(AttrFactory); + SourceLocation endLoc; + ParseGNUAttributes(attrs, &endLoc, LateAttrs, &D); + D.takeAttributes(attrs, endLoc); + } + } + void MaybeParseGNUAttributes(ParsedAttributes &attrs, + SourceLocation *endLoc = nullptr, + LateParsedAttrList *LateAttrs = nullptr) { + if (Tok.is(tok::kw___attribute)) + ParseGNUAttributes(attrs, endLoc, LateAttrs); + } + void ParseGNUAttributes(ParsedAttributes &attrs, + SourceLocation *endLoc = nullptr, + LateParsedAttrList *LateAttrs = nullptr, + Declarator *D = nullptr); + void ParseGNUAttributeArgs(IdentifierInfo *AttrName, + SourceLocation AttrNameLoc, + ParsedAttributes &Attrs, + SourceLocation *EndLoc, + IdentifierInfo *ScopeName, + SourceLocation ScopeLoc, + AttributeList::Syntax Syntax, + Declarator *D); + IdentifierLoc *ParseIdentifierLoc(); + + void MaybeParseCXX11Attributes(Declarator &D) { + if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) { + ParsedAttributesWithRange attrs(AttrFactory); + SourceLocation endLoc; + ParseCXX11Attributes(attrs, &endLoc); + D.takeAttributes(attrs, endLoc); + } + } + void MaybeParseCXX11Attributes(ParsedAttributes &attrs, + SourceLocation *endLoc = nullptr) { + if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) { + ParsedAttributesWithRange attrsWithRange(AttrFactory); + ParseCXX11Attributes(attrsWithRange, endLoc); + attrs.takeAllFrom(attrsWithRange); + } + } + void MaybeParseCXX11Attributes(ParsedAttributesWithRange &attrs, + SourceLocation *endLoc = nullptr, + bool OuterMightBeMessageSend = false) { + if (getLangOpts().CPlusPlus11 && + isCXX11AttributeSpecifier(false, OuterMightBeMessageSend)) + ParseCXX11Attributes(attrs, endLoc); + } + + void ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, + SourceLocation *EndLoc = nullptr); + void ParseCXX11Attributes(ParsedAttributesWithRange &attrs, + SourceLocation *EndLoc = nullptr); + /// \brief Parses a C++-style attribute argument list. Returns true if this + /// results in adding an attribute to the ParsedAttributes list. + bool ParseCXX11AttributeArgs(IdentifierInfo *AttrName, + SourceLocation AttrNameLoc, + ParsedAttributes &Attrs, SourceLocation *EndLoc, + IdentifierInfo *ScopeName, + SourceLocation ScopeLoc); + + IdentifierInfo *TryParseCXX11AttributeIdentifier(SourceLocation &Loc); + + void MaybeParseMicrosoftAttributes(ParsedAttributes &attrs, + SourceLocation *endLoc = nullptr) { + if (getLangOpts().MicrosoftExt && Tok.is(tok::l_square)) + ParseMicrosoftAttributes(attrs, endLoc); + } + void ParseMicrosoftAttributes(ParsedAttributes &attrs, + SourceLocation *endLoc = nullptr); + void MaybeParseMicrosoftDeclSpecs(ParsedAttributes &Attrs, + SourceLocation *End = nullptr) { + const auto &LO = getLangOpts(); + if (LO.DeclSpecKeyword && Tok.is(tok::kw___declspec)) + ParseMicrosoftDeclSpecs(Attrs, End); + } + void ParseMicrosoftDeclSpecs(ParsedAttributes &Attrs, + SourceLocation *End = nullptr); + bool ParseMicrosoftDeclSpecArgs(IdentifierInfo *AttrName, + SourceLocation AttrNameLoc, + ParsedAttributes &Attrs); + void ParseMicrosoftTypeAttributes(ParsedAttributes &attrs); + void DiagnoseAndSkipExtendedMicrosoftTypeAttributes(); + SourceLocation SkipExtendedMicrosoftTypeAttributes(); + void ParseMicrosoftInheritanceClassAttributes(ParsedAttributes &attrs); + void ParseBorlandTypeAttributes(ParsedAttributes &attrs); + void ParseOpenCLAttributes(ParsedAttributes &attrs); + void ParseOpenCLQualifiers(ParsedAttributes &Attrs); + void ParseNullabilityTypeSpecifiers(ParsedAttributes &attrs); + + VersionTuple ParseVersionTuple(SourceRange &Range); + void ParseAvailabilityAttribute(IdentifierInfo &Availability, + SourceLocation AvailabilityLoc, + ParsedAttributes &attrs, + SourceLocation *endLoc, + IdentifierInfo *ScopeName, + SourceLocation ScopeLoc, + AttributeList::Syntax Syntax); + + void ParseObjCBridgeRelatedAttribute(IdentifierInfo &ObjCBridgeRelated, + SourceLocation ObjCBridgeRelatedLoc, + ParsedAttributes &attrs, + SourceLocation *endLoc, + IdentifierInfo *ScopeName, + SourceLocation ScopeLoc, + AttributeList::Syntax Syntax); + + void ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName, + SourceLocation AttrNameLoc, + ParsedAttributes &Attrs, + SourceLocation *EndLoc, + IdentifierInfo *ScopeName, + SourceLocation ScopeLoc, + AttributeList::Syntax Syntax); + + void ParseAttributeWithTypeArg(IdentifierInfo &AttrName, + SourceLocation AttrNameLoc, + ParsedAttributes &Attrs, + SourceLocation *EndLoc, + IdentifierInfo *ScopeName, + SourceLocation ScopeLoc, + AttributeList::Syntax Syntax); + + void ParseTypeofSpecifier(DeclSpec &DS); + SourceLocation ParseDecltypeSpecifier(DeclSpec &DS); + void AnnotateExistingDecltypeSpecifier(const DeclSpec &DS, + SourceLocation StartLoc, + SourceLocation EndLoc); + void ParseUnderlyingTypeSpecifier(DeclSpec &DS); + void ParseAtomicSpecifier(DeclSpec &DS); + + ExprResult ParseAlignArgument(SourceLocation Start, + SourceLocation &EllipsisLoc); + void ParseAlignmentSpecifier(ParsedAttributes &Attrs, + SourceLocation *endLoc = nullptr); + + VirtSpecifiers::Specifier isCXX11VirtSpecifier(const Token &Tok) const; + VirtSpecifiers::Specifier isCXX11VirtSpecifier() const { + return isCXX11VirtSpecifier(Tok); + } + void ParseOptionalCXX11VirtSpecifierSeq(VirtSpecifiers &VS, bool IsInterface, + SourceLocation FriendLoc); + + bool isCXX11FinalKeyword() const; + + /// DeclaratorScopeObj - RAII object used in Parser::ParseDirectDeclarator to + /// enter a new C++ declarator scope and exit it when the function is + /// finished. + class DeclaratorScopeObj { + Parser &P; + CXXScopeSpec &SS; + bool EnteredScope; + bool CreatedScope; + public: + DeclaratorScopeObj(Parser &p, CXXScopeSpec &ss) + : P(p), SS(ss), EnteredScope(false), CreatedScope(false) {} + + void EnterDeclaratorScope() { + assert(!EnteredScope && "Already entered the scope!"); + assert(SS.isSet() && "C++ scope was not set!"); + + CreatedScope = true; + P.EnterScope(0); // Not a decl scope. + + if (!P.Actions.ActOnCXXEnterDeclaratorScope(P.getCurScope(), SS)) + EnteredScope = true; + } + + ~DeclaratorScopeObj() { + if (EnteredScope) { + assert(SS.isSet() && "C++ scope was cleared ?"); + P.Actions.ActOnCXXExitDeclaratorScope(P.getCurScope(), SS); + } + if (CreatedScope) + P.ExitScope(); + } + }; + + /// ParseDeclarator - Parse and verify a newly-initialized declarator. + void ParseDeclarator(Declarator &D); + /// A function that parses a variant of direct-declarator. + typedef void (Parser::*DirectDeclParseFunction)(Declarator&); + void ParseDeclaratorInternal(Declarator &D, + DirectDeclParseFunction DirectDeclParser); + + enum AttrRequirements { + AR_NoAttributesParsed = 0, ///< No attributes are diagnosed. + AR_GNUAttributesParsedAndRejected = 1 << 0, ///< Diagnose GNU attributes. + AR_GNUAttributesParsed = 1 << 1, + AR_CXX11AttributesParsed = 1 << 2, + AR_DeclspecAttributesParsed = 1 << 3, + AR_AllAttributesParsed = AR_GNUAttributesParsed | + AR_CXX11AttributesParsed | + AR_DeclspecAttributesParsed, + AR_VendorAttributesParsed = AR_GNUAttributesParsed | + AR_DeclspecAttributesParsed + }; + + void ParseTypeQualifierListOpt(DeclSpec &DS, + unsigned AttrReqs = AR_AllAttributesParsed, + bool AtomicAllowed = true, + bool IdentifierRequired = false); + void ParseDirectDeclarator(Declarator &D); + void ParseParenDeclarator(Declarator &D); + void ParseFunctionDeclarator(Declarator &D, + ParsedAttributes &attrs, + BalancedDelimiterTracker &Tracker, + bool IsAmbiguous, + bool RequiresArg = false); + bool ParseRefQualifier(bool &RefQualifierIsLValueRef, + SourceLocation &RefQualifierLoc); + bool isFunctionDeclaratorIdentifierList(); + void ParseFunctionDeclaratorIdentifierList( + Declarator &D, + SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo); + void ParseParameterDeclarationClause( + Declarator &D, + ParsedAttributes &attrs, + SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo, + SourceLocation &EllipsisLoc); + void ParseBracketDeclarator(Declarator &D); + void ParseMisplacedBracketDeclarator(Declarator &D); + + //===--------------------------------------------------------------------===// + // C++ 7: Declarations [dcl.dcl] + + /// The kind of attribute specifier we have found. + enum CXX11AttributeKind { + /// This is not an attribute specifier. + CAK_NotAttributeSpecifier, + /// This should be treated as an attribute-specifier. + CAK_AttributeSpecifier, + /// The next tokens are '[[', but this is not an attribute-specifier. This + /// is ill-formed by C++11 [dcl.attr.grammar]p6. + CAK_InvalidAttributeSpecifier + }; + CXX11AttributeKind + isCXX11AttributeSpecifier(bool Disambiguate = false, + bool OuterMightBeMessageSend = false); + + void DiagnoseUnexpectedNamespace(NamedDecl *Context); + + DeclGroupPtrTy ParseNamespace(unsigned Context, SourceLocation &DeclEnd, + SourceLocation InlineLoc = SourceLocation()); + void ParseInnerNamespace(std::vector<SourceLocation>& IdentLoc, + std::vector<IdentifierInfo*>& Ident, + std::vector<SourceLocation>& NamespaceLoc, + unsigned int index, SourceLocation& InlineLoc, + ParsedAttributes& attrs, + BalancedDelimiterTracker &Tracker); + Decl *ParseLinkage(ParsingDeclSpec &DS, unsigned Context); + Decl *ParseUsingDirectiveOrDeclaration(unsigned Context, + const ParsedTemplateInfo &TemplateInfo, + SourceLocation &DeclEnd, + ParsedAttributesWithRange &attrs, + Decl **OwnedType = nullptr); + Decl *ParseUsingDirective(unsigned Context, + SourceLocation UsingLoc, + SourceLocation &DeclEnd, + ParsedAttributes &attrs); + Decl *ParseUsingDeclaration(unsigned Context, + const ParsedTemplateInfo &TemplateInfo, + SourceLocation UsingLoc, + SourceLocation &DeclEnd, + AccessSpecifier AS = AS_none, + Decl **OwnedType = nullptr); + Decl *ParseStaticAssertDeclaration(SourceLocation &DeclEnd); + Decl *ParseNamespaceAlias(SourceLocation NamespaceLoc, + SourceLocation AliasLoc, IdentifierInfo *Alias, + SourceLocation &DeclEnd); + + //===--------------------------------------------------------------------===// + // C++ 9: classes [class] and C structs/unions. + bool isValidAfterTypeSpecifier(bool CouldBeBitfield); + void ParseClassSpecifier(tok::TokenKind TagTokKind, SourceLocation TagLoc, + DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo, + AccessSpecifier AS, bool EnteringContext, + DeclSpecContext DSC, + ParsedAttributesWithRange &Attributes); + void SkipCXXMemberSpecification(SourceLocation StartLoc, + SourceLocation AttrFixitLoc, + unsigned TagType, + Decl *TagDecl); + void ParseCXXMemberSpecification(SourceLocation StartLoc, + SourceLocation AttrFixitLoc, + ParsedAttributesWithRange &Attrs, + unsigned TagType, + Decl *TagDecl); + ExprResult ParseCXXMemberInitializer(Decl *D, bool IsFunction, + SourceLocation &EqualLoc); + bool ParseCXXMemberDeclaratorBeforeInitializer(Declarator &DeclaratorInfo, + VirtSpecifiers &VS, + ExprResult &BitfieldSize, + LateParsedAttrList &LateAttrs); + void MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq(Declarator &D, + VirtSpecifiers &VS); + DeclGroupPtrTy ParseCXXClassMemberDeclaration( + AccessSpecifier AS, AttributeList *Attr, + const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), + ParsingDeclRAIIObject *DiagsFromTParams = nullptr); + DeclGroupPtrTy ParseCXXClassMemberDeclarationWithPragmas( + AccessSpecifier &AS, ParsedAttributesWithRange &AccessAttrs, + DeclSpec::TST TagType, Decl *TagDecl); + void ParseConstructorInitializer(Decl *ConstructorDecl); + MemInitResult ParseMemInitializer(Decl *ConstructorDecl); + void HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo, + Decl *ThisDecl); + + //===--------------------------------------------------------------------===// + // C++ 10: Derived classes [class.derived] + TypeResult ParseBaseTypeSpecifier(SourceLocation &BaseLoc, + SourceLocation &EndLocation); + void ParseBaseClause(Decl *ClassDecl); + BaseResult ParseBaseSpecifier(Decl *ClassDecl); + AccessSpecifier getAccessSpecifierIfPresent() const; + + bool ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + IdentifierInfo *Name, + SourceLocation NameLoc, + bool EnteringContext, + ParsedType ObjectType, + UnqualifiedId &Id, + bool AssumeTemplateId); + bool ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, + ParsedType ObjectType, + UnqualifiedId &Result); + + //===--------------------------------------------------------------------===// + // OpenMP: Directives and clauses. + /// \brief Parses declarative OpenMP directives. + DeclGroupPtrTy ParseOpenMPDeclarativeDirective(); + /// \brief Parses simple list of variables. + /// + /// \param Kind Kind of the directive. + /// \param [out] VarList List of referenced variables. + /// \param AllowScopeSpecifier true, if the variables can have fully + /// qualified names. + /// + bool ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind, + SmallVectorImpl<Expr *> &VarList, + bool AllowScopeSpecifier); + /// \brief Parses declarative or executable directive. + /// + /// \param StandAloneAllowed true if allowed stand-alone directives, + /// false - otherwise + /// + StmtResult + ParseOpenMPDeclarativeOrExecutableDirective(bool StandAloneAllowed); + /// \brief Parses clause of kind \a CKind for directive of a kind \a Kind. + /// + /// \param DKind Kind of current directive. + /// \param CKind Kind of current clause. + /// \param FirstClause true, if this is the first clause of a kind \a CKind + /// in current directive. + /// + OMPClause *ParseOpenMPClause(OpenMPDirectiveKind DKind, + OpenMPClauseKind CKind, bool FirstClause); + /// \brief Parses clause with a single expression of a kind \a Kind. + /// + /// \param Kind Kind of current clause. + /// + OMPClause *ParseOpenMPSingleExprClause(OpenMPClauseKind Kind); + /// \brief Parses simple clause of a kind \a Kind. + /// + /// \param Kind Kind of current clause. + /// + OMPClause *ParseOpenMPSimpleClause(OpenMPClauseKind Kind); + /// \brief Parses clause with a single expression and an additional argument + /// of a kind \a Kind. + /// + /// \param Kind Kind of current clause. + /// + OMPClause *ParseOpenMPSingleExprWithArgClause(OpenMPClauseKind Kind); + /// \brief Parses clause without any additional arguments. + /// + /// \param Kind Kind of current clause. + /// + OMPClause *ParseOpenMPClause(OpenMPClauseKind Kind); + /// \brief Parses clause with the list of variables of a kind \a Kind. + /// + /// \param Kind Kind of current clause. + /// + OMPClause *ParseOpenMPVarListClause(OpenMPDirectiveKind DKind, + OpenMPClauseKind Kind); + +public: + bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, + bool AllowDestructorName, + bool AllowConstructorName, + ParsedType ObjectType, + SourceLocation& TemplateKWLoc, + UnqualifiedId &Result); + +private: + //===--------------------------------------------------------------------===// + // C++ 14: Templates [temp] + + // C++ 14.1: Template Parameters [temp.param] + Decl *ParseDeclarationStartingWithTemplate(unsigned Context, + SourceLocation &DeclEnd, + AccessSpecifier AS = AS_none, + AttributeList *AccessAttrs = nullptr); + Decl *ParseTemplateDeclarationOrSpecialization(unsigned Context, + SourceLocation &DeclEnd, + AccessSpecifier AS, + AttributeList *AccessAttrs); + Decl *ParseSingleDeclarationAfterTemplate( + unsigned Context, + const ParsedTemplateInfo &TemplateInfo, + ParsingDeclRAIIObject &DiagsFromParams, + SourceLocation &DeclEnd, + AccessSpecifier AS=AS_none, + AttributeList *AccessAttrs = nullptr); + bool ParseTemplateParameters(unsigned Depth, + SmallVectorImpl<Decl*> &TemplateParams, + SourceLocation &LAngleLoc, + SourceLocation &RAngleLoc); + bool ParseTemplateParameterList(unsigned Depth, + SmallVectorImpl<Decl*> &TemplateParams); + bool isStartOfTemplateTypeParameter(); + Decl *ParseTemplateParameter(unsigned Depth, unsigned Position); + Decl *ParseTypeParameter(unsigned Depth, unsigned Position); + Decl *ParseTemplateTemplateParameter(unsigned Depth, unsigned Position); + Decl *ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position); + void DiagnoseMisplacedEllipsis(SourceLocation EllipsisLoc, + SourceLocation CorrectLoc, + bool AlreadyHasEllipsis, + bool IdentifierHasName); + void DiagnoseMisplacedEllipsisInDeclarator(SourceLocation EllipsisLoc, + Declarator &D); + // C++ 14.3: Template arguments [temp.arg] + typedef SmallVector<ParsedTemplateArgument, 16> TemplateArgList; + + bool ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc, + bool ConsumeLastToken, + bool ObjCGenericList); + bool ParseTemplateIdAfterTemplateName(TemplateTy Template, + SourceLocation TemplateNameLoc, + const CXXScopeSpec &SS, + bool ConsumeLastToken, + SourceLocation &LAngleLoc, + TemplateArgList &TemplateArgs, + SourceLocation &RAngleLoc); + + bool AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, + CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + UnqualifiedId &TemplateName, + bool AllowTypeAnnotation = true); + void AnnotateTemplateIdTokenAsType(); + bool IsTemplateArgumentList(unsigned Skip = 0); + bool ParseTemplateArgumentList(TemplateArgList &TemplateArgs); + ParsedTemplateArgument ParseTemplateTemplateArgument(); + ParsedTemplateArgument ParseTemplateArgument(); + Decl *ParseExplicitInstantiation(unsigned Context, + SourceLocation ExternLoc, + SourceLocation TemplateLoc, + SourceLocation &DeclEnd, + AccessSpecifier AS = AS_none); + + //===--------------------------------------------------------------------===// + // Modules + DeclGroupPtrTy ParseModuleImport(SourceLocation AtLoc); + bool parseMisplacedModuleImport(); + bool tryParseMisplacedModuleImport() { + tok::TokenKind Kind = Tok.getKind(); + if (Kind == tok::annot_module_begin || Kind == tok::annot_module_end || + Kind == tok::annot_module_include) + return parseMisplacedModuleImport(); + return false; + } + + //===--------------------------------------------------------------------===// + // C++11/G++: Type Traits [Type-Traits.html in the GCC manual] + ExprResult ParseTypeTrait(); + + //===--------------------------------------------------------------------===// + // Embarcadero: Arary and Expression Traits + ExprResult ParseArrayTypeTrait(); + ExprResult ParseExpressionTrait(); + + //===--------------------------------------------------------------------===// + // Preprocessor code-completion pass-through + void CodeCompleteDirective(bool InConditional) override; + void CodeCompleteInConditionalExclusion() override; + void CodeCompleteMacroName(bool IsDefinition) override; + void CodeCompletePreprocessorExpression() override; + void CodeCompleteMacroArgument(IdentifierInfo *Macro, MacroInfo *MacroInfo, + unsigned ArgumentIndex) override; + void CodeCompleteNaturalLanguage() override; +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Rewrite/Core/DeltaTree.h b/contrib/llvm/tools/clang/include/clang/Rewrite/Core/DeltaTree.h new file mode 100644 index 0000000..fbffb38 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Rewrite/Core/DeltaTree.h @@ -0,0 +1,50 @@ +//===--- DeltaTree.h - B-Tree for Rewrite Delta tracking --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the DeltaTree class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_REWRITE_CORE_DELTATREE_H +#define LLVM_CLANG_REWRITE_CORE_DELTATREE_H + +#include "llvm/Support/Compiler.h" + +namespace clang { + + /// DeltaTree - a multiway search tree (BTree) structure with some fancy + /// features. B-Trees are generally more memory and cache efficient than + /// binary trees, because they store multiple keys/values in each node. This + /// implements a key/value mapping from index to delta, and allows fast lookup + /// on index. However, an added (important) bonus is that it can also + /// efficiently tell us the full accumulated delta for a specific file offset + /// as well, without traversing the whole tree. + class DeltaTree { + void *Root; // "DeltaTreeNode *" + void operator=(const DeltaTree &) = delete; + public: + DeltaTree(); + + // Note: Currently we only support copying when the RHS is empty. + DeltaTree(const DeltaTree &RHS); + ~DeltaTree(); + + /// getDeltaAt - Return the accumulated delta at the specified file offset. + /// This includes all insertions or delections that occurred *before* the + /// specified file index. + int getDeltaAt(unsigned FileIndex) const; + + /// AddDelta - When a change is made that shifts around the text buffer, + /// this method is used to record that info. It inserts a delta of 'Delta' + /// into the current DeltaTree at offset FileIndex. + void AddDelta(unsigned FileIndex, int Delta); + }; +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Rewrite/Core/HTMLRewrite.h b/contrib/llvm/tools/clang/include/clang/Rewrite/Core/HTMLRewrite.h new file mode 100644 index 0000000..dafdf51 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Rewrite/Core/HTMLRewrite.h @@ -0,0 +1,81 @@ +//==- HTMLRewrite.h - Translate source code into prettified HTML ---*- 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 set of functions used for translating source code +// into beautified HTML. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_REWRITE_CORE_HTMLREWRITE_H +#define LLVM_CLANG_REWRITE_CORE_HTMLREWRITE_H + +#include "clang/Basic/SourceLocation.h" +#include <string> + +namespace clang { + +class Rewriter; +class RewriteBuffer; +class Preprocessor; + +namespace html { + + /// HighlightRange - Highlight a range in the source code with the specified + /// start/end tags. B/E must be in the same file. This ensures that + /// start/end tags are placed at the start/end of each line if the range is + /// multiline. + void HighlightRange(Rewriter &R, SourceLocation B, SourceLocation E, + const char *StartTag, const char *EndTag); + + /// HighlightRange - Highlight a range in the source code with the specified + /// start/end tags. The Start/end of the range must be in the same file. + /// This ensures that start/end tags are placed at the start/end of each line + /// if the range is multiline. + inline void HighlightRange(Rewriter &R, SourceRange Range, + const char *StartTag, const char *EndTag) { + HighlightRange(R, Range.getBegin(), Range.getEnd(), StartTag, EndTag); + } + + /// HighlightRange - This is the same as the above method, but takes + /// decomposed file locations. + void HighlightRange(RewriteBuffer &RB, unsigned B, unsigned E, + const char *BufferStart, + const char *StartTag, const char *EndTag); + + /// EscapeText - HTMLize a specified file so that special characters are + /// are translated so that they are not interpreted as HTML tags. + void EscapeText(Rewriter& R, FileID FID, + bool EscapeSpaces = false, bool ReplaceTabs = false); + + /// EscapeText - HTMLized the provided string so that special characters + /// in 's' are not interpreted as HTML tags. Unlike the version of + /// EscapeText that rewrites a file, this version by default replaces tabs + /// with spaces. + std::string EscapeText(StringRef s, + bool EscapeSpaces = false, bool ReplaceTabs = false); + + void AddLineNumbers(Rewriter& R, FileID FID); + + void AddHeaderFooterInternalBuiltinCSS(Rewriter& R, FileID FID, + const char *title = nullptr); + + /// SyntaxHighlight - Relex the specified FileID and annotate the HTML with + /// information about keywords, comments, etc. + void SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP); + + /// HighlightMacros - This uses the macro table state from the end of the + /// file, to reexpand macros and insert (into the HTML) information about the + /// macro expansions. This won't be perfectly perfect, but it will be + /// reasonably close. + void HighlightMacros(Rewriter &R, FileID FID, const Preprocessor &PP); + +} // end html namespace +} // end clang namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Rewrite/Core/RewriteBuffer.h b/contrib/llvm/tools/clang/include/clang/Rewrite/Core/RewriteBuffer.h new file mode 100644 index 0000000..d69c69b --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Rewrite/Core/RewriteBuffer.h @@ -0,0 +1,117 @@ +//===--- RewriteBuffer.h - Buffer rewriting interface -----------*- 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_REWRITE_CORE_REWRITEBUFFER_H +#define LLVM_CLANG_REWRITE_CORE_REWRITEBUFFER_H + +#include "clang/Basic/LLVM.h" +#include "clang/Rewrite/Core/DeltaTree.h" +#include "clang/Rewrite/Core/RewriteRope.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { + class Rewriter; + +/// RewriteBuffer - As code is rewritten, SourceBuffer's from the original +/// input with modifications get a new RewriteBuffer associated with them. The +/// RewriteBuffer captures the modified text itself as well as information used +/// to map between SourceLocation's in the original input and offsets in the +/// RewriteBuffer. For example, if text is inserted into the buffer, any +/// locations after the insertion point have to be mapped. +class RewriteBuffer { + friend class Rewriter; + /// Deltas - Keep track of all the deltas in the source code due to insertions + /// and deletions. + DeltaTree Deltas; + RewriteRope Buffer; +public: + typedef RewriteRope::const_iterator iterator; + iterator begin() const { return Buffer.begin(); } + iterator end() const { return Buffer.end(); } + unsigned size() const { return Buffer.size(); } + + /// Initialize - Start this rewrite buffer out with a copy of the unmodified + /// input buffer. + void Initialize(const char *BufStart, const char *BufEnd) { + Buffer.assign(BufStart, BufEnd); + } + void Initialize(StringRef Input) { + Initialize(Input.begin(), Input.end()); + } + + /// \brief Write to \p Stream the result of applying all changes to the + /// original buffer. + /// Note that it isn't safe to use this function to overwrite memory mapped + /// files in-place (PR17960). Consider using a higher-level utility such as + /// Rewriter::overwriteChangedFiles() instead. + /// + /// The original buffer is not actually changed. + raw_ostream &write(raw_ostream &Stream) const; + + /// RemoveText - Remove the specified text. + void RemoveText(unsigned OrigOffset, unsigned Size, + bool removeLineIfEmpty = false); + + /// InsertText - Insert some text at the specified point, where the offset in + /// the buffer is specified relative to the original SourceBuffer. The + /// text is inserted after the specified location. + /// + void InsertText(unsigned OrigOffset, StringRef Str, + bool InsertAfter = true); + + + /// InsertTextBefore - Insert some text before the specified point, where the + /// offset in the buffer is specified relative to the original + /// SourceBuffer. The text is inserted before the specified location. This is + /// method is the same as InsertText with "InsertAfter == false". + void InsertTextBefore(unsigned OrigOffset, StringRef Str) { + InsertText(OrigOffset, Str, false); + } + + /// InsertTextAfter - Insert some text at the specified point, where the + /// offset in the buffer is specified relative to the original SourceBuffer. + /// The text is inserted after the specified location. + void InsertTextAfter(unsigned OrigOffset, StringRef Str) { + InsertText(OrigOffset, Str); + } + + /// ReplaceText - This method replaces a range of characters in the input + /// buffer with a new string. This is effectively a combined "remove/insert" + /// operation. + void ReplaceText(unsigned OrigOffset, unsigned OrigLength, + StringRef NewStr); + +private: // Methods only usable by Rewriter. + + /// getMappedOffset - Given an offset into the original SourceBuffer that this + /// RewriteBuffer is based on, map it into the offset space of the + /// RewriteBuffer. If AfterInserts is true and if the OrigOffset indicates a + /// position where text is inserted, the location returned will be after any + /// inserted text at the position. + unsigned getMappedOffset(unsigned OrigOffset, + bool AfterInserts = false) const{ + return Deltas.getDeltaAt(2*OrigOffset+AfterInserts)+OrigOffset; + } + + /// AddInsertDelta - When an insertion is made at a position, this + /// method is used to record that information. + void AddInsertDelta(unsigned OrigOffset, int Change) { + return Deltas.AddDelta(2*OrigOffset, Change); + } + + /// AddReplaceDelta - When a replacement/deletion is made at a position, this + /// method is used to record that information. + void AddReplaceDelta(unsigned OrigOffset, int Change) { + return Deltas.AddDelta(2*OrigOffset+1, Change); + } +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Rewrite/Core/RewriteRope.h b/contrib/llvm/tools/clang/include/clang/Rewrite/Core/RewriteRope.h new file mode 100644 index 0000000..5002554 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Rewrite/Core/RewriteRope.h @@ -0,0 +1,214 @@ +//===--- RewriteRope.h - Rope specialized for rewriter ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the RewriteRope class, which is a powerful string class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_REWRITE_CORE_REWRITEROPE_H +#define LLVM_CLANG_REWRITE_CORE_REWRITEROPE_H + +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Compiler.h" +#include <cassert> +#include <cstddef> +#include <cstring> +#include <iterator> + +namespace clang { + //===--------------------------------------------------------------------===// + // RopeRefCountString Class + //===--------------------------------------------------------------------===// + + /// RopeRefCountString - This struct is allocated with 'new char[]' from the + /// heap, and represents a reference counted chunk of string data. When its + /// ref count drops to zero, it is delete[]'d. This is primarily managed + /// through the RopePiece class below. + struct RopeRefCountString { + unsigned RefCount; + char Data[1]; // Variable sized. + + void Retain() { ++RefCount; } + + void Release() { + assert(RefCount > 0 && "Reference count is already zero."); + if (--RefCount == 0) + delete [] (char*)this; + } + }; + + //===--------------------------------------------------------------------===// + // RopePiece Class + //===--------------------------------------------------------------------===// + + /// RopePiece - This class represents a view into a RopeRefCountString object. + /// This allows references to string data to be efficiently chopped up and + /// moved around without having to push around the string data itself. + /// + /// For example, we could have a 1M RopePiece and want to insert something + /// into the middle of it. To do this, we split it into two RopePiece objects + /// that both refer to the same underlying RopeRefCountString (just with + /// different offsets) which is a nice constant time operation. + struct RopePiece { + llvm::IntrusiveRefCntPtr<RopeRefCountString> StrData; + unsigned StartOffs; + unsigned EndOffs; + + RopePiece() : StrData(nullptr), StartOffs(0), EndOffs(0) {} + + RopePiece(llvm::IntrusiveRefCntPtr<RopeRefCountString> Str, unsigned Start, + unsigned End) + : StrData(std::move(Str)), StartOffs(Start), EndOffs(End) {} + + const char &operator[](unsigned Offset) const { + return StrData->Data[Offset+StartOffs]; + } + char &operator[](unsigned Offset) { + return StrData->Data[Offset+StartOffs]; + } + + unsigned size() const { return EndOffs-StartOffs; } + }; + + //===--------------------------------------------------------------------===// + // RopePieceBTreeIterator Class + //===--------------------------------------------------------------------===// + + /// RopePieceBTreeIterator - This class provides read-only forward iteration + /// over bytes that are in a RopePieceBTree. This first iterates over bytes + /// in a RopePiece, then iterates over RopePiece's in a RopePieceBTreeLeaf, + /// then iterates over RopePieceBTreeLeaf's in a RopePieceBTree. + class RopePieceBTreeIterator : + public std::iterator<std::forward_iterator_tag, const char, ptrdiff_t> { + /// CurNode - The current B+Tree node that we are inspecting. + const void /*RopePieceBTreeLeaf*/ *CurNode; + /// CurPiece - The current RopePiece in the B+Tree node that we're + /// inspecting. + const RopePiece *CurPiece; + /// CurChar - The current byte in the RopePiece we are pointing to. + unsigned CurChar; + public: + // begin iterator. + RopePieceBTreeIterator(const void /*RopePieceBTreeNode*/ *N); + // end iterator + RopePieceBTreeIterator() + : CurNode(nullptr), CurPiece(nullptr), CurChar(0) {} + + char operator*() const { + return (*CurPiece)[CurChar]; + } + + bool operator==(const RopePieceBTreeIterator &RHS) const { + return CurPiece == RHS.CurPiece && CurChar == RHS.CurChar; + } + bool operator!=(const RopePieceBTreeIterator &RHS) const { + return !operator==(RHS); + } + + RopePieceBTreeIterator& operator++() { // Preincrement + if (CurChar+1 < CurPiece->size()) + ++CurChar; + else + MoveToNextPiece(); + return *this; + } + inline RopePieceBTreeIterator operator++(int) { // Postincrement + RopePieceBTreeIterator tmp = *this; ++*this; return tmp; + } + + llvm::StringRef piece() const { + return llvm::StringRef(&(*CurPiece)[0], CurPiece->size()); + } + + void MoveToNextPiece(); + }; + + //===--------------------------------------------------------------------===// + // RopePieceBTree Class + //===--------------------------------------------------------------------===// + + class RopePieceBTree { + void /*RopePieceBTreeNode*/ *Root; + void operator=(const RopePieceBTree &) = delete; + public: + RopePieceBTree(); + RopePieceBTree(const RopePieceBTree &RHS); + ~RopePieceBTree(); + + typedef RopePieceBTreeIterator iterator; + iterator begin() const { return iterator(Root); } + iterator end() const { return iterator(); } + unsigned size() const; + unsigned empty() const { return size() == 0; } + + void clear(); + + void insert(unsigned Offset, const RopePiece &R); + + void erase(unsigned Offset, unsigned NumBytes); + }; + + //===--------------------------------------------------------------------===// + // RewriteRope Class + //===--------------------------------------------------------------------===// + +/// RewriteRope - A powerful string class. This class supports extremely +/// efficient insertions and deletions into the middle of it, even for +/// ridiculously long strings. +class RewriteRope { + RopePieceBTree Chunks; + + /// We allocate space for string data out of a buffer of size AllocChunkSize. + /// This keeps track of how much space is left. + llvm::IntrusiveRefCntPtr<RopeRefCountString> AllocBuffer; + unsigned AllocOffs; + enum { AllocChunkSize = 4080 }; + +public: + RewriteRope() : AllocBuffer(nullptr), AllocOffs(AllocChunkSize) {} + RewriteRope(const RewriteRope &RHS) + : Chunks(RHS.Chunks), AllocBuffer(nullptr), AllocOffs(AllocChunkSize) { + } + + typedef RopePieceBTree::iterator iterator; + typedef RopePieceBTree::iterator const_iterator; + iterator begin() const { return Chunks.begin(); } + iterator end() const { return Chunks.end(); } + unsigned size() const { return Chunks.size(); } + + void clear() { + Chunks.clear(); + } + + void assign(const char *Start, const char *End) { + clear(); + if (Start != End) + Chunks.insert(0, MakeRopeString(Start, End)); + } + + void insert(unsigned Offset, const char *Start, const char *End) { + assert(Offset <= size() && "Invalid position to insert!"); + if (Start == End) return; + Chunks.insert(Offset, MakeRopeString(Start, End)); + } + + void erase(unsigned Offset, unsigned NumBytes) { + assert(Offset+NumBytes <= size() && "Invalid region to erase!"); + if (NumBytes == 0) return; + Chunks.erase(Offset, NumBytes); + } + +private: + RopePiece MakeRopeString(const char *Start, const char *End); +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Rewrite/Core/Rewriter.h b/contrib/llvm/tools/clang/include/clang/Rewrite/Core/Rewriter.h new file mode 100644 index 0000000..800372e --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Rewrite/Core/Rewriter.h @@ -0,0 +1,195 @@ +//===--- Rewriter.h - Code rewriting interface ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Rewriter class, which is used for code +// transformations. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_REWRITE_CORE_REWRITER_H +#define LLVM_CLANG_REWRITE_CORE_REWRITER_H + +#include "clang/Basic/SourceLocation.h" +#include "clang/Rewrite/Core/RewriteBuffer.h" +#include <cstring> +#include <map> +#include <string> + +namespace clang { + class LangOptions; + class SourceManager; + +/// Rewriter - This is the main interface to the rewrite buffers. Its primary +/// job is to dispatch high-level requests to the low-level RewriteBuffers that +/// are involved. +class Rewriter { + SourceManager *SourceMgr; + const LangOptions *LangOpts; + std::map<FileID, RewriteBuffer> RewriteBuffers; +public: + struct RewriteOptions { + /// \brief Given a source range, true to include previous inserts at the + /// beginning of the range as part of the range itself (true by default). + bool IncludeInsertsAtBeginOfRange; + /// \brief Given a source range, true to include previous inserts at the + /// end of the range as part of the range itself (true by default). + bool IncludeInsertsAtEndOfRange; + /// \brief If true and removing some text leaves a blank line + /// also remove the empty line (false by default). + bool RemoveLineIfEmpty; + + RewriteOptions() + : IncludeInsertsAtBeginOfRange(true), + IncludeInsertsAtEndOfRange(true), + RemoveLineIfEmpty(false) { } + }; + + typedef std::map<FileID, RewriteBuffer>::iterator buffer_iterator; + typedef std::map<FileID, RewriteBuffer>::const_iterator const_buffer_iterator; + + explicit Rewriter(SourceManager &SM, const LangOptions &LO) + : SourceMgr(&SM), LangOpts(&LO) {} + explicit Rewriter() : SourceMgr(nullptr), LangOpts(nullptr) {} + + void setSourceMgr(SourceManager &SM, const LangOptions &LO) { + SourceMgr = &SM; + LangOpts = &LO; + } + SourceManager &getSourceMgr() const { return *SourceMgr; } + const LangOptions &getLangOpts() const { return *LangOpts; } + + /// isRewritable - Return true if this location is a raw file location, which + /// is rewritable. Locations from macros, etc are not rewritable. + static bool isRewritable(SourceLocation Loc) { + return Loc.isFileID(); + } + + /// getRangeSize - Return the size in bytes of the specified range if they + /// are in the same file. If not, this returns -1. + int getRangeSize(SourceRange Range, + RewriteOptions opts = RewriteOptions()) const; + int getRangeSize(const CharSourceRange &Range, + RewriteOptions opts = RewriteOptions()) const; + + /// getRewrittenText - Return the rewritten form of the text in the specified + /// range. If the start or end of the range was unrewritable or if they are + /// in different buffers, this returns an empty string. + /// + /// Note that this method is not particularly efficient. + /// + std::string getRewrittenText(SourceRange Range) const; + + /// InsertText - Insert the specified string at the specified location in the + /// original buffer. This method returns true (and does nothing) if the input + /// location was not rewritable, false otherwise. + /// + /// \param indentNewLines if true new lines in the string are indented + /// using the indentation of the source line in position \p Loc. + bool InsertText(SourceLocation Loc, StringRef Str, + bool InsertAfter = true, bool indentNewLines = false); + + /// InsertTextAfter - Insert the specified string at the specified location in + /// the original buffer. This method returns true (and does nothing) if + /// the input location was not rewritable, false otherwise. Text is + /// inserted after any other text that has been previously inserted + /// at the some point (the default behavior for InsertText). + bool InsertTextAfter(SourceLocation Loc, StringRef Str) { + return InsertText(Loc, Str); + } + + /// \brief Insert the specified string after the token in the + /// specified location. + bool InsertTextAfterToken(SourceLocation Loc, StringRef Str); + + /// InsertText - Insert the specified string at the specified location in the + /// original buffer. This method returns true (and does nothing) if the input + /// location was not rewritable, false otherwise. Text is + /// inserted before any other text that has been previously inserted + /// at the some point. + bool InsertTextBefore(SourceLocation Loc, StringRef Str) { + return InsertText(Loc, Str, false); + } + + /// RemoveText - Remove the specified text region. + bool RemoveText(SourceLocation Start, unsigned Length, + RewriteOptions opts = RewriteOptions()); + + /// \brief Remove the specified text region. + bool RemoveText(CharSourceRange range, + RewriteOptions opts = RewriteOptions()) { + return RemoveText(range.getBegin(), getRangeSize(range, opts), opts); + } + + /// \brief Remove the specified text region. + bool RemoveText(SourceRange range, RewriteOptions opts = RewriteOptions()) { + return RemoveText(range.getBegin(), getRangeSize(range, opts), opts); + } + + /// ReplaceText - This method replaces a range of characters in the input + /// buffer with a new string. This is effectively a combined "remove/insert" + /// operation. + bool ReplaceText(SourceLocation Start, unsigned OrigLength, + StringRef NewStr); + + /// ReplaceText - This method replaces a range of characters in the input + /// buffer with a new string. This is effectively a combined "remove/insert" + /// operation. + bool ReplaceText(SourceRange range, StringRef NewStr) { + return ReplaceText(range.getBegin(), getRangeSize(range), NewStr); + } + + /// ReplaceText - This method replaces a range of characters in the input + /// buffer with a new string. This is effectively a combined "remove/insert" + /// operation. + bool ReplaceText(SourceRange range, SourceRange replacementRange); + + /// \brief Increase indentation for the lines between the given source range. + /// To determine what the indentation should be, 'parentIndent' is used + /// that should be at a source location with an indentation one degree + /// lower than the given range. + bool IncreaseIndentation(CharSourceRange range, SourceLocation parentIndent); + bool IncreaseIndentation(SourceRange range, SourceLocation parentIndent) { + return IncreaseIndentation(CharSourceRange::getTokenRange(range), + parentIndent); + } + + /// getEditBuffer - This is like getRewriteBufferFor, but always returns a + /// buffer, and allows you to write on it directly. This is useful if you + /// want efficient low-level access to apis for scribbling on one specific + /// FileID's buffer. + RewriteBuffer &getEditBuffer(FileID FID); + + /// getRewriteBufferFor - Return the rewrite buffer for the specified FileID. + /// If no modification has been made to it, return null. + const RewriteBuffer *getRewriteBufferFor(FileID FID) const { + std::map<FileID, RewriteBuffer>::const_iterator I = + RewriteBuffers.find(FID); + return I == RewriteBuffers.end() ? nullptr : &I->second; + } + + // Iterators over rewrite buffers. + buffer_iterator buffer_begin() { return RewriteBuffers.begin(); } + buffer_iterator buffer_end() { return RewriteBuffers.end(); } + const_buffer_iterator buffer_begin() const { return RewriteBuffers.begin(); } + const_buffer_iterator buffer_end() const { return RewriteBuffers.end(); } + + /// overwriteChangedFiles - Save all changed files to disk. + /// + /// Returns true if any files were not saved successfully. + /// Outputs diagnostics via the source manager's diagnostic engine + /// in case of an error. + bool overwriteChangedFiles(); + +private: + unsigned getLocationOffsetAndFileID(SourceLocation Loc, FileID &FID) const; +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Rewrite/Core/TokenRewriter.h b/contrib/llvm/tools/clang/include/clang/Rewrite/Core/TokenRewriter.h new file mode 100644 index 0000000..0f71e81 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Rewrite/Core/TokenRewriter.h @@ -0,0 +1,79 @@ +//===--- TokenRewriter.h - Token-based Rewriter -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TokenRewriter class, which is used for code +// transformations. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_REWRITE_CORE_TOKENREWRITER_H +#define LLVM_CLANG_REWRITE_CORE_TOKENREWRITER_H + +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Token.h" +#include <list> +#include <map> +#include <memory> + +namespace clang { + class LangOptions; + class ScratchBuffer; + + class TokenRewriter { + /// TokenList - This is the list of raw tokens that make up this file. Each + /// of these tokens has a unique SourceLocation, which is a FileID. + std::list<Token> TokenList; + + /// TokenRefTy - This is the type used to refer to a token in the TokenList. + typedef std::list<Token>::iterator TokenRefTy; + + /// TokenAtLoc - This map indicates which token exists at a specific + /// SourceLocation. Since each token has a unique SourceLocation, this is a + /// one to one map. The token can return its own location directly, to map + /// backwards. + std::map<SourceLocation, TokenRefTy> TokenAtLoc; + + /// ScratchBuf - This is the buffer that we create scratch tokens from. + /// + std::unique_ptr<ScratchBuffer> ScratchBuf; + + TokenRewriter(const TokenRewriter &) = delete; + void operator=(const TokenRewriter &) = delete; + public: + /// TokenRewriter - This creates a TokenRewriter for the file with the + /// specified FileID. + TokenRewriter(FileID FID, SourceManager &SM, const LangOptions &LO); + ~TokenRewriter(); + + typedef std::list<Token>::const_iterator token_iterator; + token_iterator token_begin() const { return TokenList.begin(); } + token_iterator token_end() const { return TokenList.end(); } + + + token_iterator AddTokenBefore(token_iterator I, const char *Val); + token_iterator AddTokenAfter(token_iterator I, const char *Val) { + assert(I != token_end() && "Cannot insert after token_end()!"); + return AddTokenBefore(++I, Val); + } + + private: + /// RemapIterator - Convert from token_iterator (a const iterator) to + /// TokenRefTy (a non-const iterator). + TokenRefTy RemapIterator(token_iterator I); + + /// AddToken - Add the specified token into the Rewriter before the other + /// position. + TokenRefTy AddToken(const Token &T, TokenRefTy Where); + }; + + + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Rewrite/Frontend/ASTConsumers.h b/contrib/llvm/tools/clang/include/clang/Rewrite/Frontend/ASTConsumers.h new file mode 100644 index 0000000..c9df889 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Rewrite/Frontend/ASTConsumers.h @@ -0,0 +1,48 @@ +//===--- ASTConsumers.h - ASTConsumer implementations -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// AST Consumers. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_REWRITE_FRONTEND_ASTCONSUMERS_H +#define LLVM_CLANG_REWRITE_FRONTEND_ASTCONSUMERS_H + +#include "clang/Basic/LLVM.h" +#include <memory> +#include <string> + +namespace clang { + +class ASTConsumer; +class DiagnosticsEngine; +class LangOptions; +class Preprocessor; + +// ObjC rewriter: attempts to rewrite ObjC constructs into pure C code. +// This is considered experimental, and only works with Apple's ObjC runtime. +std::unique_ptr<ASTConsumer> +CreateObjCRewriter(const std::string &InFile, raw_ostream *OS, + DiagnosticsEngine &Diags, const LangOptions &LOpts, + bool SilenceRewriteMacroWarning); +std::unique_ptr<ASTConsumer> +CreateModernObjCRewriter(const std::string &InFile, raw_ostream *OS, + DiagnosticsEngine &Diags, const LangOptions &LOpts, + bool SilenceRewriteMacroWarning, bool LineInfo); + +/// CreateHTMLPrinter - Create an AST consumer which rewrites source code to +/// HTML with syntax highlighting suitable for viewing in a web-browser. +std::unique_ptr<ASTConsumer> CreateHTMLPrinter(raw_ostream *OS, + Preprocessor &PP, + bool SyntaxHighlight = true, + bool HighlightMacros = true); + +} // end clang namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Rewrite/Frontend/FixItRewriter.h b/contrib/llvm/tools/clang/include/clang/Rewrite/Frontend/FixItRewriter.h new file mode 100644 index 0000000..3b1b31e --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Rewrite/Frontend/FixItRewriter.h @@ -0,0 +1,132 @@ +//===--- FixItRewriter.h - Fix-It Rewriter Diagnostic Client ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a diagnostic client adaptor that performs rewrites as +// suggested by code modification hints attached to diagnostics. It +// then forwards any diagnostics to the adapted diagnostic client. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_REWRITE_FRONTEND_FIXITREWRITER_H +#define LLVM_CLANG_REWRITE_FRONTEND_FIXITREWRITER_H + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Edit/EditedSource.h" +#include "clang/Rewrite/Core/Rewriter.h" + +namespace clang { + +class SourceManager; +class FileEntry; + +class FixItOptions { +public: + FixItOptions() : InPlace(false), FixWhatYouCan(false), + FixOnlyWarnings(false), Silent(false) { } + + virtual ~FixItOptions(); + + /// \brief This file is about to be rewritten. Return the name of the file + /// that is okay to write to. + /// + /// \param fd out parameter for file descriptor. After the call it may be set + /// to an open file descriptor for the returned filename, or it will be -1 + /// otherwise. + /// + virtual std::string RewriteFilename(const std::string &Filename, int &fd) = 0; + + /// True if files should be updated in place. RewriteFilename is only called + /// if this is false. + bool InPlace; + + /// \brief Whether to abort fixing a file when not all errors could be fixed. + bool FixWhatYouCan; + + /// \brief Whether to only fix warnings and not errors. + bool FixOnlyWarnings; + + /// \brief If true, only pass the diagnostic to the actual diagnostic consumer + /// if it is an error or a fixit was applied as part of the diagnostic. + /// It basically silences warnings without accompanying fixits. + bool Silent; +}; + +class FixItRewriter : public DiagnosticConsumer { + /// \brief The diagnostics machinery. + DiagnosticsEngine &Diags; + + edit::EditedSource Editor; + + /// \brief The rewriter used to perform the various code + /// modifications. + Rewriter Rewrite; + + /// \brief The diagnostic client that performs the actual formatting + /// of error messages. + DiagnosticConsumer *Client; + std::unique_ptr<DiagnosticConsumer> Owner; + + /// \brief Turn an input path into an output path. NULL implies overwriting + /// the original. + FixItOptions *FixItOpts; + + /// \brief The number of rewriter failures. + unsigned NumFailures; + + /// \brief Whether the previous diagnostic was not passed to the consumer. + bool PrevDiagSilenced; + +public: + typedef Rewriter::buffer_iterator iterator; + + /// \brief Initialize a new fix-it rewriter. + FixItRewriter(DiagnosticsEngine &Diags, SourceManager &SourceMgr, + const LangOptions &LangOpts, FixItOptions *FixItOpts); + + /// \brief Destroy the fix-it rewriter. + ~FixItRewriter() override; + + /// \brief Check whether there are modifications for a given file. + bool IsModified(FileID ID) const { + return Rewrite.getRewriteBufferFor(ID) != nullptr; + } + + // Iteration over files with changes. + iterator buffer_begin() { return Rewrite.buffer_begin(); } + iterator buffer_end() { return Rewrite.buffer_end(); } + + /// \brief Write a single modified source file. + /// + /// \returns true if there was an error, false otherwise. + bool WriteFixedFile(FileID ID, raw_ostream &OS); + + /// \brief Write the modified source files. + /// + /// \returns true if there was an error, false otherwise. + bool WriteFixedFiles( + std::vector<std::pair<std::string, std::string> > *RewrittenFiles=nullptr); + + /// IncludeInDiagnosticCounts - This method (whose default implementation + /// returns true) indicates whether the diagnostics handled by this + /// DiagnosticConsumer should be included in the number of diagnostics + /// reported by DiagnosticsEngine. + bool IncludeInDiagnosticCounts() const override; + + /// HandleDiagnostic - Handle this diagnostic, reporting it to the user or + /// capturing it to a log as needed. + void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, + const Diagnostic &Info) override; + + /// \brief Emit a diagnostic via the adapted diagnostic client. + void Diag(SourceLocation Loc, unsigned DiagID); +}; + +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Rewrite/Frontend/FrontendActions.h b/contrib/llvm/tools/clang/include/clang/Rewrite/Frontend/FrontendActions.h new file mode 100644 index 0000000..6c290e4 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Rewrite/Frontend/FrontendActions.h @@ -0,0 +1,83 @@ +//===-- FrontendActions.h - Useful Frontend Actions -------------*- 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_REWRITE_FRONTEND_FRONTENDACTIONS_H +#define LLVM_CLANG_REWRITE_FRONTEND_FRONTENDACTIONS_H + +#include "clang/Frontend/FrontendAction.h" + +namespace clang { +class FixItRewriter; +class FixItOptions; + +//===----------------------------------------------------------------------===// +// AST Consumer Actions +//===----------------------------------------------------------------------===// + +class HTMLPrintAction : public ASTFrontendAction { +protected: + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override; +}; + +class FixItAction : public ASTFrontendAction { +protected: + std::unique_ptr<FixItRewriter> Rewriter; + std::unique_ptr<FixItOptions> FixItOpts; + + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override; + + bool BeginSourceFileAction(CompilerInstance &CI, + StringRef Filename) override; + + void EndSourceFileAction() override; + + bool hasASTFileSupport() const override { return false; } + +public: + FixItAction(); + ~FixItAction() override; +}; + +/// \brief Emits changes to temporary files and uses them for the original +/// frontend action. +class FixItRecompile : public WrapperFrontendAction { +public: + FixItRecompile(FrontendAction *WrappedAction) + : WrapperFrontendAction(WrappedAction) {} + +protected: + bool BeginInvocation(CompilerInstance &CI) override; +}; + +class RewriteObjCAction : public ASTFrontendAction { +protected: + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override; +}; + +class RewriteMacrosAction : public PreprocessorFrontendAction { +protected: + void ExecuteAction() override; +}; + +class RewriteTestAction : public PreprocessorFrontendAction { +protected: + void ExecuteAction() override; +}; + +class RewriteIncludesAction : public PreprocessorFrontendAction { +protected: + void ExecuteAction() override; +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Rewrite/Frontend/Rewriters.h b/contrib/llvm/tools/clang/include/clang/Rewrite/Frontend/Rewriters.h new file mode 100644 index 0000000..3ad76df --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Rewrite/Frontend/Rewriters.h @@ -0,0 +1,35 @@ +//===--- Rewriters.h - Rewriter implementations -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header contains miscellaneous utilities for various front-end actions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_REWRITE_FRONTEND_REWRITERS_H +#define LLVM_CLANG_REWRITE_FRONTEND_REWRITERS_H + +#include "clang/Basic/LLVM.h" + +namespace clang { +class Preprocessor; +class PreprocessorOutputOptions; + +/// RewriteMacrosInInput - Implement -rewrite-macros mode. +void RewriteMacrosInInput(Preprocessor &PP, raw_ostream *OS); + +/// DoRewriteTest - A simple test for the TokenRewriter class. +void DoRewriteTest(Preprocessor &PP, raw_ostream *OS); + +/// RewriteIncludesInInput - Implement -frewrite-includes mode. +void RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS, + const PreprocessorOutputOptions &Opts); + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Sema/AnalysisBasedWarnings.h b/contrib/llvm/tools/clang/include/clang/Sema/AnalysisBasedWarnings.h new file mode 100644 index 0000000..64dd2d3 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Sema/AnalysisBasedWarnings.h @@ -0,0 +1,103 @@ +//=- AnalysisBasedWarnings.h - Sema warnings based on libAnalysis -*- 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 AnalysisBasedWarnings, a worker object used by Sema +// that issues warnings based on dataflow-analysis. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_ANALYSISBASEDWARNINGS_H +#define LLVM_CLANG_SEMA_ANALYSISBASEDWARNINGS_H + +#include "llvm/ADT/DenseMap.h" + +namespace clang { + +class BlockExpr; +class Decl; +class FunctionDecl; +class ObjCMethodDecl; +class QualType; +class Sema; +namespace sema { + class FunctionScopeInfo; +} + +namespace sema { + +class AnalysisBasedWarnings { +public: + class Policy { + friend class AnalysisBasedWarnings; + // The warnings to run. + unsigned enableCheckFallThrough : 1; + unsigned enableCheckUnreachable : 1; + unsigned enableThreadSafetyAnalysis : 1; + unsigned enableConsumedAnalysis : 1; + public: + Policy(); + void disableCheckFallThrough() { enableCheckFallThrough = 0; } + }; + +private: + Sema &S; + Policy DefaultPolicy; + + enum VisitFlag { NotVisited = 0, Visited = 1, Pending = 2 }; + llvm::DenseMap<const FunctionDecl*, VisitFlag> VisitedFD; + + /// \name Statistics + /// @{ + + /// \brief Number of function CFGs built and analyzed. + unsigned NumFunctionsAnalyzed; + + /// \brief Number of functions for which the CFG could not be successfully + /// built. + unsigned NumFunctionsWithBadCFGs; + + /// \brief Total number of blocks across all CFGs. + unsigned NumCFGBlocks; + + /// \brief Largest number of CFG blocks for a single function analyzed. + unsigned MaxCFGBlocksPerFunction; + + /// \brief Total number of CFGs with variables analyzed for uninitialized + /// uses. + unsigned NumUninitAnalysisFunctions; + + /// \brief Total number of variables analyzed for uninitialized uses. + unsigned NumUninitAnalysisVariables; + + /// \brief Max number of variables analyzed for uninitialized uses in a single + /// function. + unsigned MaxUninitAnalysisVariablesPerFunction; + + /// \brief Total number of block visits during uninitialized use analysis. + unsigned NumUninitAnalysisBlockVisits; + + /// \brief Max number of block visits during uninitialized use analysis of + /// a single function. + unsigned MaxUninitAnalysisBlockVisitsPerFunction; + + /// @} + +public: + AnalysisBasedWarnings(Sema &s); + + void IssueWarnings(Policy P, FunctionScopeInfo *fscope, + const Decl *D, const BlockExpr *blkExpr); + + Policy getDefaultPolicy() { return DefaultPolicy; } + + void PrintStats() const; +}; + +}} // end namespace clang::sema + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Sema/AttributeList.h b/contrib/llvm/tools/clang/include/clang/Sema/AttributeList.h new file mode 100644 index 0000000..e32781d --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Sema/AttributeList.h @@ -0,0 +1,863 @@ +//===--- AttributeList.h - Parsed attribute sets ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the AttributeList class, which is used to collect +// parsed attributes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_ATTRIBUTELIST_H +#define LLVM_CLANG_SEMA_ATTRIBUTELIST_H + +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/VersionTuple.h" +#include "clang/Sema/Ownership.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Allocator.h" +#include <cassert> + +namespace clang { + class ASTContext; + class IdentifierInfo; + class Expr; + +/// \brief Represents information about a change in availability for +/// an entity, which is part of the encoding of the 'availability' +/// attribute. +struct AvailabilityChange { + /// \brief The location of the keyword indicating the kind of change. + SourceLocation KeywordLoc; + + /// \brief The version number at which the change occurred. + VersionTuple Version; + + /// \brief The source range covering the version number. + SourceRange VersionRange; + + /// \brief Determine whether this availability change is valid. + bool isValid() const { return !Version.empty(); } +}; + +/// \brief Wraps an identifier and optional source location for the identifier. +struct IdentifierLoc { + SourceLocation Loc; + IdentifierInfo *Ident; + + static IdentifierLoc *create(ASTContext &Ctx, SourceLocation Loc, + IdentifierInfo *Ident); +}; + +/// \brief A union of the various pointer types that can be passed to an +/// AttributeList as an argument. +typedef llvm::PointerUnion<Expr*, IdentifierLoc*> ArgsUnion; +typedef llvm::SmallVector<ArgsUnion, 12U> ArgsVector; + +/// AttributeList - Represents a syntactic attribute. +/// +/// For a GNU attribute, there are four forms of this construct: +/// +/// 1: __attribute__(( const )). ParmName/Args/NumArgs will all be unused. +/// 2: __attribute__(( mode(byte) )). ParmName used, Args/NumArgs unused. +/// 3: __attribute__(( format(printf, 1, 2) )). ParmName/Args/NumArgs all used. +/// 4: __attribute__(( aligned(16) )). ParmName is unused, Args/Num used. +/// +class AttributeList { // TODO: This should really be called ParsedAttribute +public: + /// The style used to specify an attribute. + enum Syntax { + /// __attribute__((...)) + AS_GNU, + /// [[...]] + AS_CXX11, + /// __declspec(...) + AS_Declspec, + /// __ptr16, alignas(...), etc. + AS_Keyword, + /// Context-sensitive version of a keyword attribute. + AS_ContextSensitiveKeyword, + /// #pragma ... + AS_Pragma + }; + +private: + IdentifierInfo *AttrName; + IdentifierInfo *ScopeName; + SourceRange AttrRange; + SourceLocation ScopeLoc; + SourceLocation EllipsisLoc; + + /// The number of expression arguments this attribute has. + /// The expressions themselves are stored after the object. + unsigned NumArgs : 15; + + /// Corresponds to the Syntax enum. + unsigned SyntaxUsed : 3; + + /// True if already diagnosed as invalid. + mutable unsigned Invalid : 1; + + /// True if this attribute was used as a type attribute. + mutable unsigned UsedAsTypeAttr : 1; + + /// True if this has the extra information associated with an + /// availability attribute. + unsigned IsAvailability : 1; + + /// True if this has extra information associated with a + /// type_tag_for_datatype attribute. + unsigned IsTypeTagForDatatype : 1; + + /// True if this has extra information associated with a + /// Microsoft __delcspec(property) attribute. + unsigned IsProperty : 1; + + /// True if this has a ParsedType + unsigned HasParsedType : 1; + + unsigned AttrKind : 8; + + /// \brief The location of the 'unavailable' keyword in an + /// availability attribute. + SourceLocation UnavailableLoc; + + const Expr *MessageExpr; + + /// The next attribute in the current position. + AttributeList *NextInPosition; + + /// The next attribute allocated in the current Pool. + AttributeList *NextInPool; + + /// Arguments, if any, are stored immediately following the object. + ArgsUnion *getArgsBuffer() { return reinterpret_cast<ArgsUnion *>(this + 1); } + ArgsUnion const *getArgsBuffer() const { + return reinterpret_cast<ArgsUnion const *>(this + 1); + } + + enum AvailabilitySlot { + IntroducedSlot, DeprecatedSlot, ObsoletedSlot + }; + + /// Availability information is stored immediately following the arguments, + /// if any, at the end of the object. + AvailabilityChange &getAvailabilitySlot(AvailabilitySlot index) { + return reinterpret_cast<AvailabilityChange*>(getArgsBuffer() + + NumArgs)[index]; + } + const AvailabilityChange &getAvailabilitySlot(AvailabilitySlot index) const { + return reinterpret_cast<const AvailabilityChange*>(getArgsBuffer() + + NumArgs)[index]; + } + +public: + struct TypeTagForDatatypeData { + ParsedType *MatchingCType; + unsigned LayoutCompatible : 1; + unsigned MustBeNull : 1; + }; + struct PropertyData { + IdentifierInfo *GetterId, *SetterId; + PropertyData(IdentifierInfo *getterId, IdentifierInfo *setterId) + : GetterId(getterId), SetterId(setterId) {} + }; + +private: + /// Type tag information is stored immediately following the arguments, if + /// any, at the end of the object. They are mutually exlusive with + /// availability slots. + TypeTagForDatatypeData &getTypeTagForDatatypeDataSlot() { + return *reinterpret_cast<TypeTagForDatatypeData*>(getArgsBuffer()+NumArgs); + } + + const TypeTagForDatatypeData &getTypeTagForDatatypeDataSlot() const { + return *reinterpret_cast<const TypeTagForDatatypeData*>(getArgsBuffer() + + NumArgs); + } + + /// The type buffer immediately follows the object and are mutually exclusive + /// with arguments. + ParsedType &getTypeBuffer() { + return *reinterpret_cast<ParsedType *>(this + 1); + } + + const ParsedType &getTypeBuffer() const { + return *reinterpret_cast<const ParsedType *>(this + 1); + } + + /// The property data immediately follows the object is is mutually exclusive + /// with arguments. + PropertyData &getPropertyDataBuffer() { + assert(IsProperty); + return *reinterpret_cast<PropertyData*>(this + 1); + } + + const PropertyData &getPropertyDataBuffer() const { + assert(IsProperty); + return *reinterpret_cast<const PropertyData*>(this + 1); + } + + AttributeList(const AttributeList &) = delete; + void operator=(const AttributeList &) = delete; + void operator delete(void *) = delete; + ~AttributeList() = delete; + + size_t allocated_size() const; + + /// Constructor for attributes with expression arguments. + AttributeList(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + ArgsUnion *args, unsigned numArgs, + Syntax syntaxUsed, SourceLocation ellipsisLoc) + : AttrName(attrName), ScopeName(scopeName), AttrRange(attrRange), + ScopeLoc(scopeLoc), EllipsisLoc(ellipsisLoc), NumArgs(numArgs), + SyntaxUsed(syntaxUsed), Invalid(false), UsedAsTypeAttr(false), + IsAvailability(false), IsTypeTagForDatatype(false), IsProperty(false), + HasParsedType(false), NextInPosition(nullptr), NextInPool(nullptr) { + if (numArgs) memcpy(getArgsBuffer(), args, numArgs * sizeof(ArgsUnion)); + AttrKind = getKind(getName(), getScopeName(), syntaxUsed); + } + + /// Constructor for availability attributes. + AttributeList(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierLoc *Parm, const AvailabilityChange &introduced, + const AvailabilityChange &deprecated, + const AvailabilityChange &obsoleted, + SourceLocation unavailable, + const Expr *messageExpr, + Syntax syntaxUsed) + : AttrName(attrName), ScopeName(scopeName), AttrRange(attrRange), + ScopeLoc(scopeLoc), EllipsisLoc(), NumArgs(1), SyntaxUsed(syntaxUsed), + Invalid(false), UsedAsTypeAttr(false), IsAvailability(true), + IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(false), + UnavailableLoc(unavailable), MessageExpr(messageExpr), + NextInPosition(nullptr), NextInPool(nullptr) { + ArgsUnion PVal(Parm); + memcpy(getArgsBuffer(), &PVal, sizeof(ArgsUnion)); + new (&getAvailabilitySlot(IntroducedSlot)) AvailabilityChange(introduced); + new (&getAvailabilitySlot(DeprecatedSlot)) AvailabilityChange(deprecated); + new (&getAvailabilitySlot(ObsoletedSlot)) AvailabilityChange(obsoleted); + AttrKind = getKind(getName(), getScopeName(), syntaxUsed); + } + + /// Constructor for objc_bridge_related attributes. + AttributeList(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierLoc *Parm1, + IdentifierLoc *Parm2, + IdentifierLoc *Parm3, + Syntax syntaxUsed) + : AttrName(attrName), ScopeName(scopeName), AttrRange(attrRange), + ScopeLoc(scopeLoc), EllipsisLoc(), NumArgs(3), SyntaxUsed(syntaxUsed), + Invalid(false), UsedAsTypeAttr(false), IsAvailability(false), + IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(false), + NextInPosition(nullptr), NextInPool(nullptr) { + ArgsVector Args; + Args.push_back(Parm1); + Args.push_back(Parm2); + Args.push_back(Parm3); + memcpy(getArgsBuffer(), &Args[0], 3 * sizeof(ArgsUnion)); + AttrKind = getKind(getName(), getScopeName(), syntaxUsed); + } + + /// Constructor for type_tag_for_datatype attribute. + AttributeList(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierLoc *ArgKind, ParsedType matchingCType, + bool layoutCompatible, bool mustBeNull, Syntax syntaxUsed) + : AttrName(attrName), ScopeName(scopeName), AttrRange(attrRange), + ScopeLoc(scopeLoc), EllipsisLoc(), NumArgs(1), SyntaxUsed(syntaxUsed), + Invalid(false), UsedAsTypeAttr(false), IsAvailability(false), + IsTypeTagForDatatype(true), IsProperty(false), HasParsedType(false), + NextInPosition(nullptr), NextInPool(nullptr) { + ArgsUnion PVal(ArgKind); + memcpy(getArgsBuffer(), &PVal, sizeof(ArgsUnion)); + TypeTagForDatatypeData &ExtraData = getTypeTagForDatatypeDataSlot(); + new (&ExtraData.MatchingCType) ParsedType(matchingCType); + ExtraData.LayoutCompatible = layoutCompatible; + ExtraData.MustBeNull = mustBeNull; + AttrKind = getKind(getName(), getScopeName(), syntaxUsed); + } + + /// Constructor for attributes with a single type argument. + AttributeList(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + ParsedType typeArg, Syntax syntaxUsed) + : AttrName(attrName), ScopeName(scopeName), AttrRange(attrRange), + ScopeLoc(scopeLoc), EllipsisLoc(), NumArgs(0), SyntaxUsed(syntaxUsed), + Invalid(false), UsedAsTypeAttr(false), IsAvailability(false), + IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(true), + NextInPosition(nullptr), NextInPool(nullptr) { + new (&getTypeBuffer()) ParsedType(typeArg); + AttrKind = getKind(getName(), getScopeName(), syntaxUsed); + } + + /// Constructor for microsoft __declspec(property) attribute. + AttributeList(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierInfo *getterId, IdentifierInfo *setterId, + Syntax syntaxUsed) + : AttrName(attrName), ScopeName(scopeName), AttrRange(attrRange), + ScopeLoc(scopeLoc), EllipsisLoc(), NumArgs(0), SyntaxUsed(syntaxUsed), + Invalid(false), UsedAsTypeAttr(false), IsAvailability(false), + IsTypeTagForDatatype(false), IsProperty(true), HasParsedType(false), + NextInPosition(nullptr), NextInPool(nullptr) { + new (&getPropertyDataBuffer()) PropertyData(getterId, setterId); + AttrKind = getKind(getName(), getScopeName(), syntaxUsed); + } + + friend class AttributePool; + friend class AttributeFactory; + +public: + enum Kind { + #define PARSED_ATTR(NAME) AT_##NAME, + #include "clang/Sema/AttrParsedAttrList.inc" + #undef PARSED_ATTR + IgnoredAttribute, + UnknownAttribute + }; + + IdentifierInfo *getName() const { return AttrName; } + SourceLocation getLoc() const { return AttrRange.getBegin(); } + SourceRange getRange() const { return AttrRange; } + + bool hasScope() const { return ScopeName; } + IdentifierInfo *getScopeName() const { return ScopeName; } + SourceLocation getScopeLoc() const { return ScopeLoc; } + + bool hasParsedType() const { return HasParsedType; } + + /// Is this the Microsoft __declspec(property) attribute? + bool isDeclspecPropertyAttribute() const { + return IsProperty; + } + + bool isAlignasAttribute() const { + // FIXME: Use a better mechanism to determine this. + return getKind() == AT_Aligned && isKeywordAttribute(); + } + + bool isDeclspecAttribute() const { return SyntaxUsed == AS_Declspec; } + bool isCXX11Attribute() const { + return SyntaxUsed == AS_CXX11 || isAlignasAttribute(); + } + bool isKeywordAttribute() const { + return SyntaxUsed == AS_Keyword || SyntaxUsed == AS_ContextSensitiveKeyword; + } + + bool isContextSensitiveKeywordAttribute() const { + return SyntaxUsed == AS_ContextSensitiveKeyword; + } + + bool isInvalid() const { return Invalid; } + void setInvalid(bool b = true) const { Invalid = b; } + + bool isUsedAsTypeAttr() const { return UsedAsTypeAttr; } + void setUsedAsTypeAttr() { UsedAsTypeAttr = true; } + + bool isPackExpansion() const { return EllipsisLoc.isValid(); } + SourceLocation getEllipsisLoc() const { return EllipsisLoc; } + + Kind getKind() const { return Kind(AttrKind); } + static Kind getKind(const IdentifierInfo *Name, const IdentifierInfo *Scope, + Syntax SyntaxUsed); + + AttributeList *getNext() const { return NextInPosition; } + void setNext(AttributeList *N) { NextInPosition = N; } + + /// getNumArgs - Return the number of actual arguments to this attribute. + unsigned getNumArgs() const { return NumArgs; } + + /// getArg - Return the specified argument. + ArgsUnion getArg(unsigned Arg) const { + assert(Arg < NumArgs && "Arg access out of range!"); + return getArgsBuffer()[Arg]; + } + + bool isArgExpr(unsigned Arg) const { + return Arg < NumArgs && getArg(Arg).is<Expr*>(); + } + Expr *getArgAsExpr(unsigned Arg) const { + return getArg(Arg).get<Expr*>(); + } + + bool isArgIdent(unsigned Arg) const { + return Arg < NumArgs && getArg(Arg).is<IdentifierLoc*>(); + } + IdentifierLoc *getArgAsIdent(unsigned Arg) const { + return getArg(Arg).get<IdentifierLoc*>(); + } + + const AvailabilityChange &getAvailabilityIntroduced() const { + assert(getKind() == AT_Availability && "Not an availability attribute"); + return getAvailabilitySlot(IntroducedSlot); + } + + const AvailabilityChange &getAvailabilityDeprecated() const { + assert(getKind() == AT_Availability && "Not an availability attribute"); + return getAvailabilitySlot(DeprecatedSlot); + } + + const AvailabilityChange &getAvailabilityObsoleted() const { + assert(getKind() == AT_Availability && "Not an availability attribute"); + return getAvailabilitySlot(ObsoletedSlot); + } + + SourceLocation getUnavailableLoc() const { + assert(getKind() == AT_Availability && "Not an availability attribute"); + return UnavailableLoc; + } + + const Expr * getMessageExpr() const { + assert(getKind() == AT_Availability && "Not an availability attribute"); + return MessageExpr; + } + + const ParsedType &getMatchingCType() const { + assert(getKind() == AT_TypeTagForDatatype && + "Not a type_tag_for_datatype attribute"); + return *getTypeTagForDatatypeDataSlot().MatchingCType; + } + + bool getLayoutCompatible() const { + assert(getKind() == AT_TypeTagForDatatype && + "Not a type_tag_for_datatype attribute"); + return getTypeTagForDatatypeDataSlot().LayoutCompatible; + } + + bool getMustBeNull() const { + assert(getKind() == AT_TypeTagForDatatype && + "Not a type_tag_for_datatype attribute"); + return getTypeTagForDatatypeDataSlot().MustBeNull; + } + + const ParsedType &getTypeArg() const { + assert(HasParsedType && "Not a type attribute"); + return getTypeBuffer(); + } + + const PropertyData &getPropertyData() const { + assert(isDeclspecPropertyAttribute() && "Not a __delcspec(property) attribute"); + return getPropertyDataBuffer(); + } + + /// \brief Get an index into the attribute spelling list + /// defined in Attr.td. This index is used by an attribute + /// to pretty print itself. + unsigned getAttributeSpellingListIndex() const; + + bool isTargetSpecificAttr() const; + bool isTypeAttr() const; + + bool hasCustomParsing() const; + unsigned getMinArgs() const; + unsigned getMaxArgs() const; + bool hasVariadicArg() const; + bool diagnoseAppertainsTo(class Sema &S, const Decl *D) const; + bool diagnoseLangOpts(class Sema &S) const; + bool existsInTarget(const TargetInfo &Target) const; + bool isKnownToGCC() const; + + /// \brief If the parsed attribute has a semantic equivalent, and it would + /// have a semantic Spelling enumeration (due to having semantically-distinct + /// spelling variations), return the value of that semantic spelling. If the + /// parsed attribute does not have a semantic equivalent, or would not have + /// a Spelling enumeration, the value UINT_MAX is returned. + unsigned getSemanticSpelling() const; +}; + +/// A factory, from which one makes pools, from which one creates +/// individual attributes which are deallocated with the pool. +/// +/// Note that it's tolerably cheap to create and destroy one of +/// these as long as you don't actually allocate anything in it. +class AttributeFactory { +public: + enum { + /// The required allocation size of an availability attribute, + /// which we want to ensure is a multiple of sizeof(void*). + AvailabilityAllocSize = + sizeof(AttributeList) + + ((3 * sizeof(AvailabilityChange) + sizeof(void*) + + sizeof(ArgsUnion) - 1) + / sizeof(void*) * sizeof(void*)), + TypeTagForDatatypeAllocSize = + sizeof(AttributeList) + + (sizeof(AttributeList::TypeTagForDatatypeData) + sizeof(void *) + + sizeof(ArgsUnion) - 1) + / sizeof(void*) * sizeof(void*), + PropertyAllocSize = + sizeof(AttributeList) + + (sizeof(AttributeList::PropertyData) + sizeof(void *) - 1) + / sizeof(void*) * sizeof(void*) + }; + +private: + enum { + /// The number of free lists we want to be sure to support + /// inline. This is just enough that availability attributes + /// don't surpass it. It's actually very unlikely we'll see an + /// attribute that needs more than that; on x86-64 you'd need 10 + /// expression arguments, and on i386 you'd need 19. + InlineFreeListsCapacity = + 1 + (AvailabilityAllocSize - sizeof(AttributeList)) / sizeof(void*) + }; + + llvm::BumpPtrAllocator Alloc; + + /// Free lists. The index is determined by the following formula: + /// (size - sizeof(AttributeList)) / sizeof(void*) + SmallVector<AttributeList*, InlineFreeListsCapacity> FreeLists; + + // The following are the private interface used by AttributePool. + friend class AttributePool; + + /// Allocate an attribute of the given size. + void *allocate(size_t size); + + /// Reclaim all the attributes in the given pool chain, which is + /// non-empty. Note that the current implementation is safe + /// against reclaiming things which were not actually allocated + /// with the allocator, although of course it's important to make + /// sure that their allocator lives at least as long as this one. + void reclaimPool(AttributeList *head); + +public: + AttributeFactory(); + ~AttributeFactory(); +}; + +class AttributePool { + AttributeFactory &Factory; + AttributeList *Head; + + void *allocate(size_t size) { + return Factory.allocate(size); + } + + AttributeList *add(AttributeList *attr) { + // We don't care about the order of the pool. + attr->NextInPool = Head; + Head = attr; + return attr; + } + + void takePool(AttributeList *pool); + +public: + /// Create a new pool for a factory. + AttributePool(AttributeFactory &factory) : Factory(factory), Head(nullptr) {} + + AttributePool(const AttributePool &) = delete; + + /// Move the given pool's allocations to this pool. + AttributePool(AttributePool &&pool) : Factory(pool.Factory), Head(pool.Head) { + pool.Head = nullptr; + } + + AttributeFactory &getFactory() const { return Factory; } + + void clear() { + if (Head) { + Factory.reclaimPool(Head); + Head = nullptr; + } + } + + /// Take the given pool's allocations and add them to this pool. + void takeAllFrom(AttributePool &pool) { + if (pool.Head) { + takePool(pool.Head); + pool.Head = nullptr; + } + } + + ~AttributePool() { + if (Head) Factory.reclaimPool(Head); + } + + AttributeList *create(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + ArgsUnion *args, unsigned numArgs, + AttributeList::Syntax syntax, + SourceLocation ellipsisLoc = SourceLocation()) { + void *memory = allocate(sizeof(AttributeList) + + numArgs * sizeof(ArgsUnion)); + return add(new (memory) AttributeList(attrName, attrRange, + scopeName, scopeLoc, + args, numArgs, syntax, + ellipsisLoc)); + } + + AttributeList *create(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierLoc *Param, + const AvailabilityChange &introduced, + const AvailabilityChange &deprecated, + const AvailabilityChange &obsoleted, + SourceLocation unavailable, + const Expr *MessageExpr, + AttributeList::Syntax syntax) { + void *memory = allocate(AttributeFactory::AvailabilityAllocSize); + return add(new (memory) AttributeList(attrName, attrRange, + scopeName, scopeLoc, + Param, introduced, deprecated, + obsoleted, unavailable, MessageExpr, + syntax)); + } + + AttributeList *create(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierLoc *Param1, + IdentifierLoc *Param2, + IdentifierLoc *Param3, + AttributeList::Syntax syntax) { + size_t size = sizeof(AttributeList) + 3 * sizeof(ArgsUnion); + void *memory = allocate(size); + return add(new (memory) AttributeList(attrName, attrRange, + scopeName, scopeLoc, + Param1, Param2, Param3, + syntax)); + } + + AttributeList *createTypeTagForDatatype( + IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierLoc *argumentKind, ParsedType matchingCType, + bool layoutCompatible, bool mustBeNull, + AttributeList::Syntax syntax) { + void *memory = allocate(AttributeFactory::TypeTagForDatatypeAllocSize); + return add(new (memory) AttributeList(attrName, attrRange, + scopeName, scopeLoc, + argumentKind, matchingCType, + layoutCompatible, mustBeNull, + syntax)); + } + + AttributeList *createTypeAttribute( + IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + ParsedType typeArg, AttributeList::Syntax syntaxUsed) { + void *memory = allocate(sizeof(AttributeList) + sizeof(void *)); + return add(new (memory) AttributeList(attrName, attrRange, + scopeName, scopeLoc, + typeArg, syntaxUsed)); + } + + AttributeList *createPropertyAttribute( + IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierInfo *getterId, IdentifierInfo *setterId, + AttributeList::Syntax syntaxUsed) { + void *memory = allocate(AttributeFactory::PropertyAllocSize); + return add(new (memory) AttributeList(attrName, attrRange, + scopeName, scopeLoc, + getterId, setterId, + syntaxUsed)); + } +}; + +/// ParsedAttributes - A collection of parsed attributes. Currently +/// we don't differentiate between the various attribute syntaxes, +/// which is basically silly. +/// +/// Right now this is a very lightweight container, but the expectation +/// is that this will become significantly more serious. +class ParsedAttributes { +public: + ParsedAttributes(AttributeFactory &factory) + : pool(factory), list(nullptr) { + } + + ParsedAttributes(const ParsedAttributes &) = delete; + + AttributePool &getPool() const { return pool; } + + bool empty() const { return list == nullptr; } + + void add(AttributeList *newAttr) { + assert(newAttr); + assert(newAttr->getNext() == nullptr); + newAttr->setNext(list); + list = newAttr; + } + + void addAll(AttributeList *newList) { + if (!newList) return; + + AttributeList *lastInNewList = newList; + while (AttributeList *next = lastInNewList->getNext()) + lastInNewList = next; + + lastInNewList->setNext(list); + list = newList; + } + + void set(AttributeList *newList) { + list = newList; + } + + void takeAllFrom(ParsedAttributes &attrs) { + addAll(attrs.list); + attrs.list = nullptr; + pool.takeAllFrom(attrs.pool); + } + + void clear() { list = nullptr; pool.clear(); } + AttributeList *getList() const { return list; } + + /// Returns a reference to the attribute list. Try not to introduce + /// dependencies on this method, it may not be long-lived. + AttributeList *&getListRef() { return list; } + + /// Add attribute with expression arguments. + AttributeList *addNew(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + ArgsUnion *args, unsigned numArgs, + AttributeList::Syntax syntax, + SourceLocation ellipsisLoc = SourceLocation()) { + AttributeList *attr = + pool.create(attrName, attrRange, scopeName, scopeLoc, args, numArgs, + syntax, ellipsisLoc); + add(attr); + return attr; + } + + /// Add availability attribute. + AttributeList *addNew(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierLoc *Param, + const AvailabilityChange &introduced, + const AvailabilityChange &deprecated, + const AvailabilityChange &obsoleted, + SourceLocation unavailable, + const Expr *MessageExpr, + AttributeList::Syntax syntax) { + AttributeList *attr = + pool.create(attrName, attrRange, scopeName, scopeLoc, Param, introduced, + deprecated, obsoleted, unavailable, MessageExpr, syntax); + add(attr); + return attr; + } + + /// Add objc_bridge_related attribute. + AttributeList *addNew(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierLoc *Param1, + IdentifierLoc *Param2, + IdentifierLoc *Param3, + AttributeList::Syntax syntax) { + AttributeList *attr = + pool.create(attrName, attrRange, scopeName, scopeLoc, + Param1, Param2, Param3, syntax); + add(attr); + return attr; + } + + /// Add type_tag_for_datatype attribute. + AttributeList *addNewTypeTagForDatatype( + IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierLoc *argumentKind, ParsedType matchingCType, + bool layoutCompatible, bool mustBeNull, + AttributeList::Syntax syntax) { + AttributeList *attr = + pool.createTypeTagForDatatype(attrName, attrRange, + scopeName, scopeLoc, + argumentKind, matchingCType, + layoutCompatible, mustBeNull, syntax); + add(attr); + return attr; + } + + /// Add an attribute with a single type argument. + AttributeList * + addNewTypeAttr(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + ParsedType typeArg, AttributeList::Syntax syntaxUsed) { + AttributeList *attr = + pool.createTypeAttribute(attrName, attrRange, scopeName, scopeLoc, + typeArg, syntaxUsed); + add(attr); + return attr; + } + + /// Add microsoft __delspec(property) attribute. + AttributeList * + addNewPropertyAttr(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierInfo *getterId, IdentifierInfo *setterId, + AttributeList::Syntax syntaxUsed) { + AttributeList *attr = + pool.createPropertyAttribute(attrName, attrRange, scopeName, scopeLoc, + getterId, setterId, syntaxUsed); + add(attr); + return attr; + } + +private: + mutable AttributePool pool; + AttributeList *list; +}; + +/// These constants match the enumerated choices of +/// err_attribute_argument_n_type and err_attribute_argument_type. +enum AttributeArgumentNType { + AANT_ArgumentIntOrBool, + AANT_ArgumentIntegerConstant, + AANT_ArgumentString, + AANT_ArgumentIdentifier +}; + +/// These constants match the enumerated choices of +/// warn_attribute_wrong_decl_type and err_attribute_wrong_decl_type. +enum AttributeDeclKind { + ExpectedFunction, + ExpectedUnion, + ExpectedVariableOrFunction, + ExpectedFunctionOrMethod, + ExpectedParameter, + ExpectedFunctionMethodOrBlock, + ExpectedFunctionMethodOrClass, + ExpectedFunctionMethodOrParameter, + ExpectedClass, + ExpectedEnum, + ExpectedVariable, + ExpectedMethod, + ExpectedVariableFunctionOrLabel, + ExpectedFieldOrGlobalVar, + ExpectedStruct, + ExpectedVariableOrTypedef, + ExpectedTLSVar, + ExpectedVariableOrField, + ExpectedVariableFieldOrTag, + ExpectedTypeOrNamespace, + ExpectedObjectiveCInterface, + ExpectedMethodOrProperty, + ExpectedStructOrUnion, + ExpectedStructOrUnionOrClass, + ExpectedType, + ExpectedObjCInstanceMethod, + ExpectedObjCInterfaceDeclInitMethod, + ExpectedFunctionVariableOrClass, + ExpectedObjectiveCProtocol, + ExpectedFunctionGlobalVarMethodOrProperty, + ExpectedStructOrUnionOrTypedef, + ExpectedStructOrTypedef, + ExpectedObjectiveCInterfaceOrProtocol, + ExpectedKernelFunction, + ExpectedFunctionWithProtoType +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Sema/CXXFieldCollector.h b/contrib/llvm/tools/clang/include/clang/Sema/CXXFieldCollector.h new file mode 100644 index 0000000..6685751 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Sema/CXXFieldCollector.h @@ -0,0 +1,80 @@ +//===- CXXFieldCollector.h - Utility class for C++ class semantic analysis ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides CXXFieldCollector that is used during parsing & semantic +// analysis of C++ classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_CXXFIELDCOLLECTOR_H +#define LLVM_CLANG_SEMA_CXXFIELDCOLLECTOR_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { + class FieldDecl; + +/// CXXFieldCollector - Used to keep track of CXXFieldDecls during parsing of +/// C++ classes. +class CXXFieldCollector { + /// Fields - Contains all FieldDecls collected during parsing of a C++ + /// class. When a nested class is entered, its fields are appended to the + /// fields of its parent class, when it is exited its fields are removed. + SmallVector<FieldDecl*, 32> Fields; + + /// FieldCount - Each entry represents the number of fields collected during + /// the parsing of a C++ class. When a nested class is entered, a new field + /// count is pushed, when it is exited, the field count is popped. + SmallVector<size_t, 4> FieldCount; + + // Example: + // + // class C { + // int x,y; + // class NC { + // int q; + // // At this point, Fields contains [x,y,q] decls and FieldCount contains + // // [2,1]. + // }; + // int z; + // // At this point, Fields contains [x,y,z] decls and FieldCount contains + // // [3]. + // }; + +public: + /// StartClass - Called by Sema::ActOnStartCXXClassDef. + void StartClass() { FieldCount.push_back(0); } + + /// Add - Called by Sema::ActOnCXXMemberDeclarator. + void Add(FieldDecl *D) { + Fields.push_back(D); + ++FieldCount.back(); + } + + /// getCurNumField - The number of fields added to the currently parsed class. + size_t getCurNumFields() const { + assert(!FieldCount.empty() && "no currently-parsed class"); + return FieldCount.back(); + } + + /// getCurFields - Pointer to array of fields added to the currently parsed + /// class. + FieldDecl **getCurFields() { return &*(Fields.end() - getCurNumFields()); } + + /// FinishClass - Called by Sema::ActOnFinishCXXClassDef. + void FinishClass() { + Fields.resize(Fields.size() - getCurNumFields()); + FieldCount.pop_back(); + } +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Sema/CodeCompleteConsumer.h b/contrib/llvm/tools/clang/include/clang/Sema/CodeCompleteConsumer.h new file mode 100644 index 0000000..9702273 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Sema/CodeCompleteConsumer.h @@ -0,0 +1,976 @@ +//===---- CodeCompleteConsumer.h - Code Completion Interface ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the CodeCompleteConsumer class. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_SEMA_CODECOMPLETECONSUMER_H +#define LLVM_CLANG_SEMA_CODECOMPLETECONSUMER_H + +#include "clang-c/Index.h" +#include "clang/AST/CanonicalType.h" +#include "clang/AST/Type.h" +#include "clang/Sema/CodeCompleteOptions.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Allocator.h" +#include <string> + +namespace clang { + +class Decl; + +/// \brief Default priority values for code-completion results based +/// on their kind. +enum { + /// \brief Priority for the next initialization in a constructor initializer + /// list. + CCP_NextInitializer = 7, + /// \brief Priority for an enumeration constant inside a switch whose + /// condition is of the enumeration type. + CCP_EnumInCase = 7, + /// \brief Priority for a send-to-super completion. + CCP_SuperCompletion = 20, + /// \brief Priority for a declaration that is in the local scope. + CCP_LocalDeclaration = 34, + /// \brief Priority for a member declaration found from the current + /// method or member function. + CCP_MemberDeclaration = 35, + /// \brief Priority for a language keyword (that isn't any of the other + /// categories). + CCP_Keyword = 40, + /// \brief Priority for a code pattern. + CCP_CodePattern = 40, + /// \brief Priority for a non-type declaration. + CCP_Declaration = 50, + /// \brief Priority for a type. + CCP_Type = CCP_Declaration, + /// \brief Priority for a constant value (e.g., enumerator). + CCP_Constant = 65, + /// \brief Priority for a preprocessor macro. + CCP_Macro = 70, + /// \brief Priority for a nested-name-specifier. + CCP_NestedNameSpecifier = 75, + /// \brief Priority for a result that isn't likely to be what the user wants, + /// but is included for completeness. + CCP_Unlikely = 80, + + /// \brief Priority for the Objective-C "_cmd" implicit parameter. + CCP_ObjC_cmd = CCP_Unlikely +}; + +/// \brief Priority value deltas that are added to code-completion results +/// based on the context of the result. +enum { + /// \brief The result is in a base class. + CCD_InBaseClass = 2, + /// \brief The result is a C++ non-static member function whose qualifiers + /// exactly match the object type on which the member function can be called. + CCD_ObjectQualifierMatch = -1, + /// \brief The selector of the given message exactly matches the selector + /// of the current method, which might imply that some kind of delegation + /// is occurring. + CCD_SelectorMatch = -3, + + /// \brief Adjustment to the "bool" type in Objective-C, where the typedef + /// "BOOL" is preferred. + CCD_bool_in_ObjC = 1, + + /// \brief Adjustment for KVC code pattern priorities when it doesn't look + /// like the + CCD_ProbablyNotObjCCollection = 15, + + /// \brief An Objective-C method being used as a property. + CCD_MethodAsProperty = 2 +}; + +/// \brief Priority value factors by which we will divide or multiply the +/// priority of a code-completion result. +enum { + /// \brief Divide by this factor when a code-completion result's type exactly + /// matches the type we expect. + CCF_ExactTypeMatch = 4, + /// \brief Divide by this factor when a code-completion result's type is + /// similar to the type we expect (e.g., both arithmetic types, both + /// Objective-C object pointer types). + CCF_SimilarTypeMatch = 2 +}; + +/// \brief A simplified classification of types used when determining +/// "similar" types for code completion. +enum SimplifiedTypeClass { + STC_Arithmetic, + STC_Array, + STC_Block, + STC_Function, + STC_ObjectiveC, + STC_Other, + STC_Pointer, + STC_Record, + STC_Void +}; + +/// \brief Determine the simplified type class of the given canonical type. +SimplifiedTypeClass getSimplifiedTypeClass(CanQualType T); + +/// \brief Determine the type that this declaration will have if it is used +/// as a type or in an expression. +QualType getDeclUsageType(ASTContext &C, const NamedDecl *ND); + +/// \brief Determine the priority to be given to a macro code completion result +/// with the given name. +/// +/// \param MacroName The name of the macro. +/// +/// \param LangOpts Options describing the current language dialect. +/// +/// \param PreferredTypeIsPointer Whether the preferred type for the context +/// of this macro is a pointer type. +unsigned getMacroUsagePriority(StringRef MacroName, + const LangOptions &LangOpts, + bool PreferredTypeIsPointer = false); + +/// \brief Determine the libclang cursor kind associated with the given +/// declaration. +CXCursorKind getCursorKindForDecl(const Decl *D); + +class FunctionDecl; +class FunctionType; +class FunctionTemplateDecl; +class IdentifierInfo; +class NamedDecl; +class NestedNameSpecifier; +class Sema; + +/// \brief The context in which code completion occurred, so that the +/// code-completion consumer can process the results accordingly. +class CodeCompletionContext { +public: + enum Kind { + /// \brief An unspecified code-completion context. + CCC_Other, + /// \brief An unspecified code-completion context where we should also add + /// macro completions. + CCC_OtherWithMacros, + /// \brief Code completion occurred within a "top-level" completion context, + /// e.g., at namespace or global scope. + CCC_TopLevel, + /// \brief Code completion occurred within an Objective-C interface, + /// protocol, or category interface. + CCC_ObjCInterface, + /// \brief Code completion occurred within an Objective-C implementation + /// or category implementation. + CCC_ObjCImplementation, + /// \brief Code completion occurred within the instance variable list of + /// an Objective-C interface, implementation, or category implementation. + CCC_ObjCIvarList, + /// \brief Code completion occurred within a class, struct, or union. + CCC_ClassStructUnion, + /// \brief Code completion occurred where a statement (or declaration) is + /// expected in a function, method, or block. + CCC_Statement, + /// \brief Code completion occurred where an expression is expected. + CCC_Expression, + /// \brief Code completion occurred where an Objective-C message receiver + /// is expected. + CCC_ObjCMessageReceiver, + /// \brief Code completion occurred on the right-hand side of a member + /// access expression using the dot operator. + /// + /// The results of this completion are the members of the type being + /// accessed. The type itself is available via + /// \c CodeCompletionContext::getType(). + CCC_DotMemberAccess, + /// \brief Code completion occurred on the right-hand side of a member + /// access expression using the arrow operator. + /// + /// The results of this completion are the members of the type being + /// accessed. The type itself is available via + /// \c CodeCompletionContext::getType(). + CCC_ArrowMemberAccess, + /// \brief Code completion occurred on the right-hand side of an Objective-C + /// property access expression. + /// + /// The results of this completion are the members of the type being + /// accessed. The type itself is available via + /// \c CodeCompletionContext::getType(). + CCC_ObjCPropertyAccess, + /// \brief Code completion occurred after the "enum" keyword, to indicate + /// an enumeration name. + CCC_EnumTag, + /// \brief Code completion occurred after the "union" keyword, to indicate + /// a union name. + CCC_UnionTag, + /// \brief Code completion occurred after the "struct" or "class" keyword, + /// to indicate a struct or class name. + CCC_ClassOrStructTag, + /// \brief Code completion occurred where a protocol name is expected. + CCC_ObjCProtocolName, + /// \brief Code completion occurred where a namespace or namespace alias + /// is expected. + CCC_Namespace, + /// \brief Code completion occurred where a type name is expected. + CCC_Type, + /// \brief Code completion occurred where a new name is expected. + CCC_Name, + /// \brief Code completion occurred where a new name is expected and a + /// qualified name is permissible. + CCC_PotentiallyQualifiedName, + /// \brief Code completion occurred where an macro is being defined. + CCC_MacroName, + /// \brief Code completion occurred where a macro name is expected + /// (without any arguments, in the case of a function-like macro). + CCC_MacroNameUse, + /// \brief Code completion occurred within a preprocessor expression. + CCC_PreprocessorExpression, + /// \brief Code completion occurred where a preprocessor directive is + /// expected. + CCC_PreprocessorDirective, + /// \brief Code completion occurred in a context where natural language is + /// expected, e.g., a comment or string literal. + /// + /// This context usually implies that no completions should be added, + /// unless they come from an appropriate natural-language dictionary. + CCC_NaturalLanguage, + /// \brief Code completion for a selector, as in an \@selector expression. + CCC_SelectorName, + /// \brief Code completion within a type-qualifier list. + CCC_TypeQualifiers, + /// \brief Code completion in a parenthesized expression, which means that + /// we may also have types here in C and Objective-C (as well as in C++). + CCC_ParenthesizedExpression, + /// \brief Code completion where an Objective-C instance message is + /// expected. + CCC_ObjCInstanceMessage, + /// \brief Code completion where an Objective-C class message is expected. + CCC_ObjCClassMessage, + /// \brief Code completion where the name of an Objective-C class is + /// expected. + CCC_ObjCInterfaceName, + /// \brief Code completion where an Objective-C category name is expected. + CCC_ObjCCategoryName, + /// \brief An unknown context, in which we are recovering from a parsing + /// error and don't know which completions we should give. + CCC_Recovery + }; + +private: + enum Kind Kind; + + /// \brief The type that would prefer to see at this point (e.g., the type + /// of an initializer or function parameter). + QualType PreferredType; + + /// \brief The type of the base object in a member access expression. + QualType BaseType; + + /// \brief The identifiers for Objective-C selector parts. + ArrayRef<IdentifierInfo *> SelIdents; + +public: + /// \brief Construct a new code-completion context of the given kind. + CodeCompletionContext(enum Kind Kind) : Kind(Kind), SelIdents(None) { } + + /// \brief Construct a new code-completion context of the given kind. + CodeCompletionContext(enum Kind Kind, QualType T, + ArrayRef<IdentifierInfo *> SelIdents = None) + : Kind(Kind), + SelIdents(SelIdents) { + if (Kind == CCC_DotMemberAccess || Kind == CCC_ArrowMemberAccess || + Kind == CCC_ObjCPropertyAccess || Kind == CCC_ObjCClassMessage || + Kind == CCC_ObjCInstanceMessage) + BaseType = T; + else + PreferredType = T; + } + + /// \brief Retrieve the kind of code-completion context. + enum Kind getKind() const { return Kind; } + + /// \brief Retrieve the type that this expression would prefer to have, e.g., + /// if the expression is a variable initializer or a function argument, the + /// type of the corresponding variable or function parameter. + QualType getPreferredType() const { return PreferredType; } + + /// \brief Retrieve the type of the base object in a member-access + /// expression. + QualType getBaseType() const { return BaseType; } + + /// \brief Retrieve the Objective-C selector identifiers. + ArrayRef<IdentifierInfo *> getSelIdents() const { return SelIdents; } + + /// \brief Determines whether we want C++ constructors as results within this + /// context. + bool wantConstructorResults() const; +}; + + +/// \brief A "string" used to describe how code completion can +/// be performed for an entity. +/// +/// A code completion string typically shows how a particular entity can be +/// used. For example, the code completion string for a function would show +/// the syntax to call it, including the parentheses, placeholders for the +/// arguments, etc. +class CodeCompletionString { +public: + /// \brief The different kinds of "chunks" that can occur within a code + /// completion string. + enum ChunkKind { + /// \brief The piece of text that the user is expected to type to + /// match the code-completion string, typically a keyword or the name of a + /// declarator or macro. + CK_TypedText, + /// \brief A piece of text that should be placed in the buffer, e.g., + /// parentheses or a comma in a function call. + CK_Text, + /// \brief A code completion string that is entirely optional. For example, + /// an optional code completion string that describes the default arguments + /// in a function call. + CK_Optional, + /// \brief A string that acts as a placeholder for, e.g., a function + /// call argument. + CK_Placeholder, + /// \brief A piece of text that describes something about the result but + /// should not be inserted into the buffer. + CK_Informative, + /// \brief A piece of text that describes the type of an entity or, for + /// functions and methods, the return type. + CK_ResultType, + /// \brief A piece of text that describes the parameter that corresponds + /// to the code-completion location within a function call, message send, + /// macro invocation, etc. + CK_CurrentParameter, + /// \brief A left parenthesis ('('). + CK_LeftParen, + /// \brief A right parenthesis (')'). + CK_RightParen, + /// \brief A left bracket ('['). + CK_LeftBracket, + /// \brief A right bracket (']'). + CK_RightBracket, + /// \brief A left brace ('{'). + CK_LeftBrace, + /// \brief A right brace ('}'). + CK_RightBrace, + /// \brief A left angle bracket ('<'). + CK_LeftAngle, + /// \brief A right angle bracket ('>'). + CK_RightAngle, + /// \brief A comma separator (','). + CK_Comma, + /// \brief A colon (':'). + CK_Colon, + /// \brief A semicolon (';'). + CK_SemiColon, + /// \brief An '=' sign. + CK_Equal, + /// \brief Horizontal whitespace (' '). + CK_HorizontalSpace, + /// \brief Vertical whitespace ('\\n' or '\\r\\n', depending on the + /// platform). + CK_VerticalSpace + }; + + /// \brief One piece of the code completion string. + struct Chunk { + /// \brief The kind of data stored in this piece of the code completion + /// string. + ChunkKind Kind; + + union { + /// \brief The text string associated with a CK_Text, CK_Placeholder, + /// CK_Informative, or CK_Comma chunk. + /// The string is owned by the chunk and will be deallocated + /// (with delete[]) when the chunk is destroyed. + const char *Text; + + /// \brief The code completion string associated with a CK_Optional chunk. + /// The optional code completion string is owned by the chunk, and will + /// be deallocated (with delete) when the chunk is destroyed. + CodeCompletionString *Optional; + }; + + Chunk() : Kind(CK_Text), Text(nullptr) { } + + explicit Chunk(ChunkKind Kind, const char *Text = ""); + + /// \brief Create a new text chunk. + static Chunk CreateText(const char *Text); + + /// \brief Create a new optional chunk. + static Chunk CreateOptional(CodeCompletionString *Optional); + + /// \brief Create a new placeholder chunk. + static Chunk CreatePlaceholder(const char *Placeholder); + + /// \brief Create a new informative chunk. + static Chunk CreateInformative(const char *Informative); + + /// \brief Create a new result type chunk. + static Chunk CreateResultType(const char *ResultType); + + /// \brief Create a new current-parameter chunk. + static Chunk CreateCurrentParameter(const char *CurrentParameter); + }; + +private: + /// \brief The number of chunks stored in this string. + unsigned NumChunks : 16; + + /// \brief The number of annotations for this code-completion result. + unsigned NumAnnotations : 16; + + /// \brief The priority of this code-completion string. + unsigned Priority : 16; + + /// \brief The availability of this code-completion result. + unsigned Availability : 2; + + /// \brief The name of the parent context. + StringRef ParentName; + + /// \brief A brief documentation comment attached to the declaration of + /// entity being completed by this result. + const char *BriefComment; + + CodeCompletionString(const CodeCompletionString &) = delete; + void operator=(const CodeCompletionString &) = delete; + + CodeCompletionString(const Chunk *Chunks, unsigned NumChunks, + unsigned Priority, CXAvailabilityKind Availability, + const char **Annotations, unsigned NumAnnotations, + StringRef ParentName, + const char *BriefComment); + ~CodeCompletionString() = default; + + friend class CodeCompletionBuilder; + friend class CodeCompletionResult; + +public: + typedef const Chunk *iterator; + iterator begin() const { return reinterpret_cast<const Chunk *>(this + 1); } + iterator end() const { return begin() + NumChunks; } + bool empty() const { return NumChunks == 0; } + unsigned size() const { return NumChunks; } + + const Chunk &operator[](unsigned I) const { + assert(I < size() && "Chunk index out-of-range"); + return begin()[I]; + } + + /// \brief Returns the text in the TypedText chunk. + const char *getTypedText() const; + + /// \brief Retrieve the priority of this code completion result. + unsigned getPriority() const { return Priority; } + + /// \brief Retrieve the availability of this code completion result. + unsigned getAvailability() const { return Availability; } + + /// \brief Retrieve the number of annotations for this code completion result. + unsigned getAnnotationCount() const; + + /// \brief Retrieve the annotation string specified by \c AnnotationNr. + const char *getAnnotation(unsigned AnnotationNr) const; + + /// \brief Retrieve the name of the parent context. + StringRef getParentContextName() const { + return ParentName; + } + + const char *getBriefComment() const { + return BriefComment; + } + + /// \brief Retrieve a string representation of the code completion string, + /// which is mainly useful for debugging. + std::string getAsString() const; +}; + +/// \brief An allocator used specifically for the purpose of code completion. +class CodeCompletionAllocator : public llvm::BumpPtrAllocator { +public: + /// \brief Copy the given string into this allocator. + const char *CopyString(const Twine &String); +}; + +/// \brief Allocator for a cached set of global code completions. +class GlobalCodeCompletionAllocator + : public CodeCompletionAllocator, + public RefCountedBase<GlobalCodeCompletionAllocator> +{ + +}; + +class CodeCompletionTUInfo { + llvm::DenseMap<const DeclContext *, StringRef> ParentNames; + IntrusiveRefCntPtr<GlobalCodeCompletionAllocator> AllocatorRef; + +public: + explicit CodeCompletionTUInfo( + IntrusiveRefCntPtr<GlobalCodeCompletionAllocator> Allocator) + : AllocatorRef(Allocator) { } + + IntrusiveRefCntPtr<GlobalCodeCompletionAllocator> getAllocatorRef() const { + return AllocatorRef; + } + CodeCompletionAllocator &getAllocator() const { + assert(AllocatorRef); + return *AllocatorRef; + } + + StringRef getParentName(const DeclContext *DC); +}; + +} // end namespace clang + +namespace llvm { + template <> struct isPodLike<clang::CodeCompletionString::Chunk> { + static const bool value = true; + }; +} + +namespace clang { + +/// \brief A builder class used to construct new code-completion strings. +class CodeCompletionBuilder { +public: + typedef CodeCompletionString::Chunk Chunk; + +private: + CodeCompletionAllocator &Allocator; + CodeCompletionTUInfo &CCTUInfo; + unsigned Priority; + CXAvailabilityKind Availability; + StringRef ParentName; + const char *BriefComment; + + /// \brief The chunks stored in this string. + SmallVector<Chunk, 4> Chunks; + + SmallVector<const char *, 2> Annotations; + +public: + CodeCompletionBuilder(CodeCompletionAllocator &Allocator, + CodeCompletionTUInfo &CCTUInfo) + : Allocator(Allocator), CCTUInfo(CCTUInfo), + Priority(0), Availability(CXAvailability_Available), + BriefComment(nullptr) { } + + CodeCompletionBuilder(CodeCompletionAllocator &Allocator, + CodeCompletionTUInfo &CCTUInfo, + unsigned Priority, CXAvailabilityKind Availability) + : Allocator(Allocator), CCTUInfo(CCTUInfo), + Priority(Priority), Availability(Availability), + BriefComment(nullptr) { } + + /// \brief Retrieve the allocator into which the code completion + /// strings should be allocated. + CodeCompletionAllocator &getAllocator() const { return Allocator; } + + CodeCompletionTUInfo &getCodeCompletionTUInfo() const { return CCTUInfo; } + + /// \brief Take the resulting completion string. + /// + /// This operation can only be performed once. + CodeCompletionString *TakeString(); + + /// \brief Add a new typed-text chunk. + void AddTypedTextChunk(const char *Text); + + /// \brief Add a new text chunk. + void AddTextChunk(const char *Text); + + /// \brief Add a new optional chunk. + void AddOptionalChunk(CodeCompletionString *Optional); + + /// \brief Add a new placeholder chunk. + void AddPlaceholderChunk(const char *Placeholder); + + /// \brief Add a new informative chunk. + void AddInformativeChunk(const char *Text); + + /// \brief Add a new result-type chunk. + void AddResultTypeChunk(const char *ResultType); + + /// \brief Add a new current-parameter chunk. + void AddCurrentParameterChunk(const char *CurrentParameter); + + /// \brief Add a new chunk. + void AddChunk(CodeCompletionString::ChunkKind CK, const char *Text = ""); + + void AddAnnotation(const char *A) { Annotations.push_back(A); } + + /// \brief Add the parent context information to this code completion. + void addParentContext(const DeclContext *DC); + + const char *getBriefComment() const { return BriefComment; } + void addBriefComment(StringRef Comment); + + StringRef getParentName() const { return ParentName; } +}; + +/// \brief Captures a result of code completion. +class CodeCompletionResult { +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_Macro, ///< Refers to a macro + RK_Pattern ///< Refers to a precomputed pattern. + }; + + /// \brief When Kind == RK_Declaration or RK_Pattern, the declaration we are + /// referring to. In the latter case, the declaration might be NULL. + const NamedDecl *Declaration; + + union { + /// \brief When Kind == RK_Keyword, the string representing the keyword + /// or symbol's spelling. + const char *Keyword; + + /// \brief When Kind == RK_Pattern, the code-completion string that + /// describes the completion text to insert. + CodeCompletionString *Pattern; + + /// \brief When Kind == RK_Macro, the identifier that refers to a macro. + const IdentifierInfo *Macro; + }; + + /// \brief The priority of this particular code-completion result. + unsigned Priority; + + /// \brief Specifies which parameter (of a function, Objective-C method, + /// macro, etc.) we should start with when formatting the result. + unsigned StartParameter; + + /// \brief The kind of result stored here. + ResultKind Kind; + + /// \brief The cursor kind that describes this result. + CXCursorKind CursorKind; + + /// \brief The availability of this result. + CXAvailabilityKind Availability; + + /// \brief Whether this result is hidden by another name. + bool Hidden : 1; + + /// \brief Whether this result was found via lookup into a base class. + bool QualifierIsInformative : 1; + + /// \brief Whether this declaration is the beginning of a + /// nested-name-specifier and, therefore, should be followed by '::'. + bool StartsNestedNameSpecifier : 1; + + /// \brief Whether all parameters (of a function, Objective-C + /// method, etc.) should be considered "informative". + bool AllParametersAreInformative : 1; + + /// \brief Whether we're completing a declaration of the given entity, + /// rather than a use of that entity. + bool DeclaringEntity : 1; + + /// \brief If the result should have a nested-name-specifier, this is it. + /// When \c QualifierIsInformative, the nested-name-specifier is + /// informative rather than required. + NestedNameSpecifier *Qualifier; + + /// \brief Build a result that refers to a declaration. + CodeCompletionResult(const NamedDecl *Declaration, + unsigned Priority, + NestedNameSpecifier *Qualifier = nullptr, + bool QualifierIsInformative = false, + bool Accessible = true) + : Declaration(Declaration), Priority(Priority), + StartParameter(0), Kind(RK_Declaration), + Availability(CXAvailability_Available), Hidden(false), + QualifierIsInformative(QualifierIsInformative), + StartsNestedNameSpecifier(false), AllParametersAreInformative(false), + DeclaringEntity(false), Qualifier(Qualifier) { + computeCursorKindAndAvailability(Accessible); + } + + /// \brief Build a result that refers to a keyword or symbol. + CodeCompletionResult(const char *Keyword, unsigned Priority = CCP_Keyword) + : Declaration(nullptr), Keyword(Keyword), Priority(Priority), + StartParameter(0), Kind(RK_Keyword), CursorKind(CXCursor_NotImplemented), + Availability(CXAvailability_Available), Hidden(false), + QualifierIsInformative(0), StartsNestedNameSpecifier(false), + AllParametersAreInformative(false), DeclaringEntity(false), + Qualifier(nullptr) {} + + /// \brief Build a result that refers to a macro. + CodeCompletionResult(const IdentifierInfo *Macro, + unsigned Priority = CCP_Macro) + : Declaration(nullptr), Macro(Macro), Priority(Priority), StartParameter(0), + Kind(RK_Macro), CursorKind(CXCursor_MacroDefinition), + Availability(CXAvailability_Available), Hidden(false), + QualifierIsInformative(0), StartsNestedNameSpecifier(false), + AllParametersAreInformative(false), DeclaringEntity(false), + Qualifier(nullptr) {} + + /// \brief Build a result that refers to a pattern. + CodeCompletionResult(CodeCompletionString *Pattern, + unsigned Priority = CCP_CodePattern, + CXCursorKind CursorKind = CXCursor_NotImplemented, + CXAvailabilityKind Availability = CXAvailability_Available, + const NamedDecl *D = nullptr) + : Declaration(D), Pattern(Pattern), Priority(Priority), StartParameter(0), + Kind(RK_Pattern), CursorKind(CursorKind), Availability(Availability), + Hidden(false), QualifierIsInformative(0), + StartsNestedNameSpecifier(false), AllParametersAreInformative(false), + DeclaringEntity(false), Qualifier(nullptr) + { + } + + /// \brief Build a result that refers to a pattern with an associated + /// declaration. + CodeCompletionResult(CodeCompletionString *Pattern, NamedDecl *D, + unsigned Priority) + : Declaration(D), Pattern(Pattern), Priority(Priority), StartParameter(0), + Kind(RK_Pattern), Availability(CXAvailability_Available), Hidden(false), + QualifierIsInformative(false), StartsNestedNameSpecifier(false), + AllParametersAreInformative(false), DeclaringEntity(false), + Qualifier(nullptr) { + computeCursorKindAndAvailability(); + } + + /// \brief Retrieve the declaration stored in this result. + const NamedDecl *getDeclaration() const { + assert(Kind == RK_Declaration && "Not a declaration result"); + return Declaration; + } + + /// \brief Retrieve the keyword stored in this result. + const char *getKeyword() const { + assert(Kind == RK_Keyword && "Not a keyword result"); + return Keyword; + } + + /// \brief Create a new code-completion string that describes how to insert + /// this result into a program. + /// + /// \param S The semantic analysis that created the result. + /// + /// \param Allocator The allocator that will be used to allocate the + /// string itself. + CodeCompletionString *CreateCodeCompletionString(Sema &S, + const CodeCompletionContext &CCContext, + CodeCompletionAllocator &Allocator, + CodeCompletionTUInfo &CCTUInfo, + bool IncludeBriefComments); + CodeCompletionString *CreateCodeCompletionString(ASTContext &Ctx, + Preprocessor &PP, + const CodeCompletionContext &CCContext, + CodeCompletionAllocator &Allocator, + CodeCompletionTUInfo &CCTUInfo, + bool IncludeBriefComments); + +private: + void computeCursorKindAndAvailability(bool Accessible = true); +}; + +bool operator<(const CodeCompletionResult &X, const CodeCompletionResult &Y); + +inline bool operator>(const CodeCompletionResult &X, + const CodeCompletionResult &Y) { + return Y < X; +} + +inline bool operator<=(const CodeCompletionResult &X, + const CodeCompletionResult &Y) { + return !(Y < X); +} + +inline bool operator>=(const CodeCompletionResult &X, + const CodeCompletionResult &Y) { + return !(X < Y); +} + + +raw_ostream &operator<<(raw_ostream &OS, + const CodeCompletionString &CCS); + +/// \brief Abstract interface for a consumer of code-completion +/// information. +class CodeCompleteConsumer { +protected: + const CodeCompleteOptions CodeCompleteOpts; + + /// \brief Whether the output format for the code-completion consumer is + /// binary. + bool OutputIsBinary; + +public: + class OverloadCandidate { + public: + /// \brief Describes the type of overload candidate. + enum CandidateKind { + /// \brief The candidate is a function declaration. + CK_Function, + /// \brief The candidate is a function template. + CK_FunctionTemplate, + /// \brief The "candidate" is actually a variable, expression, or block + /// for which we only have a function prototype. + CK_FunctionType + }; + + private: + /// \brief The kind of overload candidate. + CandidateKind Kind; + + union { + /// \brief The function overload candidate, available when + /// Kind == CK_Function. + FunctionDecl *Function; + + /// \brief The function template overload candidate, available when + /// Kind == CK_FunctionTemplate. + FunctionTemplateDecl *FunctionTemplate; + + /// \brief The function type that describes the entity being called, + /// when Kind == CK_FunctionType. + const FunctionType *Type; + }; + + public: + OverloadCandidate(FunctionDecl *Function) + : Kind(CK_Function), Function(Function) { } + + OverloadCandidate(FunctionTemplateDecl *FunctionTemplateDecl) + : Kind(CK_FunctionTemplate), FunctionTemplate(FunctionTemplateDecl) { } + + OverloadCandidate(const FunctionType *Type) + : Kind(CK_FunctionType), Type(Type) { } + + /// \brief Determine the kind of overload candidate. + CandidateKind getKind() const { return Kind; } + + /// \brief Retrieve the function overload candidate or the templated + /// function declaration for a function template. + FunctionDecl *getFunction() const; + + /// \brief Retrieve the function template overload candidate. + FunctionTemplateDecl *getFunctionTemplate() const { + assert(getKind() == CK_FunctionTemplate && "Not a function template"); + return FunctionTemplate; + } + + /// \brief Retrieve the function type of the entity, regardless of how the + /// function is stored. + const FunctionType *getFunctionType() const; + + /// \brief Create a new code-completion string that describes the function + /// signature of this overload candidate. + CodeCompletionString *CreateSignatureString(unsigned CurrentArg, + Sema &S, + CodeCompletionAllocator &Allocator, + CodeCompletionTUInfo &CCTUInfo, + bool IncludeBriefComments) const; + }; + + CodeCompleteConsumer(const CodeCompleteOptions &CodeCompleteOpts, + bool OutputIsBinary) + : CodeCompleteOpts(CodeCompleteOpts), OutputIsBinary(OutputIsBinary) + { } + + /// \brief Whether the code-completion consumer wants to see macros. + bool includeMacros() const { + return CodeCompleteOpts.IncludeMacros; + } + + /// \brief Whether the code-completion consumer wants to see code patterns. + bool includeCodePatterns() const { + return CodeCompleteOpts.IncludeCodePatterns; + } + + /// \brief Whether to include global (top-level) declaration results. + bool includeGlobals() const { + return CodeCompleteOpts.IncludeGlobals; + } + + /// \brief Whether to include brief documentation comments within the set of + /// code completions returned. + bool includeBriefComments() const { + return CodeCompleteOpts.IncludeBriefComments; + } + + /// \brief Determine whether the output of this consumer is binary. + bool isOutputBinary() const { return OutputIsBinary; } + + /// \brief Deregisters and destroys this code-completion consumer. + virtual ~CodeCompleteConsumer(); + + /// \name Code-completion callbacks + //@{ + /// \brief Process the finalized code-completion results. + virtual void ProcessCodeCompleteResults(Sema &S, + CodeCompletionContext Context, + CodeCompletionResult *Results, + unsigned NumResults) { } + + /// \param S the semantic-analyzer object for which code-completion is being + /// done. + /// + /// \param CurrentArg the index of the current argument. + /// + /// \param Candidates an array of overload candidates. + /// + /// \param NumCandidates the number of overload candidates + virtual void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, + OverloadCandidate *Candidates, + unsigned NumCandidates) { } + //@} + + /// \brief Retrieve the allocator that will be used to allocate + /// code completion strings. + virtual CodeCompletionAllocator &getAllocator() = 0; + + virtual CodeCompletionTUInfo &getCodeCompletionTUInfo() = 0; +}; + +/// \brief A simple code-completion consumer that prints the results it +/// receives in a simple format. +class PrintingCodeCompleteConsumer : public CodeCompleteConsumer { + /// \brief The raw output stream. + raw_ostream &OS; + + CodeCompletionTUInfo CCTUInfo; + +public: + /// \brief Create a new printing code-completion consumer that prints its + /// results to the given raw output stream. + PrintingCodeCompleteConsumer(const CodeCompleteOptions &CodeCompleteOpts, + raw_ostream &OS) + : CodeCompleteConsumer(CodeCompleteOpts, false), OS(OS), + CCTUInfo(new GlobalCodeCompletionAllocator) {} + + /// \brief Prints the finalized code-completion results. + void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context, + CodeCompletionResult *Results, + unsigned NumResults) override; + + void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, + OverloadCandidate *Candidates, + unsigned NumCandidates) override; + + CodeCompletionAllocator &getAllocator() override { + return CCTUInfo.getAllocator(); + } + + CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; } +}; + +} // end namespace clang + +#endif // LLVM_CLANG_SEMA_CODECOMPLETECONSUMER_H diff --git a/contrib/llvm/tools/clang/include/clang/Sema/CodeCompleteOptions.h b/contrib/llvm/tools/clang/include/clang/Sema/CodeCompleteOptions.h new file mode 100644 index 0000000..fc7713c --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Sema/CodeCompleteOptions.h @@ -0,0 +1,41 @@ +//===---- CodeCompleteOptions.h - Code Completion Options -------*- 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_SEMA_CODECOMPLETEOPTIONS_H +#define LLVM_CLANG_SEMA_CODECOMPLETEOPTIONS_H + +namespace clang { + +/// Options controlling the behavior of code completion. +class CodeCompleteOptions { +public: + /// Show macros in code completion results. + unsigned IncludeMacros : 1; + + /// Show code patterns in code completion results. + unsigned IncludeCodePatterns : 1; + + /// Show top-level decls in code completion results. + unsigned IncludeGlobals : 1; + + /// Show brief documentation comments in code completion results. + unsigned IncludeBriefComments : 1; + + CodeCompleteOptions() : + IncludeMacros(0), + IncludeCodePatterns(0), + IncludeGlobals(1), + IncludeBriefComments(0) + { } +}; + +} // namespace clang + +#endif + diff --git a/contrib/llvm/tools/clang/include/clang/Sema/DeclSpec.h b/contrib/llvm/tools/clang/include/clang/Sema/DeclSpec.h new file mode 100644 index 0000000..e9fdb70 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Sema/DeclSpec.h @@ -0,0 +1,2313 @@ +//===--- DeclSpec.h - Parsed declaration specifiers -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file defines the classes used to store parsed information about +/// declaration-specifiers and declarators. +/// +/// \verbatim +/// static const int volatile x, *y, *(*(*z)[10])(const void *x); +/// ------------------------- - -- --------------------------- +/// declaration-specifiers \ | / +/// declarators +/// \endverbatim +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_DECLSPEC_H +#define LLVM_CLANG_SEMA_DECLSPEC_H + +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/Basic/ExceptionSpecificationType.h" +#include "clang/Basic/Lambda.h" +#include "clang/Basic/OperatorKinds.h" +#include "clang/Basic/Specifiers.h" +#include "clang/Lex/Token.h" +#include "clang/Sema/AttributeList.h" +#include "clang/Sema/Ownership.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" + +namespace clang { + class ASTContext; + class CXXRecordDecl; + class TypeLoc; + class LangOptions; + class IdentifierInfo; + class NamespaceAliasDecl; + class NamespaceDecl; + class ObjCDeclSpec; + class Sema; + class Declarator; + struct TemplateIdAnnotation; + +/// \brief Represents a C++ nested-name-specifier or a global scope specifier. +/// +/// These can be in 3 states: +/// 1) Not present, identified by isEmpty() +/// 2) Present, identified by isNotEmpty() +/// 2.a) Valid, identified by isValid() +/// 2.b) Invalid, identified by isInvalid(). +/// +/// isSet() is deprecated because it mostly corresponded to "valid" but was +/// often used as if it meant "present". +/// +/// The actual scope is described by getScopeRep(). +class CXXScopeSpec { + SourceRange Range; + NestedNameSpecifierLocBuilder Builder; + +public: + SourceRange getRange() const { return Range; } + void setRange(SourceRange R) { Range = R; } + void setBeginLoc(SourceLocation Loc) { Range.setBegin(Loc); } + void setEndLoc(SourceLocation Loc) { Range.setEnd(Loc); } + SourceLocation getBeginLoc() const { return Range.getBegin(); } + SourceLocation getEndLoc() const { return Range.getEnd(); } + + /// \brief Retrieve the representation of the nested-name-specifier. + NestedNameSpecifier *getScopeRep() const { + return Builder.getRepresentation(); + } + + /// \brief Extend the current nested-name-specifier by another + /// nested-name-specifier component of the form 'type::'. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param TemplateKWLoc The location of the 'template' keyword, if present. + /// + /// \param TL The TypeLoc that describes the type preceding the '::'. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void Extend(ASTContext &Context, SourceLocation TemplateKWLoc, TypeLoc TL, + SourceLocation ColonColonLoc); + + /// \brief Extend the current nested-name-specifier by another + /// nested-name-specifier component of the form 'identifier::'. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param Identifier The identifier. + /// + /// \param IdentifierLoc The location of the identifier. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void Extend(ASTContext &Context, IdentifierInfo *Identifier, + SourceLocation IdentifierLoc, SourceLocation ColonColonLoc); + + /// \brief Extend the current nested-name-specifier by another + /// nested-name-specifier component of the form 'namespace::'. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param Namespace The namespace. + /// + /// \param NamespaceLoc The location of the namespace name. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void Extend(ASTContext &Context, NamespaceDecl *Namespace, + SourceLocation NamespaceLoc, SourceLocation ColonColonLoc); + + /// \brief Extend the current nested-name-specifier by another + /// nested-name-specifier component of the form 'namespace-alias::'. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param Alias The namespace alias. + /// + /// \param AliasLoc The location of the namespace alias + /// name. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void Extend(ASTContext &Context, NamespaceAliasDecl *Alias, + SourceLocation AliasLoc, SourceLocation ColonColonLoc); + + /// \brief Turn this (empty) nested-name-specifier into the global + /// nested-name-specifier '::'. + void MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc); + + /// \brief Turns this (empty) nested-name-specifier into '__super' + /// nested-name-specifier. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param RD The declaration of the class in which nested-name-specifier + /// appeared. + /// + /// \param SuperLoc The location of the '__super' keyword. + /// name. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void MakeSuper(ASTContext &Context, CXXRecordDecl *RD, + SourceLocation SuperLoc, SourceLocation ColonColonLoc); + + /// \brief Make a new nested-name-specifier from incomplete source-location + /// information. + /// + /// FIXME: This routine should be used very, very rarely, in cases where we + /// need to synthesize a nested-name-specifier. Most code should instead use + /// \c Adopt() with a proper \c NestedNameSpecifierLoc. + void MakeTrivial(ASTContext &Context, NestedNameSpecifier *Qualifier, + SourceRange R); + + /// \brief Adopt an existing nested-name-specifier (with source-range + /// information). + void Adopt(NestedNameSpecifierLoc Other); + + /// \brief Retrieve a nested-name-specifier with location information, copied + /// into the given AST context. + /// + /// \param Context The context into which this nested-name-specifier will be + /// copied. + NestedNameSpecifierLoc getWithLocInContext(ASTContext &Context) const; + + /// \brief Retrieve the location of the name in the last qualifier + /// in this nested name specifier. + /// + /// For example, the location of \c bar + /// in + /// \verbatim + /// \::foo::bar<0>:: + /// ^~~ + /// \endverbatim + SourceLocation getLastQualifierNameLoc() const; + + /// No scope specifier. + bool isEmpty() const { return !Range.isValid(); } + /// A scope specifier is present, but may be valid or invalid. + bool isNotEmpty() const { return !isEmpty(); } + + /// An error occurred during parsing of the scope specifier. + bool isInvalid() const { return isNotEmpty() && getScopeRep() == nullptr; } + /// A scope specifier is present, and it refers to a real scope. + bool isValid() const { return isNotEmpty() && getScopeRep() != nullptr; } + + /// \brief Indicate that this nested-name-specifier is invalid. + void SetInvalid(SourceRange R) { + assert(R.isValid() && "Must have a valid source range"); + if (Range.getBegin().isInvalid()) + Range.setBegin(R.getBegin()); + Range.setEnd(R.getEnd()); + Builder.Clear(); + } + + /// Deprecated. Some call sites intend isNotEmpty() while others intend + /// isValid(). + bool isSet() const { return getScopeRep() != nullptr; } + + void clear() { + Range = SourceRange(); + Builder.Clear(); + } + + /// \brief Retrieve the data associated with the source-location information. + char *location_data() const { return Builder.getBuffer().first; } + + /// \brief Retrieve the size of the data associated with source-location + /// information. + unsigned location_size() const { return Builder.getBuffer().second; } +}; + +/// \brief Captures information about "declaration specifiers". +/// +/// "Declaration specifiers" encompasses storage-class-specifiers, +/// type-specifiers, type-qualifiers, and function-specifiers. +class DeclSpec { +public: + /// \brief storage-class-specifier + /// \note The order of these enumerators is important for diagnostics. + enum SCS { + SCS_unspecified = 0, + SCS_typedef, + SCS_extern, + SCS_static, + SCS_auto, + SCS_register, + SCS_private_extern, + SCS_mutable + }; + + // Import thread storage class specifier enumeration and constants. + // These can be combined with SCS_extern and SCS_static. + typedef ThreadStorageClassSpecifier TSCS; + static const TSCS TSCS_unspecified = clang::TSCS_unspecified; + static const TSCS TSCS___thread = clang::TSCS___thread; + static const TSCS TSCS_thread_local = clang::TSCS_thread_local; + static const TSCS TSCS__Thread_local = clang::TSCS__Thread_local; + + // Import type specifier width enumeration and constants. + typedef TypeSpecifierWidth TSW; + static const TSW TSW_unspecified = clang::TSW_unspecified; + static const TSW TSW_short = clang::TSW_short; + static const TSW TSW_long = clang::TSW_long; + static const TSW TSW_longlong = clang::TSW_longlong; + + enum TSC { + TSC_unspecified, + TSC_imaginary, + TSC_complex + }; + + // Import type specifier sign enumeration and constants. + typedef TypeSpecifierSign TSS; + static const TSS TSS_unspecified = clang::TSS_unspecified; + static const TSS TSS_signed = clang::TSS_signed; + static const TSS TSS_unsigned = clang::TSS_unsigned; + + // Import type specifier type enumeration and constants. + typedef TypeSpecifierType TST; + static const TST TST_unspecified = clang::TST_unspecified; + static const TST TST_void = clang::TST_void; + static const TST TST_char = clang::TST_char; + static const TST TST_wchar = clang::TST_wchar; + static const TST TST_char16 = clang::TST_char16; + static const TST TST_char32 = clang::TST_char32; + static const TST TST_int = clang::TST_int; + static const TST TST_int128 = clang::TST_int128; + static const TST TST_half = clang::TST_half; + static const TST TST_float = clang::TST_float; + static const TST TST_double = clang::TST_double; + static const TST TST_bool = clang::TST_bool; + static const TST TST_decimal32 = clang::TST_decimal32; + static const TST TST_decimal64 = clang::TST_decimal64; + static const TST TST_decimal128 = clang::TST_decimal128; + static const TST TST_enum = clang::TST_enum; + static const TST TST_union = clang::TST_union; + static const TST TST_struct = clang::TST_struct; + static const TST TST_interface = clang::TST_interface; + static const TST TST_class = clang::TST_class; + static const TST TST_typename = clang::TST_typename; + static const TST TST_typeofType = clang::TST_typeofType; + static const TST TST_typeofExpr = clang::TST_typeofExpr; + static const TST TST_decltype = clang::TST_decltype; + static const TST TST_decltype_auto = clang::TST_decltype_auto; + static const TST TST_underlyingType = clang::TST_underlyingType; + static const TST TST_auto = clang::TST_auto; + static const TST TST_auto_type = clang::TST_auto_type; + static const TST TST_unknown_anytype = clang::TST_unknown_anytype; + static const TST TST_atomic = clang::TST_atomic; + static const TST TST_error = clang::TST_error; + + // type-qualifiers + enum TQ { // NOTE: These flags must be kept in sync with Qualifiers::TQ. + TQ_unspecified = 0, + TQ_const = 1, + TQ_restrict = 2, + TQ_volatile = 4, + // This has no corresponding Qualifiers::TQ value, because it's not treated + // as a qualifier in our type system. + TQ_atomic = 8 + }; + + /// ParsedSpecifiers - Flags to query which specifiers were applied. This is + /// returned by getParsedSpecifiers. + enum ParsedSpecifiers { + PQ_None = 0, + PQ_StorageClassSpecifier = 1, + PQ_TypeSpecifier = 2, + PQ_TypeQualifier = 4, + PQ_FunctionSpecifier = 8 + }; + +private: + // storage-class-specifier + /*SCS*/unsigned StorageClassSpec : 3; + /*TSCS*/unsigned ThreadStorageClassSpec : 2; + unsigned SCS_extern_in_linkage_spec : 1; + + // type-specifier + /*TSW*/unsigned TypeSpecWidth : 2; + /*TSC*/unsigned TypeSpecComplex : 2; + /*TSS*/unsigned TypeSpecSign : 2; + /*TST*/unsigned TypeSpecType : 6; + unsigned TypeAltiVecVector : 1; + unsigned TypeAltiVecPixel : 1; + unsigned TypeAltiVecBool : 1; + unsigned TypeSpecOwned : 1; + + // type-qualifiers + unsigned TypeQualifiers : 4; // Bitwise OR of TQ. + + // function-specifier + unsigned FS_inline_specified : 1; + unsigned FS_forceinline_specified: 1; + unsigned FS_virtual_specified : 1; + unsigned FS_explicit_specified : 1; + unsigned FS_noreturn_specified : 1; + + // friend-specifier + unsigned Friend_specified : 1; + + // constexpr-specifier + unsigned Constexpr_specified : 1; + + // concept-specifier + unsigned Concept_specified : 1; + + union { + UnionParsedType TypeRep; + Decl *DeclRep; + Expr *ExprRep; + }; + + // attributes. + ParsedAttributes Attrs; + + // Scope specifier for the type spec, if applicable. + CXXScopeSpec TypeScope; + + // SourceLocation info. These are null if the item wasn't specified or if + // the setting was synthesized. + SourceRange Range; + + SourceLocation StorageClassSpecLoc, ThreadStorageClassSpecLoc; + SourceLocation TSWLoc, TSCLoc, TSSLoc, TSTLoc, AltiVecLoc; + /// TSTNameLoc - If TypeSpecType is any of class, enum, struct, union, + /// typename, then this is the location of the named type (if present); + /// otherwise, it is the same as TSTLoc. Hence, the pair TSTLoc and + /// TSTNameLoc provides source range info for tag types. + SourceLocation TSTNameLoc; + SourceRange TypeofParensRange; + SourceLocation TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc, TQ_atomicLoc; + SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc, FS_noreturnLoc; + SourceLocation FS_forceinlineLoc; + SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc, ConceptLoc; + + WrittenBuiltinSpecs writtenBS; + void SaveWrittenBuiltinSpecs(); + + ObjCDeclSpec *ObjCQualifiers; + + static bool isTypeRep(TST T) { + return (T == TST_typename || T == TST_typeofType || + T == TST_underlyingType || T == TST_atomic); + } + static bool isExprRep(TST T) { + return (T == TST_typeofExpr || T == TST_decltype); + } + + DeclSpec(const DeclSpec &) = delete; + void operator=(const DeclSpec &) = delete; +public: + static bool isDeclRep(TST T) { + return (T == TST_enum || T == TST_struct || + T == TST_interface || T == TST_union || + T == TST_class); + } + + DeclSpec(AttributeFactory &attrFactory) + : StorageClassSpec(SCS_unspecified), + ThreadStorageClassSpec(TSCS_unspecified), + SCS_extern_in_linkage_spec(false), + TypeSpecWidth(TSW_unspecified), + TypeSpecComplex(TSC_unspecified), + TypeSpecSign(TSS_unspecified), + TypeSpecType(TST_unspecified), + TypeAltiVecVector(false), + TypeAltiVecPixel(false), + TypeAltiVecBool(false), + TypeSpecOwned(false), + TypeQualifiers(TQ_unspecified), + FS_inline_specified(false), + FS_forceinline_specified(false), + FS_virtual_specified(false), + FS_explicit_specified(false), + FS_noreturn_specified(false), + Friend_specified(false), + Constexpr_specified(false), + Concept_specified(false), + Attrs(attrFactory), + writtenBS(), + ObjCQualifiers(nullptr) { + } + + // storage-class-specifier + SCS getStorageClassSpec() const { return (SCS)StorageClassSpec; } + TSCS getThreadStorageClassSpec() const { + return (TSCS)ThreadStorageClassSpec; + } + bool isExternInLinkageSpec() const { return SCS_extern_in_linkage_spec; } + void setExternInLinkageSpec(bool Value) { + SCS_extern_in_linkage_spec = Value; + } + + SourceLocation getStorageClassSpecLoc() const { return StorageClassSpecLoc; } + SourceLocation getThreadStorageClassSpecLoc() const { + return ThreadStorageClassSpecLoc; + } + + void ClearStorageClassSpecs() { + StorageClassSpec = DeclSpec::SCS_unspecified; + ThreadStorageClassSpec = DeclSpec::TSCS_unspecified; + SCS_extern_in_linkage_spec = false; + StorageClassSpecLoc = SourceLocation(); + ThreadStorageClassSpecLoc = SourceLocation(); + } + + void ClearTypeSpecType() { + TypeSpecType = DeclSpec::TST_unspecified; + TypeSpecOwned = false; + TSTLoc = SourceLocation(); + } + + // type-specifier + TSW getTypeSpecWidth() const { return (TSW)TypeSpecWidth; } + TSC getTypeSpecComplex() const { return (TSC)TypeSpecComplex; } + TSS getTypeSpecSign() const { return (TSS)TypeSpecSign; } + TST getTypeSpecType() const { return (TST)TypeSpecType; } + bool isTypeAltiVecVector() const { return TypeAltiVecVector; } + bool isTypeAltiVecPixel() const { return TypeAltiVecPixel; } + bool isTypeAltiVecBool() const { return TypeAltiVecBool; } + bool isTypeSpecOwned() const { return TypeSpecOwned; } + bool isTypeRep() const { return isTypeRep((TST) TypeSpecType); } + + ParsedType getRepAsType() const { + assert(isTypeRep((TST) TypeSpecType) && "DeclSpec does not store a type"); + return TypeRep; + } + Decl *getRepAsDecl() const { + assert(isDeclRep((TST) TypeSpecType) && "DeclSpec does not store a decl"); + return DeclRep; + } + Expr *getRepAsExpr() const { + assert(isExprRep((TST) TypeSpecType) && "DeclSpec does not store an expr"); + return ExprRep; + } + CXXScopeSpec &getTypeSpecScope() { return TypeScope; } + const CXXScopeSpec &getTypeSpecScope() const { return TypeScope; } + + SourceRange getSourceRange() const LLVM_READONLY { return Range; } + SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } + SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } + + SourceLocation getTypeSpecWidthLoc() const { return TSWLoc; } + SourceLocation getTypeSpecComplexLoc() const { return TSCLoc; } + SourceLocation getTypeSpecSignLoc() const { return TSSLoc; } + SourceLocation getTypeSpecTypeLoc() const { return TSTLoc; } + SourceLocation getAltiVecLoc() const { return AltiVecLoc; } + + SourceLocation getTypeSpecTypeNameLoc() const { + assert(isDeclRep((TST) TypeSpecType) || TypeSpecType == TST_typename); + return TSTNameLoc; + } + + SourceRange getTypeofParensRange() const { return TypeofParensRange; } + void setTypeofParensRange(SourceRange range) { TypeofParensRange = range; } + + bool containsPlaceholderType() const { + return (TypeSpecType == TST_auto || TypeSpecType == TST_auto_type || + TypeSpecType == TST_decltype_auto); + } + + bool hasTagDefinition() const; + + /// \brief Turn a type-specifier-type into a string like "_Bool" or "union". + static const char *getSpecifierName(DeclSpec::TST T, + const PrintingPolicy &Policy); + static const char *getSpecifierName(DeclSpec::TQ Q); + static const char *getSpecifierName(DeclSpec::TSS S); + static const char *getSpecifierName(DeclSpec::TSC C); + static const char *getSpecifierName(DeclSpec::TSW W); + static const char *getSpecifierName(DeclSpec::SCS S); + static const char *getSpecifierName(DeclSpec::TSCS S); + + // type-qualifiers + + /// getTypeQualifiers - Return a set of TQs. + unsigned getTypeQualifiers() const { return TypeQualifiers; } + SourceLocation getConstSpecLoc() const { return TQ_constLoc; } + SourceLocation getRestrictSpecLoc() const { return TQ_restrictLoc; } + SourceLocation getVolatileSpecLoc() const { return TQ_volatileLoc; } + SourceLocation getAtomicSpecLoc() const { return TQ_atomicLoc; } + + /// \brief Clear out all of the type qualifiers. + void ClearTypeQualifiers() { + TypeQualifiers = 0; + TQ_constLoc = SourceLocation(); + TQ_restrictLoc = SourceLocation(); + TQ_volatileLoc = SourceLocation(); + TQ_atomicLoc = SourceLocation(); + } + + // function-specifier + bool isInlineSpecified() const { + return FS_inline_specified | FS_forceinline_specified; + } + SourceLocation getInlineSpecLoc() const { + return FS_inline_specified ? FS_inlineLoc : FS_forceinlineLoc; + } + + bool isVirtualSpecified() const { return FS_virtual_specified; } + SourceLocation getVirtualSpecLoc() const { return FS_virtualLoc; } + + bool isExplicitSpecified() const { return FS_explicit_specified; } + SourceLocation getExplicitSpecLoc() const { return FS_explicitLoc; } + + bool isNoreturnSpecified() const { return FS_noreturn_specified; } + SourceLocation getNoreturnSpecLoc() const { return FS_noreturnLoc; } + + void ClearFunctionSpecs() { + FS_inline_specified = false; + FS_inlineLoc = SourceLocation(); + FS_forceinline_specified = false; + FS_forceinlineLoc = SourceLocation(); + FS_virtual_specified = false; + FS_virtualLoc = SourceLocation(); + FS_explicit_specified = false; + FS_explicitLoc = SourceLocation(); + FS_noreturn_specified = false; + FS_noreturnLoc = SourceLocation(); + } + + /// \brief Return true if any type-specifier has been found. + bool hasTypeSpecifier() const { + return getTypeSpecType() != DeclSpec::TST_unspecified || + getTypeSpecWidth() != DeclSpec::TSW_unspecified || + getTypeSpecComplex() != DeclSpec::TSC_unspecified || + getTypeSpecSign() != DeclSpec::TSS_unspecified; + } + + /// \brief Return a bitmask of which flavors of specifiers this + /// DeclSpec includes. + unsigned getParsedSpecifiers() const; + + /// isEmpty - Return true if this declaration specifier is completely empty: + /// no tokens were parsed in the production of it. + bool isEmpty() const { + return getParsedSpecifiers() == DeclSpec::PQ_None; + } + + void SetRangeStart(SourceLocation Loc) { Range.setBegin(Loc); } + void SetRangeEnd(SourceLocation Loc) { Range.setEnd(Loc); } + + /// These methods set the specified attribute of the DeclSpec and + /// return false if there was no error. If an error occurs (for + /// example, if we tried to set "auto" on a spec with "extern" + /// already set), they return true and set PrevSpec and DiagID + /// such that + /// Diag(Loc, DiagID) << PrevSpec; + /// will yield a useful result. + /// + /// TODO: use a more general approach that still allows these + /// diagnostics to be ignored when desired. + bool SetStorageClassSpec(Sema &S, SCS SC, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID, + const PrintingPolicy &Policy); + bool SetStorageClassSpecThread(TSCS TSC, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID); + bool SetTypeSpecWidth(TSW W, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID, const PrintingPolicy &Policy); + bool SetTypeSpecComplex(TSC C, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + bool SetTypeSpecSign(TSS S, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID, const PrintingPolicy &Policy); + bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID, ParsedType Rep, + const PrintingPolicy &Policy); + bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID, Decl *Rep, bool Owned, + const PrintingPolicy &Policy); + bool SetTypeSpecType(TST T, SourceLocation TagKwLoc, + SourceLocation TagNameLoc, const char *&PrevSpec, + unsigned &DiagID, ParsedType Rep, + const PrintingPolicy &Policy); + bool SetTypeSpecType(TST T, SourceLocation TagKwLoc, + SourceLocation TagNameLoc, const char *&PrevSpec, + unsigned &DiagID, Decl *Rep, bool Owned, + const PrintingPolicy &Policy); + + bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID, Expr *Rep, + const PrintingPolicy &policy); + bool SetTypeAltiVecVector(bool isAltiVecVector, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID, + const PrintingPolicy &Policy); + bool SetTypeAltiVecPixel(bool isAltiVecPixel, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID, + const PrintingPolicy &Policy); + bool SetTypeAltiVecBool(bool isAltiVecBool, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID, + const PrintingPolicy &Policy); + bool SetTypeSpecError(); + void UpdateDeclRep(Decl *Rep) { + assert(isDeclRep((TST) TypeSpecType)); + DeclRep = Rep; + } + void UpdateTypeRep(ParsedType Rep) { + assert(isTypeRep((TST) TypeSpecType)); + TypeRep = Rep; + } + void UpdateExprRep(Expr *Rep) { + assert(isExprRep((TST) TypeSpecType)); + ExprRep = Rep; + } + + bool SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID, const LangOptions &Lang); + + bool setFunctionSpecInline(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + bool setFunctionSpecForceInline(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + bool setFunctionSpecVirtual(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + bool setFunctionSpecExplicit(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + bool setFunctionSpecNoreturn(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + + bool SetFriendSpec(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + bool setModulePrivateSpec(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + bool SetConstexprSpec(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + bool SetConceptSpec(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + + bool isFriendSpecified() const { return Friend_specified; } + SourceLocation getFriendSpecLoc() const { return FriendLoc; } + + bool isModulePrivateSpecified() const { return ModulePrivateLoc.isValid(); } + SourceLocation getModulePrivateSpecLoc() const { return ModulePrivateLoc; } + + bool isConstexprSpecified() const { return Constexpr_specified; } + SourceLocation getConstexprSpecLoc() const { return ConstexprLoc; } + + bool isConceptSpecified() const { return Concept_specified; } + SourceLocation getConceptSpecLoc() const { return ConceptLoc; } + + void ClearConstexprSpec() { + Constexpr_specified = false; + ConstexprLoc = SourceLocation(); + } + + void ClearConceptSpec() { + Concept_specified = false; + ConceptLoc = SourceLocation(); + } + + AttributePool &getAttributePool() const { + return Attrs.getPool(); + } + + /// \brief Concatenates two attribute lists. + /// + /// The GCC attribute syntax allows for the following: + /// + /// \code + /// short __attribute__(( unused, deprecated )) + /// int __attribute__(( may_alias, aligned(16) )) var; + /// \endcode + /// + /// This declares 4 attributes using 2 lists. The following syntax is + /// also allowed and equivalent to the previous declaration. + /// + /// \code + /// short __attribute__((unused)) __attribute__((deprecated)) + /// int __attribute__((may_alias)) __attribute__((aligned(16))) var; + /// \endcode + /// + void addAttributes(AttributeList *AL) { + Attrs.addAll(AL); + } + + bool hasAttributes() const { return !Attrs.empty(); } + + ParsedAttributes &getAttributes() { return Attrs; } + const ParsedAttributes &getAttributes() const { return Attrs; } + + void takeAttributesFrom(ParsedAttributes &attrs) { + Attrs.takeAllFrom(attrs); + } + + /// Finish - This does final analysis of the declspec, issuing diagnostics for + /// things like "_Imaginary" (lacking an FP type). After calling this method, + /// DeclSpec is guaranteed self-consistent, even if an error occurred. + void Finish(Sema &S, const PrintingPolicy &Policy); + + const WrittenBuiltinSpecs& getWrittenBuiltinSpecs() const { + return writtenBS; + } + + ObjCDeclSpec *getObjCQualifiers() const { return ObjCQualifiers; } + void setObjCQualifiers(ObjCDeclSpec *quals) { ObjCQualifiers = quals; } + + /// \brief Checks if this DeclSpec can stand alone, without a Declarator. + /// + /// Only tag declspecs can stand alone. + bool isMissingDeclaratorOk(); +}; + +/// \brief Captures information about "declaration specifiers" specific to +/// Objective-C. +class ObjCDeclSpec { +public: + /// ObjCDeclQualifier - Qualifier used on types in method + /// declarations. Not all combinations are sensible. Parameters + /// can be one of { in, out, inout } with one of { bycopy, byref }. + /// Returns can either be { oneway } or not. + /// + /// This should be kept in sync with Decl::ObjCDeclQualifier. + enum ObjCDeclQualifier { + DQ_None = 0x0, + DQ_In = 0x1, + DQ_Inout = 0x2, + DQ_Out = 0x4, + DQ_Bycopy = 0x8, + DQ_Byref = 0x10, + DQ_Oneway = 0x20, + DQ_CSNullability = 0x40 + }; + + /// PropertyAttributeKind - list of property attributes. + enum ObjCPropertyAttributeKind { + DQ_PR_noattr = 0x0, + DQ_PR_readonly = 0x01, + DQ_PR_getter = 0x02, + DQ_PR_assign = 0x04, + DQ_PR_readwrite = 0x08, + DQ_PR_retain = 0x10, + DQ_PR_copy = 0x20, + DQ_PR_nonatomic = 0x40, + DQ_PR_setter = 0x80, + DQ_PR_atomic = 0x100, + DQ_PR_weak = 0x200, + DQ_PR_strong = 0x400, + DQ_PR_unsafe_unretained = 0x800, + DQ_PR_nullability = 0x1000, + DQ_PR_null_resettable = 0x2000 + }; + + ObjCDeclSpec() + : objcDeclQualifier(DQ_None), PropertyAttributes(DQ_PR_noattr), + Nullability(0), GetterName(nullptr), SetterName(nullptr) { } + + ObjCDeclQualifier getObjCDeclQualifier() const { return objcDeclQualifier; } + void setObjCDeclQualifier(ObjCDeclQualifier DQVal) { + objcDeclQualifier = (ObjCDeclQualifier) (objcDeclQualifier | DQVal); + } + void clearObjCDeclQualifier(ObjCDeclQualifier DQVal) { + objcDeclQualifier = (ObjCDeclQualifier) (objcDeclQualifier & ~DQVal); + } + + ObjCPropertyAttributeKind getPropertyAttributes() const { + return ObjCPropertyAttributeKind(PropertyAttributes); + } + void setPropertyAttributes(ObjCPropertyAttributeKind PRVal) { + PropertyAttributes = + (ObjCPropertyAttributeKind)(PropertyAttributes | PRVal); + } + + NullabilityKind getNullability() const { + assert(((getObjCDeclQualifier() & DQ_CSNullability) || + (getPropertyAttributes() & DQ_PR_nullability)) && + "Objective-C declspec doesn't have nullability"); + return static_cast<NullabilityKind>(Nullability); + } + + SourceLocation getNullabilityLoc() const { + assert(((getObjCDeclQualifier() & DQ_CSNullability) || + (getPropertyAttributes() & DQ_PR_nullability)) && + "Objective-C declspec doesn't have nullability"); + return NullabilityLoc; + } + + void setNullability(SourceLocation loc, NullabilityKind kind) { + assert(((getObjCDeclQualifier() & DQ_CSNullability) || + (getPropertyAttributes() & DQ_PR_nullability)) && + "Set the nullability declspec or property attribute first"); + Nullability = static_cast<unsigned>(kind); + NullabilityLoc = loc; + } + + const IdentifierInfo *getGetterName() const { return GetterName; } + IdentifierInfo *getGetterName() { return GetterName; } + void setGetterName(IdentifierInfo *name) { GetterName = name; } + + const IdentifierInfo *getSetterName() const { return SetterName; } + IdentifierInfo *getSetterName() { return SetterName; } + void setSetterName(IdentifierInfo *name) { SetterName = name; } + +private: + // FIXME: These two are unrelated and mutually exclusive. So perhaps + // we can put them in a union to reflect their mutual exclusivity + // (space saving is negligible). + ObjCDeclQualifier objcDeclQualifier : 7; + + // NOTE: VC++ treats enums as signed, avoid using ObjCPropertyAttributeKind + unsigned PropertyAttributes : 14; + + unsigned Nullability : 2; + + SourceLocation NullabilityLoc; + + IdentifierInfo *GetterName; // getter name or NULL if no getter + IdentifierInfo *SetterName; // setter name or NULL if no setter +}; + +/// \brief Represents a C++ unqualified-id that has been parsed. +class UnqualifiedId { +private: + UnqualifiedId(const UnqualifiedId &Other) = delete; + const UnqualifiedId &operator=(const UnqualifiedId &) = delete; + +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 user-defined literal name, e.g., operator "" _i. + IK_LiteralOperatorId, + /// \brief A constructor name. + IK_ConstructorName, + /// \brief A constructor named via a template-id. + IK_ConstructorTemplateId, + /// \brief A destructor name. + IK_DestructorName, + /// \brief A template-id, e.g., f<int>. + IK_TemplateId, + /// \brief An implicit 'self' parameter + IK_ImplicitSelfParam + } Kind; + + struct OFI { + /// \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]; + }; + + /// \brief Anonymous union that holds extra data associated with the + /// parsed unqualified-id. + union { + /// \brief When Kind == IK_Identifier, the parsed identifier, or when Kind + /// == IK_UserLiteralId, the identifier suffix. + IdentifierInfo *Identifier; + + /// \brief When Kind == IK_OperatorFunctionId, the overloaded operator + /// that we parsed. + struct OFI OperatorFunctionId; + + /// \brief When Kind == IK_ConversionFunctionId, the type that the + /// conversion function names. + UnionParsedType ConversionFunctionId; + + /// \brief When Kind == IK_ConstructorName, the class-name of the type + /// whose constructor is being referenced. + UnionParsedType ConstructorName; + + /// \brief When Kind == IK_DestructorName, the type referred to by the + /// class-name. + UnionParsedType DestructorName; + + /// \brief When Kind == IK_TemplateId or IK_ConstructorTemplateId, + /// 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(nullptr) { } + + /// \brief Clear out this unqualified-id, setting it to default (invalid) + /// state. + void clear() { + Kind = IK_Identifier; + Identifier = nullptr; + StartLocation = SourceLocation(); + EndLocation = SourceLocation(); + } + + /// \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; } + void setKind(IdKind kind) { Kind = 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, + ParsedType Ty, + SourceLocation EndLoc) { + Kind = IK_ConversionFunctionId; + StartLocation = OperatorLoc; + EndLocation = EndLoc; + ConversionFunctionId = Ty; + } + + /// \brief Specific that this unqualified-id was parsed as a + /// literal-operator-id. + /// + /// \param Id the parsed identifier. + /// + /// \param OpLoc the location of the 'operator' keyword. + /// + /// \param IdLoc the location of the identifier. + void setLiteralOperatorId(const IdentifierInfo *Id, SourceLocation OpLoc, + SourceLocation IdLoc) { + Kind = IK_LiteralOperatorId; + Identifier = const_cast<IdentifierInfo *>(Id); + StartLocation = OpLoc; + EndLocation = IdLoc; + } + + /// \brief Specify that this unqualified-id was parsed as a constructor name. + /// + /// \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(ParsedType ClassType, + SourceLocation ClassNameLoc, + SourceLocation EndLoc) { + Kind = IK_ConstructorName; + StartLocation = ClassNameLoc; + EndLocation = EndLoc; + ConstructorName = ClassType; + } + + /// \brief Specify that this unqualified-id was parsed as a + /// template-id that names a constructor. + /// + /// \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 setConstructorTemplateId(TemplateIdAnnotation *TemplateId); + + /// \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, + ParsedType 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); + + /// \brief Return the source range that covers this unqualified-id. + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(StartLocation, EndLocation); + } + SourceLocation getLocStart() const LLVM_READONLY { return StartLocation; } + SourceLocation getLocEnd() const LLVM_READONLY { return EndLocation; } +}; + +/// \brief A set of tokens that has been cached for later parsing. +typedef SmallVector<Token, 4> CachedTokens; + +/// \brief One instance of this struct is used for each type in a +/// declarator that is parsed. +/// +/// This is intended to be a small value object. +struct DeclaratorChunk { + enum { + Pointer, Reference, Array, Function, BlockPointer, MemberPointer, Paren + } Kind; + + /// Loc - The place where this type was defined. + SourceLocation Loc; + /// EndLoc - If valid, the place where this chunck ends. + SourceLocation EndLoc; + + SourceRange getSourceRange() const { + if (EndLoc.isInvalid()) + return SourceRange(Loc, Loc); + return SourceRange(Loc, EndLoc); + } + + struct TypeInfoCommon { + AttributeList *AttrList; + }; + + struct PointerTypeInfo : TypeInfoCommon { + /// The type qualifiers: const/volatile/restrict/atomic. + unsigned TypeQuals : 4; + + /// The location of the const-qualifier, if any. + unsigned ConstQualLoc; + + /// The location of the volatile-qualifier, if any. + unsigned VolatileQualLoc; + + /// The location of the restrict-qualifier, if any. + unsigned RestrictQualLoc; + + /// The location of the _Atomic-qualifier, if any. + unsigned AtomicQualLoc; + + void destroy() { + } + }; + + struct ReferenceTypeInfo : TypeInfoCommon { + /// The type qualifier: restrict. [GNU] C++ extension + bool HasRestrict : 1; + /// True if this is an lvalue reference, false if it's an rvalue reference. + bool LValueRef : 1; + void destroy() { + } + }; + + struct ArrayTypeInfo : TypeInfoCommon { + /// The type qualifiers for the array: const/volatile/restrict/_Atomic. + unsigned TypeQuals : 4; + + /// True if this dimension included the 'static' keyword. + bool hasStatic : 1; + + /// True if this dimension was [*]. In this case, NumElts is null. + bool isStar : 1; + + /// This is the size of the array, or null if [] or [*] was specified. + /// Since the parser is multi-purpose, and we don't want to impose a root + /// expression class on all clients, NumElts is untyped. + Expr *NumElts; + + void destroy() {} + }; + + /// ParamInfo - An array of paraminfo objects is allocated whenever a function + /// declarator is parsed. There are two interesting styles of parameters + /// here: + /// K&R-style identifier lists and parameter type lists. K&R-style identifier + /// lists will have information about the identifier, but no type information. + /// Parameter type lists will have type info (if the actions module provides + /// it), but may have null identifier info: e.g. for 'void foo(int X, int)'. + struct ParamInfo { + IdentifierInfo *Ident; + SourceLocation IdentLoc; + Decl *Param; + + /// DefaultArgTokens - When the parameter's default argument + /// cannot be parsed immediately (because it occurs within the + /// declaration of a member function), it will be stored here as a + /// sequence of tokens to be parsed once the class definition is + /// complete. Non-NULL indicates that there is a default argument. + CachedTokens *DefaultArgTokens; + + ParamInfo() {} + ParamInfo(IdentifierInfo *ident, SourceLocation iloc, + Decl *param, + CachedTokens *DefArgTokens = nullptr) + : Ident(ident), IdentLoc(iloc), Param(param), + DefaultArgTokens(DefArgTokens) {} + }; + + struct TypeAndRange { + ParsedType Ty; + SourceRange Range; + }; + + struct FunctionTypeInfo : TypeInfoCommon { + /// hasPrototype - This is true if the function had at least one typed + /// parameter. If the function is () or (a,b,c), then it has no prototype, + /// and is treated as a K&R-style function. + unsigned hasPrototype : 1; + + /// isVariadic - If this function has a prototype, and if that + /// proto ends with ',...)', this is true. When true, EllipsisLoc + /// contains the location of the ellipsis. + unsigned isVariadic : 1; + + /// Can this declaration be a constructor-style initializer? + unsigned isAmbiguous : 1; + + /// \brief Whether the ref-qualifier (if any) is an lvalue reference. + /// Otherwise, it's an rvalue reference. + unsigned RefQualifierIsLValueRef : 1; + + /// The type qualifiers: const/volatile/restrict. + /// The qualifier bitmask values are the same as in QualType. + unsigned TypeQuals : 3; + + /// ExceptionSpecType - An ExceptionSpecificationType value. + unsigned ExceptionSpecType : 4; + + /// DeleteParams - If this is true, we need to delete[] Params. + unsigned DeleteParams : 1; + + /// HasTrailingReturnType - If this is true, a trailing return type was + /// specified. + unsigned HasTrailingReturnType : 1; + + /// The location of the left parenthesis in the source. + unsigned LParenLoc; + + /// When isVariadic is true, the location of the ellipsis in the source. + unsigned EllipsisLoc; + + /// The location of the right parenthesis in the source. + unsigned RParenLoc; + + /// NumParams - This is the number of formal parameters specified by the + /// declarator. + unsigned NumParams; + + /// NumExceptions - This is the number of types in the dynamic-exception- + /// decl, if the function has one. + unsigned NumExceptions; + + /// \brief The location of the ref-qualifier, if any. + /// + /// If this is an invalid location, there is no ref-qualifier. + unsigned RefQualifierLoc; + + /// \brief The location of the const-qualifier, if any. + /// + /// If this is an invalid location, there is no const-qualifier. + unsigned ConstQualifierLoc; + + /// \brief The location of the volatile-qualifier, if any. + /// + /// If this is an invalid location, there is no volatile-qualifier. + unsigned VolatileQualifierLoc; + + /// \brief The location of the restrict-qualifier, if any. + /// + /// If this is an invalid location, there is no restrict-qualifier. + unsigned RestrictQualifierLoc; + + /// \brief The location of the 'mutable' qualifer in a lambda-declarator, if + /// any. + unsigned MutableLoc; + + /// \brief The beginning location of the exception specification, if any. + unsigned ExceptionSpecLocBeg; + + /// \brief The end location of the exception specification, if any. + unsigned ExceptionSpecLocEnd; + + /// Params - This is a pointer to a new[]'d array of ParamInfo objects that + /// describe the parameters specified by this function declarator. null if + /// there are no parameters specified. + ParamInfo *Params; + + union { + /// \brief Pointer to a new[]'d array of TypeAndRange objects that + /// contain the types in the function's dynamic exception specification + /// and their locations, if there is one. + TypeAndRange *Exceptions; + + /// \brief Pointer to the expression in the noexcept-specifier of this + /// function, if it has one. + Expr *NoexceptExpr; + + /// \brief Pointer to the cached tokens for an exception-specification + /// that has not yet been parsed. + CachedTokens *ExceptionSpecTokens; + }; + + /// \brief If HasTrailingReturnType is true, this is the trailing return + /// type specified. + UnionParsedType TrailingReturnType; + + /// \brief Reset the parameter list to having zero parameters. + /// + /// This is used in various places for error recovery. + void freeParams() { + for (unsigned I = 0; I < NumParams; ++I) { + delete Params[I].DefaultArgTokens; + Params[I].DefaultArgTokens = nullptr; + } + if (DeleteParams) { + delete[] Params; + DeleteParams = false; + } + NumParams = 0; + } + + void destroy() { + if (DeleteParams) + delete[] Params; + if (getExceptionSpecType() == EST_Dynamic) + delete[] Exceptions; + else if (getExceptionSpecType() == EST_Unparsed) + delete ExceptionSpecTokens; + } + + /// isKNRPrototype - Return true if this is a K&R style identifier list, + /// like "void foo(a,b,c)". In a function definition, this will be followed + /// by the parameter type definitions. + bool isKNRPrototype() const { return !hasPrototype && NumParams != 0; } + + SourceLocation getLParenLoc() const { + return SourceLocation::getFromRawEncoding(LParenLoc); + } + + SourceLocation getEllipsisLoc() const { + return SourceLocation::getFromRawEncoding(EllipsisLoc); + } + + SourceLocation getRParenLoc() const { + return SourceLocation::getFromRawEncoding(RParenLoc); + } + + SourceLocation getExceptionSpecLocBeg() const { + return SourceLocation::getFromRawEncoding(ExceptionSpecLocBeg); + } + + SourceLocation getExceptionSpecLocEnd() const { + return SourceLocation::getFromRawEncoding(ExceptionSpecLocEnd); + } + + SourceRange getExceptionSpecRange() const { + return SourceRange(getExceptionSpecLocBeg(), getExceptionSpecLocEnd()); + } + + /// \brief Retrieve the location of the ref-qualifier, if any. + SourceLocation getRefQualifierLoc() const { + return SourceLocation::getFromRawEncoding(RefQualifierLoc); + } + + /// \brief Retrieve the location of the 'const' qualifier, if any. + SourceLocation getConstQualifierLoc() const { + return SourceLocation::getFromRawEncoding(ConstQualifierLoc); + } + + /// \brief Retrieve the location of the 'volatile' qualifier, if any. + SourceLocation getVolatileQualifierLoc() const { + return SourceLocation::getFromRawEncoding(VolatileQualifierLoc); + } + + /// \brief Retrieve the location of the 'restrict' qualifier, if any. + SourceLocation getRestrictQualifierLoc() const { + return SourceLocation::getFromRawEncoding(RestrictQualifierLoc); + } + + /// \brief Retrieve the location of the 'mutable' qualifier, if any. + SourceLocation getMutableLoc() const { + return SourceLocation::getFromRawEncoding(MutableLoc); + } + + /// \brief Determine whether this function declaration contains a + /// ref-qualifier. + bool hasRefQualifier() const { return getRefQualifierLoc().isValid(); } + + /// \brief Determine whether this lambda-declarator contains a 'mutable' + /// qualifier. + bool hasMutableQualifier() const { return getMutableLoc().isValid(); } + + /// \brief Get the type of exception specification this function has. + ExceptionSpecificationType getExceptionSpecType() const { + return static_cast<ExceptionSpecificationType>(ExceptionSpecType); + } + + /// \brief Determine whether this function declarator had a + /// trailing-return-type. + bool hasTrailingReturnType() const { return HasTrailingReturnType; } + + /// \brief Get the trailing-return-type for this function declarator. + ParsedType getTrailingReturnType() const { return TrailingReturnType; } + }; + + struct BlockPointerTypeInfo : TypeInfoCommon { + /// For now, sema will catch these as invalid. + /// The type qualifiers: const/volatile/restrict/_Atomic. + unsigned TypeQuals : 4; + + void destroy() { + } + }; + + struct MemberPointerTypeInfo : TypeInfoCommon { + /// The type qualifiers: const/volatile/restrict/_Atomic. + unsigned TypeQuals : 4; + // CXXScopeSpec has a constructor, so it can't be a direct member. + // So we need some pointer-aligned storage and a bit of trickery. + union { + void *Aligner; + char Mem[sizeof(CXXScopeSpec)]; + } ScopeMem; + CXXScopeSpec &Scope() { + return *reinterpret_cast<CXXScopeSpec*>(ScopeMem.Mem); + } + const CXXScopeSpec &Scope() const { + return *reinterpret_cast<const CXXScopeSpec*>(ScopeMem.Mem); + } + void destroy() { + Scope().~CXXScopeSpec(); + } + }; + + union { + TypeInfoCommon Common; + PointerTypeInfo Ptr; + ReferenceTypeInfo Ref; + ArrayTypeInfo Arr; + FunctionTypeInfo Fun; + BlockPointerTypeInfo Cls; + MemberPointerTypeInfo Mem; + }; + + void destroy() { + switch (Kind) { + case DeclaratorChunk::Function: return Fun.destroy(); + case DeclaratorChunk::Pointer: return Ptr.destroy(); + case DeclaratorChunk::BlockPointer: return Cls.destroy(); + case DeclaratorChunk::Reference: return Ref.destroy(); + case DeclaratorChunk::Array: return Arr.destroy(); + case DeclaratorChunk::MemberPointer: return Mem.destroy(); + case DeclaratorChunk::Paren: return; + } + } + + /// \brief If there are attributes applied to this declaratorchunk, return + /// them. + const AttributeList *getAttrs() const { + return Common.AttrList; + } + + AttributeList *&getAttrListRef() { + return Common.AttrList; + } + + /// \brief Return a DeclaratorChunk for a pointer. + static DeclaratorChunk getPointer(unsigned TypeQuals, SourceLocation Loc, + SourceLocation ConstQualLoc, + SourceLocation VolatileQualLoc, + SourceLocation RestrictQualLoc, + SourceLocation AtomicQualLoc) { + DeclaratorChunk I; + I.Kind = Pointer; + I.Loc = Loc; + I.Ptr.TypeQuals = TypeQuals; + I.Ptr.ConstQualLoc = ConstQualLoc.getRawEncoding(); + I.Ptr.VolatileQualLoc = VolatileQualLoc.getRawEncoding(); + I.Ptr.RestrictQualLoc = RestrictQualLoc.getRawEncoding(); + I.Ptr.AtomicQualLoc = AtomicQualLoc.getRawEncoding(); + I.Ptr.AttrList = nullptr; + return I; + } + + /// \brief Return a DeclaratorChunk for a reference. + static DeclaratorChunk getReference(unsigned TypeQuals, SourceLocation Loc, + bool lvalue) { + DeclaratorChunk I; + I.Kind = Reference; + I.Loc = Loc; + I.Ref.HasRestrict = (TypeQuals & DeclSpec::TQ_restrict) != 0; + I.Ref.LValueRef = lvalue; + I.Ref.AttrList = nullptr; + return I; + } + + /// \brief Return a DeclaratorChunk for an array. + static DeclaratorChunk getArray(unsigned TypeQuals, + bool isStatic, bool isStar, Expr *NumElts, + SourceLocation LBLoc, SourceLocation RBLoc) { + DeclaratorChunk I; + I.Kind = Array; + I.Loc = LBLoc; + I.EndLoc = RBLoc; + I.Arr.AttrList = nullptr; + I.Arr.TypeQuals = TypeQuals; + I.Arr.hasStatic = isStatic; + I.Arr.isStar = isStar; + I.Arr.NumElts = NumElts; + return I; + } + + /// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function. + /// "TheDeclarator" is the declarator that this will be added to. + static DeclaratorChunk getFunction(bool HasProto, + bool IsAmbiguous, + SourceLocation LParenLoc, + ParamInfo *Params, unsigned NumParams, + SourceLocation EllipsisLoc, + SourceLocation RParenLoc, + unsigned TypeQuals, + bool RefQualifierIsLvalueRef, + SourceLocation RefQualifierLoc, + SourceLocation ConstQualifierLoc, + SourceLocation VolatileQualifierLoc, + SourceLocation RestrictQualifierLoc, + SourceLocation MutableLoc, + ExceptionSpecificationType ESpecType, + SourceRange ESpecRange, + ParsedType *Exceptions, + SourceRange *ExceptionRanges, + unsigned NumExceptions, + Expr *NoexceptExpr, + CachedTokens *ExceptionSpecTokens, + SourceLocation LocalRangeBegin, + SourceLocation LocalRangeEnd, + Declarator &TheDeclarator, + TypeResult TrailingReturnType = + TypeResult()); + + /// \brief Return a DeclaratorChunk for a block. + static DeclaratorChunk getBlockPointer(unsigned TypeQuals, + SourceLocation Loc) { + DeclaratorChunk I; + I.Kind = BlockPointer; + I.Loc = Loc; + I.Cls.TypeQuals = TypeQuals; + I.Cls.AttrList = nullptr; + return I; + } + + static DeclaratorChunk getMemberPointer(const CXXScopeSpec &SS, + unsigned TypeQuals, + SourceLocation Loc) { + DeclaratorChunk I; + I.Kind = MemberPointer; + I.Loc = SS.getBeginLoc(); + I.EndLoc = Loc; + I.Mem.TypeQuals = TypeQuals; + I.Mem.AttrList = nullptr; + new (I.Mem.ScopeMem.Mem) CXXScopeSpec(SS); + return I; + } + + /// \brief Return a DeclaratorChunk for a paren. + static DeclaratorChunk getParen(SourceLocation LParenLoc, + SourceLocation RParenLoc) { + DeclaratorChunk I; + I.Kind = Paren; + I.Loc = LParenLoc; + I.EndLoc = RParenLoc; + I.Common.AttrList = nullptr; + return I; + } + + bool isParen() const { + return Kind == Paren; + } +}; + +/// \brief Described the kind of function definition (if any) provided for +/// a function. +enum FunctionDefinitionKind { + FDK_Declaration, + FDK_Definition, + FDK_Defaulted, + FDK_Deleted +}; + +/// \brief Information about one declarator, including the parsed type +/// information and the identifier. +/// +/// When the declarator is fully formed, this is turned into the appropriate +/// Decl object. +/// +/// Declarators come in two types: normal declarators and abstract declarators. +/// Abstract declarators are used when parsing types, and don't have an +/// identifier. Normal declarators do have ID's. +/// +/// Instances of this class should be a transient object that lives on the +/// stack, not objects that are allocated in large quantities on the heap. +class Declarator { +public: + enum TheContext { + FileContext, // File scope declaration. + PrototypeContext, // Within a function prototype. + ObjCResultContext, // An ObjC method result type. + ObjCParameterContext,// An ObjC method parameter type. + KNRTypeListContext, // K&R type definition list for formals. + TypeNameContext, // Abstract declarator for types. + MemberContext, // Struct/Union field. + BlockContext, // Declaration within a block in a function. + ForContext, // Declaration within first part of a for loop. + ConditionContext, // Condition declaration in a C++ if/switch/while/for. + TemplateParamContext,// Within a template parameter list. + CXXNewContext, // C++ new-expression. + CXXCatchContext, // C++ catch exception-declaration + ObjCCatchContext, // Objective-C catch exception-declaration + BlockLiteralContext, // Block literal declarator. + LambdaExprContext, // Lambda-expression declarator. + LambdaExprParameterContext, // Lambda-expression parameter declarator. + ConversionIdContext, // C++ conversion-type-id. + TrailingReturnContext, // C++11 trailing-type-specifier. + TemplateTypeArgContext, // Template type argument. + AliasDeclContext, // C++11 alias-declaration. + AliasTemplateContext // C++11 alias-declaration template. + }; + +private: + const DeclSpec &DS; + CXXScopeSpec SS; + UnqualifiedId Name; + SourceRange Range; + + /// \brief Where we are parsing this declarator. + TheContext Context; + + /// 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 + /// DeclTypeInfo.back() will be the least closely bound. + SmallVector<DeclaratorChunk, 8> DeclTypeInfo; + + /// InvalidType - Set by Sema::GetTypeForDeclarator(). + bool InvalidType : 1; + + /// GroupingParens - Set by Parser::ParseParenDeclarator(). + bool GroupingParens : 1; + + /// FunctionDefinition - Is this Declarator for a function or member + /// definition and, if so, what kind? + /// + /// Actually a FunctionDefinitionKind. + unsigned FunctionDefinition : 2; + + /// \brief Is this Declarator a redeclaration? + bool Redeclaration : 1; + + /// Attrs - Attributes. + ParsedAttributes Attrs; + + /// \brief The asm label, if specified. + Expr *AsmLabel; + + /// 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. + DeclaratorChunk::ParamInfo InlineParams[16]; + bool InlineParamsUsed; + + /// \brief true if the declaration is preceded by \c __extension__. + unsigned Extension : 1; + + /// Indicates whether this is an Objective-C instance variable. + unsigned ObjCIvar : 1; + + /// Indicates whether this is an Objective-C 'weak' property. + unsigned ObjCWeakProperty : 1; + + /// \brief If this is the second or subsequent declarator in this declaration, + /// the location of the comma before this declarator. + SourceLocation CommaLoc; + + /// \brief If provided, the source location of the ellipsis used to describe + /// this declarator as a parameter pack. + SourceLocation EllipsisLoc; + + friend struct DeclaratorChunk; + +public: + Declarator(const DeclSpec &ds, TheContext C) + : DS(ds), Range(ds.getSourceRange()), Context(C), + InvalidType(DS.getTypeSpecType() == DeclSpec::TST_error), + GroupingParens(false), FunctionDefinition(FDK_Declaration), + Redeclaration(false), + Attrs(ds.getAttributePool().getFactory()), AsmLabel(nullptr), + InlineParamsUsed(false), Extension(false), ObjCIvar(false), + ObjCWeakProperty(false) { + } + + ~Declarator() { + clear(); + } + /// getDeclSpec - Return the declaration-specifier that this declarator was + /// declared with. + const DeclSpec &getDeclSpec() const { return DS; } + + /// getMutableDeclSpec - Return a non-const version of the DeclSpec. This + /// should be used with extreme care: declspecs can often be shared between + /// multiple declarators, so mutating the DeclSpec affects all of the + /// Declarators. This should only be done when the declspec is known to not + /// be shared or when in error recovery etc. + DeclSpec &getMutableDeclSpec() { return const_cast<DeclSpec &>(DS); } + + AttributePool &getAttributePool() const { + return Attrs.getPool(); + } + + /// getCXXScopeSpec - Return the C++ scope specifier (global scope or + /// nested-name-specifier) that is part of the declarator-id. + 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; } + + bool isPrototypeContext() const { + return (Context == PrototypeContext || + Context == ObjCParameterContext || + Context == ObjCResultContext || + Context == LambdaExprParameterContext); + } + + /// \brief Get the source range that spans this declarator. + SourceRange getSourceRange() const LLVM_READONLY { return Range; } + SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } + SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } + + void SetSourceRange(SourceRange R) { Range = R; } + /// SetRangeBegin - Set the start of the source range to Loc, unless it's + /// invalid. + void SetRangeBegin(SourceLocation Loc) { + if (!Loc.isInvalid()) + Range.setBegin(Loc); + } + /// SetRangeEnd - Set the end of the source range to Loc, unless it's invalid. + void SetRangeEnd(SourceLocation Loc) { + if (!Loc.isInvalid()) + Range.setEnd(Loc); + } + /// ExtendWithDeclSpec - Extend the declarator source range to include the + /// given declspec, unless its location is invalid. Adopts the range start if + /// the current range start is invalid. + void ExtendWithDeclSpec(const DeclSpec &DS) { + SourceRange SR = DS.getSourceRange(); + if (Range.getBegin().isInvalid()) + Range.setBegin(SR.getBegin()); + if (!SR.getEnd().isInvalid()) + Range.setEnd(SR.getEnd()); + } + + /// \brief Reset the contents of this Declarator. + void clear() { + SS.clear(); + Name.clear(); + Range = DS.getSourceRange(); + + for (unsigned i = 0, e = DeclTypeInfo.size(); i != e; ++i) + DeclTypeInfo[i].destroy(); + DeclTypeInfo.clear(); + Attrs.clear(); + AsmLabel = nullptr; + InlineParamsUsed = false; + ObjCIvar = false; + ObjCWeakProperty = false; + CommaLoc = SourceLocation(); + EllipsisLoc = SourceLocation(); + } + + /// mayOmitIdentifier - Return true if the identifier is either optional or + /// not allowed. This is true for typenames, prototypes, and template + /// parameter lists. + bool mayOmitIdentifier() const { + switch (Context) { + case FileContext: + case KNRTypeListContext: + case MemberContext: + case BlockContext: + case ForContext: + case ConditionContext: + return false; + + case TypeNameContext: + case AliasDeclContext: + case AliasTemplateContext: + case PrototypeContext: + case LambdaExprParameterContext: + case ObjCParameterContext: + case ObjCResultContext: + case TemplateParamContext: + case CXXNewContext: + case CXXCatchContext: + case ObjCCatchContext: + case BlockLiteralContext: + case LambdaExprContext: + case ConversionIdContext: + case TemplateTypeArgContext: + case TrailingReturnContext: + return true; + } + llvm_unreachable("unknown context kind!"); + } + + /// mayHaveIdentifier - Return true if the identifier is either optional or + /// required. This is true for normal declarators and prototypes, but not + /// typenames. + bool mayHaveIdentifier() const { + switch (Context) { + case FileContext: + case KNRTypeListContext: + case MemberContext: + case BlockContext: + case ForContext: + case ConditionContext: + case PrototypeContext: + case LambdaExprParameterContext: + case TemplateParamContext: + case CXXCatchContext: + case ObjCCatchContext: + return true; + + case TypeNameContext: + case CXXNewContext: + case AliasDeclContext: + case AliasTemplateContext: + case ObjCParameterContext: + case ObjCResultContext: + case BlockLiteralContext: + case LambdaExprContext: + case ConversionIdContext: + case TemplateTypeArgContext: + case TrailingReturnContext: + return false; + } + llvm_unreachable("unknown context kind!"); + } + + /// diagnoseIdentifier - Return true if the identifier is prohibited and + /// should be diagnosed (because it cannot be anything else). + bool diagnoseIdentifier() const { + switch (Context) { + case FileContext: + case KNRTypeListContext: + case MemberContext: + case BlockContext: + case ForContext: + case ConditionContext: + case PrototypeContext: + case LambdaExprParameterContext: + case TemplateParamContext: + case CXXCatchContext: + case ObjCCatchContext: + case TypeNameContext: + case ConversionIdContext: + case ObjCParameterContext: + case ObjCResultContext: + case BlockLiteralContext: + case CXXNewContext: + case LambdaExprContext: + return false; + + case AliasDeclContext: + case AliasTemplateContext: + case TemplateTypeArgContext: + case TrailingReturnContext: + return true; + } + llvm_unreachable("unknown context kind!"); + } + + /// mayBeFollowedByCXXDirectInit - Return true if the declarator can be + /// followed by a C++ direct initializer, e.g. "int x(1);". + bool mayBeFollowedByCXXDirectInit() const { + if (hasGroupingParens()) return false; + + if (getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) + return false; + + if (getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_extern && + Context != FileContext) + return false; + + // Special names can't have direct initializers. + if (Name.getKind() != UnqualifiedId::IK_Identifier) + return false; + + switch (Context) { + case FileContext: + case BlockContext: + case ForContext: + return true; + + case ConditionContext: + // This may not be followed by a direct initializer, but it can't be a + // function declaration either, and we'd prefer to perform a tentative + // parse in order to produce the right diagnostic. + return true; + + case KNRTypeListContext: + case MemberContext: + case PrototypeContext: + case LambdaExprParameterContext: + case ObjCParameterContext: + case ObjCResultContext: + case TemplateParamContext: + case CXXCatchContext: + case ObjCCatchContext: + case TypeNameContext: + case CXXNewContext: + case AliasDeclContext: + case AliasTemplateContext: + case BlockLiteralContext: + case LambdaExprContext: + case ConversionIdContext: + case TemplateTypeArgContext: + case TrailingReturnContext: + return false; + } + llvm_unreachable("unknown context kind!"); + } + + /// isPastIdentifier - Return true if we have parsed beyond the point where + /// the + 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 Name.getKind() != UnqualifiedId::IK_Identifier || Name.Identifier; + } + + IdentifierInfo *getIdentifier() const { + if (Name.getKind() == UnqualifiedId::IK_Identifier) + return Name.Identifier; + + return nullptr; + } + SourceLocation getIdentifierLoc() const { return Name.StartLocation; } + + /// \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, + ParsedAttributes &attrs, + SourceLocation EndLoc) { + DeclTypeInfo.push_back(TI); + DeclTypeInfo.back().getAttrListRef() = attrs.getList(); + getAttributePool().takeAllFrom(attrs.getPool()); + + if (!EndLoc.isInvalid()) + SetRangeEnd(EndLoc); + } + + /// \brief Add a new innermost chunk to this declarator. + void AddInnermostTypeInfo(const DeclaratorChunk &TI) { + DeclTypeInfo.insert(DeclTypeInfo.begin(), TI); + } + + /// \brief Return the number of types applied to this declarator. + unsigned getNumTypeObjects() const { return DeclTypeInfo.size(); } + + /// Return the specified TypeInfo from this declarator. TypeInfo #0 is + /// closest to the identifier. + const DeclaratorChunk &getTypeObject(unsigned i) const { + assert(i < DeclTypeInfo.size() && "Invalid type chunk"); + return DeclTypeInfo[i]; + } + DeclaratorChunk &getTypeObject(unsigned i) { + assert(i < DeclTypeInfo.size() && "Invalid type chunk"); + return DeclTypeInfo[i]; + } + + typedef SmallVectorImpl<DeclaratorChunk>::const_iterator type_object_iterator; + typedef llvm::iterator_range<type_object_iterator> type_object_range; + + /// Returns the range of type objects, from the identifier outwards. + type_object_range type_objects() const { + return type_object_range(DeclTypeInfo.begin(), DeclTypeInfo.end()); + } + + void DropFirstTypeObject() { + assert(!DeclTypeInfo.empty() && "No type chunks to drop."); + DeclTypeInfo.front().destroy(); + DeclTypeInfo.erase(DeclTypeInfo.begin()); + } + + /// Return the innermost (closest to the declarator) chunk of this + /// declarator that is not a parens chunk, or null if there are no + /// non-parens chunks. + const DeclaratorChunk *getInnermostNonParenChunk() const { + for (unsigned i = 0, i_end = DeclTypeInfo.size(); i < i_end; ++i) { + if (!DeclTypeInfo[i].isParen()) + return &DeclTypeInfo[i]; + } + return nullptr; + } + + /// Return the outermost (furthest from the declarator) chunk of + /// this declarator that is not a parens chunk, or null if there are + /// no non-parens chunks. + const DeclaratorChunk *getOutermostNonParenChunk() const { + for (unsigned i = DeclTypeInfo.size(), i_end = 0; i != i_end; --i) { + if (!DeclTypeInfo[i-1].isParen()) + return &DeclTypeInfo[i-1]; + } + return nullptr; + } + + /// isArrayOfUnknownBound - This method returns true if the declarator + /// is a declarator for an array of unknown bound (looking through + /// parentheses). + bool isArrayOfUnknownBound() const { + const DeclaratorChunk *chunk = getInnermostNonParenChunk(); + return (chunk && chunk->Kind == DeclaratorChunk::Array && + !chunk->Arr.NumElts); + } + + /// isFunctionDeclarator - This method returns true if the declarator + /// is a function declarator (looking through parentheses). + /// If true is returned, then the reference type parameter idx is + /// assigned with the index of the declaration chunk. + bool isFunctionDeclarator(unsigned& idx) const { + for (unsigned i = 0, i_end = DeclTypeInfo.size(); i < i_end; ++i) { + switch (DeclTypeInfo[i].Kind) { + case DeclaratorChunk::Function: + idx = i; + return true; + case DeclaratorChunk::Paren: + continue; + case DeclaratorChunk::Pointer: + case DeclaratorChunk::Reference: + case DeclaratorChunk::Array: + case DeclaratorChunk::BlockPointer: + case DeclaratorChunk::MemberPointer: + return false; + } + llvm_unreachable("Invalid type chunk"); + } + return false; + } + + /// isFunctionDeclarator - Once this declarator is fully parsed and formed, + /// this method returns true if the identifier is a function declarator + /// (looking through parentheses). + bool isFunctionDeclarator() const { + unsigned index; + return isFunctionDeclarator(index); + } + + /// getFunctionTypeInfo - Retrieves the function type info object + /// (looking through parentheses). + DeclaratorChunk::FunctionTypeInfo &getFunctionTypeInfo() { + assert(isFunctionDeclarator() && "Not a function declarator!"); + unsigned index = 0; + isFunctionDeclarator(index); + return DeclTypeInfo[index].Fun; + } + + /// getFunctionTypeInfo - Retrieves the function type info object + /// (looking through parentheses). + const DeclaratorChunk::FunctionTypeInfo &getFunctionTypeInfo() const { + return const_cast<Declarator*>(this)->getFunctionTypeInfo(); + } + + /// \brief Determine whether the declaration that will be produced from + /// this declaration will be a function. + /// + /// A declaration can declare a function even if the declarator itself + /// isn't a function declarator, if the type specifier refers to a function + /// type. This routine checks for both cases. + bool isDeclarationOfFunction() const; + + /// \brief Return true if this declaration appears in a context where a + /// function declarator would be a function declaration. + bool isFunctionDeclarationContext() const { + if (getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) + return false; + + switch (Context) { + case FileContext: + case MemberContext: + case BlockContext: + return true; + + case ForContext: + case ConditionContext: + case KNRTypeListContext: + case TypeNameContext: + case AliasDeclContext: + case AliasTemplateContext: + case PrototypeContext: + case LambdaExprParameterContext: + case ObjCParameterContext: + case ObjCResultContext: + case TemplateParamContext: + case CXXNewContext: + case CXXCatchContext: + case ObjCCatchContext: + case BlockLiteralContext: + case LambdaExprContext: + case ConversionIdContext: + case TemplateTypeArgContext: + case TrailingReturnContext: + return false; + } + llvm_unreachable("unknown context kind!"); + } + + /// \brief Return true if a function declarator at this position would be a + /// function declaration. + bool isFunctionDeclaratorAFunctionDeclaration() const { + if (!isFunctionDeclarationContext()) + return false; + + for (unsigned I = 0, N = getNumTypeObjects(); I != N; ++I) + if (getTypeObject(I).Kind != DeclaratorChunk::Paren) + return false; + + return true; + } + + /// takeAttributes - Takes attributes from the given parsed-attributes + /// set and add them to this declarator. + /// + /// These examples both add 3 attributes to "var": + /// short int var __attribute__((aligned(16),common,deprecated)); + /// short int x, __attribute__((aligned(16)) var + /// __attribute__((common,deprecated)); + /// + /// Also extends the range of the declarator. + void takeAttributes(ParsedAttributes &attrs, SourceLocation lastLoc) { + Attrs.takeAllFrom(attrs); + + if (!lastLoc.isInvalid()) + SetRangeEnd(lastLoc); + } + + const AttributeList *getAttributes() const { return Attrs.getList(); } + AttributeList *getAttributes() { return Attrs.getList(); } + + AttributeList *&getAttrListRef() { return Attrs.getListRef(); } + + /// hasAttributes - do we contain any attributes? + bool hasAttributes() const { + if (getAttributes() || getDeclSpec().hasAttributes()) return true; + for (unsigned i = 0, e = getNumTypeObjects(); i != e; ++i) + if (getTypeObject(i).getAttrs()) + return true; + return false; + } + + /// \brief Return a source range list of C++11 attributes associated + /// with the declarator. + void getCXX11AttributeRanges(SmallVectorImpl<SourceRange> &Ranges) { + AttributeList *AttrList = Attrs.getList(); + while (AttrList) { + if (AttrList->isCXX11Attribute()) + Ranges.push_back(AttrList->getRange()); + AttrList = AttrList->getNext(); + } + } + + void setAsmLabel(Expr *E) { AsmLabel = E; } + Expr *getAsmLabel() const { return AsmLabel; } + + void setExtension(bool Val = true) { Extension = Val; } + bool getExtension() const { return Extension; } + + void setObjCIvar(bool Val = true) { ObjCIvar = Val; } + bool isObjCIvar() const { return ObjCIvar; } + + void setObjCWeakProperty(bool Val = true) { ObjCWeakProperty = Val; } + bool isObjCWeakProperty() const { return ObjCWeakProperty; } + + void setInvalidType(bool Val = true) { InvalidType = Val; } + bool isInvalidType() const { + return InvalidType || DS.getTypeSpecType() == DeclSpec::TST_error; + } + + void setGroupingParens(bool flag) { GroupingParens = flag; } + bool hasGroupingParens() const { return GroupingParens; } + + bool isFirstDeclarator() const { return !CommaLoc.isValid(); } + SourceLocation getCommaLoc() const { return CommaLoc; } + void setCommaLoc(SourceLocation CL) { CommaLoc = CL; } + + bool hasEllipsis() const { return EllipsisLoc.isValid(); } + SourceLocation getEllipsisLoc() const { return EllipsisLoc; } + void setEllipsisLoc(SourceLocation EL) { EllipsisLoc = EL; } + + void setFunctionDefinitionKind(FunctionDefinitionKind Val) { + FunctionDefinition = Val; + } + + bool isFunctionDefinition() const { + return getFunctionDefinitionKind() != FDK_Declaration; + } + + FunctionDefinitionKind getFunctionDefinitionKind() const { + return (FunctionDefinitionKind)FunctionDefinition; + } + + /// Returns true if this declares a real member and not a friend. + bool isFirstDeclarationOfMember() { + return getContext() == MemberContext && !getDeclSpec().isFriendSpecified(); + } + + /// Returns true if this declares a static member. This cannot be called on a + /// declarator outside of a MemberContext because we won't know until + /// redeclaration time if the decl is static. + bool isStaticMember(); + + /// Returns true if this declares a constructor or a destructor. + bool isCtorOrDtor(); + + void setRedeclaration(bool Val) { Redeclaration = Val; } + bool isRedeclaration() const { return Redeclaration; } +}; + +/// \brief This little struct is used to capture information about +/// structure field declarators, which is basically just a bitfield size. +struct FieldDeclarator { + Declarator D; + Expr *BitfieldSize; + explicit FieldDeclarator(const DeclSpec &DS) + : D(DS, Declarator::MemberContext), BitfieldSize(nullptr) { } +}; + +/// \brief Represents a C++11 virt-specifier-seq. +class VirtSpecifiers { +public: + enum Specifier { + VS_None = 0, + VS_Override = 1, + VS_Final = 2, + VS_Sealed = 4 + }; + + VirtSpecifiers() : Specifiers(0), LastSpecifier(VS_None) { } + + bool SetSpecifier(Specifier VS, SourceLocation Loc, + const char *&PrevSpec); + + bool isUnset() const { return Specifiers == 0; } + + bool isOverrideSpecified() const { return Specifiers & VS_Override; } + SourceLocation getOverrideLoc() const { return VS_overrideLoc; } + + bool isFinalSpecified() const { return Specifiers & (VS_Final | VS_Sealed); } + bool isFinalSpelledSealed() const { return Specifiers & VS_Sealed; } + SourceLocation getFinalLoc() const { return VS_finalLoc; } + + void clear() { Specifiers = 0; } + + static const char *getSpecifierName(Specifier VS); + + SourceLocation getFirstLocation() const { return FirstLocation; } + SourceLocation getLastLocation() const { return LastLocation; } + Specifier getLastSpecifier() const { return LastSpecifier; } + +private: + unsigned Specifiers; + Specifier LastSpecifier; + + SourceLocation VS_overrideLoc, VS_finalLoc; + SourceLocation FirstLocation; + SourceLocation LastLocation; +}; + +enum class LambdaCaptureInitKind { + NoInit, //!< [a] + CopyInit, //!< [a = b], [a = {b}] + DirectInit, //!< [a(b)] + ListInit //!< [a{b}] +}; + +/// \brief Represents a complete lambda introducer. +struct LambdaIntroducer { + /// \brief An individual capture in a lambda introducer. + struct LambdaCapture { + LambdaCaptureKind Kind; + SourceLocation Loc; + IdentifierInfo *Id; + SourceLocation EllipsisLoc; + LambdaCaptureInitKind InitKind; + ExprResult Init; + ParsedType InitCaptureType; + LambdaCapture(LambdaCaptureKind Kind, SourceLocation Loc, + IdentifierInfo *Id, SourceLocation EllipsisLoc, + LambdaCaptureInitKind InitKind, ExprResult Init, + ParsedType InitCaptureType) + : Kind(Kind), Loc(Loc), Id(Id), EllipsisLoc(EllipsisLoc), + InitKind(InitKind), Init(Init), InitCaptureType(InitCaptureType) {} + }; + + SourceRange Range; + SourceLocation DefaultLoc; + LambdaCaptureDefault Default; + SmallVector<LambdaCapture, 4> Captures; + + LambdaIntroducer() + : Default(LCD_None) {} + + /// \brief Append a capture in a lambda introducer. + void addCapture(LambdaCaptureKind Kind, + SourceLocation Loc, + IdentifierInfo* Id, + SourceLocation EllipsisLoc, + LambdaCaptureInitKind InitKind, + ExprResult Init, + ParsedType InitCaptureType) { + Captures.push_back(LambdaCapture(Kind, Loc, Id, EllipsisLoc, InitKind, Init, + InitCaptureType)); + } +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Sema/DelayedDiagnostic.h b/contrib/llvm/tools/clang/include/clang/Sema/DelayedDiagnostic.h new file mode 100644 index 0000000..155b3aa --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Sema/DelayedDiagnostic.h @@ -0,0 +1,305 @@ +//===--- DelayedDiagnostic.h - Delayed declarator diagnostics ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the classes clang::DelayedDiagnostic and +/// clang::AccessedEntity. +/// +/// DelayedDiangostic is used to record diagnostics that are being +/// conditionally produced during declarator parsing. Certain kinds of +/// diagnostics -- notably deprecation and access control -- are suppressed +/// based on semantic properties of the parsed declaration that aren't known +/// until it is fully parsed. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_DELAYEDDIAGNOSTIC_H +#define LLVM_CLANG_SEMA_DELAYEDDIAGNOSTIC_H + +#include "clang/Sema/Sema.h" + +namespace clang { +namespace sema { + +/// A declaration being accessed, together with information about how +/// it was accessed. +class AccessedEntity { +public: + /// A member declaration found through lookup. The target is the + /// member. + enum MemberNonce { Member }; + + /// A hierarchy (base-to-derived or derived-to-base) conversion. + /// The target is the base class. + enum BaseNonce { Base }; + + bool isMemberAccess() const { return IsMember; } + + AccessedEntity(PartialDiagnostic::StorageAllocator &Allocator, + MemberNonce _, + CXXRecordDecl *NamingClass, + DeclAccessPair FoundDecl, + QualType BaseObjectType) + : Access(FoundDecl.getAccess()), IsMember(true), + Target(FoundDecl.getDecl()), NamingClass(NamingClass), + BaseObjectType(BaseObjectType), Diag(0, Allocator) { + } + + AccessedEntity(PartialDiagnostic::StorageAllocator &Allocator, + BaseNonce _, + CXXRecordDecl *BaseClass, + CXXRecordDecl *DerivedClass, + AccessSpecifier Access) + : Access(Access), IsMember(false), + Target(BaseClass), + NamingClass(DerivedClass), + Diag(0, Allocator) { + } + + bool isQuiet() const { return Diag.getDiagID() == 0; } + + AccessSpecifier getAccess() const { return AccessSpecifier(Access); } + + // These apply to member decls... + NamedDecl *getTargetDecl() const { return Target; } + CXXRecordDecl *getNamingClass() const { return NamingClass; } + + // ...and these apply to hierarchy conversions. + CXXRecordDecl *getBaseClass() const { + assert(!IsMember); return cast<CXXRecordDecl>(Target); + } + CXXRecordDecl *getDerivedClass() const { return NamingClass; } + + /// Retrieves the base object type, important when accessing + /// an instance member. + QualType getBaseObjectType() const { return BaseObjectType; } + + /// Sets a diagnostic to be performed. The diagnostic is given + /// four (additional) arguments: + /// %0 - 0 if the entity was private, 1 if protected + /// %1 - the DeclarationName of the entity + /// %2 - the TypeDecl type of the naming class + /// %3 - the TypeDecl type of the declaring class + void setDiag(const PartialDiagnostic &PDiag) { + assert(isQuiet() && "partial diagnostic already defined"); + Diag = PDiag; + } + PartialDiagnostic &setDiag(unsigned DiagID) { + assert(isQuiet() && "partial diagnostic already defined"); + assert(DiagID && "creating null diagnostic"); + Diag.Reset(DiagID); + return Diag; + } + const PartialDiagnostic &getDiag() const { + return Diag; + } + +private: + unsigned Access : 2; + unsigned IsMember : 1; + NamedDecl *Target; + CXXRecordDecl *NamingClass; + QualType BaseObjectType; + PartialDiagnostic Diag; +}; + +/// A diagnostic message which has been conditionally emitted pending +/// the complete parsing of the current declaration. +class DelayedDiagnostic { +public: + enum DDKind { Deprecation, Unavailable, Access, ForbiddenType }; + + unsigned char Kind; // actually a DDKind + bool Triggered; + + SourceLocation Loc; + + void Destroy(); + + static DelayedDiagnostic makeAvailability(Sema::AvailabilityDiagnostic AD, + SourceLocation Loc, + const NamedDecl *D, + const ObjCInterfaceDecl *UnknownObjCClass, + const ObjCPropertyDecl *ObjCProperty, + StringRef Msg, + bool ObjCPropertyAccess); + + + static DelayedDiagnostic makeAccess(SourceLocation Loc, + const AccessedEntity &Entity) { + DelayedDiagnostic DD; + DD.Kind = Access; + DD.Triggered = false; + DD.Loc = Loc; + new (&DD.getAccessData()) AccessedEntity(Entity); + return DD; + } + + static DelayedDiagnostic makeForbiddenType(SourceLocation loc, + unsigned diagnostic, + QualType type, + unsigned argument) { + DelayedDiagnostic DD; + DD.Kind = ForbiddenType; + DD.Triggered = false; + DD.Loc = loc; + DD.ForbiddenTypeData.Diagnostic = diagnostic; + DD.ForbiddenTypeData.OperandType = type.getAsOpaquePtr(); + DD.ForbiddenTypeData.Argument = argument; + return DD; + } + + AccessedEntity &getAccessData() { + assert(Kind == Access && "Not an access diagnostic."); + return *reinterpret_cast<AccessedEntity*>(AccessData); + } + const AccessedEntity &getAccessData() const { + assert(Kind == Access && "Not an access diagnostic."); + return *reinterpret_cast<const AccessedEntity*>(AccessData); + } + + const NamedDecl *getDeprecationDecl() const { + assert((Kind == Deprecation || Kind == Unavailable) && + "Not a deprecation diagnostic."); + return DeprecationData.Decl; + } + + StringRef getDeprecationMessage() const { + assert((Kind == Deprecation || Kind == Unavailable) && + "Not a deprecation diagnostic."); + return StringRef(DeprecationData.Message, + DeprecationData.MessageLen); + } + + /// The diagnostic ID to emit. Used like so: + /// Diag(diag.Loc, diag.getForbiddenTypeDiagnostic()) + /// << diag.getForbiddenTypeOperand() + /// << diag.getForbiddenTypeArgument(); + unsigned getForbiddenTypeDiagnostic() const { + assert(Kind == ForbiddenType && "not a forbidden-type diagnostic"); + return ForbiddenTypeData.Diagnostic; + } + + unsigned getForbiddenTypeArgument() const { + assert(Kind == ForbiddenType && "not a forbidden-type diagnostic"); + return ForbiddenTypeData.Argument; + } + + QualType getForbiddenTypeOperand() const { + assert(Kind == ForbiddenType && "not a forbidden-type diagnostic"); + return QualType::getFromOpaquePtr(ForbiddenTypeData.OperandType); + } + + const ObjCInterfaceDecl *getUnknownObjCClass() const { + return DeprecationData.UnknownObjCClass; + } + + const ObjCPropertyDecl *getObjCProperty() const { + return DeprecationData.ObjCProperty; + } + + bool getObjCPropertyAccess() const { + return DeprecationData.ObjCPropertyAccess; + } + +private: + + struct DD { + const NamedDecl *Decl; + const ObjCInterfaceDecl *UnknownObjCClass; + const ObjCPropertyDecl *ObjCProperty; + const char *Message; + size_t MessageLen; + bool ObjCPropertyAccess; + }; + + struct FTD { + unsigned Diagnostic; + unsigned Argument; + void *OperandType; + }; + + union { + /// Deprecation + struct DD DeprecationData; + struct FTD ForbiddenTypeData; + + /// Access control. + char AccessData[sizeof(AccessedEntity)]; + }; +}; + +/// \brief A collection of diagnostics which were delayed. +class DelayedDiagnosticPool { + const DelayedDiagnosticPool *Parent; + SmallVector<DelayedDiagnostic, 4> Diagnostics; + + DelayedDiagnosticPool(const DelayedDiagnosticPool &) = delete; + void operator=(const DelayedDiagnosticPool &) = delete; +public: + DelayedDiagnosticPool(const DelayedDiagnosticPool *parent) : Parent(parent) {} + ~DelayedDiagnosticPool() { + for (SmallVectorImpl<DelayedDiagnostic>::iterator + i = Diagnostics.begin(), e = Diagnostics.end(); i != e; ++i) + i->Destroy(); + } + + DelayedDiagnosticPool(DelayedDiagnosticPool &&Other) + : Parent(Other.Parent), Diagnostics(std::move(Other.Diagnostics)) { + Other.Diagnostics.clear(); + } + DelayedDiagnosticPool &operator=(DelayedDiagnosticPool &&Other) { + Parent = Other.Parent; + Diagnostics = std::move(Other.Diagnostics); + Other.Diagnostics.clear(); + return *this; + } + + const DelayedDiagnosticPool *getParent() const { return Parent; } + + /// Does this pool, or any of its ancestors, contain any diagnostics? + bool empty() const { + return (Diagnostics.empty() && (!Parent || Parent->empty())); + } + + /// Add a diagnostic to this pool. + void add(const DelayedDiagnostic &diag) { + Diagnostics.push_back(diag); + } + + /// Steal the diagnostics from the given pool. + void steal(DelayedDiagnosticPool &pool) { + if (pool.Diagnostics.empty()) return; + + if (Diagnostics.empty()) { + Diagnostics = std::move(pool.Diagnostics); + } else { + Diagnostics.append(pool.pool_begin(), pool.pool_end()); + } + pool.Diagnostics.clear(); + } + + typedef SmallVectorImpl<DelayedDiagnostic>::const_iterator pool_iterator; + pool_iterator pool_begin() const { return Diagnostics.begin(); } + pool_iterator pool_end() const { return Diagnostics.end(); } + bool pool_empty() const { return Diagnostics.empty(); } +}; + +} + +/// Add a diagnostic to the current delay pool. +inline void Sema::DelayedDiagnostics::add(const sema::DelayedDiagnostic &diag) { + assert(shouldDelayDiagnostics() && "trying to delay without pool"); + CurPool->add(diag); +} + + +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Sema/Designator.h b/contrib/llvm/tools/clang/include/clang/Sema/Designator.h new file mode 100644 index 0000000..55603fe --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Sema/Designator.h @@ -0,0 +1,210 @@ +//===--- Designator.h - Initialization Designator ---------------*- 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 interfaces used to represent designators (a la +// C99 designated initializers) during parsing. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_DESIGNATOR_H +#define LLVM_CLANG_SEMA_DESIGNATOR_H + +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { + +class Expr; +class IdentifierInfo; +class Sema; + +/// Designator - A designator in a C99 designated initializer. +/// +/// This class is a discriminated union which holds the various +/// different sorts of designators possible. A Designation is an array of +/// these. An example of a designator are things like this: +/// [8] .field [47] // C99 designation: 3 designators +/// [8 ... 47] field: // GNU extensions: 2 designators +/// These occur in initializers, e.g.: +/// int a[10] = {2, 4, [8]=9, 10}; +/// +class Designator { +public: + enum DesignatorKind { + FieldDesignator, ArrayDesignator, ArrayRangeDesignator + }; +private: + DesignatorKind Kind; + + struct FieldDesignatorInfo { + const IdentifierInfo *II; + unsigned DotLoc; + unsigned NameLoc; + }; + struct ArrayDesignatorInfo { + Expr *Index; + unsigned LBracketLoc; + mutable unsigned RBracketLoc; + }; + struct ArrayRangeDesignatorInfo { + Expr *Start, *End; + unsigned LBracketLoc, EllipsisLoc; + mutable unsigned RBracketLoc; + }; + + union { + FieldDesignatorInfo FieldInfo; + ArrayDesignatorInfo ArrayInfo; + ArrayRangeDesignatorInfo ArrayRangeInfo; + }; + +public: + + DesignatorKind getKind() const { return Kind; } + bool isFieldDesignator() const { return Kind == FieldDesignator; } + bool isArrayDesignator() const { return Kind == ArrayDesignator; } + bool isArrayRangeDesignator() const { return Kind == ArrayRangeDesignator; } + + const IdentifierInfo *getField() const { + assert(isFieldDesignator() && "Invalid accessor"); + return FieldInfo.II; + } + + SourceLocation getDotLoc() const { + assert(isFieldDesignator() && "Invalid accessor"); + return SourceLocation::getFromRawEncoding(FieldInfo.DotLoc); + } + + SourceLocation getFieldLoc() const { + assert(isFieldDesignator() && "Invalid accessor"); + return SourceLocation::getFromRawEncoding(FieldInfo.NameLoc); + } + + Expr *getArrayIndex() const { + assert(isArrayDesignator() && "Invalid accessor"); + return ArrayInfo.Index; + } + + Expr *getArrayRangeStart() const { + assert(isArrayRangeDesignator() && "Invalid accessor"); + return ArrayRangeInfo.Start; + } + Expr *getArrayRangeEnd() const { + assert(isArrayRangeDesignator() && "Invalid accessor"); + return ArrayRangeInfo.End; + } + + SourceLocation getLBracketLoc() const { + assert((isArrayDesignator() || isArrayRangeDesignator()) && + "Invalid accessor"); + if (isArrayDesignator()) + return SourceLocation::getFromRawEncoding(ArrayInfo.LBracketLoc); + else + return SourceLocation::getFromRawEncoding(ArrayRangeInfo.LBracketLoc); + } + + SourceLocation getRBracketLoc() const { + assert((isArrayDesignator() || isArrayRangeDesignator()) && + "Invalid accessor"); + if (isArrayDesignator()) + return SourceLocation::getFromRawEncoding(ArrayInfo.RBracketLoc); + else + return SourceLocation::getFromRawEncoding(ArrayRangeInfo.RBracketLoc); + } + + SourceLocation getEllipsisLoc() const { + assert(isArrayRangeDesignator() && "Invalid accessor"); + return SourceLocation::getFromRawEncoding(ArrayRangeInfo.EllipsisLoc); + } + + static Designator getField(const IdentifierInfo *II, SourceLocation DotLoc, + SourceLocation NameLoc) { + Designator D; + D.Kind = FieldDesignator; + D.FieldInfo.II = II; + D.FieldInfo.DotLoc = DotLoc.getRawEncoding(); + D.FieldInfo.NameLoc = NameLoc.getRawEncoding(); + return D; + } + + static Designator getArray(Expr *Index, + SourceLocation LBracketLoc) { + Designator D; + D.Kind = ArrayDesignator; + D.ArrayInfo.Index = Index; + D.ArrayInfo.LBracketLoc = LBracketLoc.getRawEncoding(); + D.ArrayInfo.RBracketLoc = 0; + return D; + } + + static Designator getArrayRange(Expr *Start, + Expr *End, + SourceLocation LBracketLoc, + SourceLocation EllipsisLoc) { + Designator D; + D.Kind = ArrayRangeDesignator; + D.ArrayRangeInfo.Start = Start; + D.ArrayRangeInfo.End = End; + D.ArrayRangeInfo.LBracketLoc = LBracketLoc.getRawEncoding(); + D.ArrayRangeInfo.EllipsisLoc = EllipsisLoc.getRawEncoding(); + D.ArrayRangeInfo.RBracketLoc = 0; + return D; + } + + void setRBracketLoc(SourceLocation RBracketLoc) const { + assert((isArrayDesignator() || isArrayRangeDesignator()) && + "Invalid accessor"); + if (isArrayDesignator()) + ArrayInfo.RBracketLoc = RBracketLoc.getRawEncoding(); + else + ArrayRangeInfo.RBracketLoc = RBracketLoc.getRawEncoding(); + } + + /// ClearExprs - Null out any expression references, which prevents + /// them from being 'delete'd later. + void ClearExprs(Sema &Actions) {} + + /// FreeExprs - Release any unclaimed memory for the expressions in + /// this designator. + void FreeExprs(Sema &Actions) {} +}; + + +/// Designation - Represent a full designation, which is a sequence of +/// designators. This class is mostly a helper for InitListDesignations. +class Designation { + /// Designators - The actual designators for this initializer. + SmallVector<Designator, 2> Designators; + +public: + /// AddDesignator - Add a designator to the end of this list. + void AddDesignator(Designator D) { + Designators.push_back(D); + } + + bool empty() const { return Designators.empty(); } + + unsigned getNumDesignators() const { return Designators.size(); } + const Designator &getDesignator(unsigned Idx) const { + assert(Idx < Designators.size()); + return Designators[Idx]; + } + + /// ClearExprs - Null out any expression references, which prevents them from + /// being 'delete'd later. + void ClearExprs(Sema &Actions) {} + + /// FreeExprs - Release any unclaimed memory for the expressions in this + /// designation. + void FreeExprs(Sema &Actions) {} +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Sema/ExternalSemaSource.h b/contrib/llvm/tools/clang/include/clang/Sema/ExternalSemaSource.h new file mode 100644 index 0000000..97f78f4 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Sema/ExternalSemaSource.h @@ -0,0 +1,229 @@ +//===--- ExternalSemaSource.h - External Sema Interface ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ExternalSemaSource interface. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_SEMA_EXTERNALSEMASOURCE_H +#define LLVM_CLANG_SEMA_EXTERNALSEMASOURCE_H + +#include "clang/AST/ExternalASTSource.h" +#include "clang/AST/Type.h" +#include "clang/Sema/TypoCorrection.h" +#include "clang/Sema/Weak.h" +#include "llvm/ADT/MapVector.h" +#include <utility> + +namespace llvm { +template <class T, unsigned n> class SmallSetVector; +} + +namespace clang { + +class CXXConstructorDecl; +class CXXDeleteExpr; +class CXXRecordDecl; +class DeclaratorDecl; +class LookupResult; +struct ObjCMethodList; +class Scope; +class Sema; +class TypedefNameDecl; +class ValueDecl; +class VarDecl; +struct LateParsedTemplate; + +/// \brief A simple structure that captures a vtable use for the purposes of +/// the \c ExternalSemaSource. +struct ExternalVTableUse { + CXXRecordDecl *Record; + SourceLocation Location; + bool DefinitionRequired; +}; + +/// \brief An abstract interface that should be implemented by +/// external AST sources that also provide information for semantic +/// analysis. +class ExternalSemaSource : public ExternalASTSource { +public: + ExternalSemaSource() { + ExternalASTSource::SemaSource = true; + } + + ~ExternalSemaSource() override; + + /// \brief Initialize the semantic source with the Sema instance + /// being used to perform semantic analysis on the abstract syntax + /// tree. + virtual void InitializeSema(Sema &S) {} + + /// \brief Inform the semantic consumer that Sema is no longer available. + virtual void ForgetSema() {} + + /// \brief Load the contents of the global method pool for a given + /// selector. + virtual void ReadMethodPool(Selector Sel); + + /// \brief Load the set of namespaces that are known to the external source, + /// which will be used during typo correction. + virtual void ReadKnownNamespaces( + SmallVectorImpl<NamespaceDecl *> &Namespaces); + + /// \brief Load the set of used but not defined functions or variables with + /// internal linkage, or used but not defined internal functions. + virtual void ReadUndefinedButUsed( + llvm::DenseMap<NamedDecl*, SourceLocation> &Undefined); + + virtual void ReadMismatchingDeleteExpressions(llvm::MapVector< + FieldDecl *, llvm::SmallVector<std::pair<SourceLocation, bool>, 4>> &); + + /// \brief Do last resort, unqualified lookup on a LookupResult that + /// Sema cannot find. + /// + /// \param R a LookupResult that is being recovered. + /// + /// \param S the Scope of the identifier occurrence. + /// + /// \return true to tell Sema to recover using the LookupResult. + virtual bool LookupUnqualified(LookupResult &R, Scope *S) { return false; } + + /// \brief Read the set of tentative definitions known to the external Sema + /// source. + /// + /// The external source should append its own tentative definitions to the + /// given vector of tentative definitions. Note that this routine may be + /// invoked multiple times; the external source should take care not to + /// introduce the same declarations repeatedly. + virtual void ReadTentativeDefinitions( + SmallVectorImpl<VarDecl *> &TentativeDefs) {} + + /// \brief Read the set of unused file-scope declarations known to the + /// external Sema source. + /// + /// The external source should append its own unused, filed-scope to the + /// given vector of declarations. Note that this routine may be + /// invoked multiple times; the external source should take care not to + /// introduce the same declarations repeatedly. + virtual void ReadUnusedFileScopedDecls( + SmallVectorImpl<const DeclaratorDecl *> &Decls) {} + + /// \brief Read the set of delegating constructors known to the + /// external Sema source. + /// + /// The external source should append its own delegating constructors to the + /// given vector of declarations. Note that this routine may be + /// invoked multiple times; the external source should take care not to + /// introduce the same declarations repeatedly. + virtual void ReadDelegatingConstructors( + SmallVectorImpl<CXXConstructorDecl *> &Decls) {} + + /// \brief Read the set of ext_vector type declarations known to the + /// external Sema source. + /// + /// The external source should append its own ext_vector type declarations to + /// the given vector of declarations. Note that this routine may be + /// invoked multiple times; the external source should take care not to + /// introduce the same declarations repeatedly. + virtual void ReadExtVectorDecls(SmallVectorImpl<TypedefNameDecl *> &Decls) {} + + /// \brief Read the set of potentially unused typedefs known to the source. + /// + /// The external source should append its own potentially unused local + /// typedefs to the given vector of declarations. Note that this routine may + /// be invoked multiple times; the external source should take care not to + /// introduce the same declarations repeatedly. + virtual void ReadUnusedLocalTypedefNameCandidates( + llvm::SmallSetVector<const TypedefNameDecl *, 4> &Decls) {} + + /// \brief Read the set of referenced selectors known to the + /// external Sema source. + /// + /// The external source should append its own referenced selectors to the + /// given vector of selectors. Note that this routine + /// may be invoked multiple times; the external source should take care not + /// to introduce the same selectors repeatedly. + virtual void ReadReferencedSelectors( + SmallVectorImpl<std::pair<Selector, SourceLocation> > &Sels) {} + + /// \brief Read the set of weak, undeclared identifiers known to the + /// external Sema source. + /// + /// The external source should append its own weak, undeclared identifiers to + /// the given vector. Note that this routine may be invoked multiple times; + /// the external source should take care not to introduce the same identifiers + /// repeatedly. + virtual void ReadWeakUndeclaredIdentifiers( + SmallVectorImpl<std::pair<IdentifierInfo *, WeakInfo> > &WI) {} + + /// \brief Read the set of used vtables known to the external Sema source. + /// + /// The external source should append its own used vtables to the given + /// vector. Note that this routine may be invoked multiple times; the external + /// source should take care not to introduce the same vtables repeatedly. + virtual void ReadUsedVTables(SmallVectorImpl<ExternalVTableUse> &VTables) {} + + /// \brief Read the set of pending instantiations known to the external + /// Sema source. + /// + /// The external source should append its own pending instantiations to the + /// given vector. Note that this routine may be invoked multiple times; the + /// external source should take care not to introduce the same instantiations + /// repeatedly. + virtual void ReadPendingInstantiations( + SmallVectorImpl<std::pair<ValueDecl *, + SourceLocation> > &Pending) {} + + /// \brief Read the set of late parsed template functions for this source. + /// + /// The external source should insert its own late parsed template functions + /// into the map. Note that this routine may be invoked multiple times; the + /// external source should take care not to introduce the same map entries + /// repeatedly. + virtual void ReadLateParsedTemplates( + llvm::MapVector<const FunctionDecl *, LateParsedTemplate *> &LPTMap) {} + + /// \copydoc Sema::CorrectTypo + /// \note LookupKind must correspond to a valid Sema::LookupNameKind + /// + /// ExternalSemaSource::CorrectTypo is always given the first chance to + /// correct a typo (really, to offer suggestions to repair a failed lookup). + /// It will even be called when SpellChecking is turned off or after a + /// fatal error has already been detected. + virtual TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo, + int LookupKind, Scope *S, CXXScopeSpec *SS, + CorrectionCandidateCallback &CCC, + DeclContext *MemberContext, + bool EnteringContext, + const ObjCObjectPointerType *OPT) { + return TypoCorrection(); + } + + /// \brief Produces a diagnostic note if the external source contains a + /// complete definition for \p T. + /// + /// \param Loc the location at which a complete type was required but not + /// provided + /// + /// \param T the \c QualType that should have been complete at \p Loc + /// + /// \return true if a diagnostic was produced, false otherwise. + virtual bool MaybeDiagnoseMissingCompleteType(SourceLocation Loc, + QualType T) { + return false; + } + + // isa/cast/dyn_cast support + static bool classof(const ExternalASTSource *Source) { + return Source->SemaSource; + } +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Sema/IdentifierResolver.h b/contrib/llvm/tools/clang/include/clang/Sema/IdentifierResolver.h new file mode 100644 index 0000000..a07834f --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Sema/IdentifierResolver.h @@ -0,0 +1,213 @@ +//===- IdentifierResolver.h - Lexical Scope Name lookup ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the IdentifierResolver class, which is used for lexical +// scoped lookup, based on declaration names. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_IDENTIFIERRESOLVER_H +#define LLVM_CLANG_SEMA_IDENTIFIERRESOLVER_H + +#include "clang/Basic/IdentifierTable.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { + +class ASTContext; +class Decl; +class DeclContext; +class DeclarationName; +class ExternalPreprocessorSource; +class NamedDecl; +class Preprocessor; +class Scope; + +/// IdentifierResolver - Keeps track of shadowed decls on enclosing +/// scopes. It manages the shadowing chains of declaration names and +/// implements efficient decl lookup based on a declaration name. +class IdentifierResolver { + + /// IdDeclInfo - Keeps track of information about decls associated + /// to a particular declaration name. IdDeclInfos are lazily + /// constructed and assigned to a declaration name the first time a + /// decl with that declaration name is shadowed in some scope. + class IdDeclInfo { + public: + typedef SmallVector<NamedDecl*, 2> DeclsTy; + + inline DeclsTy::iterator decls_begin() { return Decls.begin(); } + inline DeclsTy::iterator decls_end() { return Decls.end(); } + + void AddDecl(NamedDecl *D) { Decls.push_back(D); } + + /// RemoveDecl - Remove the decl from the scope chain. + /// The decl must already be part of the decl chain. + void RemoveDecl(NamedDecl *D); + + /// \brief Insert the given declaration at the given position in the list. + void InsertDecl(DeclsTy::iterator Pos, NamedDecl *D) { + Decls.insert(Pos, D); + } + + private: + DeclsTy Decls; + }; + +public: + + /// iterator - Iterate over the decls of a specified declaration name. + /// It will walk or not the parent declaration contexts depending on how + /// it was instantiated. + class iterator { + public: + typedef NamedDecl * value_type; + typedef NamedDecl * reference; + typedef NamedDecl * pointer; + typedef std::input_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + + /// Ptr - There are 3 forms that 'Ptr' represents: + /// 1) A single NamedDecl. (Ptr & 0x1 == 0) + /// 2) A IdDeclInfo::DeclsTy::iterator that traverses only the decls of the + /// same declaration context. (Ptr & 0x3 == 0x1) + /// 3) A IdDeclInfo::DeclsTy::iterator that traverses the decls of parent + /// declaration contexts too. (Ptr & 0x3 == 0x3) + uintptr_t Ptr; + typedef IdDeclInfo::DeclsTy::iterator BaseIter; + + /// A single NamedDecl. (Ptr & 0x1 == 0) + iterator(NamedDecl *D) { + Ptr = reinterpret_cast<uintptr_t>(D); + assert((Ptr & 0x1) == 0 && "Invalid Ptr!"); + } + /// A IdDeclInfo::DeclsTy::iterator that walks or not the parent declaration + /// contexts depending on 'LookInParentCtx'. + iterator(BaseIter I) { + Ptr = reinterpret_cast<uintptr_t>(I) | 0x1; + } + + bool isIterator() const { return (Ptr & 0x1); } + + BaseIter getIterator() const { + assert(isIterator() && "Ptr not an iterator!"); + return reinterpret_cast<BaseIter>(Ptr & ~0x3); + } + + friend class IdentifierResolver; + + void incrementSlowCase(); + public: + iterator() : Ptr(0) {} + + NamedDecl *operator*() const { + if (isIterator()) + return *getIterator(); + else + return reinterpret_cast<NamedDecl*>(Ptr); + } + + bool operator==(const iterator &RHS) const { + return Ptr == RHS.Ptr; + } + bool operator!=(const iterator &RHS) const { + return Ptr != RHS.Ptr; + } + + // Preincrement. + iterator& operator++() { + if (!isIterator()) // common case. + Ptr = 0; + else + incrementSlowCase(); + return *this; + } + + uintptr_t getAsOpaqueValue() const { return Ptr; } + + static iterator getFromOpaqueValue(uintptr_t P) { + iterator Result; + Result.Ptr = P; + return Result; + } + }; + + /// begin - Returns an iterator for decls with the name 'Name'. + iterator begin(DeclarationName Name); + + /// end - Returns an iterator that has 'finished'. + iterator end() { + return iterator(); + } + + /// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true + /// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns + /// true if 'D' belongs to the given declaration context. + /// + /// \param AllowInlineNamespace If \c true, we are checking whether a prior + /// declaration is in scope in a declaration that requires a prior + /// declaration (because it is either explicitly qualified or is a + /// template instantiation or specialization). In this case, a + /// declaration is in scope if it's in the inline namespace set of the + /// context. + bool isDeclInScope(Decl *D, DeclContext *Ctx, Scope *S = nullptr, + bool AllowInlineNamespace = false) const; + + /// AddDecl - Link the decl to its shadowed decl chain. + void AddDecl(NamedDecl *D); + + /// RemoveDecl - Unlink the decl from its shadowed decl chain. + /// The decl must already be part of the decl chain. + void RemoveDecl(NamedDecl *D); + + /// \brief Insert the given declaration after the given iterator + /// position. + void InsertDeclAfter(iterator Pos, NamedDecl *D); + + /// \brief Try to add the given declaration to the top level scope, if it + /// (or a redeclaration of it) hasn't already been added. + /// + /// \param D The externally-produced declaration to add. + /// + /// \param Name The name of the externally-produced declaration. + /// + /// \returns true if the declaration was added, false otherwise. + bool tryAddTopLevelDecl(NamedDecl *D, DeclarationName Name); + + explicit IdentifierResolver(Preprocessor &PP); + ~IdentifierResolver(); + +private: + const LangOptions &LangOpt; + Preprocessor &PP; + + class IdDeclInfoMap; + IdDeclInfoMap *IdDeclInfos; + + void updatingIdentifier(IdentifierInfo &II); + void readingIdentifier(IdentifierInfo &II); + + /// FETokenInfo contains a Decl pointer if lower bit == 0. + static inline bool isDeclPtr(void *Ptr) { + return (reinterpret_cast<uintptr_t>(Ptr) & 0x1) == 0; + } + + /// FETokenInfo contains a IdDeclInfo pointer if lower bit == 1. + static inline IdDeclInfo *toIdDeclInfo(void *Ptr) { + assert((reinterpret_cast<uintptr_t>(Ptr) & 0x1) == 1 + && "Ptr not a IdDeclInfo* !"); + return reinterpret_cast<IdDeclInfo*>( + reinterpret_cast<uintptr_t>(Ptr) & ~0x1 + ); + } +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Sema/Initialization.h b/contrib/llvm/tools/clang/include/clang/Sema/Initialization.h new file mode 100644 index 0000000..d4f57b7 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Sema/Initialization.h @@ -0,0 +1,1145 @@ +//===--- Initialization.h - Semantic Analysis for Initializers --*- 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 supporting data types for initialization of objects. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_SEMA_INITIALIZATION_H +#define LLVM_CLANG_SEMA_INITIALIZATION_H + +#include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" +#include "clang/AST/Type.h" +#include "clang/AST/UnresolvedSet.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Sema/Overload.h" +#include "clang/Sema/Ownership.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/SmallVector.h" +#include <cassert> + +namespace clang { + +class CXXBaseSpecifier; +class DeclaratorDecl; +class DeclaratorInfo; +class FieldDecl; +class FunctionDecl; +class ParmVarDecl; +class Sema; +class TypeLoc; +class VarDecl; +class ObjCMethodDecl; + +/// \brief Describes an entity that is being initialized. +class InitializedEntity { +public: + /// \brief Specifies the kind of entity being initialized. + enum EntityKind { + /// \brief The entity being initialized is a variable. + EK_Variable, + /// \brief The entity being initialized is a function parameter. + EK_Parameter, + /// \brief The entity being initialized is the result of a function call. + EK_Result, + /// \brief The entity being initialized is an exception object that + /// is being thrown. + EK_Exception, + /// \brief The entity being initialized is a non-static data member + /// subobject. + EK_Member, + /// \brief The entity being initialized is an element of an array. + EK_ArrayElement, + /// \brief The entity being initialized is an object (or array of + /// objects) allocated via new. + EK_New, + /// \brief The entity being initialized is a temporary object. + EK_Temporary, + /// \brief The entity being initialized is a base member subobject. + EK_Base, + /// \brief The initialization is being done by a delegating constructor. + EK_Delegating, + /// \brief The entity being initialized is an element of a vector. + /// or vector. + EK_VectorElement, + /// \brief The entity being initialized is a field of block descriptor for + /// the copied-in c++ object. + EK_BlockElement, + /// \brief The entity being initialized is the real or imaginary part of a + /// complex number. + EK_ComplexElement, + /// \brief The entity being initialized is the field that captures a + /// variable in a lambda. + EK_LambdaCapture, + /// \brief The entity being initialized is the initializer for a compound + /// literal. + EK_CompoundLiteralInit, + /// \brief The entity being implicitly initialized back to the formal + /// result type. + EK_RelatedResult, + /// \brief The entity being initialized is a function parameter; function + /// is member of group of audited CF APIs. + EK_Parameter_CF_Audited + + // Note: err_init_conversion_failed in DiagnosticSemaKinds.td uses this + // enum as an index for its first %select. When modifying this list, + // that diagnostic text needs to be updated as well. + }; + +private: + /// \brief The kind of entity being initialized. + EntityKind Kind; + + /// \brief If non-NULL, the parent entity in which this + /// initialization occurs. + const InitializedEntity *Parent; + + /// \brief The type of the object or reference being initialized. + QualType Type; + + /// \brief The mangling number for the next reference temporary to be created. + mutable unsigned ManglingNumber; + + struct LN { + /// \brief When Kind == EK_Result, EK_Exception, EK_New, the + /// location of the 'return', 'throw', or 'new' keyword, + /// respectively. When Kind == EK_Temporary, the location where + /// the temporary is being created. + unsigned Location; + + /// \brief Whether the entity being initialized may end up using the + /// named return value optimization (NRVO). + bool NRVO; + }; + + struct C { + /// \brief The name of the variable being captured by an EK_LambdaCapture. + IdentifierInfo *VarID; + + /// \brief The source location at which the capture occurs. + unsigned Location; + }; + + union { + /// \brief When Kind == EK_Variable, or EK_Member, the VarDecl or + /// FieldDecl, respectively. + DeclaratorDecl *VariableOrMember; + + /// \brief When Kind == EK_RelatedResult, the ObjectiveC method where + /// result type was implicitly changed to accommodate ARC semantics. + ObjCMethodDecl *MethodDecl; + + /// \brief When Kind == EK_Parameter, the ParmVarDecl, with the + /// low bit indicating whether the parameter is "consumed". + uintptr_t Parameter; + + /// \brief When Kind == EK_Temporary or EK_CompoundLiteralInit, the type + /// source information for the temporary. + TypeSourceInfo *TypeInfo; + + struct LN LocAndNRVO; + + /// \brief When Kind == EK_Base, the base specifier that provides the + /// base class. The lower bit specifies whether the base is an inherited + /// virtual base. + uintptr_t Base; + + /// \brief When Kind == EK_ArrayElement, EK_VectorElement, or + /// EK_ComplexElement, the index of the array or vector element being + /// initialized. + unsigned Index; + + struct C Capture; + }; + + InitializedEntity() : ManglingNumber(0) {} + + /// \brief Create the initialization entity for a variable. + InitializedEntity(VarDecl *Var) + : Kind(EK_Variable), Parent(nullptr), Type(Var->getType()), + ManglingNumber(0), VariableOrMember(Var) { } + + /// \brief Create the initialization entity for the result of a + /// function, throwing an object, performing an explicit cast, or + /// initializing a parameter for which there is no declaration. + InitializedEntity(EntityKind Kind, SourceLocation Loc, QualType Type, + bool NRVO = false) + : Kind(Kind), Parent(nullptr), Type(Type), ManglingNumber(0) + { + LocAndNRVO.Location = Loc.getRawEncoding(); + LocAndNRVO.NRVO = NRVO; + } + + /// \brief Create the initialization entity for a member subobject. + InitializedEntity(FieldDecl *Member, const InitializedEntity *Parent) + : Kind(EK_Member), Parent(Parent), Type(Member->getType()), + ManglingNumber(0), VariableOrMember(Member) { } + + /// \brief Create the initialization entity for an array element. + InitializedEntity(ASTContext &Context, unsigned Index, + const InitializedEntity &Parent); + + /// \brief Create the initialization entity for a lambda capture. + InitializedEntity(IdentifierInfo *VarID, QualType FieldType, SourceLocation Loc) + : Kind(EK_LambdaCapture), Parent(nullptr), Type(FieldType), + ManglingNumber(0) + { + Capture.VarID = VarID; + Capture.Location = Loc.getRawEncoding(); + } + +public: + /// \brief Create the initialization entity for a variable. + static InitializedEntity InitializeVariable(VarDecl *Var) { + return InitializedEntity(Var); + } + + /// \brief Create the initialization entity for a parameter. + static InitializedEntity InitializeParameter(ASTContext &Context, + ParmVarDecl *Parm) { + return InitializeParameter(Context, Parm, Parm->getType()); + } + + /// \brief Create the initialization entity for a parameter, but use + /// another type. + static InitializedEntity InitializeParameter(ASTContext &Context, + ParmVarDecl *Parm, + QualType Type) { + bool Consumed = (Context.getLangOpts().ObjCAutoRefCount && + Parm->hasAttr<NSConsumedAttr>()); + + InitializedEntity Entity; + Entity.Kind = EK_Parameter; + Entity.Type = + Context.getVariableArrayDecayedType(Type.getUnqualifiedType()); + Entity.Parent = nullptr; + Entity.Parameter + = (static_cast<uintptr_t>(Consumed) | reinterpret_cast<uintptr_t>(Parm)); + return Entity; + } + + /// \brief Create the initialization entity for a parameter that is + /// only known by its type. + static InitializedEntity InitializeParameter(ASTContext &Context, + QualType Type, + bool Consumed) { + InitializedEntity Entity; + Entity.Kind = EK_Parameter; + Entity.Type = Context.getVariableArrayDecayedType(Type); + Entity.Parent = nullptr; + Entity.Parameter = (Consumed); + return Entity; + } + + /// \brief Create the initialization entity for the result of a function. + static InitializedEntity InitializeResult(SourceLocation ReturnLoc, + QualType Type, bool NRVO) { + return InitializedEntity(EK_Result, ReturnLoc, Type, NRVO); + } + + static InitializedEntity InitializeBlock(SourceLocation BlockVarLoc, + QualType Type, bool NRVO) { + return InitializedEntity(EK_BlockElement, BlockVarLoc, Type, NRVO); + } + + /// \brief Create the initialization entity for an exception object. + static InitializedEntity InitializeException(SourceLocation ThrowLoc, + QualType Type, bool NRVO) { + return InitializedEntity(EK_Exception, ThrowLoc, Type, NRVO); + } + + /// \brief Create the initialization entity for an object allocated via new. + static InitializedEntity InitializeNew(SourceLocation NewLoc, QualType Type) { + return InitializedEntity(EK_New, NewLoc, Type); + } + + /// \brief Create the initialization entity for a temporary. + static InitializedEntity InitializeTemporary(QualType Type) { + InitializedEntity Result(EK_Temporary, SourceLocation(), Type); + Result.TypeInfo = nullptr; + return Result; + } + + /// \brief Create the initialization entity for a temporary. + static InitializedEntity InitializeTemporary(TypeSourceInfo *TypeInfo) { + InitializedEntity Result(EK_Temporary, SourceLocation(), + TypeInfo->getType()); + Result.TypeInfo = TypeInfo; + return Result; + } + + /// \brief Create the initialization entity for a related result. + static InitializedEntity InitializeRelatedResult(ObjCMethodDecl *MD, + QualType Type) { + InitializedEntity Result(EK_RelatedResult, SourceLocation(), Type); + Result.MethodDecl = MD; + return Result; + } + + + /// \brief Create the initialization entity for a base class subobject. + static InitializedEntity InitializeBase(ASTContext &Context, + const CXXBaseSpecifier *Base, + bool IsInheritedVirtualBase); + + /// \brief Create the initialization entity for a delegated constructor. + static InitializedEntity InitializeDelegation(QualType Type) { + return InitializedEntity(EK_Delegating, SourceLocation(), Type); + } + + /// \brief Create the initialization entity for a member subobject. + static InitializedEntity + InitializeMember(FieldDecl *Member, + const InitializedEntity *Parent = nullptr) { + return InitializedEntity(Member, Parent); + } + + /// \brief Create the initialization entity for a member subobject. + static InitializedEntity + InitializeMember(IndirectFieldDecl *Member, + const InitializedEntity *Parent = nullptr) { + return InitializedEntity(Member->getAnonField(), Parent); + } + + /// \brief Create the initialization entity for an array element. + static InitializedEntity InitializeElement(ASTContext &Context, + unsigned Index, + const InitializedEntity &Parent) { + return InitializedEntity(Context, Index, Parent); + } + + /// \brief Create the initialization entity for a lambda capture. + static InitializedEntity InitializeLambdaCapture(IdentifierInfo *VarID, + QualType FieldType, + SourceLocation Loc) { + return InitializedEntity(VarID, FieldType, Loc); + } + + /// \brief Create the entity for a compound literal initializer. + static InitializedEntity InitializeCompoundLiteralInit(TypeSourceInfo *TSI) { + InitializedEntity Result(EK_CompoundLiteralInit, SourceLocation(), + TSI->getType()); + Result.TypeInfo = TSI; + return Result; + } + + + /// \brief Determine the kind of initialization. + EntityKind getKind() const { return Kind; } + + /// \brief Retrieve the parent of the entity being initialized, when + /// the initialization itself is occurring within the context of a + /// larger initialization. + const InitializedEntity *getParent() const { return Parent; } + + /// \brief Retrieve type being initialized. + QualType getType() const { return Type; } + + /// \brief Retrieve complete type-source information for the object being + /// constructed, if known. + TypeSourceInfo *getTypeSourceInfo() const { + if (Kind == EK_Temporary || Kind == EK_CompoundLiteralInit) + return TypeInfo; + + return nullptr; + } + + /// \brief Retrieve the name of the entity being initialized. + DeclarationName getName() const; + + /// \brief Retrieve the variable, parameter, or field being + /// initialized. + DeclaratorDecl *getDecl() const; + + /// \brief Retrieve the ObjectiveC method being initialized. + ObjCMethodDecl *getMethodDecl() const { return MethodDecl; } + + /// \brief Determine whether this initialization allows the named return + /// value optimization, which also applies to thrown objects. + bool allowsNRVO() const; + + bool isParameterKind() const { + return (getKind() == EK_Parameter || + getKind() == EK_Parameter_CF_Audited); + } + /// \brief Determine whether this initialization consumes the + /// parameter. + bool isParameterConsumed() const { + assert(isParameterKind() && "Not a parameter"); + return (Parameter & 1); + } + + /// \brief Retrieve the base specifier. + const CXXBaseSpecifier *getBaseSpecifier() const { + assert(getKind() == EK_Base && "Not a base specifier"); + return reinterpret_cast<const CXXBaseSpecifier *>(Base & ~0x1); + } + + /// \brief Return whether the base is an inherited virtual base. + bool isInheritedVirtualBase() const { + assert(getKind() == EK_Base && "Not a base specifier"); + return Base & 0x1; + } + + /// \brief Determine the location of the 'return' keyword when initializing + /// the result of a function call. + SourceLocation getReturnLoc() const { + assert(getKind() == EK_Result && "No 'return' location!"); + return SourceLocation::getFromRawEncoding(LocAndNRVO.Location); + } + + /// \brief Determine the location of the 'throw' keyword when initializing + /// an exception object. + SourceLocation getThrowLoc() const { + assert(getKind() == EK_Exception && "No 'throw' location!"); + return SourceLocation::getFromRawEncoding(LocAndNRVO.Location); + } + + /// \brief If this is an array, vector, or complex number element, get the + /// element's index. + unsigned getElementIndex() const { + assert(getKind() == EK_ArrayElement || getKind() == EK_VectorElement || + getKind() == EK_ComplexElement); + return Index; + } + /// \brief If this is already the initializer for an array or vector + /// element, sets the element index. + void setElementIndex(unsigned Index) { + assert(getKind() == EK_ArrayElement || getKind() == EK_VectorElement || + getKind() == EK_ComplexElement); + this->Index = Index; + } + /// \brief For a lambda capture, return the capture's name. + StringRef getCapturedVarName() const { + assert(getKind() == EK_LambdaCapture && "Not a lambda capture!"); + return Capture.VarID->getName(); + } + /// \brief Determine the location of the capture when initializing + /// field from a captured variable in a lambda. + SourceLocation getCaptureLoc() const { + assert(getKind() == EK_LambdaCapture && "Not a lambda capture!"); + return SourceLocation::getFromRawEncoding(Capture.Location); + } + + void setParameterCFAudited() { + Kind = EK_Parameter_CF_Audited; + } + + unsigned allocateManglingNumber() const { return ++ManglingNumber; } + + /// Dump a representation of the initialized entity to standard error, + /// for debugging purposes. + void dump() const; + +private: + unsigned dumpImpl(raw_ostream &OS) const; +}; + +/// \brief Describes the kind of initialization being performed, along with +/// location information for tokens related to the initialization (equal sign, +/// parentheses). +class InitializationKind { +public: + /// \brief The kind of initialization being performed. + enum InitKind { + IK_Direct, ///< Direct initialization + IK_DirectList, ///< Direct list-initialization + IK_Copy, ///< Copy initialization + IK_Default, ///< Default initialization + IK_Value ///< Value initialization + }; + +private: + /// \brief The context of the initialization. + enum InitContext { + IC_Normal, ///< Normal context + IC_ExplicitConvs, ///< Normal context, but allows explicit conversion funcs + IC_Implicit, ///< Implicit context (value initialization) + IC_StaticCast, ///< Static cast context + IC_CStyleCast, ///< C-style cast context + IC_FunctionalCast ///< Functional cast context + }; + + /// \brief The kind of initialization being performed. + InitKind Kind : 8; + + /// \brief The context of the initialization. + InitContext Context : 8; + + /// \brief The source locations involved in the initialization. + SourceLocation Locations[3]; + + InitializationKind(InitKind Kind, InitContext Context, SourceLocation Loc1, + SourceLocation Loc2, SourceLocation Loc3) + : Kind(Kind), Context(Context) + { + Locations[0] = Loc1; + Locations[1] = Loc2; + Locations[2] = Loc3; + } + +public: + /// \brief Create a direct initialization. + static InitializationKind CreateDirect(SourceLocation InitLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc) { + return InitializationKind(IK_Direct, IC_Normal, + InitLoc, LParenLoc, RParenLoc); + } + + static InitializationKind CreateDirectList(SourceLocation InitLoc) { + return InitializationKind(IK_DirectList, IC_Normal, + InitLoc, InitLoc, InitLoc); + } + + /// \brief Create a direct initialization due to a cast that isn't a C-style + /// or functional cast. + static InitializationKind CreateCast(SourceRange TypeRange) { + return InitializationKind(IK_Direct, IC_StaticCast, TypeRange.getBegin(), + TypeRange.getBegin(), TypeRange.getEnd()); + } + + /// \brief Create a direct initialization for a C-style cast. + static InitializationKind CreateCStyleCast(SourceLocation StartLoc, + SourceRange TypeRange, + bool InitList) { + // C++ cast syntax doesn't permit init lists, but C compound literals are + // exactly that. + return InitializationKind(InitList ? IK_DirectList : IK_Direct, + IC_CStyleCast, StartLoc, TypeRange.getBegin(), + TypeRange.getEnd()); + } + + /// \brief Create a direct initialization for a functional cast. + static InitializationKind CreateFunctionalCast(SourceRange TypeRange, + bool InitList) { + return InitializationKind(InitList ? IK_DirectList : IK_Direct, + IC_FunctionalCast, TypeRange.getBegin(), + TypeRange.getBegin(), TypeRange.getEnd()); + } + + /// \brief Create a copy initialization. + static InitializationKind CreateCopy(SourceLocation InitLoc, + SourceLocation EqualLoc, + bool AllowExplicitConvs = false) { + return InitializationKind(IK_Copy, + AllowExplicitConvs? IC_ExplicitConvs : IC_Normal, + InitLoc, EqualLoc, EqualLoc); + } + + /// \brief Create a default initialization. + static InitializationKind CreateDefault(SourceLocation InitLoc) { + return InitializationKind(IK_Default, IC_Normal, InitLoc, InitLoc, InitLoc); + } + + /// \brief Create a value initialization. + static InitializationKind CreateValue(SourceLocation InitLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc, + bool isImplicit = false) { + return InitializationKind(IK_Value, isImplicit ? IC_Implicit : IC_Normal, + InitLoc, LParenLoc, RParenLoc); + } + + /// \brief Determine the initialization kind. + InitKind getKind() const { + return Kind; + } + + /// \brief Determine whether this initialization is an explicit cast. + bool isExplicitCast() const { + return Context >= IC_StaticCast; + } + + /// \brief Determine whether this initialization is a C-style cast. + bool isCStyleOrFunctionalCast() const { + return Context >= IC_CStyleCast; + } + + /// \brief Determine whether this is a C-style cast. + bool isCStyleCast() const { + return Context == IC_CStyleCast; + } + + /// \brief Determine whether this is a functional-style cast. + bool isFunctionalCast() const { + return Context == IC_FunctionalCast; + } + + /// \brief Determine whether this initialization is an implicit + /// value-initialization, e.g., as occurs during aggregate + /// initialization. + bool isImplicitValueInit() const { return Context == IC_Implicit; } + + /// \brief Retrieve the location at which initialization is occurring. + SourceLocation getLocation() const { return Locations[0]; } + + /// \brief Retrieve the source range that covers the initialization. + SourceRange getRange() const { + return SourceRange(Locations[0], Locations[2]); + } + + /// \brief Retrieve the location of the equal sign for copy initialization + /// (if present). + SourceLocation getEqualLoc() const { + assert(Kind == IK_Copy && "Only copy initialization has an '='"); + return Locations[1]; + } + + bool isCopyInit() const { return Kind == IK_Copy; } + + /// \brief Retrieve whether this initialization allows the use of explicit + /// constructors. + bool AllowExplicit() const { return !isCopyInit(); } + + /// \brief Retrieve whether this initialization allows the use of explicit + /// conversion functions when binding a reference. If the reference is the + /// first parameter in a copy or move constructor, such conversions are + /// permitted even though we are performing copy-initialization. + bool allowExplicitConversionFunctionsInRefBinding() const { + return !isCopyInit() || Context == IC_ExplicitConvs; + } + + /// \brief Retrieve the source range containing the locations of the open + /// and closing parentheses for value and direct initializations. + SourceRange getParenRange() const { + assert((Kind == IK_Direct || Kind == IK_Value) && + "Only direct- and value-initialization have parentheses"); + return SourceRange(Locations[1], Locations[2]); + } +}; + +/// \brief Describes the sequence of initializations required to initialize +/// a given object or reference with a set of arguments. +class InitializationSequence { +public: + /// \brief Describes the kind of initialization sequence computed. + enum SequenceKind { + /// \brief A failed initialization sequence. The failure kind tells what + /// happened. + FailedSequence = 0, + + /// \brief A dependent initialization, which could not be + /// type-checked due to the presence of dependent types or + /// dependently-typed expressions. + DependentSequence, + + /// \brief A normal sequence. + NormalSequence + }; + + /// \brief Describes the kind of a particular step in an initialization + /// sequence. + enum StepKind { + /// \brief Resolve the address of an overloaded function to a specific + /// function declaration. + SK_ResolveAddressOfOverloadedFunction, + /// \brief Perform a derived-to-base cast, producing an rvalue. + SK_CastDerivedToBaseRValue, + /// \brief Perform a derived-to-base cast, producing an xvalue. + SK_CastDerivedToBaseXValue, + /// \brief Perform a derived-to-base cast, producing an lvalue. + SK_CastDerivedToBaseLValue, + /// \brief Reference binding to an lvalue. + SK_BindReference, + /// \brief Reference binding to a temporary. + SK_BindReferenceToTemporary, + /// \brief An optional copy of a temporary object to another + /// temporary object, which is permitted (but not required) by + /// C++98/03 but not C++0x. + SK_ExtraneousCopyToTemporary, + /// \brief Perform a user-defined conversion, either via a conversion + /// function or via a constructor. + SK_UserConversion, + /// \brief Perform a qualification conversion, producing an rvalue. + SK_QualificationConversionRValue, + /// \brief Perform a qualification conversion, producing an xvalue. + SK_QualificationConversionXValue, + /// \brief Perform a qualification conversion, producing an lvalue. + SK_QualificationConversionLValue, + /// \brief Perform a conversion adding _Atomic to a type. + SK_AtomicConversion, + /// \brief Perform a load from a glvalue, producing an rvalue. + SK_LValueToRValue, + /// \brief Perform an implicit conversion sequence. + SK_ConversionSequence, + /// \brief Perform an implicit conversion sequence without narrowing. + SK_ConversionSequenceNoNarrowing, + /// \brief Perform list-initialization without a constructor. + SK_ListInitialization, + /// \brief Unwrap the single-element initializer list for a reference. + SK_UnwrapInitList, + /// \brief Rewrap the single-element initializer list for a reference. + SK_RewrapInitList, + /// \brief Perform initialization via a constructor. + SK_ConstructorInitialization, + /// \brief Perform initialization via a constructor, taking arguments from + /// a single InitListExpr. + SK_ConstructorInitializationFromList, + /// \brief Zero-initialize the object + SK_ZeroInitialization, + /// \brief C assignment + SK_CAssignment, + /// \brief Initialization by string + SK_StringInit, + /// \brief An initialization that "converts" an Objective-C object + /// (not a point to an object) to another Objective-C object type. + SK_ObjCObjectConversion, + /// \brief Array initialization (from an array rvalue). + /// This is a GNU C extension. + SK_ArrayInit, + /// \brief Array initialization from a parenthesized initializer list. + /// This is a GNU C++ extension. + SK_ParenthesizedArrayInit, + /// \brief Pass an object by indirect copy-and-restore. + SK_PassByIndirectCopyRestore, + /// \brief Pass an object by indirect restore. + SK_PassByIndirectRestore, + /// \brief Produce an Objective-C object pointer. + SK_ProduceObjCObject, + /// \brief Construct a std::initializer_list from an initializer list. + SK_StdInitializerList, + /// \brief Perform initialization via a constructor taking a single + /// std::initializer_list argument. + SK_StdInitializerListConstructorCall, + /// \brief Initialize an OpenCL sampler from an integer. + SK_OCLSamplerInit, + /// \brief Passing zero to a function where OpenCL event_t is expected. + SK_OCLZeroEvent + }; + + /// \brief A single step in the initialization sequence. + class Step { + public: + /// \brief The kind of conversion or initialization step we are taking. + StepKind Kind; + + // \brief The type that results from this initialization. + QualType Type; + + struct F { + bool HadMultipleCandidates; + FunctionDecl *Function; + DeclAccessPair FoundDecl; + }; + + union { + /// \brief When Kind == SK_ResolvedOverloadedFunction or Kind == + /// SK_UserConversion, the function that the expression should be + /// resolved to or the conversion function to call, respectively. + /// When Kind == SK_ConstructorInitialization or SK_ListConstruction, + /// the constructor to be called. + /// + /// Always a FunctionDecl, plus a Boolean flag telling if it was + /// selected from an overloaded set having size greater than 1. + /// For conversion decls, the naming class is the source type. + /// For construct decls, the naming class is the target type. + struct F Function; + + /// \brief When Kind = SK_ConversionSequence, the implicit conversion + /// sequence. + ImplicitConversionSequence *ICS; + + /// \brief When Kind = SK_RewrapInitList, the syntactic form of the + /// wrapping list. + InitListExpr *WrappingSyntacticList; + }; + + void Destroy(); + }; + +private: + /// \brief The kind of initialization sequence computed. + enum SequenceKind SequenceKind; + + /// \brief Steps taken by this initialization. + SmallVector<Step, 4> Steps; + +public: + /// \brief Describes why initialization failed. + enum FailureKind { + /// \brief Too many initializers provided for a reference. + FK_TooManyInitsForReference, + /// \brief Array must be initialized with an initializer list. + FK_ArrayNeedsInitList, + /// \brief Array must be initialized with an initializer list or a + /// string literal. + FK_ArrayNeedsInitListOrStringLiteral, + /// \brief Array must be initialized with an initializer list or a + /// wide string literal. + FK_ArrayNeedsInitListOrWideStringLiteral, + /// \brief Initializing a wide char array with narrow string literal. + FK_NarrowStringIntoWideCharArray, + /// \brief Initializing char array with wide string literal. + FK_WideStringIntoCharArray, + /// \brief Initializing wide char array with incompatible wide string + /// literal. + FK_IncompatWideStringIntoWideChar, + /// \brief Array type mismatch. + FK_ArrayTypeMismatch, + /// \brief Non-constant array initializer + FK_NonConstantArrayInit, + /// \brief Cannot resolve the address of an overloaded function. + FK_AddressOfOverloadFailed, + /// \brief Overloading due to reference initialization failed. + FK_ReferenceInitOverloadFailed, + /// \brief Non-const lvalue reference binding to a temporary. + FK_NonConstLValueReferenceBindingToTemporary, + /// \brief Non-const lvalue reference binding to an lvalue of unrelated + /// type. + FK_NonConstLValueReferenceBindingToUnrelated, + /// \brief Rvalue reference binding to an lvalue. + FK_RValueReferenceBindingToLValue, + /// \brief Reference binding drops qualifiers. + FK_ReferenceInitDropsQualifiers, + /// \brief Reference binding failed. + FK_ReferenceInitFailed, + /// \brief Implicit conversion failed. + FK_ConversionFailed, + /// \brief Implicit conversion failed. + FK_ConversionFromPropertyFailed, + /// \brief Too many initializers for scalar + FK_TooManyInitsForScalar, + /// \brief Reference initialization from an initializer list + FK_ReferenceBindingToInitList, + /// \brief Initialization of some unused destination type with an + /// initializer list. + FK_InitListBadDestinationType, + /// \brief Overloading for a user-defined conversion failed. + FK_UserConversionOverloadFailed, + /// \brief Overloading for initialization by constructor failed. + FK_ConstructorOverloadFailed, + /// \brief Overloading for list-initialization by constructor failed. + FK_ListConstructorOverloadFailed, + /// \brief Default-initialization of a 'const' object. + FK_DefaultInitOfConst, + /// \brief Initialization of an incomplete type. + FK_Incomplete, + /// \brief Variable-length array must not have an initializer. + FK_VariableLengthArrayHasInitializer, + /// \brief List initialization failed at some point. + FK_ListInitializationFailed, + /// \brief Initializer has a placeholder type which cannot be + /// resolved by initialization. + FK_PlaceholderType, + /// \brief Trying to take the address of a function that doesn't support + /// having its address taken. + FK_AddressOfUnaddressableFunction, + /// \brief List-copy-initialization chose an explicit constructor. + FK_ExplicitConstructor + }; + +private: + /// \brief The reason why initialization failed. + FailureKind Failure; + + /// \brief The failed result of overload resolution. + OverloadingResult FailedOverloadResult; + + /// \brief The candidate set created when initialization failed. + OverloadCandidateSet FailedCandidateSet; + + /// \brief The incomplete type that caused a failure. + QualType FailedIncompleteType; + + /// \brief The fixit that needs to be applied to make this initialization + /// succeed. + std::string ZeroInitializationFixit; + SourceLocation ZeroInitializationFixitLoc; + +public: + /// \brief Call for initializations are invalid but that would be valid + /// zero initialzations if Fixit was applied. + void SetZeroInitializationFixit(const std::string& Fixit, SourceLocation L) { + ZeroInitializationFixit = Fixit; + ZeroInitializationFixitLoc = L; + } + +private: + + /// \brief Prints a follow-up note that highlights the location of + /// the initialized entity, if it's remote. + void PrintInitLocationNote(Sema &S, const InitializedEntity &Entity); + +public: + /// \brief Try to perform initialization of the given entity, creating a + /// record of the steps required to perform the initialization. + /// + /// The generated initialization sequence will either contain enough + /// information to diagnose + /// + /// \param S the semantic analysis object. + /// + /// \param Entity the entity being initialized. + /// + /// \param Kind the kind of initialization being performed. + /// + /// \param Args the argument(s) provided for initialization. + /// + /// \param TopLevelOfInitList true if we are initializing from an expression + /// at the top level inside an initializer list. This disallows + /// narrowing conversions in C++11 onwards. + InitializationSequence(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + MultiExprArg Args, + bool TopLevelOfInitList = false); + void InitializeFrom(Sema &S, const InitializedEntity &Entity, + const InitializationKind &Kind, MultiExprArg Args, + bool TopLevelOfInitList); + + ~InitializationSequence(); + + /// \brief Perform the actual initialization of the given entity based on + /// the computed initialization sequence. + /// + /// \param S the semantic analysis object. + /// + /// \param Entity the entity being initialized. + /// + /// \param Kind the kind of initialization being performed. + /// + /// \param Args the argument(s) provided for initialization, ownership of + /// which is transferred into the routine. + /// + /// \param ResultType if non-NULL, will be set to the type of the + /// initialized object, which is the type of the declaration in most + /// cases. However, when the initialized object is a variable of + /// incomplete array type and the initializer is an initializer + /// list, this type will be set to the completed array type. + /// + /// \returns an expression that performs the actual object initialization, if + /// the initialization is well-formed. Otherwise, emits diagnostics + /// and returns an invalid expression. + ExprResult Perform(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + MultiExprArg Args, + QualType *ResultType = nullptr); + + /// \brief Diagnose an potentially-invalid initialization sequence. + /// + /// \returns true if the initialization sequence was ill-formed, + /// false otherwise. + bool Diagnose(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + ArrayRef<Expr *> Args); + + /// \brief Determine the kind of initialization sequence computed. + enum SequenceKind getKind() const { return SequenceKind; } + + /// \brief Set the kind of sequence computed. + void setSequenceKind(enum SequenceKind SK) { SequenceKind = SK; } + + /// \brief Determine whether the initialization sequence is valid. + explicit operator bool() const { return !Failed(); } + + /// \brief Determine whether the initialization sequence is invalid. + bool Failed() const { return SequenceKind == FailedSequence; } + + typedef SmallVectorImpl<Step>::const_iterator step_iterator; + step_iterator step_begin() const { return Steps.begin(); } + step_iterator step_end() const { return Steps.end(); } + + /// \brief Determine whether this initialization is a direct reference + /// binding (C++ [dcl.init.ref]). + bool isDirectReferenceBinding() const; + + /// \brief Determine whether this initialization failed due to an ambiguity. + bool isAmbiguous() const; + + /// \brief Determine whether this initialization is direct call to a + /// constructor. + bool isConstructorInitialization() const; + + /// \brief Returns whether the last step in this initialization sequence is a + /// narrowing conversion, defined by C++0x [dcl.init.list]p7. + /// + /// If this function returns true, *isInitializerConstant will be set to + /// describe whether *Initializer was a constant expression. If + /// *isInitializerConstant is set to true, *ConstantValue will be set to the + /// evaluated value of *Initializer. + bool endsWithNarrowing(ASTContext &Ctx, const Expr *Initializer, + bool *isInitializerConstant, + APValue *ConstantValue) const; + + /// \brief Add a new step in the initialization that resolves the address + /// of an overloaded function to a specific function declaration. + /// + /// \param Function the function to which the overloaded function reference + /// resolves. + void AddAddressOverloadResolutionStep(FunctionDecl *Function, + DeclAccessPair Found, + bool HadMultipleCandidates); + + /// \brief Add a new step in the initialization that performs a derived-to- + /// base cast. + /// + /// \param BaseType the base type to which we will be casting. + /// + /// \param Category Indicates whether the result will be treated as an + /// rvalue, an xvalue, or an lvalue. + void AddDerivedToBaseCastStep(QualType BaseType, + ExprValueKind Category); + + /// \brief Add a new step binding a reference to an object. + /// + /// \param BindingTemporary True if we are binding a reference to a temporary + /// object (thereby extending its lifetime); false if we are binding to an + /// lvalue or an lvalue treated as an rvalue. + void AddReferenceBindingStep(QualType T, bool BindingTemporary); + + /// \brief Add a new step that makes an extraneous copy of the input + /// to a temporary of the same class type. + /// + /// This extraneous copy only occurs during reference binding in + /// C++98/03, where we are permitted (but not required) to introduce + /// an extra copy. At a bare minimum, we must check that we could + /// call the copy constructor, and produce a diagnostic if the copy + /// constructor is inaccessible or no copy constructor matches. + // + /// \param T The type of the temporary being created. + void AddExtraneousCopyToTemporary(QualType T); + + /// \brief Add a new step invoking a conversion function, which is either + /// a constructor or a conversion function. + void AddUserConversionStep(FunctionDecl *Function, + DeclAccessPair FoundDecl, + QualType T, + bool HadMultipleCandidates); + + /// \brief Add a new step that performs a qualification conversion to the + /// given type. + void AddQualificationConversionStep(QualType Ty, + ExprValueKind Category); + + /// \brief Add a new step that performs conversion from non-atomic to atomic + /// type. + void AddAtomicConversionStep(QualType Ty); + + /// \brief Add a new step that performs a load of the given type. + /// + /// Although the term "LValueToRValue" is conventional, this applies to both + /// lvalues and xvalues. + void AddLValueToRValueStep(QualType Ty); + + /// \brief Add a new step that applies an implicit conversion sequence. + void AddConversionSequenceStep(const ImplicitConversionSequence &ICS, + QualType T, bool TopLevelOfInitList = false); + + /// \brief Add a list-initialization step. + void AddListInitializationStep(QualType T); + + /// \brief Add a constructor-initialization step. + /// + /// \param FromInitList The constructor call is syntactically an initializer + /// list. + /// \param AsInitList The constructor is called as an init list constructor. + void AddConstructorInitializationStep(CXXConstructorDecl *Constructor, + AccessSpecifier Access, + QualType T, + bool HadMultipleCandidates, + bool FromInitList, bool AsInitList); + + /// \brief Add a zero-initialization step. + void AddZeroInitializationStep(QualType T); + + /// \brief Add a C assignment step. + // + // FIXME: It isn't clear whether this should ever be needed; + // ideally, we would handle everything needed in C in the common + // path. However, that isn't the case yet. + void AddCAssignmentStep(QualType T); + + /// \brief Add a string init step. + void AddStringInitStep(QualType T); + + /// \brief Add an Objective-C object conversion step, which is + /// always a no-op. + void AddObjCObjectConversionStep(QualType T); + + /// \brief Add an array initialization step. + void AddArrayInitStep(QualType T); + + /// \brief Add a parenthesized array initialization step. + void AddParenthesizedArrayInitStep(QualType T); + + /// \brief Add a step to pass an object by indirect copy-restore. + void AddPassByIndirectCopyRestoreStep(QualType T, bool shouldCopy); + + /// \brief Add a step to "produce" an Objective-C object (by + /// retaining it). + void AddProduceObjCObjectStep(QualType T); + + /// \brief Add a step to construct a std::initializer_list object from an + /// initializer list. + void AddStdInitializerListConstructionStep(QualType T); + + /// \brief Add a step to initialize an OpenCL sampler from an integer + /// constant. + void AddOCLSamplerInitStep(QualType T); + + /// \brief Add a step to initialize an OpenCL event_t from a NULL + /// constant. + void AddOCLZeroEventStep(QualType T); + + /// \brief Add steps to unwrap a initializer list for a reference around a + /// single element and rewrap it at the end. + void RewrapReferenceInitList(QualType T, InitListExpr *Syntactic); + + /// \brief Note that this initialization sequence failed. + void SetFailed(FailureKind Failure) { + SequenceKind = FailedSequence; + this->Failure = Failure; + assert((Failure != FK_Incomplete || !FailedIncompleteType.isNull()) && + "Incomplete type failure requires a type!"); + } + + /// \brief Note that this initialization sequence failed due to failed + /// overload resolution. + void SetOverloadFailure(FailureKind Failure, OverloadingResult Result); + + /// \brief Retrieve a reference to the candidate set when overload + /// resolution fails. + OverloadCandidateSet &getFailedCandidateSet() { + return FailedCandidateSet; + } + + /// \brief Get the overloading result, for when the initialization + /// sequence failed due to a bad overload. + OverloadingResult getFailedOverloadResult() const { + return FailedOverloadResult; + } + + /// \brief Note that this initialization sequence failed due to an + /// incomplete type. + void setIncompleteTypeFailure(QualType IncompleteType) { + FailedIncompleteType = IncompleteType; + SetFailed(FK_Incomplete); + } + + /// \brief Determine why initialization failed. + FailureKind getFailureKind() const { + assert(Failed() && "Not an initialization failure!"); + return Failure; + } + + /// \brief Dump a representation of this initialization sequence to + /// the given stream, for debugging purposes. + void dump(raw_ostream &OS) const; + + /// \brief Dump a representation of this initialization sequence to + /// standard error, for debugging purposes. + void dump() const; +}; + +} // end namespace clang + +#endif // LLVM_CLANG_SEMA_INITIALIZATION_H diff --git a/contrib/llvm/tools/clang/include/clang/Sema/LocInfoType.h b/contrib/llvm/tools/clang/include/clang/Sema/LocInfoType.h new file mode 100644 index 0000000..63dfa72 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Sema/LocInfoType.h @@ -0,0 +1,62 @@ +//===--- LocInfoType.h - Parsed Type with Location Information---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the LocInfoType class, which holds a type and its +// source-location information. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_SEMA_LOCINFOTYPE_H +#define LLVM_CLANG_SEMA_LOCINFOTYPE_H + +#include "clang/AST/Type.h" + +namespace clang { + +class TypeSourceInfo; + +/// \brief Holds a QualType and a TypeSourceInfo* that came out of a declarator +/// parsing. +/// +/// LocInfoType is a "transient" type, only needed for passing to/from Parser +/// and Sema, when we want to preserve type source info for a parsed type. +/// It will not participate in the type system semantics in any way. +class LocInfoType : public Type { + enum { + // The last number that can fit in Type's TC. + // Avoids conflict with an existing Type class. + LocInfo = Type::TypeLast + 1 + }; + + TypeSourceInfo *DeclInfo; + + LocInfoType(QualType ty, TypeSourceInfo *TInfo) + : Type((TypeClass)LocInfo, ty, ty->isDependentType(), + ty->isInstantiationDependentType(), + ty->isVariablyModifiedType(), + ty->containsUnexpandedParameterPack()), + DeclInfo(TInfo) { + assert(getTypeClass() == (TypeClass)LocInfo && "LocInfo didn't fit in TC?"); + } + friend class Sema; + +public: + QualType getType() const { return getCanonicalTypeInternal(); } + TypeSourceInfo *getTypeSourceInfo() const { return DeclInfo; } + + void getAsStringInternal(std::string &Str, + const PrintingPolicy &Policy) const; + + static bool classof(const Type *T) { + return T->getTypeClass() == (TypeClass)LocInfo; + } +}; + +} // end namespace clang + +#endif // LLVM_CLANG_SEMA_LOCINFOTYPE_H diff --git a/contrib/llvm/tools/clang/include/clang/Sema/Lookup.h b/contrib/llvm/tools/clang/include/clang/Sema/Lookup.h new file mode 100644 index 0000000..87c40f0 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Sema/Lookup.h @@ -0,0 +1,760 @@ +//===--- Lookup.h - Classes for name lookup ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the LookupResult class, which is integral to +// Sema's name-lookup subsystem. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_LOOKUP_H +#define LLVM_CLANG_SEMA_LOOKUP_H + +#include "clang/AST/DeclCXX.h" +#include "clang/Sema/Sema.h" + +namespace clang { + +/// @brief Represents the results of name lookup. +/// +/// An instance of the LookupResult class captures the results of a +/// single name lookup, which can return no result (nothing found), +/// a single declaration, a set of overloaded functions, or an +/// ambiguity. Use the getKind() method to determine which of these +/// results occurred for a given lookup. +class LookupResult { +public: + enum LookupResultKind { + /// @brief No entity found met the criteria. + NotFound = 0, + + /// @brief No entity found met the criteria within the current + /// instantiation,, but there were dependent base classes of the + /// current instantiation that could not be searched. + NotFoundInCurrentInstantiation, + + /// @brief Name lookup found a single declaration that met the + /// criteria. getFoundDecl() will return this declaration. + Found, + + /// @brief Name lookup found a set of overloaded functions that + /// met the criteria. + FoundOverloaded, + + /// @brief Name lookup found an unresolvable value declaration + /// and cannot yet complete. This only happens in C++ dependent + /// contexts with dependent using declarations. + FoundUnresolvedValue, + + /// @brief Name lookup results in an ambiguity; use + /// getAmbiguityKind to figure out what kind of ambiguity + /// we have. + Ambiguous + }; + + enum AmbiguityKind { + /// Name lookup results in an ambiguity because multiple + /// entities that meet the lookup criteria were found in + /// subobjects of different types. For example: + /// @code + /// struct A { void f(int); } + /// struct B { void f(double); } + /// struct C : A, B { }; + /// void test(C c) { + /// c.f(0); // error: A::f and B::f come from subobjects of different + /// // types. overload resolution is not performed. + /// } + /// @endcode + AmbiguousBaseSubobjectTypes, + + /// Name lookup results in an ambiguity because multiple + /// nonstatic entities that meet the lookup criteria were found + /// in different subobjects of the same type. For example: + /// @code + /// struct A { int x; }; + /// struct B : A { }; + /// struct C : A { }; + /// struct D : B, C { }; + /// int test(D d) { + /// return d.x; // error: 'x' is found in two A subobjects (of B and C) + /// } + /// @endcode + AmbiguousBaseSubobjects, + + /// Name lookup results in an ambiguity because multiple definitions + /// of entity that meet the lookup criteria were found in different + /// declaration contexts. + /// @code + /// namespace A { + /// int i; + /// namespace B { int i; } + /// int test() { + /// using namespace B; + /// return i; // error 'i' is found in namespace A and A::B + /// } + /// } + /// @endcode + AmbiguousReference, + + /// Name lookup results in an ambiguity because an entity with a + /// tag name was hidden by an entity with an ordinary name from + /// a different context. + /// @code + /// namespace A { struct Foo {}; } + /// namespace B { void Foo(); } + /// namespace C { + /// using namespace A; + /// using namespace B; + /// } + /// void test() { + /// C::Foo(); // error: tag 'A::Foo' is hidden by an object in a + /// // different namespace + /// } + /// @endcode + AmbiguousTagHiding + }; + + /// A little identifier for flagging temporary lookup results. + enum TemporaryToken { + Temporary + }; + + typedef UnresolvedSetImpl::iterator iterator; + + LookupResult(Sema &SemaRef, const DeclarationNameInfo &NameInfo, + Sema::LookupNameKind LookupKind, + Sema::RedeclarationKind Redecl = Sema::NotForRedeclaration) + : ResultKind(NotFound), + Paths(nullptr), + NamingClass(nullptr), + SemaPtr(&SemaRef), + NameInfo(NameInfo), + LookupKind(LookupKind), + IDNS(0), + Redecl(Redecl != Sema::NotForRedeclaration), + HideTags(true), + Diagnose(Redecl == Sema::NotForRedeclaration), + AllowHidden(false), + Shadowed(false) + { + configure(); + } + + // TODO: consider whether this constructor should be restricted to take + // as input a const IndentifierInfo* (instead of Name), + // forcing other cases towards the constructor taking a DNInfo. + LookupResult(Sema &SemaRef, DeclarationName Name, + SourceLocation NameLoc, Sema::LookupNameKind LookupKind, + Sema::RedeclarationKind Redecl = Sema::NotForRedeclaration) + : ResultKind(NotFound), + Paths(nullptr), + NamingClass(nullptr), + SemaPtr(&SemaRef), + NameInfo(Name, NameLoc), + LookupKind(LookupKind), + IDNS(0), + Redecl(Redecl != Sema::NotForRedeclaration), + HideTags(true), + Diagnose(Redecl == Sema::NotForRedeclaration), + AllowHidden(false), + Shadowed(false) + { + configure(); + } + + /// Creates a temporary lookup result, initializing its core data + /// using the information from another result. Diagnostics are always + /// disabled. + LookupResult(TemporaryToken _, const LookupResult &Other) + : ResultKind(NotFound), + Paths(nullptr), + NamingClass(nullptr), + SemaPtr(Other.SemaPtr), + NameInfo(Other.NameInfo), + LookupKind(Other.LookupKind), + IDNS(Other.IDNS), + Redecl(Other.Redecl), + HideTags(Other.HideTags), + Diagnose(false), + AllowHidden(Other.AllowHidden), + Shadowed(false) + {} + + ~LookupResult() { + if (Diagnose) diagnose(); + if (Paths) deletePaths(Paths); + } + + /// Gets the name info to look up. + const DeclarationNameInfo &getLookupNameInfo() const { + return NameInfo; + } + + /// \brief Sets the name info to look up. + void setLookupNameInfo(const DeclarationNameInfo &NameInfo) { + this->NameInfo = NameInfo; + } + + /// Gets the name to look up. + DeclarationName getLookupName() const { + return NameInfo.getName(); + } + + /// \brief Sets the name to look up. + void setLookupName(DeclarationName Name) { + NameInfo.setName(Name); + } + + /// Gets the kind of lookup to perform. + Sema::LookupNameKind getLookupKind() const { + return LookupKind; + } + + /// True if this lookup is just looking for an existing declaration. + bool isForRedeclaration() const { + return Redecl; + } + + /// \brief Specify whether hidden declarations are visible, e.g., + /// for recovery reasons. + void setAllowHidden(bool AH) { + AllowHidden = AH; + } + + /// \brief Determine whether this lookup is permitted to see hidden + /// declarations, such as those in modules that have not yet been imported. + bool isHiddenDeclarationVisible(NamedDecl *ND) const { + return AllowHidden || + (isForRedeclaration() && ND->isExternallyVisible()); + } + + /// Sets whether tag declarations should be hidden by non-tag + /// declarations during resolution. The default is true. + void setHideTags(bool Hide) { + HideTags = Hide; + } + + bool isAmbiguous() const { + return getResultKind() == Ambiguous; + } + + /// Determines if this names a single result which is not an + /// unresolved value using decl. If so, it is safe to call + /// getFoundDecl(). + bool isSingleResult() const { + return getResultKind() == Found; + } + + /// Determines if the results are overloaded. + bool isOverloadedResult() const { + return getResultKind() == FoundOverloaded; + } + + bool isUnresolvableResult() const { + return getResultKind() == FoundUnresolvedValue; + } + + LookupResultKind getResultKind() const { + assert(sanity()); + return ResultKind; + } + + AmbiguityKind getAmbiguityKind() const { + assert(isAmbiguous()); + return Ambiguity; + } + + const UnresolvedSetImpl &asUnresolvedSet() const { + return Decls; + } + + iterator begin() const { return iterator(Decls.begin()); } + iterator end() const { return iterator(Decls.end()); } + + /// \brief Return true if no decls were found + bool empty() const { return Decls.empty(); } + + /// \brief Return the base paths structure that's associated with + /// these results, or null if none is. + CXXBasePaths *getBasePaths() const { + return Paths; + } + + /// \brief Determine whether the given declaration is visible to the + /// program. + static bool isVisible(Sema &SemaRef, NamedDecl *D) { + // If this declaration is not hidden, it's visible. + if (!D->isHidden()) + return true; + + // During template instantiation, we can refer to hidden declarations, if + // they were visible in any module along the path of instantiation. + return isVisibleSlow(SemaRef, D); + } + + /// \brief Retrieve the accepted (re)declaration of the given declaration, + /// if there is one. + NamedDecl *getAcceptableDecl(NamedDecl *D) const { + if (!D->isInIdentifierNamespace(IDNS)) + return nullptr; + + if (isVisible(getSema(), D) || isHiddenDeclarationVisible(D)) + return D; + + return getAcceptableDeclSlow(D); + } + +private: + static bool isVisibleSlow(Sema &SemaRef, NamedDecl *D); + NamedDecl *getAcceptableDeclSlow(NamedDecl *D) const; + +public: + /// \brief Returns the identifier namespace mask for this lookup. + unsigned getIdentifierNamespace() const { + return IDNS; + } + + /// \brief Returns whether these results arose from performing a + /// lookup into a class. + bool isClassLookup() const { + return NamingClass != nullptr; + } + + /// \brief Returns the 'naming class' for this lookup, i.e. the + /// class which was looked into to find these results. + /// + /// C++0x [class.access.base]p5: + /// The access to a member is affected by the class in which the + /// member is named. This naming class is the class in which the + /// member name was looked up and found. [Note: this class can be + /// explicit, e.g., when a qualified-id is used, or implicit, + /// e.g., when a class member access operator (5.2.5) is used + /// (including cases where an implicit "this->" is added). If both + /// a class member access operator and a qualified-id are used to + /// name the member (as in p->T::m), the class naming the member + /// is the class named by the nested-name-specifier of the + /// qualified-id (that is, T). -- end note ] + /// + /// This is set by the lookup routines when they find results in a class. + CXXRecordDecl *getNamingClass() const { + return NamingClass; + } + + /// \brief Sets the 'naming class' for this lookup. + void setNamingClass(CXXRecordDecl *Record) { + NamingClass = Record; + } + + /// \brief Returns the base object type associated with this lookup; + /// important for [class.protected]. Most lookups do not have an + /// associated base object. + QualType getBaseObjectType() const { + return BaseObjectType; + } + + /// \brief Sets the base object type for this lookup. + void setBaseObjectType(QualType T) { + BaseObjectType = T; + } + + /// \brief Add a declaration to these results with its natural access. + /// Does not test the acceptance criteria. + void addDecl(NamedDecl *D) { + addDecl(D, D->getAccess()); + } + + /// \brief Add a declaration to these results with the given access. + /// Does not test the acceptance criteria. + void addDecl(NamedDecl *D, AccessSpecifier AS) { + Decls.addDecl(D, AS); + ResultKind = Found; + } + + /// \brief Add all the declarations from another set of lookup + /// results. + void addAllDecls(const LookupResult &Other) { + Decls.append(Other.Decls.begin(), Other.Decls.end()); + ResultKind = Found; + } + + /// \brief Determine whether no result was found because we could not + /// search into dependent base classes of the current instantiation. + bool wasNotFoundInCurrentInstantiation() const { + return ResultKind == NotFoundInCurrentInstantiation; + } + + /// \brief Note that while no result was found in the current instantiation, + /// there were dependent base classes that could not be searched. + void setNotFoundInCurrentInstantiation() { + assert(ResultKind == NotFound && Decls.empty()); + ResultKind = NotFoundInCurrentInstantiation; + } + + /// \brief Determine whether the lookup result was shadowed by some other + /// declaration that lookup ignored. + bool isShadowed() const { return Shadowed; } + + /// \brief Note that we found and ignored a declaration while performing + /// lookup. + void setShadowed() { Shadowed = true; } + + /// \brief Resolves the result kind of the lookup, possibly hiding + /// decls. + /// + /// This should be called in any environment where lookup might + /// generate multiple lookup results. + void resolveKind(); + + /// \brief Re-resolves the result kind of the lookup after a set of + /// removals has been performed. + void resolveKindAfterFilter() { + if (Decls.empty()) { + if (ResultKind != NotFoundInCurrentInstantiation) + ResultKind = NotFound; + + if (Paths) { + deletePaths(Paths); + Paths = nullptr; + } + } else { + AmbiguityKind SavedAK; + bool WasAmbiguous = false; + if (ResultKind == Ambiguous) { + SavedAK = Ambiguity; + WasAmbiguous = true; + } + ResultKind = Found; + resolveKind(); + + // If we didn't make the lookup unambiguous, restore the old + // ambiguity kind. + if (ResultKind == Ambiguous) { + (void)WasAmbiguous; + assert(WasAmbiguous); + Ambiguity = SavedAK; + } else if (Paths) { + deletePaths(Paths); + Paths = nullptr; + } + } + } + + template <class DeclClass> + DeclClass *getAsSingle() const { + if (getResultKind() != Found) return nullptr; + return dyn_cast<DeclClass>(getFoundDecl()); + } + + /// \brief Fetch the unique decl found by this lookup. Asserts + /// that one was found. + /// + /// This is intended for users who have examined the result kind + /// and are certain that there is only one result. + NamedDecl *getFoundDecl() const { + assert(getResultKind() == Found + && "getFoundDecl called on non-unique result"); + return (*begin())->getUnderlyingDecl(); + } + + /// Fetches a representative decl. Useful for lazy diagnostics. + NamedDecl *getRepresentativeDecl() const { + assert(!Decls.empty() && "cannot get representative of empty set"); + return *begin(); + } + + /// \brief Asks if the result is a single tag decl. + bool isSingleTagDecl() const { + return getResultKind() == Found && isa<TagDecl>(getFoundDecl()); + } + + /// \brief Make these results show that the name was found in + /// base classes of different types. + /// + /// The given paths object is copied and invalidated. + void setAmbiguousBaseSubobjectTypes(CXXBasePaths &P); + + /// \brief Make these results show that the name was found in + /// distinct base classes of the same type. + /// + /// The given paths object is copied and invalidated. + void setAmbiguousBaseSubobjects(CXXBasePaths &P); + + /// \brief Make these results show that the name was found in + /// different contexts and a tag decl was hidden by an ordinary + /// decl in a different context. + void setAmbiguousQualifiedTagHiding() { + setAmbiguous(AmbiguousTagHiding); + } + + /// \brief Clears out any current state. + void clear() { + ResultKind = NotFound; + Decls.clear(); + if (Paths) deletePaths(Paths); + Paths = nullptr; + NamingClass = nullptr; + Shadowed = false; + } + + /// \brief Clears out any current state and re-initializes for a + /// different kind of lookup. + void clear(Sema::LookupNameKind Kind) { + clear(); + LookupKind = Kind; + configure(); + } + + /// \brief Change this lookup's redeclaration kind. + void setRedeclarationKind(Sema::RedeclarationKind RK) { + Redecl = RK; + configure(); + } + + void print(raw_ostream &); + + /// Suppress the diagnostics that would normally fire because of this + /// lookup. This happens during (e.g.) redeclaration lookups. + void suppressDiagnostics() { + Diagnose = false; + } + + /// Determines whether this lookup is suppressing diagnostics. + bool isSuppressingDiagnostics() const { + return !Diagnose; + } + + /// Sets a 'context' source range. + void setContextRange(SourceRange SR) { + NameContextRange = SR; + } + + /// Gets the source range of the context of this name; for C++ + /// qualified lookups, this is the source range of the scope + /// specifier. + SourceRange getContextRange() const { + return NameContextRange; + } + + /// Gets the location of the identifier. This isn't always defined: + /// sometimes we're doing lookups on synthesized names. + SourceLocation getNameLoc() const { + return NameInfo.getLoc(); + } + + /// \brief Get the Sema object that this lookup result is searching + /// with. + Sema &getSema() const { return *SemaPtr; } + + /// A class for iterating through a result set and possibly + /// filtering out results. The results returned are possibly + /// sugared. + class Filter { + LookupResult &Results; + LookupResult::iterator I; + bool Changed; + bool CalledDone; + + friend class LookupResult; + Filter(LookupResult &Results) + : Results(Results), I(Results.begin()), Changed(false), CalledDone(false) + {} + + public: + Filter(Filter &&F) + : Results(F.Results), I(F.I), Changed(F.Changed), + CalledDone(F.CalledDone) { + F.CalledDone = true; + } + ~Filter() { + assert(CalledDone && + "LookupResult::Filter destroyed without done() call"); + } + + bool hasNext() const { + return I != Results.end(); + } + + NamedDecl *next() { + assert(I != Results.end() && "next() called on empty filter"); + return *I++; + } + + /// Restart the iteration. + void restart() { + I = Results.begin(); + } + + /// Erase the last element returned from this iterator. + void erase() { + Results.Decls.erase(--I); + Changed = true; + } + + /// Replaces the current entry with the given one, preserving the + /// access bits. + void replace(NamedDecl *D) { + Results.Decls.replace(I-1, D); + Changed = true; + } + + /// Replaces the current entry with the given one. + void replace(NamedDecl *D, AccessSpecifier AS) { + Results.Decls.replace(I-1, D, AS); + Changed = true; + } + + void done() { + assert(!CalledDone && "done() called twice"); + CalledDone = true; + + if (Changed) + Results.resolveKindAfterFilter(); + } + }; + + /// Create a filter for this result set. + Filter makeFilter() { + return Filter(*this); + } + + void setFindLocalExtern(bool FindLocalExtern) { + if (FindLocalExtern) + IDNS |= Decl::IDNS_LocalExtern; + else + IDNS &= ~Decl::IDNS_LocalExtern; + } + +private: + void diagnose() { + if (isAmbiguous()) + getSema().DiagnoseAmbiguousLookup(*this); + else if (isClassLookup() && getSema().getLangOpts().AccessControl) + getSema().CheckLookupAccess(*this); + } + + void setAmbiguous(AmbiguityKind AK) { + ResultKind = Ambiguous; + Ambiguity = AK; + } + + void addDeclsFromBasePaths(const CXXBasePaths &P); + void configure(); + + // Sanity checks. + bool sanity() const; + + bool sanityCheckUnresolved() const { + for (iterator I = begin(), E = end(); I != E; ++I) + if (isa<UnresolvedUsingValueDecl>((*I)->getUnderlyingDecl())) + return true; + return false; + } + + static void deletePaths(CXXBasePaths *); + + // Results. + LookupResultKind ResultKind; + AmbiguityKind Ambiguity; // ill-defined unless ambiguous + UnresolvedSet<8> Decls; + CXXBasePaths *Paths; + CXXRecordDecl *NamingClass; + QualType BaseObjectType; + + // Parameters. + Sema *SemaPtr; + DeclarationNameInfo NameInfo; + SourceRange NameContextRange; + Sema::LookupNameKind LookupKind; + unsigned IDNS; // set by configure() + + bool Redecl; + + /// \brief True if tag declarations should be hidden if non-tags + /// are present + bool HideTags; + + bool Diagnose; + + /// \brief True if we should allow hidden declarations to be 'visible'. + bool AllowHidden; + + /// \brief True if the found declarations were shadowed by some other + /// declaration that we skipped. This only happens when \c LookupKind + /// is \c LookupRedeclarationWithLinkage. + bool Shadowed; +}; + +/// \brief Consumes visible declarations found when searching for +/// all visible names within a given scope or context. +/// +/// This abstract class is meant to be subclassed by clients of \c +/// Sema::LookupVisibleDecls(), each of which should override the \c +/// FoundDecl() function to process declarations as they are found. +class VisibleDeclConsumer { +public: + /// \brief Destroys the visible declaration consumer. + virtual ~VisibleDeclConsumer(); + + /// \brief Determine whether hidden declarations (from unimported + /// modules) should be given to this consumer. By default, they + /// are not included. + virtual bool includeHiddenDecls() const; + + /// \brief Invoked each time \p Sema::LookupVisibleDecls() finds a + /// declaration visible from the current scope or context. + /// + /// \param ND the declaration found. + /// + /// \param Hiding a declaration that hides the declaration \p ND, + /// or NULL if no such declaration exists. + /// + /// \param Ctx the original context from which the lookup started. + /// + /// \param InBaseClass whether this declaration was found in base + /// class of the context we searched. + virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx, + bool InBaseClass) = 0; +}; + +/// \brief A class for storing results from argument-dependent lookup. +class ADLResult { +private: + /// A map from canonical decls to the 'most recent' decl. + llvm::DenseMap<NamedDecl*, NamedDecl*> Decls; + +public: + /// Adds a new ADL candidate to this map. + void insert(NamedDecl *D); + + /// Removes any data associated with a given decl. + void erase(NamedDecl *D) { + Decls.erase(cast<NamedDecl>(D->getCanonicalDecl())); + } + + class iterator + : public llvm::iterator_adaptor_base< + iterator, llvm::DenseMap<NamedDecl *, NamedDecl *>::iterator, + std::forward_iterator_tag, NamedDecl *> { + friend class ADLResult; + + iterator(llvm::DenseMap<NamedDecl *, NamedDecl *>::iterator Iter) + : iterator_adaptor_base(std::move(Iter)) {} + + public: + iterator() {} + + value_type operator*() const { return I->second; } + }; + + iterator begin() { return iterator(Decls.begin()); } + iterator end() { return iterator(Decls.end()); } +}; + +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Sema/LoopHint.h b/contrib/llvm/tools/clang/include/clang/Sema/LoopHint.h new file mode 100644 index 0000000..c8b2ee8 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Sema/LoopHint.h @@ -0,0 +1,45 @@ +//===--- LoopHint.h - Types for LoopHint ------------------------*- 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_SEMA_LOOPHINT_H +#define LLVM_CLANG_SEMA_LOOPHINT_H + +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Sema/AttributeList.h" +#include "clang/Sema/Ownership.h" + +namespace clang { + +/// \brief Loop optimization hint for loop and unroll pragmas. +struct LoopHint { + // Source range of the directive. + SourceRange Range; + // Identifier corresponding to the name of the pragma. "loop" for + // "#pragma clang loop" directives and "unroll" for "#pragma unroll" + // hints. + IdentifierLoc *PragmaNameLoc; + // Name of the loop hint. Examples: "unroll", "vectorize". In the + // "#pragma unroll" and "#pragma nounroll" cases, this is identical to + // PragmaNameLoc. + IdentifierLoc *OptionLoc; + // Identifier for the hint state argument. If null, then the state is + // default value such as for "#pragma unroll". + IdentifierLoc *StateLoc; + // Expression for the hint argument if it exists, null otherwise. + Expr *ValueExpr; + + LoopHint() + : PragmaNameLoc(nullptr), OptionLoc(nullptr), StateLoc(nullptr), + ValueExpr(nullptr) {} +}; + +} // end namespace clang + +#endif // LLVM_CLANG_SEMA_LOOPHINT_H diff --git a/contrib/llvm/tools/clang/include/clang/Sema/MultiplexExternalSemaSource.h b/contrib/llvm/tools/clang/include/clang/Sema/MultiplexExternalSemaSource.h new file mode 100644 index 0000000..d6daadc --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Sema/MultiplexExternalSemaSource.h @@ -0,0 +1,353 @@ +//===--- MultiplexExternalSemaSource.h - External Sema Interface-*- 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 ExternalSemaSource interface, dispatching to all clients +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_SEMA_MULTIPLEXEXTERNALSEMASOURCE_H +#define LLVM_CLANG_SEMA_MULTIPLEXEXTERNALSEMASOURCE_H + +#include "clang/Sema/ExternalSemaSource.h" +#include "clang/Sema/Weak.h" +#include "llvm/ADT/SmallVector.h" +#include <utility> + +namespace clang { + + class CXXConstructorDecl; + class CXXRecordDecl; + class DeclaratorDecl; + struct ExternalVTableUse; + class LookupResult; + class NamespaceDecl; + class Scope; + class Sema; + class TypedefNameDecl; + class ValueDecl; + class VarDecl; + + +/// \brief An abstract interface that should be implemented by +/// external AST sources that also provide information for semantic +/// analysis. +class MultiplexExternalSemaSource : public ExternalSemaSource { + +private: + SmallVector<ExternalSemaSource *, 2> Sources; // doesn't own them. + +public: + + ///\brief Constructs a new multiplexing external sema source and appends the + /// given element to it. + /// + ///\param[in] s1 - A non-null (old) ExternalSemaSource. + ///\param[in] s2 - A non-null (new) ExternalSemaSource. + /// + MultiplexExternalSemaSource(ExternalSemaSource& s1, ExternalSemaSource& s2); + + ~MultiplexExternalSemaSource() override; + + ///\brief Appends new source to the source list. + /// + ///\param[in] source - An ExternalSemaSource. + /// + void addSource(ExternalSemaSource &source); + + //===--------------------------------------------------------------------===// + // ExternalASTSource. + //===--------------------------------------------------------------------===// + + /// \brief Resolve a declaration ID into a declaration, potentially + /// building a new declaration. + Decl *GetExternalDecl(uint32_t ID) override; + + /// \brief Complete the redeclaration chain if it's been extended since the + /// previous generation of the AST source. + void CompleteRedeclChain(const Decl *D) override; + + /// \brief Resolve a selector ID into a selector. + Selector GetExternalSelector(uint32_t ID) override; + + /// \brief Returns the number of selectors known to the external AST + /// source. + uint32_t GetNumExternalSelectors() override; + + /// \brief Resolve the offset of a statement in the decl stream into + /// a statement. + Stmt *GetExternalDeclStmt(uint64_t Offset) override; + + /// \brief Resolve the offset of a set of C++ base specifiers in the decl + /// stream into an array of specifiers. + CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset) override; + + /// \brief Resolve a handle to a list of ctor initializers into the list of + /// initializers themselves. + CXXCtorInitializer **GetExternalCXXCtorInitializers(uint64_t Offset) override; + + /// \brief Find all declarations with the given name in the + /// given context. + bool FindExternalVisibleDeclsByName(const DeclContext *DC, + DeclarationName Name) override; + + /// \brief Ensures that the table of all visible declarations inside this + /// context is up to date. + void completeVisibleDeclsMap(const DeclContext *DC) override; + + /// \brief Finds all declarations lexically contained within the given + /// DeclContext, after applying an optional filter predicate. + /// + /// \param IsKindWeWant a predicate function that returns true if the passed + /// declaration kind is one we are looking for. + void + FindExternalLexicalDecls(const DeclContext *DC, + llvm::function_ref<bool(Decl::Kind)> IsKindWeWant, + SmallVectorImpl<Decl *> &Result) override; + + /// \brief Get the decls that are contained in a file in the Offset/Length + /// range. \p Length can be 0 to indicate a point at \p Offset instead of + /// a range. + void FindFileRegionDecls(FileID File, unsigned Offset,unsigned Length, + SmallVectorImpl<Decl *> &Decls) override; + + /// \brief Gives the external AST source an opportunity to complete + /// an incomplete type. + void CompleteType(TagDecl *Tag) override; + + /// \brief Gives the external AST source an opportunity to complete an + /// incomplete Objective-C class. + /// + /// This routine will only be invoked if the "externally completed" bit is + /// set on the ObjCInterfaceDecl via the function + /// \c ObjCInterfaceDecl::setExternallyCompleted(). + void CompleteType(ObjCInterfaceDecl *Class) override; + + /// \brief Loads comment ranges. + void ReadComments() override; + + /// \brief Notify ExternalASTSource that we started deserialization of + /// a decl or type so until FinishedDeserializing is called there may be + /// decls that are initializing. Must be paired with FinishedDeserializing. + void StartedDeserializing() override; + + /// \brief Notify ExternalASTSource that we finished the deserialization of + /// a decl or type. Must be paired with StartedDeserializing. + void FinishedDeserializing() override; + + /// \brief Function that will be invoked when we begin parsing a new + /// translation unit involving this external AST source. + void StartTranslationUnit(ASTConsumer *Consumer) override; + + /// \brief Print any statistics that have been gathered regarding + /// the external AST source. + void PrintStats() override; + + + /// \brief Perform layout on the given record. + /// + /// This routine allows the external AST source to provide an specific + /// layout for a record, overriding the layout that would normally be + /// constructed. It is intended for clients who receive specific layout + /// details rather than source code (such as LLDB). The client is expected + /// to fill in the field offsets, base offsets, virtual base offsets, and + /// complete object size. + /// + /// \param Record The record whose layout is being requested. + /// + /// \param Size The final size of the record, in bits. + /// + /// \param Alignment The final alignment of the record, in bits. + /// + /// \param FieldOffsets The offset of each of the fields within the record, + /// expressed in bits. All of the fields must be provided with offsets. + /// + /// \param BaseOffsets The offset of each of the direct, non-virtual base + /// classes. If any bases are not given offsets, the bases will be laid + /// out according to the ABI. + /// + /// \param VirtualBaseOffsets The offset of each of the virtual base classes + /// (either direct or not). If any bases are not given offsets, the bases will + /// be laid out according to the ABI. + /// + /// \returns true if the record layout was provided, false otherwise. + bool + layoutRecordType(const RecordDecl *Record, + uint64_t &Size, uint64_t &Alignment, + llvm::DenseMap<const FieldDecl *, uint64_t> &FieldOffsets, + llvm::DenseMap<const CXXRecordDecl *, CharUnits> &BaseOffsets, + llvm::DenseMap<const CXXRecordDecl *, + CharUnits> &VirtualBaseOffsets) override; + + /// Return the amount of memory used by memory buffers, breaking down + /// by heap-backed versus mmap'ed memory. + void getMemoryBufferSizes(MemoryBufferSizes &sizes) const override; + + //===--------------------------------------------------------------------===// + // ExternalSemaSource. + //===--------------------------------------------------------------------===// + + /// \brief Initialize the semantic source with the Sema instance + /// being used to perform semantic analysis on the abstract syntax + /// tree. + void InitializeSema(Sema &S) override; + + /// \brief Inform the semantic consumer that Sema is no longer available. + void ForgetSema() override; + + /// \brief Load the contents of the global method pool for a given + /// selector. + void ReadMethodPool(Selector Sel) override; + + /// \brief Load the set of namespaces that are known to the external source, + /// which will be used during typo correction. + void + ReadKnownNamespaces(SmallVectorImpl<NamespaceDecl*> &Namespaces) override; + + /// \brief Load the set of used but not defined functions or variables with + /// internal linkage, or used but not defined inline functions. + void ReadUndefinedButUsed( + llvm::DenseMap<NamedDecl*, SourceLocation> &Undefined) override; + + void ReadMismatchingDeleteExpressions(llvm::MapVector< + FieldDecl *, llvm::SmallVector<std::pair<SourceLocation, bool>, 4>> & + Exprs) override; + + /// \brief Do last resort, unqualified lookup on a LookupResult that + /// Sema cannot find. + /// + /// \param R a LookupResult that is being recovered. + /// + /// \param S the Scope of the identifier occurrence. + /// + /// \return true to tell Sema to recover using the LookupResult. + bool LookupUnqualified(LookupResult &R, Scope *S) override; + + /// \brief Read the set of tentative definitions known to the external Sema + /// source. + /// + /// The external source should append its own tentative definitions to the + /// given vector of tentative definitions. Note that this routine may be + /// invoked multiple times; the external source should take care not to + /// introduce the same declarations repeatedly. + void ReadTentativeDefinitions(SmallVectorImpl<VarDecl*> &Defs) override; + + /// \brief Read the set of unused file-scope declarations known to the + /// external Sema source. + /// + /// The external source should append its own unused, filed-scope to the + /// given vector of declarations. Note that this routine may be + /// invoked multiple times; the external source should take care not to + /// introduce the same declarations repeatedly. + void ReadUnusedFileScopedDecls( + SmallVectorImpl<const DeclaratorDecl*> &Decls) override; + + /// \brief Read the set of delegating constructors known to the + /// external Sema source. + /// + /// The external source should append its own delegating constructors to the + /// given vector of declarations. Note that this routine may be + /// invoked multiple times; the external source should take care not to + /// introduce the same declarations repeatedly. + void ReadDelegatingConstructors( + SmallVectorImpl<CXXConstructorDecl*> &Decls) override; + + /// \brief Read the set of ext_vector type declarations known to the + /// external Sema source. + /// + /// The external source should append its own ext_vector type declarations to + /// the given vector of declarations. Note that this routine may be + /// invoked multiple times; the external source should take care not to + /// introduce the same declarations repeatedly. + void ReadExtVectorDecls(SmallVectorImpl<TypedefNameDecl*> &Decls) override; + + /// \brief Read the set of potentially unused typedefs known to the source. + /// + /// The external source should append its own potentially unused local + /// typedefs to the given vector of declarations. Note that this routine may + /// be invoked multiple times; the external source should take care not to + /// introduce the same declarations repeatedly. + void ReadUnusedLocalTypedefNameCandidates( + llvm::SmallSetVector<const TypedefNameDecl *, 4> &Decls) override; + + /// \brief Read the set of referenced selectors known to the + /// external Sema source. + /// + /// The external source should append its own referenced selectors to the + /// given vector of selectors. Note that this routine + /// may be invoked multiple times; the external source should take care not + /// to introduce the same selectors repeatedly. + void ReadReferencedSelectors(SmallVectorImpl<std::pair<Selector, + SourceLocation> > &Sels) override; + + /// \brief Read the set of weak, undeclared identifiers known to the + /// external Sema source. + /// + /// The external source should append its own weak, undeclared identifiers to + /// the given vector. Note that this routine may be invoked multiple times; + /// the external source should take care not to introduce the same identifiers + /// repeatedly. + void ReadWeakUndeclaredIdentifiers( + SmallVectorImpl<std::pair<IdentifierInfo*, WeakInfo> > &WI) override; + + /// \brief Read the set of used vtables known to the external Sema source. + /// + /// The external source should append its own used vtables to the given + /// vector. Note that this routine may be invoked multiple times; the external + /// source should take care not to introduce the same vtables repeatedly. + void ReadUsedVTables(SmallVectorImpl<ExternalVTableUse> &VTables) override; + + /// \brief Read the set of pending instantiations known to the external + /// Sema source. + /// + /// The external source should append its own pending instantiations to the + /// given vector. Note that this routine may be invoked multiple times; the + /// external source should take care not to introduce the same instantiations + /// repeatedly. + void ReadPendingInstantiations( + SmallVectorImpl<std::pair<ValueDecl*, SourceLocation> >& Pending) override; + + /// \brief Read the set of late parsed template functions for this source. + /// + /// The external source should insert its own late parsed template functions + /// into the map. Note that this routine may be invoked multiple times; the + /// external source should take care not to introduce the same map entries + /// repeatedly. + void ReadLateParsedTemplates( + llvm::MapVector<const FunctionDecl *, LateParsedTemplate *> &LPTMap) + override; + + /// \copydoc ExternalSemaSource::CorrectTypo + /// \note Returns the first nonempty correction. + TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo, + int LookupKind, Scope *S, CXXScopeSpec *SS, + CorrectionCandidateCallback &CCC, + DeclContext *MemberContext, + bool EnteringContext, + const ObjCObjectPointerType *OPT) override; + + /// \brief Produces a diagnostic note if one of the attached sources + /// contains a complete definition for \p T. Queries the sources in list + /// order until the first one claims that a diagnostic was produced. + /// + /// \param Loc the location at which a complete type was required but not + /// provided + /// + /// \param T the \c QualType that should have been complete at \p Loc + /// + /// \return true if a diagnostic was produced, false otherwise. + bool MaybeDiagnoseMissingCompleteType(SourceLocation Loc, + QualType T) override; + + // isa/cast/dyn_cast support + static bool classof(const MultiplexExternalSemaSource*) { return true; } + //static bool classof(const ExternalSemaSource*) { return true; } +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Sema/ObjCMethodList.h b/contrib/llvm/tools/clang/include/clang/Sema/ObjCMethodList.h new file mode 100644 index 0000000..b618e38 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Sema/ObjCMethodList.h @@ -0,0 +1,58 @@ +//===--- ObjCMethodList.h - A singly linked list of methods -----*- 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 ObjCMethodList, a singly-linked list of methods. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_OBJCMETHODLIST_H +#define LLVM_CLANG_SEMA_OBJCMETHODLIST_H + +#include "llvm/ADT/PointerIntPair.h" + +namespace clang { + +class ObjCMethodDecl; + +/// \brief a linked list of methods with the same selector name but different +/// signatures. +struct ObjCMethodList { + // NOTE: If you add any members to this struct, make sure to serialize them. + /// \brief If there is more than one decl with this signature. + llvm::PointerIntPair<ObjCMethodDecl *, 1> MethodAndHasMoreThanOneDecl; + /// \brief The next list object and 2 bits for extra info. + llvm::PointerIntPair<ObjCMethodList *, 2> NextAndExtraBits; + + ObjCMethodList() { } + ObjCMethodList(ObjCMethodDecl *M) + : MethodAndHasMoreThanOneDecl(M, 0) {} + + ObjCMethodList *getNext() const { return NextAndExtraBits.getPointer(); } + unsigned getBits() const { return NextAndExtraBits.getInt(); } + void setNext(ObjCMethodList *L) { NextAndExtraBits.setPointer(L); } + void setBits(unsigned B) { NextAndExtraBits.setInt(B); } + + ObjCMethodDecl *getMethod() const { + return MethodAndHasMoreThanOneDecl.getPointer(); + } + void setMethod(ObjCMethodDecl *M) { + return MethodAndHasMoreThanOneDecl.setPointer(M); + } + + bool hasMoreThanOneDecl() const { + return MethodAndHasMoreThanOneDecl.getInt(); + } + void setHasMoreThanOneDecl(bool B) { + return MethodAndHasMoreThanOneDecl.setInt(B); + } +}; + +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Sema/Overload.h b/contrib/llvm/tools/clang/include/clang/Sema/Overload.h new file mode 100644 index 0000000..20958b0 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Sema/Overload.h @@ -0,0 +1,799 @@ +//===--- Overload.h - C++ Overloading ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the data structures and types used in C++ +// overload resolution. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_OVERLOAD_H +#define LLVM_CLANG_SEMA_OVERLOAD_H + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/Type.h" +#include "clang/AST/UnresolvedSet.h" +#include "clang/Sema/SemaFixItUtils.h" +#include "clang/Sema/TemplateDeduction.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/AlignOf.h" +#include "llvm/Support/Allocator.h" + +namespace clang { + class ASTContext; + class CXXConstructorDecl; + class CXXConversionDecl; + class FunctionDecl; + class Sema; + + /// OverloadingResult - Capture the result of performing overload + /// resolution. + enum OverloadingResult { + OR_Success, ///< Overload resolution succeeded. + OR_No_Viable_Function, ///< No viable function found. + OR_Ambiguous, ///< Ambiguous candidates found. + OR_Deleted ///< Succeeded, but refers to a deleted function. + }; + + enum OverloadCandidateDisplayKind { + /// Requests that all candidates be shown. Viable candidates will + /// be printed first. + OCD_AllCandidates, + + /// Requests that only viable candidates be shown. + OCD_ViableCandidates + }; + + /// ImplicitConversionKind - The kind of implicit conversion used to + /// convert an argument to a parameter's type. The enumerator values + /// match with Table 9 of (C++ 13.3.3.1.1) and are listed such that + /// better conversion kinds have smaller values. + enum ImplicitConversionKind { + ICK_Identity = 0, ///< Identity conversion (no conversion) + ICK_Lvalue_To_Rvalue, ///< Lvalue-to-rvalue conversion (C++ 4.1) + ICK_Array_To_Pointer, ///< Array-to-pointer conversion (C++ 4.2) + ICK_Function_To_Pointer, ///< Function-to-pointer (C++ 4.3) + ICK_NoReturn_Adjustment, ///< Removal of noreturn from a type (Clang) + ICK_Qualification, ///< Qualification conversions (C++ 4.4) + ICK_Integral_Promotion, ///< Integral promotions (C++ 4.5) + ICK_Floating_Promotion, ///< Floating point promotions (C++ 4.6) + ICK_Complex_Promotion, ///< Complex promotions (Clang extension) + ICK_Integral_Conversion, ///< Integral conversions (C++ 4.7) + ICK_Floating_Conversion, ///< Floating point conversions (C++ 4.8) + ICK_Complex_Conversion, ///< Complex conversions (C99 6.3.1.6) + ICK_Floating_Integral, ///< Floating-integral conversions (C++ 4.9) + ICK_Pointer_Conversion, ///< Pointer conversions (C++ 4.10) + ICK_Pointer_Member, ///< Pointer-to-member conversions (C++ 4.11) + ICK_Boolean_Conversion, ///< Boolean conversions (C++ 4.12) + ICK_Compatible_Conversion, ///< Conversions between compatible types in C99 + ICK_Derived_To_Base, ///< Derived-to-base (C++ [over.best.ics]) + ICK_Vector_Conversion, ///< Vector conversions + ICK_Vector_Splat, ///< A vector splat from an arithmetic type + ICK_Complex_Real, ///< Complex-real conversions (C99 6.3.1.7) + ICK_Block_Pointer_Conversion, ///< Block Pointer conversions + ICK_TransparentUnionConversion, ///< Transparent Union Conversions + ICK_Writeback_Conversion, ///< Objective-C ARC writeback conversion + ICK_Zero_Event_Conversion, ///< Zero constant to event (OpenCL1.2 6.12.10) + ICK_C_Only_Conversion, ///< Conversions allowed in C, but not C++ + ICK_Num_Conversion_Kinds, ///< The number of conversion kinds + }; + + /// ImplicitConversionRank - The rank of an implicit conversion + /// kind. The enumerator values match with Table 9 of (C++ + /// 13.3.3.1.1) and are listed such that better conversion ranks + /// have smaller values. + enum ImplicitConversionRank { + ICR_Exact_Match = 0, ///< Exact Match + ICR_Promotion, ///< Promotion + ICR_Conversion, ///< Conversion + ICR_Complex_Real_Conversion, ///< Complex <-> Real conversion + ICR_Writeback_Conversion, ///< ObjC ARC writeback conversion + ICR_C_Conversion ///< Conversion only allowed in the C standard. + /// (e.g. void* to char*) + }; + + ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind); + + /// NarrowingKind - The kind of narrowing conversion being performed by a + /// standard conversion sequence according to C++11 [dcl.init.list]p7. + enum NarrowingKind { + /// Not a narrowing conversion. + NK_Not_Narrowing, + + /// A narrowing conversion by virtue of the source and destination types. + NK_Type_Narrowing, + + /// A narrowing conversion, because a constant expression got narrowed. + NK_Constant_Narrowing, + + /// A narrowing conversion, because a non-constant-expression variable might + /// have got narrowed. + NK_Variable_Narrowing + }; + + /// StandardConversionSequence - represents a standard conversion + /// sequence (C++ 13.3.3.1.1). A standard conversion sequence + /// contains between zero and three conversions. If a particular + /// conversion is not needed, it will be set to the identity conversion + /// (ICK_Identity). Note that the three conversions are + /// specified as separate members (rather than in an array) so that + /// we can keep the size of a standard conversion sequence to a + /// single word. + class StandardConversionSequence { + public: + /// First -- The first conversion can be an lvalue-to-rvalue + /// conversion, array-to-pointer conversion, or + /// function-to-pointer conversion. + ImplicitConversionKind First : 8; + + /// Second - The second conversion can be an integral promotion, + /// floating point promotion, integral conversion, floating point + /// conversion, floating-integral conversion, pointer conversion, + /// pointer-to-member conversion, or boolean conversion. + ImplicitConversionKind Second : 8; + + /// Third - The third conversion can be a qualification conversion. + ImplicitConversionKind Third : 8; + + /// \brief Whether this is the deprecated conversion of a + /// string literal to a pointer to non-const character data + /// (C++ 4.2p2). + unsigned DeprecatedStringLiteralToCharPtr : 1; + + /// \brief Whether the qualification conversion involves a change in the + /// Objective-C lifetime (for automatic reference counting). + unsigned QualificationIncludesObjCLifetime : 1; + + /// IncompatibleObjC - Whether this is an Objective-C conversion + /// that we should warn about (if we actually use it). + unsigned IncompatibleObjC : 1; + + /// ReferenceBinding - True when this is a reference binding + /// (C++ [over.ics.ref]). + unsigned ReferenceBinding : 1; + + /// DirectBinding - True when this is a reference binding that is a + /// direct binding (C++ [dcl.init.ref]). + unsigned DirectBinding : 1; + + /// \brief Whether this is an lvalue reference binding (otherwise, it's + /// an rvalue reference binding). + unsigned IsLvalueReference : 1; + + /// \brief Whether we're binding to a function lvalue. + unsigned BindsToFunctionLvalue : 1; + + /// \brief Whether we're binding to an rvalue. + unsigned BindsToRvalue : 1; + + /// \brief Whether this binds an implicit object argument to a + /// non-static member function without a ref-qualifier. + unsigned BindsImplicitObjectArgumentWithoutRefQualifier : 1; + + /// \brief Whether this binds a reference to an object with a different + /// Objective-C lifetime qualifier. + unsigned ObjCLifetimeConversionBinding : 1; + + /// FromType - The type that this conversion is converting + /// from. This is an opaque pointer that can be translated into a + /// QualType. + void *FromTypePtr; + + /// ToType - The types that this conversion is converting to in + /// each step. This is an opaque pointer that can be translated + /// into a QualType. + void *ToTypePtrs[3]; + + /// CopyConstructor - The copy constructor that is used to perform + /// this conversion, when the conversion is actually just the + /// initialization of an object via copy constructor. Such + /// conversions are either identity conversions or derived-to-base + /// conversions. + CXXConstructorDecl *CopyConstructor; + + void setFromType(QualType T) { FromTypePtr = T.getAsOpaquePtr(); } + void setToType(unsigned Idx, QualType T) { + assert(Idx < 3 && "To type index is out of range"); + ToTypePtrs[Idx] = T.getAsOpaquePtr(); + } + void setAllToTypes(QualType T) { + ToTypePtrs[0] = T.getAsOpaquePtr(); + ToTypePtrs[1] = ToTypePtrs[0]; + ToTypePtrs[2] = ToTypePtrs[0]; + } + + QualType getFromType() const { + return QualType::getFromOpaquePtr(FromTypePtr); + } + QualType getToType(unsigned Idx) const { + assert(Idx < 3 && "To type index is out of range"); + return QualType::getFromOpaquePtr(ToTypePtrs[Idx]); + } + + void setAsIdentityConversion(); + + bool isIdentityConversion() const { + return Second == ICK_Identity && Third == ICK_Identity; + } + + ImplicitConversionRank getRank() const; + NarrowingKind getNarrowingKind(ASTContext &Context, const Expr *Converted, + APValue &ConstantValue, + QualType &ConstantType) const; + bool isPointerConversionToBool() const; + bool isPointerConversionToVoidPointer(ASTContext& Context) const; + void dump() const; + }; + + /// UserDefinedConversionSequence - Represents a user-defined + /// conversion sequence (C++ 13.3.3.1.2). + struct UserDefinedConversionSequence { + /// \brief Represents the standard conversion that occurs before + /// the actual user-defined conversion. + /// + /// C++11 13.3.3.1.2p1: + /// If the user-defined conversion is specified by a constructor + /// (12.3.1), the initial standard conversion sequence converts + /// the source type to the type required by the argument of the + /// constructor. If the user-defined conversion is specified by + /// a conversion function (12.3.2), the initial standard + /// conversion sequence converts the source type to the implicit + /// object parameter of the conversion function. + StandardConversionSequence Before; + + /// EllipsisConversion - When this is true, it means user-defined + /// conversion sequence starts with a ... (ellipsis) conversion, instead of + /// a standard conversion. In this case, 'Before' field must be ignored. + // FIXME. I much rather put this as the first field. But there seems to be + // a gcc code gen. bug which causes a crash in a test. Putting it here seems + // to work around the crash. + bool EllipsisConversion : 1; + + /// HadMultipleCandidates - When this is true, it means that the + /// conversion function was resolved from an overloaded set having + /// size greater than 1. + bool HadMultipleCandidates : 1; + + /// After - Represents the standard conversion that occurs after + /// the actual user-defined conversion. + StandardConversionSequence After; + + /// ConversionFunction - The function that will perform the + /// user-defined conversion. Null if the conversion is an + /// aggregate initialization from an initializer list. + FunctionDecl* ConversionFunction; + + /// \brief The declaration that we found via name lookup, which might be + /// the same as \c ConversionFunction or it might be a using declaration + /// that refers to \c ConversionFunction. + DeclAccessPair FoundConversionFunction; + + void dump() const; + }; + + /// Represents an ambiguous user-defined conversion sequence. + struct AmbiguousConversionSequence { + typedef SmallVector<FunctionDecl*, 4> ConversionSet; + + void *FromTypePtr; + void *ToTypePtr; + char Buffer[sizeof(ConversionSet)]; + + QualType getFromType() const { + return QualType::getFromOpaquePtr(FromTypePtr); + } + QualType getToType() const { + return QualType::getFromOpaquePtr(ToTypePtr); + } + void setFromType(QualType T) { FromTypePtr = T.getAsOpaquePtr(); } + void setToType(QualType T) { ToTypePtr = T.getAsOpaquePtr(); } + + ConversionSet &conversions() { + return *reinterpret_cast<ConversionSet*>(Buffer); + } + + const ConversionSet &conversions() const { + return *reinterpret_cast<const ConversionSet*>(Buffer); + } + + void addConversion(FunctionDecl *D) { + conversions().push_back(D); + } + + typedef ConversionSet::iterator iterator; + iterator begin() { return conversions().begin(); } + iterator end() { return conversions().end(); } + + typedef ConversionSet::const_iterator const_iterator; + const_iterator begin() const { return conversions().begin(); } + const_iterator end() const { return conversions().end(); } + + void construct(); + void destruct(); + void copyFrom(const AmbiguousConversionSequence &); + }; + + /// BadConversionSequence - Records information about an invalid + /// conversion sequence. + struct BadConversionSequence { + enum FailureKind { + no_conversion, + unrelated_class, + bad_qualifiers, + lvalue_ref_to_rvalue, + rvalue_ref_to_lvalue + }; + + // This can be null, e.g. for implicit object arguments. + Expr *FromExpr; + + FailureKind Kind; + + private: + // The type we're converting from (an opaque QualType). + void *FromTy; + + // The type we're converting to (an opaque QualType). + void *ToTy; + + public: + void init(FailureKind K, Expr *From, QualType To) { + init(K, From->getType(), To); + FromExpr = From; + } + void init(FailureKind K, QualType From, QualType To) { + Kind = K; + FromExpr = nullptr; + setFromType(From); + setToType(To); + } + + QualType getFromType() const { return QualType::getFromOpaquePtr(FromTy); } + QualType getToType() const { return QualType::getFromOpaquePtr(ToTy); } + + void setFromExpr(Expr *E) { + FromExpr = E; + setFromType(E->getType()); + } + void setFromType(QualType T) { FromTy = T.getAsOpaquePtr(); } + void setToType(QualType T) { ToTy = T.getAsOpaquePtr(); } + }; + + /// ImplicitConversionSequence - Represents an implicit conversion + /// sequence, which may be a standard conversion sequence + /// (C++ 13.3.3.1.1), user-defined conversion sequence (C++ 13.3.3.1.2), + /// or an ellipsis conversion sequence (C++ 13.3.3.1.3). + class ImplicitConversionSequence { + public: + /// Kind - The kind of implicit conversion sequence. BadConversion + /// specifies that there is no conversion from the source type to + /// the target type. AmbiguousConversion represents the unique + /// ambiguous conversion (C++0x [over.best.ics]p10). + enum Kind { + StandardConversion = 0, + UserDefinedConversion, + AmbiguousConversion, + EllipsisConversion, + BadConversion + }; + + private: + enum { + Uninitialized = BadConversion + 1 + }; + + /// ConversionKind - The kind of implicit conversion sequence. + unsigned ConversionKind : 30; + + /// \brief Whether the target is really a std::initializer_list, and the + /// sequence only represents the worst element conversion. + bool StdInitializerListElement : 1; + + void setKind(Kind K) { + destruct(); + ConversionKind = K; + } + + void destruct() { + if (ConversionKind == AmbiguousConversion) Ambiguous.destruct(); + } + + public: + union { + /// When ConversionKind == StandardConversion, provides the + /// details of the standard conversion sequence. + StandardConversionSequence Standard; + + /// When ConversionKind == UserDefinedConversion, provides the + /// details of the user-defined conversion sequence. + UserDefinedConversionSequence UserDefined; + + /// When ConversionKind == AmbiguousConversion, provides the + /// details of the ambiguous conversion. + AmbiguousConversionSequence Ambiguous; + + /// When ConversionKind == BadConversion, provides the details + /// of the bad conversion. + BadConversionSequence Bad; + }; + + ImplicitConversionSequence() + : ConversionKind(Uninitialized), StdInitializerListElement(false) + {} + ~ImplicitConversionSequence() { + destruct(); + } + ImplicitConversionSequence(const ImplicitConversionSequence &Other) + : ConversionKind(Other.ConversionKind), + StdInitializerListElement(Other.StdInitializerListElement) + { + switch (ConversionKind) { + case Uninitialized: break; + case StandardConversion: Standard = Other.Standard; break; + case UserDefinedConversion: UserDefined = Other.UserDefined; break; + case AmbiguousConversion: Ambiguous.copyFrom(Other.Ambiguous); break; + case EllipsisConversion: break; + case BadConversion: Bad = Other.Bad; break; + } + } + + ImplicitConversionSequence & + operator=(const ImplicitConversionSequence &Other) { + destruct(); + new (this) ImplicitConversionSequence(Other); + return *this; + } + + Kind getKind() const { + assert(isInitialized() && "querying uninitialized conversion"); + return Kind(ConversionKind); + } + + /// \brief Return a ranking of the implicit conversion sequence + /// kind, where smaller ranks represent better conversion + /// sequences. + /// + /// In particular, this routine gives user-defined conversion + /// sequences and ambiguous conversion sequences the same rank, + /// per C++ [over.best.ics]p10. + unsigned getKindRank() const { + switch (getKind()) { + case StandardConversion: + return 0; + + case UserDefinedConversion: + case AmbiguousConversion: + return 1; + + case EllipsisConversion: + return 2; + + case BadConversion: + return 3; + } + + llvm_unreachable("Invalid ImplicitConversionSequence::Kind!"); + } + + bool isBad() const { return getKind() == BadConversion; } + bool isStandard() const { return getKind() == StandardConversion; } + bool isEllipsis() const { return getKind() == EllipsisConversion; } + bool isAmbiguous() const { return getKind() == AmbiguousConversion; } + bool isUserDefined() const { return getKind() == UserDefinedConversion; } + bool isFailure() const { return isBad() || isAmbiguous(); } + + /// Determines whether this conversion sequence has been + /// initialized. Most operations should never need to query + /// uninitialized conversions and should assert as above. + bool isInitialized() const { return ConversionKind != Uninitialized; } + + /// Sets this sequence as a bad conversion for an explicit argument. + void setBad(BadConversionSequence::FailureKind Failure, + Expr *FromExpr, QualType ToType) { + setKind(BadConversion); + Bad.init(Failure, FromExpr, ToType); + } + + /// Sets this sequence as a bad conversion for an implicit argument. + void setBad(BadConversionSequence::FailureKind Failure, + QualType FromType, QualType ToType) { + setKind(BadConversion); + Bad.init(Failure, FromType, ToType); + } + + void setStandard() { setKind(StandardConversion); } + void setEllipsis() { setKind(EllipsisConversion); } + void setUserDefined() { setKind(UserDefinedConversion); } + void setAmbiguous() { + if (ConversionKind == AmbiguousConversion) return; + ConversionKind = AmbiguousConversion; + Ambiguous.construct(); + } + + /// \brief Whether the target is really a std::initializer_list, and the + /// sequence only represents the worst element conversion. + bool isStdInitializerListElement() const { + return StdInitializerListElement; + } + + void setStdInitializerListElement(bool V = true) { + StdInitializerListElement = V; + } + + // The result of a comparison between implicit conversion + // sequences. Use Sema::CompareImplicitConversionSequences to + // actually perform the comparison. + enum CompareKind { + Better = -1, + Indistinguishable = 0, + Worse = 1 + }; + + void DiagnoseAmbiguousConversion(Sema &S, + SourceLocation CaretLoc, + const PartialDiagnostic &PDiag) const; + + void dump() const; + }; + + enum OverloadFailureKind { + ovl_fail_too_many_arguments, + ovl_fail_too_few_arguments, + ovl_fail_bad_conversion, + ovl_fail_bad_deduction, + + /// This conversion candidate was not considered because it + /// duplicates the work of a trivial or derived-to-base + /// conversion. + ovl_fail_trivial_conversion, + + /// This conversion candidate was not considered because it is + /// an illegal instantiation of a constructor temploid: it is + /// callable with one argument, we only have one argument, and + /// its first parameter type is exactly the type of the class. + /// + /// Defining such a constructor directly is illegal, and + /// template-argument deduction is supposed to ignore such + /// instantiations, but we can still get one with the right + /// kind of implicit instantiation. + ovl_fail_illegal_constructor, + + /// This conversion candidate is not viable because its result + /// type is not implicitly convertible to the desired type. + ovl_fail_bad_final_conversion, + + /// This conversion function template specialization candidate is not + /// viable because the final conversion was not an exact match. + ovl_fail_final_conversion_not_exact, + + /// (CUDA) This candidate was not viable because the callee + /// was not accessible from the caller's target (i.e. host->device, + /// global->host, device->host). + ovl_fail_bad_target, + + /// This candidate function was not viable because an enable_if + /// attribute disabled it. + ovl_fail_enable_if + }; + + /// OverloadCandidate - A single candidate in an overload set (C++ 13.3). + struct OverloadCandidate { + /// Function - The actual function that this candidate + /// represents. When NULL, this is a built-in candidate + /// (C++ [over.oper]) or a surrogate for a conversion to a + /// function pointer or reference (C++ [over.call.object]). + FunctionDecl *Function; + + /// FoundDecl - The original declaration that was looked up / + /// invented / otherwise found, together with its access. + /// Might be a UsingShadowDecl or a FunctionTemplateDecl. + DeclAccessPair FoundDecl; + + // BuiltinTypes - Provides the return and parameter types of a + // built-in overload candidate. Only valid when Function is NULL. + struct { + QualType ResultTy; + QualType ParamTypes[3]; + } BuiltinTypes; + + /// Surrogate - The conversion function for which this candidate + /// is a surrogate, but only if IsSurrogate is true. + CXXConversionDecl *Surrogate; + + /// Conversions - The conversion sequences used to convert the + /// function arguments to the function parameters, the pointer points to a + /// fixed size array with NumConversions elements. The memory is owned by + /// the OverloadCandidateSet. + ImplicitConversionSequence *Conversions; + + /// The FixIt hints which can be used to fix the Bad candidate. + ConversionFixItGenerator Fix; + + /// NumConversions - The number of elements in the Conversions array. + unsigned NumConversions; + + /// Viable - True to indicate that this overload candidate is viable. + bool Viable; + + /// IsSurrogate - True to indicate that this candidate is a + /// surrogate for a conversion to a function pointer or reference + /// (C++ [over.call.object]). + bool IsSurrogate; + + /// IgnoreObjectArgument - True to indicate that the first + /// argument's conversion, which for this function represents the + /// implicit object argument, should be ignored. This will be true + /// when the candidate is a static member function (where the + /// implicit object argument is just a placeholder) or a + /// non-static member function when the call doesn't have an + /// object argument. + bool IgnoreObjectArgument; + + /// FailureKind - The reason why this candidate is not viable. + /// Actually an OverloadFailureKind. + unsigned char FailureKind; + + /// \brief The number of call arguments that were explicitly provided, + /// to be used while performing partial ordering of function templates. + unsigned ExplicitCallArguments; + + union { + DeductionFailureInfo DeductionFailure; + + /// FinalConversion - For a conversion function (where Function is + /// a CXXConversionDecl), the standard conversion that occurs + /// after the call to the overload candidate to convert the result + /// of calling the conversion function to the required type. + StandardConversionSequence FinalConversion; + }; + + /// hasAmbiguousConversion - Returns whether this overload + /// candidate requires an ambiguous conversion or not. + bool hasAmbiguousConversion() const { + for (unsigned i = 0, e = NumConversions; i != e; ++i) { + if (!Conversions[i].isInitialized()) return false; + if (Conversions[i].isAmbiguous()) return true; + } + return false; + } + + bool TryToFixBadConversion(unsigned Idx, Sema &S) { + bool CanFix = Fix.tryToFixConversion( + Conversions[Idx].Bad.FromExpr, + Conversions[Idx].Bad.getFromType(), + Conversions[Idx].Bad.getToType(), S); + + // If at least one conversion fails, the candidate cannot be fixed. + if (!CanFix) + Fix.clear(); + + return CanFix; + } + + unsigned getNumParams() const { + if (IsSurrogate) { + auto STy = Surrogate->getConversionType(); + while (STy->isPointerType() || STy->isReferenceType()) + STy = STy->getPointeeType(); + return STy->getAs<FunctionProtoType>()->getNumParams(); + } + if (Function) + return Function->getNumParams(); + return ExplicitCallArguments; + } + }; + + /// OverloadCandidateSet - A set of overload candidates, used in C++ + /// overload resolution (C++ 13.3). + class OverloadCandidateSet { + public: + enum CandidateSetKind { + /// Normal lookup. + CSK_Normal, + /// Lookup for candidates for a call using operator syntax. Candidates + /// that have no parameters of class type will be skipped unless there + /// is a parameter of (reference to) enum type and the corresponding + /// argument is of the same enum type. + CSK_Operator + }; + + private: + SmallVector<OverloadCandidate, 16> Candidates; + llvm::SmallPtrSet<Decl *, 16> Functions; + + // Allocator for OverloadCandidate::Conversions. We store the first few + // elements inline to avoid allocation for small sets. + llvm::BumpPtrAllocator ConversionSequenceAllocator; + + SourceLocation Loc; + CandidateSetKind Kind; + + unsigned NumInlineSequences; + llvm::AlignedCharArray<llvm::AlignOf<ImplicitConversionSequence>::Alignment, + 16 * sizeof(ImplicitConversionSequence)> InlineSpace; + + OverloadCandidateSet(const OverloadCandidateSet &) = delete; + void operator=(const OverloadCandidateSet &) = delete; + + void destroyCandidates(); + + public: + OverloadCandidateSet(SourceLocation Loc, CandidateSetKind CSK) + : Loc(Loc), Kind(CSK), NumInlineSequences(0) {} + ~OverloadCandidateSet() { destroyCandidates(); } + + SourceLocation getLocation() const { return Loc; } + CandidateSetKind getKind() const { return Kind; } + + /// \brief Determine when this overload candidate will be new to the + /// overload set. + bool isNewCandidate(Decl *F) { + return Functions.insert(F->getCanonicalDecl()).second; + } + + /// \brief Clear out all of the candidates. + void clear(); + + typedef SmallVectorImpl<OverloadCandidate>::iterator iterator; + iterator begin() { return Candidates.begin(); } + iterator end() { return Candidates.end(); } + + size_t size() const { return Candidates.size(); } + bool empty() const { return Candidates.empty(); } + + /// \brief Add a new candidate with NumConversions conversion sequence slots + /// to the overload set. + OverloadCandidate &addCandidate(unsigned NumConversions = 0) { + Candidates.push_back(OverloadCandidate()); + OverloadCandidate &C = Candidates.back(); + + // Assign space from the inline array if there are enough free slots + // available. + if (NumConversions + NumInlineSequences <= 16) { + ImplicitConversionSequence *I = + (ImplicitConversionSequence *)InlineSpace.buffer; + C.Conversions = &I[NumInlineSequences]; + NumInlineSequences += NumConversions; + } else { + // Otherwise get memory from the allocator. + C.Conversions = ConversionSequenceAllocator + .Allocate<ImplicitConversionSequence>(NumConversions); + } + + // Construct the new objects. + for (unsigned i = 0; i != NumConversions; ++i) + new (&C.Conversions[i]) ImplicitConversionSequence(); + + C.NumConversions = NumConversions; + return C; + } + + /// Find the best viable function on this overload set, if it exists. + OverloadingResult BestViableFunction(Sema &S, SourceLocation Loc, + OverloadCandidateSet::iterator& Best, + bool UserDefinedConversion = false); + + void NoteCandidates(Sema &S, + OverloadCandidateDisplayKind OCD, + ArrayRef<Expr *> Args, + StringRef Opc = "", + SourceLocation Loc = SourceLocation()); + }; + + bool isBetterOverloadCandidate(Sema &S, + const OverloadCandidate& Cand1, + const OverloadCandidate& Cand2, + SourceLocation Loc, + bool UserDefinedConversion = false); +} // end namespace clang + +#endif // LLVM_CLANG_SEMA_OVERLOAD_H diff --git a/contrib/llvm/tools/clang/include/clang/Sema/Ownership.h b/contrib/llvm/tools/clang/include/clang/Sema/Ownership.h new file mode 100644 index 0000000..8acf9e8 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Sema/Ownership.h @@ -0,0 +1,287 @@ +//===--- Ownership.h - Parser ownership helpers -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains classes for managing ownership of Stmt and Expr nodes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_OWNERSHIP_H +#define LLVM_CLANG_SEMA_OWNERSHIP_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/PointerIntPair.h" + +//===----------------------------------------------------------------------===// +// OpaquePtr +//===----------------------------------------------------------------------===// + +namespace clang { + class CXXCtorInitializer; + class CXXBaseSpecifier; + class Decl; + class Expr; + class ParsedTemplateArgument; + class QualType; + class Stmt; + class TemplateName; + class TemplateParameterList; + + /// \brief Wrapper for void* pointer. + /// \tparam PtrTy Either a pointer type like 'T*' or a type that behaves like + /// a pointer. + /// + /// This is a very simple POD type that wraps a pointer that the Parser + /// doesn't know about but that Sema or another client does. The PtrTy + /// template argument is used to make sure that "Decl" pointers are not + /// compatible with "Type" pointers for example. + template <class PtrTy> + class OpaquePtr { + void *Ptr; + explicit OpaquePtr(void *Ptr) : Ptr(Ptr) {} + + typedef llvm::PointerLikeTypeTraits<PtrTy> Traits; + + public: + OpaquePtr() : Ptr(nullptr) {} + + static OpaquePtr make(PtrTy P) { OpaquePtr OP; OP.set(P); return OP; } + + /// \brief Returns plain pointer to the entity pointed by this wrapper. + /// \tparam PointeeT Type of pointed entity. + /// + /// It is identical to getPtrAs<PointeeT*>. + template <typename PointeeT> PointeeT* getPtrTo() const { + return get(); + } + + /// \brief Returns pointer converted to the specified type. + /// \tparam PtrT Result pointer type. There must be implicit conversion + /// from PtrTy to PtrT. + /// + /// In contrast to getPtrTo, this method allows the return type to be + /// a smart pointer. + template <typename PtrT> PtrT getPtrAs() const { + return get(); + } + + PtrTy get() const { + return Traits::getFromVoidPointer(Ptr); + } + + void set(PtrTy P) { + Ptr = Traits::getAsVoidPointer(P); + } + + explicit operator bool() const { return Ptr != nullptr; } + + void *getAsOpaquePtr() const { return Ptr; } + static OpaquePtr getFromOpaquePtr(void *P) { return OpaquePtr(P); } + }; + + /// UnionOpaquePtr - A version of OpaquePtr suitable for membership + /// in a union. + template <class T> struct UnionOpaquePtr { + void *Ptr; + + static UnionOpaquePtr make(OpaquePtr<T> P) { + UnionOpaquePtr OP = { P.getAsOpaquePtr() }; + return OP; + } + + OpaquePtr<T> get() const { return OpaquePtr<T>::getFromOpaquePtr(Ptr); } + operator OpaquePtr<T>() const { return get(); } + + UnionOpaquePtr &operator=(OpaquePtr<T> P) { + Ptr = P.getAsOpaquePtr(); + return *this; + } + }; +} + +namespace llvm { + template <class T> + class PointerLikeTypeTraits<clang::OpaquePtr<T> > { + public: + static inline void *getAsVoidPointer(clang::OpaquePtr<T> P) { + // FIXME: Doesn't work? return P.getAs< void >(); + return P.getAsOpaquePtr(); + } + static inline clang::OpaquePtr<T> getFromVoidPointer(void *P) { + return clang::OpaquePtr<T>::getFromOpaquePtr(P); + } + enum { NumLowBitsAvailable = 0 }; + }; + + template <class T> + struct isPodLike<clang::OpaquePtr<T> > { static const bool value = true; }; +} + +namespace clang { + // Basic + class DiagnosticBuilder; + + // Determines whether the low bit of the result pointer for the + // given UID is always zero. If so, ActionResult will use that bit + // for it's "invalid" flag. + template<class Ptr> + struct IsResultPtrLowBitFree { + static const bool value = false; + }; + + /// ActionResult - This structure is used while parsing/acting on + /// expressions, stmts, etc. It encapsulates both the object returned by + /// the action, plus a sense of whether or not it is valid. + /// When CompressInvalid is true, the "invalid" flag will be + /// stored in the low bit of the Val pointer. + template<class PtrTy, + bool CompressInvalid = IsResultPtrLowBitFree<PtrTy>::value> + class ActionResult { + PtrTy Val; + bool Invalid; + + public: + ActionResult(bool Invalid = false) + : Val(PtrTy()), Invalid(Invalid) {} + ActionResult(PtrTy val) : Val(val), Invalid(false) {} + ActionResult(const DiagnosticBuilder &) : Val(PtrTy()), Invalid(true) {} + + // These two overloads prevent void* -> bool conversions. + ActionResult(const void *); + ActionResult(volatile void *); + + bool isInvalid() const { return Invalid; } + bool isUsable() const { return !Invalid && Val; } + bool isUnset() const { return !Invalid && !Val; } + + PtrTy get() const { return Val; } + template <typename T> T *getAs() { return static_cast<T*>(get()); } + + void set(PtrTy V) { Val = V; } + + const ActionResult &operator=(PtrTy RHS) { + Val = RHS; + Invalid = false; + return *this; + } + }; + + // This ActionResult partial specialization places the "invalid" + // flag into the low bit of the pointer. + template<typename PtrTy> + class ActionResult<PtrTy, true> { + // A pointer whose low bit is 1 if this result is invalid, 0 + // otherwise. + uintptr_t PtrWithInvalid; + typedef llvm::PointerLikeTypeTraits<PtrTy> PtrTraits; + public: + ActionResult(bool Invalid = false) + : PtrWithInvalid(static_cast<uintptr_t>(Invalid)) { } + + ActionResult(PtrTy V) { + void *VP = PtrTraits::getAsVoidPointer(V); + PtrWithInvalid = reinterpret_cast<uintptr_t>(VP); + assert((PtrWithInvalid & 0x01) == 0 && "Badly aligned pointer"); + } + ActionResult(const DiagnosticBuilder &) : PtrWithInvalid(0x01) { } + + // These two overloads prevent void* -> bool conversions. + ActionResult(const void *); + ActionResult(volatile void *); + + bool isInvalid() const { return PtrWithInvalid & 0x01; } + bool isUsable() const { return PtrWithInvalid > 0x01; } + bool isUnset() const { return PtrWithInvalid == 0; } + + PtrTy get() const { + void *VP = reinterpret_cast<void *>(PtrWithInvalid & ~0x01); + return PtrTraits::getFromVoidPointer(VP); + } + template <typename T> T *getAs() { return static_cast<T*>(get()); } + + void set(PtrTy V) { + void *VP = PtrTraits::getAsVoidPointer(V); + PtrWithInvalid = reinterpret_cast<uintptr_t>(VP); + assert((PtrWithInvalid & 0x01) == 0 && "Badly aligned pointer"); + } + + const ActionResult &operator=(PtrTy RHS) { + void *VP = PtrTraits::getAsVoidPointer(RHS); + PtrWithInvalid = reinterpret_cast<uintptr_t>(VP); + assert((PtrWithInvalid & 0x01) == 0 && "Badly aligned pointer"); + return *this; + } + + // For types where we can fit a flag in with the pointer, provide + // conversions to/from pointer type. + static ActionResult getFromOpaquePointer(void *P) { + ActionResult Result; + Result.PtrWithInvalid = (uintptr_t)P; + return Result; + } + void *getAsOpaquePointer() const { return (void*)PtrWithInvalid; } + }; + + /// An opaque type for threading parsed type information through the + /// parser. + typedef OpaquePtr<QualType> ParsedType; + typedef UnionOpaquePtr<QualType> UnionParsedType; + + // We can re-use the low bit of expression, statement, base, and + // member-initializer pointers for the "invalid" flag of + // ActionResult. + template<> struct IsResultPtrLowBitFree<Expr*> { + static const bool value = true; + }; + template<> struct IsResultPtrLowBitFree<Stmt*> { + static const bool value = true; + }; + template<> struct IsResultPtrLowBitFree<CXXBaseSpecifier*> { + static const bool value = true; + }; + template<> struct IsResultPtrLowBitFree<CXXCtorInitializer*> { + static const bool value = true; + }; + + typedef ActionResult<Expr*> ExprResult; + typedef ActionResult<Stmt*> StmtResult; + typedef ActionResult<ParsedType> TypeResult; + typedef ActionResult<CXXBaseSpecifier*> BaseResult; + typedef ActionResult<CXXCtorInitializer*> MemInitResult; + + typedef ActionResult<Decl*> DeclResult; + typedef OpaquePtr<TemplateName> ParsedTemplateTy; + + typedef MutableArrayRef<Expr*> MultiExprArg; + typedef MutableArrayRef<Stmt*> MultiStmtArg; + typedef MutableArrayRef<ParsedTemplateArgument> ASTTemplateArgsPtr; + typedef MutableArrayRef<ParsedType> MultiTypeArg; + typedef MutableArrayRef<TemplateParameterList*> MultiTemplateParamsArg; + + inline ExprResult ExprError() { return ExprResult(true); } + inline StmtResult StmtError() { return StmtResult(true); } + + inline ExprResult ExprError(const DiagnosticBuilder&) { return ExprError(); } + inline StmtResult StmtError(const DiagnosticBuilder&) { return StmtError(); } + + inline ExprResult ExprEmpty() { return ExprResult(false); } + inline StmtResult StmtEmpty() { return StmtResult(false); } + + inline Expr *AssertSuccess(ExprResult R) { + assert(!R.isInvalid() && "operation was asserted to never fail!"); + return R.get(); + } + + inline Stmt *AssertSuccess(StmtResult R) { + assert(!R.isInvalid() && "operation was asserted to never fail!"); + return R.get(); + } +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Sema/ParsedTemplate.h b/contrib/llvm/tools/clang/include/clang/Sema/ParsedTemplate.h new file mode 100644 index 0000000..b36425f --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Sema/ParsedTemplate.h @@ -0,0 +1,214 @@ +//===--- ParsedTemplate.h - Template Parsing Data Types -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides data structures that store the parsed representation of +// templates. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_SEMA_PARSEDTEMPLATE_H +#define LLVM_CLANG_SEMA_PARSEDTEMPLATE_H + +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/Ownership.h" +#include <cassert> + +namespace clang { + /// \brief Represents the parsed form of a C++ template argument. + class ParsedTemplateArgument { + public: + /// \brief Describes the kind of template argument that was parsed. + enum KindType { + /// \brief A template type parameter, stored as a type. + Type, + /// \brief A non-type template parameter, stored as an expression. + NonType, + /// \brief A template template argument, stored as a template name. + Template + }; + + /// \brief Build an empty template argument. + /// + /// This template argument is invalid. + ParsedTemplateArgument() : Kind(Type), Arg(nullptr) { } + + /// \brief Create a template type argument or non-type template argument. + /// + /// \param Arg the template type argument or non-type template argument. + /// \param Loc the location of the type. + ParsedTemplateArgument(KindType Kind, void *Arg, SourceLocation Loc) + : Kind(Kind), Arg(Arg), Loc(Loc) { } + + /// \brief Create a template template argument. + /// + /// \param SS the C++ scope specifier that precedes the template name, if + /// any. + /// + /// \param Template the template to which this template template + /// argument refers. + /// + /// \param TemplateLoc the location of the template name. + ParsedTemplateArgument(const CXXScopeSpec &SS, + ParsedTemplateTy Template, + SourceLocation TemplateLoc) + : Kind(ParsedTemplateArgument::Template), + Arg(Template.getAsOpaquePtr()), + SS(SS), Loc(TemplateLoc), EllipsisLoc() { } + + /// \brief Determine whether the given template argument is invalid. + bool isInvalid() const { return Arg == nullptr; } + + /// \brief Determine what kind of template argument we have. + KindType getKind() const { return Kind; } + + /// \brief Retrieve the template type argument's type. + ParsedType getAsType() const { + assert(Kind == Type && "Not a template type argument"); + return ParsedType::getFromOpaquePtr(Arg); + } + + /// \brief Retrieve the non-type template argument's expression. + Expr *getAsExpr() const { + assert(Kind == NonType && "Not a non-type template argument"); + return static_cast<Expr*>(Arg); + } + + /// \brief Retrieve the template template argument's template name. + ParsedTemplateTy getAsTemplate() const { + assert(Kind == Template && "Not a template template argument"); + return ParsedTemplateTy::getFromOpaquePtr(Arg); + } + + /// \brief Retrieve the location of the template argument. + SourceLocation getLocation() const { return Loc; } + + /// \brief Retrieve the nested-name-specifier that precedes the template + /// name in a template template argument. + const CXXScopeSpec &getScopeSpec() const { + assert(Kind == Template && + "Only template template arguments can have a scope specifier"); + return SS; + } + + /// \brief Retrieve the location of the ellipsis that makes a template + /// template argument into a pack expansion. + SourceLocation getEllipsisLoc() const { + assert(Kind == Template && + "Only template template arguments can have an ellipsis"); + return EllipsisLoc; + } + + /// \brief Retrieve a pack expansion of the given template template + /// argument. + /// + /// \param EllipsisLoc The location of the ellipsis. + ParsedTemplateArgument getTemplatePackExpansion( + SourceLocation EllipsisLoc) const; + + private: + KindType Kind; + + /// \brief The actual template argument representation, which may be + /// an \c ActionBase::TypeTy* (for a type), an Expr* (for an + /// expression), or an ActionBase::TemplateTy (for a template). + void *Arg; + + /// \brief The nested-name-specifier that can accompany a template template + /// argument. + CXXScopeSpec SS; + + /// \brief the location of the template argument. + SourceLocation Loc; + + /// \brief The ellipsis location that can accompany a template template + /// argument (turning it into a template template argument expansion). + SourceLocation EllipsisLoc; + }; + + /// \brief Information about a template-id annotation + /// token. + /// + /// A template-id annotation token contains the template declaration, + /// template arguments, whether those template arguments were types, + /// expressions, or template names, and the source locations for important + /// tokens. All of the information about template arguments is allocated + /// directly after this structure. + struct TemplateIdAnnotation { + /// \brief The nested-name-specifier that precedes the template name. + CXXScopeSpec SS; + + /// TemplateKWLoc - The location of the template keyword within the + /// source. + SourceLocation TemplateKWLoc; + + /// TemplateNameLoc - The location of the template name within the + /// source. + SourceLocation TemplateNameLoc; + + /// 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. + ParsedTemplateTy Template; + + /// The kind of template that Template refers to. + TemplateNameKind Kind; + + /// The location of the '<' before the template argument + /// list. + SourceLocation LAngleLoc; + + /// The location of the '>' after the template argument + /// list. + SourceLocation RAngleLoc; + + /// NumArgs - The number of template arguments. + unsigned NumArgs; + + /// \brief Retrieves a pointer to the template arguments + ParsedTemplateArgument *getTemplateArgs() { + return reinterpret_cast<ParsedTemplateArgument *>(this + 1); + } + + /// \brief Creates a new TemplateIdAnnotation with NumArgs arguments and + /// appends it to List. + static TemplateIdAnnotation * + Allocate(unsigned NumArgs, SmallVectorImpl<TemplateIdAnnotation*> &List) { + TemplateIdAnnotation *TemplateId + = (TemplateIdAnnotation *)std::malloc(sizeof(TemplateIdAnnotation) + + sizeof(ParsedTemplateArgument) * NumArgs); + TemplateId->NumArgs = NumArgs; + + // Default-construct nested-name-specifier. + new (&TemplateId->SS) CXXScopeSpec(); + + // Default-construct parsed template arguments. + ParsedTemplateArgument *TemplateArgs = TemplateId->getTemplateArgs(); + for (unsigned I = 0; I != NumArgs; ++I) + new (TemplateArgs + I) ParsedTemplateArgument(); + + List.push_back(TemplateId); + return TemplateId; + } + + void Destroy() { + SS.~CXXScopeSpec(); + free(this); + } + }; + + /// Retrieves the range of the given template parameter lists. + SourceRange getTemplateParamsRange(TemplateParameterList const *const *Params, + unsigned NumParams); +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Sema/PrettyDeclStackTrace.h b/contrib/llvm/tools/clang/include/clang/Sema/PrettyDeclStackTrace.h new file mode 100644 index 0000000..ca22e64 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Sema/PrettyDeclStackTrace.h @@ -0,0 +1,47 @@ +//===- PrettyDeclStackTrace.h - Stack trace for decl processing -*- 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 an llvm::PrettyStackTraceEntry object for showing +// that a particular declaration was being processed when a crash +// occurred. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_PRETTYDECLSTACKTRACE_H +#define LLVM_CLANG_SEMA_PRETTYDECLSTACKTRACE_H + +#include "clang/Basic/SourceLocation.h" +#include "llvm/Support/PrettyStackTrace.h" + +namespace clang { + +class Decl; +class Sema; +class SourceManager; + +/// PrettyDeclStackTraceEntry - If a crash occurs in the parser while +/// parsing something related to a declaration, include that +/// declaration in the stack trace. +class PrettyDeclStackTraceEntry : public llvm::PrettyStackTraceEntry { + Sema &S; + Decl *TheDecl; + SourceLocation Loc; + const char *Message; + +public: + PrettyDeclStackTraceEntry(Sema &S, Decl *D, SourceLocation Loc, + const char *Msg) + : S(S), TheDecl(D), Loc(Loc), Message(Msg) {} + + void print(raw_ostream &OS) const override; +}; + +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Sema/Scope.h b/contrib/llvm/tools/clang/include/clang/Sema/Scope.h new file mode 100644 index 0000000..dfc6f9c --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Sema/Scope.h @@ -0,0 +1,484 @@ +//===--- Scope.h - Scope interface ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Scope interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SCOPE_H +#define LLVM_CLANG_SEMA_SCOPE_H + +#include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" + +namespace llvm { + +class raw_ostream; + +} + +namespace clang { + +class Decl; +class UsingDirectiveDecl; +class VarDecl; + +/// Scope - A scope is a transient data structure that is used while parsing the +/// program. It assists with resolving identifiers to the appropriate +/// declaration. +/// +class Scope { +public: + /// ScopeFlags - These are bitfields that are or'd together when creating a + /// scope, which defines the sorts of things the scope contains. + enum ScopeFlags { + /// \brief This indicates that the scope corresponds to a function, which + /// means that labels are set here. + FnScope = 0x01, + + /// \brief This is a while, do, switch, for, etc that can have break + /// statements embedded into it. + BreakScope = 0x02, + + /// \brief This is a while, do, for, which can have continue statements + /// embedded into it. + ContinueScope = 0x04, + + /// \brief This is a scope that can contain a declaration. Some scopes + /// just contain loop constructs but don't contain decls. + DeclScope = 0x08, + + /// \brief The controlling scope in a if/switch/while/for statement. + ControlScope = 0x10, + + /// \brief The scope of a struct/union/class definition. + ClassScope = 0x20, + + /// \brief This is a scope that corresponds to a block/closure object. + /// Blocks serve as top-level scopes for some objects like labels, they + /// also prevent things like break and continue. BlockScopes always have + /// the FnScope and DeclScope flags set as well. + BlockScope = 0x40, + + /// \brief This is a scope that corresponds to the + /// template parameters of a C++ template. Template parameter + /// scope starts at the 'template' keyword and ends when the + /// template declaration ends. + TemplateParamScope = 0x80, + + /// \brief This is a scope that corresponds to the + /// parameters within a function prototype. + FunctionPrototypeScope = 0x100, + + /// \brief This is a scope that corresponds to the parameters within + /// a function prototype for a function declaration (as opposed to any + /// other kind of function declarator). Always has FunctionPrototypeScope + /// set as well. + FunctionDeclarationScope = 0x200, + + /// \brief This is a scope that corresponds to the Objective-C + /// \@catch statement. + AtCatchScope = 0x400, + + /// \brief This scope corresponds to an Objective-C method body. + /// It always has FnScope and DeclScope set as well. + ObjCMethodScope = 0x800, + + /// \brief This is a scope that corresponds to a switch statement. + SwitchScope = 0x1000, + + /// \brief This is the scope of a C++ try statement. + TryScope = 0x2000, + + /// \brief This is the scope for a function-level C++ try or catch scope. + FnTryCatchScope = 0x4000, + + /// \brief This is the scope of OpenMP executable directive. + OpenMPDirectiveScope = 0x8000, + + /// \brief This is the scope of some OpenMP loop directive. + OpenMPLoopDirectiveScope = 0x10000, + + /// \brief This is the scope of some OpenMP simd directive. + /// For example, it is used for 'omp simd', 'omp for simd'. + /// This flag is propagated to children scopes. + OpenMPSimdDirectiveScope = 0x20000, + + /// This scope corresponds to an enum. + EnumScope = 0x40000, + + /// This scope corresponds to an SEH try. + SEHTryScope = 0x80000, + + /// This scope corresponds to an SEH except. + SEHExceptScope = 0x100000, + + /// We are currently in the filter expression of an SEH except block. + SEHFilterScope = 0x200000, + }; +private: + /// The parent scope for this scope. This is null for the translation-unit + /// scope. + Scope *AnyParent; + + /// Flags - This contains a set of ScopeFlags, which indicates how the scope + /// interrelates with other control flow statements. + unsigned Flags; + + /// Depth - This is the depth of this scope. The translation-unit scope has + /// depth 0. + unsigned short Depth; + + /// \brief Declarations with static linkage are mangled with the number of + /// scopes seen as a component. + unsigned short MSLastManglingNumber; + + unsigned short MSCurManglingNumber; + + /// PrototypeDepth - This is the number of function prototype scopes + /// enclosing this scope, including this scope. + unsigned short PrototypeDepth; + + /// PrototypeIndex - This is the number of parameters currently + /// declared in this scope. + unsigned short PrototypeIndex; + + /// FnParent - If this scope has a parent scope that is a function body, this + /// pointer is non-null and points to it. This is used for label processing. + Scope *FnParent; + Scope *MSLastManglingParent; + + /// BreakParent/ContinueParent - This is a direct link to the innermost + /// BreakScope/ContinueScope which contains the contents of this scope + /// for control flow purposes (and might be this scope itself), or null + /// if there is no such scope. + Scope *BreakParent, *ContinueParent; + + /// BlockParent - This is a direct link to the immediately containing + /// BlockScope if this scope is not one, or null if there is none. + Scope *BlockParent; + + /// TemplateParamParent - This is a direct link to the + /// immediately containing template parameter scope. In the + /// case of nested templates, template parameter scopes can have + /// other template parameter scopes as parents. + Scope *TemplateParamParent; + + /// DeclsInScope - This keeps track of all declarations in this scope. When + /// the declaration is added to the scope, it is set as the current + /// declaration for the identifier in the IdentifierTable. When the scope is + /// popped, these declarations are removed from the IdentifierTable's notion + /// of current declaration. It is up to the current Action implementation to + /// implement these semantics. + typedef llvm::SmallPtrSet<Decl *, 32> DeclSetTy; + DeclSetTy DeclsInScope; + + /// The DeclContext with which this scope is associated. For + /// example, the entity of a class scope is the class itself, the + /// entity of a function scope is a function, etc. + DeclContext *Entity; + + typedef SmallVector<UsingDirectiveDecl *, 2> UsingDirectivesTy; + UsingDirectivesTy UsingDirectives; + + /// \brief Used to determine if errors occurred in this scope. + DiagnosticErrorTrap ErrorTrap; + + /// A lattice consisting of undefined, a single NRVO candidate variable in + /// this scope, or over-defined. The bit is true when over-defined. + llvm::PointerIntPair<VarDecl *, 1, bool> NRVO; + +public: + Scope(Scope *Parent, unsigned ScopeFlags, DiagnosticsEngine &Diag) + : ErrorTrap(Diag) { + Init(Parent, ScopeFlags); + } + + /// getFlags - Return the flags for this scope. + /// + unsigned getFlags() const { return Flags; } + void setFlags(unsigned F) { Flags = F; } + + /// isBlockScope - Return true if this scope correspond to a closure. + bool isBlockScope() const { return Flags & BlockScope; } + + /// getParent - Return the scope that this is nested in. + /// + const Scope *getParent() const { return AnyParent; } + Scope *getParent() { return AnyParent; } + + /// getFnParent - Return the closest scope that is a function body. + /// + const Scope *getFnParent() const { return FnParent; } + Scope *getFnParent() { return FnParent; } + + const Scope *getMSLastManglingParent() const { + return MSLastManglingParent; + } + Scope *getMSLastManglingParent() { return MSLastManglingParent; } + + /// getContinueParent - Return the closest scope that a continue statement + /// would be affected by. + Scope *getContinueParent() { + return ContinueParent; + } + + const Scope *getContinueParent() const { + return const_cast<Scope*>(this)->getContinueParent(); + } + + /// getBreakParent - Return the closest scope that a break statement + /// would be affected by. + Scope *getBreakParent() { + return BreakParent; + } + const Scope *getBreakParent() const { + return const_cast<Scope*>(this)->getBreakParent(); + } + + Scope *getBlockParent() { return BlockParent; } + const Scope *getBlockParent() const { return BlockParent; } + + Scope *getTemplateParamParent() { return TemplateParamParent; } + const Scope *getTemplateParamParent() const { return TemplateParamParent; } + + /// Returns the number of function prototype scopes in this scope + /// chain. + unsigned getFunctionPrototypeDepth() const { + return PrototypeDepth; + } + + /// Return the number of parameters declared in this function + /// prototype, increasing it by one for the next call. + unsigned getNextFunctionPrototypeIndex() { + assert(isFunctionPrototypeScope()); + return PrototypeIndex++; + } + + typedef llvm::iterator_range<DeclSetTy::iterator> decl_range; + decl_range decls() const { + return decl_range(DeclsInScope.begin(), DeclsInScope.end()); + } + bool decl_empty() const { return DeclsInScope.empty(); } + + void AddDecl(Decl *D) { + DeclsInScope.insert(D); + } + + void RemoveDecl(Decl *D) { + DeclsInScope.erase(D); + } + + void incrementMSManglingNumber() { + if (Scope *MSLMP = getMSLastManglingParent()) { + MSLMP->MSLastManglingNumber += 1; + MSCurManglingNumber += 1; + } + } + + void decrementMSManglingNumber() { + if (Scope *MSLMP = getMSLastManglingParent()) { + MSLMP->MSLastManglingNumber -= 1; + MSCurManglingNumber -= 1; + } + } + + unsigned getMSLastManglingNumber() const { + if (const Scope *MSLMP = getMSLastManglingParent()) + return MSLMP->MSLastManglingNumber; + return 1; + } + + unsigned getMSCurManglingNumber() const { + return MSCurManglingNumber; + } + + /// isDeclScope - Return true if this is the scope that the specified decl is + /// declared in. + bool isDeclScope(Decl *D) { + return DeclsInScope.count(D) != 0; + } + + DeclContext *getEntity() const { return Entity; } + void setEntity(DeclContext *E) { Entity = E; } + + bool hasErrorOccurred() const { return ErrorTrap.hasErrorOccurred(); } + + bool hasUnrecoverableErrorOccurred() const { + return ErrorTrap.hasUnrecoverableErrorOccurred(); + } + + /// isFunctionScope() - Return true if this scope is a function scope. + bool isFunctionScope() const { return (getFlags() & Scope::FnScope); } + + /// isClassScope - Return true if this scope is a class/struct/union scope. + bool isClassScope() const { + return (getFlags() & Scope::ClassScope); + } + + /// isInCXXInlineMethodScope - Return true if this scope is a C++ inline + /// method scope or is inside one. + bool isInCXXInlineMethodScope() const { + if (const Scope *FnS = getFnParent()) { + assert(FnS->getParent() && "TUScope not created?"); + return FnS->getParent()->isClassScope(); + } + return false; + } + + /// isInObjcMethodScope - Return true if this scope is, or is contained in, an + /// Objective-C method body. Note that this method is not constant time. + bool isInObjcMethodScope() const { + for (const Scope *S = this; S; S = S->getParent()) { + // If this scope is an objc method scope, then we succeed. + if (S->getFlags() & ObjCMethodScope) + return true; + } + return false; + } + + /// isInObjcMethodOuterScope - Return true if this scope is an + /// Objective-C method outer most body. + bool isInObjcMethodOuterScope() const { + if (const Scope *S = this) { + // If this scope is an objc method scope, then we succeed. + if (S->getFlags() & ObjCMethodScope) + return true; + } + return false; + } + + + /// isTemplateParamScope - Return true if this scope is a C++ + /// template parameter scope. + bool isTemplateParamScope() const { + return getFlags() & Scope::TemplateParamScope; + } + + /// isFunctionPrototypeScope - Return true if this scope is a + /// function prototype scope. + bool isFunctionPrototypeScope() const { + return getFlags() & Scope::FunctionPrototypeScope; + } + + /// isAtCatchScope - Return true if this scope is \@catch. + bool isAtCatchScope() const { + return getFlags() & Scope::AtCatchScope; + } + + /// isSwitchScope - Return true if this scope is a switch scope. + bool isSwitchScope() const { + for (const Scope *S = this; S; S = S->getParent()) { + if (S->getFlags() & Scope::SwitchScope) + return true; + else if (S->getFlags() & (Scope::FnScope | Scope::ClassScope | + Scope::BlockScope | Scope::TemplateParamScope | + Scope::FunctionPrototypeScope | + Scope::AtCatchScope | Scope::ObjCMethodScope)) + return false; + } + return false; + } + + /// \brief Determines whether this scope is the OpenMP directive scope + bool isOpenMPDirectiveScope() const { + return (getFlags() & Scope::OpenMPDirectiveScope); + } + + /// \brief Determine whether this scope is some OpenMP loop directive scope + /// (for example, 'omp for', 'omp simd'). + bool isOpenMPLoopDirectiveScope() const { + if (getFlags() & Scope::OpenMPLoopDirectiveScope) { + assert(isOpenMPDirectiveScope() && + "OpenMP loop directive scope is not a directive scope"); + return true; + } + return false; + } + + /// \brief Determine whether this scope is (or is nested into) some OpenMP + /// loop simd directive scope (for example, 'omp simd', 'omp for simd'). + bool isOpenMPSimdDirectiveScope() const { + return getFlags() & Scope::OpenMPSimdDirectiveScope; + } + + /// \brief Determine whether this scope is a loop having OpenMP loop + /// directive attached. + bool isOpenMPLoopScope() const { + const Scope *P = getParent(); + return P && P->isOpenMPLoopDirectiveScope(); + } + + /// \brief Determine whether this scope is a C++ 'try' block. + bool isTryScope() const { return getFlags() & Scope::TryScope; } + + /// \brief Determine whether this scope is a SEH '__try' block. + bool isSEHTryScope() const { return getFlags() & Scope::SEHTryScope; } + + /// \brief Determine whether this scope is a SEH '__except' block. + bool isSEHExceptScope() const { return getFlags() & Scope::SEHExceptScope; } + + /// \brief Returns if rhs has a higher scope depth than this. + /// + /// The caller is responsible for calling this only if one of the two scopes + /// is an ancestor of the other. + bool Contains(const Scope& rhs) const { return Depth < rhs.Depth; } + + /// containedInPrototypeScope - Return true if this or a parent scope + /// is a FunctionPrototypeScope. + bool containedInPrototypeScope() const; + + void PushUsingDirective(UsingDirectiveDecl *UDir) { + UsingDirectives.push_back(UDir); + } + + typedef llvm::iterator_range<UsingDirectivesTy::iterator> + using_directives_range; + + using_directives_range using_directives() { + return using_directives_range(UsingDirectives.begin(), + UsingDirectives.end()); + } + + void addNRVOCandidate(VarDecl *VD) { + if (NRVO.getInt()) + return; + if (NRVO.getPointer() == nullptr) { + NRVO.setPointer(VD); + return; + } + if (NRVO.getPointer() != VD) + setNoNRVO(); + } + + void setNoNRVO() { + NRVO.setInt(1); + NRVO.setPointer(nullptr); + } + + void mergeNRVOIntoParent(); + + /// Init - This is used by the parser to implement scope caching. + /// + void Init(Scope *parent, unsigned flags); + + /// \brief Sets up the specified scope flags and adjusts the scope state + /// variables accordingly. + /// + void AddFlags(unsigned Flags); + + void dumpImpl(raw_ostream &OS) const; + void dump() const; +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Sema/ScopeInfo.h b/contrib/llvm/tools/clang/include/clang/Sema/ScopeInfo.h new file mode 100644 index 0000000..d13667e --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Sema/ScopeInfo.h @@ -0,0 +1,858 @@ +//===--- ScopeInfo.h - Information about a semantic context -----*- 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 FunctionScopeInfo and its subclasses, which contain +// information about a single function, block, lambda, or method body. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SCOPEINFO_H +#define LLVM_CLANG_SEMA_SCOPEINFO_H + +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "clang/Basic/CapturedStmt.h" +#include "clang/Basic/PartialDiagnostic.h" +#include "clang/Sema/Ownership.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallVector.h" +#include <algorithm> + +namespace clang { + +class Decl; +class BlockDecl; +class CapturedDecl; +class CXXMethodDecl; +class FieldDecl; +class ObjCPropertyDecl; +class IdentifierInfo; +class ImplicitParamDecl; +class LabelDecl; +class ReturnStmt; +class Scope; +class SwitchStmt; +class TemplateTypeParmDecl; +class TemplateParameterList; +class VarDecl; +class ObjCIvarRefExpr; +class ObjCPropertyRefExpr; +class ObjCMessageExpr; + +namespace sema { + +/// \brief Contains information about the compound statement currently being +/// parsed. +class CompoundScopeInfo { +public: + CompoundScopeInfo() + : HasEmptyLoopBodies(false) { } + + /// \brief Whether this compound stamement contains `for' or `while' loops + /// with empty bodies. + bool HasEmptyLoopBodies; + + void setHasEmptyLoopBodies() { + HasEmptyLoopBodies = true; + } +}; + +class PossiblyUnreachableDiag { +public: + PartialDiagnostic PD; + SourceLocation Loc; + const Stmt *stmt; + + PossiblyUnreachableDiag(const PartialDiagnostic &PD, SourceLocation Loc, + const Stmt *stmt) + : PD(PD), Loc(Loc), stmt(stmt) {} +}; + +/// \brief Retains information about a function, method, or block that is +/// currently being parsed. +class FunctionScopeInfo { +protected: + enum ScopeKind { + SK_Function, + SK_Block, + SK_Lambda, + SK_CapturedRegion + }; + +public: + /// \brief What kind of scope we are describing. + /// + ScopeKind Kind : 3; + + /// \brief Whether this function contains a VLA, \@try, try, C++ + /// initializer, or anything else that can't be jumped past. + bool HasBranchProtectedScope : 1; + + /// \brief Whether this function contains any switches or direct gotos. + bool HasBranchIntoScope : 1; + + /// \brief Whether this function contains any indirect gotos. + bool HasIndirectGoto : 1; + + /// \brief Whether a statement was dropped because it was invalid. + bool HasDroppedStmt : 1; + + /// A flag that is set when parsing a method that must call super's + /// implementation, such as \c -dealloc, \c -finalize, or any method marked + /// with \c __attribute__((objc_requires_super)). + bool ObjCShouldCallSuper : 1; + + /// True when this is a method marked as a designated initializer. + bool ObjCIsDesignatedInit : 1; + /// This starts true for a method marked as designated initializer and will + /// be set to false if there is an invocation to a designated initializer of + /// the super class. + bool ObjCWarnForNoDesignatedInitChain : 1; + + /// True when this is an initializer method not marked as a designated + /// initializer within a class that has at least one initializer marked as a + /// designated initializer. + bool ObjCIsSecondaryInit : 1; + /// This starts true for a secondary initializer method and will be set to + /// false if there is an invocation of an initializer on 'self'. + bool ObjCWarnForNoInitDelegation : 1; + + /// First 'return' statement in the current function. + SourceLocation FirstReturnLoc; + + /// First C++ 'try' statement in the current function. + SourceLocation FirstCXXTryLoc; + + /// First SEH '__try' statement in the current function. + SourceLocation FirstSEHTryLoc; + + /// \brief Used to determine if errors occurred in this function or block. + DiagnosticErrorTrap ErrorTrap; + + /// SwitchStack - This is the current set of active switch statements in the + /// block. + SmallVector<SwitchStmt*, 8> SwitchStack; + + /// \brief The list of return statements that occur within the function or + /// block, if there is any chance of applying the named return value + /// optimization, or if we need to infer a return type. + SmallVector<ReturnStmt*, 4> Returns; + + /// \brief The promise object for this coroutine, if any. + VarDecl *CoroutinePromise; + + /// \brief The list of coroutine control flow constructs (co_await, co_yield, + /// co_return) that occur within the function or block. Empty if and only if + /// this function or block is not (yet known to be) a coroutine. + SmallVector<Stmt*, 4> CoroutineStmts; + + /// \brief The stack of currently active compound stamement scopes in the + /// function. + SmallVector<CompoundScopeInfo, 4> CompoundScopes; + + /// \brief A list of PartialDiagnostics created but delayed within the + /// current function scope. These diagnostics are vetted for reachability + /// prior to being emitted. + SmallVector<PossiblyUnreachableDiag, 4> PossiblyUnreachableDiags; + + /// \brief A list of parameters which have the nonnull attribute and are + /// modified in the function. + llvm::SmallPtrSet<const ParmVarDecl*, 8> ModifiedNonNullParams; + +public: + /// Represents a simple identification of a weak object. + /// + /// Part of the implementation of -Wrepeated-use-of-weak. + /// + /// This is used to determine if two weak accesses refer to the same object. + /// Here are some examples of how various accesses are "profiled": + /// + /// Access Expression | "Base" Decl | "Property" Decl + /// :---------------: | :-----------------: | :------------------------------: + /// self.property | self (VarDecl) | property (ObjCPropertyDecl) + /// self.implicitProp | self (VarDecl) | -implicitProp (ObjCMethodDecl) + /// self->ivar.prop | ivar (ObjCIvarDecl) | prop (ObjCPropertyDecl) + /// cxxObj.obj.prop | obj (FieldDecl) | prop (ObjCPropertyDecl) + /// [self foo].prop | 0 (unknown) | prop (ObjCPropertyDecl) + /// self.prop1.prop2 | prop1 (ObjCPropertyDecl) | prop2 (ObjCPropertyDecl) + /// MyClass.prop | MyClass (ObjCInterfaceDecl) | -prop (ObjCMethodDecl) + /// weakVar | 0 (known) | weakVar (VarDecl) + /// self->weakIvar | self (VarDecl) | weakIvar (ObjCIvarDecl) + /// + /// Objects are identified with only two Decls to make it reasonably fast to + /// compare them. + class WeakObjectProfileTy { + /// The base object decl, as described in the class documentation. + /// + /// The extra flag is "true" if the Base and Property are enough to uniquely + /// identify the object in memory. + /// + /// \sa isExactProfile() + typedef llvm::PointerIntPair<const NamedDecl *, 1, bool> BaseInfoTy; + BaseInfoTy Base; + + /// The "property" decl, as described in the class documentation. + /// + /// Note that this may not actually be an ObjCPropertyDecl, e.g. in the + /// case of "implicit" properties (regular methods accessed via dot syntax). + const NamedDecl *Property; + + /// Used to find the proper base profile for a given base expression. + static BaseInfoTy getBaseInfo(const Expr *BaseE); + + inline WeakObjectProfileTy(); + static inline WeakObjectProfileTy getSentinel(); + + public: + WeakObjectProfileTy(const ObjCPropertyRefExpr *RE); + WeakObjectProfileTy(const Expr *Base, const ObjCPropertyDecl *Property); + WeakObjectProfileTy(const DeclRefExpr *RE); + WeakObjectProfileTy(const ObjCIvarRefExpr *RE); + + const NamedDecl *getBase() const { return Base.getPointer(); } + const NamedDecl *getProperty() const { return Property; } + + /// Returns true if the object base specifies a known object in memory, + /// rather than, say, an instance variable or property of another object. + /// + /// Note that this ignores the effects of aliasing; that is, \c foo.bar is + /// considered an exact profile if \c foo is a local variable, even if + /// another variable \c foo2 refers to the same object as \c foo. + /// + /// For increased precision, accesses with base variables that are + /// properties or ivars of 'self' (e.g. self.prop1.prop2) are considered to + /// be exact, though this is not true for arbitrary variables + /// (foo.prop1.prop2). + bool isExactProfile() const { + return Base.getInt(); + } + + bool operator==(const WeakObjectProfileTy &Other) const { + return Base == Other.Base && Property == Other.Property; + } + + // For use in DenseMap. + // We can't specialize the usual llvm::DenseMapInfo at the end of the file + // because by that point the DenseMap in FunctionScopeInfo has already been + // instantiated. + class DenseMapInfo { + public: + static inline WeakObjectProfileTy getEmptyKey() { + return WeakObjectProfileTy(); + } + static inline WeakObjectProfileTy getTombstoneKey() { + return WeakObjectProfileTy::getSentinel(); + } + + static unsigned getHashValue(const WeakObjectProfileTy &Val) { + typedef std::pair<BaseInfoTy, const NamedDecl *> Pair; + return llvm::DenseMapInfo<Pair>::getHashValue(Pair(Val.Base, + Val.Property)); + } + + static bool isEqual(const WeakObjectProfileTy &LHS, + const WeakObjectProfileTy &RHS) { + return LHS == RHS; + } + }; + }; + + /// Represents a single use of a weak object. + /// + /// Stores both the expression and whether the access is potentially unsafe + /// (i.e. it could potentially be warned about). + /// + /// Part of the implementation of -Wrepeated-use-of-weak. + class WeakUseTy { + llvm::PointerIntPair<const Expr *, 1, bool> Rep; + public: + WeakUseTy(const Expr *Use, bool IsRead) : Rep(Use, IsRead) {} + + const Expr *getUseExpr() const { return Rep.getPointer(); } + bool isUnsafe() const { return Rep.getInt(); } + void markSafe() { Rep.setInt(false); } + + bool operator==(const WeakUseTy &Other) const { + return Rep == Other.Rep; + } + }; + + /// Used to collect uses of a particular weak object in a function body. + /// + /// Part of the implementation of -Wrepeated-use-of-weak. + typedef SmallVector<WeakUseTy, 4> WeakUseVector; + + /// Used to collect all uses of weak objects in a function body. + /// + /// Part of the implementation of -Wrepeated-use-of-weak. + typedef llvm::SmallDenseMap<WeakObjectProfileTy, WeakUseVector, 8, + WeakObjectProfileTy::DenseMapInfo> + WeakObjectUseMap; + +private: + /// Used to collect all uses of weak objects in this function body. + /// + /// Part of the implementation of -Wrepeated-use-of-weak. + WeakObjectUseMap WeakObjectUses; + +protected: + FunctionScopeInfo(const FunctionScopeInfo&) = default; + +public: + /// Record that a weak object was accessed. + /// + /// Part of the implementation of -Wrepeated-use-of-weak. + template <typename ExprT> + inline void recordUseOfWeak(const ExprT *E, bool IsRead = true); + + void recordUseOfWeak(const ObjCMessageExpr *Msg, + const ObjCPropertyDecl *Prop); + + /// Record that a given expression is a "safe" access of a weak object (e.g. + /// assigning it to a strong variable.) + /// + /// Part of the implementation of -Wrepeated-use-of-weak. + void markSafeWeakUse(const Expr *E); + + const WeakObjectUseMap &getWeakObjectUses() const { + return WeakObjectUses; + } + + void setHasBranchIntoScope() { + HasBranchIntoScope = true; + } + + void setHasBranchProtectedScope() { + HasBranchProtectedScope = true; + } + + void setHasIndirectGoto() { + HasIndirectGoto = true; + } + + void setHasDroppedStmt() { + HasDroppedStmt = true; + } + + void setHasCXXTry(SourceLocation TryLoc) { + setHasBranchProtectedScope(); + FirstCXXTryLoc = TryLoc; + } + + void setHasSEHTry(SourceLocation TryLoc) { + setHasBranchProtectedScope(); + FirstSEHTryLoc = TryLoc; + } + + bool NeedsScopeChecking() const { + return !HasDroppedStmt && + (HasIndirectGoto || + (HasBranchProtectedScope && HasBranchIntoScope)); + } + + FunctionScopeInfo(DiagnosticsEngine &Diag) + : Kind(SK_Function), + HasBranchProtectedScope(false), + HasBranchIntoScope(false), + HasIndirectGoto(false), + HasDroppedStmt(false), + ObjCShouldCallSuper(false), + ObjCIsDesignatedInit(false), + ObjCWarnForNoDesignatedInitChain(false), + ObjCIsSecondaryInit(false), + ObjCWarnForNoInitDelegation(false), + ErrorTrap(Diag) { } + + virtual ~FunctionScopeInfo(); + + /// \brief Clear out the information in this function scope, making it + /// suitable for reuse. + void Clear(); +}; + +class CapturingScopeInfo : public FunctionScopeInfo { +protected: + CapturingScopeInfo(const CapturingScopeInfo&) = default; + +public: + enum ImplicitCaptureStyle { + ImpCap_None, ImpCap_LambdaByval, ImpCap_LambdaByref, ImpCap_Block, + ImpCap_CapturedRegion + }; + + ImplicitCaptureStyle ImpCaptureStyle; + + class Capture { + // There are three categories of capture: capturing 'this', capturing + // local variables, and C++1y initialized captures (which can have an + // arbitrary initializer, and don't really capture in the traditional + // sense at all). + // + // There are three ways to capture a local variable: + // - capture by copy in the C++11 sense, + // - capture by reference in the C++11 sense, and + // - __block capture. + // Lambdas explicitly specify capture by copy or capture by reference. + // For blocks, __block capture applies to variables with that annotation, + // variables of reference type are captured by reference, and other + // variables are captured by copy. + enum CaptureKind { + Cap_ByCopy, Cap_ByRef, Cap_Block, Cap_This + }; + + /// The variable being captured (if we are not capturing 'this') and whether + /// this is a nested capture. + llvm::PointerIntPair<VarDecl*, 1, bool> VarAndNested; + + /// Expression to initialize a field of the given type, and the kind of + /// capture (if this is a capture and not an init-capture). The expression + /// is only required if we are capturing ByVal and the variable's type has + /// a non-trivial copy constructor. + llvm::PointerIntPair<void *, 2, CaptureKind> InitExprAndCaptureKind; + + /// \brief The source location at which the first capture occurred. + SourceLocation Loc; + + /// \brief The location of the ellipsis that expands a parameter pack. + SourceLocation EllipsisLoc; + + /// \brief The type as it was captured, which is in effect the type of the + /// non-static data member that would hold the capture. + QualType CaptureType; + + public: + Capture(VarDecl *Var, bool Block, bool ByRef, bool IsNested, + SourceLocation Loc, SourceLocation EllipsisLoc, + QualType CaptureType, Expr *Cpy) + : VarAndNested(Var, IsNested), + InitExprAndCaptureKind(Cpy, Block ? Cap_Block : + ByRef ? Cap_ByRef : Cap_ByCopy), + Loc(Loc), EllipsisLoc(EllipsisLoc), CaptureType(CaptureType) {} + + enum IsThisCapture { ThisCapture }; + Capture(IsThisCapture, bool IsNested, SourceLocation Loc, + QualType CaptureType, Expr *Cpy) + : VarAndNested(nullptr, IsNested), + InitExprAndCaptureKind(Cpy, Cap_This), + Loc(Loc), EllipsisLoc(), CaptureType(CaptureType) {} + + bool isThisCapture() const { + return InitExprAndCaptureKind.getInt() == Cap_This; + } + bool isVariableCapture() const { + return InitExprAndCaptureKind.getInt() != Cap_This && !isVLATypeCapture(); + } + bool isCopyCapture() const { + return InitExprAndCaptureKind.getInt() == Cap_ByCopy && + !isVLATypeCapture(); + } + bool isReferenceCapture() const { + return InitExprAndCaptureKind.getInt() == Cap_ByRef; + } + bool isBlockCapture() const { + return InitExprAndCaptureKind.getInt() == Cap_Block; + } + bool isVLATypeCapture() const { + return InitExprAndCaptureKind.getInt() == Cap_ByCopy && + getVariable() == nullptr; + } + bool isNested() const { return VarAndNested.getInt(); } + + VarDecl *getVariable() const { + return VarAndNested.getPointer(); + } + + /// \brief Retrieve the location at which this variable was captured. + SourceLocation getLocation() const { return Loc; } + + /// \brief Retrieve the source location of the ellipsis, whose presence + /// indicates that the capture is a pack expansion. + SourceLocation getEllipsisLoc() const { return EllipsisLoc; } + + /// \brief Retrieve the capture type for this capture, which is effectively + /// the type of the non-static data member in the lambda/block structure + /// that would store this capture. + QualType getCaptureType() const { return CaptureType; } + + Expr *getInitExpr() const { + assert(!isVLATypeCapture() && "no init expression for type capture"); + return static_cast<Expr *>(InitExprAndCaptureKind.getPointer()); + } + }; + + CapturingScopeInfo(DiagnosticsEngine &Diag, ImplicitCaptureStyle Style) + : FunctionScopeInfo(Diag), ImpCaptureStyle(Style), CXXThisCaptureIndex(0), + HasImplicitReturnType(false) + {} + + /// CaptureMap - A map of captured variables to (index+1) into Captures. + llvm::DenseMap<VarDecl*, unsigned> CaptureMap; + + /// CXXThisCaptureIndex - The (index+1) of the capture of 'this'; + /// zero if 'this' is not captured. + unsigned CXXThisCaptureIndex; + + /// Captures - The captures. + SmallVector<Capture, 4> Captures; + + /// \brief - Whether the target type of return statements in this context + /// is deduced (e.g. a lambda or block with omitted return type). + bool HasImplicitReturnType; + + /// ReturnType - The target type of return statements in this context, + /// or null if unknown. + QualType ReturnType; + + void addCapture(VarDecl *Var, bool isBlock, bool isByref, bool isNested, + SourceLocation Loc, SourceLocation EllipsisLoc, + QualType CaptureType, Expr *Cpy) { + Captures.push_back(Capture(Var, isBlock, isByref, isNested, Loc, + EllipsisLoc, CaptureType, Cpy)); + CaptureMap[Var] = Captures.size(); + } + + void addVLATypeCapture(SourceLocation Loc, QualType CaptureType) { + Captures.push_back(Capture(/*Var*/ nullptr, /*isBlock*/ false, + /*isByref*/ false, /*isNested*/ false, Loc, + /*EllipsisLoc*/ SourceLocation(), CaptureType, + /*Cpy*/ nullptr)); + } + + void addThisCapture(bool isNested, SourceLocation Loc, QualType CaptureType, + Expr *Cpy); + + /// \brief Determine whether the C++ 'this' is captured. + bool isCXXThisCaptured() const { return CXXThisCaptureIndex != 0; } + + /// \brief Retrieve the capture of C++ 'this', if it has been captured. + Capture &getCXXThisCapture() { + assert(isCXXThisCaptured() && "this has not been captured"); + return Captures[CXXThisCaptureIndex - 1]; + } + + /// \brief Determine whether the given variable has been captured. + bool isCaptured(VarDecl *Var) const { + return CaptureMap.count(Var); + } + + /// \brief Determine whether the given variable-array type has been captured. + bool isVLATypeCaptured(const VariableArrayType *VAT) const; + + /// \brief Retrieve the capture of the given variable, if it has been + /// captured already. + Capture &getCapture(VarDecl *Var) { + assert(isCaptured(Var) && "Variable has not been captured"); + return Captures[CaptureMap[Var] - 1]; + } + + const Capture &getCapture(VarDecl *Var) const { + llvm::DenseMap<VarDecl*, unsigned>::const_iterator Known + = CaptureMap.find(Var); + assert(Known != CaptureMap.end() && "Variable has not been captured"); + return Captures[Known->second - 1]; + } + + static bool classof(const FunctionScopeInfo *FSI) { + return FSI->Kind == SK_Block || FSI->Kind == SK_Lambda + || FSI->Kind == SK_CapturedRegion; + } +}; + +/// \brief Retains information about a block that is currently being parsed. +class BlockScopeInfo final : public CapturingScopeInfo { +public: + BlockDecl *TheDecl; + + /// TheScope - This is the scope for the block itself, which contains + /// arguments etc. + Scope *TheScope; + + /// BlockType - The function type of the block, if one was given. + /// Its return type may be BuiltinType::Dependent. + QualType FunctionType; + + BlockScopeInfo(DiagnosticsEngine &Diag, Scope *BlockScope, BlockDecl *Block) + : CapturingScopeInfo(Diag, ImpCap_Block), TheDecl(Block), + TheScope(BlockScope) + { + Kind = SK_Block; + } + + ~BlockScopeInfo() override; + + static bool classof(const FunctionScopeInfo *FSI) { + return FSI->Kind == SK_Block; + } +}; + +/// \brief Retains information about a captured region. +class CapturedRegionScopeInfo final : public CapturingScopeInfo { +public: + /// \brief The CapturedDecl for this statement. + CapturedDecl *TheCapturedDecl; + /// \brief The captured record type. + RecordDecl *TheRecordDecl; + /// \brief This is the enclosing scope of the captured region. + Scope *TheScope; + /// \brief The implicit parameter for the captured variables. + ImplicitParamDecl *ContextParam; + /// \brief The kind of captured region. + CapturedRegionKind CapRegionKind; + + CapturedRegionScopeInfo(DiagnosticsEngine &Diag, Scope *S, CapturedDecl *CD, + RecordDecl *RD, ImplicitParamDecl *Context, + CapturedRegionKind K) + : CapturingScopeInfo(Diag, ImpCap_CapturedRegion), + TheCapturedDecl(CD), TheRecordDecl(RD), TheScope(S), + ContextParam(Context), CapRegionKind(K) + { + Kind = SK_CapturedRegion; + } + + ~CapturedRegionScopeInfo() override; + + /// \brief A descriptive name for the kind of captured region this is. + StringRef getRegionName() const { + switch (CapRegionKind) { + case CR_Default: + return "default captured statement"; + case CR_OpenMP: + return "OpenMP region"; + } + llvm_unreachable("Invalid captured region kind!"); + } + + static bool classof(const FunctionScopeInfo *FSI) { + return FSI->Kind == SK_CapturedRegion; + } +}; + +class LambdaScopeInfo final : public CapturingScopeInfo { +public: + /// \brief The class that describes the lambda. + CXXRecordDecl *Lambda; + + /// \brief The lambda's compiler-generated \c operator(). + CXXMethodDecl *CallOperator; + + /// \brief Source range covering the lambda introducer [...]. + SourceRange IntroducerRange; + + /// \brief Source location of the '&' or '=' specifying the default capture + /// type, if any. + SourceLocation CaptureDefaultLoc; + + /// \brief The number of captures in the \c Captures list that are + /// explicit captures. + unsigned NumExplicitCaptures; + + /// \brief Whether this is a mutable lambda. + bool Mutable; + + /// \brief Whether the (empty) parameter list is explicit. + bool ExplicitParams; + + /// \brief Whether any of the capture expressions requires cleanups. + bool ExprNeedsCleanups; + + /// \brief Whether the lambda contains an unexpanded parameter pack. + bool ContainsUnexpandedParameterPack; + + /// \brief If this is a generic lambda, use this as the depth of + /// each 'auto' parameter, during initial AST construction. + unsigned AutoTemplateParameterDepth; + + /// \brief Store the list of the auto parameters for a generic lambda. + /// If this is a generic lambda, store the list of the auto + /// parameters converted into TemplateTypeParmDecls into a vector + /// that can be used to construct the generic lambda's template + /// parameter list, during initial AST construction. + SmallVector<TemplateTypeParmDecl*, 4> AutoTemplateParams; + + /// If this is a generic lambda, and the template parameter + /// list has been created (from the AutoTemplateParams) then + /// store a reference to it (cache it to avoid reconstructing it). + TemplateParameterList *GLTemplateParameterList; + + /// \brief Contains all variable-referring-expressions (i.e. DeclRefExprs + /// or MemberExprs) that refer to local variables in a generic lambda + /// or a lambda in a potentially-evaluated-if-used context. + /// + /// Potentially capturable variables of a nested lambda that might need + /// to be captured by the lambda are housed here. + /// This is specifically useful for generic lambdas or + /// lambdas within a a potentially evaluated-if-used context. + /// If an enclosing variable is named in an expression of a lambda nested + /// within a generic lambda, we don't always know know whether the variable + /// will truly be odr-used (i.e. need to be captured) by that nested lambda, + /// until its instantiation. But we still need to capture it in the + /// enclosing lambda if all intervening lambdas can capture the variable. + + llvm::SmallVector<Expr*, 4> PotentiallyCapturingExprs; + + /// \brief Contains all variable-referring-expressions that refer + /// to local variables that are usable as constant expressions and + /// do not involve an odr-use (they may still need to be captured + /// if the enclosing full-expression is instantiation dependent). + llvm::SmallSet<Expr*, 8> NonODRUsedCapturingExprs; + + SourceLocation PotentialThisCaptureLocation; + + LambdaScopeInfo(DiagnosticsEngine &Diag) + : CapturingScopeInfo(Diag, ImpCap_None), Lambda(nullptr), + CallOperator(nullptr), NumExplicitCaptures(0), Mutable(false), + ExplicitParams(false), ExprNeedsCleanups(false), + ContainsUnexpandedParameterPack(false), AutoTemplateParameterDepth(0), + GLTemplateParameterList(nullptr) { + Kind = SK_Lambda; + } + + /// \brief Note when all explicit captures have been added. + void finishedExplicitCaptures() { + NumExplicitCaptures = Captures.size(); + } + + static bool classof(const FunctionScopeInfo *FSI) { + return FSI->Kind == SK_Lambda; + } + + /// + /// \brief Add a variable that might potentially be captured by the + /// lambda and therefore the enclosing lambdas. + /// + /// This is also used by enclosing lambda's to speculatively capture + /// variables that nested lambda's - depending on their enclosing + /// specialization - might need to capture. + /// Consider: + /// void f(int, int); <-- don't capture + /// void f(const int&, double); <-- capture + /// void foo() { + /// const int x = 10; + /// auto L = [=](auto a) { // capture 'x' + /// return [=](auto b) { + /// f(x, a); // we may or may not need to capture 'x' + /// }; + /// }; + /// } + void addPotentialCapture(Expr *VarExpr) { + assert(isa<DeclRefExpr>(VarExpr) || isa<MemberExpr>(VarExpr)); + PotentiallyCapturingExprs.push_back(VarExpr); + } + + void addPotentialThisCapture(SourceLocation Loc) { + PotentialThisCaptureLocation = Loc; + } + bool hasPotentialThisCapture() const { + return PotentialThisCaptureLocation.isValid(); + } + + /// \brief Mark a variable's reference in a lambda as non-odr using. + /// + /// For generic lambdas, if a variable is named in a potentially evaluated + /// expression, where the enclosing full expression is dependent then we + /// must capture the variable (given a default capture). + /// This is accomplished by recording all references to variables + /// (DeclRefExprs or MemberExprs) within said nested lambda in its array of + /// PotentialCaptures. All such variables have to be captured by that lambda, + /// except for as described below. + /// If that variable is usable as a constant expression and is named in a + /// manner that does not involve its odr-use (e.g. undergoes + /// lvalue-to-rvalue conversion, or discarded) record that it is so. Upon the + /// act of analyzing the enclosing full expression (ActOnFinishFullExpr) + /// if we can determine that the full expression is not instantiation- + /// dependent, then we can entirely avoid its capture. + /// + /// const int n = 0; + /// [&] (auto x) { + /// (void)+n + x; + /// }; + /// Interestingly, this strategy would involve a capture of n, even though + /// it's obviously not odr-used here, because the full-expression is + /// instantiation-dependent. It could be useful to avoid capturing such + /// variables, even when they are referred to in an instantiation-dependent + /// expression, if we can unambiguously determine that they shall never be + /// odr-used. This would involve removal of the variable-referring-expression + /// from the array of PotentialCaptures during the lvalue-to-rvalue + /// conversions. But per the working draft N3797, (post-chicago 2013) we must + /// capture such variables. + /// Before anyone is tempted to implement a strategy for not-capturing 'n', + /// consider the insightful warning in: + /// /cfe-commits/Week-of-Mon-20131104/092596.html + /// "The problem is that the set of captures for a lambda is part of the ABI + /// (since lambda layout can be made visible through inline functions and the + /// like), and there are no guarantees as to which cases we'll manage to build + /// an lvalue-to-rvalue conversion in, when parsing a template -- some + /// seemingly harmless change elsewhere in Sema could cause us to start or stop + /// building such a node. So we need a rule that anyone can implement and get + /// exactly the same result". + /// + void markVariableExprAsNonODRUsed(Expr *CapturingVarExpr) { + assert(isa<DeclRefExpr>(CapturingVarExpr) + || isa<MemberExpr>(CapturingVarExpr)); + NonODRUsedCapturingExprs.insert(CapturingVarExpr); + } + bool isVariableExprMarkedAsNonODRUsed(Expr *CapturingVarExpr) const { + assert(isa<DeclRefExpr>(CapturingVarExpr) + || isa<MemberExpr>(CapturingVarExpr)); + return NonODRUsedCapturingExprs.count(CapturingVarExpr); + } + void removePotentialCapture(Expr *E) { + PotentiallyCapturingExprs.erase( + std::remove(PotentiallyCapturingExprs.begin(), + PotentiallyCapturingExprs.end(), E), + PotentiallyCapturingExprs.end()); + } + void clearPotentialCaptures() { + PotentiallyCapturingExprs.clear(); + PotentialThisCaptureLocation = SourceLocation(); + } + unsigned getNumPotentialVariableCaptures() const { + return PotentiallyCapturingExprs.size(); + } + + bool hasPotentialCaptures() const { + return getNumPotentialVariableCaptures() || + PotentialThisCaptureLocation.isValid(); + } + + // When passed the index, returns the VarDecl and Expr associated + // with the index. + void getPotentialVariableCapture(unsigned Idx, VarDecl *&VD, Expr *&E) const; +}; + +FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy() + : Base(nullptr, false), Property(nullptr) {} + +FunctionScopeInfo::WeakObjectProfileTy +FunctionScopeInfo::WeakObjectProfileTy::getSentinel() { + FunctionScopeInfo::WeakObjectProfileTy Result; + Result.Base.setInt(true); + return Result; +} + +template <typename ExprT> +void FunctionScopeInfo::recordUseOfWeak(const ExprT *E, bool IsRead) { + assert(E); + WeakUseVector &Uses = WeakObjectUses[WeakObjectProfileTy(E)]; + Uses.push_back(WeakUseTy(E, IsRead)); +} + +inline void +CapturingScopeInfo::addThisCapture(bool isNested, SourceLocation Loc, + QualType CaptureType, Expr *Cpy) { + Captures.push_back(Capture(Capture::ThisCapture, isNested, Loc, CaptureType, + Cpy)); + CXXThisCaptureIndex = Captures.size(); +} + +} // end namespace sema +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Sema/Sema.h b/contrib/llvm/tools/clang/include/clang/Sema/Sema.h new file mode 100644 index 0000000..77d06f2 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Sema/Sema.h @@ -0,0 +1,9265 @@ +//===--- Sema.h - Semantic Analysis & AST Building --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Sema class, which performs semantic analysis and +// builds ASTs. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMA_H +#define LLVM_CLANG_SEMA_SEMA_H + +#include "clang/AST/Attr.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/ExternalASTSource.h" +#include "clang/AST/MangleNumberingContext.h" +#include "clang/AST/NSAPI.h" +#include "clang/AST/PrettyPrinter.h" +#include "clang/AST/TypeLoc.h" +#include "clang/Basic/ExpressionTraits.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/Module.h" +#include "clang/Basic/OpenMPKinds.h" +#include "clang/Basic/Specifiers.h" +#include "clang/Basic/TemplateKinds.h" +#include "clang/Basic/TypeTraits.h" +#include "clang/Sema/AnalysisBasedWarnings.h" +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/ExternalSemaSource.h" +#include "clang/Sema/IdentifierResolver.h" +#include "clang/Sema/LocInfoType.h" +#include "clang/Sema/ObjCMethodList.h" +#include "clang/Sema/Ownership.h" +#include "clang/Sema/Scope.h" +#include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/TypoCorrection.h" +#include "clang/Sema/Weak.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/TinyPtrVector.h" +#include <deque> +#include <memory> +#include <string> +#include <vector> + +namespace llvm { + class APSInt; + template <typename ValueT> struct DenseMapInfo; + template <typename ValueT, typename ValueInfoT> class DenseSet; + class SmallBitVector; + class InlineAsmIdentifierInfo; +} + +namespace clang { + class ADLResult; + class ASTConsumer; + class ASTContext; + class ASTMutationListener; + class ASTReader; + class ASTWriter; + class ArrayType; + class AttributeList; + class BlockDecl; + class CapturedDecl; + class CXXBasePath; + class CXXBasePaths; + class CXXBindTemporaryExpr; + typedef SmallVector<CXXBaseSpecifier*, 4> CXXCastPath; + class CXXConstructorDecl; + class CXXConversionDecl; + class CXXDeleteExpr; + class CXXDestructorDecl; + class CXXFieldCollector; + class CXXMemberCallExpr; + class CXXMethodDecl; + class CXXScopeSpec; + class CXXTemporary; + class CXXTryStmt; + class CallExpr; + class ClassTemplateDecl; + class ClassTemplatePartialSpecializationDecl; + class ClassTemplateSpecializationDecl; + class VarTemplatePartialSpecializationDecl; + class CodeCompleteConsumer; + class CodeCompletionAllocator; + class CodeCompletionTUInfo; + class CodeCompletionResult; + class Decl; + class DeclAccessPair; + class DeclContext; + class DeclRefExpr; + class DeclaratorDecl; + class DeducedTemplateArgument; + class DependentDiagnostic; + class DesignatedInitExpr; + class Designation; + class EnableIfAttr; + class EnumConstantDecl; + class Expr; + class ExtVectorType; + class ExternalSemaSource; + class FormatAttr; + class FriendDecl; + class FunctionDecl; + class FunctionProtoType; + class FunctionTemplateDecl; + class ImplicitConversionSequence; + class InitListExpr; + class InitializationKind; + class InitializationSequence; + class InitializedEntity; + class IntegerLiteral; + class LabelStmt; + class LambdaExpr; + class LangOptions; + class LocalInstantiationScope; + class LookupResult; + class MacroInfo; + typedef ArrayRef<std::pair<IdentifierInfo *, SourceLocation>> ModuleIdPath; + class ModuleLoader; + class MultiLevelTemplateArgumentList; + class NamedDecl; + class ObjCCategoryDecl; + class ObjCCategoryImplDecl; + class ObjCCompatibleAliasDecl; + class ObjCContainerDecl; + class ObjCImplDecl; + class ObjCImplementationDecl; + class ObjCInterfaceDecl; + class ObjCIvarDecl; + template <class T> class ObjCList; + class ObjCMessageExpr; + class ObjCMethodDecl; + class ObjCPropertyDecl; + class ObjCProtocolDecl; + class OMPThreadPrivateDecl; + class OMPClause; + struct OverloadCandidate; + class OverloadCandidateSet; + class OverloadExpr; + class ParenListExpr; + class ParmVarDecl; + class Preprocessor; + class PseudoDestructorTypeStorage; + class PseudoObjectExpr; + class QualType; + class StandardConversionSequence; + class Stmt; + class StringLiteral; + class SwitchStmt; + class TemplateArgument; + class TemplateArgumentList; + class TemplateArgumentLoc; + class TemplateDecl; + class TemplateParameterList; + class TemplatePartialOrderingContext; + class TemplateTemplateParmDecl; + class Token; + class TypeAliasDecl; + class TypedefDecl; + class TypedefNameDecl; + class TypeLoc; + class TypoCorrectionConsumer; + class UnqualifiedId; + class UnresolvedLookupExpr; + class UnresolvedMemberExpr; + class UnresolvedSetImpl; + class UnresolvedSetIterator; + class UsingDecl; + class UsingShadowDecl; + class ValueDecl; + class VarDecl; + class VarTemplateSpecializationDecl; + class VisibilityAttr; + class VisibleDeclConsumer; + class IndirectFieldDecl; + struct DeductionFailureInfo; + class TemplateSpecCandidateSet; + +namespace sema { + class AccessedEntity; + class BlockScopeInfo; + class CapturedRegionScopeInfo; + class CapturingScopeInfo; + class CompoundScopeInfo; + class DelayedDiagnostic; + class DelayedDiagnosticPool; + class FunctionScopeInfo; + class LambdaScopeInfo; + class PossiblyUnreachableDiag; + class TemplateDeductionInfo; +} + +namespace threadSafety { + class BeforeSet; + void threadSafetyCleanup(BeforeSet* Cache); +} + +// FIXME: No way to easily map from TemplateTypeParmTypes to +// TemplateTypeParmDecls, so we have this horrible PointerUnion. +typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType*, NamedDecl*>, + SourceLocation> UnexpandedParameterPack; + +/// Describes whether we've seen any nullability information for the given +/// file. +struct FileNullability { + /// The first pointer declarator (of any pointer kind) in the file that does + /// not have a corresponding nullability annotation. + SourceLocation PointerLoc; + + /// Which kind of pointer declarator we saw. + uint8_t PointerKind; + + /// Whether we saw any type nullability annotations in the given file. + bool SawTypeNullability = false; +}; + +/// A mapping from file IDs to a record of whether we've seen nullability +/// information in that file. +class FileNullabilityMap { + /// A mapping from file IDs to the nullability information for each file ID. + llvm::DenseMap<FileID, FileNullability> Map; + + /// A single-element cache based on the file ID. + struct { + FileID File; + FileNullability Nullability; + } Cache; + +public: + FileNullability &operator[](FileID file) { + // Check the single-element cache. + if (file == Cache.File) + return Cache.Nullability; + + // It's not in the single-element cache; flush the cache if we have one. + if (!Cache.File.isInvalid()) { + Map[Cache.File] = Cache.Nullability; + } + + // Pull this entry into the cache. + Cache.File = file; + Cache.Nullability = Map[file]; + return Cache.Nullability; + } +}; + +/// Sema - This implements semantic analysis and AST building for C. +class Sema { + Sema(const Sema &) = delete; + void operator=(const Sema &) = delete; + + ///\brief Source of additional semantic information. + ExternalSemaSource *ExternalSource; + + ///\brief Whether Sema has generated a multiplexer and has to delete it. + bool isMultiplexExternalSource; + + static bool mightHaveNonExternalLinkage(const DeclaratorDecl *FD); + + bool isVisibleSlow(const NamedDecl *D); + + bool shouldLinkPossiblyHiddenDecl(const NamedDecl *Old, + const NamedDecl *New) { + // We are about to link these. It is now safe to compute the linkage of + // the new decl. If the new decl has external linkage, we will + // link it with the hidden decl (which also has external linkage) and + // it will keep having external linkage. If it has internal linkage, we + // will not link it. Since it has no previous decls, it will remain + // with internal linkage. + return isVisible(Old) || New->isExternallyVisible(); + } + bool shouldLinkPossiblyHiddenDecl(LookupResult &Old, const NamedDecl *New); + +public: + typedef OpaquePtr<DeclGroupRef> DeclGroupPtrTy; + typedef OpaquePtr<TemplateName> TemplateTy; + typedef OpaquePtr<QualType> TypeTy; + + OpenCLOptions OpenCLFeatures; + FPOptions FPFeatures; + + const LangOptions &LangOpts; + Preprocessor &PP; + ASTContext &Context; + ASTConsumer &Consumer; + DiagnosticsEngine &Diags; + SourceManager &SourceMgr; + + /// \brief Flag indicating whether or not to collect detailed statistics. + bool CollectStats; + + /// \brief Code-completion consumer. + CodeCompleteConsumer *CodeCompleter; + + /// CurContext - This is the current declaration context of parsing. + DeclContext *CurContext; + + /// \brief Generally null except when we temporarily switch decl contexts, + /// like in \see ActOnObjCTemporaryExitContainerContext. + DeclContext *OriginalLexicalContext; + + /// VAListTagName - The declaration name corresponding to __va_list_tag. + /// This is used as part of a hack to omit that class from ADL results. + DeclarationName VAListTagName; + + /// PackContext - Manages the stack for \#pragma pack. An alignment + /// of 0 indicates default alignment. + void *PackContext; // Really a "PragmaPackStack*" + + bool MSStructPragmaOn; // True when \#pragma ms_struct on + + /// \brief Controls member pointer representation format under the MS ABI. + LangOptions::PragmaMSPointersToMembersKind + MSPointerToMemberRepresentationMethod; + + enum PragmaVtorDispKind { + PVDK_Push, ///< #pragma vtordisp(push, mode) + PVDK_Set, ///< #pragma vtordisp(mode) + PVDK_Pop, ///< #pragma vtordisp(pop) + PVDK_Reset ///< #pragma vtordisp() + }; + + enum PragmaMsStackAction { + PSK_Reset, // #pragma () + PSK_Set, // #pragma ("name") + PSK_Push, // #pragma (push[, id]) + PSK_Push_Set, // #pragma (push[, id], "name") + PSK_Pop, // #pragma (pop[, id]) + PSK_Pop_Set, // #pragma (pop[, id], "name") + }; + + /// \brief Whether to insert vtordisps prior to virtual bases in the Microsoft + /// C++ ABI. Possible values are 0, 1, and 2, which mean: + /// + /// 0: Suppress all vtordisps + /// 1: Insert vtordisps in the presence of vbase overrides and non-trivial + /// structors + /// 2: Always insert vtordisps to support RTTI on partially constructed + /// objects + /// + /// The stack always has at least one element in it. + SmallVector<MSVtorDispAttr::Mode, 2> VtorDispModeStack; + + /// Stack of active SEH __finally scopes. Can be empty. + SmallVector<Scope*, 2> CurrentSEHFinally; + + /// \brief Source location for newly created implicit MSInheritanceAttrs + SourceLocation ImplicitMSInheritanceAttrLoc; + + template<typename ValueType> + struct PragmaStack { + struct Slot { + llvm::StringRef StackSlotLabel; + ValueType Value; + SourceLocation PragmaLocation; + Slot(llvm::StringRef StackSlotLabel, + ValueType Value, + SourceLocation PragmaLocation) + : StackSlotLabel(StackSlotLabel), Value(Value), + PragmaLocation(PragmaLocation) {} + }; + void Act(SourceLocation PragmaLocation, + PragmaMsStackAction Action, + llvm::StringRef StackSlotLabel, + ValueType Value); + explicit PragmaStack(const ValueType &Value) + : CurrentValue(Value) {} + SmallVector<Slot, 2> Stack; + ValueType CurrentValue; + SourceLocation CurrentPragmaLocation; + }; + // FIXME: We should serialize / deserialize these if they occur in a PCH (but + // we shouldn't do so if they're in a module). + PragmaStack<StringLiteral *> DataSegStack; + PragmaStack<StringLiteral *> BSSSegStack; + PragmaStack<StringLiteral *> ConstSegStack; + PragmaStack<StringLiteral *> CodeSegStack; + + /// A mapping that describes the nullability we've seen in each header file. + FileNullabilityMap NullabilityMap; + + /// Last section used with #pragma init_seg. + StringLiteral *CurInitSeg; + SourceLocation CurInitSegLoc; + + /// VisContext - Manages the stack for \#pragma GCC visibility. + void *VisContext; // Really a "PragmaVisStack*" + + /// \brief This represents the last location of a "#pragma clang optimize off" + /// directive if such a directive has not been closed by an "on" yet. If + /// optimizations are currently "on", this is set to an invalid location. + SourceLocation OptimizeOffPragmaLocation; + + /// \brief Flag indicating if Sema is building a recovery call expression. + /// + /// This flag is used to avoid building recovery call expressions + /// if Sema is already doing so, which would cause infinite recursions. + bool IsBuildingRecoveryCallExpr; + + /// ExprNeedsCleanups - True if the current evaluation context + /// requires cleanups to be run at its conclusion. + bool ExprNeedsCleanups; + + /// ExprCleanupObjects - This is the stack of objects requiring + /// cleanup that are created by the current full expression. The + /// element type here is ExprWithCleanups::Object. + SmallVector<BlockDecl*, 8> ExprCleanupObjects; + + /// \brief Store a list of either DeclRefExprs or MemberExprs + /// that contain a reference to a variable (constant) that may or may not + /// be odr-used in this Expr, and we won't know until all lvalue-to-rvalue + /// and discarded value conversions have been applied to all subexpressions + /// of the enclosing full expression. This is cleared at the end of each + /// full expression. + llvm::SmallPtrSet<Expr*, 2> MaybeODRUseExprs; + + /// \brief Stack containing information about each of the nested + /// function, block, and method scopes that are currently active. + /// + /// This array is never empty. Clients should ignore the first + /// element, which is used to cache a single FunctionScopeInfo + /// that's used to parse every top-level function. + SmallVector<sema::FunctionScopeInfo *, 4> FunctionScopes; + + typedef LazyVector<TypedefNameDecl *, ExternalSemaSource, + &ExternalSemaSource::ReadExtVectorDecls, 2, 2> + ExtVectorDeclsType; + + /// ExtVectorDecls - This is a list all the extended vector types. This allows + /// us to associate a raw vector type with one of the ext_vector type names. + /// This is only necessary for issuing pretty diagnostics. + ExtVectorDeclsType ExtVectorDecls; + + /// FieldCollector - Collects CXXFieldDecls during parsing of C++ classes. + std::unique_ptr<CXXFieldCollector> FieldCollector; + + typedef llvm::SmallSetVector<const NamedDecl*, 16> NamedDeclSetType; + + /// \brief Set containing all declared private fields that are not used. + NamedDeclSetType UnusedPrivateFields; + + /// \brief Set containing all typedefs that are likely unused. + llvm::SmallSetVector<const TypedefNameDecl *, 4> + UnusedLocalTypedefNameCandidates; + + /// \brief Delete-expressions to be analyzed at the end of translation unit + /// + /// This list contains class members, and locations of delete-expressions + /// that could not be proven as to whether they mismatch with new-expression + /// used in initializer of the field. + typedef std::pair<SourceLocation, bool> DeleteExprLoc; + typedef llvm::SmallVector<DeleteExprLoc, 4> DeleteLocs; + llvm::MapVector<FieldDecl *, DeleteLocs> DeleteExprs; + + typedef llvm::SmallPtrSet<const CXXRecordDecl*, 8> RecordDeclSetTy; + + /// PureVirtualClassDiagSet - a set of class declarations which we have + /// emitted a list of pure virtual functions. Used to prevent emitting the + /// same list more than once. + std::unique_ptr<RecordDeclSetTy> PureVirtualClassDiagSet; + + /// ParsingInitForAutoVars - a set of declarations with auto types for which + /// we are currently parsing the initializer. + llvm::SmallPtrSet<const Decl*, 4> ParsingInitForAutoVars; + + /// \brief Look for a locally scoped extern "C" declaration by the given name. + NamedDecl *findLocallyScopedExternCDecl(DeclarationName Name); + + typedef LazyVector<VarDecl *, ExternalSemaSource, + &ExternalSemaSource::ReadTentativeDefinitions, 2, 2> + TentativeDefinitionsType; + + /// \brief All the tentative definitions encountered in the TU. + TentativeDefinitionsType TentativeDefinitions; + + typedef LazyVector<const DeclaratorDecl *, ExternalSemaSource, + &ExternalSemaSource::ReadUnusedFileScopedDecls, 2, 2> + UnusedFileScopedDeclsType; + + /// \brief The set of file scoped decls seen so far that have not been used + /// and must warn if not used. Only contains the first declaration. + UnusedFileScopedDeclsType UnusedFileScopedDecls; + + typedef LazyVector<CXXConstructorDecl *, ExternalSemaSource, + &ExternalSemaSource::ReadDelegatingConstructors, 2, 2> + DelegatingCtorDeclsType; + + /// \brief All the delegating constructors seen so far in the file, used for + /// cycle detection at the end of the TU. + DelegatingCtorDeclsType DelegatingCtorDecls; + + /// \brief All the overriding functions seen during a class definition + /// that had their exception spec checks delayed, plus the overridden + /// function. + SmallVector<std::pair<const CXXMethodDecl*, const CXXMethodDecl*>, 2> + DelayedExceptionSpecChecks; + + /// \brief All the members seen during a class definition which were both + /// explicitly defaulted and had explicitly-specified exception + /// specifications, along with the function type containing their + /// user-specified exception specification. Those exception specifications + /// were overridden with the default specifications, but we still need to + /// check whether they are compatible with the default specification, and + /// we can't do that until the nesting set of class definitions is complete. + SmallVector<std::pair<CXXMethodDecl*, const FunctionProtoType*>, 2> + DelayedDefaultedMemberExceptionSpecs; + + typedef llvm::MapVector<const FunctionDecl *, LateParsedTemplate *> + LateParsedTemplateMapT; + LateParsedTemplateMapT LateParsedTemplateMap; + + /// \brief Callback to the parser to parse templated functions when needed. + typedef void LateTemplateParserCB(void *P, LateParsedTemplate &LPT); + typedef void LateTemplateParserCleanupCB(void *P); + LateTemplateParserCB *LateTemplateParser; + LateTemplateParserCleanupCB *LateTemplateParserCleanup; + void *OpaqueParser; + + void SetLateTemplateParser(LateTemplateParserCB *LTP, + LateTemplateParserCleanupCB *LTPCleanup, + void *P) { + LateTemplateParser = LTP; + LateTemplateParserCleanup = LTPCleanup; + OpaqueParser = P; + } + + class DelayedDiagnostics; + + class DelayedDiagnosticsState { + sema::DelayedDiagnosticPool *SavedPool; + friend class Sema::DelayedDiagnostics; + }; + typedef DelayedDiagnosticsState ParsingDeclState; + typedef DelayedDiagnosticsState ProcessingContextState; + + /// A class which encapsulates the logic for delaying diagnostics + /// during parsing and other processing. + class DelayedDiagnostics { + /// \brief The current pool of diagnostics into which delayed + /// diagnostics should go. + sema::DelayedDiagnosticPool *CurPool; + + public: + DelayedDiagnostics() : CurPool(nullptr) {} + + /// Adds a delayed diagnostic. + void add(const sema::DelayedDiagnostic &diag); // in DelayedDiagnostic.h + + /// Determines whether diagnostics should be delayed. + bool shouldDelayDiagnostics() { return CurPool != nullptr; } + + /// Returns the current delayed-diagnostics pool. + sema::DelayedDiagnosticPool *getCurrentPool() const { + return CurPool; + } + + /// Enter a new scope. Access and deprecation diagnostics will be + /// collected in this pool. + DelayedDiagnosticsState push(sema::DelayedDiagnosticPool &pool) { + DelayedDiagnosticsState state; + state.SavedPool = CurPool; + CurPool = &pool; + return state; + } + + /// Leave a delayed-diagnostic state that was previously pushed. + /// Do not emit any of the diagnostics. This is performed as part + /// of the bookkeeping of popping a pool "properly". + void popWithoutEmitting(DelayedDiagnosticsState state) { + CurPool = state.SavedPool; + } + + /// Enter a new scope where access and deprecation diagnostics are + /// not delayed. + DelayedDiagnosticsState pushUndelayed() { + DelayedDiagnosticsState state; + state.SavedPool = CurPool; + CurPool = nullptr; + return state; + } + + /// Undo a previous pushUndelayed(). + void popUndelayed(DelayedDiagnosticsState state) { + assert(CurPool == nullptr); + CurPool = state.SavedPool; + } + } DelayedDiagnostics; + + /// A RAII object to temporarily push a declaration context. + class ContextRAII { + private: + Sema &S; + DeclContext *SavedContext; + ProcessingContextState SavedContextState; + QualType SavedCXXThisTypeOverride; + + public: + ContextRAII(Sema &S, DeclContext *ContextToPush, bool NewThisContext = true) + : S(S), SavedContext(S.CurContext), + SavedContextState(S.DelayedDiagnostics.pushUndelayed()), + SavedCXXThisTypeOverride(S.CXXThisTypeOverride) + { + assert(ContextToPush && "pushing null context"); + S.CurContext = ContextToPush; + if (NewThisContext) + S.CXXThisTypeOverride = QualType(); + } + + void pop() { + if (!SavedContext) return; + S.CurContext = SavedContext; + S.DelayedDiagnostics.popUndelayed(SavedContextState); + S.CXXThisTypeOverride = SavedCXXThisTypeOverride; + SavedContext = nullptr; + } + + ~ContextRAII() { + pop(); + } + }; + + /// \brief RAII object to handle the state changes required to synthesize + /// a function body. + class SynthesizedFunctionScope { + Sema &S; + Sema::ContextRAII SavedContext; + + public: + SynthesizedFunctionScope(Sema &S, DeclContext *DC) + : S(S), SavedContext(S, DC) + { + S.PushFunctionScope(); + S.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated); + } + + ~SynthesizedFunctionScope() { + S.PopExpressionEvaluationContext(); + S.PopFunctionScopeInfo(); + } + }; + + /// WeakUndeclaredIdentifiers - Identifiers contained in + /// \#pragma weak before declared. rare. may alias another + /// identifier, declared or undeclared + llvm::MapVector<IdentifierInfo *, WeakInfo> WeakUndeclaredIdentifiers; + + /// ExtnameUndeclaredIdentifiers - Identifiers contained in + /// \#pragma redefine_extname before declared. Used in Solaris system headers + /// to define functions that occur in multiple standards to call the version + /// in the currently selected standard. + llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*> ExtnameUndeclaredIdentifiers; + + + /// \brief Load weak undeclared identifiers from the external source. + void LoadExternalWeakUndeclaredIdentifiers(); + + /// WeakTopLevelDecl - Translation-unit scoped declarations generated by + /// \#pragma weak during processing of other Decls. + /// I couldn't figure out a clean way to generate these in-line, so + /// we store them here and handle separately -- which is a hack. + /// It would be best to refactor this. + SmallVector<Decl*,2> WeakTopLevelDecl; + + IdentifierResolver IdResolver; + + /// Translation Unit Scope - useful to Objective-C actions that need + /// to lookup file scope declarations in the "ordinary" C decl namespace. + /// For example, user-defined classes, built-in "id" type, etc. + Scope *TUScope; + + /// \brief The C++ "std" namespace, where the standard library resides. + LazyDeclPtr StdNamespace; + + /// \brief The C++ "std::bad_alloc" class, which is defined by the C++ + /// standard library. + LazyDeclPtr StdBadAlloc; + + /// \brief The C++ "std::initializer_list" template, which is defined in + /// \<initializer_list>. + ClassTemplateDecl *StdInitializerList; + + /// \brief The C++ "type_info" declaration, which is defined in \<typeinfo>. + RecordDecl *CXXTypeInfoDecl; + + /// \brief The MSVC "_GUID" struct, which is defined in MSVC header files. + RecordDecl *MSVCGuidDecl; + + /// \brief Caches identifiers/selectors for NSFoundation APIs. + std::unique_ptr<NSAPI> NSAPIObj; + + /// \brief The declaration of the Objective-C NSNumber class. + ObjCInterfaceDecl *NSNumberDecl; + + /// \brief The declaration of the Objective-C NSValue class. + ObjCInterfaceDecl *NSValueDecl; + + /// \brief Pointer to NSNumber type (NSNumber *). + QualType NSNumberPointer; + + /// \brief Pointer to NSValue type (NSValue *). + QualType NSValuePointer; + + /// \brief The Objective-C NSNumber methods used to create NSNumber literals. + ObjCMethodDecl *NSNumberLiteralMethods[NSAPI::NumNSNumberLiteralMethods]; + + /// \brief The declaration of the Objective-C NSString class. + ObjCInterfaceDecl *NSStringDecl; + + /// \brief Pointer to NSString type (NSString *). + QualType NSStringPointer; + + /// \brief The declaration of the stringWithUTF8String: method. + ObjCMethodDecl *StringWithUTF8StringMethod; + + /// \brief The declaration of the valueWithBytes:objCType: method. + ObjCMethodDecl *ValueWithBytesObjCTypeMethod; + + /// \brief The declaration of the Objective-C NSArray class. + ObjCInterfaceDecl *NSArrayDecl; + + /// \brief The declaration of the arrayWithObjects:count: method. + ObjCMethodDecl *ArrayWithObjectsMethod; + + /// \brief The declaration of the Objective-C NSDictionary class. + ObjCInterfaceDecl *NSDictionaryDecl; + + /// \brief The declaration of the dictionaryWithObjects:forKeys:count: method. + ObjCMethodDecl *DictionaryWithObjectsMethod; + + /// \brief id<NSCopying> type. + QualType QIDNSCopying; + + /// \brief will hold 'respondsToSelector:' + Selector RespondsToSelectorSel; + + /// \brief counter for internal MS Asm label names. + unsigned MSAsmLabelNameCounter; + + /// A flag to remember whether the implicit forms of operator new and delete + /// have been declared. + bool GlobalNewDeleteDeclared; + + /// A flag to indicate that we're in a context that permits abstract + /// references to fields. This is really a + bool AllowAbstractFieldReference; + + /// \brief Describes how the expressions currently being parsed are + /// evaluated at run-time, if at all. + enum ExpressionEvaluationContext { + /// \brief The current expression and its subexpressions occur within an + /// unevaluated operand (C++11 [expr]p7), such as the subexpression of + /// \c sizeof, where the type of the expression may be significant but + /// no code will be generated to evaluate the value of the expression at + /// run time. + Unevaluated, + + /// \brief The current expression occurs within an unevaluated + /// operand that unconditionally permits abstract references to + /// fields, such as a SIZE operator in MS-style inline assembly. + UnevaluatedAbstract, + + /// \brief The current context is "potentially evaluated" in C++11 terms, + /// but the expression is evaluated at compile-time (like the values of + /// cases in a switch statement). + ConstantEvaluated, + + /// \brief The current expression is potentially evaluated at run time, + /// which means that code may be generated to evaluate the value of the + /// expression at run time. + PotentiallyEvaluated, + + /// \brief The current expression is potentially evaluated, but any + /// declarations referenced inside that expression are only used if + /// in fact the current expression is used. + /// + /// This value is used when parsing default function arguments, for which + /// we would like to provide diagnostics (e.g., passing non-POD arguments + /// through varargs) but do not want to mark declarations as "referenced" + /// until the default argument is used. + PotentiallyEvaluatedIfUsed + }; + + /// \brief Data structure used to record current or nested + /// expression evaluation contexts. + struct ExpressionEvaluationContextRecord { + /// \brief The expression evaluation context. + ExpressionEvaluationContext Context; + + /// \brief Whether the enclosing context needed a cleanup. + bool ParentNeedsCleanups; + + /// \brief Whether we are in a decltype expression. + bool IsDecltype; + + /// \brief The number of active cleanup objects when we entered + /// this expression evaluation context. + unsigned NumCleanupObjects; + + /// \brief The number of typos encountered during this expression evaluation + /// context (i.e. the number of TypoExprs created). + unsigned NumTypos; + + llvm::SmallPtrSet<Expr*, 2> SavedMaybeODRUseExprs; + + /// \brief The lambdas that are present within this context, if it + /// is indeed an unevaluated context. + SmallVector<LambdaExpr *, 2> Lambdas; + + /// \brief The declaration that provides context for lambda expressions + /// and block literals if the normal declaration context does not + /// suffice, e.g., in a default function argument. + Decl *ManglingContextDecl; + + /// \brief The context information used to mangle lambda expressions + /// and block literals within this context. + /// + /// This mangling information is allocated lazily, since most contexts + /// do not have lambda expressions or block literals. + IntrusiveRefCntPtr<MangleNumberingContext> MangleNumbering; + + /// \brief If we are processing a decltype type, a set of call expressions + /// for which we have deferred checking the completeness of the return type. + SmallVector<CallExpr *, 8> DelayedDecltypeCalls; + + /// \brief If we are processing a decltype type, a set of temporary binding + /// expressions for which we have deferred checking the destructor. + SmallVector<CXXBindTemporaryExpr *, 8> DelayedDecltypeBinds; + + ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context, + unsigned NumCleanupObjects, + bool ParentNeedsCleanups, + Decl *ManglingContextDecl, + bool IsDecltype) + : Context(Context), ParentNeedsCleanups(ParentNeedsCleanups), + IsDecltype(IsDecltype), NumCleanupObjects(NumCleanupObjects), + NumTypos(0), + ManglingContextDecl(ManglingContextDecl), MangleNumbering() { } + + /// \brief Retrieve the mangling numbering context, used to consistently + /// number constructs like lambdas for mangling. + MangleNumberingContext &getMangleNumberingContext(ASTContext &Ctx); + + bool isUnevaluated() const { + return Context == Unevaluated || Context == UnevaluatedAbstract; + } + }; + + /// A stack of expression evaluation contexts. + SmallVector<ExpressionEvaluationContextRecord, 8> ExprEvalContexts; + + /// \brief Compute the mangling number context for a lambda expression or + /// block literal. + /// + /// \param DC - The DeclContext containing the lambda expression or + /// block literal. + /// \param[out] ManglingContextDecl - Returns the ManglingContextDecl + /// associated with the context, if relevant. + MangleNumberingContext *getCurrentMangleNumberContext( + const DeclContext *DC, + Decl *&ManglingContextDecl); + + + /// SpecialMemberOverloadResult - The overloading result for a special member + /// function. + /// + /// This is basically a wrapper around PointerIntPair. The lowest bits of the + /// integer are used to determine whether overload resolution succeeded. + class SpecialMemberOverloadResult : public llvm::FastFoldingSetNode { + public: + enum Kind { + NoMemberOrDeleted, + Ambiguous, + Success + }; + + private: + llvm::PointerIntPair<CXXMethodDecl*, 2> Pair; + + public: + SpecialMemberOverloadResult(const llvm::FoldingSetNodeID &ID) + : FastFoldingSetNode(ID) + {} + + CXXMethodDecl *getMethod() const { return Pair.getPointer(); } + void setMethod(CXXMethodDecl *MD) { Pair.setPointer(MD); } + + Kind getKind() const { return static_cast<Kind>(Pair.getInt()); } + void setKind(Kind K) { Pair.setInt(K); } + }; + + /// \brief A cache of special member function overload resolution results + /// for C++ records. + llvm::FoldingSet<SpecialMemberOverloadResult> SpecialMemberCache; + + /// \brief A cache of the flags available in enumerations with the flag_bits + /// attribute. + mutable llvm::DenseMap<const EnumDecl*, llvm::APInt> FlagBitsCache; + + /// \brief The kind of translation unit we are processing. + /// + /// When we're processing a complete translation unit, Sema will perform + /// end-of-translation-unit semantic tasks (such as creating + /// initializers for tentative definitions in C) once parsing has + /// completed. Modules and precompiled headers perform different kinds of + /// checks. + TranslationUnitKind TUKind; + + llvm::BumpPtrAllocator BumpAlloc; + + /// \brief The number of SFINAE diagnostics that have been trapped. + unsigned NumSFINAEErrors; + + typedef llvm::DenseMap<ParmVarDecl *, llvm::TinyPtrVector<ParmVarDecl *>> + UnparsedDefaultArgInstantiationsMap; + + /// \brief A mapping from parameters with unparsed default arguments to the + /// set of instantiations of each parameter. + /// + /// This mapping is a temporary data structure used when parsing + /// nested class templates or nested classes of class templates, + /// where we might end up instantiating an inner class before the + /// default arguments of its methods have been parsed. + UnparsedDefaultArgInstantiationsMap UnparsedDefaultArgInstantiations; + + // Contains the locations of the beginning of unparsed default + // argument locations. + llvm::DenseMap<ParmVarDecl *, SourceLocation> UnparsedDefaultArgLocs; + + /// UndefinedInternals - all the used, undefined objects which require a + /// definition in this translation unit. + llvm::DenseMap<NamedDecl *, SourceLocation> UndefinedButUsed; + + /// Obtain a sorted list of functions that are undefined but ODR-used. + void getUndefinedButUsed( + SmallVectorImpl<std::pair<NamedDecl *, SourceLocation> > &Undefined); + + /// Retrieves list of suspicious delete-expressions that will be checked at + /// the end of translation unit. + const llvm::MapVector<FieldDecl *, DeleteLocs> & + getMismatchingDeleteExpressions() const; + + typedef std::pair<ObjCMethodList, ObjCMethodList> GlobalMethods; + typedef llvm::DenseMap<Selector, GlobalMethods> GlobalMethodPool; + + /// Method Pool - allows efficient lookup when typechecking messages to "id". + /// We need to maintain a list, since selectors can have differing signatures + /// across classes. In Cocoa, this happens to be extremely uncommon (only 1% + /// of selectors are "overloaded"). + /// At the head of the list it is recorded whether there were 0, 1, or >= 2 + /// methods inside categories with a particular selector. + GlobalMethodPool MethodPool; + + /// Method selectors used in a \@selector expression. Used for implementation + /// of -Wselector. + llvm::MapVector<Selector, SourceLocation> ReferencedSelectors; + + /// Kinds of C++ special members. + enum CXXSpecialMember { + CXXDefaultConstructor, + CXXCopyConstructor, + CXXMoveConstructor, + CXXCopyAssignment, + CXXMoveAssignment, + CXXDestructor, + CXXInvalid + }; + + typedef std::pair<CXXRecordDecl*, CXXSpecialMember> SpecialMemberDecl; + + /// The C++ special members which we are currently in the process of + /// declaring. If this process recursively triggers the declaration of the + /// same special member, we should act as if it is not yet declared. + llvm::SmallSet<SpecialMemberDecl, 4> SpecialMembersBeingDeclared; + + void ReadMethodPool(Selector Sel); + + /// Private Helper predicate to check for 'self'. + bool isSelfExpr(Expr *RExpr); + bool isSelfExpr(Expr *RExpr, const ObjCMethodDecl *Method); + + /// \brief Cause the active diagnostic on the DiagosticsEngine to be + /// emitted. This is closely coupled to the SemaDiagnosticBuilder class and + /// should not be used elsewhere. + void EmitCurrentDiagnostic(unsigned DiagID); + + /// Records and restores the FP_CONTRACT state on entry/exit of compound + /// statements. + class FPContractStateRAII { + public: + FPContractStateRAII(Sema& S) + : S(S), OldFPContractState(S.FPFeatures.fp_contract) {} + ~FPContractStateRAII() { + S.FPFeatures.fp_contract = OldFPContractState; + } + private: + Sema& S; + bool OldFPContractState : 1; + }; + + /// Records and restores the vtordisp state on entry/exit of C++ method body. + class VtorDispStackRAII { + public: + VtorDispStackRAII(Sema &S, bool ShouldSaveAndRestore) + : S(S), ShouldSaveAndRestore(ShouldSaveAndRestore), OldVtorDispStack() { + if (ShouldSaveAndRestore) + OldVtorDispStack = S.VtorDispModeStack; + } + ~VtorDispStackRAII() { + if (ShouldSaveAndRestore) + S.VtorDispModeStack = OldVtorDispStack; + } + private: + Sema &S; + bool ShouldSaveAndRestore; + SmallVector<MSVtorDispAttr::Mode, 2> OldVtorDispStack; + }; + + void addImplicitTypedef(StringRef Name, QualType T); + +public: + Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, + TranslationUnitKind TUKind = TU_Complete, + CodeCompleteConsumer *CompletionConsumer = nullptr); + ~Sema(); + + /// \brief Perform initialization that occurs after the parser has been + /// initialized but before it parses anything. + void Initialize(); + + const LangOptions &getLangOpts() const { return LangOpts; } + OpenCLOptions &getOpenCLOptions() { return OpenCLFeatures; } + FPOptions &getFPOptions() { return FPFeatures; } + + DiagnosticsEngine &getDiagnostics() const { return Diags; } + SourceManager &getSourceManager() const { return SourceMgr; } + Preprocessor &getPreprocessor() const { return PP; } + ASTContext &getASTContext() const { return Context; } + ASTConsumer &getASTConsumer() const { return Consumer; } + ASTMutationListener *getASTMutationListener() const; + ExternalSemaSource* getExternalSource() const { return ExternalSource; } + + ///\brief Registers an external source. If an external source already exists, + /// creates a multiplex external source and appends to it. + /// + ///\param[in] E - A non-null external sema source. + /// + void addExternalSource(ExternalSemaSource *E); + + void PrintStats() const; + + /// \brief Helper class that creates diagnostics with optional + /// template instantiation stacks. + /// + /// This class provides a wrapper around the basic DiagnosticBuilder + /// class that emits diagnostics. SemaDiagnosticBuilder is + /// responsible for emitting the diagnostic (as DiagnosticBuilder + /// does) and, if the diagnostic comes from inside a template + /// instantiation, printing the template instantiation stack as + /// well. + class SemaDiagnosticBuilder : public DiagnosticBuilder { + Sema &SemaRef; + unsigned DiagID; + + public: + SemaDiagnosticBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID) + : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) { } + + // This is a cunning lie. DiagnosticBuilder actually performs move + // construction in its copy constructor (but due to varied uses, it's not + // possible to conveniently express this as actual move construction). So + // the default copy ctor here is fine, because the base class disables the + // source anyway, so the user-defined ~SemaDiagnosticBuilder is a safe no-op + // in that case anwyay. + SemaDiagnosticBuilder(const SemaDiagnosticBuilder&) = default; + + ~SemaDiagnosticBuilder() { + // If we aren't active, there is nothing to do. + if (!isActive()) return; + + // Otherwise, we need to emit the diagnostic. First flush the underlying + // DiagnosticBuilder data, and clear the diagnostic builder itself so it + // won't emit the diagnostic in its own destructor. + // + // This seems wasteful, in that as written the DiagnosticBuilder dtor will + // do its own needless checks to see if the diagnostic needs to be + // emitted. However, because we take care to ensure that the builder + // objects never escape, a sufficiently smart compiler will be able to + // eliminate that code. + FlushCounts(); + Clear(); + + // Dispatch to Sema to emit the diagnostic. + SemaRef.EmitCurrentDiagnostic(DiagID); + } + + /// Teach operator<< to produce an object of the correct type. + template<typename T> + friend const SemaDiagnosticBuilder &operator<<( + const SemaDiagnosticBuilder &Diag, const T &Value) { + const DiagnosticBuilder &BaseDiag = Diag; + BaseDiag << Value; + return Diag; + } + }; + + /// \brief Emit a diagnostic. + SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) { + DiagnosticBuilder DB = Diags.Report(Loc, DiagID); + return SemaDiagnosticBuilder(DB, *this, DiagID); + } + + /// \brief Emit a partial diagnostic. + SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic& PD); + + /// \brief Build a partial diagnostic. + PartialDiagnostic PDiag(unsigned DiagID = 0); // in SemaInternal.h + + bool findMacroSpelling(SourceLocation &loc, StringRef name); + + /// \brief Get a string to suggest for zero-initialization of a type. + std::string + getFixItZeroInitializerForType(QualType T, SourceLocation Loc) const; + std::string getFixItZeroLiteralForType(QualType T, SourceLocation Loc) const; + + /// \brief Calls \c Lexer::getLocForEndOfToken() + SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset = 0); + + /// \brief Retrieve the module loader associated with the preprocessor. + ModuleLoader &getModuleLoader() const; + + void emitAndClearUnusedLocalTypedefWarnings(); + + void ActOnEndOfTranslationUnit(); + + void CheckDelegatingCtorCycles(); + + Scope *getScopeForContext(DeclContext *Ctx); + + void PushFunctionScope(); + void PushBlockScope(Scope *BlockScope, BlockDecl *Block); + sema::LambdaScopeInfo *PushLambdaScope(); + + /// \brief This is used to inform Sema what the current TemplateParameterDepth + /// is during Parsing. Currently it is used to pass on the depth + /// when parsing generic lambda 'auto' parameters. + void RecordParsingTemplateParameterDepth(unsigned Depth); + + void PushCapturedRegionScope(Scope *RegionScope, CapturedDecl *CD, + RecordDecl *RD, + CapturedRegionKind K); + void + PopFunctionScopeInfo(const sema::AnalysisBasedWarnings::Policy *WP = nullptr, + const Decl *D = nullptr, + const BlockExpr *blkExpr = nullptr); + + sema::FunctionScopeInfo *getCurFunction() const { + return FunctionScopes.back(); + } + + sema::FunctionScopeInfo *getEnclosingFunction() const { + if (FunctionScopes.empty()) + return nullptr; + + for (int e = FunctionScopes.size()-1; e >= 0; --e) { + if (isa<sema::BlockScopeInfo>(FunctionScopes[e])) + continue; + return FunctionScopes[e]; + } + return nullptr; + } + + template <typename ExprT> + void recordUseOfEvaluatedWeak(const ExprT *E, bool IsRead=true) { + if (!isUnevaluatedContext()) + getCurFunction()->recordUseOfWeak(E, IsRead); + } + + void PushCompoundScope(); + void PopCompoundScope(); + + sema::CompoundScopeInfo &getCurCompoundScope() const; + + bool hasAnyUnrecoverableErrorsInThisFunction() const; + + /// \brief Retrieve the current block, if any. + sema::BlockScopeInfo *getCurBlock(); + + /// \brief Retrieve the current lambda scope info, if any. + sema::LambdaScopeInfo *getCurLambda(); + + /// \brief Retrieve the current generic lambda info, if any. + sema::LambdaScopeInfo *getCurGenericLambda(); + + /// \brief Retrieve the current captured region, if any. + sema::CapturedRegionScopeInfo *getCurCapturedRegion(); + + /// WeakTopLevelDeclDecls - access to \#pragma weak-generated Decls + SmallVectorImpl<Decl *> &WeakTopLevelDecls() { return WeakTopLevelDecl; } + + void ActOnComment(SourceRange Comment); + + //===--------------------------------------------------------------------===// + // Type Analysis / Processing: SemaType.cpp. + // + + QualType BuildQualifiedType(QualType T, SourceLocation Loc, Qualifiers Qs, + const DeclSpec *DS = nullptr); + QualType BuildQualifiedType(QualType T, SourceLocation Loc, unsigned CVRA, + const DeclSpec *DS = nullptr); + QualType BuildPointerType(QualType T, + SourceLocation Loc, DeclarationName Entity); + QualType BuildReferenceType(QualType T, bool LValueRef, + SourceLocation Loc, DeclarationName Entity); + QualType BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, + Expr *ArraySize, unsigned Quals, + SourceRange Brackets, DeclarationName Entity); + QualType BuildExtVectorType(QualType T, Expr *ArraySize, + SourceLocation AttrLoc); + + bool CheckFunctionReturnType(QualType T, SourceLocation Loc); + + /// \brief Build a function type. + /// + /// This routine checks the function type according to C++ rules and + /// under the assumption that the result type and parameter types have + /// just been instantiated from a template. It therefore duplicates + /// some of the behavior of GetTypeForDeclarator, but in a much + /// simpler form that is only suitable for this narrow use case. + /// + /// \param T The return type of the function. + /// + /// \param ParamTypes The parameter types of the function. This array + /// will be modified to account for adjustments to the types of the + /// function parameters. + /// + /// \param Loc The location of the entity whose type involves this + /// function type or, if there is no such entity, the location of the + /// type that will have function type. + /// + /// \param Entity The name of the entity that involves the function + /// type, if known. + /// + /// \param EPI Extra information about the function type. Usually this will + /// be taken from an existing function with the same prototype. + /// + /// \returns A suitable function type, if there are no errors. The + /// unqualified type will always be a FunctionProtoType. + /// Otherwise, returns a NULL type. + QualType BuildFunctionType(QualType T, + MutableArrayRef<QualType> ParamTypes, + SourceLocation Loc, DeclarationName Entity, + const FunctionProtoType::ExtProtoInfo &EPI); + + QualType BuildMemberPointerType(QualType T, QualType Class, + SourceLocation Loc, + DeclarationName Entity); + QualType BuildBlockPointerType(QualType T, + SourceLocation Loc, DeclarationName Entity); + QualType BuildParenType(QualType T); + QualType BuildAtomicType(QualType T, SourceLocation Loc); + + TypeSourceInfo *GetTypeForDeclarator(Declarator &D, Scope *S); + TypeSourceInfo *GetTypeForDeclaratorCast(Declarator &D, QualType FromTy); + TypeSourceInfo *GetTypeSourceInfoForDeclarator(Declarator &D, QualType T, + TypeSourceInfo *ReturnTypeInfo); + + /// \brief Package the given type and TSI into a ParsedType. + ParsedType CreateParsedType(QualType T, TypeSourceInfo *TInfo); + DeclarationNameInfo GetNameForDeclarator(Declarator &D); + DeclarationNameInfo GetNameFromUnqualifiedId(const UnqualifiedId &Name); + static QualType GetTypeFromParser(ParsedType Ty, + TypeSourceInfo **TInfo = nullptr); + CanThrowResult canThrow(const Expr *E); + const FunctionProtoType *ResolveExceptionSpec(SourceLocation Loc, + const FunctionProtoType *FPT); + void UpdateExceptionSpec(FunctionDecl *FD, + const FunctionProtoType::ExceptionSpecInfo &ESI); + bool CheckSpecifiedExceptionType(QualType &T, SourceRange Range); + bool CheckDistantExceptionSpec(QualType T); + bool CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New); + bool CheckEquivalentExceptionSpec( + const FunctionProtoType *Old, SourceLocation OldLoc, + const FunctionProtoType *New, SourceLocation NewLoc); + bool CheckEquivalentExceptionSpec( + const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, + const FunctionProtoType *Old, SourceLocation OldLoc, + const FunctionProtoType *New, SourceLocation NewLoc, + bool *MissingExceptionSpecification = nullptr, + bool *MissingEmptyExceptionSpecification = nullptr, + bool AllowNoexceptAllMatchWithNoSpec = false, + bool IsOperatorNew = false); + bool CheckExceptionSpecSubset( + const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, + const FunctionProtoType *Superset, SourceLocation SuperLoc, + const FunctionProtoType *Subset, SourceLocation SubLoc); + bool CheckParamExceptionSpec(const PartialDiagnostic & NoteID, + const FunctionProtoType *Target, SourceLocation TargetLoc, + const FunctionProtoType *Source, SourceLocation SourceLoc); + + TypeResult ActOnTypeName(Scope *S, Declarator &D); + + /// \brief The parser has parsed the context-sensitive type 'instancetype' + /// in an Objective-C message declaration. Return the appropriate type. + ParsedType ActOnObjCInstanceType(SourceLocation Loc); + + /// \brief Abstract class used to diagnose incomplete types. + struct TypeDiagnoser { + TypeDiagnoser() {} + + virtual void diagnose(Sema &S, SourceLocation Loc, QualType T) = 0; + virtual ~TypeDiagnoser() {} + }; + + static int getPrintable(int I) { return I; } + static unsigned getPrintable(unsigned I) { return I; } + static bool getPrintable(bool B) { return B; } + static const char * getPrintable(const char *S) { return S; } + static StringRef getPrintable(StringRef S) { return S; } + static const std::string &getPrintable(const std::string &S) { return S; } + static const IdentifierInfo *getPrintable(const IdentifierInfo *II) { + return II; + } + static DeclarationName getPrintable(DeclarationName N) { return N; } + static QualType getPrintable(QualType T) { return T; } + static SourceRange getPrintable(SourceRange R) { return R; } + static SourceRange getPrintable(SourceLocation L) { return L; } + static SourceRange getPrintable(const Expr *E) { return E->getSourceRange(); } + static SourceRange getPrintable(TypeLoc TL) { return TL.getSourceRange();} + + template <typename... Ts> class BoundTypeDiagnoser : public TypeDiagnoser { + unsigned DiagID; + std::tuple<const Ts &...> Args; + + template <std::size_t... Is> + void emit(const SemaDiagnosticBuilder &DB, + llvm::index_sequence<Is...>) const { + // Apply all tuple elements to the builder in order. + bool Dummy[] = {false, (DB << getPrintable(std::get<Is>(Args)))...}; + (void)Dummy; + } + + public: + BoundTypeDiagnoser(unsigned DiagID, const Ts &...Args) + : TypeDiagnoser(), DiagID(DiagID), Args(Args...) { + assert(DiagID != 0 && "no diagnostic for type diagnoser"); + } + + void diagnose(Sema &S, SourceLocation Loc, QualType T) override { + const SemaDiagnosticBuilder &DB = S.Diag(Loc, DiagID); + emit(DB, llvm::index_sequence_for<Ts...>()); + DB << T; + } + }; + +private: + bool RequireCompleteTypeImpl(SourceLocation Loc, QualType T, + TypeDiagnoser *Diagnoser); + + VisibleModuleSet VisibleModules; + llvm::SmallVector<VisibleModuleSet, 16> VisibleModulesStack; + + Module *CachedFakeTopLevelModule; + +public: + /// \brief Get the module owning an entity. + Module *getOwningModule(Decl *Entity); + + /// \brief Make a merged definition of an existing hidden definition \p ND + /// visible at the specified location. + void makeMergedDefinitionVisible(NamedDecl *ND, SourceLocation Loc); + + bool isModuleVisible(Module *M) { return VisibleModules.isVisible(M); } + + /// Determine whether a declaration is visible to name lookup. + bool isVisible(const NamedDecl *D) { + return !D->isHidden() || isVisibleSlow(D); + } + bool hasVisibleMergedDefinition(NamedDecl *Def); + + /// Determine if \p D has a visible definition. If not, suggest a declaration + /// that should be made visible to expose the definition. + bool hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested, + bool OnlyNeedComplete = false); + bool hasVisibleDefinition(const NamedDecl *D) { + NamedDecl *Hidden; + return hasVisibleDefinition(const_cast<NamedDecl*>(D), &Hidden); + } + + /// Determine if the template parameter \p D has a visible default argument. + bool + hasVisibleDefaultArgument(const NamedDecl *D, + llvm::SmallVectorImpl<Module *> *Modules = nullptr); + + /// Determine if \p A and \p B are equivalent internal linkage declarations + /// from different modules, and thus an ambiguity error can be downgraded to + /// an extension warning. + bool isEquivalentInternalLinkageDeclaration(const NamedDecl *A, + const NamedDecl *B); + void diagnoseEquivalentInternalLinkageDeclarations( + SourceLocation Loc, const NamedDecl *D, + ArrayRef<const NamedDecl *> Equiv); + + bool isCompleteType(SourceLocation Loc, QualType T) { + return !RequireCompleteTypeImpl(Loc, T, nullptr); + } + bool RequireCompleteType(SourceLocation Loc, QualType T, + TypeDiagnoser &Diagnoser); + bool RequireCompleteType(SourceLocation Loc, QualType T, + unsigned DiagID); + + template <typename... Ts> + bool RequireCompleteType(SourceLocation Loc, QualType T, unsigned DiagID, + const Ts &...Args) { + BoundTypeDiagnoser<Ts...> Diagnoser(DiagID, Args...); + return RequireCompleteType(Loc, T, Diagnoser); + } + + void completeExprArrayBound(Expr *E); + bool RequireCompleteExprType(Expr *E, TypeDiagnoser &Diagnoser); + bool RequireCompleteExprType(Expr *E, unsigned DiagID); + + template <typename... Ts> + bool RequireCompleteExprType(Expr *E, unsigned DiagID, const Ts &...Args) { + BoundTypeDiagnoser<Ts...> Diagnoser(DiagID, Args...); + return RequireCompleteExprType(E, Diagnoser); + } + + bool RequireLiteralType(SourceLocation Loc, QualType T, + TypeDiagnoser &Diagnoser); + bool RequireLiteralType(SourceLocation Loc, QualType T, unsigned DiagID); + + template <typename... Ts> + bool RequireLiteralType(SourceLocation Loc, QualType T, unsigned DiagID, + const Ts &...Args) { + BoundTypeDiagnoser<Ts...> Diagnoser(DiagID, Args...); + return RequireLiteralType(Loc, T, Diagnoser); + } + + QualType getElaboratedType(ElaboratedTypeKeyword Keyword, + const CXXScopeSpec &SS, QualType T); + + QualType BuildTypeofExprType(Expr *E, SourceLocation Loc); + /// If AsUnevaluated is false, E is treated as though it were an evaluated + /// context, such as when building a type for decltype(auto). + QualType BuildDecltypeType(Expr *E, SourceLocation Loc, + bool AsUnevaluated = true); + QualType BuildUnaryTransformType(QualType BaseType, + UnaryTransformType::UTTKind UKind, + SourceLocation Loc); + + //===--------------------------------------------------------------------===// + // Symbol table / Decl tracking callbacks: SemaDecl.cpp. + // + + struct SkipBodyInfo { + SkipBodyInfo() : ShouldSkip(false), Previous(nullptr) {} + bool ShouldSkip; + NamedDecl *Previous; + }; + + /// List of decls defined in a function prototype. This contains EnumConstants + /// that incorrectly end up in translation unit scope because there is no + /// function to pin them on. ActOnFunctionDeclarator reads this list and patches + /// them into the FunctionDecl. + std::vector<NamedDecl*> DeclsInPrototypeScope; + + DeclGroupPtrTy ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType = nullptr); + + void DiagnoseUseOfUnimplementedSelectors(); + + bool isSimpleTypeSpecifier(tok::TokenKind Kind) const; + + ParsedType getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, + Scope *S, CXXScopeSpec *SS = nullptr, + bool isClassName = false, + bool HasTrailingDot = false, + ParsedType ObjectType = ParsedType(), + bool IsCtorOrDtorName = false, + bool WantNontrivialTypeSourceInfo = false, + IdentifierInfo **CorrectedII = nullptr); + TypeSpecifierType isTagName(IdentifierInfo &II, Scope *S); + bool isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S); + void DiagnoseUnknownTypeName(IdentifierInfo *&II, + SourceLocation IILoc, + Scope *S, + CXXScopeSpec *SS, + ParsedType &SuggestedType, + bool AllowClassTemplates = false); + + /// \brief For compatibility with MSVC, we delay parsing of some default + /// template type arguments until instantiation time. Emits a warning and + /// returns a synthesized DependentNameType that isn't really dependent on any + /// other template arguments. + ParsedType ActOnDelayedDefaultTemplateArg(const IdentifierInfo &II, + SourceLocation NameLoc); + + /// \brief Describes the result of the name lookup and resolution performed + /// by \c ClassifyName(). + enum NameClassificationKind { + NC_Unknown, + NC_Error, + NC_Keyword, + NC_Type, + NC_Expression, + NC_NestedNameSpecifier, + NC_TypeTemplate, + NC_VarTemplate, + NC_FunctionTemplate + }; + + class NameClassification { + NameClassificationKind Kind; + ExprResult Expr; + TemplateName Template; + ParsedType Type; + const IdentifierInfo *Keyword; + + explicit NameClassification(NameClassificationKind Kind) : Kind(Kind) {} + + public: + NameClassification(ExprResult Expr) : Kind(NC_Expression), Expr(Expr) {} + + NameClassification(ParsedType Type) : Kind(NC_Type), Type(Type) {} + + NameClassification(const IdentifierInfo *Keyword) + : Kind(NC_Keyword), Keyword(Keyword) { } + + static NameClassification Error() { + return NameClassification(NC_Error); + } + + static NameClassification Unknown() { + return NameClassification(NC_Unknown); + } + + static NameClassification NestedNameSpecifier() { + return NameClassification(NC_NestedNameSpecifier); + } + + static NameClassification TypeTemplate(TemplateName Name) { + NameClassification Result(NC_TypeTemplate); + Result.Template = Name; + return Result; + } + + static NameClassification VarTemplate(TemplateName Name) { + NameClassification Result(NC_VarTemplate); + Result.Template = Name; + return Result; + } + + static NameClassification FunctionTemplate(TemplateName Name) { + NameClassification Result(NC_FunctionTemplate); + Result.Template = Name; + return Result; + } + + NameClassificationKind getKind() const { return Kind; } + + ParsedType getType() const { + assert(Kind == NC_Type); + return Type; + } + + ExprResult getExpression() const { + assert(Kind == NC_Expression); + return Expr; + } + + TemplateName getTemplateName() const { + assert(Kind == NC_TypeTemplate || Kind == NC_FunctionTemplate || + Kind == NC_VarTemplate); + return Template; + } + + TemplateNameKind getTemplateNameKind() const { + switch (Kind) { + case NC_TypeTemplate: + return TNK_Type_template; + case NC_FunctionTemplate: + return TNK_Function_template; + case NC_VarTemplate: + return TNK_Var_template; + default: + llvm_unreachable("unsupported name classification."); + } + } + }; + + /// \brief Perform name lookup on the given name, classifying it based on + /// the results of name lookup and the following token. + /// + /// This routine is used by the parser to resolve identifiers and help direct + /// parsing. When the identifier cannot be found, this routine will attempt + /// to correct the typo and classify based on the resulting name. + /// + /// \param S The scope in which we're performing name lookup. + /// + /// \param SS The nested-name-specifier that precedes the name. + /// + /// \param Name The identifier. If typo correction finds an alternative name, + /// this pointer parameter will be updated accordingly. + /// + /// \param NameLoc The location of the identifier. + /// + /// \param NextToken The token following the identifier. Used to help + /// disambiguate the name. + /// + /// \param IsAddressOfOperand True if this name is the operand of a unary + /// address of ('&') expression, assuming it is classified as an + /// expression. + /// + /// \param CCC The correction callback, if typo correction is desired. + NameClassification + ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name, + SourceLocation NameLoc, const Token &NextToken, + bool IsAddressOfOperand, + std::unique_ptr<CorrectionCandidateCallback> CCC = nullptr); + + Decl *ActOnDeclarator(Scope *S, Declarator &D); + + NamedDecl *HandleDeclarator(Scope *S, Declarator &D, + MultiTemplateParamsArg TemplateParameterLists); + void RegisterLocallyScopedExternCDecl(NamedDecl *ND, Scope *S); + bool DiagnoseClassNameShadow(DeclContext *DC, DeclarationNameInfo Info); + bool diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC, + DeclarationName Name, + SourceLocation Loc); + void + diagnoseIgnoredQualifiers(unsigned DiagID, unsigned Quals, + SourceLocation FallbackLoc, + SourceLocation ConstQualLoc = SourceLocation(), + SourceLocation VolatileQualLoc = SourceLocation(), + SourceLocation RestrictQualLoc = SourceLocation(), + SourceLocation AtomicQualLoc = SourceLocation()); + + static bool adjustContextForLocalExternDecl(DeclContext *&DC); + void DiagnoseFunctionSpecifiers(const DeclSpec &DS); + void CheckShadow(Scope *S, VarDecl *D, const LookupResult& R); + void CheckShadow(Scope *S, VarDecl *D); + void CheckCastAlign(Expr *Op, QualType T, SourceRange TRange); + void handleTagNumbering(const TagDecl *Tag, Scope *TagScope); + void setTagNameForLinkagePurposes(TagDecl *TagFromDeclSpec, + TypedefNameDecl *NewTD); + void CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *D); + NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, + TypeSourceInfo *TInfo, + LookupResult &Previous); + NamedDecl* ActOnTypedefNameDecl(Scope* S, DeclContext* DC, TypedefNameDecl *D, + LookupResult &Previous, bool &Redeclaration); + NamedDecl *ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, + TypeSourceInfo *TInfo, + LookupResult &Previous, + MultiTemplateParamsArg TemplateParamLists, + bool &AddToScope); + // Returns true if the variable declaration is a redeclaration + bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous); + void CheckVariableDeclarationType(VarDecl *NewVD); + void CheckCompleteVariableDeclaration(VarDecl *var); + void MaybeSuggestAddingStaticToDecl(const FunctionDecl *D); + + NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, + TypeSourceInfo *TInfo, + LookupResult &Previous, + MultiTemplateParamsArg TemplateParamLists, + bool &AddToScope); + bool AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD); + + bool CheckConstexprFunctionDecl(const FunctionDecl *FD); + bool CheckConstexprFunctionBody(const FunctionDecl *FD, Stmt *Body); + + void DiagnoseHiddenVirtualMethods(CXXMethodDecl *MD); + void FindHiddenVirtualMethods(CXXMethodDecl *MD, + SmallVectorImpl<CXXMethodDecl*> &OverloadedMethods); + void NoteHiddenVirtualMethods(CXXMethodDecl *MD, + SmallVectorImpl<CXXMethodDecl*> &OverloadedMethods); + // Returns true if the function declaration is a redeclaration + bool CheckFunctionDeclaration(Scope *S, + FunctionDecl *NewFD, LookupResult &Previous, + bool IsExplicitSpecialization); + void CheckMain(FunctionDecl *FD, const DeclSpec &D); + void CheckMSVCRTEntryPoint(FunctionDecl *FD); + Decl *ActOnParamDeclarator(Scope *S, Declarator &D); + ParmVarDecl *BuildParmVarDeclForTypedef(DeclContext *DC, + SourceLocation Loc, + QualType T); + ParmVarDecl *CheckParameter(DeclContext *DC, SourceLocation StartLoc, + SourceLocation NameLoc, IdentifierInfo *Name, + QualType T, TypeSourceInfo *TSInfo, + StorageClass SC); + void ActOnParamDefaultArgument(Decl *param, + SourceLocation EqualLoc, + Expr *defarg); + void ActOnParamUnparsedDefaultArgument(Decl *param, + SourceLocation EqualLoc, + SourceLocation ArgLoc); + void ActOnParamDefaultArgumentError(Decl *param, SourceLocation EqualLoc); + bool SetParamDefaultArgument(ParmVarDecl *Param, Expr *DefaultArg, + SourceLocation EqualLoc); + + void AddInitializerToDecl(Decl *dcl, Expr *init, bool DirectInit, + bool TypeMayContainAuto); + void ActOnUninitializedDecl(Decl *dcl, bool TypeMayContainAuto); + void ActOnInitializerError(Decl *Dcl); + void ActOnPureSpecifier(Decl *D, SourceLocation PureSpecLoc); + void ActOnCXXForRangeDecl(Decl *D); + StmtResult ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc, + IdentifierInfo *Ident, + ParsedAttributes &Attrs, + SourceLocation AttrEnd); + void SetDeclDeleted(Decl *dcl, SourceLocation DelLoc); + void SetDeclDefaulted(Decl *dcl, SourceLocation DefaultLoc); + void FinalizeDeclaration(Decl *D); + DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, + ArrayRef<Decl *> Group); + DeclGroupPtrTy BuildDeclaratorGroup(MutableArrayRef<Decl *> Group, + bool TypeMayContainAuto = true); + + /// Should be called on all declarations that might have attached + /// documentation comments. + void ActOnDocumentableDecl(Decl *D); + void ActOnDocumentableDecls(ArrayRef<Decl *> Group); + + void ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, + SourceLocation LocAfterDecls); + void CheckForFunctionRedefinition( + FunctionDecl *FD, const FunctionDecl *EffectiveDefinition = nullptr, + SkipBodyInfo *SkipBody = nullptr); + Decl *ActOnStartOfFunctionDef(Scope *S, Declarator &D, + MultiTemplateParamsArg TemplateParamLists, + SkipBodyInfo *SkipBody = nullptr); + Decl *ActOnStartOfFunctionDef(Scope *S, Decl *D, + SkipBodyInfo *SkipBody = nullptr); + void ActOnStartOfObjCMethodDef(Scope *S, Decl *D); + bool isObjCMethodDecl(Decl *D) { + return D && isa<ObjCMethodDecl>(D); + } + + /// \brief Determine whether we can delay parsing the body of a function or + /// function template until it is used, assuming we don't care about emitting + /// code for that function. + /// + /// This will be \c false if we may need the body of the function in the + /// middle of parsing an expression (where it's impractical to switch to + /// parsing a different function), for instance, if it's constexpr in C++11 + /// or has an 'auto' return type in C++14. These cases are essentially bugs. + bool canDelayFunctionBody(const Declarator &D); + + /// \brief Determine whether we can skip parsing the body of a function + /// definition, assuming we don't care about analyzing its body or emitting + /// code for that function. + /// + /// This will be \c false only if we may need the body of the function in + /// order to parse the rest of the program (for instance, if it is + /// \c constexpr in C++11 or has an 'auto' return type in C++14). + bool canSkipFunctionBody(Decl *D); + + void computeNRVO(Stmt *Body, sema::FunctionScopeInfo *Scope); + Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body); + Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body, bool IsInstantiation); + Decl *ActOnSkippedFunctionBody(Decl *Decl); + void ActOnFinishInlineMethodDef(CXXMethodDecl *D); + + /// ActOnFinishDelayedAttribute - Invoked when we have finished parsing an + /// attribute for which parsing is delayed. + void ActOnFinishDelayedAttribute(Scope *S, Decl *D, ParsedAttributes &Attrs); + + /// \brief Diagnose any unused parameters in the given sequence of + /// ParmVarDecl pointers. + void DiagnoseUnusedParameters(ParmVarDecl * const *Begin, + ParmVarDecl * const *End); + + /// \brief Diagnose whether the size of parameters or return value of a + /// function or obj-c method definition is pass-by-value and larger than a + /// specified threshold. + void DiagnoseSizeOfParametersAndReturnValue(ParmVarDecl * const *Begin, + ParmVarDecl * const *End, + QualType ReturnTy, + NamedDecl *D); + + void DiagnoseInvalidJumps(Stmt *Body); + Decl *ActOnFileScopeAsmDecl(Expr *expr, + SourceLocation AsmLoc, + SourceLocation RParenLoc); + + /// \brief Handle a C++11 empty-declaration and attribute-declaration. + Decl *ActOnEmptyDeclaration(Scope *S, + AttributeList *AttrList, + SourceLocation SemiLoc); + + /// \brief The parser has processed a module import declaration. + /// + /// \param AtLoc The location of the '@' symbol, if any. + /// + /// \param ImportLoc The location of the 'import' keyword. + /// + /// \param Path The module access path. + DeclResult ActOnModuleImport(SourceLocation AtLoc, SourceLocation ImportLoc, + ModuleIdPath Path); + + /// \brief The parser has processed a module import translated from a + /// #include or similar preprocessing directive. + void ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod); + + /// \brief The parsed has entered a submodule. + void ActOnModuleBegin(SourceLocation DirectiveLoc, Module *Mod); + /// \brief The parser has left a submodule. + void ActOnModuleEnd(SourceLocation DirectiveLoc, Module *Mod); + + /// \brief Check if module import may be found in the current context, + /// emit error if not. + void diagnoseMisplacedModuleImport(Module *M, SourceLocation ImportLoc); + + /// \brief Create an implicit import of the given module at the given + /// source location, for error recovery, if possible. + /// + /// This routine is typically used when an entity found by name lookup + /// is actually hidden within a module that we know about but the user + /// has forgotten to import. + void createImplicitModuleImportForErrorRecovery(SourceLocation Loc, + Module *Mod); + + /// Kinds of missing import. Note, the values of these enumerators correspond + /// to %select values in diagnostics. + enum class MissingImportKind { + Declaration, + Definition, + DefaultArgument + }; + + /// \brief Diagnose that the specified declaration needs to be visible but + /// isn't, and suggest a module import that would resolve the problem. + void diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl, + bool NeedDefinition, bool Recover = true); + void diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl, + SourceLocation DeclLoc, ArrayRef<Module *> Modules, + MissingImportKind MIK, bool Recover); + + /// \brief Retrieve a suitable printing policy. + PrintingPolicy getPrintingPolicy() const { + return getPrintingPolicy(Context, PP); + } + + /// \brief Retrieve a suitable printing policy. + static PrintingPolicy getPrintingPolicy(const ASTContext &Ctx, + const Preprocessor &PP); + + /// Scope actions. + void ActOnPopScope(SourceLocation Loc, Scope *S); + void ActOnTranslationUnitScope(Scope *S); + + Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, + DeclSpec &DS); + Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, + DeclSpec &DS, + MultiTemplateParamsArg TemplateParams, + bool IsExplicitInstantiation = false); + + Decl *BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, + AccessSpecifier AS, + RecordDecl *Record, + const PrintingPolicy &Policy); + + Decl *BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS, + RecordDecl *Record); + + bool isAcceptableTagRedeclaration(const TagDecl *Previous, + TagTypeKind NewTag, bool isDefinition, + SourceLocation NewTagLoc, + const IdentifierInfo *Name); + + enum TagUseKind { + TUK_Reference, // Reference to a tag: 'struct foo *X;' + TUK_Declaration, // Fwd decl of a tag: 'struct foo;' + TUK_Definition, // Definition of a tag: 'struct foo { int X; } Y;' + TUK_Friend // Friend declaration: 'friend struct foo;' + }; + + Decl *ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, + SourceLocation KWLoc, CXXScopeSpec &SS, + IdentifierInfo *Name, SourceLocation NameLoc, + AttributeList *Attr, AccessSpecifier AS, + SourceLocation ModulePrivateLoc, + MultiTemplateParamsArg TemplateParameterLists, + bool &OwnedDecl, bool &IsDependent, + SourceLocation ScopedEnumKWLoc, + bool ScopedEnumUsesClassTag, TypeResult UnderlyingType, + bool IsTypeSpecifier, SkipBodyInfo *SkipBody = nullptr); + + Decl *ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, + unsigned TagSpec, SourceLocation TagLoc, + CXXScopeSpec &SS, + IdentifierInfo *Name, SourceLocation NameLoc, + AttributeList *Attr, + MultiTemplateParamsArg TempParamLists); + + TypeResult ActOnDependentTag(Scope *S, + unsigned TagSpec, + TagUseKind TUK, + const CXXScopeSpec &SS, + IdentifierInfo *Name, + SourceLocation TagLoc, + SourceLocation NameLoc); + + void ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart, + IdentifierInfo *ClassName, + SmallVectorImpl<Decl *> &Decls); + Decl *ActOnField(Scope *S, Decl *TagD, SourceLocation DeclStart, + Declarator &D, Expr *BitfieldWidth); + + FieldDecl *HandleField(Scope *S, RecordDecl *TagD, SourceLocation DeclStart, + Declarator &D, Expr *BitfieldWidth, + InClassInitStyle InitStyle, + AccessSpecifier AS); + MSPropertyDecl *HandleMSProperty(Scope *S, RecordDecl *TagD, + SourceLocation DeclStart, + Declarator &D, Expr *BitfieldWidth, + InClassInitStyle InitStyle, + AccessSpecifier AS, + AttributeList *MSPropertyAttr); + + FieldDecl *CheckFieldDecl(DeclarationName Name, QualType T, + TypeSourceInfo *TInfo, + RecordDecl *Record, SourceLocation Loc, + bool Mutable, Expr *BitfieldWidth, + InClassInitStyle InitStyle, + SourceLocation TSSL, + AccessSpecifier AS, NamedDecl *PrevDecl, + Declarator *D = nullptr); + + bool CheckNontrivialField(FieldDecl *FD); + void DiagnoseNontrivial(const CXXRecordDecl *Record, CXXSpecialMember CSM); + bool SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM, + bool Diagnose = false); + CXXSpecialMember getSpecialMember(const CXXMethodDecl *MD); + void ActOnLastBitfield(SourceLocation DeclStart, + SmallVectorImpl<Decl *> &AllIvarDecls); + Decl *ActOnIvar(Scope *S, SourceLocation DeclStart, + Declarator &D, Expr *BitfieldWidth, + tok::ObjCKeywordKind visibility); + + // This is used for both record definitions and ObjC interface declarations. + void ActOnFields(Scope* S, SourceLocation RecLoc, Decl *TagDecl, + ArrayRef<Decl *> Fields, + SourceLocation LBrac, SourceLocation RBrac, + AttributeList *AttrList); + + /// ActOnTagStartDefinition - Invoked when we have entered the + /// scope of a tag's definition (e.g., for an enumeration, class, + /// struct, or union). + void ActOnTagStartDefinition(Scope *S, Decl *TagDecl); + + typedef void *SkippedDefinitionContext; + + /// \brief Invoked when we enter a tag definition that we're skipping. + SkippedDefinitionContext ActOnTagStartSkippedDefinition(Scope *S, Decl *TD); + + Decl *ActOnObjCContainerStartDefinition(Decl *IDecl); + + /// ActOnStartCXXMemberDeclarations - Invoked when we have parsed a + /// C++ record definition's base-specifiers clause and are starting its + /// member declarations. + void ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagDecl, + SourceLocation FinalLoc, + bool IsFinalSpelledSealed, + SourceLocation LBraceLoc); + + /// ActOnTagFinishDefinition - Invoked once we have finished parsing + /// the definition of a tag (enumeration, class, struct, or union). + void ActOnTagFinishDefinition(Scope *S, Decl *TagDecl, + SourceLocation RBraceLoc); + + void ActOnTagFinishSkippedDefinition(SkippedDefinitionContext Context); + + void ActOnObjCContainerFinishDefinition(); + + /// \brief Invoked when we must temporarily exit the objective-c container + /// scope for parsing/looking-up C constructs. + /// + /// Must be followed by a call to \see ActOnObjCReenterContainerContext + void ActOnObjCTemporaryExitContainerContext(DeclContext *DC); + void ActOnObjCReenterContainerContext(DeclContext *DC); + + /// ActOnTagDefinitionError - Invoked when there was an unrecoverable + /// error parsing the definition of a tag. + void ActOnTagDefinitionError(Scope *S, Decl *TagDecl); + + EnumConstantDecl *CheckEnumConstant(EnumDecl *Enum, + EnumConstantDecl *LastEnumConst, + SourceLocation IdLoc, + IdentifierInfo *Id, + Expr *val); + bool CheckEnumUnderlyingType(TypeSourceInfo *TI); + bool CheckEnumRedeclaration(SourceLocation EnumLoc, bool IsScoped, + QualType EnumUnderlyingTy, + bool EnumUnderlyingIsImplicit, + const EnumDecl *Prev); + + /// Determine whether the body of an anonymous enumeration should be skipped. + /// \param II The name of the first enumerator. + SkipBodyInfo shouldSkipAnonEnumBody(Scope *S, IdentifierInfo *II, + SourceLocation IILoc); + + Decl *ActOnEnumConstant(Scope *S, Decl *EnumDecl, Decl *LastEnumConstant, + SourceLocation IdLoc, IdentifierInfo *Id, + AttributeList *Attrs, + SourceLocation EqualLoc, Expr *Val); + void ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, + SourceLocation RBraceLoc, Decl *EnumDecl, + ArrayRef<Decl *> Elements, + Scope *S, AttributeList *Attr); + + DeclContext *getContainingDC(DeclContext *DC); + + /// Set the current declaration context until it gets popped. + void PushDeclContext(Scope *S, DeclContext *DC); + void PopDeclContext(); + + /// EnterDeclaratorContext - Used when we must lookup names in the context + /// of a declarator's nested name specifier. + void EnterDeclaratorContext(Scope *S, DeclContext *DC); + void ExitDeclaratorContext(Scope *S); + + /// Push the parameters of D, which must be a function, into scope. + void ActOnReenterFunctionContext(Scope* S, Decl* D); + void ActOnExitFunctionContext(); + + DeclContext *getFunctionLevelDeclContext(); + + /// getCurFunctionDecl - If inside of a function body, this returns a pointer + /// to the function decl for the function being parsed. If we're currently + /// in a 'block', this returns the containing context. + FunctionDecl *getCurFunctionDecl(); + + /// getCurMethodDecl - If inside of a method body, this returns a pointer to + /// the method decl for the method being parsed. If we're currently + /// in a 'block', this returns the containing context. + ObjCMethodDecl *getCurMethodDecl(); + + /// getCurFunctionOrMethodDecl - Return the Decl for the current ObjC method + /// or C function we're in, otherwise return null. If we're currently + /// in a 'block', this returns the containing context. + NamedDecl *getCurFunctionOrMethodDecl(); + + /// Add this decl to the scope shadowed decl chains. + void PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext = true); + + /// \brief Make the given externally-produced declaration visible at the + /// top level scope. + /// + /// \param D The externally-produced declaration to push. + /// + /// \param Name The name of the externally-produced declaration. + void pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name); + + /// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true + /// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns + /// true if 'D' belongs to the given declaration context. + /// + /// \param AllowInlineNamespace If \c true, allow the declaration to be in the + /// enclosing namespace set of the context, rather than contained + /// directly within it. + bool isDeclInScope(NamedDecl *D, DeclContext *Ctx, Scope *S = nullptr, + bool AllowInlineNamespace = false); + + /// Finds the scope corresponding to the given decl context, if it + /// happens to be an enclosing scope. Otherwise return NULL. + static Scope *getScopeForDeclContext(Scope *S, DeclContext *DC); + + /// Subroutines of ActOnDeclarator(). + TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T, + TypeSourceInfo *TInfo); + bool isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New); + + /// \brief Describes the kind of merge to perform for availability + /// attributes (including "deprecated", "unavailable", and "availability"). + enum AvailabilityMergeKind { + /// \brief Don't merge availability attributes at all. + AMK_None, + /// \brief Merge availability attributes for a redeclaration, which requires + /// an exact match. + AMK_Redeclaration, + /// \brief Merge availability attributes for an override, which requires + /// an exact match or a weakening of constraints. + AMK_Override, + /// \brief Merge availability attributes for an implementation of + /// a protocol requirement. + AMK_ProtocolImplementation, + }; + + /// Attribute merging methods. Return true if a new attribute was added. + AvailabilityAttr *mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, + IdentifierInfo *Platform, + VersionTuple Introduced, + VersionTuple Deprecated, + VersionTuple Obsoleted, + bool IsUnavailable, + StringRef Message, + AvailabilityMergeKind AMK, + unsigned AttrSpellingListIndex); + TypeVisibilityAttr *mergeTypeVisibilityAttr(Decl *D, SourceRange Range, + TypeVisibilityAttr::VisibilityType Vis, + unsigned AttrSpellingListIndex); + VisibilityAttr *mergeVisibilityAttr(Decl *D, SourceRange Range, + VisibilityAttr::VisibilityType Vis, + unsigned AttrSpellingListIndex); + DLLImportAttr *mergeDLLImportAttr(Decl *D, SourceRange Range, + unsigned AttrSpellingListIndex); + DLLExportAttr *mergeDLLExportAttr(Decl *D, SourceRange Range, + unsigned AttrSpellingListIndex); + MSInheritanceAttr * + mergeMSInheritanceAttr(Decl *D, SourceRange Range, bool BestCase, + unsigned AttrSpellingListIndex, + MSInheritanceAttr::Spelling SemanticSpelling); + FormatAttr *mergeFormatAttr(Decl *D, SourceRange Range, + IdentifierInfo *Format, int FormatIdx, + int FirstArg, unsigned AttrSpellingListIndex); + SectionAttr *mergeSectionAttr(Decl *D, SourceRange Range, StringRef Name, + unsigned AttrSpellingListIndex); + AlwaysInlineAttr *mergeAlwaysInlineAttr(Decl *D, SourceRange Range, + IdentifierInfo *Ident, + unsigned AttrSpellingListIndex); + MinSizeAttr *mergeMinSizeAttr(Decl *D, SourceRange Range, + unsigned AttrSpellingListIndex); + OptimizeNoneAttr *mergeOptimizeNoneAttr(Decl *D, SourceRange Range, + unsigned AttrSpellingListIndex); + InternalLinkageAttr *mergeInternalLinkageAttr(Decl *D, SourceRange Range, + IdentifierInfo *Ident, + unsigned AttrSpellingListIndex); + CommonAttr *mergeCommonAttr(Decl *D, SourceRange Range, IdentifierInfo *Ident, + unsigned AttrSpellingListIndex); + + void mergeDeclAttributes(NamedDecl *New, Decl *Old, + AvailabilityMergeKind AMK = AMK_Redeclaration); + void MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New, + LookupResult &OldDecls); + bool MergeFunctionDecl(FunctionDecl *New, NamedDecl *&Old, Scope *S, + bool MergeTypeWithOld); + bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old, + Scope *S, bool MergeTypeWithOld); + void mergeObjCMethodDecls(ObjCMethodDecl *New, ObjCMethodDecl *Old); + void MergeVarDecl(VarDecl *New, LookupResult &Previous); + void MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool MergeTypeWithOld); + void MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old); + bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Scope *S); + + // AssignmentAction - This is used by all the assignment diagnostic functions + // to represent what is actually causing the operation + enum AssignmentAction { + AA_Assigning, + AA_Passing, + AA_Returning, + AA_Converting, + AA_Initializing, + AA_Sending, + AA_Casting, + AA_Passing_CFAudited + }; + + /// C++ Overloading. + enum OverloadKind { + /// This is a legitimate overload: the existing declarations are + /// functions or function templates with different signatures. + Ovl_Overload, + + /// This is not an overload because the signature exactly matches + /// an existing declaration. + Ovl_Match, + + /// This is not an overload because the lookup results contain a + /// non-function. + Ovl_NonFunction + }; + OverloadKind CheckOverload(Scope *S, + FunctionDecl *New, + const LookupResult &OldDecls, + NamedDecl *&OldDecl, + bool IsForUsingDecl); + bool IsOverload(FunctionDecl *New, FunctionDecl *Old, bool IsForUsingDecl); + + /// \brief Checks availability of the function depending on the current + /// function context.Inside an unavailable function,unavailability is ignored. + /// + /// \returns true if \p FD is unavailable and current context is inside + /// an available function, false otherwise. + bool isFunctionConsideredUnavailable(FunctionDecl *FD); + + ImplicitConversionSequence + TryImplicitConversion(Expr *From, QualType ToType, + bool SuppressUserConversions, + bool AllowExplicit, + bool InOverloadResolution, + bool CStyle, + bool AllowObjCWritebackConversion); + + bool IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType); + bool IsFloatingPointPromotion(QualType FromType, QualType ToType); + bool IsComplexPromotion(QualType FromType, QualType ToType); + bool IsPointerConversion(Expr *From, QualType FromType, QualType ToType, + bool InOverloadResolution, + QualType& ConvertedType, bool &IncompatibleObjC); + bool isObjCPointerConversion(QualType FromType, QualType ToType, + QualType& ConvertedType, bool &IncompatibleObjC); + bool isObjCWritebackConversion(QualType FromType, QualType ToType, + QualType &ConvertedType); + bool IsBlockPointerConversion(QualType FromType, QualType ToType, + QualType& ConvertedType); + bool FunctionParamTypesAreEqual(const FunctionProtoType *OldType, + const FunctionProtoType *NewType, + unsigned *ArgPos = nullptr); + void HandleFunctionTypeMismatch(PartialDiagnostic &PDiag, + QualType FromType, QualType ToType); + + void maybeExtendBlockObject(ExprResult &E); + CastKind PrepareCastToObjCObjectPointer(ExprResult &E); + bool CheckPointerConversion(Expr *From, QualType ToType, + CastKind &Kind, + CXXCastPath& BasePath, + bool IgnoreBaseAccess); + bool IsMemberPointerConversion(Expr *From, QualType FromType, QualType ToType, + bool InOverloadResolution, + QualType &ConvertedType); + bool CheckMemberPointerConversion(Expr *From, QualType ToType, + CastKind &Kind, + CXXCastPath &BasePath, + bool IgnoreBaseAccess); + bool IsQualificationConversion(QualType FromType, QualType ToType, + bool CStyle, bool &ObjCLifetimeConversion); + bool IsNoReturnConversion(QualType FromType, QualType ToType, + QualType &ResultTy); + bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType); + bool isSameOrCompatibleFunctionType(CanQualType Param, CanQualType Arg); + + ExprResult PerformMoveOrCopyInitialization(const InitializedEntity &Entity, + const VarDecl *NRVOCandidate, + QualType ResultType, + Expr *Value, + bool AllowNRVO = true); + + bool CanPerformCopyInitialization(const InitializedEntity &Entity, + ExprResult Init); + ExprResult PerformCopyInitialization(const InitializedEntity &Entity, + SourceLocation EqualLoc, + ExprResult Init, + bool TopLevelOfInitList = false, + bool AllowExplicit = false); + ExprResult PerformObjectArgumentInitialization(Expr *From, + NestedNameSpecifier *Qualifier, + NamedDecl *FoundDecl, + CXXMethodDecl *Method); + + ExprResult PerformContextuallyConvertToBool(Expr *From); + ExprResult PerformContextuallyConvertToObjCPointer(Expr *From); + + /// Contexts in which a converted constant expression is required. + enum CCEKind { + CCEK_CaseValue, ///< Expression in a case label. + CCEK_Enumerator, ///< Enumerator value with fixed underlying type. + CCEK_TemplateArg, ///< Value of a non-type template parameter. + CCEK_NewExpr ///< Constant expression in a noptr-new-declarator. + }; + ExprResult CheckConvertedConstantExpression(Expr *From, QualType T, + llvm::APSInt &Value, CCEKind CCE); + ExprResult CheckConvertedConstantExpression(Expr *From, QualType T, + APValue &Value, CCEKind CCE); + + /// \brief Abstract base class used to perform a contextual implicit + /// conversion from an expression to any type passing a filter. + class ContextualImplicitConverter { + public: + bool Suppress; + bool SuppressConversion; + + ContextualImplicitConverter(bool Suppress = false, + bool SuppressConversion = false) + : Suppress(Suppress), SuppressConversion(SuppressConversion) {} + + /// \brief Determine whether the specified type is a valid destination type + /// for this conversion. + virtual bool match(QualType T) = 0; + + /// \brief Emits a diagnostic complaining that the expression does not have + /// integral or enumeration type. + virtual SemaDiagnosticBuilder + diagnoseNoMatch(Sema &S, SourceLocation Loc, QualType T) = 0; + + /// \brief Emits a diagnostic when the expression has incomplete class type. + virtual SemaDiagnosticBuilder + diagnoseIncomplete(Sema &S, SourceLocation Loc, QualType T) = 0; + + /// \brief Emits a diagnostic when the only matching conversion function + /// is explicit. + virtual SemaDiagnosticBuilder diagnoseExplicitConv( + Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) = 0; + + /// \brief Emits a note for the explicit conversion function. + virtual SemaDiagnosticBuilder + noteExplicitConv(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) = 0; + + /// \brief Emits a diagnostic when there are multiple possible conversion + /// functions. + virtual SemaDiagnosticBuilder + diagnoseAmbiguous(Sema &S, SourceLocation Loc, QualType T) = 0; + + /// \brief Emits a note for one of the candidate conversions. + virtual SemaDiagnosticBuilder + noteAmbiguous(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) = 0; + + /// \brief Emits a diagnostic when we picked a conversion function + /// (for cases when we are not allowed to pick a conversion function). + virtual SemaDiagnosticBuilder diagnoseConversion( + Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) = 0; + + virtual ~ContextualImplicitConverter() {} + }; + + class ICEConvertDiagnoser : public ContextualImplicitConverter { + bool AllowScopedEnumerations; + + public: + ICEConvertDiagnoser(bool AllowScopedEnumerations, + bool Suppress, bool SuppressConversion) + : ContextualImplicitConverter(Suppress, SuppressConversion), + AllowScopedEnumerations(AllowScopedEnumerations) {} + + /// Match an integral or (possibly scoped) enumeration type. + bool match(QualType T) override; + + SemaDiagnosticBuilder + diagnoseNoMatch(Sema &S, SourceLocation Loc, QualType T) override { + return diagnoseNotInt(S, Loc, T); + } + + /// \brief Emits a diagnostic complaining that the expression does not have + /// integral or enumeration type. + virtual SemaDiagnosticBuilder + diagnoseNotInt(Sema &S, SourceLocation Loc, QualType T) = 0; + }; + + /// Perform a contextual implicit conversion. + ExprResult PerformContextualImplicitConversion( + SourceLocation Loc, Expr *FromE, ContextualImplicitConverter &Converter); + + + enum ObjCSubscriptKind { + OS_Array, + OS_Dictionary, + OS_Error + }; + ObjCSubscriptKind CheckSubscriptingKind(Expr *FromE); + + // Note that LK_String is intentionally after the other literals, as + // this is used for diagnostics logic. + enum ObjCLiteralKind { + LK_Array, + LK_Dictionary, + LK_Numeric, + LK_Boxed, + LK_String, + LK_Block, + LK_None + }; + ObjCLiteralKind CheckLiteralKind(Expr *FromE); + + ExprResult PerformObjectMemberConversion(Expr *From, + NestedNameSpecifier *Qualifier, + NamedDecl *FoundDecl, + NamedDecl *Member); + + // Members have to be NamespaceDecl* or TranslationUnitDecl*. + // TODO: make this is a typesafe union. + typedef llvm::SmallPtrSet<DeclContext *, 16> AssociatedNamespaceSet; + typedef llvm::SmallPtrSet<CXXRecordDecl *, 16> AssociatedClassSet; + + void AddOverloadCandidate(FunctionDecl *Function, + DeclAccessPair FoundDecl, + ArrayRef<Expr *> Args, + OverloadCandidateSet& CandidateSet, + bool SuppressUserConversions = false, + bool PartialOverloading = false, + bool AllowExplicit = false); + void AddFunctionCandidates(const UnresolvedSetImpl &Functions, + ArrayRef<Expr *> Args, + OverloadCandidateSet &CandidateSet, + TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr, + bool SuppressUserConversions = false, + bool PartialOverloading = false); + void AddMethodCandidate(DeclAccessPair FoundDecl, + QualType ObjectType, + Expr::Classification ObjectClassification, + ArrayRef<Expr *> Args, + OverloadCandidateSet& CandidateSet, + bool SuppressUserConversion = false); + void AddMethodCandidate(CXXMethodDecl *Method, + DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, QualType ObjectType, + Expr::Classification ObjectClassification, + ArrayRef<Expr *> Args, + OverloadCandidateSet& CandidateSet, + bool SuppressUserConversions = false, + bool PartialOverloading = false); + void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, + DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, + TemplateArgumentListInfo *ExplicitTemplateArgs, + QualType ObjectType, + Expr::Classification ObjectClassification, + ArrayRef<Expr *> Args, + OverloadCandidateSet& CandidateSet, + bool SuppressUserConversions = false, + bool PartialOverloading = false); + void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, + DeclAccessPair FoundDecl, + TemplateArgumentListInfo *ExplicitTemplateArgs, + ArrayRef<Expr *> Args, + OverloadCandidateSet& CandidateSet, + bool SuppressUserConversions = false, + bool PartialOverloading = false); + void AddConversionCandidate(CXXConversionDecl *Conversion, + DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, + Expr *From, QualType ToType, + OverloadCandidateSet& CandidateSet, + bool AllowObjCConversionOnExplicit); + void AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, + DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, + Expr *From, QualType ToType, + OverloadCandidateSet &CandidateSet, + bool AllowObjCConversionOnExplicit); + void AddSurrogateCandidate(CXXConversionDecl *Conversion, + DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, + const FunctionProtoType *Proto, + Expr *Object, ArrayRef<Expr *> Args, + OverloadCandidateSet& CandidateSet); + void AddMemberOperatorCandidates(OverloadedOperatorKind Op, + SourceLocation OpLoc, ArrayRef<Expr *> Args, + OverloadCandidateSet& CandidateSet, + SourceRange OpRange = SourceRange()); + void AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, + ArrayRef<Expr *> Args, + OverloadCandidateSet& CandidateSet, + bool IsAssignmentOperator = false, + unsigned NumContextualBoolArguments = 0); + void AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, + SourceLocation OpLoc, ArrayRef<Expr *> Args, + OverloadCandidateSet& CandidateSet); + void AddArgumentDependentLookupCandidates(DeclarationName Name, + SourceLocation Loc, + ArrayRef<Expr *> Args, + TemplateArgumentListInfo *ExplicitTemplateArgs, + OverloadCandidateSet& CandidateSet, + bool PartialOverloading = false); + + // Emit as a 'note' the specific overload candidate + void NoteOverloadCandidate(FunctionDecl *Fn, QualType DestType = QualType(), + bool TakingAddress = false); + + // Emit as a series of 'note's all template and non-templates identified by + // the expression Expr + void NoteAllOverloadCandidates(Expr *E, QualType DestType = QualType(), + bool TakingAddress = false); + + /// Check the enable_if expressions on the given function. Returns the first + /// failing attribute, or NULL if they were all successful. + EnableIfAttr *CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args, + bool MissingImplicitThis = false); + + /// Returns whether the given function's address can be taken or not, + /// optionally emitting a diagnostic if the address can't be taken. + /// + /// Returns false if taking the address of the function is illegal. + bool checkAddressOfFunctionIsAvailable(const FunctionDecl *Function, + bool Complain = false, + SourceLocation Loc = SourceLocation()); + + // [PossiblyAFunctionType] --> [Return] + // NonFunctionType --> NonFunctionType + // R (A) --> R(A) + // R (*)(A) --> R (A) + // R (&)(A) --> R (A) + // R (S::*)(A) --> R (A) + QualType ExtractUnqualifiedFunctionType(QualType PossiblyAFunctionType); + + FunctionDecl * + ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr, + QualType TargetType, + bool Complain, + DeclAccessPair &Found, + bool *pHadMultipleCandidates = nullptr); + + FunctionDecl * + ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl, + bool Complain = false, + DeclAccessPair *Found = nullptr); + + bool ResolveAndFixSingleFunctionTemplateSpecialization( + ExprResult &SrcExpr, + bool DoFunctionPointerConverion = false, + bool Complain = false, + SourceRange OpRangeForComplaining = SourceRange(), + QualType DestTypeForComplaining = QualType(), + unsigned DiagIDForComplaining = 0); + + + Expr *FixOverloadedFunctionReference(Expr *E, + DeclAccessPair FoundDecl, + FunctionDecl *Fn); + ExprResult FixOverloadedFunctionReference(ExprResult, + DeclAccessPair FoundDecl, + FunctionDecl *Fn); + + void AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, + ArrayRef<Expr *> Args, + OverloadCandidateSet &CandidateSet, + bool PartialOverloading = false); + + // An enum used to represent the different possible results of building a + // range-based for loop. + enum ForRangeStatus { + FRS_Success, + FRS_NoViableFunction, + FRS_DiagnosticIssued + }; + + ForRangeStatus BuildForRangeBeginEndCall(SourceLocation Loc, + SourceLocation RangeLoc, + const DeclarationNameInfo &NameInfo, + LookupResult &MemberLookup, + OverloadCandidateSet *CandidateSet, + Expr *Range, ExprResult *CallExpr); + + ExprResult BuildOverloadedCallExpr(Scope *S, Expr *Fn, + UnresolvedLookupExpr *ULE, + SourceLocation LParenLoc, + MultiExprArg Args, + SourceLocation RParenLoc, + Expr *ExecConfig, + bool AllowTypoCorrection=true); + + bool buildOverloadedCallSet(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, + MultiExprArg Args, SourceLocation RParenLoc, + OverloadCandidateSet *CandidateSet, + ExprResult *Result); + + ExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc, + UnaryOperatorKind Opc, + const UnresolvedSetImpl &Fns, + Expr *input); + + ExprResult CreateOverloadedBinOp(SourceLocation OpLoc, + BinaryOperatorKind Opc, + const UnresolvedSetImpl &Fns, + Expr *LHS, Expr *RHS); + + ExprResult CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, + SourceLocation RLoc, + Expr *Base,Expr *Idx); + + ExprResult + BuildCallToMemberFunction(Scope *S, Expr *MemExpr, + SourceLocation LParenLoc, + MultiExprArg Args, + SourceLocation RParenLoc); + ExprResult + BuildCallToObjectOfClassType(Scope *S, Expr *Object, SourceLocation LParenLoc, + MultiExprArg Args, + SourceLocation RParenLoc); + + ExprResult BuildOverloadedArrowExpr(Scope *S, Expr *Base, + SourceLocation OpLoc, + bool *NoArrowOperatorFound = nullptr); + + /// CheckCallReturnType - Checks that a call expression's return type is + /// complete. Returns true on failure. The location passed in is the location + /// that best represents the call. + bool CheckCallReturnType(QualType ReturnType, SourceLocation Loc, + CallExpr *CE, FunctionDecl *FD); + + /// Helpers for dealing with blocks and functions. + bool CheckParmsForFunctionDef(ParmVarDecl *const *Param, + ParmVarDecl *const *ParamEnd, + bool CheckParameterNames); + void CheckCXXDefaultArguments(FunctionDecl *FD); + void CheckExtraCXXDefaultArguments(Declarator &D); + Scope *getNonFieldDeclScope(Scope *S); + + /// \name Name lookup + /// + /// These routines provide name lookup that is used during semantic + /// analysis to resolve the various kinds of names (identifiers, + /// overloaded operator names, constructor names, etc.) into zero or + /// more declarations within a particular scope. The major entry + /// points are LookupName, which performs unqualified name lookup, + /// and LookupQualifiedName, which performs qualified name lookup. + /// + /// All name lookup is performed based on some specific criteria, + /// which specify what names will be visible to name lookup and how + /// far name lookup should work. These criteria are important both + /// for capturing language semantics (certain lookups will ignore + /// certain names, for example) and for performance, since name + /// lookup is often a bottleneck in the compilation of C++. Name + /// lookup criteria is specified via the LookupCriteria enumeration. + /// + /// The results of name lookup can vary based on the kind of name + /// lookup performed, the current language, and the translation + /// unit. In C, for example, name lookup will either return nothing + /// (no entity found) or a single declaration. In C++, name lookup + /// can additionally refer to a set of overloaded functions or + /// result in an ambiguity. All of the possible results of name + /// lookup are captured by the LookupResult class, which provides + /// the ability to distinguish among them. + //@{ + + /// @brief Describes the kind of name lookup to perform. + enum LookupNameKind { + /// Ordinary name lookup, which finds ordinary names (functions, + /// variables, typedefs, etc.) in C and most kinds of names + /// (functions, variables, members, types, etc.) in C++. + LookupOrdinaryName = 0, + /// Tag name lookup, which finds the names of enums, classes, + /// structs, and unions. + LookupTagName, + /// Label name lookup. + LookupLabel, + /// Member name lookup, which finds the names of + /// class/struct/union members. + LookupMemberName, + /// Look up of an operator name (e.g., operator+) for use with + /// operator overloading. This lookup is similar to ordinary name + /// lookup, but will ignore any declarations that are class members. + LookupOperatorName, + /// Look up of a name that precedes the '::' scope resolution + /// operator in C++. This lookup completely ignores operator, object, + /// function, and enumerator names (C++ [basic.lookup.qual]p1). + LookupNestedNameSpecifierName, + /// Look up a namespace name within a C++ using directive or + /// namespace alias definition, ignoring non-namespace names (C++ + /// [basic.lookup.udir]p1). + LookupNamespaceName, + /// Look up all declarations in a scope with the given name, + /// including resolved using declarations. This is appropriate + /// for checking redeclarations for a using declaration. + LookupUsingDeclName, + /// Look up an ordinary name that is going to be redeclared as a + /// name with linkage. This lookup ignores any declarations that + /// are outside of the current scope unless they have linkage. See + /// C99 6.2.2p4-5 and C++ [basic.link]p6. + LookupRedeclarationWithLinkage, + /// Look up a friend of a local class. This lookup does not look + /// outside the innermost non-class scope. See C++11 [class.friend]p11. + LookupLocalFriendName, + /// Look up the name of an Objective-C protocol. + LookupObjCProtocolName, + /// Look up implicit 'self' parameter of an objective-c method. + LookupObjCImplicitSelfParam, + /// \brief Look up any declaration with any name. + LookupAnyName + }; + + /// \brief Specifies whether (or how) name lookup is being performed for a + /// redeclaration (vs. a reference). + enum RedeclarationKind { + /// \brief The lookup is a reference to this name that is not for the + /// purpose of redeclaring the name. + NotForRedeclaration = 0, + /// \brief The lookup results will be used for redeclaration of a name, + /// if an entity by that name already exists. + ForRedeclaration + }; + + /// \brief The possible outcomes of name lookup for a literal operator. + enum LiteralOperatorLookupResult { + /// \brief The lookup resulted in an error. + LOLR_Error, + /// \brief The lookup found a single 'cooked' literal operator, which + /// expects a normal literal to be built and passed to it. + LOLR_Cooked, + /// \brief The lookup found a single 'raw' literal operator, which expects + /// a string literal containing the spelling of the literal token. + LOLR_Raw, + /// \brief The lookup found an overload set of literal operator templates, + /// which expect the characters of the spelling of the literal token to be + /// passed as a non-type template argument pack. + LOLR_Template, + /// \brief The lookup found an overload set of literal operator templates, + /// which expect the character type and characters of the spelling of the + /// string literal token to be passed as template arguments. + LOLR_StringTemplate + }; + + SpecialMemberOverloadResult *LookupSpecialMember(CXXRecordDecl *D, + CXXSpecialMember SM, + bool ConstArg, + bool VolatileArg, + bool RValueThis, + bool ConstThis, + bool VolatileThis); + + typedef std::function<void(const TypoCorrection &)> TypoDiagnosticGenerator; + typedef std::function<ExprResult(Sema &, TypoExpr *, TypoCorrection)> + TypoRecoveryCallback; + +private: + bool CppLookupName(LookupResult &R, Scope *S); + + struct TypoExprState { + std::unique_ptr<TypoCorrectionConsumer> Consumer; + TypoDiagnosticGenerator DiagHandler; + TypoRecoveryCallback RecoveryHandler; + TypoExprState(); + TypoExprState(TypoExprState&& other) LLVM_NOEXCEPT; + TypoExprState& operator=(TypoExprState&& other) LLVM_NOEXCEPT; + }; + + /// \brief The set of unhandled TypoExprs and their associated state. + llvm::MapVector<TypoExpr *, TypoExprState> DelayedTypos; + + /// \brief Creates a new TypoExpr AST node. + TypoExpr *createDelayedTypo(std::unique_ptr<TypoCorrectionConsumer> TCC, + TypoDiagnosticGenerator TDG, + TypoRecoveryCallback TRC); + + // \brief The set of known/encountered (unique, canonicalized) NamespaceDecls. + // + // The boolean value will be true to indicate that the namespace was loaded + // from an AST/PCH file, or false otherwise. + llvm::MapVector<NamespaceDecl*, bool> KnownNamespaces; + + /// \brief Whether we have already loaded known namespaces from an extenal + /// source. + bool LoadedExternalKnownNamespaces; + + /// \brief Helper for CorrectTypo and CorrectTypoDelayed used to create and + /// populate a new TypoCorrectionConsumer. Returns nullptr if typo correction + /// should be skipped entirely. + std::unique_ptr<TypoCorrectionConsumer> + makeTypoCorrectionConsumer(const DeclarationNameInfo &Typo, + Sema::LookupNameKind LookupKind, Scope *S, + CXXScopeSpec *SS, + std::unique_ptr<CorrectionCandidateCallback> CCC, + DeclContext *MemberContext, bool EnteringContext, + const ObjCObjectPointerType *OPT, + bool ErrorRecovery); + +public: + const TypoExprState &getTypoExprState(TypoExpr *TE) const; + + /// \brief Clears the state of the given TypoExpr. + void clearDelayedTypo(TypoExpr *TE); + + /// \brief Look up a name, looking for a single declaration. Return + /// null if the results were absent, ambiguous, or overloaded. + /// + /// It is preferable to use the elaborated form and explicitly handle + /// ambiguity and overloaded. + NamedDecl *LookupSingleName(Scope *S, DeclarationName Name, + SourceLocation Loc, + LookupNameKind NameKind, + RedeclarationKind Redecl + = NotForRedeclaration); + bool LookupName(LookupResult &R, Scope *S, + bool AllowBuiltinCreation = false); + bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, + bool InUnqualifiedLookup = false); + bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, + CXXScopeSpec &SS); + bool LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS, + bool AllowBuiltinCreation = false, + bool EnteringContext = false); + ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II, SourceLocation IdLoc, + RedeclarationKind Redecl + = NotForRedeclaration); + bool LookupInSuper(LookupResult &R, CXXRecordDecl *Class); + + void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, + QualType T1, QualType T2, + UnresolvedSetImpl &Functions); + void addOverloadedOperatorToUnresolvedSet(UnresolvedSetImpl &Functions, + DeclAccessPair Operator, + QualType T1, QualType T2); + + LabelDecl *LookupOrCreateLabel(IdentifierInfo *II, SourceLocation IdentLoc, + SourceLocation GnuLabelLoc = SourceLocation()); + + DeclContextLookupResult LookupConstructors(CXXRecordDecl *Class); + CXXConstructorDecl *LookupDefaultConstructor(CXXRecordDecl *Class); + CXXConstructorDecl *LookupCopyingConstructor(CXXRecordDecl *Class, + unsigned Quals); + CXXMethodDecl *LookupCopyingAssignment(CXXRecordDecl *Class, unsigned Quals, + bool RValueThis, unsigned ThisQuals); + CXXConstructorDecl *LookupMovingConstructor(CXXRecordDecl *Class, + unsigned Quals); + CXXMethodDecl *LookupMovingAssignment(CXXRecordDecl *Class, unsigned Quals, + bool RValueThis, unsigned ThisQuals); + CXXDestructorDecl *LookupDestructor(CXXRecordDecl *Class); + + bool checkLiteralOperatorId(const CXXScopeSpec &SS, const UnqualifiedId &Id); + LiteralOperatorLookupResult LookupLiteralOperator(Scope *S, LookupResult &R, + ArrayRef<QualType> ArgTys, + bool AllowRaw, + bool AllowTemplate, + bool AllowStringTemplate); + bool isKnownName(StringRef name); + + void ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc, + ArrayRef<Expr *> Args, ADLResult &Functions); + + void LookupVisibleDecls(Scope *S, LookupNameKind Kind, + VisibleDeclConsumer &Consumer, + bool IncludeGlobalScope = true); + void LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, + VisibleDeclConsumer &Consumer, + bool IncludeGlobalScope = true); + + enum CorrectTypoKind { + CTK_NonError, // CorrectTypo used in a non error recovery situation. + CTK_ErrorRecovery // CorrectTypo used in normal error recovery. + }; + + TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo, + Sema::LookupNameKind LookupKind, + Scope *S, CXXScopeSpec *SS, + std::unique_ptr<CorrectionCandidateCallback> CCC, + CorrectTypoKind Mode, + DeclContext *MemberContext = nullptr, + bool EnteringContext = false, + const ObjCObjectPointerType *OPT = nullptr, + bool RecordFailure = true); + + TypoExpr *CorrectTypoDelayed(const DeclarationNameInfo &Typo, + Sema::LookupNameKind LookupKind, Scope *S, + CXXScopeSpec *SS, + std::unique_ptr<CorrectionCandidateCallback> CCC, + TypoDiagnosticGenerator TDG, + TypoRecoveryCallback TRC, CorrectTypoKind Mode, + DeclContext *MemberContext = nullptr, + bool EnteringContext = false, + const ObjCObjectPointerType *OPT = nullptr); + + /// \brief Process any TypoExprs in the given Expr and its children, + /// generating diagnostics as appropriate and returning a new Expr if there + /// were typos that were all successfully corrected and ExprError if one or + /// more typos could not be corrected. + /// + /// \param E The Expr to check for TypoExprs. + /// + /// \param InitDecl A VarDecl to avoid because the Expr being corrected is its + /// initializer. + /// + /// \param Filter A function applied to a newly rebuilt Expr to determine if + /// it is an acceptable/usable result from a single combination of typo + /// corrections. As long as the filter returns ExprError, different + /// combinations of corrections will be tried until all are exhausted. + ExprResult + CorrectDelayedTyposInExpr(Expr *E, VarDecl *InitDecl = nullptr, + llvm::function_ref<ExprResult(Expr *)> Filter = + [](Expr *E) -> ExprResult { return E; }); + + ExprResult + CorrectDelayedTyposInExpr(Expr *E, + llvm::function_ref<ExprResult(Expr *)> Filter) { + return CorrectDelayedTyposInExpr(E, nullptr, Filter); + } + + ExprResult + CorrectDelayedTyposInExpr(ExprResult ER, VarDecl *InitDecl = nullptr, + llvm::function_ref<ExprResult(Expr *)> Filter = + [](Expr *E) -> ExprResult { return E; }) { + return ER.isInvalid() ? ER : CorrectDelayedTyposInExpr(ER.get(), Filter); + } + + ExprResult + CorrectDelayedTyposInExpr(ExprResult ER, + llvm::function_ref<ExprResult(Expr *)> Filter) { + return CorrectDelayedTyposInExpr(ER, nullptr, Filter); + } + + void diagnoseTypo(const TypoCorrection &Correction, + const PartialDiagnostic &TypoDiag, + bool ErrorRecovery = true); + + void diagnoseTypo(const TypoCorrection &Correction, + const PartialDiagnostic &TypoDiag, + const PartialDiagnostic &PrevNote, + bool ErrorRecovery = true); + + void FindAssociatedClassesAndNamespaces(SourceLocation InstantiationLoc, + ArrayRef<Expr *> Args, + AssociatedNamespaceSet &AssociatedNamespaces, + AssociatedClassSet &AssociatedClasses); + + void FilterLookupForScope(LookupResult &R, DeclContext *Ctx, Scope *S, + bool ConsiderLinkage, bool AllowInlineNamespace); + + void DiagnoseAmbiguousLookup(LookupResult &Result); + //@} + + ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *&Id, + SourceLocation IdLoc, + bool TypoCorrection = false); + NamedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, + Scope *S, bool ForRedeclaration, + SourceLocation Loc); + NamedDecl *ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II, + Scope *S); + void AddKnownFunctionAttributes(FunctionDecl *FD); + + // More parsing and symbol table subroutines. + + void ProcessPragmaWeak(Scope *S, Decl *D); + // Decl attributes - this routine is the top level dispatcher. + void ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD); + void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AL, + bool IncludeCXX11Attributes = true); + bool ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl, + const AttributeList *AttrList); + + void checkUnusedDeclAttributes(Declarator &D); + + /// Determine if type T is a valid subject for a nonnull and similar + /// attributes. By default, we look through references (the behavior used by + /// nonnull), but if the second parameter is true, then we treat a reference + /// type as valid. + bool isValidPointerAttrType(QualType T, bool RefOkay = false); + + bool CheckRegparmAttr(const AttributeList &attr, unsigned &value); + bool CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, + const FunctionDecl *FD = nullptr); + bool CheckNoReturnAttr(const AttributeList &attr); + bool checkStringLiteralArgumentAttr(const AttributeList &Attr, + unsigned ArgNum, StringRef &Str, + SourceLocation *ArgLocation = nullptr); + bool checkSectionName(SourceLocation LiteralLoc, StringRef Str); + void checkTargetAttr(SourceLocation LiteralLoc, StringRef Str); + bool checkMSInheritanceAttrOnDefinition( + CXXRecordDecl *RD, SourceRange Range, bool BestCase, + MSInheritanceAttr::Spelling SemanticSpelling); + + void CheckAlignasUnderalignment(Decl *D); + + /// Adjust the calling convention of a method to be the ABI default if it + /// wasn't specified explicitly. This handles method types formed from + /// function type typedefs and typename template arguments. + void adjustMemberFunctionCC(QualType &T, bool IsStatic, bool IsCtorOrDtor, + SourceLocation Loc); + + // Check if there is an explicit attribute, but only look through parens. + // The intent is to look for an attribute on the current declarator, but not + // one that came from a typedef. + bool hasExplicitCallingConv(QualType &T); + + /// Get the outermost AttributedType node that sets a calling convention. + /// Valid types should not have multiple attributes with different CCs. + const AttributedType *getCallingConvAttributedType(QualType T) const; + + /// Check whether a nullability type specifier can be added to the given + /// type. + /// + /// \param type The type to which the nullability specifier will be + /// added. On success, this type will be updated appropriately. + /// + /// \param nullability The nullability specifier to add. + /// + /// \param nullabilityLoc The location of the nullability specifier. + /// + /// \param isContextSensitive Whether this nullability specifier was + /// written as a context-sensitive keyword (in an Objective-C + /// method) or an Objective-C property attribute, rather than as an + /// underscored type specifier. + /// + /// \returns true if nullability cannot be applied, false otherwise. + bool checkNullabilityTypeSpecifier(QualType &type, NullabilityKind nullability, + SourceLocation nullabilityLoc, + bool isContextSensitive); + + /// \brief Stmt attributes - this routine is the top level dispatcher. + StmtResult ProcessStmtAttributes(Stmt *Stmt, AttributeList *Attrs, + SourceRange Range); + + void WarnConflictingTypedMethods(ObjCMethodDecl *Method, + ObjCMethodDecl *MethodDecl, + bool IsProtocolMethodDecl); + + void CheckConflictingOverridingMethod(ObjCMethodDecl *Method, + ObjCMethodDecl *Overridden, + bool IsProtocolMethodDecl); + + /// WarnExactTypedMethods - This routine issues a warning if method + /// implementation declaration matches exactly that of its declaration. + void WarnExactTypedMethods(ObjCMethodDecl *Method, + ObjCMethodDecl *MethodDecl, + bool IsProtocolMethodDecl); + + typedef llvm::SmallPtrSet<Selector, 8> SelectorSet; + typedef llvm::DenseMap<Selector, ObjCMethodDecl*> ProtocolsMethodsMap; + + /// CheckImplementationIvars - This routine checks if the instance variables + /// listed in the implelementation match those listed in the interface. + void CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, + ObjCIvarDecl **Fields, unsigned nIvars, + SourceLocation Loc); + + /// ImplMethodsVsClassMethods - This is main routine to warn if any method + /// remains unimplemented in the class or category \@implementation. + void ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, + ObjCContainerDecl* IDecl, + bool IncompleteImpl = false); + + /// DiagnoseUnimplementedProperties - This routine warns on those properties + /// which must be implemented by this implementation. + void DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, + ObjCContainerDecl *CDecl, + bool SynthesizeProperties); + + /// Diagnose any null-resettable synthesized setters. + void diagnoseNullResettableSynthesizedSetters(const ObjCImplDecl *impDecl); + + /// DefaultSynthesizeProperties - This routine default synthesizes all + /// properties which must be synthesized in the class's \@implementation. + void DefaultSynthesizeProperties (Scope *S, ObjCImplDecl* IMPDecl, + ObjCInterfaceDecl *IDecl); + void DefaultSynthesizeProperties(Scope *S, Decl *D); + + /// IvarBacksCurrentMethodAccessor - This routine returns 'true' if 'IV' is + /// an ivar synthesized for 'Method' and 'Method' is a property accessor + /// declared in class 'IFace'. + bool IvarBacksCurrentMethodAccessor(ObjCInterfaceDecl *IFace, + ObjCMethodDecl *Method, ObjCIvarDecl *IV); + + /// DiagnoseUnusedBackingIvarInAccessor - Issue an 'unused' warning if ivar which + /// backs the property is not used in the property's accessor. + void DiagnoseUnusedBackingIvarInAccessor(Scope *S, + const ObjCImplementationDecl *ImplD); + + /// GetIvarBackingPropertyAccessor - If method is a property setter/getter and + /// it property has a backing ivar, returns this ivar; otherwise, returns NULL. + /// It also returns ivar's property on success. + ObjCIvarDecl *GetIvarBackingPropertyAccessor(const ObjCMethodDecl *Method, + const ObjCPropertyDecl *&PDecl) const; + + /// Called by ActOnProperty to handle \@property declarations in + /// class extensions. + ObjCPropertyDecl *HandlePropertyInClassExtension(Scope *S, + SourceLocation AtLoc, + SourceLocation LParenLoc, + FieldDeclarator &FD, + Selector GetterSel, + Selector SetterSel, + const bool isReadWrite, + unsigned &Attributes, + const unsigned AttributesAsWritten, + QualType T, + TypeSourceInfo *TSI, + tok::ObjCKeywordKind MethodImplKind); + + /// Called by ActOnProperty and HandlePropertyInClassExtension to + /// handle creating the ObjcPropertyDecl for a category or \@interface. + ObjCPropertyDecl *CreatePropertyDecl(Scope *S, + ObjCContainerDecl *CDecl, + SourceLocation AtLoc, + SourceLocation LParenLoc, + FieldDeclarator &FD, + Selector GetterSel, + Selector SetterSel, + const bool isReadWrite, + const unsigned Attributes, + const unsigned AttributesAsWritten, + QualType T, + TypeSourceInfo *TSI, + tok::ObjCKeywordKind MethodImplKind, + DeclContext *lexicalDC = nullptr); + + /// AtomicPropertySetterGetterRules - This routine enforces the rule (via + /// warning) when atomic property has one but not the other user-declared + /// setter or getter. + void AtomicPropertySetterGetterRules(ObjCImplDecl* IMPDecl, + ObjCInterfaceDecl* IDecl); + + void DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D); + + void DiagnoseMissingDesignatedInitOverrides( + const ObjCImplementationDecl *ImplD, + const ObjCInterfaceDecl *IFD); + + void DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID, ObjCInterfaceDecl *SID); + + enum MethodMatchStrategy { + MMS_loose, + MMS_strict + }; + + /// MatchTwoMethodDeclarations - Checks if two methods' type match and returns + /// true, or false, accordingly. + bool MatchTwoMethodDeclarations(const ObjCMethodDecl *Method, + const ObjCMethodDecl *PrevMethod, + MethodMatchStrategy strategy = MMS_strict); + + /// MatchAllMethodDeclarations - Check methods declaraed in interface or + /// or protocol against those declared in their implementations. + void MatchAllMethodDeclarations(const SelectorSet &InsMap, + const SelectorSet &ClsMap, + SelectorSet &InsMapSeen, + SelectorSet &ClsMapSeen, + ObjCImplDecl* IMPDecl, + ObjCContainerDecl* IDecl, + bool &IncompleteImpl, + bool ImmediateClass, + bool WarnCategoryMethodImpl=false); + + /// CheckCategoryVsClassMethodMatches - Checks that methods implemented in + /// category matches with those implemented in its primary class and + /// warns each time an exact match is found. + void CheckCategoryVsClassMethodMatches(ObjCCategoryImplDecl *CatIMP); + + /// \brief Add the given method to the list of globally-known methods. + void addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method); + +private: + /// AddMethodToGlobalPool - Add an instance or factory method to the global + /// pool. See descriptoin of AddInstanceMethodToGlobalPool. + void AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl, bool instance); + + /// LookupMethodInGlobalPool - Returns the instance or factory method and + /// optionally warns if there are multiple signatures. + ObjCMethodDecl *LookupMethodInGlobalPool(Selector Sel, SourceRange R, + bool receiverIdOrClass, + bool instance); + +public: + /// \brief - Returns instance or factory methods in global method pool for + /// given selector. If no such method or only one method found, function returns + /// false; otherwise, it returns true + bool CollectMultipleMethodsInGlobalPool(Selector Sel, + SmallVectorImpl<ObjCMethodDecl*>& Methods, + bool instance); + + bool AreMultipleMethodsInGlobalPool(Selector Sel, ObjCMethodDecl *BestMethod, + SourceRange R, + bool receiverIdOrClass); + + void DiagnoseMultipleMethodInGlobalPool(SmallVectorImpl<ObjCMethodDecl*> &Methods, + Selector Sel, SourceRange R, + bool receiverIdOrClass); + +private: + /// \brief - Returns a selector which best matches given argument list or + /// nullptr if none could be found + ObjCMethodDecl *SelectBestMethod(Selector Sel, MultiExprArg Args, + bool IsInstance); + + + /// \brief Record the typo correction failure and return an empty correction. + TypoCorrection FailedCorrection(IdentifierInfo *Typo, SourceLocation TypoLoc, + bool RecordFailure = true) { + if (RecordFailure) + TypoCorrectionFailures[Typo].insert(TypoLoc); + return TypoCorrection(); + } + +public: + /// AddInstanceMethodToGlobalPool - All instance methods in a translation + /// unit are added to a global pool. This allows us to efficiently associate + /// a selector with a method declaraation for purposes of typechecking + /// messages sent to "id" (where the class of the object is unknown). + void AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method, bool impl=false) { + AddMethodToGlobalPool(Method, impl, /*instance*/true); + } + + /// AddFactoryMethodToGlobalPool - Same as above, but for factory methods. + void AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method, bool impl=false) { + AddMethodToGlobalPool(Method, impl, /*instance*/false); + } + + /// AddAnyMethodToGlobalPool - Add any method, instance or factory to global + /// pool. + void AddAnyMethodToGlobalPool(Decl *D); + + /// LookupInstanceMethodInGlobalPool - Returns the method and warns if + /// there are multiple signatures. + ObjCMethodDecl *LookupInstanceMethodInGlobalPool(Selector Sel, SourceRange R, + bool receiverIdOrClass=false) { + return LookupMethodInGlobalPool(Sel, R, receiverIdOrClass, + /*instance*/true); + } + + /// LookupFactoryMethodInGlobalPool - Returns the method and warns if + /// there are multiple signatures. + ObjCMethodDecl *LookupFactoryMethodInGlobalPool(Selector Sel, SourceRange R, + bool receiverIdOrClass=false) { + return LookupMethodInGlobalPool(Sel, R, receiverIdOrClass, + /*instance*/false); + } + + const ObjCMethodDecl *SelectorsForTypoCorrection(Selector Sel, + QualType ObjectType=QualType()); + /// LookupImplementedMethodInGlobalPool - Returns the method which has an + /// implementation. + ObjCMethodDecl *LookupImplementedMethodInGlobalPool(Selector Sel); + + /// CollectIvarsToConstructOrDestruct - Collect those ivars which require + /// initialization. + void CollectIvarsToConstructOrDestruct(ObjCInterfaceDecl *OI, + SmallVectorImpl<ObjCIvarDecl*> &Ivars); + + //===--------------------------------------------------------------------===// + // Statement Parsing Callbacks: SemaStmt.cpp. +public: + class FullExprArg { + public: + FullExprArg(Sema &actions) : E(nullptr) { } + + ExprResult release() { + return E; + } + + Expr *get() const { return E; } + + Expr *operator->() { + return E; + } + + private: + // FIXME: No need to make the entire Sema class a friend when it's just + // Sema::MakeFullExpr that needs access to the constructor below. + friend class Sema; + + explicit FullExprArg(Expr *expr) : E(expr) {} + + Expr *E; + }; + + FullExprArg MakeFullExpr(Expr *Arg) { + return MakeFullExpr(Arg, Arg ? Arg->getExprLoc() : SourceLocation()); + } + FullExprArg MakeFullExpr(Expr *Arg, SourceLocation CC) { + return FullExprArg(ActOnFinishFullExpr(Arg, CC).get()); + } + FullExprArg MakeFullDiscardedValueExpr(Expr *Arg) { + ExprResult FE = + ActOnFinishFullExpr(Arg, Arg ? Arg->getExprLoc() : SourceLocation(), + /*DiscardedValue*/ true); + return FullExprArg(FE.get()); + } + + StmtResult ActOnExprStmt(ExprResult Arg); + StmtResult ActOnExprStmtError(); + + StmtResult ActOnNullStmt(SourceLocation SemiLoc, + bool HasLeadingEmptyMacro = false); + + void ActOnStartOfCompoundStmt(); + void ActOnFinishOfCompoundStmt(); + StmtResult ActOnCompoundStmt(SourceLocation L, SourceLocation R, + ArrayRef<Stmt *> Elts, bool isStmtExpr); + + /// \brief A RAII object to enter scope of a compound statement. + class CompoundScopeRAII { + public: + CompoundScopeRAII(Sema &S): S(S) { + S.ActOnStartOfCompoundStmt(); + } + + ~CompoundScopeRAII() { + S.ActOnFinishOfCompoundStmt(); + } + + private: + Sema &S; + }; + + /// An RAII helper that pops function a function scope on exit. + struct FunctionScopeRAII { + Sema &S; + bool Active; + FunctionScopeRAII(Sema &S) : S(S), Active(true) {} + ~FunctionScopeRAII() { + if (Active) + S.PopFunctionScopeInfo(); + } + void disable() { Active = false; } + }; + + StmtResult ActOnDeclStmt(DeclGroupPtrTy Decl, + SourceLocation StartLoc, + SourceLocation EndLoc); + void ActOnForEachDeclStmt(DeclGroupPtrTy Decl); + StmtResult ActOnForEachLValueExpr(Expr *E); + StmtResult ActOnCaseStmt(SourceLocation CaseLoc, Expr *LHSVal, + SourceLocation DotDotDotLoc, Expr *RHSVal, + SourceLocation ColonLoc); + void ActOnCaseStmtBody(Stmt *CaseStmt, Stmt *SubStmt); + + StmtResult ActOnDefaultStmt(SourceLocation DefaultLoc, + SourceLocation ColonLoc, + Stmt *SubStmt, Scope *CurScope); + StmtResult ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl, + SourceLocation ColonLoc, Stmt *SubStmt); + + StmtResult ActOnAttributedStmt(SourceLocation AttrLoc, + ArrayRef<const Attr*> Attrs, + Stmt *SubStmt); + + StmtResult ActOnIfStmt(SourceLocation IfLoc, + FullExprArg CondVal, Decl *CondVar, + Stmt *ThenVal, + SourceLocation ElseLoc, Stmt *ElseVal); + StmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, + Expr *Cond, + Decl *CondVar); + StmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc, + Stmt *Switch, Stmt *Body); + StmtResult ActOnWhileStmt(SourceLocation WhileLoc, + FullExprArg Cond, + Decl *CondVar, Stmt *Body); + StmtResult ActOnDoStmt(SourceLocation DoLoc, Stmt *Body, + SourceLocation WhileLoc, + SourceLocation CondLParen, Expr *Cond, + SourceLocation CondRParen); + + StmtResult ActOnForStmt(SourceLocation ForLoc, + SourceLocation LParenLoc, + Stmt *First, FullExprArg Second, + Decl *SecondVar, + FullExprArg Third, + SourceLocation RParenLoc, + Stmt *Body); + ExprResult CheckObjCForCollectionOperand(SourceLocation forLoc, + Expr *collection); + StmtResult ActOnObjCForCollectionStmt(SourceLocation ForColLoc, + Stmt *First, Expr *collection, + SourceLocation RParenLoc); + StmtResult FinishObjCForCollectionStmt(Stmt *ForCollection, Stmt *Body); + + enum BuildForRangeKind { + /// Initial building of a for-range statement. + BFRK_Build, + /// Instantiation or recovery rebuild of a for-range statement. Don't + /// attempt any typo-correction. + BFRK_Rebuild, + /// Determining whether a for-range statement could be built. Avoid any + /// unnecessary or irreversible actions. + BFRK_Check + }; + + StmtResult ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc, + SourceLocation CoawaitLoc, + Stmt *LoopVar, + SourceLocation ColonLoc, Expr *Collection, + SourceLocation RParenLoc, + BuildForRangeKind Kind); + StmtResult BuildCXXForRangeStmt(SourceLocation ForLoc, + SourceLocation CoawaitLoc, + SourceLocation ColonLoc, + Stmt *RangeDecl, Stmt *BeginEndDecl, + Expr *Cond, Expr *Inc, + Stmt *LoopVarDecl, + SourceLocation RParenLoc, + BuildForRangeKind Kind); + StmtResult FinishCXXForRangeStmt(Stmt *ForRange, Stmt *Body); + + StmtResult ActOnGotoStmt(SourceLocation GotoLoc, + SourceLocation LabelLoc, + LabelDecl *TheDecl); + StmtResult ActOnIndirectGotoStmt(SourceLocation GotoLoc, + SourceLocation StarLoc, + Expr *DestExp); + StmtResult ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope); + StmtResult ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope); + + void ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope, + CapturedRegionKind Kind, unsigned NumParams); + typedef std::pair<StringRef, QualType> CapturedParamNameType; + void ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope, + CapturedRegionKind Kind, + ArrayRef<CapturedParamNameType> Params); + StmtResult ActOnCapturedRegionEnd(Stmt *S); + void ActOnCapturedRegionError(); + RecordDecl *CreateCapturedStmtRecordDecl(CapturedDecl *&CD, + SourceLocation Loc, + unsigned NumParams); + VarDecl *getCopyElisionCandidate(QualType ReturnType, Expr *E, + bool AllowFunctionParameters); + bool isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD, + bool AllowFunctionParameters); + + StmtResult ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp, + Scope *CurScope); + StmtResult BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp); + StmtResult ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp); + + StmtResult ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, + bool IsVolatile, unsigned NumOutputs, + unsigned NumInputs, IdentifierInfo **Names, + MultiExprArg Constraints, MultiExprArg Exprs, + Expr *AsmString, MultiExprArg Clobbers, + SourceLocation RParenLoc); + + ExprResult LookupInlineAsmIdentifier(CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + UnqualifiedId &Id, + llvm::InlineAsmIdentifierInfo &Info, + bool IsUnevaluatedContext); + bool LookupInlineAsmField(StringRef Base, StringRef Member, + unsigned &Offset, SourceLocation AsmLoc); + ExprResult LookupInlineAsmVarDeclField(Expr *RefExpr, StringRef Member, + llvm::InlineAsmIdentifierInfo &Info, + SourceLocation AsmLoc); + StmtResult ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc, + ArrayRef<Token> AsmToks, + StringRef AsmString, + unsigned NumOutputs, unsigned NumInputs, + ArrayRef<StringRef> Constraints, + ArrayRef<StringRef> Clobbers, + ArrayRef<Expr*> Exprs, + SourceLocation EndLoc); + LabelDecl *GetOrCreateMSAsmLabel(StringRef ExternalLabelName, + SourceLocation Location, + bool AlwaysCreate); + + VarDecl *BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType ExceptionType, + SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + bool Invalid = false); + + Decl *ActOnObjCExceptionDecl(Scope *S, Declarator &D); + + StmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc, SourceLocation RParen, + Decl *Parm, Stmt *Body); + + StmtResult ActOnObjCAtFinallyStmt(SourceLocation AtLoc, Stmt *Body); + + StmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc, Stmt *Try, + MultiStmtArg Catch, Stmt *Finally); + + StmtResult BuildObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw); + StmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw, + Scope *CurScope); + ExprResult ActOnObjCAtSynchronizedOperand(SourceLocation atLoc, + Expr *operand); + StmtResult ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, + Expr *SynchExpr, + Stmt *SynchBody); + + StmtResult ActOnObjCAutoreleasePoolStmt(SourceLocation AtLoc, Stmt *Body); + + VarDecl *BuildExceptionDeclaration(Scope *S, TypeSourceInfo *TInfo, + SourceLocation StartLoc, + SourceLocation IdLoc, + IdentifierInfo *Id); + + Decl *ActOnExceptionDeclarator(Scope *S, Declarator &D); + + StmtResult ActOnCXXCatchBlock(SourceLocation CatchLoc, + Decl *ExDecl, Stmt *HandlerBlock); + StmtResult ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, + ArrayRef<Stmt *> Handlers); + + StmtResult ActOnSEHTryBlock(bool IsCXXTry, // try (true) or __try (false) ? + SourceLocation TryLoc, Stmt *TryBlock, + Stmt *Handler); + StmtResult ActOnSEHExceptBlock(SourceLocation Loc, + Expr *FilterExpr, + Stmt *Block); + void ActOnStartSEHFinallyBlock(); + void ActOnAbortSEHFinallyBlock(); + StmtResult ActOnFinishSEHFinallyBlock(SourceLocation Loc, Stmt *Block); + StmtResult ActOnSEHLeaveStmt(SourceLocation Loc, Scope *CurScope); + + void DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock); + + bool ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const; + + /// \brief If it's a file scoped decl that must warn if not used, keep track + /// of it. + void MarkUnusedFileScopedDecl(const DeclaratorDecl *D); + + /// DiagnoseUnusedExprResult - If the statement passed in is an expression + /// whose result is unused, warn. + void DiagnoseUnusedExprResult(const Stmt *S); + void DiagnoseUnusedNestedTypedefs(const RecordDecl *D); + void DiagnoseUnusedDecl(const NamedDecl *ND); + + /// Emit \p DiagID if statement located on \p StmtLoc has a suspicious null + /// statement as a \p Body, and it is located on the same line. + /// + /// This helps prevent bugs due to typos, such as: + /// if (condition); + /// do_stuff(); + void DiagnoseEmptyStmtBody(SourceLocation StmtLoc, + const Stmt *Body, + unsigned DiagID); + + /// Warn if a for/while loop statement \p S, which is followed by + /// \p PossibleBody, has a suspicious null statement as a body. + void DiagnoseEmptyLoopBody(const Stmt *S, + const Stmt *PossibleBody); + + /// Warn if a value is moved to itself. + void DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr, + SourceLocation OpLoc); + + /// \brief Warn if we're implicitly casting from a _Nullable pointer type to a + /// _Nonnull one. + void diagnoseNullableToNonnullConversion(QualType DstType, QualType SrcType, + SourceLocation Loc); + + ParsingDeclState PushParsingDeclaration(sema::DelayedDiagnosticPool &pool) { + return DelayedDiagnostics.push(pool); + } + void PopParsingDeclaration(ParsingDeclState state, Decl *decl); + + typedef ProcessingContextState ParsingClassState; + ParsingClassState PushParsingClass() { + return DelayedDiagnostics.pushUndelayed(); + } + void PopParsingClass(ParsingClassState state) { + DelayedDiagnostics.popUndelayed(state); + } + + void redelayDiagnostics(sema::DelayedDiagnosticPool &pool); + + enum AvailabilityDiagnostic { AD_Deprecation, AD_Unavailable, AD_Partial }; + + void EmitAvailabilityWarning(AvailabilityDiagnostic AD, + NamedDecl *D, StringRef Message, + SourceLocation Loc, + const ObjCInterfaceDecl *UnknownObjCClass, + const ObjCPropertyDecl *ObjCProperty, + bool ObjCPropertyAccess); + + bool makeUnavailableInSystemHeader(SourceLocation loc, + UnavailableAttr::ImplicitReason reason); + + //===--------------------------------------------------------------------===// + // Expression Parsing Callbacks: SemaExpr.cpp. + + bool CanUseDecl(NamedDecl *D); + bool DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, + const ObjCInterfaceDecl *UnknownObjCClass=nullptr, + bool ObjCPropertyAccess=false); + void NoteDeletedFunction(FunctionDecl *FD); + std::string getDeletedOrUnavailableSuffix(const FunctionDecl *FD); + bool DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *PD, + ObjCMethodDecl *Getter, + SourceLocation Loc); + void DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, + ArrayRef<Expr *> Args); + + void PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext, + Decl *LambdaContextDecl = nullptr, + bool IsDecltype = false); + enum ReuseLambdaContextDecl_t { ReuseLambdaContextDecl }; + void PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext, + ReuseLambdaContextDecl_t, + bool IsDecltype = false); + void PopExpressionEvaluationContext(); + + void DiscardCleanupsInEvaluationContext(); + + ExprResult TransformToPotentiallyEvaluated(Expr *E); + ExprResult HandleExprEvaluationContextForTypeof(Expr *E); + + ExprResult ActOnConstantExpression(ExprResult Res); + + // Functions for marking a declaration referenced. These functions also + // contain the relevant logic for marking if a reference to a function or + // variable is an odr-use (in the C++11 sense). There are separate variants + // for expressions referring to a decl; these exist because odr-use marking + // needs to be delayed for some constant variables when we build one of the + // named expressions. + void MarkAnyDeclReferenced(SourceLocation Loc, Decl *D, bool OdrUse); + void MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, + bool OdrUse = true); + void MarkVariableReferenced(SourceLocation Loc, VarDecl *Var); + void MarkDeclRefReferenced(DeclRefExpr *E); + void MarkMemberReferenced(MemberExpr *E); + + void UpdateMarkingForLValueToRValue(Expr *E); + void CleanupVarDeclMarking(); + + enum TryCaptureKind { + TryCapture_Implicit, TryCapture_ExplicitByVal, TryCapture_ExplicitByRef + }; + + /// \brief Try to capture the given variable. + /// + /// \param Var The variable to capture. + /// + /// \param Loc The location at which the capture occurs. + /// + /// \param Kind The kind of capture, which may be implicit (for either a + /// block or a lambda), or explicit by-value or by-reference (for a lambda). + /// + /// \param EllipsisLoc The location of the ellipsis, if one is provided in + /// an explicit lambda capture. + /// + /// \param BuildAndDiagnose Whether we are actually supposed to add the + /// captures or diagnose errors. If false, this routine merely check whether + /// the capture can occur without performing the capture itself or complaining + /// if the variable cannot be captured. + /// + /// \param CaptureType Will be set to the type of the field used to capture + /// this variable in the innermost block or lambda. Only valid when the + /// variable can be captured. + /// + /// \param DeclRefType Will be set to the type of a reference to the capture + /// from within the current scope. Only valid when the variable can be + /// captured. + /// + /// \param FunctionScopeIndexToStopAt If non-null, it points to the index + /// of the FunctionScopeInfo stack beyond which we do not attempt to capture. + /// This is useful when enclosing lambdas must speculatively capture + /// variables that may or may not be used in certain specializations of + /// a nested generic lambda. + /// + /// \returns true if an error occurred (i.e., the variable cannot be + /// captured) and false if the capture succeeded. + bool tryCaptureVariable(VarDecl *Var, SourceLocation Loc, TryCaptureKind Kind, + SourceLocation EllipsisLoc, bool BuildAndDiagnose, + QualType &CaptureType, + QualType &DeclRefType, + const unsigned *const FunctionScopeIndexToStopAt); + + /// \brief Try to capture the given variable. + bool tryCaptureVariable(VarDecl *Var, SourceLocation Loc, + TryCaptureKind Kind = TryCapture_Implicit, + SourceLocation EllipsisLoc = SourceLocation()); + + /// \brief Checks if the variable must be captured. + bool NeedToCaptureVariable(VarDecl *Var, SourceLocation Loc); + + /// \brief Given a variable, determine the type that a reference to that + /// variable will have in the given scope. + QualType getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc); + + void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T); + void MarkDeclarationsReferencedInExpr(Expr *E, + bool SkipLocalVariables = false); + + /// \brief Try to recover by turning the given expression into a + /// call. Returns true if recovery was attempted or an error was + /// emitted; this may also leave the ExprResult invalid. + bool tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD, + bool ForceComplain = false, + bool (*IsPlausibleResult)(QualType) = nullptr); + + /// \brief Figure out if an expression could be turned into a call. + bool tryExprAsCall(Expr &E, QualType &ZeroArgCallReturnTy, + UnresolvedSetImpl &NonTemplateOverloads); + + /// \brief Conditionally issue a diagnostic based on the current + /// evaluation context. + /// + /// \param Statement If Statement is non-null, delay reporting the + /// diagnostic until the function body is parsed, and then do a basic + /// reachability analysis to determine if the statement is reachable. + /// If it is unreachable, the diagnostic will not be emitted. + bool DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement, + const PartialDiagnostic &PD); + + // Primary Expressions. + SourceRange getExprRange(Expr *E) const; + + ExprResult ActOnIdExpression( + Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, + UnqualifiedId &Id, bool HasTrailingLParen, bool IsAddressOfOperand, + std::unique_ptr<CorrectionCandidateCallback> CCC = nullptr, + bool IsInlineAsmIdentifier = false, Token *KeywordReplacement = nullptr); + + void DecomposeUnqualifiedId(const UnqualifiedId &Id, + TemplateArgumentListInfo &Buffer, + DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *&TemplateArgs); + + bool + DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, + std::unique_ptr<CorrectionCandidateCallback> CCC, + TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr, + ArrayRef<Expr *> Args = None, TypoExpr **Out = nullptr); + + ExprResult LookupInObjCMethod(LookupResult &LookUp, Scope *S, + IdentifierInfo *II, + bool AllowBuiltinCreation=false); + + ExprResult ActOnDependentIdExpression(const CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + const DeclarationNameInfo &NameInfo, + bool isAddressOfOperand, + const TemplateArgumentListInfo *TemplateArgs); + + ExprResult BuildDeclRefExpr(ValueDecl *D, QualType Ty, + ExprValueKind VK, + SourceLocation Loc, + const CXXScopeSpec *SS = nullptr); + ExprResult + BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, + const DeclarationNameInfo &NameInfo, + const CXXScopeSpec *SS = nullptr, + NamedDecl *FoundD = nullptr, + const TemplateArgumentListInfo *TemplateArgs = nullptr); + ExprResult + BuildAnonymousStructUnionMemberReference( + const CXXScopeSpec &SS, + SourceLocation nameLoc, + IndirectFieldDecl *indirectField, + DeclAccessPair FoundDecl = DeclAccessPair::make(nullptr, AS_none), + Expr *baseObjectExpr = nullptr, + SourceLocation opLoc = SourceLocation()); + + ExprResult BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + LookupResult &R, + const TemplateArgumentListInfo *TemplateArgs, + const Scope *S); + ExprResult BuildImplicitMemberExpr(const CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + LookupResult &R, + const TemplateArgumentListInfo *TemplateArgs, + bool IsDefiniteInstance, + const Scope *S); + bool UseArgumentDependentLookup(const CXXScopeSpec &SS, + const LookupResult &R, + bool HasTrailingLParen); + + ExprResult + BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS, + const DeclarationNameInfo &NameInfo, + bool IsAddressOfOperand, const Scope *S, + TypeSourceInfo **RecoveryTSI = nullptr); + + ExprResult BuildDependentDeclRefExpr(const CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *TemplateArgs); + + ExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS, + LookupResult &R, + bool NeedsADL, + bool AcceptInvalidDecl = false); + ExprResult BuildDeclarationNameExpr( + const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, NamedDecl *D, + NamedDecl *FoundD = nullptr, + const TemplateArgumentListInfo *TemplateArgs = nullptr, + bool AcceptInvalidDecl = false); + + ExprResult BuildLiteralOperatorCall(LookupResult &R, + DeclarationNameInfo &SuffixInfo, + ArrayRef<Expr *> Args, + SourceLocation LitEndLoc, + TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr); + + ExprResult BuildPredefinedExpr(SourceLocation Loc, + PredefinedExpr::IdentType IT); + ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind); + ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val); + + bool CheckLoopHintExpr(Expr *E, SourceLocation Loc); + + ExprResult ActOnNumericConstant(const Token &Tok, Scope *UDLScope = nullptr); + ExprResult ActOnCharacterConstant(const Token &Tok, + Scope *UDLScope = nullptr); + ExprResult ActOnParenExpr(SourceLocation L, SourceLocation R, Expr *E); + ExprResult ActOnParenListExpr(SourceLocation L, + SourceLocation R, + MultiExprArg Val); + + /// ActOnStringLiteral - The specified tokens were lexed as pasted string + /// fragments (e.g. "foo" "bar" L"baz"). + ExprResult ActOnStringLiteral(ArrayRef<Token> StringToks, + Scope *UDLScope = nullptr); + + ExprResult ActOnGenericSelectionExpr(SourceLocation KeyLoc, + SourceLocation DefaultLoc, + SourceLocation RParenLoc, + Expr *ControllingExpr, + ArrayRef<ParsedType> ArgTypes, + ArrayRef<Expr *> ArgExprs); + ExprResult CreateGenericSelectionExpr(SourceLocation KeyLoc, + SourceLocation DefaultLoc, + SourceLocation RParenLoc, + Expr *ControllingExpr, + ArrayRef<TypeSourceInfo *> Types, + ArrayRef<Expr *> Exprs); + + // Binary/Unary Operators. 'Tok' is the token for the operator. + ExprResult CreateBuiltinUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, + Expr *InputExpr); + ExprResult BuildUnaryOp(Scope *S, SourceLocation OpLoc, + UnaryOperatorKind Opc, Expr *Input); + ExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc, + tok::TokenKind Op, Expr *Input); + + QualType CheckAddressOfOperand(ExprResult &Operand, SourceLocation OpLoc); + + ExprResult CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo, + SourceLocation OpLoc, + UnaryExprOrTypeTrait ExprKind, + SourceRange R); + ExprResult CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc, + UnaryExprOrTypeTrait ExprKind); + ExprResult + ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc, + UnaryExprOrTypeTrait ExprKind, + bool IsType, void *TyOrEx, + SourceRange ArgRange); + + ExprResult CheckPlaceholderExpr(Expr *E); + bool CheckVecStepExpr(Expr *E); + + bool CheckUnaryExprOrTypeTraitOperand(Expr *E, UnaryExprOrTypeTrait ExprKind); + bool CheckUnaryExprOrTypeTraitOperand(QualType ExprType, SourceLocation OpLoc, + SourceRange ExprRange, + UnaryExprOrTypeTrait ExprKind); + ExprResult ActOnSizeofParameterPackExpr(Scope *S, + SourceLocation OpLoc, + IdentifierInfo &Name, + SourceLocation NameLoc, + SourceLocation RParenLoc); + ExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, + tok::TokenKind Kind, Expr *Input); + + ExprResult ActOnArraySubscriptExpr(Scope *S, Expr *Base, SourceLocation LLoc, + Expr *Idx, SourceLocation RLoc); + ExprResult CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, + Expr *Idx, SourceLocation RLoc); + ExprResult ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc, + Expr *LowerBound, SourceLocation ColonLoc, + Expr *Length, SourceLocation RBLoc); + + // This struct is for use by ActOnMemberAccess to allow + // BuildMemberReferenceExpr to be able to reinvoke ActOnMemberAccess after + // changing the access operator from a '.' to a '->' (to see if that is the + // change needed to fix an error about an unknown member, e.g. when the class + // defines a custom operator->). + struct ActOnMemberAccessExtraArgs { + Scope *S; + UnqualifiedId &Id; + Decl *ObjCImpDecl; + }; + + ExprResult BuildMemberReferenceExpr( + Expr *Base, QualType BaseType, SourceLocation OpLoc, bool IsArrow, + CXXScopeSpec &SS, SourceLocation TemplateKWLoc, + NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *TemplateArgs, + const Scope *S, + ActOnMemberAccessExtraArgs *ExtraArgs = nullptr); + + ExprResult + BuildMemberReferenceExpr(Expr *Base, QualType BaseType, SourceLocation OpLoc, + bool IsArrow, const CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + NamedDecl *FirstQualifierInScope, LookupResult &R, + const TemplateArgumentListInfo *TemplateArgs, + const Scope *S, + bool SuppressQualifierCheck = false, + ActOnMemberAccessExtraArgs *ExtraArgs = nullptr); + + ExprResult PerformMemberExprBaseConversion(Expr *Base, bool IsArrow); + + bool CheckQualifiedMemberReference(Expr *BaseExpr, QualType BaseType, + const CXXScopeSpec &SS, + const LookupResult &R); + + ExprResult ActOnDependentMemberExpr(Expr *Base, QualType BaseType, + bool IsArrow, SourceLocation OpLoc, + const CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + NamedDecl *FirstQualifierInScope, + const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *TemplateArgs); + + ExprResult ActOnMemberAccessExpr(Scope *S, Expr *Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + UnqualifiedId &Member, + Decl *ObjCImpDecl); + + void ActOnDefaultCtorInitializers(Decl *CDtorDecl); + bool ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, + FunctionDecl *FDecl, + const FunctionProtoType *Proto, + ArrayRef<Expr *> Args, + SourceLocation RParenLoc, + bool ExecConfig = false); + void CheckStaticArrayArgument(SourceLocation CallLoc, + ParmVarDecl *Param, + const Expr *ArgExpr); + + /// 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. + ExprResult ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, + MultiExprArg ArgExprs, SourceLocation RParenLoc, + Expr *ExecConfig = nullptr, + bool IsExecConfig = false); + ExprResult BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, + SourceLocation LParenLoc, + ArrayRef<Expr *> Arg, + SourceLocation RParenLoc, + Expr *Config = nullptr, + bool IsExecConfig = false); + + ExprResult ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc, + MultiExprArg ExecConfig, + SourceLocation GGGLoc); + + ExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc, + Declarator &D, ParsedType &Ty, + SourceLocation RParenLoc, Expr *CastExpr); + ExprResult BuildCStyleCastExpr(SourceLocation LParenLoc, + TypeSourceInfo *Ty, + SourceLocation RParenLoc, + Expr *Op); + CastKind PrepareScalarCast(ExprResult &src, QualType destType); + + /// \brief Build an altivec or OpenCL literal. + ExprResult BuildVectorLiteral(SourceLocation LParenLoc, + SourceLocation RParenLoc, Expr *E, + TypeSourceInfo *TInfo); + + ExprResult MaybeConvertParenListExprToParenExpr(Scope *S, Expr *ME); + + ExprResult ActOnCompoundLiteral(SourceLocation LParenLoc, + ParsedType Ty, + SourceLocation RParenLoc, + Expr *InitExpr); + + ExprResult BuildCompoundLiteralExpr(SourceLocation LParenLoc, + TypeSourceInfo *TInfo, + SourceLocation RParenLoc, + Expr *LiteralExpr); + + ExprResult ActOnInitList(SourceLocation LBraceLoc, + MultiExprArg InitArgList, + SourceLocation RBraceLoc); + + ExprResult ActOnDesignatedInitializer(Designation &Desig, + SourceLocation Loc, + bool GNUSyntax, + ExprResult Init); + +private: + static BinaryOperatorKind ConvertTokenKindToBinaryOpcode(tok::TokenKind Kind); + +public: + ExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc, + tok::TokenKind Kind, Expr *LHSExpr, Expr *RHSExpr); + ExprResult BuildBinOp(Scope *S, SourceLocation OpLoc, + BinaryOperatorKind Opc, Expr *LHSExpr, Expr *RHSExpr); + ExprResult CreateBuiltinBinOp(SourceLocation OpLoc, BinaryOperatorKind Opc, + Expr *LHSExpr, Expr *RHSExpr); + + /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null + /// in the case of a the GNU conditional expr extension. + ExprResult ActOnConditionalOp(SourceLocation QuestionLoc, + SourceLocation ColonLoc, + Expr *CondExpr, Expr *LHSExpr, Expr *RHSExpr); + + /// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo". + ExprResult ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc, + LabelDecl *TheDecl); + + void ActOnStartStmtExpr(); + ExprResult ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, + SourceLocation RPLoc); // "({..})" + void ActOnStmtExprError(); + + // __builtin_offsetof(type, identifier(.identifier|[expr])*) + struct OffsetOfComponent { + SourceLocation LocStart, LocEnd; + bool isBrackets; // true if [expr], false if .ident + union { + IdentifierInfo *IdentInfo; + Expr *E; + } U; + }; + + /// __builtin_offsetof(type, a.b[123][456].c) + ExprResult BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, + TypeSourceInfo *TInfo, + ArrayRef<OffsetOfComponent> Components, + SourceLocation RParenLoc); + ExprResult ActOnBuiltinOffsetOf(Scope *S, + SourceLocation BuiltinLoc, + SourceLocation TypeLoc, + ParsedType ParsedArgTy, + ArrayRef<OffsetOfComponent> Components, + SourceLocation RParenLoc); + + // __builtin_choose_expr(constExpr, expr1, expr2) + ExprResult ActOnChooseExpr(SourceLocation BuiltinLoc, + Expr *CondExpr, Expr *LHSExpr, + Expr *RHSExpr, SourceLocation RPLoc); + + // __builtin_va_arg(expr, type) + ExprResult ActOnVAArg(SourceLocation BuiltinLoc, Expr *E, ParsedType Ty, + SourceLocation RPLoc); + ExprResult BuildVAArgExpr(SourceLocation BuiltinLoc, Expr *E, + TypeSourceInfo *TInfo, SourceLocation RPLoc); + + // __null + ExprResult ActOnGNUNullExpr(SourceLocation TokenLoc); + + bool CheckCaseExpression(Expr *E); + + /// \brief Describes the result of an "if-exists" condition check. + enum IfExistsResult { + /// \brief The symbol exists. + IER_Exists, + + /// \brief The symbol does not exist. + IER_DoesNotExist, + + /// \brief The name is a dependent name, so the results will differ + /// from one instantiation to the next. + IER_Dependent, + + /// \brief An error occurred. + IER_Error + }; + + IfExistsResult + CheckMicrosoftIfExistsSymbol(Scope *S, CXXScopeSpec &SS, + const DeclarationNameInfo &TargetNameInfo); + + IfExistsResult + CheckMicrosoftIfExistsSymbol(Scope *S, SourceLocation KeywordLoc, + bool IsIfExists, CXXScopeSpec &SS, + UnqualifiedId &Name); + + StmtResult BuildMSDependentExistsStmt(SourceLocation KeywordLoc, + bool IsIfExists, + NestedNameSpecifierLoc QualifierLoc, + DeclarationNameInfo NameInfo, + Stmt *Nested); + StmtResult ActOnMSDependentExistsStmt(SourceLocation KeywordLoc, + bool IsIfExists, + CXXScopeSpec &SS, UnqualifiedId &Name, + Stmt *Nested); + + //===------------------------- "Block" Extension ------------------------===// + + /// ActOnBlockStart - This callback is invoked when a block literal is + /// started. + void ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope); + + /// ActOnBlockArguments - This callback allows processing of block arguments. + /// If there are no arguments, this is still invoked. + void ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo, + Scope *CurScope); + + /// ActOnBlockError - If there is an error parsing a block, this callback + /// is invoked to pop the information about the block from the action impl. + void ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope); + + /// ActOnBlockStmtExpr - This is called when the body of a block statement + /// literal was successfully completed. ^(int x){...} + ExprResult ActOnBlockStmtExpr(SourceLocation CaretLoc, Stmt *Body, + Scope *CurScope); + + //===---------------------------- Clang Extensions ----------------------===// + + /// __builtin_convertvector(...) + ExprResult ActOnConvertVectorExpr(Expr *E, ParsedType ParsedDestTy, + SourceLocation BuiltinLoc, + SourceLocation RParenLoc); + + //===---------------------------- OpenCL Features -----------------------===// + + /// __builtin_astype(...) + ExprResult ActOnAsTypeExpr(Expr *E, ParsedType ParsedDestTy, + SourceLocation BuiltinLoc, + SourceLocation RParenLoc); + + //===---------------------------- C++ Features --------------------------===// + + // Act on C++ namespaces + Decl *ActOnStartNamespaceDef(Scope *S, SourceLocation InlineLoc, + SourceLocation NamespaceLoc, + SourceLocation IdentLoc, + IdentifierInfo *Ident, + SourceLocation LBrace, + AttributeList *AttrList, + UsingDirectiveDecl * &UsingDecl); + void ActOnFinishNamespaceDef(Decl *Dcl, SourceLocation RBrace); + + NamespaceDecl *getStdNamespace() const; + NamespaceDecl *getOrCreateStdNamespace(); + + CXXRecordDecl *getStdBadAlloc() const; + + /// \brief Tests whether Ty is an instance of std::initializer_list and, if + /// it is and Element is not NULL, assigns the element type to Element. + bool isStdInitializerList(QualType Ty, QualType *Element); + + /// \brief Looks for the std::initializer_list template and instantiates it + /// with Element, or emits an error if it's not found. + /// + /// \returns The instantiated template, or null on error. + QualType BuildStdInitializerList(QualType Element, SourceLocation Loc); + + /// \brief Determine whether Ctor is an initializer-list constructor, as + /// defined in [dcl.init.list]p2. + bool isInitListConstructor(const CXXConstructorDecl *Ctor); + + Decl *ActOnUsingDirective(Scope *CurScope, + SourceLocation UsingLoc, + SourceLocation NamespcLoc, + CXXScopeSpec &SS, + SourceLocation IdentLoc, + IdentifierInfo *NamespcName, + AttributeList *AttrList); + + void PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir); + + Decl *ActOnNamespaceAliasDef(Scope *CurScope, + SourceLocation NamespaceLoc, + SourceLocation AliasLoc, + IdentifierInfo *Alias, + CXXScopeSpec &SS, + SourceLocation IdentLoc, + IdentifierInfo *Ident); + + void HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow); + bool CheckUsingShadowDecl(UsingDecl *UD, NamedDecl *Target, + const LookupResult &PreviousDecls, + UsingShadowDecl *&PrevShadow); + UsingShadowDecl *BuildUsingShadowDecl(Scope *S, UsingDecl *UD, + NamedDecl *Target, + UsingShadowDecl *PrevDecl); + + bool CheckUsingDeclRedeclaration(SourceLocation UsingLoc, + bool HasTypenameKeyword, + const CXXScopeSpec &SS, + SourceLocation NameLoc, + const LookupResult &Previous); + bool CheckUsingDeclQualifier(SourceLocation UsingLoc, + const CXXScopeSpec &SS, + const DeclarationNameInfo &NameInfo, + SourceLocation NameLoc); + + NamedDecl *BuildUsingDeclaration(Scope *S, AccessSpecifier AS, + SourceLocation UsingLoc, + CXXScopeSpec &SS, + DeclarationNameInfo NameInfo, + AttributeList *AttrList, + bool IsInstantiation, + bool HasTypenameKeyword, + SourceLocation TypenameLoc); + + bool CheckInheritingConstructorUsingDecl(UsingDecl *UD); + + Decl *ActOnUsingDeclaration(Scope *CurScope, + AccessSpecifier AS, + bool HasUsingKeyword, + SourceLocation UsingLoc, + CXXScopeSpec &SS, + UnqualifiedId &Name, + AttributeList *AttrList, + bool HasTypenameKeyword, + SourceLocation TypenameLoc); + Decl *ActOnAliasDeclaration(Scope *CurScope, + AccessSpecifier AS, + MultiTemplateParamsArg TemplateParams, + SourceLocation UsingLoc, + UnqualifiedId &Name, + AttributeList *AttrList, + TypeResult Type, + Decl *DeclFromDeclSpec); + + /// BuildCXXConstructExpr - Creates a complete call to a constructor, + /// including handling of its default argument expressions. + /// + /// \param ConstructKind - a CXXConstructExpr::ConstructionKind + ExprResult + BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, + CXXConstructorDecl *Constructor, MultiExprArg Exprs, + bool HadMultipleCandidates, bool IsListInitialization, + bool IsStdInitListInitialization, + bool RequiresZeroInit, unsigned ConstructKind, + SourceRange ParenRange); + + // FIXME: Can we remove this and have the above BuildCXXConstructExpr check if + // the constructor can be elidable? + ExprResult + BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, + CXXConstructorDecl *Constructor, bool Elidable, + MultiExprArg Exprs, bool HadMultipleCandidates, + bool IsListInitialization, + bool IsStdInitListInitialization, bool RequiresZeroInit, + unsigned ConstructKind, SourceRange ParenRange); + + ExprResult BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field); + + /// BuildCXXDefaultArgExpr - Creates a CXXDefaultArgExpr, instantiating + /// the default expr if needed. + ExprResult BuildCXXDefaultArgExpr(SourceLocation CallLoc, + FunctionDecl *FD, + ParmVarDecl *Param); + + /// FinalizeVarWithDestructor - Prepare for calling destructor on the + /// constructed variable. + void FinalizeVarWithDestructor(VarDecl *VD, const RecordType *DeclInitType); + + /// \brief Helper class that collects exception specifications for + /// implicitly-declared special member functions. + class ImplicitExceptionSpecification { + // Pointer to allow copying + Sema *Self; + // We order exception specifications thus: + // noexcept is the most restrictive, but is only used in C++11. + // throw() comes next. + // Then a throw(collected exceptions) + // Finally no specification, which is expressed as noexcept(false). + // throw(...) is used instead if any called function uses it. + ExceptionSpecificationType ComputedEST; + llvm::SmallPtrSet<CanQualType, 4> ExceptionsSeen; + SmallVector<QualType, 4> Exceptions; + + void ClearExceptions() { + ExceptionsSeen.clear(); + Exceptions.clear(); + } + + public: + explicit ImplicitExceptionSpecification(Sema &Self) + : Self(&Self), ComputedEST(EST_BasicNoexcept) { + if (!Self.getLangOpts().CPlusPlus11) + ComputedEST = EST_DynamicNone; + } + + /// \brief Get the computed exception specification type. + ExceptionSpecificationType getExceptionSpecType() const { + assert(ComputedEST != EST_ComputedNoexcept && + "noexcept(expr) should not be a possible result"); + return ComputedEST; + } + + /// \brief The number of exceptions in the exception specification. + unsigned size() const { return Exceptions.size(); } + + /// \brief The set of exceptions in the exception specification. + const QualType *data() const { return Exceptions.data(); } + + /// \brief Integrate another called method into the collected data. + void CalledDecl(SourceLocation CallLoc, const CXXMethodDecl *Method); + + /// \brief Integrate an invoked expression into the collected data. + void CalledExpr(Expr *E); + + /// \brief Overwrite an EPI's exception specification with this + /// computed exception specification. + FunctionProtoType::ExceptionSpecInfo getExceptionSpec() const { + FunctionProtoType::ExceptionSpecInfo ESI; + ESI.Type = getExceptionSpecType(); + if (ESI.Type == EST_Dynamic) { + ESI.Exceptions = Exceptions; + } else if (ESI.Type == EST_None) { + /// C++11 [except.spec]p14: + /// The exception-specification is noexcept(false) if the set of + /// potential exceptions of the special member function contains "any" + ESI.Type = EST_ComputedNoexcept; + ESI.NoexceptExpr = Self->ActOnCXXBoolLiteral(SourceLocation(), + tok::kw_false).get(); + } + return ESI; + } + }; + + /// \brief Determine what sort of exception specification a defaulted + /// copy constructor of a class will have. + ImplicitExceptionSpecification + ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc, + CXXMethodDecl *MD); + + /// \brief Determine what sort of exception specification a defaulted + /// default constructor of a class will have, and whether the parameter + /// will be const. + ImplicitExceptionSpecification + ComputeDefaultedCopyCtorExceptionSpec(CXXMethodDecl *MD); + + /// \brief Determine what sort of exception specification a defautled + /// copy assignment operator of a class will have, and whether the + /// parameter will be const. + ImplicitExceptionSpecification + ComputeDefaultedCopyAssignmentExceptionSpec(CXXMethodDecl *MD); + + /// \brief Determine what sort of exception specification a defaulted move + /// constructor of a class will have. + ImplicitExceptionSpecification + ComputeDefaultedMoveCtorExceptionSpec(CXXMethodDecl *MD); + + /// \brief Determine what sort of exception specification a defaulted move + /// assignment operator of a class will have. + ImplicitExceptionSpecification + ComputeDefaultedMoveAssignmentExceptionSpec(CXXMethodDecl *MD); + + /// \brief Determine what sort of exception specification a defaulted + /// destructor of a class will have. + ImplicitExceptionSpecification + ComputeDefaultedDtorExceptionSpec(CXXMethodDecl *MD); + + /// \brief Determine what sort of exception specification an inheriting + /// constructor of a class will have. + ImplicitExceptionSpecification + ComputeInheritingCtorExceptionSpec(CXXConstructorDecl *CD); + + /// \brief Evaluate the implicit exception specification for a defaulted + /// special member function. + void EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD); + + /// \brief Check the given exception-specification and update the + /// exception specification information with the results. + void checkExceptionSpecification(bool IsTopLevel, + ExceptionSpecificationType EST, + ArrayRef<ParsedType> DynamicExceptions, + ArrayRef<SourceRange> DynamicExceptionRanges, + Expr *NoexceptExpr, + SmallVectorImpl<QualType> &Exceptions, + FunctionProtoType::ExceptionSpecInfo &ESI); + + /// \brief Determine if we're in a case where we need to (incorrectly) eagerly + /// parse an exception specification to work around a libstdc++ bug. + bool isLibstdcxxEagerExceptionSpecHack(const Declarator &D); + + /// \brief Add an exception-specification to the given member function + /// (or member function template). The exception-specification was parsed + /// after the method itself was declared. + void actOnDelayedExceptionSpecification(Decl *Method, + ExceptionSpecificationType EST, + SourceRange SpecificationRange, + ArrayRef<ParsedType> DynamicExceptions, + ArrayRef<SourceRange> DynamicExceptionRanges, + Expr *NoexceptExpr); + + /// \brief Determine if a special member function should have a deleted + /// definition when it is defaulted. + bool ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, + bool Diagnose = false); + + /// \brief Declare the implicit default constructor for the given class. + /// + /// \param ClassDecl The class declaration into which the implicit + /// default constructor will be added. + /// + /// \returns The implicitly-declared default constructor. + CXXConstructorDecl *DeclareImplicitDefaultConstructor( + CXXRecordDecl *ClassDecl); + + /// DefineImplicitDefaultConstructor - Checks for feasibility of + /// defining this constructor as the default constructor. + void DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, + CXXConstructorDecl *Constructor); + + /// \brief Declare the implicit destructor for the given class. + /// + /// \param ClassDecl The class declaration into which the implicit + /// destructor will be added. + /// + /// \returns The implicitly-declared destructor. + CXXDestructorDecl *DeclareImplicitDestructor(CXXRecordDecl *ClassDecl); + + /// DefineImplicitDestructor - Checks for feasibility of + /// defining this destructor as the default destructor. + void DefineImplicitDestructor(SourceLocation CurrentLocation, + CXXDestructorDecl *Destructor); + + /// \brief Build an exception spec for destructors that don't have one. + /// + /// C++11 says that user-defined destructors with no exception spec get one + /// that looks as if the destructor was implicitly declared. + void AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl, + CXXDestructorDecl *Destructor); + + /// \brief Declare all inheriting constructors for the given class. + /// + /// \param ClassDecl The class declaration into which the inheriting + /// constructors will be added. + void DeclareInheritingConstructors(CXXRecordDecl *ClassDecl); + + /// \brief Define the specified inheriting constructor. + void DefineInheritingConstructor(SourceLocation UseLoc, + CXXConstructorDecl *Constructor); + + /// \brief Declare the implicit copy constructor for the given class. + /// + /// \param ClassDecl The class declaration into which the implicit + /// copy constructor will be added. + /// + /// \returns The implicitly-declared copy constructor. + CXXConstructorDecl *DeclareImplicitCopyConstructor(CXXRecordDecl *ClassDecl); + + /// DefineImplicitCopyConstructor - Checks for feasibility of + /// defining this constructor as the copy constructor. + void DefineImplicitCopyConstructor(SourceLocation CurrentLocation, + CXXConstructorDecl *Constructor); + + /// \brief Declare the implicit move constructor for the given class. + /// + /// \param ClassDecl The Class declaration into which the implicit + /// move constructor will be added. + /// + /// \returns The implicitly-declared move constructor, or NULL if it wasn't + /// declared. + CXXConstructorDecl *DeclareImplicitMoveConstructor(CXXRecordDecl *ClassDecl); + + /// DefineImplicitMoveConstructor - Checks for feasibility of + /// defining this constructor as the move constructor. + void DefineImplicitMoveConstructor(SourceLocation CurrentLocation, + CXXConstructorDecl *Constructor); + + /// \brief Declare the implicit copy assignment operator for the given class. + /// + /// \param ClassDecl The class declaration into which the implicit + /// copy assignment operator will be added. + /// + /// \returns The implicitly-declared copy assignment operator. + CXXMethodDecl *DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl); + + /// \brief Defines an implicitly-declared copy assignment operator. + void DefineImplicitCopyAssignment(SourceLocation CurrentLocation, + CXXMethodDecl *MethodDecl); + + /// \brief Declare the implicit move assignment operator for the given class. + /// + /// \param ClassDecl The Class declaration into which the implicit + /// move assignment operator will be added. + /// + /// \returns The implicitly-declared move assignment operator, or NULL if it + /// wasn't declared. + CXXMethodDecl *DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl); + + /// \brief Defines an implicitly-declared move assignment operator. + void DefineImplicitMoveAssignment(SourceLocation CurrentLocation, + CXXMethodDecl *MethodDecl); + + /// \brief Force the declaration of any implicitly-declared members of this + /// class. + void ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class); + + /// \brief Determine whether the given function is an implicitly-deleted + /// special member function. + bool isImplicitlyDeleted(FunctionDecl *FD); + + /// \brief Check whether 'this' shows up in the type of a static member + /// function after the (naturally empty) cv-qualifier-seq would be. + /// + /// \returns true if an error occurred. + bool checkThisInStaticMemberFunctionType(CXXMethodDecl *Method); + + /// \brief Whether this' shows up in the exception specification of a static + /// member function. + bool checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method); + + /// \brief Check whether 'this' shows up in the attributes of the given + /// static member function. + /// + /// \returns true if an error occurred. + bool checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method); + + /// MaybeBindToTemporary - If the passed in expression has a record type with + /// a non-trivial destructor, this will return CXXBindTemporaryExpr. Otherwise + /// it simply returns the passed in expression. + ExprResult MaybeBindToTemporary(Expr *E); + + bool CompleteConstructorCall(CXXConstructorDecl *Constructor, + MultiExprArg ArgsPtr, + SourceLocation Loc, + SmallVectorImpl<Expr*> &ConvertedArgs, + bool AllowExplicit = false, + bool IsListInitialization = false); + + ParsedType getInheritingConstructorName(CXXScopeSpec &SS, + SourceLocation NameLoc, + IdentifierInfo &Name); + + ParsedType getDestructorName(SourceLocation TildeLoc, + IdentifierInfo &II, SourceLocation NameLoc, + Scope *S, CXXScopeSpec &SS, + ParsedType ObjectType, + bool EnteringContext); + + ParsedType getDestructorType(const DeclSpec& DS, ParsedType ObjectType); + + // Checks that reinterpret casts don't have undefined behavior. + void CheckCompatibleReinterpretCast(QualType SrcType, QualType DestType, + bool IsDereference, SourceRange Range); + + /// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's. + ExprResult ActOnCXXNamedCast(SourceLocation OpLoc, + tok::TokenKind Kind, + SourceLocation LAngleBracketLoc, + Declarator &D, + SourceLocation RAngleBracketLoc, + SourceLocation LParenLoc, + Expr *E, + SourceLocation RParenLoc); + + ExprResult BuildCXXNamedCast(SourceLocation OpLoc, + tok::TokenKind Kind, + TypeSourceInfo *Ty, + Expr *E, + SourceRange AngleBrackets, + SourceRange Parens); + + ExprResult BuildCXXTypeId(QualType TypeInfoType, + SourceLocation TypeidLoc, + TypeSourceInfo *Operand, + SourceLocation RParenLoc); + ExprResult BuildCXXTypeId(QualType TypeInfoType, + SourceLocation TypeidLoc, + Expr *Operand, + SourceLocation RParenLoc); + + /// ActOnCXXTypeid - Parse typeid( something ). + ExprResult ActOnCXXTypeid(SourceLocation OpLoc, + SourceLocation LParenLoc, bool isType, + void *TyOrExpr, + SourceLocation RParenLoc); + + ExprResult BuildCXXUuidof(QualType TypeInfoType, + SourceLocation TypeidLoc, + TypeSourceInfo *Operand, + SourceLocation RParenLoc); + ExprResult BuildCXXUuidof(QualType TypeInfoType, + SourceLocation TypeidLoc, + Expr *Operand, + SourceLocation RParenLoc); + + /// ActOnCXXUuidof - Parse __uuidof( something ). + ExprResult ActOnCXXUuidof(SourceLocation OpLoc, + SourceLocation LParenLoc, bool isType, + void *TyOrExpr, + SourceLocation RParenLoc); + + /// \brief Handle a C++1z fold-expression: ( expr op ... op expr ). + ExprResult ActOnCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS, + tok::TokenKind Operator, + SourceLocation EllipsisLoc, Expr *RHS, + SourceLocation RParenLoc); + ExprResult BuildCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS, + BinaryOperatorKind Operator, + SourceLocation EllipsisLoc, Expr *RHS, + SourceLocation RParenLoc); + ExprResult BuildEmptyCXXFoldExpr(SourceLocation EllipsisLoc, + BinaryOperatorKind Operator); + + //// ActOnCXXThis - Parse 'this' pointer. + ExprResult ActOnCXXThis(SourceLocation loc); + + /// \brief Try to retrieve the type of the 'this' pointer. + /// + /// \returns The type of 'this', if possible. Otherwise, returns a NULL type. + QualType getCurrentThisType(); + + /// \brief When non-NULL, the C++ 'this' expression is allowed despite the + /// current context not being a non-static member function. In such cases, + /// this provides the type used for 'this'. + QualType CXXThisTypeOverride; + + /// \brief RAII object used to temporarily allow the C++ 'this' expression + /// to be used, with the given qualifiers on the current class type. + class CXXThisScopeRAII { + Sema &S; + QualType OldCXXThisTypeOverride; + bool Enabled; + + public: + /// \brief Introduce a new scope where 'this' may be allowed (when enabled), + /// using the given declaration (which is either a class template or a + /// class) along with the given qualifiers. + /// along with the qualifiers placed on '*this'. + CXXThisScopeRAII(Sema &S, Decl *ContextDecl, unsigned CXXThisTypeQuals, + bool Enabled = true); + + ~CXXThisScopeRAII(); + }; + + /// \brief Make sure the value of 'this' is actually available in the current + /// context, if it is a potentially evaluated context. + /// + /// \param Loc The location at which the capture of 'this' occurs. + /// + /// \param Explicit Whether 'this' is explicitly captured in a lambda + /// capture list. + /// + /// \param FunctionScopeIndexToStopAt If non-null, it points to the index + /// of the FunctionScopeInfo stack beyond which we do not attempt to capture. + /// This is useful when enclosing lambdas must speculatively capture + /// 'this' that may or may not be used in certain specializations of + /// a nested generic lambda (depending on whether the name resolves to + /// a non-static member function or a static function). + /// \return returns 'true' if failed, 'false' if success. + bool CheckCXXThisCapture(SourceLocation Loc, bool Explicit = false, + bool BuildAndDiagnose = true, + const unsigned *const FunctionScopeIndexToStopAt = nullptr); + + /// \brief Determine whether the given type is the type of *this that is used + /// outside of the body of a member function for a type that is currently + /// being defined. + bool isThisOutsideMemberFunctionBody(QualType BaseType); + + /// ActOnCXXBoolLiteral - Parse {true,false} literals. + ExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind); + + + /// ActOnObjCBoolLiteral - Parse {__objc_yes,__objc_no} literals. + ExprResult ActOnObjCBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind); + + /// ActOnCXXNullPtrLiteral - Parse 'nullptr'. + ExprResult ActOnCXXNullPtrLiteral(SourceLocation Loc); + + //// ActOnCXXThrow - Parse throw expressions. + ExprResult ActOnCXXThrow(Scope *S, SourceLocation OpLoc, Expr *expr); + ExprResult BuildCXXThrow(SourceLocation OpLoc, Expr *Ex, + bool IsThrownVarInScope); + bool CheckCXXThrowOperand(SourceLocation ThrowLoc, QualType ThrowTy, Expr *E); + + /// ActOnCXXTypeConstructExpr - Parse construction of a specified type. + /// Can be interpreted either as function-style casting ("int(x)") + /// or class type construction ("ClassType(x,y,z)") + /// or creation of a value-initialized type ("int()"). + ExprResult ActOnCXXTypeConstructExpr(ParsedType TypeRep, + SourceLocation LParenLoc, + MultiExprArg Exprs, + SourceLocation RParenLoc); + + ExprResult BuildCXXTypeConstructExpr(TypeSourceInfo *Type, + SourceLocation LParenLoc, + MultiExprArg Exprs, + SourceLocation RParenLoc); + + /// ActOnCXXNew - Parsed a C++ 'new' expression. + ExprResult ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, + SourceLocation PlacementLParen, + MultiExprArg PlacementArgs, + SourceLocation PlacementRParen, + SourceRange TypeIdParens, Declarator &D, + Expr *Initializer); + ExprResult BuildCXXNew(SourceRange Range, bool UseGlobal, + SourceLocation PlacementLParen, + MultiExprArg PlacementArgs, + SourceLocation PlacementRParen, + SourceRange TypeIdParens, + QualType AllocType, + TypeSourceInfo *AllocTypeInfo, + Expr *ArraySize, + SourceRange DirectInitRange, + Expr *Initializer, + bool TypeMayContainAuto = true); + + bool CheckAllocatedType(QualType AllocType, SourceLocation Loc, + SourceRange R); + bool FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, + bool UseGlobal, QualType AllocType, bool IsArray, + MultiExprArg PlaceArgs, + FunctionDecl *&OperatorNew, + FunctionDecl *&OperatorDelete); + bool FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, + DeclarationName Name, MultiExprArg Args, + DeclContext *Ctx, + bool AllowMissing, FunctionDecl *&Operator, + bool Diagnose = true); + void DeclareGlobalNewDelete(); + void DeclareGlobalAllocationFunction(DeclarationName Name, QualType Return, + QualType Param1, + QualType Param2 = QualType(), + bool addRestrictAttr = false); + + bool FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, + DeclarationName Name, FunctionDecl* &Operator, + bool Diagnose = true); + FunctionDecl *FindUsualDeallocationFunction(SourceLocation StartLoc, + bool CanProvideSize, + DeclarationName Name); + + /// ActOnCXXDelete - Parsed a C++ 'delete' expression + ExprResult ActOnCXXDelete(SourceLocation StartLoc, + bool UseGlobal, bool ArrayForm, + Expr *Operand); + + DeclResult ActOnCXXConditionDeclaration(Scope *S, Declarator &D); + ExprResult CheckConditionVariable(VarDecl *ConditionVar, + SourceLocation StmtLoc, + bool ConvertToBoolean); + + ExprResult ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation LParen, + Expr *Operand, SourceLocation RParen); + ExprResult BuildCXXNoexceptExpr(SourceLocation KeyLoc, Expr *Operand, + SourceLocation RParen); + + /// \brief Parsed one of the type trait support pseudo-functions. + ExprResult ActOnTypeTrait(TypeTrait Kind, SourceLocation KWLoc, + ArrayRef<ParsedType> Args, + SourceLocation RParenLoc); + ExprResult BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc, + ArrayRef<TypeSourceInfo *> Args, + SourceLocation RParenLoc); + + /// ActOnArrayTypeTrait - Parsed one of the bianry type trait support + /// pseudo-functions. + ExprResult ActOnArrayTypeTrait(ArrayTypeTrait ATT, + SourceLocation KWLoc, + ParsedType LhsTy, + Expr *DimExpr, + SourceLocation RParen); + + ExprResult BuildArrayTypeTrait(ArrayTypeTrait ATT, + SourceLocation KWLoc, + TypeSourceInfo *TSInfo, + Expr *DimExpr, + SourceLocation RParen); + + /// ActOnExpressionTrait - Parsed one of the unary type trait support + /// pseudo-functions. + ExprResult ActOnExpressionTrait(ExpressionTrait OET, + SourceLocation KWLoc, + Expr *Queried, + SourceLocation RParen); + + ExprResult BuildExpressionTrait(ExpressionTrait OET, + SourceLocation KWLoc, + Expr *Queried, + SourceLocation RParen); + + ExprResult ActOnStartCXXMemberReference(Scope *S, + Expr *Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + ParsedType &ObjectType, + bool &MayBePseudoDestructor); + + ExprResult BuildPseudoDestructorExpr(Expr *Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + const CXXScopeSpec &SS, + TypeSourceInfo *ScopeType, + SourceLocation CCLoc, + SourceLocation TildeLoc, + PseudoDestructorTypeStorage DestroyedType); + + ExprResult ActOnPseudoDestructorExpr(Scope *S, Expr *Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + CXXScopeSpec &SS, + UnqualifiedId &FirstTypeName, + SourceLocation CCLoc, + SourceLocation TildeLoc, + UnqualifiedId &SecondTypeName); + + ExprResult ActOnPseudoDestructorExpr(Scope *S, Expr *Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + SourceLocation TildeLoc, + const DeclSpec& DS); + + /// MaybeCreateExprWithCleanups - If the current full-expression + /// requires any cleanups, surround it with a ExprWithCleanups node. + /// Otherwise, just returns the passed-in expression. + Expr *MaybeCreateExprWithCleanups(Expr *SubExpr); + Stmt *MaybeCreateStmtWithCleanups(Stmt *SubStmt); + ExprResult MaybeCreateExprWithCleanups(ExprResult SubExpr); + + ExprResult ActOnFinishFullExpr(Expr *Expr) { + return ActOnFinishFullExpr(Expr, Expr ? Expr->getExprLoc() + : SourceLocation()); + } + ExprResult ActOnFinishFullExpr(Expr *Expr, SourceLocation CC, + bool DiscardedValue = false, + bool IsConstexpr = false, + bool IsLambdaInitCaptureInitializer = false); + StmtResult ActOnFinishFullStmt(Stmt *Stmt); + + // Marks SS invalid if it represents an incomplete type. + bool RequireCompleteDeclContext(CXXScopeSpec &SS, DeclContext *DC); + + DeclContext *computeDeclContext(QualType T); + DeclContext *computeDeclContext(const CXXScopeSpec &SS, + bool EnteringContext = false); + bool isDependentScopeSpecifier(const CXXScopeSpec &SS); + CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier *NNS); + + /// \brief The parser has parsed a global nested-name-specifier '::'. + /// + /// \param CCLoc The location of the '::'. + /// + /// \param SS The nested-name-specifier, which will be updated in-place + /// to reflect the parsed nested-name-specifier. + /// + /// \returns true if an error occurred, false otherwise. + bool ActOnCXXGlobalScopeSpecifier(SourceLocation CCLoc, CXXScopeSpec &SS); + + /// \brief The parser has parsed a '__super' nested-name-specifier. + /// + /// \param SuperLoc The location of the '__super' keyword. + /// + /// \param ColonColonLoc The location of the '::'. + /// + /// \param SS The nested-name-specifier, which will be updated in-place + /// to reflect the parsed nested-name-specifier. + /// + /// \returns true if an error occurred, false otherwise. + bool ActOnSuperScopeSpecifier(SourceLocation SuperLoc, + SourceLocation ColonColonLoc, CXXScopeSpec &SS); + + bool isAcceptableNestedNameSpecifier(const NamedDecl *SD, + bool *CanCorrect = nullptr); + NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS); + + bool isNonTypeNestedNameSpecifier(Scope *S, CXXScopeSpec &SS, + SourceLocation IdLoc, + IdentifierInfo &II, + ParsedType ObjectType); + + bool BuildCXXNestedNameSpecifier(Scope *S, + IdentifierInfo &Identifier, + SourceLocation IdentifierLoc, + SourceLocation CCLoc, + QualType ObjectType, + bool EnteringContext, + CXXScopeSpec &SS, + NamedDecl *ScopeLookupResult, + bool ErrorRecoveryLookup, + bool *IsCorrectedToColon = nullptr); + + /// \brief The parser has parsed a nested-name-specifier 'identifier::'. + /// + /// \param S The scope in which this nested-name-specifier occurs. + /// + /// \param Identifier The identifier preceding the '::'. + /// + /// \param IdentifierLoc The location of the identifier. + /// + /// \param CCLoc The location of the '::'. + /// + /// \param ObjectType The type of the object, if we're parsing + /// nested-name-specifier in a member access expression. + /// + /// \param EnteringContext Whether we're entering the context nominated by + /// this nested-name-specifier. + /// + /// \param SS The nested-name-specifier, which is both an input + /// parameter (the nested-name-specifier before this type) and an + /// output parameter (containing the full nested-name-specifier, + /// including this new type). + /// + /// \param ErrorRecoveryLookup If true, then this method is called to improve + /// error recovery. In this case do not emit error message. + /// + /// \param IsCorrectedToColon If not null, suggestions to replace '::' -> ':' + /// are allowed. The bool value pointed by this parameter is set to 'true' + /// if the identifier is treated as if it was followed by ':', not '::'. + /// + /// \returns true if an error occurred, false otherwise. + bool ActOnCXXNestedNameSpecifier(Scope *S, + IdentifierInfo &Identifier, + SourceLocation IdentifierLoc, + SourceLocation CCLoc, + ParsedType ObjectType, + bool EnteringContext, + CXXScopeSpec &SS, + bool ErrorRecoveryLookup = false, + bool *IsCorrectedToColon = nullptr); + + ExprResult ActOnDecltypeExpression(Expr *E); + + bool ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS, + const DeclSpec &DS, + SourceLocation ColonColonLoc); + + bool IsInvalidUnlessNestedName(Scope *S, CXXScopeSpec &SS, + IdentifierInfo &Identifier, + SourceLocation IdentifierLoc, + SourceLocation ColonLoc, + ParsedType ObjectType, + bool EnteringContext); + + /// \brief The parser has parsed a nested-name-specifier + /// 'template[opt] template-name < template-args >::'. + /// + /// \param S The scope in which this nested-name-specifier occurs. + /// + /// \param SS The nested-name-specifier, which is both an input + /// parameter (the nested-name-specifier before this type) and an + /// output parameter (containing the full nested-name-specifier, + /// including this new type). + /// + /// \param TemplateKWLoc the location of the 'template' keyword, if any. + /// \param TemplateName the template name. + /// \param TemplateNameLoc The location of the template name. + /// \param LAngleLoc The location of the opening angle bracket ('<'). + /// \param TemplateArgs The template arguments. + /// \param RAngleLoc The location of the closing angle bracket ('>'). + /// \param CCLoc The location of the '::'. + /// + /// \param EnteringContext Whether we're entering the context of the + /// nested-name-specifier. + /// + /// + /// \returns true if an error occurred, false otherwise. + bool ActOnCXXNestedNameSpecifier(Scope *S, + CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + TemplateTy TemplateName, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgs, + SourceLocation RAngleLoc, + SourceLocation CCLoc, + bool EnteringContext); + + /// \brief Given a C++ nested-name-specifier, produce an annotation value + /// that the parser can use later to reconstruct the given + /// nested-name-specifier. + /// + /// \param SS A nested-name-specifier. + /// + /// \returns A pointer containing all of the information in the + /// nested-name-specifier \p SS. + void *SaveNestedNameSpecifierAnnotation(CXXScopeSpec &SS); + + /// \brief Given an annotation pointer for a nested-name-specifier, restore + /// the nested-name-specifier structure. + /// + /// \param Annotation The annotation pointer, produced by + /// \c SaveNestedNameSpecifierAnnotation(). + /// + /// \param AnnotationRange The source range corresponding to the annotation. + /// + /// \param SS The nested-name-specifier that will be updated with the contents + /// of the annotation pointer. + void RestoreNestedNameSpecifierAnnotation(void *Annotation, + SourceRange AnnotationRange, + CXXScopeSpec &SS); + + bool ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS); + + /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global + /// scope or nested-name-specifier) is parsed, part of a declarator-id. + /// After this method is called, according to [C++ 3.4.3p3], names should be + /// looked up in the declarator-id's scope, until the declarator is parsed and + /// ActOnCXXExitDeclaratorScope is called. + /// The 'SS' should be a non-empty valid CXXScopeSpec. + bool ActOnCXXEnterDeclaratorScope(Scope *S, CXXScopeSpec &SS); + + /// ActOnCXXExitDeclaratorScope - Called when a declarator that previously + /// invoked ActOnCXXEnterDeclaratorScope(), is finished. 'SS' is the same + /// CXXScopeSpec that was passed to ActOnCXXEnterDeclaratorScope as well. + /// Used to indicate that names should revert to being looked up in the + /// defining scope. + void ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS); + + /// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse an + /// initializer for the declaration 'Dcl'. + /// After this method is called, according to [C++ 3.4.1p13], if 'Dcl' is a + /// static data member of class X, names should be looked up in the scope of + /// class X. + void ActOnCXXEnterDeclInitializer(Scope *S, Decl *Dcl); + + /// ActOnCXXExitDeclInitializer - Invoked after we are finished parsing an + /// initializer for the declaration 'Dcl'. + void ActOnCXXExitDeclInitializer(Scope *S, Decl *Dcl); + + /// \brief Create a new lambda closure type. + CXXRecordDecl *createLambdaClosureType(SourceRange IntroducerRange, + TypeSourceInfo *Info, + bool KnownDependent, + LambdaCaptureDefault CaptureDefault); + + /// \brief Start the definition of a lambda expression. + CXXMethodDecl *startLambdaDefinition(CXXRecordDecl *Class, + SourceRange IntroducerRange, + TypeSourceInfo *MethodType, + SourceLocation EndLoc, + ArrayRef<ParmVarDecl *> Params); + + /// \brief Endow the lambda scope info with the relevant properties. + void buildLambdaScope(sema::LambdaScopeInfo *LSI, + CXXMethodDecl *CallOperator, + SourceRange IntroducerRange, + LambdaCaptureDefault CaptureDefault, + SourceLocation CaptureDefaultLoc, + bool ExplicitParams, + bool ExplicitResultType, + bool Mutable); + + /// \brief Perform initialization analysis of the init-capture and perform + /// any implicit conversions such as an lvalue-to-rvalue conversion if + /// not being used to initialize a reference. + ParsedType actOnLambdaInitCaptureInitialization( + SourceLocation Loc, bool ByRef, IdentifierInfo *Id, + LambdaCaptureInitKind InitKind, Expr *&Init) { + return ParsedType::make(buildLambdaInitCaptureInitialization( + Loc, ByRef, Id, InitKind != LambdaCaptureInitKind::CopyInit, Init)); + } + QualType buildLambdaInitCaptureInitialization(SourceLocation Loc, bool ByRef, + IdentifierInfo *Id, + bool DirectInit, Expr *&Init); + + /// \brief Create a dummy variable within the declcontext of the lambda's + /// call operator, for name lookup purposes for a lambda init capture. + /// + /// CodeGen handles emission of lambda captures, ignoring these dummy + /// variables appropriately. + VarDecl *createLambdaInitCaptureVarDecl(SourceLocation Loc, + QualType InitCaptureType, + IdentifierInfo *Id, + unsigned InitStyle, Expr *Init); + + /// \brief Build the implicit field for an init-capture. + FieldDecl *buildInitCaptureField(sema::LambdaScopeInfo *LSI, VarDecl *Var); + + /// \brief Note that we have finished the explicit captures for the + /// given lambda. + void finishLambdaExplicitCaptures(sema::LambdaScopeInfo *LSI); + + /// \brief Introduce the lambda parameters into scope. + void addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope); + + /// \brief Deduce a block or lambda's return type based on the return + /// statements present in the body. + void deduceClosureReturnType(sema::CapturingScopeInfo &CSI); + + /// ActOnStartOfLambdaDefinition - This is called just before we start + /// parsing the body of a lambda; it analyzes the explicit captures and + /// arguments, and sets up various data-structures for the body of the + /// lambda. + void ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, + Declarator &ParamInfo, Scope *CurScope); + + /// ActOnLambdaError - If there is an error parsing a lambda, this callback + /// is invoked to pop the information about the lambda. + void ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope, + bool IsInstantiation = false); + + /// ActOnLambdaExpr - This is called when the body of a lambda expression + /// was successfully completed. + ExprResult ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, + Scope *CurScope); + + /// \brief Complete a lambda-expression having processed and attached the + /// lambda body. + ExprResult BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, + sema::LambdaScopeInfo *LSI); + + /// \brief Define the "body" of the conversion from a lambda object to a + /// function pointer. + /// + /// This routine doesn't actually define a sensible body; rather, it fills + /// in the initialization expression needed to copy the lambda object into + /// the block, and IR generation actually generates the real body of the + /// block pointer conversion. + void DefineImplicitLambdaToFunctionPointerConversion( + SourceLocation CurrentLoc, CXXConversionDecl *Conv); + + /// \brief Define the "body" of the conversion from a lambda object to a + /// block pointer. + /// + /// This routine doesn't actually define a sensible body; rather, it fills + /// in the initialization expression needed to copy the lambda object into + /// the block, and IR generation actually generates the real body of the + /// block pointer conversion. + void DefineImplicitLambdaToBlockPointerConversion(SourceLocation CurrentLoc, + CXXConversionDecl *Conv); + + ExprResult BuildBlockForLambdaConversion(SourceLocation CurrentLocation, + SourceLocation ConvLocation, + CXXConversionDecl *Conv, + Expr *Src); + + // ParseObjCStringLiteral - Parse Objective-C string literals. + ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs, + ArrayRef<Expr *> Strings); + + ExprResult BuildObjCStringLiteral(SourceLocation AtLoc, StringLiteral *S); + + /// BuildObjCNumericLiteral - builds an ObjCBoxedExpr AST node for the + /// numeric literal expression. Type of the expression will be "NSNumber *" + /// or "id" if NSNumber is unavailable. + ExprResult BuildObjCNumericLiteral(SourceLocation AtLoc, Expr *Number); + ExprResult ActOnObjCBoolLiteral(SourceLocation AtLoc, SourceLocation ValueLoc, + bool Value); + ExprResult BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements); + + /// BuildObjCBoxedExpr - builds an ObjCBoxedExpr AST node for the + /// '@' prefixed parenthesized expression. The type of the expression will + /// either be "NSNumber *", "NSString *" or "NSValue *" depending on the type + /// of ValueType, which is allowed to be a built-in numeric type, "char *", + /// "const char *" or C structure with attribute 'objc_boxable'. + ExprResult BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr); + + ExprResult BuildObjCSubscriptExpression(SourceLocation RB, Expr *BaseExpr, + Expr *IndexExpr, + ObjCMethodDecl *getterMethod, + ObjCMethodDecl *setterMethod); + + ExprResult BuildObjCDictionaryLiteral(SourceRange SR, + MutableArrayRef<ObjCDictionaryElement> Elements); + + ExprResult BuildObjCEncodeExpression(SourceLocation AtLoc, + TypeSourceInfo *EncodedTypeInfo, + SourceLocation RParenLoc); + ExprResult BuildCXXMemberCallExpr(Expr *Exp, NamedDecl *FoundDecl, + CXXConversionDecl *Method, + bool HadMultipleCandidates); + + ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc, + SourceLocation EncodeLoc, + SourceLocation LParenLoc, + ParsedType Ty, + SourceLocation RParenLoc); + + /// ParseObjCSelectorExpression - Build selector expression for \@selector + ExprResult ParseObjCSelectorExpression(Selector Sel, + SourceLocation AtLoc, + SourceLocation SelLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc, + bool WarnMultipleSelectors); + + /// ParseObjCProtocolExpression - Build protocol expression for \@protocol + ExprResult ParseObjCProtocolExpression(IdentifierInfo * ProtocolName, + SourceLocation AtLoc, + SourceLocation ProtoLoc, + SourceLocation LParenLoc, + SourceLocation ProtoIdLoc, + SourceLocation RParenLoc); + + //===--------------------------------------------------------------------===// + // C++ Declarations + // + Decl *ActOnStartLinkageSpecification(Scope *S, + SourceLocation ExternLoc, + Expr *LangStr, + SourceLocation LBraceLoc); + Decl *ActOnFinishLinkageSpecification(Scope *S, + Decl *LinkageSpec, + SourceLocation RBraceLoc); + + + //===--------------------------------------------------------------------===// + // C++ Classes + // + bool isCurrentClassName(const IdentifierInfo &II, Scope *S, + const CXXScopeSpec *SS = nullptr); + bool isCurrentClassNameTypo(IdentifierInfo *&II, const CXXScopeSpec *SS); + + bool ActOnAccessSpecifier(AccessSpecifier Access, + SourceLocation ASLoc, + SourceLocation ColonLoc, + AttributeList *Attrs = nullptr); + + NamedDecl *ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, + Declarator &D, + MultiTemplateParamsArg TemplateParameterLists, + Expr *BitfieldWidth, const VirtSpecifiers &VS, + InClassInitStyle InitStyle); + + void ActOnStartCXXInClassMemberInitializer(); + void ActOnFinishCXXInClassMemberInitializer(Decl *VarDecl, + SourceLocation EqualLoc, + Expr *Init); + + MemInitResult ActOnMemInitializer(Decl *ConstructorD, + Scope *S, + CXXScopeSpec &SS, + IdentifierInfo *MemberOrBase, + ParsedType TemplateTypeTy, + const DeclSpec &DS, + SourceLocation IdLoc, + SourceLocation LParenLoc, + ArrayRef<Expr *> Args, + SourceLocation RParenLoc, + SourceLocation EllipsisLoc); + + MemInitResult ActOnMemInitializer(Decl *ConstructorD, + Scope *S, + CXXScopeSpec &SS, + IdentifierInfo *MemberOrBase, + ParsedType TemplateTypeTy, + const DeclSpec &DS, + SourceLocation IdLoc, + Expr *InitList, + SourceLocation EllipsisLoc); + + MemInitResult BuildMemInitializer(Decl *ConstructorD, + Scope *S, + CXXScopeSpec &SS, + IdentifierInfo *MemberOrBase, + ParsedType TemplateTypeTy, + const DeclSpec &DS, + SourceLocation IdLoc, + Expr *Init, + SourceLocation EllipsisLoc); + + MemInitResult BuildMemberInitializer(ValueDecl *Member, + Expr *Init, + SourceLocation IdLoc); + + MemInitResult BuildBaseInitializer(QualType BaseType, + TypeSourceInfo *BaseTInfo, + Expr *Init, + CXXRecordDecl *ClassDecl, + SourceLocation EllipsisLoc); + + MemInitResult BuildDelegatingInitializer(TypeSourceInfo *TInfo, + Expr *Init, + CXXRecordDecl *ClassDecl); + + bool SetDelegatingInitializer(CXXConstructorDecl *Constructor, + CXXCtorInitializer *Initializer); + + bool SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors, + ArrayRef<CXXCtorInitializer *> Initializers = None); + + void SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation); + + + /// MarkBaseAndMemberDestructorsReferenced - Given a record decl, + /// mark all the non-trivial destructors of its members and bases as + /// referenced. + void MarkBaseAndMemberDestructorsReferenced(SourceLocation Loc, + CXXRecordDecl *Record); + + /// \brief The list of classes whose vtables have been used within + /// this translation unit, and the source locations at which the + /// first use occurred. + typedef std::pair<CXXRecordDecl*, SourceLocation> VTableUse; + + /// \brief The list of vtables that are required but have not yet been + /// materialized. + SmallVector<VTableUse, 16> VTableUses; + + /// \brief The set of classes whose vtables have been used within + /// this translation unit, and a bit that will be true if the vtable is + /// required to be emitted (otherwise, it should be emitted only if needed + /// by code generation). + llvm::DenseMap<CXXRecordDecl *, bool> VTablesUsed; + + /// \brief Load any externally-stored vtable uses. + void LoadExternalVTableUses(); + + /// \brief Note that the vtable for the given class was used at the + /// given location. + void MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, + bool DefinitionRequired = false); + + /// \brief Mark the exception specifications of all virtual member functions + /// in the given class as needed. + void MarkVirtualMemberExceptionSpecsNeeded(SourceLocation Loc, + const CXXRecordDecl *RD); + + /// MarkVirtualMembersReferenced - Will mark all members of the given + /// CXXRecordDecl referenced. + void MarkVirtualMembersReferenced(SourceLocation Loc, + const CXXRecordDecl *RD); + + /// \brief Define all of the vtables that have been used in this + /// translation unit and reference any virtual members used by those + /// vtables. + /// + /// \returns true if any work was done, false otherwise. + bool DefineUsedVTables(); + + void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl); + + void ActOnMemInitializers(Decl *ConstructorDecl, + SourceLocation ColonLoc, + ArrayRef<CXXCtorInitializer*> MemInits, + bool AnyErrors); + + void checkClassLevelDLLAttribute(CXXRecordDecl *Class); + void propagateDLLAttrToBaseClassTemplate( + CXXRecordDecl *Class, Attr *ClassAttr, + ClassTemplateSpecializationDecl *BaseTemplateSpec, + SourceLocation BaseLoc); + void CheckCompletedCXXClass(CXXRecordDecl *Record); + void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, + Decl *TagDecl, + SourceLocation LBrac, + SourceLocation RBrac, + AttributeList *AttrList); + void ActOnFinishCXXMemberDecls(); + void ActOnFinishCXXNonNestedClass(Decl *D); + + void ActOnReenterCXXMethodParameter(Scope *S, ParmVarDecl *Param); + unsigned ActOnReenterTemplateScope(Scope *S, Decl *Template); + void ActOnStartDelayedMemberDeclarations(Scope *S, Decl *Record); + void ActOnStartDelayedCXXMethodDeclaration(Scope *S, Decl *Method); + void ActOnDelayedCXXMethodParameter(Scope *S, Decl *Param); + void ActOnFinishDelayedMemberDeclarations(Scope *S, Decl *Record); + void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, Decl *Method); + void ActOnFinishDelayedMemberInitializers(Decl *Record); + void MarkAsLateParsedTemplate(FunctionDecl *FD, Decl *FnD, + CachedTokens &Toks); + void UnmarkAsLateParsedTemplate(FunctionDecl *FD); + bool IsInsideALocalClassWithinATemplateFunction(); + + Decl *ActOnStaticAssertDeclaration(SourceLocation StaticAssertLoc, + Expr *AssertExpr, + Expr *AssertMessageExpr, + SourceLocation RParenLoc); + Decl *BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, + Expr *AssertExpr, + StringLiteral *AssertMessageExpr, + SourceLocation RParenLoc, + bool Failed); + + FriendDecl *CheckFriendTypeDecl(SourceLocation LocStart, + SourceLocation FriendLoc, + TypeSourceInfo *TSInfo); + Decl *ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, + MultiTemplateParamsArg TemplateParams); + NamedDecl *ActOnFriendFunctionDecl(Scope *S, Declarator &D, + MultiTemplateParamsArg TemplateParams); + + QualType CheckConstructorDeclarator(Declarator &D, QualType R, + StorageClass& SC); + void CheckConstructor(CXXConstructorDecl *Constructor); + QualType CheckDestructorDeclarator(Declarator &D, QualType R, + StorageClass& SC); + bool CheckDestructor(CXXDestructorDecl *Destructor); + void CheckConversionDeclarator(Declarator &D, QualType &R, + StorageClass& SC); + Decl *ActOnConversionDeclarator(CXXConversionDecl *Conversion); + + void CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD); + void CheckExplicitlyDefaultedMemberExceptionSpec(CXXMethodDecl *MD, + const FunctionProtoType *T); + void CheckDelayedMemberExceptionSpecs(); + + //===--------------------------------------------------------------------===// + // C++ Derived Classes + // + + /// ActOnBaseSpecifier - Parsed a base specifier + CXXBaseSpecifier *CheckBaseSpecifier(CXXRecordDecl *Class, + SourceRange SpecifierRange, + bool Virtual, AccessSpecifier Access, + TypeSourceInfo *TInfo, + SourceLocation EllipsisLoc); + + BaseResult ActOnBaseSpecifier(Decl *classdecl, + SourceRange SpecifierRange, + ParsedAttributes &Attrs, + bool Virtual, AccessSpecifier Access, + ParsedType basetype, + SourceLocation BaseLoc, + SourceLocation EllipsisLoc); + + bool AttachBaseSpecifiers(CXXRecordDecl *Class, + MutableArrayRef<CXXBaseSpecifier *> Bases); + void ActOnBaseSpecifiers(Decl *ClassDecl, + MutableArrayRef<CXXBaseSpecifier *> Bases); + + bool IsDerivedFrom(SourceLocation Loc, QualType Derived, QualType Base); + bool IsDerivedFrom(SourceLocation Loc, QualType Derived, QualType Base, + CXXBasePaths &Paths); + + // FIXME: I don't like this name. + void BuildBasePathArray(const CXXBasePaths &Paths, CXXCastPath &BasePath); + + bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, + SourceLocation Loc, SourceRange Range, + CXXCastPath *BasePath = nullptr, + bool IgnoreAccess = false); + bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, + unsigned InaccessibleBaseID, + unsigned AmbigiousBaseConvID, + SourceLocation Loc, SourceRange Range, + DeclarationName Name, + CXXCastPath *BasePath); + + std::string getAmbiguousPathsDisplayString(CXXBasePaths &Paths); + + bool CheckOverridingFunctionAttributes(const CXXMethodDecl *New, + const CXXMethodDecl *Old); + + /// CheckOverridingFunctionReturnType - Checks whether the return types are + /// covariant, according to C++ [class.virtual]p5. + bool CheckOverridingFunctionReturnType(const CXXMethodDecl *New, + const CXXMethodDecl *Old); + + /// CheckOverridingFunctionExceptionSpec - Checks whether the exception + /// spec is a subset of base spec. + bool CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, + const CXXMethodDecl *Old); + + bool CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange); + + /// CheckOverrideControl - Check C++11 override control semantics. + void CheckOverrideControl(NamedDecl *D); + + /// DiagnoseAbsenceOfOverrideControl - Diagnose if 'override' keyword was + /// not used in the declaration of an overriding method. + void DiagnoseAbsenceOfOverrideControl(NamedDecl *D); + + /// CheckForFunctionMarkedFinal - Checks whether a virtual member function + /// overrides a virtual member function marked 'final', according to + /// C++11 [class.virtual]p4. + bool CheckIfOverriddenFunctionIsMarkedFinal(const CXXMethodDecl *New, + const CXXMethodDecl *Old); + + + //===--------------------------------------------------------------------===// + // C++ Access Control + // + + enum AccessResult { + AR_accessible, + AR_inaccessible, + AR_dependent, + AR_delayed + }; + + bool SetMemberAccessSpecifier(NamedDecl *MemberDecl, + NamedDecl *PrevMemberDecl, + AccessSpecifier LexicalAS); + + AccessResult CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, + DeclAccessPair FoundDecl); + AccessResult CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, + DeclAccessPair FoundDecl); + AccessResult CheckAllocationAccess(SourceLocation OperatorLoc, + SourceRange PlacementRange, + CXXRecordDecl *NamingClass, + DeclAccessPair FoundDecl, + bool Diagnose = true); + AccessResult CheckConstructorAccess(SourceLocation Loc, + CXXConstructorDecl *D, + const InitializedEntity &Entity, + AccessSpecifier Access, + bool IsCopyBindingRefToTemp = false); + AccessResult CheckConstructorAccess(SourceLocation Loc, + CXXConstructorDecl *D, + const InitializedEntity &Entity, + AccessSpecifier Access, + const PartialDiagnostic &PDiag); + AccessResult CheckDestructorAccess(SourceLocation Loc, + CXXDestructorDecl *Dtor, + const PartialDiagnostic &PDiag, + QualType objectType = QualType()); + AccessResult CheckFriendAccess(NamedDecl *D); + AccessResult CheckMemberAccess(SourceLocation UseLoc, + CXXRecordDecl *NamingClass, + DeclAccessPair Found); + AccessResult CheckMemberOperatorAccess(SourceLocation Loc, + Expr *ObjectExpr, + Expr *ArgExpr, + DeclAccessPair FoundDecl); + AccessResult CheckAddressOfMemberAccess(Expr *OvlExpr, + DeclAccessPair FoundDecl); + AccessResult CheckBaseClassAccess(SourceLocation AccessLoc, + QualType Base, QualType Derived, + const CXXBasePath &Path, + unsigned DiagID, + bool ForceCheck = false, + bool ForceUnprivileged = false); + void CheckLookupAccess(const LookupResult &R); + bool IsSimplyAccessible(NamedDecl *decl, DeclContext *Ctx); + bool isSpecialMemberAccessibleForDeletion(CXXMethodDecl *decl, + AccessSpecifier access, + QualType objectType); + + void HandleDependentAccessCheck(const DependentDiagnostic &DD, + const MultiLevelTemplateArgumentList &TemplateArgs); + void PerformDependentDiagnostics(const DeclContext *Pattern, + const MultiLevelTemplateArgumentList &TemplateArgs); + + void HandleDelayedAccessCheck(sema::DelayedDiagnostic &DD, Decl *Ctx); + + /// \brief When true, access checking violations are treated as SFINAE + /// failures rather than hard errors. + bool AccessCheckingSFINAE; + + enum AbstractDiagSelID { + AbstractNone = -1, + AbstractReturnType, + AbstractParamType, + AbstractVariableType, + AbstractFieldType, + AbstractIvarType, + AbstractSynthesizedIvarType, + AbstractArrayType + }; + + bool isAbstractType(SourceLocation Loc, QualType T); + bool RequireNonAbstractType(SourceLocation Loc, QualType T, + TypeDiagnoser &Diagnoser); + template <typename... Ts> + bool RequireNonAbstractType(SourceLocation Loc, QualType T, unsigned DiagID, + const Ts &...Args) { + BoundTypeDiagnoser<Ts...> Diagnoser(DiagID, Args...); + return RequireNonAbstractType(Loc, T, Diagnoser); + } + + void DiagnoseAbstractType(const CXXRecordDecl *RD); + + //===--------------------------------------------------------------------===// + // C++ Overloaded Operators [C++ 13.5] + // + + bool CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl); + + bool CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl); + + //===--------------------------------------------------------------------===// + // C++ Templates [C++ 14] + // + void FilterAcceptableTemplateNames(LookupResult &R, + bool AllowFunctionTemplates = true); + bool hasAnyAcceptableTemplateNames(LookupResult &R, + bool AllowFunctionTemplates = true); + + void LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS, + QualType ObjectType, bool EnteringContext, + bool &MemberOfUnknownSpecialization); + + TemplateNameKind isTemplateName(Scope *S, + CXXScopeSpec &SS, + bool hasTemplateKeyword, + UnqualifiedId &Name, + ParsedType ObjectType, + bool EnteringContext, + TemplateTy &Template, + bool &MemberOfUnknownSpecialization); + + bool DiagnoseUnknownTemplateName(const IdentifierInfo &II, + SourceLocation IILoc, + Scope *S, + const CXXScopeSpec *SS, + TemplateTy &SuggestedTemplate, + TemplateNameKind &SuggestedKind); + + void DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl); + TemplateDecl *AdjustDeclIfTemplate(Decl *&Decl); + + Decl *ActOnTypeParameter(Scope *S, bool Typename, + SourceLocation EllipsisLoc, + SourceLocation KeyLoc, + IdentifierInfo *ParamName, + SourceLocation ParamNameLoc, + unsigned Depth, unsigned Position, + SourceLocation EqualLoc, + ParsedType DefaultArg); + + QualType CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc); + Decl *ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, + unsigned Depth, + unsigned Position, + SourceLocation EqualLoc, + Expr *DefaultArg); + Decl *ActOnTemplateTemplateParameter(Scope *S, + SourceLocation TmpLoc, + TemplateParameterList *Params, + SourceLocation EllipsisLoc, + IdentifierInfo *ParamName, + SourceLocation ParamNameLoc, + unsigned Depth, + unsigned Position, + SourceLocation EqualLoc, + ParsedTemplateArgument DefaultArg); + + TemplateParameterList * + ActOnTemplateParameterList(unsigned Depth, + SourceLocation ExportLoc, + SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + ArrayRef<Decl *> Params, + SourceLocation RAngleLoc); + + /// \brief The context in which we are checking a template parameter list. + enum TemplateParamListContext { + TPC_ClassTemplate, + TPC_VarTemplate, + TPC_FunctionTemplate, + TPC_ClassTemplateMember, + TPC_FriendClassTemplate, + TPC_FriendFunctionTemplate, + TPC_FriendFunctionTemplateDefinition, + TPC_TypeAliasTemplate + }; + + bool CheckTemplateParameterList(TemplateParameterList *NewParams, + TemplateParameterList *OldParams, + TemplateParamListContext TPC); + TemplateParameterList *MatchTemplateParametersToScopeSpecifier( + SourceLocation DeclStartLoc, SourceLocation DeclLoc, + const CXXScopeSpec &SS, TemplateIdAnnotation *TemplateId, + ArrayRef<TemplateParameterList *> ParamLists, + bool IsFriend, bool &IsExplicitSpecialization, bool &Invalid); + + DeclResult CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, + SourceLocation KWLoc, CXXScopeSpec &SS, + IdentifierInfo *Name, SourceLocation NameLoc, + AttributeList *Attr, + TemplateParameterList *TemplateParams, + AccessSpecifier AS, + SourceLocation ModulePrivateLoc, + SourceLocation FriendLoc, + unsigned NumOuterTemplateParamLists, + TemplateParameterList **OuterTemplateParamLists, + SkipBodyInfo *SkipBody = nullptr); + + void translateTemplateArguments(const ASTTemplateArgsPtr &In, + TemplateArgumentListInfo &Out); + + void NoteAllFoundTemplates(TemplateName Name); + + QualType CheckTemplateIdType(TemplateName Template, + SourceLocation TemplateLoc, + TemplateArgumentListInfo &TemplateArgs); + + TypeResult + ActOnTemplateIdType(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, + TemplateTy Template, SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgs, + SourceLocation RAngleLoc, + bool IsCtorOrDtorName = false); + + /// \brief Parsed an elaborated-type-specifier that refers to a template-id, + /// such as \c class T::template apply<U>. + TypeResult ActOnTagTemplateIdType(TagUseKind TUK, + TypeSpecifierType TagSpec, + SourceLocation TagLoc, + CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + TemplateTy TemplateD, + SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgsIn, + SourceLocation RAngleLoc); + + DeclResult ActOnVarTemplateSpecialization( + Scope *S, Declarator &D, TypeSourceInfo *DI, + SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams, + StorageClass SC, bool IsPartialSpecialization); + + DeclResult CheckVarTemplateId(VarTemplateDecl *Template, + SourceLocation TemplateLoc, + SourceLocation TemplateNameLoc, + const TemplateArgumentListInfo &TemplateArgs); + + ExprResult CheckVarTemplateId(const CXXScopeSpec &SS, + const DeclarationNameInfo &NameInfo, + VarTemplateDecl *Template, + SourceLocation TemplateLoc, + const TemplateArgumentListInfo *TemplateArgs); + + ExprResult BuildTemplateIdExpr(const CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + LookupResult &R, + bool RequiresADL, + const TemplateArgumentListInfo *TemplateArgs); + + ExprResult BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *TemplateArgs); + + TemplateNameKind ActOnDependentTemplateName(Scope *S, + CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + UnqualifiedId &Name, + ParsedType ObjectType, + bool EnteringContext, + TemplateTy &Template); + + DeclResult + ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK, + SourceLocation KWLoc, + SourceLocation ModulePrivateLoc, + TemplateIdAnnotation &TemplateId, + AttributeList *Attr, + MultiTemplateParamsArg TemplateParameterLists, + SkipBodyInfo *SkipBody = nullptr); + + Decl *ActOnTemplateDeclarator(Scope *S, + MultiTemplateParamsArg TemplateParameterLists, + Declarator &D); + + bool + CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, + TemplateSpecializationKind NewTSK, + NamedDecl *PrevDecl, + TemplateSpecializationKind PrevTSK, + SourceLocation PrevPtOfInstantiation, + bool &SuppressNew); + + bool CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD, + const TemplateArgumentListInfo &ExplicitTemplateArgs, + LookupResult &Previous); + + bool CheckFunctionTemplateSpecialization(FunctionDecl *FD, + TemplateArgumentListInfo *ExplicitTemplateArgs, + LookupResult &Previous); + bool CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous); + + DeclResult + ActOnExplicitInstantiation(Scope *S, + SourceLocation ExternLoc, + SourceLocation TemplateLoc, + unsigned TagSpec, + SourceLocation KWLoc, + const CXXScopeSpec &SS, + TemplateTy Template, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgs, + SourceLocation RAngleLoc, + AttributeList *Attr); + + DeclResult + ActOnExplicitInstantiation(Scope *S, + SourceLocation ExternLoc, + SourceLocation TemplateLoc, + unsigned TagSpec, + SourceLocation KWLoc, + CXXScopeSpec &SS, + IdentifierInfo *Name, + SourceLocation NameLoc, + AttributeList *Attr); + + DeclResult ActOnExplicitInstantiation(Scope *S, + SourceLocation ExternLoc, + SourceLocation TemplateLoc, + Declarator &D); + + TemplateArgumentLoc + SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, + SourceLocation TemplateLoc, + SourceLocation RAngleLoc, + Decl *Param, + SmallVectorImpl<TemplateArgument> + &Converted, + bool &HasDefaultArg); + + /// \brief Specifies the context in which a particular template + /// argument is being checked. + enum CheckTemplateArgumentKind { + /// \brief The template argument was specified in the code or was + /// instantiated with some deduced template arguments. + CTAK_Specified, + + /// \brief The template argument was deduced via template argument + /// deduction. + CTAK_Deduced, + + /// \brief The template argument was deduced from an array bound + /// via template argument deduction. + CTAK_DeducedFromArrayBound + }; + + bool CheckTemplateArgument(NamedDecl *Param, + TemplateArgumentLoc &Arg, + NamedDecl *Template, + SourceLocation TemplateLoc, + SourceLocation RAngleLoc, + unsigned ArgumentPackIndex, + SmallVectorImpl<TemplateArgument> &Converted, + CheckTemplateArgumentKind CTAK = CTAK_Specified); + + /// \brief Check that the given template arguments can be be provided to + /// the given template, converting the arguments along the way. + /// + /// \param Template The template to which the template arguments are being + /// provided. + /// + /// \param TemplateLoc The location of the template name in the source. + /// + /// \param TemplateArgs The list of template arguments. If the template is + /// a template template parameter, this function may extend the set of + /// template arguments to also include substituted, defaulted template + /// arguments. + /// + /// \param PartialTemplateArgs True if the list of template arguments is + /// intentionally partial, e.g., because we're checking just the initial + /// set of template arguments. + /// + /// \param Converted Will receive the converted, canonicalized template + /// arguments. + /// + /// \returns true if an error occurred, false otherwise. + bool CheckTemplateArgumentList(TemplateDecl *Template, + SourceLocation TemplateLoc, + TemplateArgumentListInfo &TemplateArgs, + bool PartialTemplateArgs, + SmallVectorImpl<TemplateArgument> &Converted); + + bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, + TemplateArgumentLoc &Arg, + SmallVectorImpl<TemplateArgument> &Converted); + + bool CheckTemplateArgument(TemplateTypeParmDecl *Param, + TypeSourceInfo *Arg); + ExprResult CheckTemplateArgument(NonTypeTemplateParmDecl *Param, + QualType InstantiatedParamType, Expr *Arg, + TemplateArgument &Converted, + CheckTemplateArgumentKind CTAK = CTAK_Specified); + bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, + TemplateArgumentLoc &Arg, + unsigned ArgumentPackIndex); + + ExprResult + BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, + QualType ParamType, + SourceLocation Loc); + ExprResult + BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, + SourceLocation Loc); + + /// \brief Enumeration describing how template parameter lists are compared + /// for equality. + enum TemplateParameterListEqualKind { + /// \brief We are matching the template parameter lists of two templates + /// that might be redeclarations. + /// + /// \code + /// template<typename T> struct X; + /// template<typename T> struct X; + /// \endcode + TPL_TemplateMatch, + + /// \brief We are matching the template parameter lists of two template + /// template parameters as part of matching the template parameter lists + /// of two templates that might be redeclarations. + /// + /// \code + /// template<template<int I> class TT> struct X; + /// template<template<int Value> class Other> struct X; + /// \endcode + TPL_TemplateTemplateParmMatch, + + /// \brief We are matching the template parameter lists of a template + /// template argument against the template parameter lists of a template + /// template parameter. + /// + /// \code + /// template<template<int Value> class Metafun> struct X; + /// template<int Value> struct integer_c; + /// X<integer_c> xic; + /// \endcode + TPL_TemplateTemplateArgumentMatch + }; + + bool TemplateParameterListsAreEqual(TemplateParameterList *New, + TemplateParameterList *Old, + bool Complain, + TemplateParameterListEqualKind Kind, + SourceLocation TemplateArgLoc + = SourceLocation()); + + bool CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams); + + /// \brief Called when the parser has parsed a C++ typename + /// specifier, e.g., "typename T::type". + /// + /// \param S The scope in which this typename type occurs. + /// \param TypenameLoc the location of the 'typename' keyword + /// \param SS the nested-name-specifier following the typename (e.g., 'T::'). + /// \param II the identifier we're retrieving (e.g., 'type' in the example). + /// \param IdLoc the location of the identifier. + TypeResult + ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, + const CXXScopeSpec &SS, const IdentifierInfo &II, + SourceLocation IdLoc); + + /// \brief Called when the parser has parsed a C++ typename + /// specifier that ends in a template-id, e.g., + /// "typename MetaFun::template apply<T1, T2>". + /// + /// \param S The scope in which this typename type occurs. + /// \param TypenameLoc the location of the 'typename' keyword + /// \param SS the nested-name-specifier following the typename (e.g., 'T::'). + /// \param TemplateLoc the location of the 'template' keyword, if any. + /// \param TemplateName The template name. + /// \param TemplateNameLoc The location of the template name. + /// \param LAngleLoc The location of the opening angle bracket ('<'). + /// \param TemplateArgs The template arguments. + /// \param RAngleLoc The location of the closing angle bracket ('>'). + TypeResult + ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, + const CXXScopeSpec &SS, + SourceLocation TemplateLoc, + TemplateTy TemplateName, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgs, + SourceLocation RAngleLoc); + + QualType CheckTypenameType(ElaboratedTypeKeyword Keyword, + SourceLocation KeywordLoc, + NestedNameSpecifierLoc QualifierLoc, + const IdentifierInfo &II, + SourceLocation IILoc); + + TypeSourceInfo *RebuildTypeInCurrentInstantiation(TypeSourceInfo *T, + SourceLocation Loc, + DeclarationName Name); + bool RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS); + + ExprResult RebuildExprInCurrentInstantiation(Expr *E); + bool RebuildTemplateParamsInCurrentInstantiation( + TemplateParameterList *Params); + + std::string + getTemplateArgumentBindingsText(const TemplateParameterList *Params, + const TemplateArgumentList &Args); + + std::string + getTemplateArgumentBindingsText(const TemplateParameterList *Params, + const TemplateArgument *Args, + unsigned NumArgs); + + //===--------------------------------------------------------------------===// + // C++ Variadic Templates (C++0x [temp.variadic]) + //===--------------------------------------------------------------------===// + + /// Determine whether an unexpanded parameter pack might be permitted in this + /// location. Useful for error recovery. + bool isUnexpandedParameterPackPermitted(); + + /// \brief The context in which an unexpanded parameter pack is + /// being diagnosed. + /// + /// Note that the values of this enumeration line up with the first + /// argument to the \c err_unexpanded_parameter_pack diagnostic. + enum UnexpandedParameterPackContext { + /// \brief An arbitrary expression. + UPPC_Expression = 0, + + /// \brief The base type of a class type. + UPPC_BaseType, + + /// \brief The type of an arbitrary declaration. + UPPC_DeclarationType, + + /// \brief The type of a data member. + UPPC_DataMemberType, + + /// \brief The size of a bit-field. + UPPC_BitFieldWidth, + + /// \brief The expression in a static assertion. + UPPC_StaticAssertExpression, + + /// \brief The fixed underlying type of an enumeration. + UPPC_FixedUnderlyingType, + + /// \brief The enumerator value. + UPPC_EnumeratorValue, + + /// \brief A using declaration. + UPPC_UsingDeclaration, + + /// \brief A friend declaration. + UPPC_FriendDeclaration, + + /// \brief A declaration qualifier. + UPPC_DeclarationQualifier, + + /// \brief An initializer. + UPPC_Initializer, + + /// \brief A default argument. + UPPC_DefaultArgument, + + /// \brief The type of a non-type template parameter. + UPPC_NonTypeTemplateParameterType, + + /// \brief The type of an exception. + UPPC_ExceptionType, + + /// \brief Partial specialization. + UPPC_PartialSpecialization, + + /// \brief Microsoft __if_exists. + UPPC_IfExists, + + /// \brief Microsoft __if_not_exists. + UPPC_IfNotExists, + + /// \brief Lambda expression. + UPPC_Lambda, + + /// \brief Block expression, + UPPC_Block + }; + + /// \brief Diagnose unexpanded parameter packs. + /// + /// \param Loc The location at which we should emit the diagnostic. + /// + /// \param UPPC The context in which we are diagnosing unexpanded + /// parameter packs. + /// + /// \param Unexpanded the set of unexpanded parameter packs. + /// + /// \returns true if an error occurred, false otherwise. + bool DiagnoseUnexpandedParameterPacks(SourceLocation Loc, + UnexpandedParameterPackContext UPPC, + ArrayRef<UnexpandedParameterPack> Unexpanded); + + /// \brief If the given type contains an unexpanded parameter pack, + /// diagnose the error. + /// + /// \param Loc The source location where a diagnostc should be emitted. + /// + /// \param T The type that is being checked for unexpanded parameter + /// packs. + /// + /// \returns true if an error occurred, false otherwise. + bool DiagnoseUnexpandedParameterPack(SourceLocation Loc, TypeSourceInfo *T, + UnexpandedParameterPackContext UPPC); + + /// \brief If the given expression contains an unexpanded parameter + /// pack, diagnose the error. + /// + /// \param E The expression that is being checked for unexpanded + /// parameter packs. + /// + /// \returns true if an error occurred, false otherwise. + bool DiagnoseUnexpandedParameterPack(Expr *E, + UnexpandedParameterPackContext UPPC = UPPC_Expression); + + /// \brief If the given nested-name-specifier contains an unexpanded + /// parameter pack, diagnose the error. + /// + /// \param SS The nested-name-specifier that is being checked for + /// unexpanded parameter packs. + /// + /// \returns true if an error occurred, false otherwise. + bool DiagnoseUnexpandedParameterPack(const CXXScopeSpec &SS, + UnexpandedParameterPackContext UPPC); + + /// \brief If the given name contains an unexpanded parameter pack, + /// diagnose the error. + /// + /// \param NameInfo The name (with source location information) that + /// is being checked for unexpanded parameter packs. + /// + /// \returns true if an error occurred, false otherwise. + bool DiagnoseUnexpandedParameterPack(const DeclarationNameInfo &NameInfo, + UnexpandedParameterPackContext UPPC); + + /// \brief If the given template name contains an unexpanded parameter pack, + /// diagnose the error. + /// + /// \param Loc The location of the template name. + /// + /// \param Template The template name that is being checked for unexpanded + /// parameter packs. + /// + /// \returns true if an error occurred, false otherwise. + bool DiagnoseUnexpandedParameterPack(SourceLocation Loc, + TemplateName Template, + UnexpandedParameterPackContext UPPC); + + /// \brief If the given template argument contains an unexpanded parameter + /// pack, diagnose the error. + /// + /// \param Arg The template argument that is being checked for unexpanded + /// parameter packs. + /// + /// \returns true if an error occurred, false otherwise. + bool DiagnoseUnexpandedParameterPack(TemplateArgumentLoc Arg, + UnexpandedParameterPackContext UPPC); + + /// \brief Collect the set of unexpanded parameter packs within the given + /// template argument. + /// + /// \param Arg The template argument that will be traversed to find + /// unexpanded parameter packs. + void collectUnexpandedParameterPacks(TemplateArgument Arg, + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); + + /// \brief Collect the set of unexpanded parameter packs within the given + /// template argument. + /// + /// \param Arg The template argument that will be traversed to find + /// unexpanded parameter packs. + void collectUnexpandedParameterPacks(TemplateArgumentLoc Arg, + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); + + /// \brief Collect the set of unexpanded parameter packs within the given + /// type. + /// + /// \param T The type that will be traversed to find + /// unexpanded parameter packs. + void collectUnexpandedParameterPacks(QualType T, + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); + + /// \brief Collect the set of unexpanded parameter packs within the given + /// type. + /// + /// \param TL The type that will be traversed to find + /// unexpanded parameter packs. + void collectUnexpandedParameterPacks(TypeLoc TL, + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); + + /// \brief Collect the set of unexpanded parameter packs within the given + /// nested-name-specifier. + /// + /// \param SS The nested-name-specifier that will be traversed to find + /// unexpanded parameter packs. + void collectUnexpandedParameterPacks(CXXScopeSpec &SS, + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); + + /// \brief Collect the set of unexpanded parameter packs within the given + /// name. + /// + /// \param NameInfo The name that will be traversed to find + /// unexpanded parameter packs. + void collectUnexpandedParameterPacks(const DeclarationNameInfo &NameInfo, + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); + + /// \brief Invoked when parsing a template argument followed by an + /// ellipsis, which creates a pack expansion. + /// + /// \param Arg The template argument preceding the ellipsis, which + /// may already be invalid. + /// + /// \param EllipsisLoc The location of the ellipsis. + ParsedTemplateArgument ActOnPackExpansion(const ParsedTemplateArgument &Arg, + SourceLocation EllipsisLoc); + + /// \brief Invoked when parsing a type followed by an ellipsis, which + /// creates a pack expansion. + /// + /// \param Type The type preceding the ellipsis, which will become + /// the pattern of the pack expansion. + /// + /// \param EllipsisLoc The location of the ellipsis. + TypeResult ActOnPackExpansion(ParsedType Type, SourceLocation EllipsisLoc); + + /// \brief Construct a pack expansion type from the pattern of the pack + /// expansion. + TypeSourceInfo *CheckPackExpansion(TypeSourceInfo *Pattern, + SourceLocation EllipsisLoc, + Optional<unsigned> NumExpansions); + + /// \brief Construct a pack expansion type from the pattern of the pack + /// expansion. + QualType CheckPackExpansion(QualType Pattern, + SourceRange PatternRange, + SourceLocation EllipsisLoc, + Optional<unsigned> NumExpansions); + + /// \brief Invoked when parsing an expression followed by an ellipsis, which + /// creates a pack expansion. + /// + /// \param Pattern The expression preceding the ellipsis, which will become + /// the pattern of the pack expansion. + /// + /// \param EllipsisLoc The location of the ellipsis. + ExprResult ActOnPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc); + + /// \brief Invoked when parsing an expression followed by an ellipsis, which + /// creates a pack expansion. + /// + /// \param Pattern The expression preceding the ellipsis, which will become + /// the pattern of the pack expansion. + /// + /// \param EllipsisLoc The location of the ellipsis. + ExprResult CheckPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc, + Optional<unsigned> NumExpansions); + + /// \brief Determine whether we could expand a pack expansion with the + /// given set of parameter packs into separate arguments by repeatedly + /// transforming the pattern. + /// + /// \param EllipsisLoc The location of the ellipsis that identifies the + /// pack expansion. + /// + /// \param PatternRange The source range that covers the entire pattern of + /// the pack expansion. + /// + /// \param Unexpanded The set of unexpanded parameter packs within the + /// pattern. + /// + /// \param ShouldExpand Will be set to \c true if the transformer should + /// expand the corresponding pack expansions into separate arguments. When + /// set, \c NumExpansions must also be set. + /// + /// \param RetainExpansion Whether the caller should add an unexpanded + /// pack expansion after all of the expanded arguments. This is used + /// when extending explicitly-specified template argument packs per + /// C++0x [temp.arg.explicit]p9. + /// + /// \param NumExpansions The number of separate arguments that will be in + /// the expanded form of the corresponding pack expansion. This is both an + /// input and an output parameter, which can be set by the caller if the + /// number of expansions is known a priori (e.g., due to a prior substitution) + /// and will be set by the callee when the number of expansions is known. + /// The callee must set this value when \c ShouldExpand is \c true; it may + /// set this value in other cases. + /// + /// \returns true if an error occurred (e.g., because the parameter packs + /// are to be instantiated with arguments of different lengths), false + /// otherwise. If false, \c ShouldExpand (and possibly \c NumExpansions) + /// must be set. + bool CheckParameterPacksForExpansion(SourceLocation EllipsisLoc, + SourceRange PatternRange, + ArrayRef<UnexpandedParameterPack> Unexpanded, + const MultiLevelTemplateArgumentList &TemplateArgs, + bool &ShouldExpand, + bool &RetainExpansion, + Optional<unsigned> &NumExpansions); + + /// \brief Determine the number of arguments in the given pack expansion + /// type. + /// + /// This routine assumes that the number of arguments in the expansion is + /// consistent across all of the unexpanded parameter packs in its pattern. + /// + /// Returns an empty Optional if the type can't be expanded. + Optional<unsigned> getNumArgumentsInExpansion(QualType T, + const MultiLevelTemplateArgumentList &TemplateArgs); + + /// \brief Determine whether the given declarator contains any unexpanded + /// parameter packs. + /// + /// This routine is used by the parser to disambiguate function declarators + /// with an ellipsis prior to the ')', e.g., + /// + /// \code + /// void f(T...); + /// \endcode + /// + /// To determine whether we have an (unnamed) function parameter pack or + /// a variadic function. + /// + /// \returns true if the declarator contains any unexpanded parameter packs, + /// false otherwise. + bool containsUnexpandedParameterPacks(Declarator &D); + + /// \brief Returns the pattern of the pack expansion for a template argument. + /// + /// \param OrigLoc The template argument to expand. + /// + /// \param Ellipsis Will be set to the location of the ellipsis. + /// + /// \param NumExpansions Will be set to the number of expansions that will + /// be generated from this pack expansion, if known a priori. + TemplateArgumentLoc getTemplateArgumentPackExpansionPattern( + TemplateArgumentLoc OrigLoc, + SourceLocation &Ellipsis, + Optional<unsigned> &NumExpansions) const; + + //===--------------------------------------------------------------------===// + // C++ Template Argument Deduction (C++ [temp.deduct]) + //===--------------------------------------------------------------------===// + + QualType adjustCCAndNoReturn(QualType ArgFunctionType, QualType FunctionType); + + /// \brief Describes the result of template argument deduction. + /// + /// The TemplateDeductionResult enumeration describes the result of + /// template argument deduction, as returned from + /// DeduceTemplateArguments(). The separate TemplateDeductionInfo + /// structure provides additional information about the results of + /// template argument deduction, e.g., the deduced template argument + /// list (if successful) or the specific template parameters or + /// deduced arguments that were involved in the failure. + enum TemplateDeductionResult { + /// \brief Template argument deduction was successful. + TDK_Success = 0, + /// \brief The declaration was invalid; do nothing. + TDK_Invalid, + /// \brief Template argument deduction exceeded the maximum template + /// instantiation depth (which has already been diagnosed). + TDK_InstantiationDepth, + /// \brief Template argument deduction did not deduce a value + /// for every template parameter. + TDK_Incomplete, + /// \brief Template argument deduction produced inconsistent + /// deduced values for the given template parameter. + TDK_Inconsistent, + /// \brief Template argument deduction failed due to inconsistent + /// cv-qualifiers on a template parameter type that would + /// otherwise be deduced, e.g., we tried to deduce T in "const T" + /// but were given a non-const "X". + TDK_Underqualified, + /// \brief Substitution of the deduced template argument values + /// resulted in an error. + TDK_SubstitutionFailure, + /// \brief After substituting deduced template arguments, a dependent + /// parameter type did not match the corresponding argument. + TDK_DeducedMismatch, + /// \brief A non-depnedent component of the parameter did not match the + /// corresponding component of the argument. + TDK_NonDeducedMismatch, + /// \brief When performing template argument deduction for a function + /// template, there were too many call arguments. + TDK_TooManyArguments, + /// \brief When performing template argument deduction for a function + /// template, there were too few call arguments. + TDK_TooFewArguments, + /// \brief The explicitly-specified template arguments were not valid + /// template arguments for the given template. + TDK_InvalidExplicitArguments, + /// \brief The arguments included an overloaded function name that could + /// not be resolved to a suitable function. + TDK_FailedOverloadResolution, + /// \brief Deduction failed; that's all we know. + TDK_MiscellaneousDeductionFailure + }; + + TemplateDeductionResult + DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, + const TemplateArgumentList &TemplateArgs, + sema::TemplateDeductionInfo &Info); + + TemplateDeductionResult + DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial, + const TemplateArgumentList &TemplateArgs, + sema::TemplateDeductionInfo &Info); + + TemplateDeductionResult SubstituteExplicitTemplateArguments( + FunctionTemplateDecl *FunctionTemplate, + TemplateArgumentListInfo &ExplicitTemplateArgs, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, + SmallVectorImpl<QualType> &ParamTypes, QualType *FunctionType, + sema::TemplateDeductionInfo &Info); + + /// brief A function argument from which we performed template argument + // deduction for a call. + struct OriginalCallArg { + OriginalCallArg(QualType OriginalParamType, + unsigned ArgIdx, + QualType OriginalArgType) + : OriginalParamType(OriginalParamType), ArgIdx(ArgIdx), + OriginalArgType(OriginalArgType) { } + + QualType OriginalParamType; + unsigned ArgIdx; + QualType OriginalArgType; + }; + + TemplateDeductionResult + FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, + unsigned NumExplicitlySpecified, + FunctionDecl *&Specialization, + sema::TemplateDeductionInfo &Info, + SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs = nullptr, + bool PartialOverloading = false); + + TemplateDeductionResult + DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, + TemplateArgumentListInfo *ExplicitTemplateArgs, + ArrayRef<Expr *> Args, + FunctionDecl *&Specialization, + sema::TemplateDeductionInfo &Info, + bool PartialOverloading = false); + + TemplateDeductionResult + DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, + TemplateArgumentListInfo *ExplicitTemplateArgs, + QualType ArgFunctionType, + FunctionDecl *&Specialization, + sema::TemplateDeductionInfo &Info, + bool InOverloadResolution = false); + + TemplateDeductionResult + DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, + QualType ToType, + CXXConversionDecl *&Specialization, + sema::TemplateDeductionInfo &Info); + + TemplateDeductionResult + DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, + TemplateArgumentListInfo *ExplicitTemplateArgs, + FunctionDecl *&Specialization, + sema::TemplateDeductionInfo &Info, + bool InOverloadResolution = false); + + /// \brief Substitute Replacement for \p auto in \p TypeWithAuto + QualType SubstAutoType(QualType TypeWithAuto, QualType Replacement); + /// \brief Substitute Replacement for auto in TypeWithAuto + TypeSourceInfo* SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto, + QualType Replacement); + + /// \brief Result type of DeduceAutoType. + enum DeduceAutoResult { + DAR_Succeeded, + DAR_Failed, + DAR_FailedAlreadyDiagnosed + }; + + DeduceAutoResult DeduceAutoType(TypeSourceInfo *AutoType, Expr *&Initializer, + QualType &Result); + DeduceAutoResult DeduceAutoType(TypeLoc AutoTypeLoc, Expr *&Initializer, + QualType &Result); + void DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init); + bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc, + bool Diagnose = true); + + QualType deduceVarTypeFromInitializer(VarDecl *VDecl, DeclarationName Name, + QualType Type, TypeSourceInfo *TSI, + SourceRange Range, bool DirectInit, + Expr *Init); + + TypeLoc getReturnTypeLoc(FunctionDecl *FD) const; + + bool DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, + SourceLocation ReturnLoc, + Expr *&RetExpr, AutoType *AT); + + FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, + FunctionTemplateDecl *FT2, + SourceLocation Loc, + TemplatePartialOrderingContext TPOC, + unsigned NumCallArguments1, + unsigned NumCallArguments2); + UnresolvedSetIterator + getMostSpecialized(UnresolvedSetIterator SBegin, UnresolvedSetIterator SEnd, + TemplateSpecCandidateSet &FailedCandidates, + SourceLocation Loc, + const PartialDiagnostic &NoneDiag, + const PartialDiagnostic &AmbigDiag, + const PartialDiagnostic &CandidateDiag, + bool Complain = true, QualType TargetType = QualType()); + + ClassTemplatePartialSpecializationDecl * + getMoreSpecializedPartialSpecialization( + ClassTemplatePartialSpecializationDecl *PS1, + ClassTemplatePartialSpecializationDecl *PS2, + SourceLocation Loc); + + VarTemplatePartialSpecializationDecl *getMoreSpecializedPartialSpecialization( + VarTemplatePartialSpecializationDecl *PS1, + VarTemplatePartialSpecializationDecl *PS2, SourceLocation Loc); + + void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, + bool OnlyDeduced, + unsigned Depth, + llvm::SmallBitVector &Used); + void MarkDeducedTemplateParameters( + const FunctionTemplateDecl *FunctionTemplate, + llvm::SmallBitVector &Deduced) { + return MarkDeducedTemplateParameters(Context, FunctionTemplate, Deduced); + } + static void MarkDeducedTemplateParameters(ASTContext &Ctx, + const FunctionTemplateDecl *FunctionTemplate, + llvm::SmallBitVector &Deduced); + + //===--------------------------------------------------------------------===// + // C++ Template Instantiation + // + + MultiLevelTemplateArgumentList + getTemplateInstantiationArgs(NamedDecl *D, + const TemplateArgumentList *Innermost = nullptr, + bool RelativeToPrimary = false, + const FunctionDecl *Pattern = nullptr); + + /// \brief A template instantiation that is currently in progress. + struct ActiveTemplateInstantiation { + /// \brief The kind of template instantiation we are performing + enum InstantiationKind { + /// We are instantiating a template declaration. The entity is + /// the declaration we're instantiating (e.g., a CXXRecordDecl). + TemplateInstantiation, + + /// We are instantiating a default argument for a template + /// parameter. The Entity is the template, and + /// TemplateArgs/NumTemplateArguments provides the template + /// arguments as specified. + /// FIXME: Use a TemplateArgumentList + DefaultTemplateArgumentInstantiation, + + /// We are instantiating a default argument for a function. + /// The Entity is the ParmVarDecl, and TemplateArgs/NumTemplateArgs + /// provides the template arguments as specified. + DefaultFunctionArgumentInstantiation, + + /// We are substituting explicit template arguments provided for + /// a function template. The entity is a FunctionTemplateDecl. + ExplicitTemplateArgumentSubstitution, + + /// We are substituting template argument determined as part of + /// template argument deduction for either a class template + /// partial specialization or a function template. The + /// Entity is either a ClassTemplatePartialSpecializationDecl or + /// a FunctionTemplateDecl. + DeducedTemplateArgumentSubstitution, + + /// We are substituting prior template arguments into a new + /// template parameter. The template parameter itself is either a + /// NonTypeTemplateParmDecl or a TemplateTemplateParmDecl. + PriorTemplateArgumentSubstitution, + + /// We are checking the validity of a default template argument that + /// has been used when naming a template-id. + DefaultTemplateArgumentChecking, + + /// We are instantiating the exception specification for a function + /// template which was deferred until it was needed. + ExceptionSpecInstantiation + } Kind; + + /// \brief The point of instantiation within the source code. + SourceLocation PointOfInstantiation; + + /// \brief The template (or partial specialization) in which we are + /// performing the instantiation, for substitutions of prior template + /// arguments. + NamedDecl *Template; + + /// \brief The entity that is being instantiated. + Decl *Entity; + + /// \brief The list of template arguments we are substituting, if they + /// are not part of the entity. + const TemplateArgument *TemplateArgs; + + /// \brief The number of template arguments in TemplateArgs. + unsigned NumTemplateArgs; + + /// \brief The template deduction info object associated with the + /// substitution or checking of explicit or deduced template arguments. + sema::TemplateDeductionInfo *DeductionInfo; + + /// \brief The source range that covers the construct that cause + /// the instantiation, e.g., the template-id that causes a class + /// template instantiation. + SourceRange InstantiationRange; + + ActiveTemplateInstantiation() + : Kind(TemplateInstantiation), Template(nullptr), Entity(nullptr), + TemplateArgs(nullptr), NumTemplateArgs(0), DeductionInfo(nullptr) {} + + /// \brief Determines whether this template is an actual instantiation + /// that should be counted toward the maximum instantiation depth. + bool isInstantiationRecord() const; + + friend bool operator==(const ActiveTemplateInstantiation &X, + const ActiveTemplateInstantiation &Y) { + if (X.Kind != Y.Kind) + return false; + + if (X.Entity != Y.Entity) + return false; + + switch (X.Kind) { + case TemplateInstantiation: + case ExceptionSpecInstantiation: + return true; + + case PriorTemplateArgumentSubstitution: + case DefaultTemplateArgumentChecking: + return X.Template == Y.Template && X.TemplateArgs == Y.TemplateArgs; + + case DefaultTemplateArgumentInstantiation: + case ExplicitTemplateArgumentSubstitution: + case DeducedTemplateArgumentSubstitution: + case DefaultFunctionArgumentInstantiation: + return X.TemplateArgs == Y.TemplateArgs; + + } + + llvm_unreachable("Invalid InstantiationKind!"); + } + + friend bool operator!=(const ActiveTemplateInstantiation &X, + const ActiveTemplateInstantiation &Y) { + return !(X == Y); + } + }; + + /// \brief List of active template instantiations. + /// + /// This vector is treated as a stack. As one template instantiation + /// requires another template instantiation, additional + /// instantiations are pushed onto the stack up to a + /// user-configurable limit LangOptions::InstantiationDepth. + SmallVector<ActiveTemplateInstantiation, 16> + ActiveTemplateInstantiations; + + /// \brief Extra modules inspected when performing a lookup during a template + /// instantiation. Computed lazily. + SmallVector<Module*, 16> ActiveTemplateInstantiationLookupModules; + + /// \brief Cache of additional modules that should be used for name lookup + /// within the current template instantiation. Computed lazily; use + /// getLookupModules() to get a complete set. + llvm::DenseSet<Module*> LookupModulesCache; + + /// \brief Get the set of additional modules that should be checked during + /// name lookup. A module and its imports become visible when instanting a + /// template defined within it. + llvm::DenseSet<Module*> &getLookupModules(); + + /// \brief Whether we are in a SFINAE context that is not associated with + /// template instantiation. + /// + /// This is used when setting up a SFINAE trap (\c see SFINAETrap) outside + /// of a template instantiation or template argument deduction. + bool InNonInstantiationSFINAEContext; + + /// \brief The number of ActiveTemplateInstantiation entries in + /// \c ActiveTemplateInstantiations that are not actual instantiations and, + /// therefore, should not be counted as part of the instantiation depth. + unsigned NonInstantiationEntries; + + /// \brief The last template from which a template instantiation + /// error or warning was produced. + /// + /// This value is used to suppress printing of redundant template + /// instantiation backtraces when there are multiple errors in the + /// same instantiation. FIXME: Does this belong in Sema? It's tough + /// to implement it anywhere else. + ActiveTemplateInstantiation LastTemplateInstantiationErrorContext; + + /// \brief The current index into pack expansion arguments that will be + /// used for substitution of parameter packs. + /// + /// The pack expansion index will be -1 to indicate that parameter packs + /// should be instantiated as themselves. Otherwise, the index specifies + /// which argument within the parameter pack will be used for substitution. + int ArgumentPackSubstitutionIndex; + + /// \brief RAII object used to change the argument pack substitution index + /// within a \c Sema object. + /// + /// See \c ArgumentPackSubstitutionIndex for more information. + class ArgumentPackSubstitutionIndexRAII { + Sema &Self; + int OldSubstitutionIndex; + + public: + ArgumentPackSubstitutionIndexRAII(Sema &Self, int NewSubstitutionIndex) + : Self(Self), OldSubstitutionIndex(Self.ArgumentPackSubstitutionIndex) { + Self.ArgumentPackSubstitutionIndex = NewSubstitutionIndex; + } + + ~ArgumentPackSubstitutionIndexRAII() { + Self.ArgumentPackSubstitutionIndex = OldSubstitutionIndex; + } + }; + + friend class ArgumentPackSubstitutionRAII; + + /// \brief For each declaration that involved template argument deduction, the + /// set of diagnostics that were suppressed during that template argument + /// deduction. + /// + /// FIXME: Serialize this structure to the AST file. + typedef llvm::DenseMap<Decl *, SmallVector<PartialDiagnosticAt, 1> > + SuppressedDiagnosticsMap; + SuppressedDiagnosticsMap SuppressedDiagnostics; + + /// \brief A stack object to be created when performing template + /// instantiation. + /// + /// Construction of an object of type \c InstantiatingTemplate + /// pushes the current instantiation onto the stack of active + /// instantiations. If the size of this stack exceeds the maximum + /// number of recursive template instantiations, construction + /// produces an error and evaluates true. + /// + /// Destruction of this object will pop the named instantiation off + /// the stack. + struct InstantiatingTemplate { + /// \brief Note that we are instantiating a class template, + /// function template, variable template, alias template, + /// or a member thereof. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + Decl *Entity, + SourceRange InstantiationRange = SourceRange()); + + struct ExceptionSpecification {}; + /// \brief Note that we are instantiating an exception specification + /// of a function template. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + FunctionDecl *Entity, ExceptionSpecification, + SourceRange InstantiationRange = SourceRange()); + + /// \brief Note that we are instantiating a default argument in a + /// template-id. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + TemplateDecl *Template, + ArrayRef<TemplateArgument> TemplateArgs, + SourceRange InstantiationRange = SourceRange()); + + /// \brief Note that we are instantiating a default argument in a + /// template-id. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + FunctionTemplateDecl *FunctionTemplate, + ArrayRef<TemplateArgument> TemplateArgs, + ActiveTemplateInstantiation::InstantiationKind Kind, + sema::TemplateDeductionInfo &DeductionInfo, + SourceRange InstantiationRange = SourceRange()); + + /// \brief Note that we are instantiating as part of template + /// argument deduction for a class template partial + /// specialization. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + ClassTemplatePartialSpecializationDecl *PartialSpec, + ArrayRef<TemplateArgument> TemplateArgs, + sema::TemplateDeductionInfo &DeductionInfo, + SourceRange InstantiationRange = SourceRange()); + + /// \brief Note that we are instantiating as part of template + /// argument deduction for a variable template partial + /// specialization. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + VarTemplatePartialSpecializationDecl *PartialSpec, + ArrayRef<TemplateArgument> TemplateArgs, + sema::TemplateDeductionInfo &DeductionInfo, + SourceRange InstantiationRange = SourceRange()); + + /// \brief Note that we are instantiating a default argument for a function + /// parameter. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + ParmVarDecl *Param, + ArrayRef<TemplateArgument> TemplateArgs, + SourceRange InstantiationRange = SourceRange()); + + /// \brief Note that we are substituting prior template arguments into a + /// non-type parameter. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + NamedDecl *Template, + NonTypeTemplateParmDecl *Param, + ArrayRef<TemplateArgument> TemplateArgs, + SourceRange InstantiationRange); + + /// \brief Note that we are substituting prior template arguments into a + /// template template parameter. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + NamedDecl *Template, + TemplateTemplateParmDecl *Param, + ArrayRef<TemplateArgument> TemplateArgs, + SourceRange InstantiationRange); + + /// \brief Note that we are checking the default template argument + /// against the template parameter for a given template-id. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + TemplateDecl *Template, + NamedDecl *Param, + ArrayRef<TemplateArgument> TemplateArgs, + SourceRange InstantiationRange); + + + /// \brief Note that we have finished instantiating this template. + void Clear(); + + ~InstantiatingTemplate() { Clear(); } + + /// \brief Determines whether we have exceeded the maximum + /// recursive template instantiations. + bool isInvalid() const { return Invalid; } + + private: + Sema &SemaRef; + bool Invalid; + bool SavedInNonInstantiationSFINAEContext; + bool CheckInstantiationDepth(SourceLocation PointOfInstantiation, + SourceRange InstantiationRange); + + InstantiatingTemplate( + Sema &SemaRef, ActiveTemplateInstantiation::InstantiationKind Kind, + SourceLocation PointOfInstantiation, SourceRange InstantiationRange, + Decl *Entity, NamedDecl *Template = nullptr, + ArrayRef<TemplateArgument> TemplateArgs = None, + sema::TemplateDeductionInfo *DeductionInfo = nullptr); + + InstantiatingTemplate(const InstantiatingTemplate&) = delete; + + InstantiatingTemplate& + operator=(const InstantiatingTemplate&) = delete; + }; + + void PrintInstantiationStack(); + + /// \brief Determines whether we are currently in a context where + /// template argument substitution failures are not considered + /// errors. + /// + /// \returns An empty \c Optional if we're not in a SFINAE context. + /// Otherwise, contains a pointer that, if non-NULL, contains the nearest + /// template-deduction context object, which can be used to capture + /// diagnostics that will be suppressed. + Optional<sema::TemplateDeductionInfo *> isSFINAEContext() const; + + /// \brief Determines whether we are currently in a context that + /// is not evaluated as per C++ [expr] p5. + bool isUnevaluatedContext() const { + assert(!ExprEvalContexts.empty() && + "Must be in an expression evaluation context"); + return ExprEvalContexts.back().isUnevaluated(); + } + + /// \brief RAII class used to determine whether SFINAE has + /// trapped any errors that occur during template argument + /// deduction. + class SFINAETrap { + Sema &SemaRef; + unsigned PrevSFINAEErrors; + bool PrevInNonInstantiationSFINAEContext; + bool PrevAccessCheckingSFINAE; + + public: + explicit SFINAETrap(Sema &SemaRef, bool AccessCheckingSFINAE = false) + : SemaRef(SemaRef), PrevSFINAEErrors(SemaRef.NumSFINAEErrors), + PrevInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext), + PrevAccessCheckingSFINAE(SemaRef.AccessCheckingSFINAE) + { + if (!SemaRef.isSFINAEContext()) + SemaRef.InNonInstantiationSFINAEContext = true; + SemaRef.AccessCheckingSFINAE = AccessCheckingSFINAE; + } + + ~SFINAETrap() { + SemaRef.NumSFINAEErrors = PrevSFINAEErrors; + SemaRef.InNonInstantiationSFINAEContext + = PrevInNonInstantiationSFINAEContext; + SemaRef.AccessCheckingSFINAE = PrevAccessCheckingSFINAE; + } + + /// \brief Determine whether any SFINAE errors have been trapped. + bool hasErrorOccurred() const { + return SemaRef.NumSFINAEErrors > PrevSFINAEErrors; + } + }; + + /// \brief RAII class used to indicate that we are performing provisional + /// semantic analysis to determine the validity of a construct, so + /// typo-correction and diagnostics in the immediate context (not within + /// implicitly-instantiated templates) should be suppressed. + class TentativeAnalysisScope { + Sema &SemaRef; + // FIXME: Using a SFINAETrap for this is a hack. + SFINAETrap Trap; + bool PrevDisableTypoCorrection; + public: + explicit TentativeAnalysisScope(Sema &SemaRef) + : SemaRef(SemaRef), Trap(SemaRef, true), + PrevDisableTypoCorrection(SemaRef.DisableTypoCorrection) { + SemaRef.DisableTypoCorrection = true; + } + ~TentativeAnalysisScope() { + SemaRef.DisableTypoCorrection = PrevDisableTypoCorrection; + } + }; + + /// \brief The current instantiation scope used to store local + /// variables. + LocalInstantiationScope *CurrentInstantiationScope; + + /// \brief Tracks whether we are in a context where typo correction is + /// disabled. + bool DisableTypoCorrection; + + /// \brief The number of typos corrected by CorrectTypo. + unsigned TyposCorrected; + + typedef llvm::SmallSet<SourceLocation, 2> SrcLocSet; + typedef llvm::DenseMap<IdentifierInfo *, SrcLocSet> IdentifierSourceLocations; + + /// \brief A cache containing identifiers for which typo correction failed and + /// their locations, so that repeated attempts to correct an identifier in a + /// given location are ignored if typo correction already failed for it. + IdentifierSourceLocations TypoCorrectionFailures; + + /// \brief Worker object for performing CFG-based warnings. + sema::AnalysisBasedWarnings AnalysisWarnings; + threadSafety::BeforeSet *ThreadSafetyDeclCache; + + /// \brief An entity for which implicit template instantiation is required. + /// + /// The source location associated with the declaration is the first place in + /// the source code where the declaration was "used". It is not necessarily + /// the point of instantiation (which will be either before or after the + /// namespace-scope declaration that triggered this implicit instantiation), + /// However, it is the location that diagnostics should generally refer to, + /// because users will need to know what code triggered the instantiation. + typedef std::pair<ValueDecl *, SourceLocation> PendingImplicitInstantiation; + + /// \brief The queue of implicit template instantiations that are required + /// but have not yet been performed. + std::deque<PendingImplicitInstantiation> PendingInstantiations; + + class SavePendingInstantiationsAndVTableUsesRAII { + public: + SavePendingInstantiationsAndVTableUsesRAII(Sema &S, bool Enabled) + : S(S), Enabled(Enabled) { + if (!Enabled) return; + + SavedPendingInstantiations.swap(S.PendingInstantiations); + SavedVTableUses.swap(S.VTableUses); + } + + ~SavePendingInstantiationsAndVTableUsesRAII() { + if (!Enabled) return; + + // Restore the set of pending vtables. + assert(S.VTableUses.empty() && + "VTableUses should be empty before it is discarded."); + S.VTableUses.swap(SavedVTableUses); + + // Restore the set of pending implicit instantiations. + assert(S.PendingInstantiations.empty() && + "PendingInstantiations should be empty before it is discarded."); + S.PendingInstantiations.swap(SavedPendingInstantiations); + } + + private: + Sema &S; + SmallVector<VTableUse, 16> SavedVTableUses; + std::deque<PendingImplicitInstantiation> SavedPendingInstantiations; + bool Enabled; + }; + + /// \brief The queue of implicit template instantiations that are required + /// and must be performed within the current local scope. + /// + /// This queue is only used for member functions of local classes in + /// templates, which must be instantiated in the same scope as their + /// enclosing function, so that they can reference function-local + /// types, static variables, enumerators, etc. + std::deque<PendingImplicitInstantiation> PendingLocalImplicitInstantiations; + + class SavePendingLocalImplicitInstantiationsRAII { + public: + SavePendingLocalImplicitInstantiationsRAII(Sema &S): S(S) { + SavedPendingLocalImplicitInstantiations.swap( + S.PendingLocalImplicitInstantiations); + } + + ~SavePendingLocalImplicitInstantiationsRAII() { + assert(S.PendingLocalImplicitInstantiations.empty() && + "there shouldn't be any pending local implicit instantiations"); + SavedPendingLocalImplicitInstantiations.swap( + S.PendingLocalImplicitInstantiations); + } + + private: + Sema &S; + std::deque<PendingImplicitInstantiation> + SavedPendingLocalImplicitInstantiations; + }; + + void PerformPendingInstantiations(bool LocalOnly = false); + + TypeSourceInfo *SubstType(TypeSourceInfo *T, + const MultiLevelTemplateArgumentList &TemplateArgs, + SourceLocation Loc, DeclarationName Entity); + + QualType SubstType(QualType T, + const MultiLevelTemplateArgumentList &TemplateArgs, + SourceLocation Loc, DeclarationName Entity); + + TypeSourceInfo *SubstType(TypeLoc TL, + const MultiLevelTemplateArgumentList &TemplateArgs, + SourceLocation Loc, DeclarationName Entity); + + TypeSourceInfo *SubstFunctionDeclType(TypeSourceInfo *T, + const MultiLevelTemplateArgumentList &TemplateArgs, + SourceLocation Loc, + DeclarationName Entity, + CXXRecordDecl *ThisContext, + unsigned ThisTypeQuals); + void SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto, + const MultiLevelTemplateArgumentList &Args); + ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D, + const MultiLevelTemplateArgumentList &TemplateArgs, + int indexAdjustment, + Optional<unsigned> NumExpansions, + bool ExpectParameterPack); + bool SubstParmTypes(SourceLocation Loc, + ParmVarDecl **Params, unsigned NumParams, + const MultiLevelTemplateArgumentList &TemplateArgs, + SmallVectorImpl<QualType> &ParamTypes, + SmallVectorImpl<ParmVarDecl *> *OutParams = nullptr); + ExprResult SubstExpr(Expr *E, + const MultiLevelTemplateArgumentList &TemplateArgs); + + /// \brief Substitute the given template arguments into a list of + /// expressions, expanding pack expansions if required. + /// + /// \param Exprs The list of expressions to substitute into. + /// + /// \param IsCall Whether this is some form of call, in which case + /// default arguments will be dropped. + /// + /// \param TemplateArgs The set of template arguments to substitute. + /// + /// \param Outputs Will receive all of the substituted arguments. + /// + /// \returns true if an error occurred, false otherwise. + bool SubstExprs(ArrayRef<Expr *> Exprs, bool IsCall, + const MultiLevelTemplateArgumentList &TemplateArgs, + SmallVectorImpl<Expr *> &Outputs); + + StmtResult SubstStmt(Stmt *S, + const MultiLevelTemplateArgumentList &TemplateArgs); + + Decl *SubstDecl(Decl *D, DeclContext *Owner, + const MultiLevelTemplateArgumentList &TemplateArgs); + + ExprResult SubstInitializer(Expr *E, + const MultiLevelTemplateArgumentList &TemplateArgs, + bool CXXDirectInit); + + bool + SubstBaseSpecifiers(CXXRecordDecl *Instantiation, + CXXRecordDecl *Pattern, + const MultiLevelTemplateArgumentList &TemplateArgs); + + bool + InstantiateClass(SourceLocation PointOfInstantiation, + CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, + const MultiLevelTemplateArgumentList &TemplateArgs, + TemplateSpecializationKind TSK, + bool Complain = true); + + bool InstantiateEnum(SourceLocation PointOfInstantiation, + EnumDecl *Instantiation, EnumDecl *Pattern, + const MultiLevelTemplateArgumentList &TemplateArgs, + TemplateSpecializationKind TSK); + + bool InstantiateInClassInitializer( + SourceLocation PointOfInstantiation, FieldDecl *Instantiation, + FieldDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs); + + struct LateInstantiatedAttribute { + const Attr *TmplAttr; + LocalInstantiationScope *Scope; + Decl *NewDecl; + + LateInstantiatedAttribute(const Attr *A, LocalInstantiationScope *S, + Decl *D) + : TmplAttr(A), Scope(S), NewDecl(D) + { } + }; + typedef SmallVector<LateInstantiatedAttribute, 16> LateInstantiatedAttrVec; + + void InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, + const Decl *Pattern, Decl *Inst, + LateInstantiatedAttrVec *LateAttrs = nullptr, + LocalInstantiationScope *OuterMostScope = nullptr); + + bool + InstantiateClassTemplateSpecialization(SourceLocation PointOfInstantiation, + ClassTemplateSpecializationDecl *ClassTemplateSpec, + TemplateSpecializationKind TSK, + bool Complain = true); + + void InstantiateClassMembers(SourceLocation PointOfInstantiation, + CXXRecordDecl *Instantiation, + const MultiLevelTemplateArgumentList &TemplateArgs, + TemplateSpecializationKind TSK); + + void InstantiateClassTemplateSpecializationMembers( + SourceLocation PointOfInstantiation, + ClassTemplateSpecializationDecl *ClassTemplateSpec, + TemplateSpecializationKind TSK); + + NestedNameSpecifierLoc + SubstNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS, + const MultiLevelTemplateArgumentList &TemplateArgs); + + DeclarationNameInfo + SubstDeclarationNameInfo(const DeclarationNameInfo &NameInfo, + const MultiLevelTemplateArgumentList &TemplateArgs); + TemplateName + SubstTemplateName(NestedNameSpecifierLoc QualifierLoc, TemplateName Name, + SourceLocation Loc, + const MultiLevelTemplateArgumentList &TemplateArgs); + bool Subst(const TemplateArgumentLoc *Args, unsigned NumArgs, + TemplateArgumentListInfo &Result, + const MultiLevelTemplateArgumentList &TemplateArgs); + + void InstantiateExceptionSpec(SourceLocation PointOfInstantiation, + FunctionDecl *Function); + void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, + FunctionDecl *Function, + bool Recursive = false, + bool DefinitionRequired = false); + VarTemplateSpecializationDecl *BuildVarTemplateInstantiation( + VarTemplateDecl *VarTemplate, VarDecl *FromVar, + const TemplateArgumentList &TemplateArgList, + const TemplateArgumentListInfo &TemplateArgsInfo, + SmallVectorImpl<TemplateArgument> &Converted, + SourceLocation PointOfInstantiation, void *InsertPos, + LateInstantiatedAttrVec *LateAttrs = nullptr, + LocalInstantiationScope *StartingScope = nullptr); + VarTemplateSpecializationDecl *CompleteVarTemplateSpecializationDecl( + VarTemplateSpecializationDecl *VarSpec, VarDecl *PatternDecl, + const MultiLevelTemplateArgumentList &TemplateArgs); + void + BuildVariableInstantiation(VarDecl *NewVar, VarDecl *OldVar, + const MultiLevelTemplateArgumentList &TemplateArgs, + LateInstantiatedAttrVec *LateAttrs, + DeclContext *Owner, + LocalInstantiationScope *StartingScope, + bool InstantiatingVarTemplate = false); + void InstantiateVariableInitializer( + VarDecl *Var, VarDecl *OldVar, + const MultiLevelTemplateArgumentList &TemplateArgs); + void InstantiateVariableDefinition(SourceLocation PointOfInstantiation, + VarDecl *Var, bool Recursive = false, + bool DefinitionRequired = false); + void InstantiateStaticDataMemberDefinition( + SourceLocation PointOfInstantiation, + VarDecl *Var, + bool Recursive = false, + bool DefinitionRequired = false); + + void InstantiateMemInitializers(CXXConstructorDecl *New, + const CXXConstructorDecl *Tmpl, + const MultiLevelTemplateArgumentList &TemplateArgs); + + NamedDecl *FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, + const MultiLevelTemplateArgumentList &TemplateArgs); + DeclContext *FindInstantiatedContext(SourceLocation Loc, DeclContext *DC, + const MultiLevelTemplateArgumentList &TemplateArgs); + + // Objective-C declarations. + enum ObjCContainerKind { + OCK_None = -1, + OCK_Interface = 0, + OCK_Protocol, + OCK_Category, + OCK_ClassExtension, + OCK_Implementation, + OCK_CategoryImplementation + }; + ObjCContainerKind getObjCContainerKind() const; + + DeclResult actOnObjCTypeParam(Scope *S, + ObjCTypeParamVariance variance, + SourceLocation varianceLoc, + unsigned index, + IdentifierInfo *paramName, + SourceLocation paramLoc, + SourceLocation colonLoc, + ParsedType typeBound); + + ObjCTypeParamList *actOnObjCTypeParamList(Scope *S, SourceLocation lAngleLoc, + ArrayRef<Decl *> typeParams, + SourceLocation rAngleLoc); + void popObjCTypeParamList(Scope *S, ObjCTypeParamList *typeParamList); + + Decl *ActOnStartClassInterface(Scope *S, + SourceLocation AtInterfaceLoc, + IdentifierInfo *ClassName, + SourceLocation ClassLoc, + ObjCTypeParamList *typeParamList, + IdentifierInfo *SuperName, + SourceLocation SuperLoc, + ArrayRef<ParsedType> SuperTypeArgs, + SourceRange SuperTypeArgsRange, + Decl * const *ProtoRefs, + unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, + SourceLocation EndProtoLoc, + AttributeList *AttrList); + + void ActOnSuperClassOfClassInterface(Scope *S, + SourceLocation AtInterfaceLoc, + ObjCInterfaceDecl *IDecl, + IdentifierInfo *ClassName, + SourceLocation ClassLoc, + IdentifierInfo *SuperName, + SourceLocation SuperLoc, + ArrayRef<ParsedType> SuperTypeArgs, + SourceRange SuperTypeArgsRange); + + void ActOnTypedefedProtocols(SmallVectorImpl<Decl *> &ProtocolRefs, + IdentifierInfo *SuperName, + SourceLocation SuperLoc); + + Decl *ActOnCompatibilityAlias( + SourceLocation AtCompatibilityAliasLoc, + IdentifierInfo *AliasName, SourceLocation AliasLocation, + IdentifierInfo *ClassName, SourceLocation ClassLocation); + + bool CheckForwardProtocolDeclarationForCircularDependency( + IdentifierInfo *PName, + SourceLocation &PLoc, SourceLocation PrevLoc, + const ObjCList<ObjCProtocolDecl> &PList); + + Decl *ActOnStartProtocolInterface( + SourceLocation AtProtoInterfaceLoc, + IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc, + Decl * const *ProtoRefNames, unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, + SourceLocation EndProtoLoc, + AttributeList *AttrList); + + Decl *ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, + IdentifierInfo *ClassName, + SourceLocation ClassLoc, + ObjCTypeParamList *typeParamList, + IdentifierInfo *CategoryName, + SourceLocation CategoryLoc, + Decl * const *ProtoRefs, + unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, + SourceLocation EndProtoLoc); + + Decl *ActOnStartClassImplementation( + SourceLocation AtClassImplLoc, + IdentifierInfo *ClassName, SourceLocation ClassLoc, + IdentifierInfo *SuperClassname, + SourceLocation SuperClassLoc); + + Decl *ActOnStartCategoryImplementation(SourceLocation AtCatImplLoc, + IdentifierInfo *ClassName, + SourceLocation ClassLoc, + IdentifierInfo *CatName, + SourceLocation CatLoc); + + DeclGroupPtrTy ActOnFinishObjCImplementation(Decl *ObjCImpDecl, + ArrayRef<Decl *> Decls); + + DeclGroupPtrTy ActOnForwardClassDeclaration(SourceLocation Loc, + IdentifierInfo **IdentList, + SourceLocation *IdentLocs, + ArrayRef<ObjCTypeParamList *> TypeParamLists, + unsigned NumElts); + + DeclGroupPtrTy ActOnForwardProtocolDeclaration(SourceLocation AtProtoclLoc, + ArrayRef<IdentifierLocPair> IdentList, + AttributeList *attrList); + + void FindProtocolDeclaration(bool WarnOnDeclarations, bool ForObjCContainer, + ArrayRef<IdentifierLocPair> ProtocolId, + SmallVectorImpl<Decl *> &Protocols); + + /// Given a list of identifiers (and their locations), resolve the + /// names to either Objective-C protocol qualifiers or type + /// arguments, as appropriate. + void actOnObjCTypeArgsOrProtocolQualifiers( + Scope *S, + ParsedType baseType, + SourceLocation lAngleLoc, + ArrayRef<IdentifierInfo *> identifiers, + ArrayRef<SourceLocation> identifierLocs, + SourceLocation rAngleLoc, + SourceLocation &typeArgsLAngleLoc, + SmallVectorImpl<ParsedType> &typeArgs, + SourceLocation &typeArgsRAngleLoc, + SourceLocation &protocolLAngleLoc, + SmallVectorImpl<Decl *> &protocols, + SourceLocation &protocolRAngleLoc, + bool warnOnIncompleteProtocols); + + /// Build a an Objective-C protocol-qualified 'id' type where no + /// base type was specified. + TypeResult actOnObjCProtocolQualifierType( + SourceLocation lAngleLoc, + ArrayRef<Decl *> protocols, + ArrayRef<SourceLocation> protocolLocs, + SourceLocation rAngleLoc); + + /// Build a specialized and/or protocol-qualified Objective-C type. + TypeResult actOnObjCTypeArgsAndProtocolQualifiers( + Scope *S, + SourceLocation Loc, + ParsedType BaseType, + SourceLocation TypeArgsLAngleLoc, + ArrayRef<ParsedType> TypeArgs, + SourceLocation TypeArgsRAngleLoc, + SourceLocation ProtocolLAngleLoc, + ArrayRef<Decl *> Protocols, + ArrayRef<SourceLocation> ProtocolLocs, + SourceLocation ProtocolRAngleLoc); + + /// Build an Objective-C object pointer type. + QualType BuildObjCObjectType(QualType BaseType, + SourceLocation Loc, + SourceLocation TypeArgsLAngleLoc, + ArrayRef<TypeSourceInfo *> TypeArgs, + SourceLocation TypeArgsRAngleLoc, + SourceLocation ProtocolLAngleLoc, + ArrayRef<ObjCProtocolDecl *> Protocols, + ArrayRef<SourceLocation> ProtocolLocs, + SourceLocation ProtocolRAngleLoc, + bool FailOnError = false); + + /// Check the application of the Objective-C '__kindof' qualifier to + /// the given type. + bool checkObjCKindOfType(QualType &type, SourceLocation loc); + + /// Ensure attributes are consistent with type. + /// \param [in, out] Attributes The attributes to check; they will + /// be modified to be consistent with \p PropertyTy. + void CheckObjCPropertyAttributes(Decl *PropertyPtrTy, + SourceLocation Loc, + unsigned &Attributes, + bool propertyInPrimaryClass); + + /// Process the specified property declaration and create decls for the + /// setters and getters as needed. + /// \param property The property declaration being processed + void ProcessPropertyDecl(ObjCPropertyDecl *property); + + + void DiagnosePropertyMismatch(ObjCPropertyDecl *Property, + ObjCPropertyDecl *SuperProperty, + const IdentifierInfo *Name, + bool OverridingProtocolProperty); + + void DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT, + ObjCInterfaceDecl *ID); + + Decl *ActOnAtEnd(Scope *S, SourceRange AtEnd, + ArrayRef<Decl *> allMethods = None, + ArrayRef<DeclGroupPtrTy> allTUVars = None); + + Decl *ActOnProperty(Scope *S, SourceLocation AtLoc, + SourceLocation LParenLoc, + FieldDeclarator &FD, ObjCDeclSpec &ODS, + Selector GetterSel, Selector SetterSel, + tok::ObjCKeywordKind MethodImplKind, + DeclContext *lexicalDC = nullptr); + + Decl *ActOnPropertyImplDecl(Scope *S, + SourceLocation AtLoc, + SourceLocation PropertyLoc, + bool ImplKind, + IdentifierInfo *PropertyId, + IdentifierInfo *PropertyIvar, + SourceLocation PropertyIvarLoc); + + enum ObjCSpecialMethodKind { + OSMK_None, + OSMK_Alloc, + OSMK_New, + OSMK_Copy, + OSMK_RetainingInit, + OSMK_NonRetainingInit + }; + + struct ObjCArgInfo { + IdentifierInfo *Name; + SourceLocation NameLoc; + // The Type is null if no type was specified, and the DeclSpec is invalid + // in this case. + ParsedType Type; + ObjCDeclSpec DeclSpec; + + /// ArgAttrs - Attribute list for this argument. + AttributeList *ArgAttrs; + }; + + Decl *ActOnMethodDeclaration( + Scope *S, + SourceLocation BeginLoc, // location of the + or -. + SourceLocation EndLoc, // location of the ; or {. + tok::TokenKind MethodType, + ObjCDeclSpec &ReturnQT, ParsedType ReturnType, + ArrayRef<SourceLocation> SelectorLocs, Selector Sel, + // optional arguments. The number of types/arguments is obtained + // from the Sel.getNumArgs(). + ObjCArgInfo *ArgInfo, + DeclaratorChunk::ParamInfo *CParamInfo, unsigned CNumArgs, // c-style args + AttributeList *AttrList, tok::ObjCKeywordKind MethodImplKind, + bool isVariadic, bool MethodDefinition); + + ObjCMethodDecl *LookupMethodInQualifiedType(Selector Sel, + const ObjCObjectPointerType *OPT, + bool IsInstance); + ObjCMethodDecl *LookupMethodInObjectType(Selector Sel, QualType Ty, + bool IsInstance); + + bool CheckARCMethodDecl(ObjCMethodDecl *method); + bool inferObjCARCLifetime(ValueDecl *decl); + + ExprResult + HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, + Expr *BaseExpr, + SourceLocation OpLoc, + DeclarationName MemberName, + SourceLocation MemberLoc, + SourceLocation SuperLoc, QualType SuperType, + bool Super); + + ExprResult + ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, + IdentifierInfo &propertyName, + SourceLocation receiverNameLoc, + SourceLocation propertyNameLoc); + + ObjCMethodDecl *tryCaptureObjCSelf(SourceLocation Loc); + + /// \brief Describes the kind of message expression indicated by a message + /// send that starts with an identifier. + enum ObjCMessageKind { + /// \brief The message is sent to 'super'. + ObjCSuperMessage, + /// \brief The message is an instance message. + ObjCInstanceMessage, + /// \brief The message is a class message, and the identifier is a type + /// name. + ObjCClassMessage + }; + + ObjCMessageKind getObjCMessageKind(Scope *S, + IdentifierInfo *Name, + SourceLocation NameLoc, + bool IsSuper, + bool HasTrailingDot, + ParsedType &ReceiverType); + + ExprResult ActOnSuperMessage(Scope *S, SourceLocation SuperLoc, + Selector Sel, + SourceLocation LBracLoc, + ArrayRef<SourceLocation> SelectorLocs, + SourceLocation RBracLoc, + MultiExprArg Args); + + ExprResult BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, + QualType ReceiverType, + SourceLocation SuperLoc, + Selector Sel, + ObjCMethodDecl *Method, + SourceLocation LBracLoc, + ArrayRef<SourceLocation> SelectorLocs, + SourceLocation RBracLoc, + MultiExprArg Args, + bool isImplicit = false); + + ExprResult BuildClassMessageImplicit(QualType ReceiverType, + bool isSuperReceiver, + SourceLocation Loc, + Selector Sel, + ObjCMethodDecl *Method, + MultiExprArg Args); + + ExprResult ActOnClassMessage(Scope *S, + ParsedType Receiver, + Selector Sel, + SourceLocation LBracLoc, + ArrayRef<SourceLocation> SelectorLocs, + SourceLocation RBracLoc, + MultiExprArg Args); + + ExprResult BuildInstanceMessage(Expr *Receiver, + QualType ReceiverType, + SourceLocation SuperLoc, + Selector Sel, + ObjCMethodDecl *Method, + SourceLocation LBracLoc, + ArrayRef<SourceLocation> SelectorLocs, + SourceLocation RBracLoc, + MultiExprArg Args, + bool isImplicit = false); + + ExprResult BuildInstanceMessageImplicit(Expr *Receiver, + QualType ReceiverType, + SourceLocation Loc, + Selector Sel, + ObjCMethodDecl *Method, + MultiExprArg Args); + + ExprResult ActOnInstanceMessage(Scope *S, + Expr *Receiver, + Selector Sel, + SourceLocation LBracLoc, + ArrayRef<SourceLocation> SelectorLocs, + SourceLocation RBracLoc, + MultiExprArg Args); + + ExprResult BuildObjCBridgedCast(SourceLocation LParenLoc, + ObjCBridgeCastKind Kind, + SourceLocation BridgeKeywordLoc, + TypeSourceInfo *TSInfo, + Expr *SubExpr); + + ExprResult ActOnObjCBridgedCast(Scope *S, + SourceLocation LParenLoc, + ObjCBridgeCastKind Kind, + SourceLocation BridgeKeywordLoc, + ParsedType Type, + SourceLocation RParenLoc, + Expr *SubExpr); + + void CheckTollFreeBridgeCast(QualType castType, Expr *castExpr); + + void CheckObjCBridgeRelatedCast(QualType castType, Expr *castExpr); + + bool CheckTollFreeBridgeStaticCast(QualType castType, Expr *castExpr, + CastKind &Kind); + + bool checkObjCBridgeRelatedComponents(SourceLocation Loc, + QualType DestType, QualType SrcType, + ObjCInterfaceDecl *&RelatedClass, + ObjCMethodDecl *&ClassMethod, + ObjCMethodDecl *&InstanceMethod, + TypedefNameDecl *&TDNDecl, + bool CfToNs); + + bool CheckObjCBridgeRelatedConversions(SourceLocation Loc, + QualType DestType, QualType SrcType, + Expr *&SrcExpr); + + bool ConversionToObjCStringLiteralCheck(QualType DstType, Expr *&SrcExpr); + + bool checkInitMethod(ObjCMethodDecl *method, QualType receiverTypeIfCall); + + /// \brief Check whether the given new method is a valid override of the + /// given overridden method, and set any properties that should be inherited. + void CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, + const ObjCMethodDecl *Overridden); + + /// \brief Describes the compatibility of a result type with its method. + enum ResultTypeCompatibilityKind { + RTC_Compatible, + RTC_Incompatible, + RTC_Unknown + }; + + void CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod, + ObjCInterfaceDecl *CurrentClass, + ResultTypeCompatibilityKind RTC); + + enum PragmaOptionsAlignKind { + POAK_Native, // #pragma options align=native + POAK_Natural, // #pragma options align=natural + POAK_Packed, // #pragma options align=packed + POAK_Power, // #pragma options align=power + POAK_Mac68k, // #pragma options align=mac68k + POAK_Reset // #pragma options align=reset + }; + + /// ActOnPragmaOptionsAlign - Called on well formed \#pragma options align. + void ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, + SourceLocation PragmaLoc); + + enum PragmaPackKind { + PPK_Default, // #pragma pack([n]) + PPK_Show, // #pragma pack(show), only supported by MSVC. + PPK_Push, // #pragma pack(push, [identifier], [n]) + PPK_Pop // #pragma pack(pop, [identifier], [n]) + }; + + enum PragmaMSStructKind { + PMSST_OFF, // #pragms ms_struct off + PMSST_ON // #pragms ms_struct on + }; + + enum PragmaMSCommentKind { + PCK_Unknown, + PCK_Linker, // #pragma comment(linker, ...) + PCK_Lib, // #pragma comment(lib, ...) + PCK_Compiler, // #pragma comment(compiler, ...) + PCK_ExeStr, // #pragma comment(exestr, ...) + PCK_User // #pragma comment(user, ...) + }; + + /// ActOnPragmaPack - Called on well formed \#pragma pack(...). + void ActOnPragmaPack(PragmaPackKind Kind, + IdentifierInfo *Name, + Expr *Alignment, + SourceLocation PragmaLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc); + + /// ActOnPragmaMSStruct - Called on well formed \#pragma ms_struct [on|off]. + void ActOnPragmaMSStruct(PragmaMSStructKind Kind); + + /// ActOnPragmaMSComment - Called on well formed + /// \#pragma comment(kind, "arg"). + void ActOnPragmaMSComment(PragmaMSCommentKind Kind, StringRef Arg); + + /// ActOnPragmaMSPointersToMembers - called on well formed \#pragma + /// pointers_to_members(representation method[, general purpose + /// representation]). + void ActOnPragmaMSPointersToMembers( + LangOptions::PragmaMSPointersToMembersKind Kind, + SourceLocation PragmaLoc); + + /// \brief Called on well formed \#pragma vtordisp(). + void ActOnPragmaMSVtorDisp(PragmaVtorDispKind Kind, SourceLocation PragmaLoc, + MSVtorDispAttr::Mode Value); + + enum PragmaSectionKind { + PSK_DataSeg, + PSK_BSSSeg, + PSK_ConstSeg, + PSK_CodeSeg, + }; + + bool UnifySection(StringRef SectionName, + int SectionFlags, + DeclaratorDecl *TheDecl); + bool UnifySection(StringRef SectionName, + int SectionFlags, + SourceLocation PragmaSectionLocation); + + /// \brief Called on well formed \#pragma bss_seg/data_seg/const_seg/code_seg. + void ActOnPragmaMSSeg(SourceLocation PragmaLocation, + PragmaMsStackAction Action, + llvm::StringRef StackSlotLabel, + StringLiteral *SegmentName, + llvm::StringRef PragmaName); + + /// \brief Called on well formed \#pragma section(). + void ActOnPragmaMSSection(SourceLocation PragmaLocation, + int SectionFlags, StringLiteral *SegmentName); + + /// \brief Called on well-formed \#pragma init_seg(). + void ActOnPragmaMSInitSeg(SourceLocation PragmaLocation, + StringLiteral *SegmentName); + + /// ActOnPragmaDetectMismatch - Call on well-formed \#pragma detect_mismatch + void ActOnPragmaDetectMismatch(StringRef Name, StringRef Value); + + /// ActOnPragmaUnused - Called on well-formed '\#pragma unused'. + void ActOnPragmaUnused(const Token &Identifier, + Scope *curScope, + SourceLocation PragmaLoc); + + /// ActOnPragmaVisibility - Called on well formed \#pragma GCC visibility... . + void ActOnPragmaVisibility(const IdentifierInfo* VisType, + SourceLocation PragmaLoc); + + NamedDecl *DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II, + SourceLocation Loc); + void DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W); + + /// ActOnPragmaWeakID - Called on well formed \#pragma weak ident. + void ActOnPragmaWeakID(IdentifierInfo* WeakName, + SourceLocation PragmaLoc, + SourceLocation WeakNameLoc); + + /// ActOnPragmaRedefineExtname - Called on well formed + /// \#pragma redefine_extname oldname newname. + void ActOnPragmaRedefineExtname(IdentifierInfo* WeakName, + IdentifierInfo* AliasName, + SourceLocation PragmaLoc, + SourceLocation WeakNameLoc, + SourceLocation AliasNameLoc); + + /// ActOnPragmaWeakAlias - Called on well formed \#pragma weak ident = ident. + void ActOnPragmaWeakAlias(IdentifierInfo* WeakName, + IdentifierInfo* AliasName, + SourceLocation PragmaLoc, + SourceLocation WeakNameLoc, + SourceLocation AliasNameLoc); + + /// ActOnPragmaFPContract - Called on well formed + /// \#pragma {STDC,OPENCL} FP_CONTRACT + void ActOnPragmaFPContract(tok::OnOffSwitch OOS); + + /// AddAlignmentAttributesForRecord - Adds any needed alignment attributes to + /// a the record decl, to handle '\#pragma pack' and '\#pragma options align'. + void AddAlignmentAttributesForRecord(RecordDecl *RD); + + /// AddMsStructLayoutForRecord - Adds ms_struct layout attribute to record. + void AddMsStructLayoutForRecord(RecordDecl *RD); + + /// FreePackedContext - Deallocate and null out PackContext. + void FreePackedContext(); + + /// PushNamespaceVisibilityAttr - Note that we've entered a + /// namespace with a visibility attribute. + void PushNamespaceVisibilityAttr(const VisibilityAttr *Attr, + SourceLocation Loc); + + /// AddPushedVisibilityAttribute - If '\#pragma GCC visibility' was used, + /// add an appropriate visibility attribute. + void AddPushedVisibilityAttribute(Decl *RD); + + /// PopPragmaVisibility - Pop the top element of the visibility stack; used + /// for '\#pragma GCC visibility' and visibility attributes on namespaces. + void PopPragmaVisibility(bool IsNamespaceEnd, SourceLocation EndLoc); + + /// FreeVisContext - Deallocate and null out VisContext. + void FreeVisContext(); + + /// AddCFAuditedAttribute - Check whether we're currently within + /// '\#pragma clang arc_cf_code_audited' and, if so, consider adding + /// the appropriate attribute. + void AddCFAuditedAttribute(Decl *D); + + /// \brief Called on well formed \#pragma clang optimize. + void ActOnPragmaOptimize(bool On, SourceLocation PragmaLoc); + + /// \brief Get the location for the currently active "\#pragma clang optimize + /// off". If this location is invalid, then the state of the pragma is "on". + SourceLocation getOptimizeOffPragmaLocation() const { + return OptimizeOffPragmaLocation; + } + + /// \brief Only called on function definitions; if there is a pragma in scope + /// with the effect of a range-based optnone, consider marking the function + /// with attribute optnone. + void AddRangeBasedOptnone(FunctionDecl *FD); + + /// \brief Adds the 'optnone' attribute to the function declaration if there + /// are no conflicts; Loc represents the location causing the 'optnone' + /// attribute to be added (usually because of a pragma). + void AddOptnoneAttributeIfNoConflicts(FunctionDecl *FD, SourceLocation Loc); + + /// AddAlignedAttr - Adds an aligned attribute to a particular declaration. + void AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, + unsigned SpellingListIndex, bool IsPackExpansion); + void AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *T, + unsigned SpellingListIndex, bool IsPackExpansion); + + /// AddAssumeAlignedAttr - Adds an assume_aligned attribute to a particular + /// declaration. + void AddAssumeAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, Expr *OE, + unsigned SpellingListIndex); + + /// AddAlignValueAttr - Adds an align_value attribute to a particular + /// declaration. + void AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr *E, + unsigned SpellingListIndex); + + /// AddLaunchBoundsAttr - Adds a launch_bounds attribute to a particular + /// declaration. + void AddLaunchBoundsAttr(SourceRange AttrRange, Decl *D, Expr *MaxThreads, + Expr *MinBlocks, unsigned SpellingListIndex); + + //===--------------------------------------------------------------------===// + // C++ Coroutines TS + // + ExprResult ActOnCoawaitExpr(Scope *S, SourceLocation KwLoc, Expr *E); + ExprResult ActOnCoyieldExpr(Scope *S, SourceLocation KwLoc, Expr *E); + StmtResult ActOnCoreturnStmt(SourceLocation KwLoc, Expr *E); + + ExprResult BuildCoawaitExpr(SourceLocation KwLoc, Expr *E); + ExprResult BuildCoyieldExpr(SourceLocation KwLoc, Expr *E); + StmtResult BuildCoreturnStmt(SourceLocation KwLoc, Expr *E); + + void CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body); + + //===--------------------------------------------------------------------===// + // OpenMP directives and clauses. + // +private: + void *VarDataSharingAttributesStack; + /// \brief Initialization of data-sharing attributes stack. + void InitDataSharingAttributesStack(); + void DestroyDataSharingAttributesStack(); + ExprResult + VerifyPositiveIntegerConstantInClause(Expr *Op, OpenMPClauseKind CKind, + bool StrictlyPositive = true); + +public: + /// \brief Return true if the provided declaration \a VD should be captured by + /// reference in the provided scope \a RSI. This will take into account the + /// semantics of the directive and associated clauses. + bool IsOpenMPCapturedByRef(VarDecl *VD, + const sema::CapturedRegionScopeInfo *RSI); + + /// \brief Check if the specified variable is used in one of the private + /// clauses (private, firstprivate, lastprivate, reduction etc.) in OpenMP + /// constructs. + bool IsOpenMPCapturedVar(VarDecl *VD); + + /// \brief Check if the specified variable is used in 'private' clause. + /// \param Level Relative level of nested OpenMP construct for that the check + /// is performed. + bool isOpenMPPrivateVar(VarDecl *VD, unsigned Level); + + /// \brief Check if the specified variable is captured by 'target' directive. + /// \param Level Relative level of nested OpenMP construct for that the check + /// is performed. + bool isOpenMPTargetCapturedVar(VarDecl *VD, unsigned Level); + + ExprResult PerformOpenMPImplicitIntegerConversion(SourceLocation OpLoc, + Expr *Op); + /// \brief Called on start of new data sharing attribute block. + void StartOpenMPDSABlock(OpenMPDirectiveKind K, + const DeclarationNameInfo &DirName, Scope *CurScope, + SourceLocation Loc); + /// \brief Start analysis of clauses. + void StartOpenMPClause(OpenMPClauseKind K); + /// \brief End analysis of clauses. + void EndOpenMPClause(); + /// \brief Called on end of data sharing attribute block. + void EndOpenMPDSABlock(Stmt *CurDirective); + + /// \brief Check if the current region is an OpenMP loop region and if it is, + /// mark loop control variable, used in \p Init for loop initialization, as + /// private by default. + /// \param Init First part of the for loop. + void ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init); + + // OpenMP directives and clauses. + /// \brief Called on correct id-expression from the '#pragma omp + /// threadprivate'. + ExprResult ActOnOpenMPIdExpression(Scope *CurScope, + CXXScopeSpec &ScopeSpec, + const DeclarationNameInfo &Id); + /// \brief Called on well-formed '#pragma omp threadprivate'. + DeclGroupPtrTy ActOnOpenMPThreadprivateDirective( + SourceLocation Loc, + ArrayRef<Expr *> VarList); + /// \brief Builds a new OpenMPThreadPrivateDecl and checks its correctness. + OMPThreadPrivateDecl *CheckOMPThreadPrivateDecl( + SourceLocation Loc, + ArrayRef<Expr *> VarList); + + /// \brief Initialization of captured region for OpenMP region. + void ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope); + /// \brief End of OpenMP region. + /// + /// \param S Statement associated with the current OpenMP region. + /// \param Clauses List of clauses for the current OpenMP region. + /// + /// \returns Statement for finished OpenMP region. + StmtResult ActOnOpenMPRegionEnd(StmtResult S, ArrayRef<OMPClause *> Clauses); + StmtResult ActOnOpenMPExecutableDirective( + OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName, + OpenMPDirectiveKind CancelRegion, ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp parallel' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp simd' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPSimdDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, + llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA); + /// \brief Called on well-formed '\#pragma omp for' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPForDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, + llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA); + /// \brief Called on well-formed '\#pragma omp for simd' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPForSimdDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, + llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA); + /// \brief Called on well-formed '\#pragma omp sections' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPSectionsDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp section' after parsing of the + /// associated statement. + StmtResult ActOnOpenMPSectionDirective(Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp single' after parsing of the + /// associated statement. + StmtResult ActOnOpenMPSingleDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp master' after parsing of the + /// associated statement. + StmtResult ActOnOpenMPMasterDirective(Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp critical' after parsing of the + /// associated statement. + StmtResult ActOnOpenMPCriticalDirective(const DeclarationNameInfo &DirName, + ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp parallel for' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPParallelForDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, + llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA); + /// \brief Called on well-formed '\#pragma omp parallel for simd' after + /// parsing of the associated statement. + StmtResult ActOnOpenMPParallelForSimdDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, + llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA); + /// \brief Called on well-formed '\#pragma omp parallel sections' after + /// parsing of the associated statement. + StmtResult ActOnOpenMPParallelSectionsDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp task' after parsing of the + /// associated statement. + StmtResult ActOnOpenMPTaskDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp taskyield'. + StmtResult ActOnOpenMPTaskyieldDirective(SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp barrier'. + StmtResult ActOnOpenMPBarrierDirective(SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp taskwait'. + StmtResult ActOnOpenMPTaskwaitDirective(SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp taskgroup'. + StmtResult ActOnOpenMPTaskgroupDirective(Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp flush'. + StmtResult ActOnOpenMPFlushDirective(ArrayRef<OMPClause *> Clauses, + SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp ordered' after parsing of the + /// associated statement. + StmtResult ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp atomic' after parsing of the + /// associated statement. + StmtResult ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp target' after parsing of the + /// associated statement. + StmtResult ActOnOpenMPTargetDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp target data' after parsing of + /// the associated statement. + StmtResult ActOnOpenMPTargetDataDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp teams' after parsing of the + /// associated statement. + StmtResult ActOnOpenMPTeamsDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp cancellation point'. + StmtResult + ActOnOpenMPCancellationPointDirective(SourceLocation StartLoc, + SourceLocation EndLoc, + OpenMPDirectiveKind CancelRegion); + /// \brief Called on well-formed '\#pragma omp cancel'. + StmtResult ActOnOpenMPCancelDirective(ArrayRef<OMPClause *> Clauses, + SourceLocation StartLoc, + SourceLocation EndLoc, + OpenMPDirectiveKind CancelRegion); + /// \brief Called on well-formed '\#pragma omp taskloop' after parsing of the + /// associated statement. + StmtResult ActOnOpenMPTaskLoopDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, + llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA); + /// \brief Called on well-formed '\#pragma omp taskloop simd' after parsing of + /// the associated statement. + StmtResult ActOnOpenMPTaskLoopSimdDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, + llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA); + /// \brief Called on well-formed '\#pragma omp distribute' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPDistributeDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, + llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA); + + OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, + Expr *Expr, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'if' clause. + OMPClause *ActOnOpenMPIfClause(OpenMPDirectiveKind NameModifier, + Expr *Condition, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation NameModifierLoc, + SourceLocation ColonLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'final' clause. + OMPClause *ActOnOpenMPFinalClause(Expr *Condition, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'num_threads' clause. + OMPClause *ActOnOpenMPNumThreadsClause(Expr *NumThreads, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'safelen' clause. + OMPClause *ActOnOpenMPSafelenClause(Expr *Length, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'simdlen' clause. + OMPClause *ActOnOpenMPSimdlenClause(Expr *Length, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'collapse' clause. + OMPClause *ActOnOpenMPCollapseClause(Expr *NumForLoops, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'ordered' clause. + OMPClause * + ActOnOpenMPOrderedClause(SourceLocation StartLoc, SourceLocation EndLoc, + SourceLocation LParenLoc = SourceLocation(), + Expr *NumForLoops = nullptr); + /// \brief Called on well-formed 'grainsize' clause. + OMPClause *ActOnOpenMPGrainsizeClause(Expr *Size, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'num_tasks' clause. + OMPClause *ActOnOpenMPNumTasksClause(Expr *NumTasks, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'hint' clause. + OMPClause *ActOnOpenMPHintClause(Expr *Hint, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + + OMPClause *ActOnOpenMPSimpleClause(OpenMPClauseKind Kind, + unsigned Argument, + SourceLocation ArgumentLoc, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'default' clause. + OMPClause *ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind, + SourceLocation KindLoc, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'proc_bind' clause. + OMPClause *ActOnOpenMPProcBindClause(OpenMPProcBindClauseKind Kind, + SourceLocation KindLoc, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + + OMPClause *ActOnOpenMPSingleExprWithArgClause( + OpenMPClauseKind Kind, ArrayRef<unsigned> Arguments, Expr *Expr, + SourceLocation StartLoc, SourceLocation LParenLoc, + ArrayRef<SourceLocation> ArgumentsLoc, SourceLocation DelimLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'schedule' clause. + OMPClause *ActOnOpenMPScheduleClause( + OpenMPScheduleClauseModifier M1, OpenMPScheduleClauseModifier M2, + OpenMPScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation M1Loc, SourceLocation M2Loc, + SourceLocation KindLoc, SourceLocation CommaLoc, SourceLocation EndLoc); + + OMPClause *ActOnOpenMPClause(OpenMPClauseKind Kind, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'nowait' clause. + OMPClause *ActOnOpenMPNowaitClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'untied' clause. + OMPClause *ActOnOpenMPUntiedClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'mergeable' clause. + OMPClause *ActOnOpenMPMergeableClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'read' clause. + OMPClause *ActOnOpenMPReadClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'write' clause. + OMPClause *ActOnOpenMPWriteClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'update' clause. + OMPClause *ActOnOpenMPUpdateClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'capture' clause. + OMPClause *ActOnOpenMPCaptureClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'seq_cst' clause. + OMPClause *ActOnOpenMPSeqCstClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'threads' clause. + OMPClause *ActOnOpenMPThreadsClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'simd' clause. + OMPClause *ActOnOpenMPSIMDClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'nogroup' clause. + OMPClause *ActOnOpenMPNogroupClause(SourceLocation StartLoc, + SourceLocation EndLoc); + + OMPClause *ActOnOpenMPVarListClause( + OpenMPClauseKind Kind, ArrayRef<Expr *> Vars, Expr *TailExpr, + SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ColonLoc, SourceLocation EndLoc, + CXXScopeSpec &ReductionIdScopeSpec, + const DeclarationNameInfo &ReductionId, OpenMPDependClauseKind DepKind, + OpenMPLinearClauseKind LinKind, OpenMPMapClauseKind MapTypeModifier, + OpenMPMapClauseKind MapType, SourceLocation DepLinMapLoc); + /// \brief Called on well-formed 'private' clause. + OMPClause *ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'firstprivate' clause. + OMPClause *ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'lastprivate' clause. + OMPClause *ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'shared' clause. + OMPClause *ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'reduction' clause. + OMPClause * + ActOnOpenMPReductionClause(ArrayRef<Expr *> VarList, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation ColonLoc, + SourceLocation EndLoc, + CXXScopeSpec &ReductionIdScopeSpec, + const DeclarationNameInfo &ReductionId); + /// \brief Called on well-formed 'linear' clause. + OMPClause * + ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList, Expr *Step, + SourceLocation StartLoc, SourceLocation LParenLoc, + OpenMPLinearClauseKind LinKind, SourceLocation LinLoc, + SourceLocation ColonLoc, SourceLocation EndLoc); + /// \brief Called on well-formed 'aligned' clause. + OMPClause *ActOnOpenMPAlignedClause(ArrayRef<Expr *> VarList, + Expr *Alignment, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation ColonLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'copyin' clause. + OMPClause *ActOnOpenMPCopyinClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'copyprivate' clause. + OMPClause *ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'flush' pseudo clause. + OMPClause *ActOnOpenMPFlushClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'depend' clause. + OMPClause * + ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, SourceLocation DepLoc, + SourceLocation ColonLoc, ArrayRef<Expr *> VarList, + SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'device' clause. + OMPClause *ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'map' clause. + OMPClause *ActOnOpenMPMapClause( + OpenMPMapClauseKind MapTypeModifier, OpenMPMapClauseKind MapType, + SourceLocation MapLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VarList, + SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); + /// \brief Called on well-formed 'num_teams' clause. + OMPClause *ActOnOpenMPNumTeamsClause(Expr *NumTeams, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'thread_limit' clause. + OMPClause *ActOnOpenMPThreadLimitClause(Expr *ThreadLimit, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'priority' clause. + OMPClause *ActOnOpenMPPriorityClause(Expr *Priority, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + + /// \brief The kind of conversion being performed. + enum CheckedConversionKind { + /// \brief An implicit conversion. + CCK_ImplicitConversion, + /// \brief A C-style cast. + CCK_CStyleCast, + /// \brief A functional-style cast. + CCK_FunctionalCast, + /// \brief A cast other than a C-style cast. + CCK_OtherCast + }; + + /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit + /// cast. If there is already an implicit cast, merge into the existing one. + /// If isLvalue, the result of the cast is an lvalue. + ExprResult ImpCastExprToType(Expr *E, QualType Type, CastKind CK, + ExprValueKind VK = VK_RValue, + const CXXCastPath *BasePath = nullptr, + CheckedConversionKind CCK + = CCK_ImplicitConversion); + + /// ScalarTypeToBooleanCastKind - Returns the cast kind corresponding + /// to the conversion from scalar type ScalarTy to the Boolean type. + static CastKind ScalarTypeToBooleanCastKind(QualType ScalarTy); + + /// IgnoredValueConversions - Given that an expression's result is + /// syntactically ignored, perform any conversions that are + /// required. + ExprResult IgnoredValueConversions(Expr *E); + + // UsualUnaryConversions - promotes integers (C99 6.3.1.1p2) and converts + // functions and arrays to their respective pointers (C99 6.3.2.1). + ExprResult UsualUnaryConversions(Expr *E); + + /// CallExprUnaryConversions - a special case of an unary conversion + /// performed on a function designator of a call expression. + ExprResult CallExprUnaryConversions(Expr *E); + + // DefaultFunctionArrayConversion - converts functions and arrays + // to their respective pointers (C99 6.3.2.1). + ExprResult DefaultFunctionArrayConversion(Expr *E, bool Diagnose = true); + + // DefaultFunctionArrayLvalueConversion - converts functions and + // arrays to their respective pointers and performs the + // lvalue-to-rvalue conversion. + ExprResult DefaultFunctionArrayLvalueConversion(Expr *E, + bool Diagnose = true); + + // DefaultLvalueConversion - performs lvalue-to-rvalue conversion on + // the operand. This is DefaultFunctionArrayLvalueConversion, + // except that it assumes the operand isn't of function or array + // type. + ExprResult DefaultLvalueConversion(Expr *E); + + // DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that + // do not have a prototype. Integer promotions are performed on each + // argument, and arguments that have type float are promoted to double. + ExprResult DefaultArgumentPromotion(Expr *E); + + // Used for emitting the right warning by DefaultVariadicArgumentPromotion + enum VariadicCallType { + VariadicFunction, + VariadicBlock, + VariadicMethod, + VariadicConstructor, + VariadicDoesNotApply + }; + + VariadicCallType getVariadicCallType(FunctionDecl *FDecl, + const FunctionProtoType *Proto, + Expr *Fn); + + // Used for determining in which context a type is allowed to be passed to a + // vararg function. + enum VarArgKind { + VAK_Valid, + VAK_ValidInCXX11, + VAK_Undefined, + VAK_MSVCUndefined, + VAK_Invalid + }; + + // Determines which VarArgKind fits an expression. + VarArgKind isValidVarArgType(const QualType &Ty); + + /// Check to see if the given expression is a valid argument to a variadic + /// function, issuing a diagnostic if not. + void checkVariadicArgument(const Expr *E, VariadicCallType CT); + + /// Check to see if a given expression could have '.c_str()' called on it. + bool hasCStrMethod(const Expr *E); + + /// GatherArgumentsForCall - Collector argument expressions for various + /// form of call prototypes. + bool GatherArgumentsForCall(SourceLocation CallLoc, FunctionDecl *FDecl, + const FunctionProtoType *Proto, + unsigned FirstParam, ArrayRef<Expr *> Args, + SmallVectorImpl<Expr *> &AllArgs, + VariadicCallType CallType = VariadicDoesNotApply, + bool AllowExplicit = false, + bool IsListInitialization = false); + + // DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but + // will create a runtime trap if the resulting type is not a POD type. + ExprResult DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, + FunctionDecl *FDecl); + + // UsualArithmeticConversions - performs the UsualUnaryConversions on it's + // operands and then handles various conversions that are common to binary + // operators (C99 6.3.1.8). If both operands aren't arithmetic, this + // routine returns the first non-arithmetic type found. The client is + // responsible for emitting appropriate error diagnostics. + QualType UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, + bool IsCompAssign = false); + + /// AssignConvertType - All of the 'assignment' semantic checks return this + /// enum to indicate whether the assignment was allowed. These checks are + /// done for simple assignments, as well as initialization, return from + /// function, argument passing, etc. The query is phrased in terms of a + /// source and destination type. + enum AssignConvertType { + /// Compatible - the types are compatible according to the standard. + Compatible, + + /// PointerToInt - The assignment converts a pointer to an int, which we + /// accept as an extension. + PointerToInt, + + /// IntToPointer - The assignment converts an int to a pointer, which we + /// accept as an extension. + IntToPointer, + + /// FunctionVoidPointer - The assignment is between a function pointer and + /// void*, which the standard doesn't allow, but we accept as an extension. + FunctionVoidPointer, + + /// IncompatiblePointer - The assignment is between two pointers types that + /// are not compatible, but we accept them as an extension. + IncompatiblePointer, + + /// IncompatiblePointer - The assignment is between two pointers types which + /// point to integers which have a different sign, but are otherwise + /// identical. This is a subset of the above, but broken out because it's by + /// far the most common case of incompatible pointers. + IncompatiblePointerSign, + + /// CompatiblePointerDiscardsQualifiers - The assignment discards + /// c/v/r qualifiers, which we accept as an extension. + CompatiblePointerDiscardsQualifiers, + + /// IncompatiblePointerDiscardsQualifiers - The assignment + /// discards qualifiers that we don't permit to be discarded, + /// like address spaces. + IncompatiblePointerDiscardsQualifiers, + + /// IncompatibleNestedPointerQualifiers - The assignment is between two + /// nested pointer types, and the qualifiers other than the first two + /// levels differ e.g. char ** -> const char **, but we accept them as an + /// extension. + IncompatibleNestedPointerQualifiers, + + /// IncompatibleVectors - The assignment is between two vector types that + /// have the same size, which we accept as an extension. + IncompatibleVectors, + + /// IntToBlockPointer - The assignment converts an int to a block + /// pointer. We disallow this. + IntToBlockPointer, + + /// IncompatibleBlockPointer - The assignment is between two block + /// pointers types that are not compatible. + IncompatibleBlockPointer, + + /// IncompatibleObjCQualifiedId - The assignment is between a qualified + /// id type and something else (that is incompatible with it). For example, + /// "id <XXX>" = "Foo *", where "Foo *" doesn't implement the XXX protocol. + IncompatibleObjCQualifiedId, + + /// IncompatibleObjCWeakRef - Assigning a weak-unavailable object to an + /// object with __weak qualifier. + IncompatibleObjCWeakRef, + + /// Incompatible - We reject this conversion outright, it is invalid to + /// represent it in the AST. + Incompatible + }; + + /// DiagnoseAssignmentResult - Emit a diagnostic, if required, for the + /// assignment conversion type specified by ConvTy. This returns true if the + /// conversion was invalid or false if the conversion was accepted. + bool DiagnoseAssignmentResult(AssignConvertType ConvTy, + SourceLocation Loc, + QualType DstType, QualType SrcType, + Expr *SrcExpr, AssignmentAction Action, + bool *Complained = nullptr); + + /// IsValueInFlagEnum - Determine if a value is allowed as part of a flag + /// enum. If AllowMask is true, then we also allow the complement of a valid + /// value, to be used as a mask. + bool IsValueInFlagEnum(const EnumDecl *ED, const llvm::APInt &Val, + bool AllowMask) const; + + /// DiagnoseAssignmentEnum - Warn if assignment to enum is a constant + /// integer not in the range of enum values. + void DiagnoseAssignmentEnum(QualType DstType, QualType SrcType, + Expr *SrcExpr); + + /// CheckAssignmentConstraints - Perform type checking for assignment, + /// argument passing, variable initialization, and function return values. + /// C99 6.5.16. + AssignConvertType CheckAssignmentConstraints(SourceLocation Loc, + QualType LHSType, + QualType RHSType); + + /// Check assignment constraints and optionally prepare for a conversion of + /// the RHS to the LHS type. The conversion is prepared for if ConvertRHS + /// is true. + AssignConvertType CheckAssignmentConstraints(QualType LHSType, + ExprResult &RHS, + CastKind &Kind, + bool ConvertRHS = true); + + // CheckSingleAssignmentConstraints - Currently used by + // CheckAssignmentOperands, and ActOnReturnStmt. Prior to type checking, + // this routine performs the default function/array converions, if ConvertRHS + // is true. + AssignConvertType CheckSingleAssignmentConstraints(QualType LHSType, + ExprResult &RHS, + bool Diagnose = true, + bool DiagnoseCFAudited = false, + bool ConvertRHS = true); + + // \brief If the lhs type is a transparent union, check whether we + // can initialize the transparent union with the given expression. + AssignConvertType CheckTransparentUnionArgumentConstraints(QualType ArgType, + ExprResult &RHS); + + bool IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType); + + bool CheckExceptionSpecCompatibility(Expr *From, QualType ToType); + + ExprResult PerformImplicitConversion(Expr *From, QualType ToType, + AssignmentAction Action, + bool AllowExplicit = false); + ExprResult PerformImplicitConversion(Expr *From, QualType ToType, + AssignmentAction Action, + bool AllowExplicit, + ImplicitConversionSequence& ICS); + ExprResult PerformImplicitConversion(Expr *From, QualType ToType, + const ImplicitConversionSequence& ICS, + AssignmentAction Action, + CheckedConversionKind CCK + = CCK_ImplicitConversion); + ExprResult PerformImplicitConversion(Expr *From, QualType ToType, + const StandardConversionSequence& SCS, + AssignmentAction Action, + CheckedConversionKind CCK); + + /// the following "Check" methods will return a valid/converted QualType + /// or a null QualType (indicating an error diagnostic was issued). + + /// type checking binary operators (subroutines of CreateBuiltinBinOp). + QualType InvalidOperands(SourceLocation Loc, ExprResult &LHS, + ExprResult &RHS); + QualType CheckPointerToMemberOperands( // C++ 5.5 + ExprResult &LHS, ExprResult &RHS, ExprValueKind &VK, + SourceLocation OpLoc, bool isIndirect); + QualType CheckMultiplyDivideOperands( // C99 6.5.5 + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign, + bool IsDivide); + QualType CheckRemainderOperands( // C99 6.5.5 + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, + bool IsCompAssign = false); + QualType CheckAdditionOperands( // C99 6.5.6 + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, + BinaryOperatorKind Opc, QualType* CompLHSTy = nullptr); + QualType CheckSubtractionOperands( // C99 6.5.6 + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, + QualType* CompLHSTy = nullptr); + QualType CheckShiftOperands( // C99 6.5.7 + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, + BinaryOperatorKind Opc, bool IsCompAssign = false); + QualType CheckCompareOperands( // C99 6.5.8/9 + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, + BinaryOperatorKind Opc, bool isRelational); + QualType CheckBitwiseOperands( // C99 6.5.[10...12] + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, + bool IsCompAssign = false); + QualType CheckLogicalOperands( // C99 6.5.[13,14] + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, + BinaryOperatorKind Opc); + // CheckAssignmentOperands is used for both simple and compound assignment. + // For simple assignment, pass both expressions and a null converted type. + // For compound assignment, pass both expressions and the converted type. + QualType CheckAssignmentOperands( // C99 6.5.16.[1,2] + Expr *LHSExpr, ExprResult &RHS, SourceLocation Loc, QualType CompoundType); + + ExprResult checkPseudoObjectIncDec(Scope *S, SourceLocation OpLoc, + UnaryOperatorKind Opcode, Expr *Op); + ExprResult checkPseudoObjectAssignment(Scope *S, SourceLocation OpLoc, + BinaryOperatorKind Opcode, + Expr *LHS, Expr *RHS); + ExprResult checkPseudoObjectRValue(Expr *E); + Expr *recreateSyntacticForm(PseudoObjectExpr *E); + + QualType CheckConditionalOperands( // C99 6.5.15 + ExprResult &Cond, ExprResult &LHS, ExprResult &RHS, + ExprValueKind &VK, ExprObjectKind &OK, SourceLocation QuestionLoc); + QualType CXXCheckConditionalOperands( // C++ 5.16 + ExprResult &cond, ExprResult &lhs, ExprResult &rhs, + ExprValueKind &VK, ExprObjectKind &OK, SourceLocation questionLoc); + QualType FindCompositePointerType(SourceLocation Loc, Expr *&E1, Expr *&E2, + bool *NonStandardCompositeType = nullptr); + QualType FindCompositePointerType(SourceLocation Loc, + ExprResult &E1, ExprResult &E2, + bool *NonStandardCompositeType = nullptr) { + Expr *E1Tmp = E1.get(), *E2Tmp = E2.get(); + QualType Composite = FindCompositePointerType(Loc, E1Tmp, E2Tmp, + NonStandardCompositeType); + E1 = E1Tmp; + E2 = E2Tmp; + return Composite; + } + + QualType FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS, + SourceLocation QuestionLoc); + + bool DiagnoseConditionalForNull(Expr *LHSExpr, Expr *RHSExpr, + SourceLocation QuestionLoc); + + void DiagnoseAlwaysNonNullPointer(Expr *E, + Expr::NullPointerConstantKind NullType, + bool IsEqual, SourceRange Range); + + /// type checking for vector binary operators. + QualType CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc, bool IsCompAssign, + bool AllowBothBool, bool AllowBoolConversion); + QualType GetSignedVectorType(QualType V); + QualType CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc, bool isRelational); + QualType CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc); + + bool areLaxCompatibleVectorTypes(QualType srcType, QualType destType); + bool isLaxVectorConversion(QualType srcType, QualType destType); + + /// type checking declaration initializers (C99 6.7.8) + bool CheckForConstantInitializer(Expr *e, QualType t); + + // type checking C++ declaration initializers (C++ [dcl.init]). + + /// ReferenceCompareResult - Expresses the result of comparing two + /// types (cv1 T1 and cv2 T2) to determine their compatibility for the + /// purposes of initialization by reference (C++ [dcl.init.ref]p4). + enum ReferenceCompareResult { + /// Ref_Incompatible - The two types are incompatible, so direct + /// reference binding is not possible. + Ref_Incompatible = 0, + /// Ref_Related - The two types are reference-related, which means + /// that their unqualified forms (T1 and T2) are either the same + /// or T1 is a base class of T2. + Ref_Related, + /// Ref_Compatible_With_Added_Qualification - The two types are + /// reference-compatible with added qualification, meaning that + /// they are reference-compatible and the qualifiers on T1 (cv1) + /// are greater than the qualifiers on T2 (cv2). + Ref_Compatible_With_Added_Qualification, + /// Ref_Compatible - The two types are reference-compatible and + /// have equivalent qualifiers (cv1 == cv2). + Ref_Compatible + }; + + ReferenceCompareResult CompareReferenceRelationship(SourceLocation Loc, + QualType T1, QualType T2, + bool &DerivedToBase, + bool &ObjCConversion, + bool &ObjCLifetimeConversion); + + ExprResult checkUnknownAnyCast(SourceRange TypeRange, QualType CastType, + Expr *CastExpr, CastKind &CastKind, + ExprValueKind &VK, CXXCastPath &Path); + + /// \brief Force an expression with unknown-type to an expression of the + /// given type. + ExprResult forceUnknownAnyToType(Expr *E, QualType ToType); + + /// \brief Type-check an expression that's being passed to an + /// __unknown_anytype parameter. + ExprResult checkUnknownAnyArg(SourceLocation callLoc, + Expr *result, QualType ¶mType); + + // CheckVectorCast - check type constraints for vectors. + // Since vectors are an extension, there are no C standard reference for this. + // We allow casting between vectors and integer datatypes of the same size. + // returns true if the cast is invalid + bool CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty, + CastKind &Kind); + + // CheckExtVectorCast - check type constraints for extended vectors. + // Since vectors are an extension, there are no C standard reference for this. + // We allow casting between vectors and integer datatypes of the same size, + // or vectors and the element type of that vector. + // returns the cast expr + ExprResult CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *CastExpr, + CastKind &Kind); + + ExprResult BuildCXXFunctionalCastExpr(TypeSourceInfo *TInfo, + SourceLocation LParenLoc, + Expr *CastExpr, + SourceLocation RParenLoc); + + enum ARCConversionResult { ACR_okay, ACR_unbridged }; + + /// \brief Checks for invalid conversions and casts between + /// retainable pointers and other pointer kinds. + ARCConversionResult CheckObjCARCConversion(SourceRange castRange, + QualType castType, Expr *&op, + CheckedConversionKind CCK, + bool DiagnoseCFAudited = false, + BinaryOperatorKind Opc = BO_PtrMemD + ); + + Expr *stripARCUnbridgedCast(Expr *e); + void diagnoseARCUnbridgedCast(Expr *e); + + bool CheckObjCARCUnavailableWeakConversion(QualType castType, + QualType ExprType); + + /// checkRetainCycles - Check whether an Objective-C message send + /// might create an obvious retain cycle. + void checkRetainCycles(ObjCMessageExpr *msg); + void checkRetainCycles(Expr *receiver, Expr *argument); + void checkRetainCycles(VarDecl *Var, Expr *Init); + + /// checkUnsafeAssigns - Check whether +1 expr is being assigned + /// to weak/__unsafe_unretained type. + bool checkUnsafeAssigns(SourceLocation Loc, QualType LHS, Expr *RHS); + + /// checkUnsafeExprAssigns - Check whether +1 expr is being assigned + /// to weak/__unsafe_unretained expression. + void checkUnsafeExprAssigns(SourceLocation Loc, Expr *LHS, Expr *RHS); + + /// CheckMessageArgumentTypes - Check types in an Obj-C message send. + /// \param Method - May be null. + /// \param [out] ReturnType - The return type of the send. + /// \return true iff there were any incompatible types. + bool CheckMessageArgumentTypes(QualType ReceiverType, + MultiExprArg Args, Selector Sel, + ArrayRef<SourceLocation> SelectorLocs, + ObjCMethodDecl *Method, bool isClassMessage, + bool isSuperMessage, + SourceLocation lbrac, SourceLocation rbrac, + SourceRange RecRange, + QualType &ReturnType, ExprValueKind &VK); + + /// \brief Determine the result of a message send expression based on + /// the type of the receiver, the method expected to receive the message, + /// and the form of the message send. + QualType getMessageSendResultType(QualType ReceiverType, + ObjCMethodDecl *Method, + bool isClassMessage, bool isSuperMessage); + + /// \brief If the given expression involves a message send to a method + /// with a related result type, emit a note describing what happened. + void EmitRelatedResultTypeNote(const Expr *E); + + /// \brief Given that we had incompatible pointer types in a return + /// statement, check whether we're in a method with a related result + /// type, and if so, emit a note describing what happened. + void EmitRelatedResultTypeNoteForReturn(QualType destType); + + /// CheckBooleanCondition - Diagnose problems involving the use of + /// the given expression as a boolean condition (e.g. in an if + /// statement). Also performs the standard function and array + /// decays, possibly changing the input variable. + /// + /// \param Loc - A location associated with the condition, e.g. the + /// 'if' keyword. + /// \return true iff there were any errors + ExprResult CheckBooleanCondition(Expr *E, SourceLocation Loc); + + ExprResult ActOnBooleanCondition(Scope *S, SourceLocation Loc, + Expr *SubExpr); + + /// DiagnoseAssignmentAsCondition - Given that an expression is + /// being used as a boolean condition, warn if it's an assignment. + void DiagnoseAssignmentAsCondition(Expr *E); + + /// \brief Redundant parentheses over an equality comparison can indicate + /// that the user intended an assignment used as condition. + void DiagnoseEqualityWithExtraParens(ParenExpr *ParenE); + + /// CheckCXXBooleanCondition - Returns true if conversion to bool is invalid. + ExprResult CheckCXXBooleanCondition(Expr *CondExpr); + + /// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have + /// the specified width and sign. If an overflow occurs, detect it and emit + /// the specified diagnostic. + void ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &OldVal, + unsigned NewWidth, bool NewSign, + SourceLocation Loc, unsigned DiagID); + + /// Checks that the Objective-C declaration is declared in the global scope. + /// Emits an error and marks the declaration as invalid if it's not declared + /// in the global scope. + bool CheckObjCDeclScope(Decl *D); + + /// \brief Abstract base class used for diagnosing integer constant + /// expression violations. + class VerifyICEDiagnoser { + public: + bool Suppress; + + VerifyICEDiagnoser(bool Suppress = false) : Suppress(Suppress) { } + + virtual void diagnoseNotICE(Sema &S, SourceLocation Loc, SourceRange SR) =0; + virtual void diagnoseFold(Sema &S, SourceLocation Loc, SourceRange SR); + virtual ~VerifyICEDiagnoser() { } + }; + + /// VerifyIntegerConstantExpression - Verifies that an expression is an ICE, + /// and reports the appropriate diagnostics. Returns false on success. + /// Can optionally return the value of the expression. + ExprResult VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result, + VerifyICEDiagnoser &Diagnoser, + bool AllowFold = true); + ExprResult VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result, + unsigned DiagID, + bool AllowFold = true); + ExprResult VerifyIntegerConstantExpression(Expr *E, + llvm::APSInt *Result = nullptr); + + /// VerifyBitField - verifies that a bit field expression is an ICE and has + /// the correct width, and that the field type is valid. + /// Returns false on success. + /// Can optionally return whether the bit-field is of width 0 + ExprResult VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, + QualType FieldTy, bool IsMsStruct, + Expr *BitWidth, bool *ZeroWidth = nullptr); + + enum CUDAFunctionTarget { + CFT_Device, + CFT_Global, + CFT_Host, + CFT_HostDevice, + CFT_InvalidTarget + }; + + CUDAFunctionTarget IdentifyCUDATarget(const FunctionDecl *D); + + enum CUDAFunctionPreference { + CFP_Never, // Invalid caller/callee combination. + CFP_LastResort, // Lowest priority. Only in effect if + // LangOpts.CUDADisableTargetCallChecks is true. + CFP_Fallback, // Low priority caller/callee combination + CFP_Best, // Preferred caller/callee combination + }; + + /// Identifies relative preference of a given Caller/Callee + /// combination, based on their host/device attributes. + /// \param Caller function which needs address of \p Callee. + /// nullptr in case of global context. + /// \param Callee target function + /// + /// \returns preference value for particular Caller/Callee combination. + CUDAFunctionPreference IdentifyCUDAPreference(const FunctionDecl *Caller, + const FunctionDecl *Callee); + + bool CheckCUDATarget(const FunctionDecl *Caller, const FunctionDecl *Callee); + + /// Finds a function in \p Matches with highest calling priority + /// from \p Caller context and erases all functions with lower + /// calling priority. + void EraseUnwantedCUDAMatches(const FunctionDecl *Caller, + SmallVectorImpl<FunctionDecl *> &Matches); + void EraseUnwantedCUDAMatches(const FunctionDecl *Caller, + SmallVectorImpl<DeclAccessPair> &Matches); + void EraseUnwantedCUDAMatches( + const FunctionDecl *Caller, + SmallVectorImpl<std::pair<DeclAccessPair, FunctionDecl *>> &Matches); + + /// Given a implicit special member, infer its CUDA target from the + /// calls it needs to make to underlying base/field special members. + /// \param ClassDecl the class for which the member is being created. + /// \param CSM the kind of special member. + /// \param MemberDecl the special member itself. + /// \param ConstRHS true if this is a copy operation with a const object on + /// its RHS. + /// \param Diagnose true if this call should emit diagnostics. + /// \return true if there was an error inferring. + /// The result of this call is implicit CUDA target attribute(s) attached to + /// the member declaration. + bool inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, + CXXSpecialMember CSM, + CXXMethodDecl *MemberDecl, + bool ConstRHS, + bool Diagnose); + + /// \name Code completion + //@{ + /// \brief Describes the context in which code completion occurs. + enum ParserCompletionContext { + /// \brief Code completion occurs at top-level or namespace context. + PCC_Namespace, + /// \brief Code completion occurs within a class, struct, or union. + PCC_Class, + /// \brief Code completion occurs within an Objective-C interface, protocol, + /// or category. + PCC_ObjCInterface, + /// \brief Code completion occurs within an Objective-C implementation or + /// category implementation + PCC_ObjCImplementation, + /// \brief Code completion occurs within the list of instance variables + /// in an Objective-C interface, protocol, category, or implementation. + PCC_ObjCInstanceVariableList, + /// \brief Code completion occurs following one or more template + /// headers. + PCC_Template, + /// \brief Code completion occurs following one or more template + /// headers within a class. + PCC_MemberTemplate, + /// \brief Code completion occurs within an expression. + PCC_Expression, + /// \brief Code completion occurs within a statement, which may + /// also be an expression or a declaration. + PCC_Statement, + /// \brief Code completion occurs at the beginning of the + /// initialization statement (or expression) in a for loop. + PCC_ForInit, + /// \brief Code completion occurs within the condition of an if, + /// while, switch, or for statement. + PCC_Condition, + /// \brief Code completion occurs within the body of a function on a + /// recovery path, where we do not have a specific handle on our position + /// in the grammar. + PCC_RecoveryInFunction, + /// \brief Code completion occurs where only a type is permitted. + PCC_Type, + /// \brief Code completion occurs in a parenthesized expression, which + /// might also be a type cast. + PCC_ParenthesizedExpression, + /// \brief Code completion occurs within a sequence of declaration + /// specifiers within a function, method, or block. + PCC_LocalDeclarationSpecifiers + }; + + void CodeCompleteModuleImport(SourceLocation ImportLoc, ModuleIdPath Path); + void CodeCompleteOrdinaryName(Scope *S, + ParserCompletionContext CompletionContext); + void CodeCompleteDeclSpec(Scope *S, DeclSpec &DS, + bool AllowNonIdentifiers, + bool AllowNestedNameSpecifiers); + + struct CodeCompleteExpressionData; + void CodeCompleteExpression(Scope *S, + const CodeCompleteExpressionData &Data); + void CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, + SourceLocation OpLoc, + bool IsArrow); + void CodeCompletePostfixExpression(Scope *S, ExprResult LHS); + void CodeCompleteTag(Scope *S, unsigned TagSpec); + void CodeCompleteTypeQualifiers(DeclSpec &DS); + void CodeCompleteCase(Scope *S); + void CodeCompleteCall(Scope *S, Expr *Fn, ArrayRef<Expr *> Args); + void CodeCompleteConstructor(Scope *S, QualType Type, SourceLocation Loc, + ArrayRef<Expr *> Args); + void CodeCompleteInitializer(Scope *S, Decl *D); + void CodeCompleteReturn(Scope *S); + void CodeCompleteAfterIf(Scope *S); + void CodeCompleteAssignmentRHS(Scope *S, Expr *LHS); + + void CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, + bool EnteringContext); + void CodeCompleteUsing(Scope *S); + void CodeCompleteUsingDirective(Scope *S); + void CodeCompleteNamespaceDecl(Scope *S); + void CodeCompleteNamespaceAliasDecl(Scope *S); + void CodeCompleteOperatorName(Scope *S); + void CodeCompleteConstructorInitializer( + Decl *Constructor, + ArrayRef<CXXCtorInitializer *> Initializers); + + void CodeCompleteLambdaIntroducer(Scope *S, LambdaIntroducer &Intro, + bool AfterAmpersand); + + void CodeCompleteObjCAtDirective(Scope *S); + void CodeCompleteObjCAtVisibility(Scope *S); + void CodeCompleteObjCAtStatement(Scope *S); + void CodeCompleteObjCAtExpression(Scope *S); + void CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS); + void CodeCompleteObjCPropertyGetter(Scope *S); + void CodeCompleteObjCPropertySetter(Scope *S); + void CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS, + bool IsParameter); + void CodeCompleteObjCMessageReceiver(Scope *S); + void CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, + ArrayRef<IdentifierInfo *> SelIdents, + bool AtArgumentExpression); + void CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, + ArrayRef<IdentifierInfo *> SelIdents, + bool AtArgumentExpression, + bool IsSuper = false); + void CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver, + ArrayRef<IdentifierInfo *> SelIdents, + bool AtArgumentExpression, + ObjCInterfaceDecl *Super = nullptr); + void CodeCompleteObjCForCollection(Scope *S, + DeclGroupPtrTy IterationVar); + void CodeCompleteObjCSelector(Scope *S, + ArrayRef<IdentifierInfo *> SelIdents); + void CodeCompleteObjCProtocolReferences( + ArrayRef<IdentifierLocPair> Protocols); + void CodeCompleteObjCProtocolDecl(Scope *S); + void CodeCompleteObjCInterfaceDecl(Scope *S); + void CodeCompleteObjCSuperclass(Scope *S, + IdentifierInfo *ClassName, + SourceLocation ClassNameLoc); + void CodeCompleteObjCImplementationDecl(Scope *S); + void CodeCompleteObjCInterfaceCategory(Scope *S, + IdentifierInfo *ClassName, + SourceLocation ClassNameLoc); + void CodeCompleteObjCImplementationCategory(Scope *S, + IdentifierInfo *ClassName, + SourceLocation ClassNameLoc); + void CodeCompleteObjCPropertyDefinition(Scope *S); + void CodeCompleteObjCPropertySynthesizeIvar(Scope *S, + IdentifierInfo *PropertyName); + void CodeCompleteObjCMethodDecl(Scope *S, + bool IsInstanceMethod, + ParsedType ReturnType); + void CodeCompleteObjCMethodDeclSelector(Scope *S, + bool IsInstanceMethod, + bool AtParameterName, + ParsedType ReturnType, + ArrayRef<IdentifierInfo *> SelIdents); + void CodeCompletePreprocessorDirective(bool InConditional); + void CodeCompleteInPreprocessorConditionalExclusion(Scope *S); + void CodeCompletePreprocessorMacroName(bool IsDefinition); + void CodeCompletePreprocessorExpression(); + void CodeCompletePreprocessorMacroArgument(Scope *S, + IdentifierInfo *Macro, + MacroInfo *MacroInfo, + unsigned Argument); + void CodeCompleteNaturalLanguage(); + void GatherGlobalCodeCompletions(CodeCompletionAllocator &Allocator, + CodeCompletionTUInfo &CCTUInfo, + SmallVectorImpl<CodeCompletionResult> &Results); + //@} + + //===--------------------------------------------------------------------===// + // Extra semantic analysis beyond the C type system + +public: + SourceLocation getLocationOfStringLiteralByte(const StringLiteral *SL, + unsigned ByteNo) const; + +private: + void CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, + const ArraySubscriptExpr *ASE=nullptr, + bool AllowOnePastEnd=true, bool IndexNegated=false); + void CheckArrayAccess(const Expr *E); + // Used to grab the relevant information from a FormatAttr and a + // FunctionDeclaration. + struct FormatStringInfo { + unsigned FormatIdx; + unsigned FirstDataArg; + bool HasVAListArg; + }; + + static bool getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember, + FormatStringInfo *FSI); + bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, + const FunctionProtoType *Proto); + bool CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation loc, + ArrayRef<const Expr *> Args); + bool CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall, + const FunctionProtoType *Proto); + bool CheckOtherCall(CallExpr *TheCall, const FunctionProtoType *Proto); + void CheckConstructorCall(FunctionDecl *FDecl, + ArrayRef<const Expr *> Args, + const FunctionProtoType *Proto, + SourceLocation Loc); + + void checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, + ArrayRef<const Expr *> Args, bool IsMemberFunction, + SourceLocation Loc, SourceRange Range, + VariadicCallType CallType); + + bool CheckObjCString(Expr *Arg); + + ExprResult CheckBuiltinFunctionCall(FunctionDecl *FDecl, + unsigned BuiltinID, CallExpr *TheCall); + + bool CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall, + unsigned MaxWidth); + bool CheckNeonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); + bool CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); + + bool CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); + bool CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); + bool CheckSystemZBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); + bool CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); + bool CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); + + bool SemaBuiltinVAStartImpl(CallExpr *TheCall); + bool SemaBuiltinVAStart(CallExpr *TheCall); + bool SemaBuiltinMSVAStart(CallExpr *TheCall); + bool SemaBuiltinVAStartARM(CallExpr *Call); + bool SemaBuiltinUnorderedCompare(CallExpr *TheCall); + bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs); + +public: + // Used by C++ template instantiation. + ExprResult SemaBuiltinShuffleVector(CallExpr *TheCall); + ExprResult SemaConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo, + SourceLocation BuiltinLoc, + SourceLocation RParenLoc); + +private: + bool SemaBuiltinPrefetch(CallExpr *TheCall); + bool SemaBuiltinAssume(CallExpr *TheCall); + bool SemaBuiltinAssumeAligned(CallExpr *TheCall); + bool SemaBuiltinLongjmp(CallExpr *TheCall); + bool SemaBuiltinSetjmp(CallExpr *TheCall); + ExprResult SemaBuiltinAtomicOverloaded(ExprResult TheCallResult); + ExprResult SemaBuiltinNontemporalOverloaded(ExprResult TheCallResult); + ExprResult SemaAtomicOpsOverloaded(ExprResult TheCallResult, + AtomicExpr::AtomicOp Op); + bool SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, + llvm::APSInt &Result); + bool SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, + int Low, int High); + bool SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, + int ArgNum, unsigned ExpectedFieldNum, + bool AllowName); +public: + enum FormatStringType { + FST_Scanf, + FST_Printf, + FST_NSString, + FST_Strftime, + FST_Strfmon, + FST_Kprintf, + FST_FreeBSDKPrintf, + FST_OSTrace, + FST_Unknown + }; + static FormatStringType GetFormatStringType(const FormatAttr *Format); + + void CheckFormatString(const StringLiteral *FExpr, const Expr *OrigFormatExpr, + ArrayRef<const Expr *> Args, bool HasVAListArg, + unsigned format_idx, unsigned firstDataArg, + FormatStringType Type, bool inFunctionCall, + VariadicCallType CallType, + llvm::SmallBitVector &CheckedVarArgs); + + bool FormatStringHasSArg(const StringLiteral *FExpr); + + static bool GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx); + +private: + bool CheckFormatArguments(const FormatAttr *Format, + ArrayRef<const Expr *> Args, + bool IsCXXMember, + VariadicCallType CallType, + SourceLocation Loc, SourceRange Range, + llvm::SmallBitVector &CheckedVarArgs); + bool CheckFormatArguments(ArrayRef<const Expr *> Args, + bool HasVAListArg, unsigned format_idx, + unsigned firstDataArg, FormatStringType Type, + VariadicCallType CallType, + SourceLocation Loc, SourceRange range, + llvm::SmallBitVector &CheckedVarArgs); + + void CheckAbsoluteValueFunction(const CallExpr *Call, + const FunctionDecl *FDecl, + IdentifierInfo *FnInfo); + + void CheckMemaccessArguments(const CallExpr *Call, + unsigned BId, + IdentifierInfo *FnName); + + void CheckStrlcpycatArguments(const CallExpr *Call, + IdentifierInfo *FnName); + + void CheckStrncatArguments(const CallExpr *Call, + IdentifierInfo *FnName); + + void CheckReturnValExpr(Expr *RetValExp, QualType lhsType, + SourceLocation ReturnLoc, + bool isObjCMethod = false, + const AttrVec *Attrs = nullptr, + const FunctionDecl *FD = nullptr); + + void CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr* RHS); + void CheckImplicitConversions(Expr *E, SourceLocation CC = SourceLocation()); + void CheckBoolLikeConversion(Expr *E, SourceLocation CC); + void CheckForIntOverflow(Expr *E); + void CheckUnsequencedOperations(Expr *E); + + /// \brief Perform semantic checks on a completed expression. This will either + /// be a full-expression or a default argument expression. + void CheckCompletedExpr(Expr *E, SourceLocation CheckLoc = SourceLocation(), + bool IsConstexpr = false); + + void CheckBitFieldInitialization(SourceLocation InitLoc, FieldDecl *Field, + Expr *Init); + + /// \brief Check if the given expression contains 'break' or 'continue' + /// statement that produces control flow different from GCC. + void CheckBreakContinueBinding(Expr *E); + + /// \brief Check whether receiver is mutable ObjC container which + /// attempts to add itself into the container + void CheckObjCCircularContainer(ObjCMessageExpr *Message); + + void AnalyzeDeleteExprMismatch(const CXXDeleteExpr *DE); + void AnalyzeDeleteExprMismatch(FieldDecl *Field, SourceLocation DeleteLoc, + bool DeleteWasArrayForm); +public: + /// \brief Register a magic integral constant to be used as a type tag. + void RegisterTypeTagForDatatype(const IdentifierInfo *ArgumentKind, + uint64_t MagicValue, QualType Type, + bool LayoutCompatible, bool MustBeNull); + + struct TypeTagData { + TypeTagData() {} + + TypeTagData(QualType Type, bool LayoutCompatible, bool MustBeNull) : + Type(Type), LayoutCompatible(LayoutCompatible), + MustBeNull(MustBeNull) + {} + + QualType Type; + + /// If true, \c Type should be compared with other expression's types for + /// layout-compatibility. + unsigned LayoutCompatible : 1; + unsigned MustBeNull : 1; + }; + + /// A pair of ArgumentKind identifier and magic value. This uniquely + /// identifies the magic value. + typedef std::pair<const IdentifierInfo *, uint64_t> TypeTagMagicValue; + +private: + /// \brief A map from magic value to type information. + std::unique_ptr<llvm::DenseMap<TypeTagMagicValue, TypeTagData>> + TypeTagForDatatypeMagicValues; + + /// \brief Peform checks on a call of a function with argument_with_type_tag + /// or pointer_with_type_tag attributes. + void CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, + const Expr * const *ExprArgs); + + /// \brief The parser's current scope. + /// + /// The parser maintains this state here. + Scope *CurScope; + + mutable IdentifierInfo *Ident_super; + mutable IdentifierInfo *Ident___float128; + + /// Nullability type specifiers. + IdentifierInfo *Ident__Nonnull = nullptr; + IdentifierInfo *Ident__Nullable = nullptr; + IdentifierInfo *Ident__Null_unspecified = nullptr; + + IdentifierInfo *Ident_NSError = nullptr; + +protected: + friend class Parser; + friend class InitializationSequence; + friend class ASTReader; + friend class ASTDeclReader; + friend class ASTWriter; + +public: + /// Retrieve the keyword associated + IdentifierInfo *getNullabilityKeyword(NullabilityKind nullability); + + /// The struct behind the CFErrorRef pointer. + RecordDecl *CFError = nullptr; + + /// Retrieve the identifier "NSError". + IdentifierInfo *getNSErrorIdent(); + + /// \brief Retrieve the parser's current scope. + /// + /// This routine must only be used when it is certain that semantic analysis + /// and the parser are in precisely the same context, which is not the case + /// when, e.g., we are performing any kind of template instantiation. + /// Therefore, the only safe places to use this scope are in the parser + /// itself and in routines directly invoked from the parser and *never* from + /// template substitution or instantiation. + Scope *getCurScope() const { return CurScope; } + + void incrementMSManglingNumber() const { + return CurScope->incrementMSManglingNumber(); + } + + IdentifierInfo *getSuperIdentifier() const; + IdentifierInfo *getFloat128Identifier() const; + + Decl *getObjCDeclContext() const; + + DeclContext *getCurLexicalContext() const { + return OriginalLexicalContext ? OriginalLexicalContext : CurContext; + } + + AvailabilityResult getCurContextAvailability() const; + + const DeclContext *getCurObjCLexicalContext() const { + const DeclContext *DC = getCurLexicalContext(); + // A category implicitly has the attribute of the interface. + if (const ObjCCategoryDecl *CatD = dyn_cast<ObjCCategoryDecl>(DC)) + DC = CatD->getClassInterface(); + return DC; + } + + /// \brief To be used for checking whether the arguments being passed to + /// function exceeds the number of parameters expected for it. + static bool TooManyArguments(size_t NumParams, size_t NumArgs, + bool PartialOverloading = false) { + // We check whether we're just after a comma in code-completion. + if (NumArgs > 0 && PartialOverloading) + return NumArgs + 1 > NumParams; // If so, we view as an extra argument. + return NumArgs > NumParams; + } + + // Emitting members of dllexported classes is delayed until the class + // (including field initializers) is fully parsed. + SmallVector<CXXRecordDecl*, 4> DelayedDllExportClasses; +}; + +/// \brief RAII object that enters a new expression evaluation context. +class EnterExpressionEvaluationContext { + Sema &Actions; + +public: + EnterExpressionEvaluationContext(Sema &Actions, + Sema::ExpressionEvaluationContext NewContext, + Decl *LambdaContextDecl = nullptr, + bool IsDecltype = false) + : Actions(Actions) { + Actions.PushExpressionEvaluationContext(NewContext, LambdaContextDecl, + IsDecltype); + } + EnterExpressionEvaluationContext(Sema &Actions, + Sema::ExpressionEvaluationContext NewContext, + Sema::ReuseLambdaContextDecl_t, + bool IsDecltype = false) + : Actions(Actions) { + Actions.PushExpressionEvaluationContext(NewContext, + Sema::ReuseLambdaContextDecl, + IsDecltype); + } + + ~EnterExpressionEvaluationContext() { + Actions.PopExpressionEvaluationContext(); + } +}; + +DeductionFailureInfo +MakeDeductionFailureInfo(ASTContext &Context, Sema::TemplateDeductionResult TDK, + sema::TemplateDeductionInfo &Info); + +/// \brief Contains a late templated function. +/// Will be parsed at the end of the translation unit, used by Sema & Parser. +struct LateParsedTemplate { + CachedTokens Toks; + /// \brief The template function declaration to be late parsed. + Decl *D; +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Sema/SemaConsumer.h b/contrib/llvm/tools/clang/include/clang/Sema/SemaConsumer.h new file mode 100644 index 0000000..676646a --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Sema/SemaConsumer.h @@ -0,0 +1,48 @@ +//===--- SemaConsumer.h - Abstract interface for AST semantics --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the SemaConsumer class, a subclass of +// ASTConsumer that is used by AST clients that also require +// additional semantic analysis. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_SEMA_SEMACONSUMER_H +#define LLVM_CLANG_SEMA_SEMACONSUMER_H + +#include "clang/AST/ASTConsumer.h" + +namespace clang { + class Sema; + + /// \brief An abstract interface that should be implemented by + /// clients that read ASTs and then require further semantic + /// analysis of the entities in those ASTs. + class SemaConsumer : public ASTConsumer { + virtual void anchor(); + public: + SemaConsumer() { + ASTConsumer::SemaConsumer = true; + } + + /// \brief Initialize the semantic consumer with the Sema instance + /// being used to perform semantic analysis on the abstract syntax + /// tree. + virtual void InitializeSema(Sema &S) {} + + /// \brief Inform the semantic consumer that Sema is no longer available. + virtual void ForgetSema() {} + + // isa/cast/dyn_cast support + static bool classof(const ASTConsumer *Consumer) { + return Consumer->SemaConsumer; + } + }; +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Sema/SemaDiagnostic.h b/contrib/llvm/tools/clang/include/clang/Sema/SemaDiagnostic.h new file mode 100644 index 0000000..7740d5e --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Sema/SemaDiagnostic.h @@ -0,0 +1,28 @@ +//===--- DiagnosticSema.h - Diagnostics for libsema -------------*- 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_SEMA_SEMADIAGNOSTIC_H +#define LLVM_CLANG_SEMA_SEMADIAGNOSTIC_H + +#include "clang/Basic/Diagnostic.h" + +namespace clang { + namespace diag { + enum { +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\ + SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM, +#define SEMASTART +#include "clang/Basic/DiagnosticSemaKinds.inc" +#undef DIAG + NUM_BUILTIN_SEMA_DIAGNOSTICS + }; + } // end namespace diag +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Sema/SemaFixItUtils.h b/contrib/llvm/tools/clang/include/clang/Sema/SemaFixItUtils.h new file mode 100644 index 0000000..343ccfb --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Sema/SemaFixItUtils.h @@ -0,0 +1,91 @@ +//===--- SemaFixItUtils.h - Sema FixIts -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines helper classes for generation of Sema FixItHints. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_SEMA_SEMAFIXITUTILS_H +#define LLVM_CLANG_SEMA_SEMAFIXITUTILS_H + +#include "clang/AST/Expr.h" + +namespace clang { + +enum OverloadFixItKind { + OFIK_Undefined = 0, + OFIK_Dereference, + OFIK_TakeAddress, + OFIK_RemoveDereference, + OFIK_RemoveTakeAddress +}; + +class Sema; + +/// The class facilities generation and storage of conversion FixIts. Hints for +/// new conversions are added using TryToFixConversion method. The default type +/// conversion checker can be reset. +struct ConversionFixItGenerator { + /// Performs a simple check to see if From type can be converted to To type. + static bool compareTypesSimple(CanQualType From, + CanQualType To, + Sema &S, + SourceLocation Loc, + ExprValueKind FromVK); + + /// The list of Hints generated so far. + std::vector<FixItHint> Hints; + + /// The number of Conversions fixed. This can be different from the size + /// of the Hints vector since we allow multiple FixIts per conversion. + unsigned NumConversionsFixed; + + /// The type of fix applied. If multiple conversions are fixed, corresponds + /// to the kid of the very first conversion. + OverloadFixItKind Kind; + + typedef bool (*TypeComparisonFuncTy) (const CanQualType FromTy, + const CanQualType ToTy, + Sema &S, + SourceLocation Loc, + ExprValueKind FromVK); + /// The type comparison function used to decide if expression FromExpr of + /// type FromTy can be converted to ToTy. For example, one could check if + /// an implicit conversion exists. Returns true if comparison exists. + TypeComparisonFuncTy CompareTypes; + + ConversionFixItGenerator(TypeComparisonFuncTy Foo): NumConversionsFixed(0), + Kind(OFIK_Undefined), + CompareTypes(Foo) {} + + ConversionFixItGenerator(): NumConversionsFixed(0), + Kind(OFIK_Undefined), + CompareTypes(compareTypesSimple) {} + + /// Resets the default conversion checker method. + void setConversionChecker(TypeComparisonFuncTy Foo) { + CompareTypes = Foo; + } + + /// If possible, generates and stores a fix for the given conversion. + bool tryToFixConversion(const Expr *FromExpr, + const QualType FromQTy, const QualType ToQTy, + Sema &S); + + void clear() { + Hints.clear(); + NumConversionsFixed = 0; + } + + bool isNull() { + return (NumConversionsFixed == 0); + } +}; + +} // endof namespace clang +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Sema/SemaInternal.h b/contrib/llvm/tools/clang/include/clang/Sema/SemaInternal.h new file mode 100644 index 0000000..60c6598 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Sema/SemaInternal.h @@ -0,0 +1,346 @@ +//===--- SemaInternal.h - Internal Sema Interfaces --------------*- 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 common API and #includes for the internal +// implementation of Sema. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMAINTERNAL_H +#define LLVM_CLANG_SEMA_SEMAINTERNAL_H + +#include "clang/AST/ASTContext.h" +#include "clang/Sema/Lookup.h" +#include "clang/Sema/Sema.h" +#include "clang/Sema/SemaDiagnostic.h" + +namespace clang { + +inline PartialDiagnostic Sema::PDiag(unsigned DiagID) { + return PartialDiagnostic(DiagID, Context.getDiagAllocator()); +} + +inline bool +FTIHasSingleVoidParameter(const DeclaratorChunk::FunctionTypeInfo &FTI) { + return FTI.NumParams == 1 && !FTI.isVariadic && + FTI.Params[0].Ident == nullptr && FTI.Params[0].Param && + cast<ParmVarDecl>(FTI.Params[0].Param)->getType()->isVoidType(); +} + +inline bool +FTIHasNonVoidParameters(const DeclaratorChunk::FunctionTypeInfo &FTI) { + // Assume FTI is well-formed. + return FTI.NumParams && !FTIHasSingleVoidParameter(FTI); +} + +// This requires the variable to be non-dependent and the initializer +// to not be value dependent. +inline bool IsVariableAConstantExpression(VarDecl *Var, ASTContext &Context) { + const VarDecl *DefVD = nullptr; + return !isa<ParmVarDecl>(Var) && + Var->isUsableInConstantExpressions(Context) && + Var->getAnyInitializer(DefVD) && DefVD->checkInitIsICE(); +} + +// Helper function to check whether D's attributes match current CUDA mode. +// Decls with mismatched attributes and related diagnostics may have to be +// ignored during this CUDA compilation pass. +inline bool DeclAttrsMatchCUDAMode(const LangOptions &LangOpts, Decl *D) { + if (!LangOpts.CUDA || !D) + return true; + bool isDeviceSideDecl = D->hasAttr<CUDADeviceAttr>() || + D->hasAttr<CUDASharedAttr>() || + D->hasAttr<CUDAGlobalAttr>(); + return isDeviceSideDecl == LangOpts.CUDAIsDevice; +} + +// Directly mark a variable odr-used. Given a choice, prefer to use +// MarkVariableReferenced since it does additional checks and then +// calls MarkVarDeclODRUsed. +// If the variable must be captured: +// - if FunctionScopeIndexToStopAt is null, capture it in the CurContext +// - else capture it in the DeclContext that maps to the +// *FunctionScopeIndexToStopAt on the FunctionScopeInfo stack. +inline void MarkVarDeclODRUsed(VarDecl *Var, + SourceLocation Loc, Sema &SemaRef, + const unsigned *const FunctionScopeIndexToStopAt) { + // Keep track of used but undefined variables. + // FIXME: We shouldn't suppress this warning for static data members. + if (Var->hasDefinition(SemaRef.Context) == VarDecl::DeclarationOnly && + !Var->isExternallyVisible() && + !(Var->isStaticDataMember() && Var->hasInit())) { + SourceLocation &old = SemaRef.UndefinedButUsed[Var->getCanonicalDecl()]; + if (old.isInvalid()) old = Loc; + } + QualType CaptureType, DeclRefType; + SemaRef.tryCaptureVariable(Var, Loc, Sema::TryCapture_Implicit, + /*EllipsisLoc*/ SourceLocation(), + /*BuildAndDiagnose*/ true, + CaptureType, DeclRefType, + FunctionScopeIndexToStopAt); + + Var->markUsed(SemaRef.Context); +} + +/// Return a DLL attribute from the declaration. +inline InheritableAttr *getDLLAttr(Decl *D) { + assert(!(D->hasAttr<DLLImportAttr>() && D->hasAttr<DLLExportAttr>()) && + "A declaration cannot be both dllimport and dllexport."); + if (auto *Import = D->getAttr<DLLImportAttr>()) + return Import; + if (auto *Export = D->getAttr<DLLExportAttr>()) + return Export; + return nullptr; +} + +class TypoCorrectionConsumer : public VisibleDeclConsumer { + typedef SmallVector<TypoCorrection, 1> TypoResultList; + typedef llvm::StringMap<TypoResultList> TypoResultsMap; + typedef std::map<unsigned, TypoResultsMap> TypoEditDistanceMap; + +public: + TypoCorrectionConsumer(Sema &SemaRef, + const DeclarationNameInfo &TypoName, + Sema::LookupNameKind LookupKind, + Scope *S, CXXScopeSpec *SS, + std::unique_ptr<CorrectionCandidateCallback> CCC, + DeclContext *MemberContext, + bool EnteringContext) + : Typo(TypoName.getName().getAsIdentifierInfo()), CurrentTCIndex(0), + SavedTCIndex(0), SemaRef(SemaRef), S(S), + SS(SS ? llvm::make_unique<CXXScopeSpec>(*SS) : nullptr), + CorrectionValidator(std::move(CCC)), MemberContext(MemberContext), + Result(SemaRef, TypoName, LookupKind), + Namespaces(SemaRef.Context, SemaRef.CurContext, SS), + EnteringContext(EnteringContext), SearchNamespaces(false) { + Result.suppressDiagnostics(); + // Arrange for ValidatedCorrections[0] to always be an empty correction. + ValidatedCorrections.push_back(TypoCorrection()); + } + + bool includeHiddenDecls() const override { return true; } + + // Methods for adding potential corrections to the consumer. + void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx, + bool InBaseClass) override; + void FoundName(StringRef Name); + void addKeywordResult(StringRef Keyword); + void addCorrection(TypoCorrection Correction); + + bool empty() const { + return CorrectionResults.empty() && ValidatedCorrections.size() == 1; + } + + /// \brief Return the list of TypoCorrections for the given identifier from + /// the set of corrections that have the closest edit distance, if any. + TypoResultList &operator[](StringRef Name) { + return CorrectionResults.begin()->second[Name]; + } + + /// \brief Return the edit distance of the corrections that have the + /// closest/best edit distance from the original typop. + unsigned getBestEditDistance(bool Normalized) { + if (CorrectionResults.empty()) + return (std::numeric_limits<unsigned>::max)(); + + unsigned BestED = CorrectionResults.begin()->first; + return Normalized ? TypoCorrection::NormalizeEditDistance(BestED) : BestED; + } + + /// \brief Set-up method to add to the consumer the set of namespaces to use + /// in performing corrections to nested name specifiers. This method also + /// implicitly adds all of the known classes in the current AST context to the + /// to the consumer for correcting nested name specifiers. + void + addNamespaces(const llvm::MapVector<NamespaceDecl *, bool> &KnownNamespaces); + + /// \brief Return the next typo correction that passes all internal filters + /// and is deemed valid by the consumer's CorrectionCandidateCallback, + /// starting with the corrections that have the closest edit distance. An + /// empty TypoCorrection is returned once no more viable corrections remain + /// in the consumer. + const TypoCorrection &getNextCorrection(); + + /// \brief Get the last correction returned by getNextCorrection(). + const TypoCorrection &getCurrentCorrection() { + return CurrentTCIndex < ValidatedCorrections.size() + ? ValidatedCorrections[CurrentTCIndex] + : ValidatedCorrections[0]; // The empty correction. + } + + /// \brief Return the next typo correction like getNextCorrection, but keep + /// the internal state pointed to the current correction (i.e. the next time + /// getNextCorrection is called, it will return the same correction returned + /// by peekNextcorrection). + const TypoCorrection &peekNextCorrection() { + auto Current = CurrentTCIndex; + const TypoCorrection &TC = getNextCorrection(); + CurrentTCIndex = Current; + return TC; + } + + /// \brief Reset the consumer's position in the stream of viable corrections + /// (i.e. getNextCorrection() will return each of the previously returned + /// corrections in order before returning any new corrections). + void resetCorrectionStream() { + CurrentTCIndex = 0; + } + + /// \brief Return whether the end of the stream of corrections has been + /// reached. + bool finished() { + return CorrectionResults.empty() && + CurrentTCIndex >= ValidatedCorrections.size(); + } + + /// \brief Save the current position in the correction stream (overwriting any + /// previously saved position). + void saveCurrentPosition() { + SavedTCIndex = CurrentTCIndex; + } + + /// \brief Restore the saved position in the correction stream. + void restoreSavedPosition() { + CurrentTCIndex = SavedTCIndex; + } + + ASTContext &getContext() const { return SemaRef.Context; } + const LookupResult &getLookupResult() const { return Result; } + + bool isAddressOfOperand() const { return CorrectionValidator->IsAddressOfOperand; } + const CXXScopeSpec *getSS() const { return SS.get(); } + Scope *getScope() const { return S; } + +private: + class NamespaceSpecifierSet { + struct SpecifierInfo { + DeclContext* DeclCtx; + NestedNameSpecifier* NameSpecifier; + unsigned EditDistance; + }; + + typedef SmallVector<DeclContext*, 4> DeclContextList; + typedef SmallVector<SpecifierInfo, 16> SpecifierInfoList; + + ASTContext &Context; + DeclContextList CurContextChain; + std::string CurNameSpecifier; + SmallVector<const IdentifierInfo*, 4> CurContextIdentifiers; + SmallVector<const IdentifierInfo*, 4> CurNameSpecifierIdentifiers; + + std::map<unsigned, SpecifierInfoList> DistanceMap; + + /// \brief Helper for building the list of DeclContexts between the current + /// context and the top of the translation unit + static DeclContextList buildContextChain(DeclContext *Start); + + unsigned buildNestedNameSpecifier(DeclContextList &DeclChain, + NestedNameSpecifier *&NNS); + + public: + NamespaceSpecifierSet(ASTContext &Context, DeclContext *CurContext, + CXXScopeSpec *CurScopeSpec); + + /// \brief Add the DeclContext (a namespace or record) to the set, computing + /// the corresponding NestedNameSpecifier and its distance in the process. + void addNameSpecifier(DeclContext *Ctx); + + /// \brief Provides flat iteration over specifiers, sorted by distance. + class iterator + : public llvm::iterator_facade_base<iterator, std::forward_iterator_tag, + SpecifierInfo> { + /// Always points to the last element in the distance map. + const std::map<unsigned, SpecifierInfoList>::iterator OuterBack; + /// Iterator on the distance map. + std::map<unsigned, SpecifierInfoList>::iterator Outer; + /// Iterator on an element in the distance map. + SpecifierInfoList::iterator Inner; + + public: + iterator(NamespaceSpecifierSet &Set, bool IsAtEnd) + : OuterBack(std::prev(Set.DistanceMap.end())), + Outer(Set.DistanceMap.begin()), + Inner(!IsAtEnd ? Outer->second.begin() : OuterBack->second.end()) { + assert(!Set.DistanceMap.empty()); + } + + iterator &operator++() { + ++Inner; + if (Inner == Outer->second.end() && Outer != OuterBack) { + ++Outer; + Inner = Outer->second.begin(); + } + return *this; + } + + SpecifierInfo &operator*() { return *Inner; } + bool operator==(const iterator &RHS) const { return Inner == RHS.Inner; } + }; + + iterator begin() { return iterator(*this, /*IsAtEnd=*/false); } + iterator end() { return iterator(*this, /*IsAtEnd=*/true); } + }; + + void addName(StringRef Name, NamedDecl *ND, + NestedNameSpecifier *NNS = nullptr, bool isKeyword = false); + + /// \brief Find any visible decls for the given typo correction candidate. + /// If none are found, it to the set of candidates for which qualified lookups + /// will be performed to find possible nested name specifier changes. + bool resolveCorrection(TypoCorrection &Candidate); + + /// \brief Perform qualified lookups on the queued set of typo correction + /// candidates and add the nested name specifier changes to each candidate if + /// a lookup succeeds (at which point the candidate will be returned to the + /// main pool of potential corrections). + void performQualifiedLookups(); + + /// \brief The name written that is a typo in the source. + IdentifierInfo *Typo; + + /// \brief The results found that have the smallest edit distance + /// found (so far) with the typo name. + /// + /// The pointer value being set to the current DeclContext indicates + /// whether there is a keyword with this name. + TypoEditDistanceMap CorrectionResults; + + SmallVector<TypoCorrection, 4> ValidatedCorrections; + size_t CurrentTCIndex; + size_t SavedTCIndex; + + Sema &SemaRef; + Scope *S; + std::unique_ptr<CXXScopeSpec> SS; + std::unique_ptr<CorrectionCandidateCallback> CorrectionValidator; + DeclContext *MemberContext; + LookupResult Result; + NamespaceSpecifierSet Namespaces; + SmallVector<TypoCorrection, 2> QualifiedResults; + bool EnteringContext; + bool SearchNamespaces; +}; + +inline Sema::TypoExprState::TypoExprState() {} + +inline Sema::TypoExprState::TypoExprState(TypoExprState &&other) LLVM_NOEXCEPT { + *this = std::move(other); +} + +inline Sema::TypoExprState &Sema::TypoExprState::operator=( + Sema::TypoExprState &&other) LLVM_NOEXCEPT { + Consumer = std::move(other.Consumer); + DiagHandler = std::move(other.DiagHandler); + RecoveryHandler = std::move(other.RecoveryHandler); + return *this; +} + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Sema/SemaLambda.h b/contrib/llvm/tools/clang/include/clang/Sema/SemaLambda.h new file mode 100644 index 0000000..d043e2c --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Sema/SemaLambda.h @@ -0,0 +1,36 @@ +//===--- SemaLambda.h - Lambda Helper Functions --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file provides some common utility functions for processing +/// Lambdas. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMALAMBDA_H +#define LLVM_CLANG_SEMA_SEMALAMBDA_H +#include "clang/AST/ASTLambda.h" +#include "clang/Sema/ScopeInfo.h" +namespace clang { + + +/// \brief Examines the FunctionScopeInfo stack to determine the nearest +/// enclosing lambda (to the current lambda) that is 'capture-capable' for +/// the variable referenced in the current lambda (i.e. \p VarToCapture). +/// If successful, returns the index into Sema's FunctionScopeInfo stack +/// of the capture-capable lambda's LambdaScopeInfo. +/// See Implementation for more detailed comments. + +Optional<unsigned> getStackIndexOfNearestEnclosingCaptureCapableLambda( + ArrayRef<const sema::FunctionScopeInfo *> FunctionScopes, + VarDecl *VarToCapture, Sema &S); + +} // clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Sema/Template.h b/contrib/llvm/tools/clang/include/clang/Sema/Template.h new file mode 100644 index 0000000..c092630 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Sema/Template.h @@ -0,0 +1,519 @@ +//===------- SemaTemplate.h - 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 types used in the semantic analysis of C++ templates. +// +//===----------------------------------------------------------------------===/ +#ifndef LLVM_CLANG_SEMA_TEMPLATE_H +#define LLVM_CLANG_SEMA_TEMPLATE_H + +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/Sema/Sema.h" +#include "llvm/ADT/SmallVector.h" +#include <cassert> +#include <utility> + +namespace clang { + /// \brief Data structure that captures multiple levels of template argument + /// lists for use in template instantiation. + /// + /// Multiple levels of template arguments occur when instantiating the + /// definitions of member templates. For example: + /// + /// \code + /// template<typename T> + /// struct X { + /// template<T Value> + /// struct Y { + /// void f(); + /// }; + /// }; + /// \endcode + /// + /// When instantiating X<int>::Y<17>::f, the multi-level template argument + /// list will contain a template argument list (int) at depth 0 and a + /// template argument list (17) at depth 1. + class MultiLevelTemplateArgumentList { + /// \brief The template argument list at a certain template depth + typedef ArrayRef<TemplateArgument> ArgList; + + /// \brief The template argument lists, stored from the innermost template + /// argument list (first) to the outermost template argument list (last). + SmallVector<ArgList, 4> TemplateArgumentLists; + + public: + /// \brief Construct an empty set of template argument lists. + MultiLevelTemplateArgumentList() { } + + /// \brief Construct a single-level template argument list. + explicit + MultiLevelTemplateArgumentList(const TemplateArgumentList &TemplateArgs) { + addOuterTemplateArguments(&TemplateArgs); + } + + /// \brief Determine the number of levels in this template argument + /// list. + unsigned getNumLevels() const { return TemplateArgumentLists.size(); } + + /// \brief Retrieve the template argument at a given depth and index. + const TemplateArgument &operator()(unsigned Depth, unsigned Index) const { + assert(Depth < TemplateArgumentLists.size()); + assert(Index < TemplateArgumentLists[getNumLevels() - Depth - 1].size()); + return TemplateArgumentLists[getNumLevels() - Depth - 1][Index]; + } + + /// \brief Determine whether there is a non-NULL template argument at the + /// given depth and index. + /// + /// There must exist a template argument list at the given depth. + bool hasTemplateArgument(unsigned Depth, unsigned Index) const { + assert(Depth < TemplateArgumentLists.size()); + + if (Index >= TemplateArgumentLists[getNumLevels() - Depth - 1].size()) + return false; + + return !(*this)(Depth, Index).isNull(); + } + + /// \brief Clear out a specific template argument. + void setArgument(unsigned Depth, unsigned Index, + TemplateArgument Arg) { + assert(Depth < TemplateArgumentLists.size()); + assert(Index < TemplateArgumentLists[getNumLevels() - Depth - 1].size()); + const_cast<TemplateArgument&>( + TemplateArgumentLists[getNumLevels() - Depth - 1][Index]) + = Arg; + } + + /// \brief Add a new outermost level to the multi-level template argument + /// list. + void addOuterTemplateArguments(const TemplateArgumentList *TemplateArgs) { + addOuterTemplateArguments(ArgList(TemplateArgs->data(), + TemplateArgs->size())); + } + + /// \brief Add a new outmost level to the multi-level template argument + /// list. + void addOuterTemplateArguments(ArgList Args) { + TemplateArgumentLists.push_back(Args); + } + + /// \brief Retrieve the innermost template argument list. + const ArgList &getInnermost() const { + return TemplateArgumentLists.front(); + } + }; + + /// \brief The context in which partial ordering of function templates occurs. + enum TPOC { + /// \brief Partial ordering of function templates for a function call. + TPOC_Call, + /// \brief Partial ordering of function templates for a call to a + /// conversion function. + TPOC_Conversion, + /// \brief Partial ordering of function templates in other contexts, e.g., + /// taking the address of a function template or matching a function + /// template specialization to a function template. + TPOC_Other + }; + + // This is lame but unavoidable in a world without forward + // declarations of enums. The alternatives are to either pollute + // Sema.h (by including this file) or sacrifice type safety (by + // making Sema.h declare things as enums). + class TemplatePartialOrderingContext { + TPOC Value; + public: + TemplatePartialOrderingContext(TPOC Value) : Value(Value) {} + operator TPOC() const { return Value; } + }; + + /// \brief Captures a template argument whose value has been deduced + /// via c++ template argument deduction. + class DeducedTemplateArgument : public TemplateArgument { + /// \brief For a non-type template argument, whether the value was + /// deduced from an array bound. + bool DeducedFromArrayBound; + + public: + DeducedTemplateArgument() + : TemplateArgument(), DeducedFromArrayBound(false) { } + + DeducedTemplateArgument(const TemplateArgument &Arg, + bool DeducedFromArrayBound = false) + : TemplateArgument(Arg), DeducedFromArrayBound(DeducedFromArrayBound) { } + + /// \brief Construct an integral non-type template argument that + /// has been deduced, possibly from an array bound. + DeducedTemplateArgument(ASTContext &Ctx, + const llvm::APSInt &Value, + QualType ValueType, + bool DeducedFromArrayBound) + : TemplateArgument(Ctx, Value, ValueType), + DeducedFromArrayBound(DeducedFromArrayBound) { } + + /// \brief For a non-type template argument, determine whether the + /// template argument was deduced from an array bound. + bool wasDeducedFromArrayBound() const { return DeducedFromArrayBound; } + + /// \brief Specify whether the given non-type template argument + /// was deduced from an array bound. + void setDeducedFromArrayBound(bool Deduced) { + DeducedFromArrayBound = Deduced; + } + }; + + /// \brief A stack-allocated class that identifies which local + /// variable declaration instantiations are present in this scope. + /// + /// A new instance of this class type will be created whenever we + /// instantiate a new function declaration, which will have its own + /// set of parameter declarations. + class LocalInstantiationScope { + public: + /// \brief A set of declarations. + typedef SmallVector<ParmVarDecl *, 4> DeclArgumentPack; + + private: + /// \brief Reference to the semantic analysis that is performing + /// this template instantiation. + Sema &SemaRef; + + typedef llvm::SmallDenseMap< + const Decl *, llvm::PointerUnion<Decl *, DeclArgumentPack *>, 4> + LocalDeclsMap; + + /// \brief A mapping from local declarations that occur + /// within a template to their instantiations. + /// + /// This mapping is used during instantiation to keep track of, + /// e.g., function parameter and variable declarations. For example, + /// given: + /// + /// \code + /// template<typename T> T add(T x, T y) { return x + y; } + /// \endcode + /// + /// when we instantiate add<int>, we will introduce a mapping from + /// the ParmVarDecl for 'x' that occurs in the template to the + /// instantiated ParmVarDecl for 'x'. + /// + /// For a parameter pack, the local instantiation scope may contain a + /// set of instantiated parameters. This is stored as a DeclArgumentPack + /// pointer. + LocalDeclsMap LocalDecls; + + /// \brief The set of argument packs we've allocated. + SmallVector<DeclArgumentPack *, 1> ArgumentPacks; + + /// \brief The outer scope, which contains local variable + /// definitions from some other instantiation (that may not be + /// relevant to this particular scope). + LocalInstantiationScope *Outer; + + /// \brief Whether we have already exited this scope. + bool Exited; + + /// \brief Whether to combine this scope with the outer scope, such that + /// lookup will search our outer scope. + bool CombineWithOuterScope; + + /// \brief If non-NULL, the template parameter pack that has been + /// partially substituted per C++0x [temp.arg.explicit]p9. + NamedDecl *PartiallySubstitutedPack; + + /// \brief If \c PartiallySubstitutedPack is non-null, the set of + /// explicitly-specified template arguments in that pack. + const TemplateArgument *ArgsInPartiallySubstitutedPack; + + /// \brief If \c PartiallySubstitutedPack, the number of + /// explicitly-specified template arguments in + /// ArgsInPartiallySubstitutedPack. + unsigned NumArgsInPartiallySubstitutedPack; + + // This class is non-copyable + LocalInstantiationScope( + const LocalInstantiationScope &) = delete; + void operator=(const LocalInstantiationScope &) = delete; + + public: + LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false) + : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope), + Exited(false), CombineWithOuterScope(CombineWithOuterScope), + PartiallySubstitutedPack(nullptr) + { + SemaRef.CurrentInstantiationScope = this; + } + + ~LocalInstantiationScope() { + Exit(); + } + + const Sema &getSema() const { return SemaRef; } + + /// \brief Exit this local instantiation scope early. + void Exit() { + if (Exited) + return; + + for (unsigned I = 0, N = ArgumentPacks.size(); I != N; ++I) + delete ArgumentPacks[I]; + + SemaRef.CurrentInstantiationScope = Outer; + Exited = true; + } + + /// \brief Clone this scope, and all outer scopes, down to the given + /// outermost scope. + LocalInstantiationScope *cloneScopes(LocalInstantiationScope *Outermost) { + if (this == Outermost) return this; + + // Save the current scope from SemaRef since the LocalInstantiationScope + // will overwrite it on construction + LocalInstantiationScope *oldScope = SemaRef.CurrentInstantiationScope; + + LocalInstantiationScope *newScope = + new LocalInstantiationScope(SemaRef, CombineWithOuterScope); + + newScope->Outer = nullptr; + if (Outer) + newScope->Outer = Outer->cloneScopes(Outermost); + + newScope->PartiallySubstitutedPack = PartiallySubstitutedPack; + newScope->ArgsInPartiallySubstitutedPack = ArgsInPartiallySubstitutedPack; + newScope->NumArgsInPartiallySubstitutedPack = + NumArgsInPartiallySubstitutedPack; + + for (LocalDeclsMap::iterator I = LocalDecls.begin(), E = LocalDecls.end(); + I != E; ++I) { + const Decl *D = I->first; + llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = + newScope->LocalDecls[D]; + if (I->second.is<Decl *>()) { + Stored = I->second.get<Decl *>(); + } else { + DeclArgumentPack *OldPack = I->second.get<DeclArgumentPack *>(); + DeclArgumentPack *NewPack = new DeclArgumentPack(*OldPack); + Stored = NewPack; + newScope->ArgumentPacks.push_back(NewPack); + } + } + // Restore the saved scope to SemaRef + SemaRef.CurrentInstantiationScope = oldScope; + return newScope; + } + + /// \brief deletes the given scope, and all otuer scopes, down to the + /// given outermost scope. + static void deleteScopes(LocalInstantiationScope *Scope, + LocalInstantiationScope *Outermost) { + while (Scope && Scope != Outermost) { + LocalInstantiationScope *Out = Scope->Outer; + delete Scope; + Scope = Out; + } + } + + /// \brief Find the instantiation of the declaration D within the current + /// instantiation scope. + /// + /// \param D The declaration whose instantiation we are searching for. + /// + /// \returns A pointer to the declaration or argument pack of declarations + /// to which the declaration \c D is instantiated, if found. Otherwise, + /// returns NULL. + llvm::PointerUnion<Decl *, DeclArgumentPack *> * + findInstantiationOf(const Decl *D); + + void InstantiatedLocal(const Decl *D, Decl *Inst); + void InstantiatedLocalPackArg(const Decl *D, ParmVarDecl *Inst); + void MakeInstantiatedLocalArgPack(const Decl *D); + + /// \brief Note that the given parameter pack has been partially substituted + /// via explicit specification of template arguments + /// (C++0x [temp.arg.explicit]p9). + /// + /// \param Pack The parameter pack, which will always be a template + /// parameter pack. + /// + /// \param ExplicitArgs The explicitly-specified template arguments provided + /// for this parameter pack. + /// + /// \param NumExplicitArgs The number of explicitly-specified template + /// arguments provided for this parameter pack. + void SetPartiallySubstitutedPack(NamedDecl *Pack, + const TemplateArgument *ExplicitArgs, + unsigned NumExplicitArgs); + + /// \brief Reset the partially-substituted pack when it is no longer of + /// interest. + void ResetPartiallySubstitutedPack() { + assert(PartiallySubstitutedPack && "No partially-substituted pack"); + PartiallySubstitutedPack = nullptr; + ArgsInPartiallySubstitutedPack = nullptr; + NumArgsInPartiallySubstitutedPack = 0; + } + + /// \brief Retrieve the partially-substitued template parameter pack. + /// + /// If there is no partially-substituted parameter pack, returns NULL. + NamedDecl * + getPartiallySubstitutedPack(const TemplateArgument **ExplicitArgs = nullptr, + unsigned *NumExplicitArgs = nullptr) const; + }; + + class TemplateDeclInstantiator + : public DeclVisitor<TemplateDeclInstantiator, Decl *> + { + Sema &SemaRef; + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex; + DeclContext *Owner; + const MultiLevelTemplateArgumentList &TemplateArgs; + Sema::LateInstantiatedAttrVec* LateAttrs; + LocalInstantiationScope *StartingScope; + + /// \brief A list of out-of-line class template partial + /// specializations that will need to be instantiated after the + /// enclosing class's instantiation is complete. + SmallVector<std::pair<ClassTemplateDecl *, + ClassTemplatePartialSpecializationDecl *>, 4> + OutOfLinePartialSpecs; + + /// \brief A list of out-of-line variable template partial + /// specializations that will need to be instantiated after the + /// enclosing variable's instantiation is complete. + /// FIXME: Verify that this is needed. + SmallVector< + std::pair<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>, 4> + OutOfLineVarPartialSpecs; + + public: + TemplateDeclInstantiator(Sema &SemaRef, DeclContext *Owner, + const MultiLevelTemplateArgumentList &TemplateArgs) + : SemaRef(SemaRef), + SubstIndex(SemaRef, SemaRef.ArgumentPackSubstitutionIndex), + Owner(Owner), TemplateArgs(TemplateArgs), LateAttrs(nullptr), + StartingScope(nullptr) {} + +// Define all the decl visitors using DeclNodes.inc +#define DECL(DERIVED, BASE) \ + Decl *Visit ## DERIVED ## Decl(DERIVED ## Decl *D); +#define ABSTRACT_DECL(DECL) + +// Decls which never appear inside a class or function. +#define OBJCCONTAINER(DERIVED, BASE) +#define FILESCOPEASM(DERIVED, BASE) +#define IMPORT(DERIVED, BASE) +#define LINKAGESPEC(DERIVED, BASE) +#define OBJCCOMPATIBLEALIAS(DERIVED, BASE) +#define OBJCMETHOD(DERIVED, BASE) +#define OBJCTYPEPARAM(DERIVED, BASE) +#define OBJCIVAR(DERIVED, BASE) +#define OBJCPROPERTY(DERIVED, BASE) +#define OBJCPROPERTYIMPL(DERIVED, BASE) +#define EMPTY(DERIVED, BASE) + +// Decls which use special-case instantiation code. +#define BLOCK(DERIVED, BASE) +#define CAPTURED(DERIVED, BASE) +#define IMPLICITPARAM(DERIVED, BASE) + +#include "clang/AST/DeclNodes.inc" + + // A few supplemental visitor functions. + Decl *VisitCXXMethodDecl(CXXMethodDecl *D, + TemplateParameterList *TemplateParams, + bool IsClassScopeSpecialization = false); + Decl *VisitFunctionDecl(FunctionDecl *D, + TemplateParameterList *TemplateParams); + Decl *VisitDecl(Decl *D); + Decl *VisitVarDecl(VarDecl *D, bool InstantiatingVarTemplate); + + // Enable late instantiation of attributes. Late instantiated attributes + // will be stored in LA. + void enableLateAttributeInstantiation(Sema::LateInstantiatedAttrVec *LA) { + LateAttrs = LA; + StartingScope = SemaRef.CurrentInstantiationScope; + } + + // Disable late instantiation of attributes. + void disableLateAttributeInstantiation() { + LateAttrs = nullptr; + StartingScope = nullptr; + } + + LocalInstantiationScope *getStartingScope() const { return StartingScope; } + + typedef + SmallVectorImpl<std::pair<ClassTemplateDecl *, + ClassTemplatePartialSpecializationDecl *> > + ::iterator + delayed_partial_spec_iterator; + + typedef SmallVectorImpl<std::pair< + VarTemplateDecl *, VarTemplatePartialSpecializationDecl *> >::iterator + delayed_var_partial_spec_iterator; + + /// \brief Return an iterator to the beginning of the set of + /// "delayed" partial specializations, which must be passed to + /// InstantiateClassTemplatePartialSpecialization once the class + /// definition has been completed. + delayed_partial_spec_iterator delayed_partial_spec_begin() { + return OutOfLinePartialSpecs.begin(); + } + + delayed_var_partial_spec_iterator delayed_var_partial_spec_begin() { + return OutOfLineVarPartialSpecs.begin(); + } + + /// \brief Return an iterator to the end of the set of + /// "delayed" partial specializations, which must be passed to + /// InstantiateClassTemplatePartialSpecialization once the class + /// definition has been completed. + delayed_partial_spec_iterator delayed_partial_spec_end() { + return OutOfLinePartialSpecs.end(); + } + + delayed_var_partial_spec_iterator delayed_var_partial_spec_end() { + return OutOfLineVarPartialSpecs.end(); + } + + // Helper functions for instantiating methods. + TypeSourceInfo *SubstFunctionType(FunctionDecl *D, + SmallVectorImpl<ParmVarDecl *> &Params); + bool InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl); + bool InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl); + + TemplateParameterList * + SubstTemplateParams(TemplateParameterList *List); + + bool SubstQualifier(const DeclaratorDecl *OldDecl, + DeclaratorDecl *NewDecl); + bool SubstQualifier(const TagDecl *OldDecl, + TagDecl *NewDecl); + + Decl *VisitVarTemplateSpecializationDecl( + VarTemplateDecl *VarTemplate, VarDecl *FromVar, void *InsertPos, + const TemplateArgumentListInfo &TemplateArgsInfo, + ArrayRef<TemplateArgument> Converted); + + Decl *InstantiateTypedefNameDecl(TypedefNameDecl *D, bool IsTypeAlias); + ClassTemplatePartialSpecializationDecl * + InstantiateClassTemplatePartialSpecialization( + ClassTemplateDecl *ClassTemplate, + ClassTemplatePartialSpecializationDecl *PartialSpec); + VarTemplatePartialSpecializationDecl * + InstantiateVarTemplatePartialSpecialization( + VarTemplateDecl *VarTemplate, + VarTemplatePartialSpecializationDecl *PartialSpec); + void InstantiateEnumDefinition(EnumDecl *Enum, EnumDecl *Pattern); + }; +} + +#endif // LLVM_CLANG_SEMA_TEMPLATE_H diff --git a/contrib/llvm/tools/clang/include/clang/Sema/TemplateDeduction.h b/contrib/llvm/tools/clang/include/clang/Sema/TemplateDeduction.h new file mode 100644 index 0000000..c22c703 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Sema/TemplateDeduction.h @@ -0,0 +1,315 @@ +//===- TemplateDeduction.h - C++ template argument deduction ----*- 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 types used with Sema's template argument deduction +// routines. +// +//===----------------------------------------------------------------------===/ +#ifndef LLVM_CLANG_SEMA_TEMPLATEDEDUCTION_H +#define LLVM_CLANG_SEMA_TEMPLATEDEDUCTION_H + +#include "clang/AST/DeclTemplate.h" +#include "clang/Basic/PartialDiagnostic.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { + +struct DeducedPack; +class TemplateArgumentList; +class Sema; + +namespace sema { + +/// \brief Provides information about an attempted template argument +/// deduction, whose success or failure was described by a +/// TemplateDeductionResult value. +class TemplateDeductionInfo { + /// \brief The deduced template argument list. + /// + TemplateArgumentList *Deduced; + + /// \brief The source location at which template argument + /// deduction is occurring. + SourceLocation Loc; + + /// \brief Have we suppressed an error during deduction? + bool HasSFINAEDiagnostic; + + /// \brief Warnings (and follow-on notes) that were suppressed due to + /// SFINAE while performing template argument deduction. + SmallVector<PartialDiagnosticAt, 4> SuppressedDiagnostics; + + TemplateDeductionInfo(const TemplateDeductionInfo &) = delete; + void operator=(const TemplateDeductionInfo &) = delete; + +public: + TemplateDeductionInfo(SourceLocation Loc) + : Deduced(nullptr), Loc(Loc), HasSFINAEDiagnostic(false), + Expression(nullptr) {} + + /// \brief Returns the location at which template argument is + /// occurring. + SourceLocation getLocation() const { + return Loc; + } + + /// \brief Take ownership of the deduced template argument list. + TemplateArgumentList *take() { + TemplateArgumentList *Result = Deduced; + Deduced = nullptr; + return Result; + } + + /// \brief Take ownership of the SFINAE diagnostic. + void takeSFINAEDiagnostic(PartialDiagnosticAt &PD) { + assert(HasSFINAEDiagnostic); + PD.first = SuppressedDiagnostics.front().first; + PD.second.swap(SuppressedDiagnostics.front().second); + SuppressedDiagnostics.clear(); + HasSFINAEDiagnostic = false; + } + + /// \brief Provide a new template argument list that contains the + /// results of template argument deduction. + void reset(TemplateArgumentList *NewDeduced) { + Deduced = NewDeduced; + } + + /// \brief Is a SFINAE diagnostic available? + bool hasSFINAEDiagnostic() const { + return HasSFINAEDiagnostic; + } + + /// \brief Set the diagnostic which caused the SFINAE failure. + void addSFINAEDiagnostic(SourceLocation Loc, PartialDiagnostic PD) { + // Only collect the first diagnostic. + if (HasSFINAEDiagnostic) + return; + SuppressedDiagnostics.clear(); + SuppressedDiagnostics.emplace_back(Loc, std::move(PD)); + HasSFINAEDiagnostic = true; + } + + /// \brief Add a new diagnostic to the set of diagnostics + void addSuppressedDiagnostic(SourceLocation Loc, + PartialDiagnostic PD) { + if (HasSFINAEDiagnostic) + return; + SuppressedDiagnostics.emplace_back(Loc, std::move(PD)); + } + + /// \brief Iterator over the set of suppressed diagnostics. + typedef SmallVectorImpl<PartialDiagnosticAt>::const_iterator + diag_iterator; + + /// \brief Returns an iterator at the beginning of the sequence of suppressed + /// diagnostics. + diag_iterator diag_begin() const { return SuppressedDiagnostics.begin(); } + + /// \brief Returns an iterator at the end of the sequence of suppressed + /// diagnostics. + diag_iterator diag_end() const { return SuppressedDiagnostics.end(); } + + /// \brief The template parameter to which a template argument + /// deduction failure refers. + /// + /// Depending on the result of template argument deduction, this + /// template parameter may have different meanings: + /// + /// TDK_Incomplete: this is the first template parameter whose + /// corresponding template argument was not deduced. + /// + /// TDK_Inconsistent: this is the template parameter for which + /// two different template argument values were deduced. + TemplateParameter Param; + + /// \brief The first template argument to which the template + /// argument deduction failure refers. + /// + /// Depending on the result of the template argument deduction, + /// this template argument may have different meanings: + /// + /// TDK_Inconsistent: this argument is the first value deduced + /// for the corresponding template parameter. + /// + /// TDK_SubstitutionFailure: this argument is the template + /// argument we were instantiating when we encountered an error. + /// + /// TDK_DeducedMismatch: this is the parameter type, after substituting + /// deduced arguments. + /// + /// TDK_NonDeducedMismatch: this is the component of the 'parameter' + /// of the deduction, directly provided in the source code. + TemplateArgument FirstArg; + + /// \brief The second template argument to which the template + /// argument deduction failure refers. + /// + /// TDK_Inconsistent: this argument is the second value deduced + /// for the corresponding template parameter. + /// + /// TDK_DeducedMismatch: this is the (adjusted) call argument type. + /// + /// TDK_NonDeducedMismatch: this is the mismatching component of the + /// 'argument' of the deduction, from which we are deducing arguments. + /// + /// FIXME: Finish documenting this. + TemplateArgument SecondArg; + + union { + /// \brief The expression which caused a deduction failure. + /// + /// TDK_FailedOverloadResolution: this argument is the reference to + /// an overloaded function which could not be resolved to a specific + /// function. + Expr *Expression; + + /// \brief The index of the function argument that caused a deduction + /// failure. + /// + /// TDK_DeducedMismatch: this is the index of the argument that had a + /// different argument type from its substituted parameter type. + unsigned CallArgIndex; + }; + + /// \brief Information on packs that we're currently expanding. + /// + /// FIXME: This should be kept internal to SemaTemplateDeduction. + SmallVector<DeducedPack *, 8> PendingDeducedPacks; +}; + +} // end namespace sema + +/// A structure used to record information about a failed +/// template argument deduction, for diagnosis. +struct DeductionFailureInfo { + /// A Sema::TemplateDeductionResult. + unsigned Result : 8; + + /// \brief Indicates whether a diagnostic is stored in Diagnostic. + unsigned HasDiagnostic : 1; + + /// \brief Opaque pointer containing additional data about + /// this deduction failure. + void *Data; + + /// \brief A diagnostic indicating why deduction failed. + union { + void *Align; + char Diagnostic[sizeof(PartialDiagnosticAt)]; + }; + + /// \brief Retrieve the diagnostic which caused this deduction failure, + /// if any. + PartialDiagnosticAt *getSFINAEDiagnostic(); + + /// \brief Retrieve the template parameter this deduction failure + /// refers to, if any. + TemplateParameter getTemplateParameter(); + + /// \brief Retrieve the template argument list associated with this + /// deduction failure, if any. + TemplateArgumentList *getTemplateArgumentList(); + + /// \brief Return the first template argument this deduction failure + /// refers to, if any. + const TemplateArgument *getFirstArg(); + + /// \brief Return the second template argument this deduction failure + /// refers to, if any. + const TemplateArgument *getSecondArg(); + + /// \brief Return the expression this deduction failure refers to, + /// if any. + Expr *getExpr(); + + /// \brief Return the index of the call argument that this deduction + /// failure refers to, if any. + llvm::Optional<unsigned> getCallArgIndex(); + + /// \brief Free any memory associated with this deduction failure. + void Destroy(); +}; + +/// TemplateSpecCandidate - This is a generalization of OverloadCandidate +/// which keeps track of template argument deduction failure info, when +/// handling explicit specializations (and instantiations) of templates +/// beyond function overloading. +/// For now, assume that the candidates are non-matching specializations. +/// TODO: In the future, we may need to unify/generalize this with +/// OverloadCandidate. +struct TemplateSpecCandidate { + /// Specialization - The actual specialization that this candidate + /// represents. When NULL, this may be a built-in candidate. + Decl *Specialization; + + /// Template argument deduction info + DeductionFailureInfo DeductionFailure; + + void set(Decl *Spec, DeductionFailureInfo Info) { + Specialization = Spec; + DeductionFailure = Info; + } + + /// Diagnose a template argument deduction failure. + void NoteDeductionFailure(Sema &S, bool ForTakingAddress); +}; + +/// TemplateSpecCandidateSet - A set of generalized overload candidates, +/// used in template specializations. +/// TODO: In the future, we may need to unify/generalize this with +/// OverloadCandidateSet. +class TemplateSpecCandidateSet { + SmallVector<TemplateSpecCandidate, 16> Candidates; + SourceLocation Loc; + // Stores whether we're taking the address of these candidates. This helps us + // produce better error messages when dealing with the pass_object_size + // attribute on parameters. + bool ForTakingAddress; + + TemplateSpecCandidateSet( + const TemplateSpecCandidateSet &) = delete; + void operator=(const TemplateSpecCandidateSet &) = delete; + + void destroyCandidates(); + +public: + TemplateSpecCandidateSet(SourceLocation Loc, bool ForTakingAddress = false) + : Loc(Loc), ForTakingAddress(ForTakingAddress) {} + ~TemplateSpecCandidateSet() { destroyCandidates(); } + + SourceLocation getLocation() const { return Loc; } + + /// \brief Clear out all of the candidates. + /// TODO: This may be unnecessary. + void clear(); + + typedef SmallVector<TemplateSpecCandidate, 16>::iterator iterator; + iterator begin() { return Candidates.begin(); } + iterator end() { return Candidates.end(); } + + size_t size() const { return Candidates.size(); } + bool empty() const { return Candidates.empty(); } + + /// \brief Add a new candidate with NumConversions conversion sequence slots + /// to the overload set. + TemplateSpecCandidate &addCandidate() { + Candidates.emplace_back(); + return Candidates.back(); + } + + void NoteCandidates(Sema &S, SourceLocation Loc); + + void NoteCandidates(Sema &S, SourceLocation Loc) const { + const_cast<TemplateSpecCandidateSet *>(this)->NoteCandidates(S, Loc); + } +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Sema/TypoCorrection.h b/contrib/llvm/tools/clang/include/clang/Sema/TypoCorrection.h new file mode 100644 index 0000000..3b0385e --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Sema/TypoCorrection.h @@ -0,0 +1,366 @@ +//===--- TypoCorrection.h - Class for typo correction results ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TypoCorrection class, which stores the results of +// Sema's typo correction (Sema::CorrectTypo). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_TYPOCORRECTION_H +#define LLVM_CLANG_SEMA_TYPOCORRECTION_H + +#include "clang/AST/DeclCXX.h" +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/Ownership.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { + +/// @brief Simple class containing the result of Sema::CorrectTypo +class TypoCorrection { +public: + // "Distance" for unusable corrections + static const unsigned InvalidDistance = ~0U; + // The largest distance still considered valid (larger edit distances are + // mapped to InvalidDistance by getEditDistance). + static const unsigned MaximumDistance = 10000U; + + // Relative weightings of the "edit distance" components. The higher the + // weight, the more of a penalty to fitness the component will give (higher + // weights mean greater contribution to the total edit distance, with the + // best correction candidates having the lowest edit distance). + static const unsigned CharDistanceWeight = 100U; + static const unsigned QualifierDistanceWeight = 110U; + static const unsigned CallbackDistanceWeight = 150U; + + TypoCorrection(const DeclarationName &Name, NamedDecl *NameDecl, + NestedNameSpecifier *NNS = nullptr, unsigned CharDistance = 0, + unsigned QualifierDistance = 0) + : CorrectionName(Name), CorrectionNameSpec(NNS), + CharDistance(CharDistance), QualifierDistance(QualifierDistance), + CallbackDistance(0), ForceSpecifierReplacement(false), + RequiresImport(false) { + if (NameDecl) + CorrectionDecls.push_back(NameDecl); + } + + TypoCorrection(NamedDecl *Name, NestedNameSpecifier *NNS = nullptr, + unsigned CharDistance = 0) + : CorrectionName(Name->getDeclName()), CorrectionNameSpec(NNS), + CharDistance(CharDistance), QualifierDistance(0), CallbackDistance(0), + ForceSpecifierReplacement(false), RequiresImport(false) { + if (Name) + CorrectionDecls.push_back(Name); + } + + TypoCorrection(DeclarationName Name, NestedNameSpecifier *NNS = nullptr, + unsigned CharDistance = 0) + : CorrectionName(Name), CorrectionNameSpec(NNS), + CharDistance(CharDistance), QualifierDistance(0), CallbackDistance(0), + ForceSpecifierReplacement(false), RequiresImport(false) {} + + TypoCorrection() + : CorrectionNameSpec(nullptr), CharDistance(0), QualifierDistance(0), + CallbackDistance(0), ForceSpecifierReplacement(false), + RequiresImport(false) {} + + /// \brief Gets the DeclarationName of the typo correction + DeclarationName getCorrection() const { return CorrectionName; } + IdentifierInfo *getCorrectionAsIdentifierInfo() const { + return CorrectionName.getAsIdentifierInfo(); + } + + /// \brief Gets the NestedNameSpecifier needed to use the typo correction + NestedNameSpecifier *getCorrectionSpecifier() const { + return CorrectionNameSpec; + } + void setCorrectionSpecifier(NestedNameSpecifier *NNS) { + CorrectionNameSpec = NNS; + ForceSpecifierReplacement = (NNS != nullptr); + } + + void WillReplaceSpecifier(bool ForceReplacement) { + ForceSpecifierReplacement = ForceReplacement; + } + + bool WillReplaceSpecifier() const { + return ForceSpecifierReplacement; + } + + void setQualifierDistance(unsigned ED) { + QualifierDistance = ED; + } + + void setCallbackDistance(unsigned ED) { + CallbackDistance = ED; + } + + // Convert the given weighted edit distance to a roughly equivalent number of + // single-character edits (typically for comparison to the length of the + // string being edited). + static unsigned NormalizeEditDistance(unsigned ED) { + if (ED > MaximumDistance) + return InvalidDistance; + return (ED + CharDistanceWeight / 2) / CharDistanceWeight; + } + + /// \brief Gets the "edit distance" of the typo correction from the typo. + /// If Normalized is true, scale the distance down by the CharDistanceWeight + /// to return the edit distance in terms of single-character edits. + unsigned getEditDistance(bool Normalized = true) const { + if (CharDistance > MaximumDistance || QualifierDistance > MaximumDistance || + CallbackDistance > MaximumDistance) + return InvalidDistance; + unsigned ED = + CharDistance * CharDistanceWeight + + QualifierDistance * QualifierDistanceWeight + + CallbackDistance * CallbackDistanceWeight; + if (ED > MaximumDistance) + return InvalidDistance; + // Half the CharDistanceWeight is added to ED to simulate rounding since + // integer division truncates the value (i.e. round-to-nearest-int instead + // of round-to-zero). + return Normalized ? NormalizeEditDistance(ED) : ED; + } + + /// \brief Get the correction declaration found by name lookup (before we + /// looked through using shadow declarations and the like). + NamedDecl *getFoundDecl() const { + return hasCorrectionDecl() ? *(CorrectionDecls.begin()) : nullptr; + } + + /// \brief Gets the pointer to the declaration of the typo correction + NamedDecl *getCorrectionDecl() const { + auto *D = getFoundDecl(); + return D ? D->getUnderlyingDecl() : nullptr; + } + template <class DeclClass> + DeclClass *getCorrectionDeclAs() const { + return dyn_cast_or_null<DeclClass>(getCorrectionDecl()); + } + + /// \brief Clears the list of NamedDecls. + void ClearCorrectionDecls() { + CorrectionDecls.clear(); + } + + /// \brief Clears the list of NamedDecls before adding the new one. + void setCorrectionDecl(NamedDecl *CDecl) { + CorrectionDecls.clear(); + addCorrectionDecl(CDecl); + } + + /// \brief Clears the list of NamedDecls and adds the given set. + void setCorrectionDecls(ArrayRef<NamedDecl*> Decls) { + CorrectionDecls.clear(); + CorrectionDecls.insert(CorrectionDecls.begin(), Decls.begin(), Decls.end()); + } + + /// \brief Add the given NamedDecl to the list of NamedDecls that are the + /// declarations associated with the DeclarationName of this TypoCorrection + void addCorrectionDecl(NamedDecl *CDecl); + + std::string getAsString(const LangOptions &LO) const; + std::string getQuoted(const LangOptions &LO) const { + return "'" + getAsString(LO) + "'"; + } + + /// \brief Returns whether this TypoCorrection has a non-empty DeclarationName + explicit operator bool() const { return bool(CorrectionName); } + + /// \brief Mark this TypoCorrection as being a keyword. + /// Since addCorrectionDeclsand setCorrectionDecl don't allow NULL to be + /// added to the list of the correction's NamedDecl pointers, NULL is added + /// as the only element in the list to mark this TypoCorrection as a keyword. + void makeKeyword() { + CorrectionDecls.clear(); + CorrectionDecls.push_back(nullptr); + ForceSpecifierReplacement = true; + } + + // Check if this TypoCorrection is a keyword by checking if the first + // item in CorrectionDecls is NULL. + bool isKeyword() const { + return !CorrectionDecls.empty() && CorrectionDecls.front() == nullptr; + } + + // Check if this TypoCorrection is the given keyword. + template<std::size_t StrLen> + bool isKeyword(const char (&Str)[StrLen]) const { + return isKeyword() && getCorrectionAsIdentifierInfo()->isStr(Str); + } + + // Returns true if the correction either is a keyword or has a known decl. + bool isResolved() const { return !CorrectionDecls.empty(); } + + bool isOverloaded() const { + return CorrectionDecls.size() > 1; + } + + void setCorrectionRange(CXXScopeSpec *SS, + const DeclarationNameInfo &TypoName) { + CorrectionRange = TypoName.getSourceRange(); + if (ForceSpecifierReplacement && SS && !SS->isEmpty()) + CorrectionRange.setBegin(SS->getBeginLoc()); + } + + SourceRange getCorrectionRange() const { + return CorrectionRange; + } + + typedef SmallVectorImpl<NamedDecl *>::iterator decl_iterator; + decl_iterator begin() { + return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin(); + } + decl_iterator end() { return CorrectionDecls.end(); } + typedef SmallVectorImpl<NamedDecl *>::const_iterator const_decl_iterator; + const_decl_iterator begin() const { + return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin(); + } + const_decl_iterator end() const { return CorrectionDecls.end(); } + + /// \brief Returns whether this typo correction is correcting to a + /// declaration that was declared in a module that has not been imported. + bool requiresImport() const { return RequiresImport; } + void setRequiresImport(bool Req) { RequiresImport = Req; } + +private: + bool hasCorrectionDecl() const { + return (!isKeyword() && !CorrectionDecls.empty()); + } + + // Results. + DeclarationName CorrectionName; + NestedNameSpecifier *CorrectionNameSpec; + SmallVector<NamedDecl *, 1> CorrectionDecls; + unsigned CharDistance; + unsigned QualifierDistance; + unsigned CallbackDistance; + SourceRange CorrectionRange; + bool ForceSpecifierReplacement; + bool RequiresImport; +}; + +/// @brief Base class for callback objects used by Sema::CorrectTypo to check +/// the validity of a potential typo correction. +class CorrectionCandidateCallback { +public: + static const unsigned InvalidDistance = TypoCorrection::InvalidDistance; + + explicit CorrectionCandidateCallback(IdentifierInfo *Typo = nullptr, + NestedNameSpecifier *TypoNNS = nullptr) + : WantTypeSpecifiers(true), WantExpressionKeywords(true), + WantCXXNamedCasts(true), WantFunctionLikeCasts(true), + WantRemainingKeywords(true), WantObjCSuper(false), + IsObjCIvarLookup(false), IsAddressOfOperand(false), Typo(Typo), + TypoNNS(TypoNNS) {} + + virtual ~CorrectionCandidateCallback() {} + + /// \brief Simple predicate used by the default RankCandidate to + /// determine whether to return an edit distance of 0 or InvalidDistance. + /// This can be overrided by validators that only need to determine if a + /// candidate is viable, without ranking potentially viable candidates. + /// Only ValidateCandidate or RankCandidate need to be overriden by a + /// callback wishing to check the viability of correction candidates. + /// The default predicate always returns true if the candidate is not a type + /// name or keyword, true for types if WantTypeSpecifiers is true, and true + /// for keywords if WantTypeSpecifiers, WantExpressionKeywords, + /// WantCXXNamedCasts, WantRemainingKeywords, or WantObjCSuper is true. + virtual bool ValidateCandidate(const TypoCorrection &candidate); + + /// \brief Method used by Sema::CorrectTypo to assign an "edit distance" rank + /// to a candidate (where a lower value represents a better candidate), or + /// returning InvalidDistance if the candidate is not at all viable. For + /// validation callbacks that only need to determine if a candidate is viable, + /// the default RankCandidate returns either 0 or InvalidDistance depending + /// whether ValidateCandidate returns true or false. + virtual unsigned RankCandidate(const TypoCorrection &candidate) { + return (!MatchesTypo(candidate) && ValidateCandidate(candidate)) + ? 0 + : InvalidDistance; + } + + void setTypoName(IdentifierInfo *II) { Typo = II; } + void setTypoNNS(NestedNameSpecifier *NNS) { TypoNNS = NNS; } + + // Flags for context-dependent keywords. WantFunctionLikeCasts is only + // used/meaningful when WantCXXNamedCasts is false. + // TODO: Expand these to apply to non-keywords or possibly remove them. + bool WantTypeSpecifiers; + bool WantExpressionKeywords; + bool WantCXXNamedCasts; + bool WantFunctionLikeCasts; + bool WantRemainingKeywords; + bool WantObjCSuper; + // Temporary hack for the one case where a CorrectTypoContext enum is used + // when looking up results. + bool IsObjCIvarLookup; + bool IsAddressOfOperand; + +protected: + bool MatchesTypo(const TypoCorrection &candidate) { + return Typo && candidate.isResolved() && !candidate.requiresImport() && + candidate.getCorrectionAsIdentifierInfo() == Typo && + // FIXME: This probably does not return true when both + // NestedNameSpecifiers have the same textual representation. + candidate.getCorrectionSpecifier() == TypoNNS; + } + + IdentifierInfo *Typo; + NestedNameSpecifier *TypoNNS; +}; + +/// @brief Simple template class for restricting typo correction candidates +/// to ones having a single Decl* of the given type. +template <class C> +class DeclFilterCCC : public CorrectionCandidateCallback { +public: + bool ValidateCandidate(const TypoCorrection &candidate) override { + return candidate.getCorrectionDeclAs<C>(); + } +}; + +// @brief Callback class to limit the allowed keywords and to only accept typo +// corrections that are keywords or whose decls refer to functions (or template +// functions) that accept the given number of arguments. +class FunctionCallFilterCCC : public CorrectionCandidateCallback { +public: + FunctionCallFilterCCC(Sema &SemaRef, unsigned NumArgs, + bool HasExplicitTemplateArgs, + MemberExpr *ME = nullptr); + + bool ValidateCandidate(const TypoCorrection &candidate) override; + + private: + unsigned NumArgs; + bool HasExplicitTemplateArgs; + DeclContext *CurContext; + MemberExpr *MemberFn; +}; + +// @brief Callback class that effectively disabled typo correction +class NoTypoCorrectionCCC : public CorrectionCandidateCallback { +public: + NoTypoCorrectionCCC() { + WantTypeSpecifiers = false; + WantExpressionKeywords = false; + WantCXXNamedCasts = false; + WantFunctionLikeCasts = false; + WantRemainingKeywords = false; + } + + bool ValidateCandidate(const TypoCorrection &candidate) override { + return false; + } +}; + +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Sema/Weak.h b/contrib/llvm/tools/clang/include/clang/Sema/Weak.h new file mode 100644 index 0000000..9c7212e --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Sema/Weak.h @@ -0,0 +1,46 @@ +//===-- UnresolvedSet.h - Unresolved sets of declarations ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the WeakInfo class, which is used to store +// information about the target of a #pragma weak directive. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_WEAK_H +#define LLVM_CLANG_SEMA_WEAK_H + +#include "clang/Basic/SourceLocation.h" + +namespace clang { + +class IdentifierInfo; + +/// \brief Captures information about a \#pragma weak directive. +class WeakInfo { + IdentifierInfo *alias; // alias (optional) + SourceLocation loc; // for diagnostics + bool used; // identifier later declared? +public: + WeakInfo() + : alias(nullptr), loc(SourceLocation()), used(false) {} + WeakInfo(IdentifierInfo *Alias, SourceLocation Loc) + : alias(Alias), loc(Loc), used(false) {} + inline IdentifierInfo * getAlias() const { return alias; } + inline SourceLocation getLocation() const { return loc; } + void setUsed(bool Used=true) { used = Used; } + inline bool getUsed() { return used; } + bool operator==(WeakInfo RHS) const { + return alias == RHS.getAlias() && loc == RHS.getLocation(); + } + bool operator!=(WeakInfo RHS) const { return !(*this == RHS); } +}; + +} // end namespace clang + +#endif // LLVM_CLANG_SEMA_WEAK_H diff --git a/contrib/llvm/tools/clang/include/clang/Serialization/ASTBitCodes.h b/contrib/llvm/tools/clang/include/clang/Serialization/ASTBitCodes.h new file mode 100644 index 0000000..16bda6e --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Serialization/ASTBitCodes.h @@ -0,0 +1,1605 @@ +//===- ASTBitCodes.h - Enum values for the PCH bitcode format ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header defines Bitcode enum values for Clang serialized AST files. +// +// The enum values defined in this file should be considered permanent. If +// new features are added, they should have values added at the end of the +// respective lists. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_SERIALIZATION_ASTBITCODES_H +#define LLVM_CLANG_SERIALIZATION_ASTBITCODES_H + +#include "clang/AST/DeclarationName.h" +#include "clang/AST/Type.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/Bitcode/BitCodes.h" +#include "llvm/Support/DataTypes.h" + +namespace clang { + namespace serialization { + /// \brief AST file major version number supported by this version of + /// Clang. + /// + /// Whenever the AST file format changes in a way that makes it + /// incompatible with previous versions (such that a reader + /// designed for the previous version could not support reading + /// the new version), this number should be increased. + /// + /// Version 4 of AST files also requires that the version control branch and + /// revision match exactly, since there is no backward compatibility of + /// AST files at this time. + const unsigned VERSION_MAJOR = 6; + + /// \brief AST file minor version number supported by this version of + /// Clang. + /// + /// Whenever the AST format changes in a way that is still + /// compatible with previous versions (such that a reader designed + /// for the previous version could still support reading the new + /// version by ignoring new kinds of subblocks), this number + /// should be increased. + const unsigned VERSION_MINOR = 0; + + /// \brief An ID number that refers to an identifier in an AST file. + /// + /// The ID numbers of identifiers are consecutive (in order of discovery) + /// and start at 1. 0 is reserved for NULL. + typedef uint32_t IdentifierID; + + /// \brief An ID number that refers to a declaration in an AST file. + /// + /// The ID numbers of declarations are consecutive (in order of + /// discovery), with values below NUM_PREDEF_DECL_IDS being reserved. + /// At the start of a chain of precompiled headers, declaration ID 1 is + /// used for the translation unit declaration. + typedef uint32_t DeclID; + + // FIXME: Turn these into classes so we can have some type safety when + // we go from local ID to global and vice-versa. + typedef DeclID LocalDeclID; + typedef DeclID GlobalDeclID; + + /// \brief An ID number that refers to a type in an AST file. + /// + /// The ID of a type is partitioned into two parts: the lower + /// three bits are used to store the const/volatile/restrict + /// qualifiers (as with QualType) and the upper bits provide a + /// type index. The type index values are partitioned into two + /// sets. The values below NUM_PREDEF_TYPE_IDs are predefined type + /// IDs (based on the PREDEF_TYPE_*_ID constants), with 0 as a + /// placeholder for "no type". Values from NUM_PREDEF_TYPE_IDs are + /// other types that have serialized representations. + typedef uint32_t TypeID; + + /// \brief A type index; the type ID with the qualifier bits removed. + class TypeIdx { + uint32_t Idx; + public: + TypeIdx() : Idx(0) { } + explicit TypeIdx(uint32_t index) : Idx(index) { } + + uint32_t getIndex() const { return Idx; } + TypeID asTypeID(unsigned FastQuals) const { + if (Idx == uint32_t(-1)) + return TypeID(-1); + + return (Idx << Qualifiers::FastWidth) | FastQuals; + } + static TypeIdx fromTypeID(TypeID ID) { + if (ID == TypeID(-1)) + return TypeIdx(-1); + + return TypeIdx(ID >> Qualifiers::FastWidth); + } + }; + + /// A structure for putting "fast"-unqualified QualTypes into a + /// DenseMap. This uses the standard pointer hash function. + struct UnsafeQualTypeDenseMapInfo { + static inline bool isEqual(QualType A, QualType B) { return A == B; } + static inline QualType getEmptyKey() { + return QualType::getFromOpaquePtr((void*) 1); + } + static inline QualType getTombstoneKey() { + return QualType::getFromOpaquePtr((void*) 2); + } + static inline unsigned getHashValue(QualType T) { + assert(!T.getLocalFastQualifiers() && + "hash invalid for types with fast quals"); + uintptr_t v = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr()); + return (unsigned(v) >> 4) ^ (unsigned(v) >> 9); + } + }; + + /// \brief An ID number that refers to an identifier in an AST file. + typedef uint32_t IdentID; + + /// \brief The number of predefined identifier IDs. + const unsigned int NUM_PREDEF_IDENT_IDS = 1; + + /// \brief An ID number that refers to a macro in an AST file. + typedef uint32_t MacroID; + + /// \brief A global ID number that refers to a macro in an AST file. + typedef uint32_t GlobalMacroID; + + /// \brief A local to a module ID number that refers to a macro in an + /// AST file. + typedef uint32_t LocalMacroID; + + /// \brief The number of predefined macro IDs. + const unsigned int NUM_PREDEF_MACRO_IDS = 1; + + /// \brief An ID number that refers to an ObjC selector in an AST file. + typedef uint32_t SelectorID; + + /// \brief The number of predefined selector IDs. + const unsigned int NUM_PREDEF_SELECTOR_IDS = 1; + + /// \brief An ID number that refers to a set of CXXBaseSpecifiers in an + /// AST file. + typedef uint32_t CXXBaseSpecifiersID; + + /// \brief An ID number that refers to a list of CXXCtorInitializers in an + /// AST file. + typedef uint32_t CXXCtorInitializersID; + + /// \brief An ID number that refers to an entity in the detailed + /// preprocessing record. + typedef uint32_t PreprocessedEntityID; + + /// \brief An ID number that refers to a submodule in a module file. + typedef uint32_t SubmoduleID; + + /// \brief The number of predefined submodule IDs. + const unsigned int NUM_PREDEF_SUBMODULE_IDS = 1; + + /// \brief Source range/offset of a preprocessed entity. + struct PPEntityOffset { + /// \brief Raw source location of beginning of range. + unsigned Begin; + /// \brief Raw source location of end of range. + unsigned End; + /// \brief Offset in the AST file. + uint32_t BitOffset; + + PPEntityOffset(SourceRange R, uint32_t BitOffset) + : Begin(R.getBegin().getRawEncoding()), + End(R.getEnd().getRawEncoding()), + BitOffset(BitOffset) { } + }; + + /// \brief Source range/offset of a preprocessed entity. + struct DeclOffset { + /// \brief Raw source location. + unsigned Loc; + /// \brief Offset in the AST file. + uint32_t BitOffset; + + DeclOffset() : Loc(0), BitOffset(0) { } + DeclOffset(SourceLocation Loc, uint32_t BitOffset) + : Loc(Loc.getRawEncoding()), + BitOffset(BitOffset) { } + void setLocation(SourceLocation L) { + Loc = L.getRawEncoding(); + } + }; + + /// \brief The number of predefined preprocessed entity IDs. + const unsigned int NUM_PREDEF_PP_ENTITY_IDS = 1; + + /// \brief Describes the various kinds of blocks that occur within + /// an AST file. + enum BlockIDs { + /// \brief The AST block, which acts as a container around the + /// full AST block. + AST_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID, + + /// \brief The block containing information about the source + /// manager. + SOURCE_MANAGER_BLOCK_ID, + + /// \brief The block containing information about the + /// preprocessor. + PREPROCESSOR_BLOCK_ID, + + /// \brief The block containing the definitions of all of the + /// types and decls used within the AST file. + DECLTYPES_BLOCK_ID, + + /// \brief The block containing the detailed preprocessing record. + PREPROCESSOR_DETAIL_BLOCK_ID, + + /// \brief The block containing the submodule structure. + SUBMODULE_BLOCK_ID, + + /// \brief The block containing comments. + COMMENTS_BLOCK_ID, + + /// \brief The control block, which contains all of the + /// information that needs to be validated prior to committing + /// to loading the AST file. + CONTROL_BLOCK_ID, + + /// \brief The block of input files, which were used as inputs + /// to create this AST file. + /// + /// This block is part of the control block. + INPUT_FILES_BLOCK_ID, + + /// \brief The block of configuration options, used to check that + /// a module is being used in a configuration compatible with the + /// configuration in which it was built. + /// + /// This block is part of the control block. + OPTIONS_BLOCK_ID, + + /// \brief A block containing a module file extension. + EXTENSION_BLOCK_ID, + }; + + /// \brief Record types that occur within the control block. + enum ControlRecordTypes { + /// \brief AST file metadata, including the AST file version number + /// and information about the compiler used to build this AST file. + METADATA = 1, + + /// \brief Record code for the list of other AST files imported by + /// this AST file. + IMPORTS, + + /// \brief Record code for the original file that was used to + /// generate the AST file, including both its file ID and its + /// name. + ORIGINAL_FILE, + + /// \brief The directory that the PCH was originally created in. + ORIGINAL_PCH_DIR, + + /// \brief Record code for file ID of the file or buffer that was used to + /// generate the AST file. + ORIGINAL_FILE_ID, + + /// \brief Offsets into the input-files block where input files + /// reside. + INPUT_FILE_OFFSETS, + + /// \brief Record code for the module name. + MODULE_NAME, + + /// \brief Record code for the module map file that was used to build this + /// AST file. + MODULE_MAP_FILE, + + /// \brief Record code for the signature that identifiers this AST file. + SIGNATURE, + + /// \brief Record code for the module build directory. + MODULE_DIRECTORY, + }; + + /// \brief Record types that occur within the options block inside + /// the control block. + enum OptionsRecordTypes { + /// \brief Record code for the language options table. + /// + /// The record with this code contains the contents of the + /// LangOptions structure. We serialize the entire contents of + /// the structure, and let the reader decide which options are + /// actually important to check. + LANGUAGE_OPTIONS = 1, + + /// \brief Record code for the target options table. + TARGET_OPTIONS, + + /// \brief Record code for the diagnostic options table. + DIAGNOSTIC_OPTIONS, + + /// \brief Record code for the filesystem options table. + FILE_SYSTEM_OPTIONS, + + /// \brief Record code for the headers search options table. + HEADER_SEARCH_OPTIONS, + + /// \brief Record code for the preprocessor options table. + PREPROCESSOR_OPTIONS, + }; + + /// \brief Record code for extension blocks. + enum ExtensionBlockRecordTypes { + /// Metadata describing this particular extension. + EXTENSION_METADATA = 1, + + /// The first record ID allocated to the extensions themselves. + FIRST_EXTENSION_RECORD_ID = 4 + }; + + /// \brief Record types that occur within the input-files block + /// inside the control block. + enum InputFileRecordTypes { + /// \brief An input file. + INPUT_FILE = 1 + }; + + /// \brief Record types that occur within the AST block itself. + enum ASTRecordTypes { + /// \brief Record code for the offsets of each type. + /// + /// The TYPE_OFFSET constant describes the record that occurs + /// within the AST block. The record itself is an array of offsets that + /// point into the declarations and types block (identified by + /// DECLTYPES_BLOCK_ID). The index into the array is based on the ID + /// of a type. For a given type ID @c T, the lower three bits of + /// @c T are its qualifiers (const, volatile, restrict), as in + /// the QualType class. The upper bits, after being shifted and + /// subtracting NUM_PREDEF_TYPE_IDS, are used to index into the + /// TYPE_OFFSET block to determine the offset of that type's + /// corresponding record within the DECLTYPES_BLOCK_ID block. + TYPE_OFFSET = 1, + + /// \brief Record code for the offsets of each decl. + /// + /// The DECL_OFFSET constant describes the record that occurs + /// within the block identified by DECL_OFFSETS_BLOCK_ID within + /// the AST block. The record itself is an array of offsets that + /// point into the declarations and types block (identified by + /// DECLTYPES_BLOCK_ID). The declaration ID is an index into this + /// record, after subtracting one to account for the use of + /// declaration ID 0 for a NULL declaration pointer. Index 0 is + /// reserved for the translation unit declaration. + DECL_OFFSET = 2, + + /// \brief Record code for the table of offsets of each + /// identifier ID. + /// + /// The offset table contains offsets into the blob stored in + /// the IDENTIFIER_TABLE record. Each offset points to the + /// NULL-terminated string that corresponds to that identifier. + IDENTIFIER_OFFSET = 3, + + /// \brief This is so that older clang versions, before the introduction + /// of the control block, can read and reject the newer PCH format. + /// *DON'T CHANGE THIS NUMBER*. + METADATA_OLD_FORMAT = 4, + + /// \brief Record code for the identifier table. + /// + /// The identifier table is a simple blob that contains + /// NULL-terminated strings for all of the identifiers + /// referenced by the AST file. The IDENTIFIER_OFFSET table + /// contains the mapping from identifier IDs to the characters + /// in this blob. Note that the starting offsets of all of the + /// identifiers are odd, so that, when the identifier offset + /// table is loaded in, we can use the low bit to distinguish + /// between offsets (for unresolved identifier IDs) and + /// IdentifierInfo pointers (for already-resolved identifier + /// IDs). + IDENTIFIER_TABLE = 5, + + /// \brief Record code for the array of eagerly deserialized decls. + /// + /// The AST file contains a list of all of the declarations that should be + /// eagerly deserialized present within the parsed headers, stored as an + /// array of declaration IDs. These declarations will be + /// reported to the AST consumer after the AST file has been + /// read, since their presence can affect the semantics of the + /// program (e.g., for code generation). + EAGERLY_DESERIALIZED_DECLS = 6, + + /// \brief Record code for the set of non-builtin, special + /// types. + /// + /// This record contains the type IDs for the various type nodes + /// that are constructed during semantic analysis (e.g., + /// __builtin_va_list). The SPECIAL_TYPE_* constants provide + /// offsets into this record. + SPECIAL_TYPES = 7, + + /// \brief Record code for the extra statistics we gather while + /// generating an AST file. + STATISTICS = 8, + + /// \brief Record code for the array of tentative definitions. + TENTATIVE_DEFINITIONS = 9, + + // ID 10 used to be for a list of extern "C" declarations. + + /// \brief Record code for the table of offsets into the + /// Objective-C method pool. + SELECTOR_OFFSETS = 11, + + /// \brief Record code for the Objective-C method pool, + METHOD_POOL = 12, + + /// \brief The value of the next __COUNTER__ to dispense. + /// [PP_COUNTER_VALUE, Val] + PP_COUNTER_VALUE = 13, + + /// \brief Record code for the table of offsets into the block + /// of source-location information. + SOURCE_LOCATION_OFFSETS = 14, + + /// \brief Record code for the set of source location entries + /// that need to be preloaded by the AST reader. + /// + /// This set contains the source location entry for the + /// predefines buffer and for any file entries that need to be + /// preloaded. + SOURCE_LOCATION_PRELOADS = 15, + + /// \brief Record code for the set of ext_vector type names. + EXT_VECTOR_DECLS = 16, + + /// \brief Record code for the array of unused file scoped decls. + UNUSED_FILESCOPED_DECLS = 17, + + /// \brief Record code for the table of offsets to entries in the + /// preprocessing record. + PPD_ENTITIES_OFFSETS = 18, + + /// \brief Record code for the array of VTable uses. + VTABLE_USES = 19, + + // ID 20 used to be for a list of dynamic classes. + + /// \brief Record code for referenced selector pool. + REFERENCED_SELECTOR_POOL = 21, + + /// \brief Record code for an update to the TU's lexically contained + /// declarations. + TU_UPDATE_LEXICAL = 22, + + // ID 23 used to be for a list of local redeclarations. + + /// \brief Record code for declarations that Sema keeps references of. + SEMA_DECL_REFS = 24, + + /// \brief Record code for weak undeclared identifiers. + WEAK_UNDECLARED_IDENTIFIERS = 25, + + /// \brief Record code for pending implicit instantiations. + PENDING_IMPLICIT_INSTANTIATIONS = 26, + + /// \brief Record code for a decl replacement block. + /// + /// If a declaration is modified after having been deserialized, and then + /// written to a dependent AST file, its ID and offset must be added to + /// the replacement block. + DECL_REPLACEMENTS = 27, + + /// \brief Record code for an update to a decl context's lookup table. + /// + /// In practice, this should only be used for the TU and namespaces. + UPDATE_VISIBLE = 28, + + /// \brief Record for offsets of DECL_UPDATES records for declarations + /// that were modified after being deserialized and need updates. + DECL_UPDATE_OFFSETS = 29, + + /// \brief Record of updates for a declaration that was modified after + /// being deserialized. + DECL_UPDATES = 30, + + /// \brief Record code for the table of offsets to CXXBaseSpecifier + /// sets. + CXX_BASE_SPECIFIER_OFFSETS = 31, + + /// \brief Record code for \#pragma diagnostic mappings. + DIAG_PRAGMA_MAPPINGS = 32, + + /// \brief Record code for special CUDA declarations. + CUDA_SPECIAL_DECL_REFS = 33, + + /// \brief Record code for header search information. + HEADER_SEARCH_TABLE = 34, + + /// \brief Record code for floating point \#pragma options. + FP_PRAGMA_OPTIONS = 35, + + /// \brief Record code for enabled OpenCL extensions. + OPENCL_EXTENSIONS = 36, + + /// \brief The list of delegating constructor declarations. + DELEGATING_CTORS = 37, + + /// \brief Record code for the set of known namespaces, which are used + /// for typo correction. + KNOWN_NAMESPACES = 38, + + /// \brief Record code for the remapping information used to relate + /// loaded modules to the various offsets and IDs(e.g., source location + /// offests, declaration and type IDs) that are used in that module to + /// refer to other modules. + MODULE_OFFSET_MAP = 39, + + /// \brief Record code for the source manager line table information, + /// which stores information about \#line directives. + SOURCE_MANAGER_LINE_TABLE = 40, + + /// \brief Record code for map of Objective-C class definition IDs to the + /// ObjC categories in a module that are attached to that class. + OBJC_CATEGORIES_MAP = 41, + + /// \brief Record code for a file sorted array of DeclIDs in a module. + FILE_SORTED_DECLS = 42, + + /// \brief Record code for an array of all of the (sub)modules that were + /// imported by the AST file. + IMPORTED_MODULES = 43, + + // ID 44 used to be a table of merged canonical declarations. + // ID 45 used to be a list of declaration IDs of local redeclarations. + + /// \brief Record code for the array of Objective-C categories (including + /// extensions). + /// + /// This array can only be interpreted properly using the Objective-C + /// categories map. + OBJC_CATEGORIES = 46, + + /// \brief Record code for the table of offsets of each macro ID. + /// + /// The offset table contains offsets into the blob stored in + /// the preprocessor block. Each offset points to the corresponding + /// macro definition. + MACRO_OFFSET = 47, + + /// \brief A list of "interesting" identifiers. Only used in C++ (where we + /// don't normally do lookups into the serialized identifier table). These + /// are eagerly deserialized. + INTERESTING_IDENTIFIERS = 48, + + /// \brief Record code for undefined but used functions and variables that + /// need a definition in this TU. + UNDEFINED_BUT_USED = 49, + + /// \brief Record code for late parsed template functions. + LATE_PARSED_TEMPLATE = 50, + + /// \brief Record code for \#pragma optimize options. + OPTIMIZE_PRAGMA_OPTIONS = 51, + + /// \brief Record code for potentially unused local typedef names. + UNUSED_LOCAL_TYPEDEF_NAME_CANDIDATES = 52, + + /// \brief Record code for the table of offsets to CXXCtorInitializers + /// lists. + CXX_CTOR_INITIALIZERS_OFFSETS = 53, + + /// \brief Delete expressions that will be analyzed later. + DELETE_EXPRS_TO_ANALYZE = 54 + }; + + /// \brief Record types used within a source manager block. + enum SourceManagerRecordTypes { + /// \brief Describes a source location entry (SLocEntry) for a + /// file. + SM_SLOC_FILE_ENTRY = 1, + /// \brief Describes a source location entry (SLocEntry) for a + /// buffer. + SM_SLOC_BUFFER_ENTRY = 2, + /// \brief Describes a blob that contains the data for a buffer + /// entry. This kind of record always directly follows a + /// SM_SLOC_BUFFER_ENTRY record or a SM_SLOC_FILE_ENTRY with an + /// overridden buffer. + SM_SLOC_BUFFER_BLOB = 3, + /// \brief Describes a source location entry (SLocEntry) for a + /// macro expansion. + SM_SLOC_EXPANSION_ENTRY = 4 + }; + + /// \brief Record types used within a preprocessor block. + enum PreprocessorRecordTypes { + // The macros in the PP section are a PP_MACRO_* instance followed by a + // list of PP_TOKEN instances for each token in the definition. + + /// \brief An object-like macro definition. + /// [PP_MACRO_OBJECT_LIKE, IdentInfoID, SLoc, IsUsed] + PP_MACRO_OBJECT_LIKE = 1, + + /// \brief A function-like macro definition. + /// [PP_MACRO_FUNCTION_LIKE, \<ObjectLikeStuff>, IsC99Varargs, + /// IsGNUVarars, NumArgs, ArgIdentInfoID* ] + PP_MACRO_FUNCTION_LIKE = 2, + + /// \brief Describes one token. + /// [PP_TOKEN, SLoc, Length, IdentInfoID, Kind, Flags] + PP_TOKEN = 3, + + /// \brief The macro directives history for a particular identifier. + PP_MACRO_DIRECTIVE_HISTORY = 4, + + /// \brief A macro directive exported by a module. + /// [PP_MODULE_MACRO, SubmoduleID, MacroID, (Overridden SubmoduleID)*] + PP_MODULE_MACRO = 5, + }; + + /// \brief Record types used within a preprocessor detail block. + enum PreprocessorDetailRecordTypes { + /// \brief Describes a macro expansion within the preprocessing record. + PPD_MACRO_EXPANSION = 0, + + /// \brief Describes a macro definition within the preprocessing record. + PPD_MACRO_DEFINITION = 1, + + /// \brief Describes an inclusion directive within the preprocessing + /// record. + PPD_INCLUSION_DIRECTIVE = 2 + }; + + /// \brief Record types used within a submodule description block. + enum SubmoduleRecordTypes { + /// \brief Metadata for submodules as a whole. + SUBMODULE_METADATA = 0, + /// \brief Defines the major attributes of a submodule, including its + /// name and parent. + SUBMODULE_DEFINITION = 1, + /// \brief Specifies the umbrella header used to create this module, + /// if any. + SUBMODULE_UMBRELLA_HEADER = 2, + /// \brief Specifies a header that falls into this (sub)module. + SUBMODULE_HEADER = 3, + /// \brief Specifies a top-level header that falls into this (sub)module. + SUBMODULE_TOPHEADER = 4, + /// \brief Specifies an umbrella directory. + SUBMODULE_UMBRELLA_DIR = 5, + /// \brief Specifies the submodules that are imported by this + /// submodule. + SUBMODULE_IMPORTS = 6, + /// \brief Specifies the submodules that are re-exported from this + /// submodule. + SUBMODULE_EXPORTS = 7, + /// \brief Specifies a required feature. + SUBMODULE_REQUIRES = 8, + /// \brief Specifies a header that has been explicitly excluded + /// from this submodule. + SUBMODULE_EXCLUDED_HEADER = 9, + /// \brief Specifies a library or framework to link against. + SUBMODULE_LINK_LIBRARY = 10, + /// \brief Specifies a configuration macro for this module. + SUBMODULE_CONFIG_MACRO = 11, + /// \brief Specifies a conflict with another module. + SUBMODULE_CONFLICT = 12, + /// \brief Specifies a header that is private to this submodule. + SUBMODULE_PRIVATE_HEADER = 13, + /// \brief Specifies a header that is part of the module but must be + /// textually included. + SUBMODULE_TEXTUAL_HEADER = 14, + /// \brief Specifies a header that is private to this submodule but + /// must be textually included. + SUBMODULE_PRIVATE_TEXTUAL_HEADER = 15, + }; + + /// \brief Record types used within a comments block. + enum CommentRecordTypes { + COMMENTS_RAW_COMMENT = 0 + }; + + /// \defgroup ASTAST AST file AST constants + /// + /// The constants in this group describe various components of the + /// abstract syntax tree within an AST file. + /// + /// @{ + + /// \brief Predefined type IDs. + /// + /// These type IDs correspond to predefined types in the AST + /// context, such as built-in types (int) and special place-holder + /// types (the \<overload> and \<dependent> type markers). Such + /// types are never actually serialized, since they will be built + /// by the AST context when it is created. + enum PredefinedTypeIDs { + /// \brief The NULL type. + PREDEF_TYPE_NULL_ID = 0, + /// \brief The void type. + PREDEF_TYPE_VOID_ID = 1, + /// \brief The 'bool' or '_Bool' type. + PREDEF_TYPE_BOOL_ID = 2, + /// \brief The 'char' type, when it is unsigned. + PREDEF_TYPE_CHAR_U_ID = 3, + /// \brief The 'unsigned char' type. + PREDEF_TYPE_UCHAR_ID = 4, + /// \brief The 'unsigned short' type. + PREDEF_TYPE_USHORT_ID = 5, + /// \brief The 'unsigned int' type. + PREDEF_TYPE_UINT_ID = 6, + /// \brief The 'unsigned long' type. + PREDEF_TYPE_ULONG_ID = 7, + /// \brief The 'unsigned long long' type. + PREDEF_TYPE_ULONGLONG_ID = 8, + /// \brief The 'char' type, when it is signed. + PREDEF_TYPE_CHAR_S_ID = 9, + /// \brief The 'signed char' type. + PREDEF_TYPE_SCHAR_ID = 10, + /// \brief The C++ 'wchar_t' type. + PREDEF_TYPE_WCHAR_ID = 11, + /// \brief The (signed) 'short' type. + PREDEF_TYPE_SHORT_ID = 12, + /// \brief The (signed) 'int' type. + PREDEF_TYPE_INT_ID = 13, + /// \brief The (signed) 'long' type. + PREDEF_TYPE_LONG_ID = 14, + /// \brief The (signed) 'long long' type. + PREDEF_TYPE_LONGLONG_ID = 15, + /// \brief The 'float' type. + PREDEF_TYPE_FLOAT_ID = 16, + /// \brief The 'double' type. + PREDEF_TYPE_DOUBLE_ID = 17, + /// \brief The 'long double' type. + PREDEF_TYPE_LONGDOUBLE_ID = 18, + /// \brief The placeholder type for overloaded function sets. + PREDEF_TYPE_OVERLOAD_ID = 19, + /// \brief The placeholder type for dependent types. + PREDEF_TYPE_DEPENDENT_ID = 20, + /// \brief The '__uint128_t' type. + PREDEF_TYPE_UINT128_ID = 21, + /// \brief The '__int128_t' type. + PREDEF_TYPE_INT128_ID = 22, + /// \brief The type of 'nullptr'. + PREDEF_TYPE_NULLPTR_ID = 23, + /// \brief The C++ 'char16_t' type. + PREDEF_TYPE_CHAR16_ID = 24, + /// \brief The C++ 'char32_t' type. + PREDEF_TYPE_CHAR32_ID = 25, + /// \brief The ObjC 'id' type. + PREDEF_TYPE_OBJC_ID = 26, + /// \brief The ObjC 'Class' type. + PREDEF_TYPE_OBJC_CLASS = 27, + /// \brief The ObjC 'SEL' type. + PREDEF_TYPE_OBJC_SEL = 28, + /// \brief The 'unknown any' placeholder type. + PREDEF_TYPE_UNKNOWN_ANY = 29, + /// \brief The placeholder type for bound member functions. + PREDEF_TYPE_BOUND_MEMBER = 30, + /// \brief The "auto" deduction type. + PREDEF_TYPE_AUTO_DEDUCT = 31, + /// \brief The "auto &&" deduction type. + PREDEF_TYPE_AUTO_RREF_DEDUCT = 32, + /// \brief The OpenCL 'half' / ARM NEON __fp16 type. + PREDEF_TYPE_HALF_ID = 33, + /// \brief ARC's unbridged-cast placeholder type. + PREDEF_TYPE_ARC_UNBRIDGED_CAST = 34, + /// \brief The pseudo-object placeholder type. + PREDEF_TYPE_PSEUDO_OBJECT = 35, + /// \brief The placeholder type for builtin functions. + PREDEF_TYPE_BUILTIN_FN = 36, + /// \brief OpenCL 1d image type. + PREDEF_TYPE_IMAGE1D_ID = 37, + /// \brief OpenCL 1d image array type. + PREDEF_TYPE_IMAGE1D_ARR_ID = 38, + /// \brief OpenCL 1d image buffer type. + PREDEF_TYPE_IMAGE1D_BUFF_ID = 39, + /// \brief OpenCL 2d image type. + PREDEF_TYPE_IMAGE2D_ID = 40, + /// \brief OpenCL 2d image array type. + PREDEF_TYPE_IMAGE2D_ARR_ID = 41, + /// \brief OpenCL 2d image depth type. + PREDEF_TYPE_IMAGE2D_DEP_ID = 42, + /// \brief OpenCL 2d image array depth type. + PREDEF_TYPE_IMAGE2D_ARR_DEP_ID = 43, + /// \brief OpenCL 2d image MSAA type. + PREDEF_TYPE_IMAGE2D_MSAA_ID = 44, + /// \brief OpenCL 2d image array MSAA type. + PREDEF_TYPE_IMAGE2D_ARR_MSAA_ID = 45, + /// \brief OpenCL 2d image MSAA depth type. + PREDEF_TYPE_IMAGE2D_MSAA_DEP_ID = 46, + /// \brief OpenCL 2d image array MSAA depth type. + PREDEF_TYPE_IMAGE2D_ARR_MSAA_DEPTH_ID = 47, + /// \brief OpenCL 3d image type. + PREDEF_TYPE_IMAGE3D_ID = 48, + /// \brief OpenCL event type. + PREDEF_TYPE_EVENT_ID = 49, + /// \brief OpenCL clk event type. + PREDEF_TYPE_CLK_EVENT_ID = 50, + /// \brief OpenCL sampler type. + PREDEF_TYPE_SAMPLER_ID = 51, + /// \brief OpenCL queue type. + PREDEF_TYPE_QUEUE_ID = 52, + /// \brief OpenCL ndrange type. + PREDEF_TYPE_NDRANGE_ID = 53, + /// \brief OpenCL reserve_id type. + PREDEF_TYPE_RESERVE_ID_ID = 54, + /// \brief The placeholder type for OpenMP array section. + PREDEF_TYPE_OMP_ARRAY_SECTION = 55 + }; + + /// \brief The number of predefined type IDs that are reserved for + /// the PREDEF_TYPE_* constants. + /// + /// Type IDs for non-predefined types will start at + /// NUM_PREDEF_TYPE_IDs. + const unsigned NUM_PREDEF_TYPE_IDS = 100; + + /// \brief Record codes for each kind of type. + /// + /// These constants describe the type records that can occur within a + /// block identified by DECLTYPES_BLOCK_ID in the AST file. Each + /// constant describes a record for a specific type class in the + /// AST. + enum TypeCode { + /// \brief An ExtQualType record. + TYPE_EXT_QUAL = 1, + /// \brief A ComplexType record. + TYPE_COMPLEX = 3, + /// \brief A PointerType record. + TYPE_POINTER = 4, + /// \brief A BlockPointerType record. + TYPE_BLOCK_POINTER = 5, + /// \brief An LValueReferenceType record. + TYPE_LVALUE_REFERENCE = 6, + /// \brief An RValueReferenceType record. + TYPE_RVALUE_REFERENCE = 7, + /// \brief A MemberPointerType record. + TYPE_MEMBER_POINTER = 8, + /// \brief A ConstantArrayType record. + TYPE_CONSTANT_ARRAY = 9, + /// \brief An IncompleteArrayType record. + TYPE_INCOMPLETE_ARRAY = 10, + /// \brief A VariableArrayType record. + TYPE_VARIABLE_ARRAY = 11, + /// \brief A VectorType record. + TYPE_VECTOR = 12, + /// \brief An ExtVectorType record. + TYPE_EXT_VECTOR = 13, + /// \brief A FunctionNoProtoType record. + TYPE_FUNCTION_NO_PROTO = 14, + /// \brief A FunctionProtoType record. + TYPE_FUNCTION_PROTO = 15, + /// \brief A TypedefType record. + TYPE_TYPEDEF = 16, + /// \brief A TypeOfExprType record. + TYPE_TYPEOF_EXPR = 17, + /// \brief A TypeOfType record. + TYPE_TYPEOF = 18, + /// \brief A RecordType record. + TYPE_RECORD = 19, + /// \brief An EnumType record. + TYPE_ENUM = 20, + /// \brief An ObjCInterfaceType record. + TYPE_OBJC_INTERFACE = 21, + /// \brief An ObjCObjectPointerType record. + TYPE_OBJC_OBJECT_POINTER = 22, + /// \brief a DecltypeType record. + TYPE_DECLTYPE = 23, + /// \brief An ElaboratedType record. + TYPE_ELABORATED = 24, + /// \brief A SubstTemplateTypeParmType record. + TYPE_SUBST_TEMPLATE_TYPE_PARM = 25, + /// \brief An UnresolvedUsingType record. + TYPE_UNRESOLVED_USING = 26, + /// \brief An InjectedClassNameType record. + TYPE_INJECTED_CLASS_NAME = 27, + /// \brief An ObjCObjectType record. + TYPE_OBJC_OBJECT = 28, + /// \brief An TemplateTypeParmType record. + TYPE_TEMPLATE_TYPE_PARM = 29, + /// \brief An TemplateSpecializationType record. + TYPE_TEMPLATE_SPECIALIZATION = 30, + /// \brief A DependentNameType record. + TYPE_DEPENDENT_NAME = 31, + /// \brief A DependentTemplateSpecializationType record. + TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION = 32, + /// \brief A DependentSizedArrayType record. + TYPE_DEPENDENT_SIZED_ARRAY = 33, + /// \brief A ParenType record. + TYPE_PAREN = 34, + /// \brief A PackExpansionType record. + TYPE_PACK_EXPANSION = 35, + /// \brief An AttributedType record. + TYPE_ATTRIBUTED = 36, + /// \brief A SubstTemplateTypeParmPackType record. + TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK = 37, + /// \brief A AutoType record. + TYPE_AUTO = 38, + /// \brief A UnaryTransformType record. + TYPE_UNARY_TRANSFORM = 39, + /// \brief An AtomicType record. + TYPE_ATOMIC = 40, + /// \brief A DecayedType record. + TYPE_DECAYED = 41, + /// \brief An AdjustedType record. + TYPE_ADJUSTED = 42 + }; + + /// \brief The type IDs for special types constructed by semantic + /// analysis. + /// + /// The constants in this enumeration are indices into the + /// SPECIAL_TYPES record. + enum SpecialTypeIDs { + /// \brief CFConstantString type + SPECIAL_TYPE_CF_CONSTANT_STRING = 0, + /// \brief C FILE typedef type + SPECIAL_TYPE_FILE = 1, + /// \brief C jmp_buf typedef type + SPECIAL_TYPE_JMP_BUF = 2, + /// \brief C sigjmp_buf typedef type + SPECIAL_TYPE_SIGJMP_BUF = 3, + /// \brief Objective-C "id" redefinition type + SPECIAL_TYPE_OBJC_ID_REDEFINITION = 4, + /// \brief Objective-C "Class" redefinition type + SPECIAL_TYPE_OBJC_CLASS_REDEFINITION = 5, + /// \brief Objective-C "SEL" redefinition type + SPECIAL_TYPE_OBJC_SEL_REDEFINITION = 6, + /// \brief C ucontext_t typedef type + SPECIAL_TYPE_UCONTEXT_T = 7 + }; + + /// \brief The number of special type IDs. + const unsigned NumSpecialTypeIDs = 8; + + /// \brief Predefined declaration IDs. + /// + /// These declaration IDs correspond to predefined declarations in the AST + /// context, such as the NULL declaration ID. Such declarations are never + /// actually serialized, since they will be built by the AST context when + /// it is created. + enum PredefinedDeclIDs { + /// \brief The NULL declaration. + PREDEF_DECL_NULL_ID = 0, + + /// \brief The translation unit. + PREDEF_DECL_TRANSLATION_UNIT_ID = 1, + + /// \brief The Objective-C 'id' type. + PREDEF_DECL_OBJC_ID_ID = 2, + + /// \brief The Objective-C 'SEL' type. + PREDEF_DECL_OBJC_SEL_ID = 3, + + /// \brief The Objective-C 'Class' type. + PREDEF_DECL_OBJC_CLASS_ID = 4, + + /// \brief The Objective-C 'Protocol' type. + PREDEF_DECL_OBJC_PROTOCOL_ID = 5, + + /// \brief The signed 128-bit integer type. + PREDEF_DECL_INT_128_ID = 6, + + /// \brief The unsigned 128-bit integer type. + PREDEF_DECL_UNSIGNED_INT_128_ID = 7, + + /// \brief The internal 'instancetype' typedef. + PREDEF_DECL_OBJC_INSTANCETYPE_ID = 8, + + /// \brief The internal '__builtin_va_list' typedef. + PREDEF_DECL_BUILTIN_VA_LIST_ID = 9, + + /// \brief The internal '__va_list_tag' struct, if any. + PREDEF_DECL_VA_LIST_TAG = 10, + + /// \brief The internal '__builtin_ms_va_list' typedef. + PREDEF_DECL_BUILTIN_MS_VA_LIST_ID = 11, + + /// \brief The extern "C" context. + PREDEF_DECL_EXTERN_C_CONTEXT_ID = 12, + + /// \brief The internal '__make_integer_seq' template. + PREDEF_DECL_MAKE_INTEGER_SEQ_ID = 13, + }; + + /// \brief The number of declaration IDs that are predefined. + /// + /// For more information about predefined declarations, see the + /// \c PredefinedDeclIDs type and the PREDEF_DECL_*_ID constants. + const unsigned int NUM_PREDEF_DECL_IDS = 14; + + /// \brief Record code for a list of local redeclarations of a declaration. + const unsigned int LOCAL_REDECLARATIONS = 50; + + /// \brief Record codes for each kind of declaration. + /// + /// These constants describe the declaration records that can occur within + /// a declarations block (identified by DECLS_BLOCK_ID). Each + /// constant describes a record for a specific declaration class + /// in the AST. + enum DeclCode { + /// \brief A TypedefDecl record. + DECL_TYPEDEF = 51, + /// \brief A TypeAliasDecl record. + DECL_TYPEALIAS, + /// \brief An EnumDecl record. + DECL_ENUM, + /// \brief A RecordDecl record. + DECL_RECORD, + /// \brief An EnumConstantDecl record. + DECL_ENUM_CONSTANT, + /// \brief A FunctionDecl record. + DECL_FUNCTION, + /// \brief A ObjCMethodDecl record. + DECL_OBJC_METHOD, + /// \brief A ObjCInterfaceDecl record. + DECL_OBJC_INTERFACE, + /// \brief A ObjCProtocolDecl record. + DECL_OBJC_PROTOCOL, + /// \brief A ObjCIvarDecl record. + DECL_OBJC_IVAR, + /// \brief A ObjCAtDefsFieldDecl record. + DECL_OBJC_AT_DEFS_FIELD, + /// \brief A ObjCCategoryDecl record. + DECL_OBJC_CATEGORY, + /// \brief A ObjCCategoryImplDecl record. + DECL_OBJC_CATEGORY_IMPL, + /// \brief A ObjCImplementationDecl record. + DECL_OBJC_IMPLEMENTATION, + /// \brief A ObjCCompatibleAliasDecl record. + DECL_OBJC_COMPATIBLE_ALIAS, + /// \brief A ObjCPropertyDecl record. + DECL_OBJC_PROPERTY, + /// \brief A ObjCPropertyImplDecl record. + DECL_OBJC_PROPERTY_IMPL, + /// \brief A FieldDecl record. + DECL_FIELD, + /// \brief A MSPropertyDecl record. + DECL_MS_PROPERTY, + /// \brief A VarDecl record. + DECL_VAR, + /// \brief An ImplicitParamDecl record. + DECL_IMPLICIT_PARAM, + /// \brief A ParmVarDecl record. + DECL_PARM_VAR, + /// \brief A FileScopeAsmDecl record. + DECL_FILE_SCOPE_ASM, + /// \brief A BlockDecl record. + DECL_BLOCK, + /// \brief A CapturedDecl record. + DECL_CAPTURED, + /// \brief A record that stores the set of declarations that are + /// lexically stored within a given DeclContext. + /// + /// The record itself is a blob that is an array of declaration IDs, + /// in the order in which those declarations were added to the + /// declaration context. This data is used when iterating over + /// the contents of a DeclContext, e.g., via + /// DeclContext::decls_begin() and DeclContext::decls_end(). + DECL_CONTEXT_LEXICAL, + /// \brief A record that stores the set of declarations that are + /// visible from a given DeclContext. + /// + /// The record itself stores a set of mappings, each of which + /// associates a declaration name with one or more declaration + /// IDs. This data is used when performing qualified name lookup + /// into a DeclContext via DeclContext::lookup. + DECL_CONTEXT_VISIBLE, + /// \brief A LabelDecl record. + DECL_LABEL, + /// \brief A NamespaceDecl record. + DECL_NAMESPACE, + /// \brief A NamespaceAliasDecl record. + DECL_NAMESPACE_ALIAS, + /// \brief A UsingDecl record. + DECL_USING, + /// \brief A UsingShadowDecl record. + DECL_USING_SHADOW, + /// \brief A UsingDirecitveDecl record. + DECL_USING_DIRECTIVE, + /// \brief An UnresolvedUsingValueDecl record. + DECL_UNRESOLVED_USING_VALUE, + /// \brief An UnresolvedUsingTypenameDecl record. + DECL_UNRESOLVED_USING_TYPENAME, + /// \brief A LinkageSpecDecl record. + DECL_LINKAGE_SPEC, + /// \brief A CXXRecordDecl record. + DECL_CXX_RECORD, + /// \brief A CXXMethodDecl record. + DECL_CXX_METHOD, + /// \brief A CXXConstructorDecl record. + DECL_CXX_CONSTRUCTOR, + /// \brief A CXXDestructorDecl record. + DECL_CXX_DESTRUCTOR, + /// \brief A CXXConversionDecl record. + DECL_CXX_CONVERSION, + /// \brief An AccessSpecDecl record. + DECL_ACCESS_SPEC, + + /// \brief A FriendDecl record. + DECL_FRIEND, + /// \brief A FriendTemplateDecl record. + DECL_FRIEND_TEMPLATE, + /// \brief A ClassTemplateDecl record. + DECL_CLASS_TEMPLATE, + /// \brief A ClassTemplateSpecializationDecl record. + DECL_CLASS_TEMPLATE_SPECIALIZATION, + /// \brief A ClassTemplatePartialSpecializationDecl record. + DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION, + /// \brief A VarTemplateDecl record. + DECL_VAR_TEMPLATE, + /// \brief A VarTemplateSpecializationDecl record. + DECL_VAR_TEMPLATE_SPECIALIZATION, + /// \brief A VarTemplatePartialSpecializationDecl record. + DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION, + /// \brief A FunctionTemplateDecl record. + DECL_FUNCTION_TEMPLATE, + /// \brief A TemplateTypeParmDecl record. + DECL_TEMPLATE_TYPE_PARM, + /// \brief A NonTypeTemplateParmDecl record. + DECL_NON_TYPE_TEMPLATE_PARM, + /// \brief A TemplateTemplateParmDecl record. + DECL_TEMPLATE_TEMPLATE_PARM, + /// \brief A TypeAliasTemplateDecl record. + DECL_TYPE_ALIAS_TEMPLATE, + /// \brief A StaticAssertDecl record. + DECL_STATIC_ASSERT, + /// \brief A record containing CXXBaseSpecifiers. + DECL_CXX_BASE_SPECIFIERS, + /// \brief A record containing CXXCtorInitializers. + DECL_CXX_CTOR_INITIALIZERS, + /// \brief A IndirectFieldDecl record. + DECL_INDIRECTFIELD, + /// \brief A NonTypeTemplateParmDecl record that stores an expanded + /// non-type template parameter pack. + DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK, + /// \brief A TemplateTemplateParmDecl record that stores an expanded + /// template template parameter pack. + DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK, + /// \brief A ClassScopeFunctionSpecializationDecl record a class scope + /// function specialization. (Microsoft extension). + DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION, + /// \brief An ImportDecl recording a module import. + DECL_IMPORT, + /// \brief An OMPThreadPrivateDecl record. + DECL_OMP_THREADPRIVATE, + /// \brief An EmptyDecl record. + DECL_EMPTY, + /// \brief An ObjCTypeParamDecl record. + DECL_OBJC_TYPE_PARAM, + }; + + /// \brief Record codes for each kind of statement or expression. + /// + /// These constants describe the records that describe statements + /// or expressions. These records occur within type and declarations + /// block, so they begin with record values of 128. Each constant + /// describes a record for a specific statement or expression class in the + /// AST. + enum StmtCode { + /// \brief A marker record that indicates that we are at the end + /// of an expression. + STMT_STOP = 128, + /// \brief A NULL expression. + STMT_NULL_PTR, + /// \brief A reference to a previously [de]serialized Stmt record. + STMT_REF_PTR, + /// \brief A NullStmt record. + STMT_NULL, + /// \brief A CompoundStmt record. + STMT_COMPOUND, + /// \brief A CaseStmt record. + STMT_CASE, + /// \brief A DefaultStmt record. + STMT_DEFAULT, + /// \brief A LabelStmt record. + STMT_LABEL, + /// \brief An AttributedStmt record. + STMT_ATTRIBUTED, + /// \brief An IfStmt record. + STMT_IF, + /// \brief A SwitchStmt record. + STMT_SWITCH, + /// \brief A WhileStmt record. + STMT_WHILE, + /// \brief A DoStmt record. + STMT_DO, + /// \brief A ForStmt record. + STMT_FOR, + /// \brief A GotoStmt record. + STMT_GOTO, + /// \brief An IndirectGotoStmt record. + STMT_INDIRECT_GOTO, + /// \brief A ContinueStmt record. + STMT_CONTINUE, + /// \brief A BreakStmt record. + STMT_BREAK, + /// \brief A ReturnStmt record. + STMT_RETURN, + /// \brief A DeclStmt record. + STMT_DECL, + /// \brief A CapturedStmt record. + STMT_CAPTURED, + /// \brief A GCC-style AsmStmt record. + STMT_GCCASM, + /// \brief A MS-style AsmStmt record. + STMT_MSASM, + /// \brief A PredefinedExpr record. + EXPR_PREDEFINED, + /// \brief A DeclRefExpr record. + EXPR_DECL_REF, + /// \brief An IntegerLiteral record. + EXPR_INTEGER_LITERAL, + /// \brief A FloatingLiteral record. + EXPR_FLOATING_LITERAL, + /// \brief An ImaginaryLiteral record. + EXPR_IMAGINARY_LITERAL, + /// \brief A StringLiteral record. + EXPR_STRING_LITERAL, + /// \brief A CharacterLiteral record. + EXPR_CHARACTER_LITERAL, + /// \brief A ParenExpr record. + EXPR_PAREN, + /// \brief A ParenListExpr record. + EXPR_PAREN_LIST, + /// \brief A UnaryOperator record. + EXPR_UNARY_OPERATOR, + /// \brief An OffsetOfExpr record. + EXPR_OFFSETOF, + /// \brief A SizefAlignOfExpr record. + EXPR_SIZEOF_ALIGN_OF, + /// \brief An ArraySubscriptExpr record. + EXPR_ARRAY_SUBSCRIPT, + /// \brief A CallExpr record. + EXPR_CALL, + /// \brief A MemberExpr record. + EXPR_MEMBER, + /// \brief A BinaryOperator record. + EXPR_BINARY_OPERATOR, + /// \brief A CompoundAssignOperator record. + EXPR_COMPOUND_ASSIGN_OPERATOR, + /// \brief A ConditionOperator record. + EXPR_CONDITIONAL_OPERATOR, + /// \brief An ImplicitCastExpr record. + EXPR_IMPLICIT_CAST, + /// \brief A CStyleCastExpr record. + EXPR_CSTYLE_CAST, + /// \brief A CompoundLiteralExpr record. + EXPR_COMPOUND_LITERAL, + /// \brief An ExtVectorElementExpr record. + EXPR_EXT_VECTOR_ELEMENT, + /// \brief An InitListExpr record. + EXPR_INIT_LIST, + /// \brief A DesignatedInitExpr record. + EXPR_DESIGNATED_INIT, + /// \brief A DesignatedInitUpdateExpr record. + EXPR_DESIGNATED_INIT_UPDATE, + /// \brief An ImplicitValueInitExpr record. + EXPR_IMPLICIT_VALUE_INIT, + /// \brief An NoInitExpr record. + EXPR_NO_INIT, + /// \brief A VAArgExpr record. + EXPR_VA_ARG, + /// \brief An AddrLabelExpr record. + EXPR_ADDR_LABEL, + /// \brief A StmtExpr record. + EXPR_STMT, + /// \brief A ChooseExpr record. + EXPR_CHOOSE, + /// \brief A GNUNullExpr record. + EXPR_GNU_NULL, + /// \brief A ShuffleVectorExpr record. + EXPR_SHUFFLE_VECTOR, + /// \brief A ConvertVectorExpr record. + EXPR_CONVERT_VECTOR, + /// \brief BlockExpr + EXPR_BLOCK, + /// \brief A GenericSelectionExpr record. + EXPR_GENERIC_SELECTION, + /// \brief A PseudoObjectExpr record. + EXPR_PSEUDO_OBJECT, + /// \brief An AtomicExpr record. + EXPR_ATOMIC, + + // Objective-C + + /// \brief An ObjCStringLiteral record. + EXPR_OBJC_STRING_LITERAL, + + EXPR_OBJC_BOXED_EXPRESSION, + EXPR_OBJC_ARRAY_LITERAL, + EXPR_OBJC_DICTIONARY_LITERAL, + + + /// \brief An ObjCEncodeExpr record. + EXPR_OBJC_ENCODE, + /// \brief An ObjCSelectorExpr record. + EXPR_OBJC_SELECTOR_EXPR, + /// \brief An ObjCProtocolExpr record. + EXPR_OBJC_PROTOCOL_EXPR, + /// \brief An ObjCIvarRefExpr record. + EXPR_OBJC_IVAR_REF_EXPR, + /// \brief An ObjCPropertyRefExpr record. + EXPR_OBJC_PROPERTY_REF_EXPR, + /// \brief An ObjCSubscriptRefExpr record. + EXPR_OBJC_SUBSCRIPT_REF_EXPR, + /// \brief UNUSED + EXPR_OBJC_KVC_REF_EXPR, + /// \brief An ObjCMessageExpr record. + EXPR_OBJC_MESSAGE_EXPR, + /// \brief An ObjCIsa Expr record. + EXPR_OBJC_ISA, + /// \brief An ObjCIndirectCopyRestoreExpr record. + EXPR_OBJC_INDIRECT_COPY_RESTORE, + + /// \brief An ObjCForCollectionStmt record. + STMT_OBJC_FOR_COLLECTION, + /// \brief An ObjCAtCatchStmt record. + STMT_OBJC_CATCH, + /// \brief An ObjCAtFinallyStmt record. + STMT_OBJC_FINALLY, + /// \brief An ObjCAtTryStmt record. + STMT_OBJC_AT_TRY, + /// \brief An ObjCAtSynchronizedStmt record. + STMT_OBJC_AT_SYNCHRONIZED, + /// \brief An ObjCAtThrowStmt record. + STMT_OBJC_AT_THROW, + /// \brief An ObjCAutoreleasePoolStmt record. + STMT_OBJC_AUTORELEASE_POOL, + /// \brief A ObjCBoolLiteralExpr record. + EXPR_OBJC_BOOL_LITERAL, + + // C++ + + /// \brief A CXXCatchStmt record. + STMT_CXX_CATCH, + /// \brief A CXXTryStmt record. + STMT_CXX_TRY, + /// \brief A CXXForRangeStmt record. + STMT_CXX_FOR_RANGE, + + /// \brief A CXXOperatorCallExpr record. + EXPR_CXX_OPERATOR_CALL, + /// \brief A CXXMemberCallExpr record. + EXPR_CXX_MEMBER_CALL, + /// \brief A CXXConstructExpr record. + EXPR_CXX_CONSTRUCT, + /// \brief A CXXTemporaryObjectExpr record. + EXPR_CXX_TEMPORARY_OBJECT, + /// \brief A CXXStaticCastExpr record. + EXPR_CXX_STATIC_CAST, + /// \brief A CXXDynamicCastExpr record. + EXPR_CXX_DYNAMIC_CAST, + /// \brief A CXXReinterpretCastExpr record. + EXPR_CXX_REINTERPRET_CAST, + /// \brief A CXXConstCastExpr record. + EXPR_CXX_CONST_CAST, + /// \brief A CXXFunctionalCastExpr record. + EXPR_CXX_FUNCTIONAL_CAST, + /// \brief A UserDefinedLiteral record. + EXPR_USER_DEFINED_LITERAL, + /// \brief A CXXStdInitializerListExpr record. + EXPR_CXX_STD_INITIALIZER_LIST, + /// \brief A CXXBoolLiteralExpr record. + EXPR_CXX_BOOL_LITERAL, + EXPR_CXX_NULL_PTR_LITERAL, // CXXNullPtrLiteralExpr + EXPR_CXX_TYPEID_EXPR, // CXXTypeidExpr (of expr). + EXPR_CXX_TYPEID_TYPE, // CXXTypeidExpr (of type). + EXPR_CXX_THIS, // CXXThisExpr + EXPR_CXX_THROW, // CXXThrowExpr + EXPR_CXX_DEFAULT_ARG, // CXXDefaultArgExpr + EXPR_CXX_DEFAULT_INIT, // CXXDefaultInitExpr + EXPR_CXX_BIND_TEMPORARY, // CXXBindTemporaryExpr + + EXPR_CXX_SCALAR_VALUE_INIT, // CXXScalarValueInitExpr + EXPR_CXX_NEW, // CXXNewExpr + EXPR_CXX_DELETE, // CXXDeleteExpr + EXPR_CXX_PSEUDO_DESTRUCTOR, // CXXPseudoDestructorExpr + + EXPR_EXPR_WITH_CLEANUPS, // ExprWithCleanups + + EXPR_CXX_DEPENDENT_SCOPE_MEMBER, // CXXDependentScopeMemberExpr + EXPR_CXX_DEPENDENT_SCOPE_DECL_REF, // DependentScopeDeclRefExpr + EXPR_CXX_UNRESOLVED_CONSTRUCT, // CXXUnresolvedConstructExpr + EXPR_CXX_UNRESOLVED_MEMBER, // UnresolvedMemberExpr + EXPR_CXX_UNRESOLVED_LOOKUP, // UnresolvedLookupExpr + + EXPR_CXX_EXPRESSION_TRAIT, // ExpressionTraitExpr + EXPR_CXX_NOEXCEPT, // CXXNoexceptExpr + + EXPR_OPAQUE_VALUE, // OpaqueValueExpr + EXPR_BINARY_CONDITIONAL_OPERATOR, // BinaryConditionalOperator + EXPR_TYPE_TRAIT, // TypeTraitExpr + EXPR_ARRAY_TYPE_TRAIT, // ArrayTypeTraitIntExpr + + EXPR_PACK_EXPANSION, // PackExpansionExpr + EXPR_SIZEOF_PACK, // SizeOfPackExpr + EXPR_SUBST_NON_TYPE_TEMPLATE_PARM, // SubstNonTypeTemplateParmExpr + EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK,// SubstNonTypeTemplateParmPackExpr + EXPR_FUNCTION_PARM_PACK, // FunctionParmPackExpr + EXPR_MATERIALIZE_TEMPORARY, // MaterializeTemporaryExpr + EXPR_CXX_FOLD, // CXXFoldExpr + + // CUDA + EXPR_CUDA_KERNEL_CALL, // CUDAKernelCallExpr + + // OpenCL + EXPR_ASTYPE, // AsTypeExpr + + // Microsoft + EXPR_CXX_PROPERTY_REF_EXPR, // MSPropertyRefExpr + EXPR_CXX_PROPERTY_SUBSCRIPT_EXPR, // MSPropertySubscriptExpr + EXPR_CXX_UUIDOF_EXPR, // CXXUuidofExpr (of expr). + EXPR_CXX_UUIDOF_TYPE, // CXXUuidofExpr (of type). + STMT_SEH_LEAVE, // SEHLeaveStmt + STMT_SEH_EXCEPT, // SEHExceptStmt + STMT_SEH_FINALLY, // SEHFinallyStmt + STMT_SEH_TRY, // SEHTryStmt + + // OpenMP directives + STMT_OMP_PARALLEL_DIRECTIVE, + STMT_OMP_SIMD_DIRECTIVE, + STMT_OMP_FOR_DIRECTIVE, + STMT_OMP_FOR_SIMD_DIRECTIVE, + STMT_OMP_SECTIONS_DIRECTIVE, + STMT_OMP_SECTION_DIRECTIVE, + STMT_OMP_SINGLE_DIRECTIVE, + STMT_OMP_MASTER_DIRECTIVE, + STMT_OMP_CRITICAL_DIRECTIVE, + STMT_OMP_PARALLEL_FOR_DIRECTIVE, + STMT_OMP_PARALLEL_FOR_SIMD_DIRECTIVE, + STMT_OMP_PARALLEL_SECTIONS_DIRECTIVE, + STMT_OMP_TASK_DIRECTIVE, + STMT_OMP_TASKYIELD_DIRECTIVE, + STMT_OMP_BARRIER_DIRECTIVE, + STMT_OMP_TASKWAIT_DIRECTIVE, + STMT_OMP_FLUSH_DIRECTIVE, + STMT_OMP_ORDERED_DIRECTIVE, + STMT_OMP_ATOMIC_DIRECTIVE, + STMT_OMP_TARGET_DIRECTIVE, + STMT_OMP_TARGET_DATA_DIRECTIVE, + STMT_OMP_TEAMS_DIRECTIVE, + STMT_OMP_TASKGROUP_DIRECTIVE, + STMT_OMP_CANCELLATION_POINT_DIRECTIVE, + STMT_OMP_CANCEL_DIRECTIVE, + STMT_OMP_TASKLOOP_DIRECTIVE, + STMT_OMP_TASKLOOP_SIMD_DIRECTIVE, + STMT_OMP_DISTRIBUTE_DIRECTIVE, + EXPR_OMP_ARRAY_SECTION, + + // ARC + EXPR_OBJC_BRIDGED_CAST, // ObjCBridgedCastExpr + + STMT_MS_DEPENDENT_EXISTS, // MSDependentExistsStmt + EXPR_LAMBDA // LambdaExpr + }; + + /// \brief The kinds of designators that can occur in a + /// DesignatedInitExpr. + enum DesignatorTypes { + /// \brief Field designator where only the field name is known. + DESIG_FIELD_NAME = 0, + /// \brief Field designator where the field has been resolved to + /// a declaration. + DESIG_FIELD_DECL = 1, + /// \brief Array designator. + DESIG_ARRAY = 2, + /// \brief GNU array range designator. + DESIG_ARRAY_RANGE = 3 + }; + + /// \brief The different kinds of data that can occur in a + /// CtorInitializer. + enum CtorInitializerType { + CTOR_INITIALIZER_BASE, + CTOR_INITIALIZER_DELEGATING, + CTOR_INITIALIZER_MEMBER, + CTOR_INITIALIZER_INDIRECT_MEMBER + }; + + /// \brief Describes the redeclarations of a declaration. + struct LocalRedeclarationsInfo { + DeclID FirstID; // The ID of the first declaration + unsigned Offset; // Offset into the array of redeclaration chains. + + friend bool operator<(const LocalRedeclarationsInfo &X, + const LocalRedeclarationsInfo &Y) { + return X.FirstID < Y.FirstID; + } + + friend bool operator>(const LocalRedeclarationsInfo &X, + const LocalRedeclarationsInfo &Y) { + return X.FirstID > Y.FirstID; + } + + friend bool operator<=(const LocalRedeclarationsInfo &X, + const LocalRedeclarationsInfo &Y) { + return X.FirstID <= Y.FirstID; + } + + friend bool operator>=(const LocalRedeclarationsInfo &X, + const LocalRedeclarationsInfo &Y) { + return X.FirstID >= Y.FirstID; + } + }; + + /// \brief Describes the categories of an Objective-C class. + struct ObjCCategoriesInfo { + DeclID DefinitionID; // The ID of the definition + unsigned Offset; // Offset into the array of category lists. + + friend bool operator<(const ObjCCategoriesInfo &X, + const ObjCCategoriesInfo &Y) { + return X.DefinitionID < Y.DefinitionID; + } + + friend bool operator>(const ObjCCategoriesInfo &X, + const ObjCCategoriesInfo &Y) { + return X.DefinitionID > Y.DefinitionID; + } + + friend bool operator<=(const ObjCCategoriesInfo &X, + const ObjCCategoriesInfo &Y) { + return X.DefinitionID <= Y.DefinitionID; + } + + friend bool operator>=(const ObjCCategoriesInfo &X, + const ObjCCategoriesInfo &Y) { + return X.DefinitionID >= Y.DefinitionID; + } + }; + + /// \brief A key used when looking up entities by \ref DeclarationName. + /// + /// Different \ref DeclarationNames are mapped to different keys, but the + /// same key can occasionally represent multiple names (for names that + /// contain types, in particular). + class DeclarationNameKey { + typedef unsigned NameKind; + + NameKind Kind; + uint64_t Data; + + public: + DeclarationNameKey() : Kind(), Data() {} + DeclarationNameKey(DeclarationName Name); + + DeclarationNameKey(NameKind Kind, uint64_t Data) + : Kind(Kind), Data(Data) {} + + NameKind getKind() const { return Kind; } + + IdentifierInfo *getIdentifier() const { + assert(Kind == DeclarationName::Identifier || + Kind == DeclarationName::CXXLiteralOperatorName); + return (IdentifierInfo *)Data; + } + Selector getSelector() const { + assert(Kind == DeclarationName::ObjCZeroArgSelector || + Kind == DeclarationName::ObjCOneArgSelector || + Kind == DeclarationName::ObjCMultiArgSelector); + return Selector(Data); + } + OverloadedOperatorKind getOperatorKind() const { + assert(Kind == DeclarationName::CXXOperatorName); + return (OverloadedOperatorKind)Data; + } + + /// Compute a fingerprint of this key for use in on-disk hash table. + unsigned getHash() const; + + friend bool operator==(const DeclarationNameKey &A, + const DeclarationNameKey &B) { + return A.Kind == B.Kind && A.Data == B.Data; + } + }; + + /// @} + } +} // end namespace clang + +namespace llvm { + template <> struct DenseMapInfo<clang::serialization::DeclarationNameKey> { + static clang::serialization::DeclarationNameKey getEmptyKey() { + return clang::serialization::DeclarationNameKey(-1, 1); + } + static clang::serialization::DeclarationNameKey getTombstoneKey() { + return clang::serialization::DeclarationNameKey(-1, 2); + } + static unsigned + getHashValue(const clang::serialization::DeclarationNameKey &Key) { + return Key.getHash(); + } + static bool isEqual(const clang::serialization::DeclarationNameKey &L, + const clang::serialization::DeclarationNameKey &R) { + return L == R; + } + }; +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Serialization/ASTDeserializationListener.h b/contrib/llvm/tools/clang/include/clang/Serialization/ASTDeserializationListener.h new file mode 100644 index 0000000..4b10c39 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Serialization/ASTDeserializationListener.h @@ -0,0 +1,58 @@ +//===- ASTDeserializationListener.h - Decl/Type PCH Read Events -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ASTDeserializationListener class, which is notified +// by the ASTReader whenever a type or declaration is deserialized. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SERIALIZATION_ASTDESERIALIZATIONLISTENER_H +#define LLVM_CLANG_SERIALIZATION_ASTDESERIALIZATIONLISTENER_H + +#include "clang/Basic/IdentifierTable.h" +#include "clang/Serialization/ASTBitCodes.h" + +namespace clang { + +class Decl; +class ASTReader; +class QualType; +class MacroDefinitionRecord; +class MacroInfo; +class Module; + +class ASTDeserializationListener { +public: + virtual ~ASTDeserializationListener(); + + /// \brief The ASTReader was initialized. + virtual void ReaderInitialized(ASTReader *Reader) { } + + /// \brief An identifier was deserialized from the AST file. + virtual void IdentifierRead(serialization::IdentID ID, + IdentifierInfo *II) { } + /// \brief A macro was read from the AST file. + virtual void MacroRead(serialization::MacroID ID, MacroInfo *MI) { } + /// \brief A type was deserialized from the AST file. The ID here has the + /// qualifier bits already removed, and T is guaranteed to be locally + /// unqualified. + virtual void TypeRead(serialization::TypeIdx Idx, QualType T) { } + /// \brief A decl was deserialized from the AST file. + virtual void DeclRead(serialization::DeclID ID, const Decl *D) { } + /// \brief A selector was read from the AST file. + virtual void SelectorRead(serialization::SelectorID iD, Selector Sel) {} + /// \brief A macro definition was read from the AST file. + virtual void MacroDefinitionRead(serialization::PreprocessedEntityID, + MacroDefinitionRecord *MD) {} + /// \brief A module definition was read from the AST file. + virtual void ModuleRead(serialization::SubmoduleID ID, Module *Mod) {} +}; +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Serialization/ASTReader.h b/contrib/llvm/tools/clang/include/clang/Serialization/ASTReader.h new file mode 100644 index 0000000..588a6a9 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Serialization/ASTReader.h @@ -0,0 +1,2141 @@ +//===--- ASTReader.h - AST File Reader --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ASTReader class, which reads AST files. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SERIALIZATION_ASTREADER_H +#define LLVM_CLANG_SERIALIZATION_ASTREADER_H + +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/TemplateBase.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/FileSystemOptions.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/Version.h" +#include "clang/Lex/ExternalPreprocessorSource.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/PreprocessingRecord.h" +#include "clang/Sema/ExternalSemaSource.h" +#include "clang/Serialization/ASTBitCodes.h" +#include "clang/Serialization/ContinuousRangeMap.h" +#include "clang/Serialization/Module.h" +#include "clang/Serialization/ModuleFileExtension.h" +#include "clang/Serialization/ModuleManager.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/MapVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/TinyPtrVector.h" +#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Timer.h" +#include <deque> +#include <map> +#include <memory> +#include <string> +#include <utility> +#include <vector> + +namespace llvm { + class MemoryBuffer; +} + +namespace clang { + +class AddrLabelExpr; +class ASTConsumer; +class ASTContext; +class ASTIdentifierIterator; +class ASTUnit; // FIXME: Layering violation and egregious hack. +class Attr; +class Decl; +class DeclContext; +class DefMacroDirective; +class DiagnosticOptions; +class NestedNameSpecifier; +class CXXBaseSpecifier; +class CXXConstructorDecl; +class CXXCtorInitializer; +class GlobalModuleIndex; +class GotoStmt; +class MacroDefinition; +class MacroDirective; +class ModuleMacro; +class NamedDecl; +class OpaqueValueExpr; +class Preprocessor; +class PreprocessorOptions; +class Sema; +class SwitchCase; +class ASTDeserializationListener; +class ASTWriter; +class ASTReader; +class ASTDeclReader; +class ASTStmtReader; +class TypeLocReader; +struct HeaderFileInfo; +class VersionTuple; +class TargetOptions; +class LazyASTUnresolvedSet; + +/// \brief Abstract interface for callback invocations by the ASTReader. +/// +/// While reading an AST file, the ASTReader will call the methods of the +/// listener to pass on specific information. Some of the listener methods can +/// return true to indicate to the ASTReader that the information (and +/// consequently the AST file) is invalid. +class ASTReaderListener { +public: + virtual ~ASTReaderListener(); + + /// \brief Receives the full Clang version information. + /// + /// \returns true to indicate that the version is invalid. Subclasses should + /// generally defer to this implementation. + virtual bool ReadFullVersionInformation(StringRef FullVersion) { + return FullVersion != getClangFullRepositoryVersion(); + } + + virtual void ReadModuleName(StringRef ModuleName) {} + virtual void ReadModuleMapFile(StringRef ModuleMapPath) {} + + /// \brief Receives the language options. + /// + /// \returns true to indicate the options are invalid or false otherwise. + virtual bool ReadLanguageOptions(const LangOptions &LangOpts, + bool Complain, + bool AllowCompatibleDifferences) { + return false; + } + + /// \brief Receives the target options. + /// + /// \returns true to indicate the target options are invalid, or false + /// otherwise. + virtual bool ReadTargetOptions(const TargetOptions &TargetOpts, bool Complain, + bool AllowCompatibleDifferences) { + return false; + } + + /// \brief Receives the diagnostic options. + /// + /// \returns true to indicate the diagnostic options are invalid, or false + /// otherwise. + virtual bool + ReadDiagnosticOptions(IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts, + bool Complain) { + return false; + } + + /// \brief Receives the file system options. + /// + /// \returns true to indicate the file system options are invalid, or false + /// otherwise. + virtual bool ReadFileSystemOptions(const FileSystemOptions &FSOpts, + bool Complain) { + return false; + } + + /// \brief Receives the header search options. + /// + /// \returns true to indicate the header search options are invalid, or false + /// otherwise. + virtual bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts, + StringRef SpecificModuleCachePath, + bool Complain) { + return false; + } + + /// \brief Receives the preprocessor options. + /// + /// \param SuggestedPredefines Can be filled in with the set of predefines + /// that are suggested by the preprocessor options. Typically only used when + /// loading a precompiled header. + /// + /// \returns true to indicate the preprocessor options are invalid, or false + /// otherwise. + virtual bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, + bool Complain, + std::string &SuggestedPredefines) { + return false; + } + + /// \brief Receives __COUNTER__ value. + virtual void ReadCounter(const serialization::ModuleFile &M, + unsigned Value) {} + + /// This is called for each AST file loaded. + virtual void visitModuleFile(StringRef Filename, + serialization::ModuleKind Kind) {} + + /// \brief Returns true if this \c ASTReaderListener wants to receive the + /// input files of the AST file via \c visitInputFile, false otherwise. + virtual bool needsInputFileVisitation() { return false; } + /// \brief Returns true if this \c ASTReaderListener wants to receive the + /// system input files of the AST file via \c visitInputFile, false otherwise. + virtual bool needsSystemInputFileVisitation() { return false; } + /// \brief if \c needsInputFileVisitation returns true, this is called for + /// each non-system input file of the AST File. If + /// \c needsSystemInputFileVisitation is true, then it is called for all + /// system input files as well. + /// + /// \returns true to continue receiving the next input file, false to stop. + virtual bool visitInputFile(StringRef Filename, bool isSystem, + bool isOverridden, bool isExplicitModule) { + return true; + } + + /// \brief Returns true if this \c ASTReaderListener wants to receive the + /// imports of the AST file via \c visitImport, false otherwise. + virtual bool needsImportVisitation() const { return false; } + /// \brief If needsImportVisitation returns \c true, this is called for each + /// AST file imported by this AST file. + virtual void visitImport(StringRef Filename) {} + + /// Indicates that a particular module file extension has been read. + virtual void readModuleFileExtension( + const ModuleFileExtensionMetadata &Metadata) {} +}; + +/// \brief Simple wrapper class for chaining listeners. +class ChainedASTReaderListener : public ASTReaderListener { + std::unique_ptr<ASTReaderListener> First; + std::unique_ptr<ASTReaderListener> Second; + +public: + /// Takes ownership of \p First and \p Second. + ChainedASTReaderListener(std::unique_ptr<ASTReaderListener> First, + std::unique_ptr<ASTReaderListener> Second) + : First(std::move(First)), Second(std::move(Second)) {} + + std::unique_ptr<ASTReaderListener> takeFirst() { return std::move(First); } + std::unique_ptr<ASTReaderListener> takeSecond() { return std::move(Second); } + + bool ReadFullVersionInformation(StringRef FullVersion) override; + void ReadModuleName(StringRef ModuleName) override; + void ReadModuleMapFile(StringRef ModuleMapPath) override; + bool ReadLanguageOptions(const LangOptions &LangOpts, bool Complain, + bool AllowCompatibleDifferences) override; + bool ReadTargetOptions(const TargetOptions &TargetOpts, bool Complain, + bool AllowCompatibleDifferences) override; + bool ReadDiagnosticOptions(IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts, + bool Complain) override; + bool ReadFileSystemOptions(const FileSystemOptions &FSOpts, + bool Complain) override; + + bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts, + StringRef SpecificModuleCachePath, + bool Complain) override; + bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, + bool Complain, + std::string &SuggestedPredefines) override; + + void ReadCounter(const serialization::ModuleFile &M, unsigned Value) override; + bool needsInputFileVisitation() override; + bool needsSystemInputFileVisitation() override; + void visitModuleFile(StringRef Filename, + serialization::ModuleKind Kind) override; + bool visitInputFile(StringRef Filename, bool isSystem, + bool isOverridden, bool isExplicitModule) override; + void readModuleFileExtension( + const ModuleFileExtensionMetadata &Metadata) override; +}; + +/// \brief ASTReaderListener implementation to validate the information of +/// the PCH file against an initialized Preprocessor. +class PCHValidator : public ASTReaderListener { + Preprocessor &PP; + ASTReader &Reader; + +public: + PCHValidator(Preprocessor &PP, ASTReader &Reader) + : PP(PP), Reader(Reader) {} + + bool ReadLanguageOptions(const LangOptions &LangOpts, bool Complain, + bool AllowCompatibleDifferences) override; + bool ReadTargetOptions(const TargetOptions &TargetOpts, bool Complain, + bool AllowCompatibleDifferences) override; + bool ReadDiagnosticOptions(IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts, + bool Complain) override; + bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, bool Complain, + std::string &SuggestedPredefines) override; + bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts, + StringRef SpecificModuleCachePath, + bool Complain) override; + void ReadCounter(const serialization::ModuleFile &M, unsigned Value) override; + +private: + void Error(const char *Msg); +}; + +namespace serialization { + +class ReadMethodPoolVisitor; + +namespace reader { + class ASTIdentifierLookupTrait; + /// \brief The on-disk hash table(s) used for DeclContext name lookup. + struct DeclContextLookupTable; +} + +} // end namespace serialization + +/// \brief Reads an AST files chain containing the contents of a translation +/// unit. +/// +/// The ASTReader class reads bitstreams (produced by the ASTWriter +/// class) containing the serialized representation of a given +/// abstract syntax tree and its supporting data structures. An +/// instance of the ASTReader can be attached to an ASTContext object, +/// which will provide access to the contents of the AST files. +/// +/// The AST reader provides lazy de-serialization of declarations, as +/// required when traversing the AST. Only those AST nodes that are +/// actually required will be de-serialized. +class ASTReader + : public ExternalPreprocessorSource, + public ExternalPreprocessingRecordSource, + public ExternalHeaderFileInfoSource, + public ExternalSemaSource, + public IdentifierInfoLookup, + public ExternalSLocEntrySource +{ +public: + typedef SmallVector<uint64_t, 64> RecordData; + typedef SmallVectorImpl<uint64_t> RecordDataImpl; + + /// \brief The result of reading the control block of an AST file, which + /// can fail for various reasons. + enum ASTReadResult { + /// \brief The control block was read successfully. Aside from failures, + /// the AST file is safe to read into the current context. + Success, + /// \brief The AST file itself appears corrupted. + Failure, + /// \brief The AST file was missing. + Missing, + /// \brief The AST file is out-of-date relative to its input files, + /// and needs to be regenerated. + OutOfDate, + /// \brief The AST file was written by a different version of Clang. + VersionMismatch, + /// \brief The AST file was writtten with a different language/target + /// configuration. + ConfigurationMismatch, + /// \brief The AST file has errors. + HadErrors + }; + + /// \brief Types of AST files. + friend class PCHValidator; + friend class ASTDeclReader; + friend class ASTStmtReader; + friend class ASTIdentifierIterator; + friend class serialization::reader::ASTIdentifierLookupTrait; + friend class TypeLocReader; + friend class ASTWriter; + friend class ASTUnit; // ASTUnit needs to remap source locations. + friend class serialization::ReadMethodPoolVisitor; + + typedef serialization::ModuleFile ModuleFile; + typedef serialization::ModuleKind ModuleKind; + typedef serialization::ModuleManager ModuleManager; + + typedef ModuleManager::ModuleIterator ModuleIterator; + typedef ModuleManager::ModuleConstIterator ModuleConstIterator; + typedef ModuleManager::ModuleReverseIterator ModuleReverseIterator; + +private: + /// \brief The receiver of some callbacks invoked by ASTReader. + std::unique_ptr<ASTReaderListener> Listener; + + /// \brief The receiver of deserialization events. + ASTDeserializationListener *DeserializationListener; + bool OwnsDeserializationListener; + + SourceManager &SourceMgr; + FileManager &FileMgr; + const PCHContainerReader &PCHContainerRdr; + DiagnosticsEngine &Diags; + + /// \brief The semantic analysis object that will be processing the + /// AST files and the translation unit that uses it. + Sema *SemaObj; + + /// \brief The preprocessor that will be loading the source file. + Preprocessor &PP; + + /// \brief The AST context into which we'll read the AST files. + ASTContext &Context; + + /// \brief The AST consumer. + ASTConsumer *Consumer; + + /// \brief The module manager which manages modules and their dependencies + ModuleManager ModuleMgr; + + /// A mapping from extension block names to module file extensions. + llvm::StringMap<IntrusiveRefCntPtr<ModuleFileExtension>> ModuleFileExtensions; + + /// \brief A timer used to track the time spent deserializing. + std::unique_ptr<llvm::Timer> ReadTimer; + + /// \brief The location where the module file will be considered as + /// imported from. For non-module AST types it should be invalid. + SourceLocation CurrentImportLoc; + + /// \brief The global module index, if loaded. + std::unique_ptr<GlobalModuleIndex> GlobalIndex; + + /// \brief A map of global bit offsets to the module that stores entities + /// at those bit offsets. + ContinuousRangeMap<uint64_t, ModuleFile*, 4> GlobalBitOffsetsMap; + + /// \brief A map of negated SLocEntryIDs to the modules containing them. + ContinuousRangeMap<unsigned, ModuleFile*, 64> GlobalSLocEntryMap; + + typedef ContinuousRangeMap<unsigned, ModuleFile*, 64> GlobalSLocOffsetMapType; + + /// \brief A map of reversed (SourceManager::MaxLoadedOffset - SLocOffset) + /// SourceLocation offsets to the modules containing them. + GlobalSLocOffsetMapType GlobalSLocOffsetMap; + + /// \brief Types that have already been loaded from the chain. + /// + /// When the pointer at index I is non-NULL, the type with + /// ID = (I + 1) << FastQual::Width has already been loaded + std::vector<QualType> TypesLoaded; + + typedef ContinuousRangeMap<serialization::TypeID, ModuleFile *, 4> + GlobalTypeMapType; + + /// \brief Mapping from global type IDs to the module in which the + /// type resides along with the offset that should be added to the + /// global type ID to produce a local ID. + GlobalTypeMapType GlobalTypeMap; + + /// \brief Declarations that have already been loaded from the chain. + /// + /// When the pointer at index I is non-NULL, the declaration with ID + /// = I + 1 has already been loaded. + std::vector<Decl *> DeclsLoaded; + + typedef ContinuousRangeMap<serialization::DeclID, ModuleFile *, 4> + GlobalDeclMapType; + + /// \brief Mapping from global declaration IDs to the module in which the + /// declaration resides. + GlobalDeclMapType GlobalDeclMap; + + typedef std::pair<ModuleFile *, uint64_t> FileOffset; + typedef SmallVector<FileOffset, 2> FileOffsetsTy; + typedef llvm::DenseMap<serialization::DeclID, FileOffsetsTy> + DeclUpdateOffsetsMap; + + /// \brief Declarations that have modifications residing in a later file + /// in the chain. + DeclUpdateOffsetsMap DeclUpdateOffsets; + + /// \brief Declaration updates for already-loaded declarations that we need + /// to apply once we finish processing an import. + llvm::SmallVector<std::pair<serialization::GlobalDeclID, Decl*>, 16> + PendingUpdateRecords; + + enum class PendingFakeDefinitionKind { NotFake, Fake, FakeLoaded }; + + /// \brief The DefinitionData pointers that we faked up for class definitions + /// that we needed but hadn't loaded yet. + llvm::DenseMap<void *, PendingFakeDefinitionKind> PendingFakeDefinitionData; + + /// \brief Exception specification updates that have been loaded but not yet + /// propagated across the relevant redeclaration chain. The map key is the + /// canonical declaration (used only for deduplication) and the value is a + /// declaration that has an exception specification. + llvm::SmallMapVector<Decl *, FunctionDecl *, 4> PendingExceptionSpecUpdates; + + struct ReplacedDeclInfo { + ModuleFile *Mod; + uint64_t Offset; + unsigned RawLoc; + + ReplacedDeclInfo() : Mod(nullptr), Offset(0), RawLoc(0) {} + ReplacedDeclInfo(ModuleFile *Mod, uint64_t Offset, unsigned RawLoc) + : Mod(Mod), Offset(Offset), RawLoc(RawLoc) {} + }; + + typedef llvm::DenseMap<serialization::DeclID, ReplacedDeclInfo> + DeclReplacementMap; + /// \brief Declarations that have been replaced in a later file in the chain. + DeclReplacementMap ReplacedDecls; + + /// \brief Declarations that have been imported and have typedef names for + /// linkage purposes. + llvm::DenseMap<std::pair<DeclContext*, IdentifierInfo*>, NamedDecl*> + ImportedTypedefNamesForLinkage; + + /// \brief Mergeable declaration contexts that have anonymous declarations + /// within them, and those anonymous declarations. + llvm::DenseMap<DeclContext*, llvm::SmallVector<NamedDecl*, 2>> + AnonymousDeclarationsForMerging; + + struct FileDeclsInfo { + ModuleFile *Mod; + ArrayRef<serialization::LocalDeclID> Decls; + + FileDeclsInfo() : Mod(nullptr) {} + FileDeclsInfo(ModuleFile *Mod, ArrayRef<serialization::LocalDeclID> Decls) + : Mod(Mod), Decls(Decls) {} + }; + + /// \brief Map from a FileID to the file-level declarations that it contains. + llvm::DenseMap<FileID, FileDeclsInfo> FileDeclIDs; + + /// \brief An array of lexical contents of a declaration context, as a sequence of + /// Decl::Kind, DeclID pairs. + typedef ArrayRef<llvm::support::unaligned_uint32_t> LexicalContents; + + /// \brief Map from a DeclContext to its lexical contents. + llvm::DenseMap<const DeclContext*, std::pair<ModuleFile*, LexicalContents>> + LexicalDecls; + + /// \brief Map from the TU to its lexical contents from each module file. + std::vector<std::pair<ModuleFile*, LexicalContents>> TULexicalDecls; + + /// \brief Map from a DeclContext to its lookup tables. + llvm::DenseMap<const DeclContext *, + serialization::reader::DeclContextLookupTable> Lookups; + + // Updates for visible decls can occur for other contexts than just the + // TU, and when we read those update records, the actual context may not + // be available yet, so have this pending map using the ID as a key. It + // will be realized when the context is actually loaded. + struct PendingVisibleUpdate { + ModuleFile *Mod; + const unsigned char *Data; + }; + typedef SmallVector<PendingVisibleUpdate, 1> DeclContextVisibleUpdates; + + /// \brief Updates to the visible declarations of declaration contexts that + /// haven't been loaded yet. + llvm::DenseMap<serialization::DeclID, DeclContextVisibleUpdates> + PendingVisibleUpdates; + + /// \brief The set of C++ or Objective-C classes that have forward + /// declarations that have not yet been linked to their definitions. + llvm::SmallPtrSet<Decl *, 4> PendingDefinitions; + + typedef llvm::MapVector<Decl *, uint64_t, + llvm::SmallDenseMap<Decl *, unsigned, 4>, + SmallVector<std::pair<Decl *, uint64_t>, 4> > + PendingBodiesMap; + + /// \brief Functions or methods that have bodies that will be attached. + PendingBodiesMap PendingBodies; + + /// \brief Definitions for which we have added merged definitions but not yet + /// performed deduplication. + llvm::SetVector<NamedDecl*> PendingMergedDefinitionsToDeduplicate; + + /// \brief Read the record that describes the lexical contents of a DC. + bool ReadLexicalDeclContextStorage(ModuleFile &M, + llvm::BitstreamCursor &Cursor, + uint64_t Offset, DeclContext *DC); + /// \brief Read the record that describes the visible contents of a DC. + bool ReadVisibleDeclContextStorage(ModuleFile &M, + llvm::BitstreamCursor &Cursor, + uint64_t Offset, serialization::DeclID ID); + + /// \brief A vector containing identifiers that have already been + /// loaded. + /// + /// If the pointer at index I is non-NULL, then it refers to the + /// IdentifierInfo for the identifier with ID=I+1 that has already + /// been loaded. + std::vector<IdentifierInfo *> IdentifiersLoaded; + + typedef ContinuousRangeMap<serialization::IdentID, ModuleFile *, 4> + GlobalIdentifierMapType; + + /// \brief Mapping from global identifier IDs to the module in which the + /// identifier resides along with the offset that should be added to the + /// global identifier ID to produce a local ID. + GlobalIdentifierMapType GlobalIdentifierMap; + + /// \brief A vector containing macros that have already been + /// loaded. + /// + /// If the pointer at index I is non-NULL, then it refers to the + /// MacroInfo for the identifier with ID=I+1 that has already + /// been loaded. + std::vector<MacroInfo *> MacrosLoaded; + + typedef std::pair<IdentifierInfo *, serialization::SubmoduleID> + LoadedMacroInfo; + + /// \brief A set of #undef directives that we have loaded; used to + /// deduplicate the same #undef information coming from multiple module + /// files. + llvm::DenseSet<LoadedMacroInfo> LoadedUndefs; + + typedef ContinuousRangeMap<serialization::MacroID, ModuleFile *, 4> + GlobalMacroMapType; + + /// \brief Mapping from global macro IDs to the module in which the + /// macro resides along with the offset that should be added to the + /// global macro ID to produce a local ID. + GlobalMacroMapType GlobalMacroMap; + + /// \brief A vector containing submodules that have already been loaded. + /// + /// This vector is indexed by the Submodule ID (-1). NULL submodule entries + /// indicate that the particular submodule ID has not yet been loaded. + SmallVector<Module *, 2> SubmodulesLoaded; + + typedef ContinuousRangeMap<serialization::SubmoduleID, ModuleFile *, 4> + GlobalSubmoduleMapType; + + /// \brief Mapping from global submodule IDs to the module file in which the + /// submodule resides along with the offset that should be added to the + /// global submodule ID to produce a local ID. + GlobalSubmoduleMapType GlobalSubmoduleMap; + + /// \brief A set of hidden declarations. + typedef SmallVector<Decl*, 2> HiddenNames; + typedef llvm::DenseMap<Module *, HiddenNames> HiddenNamesMapType; + + /// \brief A mapping from each of the hidden submodules to the deserialized + /// declarations in that submodule that could be made visible. + HiddenNamesMapType HiddenNamesMap; + + + /// \brief A module import, export, or conflict that hasn't yet been resolved. + struct UnresolvedModuleRef { + /// \brief The file in which this module resides. + ModuleFile *File; + + /// \brief The module that is importing or exporting. + Module *Mod; + + /// \brief The kind of module reference. + enum { Import, Export, Conflict } Kind; + + /// \brief The local ID of the module that is being exported. + unsigned ID; + + /// \brief Whether this is a wildcard export. + unsigned IsWildcard : 1; + + /// \brief String data. + StringRef String; + }; + + /// \brief The set of module imports and exports that still need to be + /// resolved. + SmallVector<UnresolvedModuleRef, 2> UnresolvedModuleRefs; + + /// \brief A vector containing selectors that have already been loaded. + /// + /// This vector is indexed by the Selector ID (-1). NULL selector + /// entries indicate that the particular selector ID has not yet + /// been loaded. + SmallVector<Selector, 16> SelectorsLoaded; + + typedef ContinuousRangeMap<serialization::SelectorID, ModuleFile *, 4> + GlobalSelectorMapType; + + /// \brief Mapping from global selector IDs to the module in which the + + /// global selector ID to produce a local ID. + GlobalSelectorMapType GlobalSelectorMap; + + /// \brief The generation number of the last time we loaded data from the + /// global method pool for this selector. + llvm::DenseMap<Selector, unsigned> SelectorGeneration; + + struct PendingMacroInfo { + ModuleFile *M; + uint64_t MacroDirectivesOffset; + + PendingMacroInfo(ModuleFile *M, uint64_t MacroDirectivesOffset) + : M(M), MacroDirectivesOffset(MacroDirectivesOffset) {} + }; + + typedef llvm::MapVector<IdentifierInfo *, SmallVector<PendingMacroInfo, 2> > + PendingMacroIDsMap; + + /// \brief Mapping from identifiers that have a macro history to the global + /// IDs have not yet been deserialized to the global IDs of those macros. + PendingMacroIDsMap PendingMacroIDs; + + typedef ContinuousRangeMap<unsigned, ModuleFile *, 4> + GlobalPreprocessedEntityMapType; + + /// \brief Mapping from global preprocessing entity IDs to the module in + /// which the preprocessed entity resides along with the offset that should be + /// added to the global preprocessing entitiy ID to produce a local ID. + GlobalPreprocessedEntityMapType GlobalPreprocessedEntityMap; + + /// \name CodeGen-relevant special data + /// \brief Fields containing data that is relevant to CodeGen. + //@{ + + /// \brief The IDs of all declarations that fulfill the criteria of + /// "interesting" decls. + /// + /// This contains the data loaded from all EAGERLY_DESERIALIZED_DECLS blocks + /// in the chain. The referenced declarations are deserialized and passed to + /// the consumer eagerly. + SmallVector<uint64_t, 16> EagerlyDeserializedDecls; + + /// \brief The IDs of all tentative definitions stored in the chain. + /// + /// Sema keeps track of all tentative definitions in a TU because it has to + /// complete them and pass them on to CodeGen. Thus, tentative definitions in + /// the PCH chain must be eagerly deserialized. + SmallVector<uint64_t, 16> TentativeDefinitions; + + /// \brief The IDs of all CXXRecordDecls stored in the chain whose VTables are + /// used. + /// + /// CodeGen has to emit VTables for these records, so they have to be eagerly + /// deserialized. + SmallVector<uint64_t, 64> VTableUses; + + /// \brief A snapshot of the pending instantiations in the chain. + /// + /// This record tracks the instantiations that Sema has to perform at the + /// end of the TU. It consists of a pair of values for every pending + /// instantiation where the first value is the ID of the decl and the second + /// is the instantiation location. + SmallVector<uint64_t, 64> PendingInstantiations; + + //@} + + /// \name DiagnosticsEngine-relevant special data + /// \brief Fields containing data that is used for generating diagnostics + //@{ + + /// \brief A snapshot of Sema's unused file-scoped variable tracking, for + /// generating warnings. + SmallVector<uint64_t, 16> UnusedFileScopedDecls; + + /// \brief A list of all the delegating constructors we've seen, to diagnose + /// cycles. + SmallVector<uint64_t, 4> DelegatingCtorDecls; + + /// \brief Method selectors used in a @selector expression. Used for + /// implementation of -Wselector. + SmallVector<uint64_t, 64> ReferencedSelectorsData; + + /// \brief A snapshot of Sema's weak undeclared identifier tracking, for + /// generating warnings. + SmallVector<uint64_t, 64> WeakUndeclaredIdentifiers; + + /// \brief The IDs of type aliases for ext_vectors that exist in the chain. + /// + /// Used by Sema for finding sugared names for ext_vectors in diagnostics. + SmallVector<uint64_t, 4> ExtVectorDecls; + + //@} + + /// \name Sema-relevant special data + /// \brief Fields containing data that is used for semantic analysis + //@{ + + /// \brief The IDs of all potentially unused typedef names in the chain. + /// + /// Sema tracks these to emit warnings. + SmallVector<uint64_t, 16> UnusedLocalTypedefNameCandidates; + + /// \brief The IDs of the declarations Sema stores directly. + /// + /// Sema tracks a few important decls, such as namespace std, directly. + SmallVector<uint64_t, 4> SemaDeclRefs; + + /// \brief The IDs of the types ASTContext stores directly. + /// + /// The AST context tracks a few important types, such as va_list, directly. + SmallVector<uint64_t, 16> SpecialTypes; + + /// \brief The IDs of CUDA-specific declarations ASTContext stores directly. + /// + /// The AST context tracks a few important decls, currently cudaConfigureCall, + /// directly. + SmallVector<uint64_t, 2> CUDASpecialDeclRefs; + + /// \brief The floating point pragma option settings. + SmallVector<uint64_t, 1> FPPragmaOptions; + + /// \brief The pragma clang optimize location (if the pragma state is "off"). + SourceLocation OptimizeOffPragmaLocation; + + /// \brief The OpenCL extension settings. + SmallVector<uint64_t, 1> OpenCLExtensions; + + /// \brief A list of the namespaces we've seen. + SmallVector<uint64_t, 4> KnownNamespaces; + + /// \brief A list of undefined decls with internal linkage followed by the + /// SourceLocation of a matching ODR-use. + SmallVector<uint64_t, 8> UndefinedButUsed; + + /// \brief Delete expressions to analyze at the end of translation unit. + SmallVector<uint64_t, 8> DelayedDeleteExprs; + + // \brief A list of late parsed template function data. + SmallVector<uint64_t, 1> LateParsedTemplates; + + struct ImportedSubmodule { + serialization::SubmoduleID ID; + SourceLocation ImportLoc; + + ImportedSubmodule(serialization::SubmoduleID ID, SourceLocation ImportLoc) + : ID(ID), ImportLoc(ImportLoc) {} + }; + + /// \brief A list of modules that were imported by precompiled headers or + /// any other non-module AST file. + SmallVector<ImportedSubmodule, 2> ImportedModules; + //@} + + /// \brief The directory that the PCH we are reading is stored in. + std::string CurrentDir; + + /// \brief The system include root to be used when loading the + /// precompiled header. + std::string isysroot; + + /// \brief Whether to disable the normal validation performed on precompiled + /// headers when they are loaded. + bool DisableValidation; + + /// \brief Whether to accept an AST file with compiler errors. + bool AllowASTWithCompilerErrors; + + /// \brief Whether to accept an AST file that has a different configuration + /// from the current compiler instance. + bool AllowConfigurationMismatch; + + /// \brief Whether validate system input files. + bool ValidateSystemInputs; + + /// \brief Whether we are allowed to use the global module index. + bool UseGlobalIndex; + + /// \brief Whether we have tried loading the global module index yet. + bool TriedLoadingGlobalIndex; + + typedef llvm::DenseMap<unsigned, SwitchCase *> SwitchCaseMapTy; + /// \brief Mapping from switch-case IDs in the chain to switch-case statements + /// + /// Statements usually don't have IDs, but switch cases need them, so that the + /// switch statement can refer to them. + SwitchCaseMapTy SwitchCaseStmts; + + SwitchCaseMapTy *CurrSwitchCaseStmts; + + /// \brief The number of source location entries de-serialized from + /// the PCH file. + unsigned NumSLocEntriesRead; + + /// \brief The number of source location entries in the chain. + unsigned TotalNumSLocEntries; + + /// \brief The number of statements (and expressions) de-serialized + /// from the chain. + unsigned NumStatementsRead; + + /// \brief The total number of statements (and expressions) stored + /// in the chain. + unsigned TotalNumStatements; + + /// \brief The number of macros de-serialized from the chain. + unsigned NumMacrosRead; + + /// \brief The total number of macros stored in the chain. + unsigned TotalNumMacros; + + /// \brief The number of lookups into identifier tables. + unsigned NumIdentifierLookups; + + /// \brief The number of lookups into identifier tables that succeed. + unsigned NumIdentifierLookupHits; + + /// \brief The number of selectors that have been read. + unsigned NumSelectorsRead; + + /// \brief The number of method pool entries that have been read. + unsigned NumMethodPoolEntriesRead; + + /// \brief The number of times we have looked up a selector in the method + /// pool. + unsigned NumMethodPoolLookups; + + /// \brief The number of times we have looked up a selector in the method + /// pool and found something. + unsigned NumMethodPoolHits; + + /// \brief The number of times we have looked up a selector in the method + /// pool within a specific module. + unsigned NumMethodPoolTableLookups; + + /// \brief The number of times we have looked up a selector in the method + /// pool within a specific module and found something. + unsigned NumMethodPoolTableHits; + + /// \brief The total number of method pool entries in the selector table. + unsigned TotalNumMethodPoolEntries; + + /// Number of lexical decl contexts read/total. + unsigned NumLexicalDeclContextsRead, TotalLexicalDeclContexts; + + /// Number of visible decl contexts read/total. + unsigned NumVisibleDeclContextsRead, TotalVisibleDeclContexts; + + /// Total size of modules, in bits, currently loaded + uint64_t TotalModulesSizeInBits; + + /// \brief Number of Decl/types that are currently deserializing. + unsigned NumCurrentElementsDeserializing; + + /// \brief Set true while we are in the process of passing deserialized + /// "interesting" decls to consumer inside FinishedDeserializing(). + /// This is used as a guard to avoid recursively repeating the process of + /// passing decls to consumer. + bool PassingDeclsToConsumer; + + /// \brief The set of identifiers that were read while the AST reader was + /// (recursively) loading declarations. + /// + /// The declarations on the identifier chain for these identifiers will be + /// loaded once the recursive loading has completed. + llvm::MapVector<IdentifierInfo *, SmallVector<uint32_t, 4> > + PendingIdentifierInfos; + + /// \brief The set of lookup results that we have faked in order to support + /// merging of partially deserialized decls but that we have not yet removed. + llvm::SmallMapVector<IdentifierInfo *, SmallVector<NamedDecl*, 2>, 16> + PendingFakeLookupResults; + + /// \brief The generation number of each identifier, which keeps track of + /// the last time we loaded information about this identifier. + llvm::DenseMap<IdentifierInfo *, unsigned> IdentifierGeneration; + + /// \brief Contains declarations and definitions that will be + /// "interesting" to the ASTConsumer, when we get that AST consumer. + /// + /// "Interesting" declarations are those that have data that may + /// need to be emitted, such as inline function definitions or + /// Objective-C protocols. + std::deque<Decl *> InterestingDecls; + + /// \brief The list of redeclaration chains that still need to be + /// reconstructed, and the local offset to the corresponding list + /// of redeclarations. + SmallVector<std::pair<Decl *, uint64_t>, 16> PendingDeclChains; + + /// \brief The list of canonical declarations whose redeclaration chains + /// need to be marked as incomplete once we're done deserializing things. + SmallVector<Decl *, 16> PendingIncompleteDeclChains; + + /// \brief The Decl IDs for the Sema/Lexical DeclContext of a Decl that has + /// been loaded but its DeclContext was not set yet. + struct PendingDeclContextInfo { + Decl *D; + serialization::GlobalDeclID SemaDC; + serialization::GlobalDeclID LexicalDC; + }; + + /// \brief The set of Decls that have been loaded but their DeclContexts are + /// not set yet. + /// + /// The DeclContexts for these Decls will be set once recursive loading has + /// been completed. + std::deque<PendingDeclContextInfo> PendingDeclContextInfos; + + /// \brief The set of NamedDecls that have been loaded, but are members of a + /// context that has been merged into another context where the corresponding + /// declaration is either missing or has not yet been loaded. + /// + /// We will check whether the corresponding declaration is in fact missing + /// once recursing loading has been completed. + llvm::SmallVector<NamedDecl *, 16> PendingOdrMergeChecks; + + /// \brief Record definitions in which we found an ODR violation. + llvm::SmallDenseMap<CXXRecordDecl *, llvm::TinyPtrVector<CXXRecordDecl *>, 2> + PendingOdrMergeFailures; + + /// \brief DeclContexts in which we have diagnosed an ODR violation. + llvm::SmallPtrSet<DeclContext*, 2> DiagnosedOdrMergeFailures; + + /// \brief The set of Objective-C categories that have been deserialized + /// since the last time the declaration chains were linked. + llvm::SmallPtrSet<ObjCCategoryDecl *, 16> CategoriesDeserialized; + + /// \brief The set of Objective-C class definitions that have already been + /// loaded, for which we will need to check for categories whenever a new + /// module is loaded. + SmallVector<ObjCInterfaceDecl *, 16> ObjCClassesLoaded; + + typedef llvm::DenseMap<Decl *, SmallVector<serialization::DeclID, 2> > + KeyDeclsMap; + + /// \brief A mapping from canonical declarations to the set of global + /// declaration IDs for key declaration that have been merged with that + /// canonical declaration. A key declaration is a formerly-canonical + /// declaration whose module did not import any other key declaration for that + /// entity. These are the IDs that we use as keys when finding redecl chains. + KeyDeclsMap KeyDecls; + + /// \brief A mapping from DeclContexts to the semantic DeclContext that we + /// are treating as the definition of the entity. This is used, for instance, + /// when merging implicit instantiations of class templates across modules. + llvm::DenseMap<DeclContext *, DeclContext *> MergedDeclContexts; + + /// \brief A mapping from canonical declarations of enums to their canonical + /// definitions. Only populated when using modules in C++. + llvm::DenseMap<EnumDecl *, EnumDecl *> EnumDefinitions; + + /// \brief When reading a Stmt tree, Stmt operands are placed in this stack. + SmallVector<Stmt *, 16> StmtStack; + + /// \brief What kind of records we are reading. + enum ReadingKind { + Read_None, Read_Decl, Read_Type, Read_Stmt + }; + + /// \brief What kind of records we are reading. + ReadingKind ReadingKind; + + /// \brief RAII object to change the reading kind. + class ReadingKindTracker { + ASTReader &Reader; + enum ReadingKind PrevKind; + + ReadingKindTracker(const ReadingKindTracker &) = delete; + void operator=(const ReadingKindTracker &) = delete; + + public: + ReadingKindTracker(enum ReadingKind newKind, ASTReader &reader) + : Reader(reader), PrevKind(Reader.ReadingKind) { + Reader.ReadingKind = newKind; + } + + ~ReadingKindTracker() { Reader.ReadingKind = PrevKind; } + }; + + /// \brief Suggested contents of the predefines buffer, after this + /// PCH file has been processed. + /// + /// In most cases, this string will be empty, because the predefines + /// buffer computed to build the PCH file will be identical to the + /// predefines buffer computed from the command line. However, when + /// there are differences that the PCH reader can work around, this + /// predefines buffer may contain additional definitions. + std::string SuggestedPredefines; + + /// \brief Reads a statement from the specified cursor. + Stmt *ReadStmtFromStream(ModuleFile &F); + + struct InputFileInfo { + std::string Filename; + off_t StoredSize; + time_t StoredTime; + bool Overridden; + bool Transient; + }; + + /// \brief Reads the stored information about an input file. + InputFileInfo readInputFileInfo(ModuleFile &F, unsigned ID); + + /// \brief Retrieve the file entry and 'overridden' bit for an input + /// file in the given module file. + serialization::InputFile getInputFile(ModuleFile &F, unsigned ID, + bool Complain = true); + +public: + void ResolveImportedPath(ModuleFile &M, std::string &Filename); + static void ResolveImportedPath(std::string &Filename, StringRef Prefix); + + /// \brief Returns the first key declaration for the given declaration. This + /// is one that is formerly-canonical (or still canonical) and whose module + /// did not import any other key declaration of the entity. + Decl *getKeyDeclaration(Decl *D) { + D = D->getCanonicalDecl(); + if (D->isFromASTFile()) + return D; + + auto I = KeyDecls.find(D); + if (I == KeyDecls.end() || I->second.empty()) + return D; + return GetExistingDecl(I->second[0]); + } + const Decl *getKeyDeclaration(const Decl *D) { + return getKeyDeclaration(const_cast<Decl*>(D)); + } + + /// \brief Run a callback on each imported key declaration of \p D. + template <typename Fn> + void forEachImportedKeyDecl(const Decl *D, Fn Visit) { + D = D->getCanonicalDecl(); + if (D->isFromASTFile()) + Visit(D); + + auto It = KeyDecls.find(const_cast<Decl*>(D)); + if (It != KeyDecls.end()) + for (auto ID : It->second) + Visit(GetExistingDecl(ID)); + } + + /// \brief Get the loaded lookup tables for \p Primary, if any. + const serialization::reader::DeclContextLookupTable * + getLoadedLookupTables(DeclContext *Primary) const; + +private: + struct ImportedModule { + ModuleFile *Mod; + ModuleFile *ImportedBy; + SourceLocation ImportLoc; + + ImportedModule(ModuleFile *Mod, + ModuleFile *ImportedBy, + SourceLocation ImportLoc) + : Mod(Mod), ImportedBy(ImportedBy), ImportLoc(ImportLoc) { } + }; + + ASTReadResult ReadASTCore(StringRef FileName, ModuleKind Type, + SourceLocation ImportLoc, ModuleFile *ImportedBy, + SmallVectorImpl<ImportedModule> &Loaded, + off_t ExpectedSize, time_t ExpectedModTime, + serialization::ASTFileSignature ExpectedSignature, + unsigned ClientLoadCapabilities); + ASTReadResult ReadControlBlock(ModuleFile &F, + SmallVectorImpl<ImportedModule> &Loaded, + const ModuleFile *ImportedBy, + unsigned ClientLoadCapabilities); + static ASTReadResult ReadOptionsBlock( + llvm::BitstreamCursor &Stream, unsigned ClientLoadCapabilities, + bool AllowCompatibleConfigurationMismatch, ASTReaderListener &Listener, + std::string &SuggestedPredefines); + ASTReadResult ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities); + ASTReadResult ReadExtensionBlock(ModuleFile &F); + bool ParseLineTable(ModuleFile &F, const RecordData &Record); + bool ReadSourceManagerBlock(ModuleFile &F); + llvm::BitstreamCursor &SLocCursorForID(int ID); + SourceLocation getImportLocation(ModuleFile *F); + ASTReadResult ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F, + const ModuleFile *ImportedBy, + unsigned ClientLoadCapabilities); + ASTReadResult ReadSubmoduleBlock(ModuleFile &F, + unsigned ClientLoadCapabilities); + static bool ParseLanguageOptions(const RecordData &Record, bool Complain, + ASTReaderListener &Listener, + bool AllowCompatibleDifferences); + static bool ParseTargetOptions(const RecordData &Record, bool Complain, + ASTReaderListener &Listener, + bool AllowCompatibleDifferences); + static bool ParseDiagnosticOptions(const RecordData &Record, bool Complain, + ASTReaderListener &Listener); + static bool ParseFileSystemOptions(const RecordData &Record, bool Complain, + ASTReaderListener &Listener); + static bool ParseHeaderSearchOptions(const RecordData &Record, bool Complain, + ASTReaderListener &Listener); + static bool ParsePreprocessorOptions(const RecordData &Record, bool Complain, + ASTReaderListener &Listener, + std::string &SuggestedPredefines); + + struct RecordLocation { + RecordLocation(ModuleFile *M, uint64_t O) + : F(M), Offset(O) {} + ModuleFile *F; + uint64_t Offset; + }; + + QualType readTypeRecord(unsigned Index); + void readExceptionSpec(ModuleFile &ModuleFile, + SmallVectorImpl<QualType> &ExceptionStorage, + FunctionProtoType::ExceptionSpecInfo &ESI, + const RecordData &Record, unsigned &Index); + RecordLocation TypeCursorForIndex(unsigned Index); + void LoadedDecl(unsigned Index, Decl *D); + Decl *ReadDeclRecord(serialization::DeclID ID); + void markIncompleteDeclChain(Decl *Canon); + + /// \brief Returns the most recent declaration of a declaration (which must be + /// of a redeclarable kind) that is either local or has already been loaded + /// merged into its redecl chain. + Decl *getMostRecentExistingDecl(Decl *D); + + RecordLocation DeclCursorForID(serialization::DeclID ID, + unsigned &RawLocation); + void loadDeclUpdateRecords(serialization::DeclID ID, Decl *D); + void loadPendingDeclChain(Decl *D, uint64_t LocalOffset); + void loadObjCCategories(serialization::GlobalDeclID ID, ObjCInterfaceDecl *D, + unsigned PreviousGeneration = 0); + + RecordLocation getLocalBitOffset(uint64_t GlobalOffset); + uint64_t getGlobalBitOffset(ModuleFile &M, uint32_t LocalOffset); + + /// \brief Returns the first preprocessed entity ID that begins or ends after + /// \arg Loc. + serialization::PreprocessedEntityID + findPreprocessedEntity(SourceLocation Loc, bool EndsAfter) const; + + /// \brief Find the next module that contains entities and return the ID + /// of the first entry. + /// + /// \param SLocMapI points at a chunk of a module that contains no + /// preprocessed entities or the entities it contains are not the + /// ones we are looking for. + serialization::PreprocessedEntityID + findNextPreprocessedEntity( + GlobalSLocOffsetMapType::const_iterator SLocMapI) const; + + /// \brief Returns (ModuleFile, Local index) pair for \p GlobalIndex of a + /// preprocessed entity. + std::pair<ModuleFile *, unsigned> + getModulePreprocessedEntity(unsigned GlobalIndex); + + /// \brief Returns (begin, end) pair for the preprocessed entities of a + /// particular module. + llvm::iterator_range<PreprocessingRecord::iterator> + getModulePreprocessedEntities(ModuleFile &Mod) const; + + class ModuleDeclIterator + : public llvm::iterator_adaptor_base< + ModuleDeclIterator, const serialization::LocalDeclID *, + std::random_access_iterator_tag, const Decl *, ptrdiff_t, + const Decl *, const Decl *> { + ASTReader *Reader; + ModuleFile *Mod; + + public: + ModuleDeclIterator() + : iterator_adaptor_base(nullptr), Reader(nullptr), Mod(nullptr) {} + + ModuleDeclIterator(ASTReader *Reader, ModuleFile *Mod, + const serialization::LocalDeclID *Pos) + : iterator_adaptor_base(Pos), Reader(Reader), Mod(Mod) {} + + value_type operator*() const { + return Reader->GetDecl(Reader->getGlobalDeclID(*Mod, *I)); + } + value_type operator->() const { return **this; } + + bool operator==(const ModuleDeclIterator &RHS) const { + assert(Reader == RHS.Reader && Mod == RHS.Mod); + return I == RHS.I; + } + }; + + llvm::iterator_range<ModuleDeclIterator> + getModuleFileLevelDecls(ModuleFile &Mod); + + void PassInterestingDeclsToConsumer(); + void PassInterestingDeclToConsumer(Decl *D); + + void finishPendingActions(); + void diagnoseOdrViolations(); + + void pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name); + + void addPendingDeclContextInfo(Decl *D, + serialization::GlobalDeclID SemaDC, + serialization::GlobalDeclID LexicalDC) { + assert(D); + PendingDeclContextInfo Info = { D, SemaDC, LexicalDC }; + PendingDeclContextInfos.push_back(Info); + } + + /// \brief Produce an error diagnostic and return true. + /// + /// This routine should only be used for fatal errors that have to + /// do with non-routine failures (e.g., corrupted AST file). + void Error(StringRef Msg); + void Error(unsigned DiagID, StringRef Arg1 = StringRef(), + StringRef Arg2 = StringRef()); + + ASTReader(const ASTReader &) = delete; + void operator=(const ASTReader &) = delete; +public: + /// \brief Load the AST file and validate its contents against the given + /// Preprocessor. + /// + /// \param PP the preprocessor associated with the context in which this + /// precompiled header will be loaded. + /// + /// \param Context the AST context that this precompiled header will be + /// loaded into. + /// + /// \param PCHContainerRdr the PCHContainerOperations to use for loading and + /// creating modules. + /// + /// \param Extensions the list of module file extensions that can be loaded + /// from the AST files. + /// + /// \param isysroot If non-NULL, the system include path specified by the + /// user. This is only used with relocatable PCH files. If non-NULL, + /// a relocatable PCH file will use the default path "/". + /// + /// \param DisableValidation If true, the AST reader will suppress most + /// of its regular consistency checking, allowing the use of precompiled + /// headers that cannot be determined to be compatible. + /// + /// \param AllowASTWithCompilerErrors If true, the AST reader will accept an + /// AST file the was created out of an AST with compiler errors, + /// otherwise it will reject it. + /// + /// \param AllowConfigurationMismatch If true, the AST reader will not check + /// for configuration differences between the AST file and the invocation. + /// + /// \param ValidateSystemInputs If true, the AST reader will validate + /// system input files in addition to user input files. This is only + /// meaningful if \p DisableValidation is false. + /// + /// \param UseGlobalIndex If true, the AST reader will try to load and use + /// the global module index. + /// + /// \param ReadTimer If non-null, a timer used to track the time spent + /// deserializing. + ASTReader(Preprocessor &PP, ASTContext &Context, + const PCHContainerReader &PCHContainerRdr, + ArrayRef<IntrusiveRefCntPtr<ModuleFileExtension>> Extensions, + StringRef isysroot = "", bool DisableValidation = false, + bool AllowASTWithCompilerErrors = false, + bool AllowConfigurationMismatch = false, + bool ValidateSystemInputs = false, bool UseGlobalIndex = true, + std::unique_ptr<llvm::Timer> ReadTimer = {}); + + ~ASTReader() override; + + SourceManager &getSourceManager() const { return SourceMgr; } + FileManager &getFileManager() const { return FileMgr; } + DiagnosticsEngine &getDiags() const { return Diags; } + + /// \brief Flags that indicate what kind of AST loading failures the client + /// of the AST reader can directly handle. + /// + /// When a client states that it can handle a particular kind of failure, + /// the AST reader will not emit errors when producing that kind of failure. + enum LoadFailureCapabilities { + /// \brief The client can't handle any AST loading failures. + ARR_None = 0, + /// \brief The client can handle an AST file that cannot load because it + /// is missing. + ARR_Missing = 0x1, + /// \brief The client can handle an AST file that cannot load because it + /// is out-of-date relative to its input files. + ARR_OutOfDate = 0x2, + /// \brief The client can handle an AST file that cannot load because it + /// was built with a different version of Clang. + ARR_VersionMismatch = 0x4, + /// \brief The client can handle an AST file that cannot load because it's + /// compiled configuration doesn't match that of the context it was + /// loaded into. + ARR_ConfigurationMismatch = 0x8 + }; + + /// \brief Load the AST file designated by the given file name. + /// + /// \param FileName The name of the AST file to load. + /// + /// \param Type The kind of AST being loaded, e.g., PCH, module, main file, + /// or preamble. + /// + /// \param ImportLoc the location where the module file will be considered as + /// imported from. For non-module AST types it should be invalid. + /// + /// \param ClientLoadCapabilities The set of client load-failure + /// capabilities, represented as a bitset of the enumerators of + /// LoadFailureCapabilities. + ASTReadResult ReadAST(const std::string &FileName, ModuleKind Type, + SourceLocation ImportLoc, + unsigned ClientLoadCapabilities); + + /// \brief Make the entities in the given module and any of its (non-explicit) + /// submodules visible to name lookup. + /// + /// \param Mod The module whose names should be made visible. + /// + /// \param NameVisibility The level of visibility to give the names in the + /// module. Visibility can only be increased over time. + /// + /// \param ImportLoc The location at which the import occurs. + void makeModuleVisible(Module *Mod, + Module::NameVisibilityKind NameVisibility, + SourceLocation ImportLoc); + + /// \brief Make the names within this set of hidden names visible. + void makeNamesVisible(const HiddenNames &Names, Module *Owner); + + /// \brief Take the AST callbacks listener. + std::unique_ptr<ASTReaderListener> takeListener() { + return std::move(Listener); + } + + /// \brief Set the AST callbacks listener. + void setListener(std::unique_ptr<ASTReaderListener> Listener) { + this->Listener = std::move(Listener); + } + + /// \brief Add an AST callback listener. + /// + /// Takes ownership of \p L. + void addListener(std::unique_ptr<ASTReaderListener> L) { + if (Listener) + L = llvm::make_unique<ChainedASTReaderListener>(std::move(L), + std::move(Listener)); + Listener = std::move(L); + } + + /// RAII object to temporarily add an AST callback listener. + class ListenerScope { + ASTReader &Reader; + bool Chained; + + public: + ListenerScope(ASTReader &Reader, std::unique_ptr<ASTReaderListener> L) + : Reader(Reader), Chained(false) { + auto Old = Reader.takeListener(); + if (Old) { + Chained = true; + L = llvm::make_unique<ChainedASTReaderListener>(std::move(L), + std::move(Old)); + } + Reader.setListener(std::move(L)); + } + ~ListenerScope() { + auto New = Reader.takeListener(); + if (Chained) + Reader.setListener(static_cast<ChainedASTReaderListener *>(New.get()) + ->takeSecond()); + } + }; + + /// \brief Set the AST deserialization listener. + void setDeserializationListener(ASTDeserializationListener *Listener, + bool TakeOwnership = false); + + /// \brief Determine whether this AST reader has a global index. + bool hasGlobalIndex() const { return (bool)GlobalIndex; } + + /// \brief Return global module index. + GlobalModuleIndex *getGlobalIndex() { return GlobalIndex.get(); } + + /// \brief Reset reader for a reload try. + void resetForReload() { TriedLoadingGlobalIndex = false; } + + /// \brief Attempts to load the global index. + /// + /// \returns true if loading the global index has failed for any reason. + bool loadGlobalIndex(); + + /// \brief Determine whether we tried to load the global index, but failed, + /// e.g., because it is out-of-date or does not exist. + bool isGlobalIndexUnavailable() const; + + /// \brief Initializes the ASTContext + void InitializeContext(); + + /// \brief Update the state of Sema after loading some additional modules. + void UpdateSema(); + + /// \brief Add in-memory (virtual file) buffer. + void addInMemoryBuffer(StringRef &FileName, + std::unique_ptr<llvm::MemoryBuffer> Buffer) { + ModuleMgr.addInMemoryBuffer(FileName, std::move(Buffer)); + } + + /// \brief Finalizes the AST reader's state before writing an AST file to + /// disk. + /// + /// This operation may undo temporary state in the AST that should not be + /// emitted. + void finalizeForWriting(); + + /// \brief Retrieve the module manager. + ModuleManager &getModuleManager() { return ModuleMgr; } + + /// \brief Retrieve the preprocessor. + Preprocessor &getPreprocessor() const { return PP; } + + /// \brief Retrieve the name of the original source file name for the primary + /// module file. + StringRef getOriginalSourceFile() { + return ModuleMgr.getPrimaryModule().OriginalSourceFileName; + } + + /// \brief Retrieve the name of the original source file name directly from + /// the AST file, without actually loading the AST file. + static std::string + getOriginalSourceFile(const std::string &ASTFileName, FileManager &FileMgr, + const PCHContainerReader &PCHContainerRdr, + DiagnosticsEngine &Diags); + + /// \brief Read the control block for the named AST file. + /// + /// \returns true if an error occurred, false otherwise. + static bool + readASTFileControlBlock(StringRef Filename, FileManager &FileMgr, + const PCHContainerReader &PCHContainerRdr, + bool FindModuleFileExtensions, + ASTReaderListener &Listener); + + /// \brief Determine whether the given AST file is acceptable to load into a + /// translation unit with the given language and target options. + static bool isAcceptableASTFile(StringRef Filename, FileManager &FileMgr, + const PCHContainerReader &PCHContainerRdr, + const LangOptions &LangOpts, + const TargetOptions &TargetOpts, + const PreprocessorOptions &PPOpts, + std::string ExistingModuleCachePath); + + /// \brief Returns the suggested contents of the predefines buffer, + /// which contains a (typically-empty) subset of the predefines + /// build prior to including the precompiled header. + const std::string &getSuggestedPredefines() { return SuggestedPredefines; } + + /// \brief Read a preallocated preprocessed entity from the external source. + /// + /// \returns null if an error occurred that prevented the preprocessed + /// entity from being loaded. + PreprocessedEntity *ReadPreprocessedEntity(unsigned Index) override; + + /// \brief Returns a pair of [Begin, End) indices of preallocated + /// preprocessed entities that \p Range encompasses. + std::pair<unsigned, unsigned> + findPreprocessedEntitiesInRange(SourceRange Range) override; + + /// \brief Optionally returns true or false if the preallocated preprocessed + /// entity with index \p Index came from file \p FID. + Optional<bool> isPreprocessedEntityInFileID(unsigned Index, + FileID FID) override; + + /// \brief Read the header file information for the given file entry. + HeaderFileInfo GetHeaderFileInfo(const FileEntry *FE) override; + + void ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag); + + /// \brief Returns the number of source locations found in the chain. + unsigned getTotalNumSLocs() const { + return TotalNumSLocEntries; + } + + /// \brief Returns the number of identifiers found in the chain. + unsigned getTotalNumIdentifiers() const { + return static_cast<unsigned>(IdentifiersLoaded.size()); + } + + /// \brief Returns the number of macros found in the chain. + unsigned getTotalNumMacros() const { + return static_cast<unsigned>(MacrosLoaded.size()); + } + + /// \brief Returns the number of types found in the chain. + unsigned getTotalNumTypes() const { + return static_cast<unsigned>(TypesLoaded.size()); + } + + /// \brief Returns the number of declarations found in the chain. + unsigned getTotalNumDecls() const { + return static_cast<unsigned>(DeclsLoaded.size()); + } + + /// \brief Returns the number of submodules known. + unsigned getTotalNumSubmodules() const { + return static_cast<unsigned>(SubmodulesLoaded.size()); + } + + /// \brief Returns the number of selectors found in the chain. + unsigned getTotalNumSelectors() const { + return static_cast<unsigned>(SelectorsLoaded.size()); + } + + /// \brief Returns the number of preprocessed entities known to the AST + /// reader. + unsigned getTotalNumPreprocessedEntities() const { + unsigned Result = 0; + for (ModuleConstIterator I = ModuleMgr.begin(), + E = ModuleMgr.end(); I != E; ++I) { + Result += (*I)->NumPreprocessedEntities; + } + + return Result; + } + + /// \brief Reads a TemplateArgumentLocInfo appropriate for the + /// given TemplateArgument kind. + TemplateArgumentLocInfo + GetTemplateArgumentLocInfo(ModuleFile &F, TemplateArgument::ArgKind Kind, + const RecordData &Record, unsigned &Idx); + + /// \brief Reads a TemplateArgumentLoc. + TemplateArgumentLoc + ReadTemplateArgumentLoc(ModuleFile &F, + const RecordData &Record, unsigned &Idx); + + const ASTTemplateArgumentListInfo* + ReadASTTemplateArgumentListInfo(ModuleFile &F, + const RecordData &Record, unsigned &Index); + + /// \brief Reads a declarator info from the given record. + TypeSourceInfo *GetTypeSourceInfo(ModuleFile &F, + const RecordData &Record, unsigned &Idx); + + /// \brief Resolve a type ID into a type, potentially building a new + /// type. + QualType GetType(serialization::TypeID ID); + + /// \brief Resolve a local type ID within a given AST file into a type. + QualType getLocalType(ModuleFile &F, unsigned LocalID); + + /// \brief Map a local type ID within a given AST file into a global type ID. + serialization::TypeID getGlobalTypeID(ModuleFile &F, unsigned LocalID) const; + + /// \brief Read a type from the current position in the given record, which + /// was read from the given AST file. + QualType readType(ModuleFile &F, const RecordData &Record, unsigned &Idx) { + if (Idx >= Record.size()) + return QualType(); + + return getLocalType(F, Record[Idx++]); + } + + /// \brief Map from a local declaration ID within a given module to a + /// global declaration ID. + serialization::DeclID getGlobalDeclID(ModuleFile &F, + serialization::LocalDeclID LocalID) const; + + /// \brief Returns true if global DeclID \p ID originated from module \p M. + bool isDeclIDFromModule(serialization::GlobalDeclID ID, ModuleFile &M) const; + + /// \brief Retrieve the module file that owns the given declaration, or NULL + /// if the declaration is not from a module file. + ModuleFile *getOwningModuleFile(const Decl *D); + + /// \brief Get the best name we know for the module that owns the given + /// declaration, or an empty string if the declaration is not from a module. + std::string getOwningModuleNameForDiagnostic(const Decl *D); + + /// \brief Returns the source location for the decl \p ID. + SourceLocation getSourceLocationForDeclID(serialization::GlobalDeclID ID); + + /// \brief Resolve a declaration ID into a declaration, potentially + /// building a new declaration. + Decl *GetDecl(serialization::DeclID ID); + Decl *GetExternalDecl(uint32_t ID) override; + + /// \brief Resolve a declaration ID into a declaration. Return 0 if it's not + /// been loaded yet. + Decl *GetExistingDecl(serialization::DeclID ID); + + /// \brief Reads a declaration with the given local ID in the given module. + Decl *GetLocalDecl(ModuleFile &F, uint32_t LocalID) { + return GetDecl(getGlobalDeclID(F, LocalID)); + } + + /// \brief Reads a declaration with the given local ID in the given module. + /// + /// \returns The requested declaration, casted to the given return type. + template<typename T> + T *GetLocalDeclAs(ModuleFile &F, uint32_t LocalID) { + return cast_or_null<T>(GetLocalDecl(F, LocalID)); + } + + /// \brief Map a global declaration ID into the declaration ID used to + /// refer to this declaration within the given module fule. + /// + /// \returns the global ID of the given declaration as known in the given + /// module file. + serialization::DeclID + mapGlobalIDToModuleFileGlobalID(ModuleFile &M, + serialization::DeclID GlobalID); + + /// \brief Reads a declaration ID from the given position in a record in the + /// given module. + /// + /// \returns The declaration ID read from the record, adjusted to a global ID. + serialization::DeclID ReadDeclID(ModuleFile &F, const RecordData &Record, + unsigned &Idx); + + /// \brief Reads a declaration from the given position in a record in the + /// given module. + Decl *ReadDecl(ModuleFile &F, const RecordData &R, unsigned &I) { + return GetDecl(ReadDeclID(F, R, I)); + } + + /// \brief Reads a declaration from the given position in a record in the + /// given module. + /// + /// \returns The declaration read from this location, casted to the given + /// result type. + template<typename T> + T *ReadDeclAs(ModuleFile &F, const RecordData &R, unsigned &I) { + return cast_or_null<T>(GetDecl(ReadDeclID(F, R, I))); + } + + /// \brief If any redeclarations of \p D have been imported since it was + /// last checked, this digs out those redeclarations and adds them to the + /// redeclaration chain for \p D. + void CompleteRedeclChain(const Decl *D) override; + + /// \brief Read a CXXBaseSpecifiers ID form the given record and + /// return its global bit offset. + uint64_t readCXXBaseSpecifiers(ModuleFile &M, const RecordData &Record, + unsigned &Idx); + + CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset) override; + + /// \brief Resolve the offset of a statement into a statement. + /// + /// This operation will read a new statement from the external + /// source each time it is called, and is meant to be used via a + /// LazyOffsetPtr (which is used by Decls for the body of functions, etc). + Stmt *GetExternalDeclStmt(uint64_t Offset) override; + + /// ReadBlockAbbrevs - Enter a subblock of the specified BlockID with the + /// specified cursor. Read the abbreviations that are at the top of the block + /// and then leave the cursor pointing into the block. + static bool ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor, unsigned BlockID); + + /// \brief Finds all the visible declarations with a given name. + /// The current implementation of this method just loads the entire + /// lookup table as unmaterialized references. + bool FindExternalVisibleDeclsByName(const DeclContext *DC, + DeclarationName Name) override; + + /// \brief Read all of the declarations lexically stored in a + /// declaration context. + /// + /// \param DC The declaration context whose declarations will be + /// read. + /// + /// \param IsKindWeWant A predicate indicating which declaration kinds + /// we are interested in. + /// + /// \param Decls Vector that will contain the declarations loaded + /// from the external source. The caller is responsible for merging + /// these declarations with any declarations already stored in the + /// declaration context. + void + FindExternalLexicalDecls(const DeclContext *DC, + llvm::function_ref<bool(Decl::Kind)> IsKindWeWant, + SmallVectorImpl<Decl *> &Decls) override; + + /// \brief Get the decls that are contained in a file in the Offset/Length + /// range. \p Length can be 0 to indicate a point at \p Offset instead of + /// a range. + void FindFileRegionDecls(FileID File, unsigned Offset, unsigned Length, + SmallVectorImpl<Decl *> &Decls) override; + + /// \brief Notify ASTReader that we started deserialization of + /// a decl or type so until FinishedDeserializing is called there may be + /// decls that are initializing. Must be paired with FinishedDeserializing. + void StartedDeserializing() override; + + /// \brief Notify ASTReader that we finished the deserialization of + /// a decl or type. Must be paired with StartedDeserializing. + void FinishedDeserializing() override; + + /// \brief Function that will be invoked when we begin parsing a new + /// translation unit involving this external AST source. + /// + /// This function will provide all of the external definitions to + /// the ASTConsumer. + void StartTranslationUnit(ASTConsumer *Consumer) override; + + /// \brief Print some statistics about AST usage. + void PrintStats() override; + + /// \brief Dump information about the AST reader to standard error. + void dump(); + + /// Return the amount of memory used by memory buffers, breaking down + /// by heap-backed versus mmap'ed memory. + void getMemoryBufferSizes(MemoryBufferSizes &sizes) const override; + + /// \brief Initialize the semantic source with the Sema instance + /// being used to perform semantic analysis on the abstract syntax + /// tree. + void InitializeSema(Sema &S) override; + + /// \brief Inform the semantic consumer that Sema is no longer available. + void ForgetSema() override { SemaObj = nullptr; } + + /// \brief Retrieve the IdentifierInfo for the named identifier. + /// + /// This routine builds a new IdentifierInfo for the given identifier. If any + /// declarations with this name are visible from translation unit scope, their + /// declarations will be deserialized and introduced into the declaration + /// chain of the identifier. + IdentifierInfo *get(StringRef Name) override; + + /// \brief Retrieve an iterator into the set of all identifiers + /// in all loaded AST files. + IdentifierIterator *getIdentifiers() override; + + /// \brief Load the contents of the global method pool for a given + /// selector. + void ReadMethodPool(Selector Sel) override; + + /// \brief Load the set of namespaces that are known to the external source, + /// which will be used during typo correction. + void ReadKnownNamespaces( + SmallVectorImpl<NamespaceDecl *> &Namespaces) override; + + void ReadUndefinedButUsed( + llvm::DenseMap<NamedDecl *, SourceLocation> &Undefined) override; + + void ReadMismatchingDeleteExpressions(llvm::MapVector< + FieldDecl *, llvm::SmallVector<std::pair<SourceLocation, bool>, 4>> & + Exprs) override; + + void ReadTentativeDefinitions( + SmallVectorImpl<VarDecl *> &TentativeDefs) override; + + void ReadUnusedFileScopedDecls( + SmallVectorImpl<const DeclaratorDecl *> &Decls) override; + + void ReadDelegatingConstructors( + SmallVectorImpl<CXXConstructorDecl *> &Decls) override; + + void ReadExtVectorDecls(SmallVectorImpl<TypedefNameDecl *> &Decls) override; + + void ReadUnusedLocalTypedefNameCandidates( + llvm::SmallSetVector<const TypedefNameDecl *, 4> &Decls) override; + + void ReadReferencedSelectors( + SmallVectorImpl<std::pair<Selector, SourceLocation> > &Sels) override; + + void ReadWeakUndeclaredIdentifiers( + SmallVectorImpl<std::pair<IdentifierInfo *, WeakInfo> > &WI) override; + + void ReadUsedVTables(SmallVectorImpl<ExternalVTableUse> &VTables) override; + + void ReadPendingInstantiations( + SmallVectorImpl<std::pair<ValueDecl *, + SourceLocation> > &Pending) override; + + void ReadLateParsedTemplates( + llvm::MapVector<const FunctionDecl *, LateParsedTemplate *> &LPTMap) + override; + + /// \brief Load a selector from disk, registering its ID if it exists. + void LoadSelector(Selector Sel); + + void SetIdentifierInfo(unsigned ID, IdentifierInfo *II); + void SetGloballyVisibleDecls(IdentifierInfo *II, + const SmallVectorImpl<uint32_t> &DeclIDs, + SmallVectorImpl<Decl *> *Decls = nullptr); + + /// \brief Report a diagnostic. + DiagnosticBuilder Diag(unsigned DiagID); + + /// \brief Report a diagnostic. + DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID); + + IdentifierInfo *DecodeIdentifierInfo(serialization::IdentifierID ID); + + IdentifierInfo *GetIdentifierInfo(ModuleFile &M, const RecordData &Record, + unsigned &Idx) { + return DecodeIdentifierInfo(getGlobalIdentifierID(M, Record[Idx++])); + } + + IdentifierInfo *GetIdentifier(serialization::IdentifierID ID) override { + // Note that we are loading an identifier. + Deserializing AnIdentifier(this); + + return DecodeIdentifierInfo(ID); + } + + IdentifierInfo *getLocalIdentifier(ModuleFile &M, unsigned LocalID); + + serialization::IdentifierID getGlobalIdentifierID(ModuleFile &M, + unsigned LocalID); + + void resolvePendingMacro(IdentifierInfo *II, const PendingMacroInfo &PMInfo); + + /// \brief Retrieve the macro with the given ID. + MacroInfo *getMacro(serialization::MacroID ID); + + /// \brief Retrieve the global macro ID corresponding to the given local + /// ID within the given module file. + serialization::MacroID getGlobalMacroID(ModuleFile &M, unsigned LocalID); + + /// \brief Read the source location entry with index ID. + bool ReadSLocEntry(int ID) override; + + /// \brief Retrieve the module import location and module name for the + /// given source manager entry ID. + std::pair<SourceLocation, StringRef> getModuleImportLoc(int ID) override; + + /// \brief Retrieve the global submodule ID given a module and its local ID + /// number. + serialization::SubmoduleID + getGlobalSubmoduleID(ModuleFile &M, unsigned LocalID); + + /// \brief Retrieve the submodule that corresponds to a global submodule ID. + /// + Module *getSubmodule(serialization::SubmoduleID GlobalID); + + /// \brief Retrieve the module that corresponds to the given module ID. + /// + /// Note: overrides method in ExternalASTSource + Module *getModule(unsigned ID) override; + + /// \brief Retrieve the module file with a given local ID within the specified + /// ModuleFile. + ModuleFile *getLocalModuleFile(ModuleFile &M, unsigned ID); + + /// \brief Get an ID for the given module file. + unsigned getModuleFileID(ModuleFile *M); + + /// \brief Return a descriptor for the corresponding module. + llvm::Optional<ASTSourceDescriptor> getSourceDescriptor(unsigned ID) override; + + /// \brief Retrieve a selector from the given module with its local ID + /// number. + Selector getLocalSelector(ModuleFile &M, unsigned LocalID); + + Selector DecodeSelector(serialization::SelectorID Idx); + + Selector GetExternalSelector(serialization::SelectorID ID) override; + uint32_t GetNumExternalSelectors() override; + + Selector ReadSelector(ModuleFile &M, const RecordData &Record, unsigned &Idx) { + return getLocalSelector(M, Record[Idx++]); + } + + /// \brief Retrieve the global selector ID that corresponds to this + /// the local selector ID in a given module. + serialization::SelectorID getGlobalSelectorID(ModuleFile &F, + unsigned LocalID) const; + + /// \brief Read a declaration name. + DeclarationName ReadDeclarationName(ModuleFile &F, + const RecordData &Record, unsigned &Idx); + void ReadDeclarationNameLoc(ModuleFile &F, + DeclarationNameLoc &DNLoc, DeclarationName Name, + const RecordData &Record, unsigned &Idx); + void ReadDeclarationNameInfo(ModuleFile &F, DeclarationNameInfo &NameInfo, + const RecordData &Record, unsigned &Idx); + + void ReadQualifierInfo(ModuleFile &F, QualifierInfo &Info, + const RecordData &Record, unsigned &Idx); + + NestedNameSpecifier *ReadNestedNameSpecifier(ModuleFile &F, + const RecordData &Record, + unsigned &Idx); + + NestedNameSpecifierLoc ReadNestedNameSpecifierLoc(ModuleFile &F, + const RecordData &Record, + unsigned &Idx); + + /// \brief Read a template name. + TemplateName ReadTemplateName(ModuleFile &F, const RecordData &Record, + unsigned &Idx); + + /// \brief Read a template argument. + TemplateArgument ReadTemplateArgument(ModuleFile &F, const RecordData &Record, + unsigned &Idx, + bool Canonicalize = false); + + /// \brief Read a template parameter list. + TemplateParameterList *ReadTemplateParameterList(ModuleFile &F, + const RecordData &Record, + unsigned &Idx); + + /// \brief Read a template argument array. + void ReadTemplateArgumentList(SmallVectorImpl<TemplateArgument> &TemplArgs, + ModuleFile &F, const RecordData &Record, + unsigned &Idx, bool Canonicalize = false); + + /// \brief Read a UnresolvedSet structure. + void ReadUnresolvedSet(ModuleFile &F, LazyASTUnresolvedSet &Set, + const RecordData &Record, unsigned &Idx); + + /// \brief Read a C++ base specifier. + CXXBaseSpecifier ReadCXXBaseSpecifier(ModuleFile &F, + const RecordData &Record,unsigned &Idx); + + /// \brief Read a CXXCtorInitializer array. + CXXCtorInitializer ** + ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record, + unsigned &Idx); + + /// \brief Read a CXXCtorInitializers ID from the given record and + /// return its global bit offset. + uint64_t ReadCXXCtorInitializersRef(ModuleFile &M, const RecordData &Record, + unsigned &Idx); + + /// \brief Read the contents of a CXXCtorInitializer array. + CXXCtorInitializer **GetExternalCXXCtorInitializers(uint64_t Offset) override; + + /// \brief Read a source location from raw form. + SourceLocation ReadSourceLocation(ModuleFile &ModuleFile, unsigned Raw) const { + SourceLocation Loc = SourceLocation::getFromRawEncoding(Raw); + assert(ModuleFile.SLocRemap.find(Loc.getOffset()) != ModuleFile.SLocRemap.end() && + "Cannot find offset to remap."); + int Remap = ModuleFile.SLocRemap.find(Loc.getOffset())->second; + return Loc.getLocWithOffset(Remap); + } + + /// \brief Read a source location. + SourceLocation ReadSourceLocation(ModuleFile &ModuleFile, + const RecordDataImpl &Record, + unsigned &Idx) { + return ReadSourceLocation(ModuleFile, Record[Idx++]); + } + + /// \brief Read a source range. + SourceRange ReadSourceRange(ModuleFile &F, + const RecordData &Record, unsigned &Idx); + + /// \brief Read an integral value + llvm::APInt ReadAPInt(const RecordData &Record, unsigned &Idx); + + /// \brief Read a signed integral value + llvm::APSInt ReadAPSInt(const RecordData &Record, unsigned &Idx); + + /// \brief Read a floating-point value + llvm::APFloat ReadAPFloat(const RecordData &Record, + const llvm::fltSemantics &Sem, unsigned &Idx); + + // \brief Read a string + static std::string ReadString(const RecordData &Record, unsigned &Idx); + + // \brief Read a path + std::string ReadPath(ModuleFile &F, const RecordData &Record, unsigned &Idx); + + /// \brief Read a version tuple. + static VersionTuple ReadVersionTuple(const RecordData &Record, unsigned &Idx); + + CXXTemporary *ReadCXXTemporary(ModuleFile &F, const RecordData &Record, + unsigned &Idx); + + /// \brief Reads attributes from the current stream position. + void ReadAttributes(ModuleFile &F, AttrVec &Attrs, + const RecordData &Record, unsigned &Idx); + + /// \brief Reads a statement. + Stmt *ReadStmt(ModuleFile &F); + + /// \brief Reads an expression. + Expr *ReadExpr(ModuleFile &F); + + /// \brief Reads a sub-statement operand during statement reading. + Stmt *ReadSubStmt() { + assert(ReadingKind == Read_Stmt && + "Should be called only during statement reading!"); + // Subexpressions are stored from last to first, so the next Stmt we need + // is at the back of the stack. + assert(!StmtStack.empty() && "Read too many sub-statements!"); + return StmtStack.pop_back_val(); + } + + /// \brief Reads a sub-expression operand during statement reading. + Expr *ReadSubExpr(); + + /// \brief Reads a token out of a record. + Token ReadToken(ModuleFile &M, const RecordDataImpl &Record, unsigned &Idx); + + /// \brief Reads the macro record located at the given offset. + MacroInfo *ReadMacroRecord(ModuleFile &F, uint64_t Offset); + + /// \brief Determine the global preprocessed entity ID that corresponds to + /// the given local ID within the given module. + serialization::PreprocessedEntityID + getGlobalPreprocessedEntityID(ModuleFile &M, unsigned LocalID) const; + + /// \brief Add a macro to deserialize its macro directive history. + /// + /// \param II The name of the macro. + /// \param M The module file. + /// \param MacroDirectivesOffset Offset of the serialized macro directive + /// history. + void addPendingMacro(IdentifierInfo *II, ModuleFile *M, + uint64_t MacroDirectivesOffset); + + /// \brief Read the set of macros defined by this external macro source. + void ReadDefinedMacros() override; + + /// \brief Update an out-of-date identifier. + void updateOutOfDateIdentifier(IdentifierInfo &II) override; + + /// \brief Note that this identifier is up-to-date. + void markIdentifierUpToDate(IdentifierInfo *II); + + /// \brief Load all external visible decls in the given DeclContext. + void completeVisibleDeclsMap(const DeclContext *DC) override; + + /// \brief Retrieve the AST context that this AST reader supplements. + ASTContext &getContext() { return Context; } + + // \brief Contains the IDs for declarations that were requested before we have + // access to a Sema object. + SmallVector<uint64_t, 16> PreloadedDeclIDs; + + /// \brief Retrieve the semantic analysis object used to analyze the + /// translation unit in which the precompiled header is being + /// imported. + Sema *getSema() { return SemaObj; } + + /// \brief Retrieve the identifier table associated with the + /// preprocessor. + IdentifierTable &getIdentifierTable(); + + /// \brief Record that the given ID maps to the given switch-case + /// statement. + void RecordSwitchCaseID(SwitchCase *SC, unsigned ID); + + /// \brief Retrieve the switch-case statement with the given ID. + SwitchCase *getSwitchCaseWithID(unsigned ID); + + void ClearSwitchCaseIDs(); + + /// \brief Cursors for comments blocks. + SmallVector<std::pair<llvm::BitstreamCursor, + serialization::ModuleFile *>, 8> CommentsCursors; + + /// \brief Loads comments ranges. + void ReadComments() override; +}; + +/// \brief Helper class that saves the current stream position and +/// then restores it when destroyed. +struct SavedStreamPosition { + explicit SavedStreamPosition(llvm::BitstreamCursor &Cursor) + : Cursor(Cursor), Offset(Cursor.GetCurrentBitNo()) { } + + ~SavedStreamPosition() { + Cursor.JumpToBit(Offset); + } + +private: + llvm::BitstreamCursor &Cursor; + uint64_t Offset; +}; + +inline void PCHValidator::Error(const char *Msg) { + Reader.Error(Msg); +} + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Serialization/ASTWriter.h b/contrib/llvm/tools/clang/include/clang/Serialization/ASTWriter.h new file mode 100644 index 0000000..ed34547 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Serialization/ASTWriter.h @@ -0,0 +1,920 @@ +//===--- ASTWriter.h - AST File Writer --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ASTWriter class, which writes an AST file +// containing a serialized representation of a translation unit. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_SERIALIZATION_ASTWRITER_H +#define LLVM_CLANG_SERIALIZATION_ASTWRITER_H + +#include "clang/AST/ASTMutationListener.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclarationName.h" +#include "clang/Frontend/PCHContainerOperations.h" +#include "clang/AST/TemplateBase.h" +#include "clang/Sema/SemaConsumer.h" +#include "clang/Serialization/ASTBitCodes.h" +#include "clang/Serialization/ASTDeserializationListener.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/MapVector.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Bitcode/BitstreamWriter.h" +#include <map> +#include <queue> +#include <vector> + +namespace llvm { + class APFloat; + class APInt; + class BitstreamWriter; +} + +namespace clang { + +class ASTContext; +class Attr; +class NestedNameSpecifier; +class CXXBaseSpecifier; +class CXXCtorInitializer; +class FileEntry; +class FPOptions; +class HeaderSearch; +class HeaderSearchOptions; +class IdentifierResolver; +class MacroDefinitionRecord; +class MacroDirective; +class MacroInfo; +class OpaqueValueExpr; +class OpenCLOptions; +class ASTReader; +class Module; +class ModuleFileExtension; +class ModuleFileExtensionWriter; +class PreprocessedEntity; +class PreprocessingRecord; +class Preprocessor; +class RecordDecl; +class Sema; +class SourceManager; +struct StoredDeclsList; +class SwitchCase; +class TargetInfo; +class Token; +class VersionTuple; +class ASTUnresolvedSet; + +namespace SrcMgr { class SLocEntry; } + +/// \brief Writes an AST file containing the contents of a translation unit. +/// +/// The ASTWriter class produces a bitstream containing the serialized +/// representation of a given abstract syntax tree and its supporting +/// data structures. This bitstream can be de-serialized via an +/// instance of the ASTReader class. +class ASTWriter : public ASTDeserializationListener, + public ASTMutationListener { +public: + typedef SmallVector<uint64_t, 64> RecordData; + typedef SmallVectorImpl<uint64_t> RecordDataImpl; + typedef ArrayRef<uint64_t> RecordDataRef; + + friend class ASTDeclWriter; + friend class ASTStmtWriter; +private: + /// \brief Map that provides the ID numbers of each type within the + /// output stream, plus those deserialized from a chained PCH. + /// + /// The ID numbers of types are consecutive (in order of discovery) + /// and start at 1. 0 is reserved for NULL. When types are actually + /// stored in the stream, the ID number is shifted by 2 bits to + /// allow for the const/volatile qualifiers. + /// + /// Keys in the map never have const/volatile qualifiers. + typedef llvm::DenseMap<QualType, serialization::TypeIdx, + serialization::UnsafeQualTypeDenseMapInfo> + TypeIdxMap; + + /// \brief The bitstream writer used to emit this precompiled header. + llvm::BitstreamWriter &Stream; + + /// \brief The ASTContext we're writing. + ASTContext *Context; + + /// \brief The preprocessor we're writing. + Preprocessor *PP; + + /// \brief The reader of existing AST files, if we're chaining. + ASTReader *Chain; + + /// \brief The module we're currently writing, if any. + Module *WritingModule; + + /// \brief The base directory for any relative paths we emit. + std::string BaseDirectory; + + /// \brief Indicates whether timestamps should be written to the produced + /// module file. This is the case for files implicitly written to the + /// module cache, where we need the timestamps to determine if the module + /// file is up to date, but not otherwise. + bool IncludeTimestamps; + + /// \brief Indicates when the AST writing is actively performing + /// serialization, rather than just queueing updates. + bool WritingAST; + + /// \brief Indicates that we are done serializing the collection of decls + /// and types to emit. + bool DoneWritingDeclsAndTypes; + + /// \brief Indicates that the AST contained compiler errors. + bool ASTHasCompilerErrors; + + /// \brief Mapping from input file entries to the index into the + /// offset table where information about that input file is stored. + llvm::DenseMap<const FileEntry *, uint32_t> InputFileIDs; + + /// \brief Stores a declaration or a type to be written to the AST file. + class DeclOrType { + public: + DeclOrType(Decl *D) : Stored(D), IsType(false) { } + DeclOrType(QualType T) : Stored(T.getAsOpaquePtr()), IsType(true) { } + + bool isType() const { return IsType; } + bool isDecl() const { return !IsType; } + + QualType getType() const { + assert(isType() && "Not a type!"); + return QualType::getFromOpaquePtr(Stored); + } + + Decl *getDecl() const { + assert(isDecl() && "Not a decl!"); + return static_cast<Decl *>(Stored); + } + + private: + void *Stored; + bool IsType; + }; + + /// \brief The declarations and types to emit. + std::queue<DeclOrType> DeclTypesToEmit; + + /// \brief The first ID number we can use for our own declarations. + serialization::DeclID FirstDeclID; + + /// \brief The decl ID that will be assigned to the next new decl. + serialization::DeclID NextDeclID; + + /// \brief Map that provides the ID numbers of each declaration within + /// the output stream, as well as those deserialized from a chained PCH. + /// + /// The ID numbers of declarations are consecutive (in order of + /// discovery) and start at 2. 1 is reserved for the translation + /// unit, while 0 is reserved for NULL. + llvm::DenseMap<const Decl *, serialization::DeclID> DeclIDs; + + /// \brief Offset of each declaration in the bitstream, indexed by + /// the declaration's ID. + std::vector<serialization::DeclOffset> DeclOffsets; + + /// \brief Sorted (by file offset) vector of pairs of file offset/DeclID. + typedef SmallVector<std::pair<unsigned, serialization::DeclID>, 64> + LocDeclIDsTy; + struct DeclIDInFileInfo { + LocDeclIDsTy DeclIDs; + /// \brief Set when the DeclIDs vectors from all files are joined, this + /// indicates the index that this particular vector has in the global one. + unsigned FirstDeclIndex; + }; + typedef llvm::DenseMap<FileID, DeclIDInFileInfo *> FileDeclIDsTy; + + /// \brief Map from file SLocEntries to info about the file-level declarations + /// that it contains. + FileDeclIDsTy FileDeclIDs; + + void associateDeclWithFile(const Decl *D, serialization::DeclID); + + /// \brief The first ID number we can use for our own types. + serialization::TypeID FirstTypeID; + + /// \brief The type ID that will be assigned to the next new type. + serialization::TypeID NextTypeID; + + /// \brief Map that provides the ID numbers of each type within the + /// output stream, plus those deserialized from a chained PCH. + /// + /// The ID numbers of types are consecutive (in order of discovery) + /// and start at 1. 0 is reserved for NULL. When types are actually + /// stored in the stream, the ID number is shifted by 2 bits to + /// allow for the const/volatile qualifiers. + /// + /// Keys in the map never have const/volatile qualifiers. + TypeIdxMap TypeIdxs; + + /// \brief Offset of each type in the bitstream, indexed by + /// the type's ID. + std::vector<uint32_t> TypeOffsets; + + /// \brief The first ID number we can use for our own identifiers. + serialization::IdentID FirstIdentID; + + /// \brief The identifier ID that will be assigned to the next new identifier. + serialization::IdentID NextIdentID; + + /// \brief Map that provides the ID numbers of each identifier in + /// the output stream. + /// + /// The ID numbers for identifiers are consecutive (in order of + /// discovery), starting at 1. An ID of zero refers to a NULL + /// IdentifierInfo. + llvm::MapVector<const IdentifierInfo *, serialization::IdentID> IdentifierIDs; + + /// \brief The first ID number we can use for our own macros. + serialization::MacroID FirstMacroID; + + /// \brief The identifier ID that will be assigned to the next new identifier. + serialization::MacroID NextMacroID; + + /// \brief Map that provides the ID numbers of each macro. + llvm::DenseMap<MacroInfo *, serialization::MacroID> MacroIDs; + + struct MacroInfoToEmitData { + const IdentifierInfo *Name; + MacroInfo *MI; + serialization::MacroID ID; + }; + /// \brief The macro infos to emit. + std::vector<MacroInfoToEmitData> MacroInfosToEmit; + + llvm::DenseMap<const IdentifierInfo *, uint64_t> IdentMacroDirectivesOffsetMap; + + /// @name FlushStmt Caches + /// @{ + + /// \brief Set of parent Stmts for the currently serializing sub-stmt. + llvm::DenseSet<Stmt *> ParentStmts; + + /// \brief Offsets of sub-stmts already serialized. The offset points + /// just after the stmt record. + llvm::DenseMap<Stmt *, uint64_t> SubStmtEntries; + + /// @} + + /// \brief Offsets of each of the identifier IDs into the identifier + /// table. + std::vector<uint32_t> IdentifierOffsets; + + /// \brief The first ID number we can use for our own submodules. + serialization::SubmoduleID FirstSubmoduleID; + + /// \brief The submodule ID that will be assigned to the next new submodule. + serialization::SubmoduleID NextSubmoduleID; + + /// \brief The first ID number we can use for our own selectors. + serialization::SelectorID FirstSelectorID; + + /// \brief The selector ID that will be assigned to the next new selector. + serialization::SelectorID NextSelectorID; + + /// \brief Map that provides the ID numbers of each Selector. + llvm::MapVector<Selector, serialization::SelectorID> SelectorIDs; + + /// \brief Offset of each selector within the method pool/selector + /// table, indexed by the Selector ID (-1). + std::vector<uint32_t> SelectorOffsets; + + /// \brief Mapping from macro definitions (as they occur in the preprocessing + /// record) to the macro IDs. + llvm::DenseMap<const MacroDefinitionRecord *, + serialization::PreprocessedEntityID> MacroDefinitions; + + /// \brief Cache of indices of anonymous declarations within their lexical + /// contexts. + llvm::DenseMap<const Decl *, unsigned> AnonymousDeclarationNumbers; + + /// An update to a Decl. + class DeclUpdate { + /// A DeclUpdateKind. + unsigned Kind; + union { + const Decl *Dcl; + void *Type; + unsigned Loc; + unsigned Val; + Module *Mod; + const Attr *Attribute; + }; + + public: + DeclUpdate(unsigned Kind) : Kind(Kind), Dcl(nullptr) {} + DeclUpdate(unsigned Kind, const Decl *Dcl) : Kind(Kind), Dcl(Dcl) {} + DeclUpdate(unsigned Kind, QualType Type) + : Kind(Kind), Type(Type.getAsOpaquePtr()) {} + DeclUpdate(unsigned Kind, SourceLocation Loc) + : Kind(Kind), Loc(Loc.getRawEncoding()) {} + DeclUpdate(unsigned Kind, unsigned Val) + : Kind(Kind), Val(Val) {} + DeclUpdate(unsigned Kind, Module *M) + : Kind(Kind), Mod(M) {} + DeclUpdate(unsigned Kind, const Attr *Attribute) + : Kind(Kind), Attribute(Attribute) {} + + unsigned getKind() const { return Kind; } + const Decl *getDecl() const { return Dcl; } + QualType getType() const { return QualType::getFromOpaquePtr(Type); } + SourceLocation getLoc() const { + return SourceLocation::getFromRawEncoding(Loc); + } + unsigned getNumber() const { return Val; } + Module *getModule() const { return Mod; } + const Attr *getAttr() const { return Attribute; } + }; + + typedef SmallVector<DeclUpdate, 1> UpdateRecord; + typedef llvm::MapVector<const Decl *, UpdateRecord> DeclUpdateMap; + /// \brief Mapping from declarations that came from a chained PCH to the + /// record containing modifications to them. + DeclUpdateMap DeclUpdates; + + typedef llvm::DenseMap<Decl *, Decl *> FirstLatestDeclMap; + /// \brief Map of first declarations from a chained PCH that point to the + /// most recent declarations in another PCH. + FirstLatestDeclMap FirstLatestDecls; + + /// \brief Declarations encountered that might be external + /// definitions. + /// + /// We keep track of external definitions and other 'interesting' declarations + /// as we are emitting declarations to the AST file. The AST file contains a + /// separate record for these declarations, which are provided to the AST + /// consumer by the AST reader. This is behavior is required to properly cope with, + /// e.g., tentative variable definitions that occur within + /// headers. The declarations themselves are stored as declaration + /// IDs, since they will be written out to an EAGERLY_DESERIALIZED_DECLS + /// record. + SmallVector<uint64_t, 16> EagerlyDeserializedDecls; + + /// \brief DeclContexts that have received extensions since their serialized + /// form. + /// + /// For namespaces, when we're chaining and encountering a namespace, we check + /// if its primary namespace comes from the chain. If it does, we add the + /// primary to this set, so that we can write out lexical content updates for + /// it. + llvm::SmallSetVector<const DeclContext *, 16> UpdatedDeclContexts; + + /// \brief Keeps track of visible decls that were added in DeclContexts + /// coming from another AST file. + SmallVector<const Decl *, 16> UpdatingVisibleDecls; + + /// \brief The set of Objective-C class that have categories we + /// should serialize. + llvm::SetVector<ObjCInterfaceDecl *> ObjCClassesWithCategories; + + struct ReplacedDeclInfo { + serialization::DeclID ID; + uint64_t Offset; + unsigned Loc; + + ReplacedDeclInfo() : ID(0), Offset(0), Loc(0) {} + ReplacedDeclInfo(serialization::DeclID ID, uint64_t Offset, + SourceLocation Loc) + : ID(ID), Offset(Offset), Loc(Loc.getRawEncoding()) {} + }; + + /// \brief Decls that have been replaced in the current dependent AST file. + /// + /// When a decl changes fundamentally after being deserialized (this shouldn't + /// happen, but the ObjC AST nodes are designed this way), it will be + /// serialized again. In this case, it is registered here, so that the reader + /// knows to read the updated version. + SmallVector<ReplacedDeclInfo, 16> ReplacedDecls; + + /// \brief The set of declarations that may have redeclaration chains that + /// need to be serialized. + llvm::SmallVector<const Decl *, 16> Redeclarations; + + /// \brief A cache of the first local declaration for "interesting" + /// redeclaration chains. + llvm::DenseMap<const Decl *, const Decl *> FirstLocalDeclCache; + + /// \brief Statements that we've encountered while serializing a + /// declaration or type. + SmallVector<Stmt *, 16> StmtsToEmit; + + /// \brief Statements collection to use for ASTWriter::AddStmt(). + /// It will point to StmtsToEmit unless it is overriden. + SmallVector<Stmt *, 16> *CollectedStmts; + + /// \brief Mapping from SwitchCase statements to IDs. + llvm::DenseMap<SwitchCase *, unsigned> SwitchCaseIDs; + + /// \brief The number of statements written to the AST file. + unsigned NumStatements; + + /// \brief The number of macros written to the AST file. + unsigned NumMacros; + + /// \brief The number of lexical declcontexts written to the AST + /// file. + unsigned NumLexicalDeclContexts; + + /// \brief The number of visible declcontexts written to the AST + /// file. + unsigned NumVisibleDeclContexts; + + /// \brief The offset of each CXXBaseSpecifier set within the AST. + SmallVector<uint32_t, 16> CXXBaseSpecifiersOffsets; + + /// \brief The first ID number we can use for our own base specifiers. + serialization::CXXBaseSpecifiersID FirstCXXBaseSpecifiersID; + + /// \brief The base specifiers ID that will be assigned to the next new + /// set of C++ base specifiers. + serialization::CXXBaseSpecifiersID NextCXXBaseSpecifiersID; + + /// \brief A set of C++ base specifiers that is queued to be written into the + /// AST file. + struct QueuedCXXBaseSpecifiers { + QueuedCXXBaseSpecifiers() : ID(), Bases(), BasesEnd() { } + + QueuedCXXBaseSpecifiers(serialization::CXXBaseSpecifiersID ID, + CXXBaseSpecifier const *Bases, + CXXBaseSpecifier const *BasesEnd) + : ID(ID), Bases(Bases), BasesEnd(BasesEnd) { } + + serialization::CXXBaseSpecifiersID ID; + CXXBaseSpecifier const * Bases; + CXXBaseSpecifier const * BasesEnd; + }; + + /// \brief Queue of C++ base specifiers to be written to the AST file, + /// in the order they should be written. + SmallVector<QueuedCXXBaseSpecifiers, 2> CXXBaseSpecifiersToWrite; + + /// \brief The offset of each CXXCtorInitializer list within the AST. + SmallVector<uint32_t, 16> CXXCtorInitializersOffsets; + + /// \brief The first ID number we can use for our own ctor initializers. + serialization::CXXCtorInitializersID FirstCXXCtorInitializersID; + + /// \brief The ctor initializers ID that will be assigned to the next new + /// list of C++ ctor initializers. + serialization::CXXCtorInitializersID NextCXXCtorInitializersID; + + /// \brief A set of C++ ctor initializers that is queued to be written + /// into the AST file. + struct QueuedCXXCtorInitializers { + QueuedCXXCtorInitializers() : ID() {} + + QueuedCXXCtorInitializers(serialization::CXXCtorInitializersID ID, + ArrayRef<CXXCtorInitializer*> Inits) + : ID(ID), Inits(Inits) {} + + serialization::CXXCtorInitializersID ID; + ArrayRef<CXXCtorInitializer*> Inits; + }; + + /// \brief Queue of C++ ctor initializers to be written to the AST file, + /// in the order they should be written. + SmallVector<QueuedCXXCtorInitializers, 2> CXXCtorInitializersToWrite; + + /// \brief A mapping from each known submodule to its ID number, which will + /// be a positive integer. + llvm::DenseMap<Module *, unsigned> SubmoduleIDs; + + /// \brief A list of the module file extension writers. + std::vector<std::unique_ptr<ModuleFileExtensionWriter>> + ModuleFileExtensionWriters; + + /// \brief Retrieve or create a submodule ID for this module. + unsigned getSubmoduleID(Module *Mod); + + /// \brief Write the given subexpression to the bitstream. + void WriteSubStmt(Stmt *S, + llvm::DenseMap<Stmt *, uint64_t> &SubStmtEntries, + llvm::DenseSet<Stmt *> &ParentStmts); + + void WriteBlockInfoBlock(); + uint64_t WriteControlBlock(Preprocessor &PP, ASTContext &Context, + StringRef isysroot, const std::string &OutputFile); + void WriteInputFiles(SourceManager &SourceMgr, HeaderSearchOptions &HSOpts, + bool Modules); + void WriteSourceManagerBlock(SourceManager &SourceMgr, + const Preprocessor &PP); + void WritePreprocessor(const Preprocessor &PP, bool IsModule); + void WriteHeaderSearch(const HeaderSearch &HS); + void WritePreprocessorDetail(PreprocessingRecord &PPRec); + void WriteSubmodules(Module *WritingModule); + + void WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag, + bool isModule); + void WriteCXXBaseSpecifiersOffsets(); + void WriteCXXCtorInitializersOffsets(); + + unsigned TypeExtQualAbbrev; + unsigned TypeFunctionProtoAbbrev; + void WriteTypeAbbrevs(); + void WriteType(QualType T); + + bool isLookupResultExternal(StoredDeclsList &Result, DeclContext *DC); + bool isLookupResultEntirelyExternal(StoredDeclsList &Result, DeclContext *DC); + + void GenerateNameLookupTable(const DeclContext *DC, + llvm::SmallVectorImpl<char> &LookupTable); + uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, DeclContext *DC); + uint64_t WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext *DC); + void WriteTypeDeclOffsets(); + void WriteFileDeclIDsMap(); + void WriteComments(); + void WriteSelectors(Sema &SemaRef); + void WriteReferencedSelectorsPool(Sema &SemaRef); + void WriteIdentifierTable(Preprocessor &PP, IdentifierResolver &IdResolver, + bool IsModule); + void WriteAttributes(ArrayRef<const Attr*> Attrs, RecordDataImpl &Record); + void WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord); + void WriteDeclReplacementsBlock(); + void WriteDeclContextVisibleUpdate(const DeclContext *DC); + void WriteFPPragmaOptions(const FPOptions &Opts); + void WriteOpenCLExtensions(Sema &SemaRef); + void WriteObjCCategories(); + void WriteLateParsedTemplates(Sema &SemaRef); + void WriteOptimizePragmaOptions(Sema &SemaRef); + void WriteModuleFileExtension(Sema &SemaRef, + ModuleFileExtensionWriter &Writer); + + unsigned DeclParmVarAbbrev; + unsigned DeclContextLexicalAbbrev; + unsigned DeclContextVisibleLookupAbbrev; + unsigned UpdateVisibleAbbrev; + unsigned DeclRecordAbbrev; + unsigned DeclTypedefAbbrev; + unsigned DeclVarAbbrev; + unsigned DeclFieldAbbrev; + unsigned DeclEnumAbbrev; + unsigned DeclObjCIvarAbbrev; + unsigned DeclCXXMethodAbbrev; + + unsigned DeclRefExprAbbrev; + unsigned CharacterLiteralAbbrev; + unsigned IntegerLiteralAbbrev; + unsigned ExprImplicitCastAbbrev; + + void WriteDeclAbbrevs(); + void WriteDecl(ASTContext &Context, Decl *D); + void AddFunctionDefinition(const FunctionDecl *FD, RecordData &Record); + + uint64_t WriteASTCore(Sema &SemaRef, + StringRef isysroot, const std::string &OutputFile, + Module *WritingModule); + +public: + /// \brief Create a new precompiled header writer that outputs to + /// the given bitstream. + ASTWriter(llvm::BitstreamWriter &Stream, + ArrayRef<llvm::IntrusiveRefCntPtr<ModuleFileExtension>> Extensions, + bool IncludeTimestamps = true); + ~ASTWriter() override; + + const LangOptions &getLangOpts() const; + + /// \brief Get a timestamp for output into the AST file. The actual timestamp + /// of the specified file may be ignored if we have been instructed to not + /// include timestamps in the output file. + time_t getTimestampForOutput(const FileEntry *E) const; + + /// \brief Write a precompiled header for the given semantic analysis. + /// + /// \param SemaRef a reference to the semantic analysis object that processed + /// the AST to be written into the precompiled header. + /// + /// \param WritingModule The module that we are writing. If null, we are + /// writing a precompiled header. + /// + /// \param isysroot if non-empty, write a relocatable file whose headers + /// are relative to the given system root. If we're writing a module, its + /// build directory will be used in preference to this if both are available. + /// + /// \return the module signature, which eventually will be a hash of + /// the module but currently is merely a random 32-bit number. + uint64_t WriteAST(Sema &SemaRef, const std::string &OutputFile, + Module *WritingModule, StringRef isysroot, + bool hasErrors = false); + + /// \brief Emit a token. + void AddToken(const Token &Tok, RecordDataImpl &Record); + + /// \brief Emit a source location. + void AddSourceLocation(SourceLocation Loc, RecordDataImpl &Record); + + /// \brief Emit a source range. + void AddSourceRange(SourceRange Range, RecordDataImpl &Record); + + /// \brief Emit an integral value. + void AddAPInt(const llvm::APInt &Value, RecordDataImpl &Record); + + /// \brief Emit a signed integral value. + void AddAPSInt(const llvm::APSInt &Value, RecordDataImpl &Record); + + /// \brief Emit a floating-point value. + void AddAPFloat(const llvm::APFloat &Value, RecordDataImpl &Record); + + /// \brief Emit a reference to an identifier. + void AddIdentifierRef(const IdentifierInfo *II, RecordDataImpl &Record); + + /// \brief Emit a Selector (which is a smart pointer reference). + void AddSelectorRef(Selector, RecordDataImpl &Record); + + /// \brief Emit a CXXTemporary. + void AddCXXTemporary(const CXXTemporary *Temp, RecordDataImpl &Record); + + /// \brief Emit a set of C++ base specifiers to the record. + void AddCXXBaseSpecifiersRef(CXXBaseSpecifier const *Bases, + CXXBaseSpecifier const *BasesEnd, + RecordDataImpl &Record); + + /// \brief Get the unique number used to refer to the given selector. + serialization::SelectorID getSelectorRef(Selector Sel); + + /// \brief Get the unique number used to refer to the given identifier. + serialization::IdentID getIdentifierRef(const IdentifierInfo *II); + + /// \brief Get the unique number used to refer to the given macro. + serialization::MacroID getMacroRef(MacroInfo *MI, const IdentifierInfo *Name); + + /// \brief Determine the ID of an already-emitted macro. + serialization::MacroID getMacroID(MacroInfo *MI); + + uint64_t getMacroDirectivesOffset(const IdentifierInfo *Name); + + /// \brief Emit a reference to a type. + void AddTypeRef(QualType T, RecordDataImpl &Record); + + /// \brief Force a type to be emitted and get its ID. + serialization::TypeID GetOrCreateTypeID(QualType T); + + /// \brief Determine the type ID of an already-emitted type. + serialization::TypeID getTypeID(QualType T) const; + + /// \brief Emits a reference to a declarator info. + void AddTypeSourceInfo(TypeSourceInfo *TInfo, RecordDataImpl &Record); + + /// \brief Emits a type with source-location information. + void AddTypeLoc(TypeLoc TL, RecordDataImpl &Record); + + /// \brief Emits a template argument location info. + void AddTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind, + const TemplateArgumentLocInfo &Arg, + RecordDataImpl &Record); + + /// \brief Emits a template argument location. + void AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg, + RecordDataImpl &Record); + + /// \brief Emits an AST template argument list info. + void AddASTTemplateArgumentListInfo( + const ASTTemplateArgumentListInfo *ASTTemplArgList, + RecordDataImpl &Record); + + /// \brief Find the first local declaration of a given local redeclarable + /// decl. + const Decl *getFirstLocalDecl(const Decl *D); + + /// \brief Emit a reference to a declaration. + void AddDeclRef(const Decl *D, RecordDataImpl &Record); + + + /// \brief Force a declaration to be emitted and get its ID. + serialization::DeclID GetDeclRef(const Decl *D); + + /// \brief Determine the declaration ID of an already-emitted + /// declaration. + serialization::DeclID getDeclID(const Decl *D); + + /// \brief Emit a declaration name. + void AddDeclarationName(DeclarationName Name, RecordDataImpl &Record); + void AddDeclarationNameLoc(const DeclarationNameLoc &DNLoc, + DeclarationName Name, RecordDataImpl &Record); + void AddDeclarationNameInfo(const DeclarationNameInfo &NameInfo, + RecordDataImpl &Record); + unsigned getAnonymousDeclarationNumber(const NamedDecl *D); + + void AddQualifierInfo(const QualifierInfo &Info, RecordDataImpl &Record); + + /// \brief Emit a nested name specifier. + void AddNestedNameSpecifier(NestedNameSpecifier *NNS, RecordDataImpl &Record); + + /// \brief Emit a nested name specifier with source-location information. + void AddNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS, + RecordDataImpl &Record); + + /// \brief Emit a template name. + void AddTemplateName(TemplateName Name, RecordDataImpl &Record); + + /// \brief Emit a template argument. + void AddTemplateArgument(const TemplateArgument &Arg, RecordDataImpl &Record); + + /// \brief Emit a template parameter list. + void AddTemplateParameterList(const TemplateParameterList *TemplateParams, + RecordDataImpl &Record); + + /// \brief Emit a template argument list. + void AddTemplateArgumentList(const TemplateArgumentList *TemplateArgs, + RecordDataImpl &Record); + + /// \brief Emit a UnresolvedSet structure. + void AddUnresolvedSet(const ASTUnresolvedSet &Set, RecordDataImpl &Record); + + /// \brief Emit a C++ base specifier. + void AddCXXBaseSpecifier(const CXXBaseSpecifier &Base, + RecordDataImpl &Record); + + /// \brief Emit the ID for a CXXCtorInitializer array and register the array + /// for later serialization. + void AddCXXCtorInitializersRef(ArrayRef<CXXCtorInitializer *> Inits, + RecordDataImpl &Record); + + /// \brief Emit a CXXCtorInitializer array. + void AddCXXCtorInitializers( + const CXXCtorInitializer * const *CtorInitializers, + unsigned NumCtorInitializers, + RecordDataImpl &Record); + + void AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Record); + + /// \brief Add a string to the given record. + void AddString(StringRef Str, RecordDataImpl &Record); + + /// \brief Convert a path from this build process into one that is appropriate + /// for emission in the module file. + bool PreparePathForOutput(SmallVectorImpl<char> &Path); + + /// \brief Add a path to the given record. + void AddPath(StringRef Path, RecordDataImpl &Record); + + /// \brief Emit the current record with the given path as a blob. + void EmitRecordWithPath(unsigned Abbrev, RecordDataRef Record, + StringRef Path); + + /// \brief Add a version tuple to the given record + void AddVersionTuple(const VersionTuple &Version, RecordDataImpl &Record); + + /// \brief Infer the submodule ID that contains an entity at the given + /// source location. + serialization::SubmoduleID inferSubmoduleIDFromLocation(SourceLocation Loc); + + /// \brief Retrieve or create a submodule ID for this module, or return 0 if + /// the submodule is neither local (a submodle of the currently-written module) + /// nor from an imported module. + unsigned getLocalOrImportedSubmoduleID(Module *Mod); + + /// \brief Note that the identifier II occurs at the given offset + /// within the identifier table. + void SetIdentifierOffset(const IdentifierInfo *II, uint32_t Offset); + + /// \brief Note that the selector Sel occurs at the given offset + /// within the method pool/selector table. + void SetSelectorOffset(Selector Sel, uint32_t Offset); + + /// \brief Add the given statement or expression to the queue of + /// statements to emit. + /// + /// This routine should be used when emitting types and declarations + /// that have expressions as part of their formulation. Once the + /// type or declaration has been written, call FlushStmts() to write + /// the corresponding statements just after the type or + /// declaration. + void AddStmt(Stmt *S) { + CollectedStmts->push_back(S); + } + + /// \brief Flush all of the statements and expressions that have + /// been added to the queue via AddStmt(). + void FlushStmts(); + + /// \brief Flush all of the C++ base specifier sets that have been added + /// via \c AddCXXBaseSpecifiersRef(). + void FlushCXXBaseSpecifiers(); + + /// \brief Flush all of the C++ constructor initializer lists that have been + /// added via \c AddCXXCtorInitializersRef(). + void FlushCXXCtorInitializers(); + + /// \brief Flush all pending records that are tacked onto the end of + /// decl and decl update records. + void FlushPendingAfterDecl() { + FlushStmts(); + FlushCXXBaseSpecifiers(); + FlushCXXCtorInitializers(); + } + + /// \brief Record an ID for the given switch-case statement. + unsigned RecordSwitchCaseID(SwitchCase *S); + + /// \brief Retrieve the ID for the given switch-case statement. + unsigned getSwitchCaseID(SwitchCase *S); + + void ClearSwitchCaseIDs(); + + unsigned getTypeExtQualAbbrev() const { + return TypeExtQualAbbrev; + } + unsigned getTypeFunctionProtoAbbrev() const { + return TypeFunctionProtoAbbrev; + } + + unsigned getDeclParmVarAbbrev() const { return DeclParmVarAbbrev; } + unsigned getDeclRecordAbbrev() const { return DeclRecordAbbrev; } + unsigned getDeclTypedefAbbrev() const { return DeclTypedefAbbrev; } + unsigned getDeclVarAbbrev() const { return DeclVarAbbrev; } + unsigned getDeclFieldAbbrev() const { return DeclFieldAbbrev; } + unsigned getDeclEnumAbbrev() const { return DeclEnumAbbrev; } + unsigned getDeclObjCIvarAbbrev() const { return DeclObjCIvarAbbrev; } + unsigned getDeclCXXMethodAbbrev() const { return DeclCXXMethodAbbrev; } + + unsigned getDeclRefExprAbbrev() const { return DeclRefExprAbbrev; } + unsigned getCharacterLiteralAbbrev() const { return CharacterLiteralAbbrev; } + unsigned getIntegerLiteralAbbrev() const { return IntegerLiteralAbbrev; } + unsigned getExprImplicitCastAbbrev() const { return ExprImplicitCastAbbrev; } + + bool hasChain() const { return Chain; } + ASTReader *getChain() const { return Chain; } + + // ASTDeserializationListener implementation + void ReaderInitialized(ASTReader *Reader) override; + void IdentifierRead(serialization::IdentID ID, IdentifierInfo *II) override; + void MacroRead(serialization::MacroID ID, MacroInfo *MI) override; + void TypeRead(serialization::TypeIdx Idx, QualType T) override; + void SelectorRead(serialization::SelectorID ID, Selector Sel) override; + void MacroDefinitionRead(serialization::PreprocessedEntityID ID, + MacroDefinitionRecord *MD) override; + void ModuleRead(serialization::SubmoduleID ID, Module *Mod) override; + + // ASTMutationListener implementation. + void CompletedTagDefinition(const TagDecl *D) override; + void AddedVisibleDecl(const DeclContext *DC, const Decl *D) override; + void AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D) override; + void ResolvedExceptionSpec(const FunctionDecl *FD) override; + void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) override; + void ResolvedOperatorDelete(const CXXDestructorDecl *DD, + const FunctionDecl *Delete) override; + void CompletedImplicitDefinition(const FunctionDecl *D) override; + void StaticDataMemberInstantiated(const VarDecl *D) override; + void FunctionDefinitionInstantiated(const FunctionDecl *D) override; + void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD, + const ObjCInterfaceDecl *IFD) override; + void DeclarationMarkedUsed(const Decl *D) override; + void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) override; + void RedefinedHiddenDefinition(const NamedDecl *D, Module *M) override; + void AddedAttributeToRecord(const Attr *Attr, + const RecordDecl *Record) override; +}; + +/// \brief AST and semantic-analysis consumer that generates a +/// precompiled header from the parsed source code. +class PCHGenerator : public SemaConsumer { + const Preprocessor &PP; + std::string OutputFile; + clang::Module *Module; + std::string isysroot; + Sema *SemaPtr; + std::shared_ptr<PCHBuffer> Buffer; + llvm::BitstreamWriter Stream; + ASTWriter Writer; + bool AllowASTWithErrors; + +protected: + ASTWriter &getWriter() { return Writer; } + const ASTWriter &getWriter() const { return Writer; } + SmallVectorImpl<char> &getPCH() const { return Buffer->Data; } + +public: + PCHGenerator( + const Preprocessor &PP, StringRef OutputFile, + clang::Module *Module, StringRef isysroot, + std::shared_ptr<PCHBuffer> Buffer, + ArrayRef<llvm::IntrusiveRefCntPtr<ModuleFileExtension>> Extensions, + bool AllowASTWithErrors = false, + bool IncludeTimestamps = true); + ~PCHGenerator() override; + void InitializeSema(Sema &S) override { SemaPtr = &S; } + void HandleTranslationUnit(ASTContext &Ctx) override; + ASTMutationListener *GetASTMutationListener() override; + ASTDeserializationListener *GetASTDeserializationListener() override; + bool hasEmittedPCH() const { return Buffer->IsComplete; } +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Serialization/ContinuousRangeMap.h b/contrib/llvm/tools/clang/include/clang/Serialization/ContinuousRangeMap.h new file mode 100644 index 0000000..244b01b --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Serialization/ContinuousRangeMap.h @@ -0,0 +1,139 @@ +//===--- ContinuousRangeMap.h - Map with int range as key -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ContinuousRangeMap class, which is a highly +// specialized container used by serialization. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SERIALIZATION_CONTINUOUSRANGEMAP_H +#define LLVM_CLANG_SERIALIZATION_CONTINUOUSRANGEMAP_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/SmallVector.h" +#include <algorithm> +#include <utility> + +namespace clang { + +/// \brief A map from continuous integer ranges to some value, with a very +/// specialized interface. +/// +/// CRM maps from integer ranges to values. The ranges are continuous, i.e. +/// where one ends, the next one begins. So if the map contains the stops I0-3, +/// the first range is from I0 to I1, the second from I1 to I2, the third from +/// I2 to I3 and the last from I3 to infinity. +/// +/// Ranges must be inserted in order. Inserting a new stop I4 into the map will +/// shrink the fourth range to I3 to I4 and add the new range I4 to inf. +template <typename Int, typename V, unsigned InitialCapacity> +class ContinuousRangeMap { +public: + typedef std::pair<Int, V> value_type; + typedef value_type &reference; + typedef const value_type &const_reference; + typedef value_type *pointer; + typedef const value_type *const_pointer; + +private: + typedef SmallVector<value_type, InitialCapacity> Representation; + Representation Rep; + + struct Compare { + bool operator ()(const_reference L, Int R) const { + return L.first < R; + } + bool operator ()(Int L, const_reference R) const { + return L < R.first; + } + bool operator ()(Int L, Int R) const { + return L < R; + } + bool operator ()(const_reference L, const_reference R) const { + return L.first < R.first; + } + }; + +public: + void insert(const value_type &Val) { + if (!Rep.empty() && Rep.back() == Val) + return; + + assert((Rep.empty() || Rep.back().first < Val.first) && + "Must insert keys in order."); + Rep.push_back(Val); + } + + void insertOrReplace(const value_type &Val) { + iterator I = std::lower_bound(Rep.begin(), Rep.end(), Val, Compare()); + if (I != Rep.end() && I->first == Val.first) { + I->second = Val.second; + return; + } + + Rep.insert(I, Val); + } + + typedef typename Representation::iterator iterator; + typedef typename Representation::const_iterator const_iterator; + + iterator begin() { return Rep.begin(); } + iterator end() { return Rep.end(); } + const_iterator begin() const { return Rep.begin(); } + const_iterator end() const { return Rep.end(); } + + iterator find(Int K) { + iterator I = std::upper_bound(Rep.begin(), Rep.end(), K, Compare()); + // I points to the first entry with a key > K, which is the range that + // follows the one containing K. + if (I == Rep.begin()) + return Rep.end(); + --I; + return I; + } + const_iterator find(Int K) const { + return const_cast<ContinuousRangeMap*>(this)->find(K); + } + + reference back() { return Rep.back(); } + const_reference back() const { return Rep.back(); } + + /// \brief An object that helps properly build a continuous range map + /// from a set of values. + class Builder { + ContinuousRangeMap &Self; + + Builder(const Builder&) = delete; + Builder &operator=(const Builder&) = delete; + + public: + explicit Builder(ContinuousRangeMap &Self) : Self(Self) { } + + ~Builder() { + std::sort(Self.Rep.begin(), Self.Rep.end(), Compare()); + std::unique(Self.Rep.begin(), Self.Rep.end(), + [](const_reference A, const_reference B) { + // FIXME: we should not allow any duplicate keys, but there are a lot of + // duplicate 0 -> 0 mappings to remove first. + assert((A == B || A.first != B.first) && + "ContinuousRangeMap::Builder given non-unique keys"); + return A == B; + }); + } + + void insert(const value_type &Val) { + Self.Rep.push_back(Val); + } + }; + friend class Builder; +}; + +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Serialization/GlobalModuleIndex.h b/contrib/llvm/tools/clang/include/clang/Serialization/GlobalModuleIndex.h new file mode 100644 index 0000000..0f14eca --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Serialization/GlobalModuleIndex.h @@ -0,0 +1,207 @@ +//===--- GlobalModuleIndex.h - Global Module Index --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the GlobalModuleIndex class, which manages a global index +// containing all of the identifiers known to the various modules within a given +// subdirectory of the module cache. It is used to improve the performance of +// queries such as "do any modules know about this identifier?" +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_SERIALIZATION_GLOBALMODULEINDEX_H +#define LLVM_CLANG_SERIALIZATION_GLOBALMODULEINDEX_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include <memory> +#include <utility> + +namespace llvm { +class BitstreamCursor; +class MemoryBuffer; +} + +namespace clang { + +class DirectoryEntry; +class FileEntry; +class FileManager; +class IdentifierIterator; +class PCHContainerOperations; +class PCHContainerReader; + +namespace serialization { + class ModuleFile; +} + +using llvm::SmallVector; +using llvm::SmallVectorImpl; +using llvm::StringRef; +using serialization::ModuleFile; + +/// \brief A global index for a set of module files, providing information about +/// the identifiers within those module files. +/// +/// The global index is an aid for name lookup into modules, offering a central +/// place where one can look for identifiers determine which +/// module files contain any information about that identifier. This +/// allows the client to restrict the search to only those module files known +/// to have a information about that identifier, improving performance. Moreover, +/// the global module index may know about module files that have not been +/// imported, and can be queried to determine which modules the current +/// translation could or should load to fix a problem. +class GlobalModuleIndex { + /// \brief Buffer containing the index file, which is lazily accessed so long + /// as the global module index is live. + std::unique_ptr<llvm::MemoryBuffer> Buffer; + + /// \brief The hash table. + /// + /// This pointer actually points to a IdentifierIndexTable object, + /// but that type is only accessible within the implementation of + /// GlobalModuleIndex. + void *IdentifierIndex; + + /// \brief Information about a given module file. + struct ModuleInfo { + ModuleInfo() : File(), Size(), ModTime() { } + + /// \brief The module file, once it has been resolved. + ModuleFile *File; + + /// \brief The module file name. + std::string FileName; + + /// \brief Size of the module file at the time the global index was built. + off_t Size; + + /// \brief Modification time of the module file at the time the global + /// index was built. + time_t ModTime; + + /// \brief The module IDs on which this module directly depends. + /// FIXME: We don't really need a vector here. + llvm::SmallVector<unsigned, 4> Dependencies; + }; + + /// \brief A mapping from module IDs to information about each module. + /// + /// This vector may have gaps, if module files have been removed or have + /// been updated since the index was built. A gap is indicated by an empty + /// file name. + llvm::SmallVector<ModuleInfo, 16> Modules; + + /// \brief Lazily-populated mapping from module files to their + /// corresponding index into the \c Modules vector. + llvm::DenseMap<ModuleFile *, unsigned> ModulesByFile; + + /// \brief The set of modules that have not yet been resolved. + /// + /// The string is just the name of the module itself, which maps to the + /// module ID. + llvm::StringMap<unsigned> UnresolvedModules; + + /// \brief The number of identifier lookups we performed. + unsigned NumIdentifierLookups; + + /// \brief The number of identifier lookup hits, where we recognize the + /// identifier. + unsigned NumIdentifierLookupHits; + + /// \brief Internal constructor. Use \c readIndex() to read an index. + explicit GlobalModuleIndex(std::unique_ptr<llvm::MemoryBuffer> Buffer, + llvm::BitstreamCursor Cursor); + + GlobalModuleIndex(const GlobalModuleIndex &) = delete; + GlobalModuleIndex &operator=(const GlobalModuleIndex &) = delete; + +public: + ~GlobalModuleIndex(); + + /// \brief An error code returned when trying to read an index. + enum ErrorCode { + /// \brief No error occurred. + EC_None, + /// \brief No index was found. + EC_NotFound, + /// \brief Some other process is currently building the index; it is not + /// available yet. + EC_Building, + /// \brief There was an unspecified I/O error reading or writing the index. + EC_IOError + }; + + /// \brief Read a global index file for the given directory. + /// + /// \param Path The path to the specific module cache where the module files + /// for the intended configuration reside. + /// + /// \returns A pair containing the global module index (if it exists) and + /// the error code. + static std::pair<GlobalModuleIndex *, ErrorCode> + readIndex(StringRef Path); + + /// \brief Returns an iterator for identifiers stored in the index table. + /// + /// The caller accepts ownership of the returned object. + IdentifierIterator *createIdentifierIterator() const; + + /// \brief Retrieve the set of modules that have up-to-date indexes. + /// + /// \param ModuleFiles Will be populated with the set of module files that + /// have been indexed. + void getKnownModules(SmallVectorImpl<ModuleFile *> &ModuleFiles); + + /// \brief Retrieve the set of module files on which the given module file + /// directly depends. + void getModuleDependencies(ModuleFile *File, + SmallVectorImpl<ModuleFile *> &Dependencies); + + /// \brief A set of module files in which we found a result. + typedef llvm::SmallPtrSet<ModuleFile *, 4> HitSet; + + /// \brief Look for all of the module files with information about the given + /// identifier, e.g., a global function, variable, or type with that name. + /// + /// \param Name The identifier to look for. + /// + /// \param Hits Will be populated with the set of module files that have + /// information about this name. + /// + /// \returns true if the identifier is known to the index, false otherwise. + bool lookupIdentifier(StringRef Name, HitSet &Hits); + + /// \brief Note that the given module file has been loaded. + /// + /// \returns false if the global module index has information about this + /// module file, and true otherwise. + bool loadedModuleFile(ModuleFile *File); + + /// \brief Print statistics to standard error. + void printStats(); + + /// \brief Print debugging view to standard error. + void dump(); + + /// \brief Write a global index into the given + /// + /// \param FileMgr The file manager to use to load module files. + /// \param PCHContainerRdr - The PCHContainerOperations to use for loading and + /// creating modules. + /// \param Path The path to the directory containing module files, into + /// which the global index will be written. + static ErrorCode writeIndex(FileManager &FileMgr, + const PCHContainerReader &PCHContainerRdr, + StringRef Path); +}; +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Serialization/Module.h b/contrib/llvm/tools/clang/include/clang/Serialization/Module.h new file mode 100644 index 0000000..d6d16a0 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Serialization/Module.h @@ -0,0 +1,475 @@ +//===--- Module.h - Module description --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Module class, which describes a module that has +// been loaded from an AST file. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SERIALIZATION_MODULE_H +#define LLVM_CLANG_SERIALIZATION_MODULE_H + +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Serialization/ASTBitCodes.h" +#include "clang/Serialization/ContinuousRangeMap.h" +#include "clang/Serialization/ModuleFileExtension.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Support/Endian.h" +#include <memory> +#include <string> + +namespace llvm { +template <typename Info> class OnDiskChainedHashTable; +template <typename Info> class OnDiskIterableChainedHashTable; +} + +namespace clang { + +class DeclContext; +class Module; + +namespace serialization { + +namespace reader { + class ASTDeclContextNameLookupTrait; +} + +/// \brief Specifies the kind of module that has been loaded. +enum ModuleKind { + MK_ImplicitModule, ///< File is an implicitly-loaded module. + MK_ExplicitModule, ///< File is an explicitly-loaded module. + MK_PCH, ///< File is a PCH file treated as such. + MK_Preamble, ///< File is a PCH file treated as the preamble. + MK_MainFile ///< File is a PCH file treated as the actual main file. +}; + +/// \brief The input file that has been loaded from this AST file, along with +/// bools indicating whether this was an overridden buffer or if it was +/// out-of-date or not-found. +class InputFile { + enum { + Overridden = 1, + OutOfDate = 2, + NotFound = 3 + }; + llvm::PointerIntPair<const FileEntry *, 2, unsigned> Val; + +public: + InputFile() {} + InputFile(const FileEntry *File, + bool isOverridden = false, bool isOutOfDate = false) { + assert(!(isOverridden && isOutOfDate) && + "an overridden cannot be out-of-date"); + unsigned intVal = 0; + if (isOverridden) + intVal = Overridden; + else if (isOutOfDate) + intVal = OutOfDate; + Val.setPointerAndInt(File, intVal); + } + + static InputFile getNotFound() { + InputFile File; + File.Val.setInt(NotFound); + return File; + } + + const FileEntry *getFile() const { return Val.getPointer(); } + bool isOverridden() const { return Val.getInt() == Overridden; } + bool isOutOfDate() const { return Val.getInt() == OutOfDate; } + bool isNotFound() const { return Val.getInt() == NotFound; } +}; + +typedef unsigned ASTFileSignature; + +/// \brief Information about a module that has been loaded by the ASTReader. +/// +/// Each instance of the Module class corresponds to a single AST file, which +/// may be a precompiled header, precompiled preamble, a module, or an AST file +/// of some sort loaded as the main file, all of which are specific formulations +/// of the general notion of a "module". A module may depend on any number of +/// other modules. +class ModuleFile { +public: + ModuleFile(ModuleKind Kind, unsigned Generation); + ~ModuleFile(); + + // === General information === + + /// \brief The index of this module in the list of modules. + unsigned Index; + + /// \brief The type of this module. + ModuleKind Kind; + + /// \brief The file name of the module file. + std::string FileName; + + /// \brief The name of the module. + std::string ModuleName; + + /// \brief The base directory of the module. + std::string BaseDirectory; + + std::string getTimestampFilename() const { + return FileName + ".timestamp"; + } + + /// \brief The original source file name that was used to build the + /// primary AST file, which may have been modified for + /// relocatable-pch support. + std::string OriginalSourceFileName; + + /// \brief The actual original source file name that was used to + /// build this AST file. + std::string ActualOriginalSourceFileName; + + /// \brief The file ID for the original source file that was used to + /// build this AST file. + FileID OriginalSourceFileID; + + /// \brief The directory that the PCH was originally created in. Used to + /// allow resolving headers even after headers+PCH was moved to a new path. + std::string OriginalDir; + + std::string ModuleMapPath; + + /// \brief Whether this precompiled header is a relocatable PCH file. + bool RelocatablePCH; + + /// \brief Whether timestamps are included in this module file. + bool HasTimestamps; + + /// \brief The file entry for the module file. + const FileEntry *File; + + /// \brief The signature of the module file, which may be used along with size + /// and modification time to identify this particular file. + ASTFileSignature Signature; + + /// \brief Whether this module has been directly imported by the + /// user. + bool DirectlyImported; + + /// \brief The generation of which this module file is a part. + unsigned Generation; + + /// \brief The memory buffer that stores the data associated with + /// this AST file. + std::unique_ptr<llvm::MemoryBuffer> Buffer; + + /// \brief The size of this file, in bits. + uint64_t SizeInBits; + + /// \brief The global bit offset (or base) of this module + uint64_t GlobalBitOffset; + + /// \brief The bitstream reader from which we'll read the AST file. + llvm::BitstreamReader StreamFile; + + /// \brief The main bitstream cursor for the main block. + llvm::BitstreamCursor Stream; + + /// \brief The source location where the module was explicitly or implicitly + /// imported in the local translation unit. + /// + /// If module A depends on and imports module B, both modules will have the + /// same DirectImportLoc, but different ImportLoc (B's ImportLoc will be a + /// source location inside module A). + /// + /// WARNING: This is largely useless. It doesn't tell you when a module was + /// made visible, just when the first submodule of that module was imported. + SourceLocation DirectImportLoc; + + /// \brief The source location where this module was first imported. + SourceLocation ImportLoc; + + /// \brief The first source location in this module. + SourceLocation FirstLoc; + + /// The list of extension readers that are attached to this module + /// file. + std::vector<std::unique_ptr<ModuleFileExtensionReader>> ExtensionReaders; + + // === Input Files === + /// \brief The cursor to the start of the input-files block. + llvm::BitstreamCursor InputFilesCursor; + + /// \brief Offsets for all of the input file entries in the AST file. + const llvm::support::unaligned_uint64_t *InputFileOffsets; + + /// \brief The input files that have been loaded from this AST file. + std::vector<InputFile> InputFilesLoaded; + + /// \brief If non-zero, specifies the time when we last validated input + /// files. Zero means we never validated them. + /// + /// The time is specified in seconds since the start of the Epoch. + uint64_t InputFilesValidationTimestamp; + + // === Source Locations === + + /// \brief Cursor used to read source location entries. + llvm::BitstreamCursor SLocEntryCursor; + + /// \brief The number of source location entries in this AST file. + unsigned LocalNumSLocEntries; + + /// \brief The base ID in the source manager's view of this module. + int SLocEntryBaseID; + + /// \brief The base offset in the source manager's view of this module. + unsigned SLocEntryBaseOffset; + + /// \brief Offsets for all of the source location entries in the + /// AST file. + const uint32_t *SLocEntryOffsets; + + /// \brief SLocEntries that we're going to preload. + SmallVector<uint64_t, 4> PreloadSLocEntries; + + /// \brief Remapping table for source locations in this module. + ContinuousRangeMap<uint32_t, int, 2> SLocRemap; + + // === Identifiers === + + /// \brief The number of identifiers in this AST file. + unsigned LocalNumIdentifiers; + + /// \brief Offsets into the identifier table data. + /// + /// This array is indexed by the identifier ID (-1), and provides + /// the offset into IdentifierTableData where the string data is + /// stored. + const uint32_t *IdentifierOffsets; + + /// \brief Base identifier ID for identifiers local to this module. + serialization::IdentID BaseIdentifierID; + + /// \brief Remapping table for identifier IDs in this module. + ContinuousRangeMap<uint32_t, int, 2> IdentifierRemap; + + /// \brief Actual data for the on-disk hash table of identifiers. + /// + /// This pointer points into a memory buffer, where the on-disk hash + /// table for identifiers actually lives. + const char *IdentifierTableData; + + /// \brief A pointer to an on-disk hash table of opaque type + /// IdentifierHashTable. + void *IdentifierLookupTable; + + /// \brief Offsets of identifiers that we're going to preload within + /// IdentifierTableData. + std::vector<unsigned> PreloadIdentifierOffsets; + + // === Macros === + + /// \brief The cursor to the start of the preprocessor block, which stores + /// all of the macro definitions. + llvm::BitstreamCursor MacroCursor; + + /// \brief The number of macros in this AST file. + unsigned LocalNumMacros; + + /// \brief Offsets of macros in the preprocessor block. + /// + /// This array is indexed by the macro ID (-1), and provides + /// the offset into the preprocessor block where macro definitions are + /// stored. + const uint32_t *MacroOffsets; + + /// \brief Base macro ID for macros local to this module. + serialization::MacroID BaseMacroID; + + /// \brief Remapping table for macro IDs in this module. + ContinuousRangeMap<uint32_t, int, 2> MacroRemap; + + /// \brief The offset of the start of the set of defined macros. + uint64_t MacroStartOffset; + + // === Detailed PreprocessingRecord === + + /// \brief The cursor to the start of the (optional) detailed preprocessing + /// record block. + llvm::BitstreamCursor PreprocessorDetailCursor; + + /// \brief The offset of the start of the preprocessor detail cursor. + uint64_t PreprocessorDetailStartOffset; + + /// \brief Base preprocessed entity ID for preprocessed entities local to + /// this module. + serialization::PreprocessedEntityID BasePreprocessedEntityID; + + /// \brief Remapping table for preprocessed entity IDs in this module. + ContinuousRangeMap<uint32_t, int, 2> PreprocessedEntityRemap; + + const PPEntityOffset *PreprocessedEntityOffsets; + unsigned NumPreprocessedEntities; + + // === Header search information === + + /// \brief The number of local HeaderFileInfo structures. + unsigned LocalNumHeaderFileInfos; + + /// \brief Actual data for the on-disk hash table of header file + /// information. + /// + /// This pointer points into a memory buffer, where the on-disk hash + /// table for header file information actually lives. + const char *HeaderFileInfoTableData; + + /// \brief The on-disk hash table that contains information about each of + /// the header files. + void *HeaderFileInfoTable; + + // === Submodule information === + /// \brief The number of submodules in this module. + unsigned LocalNumSubmodules; + + /// \brief Base submodule ID for submodules local to this module. + serialization::SubmoduleID BaseSubmoduleID; + + /// \brief Remapping table for submodule IDs in this module. + ContinuousRangeMap<uint32_t, int, 2> SubmoduleRemap; + + // === Selectors === + + /// \brief The number of selectors new to this file. + /// + /// This is the number of entries in SelectorOffsets. + unsigned LocalNumSelectors; + + /// \brief Offsets into the selector lookup table's data array + /// where each selector resides. + const uint32_t *SelectorOffsets; + + /// \brief Base selector ID for selectors local to this module. + serialization::SelectorID BaseSelectorID; + + /// \brief Remapping table for selector IDs in this module. + ContinuousRangeMap<uint32_t, int, 2> SelectorRemap; + + /// \brief A pointer to the character data that comprises the selector table + /// + /// The SelectorOffsets table refers into this memory. + const unsigned char *SelectorLookupTableData; + + /// \brief A pointer to an on-disk hash table of opaque type + /// ASTSelectorLookupTable. + /// + /// This hash table provides the IDs of all selectors, and the associated + /// instance and factory methods. + void *SelectorLookupTable; + + // === Declarations === + + /// DeclsCursor - This is a cursor to the start of the DECLS_BLOCK block. It + /// has read all the abbreviations at the start of the block and is ready to + /// jump around with these in context. + llvm::BitstreamCursor DeclsCursor; + + /// \brief The number of declarations in this AST file. + unsigned LocalNumDecls; + + /// \brief Offset of each declaration within the bitstream, indexed + /// by the declaration ID (-1). + const DeclOffset *DeclOffsets; + + /// \brief Base declaration ID for declarations local to this module. + serialization::DeclID BaseDeclID; + + /// \brief Remapping table for declaration IDs in this module. + ContinuousRangeMap<uint32_t, int, 2> DeclRemap; + + /// \brief Mapping from the module files that this module file depends on + /// to the base declaration ID for that module as it is understood within this + /// module. + /// + /// This is effectively a reverse global-to-local mapping for declaration + /// IDs, so that we can interpret a true global ID (for this translation unit) + /// as a local ID (for this module file). + llvm::DenseMap<ModuleFile *, serialization::DeclID> GlobalToLocalDeclIDs; + + /// \brief The number of C++ base specifier sets in this AST file. + unsigned LocalNumCXXBaseSpecifiers; + + /// \brief Offset of each C++ base specifier set within the bitstream, + /// indexed by the C++ base specifier set ID (-1). + const uint32_t *CXXBaseSpecifiersOffsets; + + /// \brief The number of C++ ctor initializer lists in this AST file. + unsigned LocalNumCXXCtorInitializers; + + /// \brief Offset of each C++ ctor initializer list within the bitstream, + /// indexed by the C++ ctor initializer list ID minus 1. + const uint32_t *CXXCtorInitializersOffsets; + + /// \brief Array of file-level DeclIDs sorted by file. + const serialization::DeclID *FileSortedDecls; + unsigned NumFileSortedDecls; + + /// \brief Array of category list location information within this + /// module file, sorted by the definition ID. + const serialization::ObjCCategoriesInfo *ObjCCategoriesMap; + + /// \brief The number of redeclaration info entries in ObjCCategoriesMap. + unsigned LocalNumObjCCategoriesInMap; + + /// \brief The Objective-C category lists for categories known to this + /// module. + SmallVector<uint64_t, 1> ObjCCategories; + + // === Types === + + /// \brief The number of types in this AST file. + unsigned LocalNumTypes; + + /// \brief Offset of each type within the bitstream, indexed by the + /// type ID, or the representation of a Type*. + const uint32_t *TypeOffsets; + + /// \brief Base type ID for types local to this module as represented in + /// the global type ID space. + serialization::TypeID BaseTypeIndex; + + /// \brief Remapping table for type IDs in this module. + ContinuousRangeMap<uint32_t, int, 2> TypeRemap; + + // === Miscellaneous === + + /// \brief Diagnostic IDs and their mappings that the user changed. + SmallVector<uint64_t, 8> PragmaDiagMappings; + + /// \brief List of modules which depend on this module + llvm::SetVector<ModuleFile *> ImportedBy; + + /// \brief List of modules which this module depends on + llvm::SetVector<ModuleFile *> Imports; + + /// \brief Determine whether this module was directly imported at + /// any point during translation. + bool isDirectlyImported() const { return DirectlyImported; } + + /// \brief Is this a module file for a module (rather than a PCH or similar). + bool isModule() const { + return Kind == MK_ImplicitModule || Kind == MK_ExplicitModule; + } + + /// \brief Dump debugging output for this module. + void dump(); +}; + +} // end namespace serialization + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Serialization/ModuleFileExtension.h b/contrib/llvm/tools/clang/include/clang/Serialization/ModuleFileExtension.h new file mode 100644 index 0000000..ba2e2fd --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Serialization/ModuleFileExtension.h @@ -0,0 +1,149 @@ +//===-- ModuleFileExtension.h - Module File Extensions ----------*- 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_SERIALIZATION_MODULEFILEEXTENSION_H +#define LLVM_CLANG_SERIALIZATION_MODULEFILEEXTENSION_H + +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include <memory> +#include <string> + +namespace llvm { +class BitstreamCursor; +class BitstreamWriter; +class hash_code; +class raw_ostream; +} + +namespace clang { + +class ASTReader; +class ASTWriter; +class Sema; + +namespace serialization { + class ModuleFile; +} // end namespace serialization + +/// Metadata for a module file extension. +struct ModuleFileExtensionMetadata { + /// The name used to identify this particular extension block within + /// the resulting module file. It should be unique to the particular + /// extension, because this name will be used to match the name of + /// an extension block to the appropriate reader. + std::string BlockName; + + /// The major version of the extension data. + unsigned MajorVersion; + + /// The minor version of the extension data. + unsigned MinorVersion; + + /// A string containing additional user information that will be + /// stored with the metadata. + std::string UserInfo; +}; + +class ModuleFileExtensionReader; +class ModuleFileExtensionWriter; + +/// An abstract superclass that describes a custom extension to the +/// module/precompiled header file format. +/// +/// A module file extension can introduce additional information into +/// compiled module files (.pcm) and precompiled headers (.pch) via a +/// custom writer that can then be accessed via a custom reader when +/// the module file or precompiled header is loaded. +class ModuleFileExtension : public llvm::RefCountedBase<ModuleFileExtension> { +public: + virtual ~ModuleFileExtension(); + + /// Retrieves the metadata for this module file extension. + virtual ModuleFileExtensionMetadata getExtensionMetadata() const = 0; + + /// Hash information about the presence of this extension into the + /// module hash code. + /// + /// The module hash code is used to distinguish different variants + /// of a module that are incompatible. If the presence, absence, or + /// version of the module file extension should force the creation + /// of a separate set of module files, override this method to + /// combine that distinguishing information into the module hash + /// code. + /// + /// The default implementation of this function simply returns the + /// hash code as given, so the presence/absence of this extension + /// does not distinguish module files. + virtual llvm::hash_code hashExtension(llvm::hash_code c) const; + + /// Create a new module file extension writer, which will be + /// responsible for writing the extension contents into a particular + /// module file. + virtual std::unique_ptr<ModuleFileExtensionWriter> + createExtensionWriter(ASTWriter &Writer) = 0; + + /// Create a new module file extension reader, given the + /// metadata read from the block and the cursor into the extension + /// block. + /// + /// May return null to indicate that an extension block with the + /// given metadata cannot be read. + virtual std::unique_ptr<ModuleFileExtensionReader> + createExtensionReader(const ModuleFileExtensionMetadata &Metadata, + ASTReader &Reader, serialization::ModuleFile &Mod, + const llvm::BitstreamCursor &Stream) = 0; +}; + +/// Abstract base class that writes a module file extension block into +/// a module file. +class ModuleFileExtensionWriter { + ModuleFileExtension *Extension; + +protected: + ModuleFileExtensionWriter(ModuleFileExtension *Extension) + : Extension(Extension) { } + +public: + virtual ~ModuleFileExtensionWriter(); + + /// Retrieve the module file extension with which this writer is + /// associated. + ModuleFileExtension *getExtension() const { return Extension; } + + /// Write the contents of the extension block into the given bitstream. + /// + /// Responsible for writing the contents of the extension into the + /// given stream. All of the contents should be written into custom + /// records with IDs >= FIRST_EXTENSION_RECORD_ID. + virtual void writeExtensionContents(Sema &SemaRef, + llvm::BitstreamWriter &Stream) = 0; +}; + +/// Abstract base class that reads a module file extension block from +/// a module file. +/// +/// Subclasses +class ModuleFileExtensionReader { + ModuleFileExtension *Extension; + +protected: + ModuleFileExtensionReader(ModuleFileExtension *Extension) + : Extension(Extension) { } + +public: + /// Retrieve the module file extension with which this reader is + /// associated. + ModuleFileExtension *getExtension() const { return Extension; } + + virtual ~ModuleFileExtensionReader(); +}; + +} // end namespace clang + +#endif // LLVM_CLANG_FRONTEND_MODULEFILEEXTENSION_H diff --git a/contrib/llvm/tools/clang/include/clang/Serialization/ModuleManager.h b/contrib/llvm/tools/clang/include/clang/Serialization/ModuleManager.h new file mode 100644 index 0000000..08e7d40 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Serialization/ModuleManager.h @@ -0,0 +1,289 @@ +//===--- ModuleManager.cpp - Module Manager ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ModuleManager class, which manages a set of loaded +// modules for the ASTReader. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SERIALIZATION_MODULEMANAGER_H +#define LLVM_CLANG_SERIALIZATION_MODULEMANAGER_H + +#include "clang/Basic/FileManager.h" +#include "clang/Serialization/Module.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" + +namespace clang { + +class GlobalModuleIndex; +class ModuleMap; +class PCHContainerReader; + +namespace serialization { + +/// \brief Manages the set of modules loaded by an AST reader. +class ModuleManager { + /// \brief The chain of AST files, in the order in which we started to load + /// them (this order isn't really useful for anything). + SmallVector<ModuleFile *, 2> Chain; + + /// \brief The chain of non-module PCH files. The first entry is the one named + /// by the user, the last one is the one that doesn't depend on anything + /// further. + SmallVector<ModuleFile *, 2> PCHChain; + + // \brief The roots of the dependency DAG of AST files. This is used + // to implement short-circuiting logic when running DFS over the dependencies. + SmallVector<ModuleFile *, 2> Roots; + + /// \brief All loaded modules, indexed by name. + llvm::DenseMap<const FileEntry *, ModuleFile *> Modules; + + /// \brief FileManager that handles translating between filenames and + /// FileEntry *. + FileManager &FileMgr; + + /// \brief Knows how to unwrap module containers. + const PCHContainerReader &PCHContainerRdr; + + /// \brief A lookup of in-memory (virtual file) buffers + llvm::DenseMap<const FileEntry *, std::unique_ptr<llvm::MemoryBuffer>> + InMemoryBuffers; + + /// \brief The visitation order. + SmallVector<ModuleFile *, 4> VisitOrder; + + /// \brief The list of module files that both we and the global module index + /// know about. + /// + /// Either the global index or the module manager may have modules that the + /// other does not know about, because the global index can be out-of-date + /// (in which case the module manager could have modules it does not) and + /// this particular translation unit might not have loaded all of the modules + /// known to the global index. + SmallVector<ModuleFile *, 4> ModulesInCommonWithGlobalIndex; + + /// \brief The global module index, if one is attached. + /// + /// The global module index will actually be owned by the ASTReader; this is + /// just an non-owning pointer. + GlobalModuleIndex *GlobalIndex; + + /// \brief State used by the "visit" operation to avoid malloc traffic in + /// calls to visit(). + struct VisitState { + explicit VisitState(unsigned N) + : VisitNumber(N, 0), NextVisitNumber(1), NextState(nullptr) + { + Stack.reserve(N); + } + + ~VisitState() { + delete NextState; + } + + /// \brief The stack used when marking the imports of a particular module + /// as not-to-be-visited. + SmallVector<ModuleFile *, 4> Stack; + + /// \brief The visit number of each module file, which indicates when + /// this module file was last visited. + SmallVector<unsigned, 4> VisitNumber; + + /// \brief The next visit number to use to mark visited module files. + unsigned NextVisitNumber; + + /// \brief The next visit state. + VisitState *NextState; + }; + + /// \brief The first visit() state in the chain. + VisitState *FirstVisitState; + + VisitState *allocateVisitState(); + void returnVisitState(VisitState *State); + +public: + typedef SmallVectorImpl<ModuleFile*>::iterator ModuleIterator; + typedef SmallVectorImpl<ModuleFile*>::const_iterator ModuleConstIterator; + typedef SmallVectorImpl<ModuleFile*>::reverse_iterator ModuleReverseIterator; + typedef std::pair<uint32_t, StringRef> ModuleOffset; + + explicit ModuleManager(FileManager &FileMgr, + const PCHContainerReader &PCHContainerRdr); + ~ModuleManager(); + + /// \brief Forward iterator to traverse all loaded modules. + ModuleIterator begin() { return Chain.begin(); } + /// \brief Forward iterator end-point to traverse all loaded modules + ModuleIterator end() { return Chain.end(); } + + /// \brief Const forward iterator to traverse all loaded modules. + ModuleConstIterator begin() const { return Chain.begin(); } + /// \brief Const forward iterator end-point to traverse all loaded modules + ModuleConstIterator end() const { return Chain.end(); } + + /// \brief Reverse iterator to traverse all loaded modules. + ModuleReverseIterator rbegin() { return Chain.rbegin(); } + /// \brief Reverse iterator end-point to traverse all loaded modules. + ModuleReverseIterator rend() { return Chain.rend(); } + + /// \brief A range covering the PCH and preamble module files loaded. + llvm::iterator_range<ModuleConstIterator> pch_modules() const { + return llvm::make_range(PCHChain.begin(), PCHChain.end()); + } + + /// \brief Returns the primary module associated with the manager, that is, + /// the first module loaded + ModuleFile &getPrimaryModule() { return *Chain[0]; } + + /// \brief Returns the primary module associated with the manager, that is, + /// the first module loaded. + ModuleFile &getPrimaryModule() const { return *Chain[0]; } + + /// \brief Returns the module associated with the given index + ModuleFile &operator[](unsigned Index) const { return *Chain[Index]; } + + /// \brief Returns the module associated with the given name + ModuleFile *lookup(StringRef Name); + + /// \brief Returns the module associated with the given module file. + ModuleFile *lookup(const FileEntry *File); + + /// \brief Returns the in-memory (virtual file) buffer with the given name + std::unique_ptr<llvm::MemoryBuffer> lookupBuffer(StringRef Name); + + /// \brief Number of modules loaded + unsigned size() const { return Chain.size(); } + + /// \brief The result of attempting to add a new module. + enum AddModuleResult { + /// \brief The module file had already been loaded. + AlreadyLoaded, + /// \brief The module file was just loaded in response to this call. + NewlyLoaded, + /// \brief The module file is missing. + Missing, + /// \brief The module file is out-of-date. + OutOfDate + }; + + typedef ASTFileSignature(*ASTFileSignatureReader)(llvm::BitstreamReader &); + + /// \brief Attempts to create a new module and add it to the list of known + /// modules. + /// + /// \param FileName The file name of the module to be loaded. + /// + /// \param Type The kind of module being loaded. + /// + /// \param ImportLoc The location at which the module is imported. + /// + /// \param ImportedBy The module that is importing this module, or NULL if + /// this module is imported directly by the user. + /// + /// \param Generation The generation in which this module was loaded. + /// + /// \param ExpectedSize The expected size of the module file, used for + /// validation. This will be zero if unknown. + /// + /// \param ExpectedModTime The expected modification time of the module + /// file, used for validation. This will be zero if unknown. + /// + /// \param ExpectedSignature The expected signature of the module file, used + /// for validation. This will be zero if unknown. + /// + /// \param ReadSignature Reads the signature from an AST file without actually + /// loading it. + /// + /// \param Module A pointer to the module file if the module was successfully + /// loaded. + /// + /// \param ErrorStr Will be set to a non-empty string if any errors occurred + /// while trying to load the module. + /// + /// \return A pointer to the module that corresponds to this file name, + /// and a value indicating whether the module was loaded. + AddModuleResult addModule(StringRef FileName, ModuleKind Type, + SourceLocation ImportLoc, + ModuleFile *ImportedBy, unsigned Generation, + off_t ExpectedSize, time_t ExpectedModTime, + ASTFileSignature ExpectedSignature, + ASTFileSignatureReader ReadSignature, + ModuleFile *&Module, + std::string &ErrorStr); + + /// \brief Remove the given set of modules. + void removeModules(ModuleIterator first, ModuleIterator last, + llvm::SmallPtrSetImpl<ModuleFile *> &LoadedSuccessfully, + ModuleMap *modMap); + + /// \brief Add an in-memory buffer the list of known buffers + void addInMemoryBuffer(StringRef FileName, + std::unique_ptr<llvm::MemoryBuffer> Buffer); + + /// \brief Set the global module index. + void setGlobalIndex(GlobalModuleIndex *Index); + + /// \brief Notification from the AST reader that the given module file + /// has been "accepted", and will not (can not) be unloaded. + void moduleFileAccepted(ModuleFile *MF); + + /// \brief Visit each of the modules. + /// + /// This routine visits each of the modules, starting with the + /// "root" modules that no other loaded modules depend on, and + /// proceeding to the leaf modules, visiting each module only once + /// during the traversal. + /// + /// This traversal is intended to support various "lookup" + /// operations that can find data in any of the loaded modules. + /// + /// \param Visitor A visitor function that will be invoked with each + /// module. The return value must be convertible to bool; when false, the + /// visitation continues to modules that the current module depends on. When + /// true, the visitation skips any modules that the current module depends on. + /// + /// \param ModuleFilesHit If non-NULL, contains the set of module files + /// that we know we need to visit because the global module index told us to. + /// Any module that is known to both the global module index and the module + /// manager that is *not* in this set can be skipped. + void visit(llvm::function_ref<bool(ModuleFile &M)> Visitor, + llvm::SmallPtrSetImpl<ModuleFile *> *ModuleFilesHit = nullptr); + + /// \brief Attempt to resolve the given module file name to a file entry. + /// + /// \param FileName The name of the module file. + /// + /// \param ExpectedSize The size that the module file is expected to have. + /// If the actual size differs, the resolver should return \c true. + /// + /// \param ExpectedModTime The modification time that the module file is + /// expected to have. If the actual modification time differs, the resolver + /// should return \c true. + /// + /// \param File Will be set to the file if there is one, or null + /// otherwise. + /// + /// \returns True if a file exists but does not meet the size/ + /// modification time criteria, false if the file is either available and + /// suitable, or is missing. + bool lookupModuleFile(StringRef FileName, + off_t ExpectedSize, + time_t ExpectedModTime, + const FileEntry *&File); + + /// \brief View the graphviz representation of the module graph. + void viewGraph(); +}; + +} } // end namespace clang::serialization + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Serialization/SerializationDiagnostic.h b/contrib/llvm/tools/clang/include/clang/Serialization/SerializationDiagnostic.h new file mode 100644 index 0000000..d50422a --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Serialization/SerializationDiagnostic.h @@ -0,0 +1,28 @@ +//===--- SerializationDiagnostic.h - Serialization Diagnostics -*- 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_SERIALIZATION_SERIALIZATIONDIAGNOSTIC_H +#define LLVM_CLANG_SERIALIZATION_SERIALIZATIONDIAGNOSTIC_H + +#include "clang/Basic/Diagnostic.h" + +namespace clang { + namespace diag { + enum { +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\ + SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM, +#define SERIALIZATIONSTART +#include "clang/Basic/DiagnosticSerializationKinds.inc" +#undef DIAG + NUM_BUILTIN_SERIALIZATION_DIAGNOSTICS + }; + } // end namespace diag +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Checkers/CheckerBase.td b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Checkers/CheckerBase.td new file mode 100644 index 0000000..11f1e5d --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Checkers/CheckerBase.td @@ -0,0 +1,39 @@ +//===--- CheckerBase.td - Checker TableGen classes ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TableGen core definitions for checkers +// +//===----------------------------------------------------------------------===// + +class CheckerGroup<string name> { + string GroupName = name; +} +class InGroup<CheckerGroup G> { CheckerGroup Group = G; } + +class Package<string name> { + string PackageName = name; + bit Hidden = 0; + Package ParentPackage; + CheckerGroup Group; +} +class InPackage<Package P> { Package ParentPackage = P; } + +// All checkers are an indirect subclass of this. +class Checker<string name = ""> { + string CheckerName = name; + string DescFile; + string HelpText; + bit Hidden = 0; + Package ParentPackage; + CheckerGroup Group; +} + +class DescFile<string filename> { string DescFile = filename; } +class HelpText<string text> { string HelpText = text; } +class Hidden { bit Hidden = 1; } diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Checkers/ClangCheckers.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Checkers/ClangCheckers.h new file mode 100644 index 0000000..cf0a30a --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Checkers/ClangCheckers.h @@ -0,0 +1,22 @@ +//===--- ClangCheckers.h - Provides builtin checkers ------------*- 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_STATICANALYZER_CHECKERS_CLANGCHECKERS_H +#define LLVM_CLANG_STATICANALYZER_CHECKERS_CLANGCHECKERS_H + +namespace clang { +namespace ento { +class CheckerRegistry; + +void registerBuiltinCheckers(CheckerRegistry ®istry); + +} // end namespace ento +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h new file mode 100644 index 0000000..463f04a --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h @@ -0,0 +1,28 @@ +//==- LocalCheckers.h - Intra-Procedural+Flow-Sensitive Checkers -*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interface to call a set of intra-procedural (local) +// checkers that use flow/path-sensitive analyses to find bugs. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CHECKERS_LOCALCHECKERS_H +#define LLVM_CLANG_STATICANALYZER_CHECKERS_LOCALCHECKERS_H + +namespace clang { +namespace ento { + +class ExprEngine; + +void RegisterCallInliner(ExprEngine &Eng); + +} // end namespace ento +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h new file mode 100644 index 0000000..5850656 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h @@ -0,0 +1,234 @@ +//==-- ObjCRetainCount.h - Retain count summaries for Cocoa -------*- C++ -*--// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the core data structures for retain count "summaries" +// for Objective-C and Core Foundation APIs. These summaries are used +// by the static analyzer to summarize the retain/release effects of +// function and method calls. This drives a path-sensitive typestate +// analysis in the static analyzer, but can also potentially be used by +// other clients. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CHECKERS_OBJCRETAINCOUNT_H +#define LLVM_CLANG_STATICANALYZER_CHECKERS_OBJCRETAINCOUNT_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { +class FunctionDecl; +class ObjCMethodDecl; + +namespace ento { namespace objc_retain { + +/// An ArgEffect summarizes the retain count behavior on an argument or receiver +/// to a function or method. +enum ArgEffect { + /// There is no effect. + DoNothing, + + /// The argument is treated as if an -autorelease message had been sent to + /// the referenced object. + Autorelease, + + /// The argument is treated as if an -dealloc message had been sent to + /// the referenced object. + Dealloc, + + /// The argument has its reference count decreased by 1. This is as + /// if CFRelease has been called on the argument. + DecRef, + + /// The argument has its reference count decreased by 1. This is as + /// if a -release message has been sent to the argument. This differs + /// in behavior from DecRef when GC is enabled. + DecRefMsg, + + /// The argument has its reference count decreased by 1 to model + /// a transferred bridge cast under ARC. + DecRefBridgedTransferred, + + /// The argument has its reference count increased by 1. This is as + /// if a -retain message has been sent to the argument. This differs + /// in behavior from IncRef when GC is enabled. + IncRefMsg, + + /// The argument has its reference count increased by 1. This is as + /// if CFRetain has been called on the argument. + IncRef, + + /// The argument acts as if has been passed to CFMakeCollectable, which + /// transfers the object to the Garbage Collector under GC. + MakeCollectable, + + /// The argument is a pointer to a retain-counted object; on exit, the new + /// value of the pointer is a +0 value or NULL. + UnretainedOutParameter, + + /// The argument is a pointer to a retain-counted object; on exit, the new + /// value of the pointer is a +1 value or NULL. + RetainedOutParameter, + + /// The argument is treated as potentially escaping, meaning that + /// even when its reference count hits 0 it should be treated as still + /// possibly being alive as someone else *may* be holding onto the object. + MayEscape, + + /// All typestate tracking of the object ceases. This is usually employed + /// when the effect of the call is completely unknown. + StopTracking, + + /// All typestate tracking of the object ceases. Unlike StopTracking, + /// this is also enforced when the method body is inlined. + /// + /// In some cases, we obtain a better summary for this checker + /// by looking at the call site than by inlining the function. + /// Signifies that we should stop tracking the symbol even if + /// the function is inlined. + StopTrackingHard, + + /// Performs the combined functionality of DecRef and StopTrackingHard. + /// + /// The models the effect that the called function decrements the reference + /// count of the argument and all typestate tracking on that argument + /// should cease. + DecRefAndStopTrackingHard, + + /// Performs the combined functionality of DecRefMsg and StopTrackingHard. + /// + /// The models the effect that the called function decrements the reference + /// count of the argument and all typestate tracking on that argument + /// should cease. + DecRefMsgAndStopTrackingHard +}; + +/// RetEffect summarizes a call's retain/release behavior with respect +/// to its return value. +class RetEffect { +public: + enum Kind { + /// Indicates that no retain count information is tracked for + /// the return value. + NoRet, + /// Indicates that the returned value is an owned (+1) symbol. + OwnedSymbol, + /// Indicates that the returned value is an owned (+1) symbol and + /// that it should be treated as freshly allocated. + OwnedAllocatedSymbol, + /// Indicates that the returned value is an object with retain count + /// semantics but that it is not owned (+0). This is the default + /// for getters, etc. + NotOwnedSymbol, + /// Indicates that the object is not owned and controlled by the + /// Garbage collector. + GCNotOwnedSymbol, + /// Indicates that the return value is an owned object when the + /// receiver is also a tracked object. + OwnedWhenTrackedReceiver, + // Treat this function as returning a non-tracked symbol even if + // the function has been inlined. This is used where the call + // site summary is more presise than the summary indirectly produced + // by inlining the function + NoRetHard + }; + + /// Determines the object kind of a tracked object. + enum ObjKind { + /// Indicates that the tracked object is a CF object. This is + /// important between GC and non-GC code. + CF, + /// Indicates that the tracked object is an Objective-C object. + ObjC, + /// Indicates that the tracked object could be a CF or Objective-C object. + AnyObj + }; + +private: + Kind K; + ObjKind O; + + RetEffect(Kind k, ObjKind o = AnyObj) : K(k), O(o) {} + +public: + Kind getKind() const { return K; } + + ObjKind getObjKind() const { return O; } + + bool isOwned() const { + return K == OwnedSymbol || K == OwnedAllocatedSymbol || + K == OwnedWhenTrackedReceiver; + } + + bool notOwned() const { + return K == NotOwnedSymbol; + } + + bool operator==(const RetEffect &Other) const { + return K == Other.K && O == Other.O; + } + + static RetEffect MakeOwnedWhenTrackedReceiver() { + return RetEffect(OwnedWhenTrackedReceiver, ObjC); + } + + static RetEffect MakeOwned(ObjKind o, bool isAllocated = false) { + return RetEffect(isAllocated ? OwnedAllocatedSymbol : OwnedSymbol, o); + } + static RetEffect MakeNotOwned(ObjKind o) { + return RetEffect(NotOwnedSymbol, o); + } + static RetEffect MakeGCNotOwned() { + return RetEffect(GCNotOwnedSymbol, ObjC); + } + static RetEffect MakeNoRet() { + return RetEffect(NoRet); + } + static RetEffect MakeNoRetHard() { + return RetEffect(NoRetHard); + } +}; + +/// Encapsulates the retain count semantics on the arguments, return value, +/// and receiver (if any) of a function/method call. +/// +/// Note that construction of these objects is not highly efficient. That +/// is okay for clients where creating these objects isn't really a bottleneck. +/// The purpose of the API is to provide something simple. The actual +/// static analyzer checker that implements retain/release typestate +/// tracking uses something more efficient. +class CallEffects { + llvm::SmallVector<ArgEffect, 10> Args; + RetEffect Ret; + ArgEffect Receiver; + + CallEffects(const RetEffect &R) : Ret(R) {} + +public: + /// Returns the argument effects for a call. + ArrayRef<ArgEffect> getArgs() const { return Args; } + + /// Returns the effects on the receiver. + ArgEffect getReceiver() const { return Receiver; } + + /// Returns the effect on the return value. + RetEffect getReturnValue() const { return Ret; } + + /// Return the CallEfect for a given Objective-C method. + static CallEffects getEffect(const ObjCMethodDecl *MD); + + /// Return the CallEfect for a given C/C++ function. + static CallEffects getEffect(const FunctionDecl *FD); +}; + +}}} + +#endif + diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/Analyses.def b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/Analyses.def new file mode 100644 index 0000000..3355f4b --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/Analyses.def @@ -0,0 +1,57 @@ +//===-- Analyses.def - Metadata about Static Analyses -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the set of static analyses used by AnalysisConsumer. +// +//===----------------------------------------------------------------------===// + +#ifndef ANALYSIS_STORE +#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) +#endif + +ANALYSIS_STORE(RegionStore, "region", "Use region-based analyzer store", CreateRegionStoreManager) + +#ifndef ANALYSIS_CONSTRAINTS +#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) +#endif + +ANALYSIS_CONSTRAINTS(RangeConstraints, "range", "Use constraint tracking of concrete value ranges", CreateRangeConstraintManager) + +#ifndef ANALYSIS_DIAGNOSTICS +#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) +#endif + +ANALYSIS_DIAGNOSTICS(HTML, "html", "Output analysis results using HTML", createHTMLDiagnosticConsumer) +ANALYSIS_DIAGNOSTICS(PLIST, "plist", "Output analysis results using Plists", createPlistDiagnosticConsumer) +ANALYSIS_DIAGNOSTICS(PLIST_MULTI_FILE, "plist-multi-file", "Output analysis results using Plists (allowing for mult-file bugs)", createPlistMultiFileDiagnosticConsumer) +ANALYSIS_DIAGNOSTICS(PLIST_HTML, "plist-html", "Output analysis results using HTML wrapped with Plists", createPlistHTMLDiagnosticConsumer) +ANALYSIS_DIAGNOSTICS(TEXT, "text", "Text output of analysis results", createTextPathDiagnosticConsumer) + +#ifndef ANALYSIS_PURGE +#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) +#endif + +ANALYSIS_PURGE(PurgeStmt, "statement", "Purge symbols, bindings, and constraints before every statement") +ANALYSIS_PURGE(PurgeBlock, "block", "Purge symbols, bindings, and constraints before every basic block") +ANALYSIS_PURGE(PurgeNone, "none", "Do not purge symbols, bindings, or constraints") + +#ifndef ANALYSIS_INLINING_MODE +#define ANALYSIS_INLINING_MODE(NAME, CMDFLAG, DESC) +#endif + +ANALYSIS_INLINING_MODE(All, "all", "Analyze all functions as top level") +ANALYSIS_INLINING_MODE(NoRedundancy, "noredundancy", "Do not analyze a function which has been previously inlined") + +#undef ANALYSIS_STORE +#undef ANALYSIS_CONSTRAINTS +#undef ANALYSIS_DIAGNOSTICS +#undef ANALYSIS_PURGE +#undef ANALYSIS_INLINING_MODE +#undef ANALYSIS_IPA + diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h new file mode 100644 index 0000000..3959de2 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -0,0 +1,567 @@ +//===--- AnalyzerOptions.h - Analysis Engine Options ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header defines various options for the static analyzer that are set +// by the frontend and are consulted throughout the analyzer. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_ANALYZEROPTIONS_H +#define LLVM_CLANG_STATICANALYZER_CORE_ANALYZEROPTIONS_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringMap.h" +#include <string> +#include <vector> + +namespace clang { +class ASTConsumer; +class DiagnosticsEngine; +class Preprocessor; +class LangOptions; + +namespace ento { +class CheckerBase; +} + +/// Analysis - Set of available source code analyses. +enum Analyses { +#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE) NAME, +#include "clang/StaticAnalyzer/Core/Analyses.def" +NumAnalyses +}; + +/// AnalysisStores - Set of available analysis store models. +enum AnalysisStores { +#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) NAME##Model, +#include "clang/StaticAnalyzer/Core/Analyses.def" +NumStores +}; + +/// AnalysisConstraints - Set of available constraint models. +enum AnalysisConstraints { +#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) NAME##Model, +#include "clang/StaticAnalyzer/Core/Analyses.def" +NumConstraints +}; + +/// AnalysisDiagClients - Set of available diagnostic clients for rendering +/// analysis results. +enum AnalysisDiagClients { +#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN) PD_##NAME, +#include "clang/StaticAnalyzer/Core/Analyses.def" +PD_NONE, +NUM_ANALYSIS_DIAG_CLIENTS +}; + +/// AnalysisPurgeModes - Set of available strategies for dead symbol removal. +enum AnalysisPurgeMode { +#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) NAME, +#include "clang/StaticAnalyzer/Core/Analyses.def" +NumPurgeModes +}; + +/// AnalysisInlineFunctionSelection - Set of inlining function selection heuristics. +enum AnalysisInliningMode { +#define ANALYSIS_INLINING_MODE(NAME, CMDFLAG, DESC) NAME, +#include "clang/StaticAnalyzer/Core/Analyses.def" +NumInliningModes +}; + +/// \brief Describes the different kinds of C++ member functions which can be +/// considered for inlining by the analyzer. +/// +/// These options are cumulative; enabling one kind of member function will +/// enable all kinds with lower enum values. +enum CXXInlineableMemberKind { + // Uninitialized = 0, + + /// A dummy mode in which no C++ inlining is enabled. + CIMK_None = 1, + + /// Refers to regular member function and operator calls. + CIMK_MemberFunctions, + + /// Refers to constructors (implicit or explicit). + /// + /// Note that a constructor will not be inlined if the corresponding + /// destructor is non-trivial. + CIMK_Constructors, + + /// Refers to destructors (implicit or explicit). + CIMK_Destructors +}; + +/// \brief Describes the different modes of inter-procedural analysis. +enum IPAKind { + IPAK_NotSet = 0, + + /// Perform only intra-procedural analysis. + IPAK_None = 1, + + /// Inline C functions and blocks when their definitions are available. + IPAK_BasicInlining = 2, + + /// Inline callees(C, C++, ObjC) when their definitions are available. + IPAK_Inlining = 3, + + /// Enable inlining of dynamically dispatched methods. + IPAK_DynamicDispatch = 4, + + /// Enable inlining of dynamically dispatched methods, bifurcate paths when + /// exact type info is unavailable. + IPAK_DynamicDispatchBifurcate = 5 +}; + +class AnalyzerOptions : public RefCountedBase<AnalyzerOptions> { +public: + typedef llvm::StringMap<std::string> ConfigTable; + + /// \brief Pair of checker name and enable/disable. + std::vector<std::pair<std::string, bool> > CheckersControlList; + + /// \brief A key-value table of use-specified configuration values. + ConfigTable Config; + AnalysisStores AnalysisStoreOpt; + AnalysisConstraints AnalysisConstraintsOpt; + AnalysisDiagClients AnalysisDiagOpt; + AnalysisPurgeMode AnalysisPurgeOpt; + + std::string AnalyzeSpecificFunction; + + /// \brief The maximum number of times the analyzer visits a block. + unsigned maxBlockVisitOnPath; + + + /// \brief Disable all analyzer checks. + /// + /// This flag allows one to disable analyzer checks on the code processed by + /// the given analysis consumer. Note, the code will get parsed and the + /// command-line options will get checked. + unsigned DisableAllChecks : 1; + + unsigned ShowCheckerHelp : 1; + unsigned AnalyzeAll : 1; + unsigned AnalyzerDisplayProgress : 1; + unsigned AnalyzeNestedBlocks : 1; + + /// \brief The flag regulates if we should eagerly assume evaluations of + /// conditionals, thus, bifurcating the path. + /// + /// This flag indicates how the engine should handle expressions such as: 'x = + /// (y != 0)'. When this flag is true then the subexpression 'y != 0' will be + /// eagerly assumed to be true or false, thus evaluating it to the integers 0 + /// or 1 respectively. The upside is that this can increase analysis + /// precision until we have a better way to lazily evaluate such logic. The + /// downside is that it eagerly bifurcates paths. + unsigned eagerlyAssumeBinOpBifurcation : 1; + + unsigned TrimGraph : 1; + unsigned visualizeExplodedGraphWithGraphViz : 1; + unsigned visualizeExplodedGraphWithUbiGraph : 1; + unsigned UnoptimizedCFG : 1; + unsigned PrintStats : 1; + + /// \brief Do not re-analyze paths leading to exhausted nodes with a different + /// strategy. We get better code coverage when retry is enabled. + unsigned NoRetryExhausted : 1; + + /// \brief The inlining stack depth limit. + unsigned InlineMaxStackDepth; + + /// \brief The mode of function selection used during inlining. + AnalysisInliningMode InliningMode; + +private: + /// \brief Describes the kinds for high-level analyzer mode. + enum UserModeKind { + UMK_NotSet = 0, + /// Perform shallow but fast analyzes. + UMK_Shallow = 1, + /// Perform deep analyzes. + UMK_Deep = 2 + }; + + /// Controls the high-level analyzer mode, which influences the default + /// settings for some of the lower-level config options (such as IPAMode). + /// \sa getUserMode + UserModeKind UserMode; + + /// Controls the mode of inter-procedural analysis. + IPAKind IPAMode; + + /// Controls which C++ member functions will be considered for inlining. + CXXInlineableMemberKind CXXMemberInliningMode; + + /// \sa includeTemporaryDtorsInCFG + Optional<bool> IncludeTemporaryDtorsInCFG; + + /// \sa mayInlineCXXStandardLibrary + Optional<bool> InlineCXXStandardLibrary; + + /// \sa mayInlineTemplateFunctions + Optional<bool> InlineTemplateFunctions; + + /// \sa mayInlineCXXAllocator + Optional<bool> InlineCXXAllocator; + + /// \sa mayInlineCXXContainerMethods + Optional<bool> InlineCXXContainerMethods; + + /// \sa mayInlineCXXSharedPtrDtor + Optional<bool> InlineCXXSharedPtrDtor; + + /// \sa mayInlineObjCMethod + Optional<bool> ObjCInliningMode; + + // Cache of the "ipa-always-inline-size" setting. + // \sa getAlwaysInlineSize + Optional<unsigned> AlwaysInlineSize; + + /// \sa shouldSuppressNullReturnPaths + Optional<bool> SuppressNullReturnPaths; + + // \sa getMaxInlinableSize + Optional<unsigned> MaxInlinableSize; + + /// \sa shouldAvoidSuppressingNullArgumentPaths + Optional<bool> AvoidSuppressingNullArgumentPaths; + + /// \sa shouldSuppressInlinedDefensiveChecks + Optional<bool> SuppressInlinedDefensiveChecks; + + /// \sa shouldSuppressFromCXXStandardLibrary + Optional<bool> SuppressFromCXXStandardLibrary; + + /// \sa reportIssuesInMainSourceFile + Optional<bool> ReportIssuesInMainSourceFile; + + /// \sa StableReportFilename + Optional<bool> StableReportFilename; + + /// \sa getGraphTrimInterval + Optional<unsigned> GraphTrimInterval; + + /// \sa getMaxTimesInlineLarge + Optional<unsigned> MaxTimesInlineLarge; + + /// \sa getMinCFGSizeTreatFunctionsAsLarge + Optional<unsigned> MinCFGSizeTreatFunctionsAsLarge; + + /// \sa getMaxNodesPerTopLevelFunction + Optional<unsigned> MaxNodesPerTopLevelFunction; + + /// \sa shouldInlineLambdas + Optional<bool> InlineLambdas; + + /// \sa shouldWidenLoops + Optional<bool> WidenLoops; + + /// A helper function that retrieves option for a given full-qualified + /// checker name. + /// Options for checkers can be specified via 'analyzer-config' command-line + /// option. + /// Example: + /// @code-analyzer-config unix.Malloc:OptionName=CheckerOptionValue @endcode + /// or @code-analyzer-config unix:OptionName=GroupOptionValue @endcode + /// for groups of checkers. + /// @param [in] CheckerName Full-qualified checker name, like + /// alpha.unix.StreamChecker. + /// @param [in] OptionName Name of the option to get. + /// @param [in] Default Default value if no option is specified. + /// @param [in] SearchInParents If set to true and the searched option was not + /// specified for the given checker the options for the parent packages will + /// be searched as well. The inner packages take precedence over the outer + /// ones. + /// @retval CheckerOptionValue An option for a checker if it was specified. + /// @retval GroupOptionValue An option for group if it was specified and no + /// checker-specific options were found. The closer group to checker, + /// the more priority it has. For example, @c coregroup.subgroup has more + /// priority than @c coregroup for @c coregroup.subgroup.CheckerName checker. + /// @retval Default If nor checker option, nor group option was found. + StringRef getCheckerOption(StringRef CheckerName, StringRef OptionName, + StringRef Default, + bool SearchInParents = false); + +public: + /// Interprets an option's string value as a boolean. The "true" string is + /// interpreted as true and the "false" string is interpreted as false. + /// + /// If an option value is not provided, returns the given \p DefaultVal. + /// @param [in] Name Name for option to retrieve. + /// @param [in] DefaultVal Default value returned if no such option was + /// specified. + /// @param [in] C The optional checker parameter that can be used to restrict + /// the search to the options of this particular checker (and its parents + /// dependening on search mode). + /// @param [in] SearchInParents If set to true and the searched option was not + /// specified for the given checker the options for the parent packages will + /// be searched as well. The inner packages take precedence over the outer + /// ones. + bool getBooleanOption(StringRef Name, bool DefaultVal, + const ento::CheckerBase *C = nullptr, + bool SearchInParents = false); + + /// Variant that accepts a Optional value to cache the result. + /// + /// @param [in,out] V Return value storage, returned if parameter contains + /// an existing valid option, else it is used to store a return value + /// @param [in] Name Name for option to retrieve. + /// @param [in] DefaultVal Default value returned if no such option was + /// specified. + /// @param [in] C The optional checker parameter that can be used to restrict + /// the search to the options of this particular checker (and its parents + /// dependening on search mode). + /// @param [in] SearchInParents If set to true and the searched option was not + /// specified for the given checker the options for the parent packages will + /// be searched as well. The inner packages take precedence over the outer + /// ones. + bool getBooleanOption(Optional<bool> &V, StringRef Name, bool DefaultVal, + const ento::CheckerBase *C = nullptr, + bool SearchInParents = false); + + /// Interprets an option's string value as an integer value. + /// + /// If an option value is not provided, returns the given \p DefaultVal. + /// @param [in] Name Name for option to retrieve. + /// @param [in] DefaultVal Default value returned if no such option was + /// specified. + /// @param [in] C The optional checker parameter that can be used to restrict + /// the search to the options of this particular checker (and its parents + /// dependening on search mode). + /// @param [in] SearchInParents If set to true and the searched option was not + /// specified for the given checker the options for the parent packages will + /// be searched as well. The inner packages take precedence over the outer + /// ones. + int getOptionAsInteger(StringRef Name, int DefaultVal, + const ento::CheckerBase *C = nullptr, + bool SearchInParents = false); + + /// Query an option's string value. + /// + /// If an option value is not provided, returns the given \p DefaultVal. + /// @param [in] Name Name for option to retrieve. + /// @param [in] DefaultVal Default value returned if no such option was + /// specified. + /// @param [in] C The optional checker parameter that can be used to restrict + /// the search to the options of this particular checker (and its parents + /// dependening on search mode). + /// @param [in] SearchInParents If set to true and the searched option was not + /// specified for the given checker the options for the parent packages will + /// be searched as well. The inner packages take precedence over the outer + /// ones. + StringRef getOptionAsString(StringRef Name, StringRef DefaultVal, + const ento::CheckerBase *C = nullptr, + bool SearchInParents = false); + + /// \brief Retrieves and sets the UserMode. This is a high-level option, + /// which is used to set other low-level options. It is not accessible + /// outside of AnalyzerOptions. + UserModeKind getUserMode(); + + /// \brief Returns the inter-procedural analysis mode. + IPAKind getIPAMode(); + + /// Returns the option controlling which C++ member functions will be + /// considered for inlining. + /// + /// This is controlled by the 'c++-inlining' config option. + /// + /// \sa CXXMemberInliningMode + bool mayInlineCXXMemberFunction(CXXInlineableMemberKind K); + + /// Returns true if ObjectiveC inlining is enabled, false otherwise. + bool mayInlineObjCMethod(); + + /// Returns whether or not the destructors for C++ temporary objects should + /// be included in the CFG. + /// + /// This is controlled by the 'cfg-temporary-dtors' config option, which + /// accepts the values "true" and "false". + bool includeTemporaryDtorsInCFG(); + + /// Returns whether or not C++ standard library functions may be considered + /// for inlining. + /// + /// This is controlled by the 'c++-stdlib-inlining' config option, which + /// accepts the values "true" and "false". + bool mayInlineCXXStandardLibrary(); + + /// Returns whether or not templated functions may be considered for inlining. + /// + /// This is controlled by the 'c++-template-inlining' config option, which + /// accepts the values "true" and "false". + bool mayInlineTemplateFunctions(); + + /// Returns whether or not allocator call may be considered for inlining. + /// + /// This is controlled by the 'c++-allocator-inlining' config option, which + /// accepts the values "true" and "false". + bool mayInlineCXXAllocator(); + + /// Returns whether or not methods of C++ container objects may be considered + /// for inlining. + /// + /// This is controlled by the 'c++-container-inlining' config option, which + /// accepts the values "true" and "false". + bool mayInlineCXXContainerMethods(); + + /// Returns whether or not the destructor of C++ 'shared_ptr' may be + /// considered for inlining. + /// + /// This covers std::shared_ptr, std::tr1::shared_ptr, and boost::shared_ptr, + /// and indeed any destructor named "~shared_ptr". + /// + /// This is controlled by the 'c++-shared_ptr-inlining' config option, which + /// accepts the values "true" and "false". + bool mayInlineCXXSharedPtrDtor(); + + /// Returns whether or not paths that go through null returns should be + /// suppressed. + /// + /// This is a heuristic for avoiding bug reports with paths that go through + /// inlined functions that are more defensive than their callers. + /// + /// This is controlled by the 'suppress-null-return-paths' config option, + /// which accepts the values "true" and "false". + bool shouldSuppressNullReturnPaths(); + + /// Returns whether a bug report should \em not be suppressed if its path + /// includes a call with a null argument, even if that call has a null return. + /// + /// This option has no effect when #shouldSuppressNullReturnPaths() is false. + /// + /// This is a counter-heuristic to avoid false negatives. + /// + /// This is controlled by the 'avoid-suppressing-null-argument-paths' config + /// option, which accepts the values "true" and "false". + bool shouldAvoidSuppressingNullArgumentPaths(); + + /// Returns whether or not diagnostics containing inlined defensive NULL + /// checks should be suppressed. + /// + /// This is controlled by the 'suppress-inlined-defensive-checks' config + /// option, which accepts the values "true" and "false". + bool shouldSuppressInlinedDefensiveChecks(); + + /// Returns whether or not diagnostics reported within the C++ standard + /// library should be suppressed. + /// + /// This is controlled by the 'suppress-c++-stdlib' config option, + /// which accepts the values "true" and "false". + bool shouldSuppressFromCXXStandardLibrary(); + + /// Returns whether or not the diagnostic report should be always reported + /// in the main source file and not the headers. + /// + /// This is controlled by the 'report-in-main-source-file' config option, + /// which accepts the values "true" and "false". + bool shouldReportIssuesInMainSourceFile(); + + /// Returns whether or not the report filename should be random or not. + /// + /// This is controlled by the 'stable-report-filename' config option, + /// which accepts the values "true" and "false". Default = false + bool shouldWriteStableReportFilename(); + + /// Returns whether irrelevant parts of a bug report path should be pruned + /// out of the final output. + /// + /// This is controlled by the 'prune-paths' config option, which accepts the + /// values "true" and "false". + bool shouldPrunePaths(); + + /// Returns true if 'static' initializers should be in conditional logic + /// in the CFG. + bool shouldConditionalizeStaticInitializers(); + + // Returns the size of the functions (in basic blocks), which should be + // considered to be small enough to always inline. + // + // This is controlled by "ipa-always-inline-size" analyzer-config option. + unsigned getAlwaysInlineSize(); + + // Returns the bound on the number of basic blocks in an inlined function + // (50 by default). + // + // This is controlled by "-analyzer-config max-inlinable-size" option. + unsigned getMaxInlinableSize(); + + /// Returns true if the analyzer engine should synthesize fake bodies + /// for well-known functions. + bool shouldSynthesizeBodies(); + + /// Returns how often nodes in the ExplodedGraph should be recycled to save + /// memory. + /// + /// This is controlled by the 'graph-trim-interval' config option. To disable + /// node reclamation, set the option to "0". + unsigned getGraphTrimInterval(); + + /// Returns the maximum times a large function could be inlined. + /// + /// This is controlled by the 'max-times-inline-large' config option. + unsigned getMaxTimesInlineLarge(); + + /// Returns the number of basic blocks a function needs to have to be + /// considered large for the 'max-times-inline-large' config option. + /// + /// This is controlled by the 'min-cfg-size-treat-functions-as-large' config + /// option. + unsigned getMinCFGSizeTreatFunctionsAsLarge(); + + /// Returns the maximum number of nodes the analyzer can generate while + /// exploring a top level function (for each exploded graph). + /// 150000 is default; 0 means no limit. + /// + /// This is controlled by the 'max-nodes' config option. + unsigned getMaxNodesPerTopLevelFunction(); + + /// Returns true if lambdas should be inlined. Otherwise a sink node will be + /// generated each time a LambdaExpr is visited. + bool shouldInlineLambdas(); + + /// Returns true if the analysis should try to widen loops. + /// This is controlled by the 'widen-loops' config option. + bool shouldWidenLoops(); + +public: + AnalyzerOptions() : + AnalysisStoreOpt(RegionStoreModel), + AnalysisConstraintsOpt(RangeConstraintsModel), + AnalysisDiagOpt(PD_HTML), + AnalysisPurgeOpt(PurgeStmt), + DisableAllChecks(0), + ShowCheckerHelp(0), + AnalyzeAll(0), + AnalyzerDisplayProgress(0), + AnalyzeNestedBlocks(0), + eagerlyAssumeBinOpBifurcation(0), + TrimGraph(0), + visualizeExplodedGraphWithGraphViz(0), + visualizeExplodedGraphWithUbiGraph(0), + UnoptimizedCFG(0), + PrintStats(0), + NoRetryExhausted(0), + // Cap the stack depth at 4 calls (5 stack frames, base + 4 calls). + InlineMaxStackDepth(5), + InliningMode(NoRedundancy), + UserMode(UMK_NotSet), + IPAMode(IPAK_NotSet), + CXXMemberInliningMode() {} + +}; + +typedef IntrusiveRefCntPtr<AnalyzerOptions> AnalyzerOptionsRef; + +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h new file mode 100644 index 0000000..57c73fd --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h @@ -0,0 +1,561 @@ +//===--- BugReporter.h - Generate PathDiagnostics --------------*- 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 BugReporter, a utility class for generating +// PathDiagnostics for analyses based on ProgramState. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTER_H +#define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTER_H + +#include "clang/Basic/SourceLocation.h" +#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h" +#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/ImmutableSet.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/ilist.h" +#include "llvm/ADT/ilist_node.h" + +namespace clang { + +class ASTContext; +class DiagnosticsEngine; +class Stmt; +class ParentMap; + +namespace ento { + +class PathDiagnostic; +class ExplodedNode; +class ExplodedGraph; +class BugReport; +class BugReporter; +class BugReporterContext; +class ExprEngine; +class BugType; + +//===----------------------------------------------------------------------===// +// Interface for individual bug reports. +//===----------------------------------------------------------------------===// + +/// This class provides an interface through which checkers can create +/// individual bug reports. +class BugReport : public llvm::ilist_node<BugReport> { +public: + class NodeResolver { + virtual void anchor(); + public: + virtual ~NodeResolver() {} + virtual const ExplodedNode* + getOriginalNode(const ExplodedNode *N) = 0; + }; + + typedef const SourceRange *ranges_iterator; + typedef SmallVector<std::unique_ptr<BugReporterVisitor>, 8> VisitorList; + typedef VisitorList::iterator visitor_iterator; + typedef SmallVector<StringRef, 2> ExtraTextList; + +protected: + friend class BugReporter; + friend class BugReportEquivClass; + + BugType& BT; + const Decl *DeclWithIssue; + std::string ShortDescription; + std::string Description; + PathDiagnosticLocation Location; + PathDiagnosticLocation UniqueingLocation; + const Decl *UniqueingDecl; + + const ExplodedNode *ErrorNode; + SmallVector<SourceRange, 4> Ranges; + ExtraTextList ExtraText; + + typedef llvm::DenseSet<SymbolRef> Symbols; + typedef llvm::DenseSet<const MemRegion *> Regions; + + /// A (stack of) a set of symbols that are registered with this + /// report as being "interesting", and thus used to help decide which + /// diagnostics to include when constructing the final path diagnostic. + /// The stack is largely used by BugReporter when generating PathDiagnostics + /// for multiple PathDiagnosticConsumers. + SmallVector<Symbols *, 2> interestingSymbols; + + /// A (stack of) set of regions that are registered with this report as being + /// "interesting", and thus used to help decide which diagnostics + /// to include when constructing the final path diagnostic. + /// The stack is largely used by BugReporter when generating PathDiagnostics + /// for multiple PathDiagnosticConsumers. + SmallVector<Regions *, 2> interestingRegions; + + /// A set of location contexts that correspoind to call sites which should be + /// considered "interesting". + llvm::SmallSet<const LocationContext *, 2> InterestingLocationContexts; + + /// A set of custom visitors which generate "event" diagnostics at + /// interesting points in the path. + VisitorList Callbacks; + + /// Used for ensuring the visitors are only added once. + llvm::FoldingSet<BugReporterVisitor> CallbacksSet; + + /// Used for clients to tell if the report's configuration has changed + /// since the last time they checked. + unsigned ConfigurationChangeToken; + + /// When set, this flag disables all callstack pruning from a diagnostic + /// path. This is useful for some reports that want maximum fidelty + /// when reporting an issue. + bool DoNotPrunePath; + + /// Used to track unique reasons why a bug report might be invalid. + /// + /// \sa markInvalid + /// \sa removeInvalidation + typedef std::pair<const void *, const void *> InvalidationRecord; + + /// If non-empty, this bug report is likely a false positive and should not be + /// shown to the user. + /// + /// \sa markInvalid + /// \sa removeInvalidation + llvm::SmallSet<InvalidationRecord, 4> Invalidations; + +private: + // Used internally by BugReporter. + Symbols &getInterestingSymbols(); + Regions &getInterestingRegions(); + + void lazyInitializeInterestingSets(); + void pushInterestingSymbolsAndRegions(); + void popInterestingSymbolsAndRegions(); + +public: + BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode) + : BT(bt), DeclWithIssue(nullptr), Description(desc), ErrorNode(errornode), + ConfigurationChangeToken(0), DoNotPrunePath(false) {} + + BugReport(BugType& bt, StringRef shortDesc, StringRef desc, + const ExplodedNode *errornode) + : BT(bt), DeclWithIssue(nullptr), ShortDescription(shortDesc), + Description(desc), ErrorNode(errornode), ConfigurationChangeToken(0), + DoNotPrunePath(false) {} + + BugReport(BugType &bt, StringRef desc, PathDiagnosticLocation l) + : BT(bt), DeclWithIssue(nullptr), Description(desc), Location(l), + ErrorNode(nullptr), ConfigurationChangeToken(0), DoNotPrunePath(false) {} + + /// \brief Create a BugReport with a custom uniqueing location. + /// + /// The reports that have the same report location, description, bug type, and + /// ranges are uniqued - only one of the equivalent reports will be presented + /// to the user. This method allows to rest the location which should be used + /// for uniquing reports. For example, memory leaks checker, could set this to + /// the allocation site, rather then the location where the bug is reported. + BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode, + PathDiagnosticLocation LocationToUnique, const Decl *DeclToUnique) + : BT(bt), DeclWithIssue(nullptr), Description(desc), + UniqueingLocation(LocationToUnique), + UniqueingDecl(DeclToUnique), + ErrorNode(errornode), ConfigurationChangeToken(0), + DoNotPrunePath(false) {} + + virtual ~BugReport(); + + const BugType& getBugType() const { return BT; } + BugType& getBugType() { return BT; } + + const ExplodedNode *getErrorNode() const { return ErrorNode; } + + StringRef getDescription() const { return Description; } + + StringRef getShortDescription(bool UseFallback = true) const { + if (ShortDescription.empty() && UseFallback) + return Description; + return ShortDescription; + } + + /// Indicates whether or not any path pruning should take place + /// when generating a PathDiagnostic from this BugReport. + bool shouldPrunePath() const { return !DoNotPrunePath; } + + /// Disable all path pruning when generating a PathDiagnostic. + void disablePathPruning() { DoNotPrunePath = true; } + + void markInteresting(SymbolRef sym); + void markInteresting(const MemRegion *R); + void markInteresting(SVal V); + void markInteresting(const LocationContext *LC); + + bool isInteresting(SymbolRef sym); + bool isInteresting(const MemRegion *R); + bool isInteresting(SVal V); + bool isInteresting(const LocationContext *LC); + + unsigned getConfigurationChangeToken() const { + return ConfigurationChangeToken; + } + + /// Returns whether or not this report should be considered valid. + /// + /// Invalid reports are those that have been classified as likely false + /// positives after the fact. + bool isValid() const { + return Invalidations.empty(); + } + + /// Marks the current report as invalid, meaning that it is probably a false + /// positive and should not be reported to the user. + /// + /// The \p Tag and \p Data arguments are intended to be opaque identifiers for + /// this particular invalidation, where \p Tag represents the visitor + /// responsible for invalidation, and \p Data represents the reason this + /// visitor decided to invalidate the bug report. + /// + /// \sa removeInvalidation + void markInvalid(const void *Tag, const void *Data) { + Invalidations.insert(std::make_pair(Tag, Data)); + } + + /// Reverses the effects of a previous invalidation. + /// + /// \sa markInvalid + void removeInvalidation(const void *Tag, const void *Data) { + Invalidations.erase(std::make_pair(Tag, Data)); + } + + /// Return the canonical declaration, be it a method or class, where + /// this issue semantically occurred. + const Decl *getDeclWithIssue() const; + + /// Specifically set the Decl where an issue occurred. This isn't necessary + /// for BugReports that cover a path as it will be automatically inferred. + void setDeclWithIssue(const Decl *declWithIssue) { + DeclWithIssue = declWithIssue; + } + + /// \brief This allows for addition of meta data to the diagnostic. + /// + /// Currently, only the HTMLDiagnosticClient knows how to display it. + void addExtraText(StringRef S) { + ExtraText.push_back(S); + } + + virtual const ExtraTextList &getExtraText() { + return ExtraText; + } + + /// \brief Return the "definitive" location of the reported bug. + /// + /// While a bug can span an entire path, usually there is a specific + /// location that can be used to identify where the key issue occurred. + /// This location is used by clients rendering diagnostics. + virtual PathDiagnosticLocation getLocation(const SourceManager &SM) const; + + /// \brief Get the location on which the report should be uniqued. + PathDiagnosticLocation getUniqueingLocation() const { + return UniqueingLocation; + } + + /// \brief Get the declaration containing the uniqueing location. + const Decl *getUniqueingDecl() const { + return UniqueingDecl; + } + + const Stmt *getStmt() const; + + /// \brief Add a range to a bug report. + /// + /// Ranges are used to highlight regions of interest in the source code. + /// They should be at the same source code line as the BugReport location. + /// By default, the source range of the statement corresponding to the error + /// node will be used; add a single invalid range to specify absence of + /// ranges. + void addRange(SourceRange R) { + assert((R.isValid() || Ranges.empty()) && "Invalid range can only be used " + "to specify that the report does not have a range."); + Ranges.push_back(R); + } + + /// \brief Get the SourceRanges associated with the report. + virtual llvm::iterator_range<ranges_iterator> getRanges(); + + /// \brief Add custom or predefined bug report visitors to this report. + /// + /// The visitors should be used when the default trace is not sufficient. + /// For example, they allow constructing a more elaborate trace. + /// \sa registerConditionVisitor(), registerTrackNullOrUndefValue(), + /// registerFindLastStore(), registerNilReceiverVisitor(), and + /// registerVarDeclsLastStore(). + void addVisitor(std::unique_ptr<BugReporterVisitor> visitor); + + /// Iterators through the custom diagnostic visitors. + visitor_iterator visitor_begin() { return Callbacks.begin(); } + visitor_iterator visitor_end() { return Callbacks.end(); } + + /// Profile to identify equivalent bug reports for error report coalescing. + /// Reports are uniqued to ensure that we do not emit multiple diagnostics + /// for each bug. + virtual void Profile(llvm::FoldingSetNodeID& hash) const; +}; + +} // end ento namespace +} // end clang namespace + +namespace llvm { + template<> struct ilist_traits<clang::ento::BugReport> + : public ilist_default_traits<clang::ento::BugReport> { + clang::ento::BugReport *createSentinel() const { + return static_cast<clang::ento::BugReport *>(&Sentinel); + } + void destroySentinel(clang::ento::BugReport *) const {} + + clang::ento::BugReport *provideInitialHead() const { + return createSentinel(); + } + clang::ento::BugReport *ensureHead(clang::ento::BugReport *) const { + return createSentinel(); + } + private: + mutable ilist_half_node<clang::ento::BugReport> Sentinel; + }; +} + +namespace clang { +namespace ento { + +//===----------------------------------------------------------------------===// +// BugTypes (collections of related reports). +//===----------------------------------------------------------------------===// + +class BugReportEquivClass : public llvm::FoldingSetNode { + /// List of *owned* BugReport objects. + llvm::ilist<BugReport> Reports; + + friend class BugReporter; + void AddReport(std::unique_ptr<BugReport> R) { + Reports.push_back(R.release()); + } + +public: + BugReportEquivClass(std::unique_ptr<BugReport> R) { AddReport(std::move(R)); } + ~BugReportEquivClass(); + + void Profile(llvm::FoldingSetNodeID& ID) const { + assert(!Reports.empty()); + Reports.front().Profile(ID); + } + + typedef llvm::ilist<BugReport>::iterator iterator; + typedef llvm::ilist<BugReport>::const_iterator const_iterator; + + iterator begin() { return Reports.begin(); } + iterator end() { return Reports.end(); } + + const_iterator begin() const { return Reports.begin(); } + const_iterator end() const { return Reports.end(); } +}; + +//===----------------------------------------------------------------------===// +// BugReporter and friends. +//===----------------------------------------------------------------------===// + +class BugReporterData { +public: + virtual ~BugReporterData(); + virtual DiagnosticsEngine& getDiagnostic() = 0; + virtual ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() = 0; + virtual ASTContext &getASTContext() = 0; + virtual SourceManager& getSourceManager() = 0; + virtual AnalyzerOptions& getAnalyzerOptions() = 0; +}; + +/// BugReporter is a utility class for generating PathDiagnostics for analysis. +/// It collects the BugReports and BugTypes and knows how to generate +/// and flush the corresponding diagnostics. +class BugReporter { +public: + enum Kind { BaseBRKind, GRBugReporterKind }; + +private: + typedef llvm::ImmutableSet<BugType*> BugTypesTy; + BugTypesTy::Factory F; + BugTypesTy BugTypes; + + const Kind kind; + BugReporterData& D; + + /// Generate and flush the diagnostics for the given bug report. + void FlushReport(BugReportEquivClass& EQ); + + /// Generate and flush the diagnostics for the given bug report + /// and PathDiagnosticConsumer. + void FlushReport(BugReport *exampleReport, + PathDiagnosticConsumer &PD, + ArrayRef<BugReport*> BugReports); + + /// The set of bug reports tracked by the BugReporter. + llvm::FoldingSet<BugReportEquivClass> EQClasses; + /// A vector of BugReports for tracking the allocated pointers and cleanup. + std::vector<BugReportEquivClass *> EQClassesVector; + +protected: + BugReporter(BugReporterData& d, Kind k) : BugTypes(F.getEmptySet()), kind(k), + D(d) {} + +public: + BugReporter(BugReporterData& d) : BugTypes(F.getEmptySet()), kind(BaseBRKind), + D(d) {} + virtual ~BugReporter(); + + /// \brief Generate and flush diagnostics for all bug reports. + void FlushReports(); + + Kind getKind() const { return kind; } + + DiagnosticsEngine& getDiagnostic() { + return D.getDiagnostic(); + } + + ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() { + return D.getPathDiagnosticConsumers(); + } + + /// \brief Iterator over the set of BugTypes tracked by the BugReporter. + typedef BugTypesTy::iterator iterator; + iterator begin() { return BugTypes.begin(); } + iterator end() { return BugTypes.end(); } + + /// \brief Iterator over the set of BugReports tracked by the BugReporter. + typedef llvm::FoldingSet<BugReportEquivClass>::iterator EQClasses_iterator; + EQClasses_iterator EQClasses_begin() { return EQClasses.begin(); } + EQClasses_iterator EQClasses_end() { return EQClasses.end(); } + + ASTContext &getContext() { return D.getASTContext(); } + + SourceManager& getSourceManager() { return D.getSourceManager(); } + + AnalyzerOptions& getAnalyzerOptions() { return D.getAnalyzerOptions(); } + + virtual bool generatePathDiagnostic(PathDiagnostic& pathDiagnostic, + PathDiagnosticConsumer &PC, + ArrayRef<BugReport *> &bugReports) { + return true; + } + + bool RemoveUnneededCalls(PathPieces &pieces, BugReport *R); + + void Register(BugType *BT); + + /// \brief Add the given report to the set of reports tracked by BugReporter. + /// + /// The reports are usually generated by the checkers. Further, they are + /// folded based on the profile value, which is done to coalesce similar + /// reports. + void emitReport(std::unique_ptr<BugReport> R); + + void EmitBasicReport(const Decl *DeclWithIssue, const CheckerBase *Checker, + StringRef BugName, StringRef BugCategory, + StringRef BugStr, PathDiagnosticLocation Loc, + ArrayRef<SourceRange> Ranges = None); + + void EmitBasicReport(const Decl *DeclWithIssue, CheckName CheckName, + StringRef BugName, StringRef BugCategory, + StringRef BugStr, PathDiagnosticLocation Loc, + ArrayRef<SourceRange> Ranges = None); + +private: + llvm::StringMap<BugType *> StrBugTypes; + + /// \brief Returns a BugType that is associated with the given name and + /// category. + BugType *getBugTypeForName(CheckName CheckName, StringRef name, + StringRef category); +}; + +// FIXME: Get rid of GRBugReporter. It's the wrong abstraction. +class GRBugReporter : public BugReporter { + ExprEngine& Eng; +public: + GRBugReporter(BugReporterData& d, ExprEngine& eng) + : BugReporter(d, GRBugReporterKind), Eng(eng) {} + + ~GRBugReporter() override; + + /// getEngine - Return the analysis engine used to analyze a given + /// function or method. + ExprEngine &getEngine() { return Eng; } + + /// getGraph - Get the exploded graph created by the analysis engine + /// for the analyzed method or function. + ExplodedGraph &getGraph(); + + /// getStateManager - Return the state manager used by the analysis + /// engine. + ProgramStateManager &getStateManager(); + + /// Generates a path corresponding to one of the given bug reports. + /// + /// Which report is used for path generation is not specified. The + /// bug reporter will try to pick the shortest path, but this is not + /// guaranteed. + /// + /// \return True if the report was valid and a path was generated, + /// false if the reports should be considered invalid. + bool generatePathDiagnostic(PathDiagnostic &PD, PathDiagnosticConsumer &PC, + ArrayRef<BugReport*> &bugReports) override; + + /// classof - Used by isa<>, cast<>, and dyn_cast<>. + static bool classof(const BugReporter* R) { + return R->getKind() == GRBugReporterKind; + } +}; + +class BugReporterContext { + virtual void anchor(); + GRBugReporter &BR; +public: + BugReporterContext(GRBugReporter& br) : BR(br) {} + + virtual ~BugReporterContext() {} + + GRBugReporter& getBugReporter() { return BR; } + + ExplodedGraph &getGraph() { return BR.getGraph(); } + + ProgramStateManager& getStateManager() { + return BR.getStateManager(); + } + + SValBuilder& getSValBuilder() { + return getStateManager().getSValBuilder(); + } + + ASTContext &getASTContext() { + return BR.getContext(); + } + + SourceManager& getSourceManager() { + return BR.getSourceManager(); + } + + virtual BugReport::NodeResolver& getNodeResolver() = 0; +}; + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h new file mode 100644 index 0000000..197d27a --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h @@ -0,0 +1,366 @@ +//===--- BugReporterVisitor.h - Generate PathDiagnostics -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares BugReporterVisitors, which are used to generate enhanced +// diagnostic traces. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITOR_H +#define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITOR_H + +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" +#include "llvm/ADT/FoldingSet.h" + +namespace clang { + +namespace ento { + +class BugReport; +class BugReporterContext; +class ExplodedNode; +class MemRegion; +class PathDiagnosticPiece; + +/// \brief BugReporterVisitors are used to add custom diagnostics along a path. +/// +/// Custom visitors should subclass the BugReporterVisitorImpl class for a +/// default implementation of the clone() method. +/// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the +/// default implementation of clone() will NOT do the right thing, and you +/// will have to provide your own implementation.) +class BugReporterVisitor : public llvm::FoldingSetNode { +public: + BugReporterVisitor() = default; + BugReporterVisitor(const BugReporterVisitor &) = default; + BugReporterVisitor(BugReporterVisitor &&) {} + virtual ~BugReporterVisitor(); + + /// \brief Returns a copy of this BugReporter. + /// + /// Custom BugReporterVisitors should not override this method directly. + /// Instead, they should inherit from BugReporterVisitorImpl and provide + /// a protected or public copy constructor. + /// + /// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the + /// default implementation of clone() will NOT do the right thing, and you + /// will have to provide your own implementation.) + virtual std::unique_ptr<BugReporterVisitor> clone() const = 0; + + /// \brief Return a diagnostic piece which should be associated with the + /// given node. + /// + /// The last parameter can be used to register a new visitor with the given + /// BugReport while processing a node. + virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *Succ, + const ExplodedNode *Pred, + BugReporterContext &BRC, + BugReport &BR) = 0; + + /// \brief Provide custom definition for the final diagnostic piece on the + /// path - the piece, which is displayed before the path is expanded. + /// + /// If returns NULL the default implementation will be used. + /// Also note that at most one visitor of a BugReport should generate a + /// non-NULL end of path diagnostic piece. + virtual std::unique_ptr<PathDiagnosticPiece> + getEndPath(BugReporterContext &BRC, const ExplodedNode *N, BugReport &BR); + + virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0; + + /// \brief Generates the default final diagnostic piece. + static std::unique_ptr<PathDiagnosticPiece> + getDefaultEndPath(BugReporterContext &BRC, const ExplodedNode *N, + BugReport &BR); +}; + +/// This class provides a convenience implementation for clone() using the +/// Curiously-Recurring Template Pattern. If you are implementing a custom +/// BugReporterVisitor, subclass BugReporterVisitorImpl and provide a public +/// or protected copy constructor. +/// +/// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the +/// default implementation of clone() will NOT do the right thing, and you +/// will have to provide your own implementation.) +template <class DERIVED> +class BugReporterVisitorImpl : public BugReporterVisitor { + std::unique_ptr<BugReporterVisitor> clone() const override { + return llvm::make_unique<DERIVED>(*static_cast<const DERIVED *>(this)); + } +}; + +class FindLastStoreBRVisitor final + : public BugReporterVisitorImpl<FindLastStoreBRVisitor> { + const MemRegion *R; + SVal V; + bool Satisfied; + + /// If the visitor is tracking the value directly responsible for the + /// bug, we are going to employ false positive suppression. + bool EnableNullFPSuppression; + +public: + /// Creates a visitor for every VarDecl inside a Stmt and registers it with + /// the BugReport. + static void registerStatementVarDecls(BugReport &BR, const Stmt *S, + bool EnableNullFPSuppression); + + FindLastStoreBRVisitor(KnownSVal V, const MemRegion *R, + bool InEnableNullFPSuppression) + : R(R), + V(V), + Satisfied(false), + EnableNullFPSuppression(InEnableNullFPSuppression) {} + + void Profile(llvm::FoldingSetNodeID &ID) const override; + + PathDiagnosticPiece *VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR) override; +}; + +class TrackConstraintBRVisitor final + : public BugReporterVisitorImpl<TrackConstraintBRVisitor> { + DefinedSVal Constraint; + bool Assumption; + bool IsSatisfied; + bool IsZeroCheck; + + /// We should start tracking from the last node along the path in which the + /// value is constrained. + bool IsTrackingTurnedOn; + +public: + TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption) + : Constraint(constraint), Assumption(assumption), IsSatisfied(false), + IsZeroCheck(!Assumption && Constraint.getAs<Loc>()), + IsTrackingTurnedOn(false) {} + + void Profile(llvm::FoldingSetNodeID &ID) const override; + + /// Return the tag associated with this visitor. This tag will be used + /// to make all PathDiagnosticPieces created by this visitor. + static const char *getTag(); + + PathDiagnosticPiece *VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR) override; + +private: + /// Checks if the constraint is valid in the current state. + bool isUnderconstrained(const ExplodedNode *N) const; + +}; + +/// \class NilReceiverBRVisitor +/// \brief Prints path notes when a message is sent to a nil receiver. +class NilReceiverBRVisitor final + : public BugReporterVisitorImpl<NilReceiverBRVisitor> { +public: + + void Profile(llvm::FoldingSetNodeID &ID) const override { + static int x = 0; + ID.AddPointer(&x); + } + + PathDiagnosticPiece *VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR) override; + + /// If the statement is a message send expression with nil receiver, returns + /// the receiver expression. Returns NULL otherwise. + static const Expr *getNilReceiver(const Stmt *S, const ExplodedNode *N); +}; + +/// Visitor that tries to report interesting diagnostics from conditions. +class ConditionBRVisitor final + : public BugReporterVisitorImpl<ConditionBRVisitor> { +public: + void Profile(llvm::FoldingSetNodeID &ID) const override { + static int x = 0; + ID.AddPointer(&x); + } + + /// Return the tag associated with this visitor. This tag will be used + /// to make all PathDiagnosticPieces created by this visitor. + static const char *getTag(); + + PathDiagnosticPiece *VisitNode(const ExplodedNode *N, + const ExplodedNode *Prev, + BugReporterContext &BRC, + BugReport &BR) override; + + PathDiagnosticPiece *VisitNodeImpl(const ExplodedNode *N, + const ExplodedNode *Prev, + BugReporterContext &BRC, + BugReport &BR); + + PathDiagnosticPiece *VisitTerminator(const Stmt *Term, + const ExplodedNode *N, + const CFGBlock *srcBlk, + const CFGBlock *dstBlk, + BugReport &R, + BugReporterContext &BRC); + + PathDiagnosticPiece *VisitTrueTest(const Expr *Cond, + bool tookTrue, + BugReporterContext &BRC, + BugReport &R, + const ExplodedNode *N); + + PathDiagnosticPiece *VisitTrueTest(const Expr *Cond, + const DeclRefExpr *DR, + const bool tookTrue, + BugReporterContext &BRC, + BugReport &R, + const ExplodedNode *N); + + PathDiagnosticPiece *VisitTrueTest(const Expr *Cond, + const BinaryOperator *BExpr, + const bool tookTrue, + BugReporterContext &BRC, + BugReport &R, + const ExplodedNode *N); + + PathDiagnosticPiece *VisitConditionVariable(StringRef LhsString, + const Expr *CondVarExpr, + const bool tookTrue, + BugReporterContext &BRC, + BugReport &R, + const ExplodedNode *N); + + bool patternMatch(const Expr *Ex, + raw_ostream &Out, + BugReporterContext &BRC, + BugReport &R, + const ExplodedNode *N, + Optional<bool> &prunable); +}; + +/// \brief Suppress reports that might lead to known false positives. +/// +/// Currently this suppresses reports based on locations of bugs. +class LikelyFalsePositiveSuppressionBRVisitor final + : public BugReporterVisitorImpl<LikelyFalsePositiveSuppressionBRVisitor> { +public: + static void *getTag() { + static int Tag = 0; + return static_cast<void *>(&Tag); + } + + void Profile(llvm::FoldingSetNodeID &ID) const override { + ID.AddPointer(getTag()); + } + + PathDiagnosticPiece *VisitNode(const ExplodedNode *N, + const ExplodedNode *Prev, + BugReporterContext &BRC, + BugReport &BR) override { + return nullptr; + } + + std::unique_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC, + const ExplodedNode *N, + BugReport &BR) override; +}; + +/// \brief When a region containing undefined value or '0' value is passed +/// as an argument in a call, marks the call as interesting. +/// +/// As a result, BugReporter will not prune the path through the function even +/// if the region's contents are not modified/accessed by the call. +class UndefOrNullArgVisitor final + : public BugReporterVisitorImpl<UndefOrNullArgVisitor> { + + /// The interesting memory region this visitor is tracking. + const MemRegion *R; + +public: + UndefOrNullArgVisitor(const MemRegion *InR) : R(InR) {} + + void Profile(llvm::FoldingSetNodeID &ID) const override { + static int Tag = 0; + ID.AddPointer(&Tag); + ID.AddPointer(R); + } + + PathDiagnosticPiece *VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR) override; +}; + +class SuppressInlineDefensiveChecksVisitor final + : public BugReporterVisitorImpl<SuppressInlineDefensiveChecksVisitor> { + /// The symbolic value for which we are tracking constraints. + /// This value is constrained to null in the end of path. + DefinedSVal V; + + /// Track if we found the node where the constraint was first added. + bool IsSatisfied; + + /// Since the visitors can be registered on nodes previous to the last + /// node in the BugReport, but the path traversal always starts with the last + /// node, the visitor invariant (that we start with a node in which V is null) + /// might not hold when node visitation starts. We are going to start tracking + /// from the last node in which the value is null. + bool IsTrackingTurnedOn; + +public: + SuppressInlineDefensiveChecksVisitor(DefinedSVal Val, const ExplodedNode *N); + + void Profile(llvm::FoldingSetNodeID &ID) const override; + + /// Return the tag associated with this visitor. This tag will be used + /// to make all PathDiagnosticPieces created by this visitor. + static const char *getTag(); + + PathDiagnosticPiece *VisitNode(const ExplodedNode *Succ, + const ExplodedNode *Pred, + BugReporterContext &BRC, + BugReport &BR) override; +}; + +namespace bugreporter { + +/// Attempts to add visitors to trace a null or undefined value back to its +/// point of origin, whether it is a symbol constrained to null or an explicit +/// assignment. +/// +/// \param N A node "downstream" from the evaluation of the statement. +/// \param S The statement whose value is null or undefined. +/// \param R The bug report to which visitors should be attached. +/// \param IsArg Whether the statement is an argument to an inlined function. +/// If this is the case, \p N \em must be the CallEnter node for +/// the function. +/// \param EnableNullFPSuppression Whether we should employ false positive +/// suppression (inlined defensive checks, returned null). +/// +/// \return Whether or not the function was able to add visitors for this +/// statement. Note that returning \c true does not actually imply +/// that any visitors were added. +bool trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, BugReport &R, + bool IsArg = false, + bool EnableNullFPSuppression = true); + +const Expr *getDerefExpr(const Stmt *S); +const Stmt *GetDenomExpr(const ExplodedNode *N); +const Stmt *GetRetValExpr(const ExplodedNode *N); +bool isDeclRefExprToReference(const Expr *E); + + +} // end namespace clang +} // end namespace ento +} // end namespace bugreporter + + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h new file mode 100644 index 0000000..16226e9 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h @@ -0,0 +1,81 @@ +//===--- 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_STATICANALYZER_CORE_BUGREPORTER_BUGTYPE_H +#define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGTYPE_H + +#include "clang/Basic/LLVM.h" +#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "llvm/ADT/FoldingSet.h" +#include <string> + +namespace clang { + +namespace ento { + +class BugReporter; +class ExplodedNode; +class ExprEngine; + +class BugType { +private: + const CheckName Check; + const std::string Name; + const std::string Category; + bool SuppressonSink; + + virtual void anchor(); +public: + BugType(class CheckName check, StringRef name, StringRef cat) + : Check(check), Name(name), Category(cat), SuppressonSink(false) {} + BugType(const CheckerBase *checker, StringRef name, StringRef cat) + : Check(checker->getCheckName()), Name(name), Category(cat), + SuppressonSink(false) {} + virtual ~BugType() {} + + // FIXME: Should these be made strings as well? + StringRef getName() const { return Name; } + StringRef getCategory() const { return Category; } + StringRef getCheckName() const { return Check.getName(); } + + /// 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); +}; + +class BuiltinBug : public BugType { + const std::string desc; + void anchor() override; +public: + BuiltinBug(class CheckName check, const char *name, const char *description) + : BugType(check, name, categories::LogicError), desc(description) {} + + BuiltinBug(const CheckerBase *checker, const char *name, + const char *description) + : BugType(checker, name, categories::LogicError), desc(description) {} + + BuiltinBug(const CheckerBase *checker, const char *name) + : BugType(checker, name, categories::LogicError), desc(name) {} + + StringRef getDescription() const { return desc; } +}; + +} // end GR namespace + +} // end clang namespace +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h new file mode 100644 index 0000000..8df2bc3 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h @@ -0,0 +1,25 @@ +//=--- CommonBugCategories.h - Provides common issue categories -*- 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_STATICANALYZER_CORE_BUGREPORTER_COMMONBUGCATEGORIES_H +#define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_COMMONBUGCATEGORIES_H + +// Common strings used for the "category" of many static analyzer issues. +namespace clang { + namespace ento { + namespace categories { + extern const char * const CoreFoundationObjectiveC; + extern const char * const LogicError; + extern const char * const MemoryCoreFoundationObjectiveC; + extern const char * const UnixAPI; + } + } +} +#endif + diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h new file mode 100644 index 0000000..35421f9 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h @@ -0,0 +1,848 @@ +//===--- PathDiagnostic.h - Path-Specific Diagnostic Handling ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the PathDiagnostic-related interfaces. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_PATHDIAGNOSTIC_H +#define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_PATHDIAGNOSTIC_H + +#include "clang/Analysis/ProgramPoint.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/PointerUnion.h" +#include <deque> +#include <iterator> +#include <list> +#include <string> +#include <vector> + +namespace clang { +class ConditionalOperator; +class AnalysisDeclContext; +class BinaryOperator; +class CompoundStmt; +class Decl; +class LocationContext; +class MemberExpr; +class ParentMap; +class ProgramPoint; +class SourceManager; +class Stmt; +class CallExpr; + +namespace ento { + +class ExplodedNode; +class SymExpr; +typedef const SymExpr* SymbolRef; + +//===----------------------------------------------------------------------===// +// High-level interface for handlers of path-sensitive diagnostics. +//===----------------------------------------------------------------------===// + +class PathDiagnostic; + +class PathDiagnosticConsumer { +public: + class PDFileEntry : public llvm::FoldingSetNode { + public: + PDFileEntry(llvm::FoldingSetNodeID &NodeID) : NodeID(NodeID) {} + + typedef std::vector<std::pair<StringRef, StringRef> > ConsumerFiles; + + /// \brief A vector of <consumer,file> pairs. + ConsumerFiles files; + + /// \brief A precomputed hash tag used for uniquing PDFileEntry objects. + const llvm::FoldingSetNodeID NodeID; + + /// \brief Used for profiling in the FoldingSet. + void Profile(llvm::FoldingSetNodeID &ID) { ID = NodeID; } + }; + + class FilesMade { + llvm::BumpPtrAllocator Alloc; + llvm::FoldingSet<PDFileEntry> Set; + + public: + ~FilesMade(); + + bool empty() const { return Set.empty(); } + + void addDiagnostic(const PathDiagnostic &PD, + StringRef ConsumerName, + StringRef fileName); + + PDFileEntry::ConsumerFiles *getFiles(const PathDiagnostic &PD); + }; + +private: + virtual void anchor(); +public: + PathDiagnosticConsumer() : flushed(false) {} + virtual ~PathDiagnosticConsumer(); + + void FlushDiagnostics(FilesMade *FilesMade); + + virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, + FilesMade *filesMade) = 0; + + virtual StringRef getName() const = 0; + + void HandlePathDiagnostic(std::unique_ptr<PathDiagnostic> D); + + enum PathGenerationScheme { None, Minimal, Extensive, AlternateExtensive }; + virtual PathGenerationScheme getGenerationScheme() const { return Minimal; } + virtual bool supportsLogicalOpControlFlow() const { return false; } + + /// Return true if the PathDiagnosticConsumer supports individual + /// PathDiagnostics that span multiple files. + virtual bool supportsCrossFileDiagnostics() const { return false; } + +protected: + bool flushed; + llvm::FoldingSet<PathDiagnostic> Diags; +}; + +//===----------------------------------------------------------------------===// +// Path-sensitive diagnostics. +//===----------------------------------------------------------------------===// + +class PathDiagnosticRange : public SourceRange { +public: + bool isPoint; + + PathDiagnosticRange(SourceRange R, bool isP = false) + : SourceRange(R), isPoint(isP) {} + + PathDiagnosticRange() : isPoint(false) {} +}; + +typedef llvm::PointerUnion<const LocationContext*, AnalysisDeclContext*> + LocationOrAnalysisDeclContext; + +class PathDiagnosticLocation { +private: + enum Kind { RangeK, SingleLocK, StmtK, DeclK } K; + const Stmt *S; + const Decl *D; + const SourceManager *SM; + FullSourceLoc Loc; + PathDiagnosticRange Range; + + PathDiagnosticLocation(SourceLocation L, const SourceManager &sm, + Kind kind) + : K(kind), S(nullptr), D(nullptr), SM(&sm), + Loc(genLocation(L)), Range(genRange()) { + } + + FullSourceLoc genLocation( + SourceLocation L = SourceLocation(), + LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext *)nullptr) const; + + PathDiagnosticRange genRange( + LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext *)nullptr) const; + +public: + /// Create an invalid location. + PathDiagnosticLocation() + : K(SingleLocK), S(nullptr), D(nullptr), SM(nullptr) {} + + /// Create a location corresponding to the given statement. + PathDiagnosticLocation(const Stmt *s, + const SourceManager &sm, + LocationOrAnalysisDeclContext lac) + : K(s->getLocStart().isValid() ? StmtK : SingleLocK), + S(K == StmtK ? s : nullptr), + D(nullptr), SM(&sm), + Loc(genLocation(SourceLocation(), lac)), + Range(genRange(lac)) { + assert(K == SingleLocK || S); + assert(K == SingleLocK || Loc.isValid()); + assert(K == SingleLocK || Range.isValid()); + } + + /// Create a location corresponding to the given declaration. + PathDiagnosticLocation(const Decl *d, const SourceManager &sm) + : K(DeclK), S(nullptr), D(d), SM(&sm), + Loc(genLocation()), Range(genRange()) { + assert(D); + assert(Loc.isValid()); + assert(Range.isValid()); + } + + /// Create a location at an explicit offset in the source. + /// + /// This should only be used if there are no more appropriate constructors. + PathDiagnosticLocation(SourceLocation loc, const SourceManager &sm) + : K(SingleLocK), S(nullptr), D(nullptr), SM(&sm), Loc(loc, sm), + Range(genRange()) { + assert(Loc.isValid()); + assert(Range.isValid()); + } + + /// Create a location corresponding to the given declaration. + static PathDiagnosticLocation create(const Decl *D, + const SourceManager &SM) { + return PathDiagnosticLocation(D, SM); + } + + /// Create a location for the beginning of the declaration. + static PathDiagnosticLocation createBegin(const Decl *D, + const SourceManager &SM); + + /// Create a location for the beginning of the statement. + static PathDiagnosticLocation createBegin(const Stmt *S, + const SourceManager &SM, + const LocationOrAnalysisDeclContext LAC); + + /// Create a location for the end of the statement. + /// + /// If the statement is a CompoundStatement, the location will point to the + /// closing brace instead of following it. + static PathDiagnosticLocation createEnd(const Stmt *S, + const SourceManager &SM, + const LocationOrAnalysisDeclContext LAC); + + /// Create the location for the operator of the binary expression. + /// Assumes the statement has a valid location. + static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO, + const SourceManager &SM); + static PathDiagnosticLocation createConditionalColonLoc( + const ConditionalOperator *CO, + const SourceManager &SM); + + /// For member expressions, return the location of the '.' or '->'. + /// Assumes the statement has a valid location. + static PathDiagnosticLocation createMemberLoc(const MemberExpr *ME, + const SourceManager &SM); + + /// Create a location for the beginning of the compound statement. + /// Assumes the statement has a valid location. + static PathDiagnosticLocation createBeginBrace(const CompoundStmt *CS, + const SourceManager &SM); + + /// Create a location for the end of the compound statement. + /// Assumes the statement has a valid location. + static PathDiagnosticLocation createEndBrace(const CompoundStmt *CS, + const SourceManager &SM); + + /// Create a location for the beginning of the enclosing declaration body. + /// Defaults to the beginning of the first statement in the declaration body. + static PathDiagnosticLocation createDeclBegin(const LocationContext *LC, + const SourceManager &SM); + + /// Constructs a location for the end of the enclosing declaration body. + /// Defaults to the end of brace. + static PathDiagnosticLocation createDeclEnd(const LocationContext *LC, + const SourceManager &SM); + + /// Create a location corresponding to the given valid ExplodedNode. + static PathDiagnosticLocation create(const ProgramPoint& P, + const SourceManager &SMng); + + /// Create a location corresponding to the next valid ExplodedNode as end + /// of path location. + static PathDiagnosticLocation createEndOfPath(const ExplodedNode* N, + const SourceManager &SM); + + /// Convert the given location into a single kind location. + static PathDiagnosticLocation createSingleLocation( + const PathDiagnosticLocation &PDL); + + bool operator==(const PathDiagnosticLocation &X) const { + return K == X.K && Loc == X.Loc && Range == X.Range; + } + + bool operator!=(const PathDiagnosticLocation &X) const { + return !(*this == X); + } + + bool isValid() const { + return SM != nullptr; + } + + FullSourceLoc asLocation() const { + return Loc; + } + + PathDiagnosticRange asRange() const { + return Range; + } + + const Stmt *asStmt() const { assert(isValid()); return S; } + const Decl *asDecl() const { assert(isValid()); return D; } + + bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; } + + void invalidate() { + *this = PathDiagnosticLocation(); + } + + void flatten(); + + const SourceManager& getManager() const { assert(isValid()); return *SM; } + + void Profile(llvm::FoldingSetNodeID &ID) const; + + void dump() const; + + /// \brief Given an exploded node, retrieve the statement that should be used + /// for the diagnostic location. + static const Stmt *getStmt(const ExplodedNode *N); + + /// \brief Retrieve the statement corresponding to the successor node. + static const Stmt *getNextStmt(const ExplodedNode *N); +}; + +class PathDiagnosticLocationPair { +private: + PathDiagnosticLocation Start, End; +public: + PathDiagnosticLocationPair(const PathDiagnosticLocation &start, + const PathDiagnosticLocation &end) + : Start(start), End(end) {} + + const PathDiagnosticLocation &getStart() const { return Start; } + const PathDiagnosticLocation &getEnd() const { return End; } + + void setStart(const PathDiagnosticLocation &L) { Start = L; } + void setEnd(const PathDiagnosticLocation &L) { End = L; } + + void flatten() { + Start.flatten(); + End.flatten(); + } + + void Profile(llvm::FoldingSetNodeID &ID) const { + Start.Profile(ID); + End.Profile(ID); + } +}; + +//===----------------------------------------------------------------------===// +// Path "pieces" for path-sensitive diagnostics. +//===----------------------------------------------------------------------===// + +class PathDiagnosticPiece : public RefCountedBaseVPTR { +public: + enum Kind { ControlFlow, Event, Macro, Call }; + enum DisplayHint { Above, Below }; + +private: + const std::string str; + const Kind kind; + const DisplayHint Hint; + + /// \brief In the containing bug report, this piece is the last piece from + /// the main source file. + bool LastInMainSourceFile; + + /// A constant string that can be used to tag the PathDiagnosticPiece, + /// typically with the identification of the creator. The actual pointer + /// value is meant to be an identifier; the string itself is useful for + /// debugging. + StringRef Tag; + + std::vector<SourceRange> ranges; + + PathDiagnosticPiece() = delete; + PathDiagnosticPiece(const PathDiagnosticPiece &P) = delete; + void operator=(const PathDiagnosticPiece &P) = delete; + +protected: + PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below); + + PathDiagnosticPiece(Kind k, DisplayHint hint = Below); + +public: + ~PathDiagnosticPiece() override; + + StringRef getString() const { return str; } + + /// Tag this PathDiagnosticPiece with the given C-string. + void setTag(const char *tag) { Tag = tag; } + + /// Return the opaque tag (if any) on the PathDiagnosticPiece. + const void *getTag() const { return Tag.data(); } + + /// Return the string representation of the tag. This is useful + /// for debugging. + StringRef getTagStr() const { return Tag; } + + /// getDisplayHint - Return a hint indicating where the diagnostic should + /// be displayed by the PathDiagnosticConsumer. + DisplayHint getDisplayHint() const { return Hint; } + + virtual PathDiagnosticLocation getLocation() const = 0; + virtual void flattenLocations() = 0; + + Kind getKind() const { return kind; } + + void addRange(SourceRange R) { + if (!R.isValid()) + return; + ranges.push_back(R); + } + + void addRange(SourceLocation B, SourceLocation E) { + if (!B.isValid() || !E.isValid()) + return; + ranges.push_back(SourceRange(B,E)); + } + + /// Return the SourceRanges associated with this PathDiagnosticPiece. + ArrayRef<SourceRange> getRanges() const { return ranges; } + + virtual void Profile(llvm::FoldingSetNodeID &ID) const; + + void setAsLastInMainSourceFile() { + LastInMainSourceFile = true; + } + + bool isLastInMainSourceFile() const { + return LastInMainSourceFile; + } + + virtual void dump() const = 0; +}; + + +class PathPieces : public std::list<IntrusiveRefCntPtr<PathDiagnosticPiece> > { + void flattenTo(PathPieces &Primary, PathPieces &Current, + bool ShouldFlattenMacros) const; +public: + + PathPieces flatten(bool ShouldFlattenMacros) const { + PathPieces Result; + flattenTo(Result, Result, ShouldFlattenMacros); + return Result; + } + + void dump() const; +}; + +class PathDiagnosticSpotPiece : public PathDiagnosticPiece { +private: + PathDiagnosticLocation Pos; +public: + PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos, + StringRef s, + PathDiagnosticPiece::Kind k, + bool addPosRange = true) + : PathDiagnosticPiece(s, k), Pos(pos) { + assert(Pos.isValid() && Pos.asLocation().isValid() && + "PathDiagnosticSpotPiece's must have a valid location."); + if (addPosRange && Pos.hasRange()) addRange(Pos.asRange()); + } + + PathDiagnosticLocation getLocation() const override { return Pos; } + void flattenLocations() override { Pos.flatten(); } + + void Profile(llvm::FoldingSetNodeID &ID) const override; + + static bool classof(const PathDiagnosticPiece *P) { + return P->getKind() == Event || P->getKind() == Macro; + } +}; + +/// \brief Interface for classes constructing Stack hints. +/// +/// If a PathDiagnosticEvent occurs in a different frame than the final +/// diagnostic the hints can be used to summarize the effect of the call. +class StackHintGenerator { +public: + virtual ~StackHintGenerator() = 0; + + /// \brief Construct the Diagnostic message for the given ExplodedNode. + virtual std::string getMessage(const ExplodedNode *N) = 0; +}; + +/// \brief Constructs a Stack hint for the given symbol. +/// +/// The class knows how to construct the stack hint message based on +/// traversing the CallExpr associated with the call and checking if the given +/// symbol is returned or is one of the arguments. +/// The hint can be customized by redefining 'getMessageForX()' methods. +class StackHintGeneratorForSymbol : public StackHintGenerator { +private: + SymbolRef Sym; + std::string Msg; + +public: + StackHintGeneratorForSymbol(SymbolRef S, StringRef M) : Sym(S), Msg(M) {} + ~StackHintGeneratorForSymbol() override {} + + /// \brief Search the call expression for the symbol Sym and dispatch the + /// 'getMessageForX()' methods to construct a specific message. + std::string getMessage(const ExplodedNode *N) override; + + /// Produces the message of the following form: + /// 'Msg via Nth parameter' + virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex); + virtual std::string getMessageForReturn(const CallExpr *CallExpr) { + return Msg; + } + virtual std::string getMessageForSymbolNotFound() { + return Msg; + } +}; + +class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece { + Optional<bool> IsPrunable; + + /// If the event occurs in a different frame than the final diagnostic, + /// supply a message that will be used to construct an extra hint on the + /// returns from all the calls on the stack from this event to the final + /// diagnostic. + std::unique_ptr<StackHintGenerator> CallStackHint; + +public: + PathDiagnosticEventPiece(const PathDiagnosticLocation &pos, + StringRef s, bool addPosRange = true, + StackHintGenerator *stackHint = nullptr) + : PathDiagnosticSpotPiece(pos, s, Event, addPosRange), + CallStackHint(stackHint) {} + + ~PathDiagnosticEventPiece() override; + + /// Mark the diagnostic piece as being potentially prunable. This + /// flag may have been previously set, at which point it will not + /// be reset unless one specifies to do so. + void setPrunable(bool isPrunable, bool override = false) { + if (IsPrunable.hasValue() && !override) + return; + IsPrunable = isPrunable; + } + + /// Return true if the diagnostic piece is prunable. + bool isPrunable() const { + return IsPrunable.hasValue() ? IsPrunable.getValue() : false; + } + + bool hasCallStackHint() { return (bool)CallStackHint; } + + /// Produce the hint for the given node. The node contains + /// information about the call for which the diagnostic can be generated. + std::string getCallStackMessage(const ExplodedNode *N) { + if (CallStackHint) + return CallStackHint->getMessage(N); + return ""; + } + + void dump() const override; + + static inline bool classof(const PathDiagnosticPiece *P) { + return P->getKind() == Event; + } +}; + +class PathDiagnosticCallPiece : public PathDiagnosticPiece { + PathDiagnosticCallPiece(const Decl *callerD, + const PathDiagnosticLocation &callReturnPos) + : PathDiagnosticPiece(Call), Caller(callerD), Callee(nullptr), + NoExit(false), callReturn(callReturnPos) {} + + PathDiagnosticCallPiece(PathPieces &oldPath, const Decl *caller) + : PathDiagnosticPiece(Call), Caller(caller), Callee(nullptr), + NoExit(true), path(oldPath) {} + + const Decl *Caller; + const Decl *Callee; + + // Flag signifying that this diagnostic has only call enter and no matching + // call exit. + bool NoExit; + + // The custom string, which should appear after the call Return Diagnostic. + // TODO: Should we allow multiple diagnostics? + std::string CallStackMessage; + +public: + PathDiagnosticLocation callEnter; + PathDiagnosticLocation callEnterWithin; + PathDiagnosticLocation callReturn; + PathPieces path; + + ~PathDiagnosticCallPiece() override; + + const Decl *getCaller() const { return Caller; } + + const Decl *getCallee() const { return Callee; } + void setCallee(const CallEnter &CE, const SourceManager &SM); + + bool hasCallStackMessage() { return !CallStackMessage.empty(); } + void setCallStackMessage(StringRef st) { + CallStackMessage = st; + } + + PathDiagnosticLocation getLocation() const override { + return callEnter; + } + + IntrusiveRefCntPtr<PathDiagnosticEventPiece> getCallEnterEvent() const; + IntrusiveRefCntPtr<PathDiagnosticEventPiece> + getCallEnterWithinCallerEvent() const; + IntrusiveRefCntPtr<PathDiagnosticEventPiece> getCallExitEvent() const; + + void flattenLocations() override { + callEnter.flatten(); + callReturn.flatten(); + for (PathPieces::iterator I = path.begin(), + E = path.end(); I != E; ++I) (*I)->flattenLocations(); + } + + static PathDiagnosticCallPiece *construct(const ExplodedNode *N, + const CallExitEnd &CE, + const SourceManager &SM); + + static PathDiagnosticCallPiece *construct(PathPieces &pieces, + const Decl *caller); + + void dump() const override; + + void Profile(llvm::FoldingSetNodeID &ID) const override; + + static inline bool classof(const PathDiagnosticPiece *P) { + return P->getKind() == Call; + } +}; + +class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece { + std::vector<PathDiagnosticLocationPair> LPairs; +public: + PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, + const PathDiagnosticLocation &endPos, + StringRef s) + : PathDiagnosticPiece(s, ControlFlow) { + LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); + } + + PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, + const PathDiagnosticLocation &endPos) + : PathDiagnosticPiece(ControlFlow) { + LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); + } + + ~PathDiagnosticControlFlowPiece() override; + + PathDiagnosticLocation getStartLocation() const { + assert(!LPairs.empty() && + "PathDiagnosticControlFlowPiece needs at least one location."); + return LPairs[0].getStart(); + } + + PathDiagnosticLocation getEndLocation() const { + assert(!LPairs.empty() && + "PathDiagnosticControlFlowPiece needs at least one location."); + return LPairs[0].getEnd(); + } + + void setStartLocation(const PathDiagnosticLocation &L) { + LPairs[0].setStart(L); + } + + void setEndLocation(const PathDiagnosticLocation &L) { + LPairs[0].setEnd(L); + } + + void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); } + + PathDiagnosticLocation getLocation() const override { + return getStartLocation(); + } + + typedef std::vector<PathDiagnosticLocationPair>::iterator iterator; + iterator begin() { return LPairs.begin(); } + iterator end() { return LPairs.end(); } + + void flattenLocations() override { + for (iterator I=begin(), E=end(); I!=E; ++I) I->flatten(); + } + + typedef std::vector<PathDiagnosticLocationPair>::const_iterator + const_iterator; + const_iterator begin() const { return LPairs.begin(); } + const_iterator end() const { return LPairs.end(); } + + static inline bool classof(const PathDiagnosticPiece *P) { + return P->getKind() == ControlFlow; + } + + void dump() const override; + + void Profile(llvm::FoldingSetNodeID &ID) const override; +}; + +class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece { +public: + PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos) + : PathDiagnosticSpotPiece(pos, "", Macro) {} + + ~PathDiagnosticMacroPiece() override; + + PathPieces subPieces; + + bool containsEvent() const; + + void flattenLocations() override { + PathDiagnosticSpotPiece::flattenLocations(); + for (PathPieces::iterator I = subPieces.begin(), + E = subPieces.end(); I != E; ++I) (*I)->flattenLocations(); + } + + static inline bool classof(const PathDiagnosticPiece *P) { + return P->getKind() == Macro; + } + + void dump() const override; + + void Profile(llvm::FoldingSetNodeID &ID) const override; +}; + +/// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive +/// diagnostic. It represents an ordered-collection of PathDiagnosticPieces, +/// each which represent the pieces of the path. +class PathDiagnostic : public llvm::FoldingSetNode { + std::string CheckName; + const Decl *DeclWithIssue; + std::string BugType; + std::string VerboseDesc; + std::string ShortDesc; + std::string Category; + std::deque<std::string> OtherDesc; + + /// \brief Loc The location of the path diagnostic report. + PathDiagnosticLocation Loc; + + PathPieces pathImpl; + SmallVector<PathPieces *, 3> pathStack; + + /// \brief Important bug uniqueing location. + /// The location info is useful to differentiate between bugs. + PathDiagnosticLocation UniqueingLoc; + const Decl *UniqueingDecl; + + PathDiagnostic() = delete; +public: + PathDiagnostic(StringRef CheckName, const Decl *DeclWithIssue, + StringRef bugtype, StringRef verboseDesc, StringRef shortDesc, + StringRef category, PathDiagnosticLocation LocationToUnique, + const Decl *DeclToUnique); + + ~PathDiagnostic(); + + const PathPieces &path; + + /// Return the path currently used by builders for constructing the + /// PathDiagnostic. + PathPieces &getActivePath() { + if (pathStack.empty()) + return pathImpl; + return *pathStack.back(); + } + + /// Return a mutable version of 'path'. + PathPieces &getMutablePieces() { + return pathImpl; + } + + /// Return the unrolled size of the path. + unsigned full_size(); + + void pushActivePath(PathPieces *p) { pathStack.push_back(p); } + void popActivePath() { if (!pathStack.empty()) pathStack.pop_back(); } + + bool isWithinCall() const { return !pathStack.empty(); } + + void setEndOfPath(std::unique_ptr<PathDiagnosticPiece> EndPiece) { + assert(!Loc.isValid() && "End location already set!"); + Loc = EndPiece->getLocation(); + assert(Loc.isValid() && "Invalid location for end-of-path piece"); + getActivePath().push_back(EndPiece.release()); + } + + void appendToDesc(StringRef S) { + if (!ShortDesc.empty()) + ShortDesc.append(S); + VerboseDesc.append(S); + } + + void resetPath() { + pathStack.clear(); + pathImpl.clear(); + Loc = PathDiagnosticLocation(); + } + + /// \brief If the last piece of the report point to the header file, resets + /// the location of the report to be the last location in the main source + /// file. + void resetDiagnosticLocationToMainFile(); + + StringRef getVerboseDescription() const { return VerboseDesc; } + StringRef getShortDescription() const { + return ShortDesc.empty() ? VerboseDesc : ShortDesc; + } + StringRef getCheckName() const { return CheckName; } + StringRef getBugType() const { return BugType; } + StringRef getCategory() const { return Category; } + + /// Return the semantic context where an issue occurred. If the + /// issue occurs along a path, this represents the "central" area + /// where the bug manifests. + const Decl *getDeclWithIssue() const { return DeclWithIssue; } + + typedef std::deque<std::string>::const_iterator meta_iterator; + meta_iterator meta_begin() const { return OtherDesc.begin(); } + meta_iterator meta_end() const { return OtherDesc.end(); } + void addMeta(StringRef s) { OtherDesc.push_back(s); } + + PathDiagnosticLocation getLocation() const { + assert(Loc.isValid() && "No report location set yet!"); + return Loc; + } + + /// \brief Get the location on which the report should be uniqued. + PathDiagnosticLocation getUniqueingLoc() const { + return UniqueingLoc; + } + + /// \brief Get the declaration containing the uniqueing location. + const Decl *getUniqueingDecl() const { + return UniqueingDecl; + } + + void flattenLocations() { + Loc.flatten(); + for (PathPieces::iterator I = pathImpl.begin(), E = pathImpl.end(); + I != E; ++I) (*I)->flattenLocations(); + } + + /// Profiles the diagnostic, independent of the path it references. + /// + /// This can be used to merge diagnostics that refer to the same issue + /// along different paths. + void Profile(llvm::FoldingSetNodeID &ID) const; + + /// Profiles the diagnostic, including its path. + /// + /// Two diagnostics with the same issue along different paths will generate + /// different profiles. + void FullProfile(llvm::FoldingSetNodeID &ID) const; +}; + +} // end GR namespace + +} //end clang namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/Checker.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/Checker.h new file mode 100644 index 0000000..1410af1 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/Checker.h @@ -0,0 +1,554 @@ +//== Checker.h - Registration mechanism for checkers -------------*- C++ -*--=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines Checker, used to create and register checkers. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_CHECKER_H +#define LLVM_CLANG_STATICANALYZER_CORE_CHECKER_H + +#include "clang/Analysis/ProgramPoint.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" +#include "llvm/Support/Casting.h" + +namespace clang { +namespace ento { + class BugReporter; + +namespace check { + +template <typename DECL> +class ASTDecl { + template <typename CHECKER> + static void _checkDecl(void *checker, const Decl *D, AnalysisManager& mgr, + BugReporter &BR) { + ((const CHECKER *)checker)->checkASTDecl(cast<DECL>(D), mgr, BR); + } + + static bool _handlesDecl(const Decl *D) { + return isa<DECL>(D); + } +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForDecl(CheckerManager::CheckDeclFunc(checker, + _checkDecl<CHECKER>), + _handlesDecl); + } +}; + +class ASTCodeBody { + template <typename CHECKER> + static void _checkBody(void *checker, const Decl *D, AnalysisManager& mgr, + BugReporter &BR) { + ((const CHECKER *)checker)->checkASTCodeBody(D, mgr, BR); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForBody(CheckerManager::CheckDeclFunc(checker, + _checkBody<CHECKER>)); + } +}; + +class EndOfTranslationUnit { + template <typename CHECKER> + static void _checkEndOfTranslationUnit(void *checker, + const TranslationUnitDecl *TU, + AnalysisManager& mgr, + BugReporter &BR) { + ((const CHECKER *)checker)->checkEndOfTranslationUnit(TU, mgr, BR); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr){ + mgr._registerForEndOfTranslationUnit( + CheckerManager::CheckEndOfTranslationUnit(checker, + _checkEndOfTranslationUnit<CHECKER>)); + } +}; + +template <typename STMT> +class PreStmt { + template <typename CHECKER> + static void _checkStmt(void *checker, const Stmt *S, CheckerContext &C) { + ((const CHECKER *)checker)->checkPreStmt(cast<STMT>(S), C); + } + + static bool _handlesStmt(const Stmt *S) { + return isa<STMT>(S); + } +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForPreStmt(CheckerManager::CheckStmtFunc(checker, + _checkStmt<CHECKER>), + _handlesStmt); + } +}; + +template <typename STMT> +class PostStmt { + template <typename CHECKER> + static void _checkStmt(void *checker, const Stmt *S, CheckerContext &C) { + ((const CHECKER *)checker)->checkPostStmt(cast<STMT>(S), C); + } + + static bool _handlesStmt(const Stmt *S) { + return isa<STMT>(S); + } +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForPostStmt(CheckerManager::CheckStmtFunc(checker, + _checkStmt<CHECKER>), + _handlesStmt); + } +}; + +class PreObjCMessage { + template <typename CHECKER> + static void _checkObjCMessage(void *checker, const ObjCMethodCall &msg, + CheckerContext &C) { + ((const CHECKER *)checker)->checkPreObjCMessage(msg, C); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForPreObjCMessage( + CheckerManager::CheckObjCMessageFunc(checker, _checkObjCMessage<CHECKER>)); + } +}; + +class ObjCMessageNil { + template <typename CHECKER> + static void _checkObjCMessage(void *checker, const ObjCMethodCall &msg, + CheckerContext &C) { + ((const CHECKER *)checker)->checkObjCMessageNil(msg, C); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForObjCMessageNil( + CheckerManager::CheckObjCMessageFunc(checker, _checkObjCMessage<CHECKER>)); + } +}; + +class PostObjCMessage { + template <typename CHECKER> + static void _checkObjCMessage(void *checker, const ObjCMethodCall &msg, + CheckerContext &C) { + ((const CHECKER *)checker)->checkPostObjCMessage(msg, C); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForPostObjCMessage( + CheckerManager::CheckObjCMessageFunc(checker, _checkObjCMessage<CHECKER>)); + } +}; + +class PreCall { + template <typename CHECKER> + static void _checkCall(void *checker, const CallEvent &msg, + CheckerContext &C) { + ((const CHECKER *)checker)->checkPreCall(msg, C); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForPreCall( + CheckerManager::CheckCallFunc(checker, _checkCall<CHECKER>)); + } +}; + +class PostCall { + template <typename CHECKER> + static void _checkCall(void *checker, const CallEvent &msg, + CheckerContext &C) { + ((const CHECKER *)checker)->checkPostCall(msg, C); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForPostCall( + CheckerManager::CheckCallFunc(checker, _checkCall<CHECKER>)); + } +}; + +class Location { + template <typename CHECKER> + static void _checkLocation(void *checker, + const SVal &location, bool isLoad, const Stmt *S, + CheckerContext &C) { + ((const CHECKER *)checker)->checkLocation(location, isLoad, S, C); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForLocation( + CheckerManager::CheckLocationFunc(checker, _checkLocation<CHECKER>)); + } +}; + +class Bind { + template <typename CHECKER> + static void _checkBind(void *checker, + const SVal &location, const SVal &val, const Stmt *S, + CheckerContext &C) { + ((const CHECKER *)checker)->checkBind(location, val, S, C); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForBind( + CheckerManager::CheckBindFunc(checker, _checkBind<CHECKER>)); + } +}; + +class EndAnalysis { + template <typename CHECKER> + static void _checkEndAnalysis(void *checker, ExplodedGraph &G, + BugReporter &BR, ExprEngine &Eng) { + ((const CHECKER *)checker)->checkEndAnalysis(G, BR, Eng); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForEndAnalysis( + CheckerManager::CheckEndAnalysisFunc(checker, _checkEndAnalysis<CHECKER>)); + } +}; + +class EndFunction { + template <typename CHECKER> + static void _checkEndFunction(void *checker, + CheckerContext &C) { + ((const CHECKER *)checker)->checkEndFunction(C); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForEndFunction( + CheckerManager::CheckEndFunctionFunc(checker, _checkEndFunction<CHECKER>)); + } +}; + +class BranchCondition { + template <typename CHECKER> + static void _checkBranchCondition(void *checker, const Stmt *Condition, + CheckerContext & C) { + ((const CHECKER *)checker)->checkBranchCondition(Condition, C); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForBranchCondition( + CheckerManager::CheckBranchConditionFunc(checker, + _checkBranchCondition<CHECKER>)); + } +}; + +class LiveSymbols { + template <typename CHECKER> + static void _checkLiveSymbols(void *checker, ProgramStateRef state, + SymbolReaper &SR) { + ((const CHECKER *)checker)->checkLiveSymbols(state, SR); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForLiveSymbols( + CheckerManager::CheckLiveSymbolsFunc(checker, _checkLiveSymbols<CHECKER>)); + } +}; + +class DeadSymbols { + template <typename CHECKER> + static void _checkDeadSymbols(void *checker, + SymbolReaper &SR, CheckerContext &C) { + ((const CHECKER *)checker)->checkDeadSymbols(SR, C); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForDeadSymbols( + CheckerManager::CheckDeadSymbolsFunc(checker, _checkDeadSymbols<CHECKER>)); + } +}; + +class RegionChanges { + template <typename CHECKER> + static ProgramStateRef + _checkRegionChanges(void *checker, + ProgramStateRef state, + const InvalidatedSymbols *invalidated, + ArrayRef<const MemRegion *> Explicits, + ArrayRef<const MemRegion *> Regions, + const CallEvent *Call) { + return ((const CHECKER *)checker)->checkRegionChanges(state, invalidated, + Explicits, Regions, Call); + } + template <typename CHECKER> + static bool _wantsRegionChangeUpdate(void *checker, + ProgramStateRef state) { + return ((const CHECKER *)checker)->wantsRegionChangeUpdate(state); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForRegionChanges( + CheckerManager::CheckRegionChangesFunc(checker, + _checkRegionChanges<CHECKER>), + CheckerManager::WantsRegionChangeUpdateFunc(checker, + _wantsRegionChangeUpdate<CHECKER>)); + } +}; + +class PointerEscape { + template <typename CHECKER> + static ProgramStateRef + _checkPointerEscape(void *Checker, + ProgramStateRef State, + const InvalidatedSymbols &Escaped, + const CallEvent *Call, + PointerEscapeKind Kind, + RegionAndSymbolInvalidationTraits *ETraits) { + + if (!ETraits) + return ((const CHECKER *)Checker)->checkPointerEscape(State, + Escaped, + Call, + Kind); + + InvalidatedSymbols RegularEscape; + for (InvalidatedSymbols::const_iterator I = Escaped.begin(), + E = Escaped.end(); I != E; ++I) + if (!ETraits->hasTrait(*I, + RegionAndSymbolInvalidationTraits::TK_PreserveContents) && + !ETraits->hasTrait(*I, + RegionAndSymbolInvalidationTraits::TK_SuppressEscape)) + RegularEscape.insert(*I); + + if (RegularEscape.empty()) + return State; + + return ((const CHECKER *)Checker)->checkPointerEscape(State, + RegularEscape, + Call, + Kind); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForPointerEscape( + CheckerManager::CheckPointerEscapeFunc(checker, + _checkPointerEscape<CHECKER>)); + } +}; + +class ConstPointerEscape { + template <typename CHECKER> + static ProgramStateRef + _checkConstPointerEscape(void *Checker, + ProgramStateRef State, + const InvalidatedSymbols &Escaped, + const CallEvent *Call, + PointerEscapeKind Kind, + RegionAndSymbolInvalidationTraits *ETraits) { + + if (!ETraits) + return State; + + InvalidatedSymbols ConstEscape; + for (InvalidatedSymbols::const_iterator I = Escaped.begin(), + E = Escaped.end(); I != E; ++I) + if (ETraits->hasTrait(*I, + RegionAndSymbolInvalidationTraits::TK_PreserveContents) && + !ETraits->hasTrait(*I, + RegionAndSymbolInvalidationTraits::TK_SuppressEscape)) + ConstEscape.insert(*I); + + if (ConstEscape.empty()) + return State; + + return ((const CHECKER *)Checker)->checkConstPointerEscape(State, + ConstEscape, + Call, + Kind); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForPointerEscape( + CheckerManager::CheckPointerEscapeFunc(checker, + _checkConstPointerEscape<CHECKER>)); + } +}; + + +template <typename EVENT> +class Event { + template <typename CHECKER> + static void _checkEvent(void *checker, const void *event) { + ((const CHECKER *)checker)->checkEvent(*(const EVENT *)event); + } +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerListenerForEvent<EVENT>( + CheckerManager::CheckEventFunc(checker, _checkEvent<CHECKER>)); + } +}; + +} // end check namespace + +namespace eval { + +class Assume { + template <typename CHECKER> + static ProgramStateRef _evalAssume(void *checker, + ProgramStateRef state, + const SVal &cond, + bool assumption) { + return ((const CHECKER *)checker)->evalAssume(state, cond, assumption); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForEvalAssume( + CheckerManager::EvalAssumeFunc(checker, _evalAssume<CHECKER>)); + } +}; + +class Call { + template <typename CHECKER> + static bool _evalCall(void *checker, const CallExpr *CE, CheckerContext &C) { + return ((const CHECKER *)checker)->evalCall(CE, C); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForEvalCall( + CheckerManager::EvalCallFunc(checker, _evalCall<CHECKER>)); + } +}; + +} // end eval namespace + +class CheckerBase : public ProgramPointTag { + CheckName Name; + friend class ::clang::ento::CheckerManager; + +public: + StringRef getTagDescription() const override; + CheckName getCheckName() const; + + /// See CheckerManager::runCheckersForPrintState. + virtual void printState(raw_ostream &Out, ProgramStateRef State, + const char *NL, const char *Sep) const { } +}; + +/// Dump checker name to stream. +raw_ostream& operator<<(raw_ostream &Out, const CheckerBase &Checker); + +/// Tag that can use a checker name as a message provider +/// (see SimpleProgramPointTag). +class CheckerProgramPointTag : public SimpleProgramPointTag { +public: + CheckerProgramPointTag(StringRef CheckerName, StringRef Msg); + CheckerProgramPointTag(const CheckerBase *Checker, StringRef Msg); +}; + +template <typename CHECK1, typename... CHECKs> +class Checker : public CHECK1, public CHECKs..., public CheckerBase { +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + CHECK1::_register(checker, mgr); + Checker<CHECKs...>::_register(checker, mgr); + } +}; + +template <typename CHECK1> +class Checker<CHECK1> : public CHECK1, public CheckerBase { +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + CHECK1::_register(checker, mgr); + } +}; + +template <typename EVENT> +class EventDispatcher { + CheckerManager *Mgr; +public: + EventDispatcher() : Mgr(nullptr) { } + + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerDispatcherForEvent<EVENT>(); + static_cast<EventDispatcher<EVENT> *>(checker)->Mgr = &mgr; + } + + void dispatchEvent(const EVENT &event) const { + Mgr->_dispatchEvent(event); + } +}; + +/// \brief We dereferenced a location that may be null. +struct ImplicitNullDerefEvent { + SVal Location; + bool IsLoad; + ExplodedNode *SinkNode; + BugReporter *BR; + // When true, the dereference is in the source code directly. When false, the + // dereference might happen later (for example pointer passed to a parameter + // that is marked with nonnull attribute.) + bool IsDirectDereference; +}; + +/// \brief A helper class which wraps a boolean value set to false by default. +/// +/// This class should behave exactly like 'bool' except that it doesn't need to +/// be explicitly initialized. +struct DefaultBool { + bool val; + DefaultBool() : val(false) {} + /*implicit*/ operator bool&() { return val; } + /*implicit*/ operator const bool&() const { return val; } + DefaultBool &operator=(bool b) { val = b; return *this; } +}; + +} // end ento namespace + +} // end clang namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h new file mode 100644 index 0000000..bc9af49 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -0,0 +1,632 @@ +//===--- CheckerManager.h - Static Analyzer Checker Manager -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Defines the Static Analyzer Checker Manager. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_CHECKERMANAGER_H +#define LLVM_CLANG_STATICANALYZER_CORE_CHECKERMANAGER_H + +#include "clang/Analysis/ProgramPoint.h" +#include "clang/Basic/LangOptions.h" +#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" +#include <vector> + +namespace clang { + class Decl; + class Stmt; + class CallExpr; + +namespace ento { + class CheckerBase; + class CheckerRegistry; + class ExprEngine; + class AnalysisManager; + class BugReporter; + class CheckerContext; + class ObjCMethodCall; + class SVal; + class ExplodedNode; + class ExplodedNodeSet; + class ExplodedGraph; + class ProgramState; + class NodeBuilder; + struct NodeBuilderContext; + class MemRegion; + class SymbolReaper; + +template <typename T> class CheckerFn; + +template <typename RET, typename... Ps> +class CheckerFn<RET(Ps...)> { + typedef RET (*Func)(void *, Ps...); + Func Fn; +public: + CheckerBase *Checker; + CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { } + RET operator()(Ps... ps) const { + return Fn(Checker, ps...); + } +}; + +/// \brief Describes the different reasons a pointer escapes +/// during analysis. +enum PointerEscapeKind { + /// A pointer escapes due to binding its value to a location + /// that the analyzer cannot track. + PSK_EscapeOnBind, + + /// The pointer has been passed to a function call directly. + PSK_DirectEscapeOnCall, + + /// The pointer has been passed to a function indirectly. + /// For example, the pointer is accessible through an + /// argument to a function. + PSK_IndirectEscapeOnCall, + + /// The reason for pointer escape is unknown. For example, + /// a region containing this pointer is invalidated. + PSK_EscapeOther +}; + +// This wrapper is used to ensure that only StringRefs originating from the +// CheckerRegistry are used as check names. We want to make sure all check +// name strings have a lifetime that keeps them alive at least until the path +// diagnostics have been processed. +class CheckName { + StringRef Name; + friend class ::clang::ento::CheckerRegistry; + explicit CheckName(StringRef Name) : Name(Name) {} + +public: + CheckName() = default; + StringRef getName() const { return Name; } +}; + +enum class ObjCMessageVisitKind { + Pre, + Post, + MessageNil +}; + +class CheckerManager { + const LangOptions LangOpts; + AnalyzerOptionsRef AOptions; + CheckName CurrentCheckName; + +public: + CheckerManager(const LangOptions &langOpts, + AnalyzerOptionsRef AOptions) + : LangOpts(langOpts), + AOptions(AOptions) {} + + ~CheckerManager(); + + void setCurrentCheckName(CheckName name) { CurrentCheckName = name; } + CheckName getCurrentCheckName() const { return CurrentCheckName; } + + bool hasPathSensitiveCheckers() const; + + void finishedCheckerRegistration(); + + const LangOptions &getLangOpts() const { return LangOpts; } + AnalyzerOptions &getAnalyzerOptions() { return *AOptions; } + + typedef CheckerBase *CheckerRef; + typedef const void *CheckerTag; + typedef CheckerFn<void ()> CheckerDtor; + +//===----------------------------------------------------------------------===// +// registerChecker +//===----------------------------------------------------------------------===// + + /// \brief Used to register checkers. + /// + /// \returns a pointer to the checker object. + template <typename CHECKER> + CHECKER *registerChecker() { + CheckerTag tag = getTag<CHECKER>(); + CheckerRef &ref = CheckerTags[tag]; + if (ref) + return static_cast<CHECKER *>(ref); // already registered. + + CHECKER *checker = new CHECKER(); + checker->Name = CurrentCheckName; + CheckerDtors.push_back(CheckerDtor(checker, destruct<CHECKER>)); + CHECKER::_register(checker, *this); + ref = checker; + return checker; + } + + template <typename CHECKER> + CHECKER *registerChecker(AnalyzerOptions &AOpts) { + CheckerTag tag = getTag<CHECKER>(); + CheckerRef &ref = CheckerTags[tag]; + if (ref) + return static_cast<CHECKER *>(ref); // already registered. + + CHECKER *checker = new CHECKER(AOpts); + checker->Name = CurrentCheckName; + CheckerDtors.push_back(CheckerDtor(checker, destruct<CHECKER>)); + CHECKER::_register(checker, *this); + ref = checker; + return checker; + } + +//===----------------------------------------------------------------------===// +// Functions for running checkers for AST traversing.. +//===----------------------------------------------------------------------===// + + /// \brief Run checkers handling Decls. + void runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr, + BugReporter &BR); + + /// \brief Run checkers handling Decls containing a Stmt body. + void runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr, + BugReporter &BR); + +//===----------------------------------------------------------------------===// +// Functions for running checkers for path-sensitive checking. +//===----------------------------------------------------------------------===// + + /// \brief Run checkers for pre-visiting Stmts. + /// + /// The notification is performed for every explored CFGElement, which does + /// not include the control flow statements such as IfStmt. + /// + /// \sa runCheckersForBranchCondition, runCheckersForPostStmt + void runCheckersForPreStmt(ExplodedNodeSet &Dst, + const ExplodedNodeSet &Src, + const Stmt *S, + ExprEngine &Eng) { + runCheckersForStmt(/*isPreVisit=*/true, Dst, Src, S, Eng); + } + + /// \brief Run checkers for post-visiting Stmts. + /// + /// The notification is performed for every explored CFGElement, which does + /// not include the control flow statements such as IfStmt. + /// + /// \sa runCheckersForBranchCondition, runCheckersForPreStmt + void runCheckersForPostStmt(ExplodedNodeSet &Dst, + const ExplodedNodeSet &Src, + const Stmt *S, + ExprEngine &Eng, + bool wasInlined = false) { + runCheckersForStmt(/*isPreVisit=*/false, Dst, Src, S, Eng, wasInlined); + } + + /// \brief Run checkers for visiting Stmts. + void runCheckersForStmt(bool isPreVisit, + ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, + const Stmt *S, ExprEngine &Eng, + bool wasInlined = false); + + /// \brief Run checkers for pre-visiting obj-c messages. + void runCheckersForPreObjCMessage(ExplodedNodeSet &Dst, + const ExplodedNodeSet &Src, + const ObjCMethodCall &msg, + ExprEngine &Eng) { + runCheckersForObjCMessage(ObjCMessageVisitKind::Pre, Dst, Src, msg, Eng); + } + + /// \brief Run checkers for post-visiting obj-c messages. + void runCheckersForPostObjCMessage(ExplodedNodeSet &Dst, + const ExplodedNodeSet &Src, + const ObjCMethodCall &msg, + ExprEngine &Eng, + bool wasInlined = false) { + runCheckersForObjCMessage(ObjCMessageVisitKind::Post, Dst, Src, msg, Eng, + wasInlined); + } + + /// \brief Run checkers for visiting an obj-c message to nil. + void runCheckersForObjCMessageNil(ExplodedNodeSet &Dst, + const ExplodedNodeSet &Src, + const ObjCMethodCall &msg, + ExprEngine &Eng) { + runCheckersForObjCMessage(ObjCMessageVisitKind::MessageNil, Dst, Src, msg, + Eng); + } + + + /// \brief Run checkers for visiting obj-c messages. + void runCheckersForObjCMessage(ObjCMessageVisitKind visitKind, + ExplodedNodeSet &Dst, + const ExplodedNodeSet &Src, + const ObjCMethodCall &msg, ExprEngine &Eng, + bool wasInlined = false); + + /// \brief Run checkers for pre-visiting obj-c messages. + void runCheckersForPreCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, + const CallEvent &Call, ExprEngine &Eng) { + runCheckersForCallEvent(/*isPreVisit=*/true, Dst, Src, Call, Eng); + } + + /// \brief Run checkers for post-visiting obj-c messages. + void runCheckersForPostCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, + const CallEvent &Call, ExprEngine &Eng, + bool wasInlined = false) { + runCheckersForCallEvent(/*isPreVisit=*/false, Dst, Src, Call, Eng, + wasInlined); + } + + /// \brief Run checkers for visiting obj-c messages. + void runCheckersForCallEvent(bool isPreVisit, ExplodedNodeSet &Dst, + const ExplodedNodeSet &Src, + const CallEvent &Call, ExprEngine &Eng, + bool wasInlined = false); + + /// \brief Run checkers for load/store of a location. + void runCheckersForLocation(ExplodedNodeSet &Dst, + const ExplodedNodeSet &Src, + SVal location, + bool isLoad, + const Stmt *NodeEx, + const Stmt *BoundEx, + ExprEngine &Eng); + + /// \brief Run checkers for binding of a value to a location. + void runCheckersForBind(ExplodedNodeSet &Dst, + const ExplodedNodeSet &Src, + SVal location, SVal val, + const Stmt *S, ExprEngine &Eng, + const ProgramPoint &PP); + + /// \brief Run checkers for end of analysis. + void runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR, + ExprEngine &Eng); + + /// \brief Run checkers on end of function. + void runCheckersForEndFunction(NodeBuilderContext &BC, + ExplodedNodeSet &Dst, + ExplodedNode *Pred, + ExprEngine &Eng); + + /// \brief Run checkers for branch condition. + void runCheckersForBranchCondition(const Stmt *condition, + ExplodedNodeSet &Dst, ExplodedNode *Pred, + ExprEngine &Eng); + + /// \brief Run checkers for live symbols. + /// + /// Allows modifying SymbolReaper object. For example, checkers can explicitly + /// register symbols of interest as live. These symbols will not be marked + /// dead and removed. + void runCheckersForLiveSymbols(ProgramStateRef state, + SymbolReaper &SymReaper); + + /// \brief Run checkers for dead symbols. + /// + /// Notifies checkers when symbols become dead. For example, this allows + /// checkers to aggressively clean up/reduce the checker state and produce + /// precise diagnostics. + void runCheckersForDeadSymbols(ExplodedNodeSet &Dst, + const ExplodedNodeSet &Src, + SymbolReaper &SymReaper, const Stmt *S, + ExprEngine &Eng, + ProgramPoint::Kind K); + + /// \brief True if at least one checker wants to check region changes. + bool wantsRegionChangeUpdate(ProgramStateRef state); + + /// \brief Run checkers for region changes. + /// + /// This corresponds to the check::RegionChanges callback. + /// \param state The current program state. + /// \param invalidated A set of all symbols potentially touched by the change. + /// \param ExplicitRegions The regions explicitly requested for invalidation. + /// For example, in the case of a function call, these would be arguments. + /// \param Regions The transitive closure of accessible regions, + /// i.e. all regions that may have been touched by this change. + /// \param Call The call expression wrapper if the regions are invalidated + /// by a call. + ProgramStateRef + runCheckersForRegionChanges(ProgramStateRef state, + const InvalidatedSymbols *invalidated, + ArrayRef<const MemRegion *> ExplicitRegions, + ArrayRef<const MemRegion *> Regions, + const CallEvent *Call); + + /// \brief Run checkers when pointers escape. + /// + /// This notifies the checkers about pointer escape, which occurs whenever + /// the analyzer cannot track the symbol any more. For example, as a + /// result of assigning a pointer into a global or when it's passed to a + /// function call the analyzer cannot model. + /// + /// \param State The state at the point of escape. + /// \param Escaped The list of escaped symbols. + /// \param Call The corresponding CallEvent, if the symbols escape as + /// parameters to the given call. + /// \param Kind The reason of pointer escape. + /// \param ITraits Information about invalidation for a particular + /// region/symbol. + /// \returns Checkers can modify the state by returning a new one. + ProgramStateRef + runCheckersForPointerEscape(ProgramStateRef State, + const InvalidatedSymbols &Escaped, + const CallEvent *Call, + PointerEscapeKind Kind, + RegionAndSymbolInvalidationTraits *ITraits); + + /// \brief Run checkers for handling assumptions on symbolic values. + ProgramStateRef runCheckersForEvalAssume(ProgramStateRef state, + SVal Cond, bool Assumption); + + /// \brief Run checkers for evaluating a call. + /// + /// Warning: Currently, the CallEvent MUST come from a CallExpr! + void runCheckersForEvalCall(ExplodedNodeSet &Dst, + const ExplodedNodeSet &Src, + const CallEvent &CE, ExprEngine &Eng); + + /// \brief Run checkers for the entire Translation Unit. + void runCheckersOnEndOfTranslationUnit(const TranslationUnitDecl *TU, + AnalysisManager &mgr, + BugReporter &BR); + + /// \brief Run checkers for debug-printing a ProgramState. + /// + /// Unlike most other callbacks, any checker can simply implement the virtual + /// method CheckerBase::printState if it has custom data to print. + /// \param Out The output stream + /// \param State The state being printed + /// \param NL The preferred representation of a newline. + /// \param Sep The preferred separator between different kinds of data. + void runCheckersForPrintState(raw_ostream &Out, ProgramStateRef State, + const char *NL, const char *Sep); + +//===----------------------------------------------------------------------===// +// Internal registration functions for AST traversing. +//===----------------------------------------------------------------------===// + + // Functions used by the registration mechanism, checkers should not touch + // these directly. + + typedef CheckerFn<void (const Decl *, AnalysisManager&, BugReporter &)> + CheckDeclFunc; + + typedef bool (*HandlesDeclFunc)(const Decl *D); + void _registerForDecl(CheckDeclFunc checkfn, HandlesDeclFunc isForDeclFn); + + void _registerForBody(CheckDeclFunc checkfn); + +//===----------------------------------------------------------------------===// +// Internal registration functions for path-sensitive checking. +//===----------------------------------------------------------------------===// + + typedef CheckerFn<void (const Stmt *, CheckerContext &)> CheckStmtFunc; + + typedef CheckerFn<void (const ObjCMethodCall &, CheckerContext &)> + CheckObjCMessageFunc; + + typedef CheckerFn<void (const CallEvent &, CheckerContext &)> + CheckCallFunc; + + typedef CheckerFn<void (const SVal &location, bool isLoad, + const Stmt *S, + CheckerContext &)> + CheckLocationFunc; + + typedef CheckerFn<void (const SVal &location, const SVal &val, + const Stmt *S, CheckerContext &)> + CheckBindFunc; + + typedef CheckerFn<void (ExplodedGraph &, BugReporter &, ExprEngine &)> + CheckEndAnalysisFunc; + + typedef CheckerFn<void (CheckerContext &)> + CheckEndFunctionFunc; + + typedef CheckerFn<void (const Stmt *, CheckerContext &)> + CheckBranchConditionFunc; + + typedef CheckerFn<void (SymbolReaper &, CheckerContext &)> + CheckDeadSymbolsFunc; + + typedef CheckerFn<void (ProgramStateRef,SymbolReaper &)> CheckLiveSymbolsFunc; + + typedef CheckerFn<ProgramStateRef (ProgramStateRef, + const InvalidatedSymbols *symbols, + ArrayRef<const MemRegion *> ExplicitRegions, + ArrayRef<const MemRegion *> Regions, + const CallEvent *Call)> + CheckRegionChangesFunc; + + typedef CheckerFn<bool (ProgramStateRef)> WantsRegionChangeUpdateFunc; + + typedef CheckerFn<ProgramStateRef (ProgramStateRef, + const InvalidatedSymbols &Escaped, + const CallEvent *Call, + PointerEscapeKind Kind, + RegionAndSymbolInvalidationTraits *ITraits)> + CheckPointerEscapeFunc; + + typedef CheckerFn<ProgramStateRef (ProgramStateRef, + const SVal &cond, bool assumption)> + EvalAssumeFunc; + + typedef CheckerFn<bool (const CallExpr *, CheckerContext &)> + EvalCallFunc; + + typedef CheckerFn<void (const TranslationUnitDecl *, + AnalysisManager&, BugReporter &)> + CheckEndOfTranslationUnit; + + typedef bool (*HandlesStmtFunc)(const Stmt *D); + void _registerForPreStmt(CheckStmtFunc checkfn, + HandlesStmtFunc isForStmtFn); + void _registerForPostStmt(CheckStmtFunc checkfn, + HandlesStmtFunc isForStmtFn); + + void _registerForPreObjCMessage(CheckObjCMessageFunc checkfn); + void _registerForPostObjCMessage(CheckObjCMessageFunc checkfn); + + void _registerForObjCMessageNil(CheckObjCMessageFunc checkfn); + + void _registerForPreCall(CheckCallFunc checkfn); + void _registerForPostCall(CheckCallFunc checkfn); + + void _registerForLocation(CheckLocationFunc checkfn); + + void _registerForBind(CheckBindFunc checkfn); + + void _registerForEndAnalysis(CheckEndAnalysisFunc checkfn); + + void _registerForEndFunction(CheckEndFunctionFunc checkfn); + + void _registerForBranchCondition(CheckBranchConditionFunc checkfn); + + void _registerForLiveSymbols(CheckLiveSymbolsFunc checkfn); + + void _registerForDeadSymbols(CheckDeadSymbolsFunc checkfn); + + void _registerForRegionChanges(CheckRegionChangesFunc checkfn, + WantsRegionChangeUpdateFunc wantUpdateFn); + + void _registerForPointerEscape(CheckPointerEscapeFunc checkfn); + + void _registerForConstPointerEscape(CheckPointerEscapeFunc checkfn); + + void _registerForEvalAssume(EvalAssumeFunc checkfn); + + void _registerForEvalCall(EvalCallFunc checkfn); + + void _registerForEndOfTranslationUnit(CheckEndOfTranslationUnit checkfn); + +//===----------------------------------------------------------------------===// +// Internal registration functions for events. +//===----------------------------------------------------------------------===// + + typedef void *EventTag; + typedef CheckerFn<void (const void *event)> CheckEventFunc; + + template <typename EVENT> + void _registerListenerForEvent(CheckEventFunc checkfn) { + EventInfo &info = Events[getTag<EVENT>()]; + info.Checkers.push_back(checkfn); + } + + template <typename EVENT> + void _registerDispatcherForEvent() { + EventInfo &info = Events[getTag<EVENT>()]; + info.HasDispatcher = true; + } + + template <typename EVENT> + void _dispatchEvent(const EVENT &event) const { + EventsTy::const_iterator I = Events.find(getTag<EVENT>()); + if (I == Events.end()) + return; + const EventInfo &info = I->second; + for (unsigned i = 0, e = info.Checkers.size(); i != e; ++i) + info.Checkers[i](&event); + } + +//===----------------------------------------------------------------------===// +// Implementation details. +//===----------------------------------------------------------------------===// + +private: + template <typename CHECKER> + static void destruct(void *obj) { delete static_cast<CHECKER *>(obj); } + + template <typename T> + static void *getTag() { static int tag; return &tag; } + + llvm::DenseMap<CheckerTag, CheckerRef> CheckerTags; + + std::vector<CheckerDtor> CheckerDtors; + + struct DeclCheckerInfo { + CheckDeclFunc CheckFn; + HandlesDeclFunc IsForDeclFn; + }; + std::vector<DeclCheckerInfo> DeclCheckers; + + std::vector<CheckDeclFunc> BodyCheckers; + + typedef SmallVector<CheckDeclFunc, 4> CachedDeclCheckers; + typedef llvm::DenseMap<unsigned, CachedDeclCheckers> CachedDeclCheckersMapTy; + CachedDeclCheckersMapTy CachedDeclCheckersMap; + + struct StmtCheckerInfo { + CheckStmtFunc CheckFn; + HandlesStmtFunc IsForStmtFn; + bool IsPreVisit; + }; + std::vector<StmtCheckerInfo> StmtCheckers; + + typedef SmallVector<CheckStmtFunc, 4> CachedStmtCheckers; + typedef llvm::DenseMap<unsigned, CachedStmtCheckers> CachedStmtCheckersMapTy; + CachedStmtCheckersMapTy CachedStmtCheckersMap; + + const CachedStmtCheckers &getCachedStmtCheckersFor(const Stmt *S, + bool isPreVisit); + + /// Returns the checkers that have registered for callbacks of the + /// given \p Kind. + const std::vector<CheckObjCMessageFunc> & + getObjCMessageCheckers(ObjCMessageVisitKind Kind); + + std::vector<CheckObjCMessageFunc> PreObjCMessageCheckers; + std::vector<CheckObjCMessageFunc> PostObjCMessageCheckers; + std::vector<CheckObjCMessageFunc> ObjCMessageNilCheckers; + + std::vector<CheckCallFunc> PreCallCheckers; + std::vector<CheckCallFunc> PostCallCheckers; + + std::vector<CheckLocationFunc> LocationCheckers; + + std::vector<CheckBindFunc> BindCheckers; + + std::vector<CheckEndAnalysisFunc> EndAnalysisCheckers; + + std::vector<CheckEndFunctionFunc> EndFunctionCheckers; + + std::vector<CheckBranchConditionFunc> BranchConditionCheckers; + + std::vector<CheckLiveSymbolsFunc> LiveSymbolsCheckers; + + std::vector<CheckDeadSymbolsFunc> DeadSymbolsCheckers; + + struct RegionChangesCheckerInfo { + CheckRegionChangesFunc CheckFn; + WantsRegionChangeUpdateFunc WantUpdateFn; + }; + std::vector<RegionChangesCheckerInfo> RegionChangesCheckers; + + std::vector<CheckPointerEscapeFunc> PointerEscapeCheckers; + + std::vector<EvalAssumeFunc> EvalAssumeCheckers; + + std::vector<EvalCallFunc> EvalCallCheckers; + + std::vector<CheckEndOfTranslationUnit> EndOfTranslationUnitCheckers; + + struct EventInfo { + SmallVector<CheckEventFunc, 4> Checkers; + bool HasDispatcher; + EventInfo() : HasDispatcher(false) { } + }; + + typedef llvm::DenseMap<EventTag, EventInfo> EventsTy; + EventsTy Events; +}; + +} // end ento namespace + +} // end clang namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/CheckerOptInfo.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/CheckerOptInfo.h new file mode 100644 index 0000000..e981871 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/CheckerOptInfo.h @@ -0,0 +1,44 @@ +//===--- CheckerOptInfo.h - Specifies which checkers to use -----*- 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_STATICANALYZER_CORE_CHECKEROPTINFO_H +#define LLVM_CLANG_STATICANALYZER_CORE_CHECKEROPTINFO_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { +namespace ento { + +/// Represents a request to include or exclude a checker or package from a +/// specific analysis run. +/// +/// \sa CheckerRegistry::initializeManager +class CheckerOptInfo { + StringRef Name; + bool Enable; + bool Claimed; + +public: + CheckerOptInfo(StringRef name, bool enable) + : Name(name), Enable(enable), Claimed(false) { } + + StringRef getName() const { return Name; } + bool isEnabled() const { return Enable; } + bool isDisabled() const { return !isEnabled(); } + + bool isClaimed() const { return Claimed; } + bool isUnclaimed() const { return !isClaimed(); } + void claim() { Claimed = true; } +}; + +} // end namespace ento +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/CheckerRegistry.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/CheckerRegistry.h new file mode 100644 index 0000000..c9724c0 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/CheckerRegistry.h @@ -0,0 +1,140 @@ +//===--- CheckerRegistry.h - Maintains all available checkers ---*- 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_STATICANALYZER_CORE_CHECKERREGISTRY_H +#define LLVM_CLANG_STATICANALYZER_CORE_CHECKERREGISTRY_H + +#include "clang/Basic/LLVM.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include <vector> + +// FIXME: move this information to an HTML file in docs/. +// At the very least, a checker plugin is a dynamic library that exports +// clang_analyzerAPIVersionString. This should be defined as follows: +// +// extern "C" +// const char clang_analyzerAPIVersionString[] = +// CLANG_ANALYZER_API_VERSION_STRING; +// +// This is used to check whether the current version of the analyzer is known to +// be incompatible with a plugin. Plugins with incompatible version strings, +// or without a version string at all, will not be loaded. +// +// To add a custom checker to the analyzer, the plugin must also define the +// function clang_registerCheckers. For example: +// +// extern "C" +// void clang_registerCheckers (CheckerRegistry ®istry) { +// registry.addChecker<MainCallChecker>("example.MainCallChecker", +// "Disallows calls to functions called main"); +// } +// +// The first method argument is the full name of the checker, including its +// enclosing package. By convention, the registered name of a checker is the +// name of the associated class (the template argument). +// The second method argument is a short human-readable description of the +// checker. +// +// The clang_registerCheckers function may add any number of checkers to the +// registry. If any checkers require additional initialization, use the three- +// argument form of CheckerRegistry::addChecker. +// +// To load a checker plugin, specify the full path to the dynamic library as +// the argument to the -load option in the cc1 frontend. You can then enable +// your custom checker using the -analyzer-checker: +// +// clang -cc1 -load </path/to/plugin.dylib> -analyze +// -analyzer-checker=<example.MainCallChecker> +// +// For a complete working example, see examples/analyzer-plugin. + +#ifndef CLANG_ANALYZER_API_VERSION_STRING +// FIXME: The Clang version string is not particularly granular; +// the analyzer infrastructure can change a lot between releases. +// Unfortunately, this string has to be statically embedded in each plugin, +// so we can't just use the functions defined in Version.h. +#include "clang/Basic/Version.h" +#define CLANG_ANALYZER_API_VERSION_STRING CLANG_VERSION_STRING +#endif + +namespace clang { +class DiagnosticsEngine; +class AnalyzerOptions; + +namespace ento { + +class CheckerOptInfo; + +/// Manages a set of available checkers for running a static analysis. +/// The checkers are organized into packages by full name, where including +/// a package will recursively include all subpackages and checkers within it. +/// For example, the checker "core.builtin.NoReturnFunctionChecker" will be +/// included if initializeManager() is called with an option of "core", +/// "core.builtin", or the full name "core.builtin.NoReturnFunctionChecker". +class CheckerRegistry { +public: + /// Initialization functions perform any necessary setup for a checker. + /// They should include a call to CheckerManager::registerChecker. + typedef void (*InitializationFunction)(CheckerManager &); + struct CheckerInfo { + InitializationFunction Initialize; + StringRef FullName; + StringRef Desc; + + CheckerInfo(InitializationFunction fn, StringRef name, StringRef desc) + : Initialize(fn), FullName(name), Desc(desc) {} + }; + + typedef std::vector<CheckerInfo> CheckerInfoList; + +private: + template <typename T> + static void initializeManager(CheckerManager &mgr) { + mgr.registerChecker<T>(); + } + +public: + /// Adds a checker to the registry. Use this non-templated overload when your + /// checker requires custom initialization. + void addChecker(InitializationFunction fn, StringRef fullName, + StringRef desc); + + /// Adds a checker to the registry. Use this templated overload when your + /// checker does not require any custom initialization. + template <class T> + void addChecker(StringRef fullName, StringRef desc) { + // Avoid MSVC's Compiler Error C2276: + // http://msdn.microsoft.com/en-us/library/850cstw1(v=VS.80).aspx + addChecker(&CheckerRegistry::initializeManager<T>, fullName, desc); + } + + /// Initializes a CheckerManager by calling the initialization functions for + /// all checkers specified by the given CheckerOptInfo list. The order of this + /// list is significant; later options can be used to reverse earlier ones. + /// This can be used to exclude certain checkers in an included package. + void initializeManager(CheckerManager &mgr, + SmallVectorImpl<CheckerOptInfo> &opts) const; + + /// Check if every option corresponds to a specific checker or package. + void validateCheckerOptions(const AnalyzerOptions &opts, + DiagnosticsEngine &diags) const; + + /// Prints the name and description of all checkers in this registry. + /// This output is not intended to be machine-parseable. + void printHelp(raw_ostream &out, size_t maxNameChars = 30) const ; + +private: + mutable CheckerInfoList Checkers; + mutable llvm::StringMap<size_t> Packages; +}; + +} // end namespace ento +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/IssueHash.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/IssueHash.h new file mode 100644 index 0000000..b3c4f14 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/IssueHash.h @@ -0,0 +1,51 @@ +//===---------- IssueHash.h - Generate identification hashes ----*- 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_STATICANALYZER_CORE_ISSUE_HASH_H +#define LLVM_CLANG_STATICANALYZER_CORE_ISSUE_HASH_H + +#include "llvm/ADT/SmallString.h" + +namespace clang { +class Decl; +class SourceManager; +class FullSourceLoc; +class LangOptions; + +/// \brief Get an MD5 hash to help identify bugs. +/// +/// This function returns a hash that helps identify bugs within a source file. +/// This identification can be utilized to diff diagnostic results on different +/// snapshots of a projects, or maintain a database of suppressed diagnotics. +/// +/// The hash contains the normalized text of the location associated with the +/// diagnostic. Normalization means removing the whitespaces. The associated +/// location is the either the last location of a diagnostic path or a uniqueing +/// location. The bugtype and the name of the checker is also part of the hash. +/// The last component is the string representation of the enclosing declaration +/// of the associated location. +/// +/// In case a new hash is introduced, the old one should still be maintained for +/// a while. One should not introduce a new hash for every change, it is +/// possible to introduce experimental hashes that may change in the future. +/// Such hashes should be marked as experimental using a comment in the plist +/// files. +llvm::SmallString<32> GetIssueHash(const SourceManager &SM, + FullSourceLoc &IssueLoc, + llvm::StringRef CheckerName, + llvm::StringRef BugType, const Decl *D, + const LangOptions &LangOpts); + +/// \brief Get the string representation of issue hash. See GetIssueHash() for +/// more information. +std::string GetIssueString(const SourceManager &SM, FullSourceLoc &IssueLoc, + llvm::StringRef CheckerName, llvm::StringRef BugType, + const Decl *D, const LangOptions &LangOpts); +} // namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h new file mode 100644 index 0000000..ce512fd --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h @@ -0,0 +1,40 @@ +//===--- PathDiagnosticClients.h - Path Diagnostic Clients ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interface to create different path diagostic clients. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHDIAGNOSTICCONSUMERS_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHDIAGNOSTICCONSUMERS_H + +#include <string> +#include <vector> + +namespace clang { + +class AnalyzerOptions; +class Preprocessor; + +namespace ento { + +class PathDiagnosticConsumer; +typedef std::vector<PathDiagnosticConsumer*> PathDiagnosticConsumers; + +#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN)\ +void CREATEFN(AnalyzerOptions &AnalyzerOpts,\ + PathDiagnosticConsumers &C,\ + const std::string &Prefix,\ + const Preprocessor &PP); +#include "clang/StaticAnalyzer/Core/Analyses.def" + +} // end 'ento' namespace +} // end 'clang' namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h new file mode 100644 index 0000000..cc8a9b8 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h @@ -0,0 +1,109 @@ +//== APSIntType.h - Simple record of the type of APSInts --------*- 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_STATICANALYZER_CORE_PATHSENSITIVE_APSINTTYPE_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_APSINTTYPE_H + +#include "llvm/ADT/APSInt.h" +#include <tuple> + +namespace clang { +namespace ento { + +/// \brief A record of the "type" of an APSInt, used for conversions. +class APSIntType { + uint32_t BitWidth; + bool IsUnsigned; + +public: + APSIntType(uint32_t Width, bool Unsigned) + : BitWidth(Width), IsUnsigned(Unsigned) {} + + /* implicit */ APSIntType(const llvm::APSInt &Value) + : BitWidth(Value.getBitWidth()), IsUnsigned(Value.isUnsigned()) {} + + uint32_t getBitWidth() const { return BitWidth; } + bool isUnsigned() const { return IsUnsigned; } + + /// \brief Convert a given APSInt, in place, to match this type. + /// + /// This behaves like a C cast: converting 255u8 (0xFF) to s16 gives + /// 255 (0x00FF), and converting -1s8 (0xFF) to u16 gives 65535 (0xFFFF). + void apply(llvm::APSInt &Value) const { + // Note the order here. We extend first to preserve the sign, if this value + // is signed, /then/ match the signedness of the result type. + Value = Value.extOrTrunc(BitWidth); + Value.setIsUnsigned(IsUnsigned); + } + + /// Convert and return a new APSInt with the given value, but this + /// type's bit width and signedness. + /// + /// \see apply + llvm::APSInt convert(const llvm::APSInt &Value) const LLVM_READONLY { + llvm::APSInt Result(Value, Value.isUnsigned()); + apply(Result); + return Result; + } + + /// Returns an all-zero value for this type. + llvm::APSInt getZeroValue() const LLVM_READONLY { + return llvm::APSInt(BitWidth, IsUnsigned); + } + + /// Returns the minimum value for this type. + llvm::APSInt getMinValue() const LLVM_READONLY { + return llvm::APSInt::getMinValue(BitWidth, IsUnsigned); + } + + /// Returns the maximum value for this type. + llvm::APSInt getMaxValue() const LLVM_READONLY { + return llvm::APSInt::getMaxValue(BitWidth, IsUnsigned); + } + + llvm::APSInt getValue(uint64_t RawValue) const LLVM_READONLY { + return (llvm::APSInt(BitWidth, IsUnsigned) = RawValue); + } + + /// Used to classify whether a value is representable using this type. + /// + /// \see testInRange + enum RangeTestResultKind { + RTR_Below = -1, ///< Value is less than the minimum representable value. + RTR_Within = 0, ///< Value is representable using this type. + RTR_Above = 1 ///< Value is greater than the maximum representable value. + }; + + /// Tests whether a given value is losslessly representable using this type. + /// + /// \param Val The value to test. + /// \param AllowMixedSign Whether or not to allow signedness conversions. + /// This determines whether -1s8 is considered in range + /// for 'unsigned char' (u8). + RangeTestResultKind testInRange(const llvm::APSInt &Val, + bool AllowMixedSign) const LLVM_READONLY; + + bool operator==(const APSIntType &Other) const { + return BitWidth == Other.BitWidth && IsUnsigned == Other.IsUnsigned; + } + + /// \brief Provide an ordering for finding a common conversion type. + /// + /// Unsigned integers are considered to be better conversion types than + /// signed integers of the same width. + bool operator<(const APSIntType &Other) const { + return std::tie(BitWidth, IsUnsigned) < + std::tie(Other.BitWidth, Other.IsUnsigned); + } +}; + +} // end ento namespace +} // end clang namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h new file mode 100644 index 0000000..3e0913e --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h @@ -0,0 +1,135 @@ +//== AnalysisManager.h - Path sensitive analysis data manager ------*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the AnalysisManager class that manages the data and policy +// for path sensitive analysis. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ANALYSISMANAGER_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ANALYSISMANAGER_H + +#include "clang/Analysis/AnalysisContext.h" +#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" +#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" +#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h" + +namespace clang { + +class CodeInjector; + +namespace ento { + class CheckerManager; + +class AnalysisManager : public BugReporterData { + virtual void anchor(); + AnalysisDeclContextManager AnaCtxMgr; + + ASTContext &Ctx; + DiagnosticsEngine &Diags; + const LangOptions &LangOpts; + PathDiagnosticConsumers PathConsumers; + + // Configurable components creators. + StoreManagerCreator CreateStoreMgr; + ConstraintManagerCreator CreateConstraintMgr; + + CheckerManager *CheckerMgr; + +public: + AnalyzerOptions &options; + + AnalysisManager(ASTContext &ctx,DiagnosticsEngine &diags, + const LangOptions &lang, + const PathDiagnosticConsumers &Consumers, + StoreManagerCreator storemgr, + ConstraintManagerCreator constraintmgr, + CheckerManager *checkerMgr, + AnalyzerOptions &Options, + CodeInjector* injector = nullptr); + + ~AnalysisManager() override; + + void ClearContexts() { + AnaCtxMgr.clear(); + } + + AnalysisDeclContextManager& getAnalysisDeclContextManager() { + return AnaCtxMgr; + } + + StoreManagerCreator getStoreManagerCreator() { + return CreateStoreMgr; + } + + AnalyzerOptions& getAnalyzerOptions() override { + return options; + } + + ConstraintManagerCreator getConstraintManagerCreator() { + return CreateConstraintMgr; + } + + CheckerManager *getCheckerManager() const { return CheckerMgr; } + + ASTContext &getASTContext() override { + return Ctx; + } + + SourceManager &getSourceManager() override { + return getASTContext().getSourceManager(); + } + + DiagnosticsEngine &getDiagnostic() override { + return Diags; + } + + const LangOptions &getLangOpts() const { + return LangOpts; + } + + ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() override { + return PathConsumers; + } + + void FlushDiagnostics(); + + bool shouldVisualize() const { + return options.visualizeExplodedGraphWithGraphViz || + options.visualizeExplodedGraphWithUbiGraph; + } + + bool shouldInlineCall() const { + return options.getIPAMode() != IPAK_None; + } + + CFG *getCFG(Decl const *D) { + return AnaCtxMgr.getContext(D)->getCFG(); + } + + template <typename T> + T *getAnalysis(Decl const *D) { + return AnaCtxMgr.getContext(D)->getAnalysis<T>(); + } + + ParentMap &getParentMap(Decl const *D) { + return AnaCtxMgr.getContext(D)->getParentMap(); + } + + AnalysisDeclContext *getAnalysisDeclContext(const Decl *D) { + return AnaCtxMgr.getContext(D); + } +}; + +} // enAnaCtxMgrspace + +} // end clang namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h new file mode 100644 index 0000000..5b007f1 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h @@ -0,0 +1,200 @@ +//=== BasicValueFactory.h - Basic values for Path Sens analysis --*- C++ -*---// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines BasicValueFactory, a class that manages the lifetime +// of APSInt objects and symbolic constraints used by ExprEngine +// and related classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_BASICVALUEFACTORY_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_BASICVALUEFACTORY_H + +#include "clang/AST/ASTContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h" + +namespace clang { +namespace ento { + +class CompoundValData : public llvm::FoldingSetNode { + QualType T; + llvm::ImmutableList<SVal> L; + +public: + CompoundValData(QualType t, llvm::ImmutableList<SVal> l) + : T(t), L(l) {} + + typedef llvm::ImmutableList<SVal>::iterator iterator; + iterator begin() const { return L.begin(); } + iterator end() const { return L.end(); } + + static void Profile(llvm::FoldingSetNodeID& ID, QualType T, + llvm::ImmutableList<SVal> L); + + void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, T, L); } +}; + +class LazyCompoundValData : public llvm::FoldingSetNode { + StoreRef store; + const TypedValueRegion *region; +public: + LazyCompoundValData(const StoreRef &st, const TypedValueRegion *r) + : store(st), region(r) {} + + const void *getStore() const { return store.getStore(); } + const TypedValueRegion *getRegion() const { return region; } + + static void Profile(llvm::FoldingSetNodeID& ID, + const StoreRef &store, + const TypedValueRegion *region); + + void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, store, region); } +}; + +class BasicValueFactory { + typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<llvm::APSInt> > + APSIntSetTy; + + ASTContext &Ctx; + llvm::BumpPtrAllocator& BPAlloc; + + APSIntSetTy APSIntSet; + void * PersistentSVals; + void * PersistentSValPairs; + + llvm::ImmutableList<SVal>::Factory SValListFactory; + llvm::FoldingSet<CompoundValData> CompoundValDataSet; + llvm::FoldingSet<LazyCompoundValData> LazyCompoundValDataSet; + + // This is private because external clients should use the factory + // method that takes a QualType. + const llvm::APSInt& getValue(uint64_t X, unsigned BitWidth, bool isUnsigned); + +public: + BasicValueFactory(ASTContext &ctx, llvm::BumpPtrAllocator &Alloc) + : Ctx(ctx), BPAlloc(Alloc), PersistentSVals(nullptr), + PersistentSValPairs(nullptr), SValListFactory(Alloc) {} + + ~BasicValueFactory(); + + ASTContext &getContext() const { return Ctx; } + + const llvm::APSInt& getValue(const llvm::APSInt& X); + const llvm::APSInt& getValue(const llvm::APInt& X, bool isUnsigned); + const llvm::APSInt& getValue(uint64_t X, QualType T); + + /// Returns the type of the APSInt used to store values of the given QualType. + APSIntType getAPSIntType(QualType T) const { + assert(T->isIntegralOrEnumerationType() || Loc::isLocType(T)); + return APSIntType(Ctx.getTypeSize(T), + !T->isSignedIntegerOrEnumerationType()); + } + + /// Convert - Create a new persistent APSInt with the same value as 'From' + /// but with the bitwidth and signedness of 'To'. + const llvm::APSInt &Convert(const llvm::APSInt& To, + const llvm::APSInt& From) { + APSIntType TargetType(To); + if (TargetType == APSIntType(From)) + return From; + + return getValue(TargetType.convert(From)); + } + + const llvm::APSInt &Convert(QualType T, const llvm::APSInt &From) { + APSIntType TargetType = getAPSIntType(T); + if (TargetType == APSIntType(From)) + return From; + + return getValue(TargetType.convert(From)); + } + + const llvm::APSInt& getIntValue(uint64_t X, bool isUnsigned) { + QualType T = isUnsigned ? Ctx.UnsignedIntTy : Ctx.IntTy; + return getValue(X, T); + } + + inline const llvm::APSInt& getMaxValue(const llvm::APSInt &v) { + return getValue(APSIntType(v).getMaxValue()); + } + + inline const llvm::APSInt& getMinValue(const llvm::APSInt &v) { + return getValue(APSIntType(v).getMinValue()); + } + + inline const llvm::APSInt& getMaxValue(QualType T) { + return getValue(getAPSIntType(T).getMaxValue()); + } + + inline const llvm::APSInt& getMinValue(QualType T) { + return getValue(getAPSIntType(T).getMinValue()); + } + + inline const llvm::APSInt& Add1(const llvm::APSInt& V) { + llvm::APSInt X = V; + ++X; + return getValue(X); + } + + inline const llvm::APSInt& Sub1(const llvm::APSInt& V) { + llvm::APSInt X = V; + --X; + return getValue(X); + } + + inline const llvm::APSInt& getZeroWithPtrWidth(bool isUnsigned = true) { + return getValue(0, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned); + } + + inline const llvm::APSInt &getIntWithPtrWidth(uint64_t X, bool isUnsigned) { + return getValue(X, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned); + } + + inline const llvm::APSInt& getTruthValue(bool b, QualType T) { + return getValue(b ? 1 : 0, Ctx.getTypeSize(T), false); + } + + inline const llvm::APSInt& getTruthValue(bool b) { + return getTruthValue(b, Ctx.getLogicalOperationType()); + } + + const CompoundValData *getCompoundValData(QualType T, + llvm::ImmutableList<SVal> Vals); + + const LazyCompoundValData *getLazyCompoundValData(const StoreRef &store, + const TypedValueRegion *region); + + llvm::ImmutableList<SVal> getEmptySValList() { + return SValListFactory.getEmptyList(); + } + + llvm::ImmutableList<SVal> consVals(SVal X, llvm::ImmutableList<SVal> L) { + return SValListFactory.add(X, L); + } + + const llvm::APSInt* evalAPSInt(BinaryOperator::Opcode Op, + const llvm::APSInt& V1, + const llvm::APSInt& V2); + + const std::pair<SVal, uintptr_t>& + getPersistentSValWithData(const SVal& V, uintptr_t Data); + + const std::pair<SVal, SVal>& + getPersistentSValPair(const SVal& V1, const SVal& V2); + + const SVal* getPersistentSVal(SVal X); +}; + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h new file mode 100644 index 0000000..1d779e6 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h @@ -0,0 +1,60 @@ +//==- BlockCounter.h - ADT for counting block visits ---------------*- 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 BlockCounter, an abstract data type used to count +// the number of times a given block has been visited along a path +// analyzed by CoreEngine. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_BLOCKCOUNTER_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_BLOCKCOUNTER_H + +#include "llvm/Support/Allocator.h" + +namespace clang { + +class StackFrameContext; + +namespace ento { + +/// \class BlockCounter +/// \brief An abstract data type used to count the number of times a given +/// block has been visited along a path analyzed by CoreEngine. +class BlockCounter { + void *Data; + + BlockCounter(void *D) : Data(D) {} + +public: + BlockCounter() : Data(nullptr) {} + + unsigned getNumVisited(const StackFrameContext *CallSite, + unsigned BlockID) const; + + class Factory { + void *F; + public: + Factory(llvm::BumpPtrAllocator& Alloc); + ~Factory(); + + BlockCounter GetEmptyCounter(); + BlockCounter IncrementCount(BlockCounter BC, + const StackFrameContext *CallSite, + unsigned BlockID); + }; + + friend class Factory; +}; + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h new file mode 100644 index 0000000..b09dffa --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -0,0 +1,1091 @@ +//===- CallEvent.h - Wrapper for all function and method calls ----*- C++ -*--// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file This file defines CallEvent and its subclasses, which represent path- +/// sensitive instances of different kinds of function and method calls +/// (C, C++, and Objective-C). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CALLEVENT_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CALLEVENT_H + +#include "clang/AST/DeclCXX.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Basic/SourceManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" +#include "llvm/ADT/PointerIntPair.h" + +namespace clang { +class ProgramPoint; +class ProgramPointTag; + +namespace ento { + +enum CallEventKind { + CE_Function, + CE_CXXMember, + CE_CXXMemberOperator, + CE_CXXDestructor, + CE_BEG_CXX_INSTANCE_CALLS = CE_CXXMember, + CE_END_CXX_INSTANCE_CALLS = CE_CXXDestructor, + CE_CXXConstructor, + CE_CXXAllocator, + CE_BEG_FUNCTION_CALLS = CE_Function, + CE_END_FUNCTION_CALLS = CE_CXXAllocator, + CE_Block, + CE_ObjCMessage +}; + +class CallEvent; +class CallEventManager; + +template<typename T = CallEvent> +class CallEventRef : public IntrusiveRefCntPtr<const T> { +public: + CallEventRef(const T *Call) : IntrusiveRefCntPtr<const T>(Call) {} + CallEventRef(const CallEventRef &Orig) : IntrusiveRefCntPtr<const T>(Orig) {} + + CallEventRef<T> cloneWithState(ProgramStateRef State) const { + return this->get()->template cloneWithState<T>(State); + } + + // Allow implicit conversions to a superclass type, since CallEventRef + // behaves like a pointer-to-const. + template <typename SuperT> + operator CallEventRef<SuperT> () const { + return this->get(); + } +}; + +/// \class RuntimeDefinition +/// \brief Defines the runtime definition of the called function. +/// +/// Encapsulates the information we have about which Decl will be used +/// when the call is executed on the given path. When dealing with dynamic +/// dispatch, the information is based on DynamicTypeInfo and might not be +/// precise. +class RuntimeDefinition { + /// The Declaration of the function which could be called at runtime. + /// NULL if not available. + const Decl *D; + + /// The region representing an object (ObjC/C++) on which the method is + /// called. With dynamic dispatch, the method definition depends on the + /// runtime type of this object. NULL when the DynamicTypeInfo is + /// precise. + const MemRegion *R; + +public: + RuntimeDefinition(): D(nullptr), R(nullptr) {} + RuntimeDefinition(const Decl *InD): D(InD), R(nullptr) {} + RuntimeDefinition(const Decl *InD, const MemRegion *InR): D(InD), R(InR) {} + const Decl *getDecl() { return D; } + + /// \brief Check if the definition we have is precise. + /// If not, it is possible that the call dispatches to another definition at + /// execution time. + bool mayHaveOtherDefinitions() { return R != nullptr; } + + /// When other definitions are possible, returns the region whose runtime type + /// determines the method definition. + const MemRegion *getDispatchRegion() { return R; } +}; + +/// \brief Represents an abstract call to a function or method along a +/// particular path. +/// +/// CallEvents are created through the factory methods of CallEventManager. +/// +/// CallEvents should always be cheap to create and destroy. In order for +/// CallEventManager to be able to re-use CallEvent-sized memory blocks, +/// subclasses of CallEvent may not add any data members to the base class. +/// Use the "Data" and "Location" fields instead. +class CallEvent { +public: + typedef CallEventKind Kind; + +private: + ProgramStateRef State; + const LocationContext *LCtx; + llvm::PointerUnion<const Expr *, const Decl *> Origin; + + void operator=(const CallEvent &) = delete; + +protected: + // This is user data for subclasses. + const void *Data; + + // This is user data for subclasses. + // This should come right before RefCount, so that the two fields can be + // packed together on LP64 platforms. + SourceLocation Location; + +private: + mutable unsigned RefCount; + + template <typename T> friend struct llvm::IntrusiveRefCntPtrInfo; + void Retain() const { ++RefCount; } + void Release() const; + +protected: + friend class CallEventManager; + + CallEvent(const Expr *E, ProgramStateRef state, const LocationContext *lctx) + : State(state), LCtx(lctx), Origin(E), RefCount(0) {} + + CallEvent(const Decl *D, ProgramStateRef state, const LocationContext *lctx) + : State(state), LCtx(lctx), Origin(D), RefCount(0) {} + + // DO NOT MAKE PUBLIC + CallEvent(const CallEvent &Original) + : State(Original.State), LCtx(Original.LCtx), Origin(Original.Origin), + Data(Original.Data), Location(Original.Location), RefCount(0) {} + + /// Copies this CallEvent, with vtable intact, into a new block of memory. + virtual void cloneTo(void *Dest) const = 0; + + /// \brief Get the value of arbitrary expressions at this point in the path. + SVal getSVal(const Stmt *S) const { + return getState()->getSVal(S, getLocationContext()); + } + + + typedef SmallVectorImpl<SVal> ValueList; + + /// \brief Used to specify non-argument regions that will be invalidated as a + /// result of this call. + virtual void getExtraInvalidatedValues(ValueList &Values, + RegionAndSymbolInvalidationTraits *ETraits) const {} + +public: + virtual ~CallEvent() {} + + /// \brief Returns the kind of call this is. + virtual Kind getKind() const = 0; + + /// \brief Returns the declaration of the function or method that will be + /// called. May be null. + virtual const Decl *getDecl() const { + return Origin.dyn_cast<const Decl *>(); + } + + /// \brief The state in which the call is being evaluated. + const ProgramStateRef &getState() const { + return State; + } + + /// \brief The context in which the call is being evaluated. + const LocationContext *getLocationContext() const { + return LCtx; + } + + /// \brief Returns the definition of the function or method that will be + /// called. + virtual RuntimeDefinition getRuntimeDefinition() const = 0; + + /// \brief Returns the expression whose value will be the result of this call. + /// May be null. + const Expr *getOriginExpr() const { + return Origin.dyn_cast<const Expr *>(); + } + + /// \brief Returns the number of arguments (explicit and implicit). + /// + /// Note that this may be greater than the number of parameters in the + /// callee's declaration, and that it may include arguments not written in + /// the source. + virtual unsigned getNumArgs() const = 0; + + /// \brief Returns true if the callee is known to be from a system header. + bool isInSystemHeader() const { + const Decl *D = getDecl(); + if (!D) + return false; + + SourceLocation Loc = D->getLocation(); + if (Loc.isValid()) { + const SourceManager &SM = + getState()->getStateManager().getContext().getSourceManager(); + return SM.isInSystemHeader(D->getLocation()); + } + + // Special case for implicitly-declared global operator new/delete. + // These should be considered system functions. + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + return FD->isOverloadedOperator() && FD->isImplicit() && FD->isGlobal(); + + return false; + } + + /// \brief Returns a source range for the entire call, suitable for + /// outputting in diagnostics. + virtual SourceRange getSourceRange() const { + return getOriginExpr()->getSourceRange(); + } + + /// \brief Returns the value of a given argument at the time of the call. + virtual SVal getArgSVal(unsigned Index) const; + + /// \brief Returns the expression associated with a given argument. + /// May be null if this expression does not appear in the source. + virtual const Expr *getArgExpr(unsigned Index) const { return nullptr; } + + /// \brief Returns the source range for errors associated with this argument. + /// + /// May be invalid if the argument is not written in the source. + virtual SourceRange getArgSourceRange(unsigned Index) const; + + /// \brief Returns the result type, adjusted for references. + QualType getResultType() const; + + /// \brief Returns the return value of the call. + /// + /// This should only be called if the CallEvent was created using a state in + /// which the return value has already been bound to the origin expression. + SVal getReturnValue() const; + + /// \brief Returns true if the type of any of the non-null arguments satisfies + /// the condition. + bool hasNonNullArgumentsWithType(bool (*Condition)(QualType)) const; + + /// \brief Returns true if any of the arguments appear to represent callbacks. + bool hasNonZeroCallbackArg() const; + + /// \brief Returns true if any of the arguments is void*. + bool hasVoidPointerToNonConstArg() const; + + /// \brief Returns true if any of the arguments are known to escape to long- + /// term storage, even if this method will not modify them. + // NOTE: The exact semantics of this are still being defined! + // We don't really want a list of hardcoded exceptions in the long run, + // but we don't want duplicated lists of known APIs in the short term either. + virtual bool argumentsMayEscape() const { + return hasNonZeroCallbackArg(); + } + + /// \brief Returns true if the callee is an externally-visible function in the + /// top-level namespace, such as \c malloc. + /// + /// You can use this call to determine that a particular function really is + /// a library function and not, say, a C++ member function with the same name. + /// + /// If a name is provided, the function must additionally match the given + /// name. + /// + /// Note that this deliberately excludes C++ library functions in the \c std + /// namespace, but will include C library functions accessed through the + /// \c std namespace. This also does not check if the function is declared + /// as 'extern "C"', or if it uses C++ name mangling. + // FIXME: Add a helper for checking namespaces. + // FIXME: Move this down to AnyFunctionCall once checkers have more + // precise callbacks. + bool isGlobalCFunction(StringRef SpecificName = StringRef()) const; + + /// \brief Returns the name of the callee, if its name is a simple identifier. + /// + /// Note that this will fail for Objective-C methods, blocks, and C++ + /// overloaded operators. The former is named by a Selector rather than a + /// simple identifier, and the latter two do not have names. + // FIXME: Move this down to AnyFunctionCall once checkers have more + // precise callbacks. + const IdentifierInfo *getCalleeIdentifier() const { + const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(getDecl()); + if (!ND) + return nullptr; + return ND->getIdentifier(); + } + + /// \brief Returns an appropriate ProgramPoint for this call. + ProgramPoint getProgramPoint(bool IsPreVisit = false, + const ProgramPointTag *Tag = nullptr) const; + + /// \brief Returns a new state with all argument regions invalidated. + /// + /// This accepts an alternate state in case some processing has already + /// occurred. + ProgramStateRef invalidateRegions(unsigned BlockCount, + ProgramStateRef Orig = nullptr) const; + + typedef std::pair<Loc, SVal> FrameBindingTy; + typedef SmallVectorImpl<FrameBindingTy> BindingsTy; + + /// Populates the given SmallVector with the bindings in the callee's stack + /// frame at the start of this call. + virtual void getInitialStackFrameContents(const StackFrameContext *CalleeCtx, + BindingsTy &Bindings) const = 0; + + /// Returns a copy of this CallEvent, but using the given state. + template <typename T> + CallEventRef<T> cloneWithState(ProgramStateRef NewState) const; + + /// Returns a copy of this CallEvent, but using the given state. + CallEventRef<> cloneWithState(ProgramStateRef NewState) const { + return cloneWithState<CallEvent>(NewState); + } + + /// \brief Returns true if this is a statement is a function or method call + /// of some kind. + static bool isCallStmt(const Stmt *S); + + /// \brief Returns the result type of a function or method declaration. + /// + /// This will return a null QualType if the result type cannot be determined. + static QualType getDeclaredResultType(const Decl *D); + + /// \brief Returns true if the given decl is known to be variadic. + /// + /// \p D must not be null. + static bool isVariadic(const Decl *D); + + // Iterator access to formal parameters and their types. +private: + typedef std::const_mem_fun_t<QualType, ParmVarDecl> get_type_fun; + +public: + /// Return call's formal parameters. + /// + /// Remember that the number of formal parameters may not match the number + /// of arguments for all calls. However, the first parameter will always + /// correspond with the argument value returned by \c getArgSVal(0). + virtual ArrayRef<ParmVarDecl*> parameters() const = 0; + + typedef llvm::mapped_iterator<ArrayRef<ParmVarDecl*>::iterator, get_type_fun> + param_type_iterator; + + /// Returns an iterator over the types of the call's formal parameters. + /// + /// This uses the callee decl found by default name lookup rather than the + /// definition because it represents a public interface, and probably has + /// more annotations. + param_type_iterator param_type_begin() const { + return llvm::map_iterator(parameters().begin(), + get_type_fun(&ParmVarDecl::getType)); + } + /// \sa param_type_begin() + param_type_iterator param_type_end() const { + return llvm::map_iterator(parameters().end(), + get_type_fun(&ParmVarDecl::getType)); + } + + // For debugging purposes only + void dump(raw_ostream &Out) const; + void dump() const; +}; + + +/// \brief Represents a call to any sort of function that might have a +/// FunctionDecl. +class AnyFunctionCall : public CallEvent { +protected: + AnyFunctionCall(const Expr *E, ProgramStateRef St, + const LocationContext *LCtx) + : CallEvent(E, St, LCtx) {} + AnyFunctionCall(const Decl *D, ProgramStateRef St, + const LocationContext *LCtx) + : CallEvent(D, St, LCtx) {} + AnyFunctionCall(const AnyFunctionCall &Other) : CallEvent(Other) {} + +public: + // This function is overridden by subclasses, but they must return + // a FunctionDecl. + const FunctionDecl *getDecl() const override { + return cast<FunctionDecl>(CallEvent::getDecl()); + } + + RuntimeDefinition getRuntimeDefinition() const override { + const FunctionDecl *FD = getDecl(); + // Note that the AnalysisDeclContext will have the FunctionDecl with + // the definition (if one exists). + if (FD) { + AnalysisDeclContext *AD = + getLocationContext()->getAnalysisDeclContext()-> + getManager()->getContext(FD); + if (AD->getBody()) + return RuntimeDefinition(AD->getDecl()); + } + + return RuntimeDefinition(); + } + + bool argumentsMayEscape() const override; + + void getInitialStackFrameContents(const StackFrameContext *CalleeCtx, + BindingsTy &Bindings) const override; + + ArrayRef<ParmVarDecl *> parameters() const override; + + static bool classof(const CallEvent *CA) { + return CA->getKind() >= CE_BEG_FUNCTION_CALLS && + CA->getKind() <= CE_END_FUNCTION_CALLS; + } +}; + +/// \brief Represents a C function or static C++ member function call. +/// +/// Example: \c fun() +class SimpleFunctionCall : public AnyFunctionCall { + friend class CallEventManager; + +protected: + SimpleFunctionCall(const CallExpr *CE, ProgramStateRef St, + const LocationContext *LCtx) + : AnyFunctionCall(CE, St, LCtx) {} + SimpleFunctionCall(const SimpleFunctionCall &Other) + : AnyFunctionCall(Other) {} + void cloneTo(void *Dest) const override { + new (Dest) SimpleFunctionCall(*this); + } + +public: + virtual const CallExpr *getOriginExpr() const { + return cast<CallExpr>(AnyFunctionCall::getOriginExpr()); + } + + const FunctionDecl *getDecl() const override; + + unsigned getNumArgs() const override { return getOriginExpr()->getNumArgs(); } + + const Expr *getArgExpr(unsigned Index) const override { + return getOriginExpr()->getArg(Index); + } + + Kind getKind() const override { return CE_Function; } + + static bool classof(const CallEvent *CA) { + return CA->getKind() == CE_Function; + } +}; + +/// \brief Represents a call to a block. +/// +/// Example: <tt>^{ /* ... */ }()</tt> +class BlockCall : public CallEvent { + friend class CallEventManager; + +protected: + BlockCall(const CallExpr *CE, ProgramStateRef St, + const LocationContext *LCtx) + : CallEvent(CE, St, LCtx) {} + + BlockCall(const BlockCall &Other) : CallEvent(Other) {} + void cloneTo(void *Dest) const override { new (Dest) BlockCall(*this); } + + void getExtraInvalidatedValues(ValueList &Values, + RegionAndSymbolInvalidationTraits *ETraits) const override; + +public: + virtual const CallExpr *getOriginExpr() const { + return cast<CallExpr>(CallEvent::getOriginExpr()); + } + + unsigned getNumArgs() const override { return getOriginExpr()->getNumArgs(); } + + const Expr *getArgExpr(unsigned Index) const override { + return getOriginExpr()->getArg(Index); + } + + /// \brief Returns the region associated with this instance of the block. + /// + /// This may be NULL if the block's origin is unknown. + const BlockDataRegion *getBlockRegion() const; + + const BlockDecl *getDecl() const override { + const BlockDataRegion *BR = getBlockRegion(); + if (!BR) + return nullptr; + return BR->getDecl(); + } + + bool isConversionFromLambda() const { + const BlockDecl *BD = getDecl(); + if (!BD) + return false; + + return BD->isConversionFromLambda(); + } + + /// \brief For a block converted from a C++ lambda, returns the block + /// VarRegion for the variable holding the captured C++ lambda record. + const VarRegion *getRegionStoringCapturedLambda() const { + assert(isConversionFromLambda()); + const BlockDataRegion *BR = getBlockRegion(); + assert(BR && "Block converted from lambda must have a block region"); + + auto I = BR->referenced_vars_begin(); + assert(I != BR->referenced_vars_end()); + + return I.getCapturedRegion(); + } + + RuntimeDefinition getRuntimeDefinition() const override { + if (!isConversionFromLambda()) + return RuntimeDefinition(getDecl()); + + // Clang converts lambdas to blocks with an implicit user-defined + // conversion operator method on the lambda record that looks (roughly) + // like: + // + // typedef R(^block_type)(P1, P2, ...); + // operator block_type() const { + // auto Lambda = *this; + // return ^(P1 p1, P2 p2, ...){ + // /* return Lambda(p1, p2, ...); */ + // }; + // } + // + // Here R is the return type of the lambda and P1, P2, ... are + // its parameter types. 'Lambda' is a fake VarDecl captured by the block + // that is initialized to a copy of the lambda. + // + // Sema leaves the body of a lambda-converted block empty (it is + // produced by CodeGen), so we can't analyze it directly. Instead, we skip + // the block body and analyze the operator() method on the captured lambda. + const VarDecl *LambdaVD = getRegionStoringCapturedLambda()->getDecl(); + const CXXRecordDecl *LambdaDecl = LambdaVD->getType()->getAsCXXRecordDecl(); + CXXMethodDecl* LambdaCallOperator = LambdaDecl->getLambdaCallOperator(); + + return RuntimeDefinition(LambdaCallOperator); + } + + bool argumentsMayEscape() const override { + return true; + } + + void getInitialStackFrameContents(const StackFrameContext *CalleeCtx, + BindingsTy &Bindings) const override; + + ArrayRef<ParmVarDecl*> parameters() const override; + + Kind getKind() const override { return CE_Block; } + + static bool classof(const CallEvent *CA) { + return CA->getKind() == CE_Block; + } +}; + +/// \brief Represents a non-static C++ member function call, no matter how +/// it is written. +class CXXInstanceCall : public AnyFunctionCall { +protected: + void getExtraInvalidatedValues(ValueList &Values, + RegionAndSymbolInvalidationTraits *ETraits) const override; + + CXXInstanceCall(const CallExpr *CE, ProgramStateRef St, + const LocationContext *LCtx) + : AnyFunctionCall(CE, St, LCtx) {} + CXXInstanceCall(const FunctionDecl *D, ProgramStateRef St, + const LocationContext *LCtx) + : AnyFunctionCall(D, St, LCtx) {} + + + CXXInstanceCall(const CXXInstanceCall &Other) : AnyFunctionCall(Other) {} + +public: + /// \brief Returns the expression representing the implicit 'this' object. + virtual const Expr *getCXXThisExpr() const { return nullptr; } + + /// \brief Returns the value of the implicit 'this' object. + virtual SVal getCXXThisVal() const; + + const FunctionDecl *getDecl() const override; + + RuntimeDefinition getRuntimeDefinition() const override; + + void getInitialStackFrameContents(const StackFrameContext *CalleeCtx, + BindingsTy &Bindings) const override; + + static bool classof(const CallEvent *CA) { + return CA->getKind() >= CE_BEG_CXX_INSTANCE_CALLS && + CA->getKind() <= CE_END_CXX_INSTANCE_CALLS; + } +}; + +/// \brief Represents a non-static C++ member function call. +/// +/// Example: \c obj.fun() +class CXXMemberCall : public CXXInstanceCall { + friend class CallEventManager; + +protected: + CXXMemberCall(const CXXMemberCallExpr *CE, ProgramStateRef St, + const LocationContext *LCtx) + : CXXInstanceCall(CE, St, LCtx) {} + + CXXMemberCall(const CXXMemberCall &Other) : CXXInstanceCall(Other) {} + void cloneTo(void *Dest) const override { new (Dest) CXXMemberCall(*this); } + +public: + virtual const CXXMemberCallExpr *getOriginExpr() const { + return cast<CXXMemberCallExpr>(CXXInstanceCall::getOriginExpr()); + } + + unsigned getNumArgs() const override { + if (const CallExpr *CE = getOriginExpr()) + return CE->getNumArgs(); + return 0; + } + + const Expr *getArgExpr(unsigned Index) const override { + return getOriginExpr()->getArg(Index); + } + + const Expr *getCXXThisExpr() const override; + + RuntimeDefinition getRuntimeDefinition() const override; + + Kind getKind() const override { return CE_CXXMember; } + + static bool classof(const CallEvent *CA) { + return CA->getKind() == CE_CXXMember; + } +}; + +/// \brief Represents a C++ overloaded operator call where the operator is +/// implemented as a non-static member function. +/// +/// Example: <tt>iter + 1</tt> +class CXXMemberOperatorCall : public CXXInstanceCall { + friend class CallEventManager; + +protected: + CXXMemberOperatorCall(const CXXOperatorCallExpr *CE, ProgramStateRef St, + const LocationContext *LCtx) + : CXXInstanceCall(CE, St, LCtx) {} + + CXXMemberOperatorCall(const CXXMemberOperatorCall &Other) + : CXXInstanceCall(Other) {} + void cloneTo(void *Dest) const override { + new (Dest) CXXMemberOperatorCall(*this); + } + +public: + virtual const CXXOperatorCallExpr *getOriginExpr() const { + return cast<CXXOperatorCallExpr>(CXXInstanceCall::getOriginExpr()); + } + + unsigned getNumArgs() const override { + return getOriginExpr()->getNumArgs() - 1; + } + const Expr *getArgExpr(unsigned Index) const override { + return getOriginExpr()->getArg(Index + 1); + } + + const Expr *getCXXThisExpr() const override; + + Kind getKind() const override { return CE_CXXMemberOperator; } + + static bool classof(const CallEvent *CA) { + return CA->getKind() == CE_CXXMemberOperator; + } +}; + +/// \brief Represents an implicit call to a C++ destructor. +/// +/// This can occur at the end of a scope (for automatic objects), at the end +/// of a full-expression (for temporaries), or as part of a delete. +class CXXDestructorCall : public CXXInstanceCall { + friend class CallEventManager; + +protected: + typedef llvm::PointerIntPair<const MemRegion *, 1, bool> DtorDataTy; + + /// Creates an implicit destructor. + /// + /// \param DD The destructor that will be called. + /// \param Trigger The statement whose completion causes this destructor call. + /// \param Target The object region to be destructed. + /// \param St The path-sensitive state at this point in the program. + /// \param LCtx The location context at this point in the program. + CXXDestructorCall(const CXXDestructorDecl *DD, const Stmt *Trigger, + const MemRegion *Target, bool IsBaseDestructor, + ProgramStateRef St, const LocationContext *LCtx) + : CXXInstanceCall(DD, St, LCtx) { + Data = DtorDataTy(Target, IsBaseDestructor).getOpaqueValue(); + Location = Trigger->getLocEnd(); + } + + CXXDestructorCall(const CXXDestructorCall &Other) : CXXInstanceCall(Other) {} + void cloneTo(void *Dest) const override {new (Dest) CXXDestructorCall(*this);} + +public: + SourceRange getSourceRange() const override { return Location; } + unsigned getNumArgs() const override { return 0; } + + RuntimeDefinition getRuntimeDefinition() const override; + + /// \brief Returns the value of the implicit 'this' object. + SVal getCXXThisVal() const override; + + /// Returns true if this is a call to a base class destructor. + bool isBaseDestructor() const { + return DtorDataTy::getFromOpaqueValue(Data).getInt(); + } + + Kind getKind() const override { return CE_CXXDestructor; } + + static bool classof(const CallEvent *CA) { + return CA->getKind() == CE_CXXDestructor; + } +}; + +/// \brief Represents a call to a C++ constructor. +/// +/// Example: \c T(1) +class CXXConstructorCall : public AnyFunctionCall { + friend class CallEventManager; + +protected: + /// Creates a constructor call. + /// + /// \param CE The constructor expression as written in the source. + /// \param Target The region where the object should be constructed. If NULL, + /// a new symbolic region will be used. + /// \param St The path-sensitive state at this point in the program. + /// \param LCtx The location context at this point in the program. + CXXConstructorCall(const CXXConstructExpr *CE, const MemRegion *Target, + ProgramStateRef St, const LocationContext *LCtx) + : AnyFunctionCall(CE, St, LCtx) { + Data = Target; + } + + CXXConstructorCall(const CXXConstructorCall &Other) : AnyFunctionCall(Other){} + void cloneTo(void *Dest) const override { new (Dest) CXXConstructorCall(*this); } + + void getExtraInvalidatedValues(ValueList &Values, + RegionAndSymbolInvalidationTraits *ETraits) const override; + +public: + virtual const CXXConstructExpr *getOriginExpr() const { + return cast<CXXConstructExpr>(AnyFunctionCall::getOriginExpr()); + } + + const CXXConstructorDecl *getDecl() const override { + return getOriginExpr()->getConstructor(); + } + + unsigned getNumArgs() const override { return getOriginExpr()->getNumArgs(); } + + const Expr *getArgExpr(unsigned Index) const override { + return getOriginExpr()->getArg(Index); + } + + /// \brief Returns the value of the implicit 'this' object. + SVal getCXXThisVal() const; + + void getInitialStackFrameContents(const StackFrameContext *CalleeCtx, + BindingsTy &Bindings) const override; + + Kind getKind() const override { return CE_CXXConstructor; } + + static bool classof(const CallEvent *CA) { + return CA->getKind() == CE_CXXConstructor; + } +}; + +/// \brief Represents the memory allocation call in a C++ new-expression. +/// +/// This is a call to "operator new". +class CXXAllocatorCall : public AnyFunctionCall { + friend class CallEventManager; + +protected: + CXXAllocatorCall(const CXXNewExpr *E, ProgramStateRef St, + const LocationContext *LCtx) + : AnyFunctionCall(E, St, LCtx) {} + + CXXAllocatorCall(const CXXAllocatorCall &Other) : AnyFunctionCall(Other) {} + void cloneTo(void *Dest) const override { new (Dest) CXXAllocatorCall(*this); } + +public: + virtual const CXXNewExpr *getOriginExpr() const { + return cast<CXXNewExpr>(AnyFunctionCall::getOriginExpr()); + } + + const FunctionDecl *getDecl() const override { + return getOriginExpr()->getOperatorNew(); + } + + unsigned getNumArgs() const override { + return getOriginExpr()->getNumPlacementArgs() + 1; + } + + const Expr *getArgExpr(unsigned Index) const override { + // The first argument of an allocator call is the size of the allocation. + if (Index == 0) + return nullptr; + return getOriginExpr()->getPlacementArg(Index - 1); + } + + Kind getKind() const override { return CE_CXXAllocator; } + + static bool classof(const CallEvent *CE) { + return CE->getKind() == CE_CXXAllocator; + } +}; + +/// \brief Represents the ways an Objective-C message send can occur. +// +// Note to maintainers: OCM_Message should always be last, since it does not +// need to fit in the Data field's low bits. +enum ObjCMessageKind { + OCM_PropertyAccess, + OCM_Subscript, + OCM_Message +}; + +/// \brief Represents any expression that calls an Objective-C method. +/// +/// This includes all of the kinds listed in ObjCMessageKind. +class ObjCMethodCall : public CallEvent { + friend class CallEventManager; + + const PseudoObjectExpr *getContainingPseudoObjectExpr() const; + +protected: + ObjCMethodCall(const ObjCMessageExpr *Msg, ProgramStateRef St, + const LocationContext *LCtx) + : CallEvent(Msg, St, LCtx) { + Data = nullptr; + } + + ObjCMethodCall(const ObjCMethodCall &Other) : CallEvent(Other) {} + void cloneTo(void *Dest) const override { new (Dest) ObjCMethodCall(*this); } + + void getExtraInvalidatedValues(ValueList &Values, + RegionAndSymbolInvalidationTraits *ETraits) const override; + + /// Check if the selector may have multiple definitions (may have overrides). + virtual bool canBeOverridenInSubclass(ObjCInterfaceDecl *IDecl, + Selector Sel) const; + +public: + virtual const ObjCMessageExpr *getOriginExpr() const { + return cast<ObjCMessageExpr>(CallEvent::getOriginExpr()); + } + const ObjCMethodDecl *getDecl() const override { + return getOriginExpr()->getMethodDecl(); + } + unsigned getNumArgs() const override { + return getOriginExpr()->getNumArgs(); + } + const Expr *getArgExpr(unsigned Index) const override { + return getOriginExpr()->getArg(Index); + } + + bool isInstanceMessage() const { + return getOriginExpr()->isInstanceMessage(); + } + ObjCMethodFamily getMethodFamily() const { + return getOriginExpr()->getMethodFamily(); + } + Selector getSelector() const { + return getOriginExpr()->getSelector(); + } + + SourceRange getSourceRange() const override; + + /// \brief Returns the value of the receiver at the time of this call. + SVal getReceiverSVal() const; + + /// \brief Return the value of 'self' if available. + SVal getSelfSVal() const; + + /// \brief Get the interface for the receiver. + /// + /// This works whether this is an instance message or a class message. + /// However, it currently just uses the static type of the receiver. + const ObjCInterfaceDecl *getReceiverInterface() const { + return getOriginExpr()->getReceiverInterface(); + } + + /// \brief Checks if the receiver refers to 'self' or 'super'. + bool isReceiverSelfOrSuper() const; + + /// Returns how the message was written in the source (property access, + /// subscript, or explicit message send). + ObjCMessageKind getMessageKind() const; + + /// Returns true if this property access or subscript is a setter (has the + /// form of an assignment). + bool isSetter() const { + switch (getMessageKind()) { + case OCM_Message: + llvm_unreachable("This is not a pseudo-object access!"); + case OCM_PropertyAccess: + return getNumArgs() > 0; + case OCM_Subscript: + return getNumArgs() > 1; + } + llvm_unreachable("Unknown message kind"); + } + + RuntimeDefinition getRuntimeDefinition() const override; + + bool argumentsMayEscape() const override; + + void getInitialStackFrameContents(const StackFrameContext *CalleeCtx, + BindingsTy &Bindings) const override; + + ArrayRef<ParmVarDecl*> parameters() const override; + + Kind getKind() const override { return CE_ObjCMessage; } + + static bool classof(const CallEvent *CA) { + return CA->getKind() == CE_ObjCMessage; + } +}; + + +/// \brief Manages the lifetime of CallEvent objects. +/// +/// CallEventManager provides a way to create arbitrary CallEvents "on the +/// stack" as if they were value objects by keeping a cache of CallEvent-sized +/// memory blocks. The CallEvents created by CallEventManager are only valid +/// for the lifetime of the OwnedCallEvent that holds them; right now these +/// objects cannot be copied and ownership cannot be transferred. +class CallEventManager { + friend class CallEvent; + + llvm::BumpPtrAllocator &Alloc; + SmallVector<void *, 8> Cache; + typedef SimpleFunctionCall CallEventTemplateTy; + + void reclaim(const void *Memory) { + Cache.push_back(const_cast<void *>(Memory)); + } + + /// Returns memory that can be initialized as a CallEvent. + void *allocate() { + if (Cache.empty()) + return Alloc.Allocate<CallEventTemplateTy>(); + else + return Cache.pop_back_val(); + } + + template <typename T, typename Arg> + T *create(Arg A, ProgramStateRef St, const LocationContext *LCtx) { + static_assert(sizeof(T) == sizeof(CallEventTemplateTy), + "CallEvent subclasses are not all the same size"); + return new (allocate()) T(A, St, LCtx); + } + + template <typename T, typename Arg1, typename Arg2> + T *create(Arg1 A1, Arg2 A2, ProgramStateRef St, const LocationContext *LCtx) { + static_assert(sizeof(T) == sizeof(CallEventTemplateTy), + "CallEvent subclasses are not all the same size"); + return new (allocate()) T(A1, A2, St, LCtx); + } + + template <typename T, typename Arg1, typename Arg2, typename Arg3> + T *create(Arg1 A1, Arg2 A2, Arg3 A3, ProgramStateRef St, + const LocationContext *LCtx) { + static_assert(sizeof(T) == sizeof(CallEventTemplateTy), + "CallEvent subclasses are not all the same size"); + return new (allocate()) T(A1, A2, A3, St, LCtx); + } + + template <typename T, typename Arg1, typename Arg2, typename Arg3, + typename Arg4> + T *create(Arg1 A1, Arg2 A2, Arg3 A3, Arg4 A4, ProgramStateRef St, + const LocationContext *LCtx) { + static_assert(sizeof(T) == sizeof(CallEventTemplateTy), + "CallEvent subclasses are not all the same size"); + return new (allocate()) T(A1, A2, A3, A4, St, LCtx); + } + +public: + CallEventManager(llvm::BumpPtrAllocator &alloc) : Alloc(alloc) {} + + + CallEventRef<> + getCaller(const StackFrameContext *CalleeCtx, ProgramStateRef State); + + + CallEventRef<> + getSimpleCall(const CallExpr *E, ProgramStateRef State, + const LocationContext *LCtx); + + CallEventRef<ObjCMethodCall> + getObjCMethodCall(const ObjCMessageExpr *E, ProgramStateRef State, + const LocationContext *LCtx) { + return create<ObjCMethodCall>(E, State, LCtx); + } + + CallEventRef<CXXConstructorCall> + getCXXConstructorCall(const CXXConstructExpr *E, const MemRegion *Target, + ProgramStateRef State, const LocationContext *LCtx) { + return create<CXXConstructorCall>(E, Target, State, LCtx); + } + + CallEventRef<CXXDestructorCall> + getCXXDestructorCall(const CXXDestructorDecl *DD, const Stmt *Trigger, + const MemRegion *Target, bool IsBase, + ProgramStateRef State, const LocationContext *LCtx) { + return create<CXXDestructorCall>(DD, Trigger, Target, IsBase, State, LCtx); + } + + CallEventRef<CXXAllocatorCall> + getCXXAllocatorCall(const CXXNewExpr *E, ProgramStateRef State, + const LocationContext *LCtx) { + return create<CXXAllocatorCall>(E, State, LCtx); + } +}; + + +template <typename T> +CallEventRef<T> CallEvent::cloneWithState(ProgramStateRef NewState) const { + assert(isa<T>(*this) && "Cloning to unrelated type"); + static_assert(sizeof(T) == sizeof(CallEvent), + "Subclasses may not add fields"); + + if (NewState == State) + return cast<T>(this); + + CallEventManager &Mgr = State->getStateManager().getCallEventManager(); + T *Copy = static_cast<T *>(Mgr.allocate()); + cloneTo(Copy); + assert(Copy->getKind() == this->getKind() && "Bad copy"); + + Copy->State = NewState; + return Copy; +} + +inline void CallEvent::Release() const { + assert(RefCount > 0 && "Reference count is already zero."); + --RefCount; + + if (RefCount > 0) + return; + + CallEventManager &Mgr = State->getStateManager().getCallEventManager(); + Mgr.reclaim(this); + + this->~CallEvent(); +} + +} // end namespace ento +} // end namespace clang + +namespace llvm { + // Support isa<>, cast<>, and dyn_cast<> for CallEventRef. + template<class T> struct simplify_type< clang::ento::CallEventRef<T> > { + typedef const T *SimpleType; + + static SimpleType + getSimplifiedValue(clang::ento::CallEventRef<T> Val) { + return Val.get(); + } + }; +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h new file mode 100644 index 0000000..d4f014d --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h @@ -0,0 +1,349 @@ +//== CheckerContext.h - Context info for path-sensitive checkers--*- C++ -*--=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines CheckerContext that provides contextual info for +// path-sensitive checkers. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CHECKERCONTEXT_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CHECKERCONTEXT_H + +#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" + +namespace clang { +namespace ento { + + /// Declares an immutable map of type \p NameTy, suitable for placement into + /// the ProgramState. This is implementing using llvm::ImmutableMap. + /// + /// \code + /// State = State->set<Name>(K, V); + /// const Value *V = State->get<Name>(K); // Returns NULL if not in the map. + /// State = State->remove<Name>(K); + /// NameTy Map = State->get<Name>(); + /// \endcode + /// + /// The macro should not be used inside namespaces, or for traits that must + /// be accessible from more than one translation unit. + #define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value) \ + REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, \ + CLANG_ENTO_PROGRAMSTATE_MAP(Key, Value)) + + /// Declares an immutable set of type \p NameTy, suitable for placement into + /// the ProgramState. This is implementing using llvm::ImmutableSet. + /// + /// \code + /// State = State->add<Name>(E); + /// State = State->remove<Name>(E); + /// bool Present = State->contains<Name>(E); + /// NameTy Set = State->get<Name>(); + /// \endcode + /// + /// The macro should not be used inside namespaces, or for traits that must + /// be accessible from more than one translation unit. + #define REGISTER_SET_WITH_PROGRAMSTATE(Name, Elem) \ + REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, llvm::ImmutableSet<Elem>) + + /// Declares an immutable list of type \p NameTy, suitable for placement into + /// the ProgramState. This is implementing using llvm::ImmutableList. + /// + /// \code + /// State = State->add<Name>(E); // Adds to the /end/ of the list. + /// bool Present = State->contains<Name>(E); + /// NameTy List = State->get<Name>(); + /// \endcode + /// + /// The macro should not be used inside namespaces, or for traits that must + /// be accessible from more than one translation unit. + #define REGISTER_LIST_WITH_PROGRAMSTATE(Name, Elem) \ + REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, llvm::ImmutableList<Elem>) + + +class CheckerContext { + ExprEngine &Eng; + /// The current exploded(symbolic execution) graph node. + ExplodedNode *Pred; + /// The flag is true if the (state of the execution) has been modified + /// by the checker using this context. For example, a new transition has been + /// added or a bug report issued. + bool Changed; + /// The tagged location, which is used to generate all new nodes. + const ProgramPoint Location; + NodeBuilder &NB; + +public: + /// If we are post visiting a call, this flag will be set if the + /// call was inlined. In all other cases it will be false. + const bool wasInlined; + + CheckerContext(NodeBuilder &builder, + ExprEngine &eng, + ExplodedNode *pred, + const ProgramPoint &loc, + bool wasInlined = false) + : Eng(eng), + Pred(pred), + Changed(false), + Location(loc), + NB(builder), + wasInlined(wasInlined) { + assert(Pred->getState() && + "We should not call the checkers on an empty state."); + } + + AnalysisManager &getAnalysisManager() { + return Eng.getAnalysisManager(); + } + + ConstraintManager &getConstraintManager() { + return Eng.getConstraintManager(); + } + + StoreManager &getStoreManager() { + return Eng.getStoreManager(); + } + + /// \brief Returns the previous node in the exploded graph, which includes + /// the state of the program before the checker ran. Note, checkers should + /// not retain the node in their state since the nodes might get invalidated. + ExplodedNode *getPredecessor() { return Pred; } + const ProgramStateRef &getState() const { return Pred->getState(); } + + /// \brief Check if the checker changed the state of the execution; ex: added + /// a new transition or a bug report. + bool isDifferent() { return Changed; } + + /// \brief Returns the number of times the current block has been visited + /// along the analyzed path. + unsigned blockCount() const { + return NB.getContext().blockCount(); + } + + ASTContext &getASTContext() { + return Eng.getContext(); + } + + const LangOptions &getLangOpts() const { + return Eng.getContext().getLangOpts(); + } + + const LocationContext *getLocationContext() const { + return Pred->getLocationContext(); + } + + const StackFrameContext *getStackFrame() const { + return Pred->getStackFrame(); + } + + /// Return true if the current LocationContext has no caller context. + bool inTopFrame() const { return getLocationContext()->inTopFrame(); } + + BugReporter &getBugReporter() { + return Eng.getBugReporter(); + } + + SourceManager &getSourceManager() { + return getBugReporter().getSourceManager(); + } + + SValBuilder &getSValBuilder() { + return Eng.getSValBuilder(); + } + + SymbolManager &getSymbolManager() { + return getSValBuilder().getSymbolManager(); + } + + bool isObjCGCEnabled() const { + return Eng.isObjCGCEnabled(); + } + + ProgramStateManager &getStateManager() { + return Eng.getStateManager(); + } + + AnalysisDeclContext *getCurrentAnalysisDeclContext() const { + return Pred->getLocationContext()->getAnalysisDeclContext(); + } + + /// \brief Get the blockID. + unsigned getBlockID() const { + return NB.getContext().getBlock()->getBlockID(); + } + + /// \brief If the given node corresponds to a PostStore program point, + /// retrieve the location region as it was uttered in the code. + /// + /// This utility can be useful for generating extensive diagnostics, for + /// example, for finding variables that the given symbol was assigned to. + static const MemRegion *getLocationRegionIfPostStore(const ExplodedNode *N) { + ProgramPoint L = N->getLocation(); + if (Optional<PostStore> PSL = L.getAs<PostStore>()) + return reinterpret_cast<const MemRegion*>(PSL->getLocationValue()); + return nullptr; + } + + /// \brief Get the value of arbitrary expressions at this point in the path. + SVal getSVal(const Stmt *S) const { + return getState()->getSVal(S, getLocationContext()); + } + + /// \brief Generates a new transition in the program state graph + /// (ExplodedGraph). Uses the default CheckerContext predecessor node. + /// + /// @param State The state of the generated node. If not specified, the state + /// will not be changed, but the new node will have the checker's tag. + /// @param Tag The tag is used to uniquely identify the creation site. If no + /// tag is specified, a default tag, unique to the given checker, + /// will be used. Tags are used to prevent states generated at + /// different sites from caching out. + ExplodedNode *addTransition(ProgramStateRef State = nullptr, + const ProgramPointTag *Tag = nullptr) { + return addTransitionImpl(State ? State : getState(), false, nullptr, Tag); + } + + /// \brief Generates a new transition with the given predecessor. + /// Allows checkers to generate a chain of nodes. + /// + /// @param State The state of the generated node. + /// @param Pred The transition will be generated from the specified Pred node + /// to the newly generated node. + /// @param Tag The tag to uniquely identify the creation site. + ExplodedNode *addTransition(ProgramStateRef State, + ExplodedNode *Pred, + const ProgramPointTag *Tag = nullptr) { + return addTransitionImpl(State, false, Pred, Tag); + } + + /// \brief Generate a sink node. Generating a sink stops exploration of the + /// given path. To create a sink node for the purpose of reporting an error, + /// checkers should use generateErrorNode() instead. + ExplodedNode *generateSink(ProgramStateRef State, ExplodedNode *Pred, + const ProgramPointTag *Tag = nullptr) { + return addTransitionImpl(State ? State : getState(), true, Pred, Tag); + } + + /// \brief Generate a transition to a node that will be used to report + /// an error. This node will be a sink. That is, it will stop exploration of + /// the given path. + /// + /// @param State The state of the generated node. + /// @param Tag The tag to uniquely identify the creation site. If null, + /// the default tag for the checker will be used. + ExplodedNode *generateErrorNode(ProgramStateRef State = nullptr, + const ProgramPointTag *Tag = nullptr) { + return generateSink(State, Pred, + (Tag ? Tag : Location.getTag())); + } + + /// \brief Generate a transition to a node that will be used to report + /// an error. This node will not be a sink. That is, exploration will + /// continue along this path. + /// + /// @param State The state of the generated node. + /// @param Tag The tag to uniquely identify the creation site. If null, + /// the default tag for the checker will be used. + ExplodedNode * + generateNonFatalErrorNode(ProgramStateRef State = nullptr, + const ProgramPointTag *Tag = nullptr) { + return addTransition(State, (Tag ? Tag : Location.getTag())); + } + + /// \brief Emit the diagnostics report. + void emitReport(std::unique_ptr<BugReport> R) { + Changed = true; + Eng.getBugReporter().emitReport(std::move(R)); + } + + /// \brief Get the declaration of the called function (path-sensitive). + const FunctionDecl *getCalleeDecl(const CallExpr *CE) const; + + /// \brief Get the name of the called function (path-sensitive). + StringRef getCalleeName(const FunctionDecl *FunDecl) const; + + /// \brief Get the identifier of the called function (path-sensitive). + const IdentifierInfo *getCalleeIdentifier(const CallExpr *CE) const { + const FunctionDecl *FunDecl = getCalleeDecl(CE); + if (FunDecl) + return FunDecl->getIdentifier(); + else + return nullptr; + } + + /// \brief Get the name of the called function (path-sensitive). + StringRef getCalleeName(const CallExpr *CE) const { + const FunctionDecl *FunDecl = getCalleeDecl(CE); + return getCalleeName(FunDecl); + } + + /// \brief Returns true if the callee is an externally-visible function in the + /// top-level namespace, such as \c malloc. + /// + /// If a name is provided, the function must additionally match the given + /// name. + /// + /// Note that this deliberately excludes C++ library functions in the \c std + /// namespace, but will include C library functions accessed through the + /// \c std namespace. This also does not check if the function is declared + /// as 'extern "C"', or if it uses C++ name mangling. + static bool isCLibraryFunction(const FunctionDecl *FD, + StringRef Name = StringRef()); + + /// \brief Depending on wither the location corresponds to a macro, return + /// either the macro name or the token spelling. + /// + /// This could be useful when checkers' logic depends on whether a function + /// is called with a given macro argument. For example: + /// s = socket(AF_INET,..) + /// If AF_INET is a macro, the result should be treated as a source of taint. + /// + /// \sa clang::Lexer::getSpelling(), clang::Lexer::getImmediateMacroName(). + StringRef getMacroNameOrSpelling(SourceLocation &Loc); + +private: + ExplodedNode *addTransitionImpl(ProgramStateRef State, + bool MarkAsSink, + ExplodedNode *P = nullptr, + const ProgramPointTag *Tag = nullptr) { + // The analyzer may stop exploring if it sees a state it has previously + // visited ("cache out"). The early return here is a defensive check to + // prevent accidental caching out by checker API clients. Unless there is a + // tag or the client checker has requested that the generated node be + // marked as a sink, we assume that a client requesting a transition to a + // state that is the same as the predecessor state has made a mistake. We + // return the predecessor rather than cache out. + // + // TODO: We could potentially change the return to an assertion to alert + // clients to their mistake, but several checkers (including + // DereferenceChecker, CallAndMessageChecker, and DynamicTypePropagation) + // rely upon the defensive behavior and would need to be updated. + if (!State || (State == Pred->getState() && !Tag && !MarkAsSink)) + return Pred; + + Changed = true; + const ProgramPoint &LocalLoc = (Tag ? Location.withTag(Tag) : Location); + if (!P) + P = Pred; + + ExplodedNode *node; + if (MarkAsSink) + node = NB.generateSink(LocalLoc, State, P); + else + node = NB.generateNode(LocalLoc, State, P); + return node; + } +}; + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h new file mode 100644 index 0000000..8dda636 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h @@ -0,0 +1,49 @@ +//== CheckerHelpers.h - Helper functions for checkers ------------*- C++ -*--=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines CheckerVisitor. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CHECKERHELPERS_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CHECKERHELPERS_H + +#include "clang/AST/Stmt.h" +#include <tuple> + +namespace clang { + +class Expr; +class VarDecl; + +namespace ento { + +bool containsMacro(const Stmt *S); +bool containsEnum(const Stmt *S); +bool containsStaticLocal(const Stmt *S); +bool containsBuiltinOffsetOf(const Stmt *S); +template <class T> bool containsStmt(const Stmt *S) { + if (isa<T>(S)) + return true; + + for (const Stmt *Child : S->children()) + if (Child && containsStmt<T>(Child)) + return true; + + return false; +} + +std::pair<const clang::VarDecl *, const clang::Expr *> +parseAssignment(const Stmt *S); + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h new file mode 100644 index 0000000..9a858c2 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h @@ -0,0 +1,188 @@ +//== ConstraintManager.h - Constraints on symbolic values.-------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defined the interface to manage constraints on symbolic values. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CONSTRAINTMANAGER_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CONSTRAINTMANAGER_H + +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" +#include "llvm/Support/SaveAndRestore.h" + +namespace llvm { +class APSInt; +} + +namespace clang { +namespace ento { + +class SubEngine; + +class ConditionTruthVal { + Optional<bool> Val; +public: + /// Construct a ConditionTruthVal indicating the constraint is constrained + /// to either true or false, depending on the boolean value provided. + ConditionTruthVal(bool constraint) : Val(constraint) {} + + /// Construct a ConstraintVal indicating the constraint is underconstrained. + ConditionTruthVal() {} + + /// Return true if the constraint is perfectly constrained to 'true'. + bool isConstrainedTrue() const { + return Val.hasValue() && Val.getValue(); + } + + /// Return true if the constraint is perfectly constrained to 'false'. + bool isConstrainedFalse() const { + return Val.hasValue() && !Val.getValue(); + } + + /// Return true if the constrained is perfectly constrained. + bool isConstrained() const { + return Val.hasValue(); + } + + /// Return true if the constrained is underconstrained and we do not know + /// if the constraint is true of value. + bool isUnderconstrained() const { + return !Val.hasValue(); + } +}; + +class ConstraintManager { +public: + ConstraintManager() : NotifyAssumeClients(true) {} + + virtual ~ConstraintManager(); + virtual ProgramStateRef assume(ProgramStateRef state, + DefinedSVal Cond, + bool Assumption) = 0; + + typedef std::pair<ProgramStateRef, ProgramStateRef> ProgramStatePair; + + /// Returns a pair of states (StTrue, StFalse) where the given condition is + /// assumed to be true or false, respectively. + ProgramStatePair assumeDual(ProgramStateRef State, DefinedSVal Cond) { + ProgramStateRef StTrue = assume(State, Cond, true); + + // If StTrue is infeasible, asserting the falseness of Cond is unnecessary + // because the existing constraints already establish this. + if (!StTrue) { +#ifndef __OPTIMIZE__ + // This check is expensive and should be disabled even in Release+Asserts + // builds. + // FIXME: __OPTIMIZE__ is a GNU extension that Clang implements but MSVC + // does not. Is there a good equivalent there? + assert(assume(State, Cond, false) && "System is over constrained."); +#endif + return ProgramStatePair((ProgramStateRef)nullptr, State); + } + + ProgramStateRef StFalse = assume(State, Cond, false); + if (!StFalse) { + // We are careful to return the original state, /not/ StTrue, + // because we want to avoid having callers generate a new node + // in the ExplodedGraph. + return ProgramStatePair(State, (ProgramStateRef)nullptr); + } + + return ProgramStatePair(StTrue, StFalse); + } + + virtual ProgramStateRef assumeWithinInclusiveRange(ProgramStateRef State, + NonLoc Value, + const llvm::APSInt &From, + const llvm::APSInt &To, + bool InBound) = 0; + + virtual ProgramStatePair assumeWithinInclusiveRangeDual( + ProgramStateRef State, NonLoc Value, const llvm::APSInt &From, + const llvm::APSInt &To) { + ProgramStateRef StInRange = assumeWithinInclusiveRange(State, Value, From, + To, true); + + // If StTrue is infeasible, asserting the falseness of Cond is unnecessary + // because the existing constraints already establish this. + if (!StInRange) + return ProgramStatePair((ProgramStateRef)nullptr, State); + + ProgramStateRef StOutOfRange = assumeWithinInclusiveRange(State, Value, + From, To, false); + if (!StOutOfRange) { + // We are careful to return the original state, /not/ StTrue, + // because we want to avoid having callers generate a new node + // in the ExplodedGraph. + return ProgramStatePair(State, (ProgramStateRef)nullptr); + } + + return ProgramStatePair(StInRange, StOutOfRange); + } + + /// \brief If a symbol is perfectly constrained to a constant, attempt + /// to return the concrete value. + /// + /// Note that a ConstraintManager is not obligated to return a concretized + /// value for a symbol, even if it is perfectly constrained. + virtual const llvm::APSInt* getSymVal(ProgramStateRef state, + SymbolRef sym) const { + return nullptr; + } + + virtual ProgramStateRef removeDeadBindings(ProgramStateRef state, + SymbolReaper& SymReaper) = 0; + + virtual void print(ProgramStateRef state, + raw_ostream &Out, + const char* nl, + const char *sep) = 0; + + virtual void EndPath(ProgramStateRef state) {} + + /// Convenience method to query the state to see if a symbol is null or + /// not null, or if neither assumption can be made. + ConditionTruthVal isNull(ProgramStateRef State, SymbolRef Sym) { + SaveAndRestore<bool> DisableNotify(NotifyAssumeClients, false); + + return checkNull(State, Sym); + } + +protected: + /// A flag to indicate that clients should be notified of assumptions. + /// By default this is the case, but sometimes this needs to be restricted + /// to avoid infinite recursions within the ConstraintManager. + /// + /// Note that this flag allows the ConstraintManager to be re-entrant, + /// but not thread-safe. + bool NotifyAssumeClients; + + /// canReasonAbout - Not all ConstraintManagers can accurately reason about + /// all SVal values. This method returns true if the ConstraintManager can + /// reasonably handle a given SVal value. This is typically queried by + /// ExprEngine to determine if the value should be replaced with a + /// conjured symbolic value in order to recover some precision. + virtual bool canReasonAbout(SVal X) const = 0; + + /// Returns whether or not a symbol is known to be null ("true"), known to be + /// non-null ("false"), or may be either ("underconstrained"). + virtual ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym); +}; + +std::unique_ptr<ConstraintManager> +CreateRangeConstraintManager(ProgramStateManager &statemgr, + SubEngine *subengine); + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h new file mode 100644 index 0000000..d5822e2 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h @@ -0,0 +1,547 @@ +//==- CoreEngine.h - Path-Sensitive Dataflow Engine ----------------*- 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 generic engine for intraprocedural, path-sensitive, +// dataflow analysis via graph reachability. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_COREENGINE_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_COREENGINE_H + +#include "clang/AST/Expr.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h" +#include <memory> + +namespace clang { + +class ProgramPointTag; + +namespace ento { + +class NodeBuilder; + +//===----------------------------------------------------------------------===// +/// CoreEngine - Implements the core logic of the graph-reachability +/// analysis. It traverses the CFG and generates the ExplodedGraph. +/// Program "states" are treated as opaque void pointers. +/// The template class CoreEngine (which subclasses CoreEngine) +/// provides the matching component to the engine that knows the actual types +/// for states. Note that this engine only dispatches to transfer functions +/// at the statement and block-level. The analyses themselves must implement +/// any transfer function logic and the sub-expression level (if any). +class CoreEngine { + friend struct NodeBuilderContext; + friend class NodeBuilder; + friend class ExprEngine; + friend class CommonNodeBuilder; + friend class IndirectGotoNodeBuilder; + friend class SwitchNodeBuilder; + friend class EndOfFunctionNodeBuilder; +public: + typedef std::vector<std::pair<BlockEdge, const ExplodedNode*> > + BlocksExhausted; + + typedef std::vector<std::pair<const CFGBlock*, const ExplodedNode*> > + BlocksAborted; + +private: + + SubEngine& SubEng; + + /// G - The simulation graph. Each node is a (location,state) pair. + mutable ExplodedGraph G; + + /// WList - A set of queued nodes that need to be processed by the + /// worklist algorithm. It is up to the implementation of WList to decide + /// the order that nodes are processed. + std::unique_ptr<WorkList> WList; + + /// BCounterFactory - A factory object for created BlockCounter objects. + /// These are used to record for key nodes in the ExplodedGraph the + /// number of times different CFGBlocks have been visited along a path. + BlockCounter::Factory BCounterFactory; + + /// The locations where we stopped doing work because we visited a location + /// too many times. + BlocksExhausted blocksExhausted; + + /// The locations where we stopped because the engine aborted analysis, + /// usually because it could not reason about something. + BlocksAborted blocksAborted; + + /// The information about functions shared by the whole translation unit. + /// (This data is owned by AnalysisConsumer.) + FunctionSummariesTy *FunctionSummaries; + + void generateNode(const ProgramPoint &Loc, + ProgramStateRef State, + ExplodedNode *Pred); + + void HandleBlockEdge(const BlockEdge &E, ExplodedNode *Pred); + void HandleBlockEntrance(const BlockEntrance &E, ExplodedNode *Pred); + void HandleBlockExit(const CFGBlock *B, ExplodedNode *Pred); + void HandlePostStmt(const CFGBlock *B, unsigned StmtIdx, ExplodedNode *Pred); + + void HandleBranch(const Stmt *Cond, const Stmt *Term, const CFGBlock *B, + ExplodedNode *Pred); + void HandleCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE, + const CFGBlock *B, ExplodedNode *Pred); + + /// Handle conditional logic for running static initializers. + void HandleStaticInit(const DeclStmt *DS, const CFGBlock *B, + ExplodedNode *Pred); + +private: + CoreEngine(const CoreEngine &) = delete; + void operator=(const CoreEngine &) = delete; + + ExplodedNode *generateCallExitBeginNode(ExplodedNode *N); + +public: + /// Construct a CoreEngine object to analyze the provided CFG. + CoreEngine(SubEngine &subengine, FunctionSummariesTy *FS) + : SubEng(subengine), WList(WorkList::makeDFS()), + BCounterFactory(G.getAllocator()), FunctionSummaries(FS) {} + + /// getGraph - Returns the exploded graph. + ExplodedGraph &getGraph() { return G; } + + /// ExecuteWorkList - Run the worklist algorithm for a maximum number of + /// steps. Returns true if there is still simulation state on the worklist. + bool ExecuteWorkList(const LocationContext *L, unsigned Steps, + ProgramStateRef InitState); + /// Returns true if there is still simulation state on the worklist. + bool ExecuteWorkListWithInitialState(const LocationContext *L, + unsigned Steps, + ProgramStateRef InitState, + ExplodedNodeSet &Dst); + + /// Dispatch the work list item based on the given location information. + /// Use Pred parameter as the predecessor state. + void dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc, + const WorkListUnit& WU); + + // Functions for external checking of whether we have unfinished work + bool wasBlockAborted() const { return !blocksAborted.empty(); } + bool wasBlocksExhausted() const { return !blocksExhausted.empty(); } + bool hasWorkRemaining() const { return wasBlocksExhausted() || + WList->hasWork() || + wasBlockAborted(); } + + /// Inform the CoreEngine that a basic block was aborted because + /// it could not be completely analyzed. + void addAbortedBlock(const ExplodedNode *node, const CFGBlock *block) { + blocksAborted.push_back(std::make_pair(block, node)); + } + + WorkList *getWorkList() const { return WList.get(); } + + BlocksExhausted::const_iterator blocks_exhausted_begin() const { + return blocksExhausted.begin(); + } + BlocksExhausted::const_iterator blocks_exhausted_end() const { + return blocksExhausted.end(); + } + BlocksAborted::const_iterator blocks_aborted_begin() const { + return blocksAborted.begin(); + } + BlocksAborted::const_iterator blocks_aborted_end() const { + return blocksAborted.end(); + } + + /// \brief Enqueue the given set of nodes onto the work list. + void enqueue(ExplodedNodeSet &Set); + + /// \brief Enqueue nodes that were created as a result of processing + /// a statement onto the work list. + void enqueue(ExplodedNodeSet &Set, const CFGBlock *Block, unsigned Idx); + + /// \brief enqueue the nodes corresponding to the end of function onto the + /// end of path / work list. + void enqueueEndOfFunction(ExplodedNodeSet &Set); + + /// \brief Enqueue a single node created as a result of statement processing. + void enqueueStmtNode(ExplodedNode *N, const CFGBlock *Block, unsigned Idx); +}; + +// TODO: Turn into a calss. +struct NodeBuilderContext { + const CoreEngine &Eng; + const CFGBlock *Block; + const LocationContext *LC; + NodeBuilderContext(const CoreEngine &E, const CFGBlock *B, ExplodedNode *N) + : Eng(E), Block(B), LC(N->getLocationContext()) { assert(B); } + + /// \brief Return the CFGBlock associated with this builder. + const CFGBlock *getBlock() const { return Block; } + + /// \brief Returns the number of times the current basic block has been + /// visited on the exploded graph path. + unsigned blockCount() const { + return Eng.WList->getBlockCounter().getNumVisited( + LC->getCurrentStackFrame(), + Block->getBlockID()); + } +}; + +/// \class NodeBuilder +/// \brief This is the simplest builder which generates nodes in the +/// ExplodedGraph. +/// +/// The main benefit of the builder is that it automatically tracks the +/// frontier nodes (or destination set). This is the set of nodes which should +/// be propagated to the next step / builder. They are the nodes which have been +/// added to the builder (either as the input node set or as the newly +/// constructed nodes) but did not have any outgoing transitions added. +class NodeBuilder { + virtual void anchor(); +protected: + const NodeBuilderContext &C; + + /// Specifies if the builder results have been finalized. For example, if it + /// is set to false, autotransitions are yet to be generated. + bool Finalized; + bool HasGeneratedNodes; + /// \brief The frontier set - a set of nodes which need to be propagated after + /// the builder dies. + ExplodedNodeSet &Frontier; + + /// Checkes if the results are ready. + virtual bool checkResults() { + if (!Finalized) + return false; + return true; + } + + bool hasNoSinksInFrontier() { + for (iterator I = Frontier.begin(), E = Frontier.end(); I != E; ++I) { + if ((*I)->isSink()) + return false; + } + return true; + } + + /// Allow subclasses to finalize results before result_begin() is executed. + virtual void finalizeResults() {} + + ExplodedNode *generateNodeImpl(const ProgramPoint &PP, + ProgramStateRef State, + ExplodedNode *Pred, + bool MarkAsSink = false); + +public: + NodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet, + const NodeBuilderContext &Ctx, bool F = true) + : C(Ctx), Finalized(F), HasGeneratedNodes(false), Frontier(DstSet) { + Frontier.Add(SrcNode); + } + + NodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet, + const NodeBuilderContext &Ctx, bool F = true) + : C(Ctx), Finalized(F), HasGeneratedNodes(false), Frontier(DstSet) { + Frontier.insert(SrcSet); + assert(hasNoSinksInFrontier()); + } + + virtual ~NodeBuilder() {} + + /// \brief Generates a node in the ExplodedGraph. + ExplodedNode *generateNode(const ProgramPoint &PP, + ProgramStateRef State, + ExplodedNode *Pred) { + return generateNodeImpl(PP, State, Pred, false); + } + + /// \brief Generates a sink in the ExplodedGraph. + /// + /// When a node is marked as sink, the exploration from the node is stopped - + /// the node becomes the last node on the path and certain kinds of bugs are + /// suppressed. + ExplodedNode *generateSink(const ProgramPoint &PP, + ProgramStateRef State, + ExplodedNode *Pred) { + return generateNodeImpl(PP, State, Pred, true); + } + + const ExplodedNodeSet &getResults() { + finalizeResults(); + assert(checkResults()); + return Frontier; + } + + typedef ExplodedNodeSet::iterator iterator; + /// \brief Iterators through the results frontier. + inline iterator begin() { + finalizeResults(); + assert(checkResults()); + return Frontier.begin(); + } + inline iterator end() { + finalizeResults(); + return Frontier.end(); + } + + const NodeBuilderContext &getContext() { return C; } + bool hasGeneratedNodes() { return HasGeneratedNodes; } + + void takeNodes(const ExplodedNodeSet &S) { + for (ExplodedNodeSet::iterator I = S.begin(), E = S.end(); I != E; ++I ) + Frontier.erase(*I); + } + void takeNodes(ExplodedNode *N) { Frontier.erase(N); } + void addNodes(const ExplodedNodeSet &S) { Frontier.insert(S); } + void addNodes(ExplodedNode *N) { Frontier.Add(N); } +}; + +/// \class NodeBuilderWithSinks +/// \brief This node builder keeps track of the generated sink nodes. +class NodeBuilderWithSinks: public NodeBuilder { + void anchor() override; +protected: + SmallVector<ExplodedNode*, 2> sinksGenerated; + ProgramPoint &Location; + +public: + NodeBuilderWithSinks(ExplodedNode *Pred, ExplodedNodeSet &DstSet, + const NodeBuilderContext &Ctx, ProgramPoint &L) + : NodeBuilder(Pred, DstSet, Ctx), Location(L) {} + + ExplodedNode *generateNode(ProgramStateRef State, + ExplodedNode *Pred, + const ProgramPointTag *Tag = nullptr) { + const ProgramPoint &LocalLoc = (Tag ? Location.withTag(Tag) : Location); + return NodeBuilder::generateNode(LocalLoc, State, Pred); + } + + ExplodedNode *generateSink(ProgramStateRef State, ExplodedNode *Pred, + const ProgramPointTag *Tag = nullptr) { + const ProgramPoint &LocalLoc = (Tag ? Location.withTag(Tag) : Location); + ExplodedNode *N = NodeBuilder::generateSink(LocalLoc, State, Pred); + if (N && N->isSink()) + sinksGenerated.push_back(N); + return N; + } + + const SmallVectorImpl<ExplodedNode*> &getSinks() const { + return sinksGenerated; + } +}; + +/// \class StmtNodeBuilder +/// \brief This builder class is useful for generating nodes that resulted from +/// visiting a statement. The main difference from its parent NodeBuilder is +/// that it creates a statement specific ProgramPoint. +class StmtNodeBuilder: public NodeBuilder { + NodeBuilder *EnclosingBldr; +public: + + /// \brief Constructs a StmtNodeBuilder. If the builder is going to process + /// nodes currently owned by another builder(with larger scope), use + /// Enclosing builder to transfer ownership. + StmtNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet, + const NodeBuilderContext &Ctx, + NodeBuilder *Enclosing = nullptr) + : NodeBuilder(SrcNode, DstSet, Ctx), EnclosingBldr(Enclosing) { + if (EnclosingBldr) + EnclosingBldr->takeNodes(SrcNode); + } + + StmtNodeBuilder(ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet, + const NodeBuilderContext &Ctx, + NodeBuilder *Enclosing = nullptr) + : NodeBuilder(SrcSet, DstSet, Ctx), EnclosingBldr(Enclosing) { + if (EnclosingBldr) + for (ExplodedNodeSet::iterator I = SrcSet.begin(), + E = SrcSet.end(); I != E; ++I ) + EnclosingBldr->takeNodes(*I); + } + + ~StmtNodeBuilder() override; + + using NodeBuilder::generateNode; + using NodeBuilder::generateSink; + + ExplodedNode *generateNode(const Stmt *S, + ExplodedNode *Pred, + ProgramStateRef St, + const ProgramPointTag *tag = nullptr, + ProgramPoint::Kind K = ProgramPoint::PostStmtKind){ + const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, + Pred->getLocationContext(), tag); + return NodeBuilder::generateNode(L, St, Pred); + } + + ExplodedNode *generateSink(const Stmt *S, + ExplodedNode *Pred, + ProgramStateRef St, + const ProgramPointTag *tag = nullptr, + ProgramPoint::Kind K = ProgramPoint::PostStmtKind){ + const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, + Pred->getLocationContext(), tag); + return NodeBuilder::generateSink(L, St, Pred); + } +}; + +/// \brief BranchNodeBuilder is responsible for constructing the nodes +/// corresponding to the two branches of the if statement - true and false. +class BranchNodeBuilder: public NodeBuilder { + void anchor() override; + const CFGBlock *DstT; + const CFGBlock *DstF; + + bool InFeasibleTrue; + bool InFeasibleFalse; + +public: + BranchNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet, + const NodeBuilderContext &C, + const CFGBlock *dstT, const CFGBlock *dstF) + : NodeBuilder(SrcNode, DstSet, C), DstT(dstT), DstF(dstF), + InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) { + // The branch node builder does not generate autotransitions. + // If there are no successors it means that both branches are infeasible. + takeNodes(SrcNode); + } + + BranchNodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet, + const NodeBuilderContext &C, + const CFGBlock *dstT, const CFGBlock *dstF) + : NodeBuilder(SrcSet, DstSet, C), DstT(dstT), DstF(dstF), + InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) { + takeNodes(SrcSet); + } + + ExplodedNode *generateNode(ProgramStateRef State, bool branch, + ExplodedNode *Pred); + + const CFGBlock *getTargetBlock(bool branch) const { + return branch ? DstT : DstF; + } + + void markInfeasible(bool branch) { + if (branch) + InFeasibleTrue = true; + else + InFeasibleFalse = true; + } + + bool isFeasible(bool branch) { + return branch ? !InFeasibleTrue : !InFeasibleFalse; + } +}; + +class IndirectGotoNodeBuilder { + CoreEngine& Eng; + const CFGBlock *Src; + const CFGBlock &DispatchBlock; + const Expr *E; + ExplodedNode *Pred; + +public: + IndirectGotoNodeBuilder(ExplodedNode *pred, const CFGBlock *src, + const Expr *e, const CFGBlock *dispatch, CoreEngine* eng) + : Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {} + + class iterator { + CFGBlock::const_succ_iterator I; + + friend class IndirectGotoNodeBuilder; + iterator(CFGBlock::const_succ_iterator i) : I(i) {} + public: + + iterator &operator++() { ++I; return *this; } + bool operator!=(const iterator &X) const { return I != X.I; } + + const LabelDecl *getLabel() const { + return cast<LabelStmt>((*I)->getLabel())->getDecl(); + } + + const CFGBlock *getBlock() const { + return *I; + } + }; + + iterator begin() { return iterator(DispatchBlock.succ_begin()); } + iterator end() { return iterator(DispatchBlock.succ_end()); } + + ExplodedNode *generateNode(const iterator &I, + ProgramStateRef State, + bool isSink = false); + + const Expr *getTarget() const { return E; } + + ProgramStateRef getState() const { return Pred->State; } + + const LocationContext *getLocationContext() const { + return Pred->getLocationContext(); + } +}; + +class SwitchNodeBuilder { + CoreEngine& Eng; + const CFGBlock *Src; + const Expr *Condition; + ExplodedNode *Pred; + +public: + SwitchNodeBuilder(ExplodedNode *pred, const CFGBlock *src, + const Expr *condition, CoreEngine* eng) + : Eng(*eng), Src(src), Condition(condition), Pred(pred) {} + + class iterator { + CFGBlock::const_succ_reverse_iterator I; + + friend class SwitchNodeBuilder; + iterator(CFGBlock::const_succ_reverse_iterator i) : I(i) {} + + public: + iterator &operator++() { ++I; return *this; } + bool operator!=(const iterator &X) const { return I != X.I; } + bool operator==(const iterator &X) const { return I == X.I; } + + const CaseStmt *getCase() const { + return cast<CaseStmt>((*I)->getLabel()); + } + + const CFGBlock *getBlock() const { + return *I; + } + }; + + iterator begin() { return iterator(Src->succ_rbegin()+1); } + iterator end() { return iterator(Src->succ_rend()); } + + const SwitchStmt *getSwitch() const { + return cast<SwitchStmt>(Src->getTerminator()); + } + + ExplodedNode *generateCaseStmtNode(const iterator &I, + ProgramStateRef State); + + ExplodedNode *generateDefaultCaseNode(ProgramStateRef State, + bool isSink = false); + + const Expr *getCondition() const { return Condition; } + + ProgramStateRef getState() const { return Pred->State; } + + const LocationContext *getLocationContext() const { + return Pred->getLocationContext(); + } +}; + +} // end ento namespace +} // end clang namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h new file mode 100644 index 0000000..e13c641 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h @@ -0,0 +1,52 @@ +//== DynamicTypeInfo.h - Runtime type information ----------------*- 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_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICTYPEINFO_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICTYPEINFO_H + +#include "clang/AST/Type.h" + +namespace clang { +namespace ento { + +/// \brief Stores the currently inferred strictest bound on the runtime type +/// of a region in a given state along the analysis path. +class DynamicTypeInfo { +private: + QualType T; + bool CanBeASubClass; + +public: + + DynamicTypeInfo() : T(QualType()) {} + DynamicTypeInfo(QualType WithType, bool CanBeSub = true) + : T(WithType), CanBeASubClass(CanBeSub) {} + + /// \brief Return false if no dynamic type info is available. + bool isValid() const { return !T.isNull(); } + + /// \brief Returns the currently inferred upper bound on the runtime type. + QualType getType() const { return T; } + + /// \brief Returns false if the type information is precise (the type T is + /// the only type in the lattice), true otherwise. + bool canBeASubClass() const { return CanBeASubClass; } + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.Add(T); + ID.AddInteger((unsigned)CanBeASubClass); + } + bool operator==(const DynamicTypeInfo &X) const { + return T == X.T && CanBeASubClass == X.CanBeASubClass; + } +}; + +} // end ento +} // end clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h new file mode 100644 index 0000000..555191d --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h @@ -0,0 +1,57 @@ +//== DynamicTypeMap.h - Dynamic type map ----------------------- -*- 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 APIs for tracking dynamic type information. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICTYPEMAP_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICTYPEMAP_H +#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" +#include "llvm/ADT/ImmutableMap.h" + +namespace clang { +namespace ento { + +/// The GDM component containing the dynamic type info. This is a map from a +/// symbol to its most likely type. +struct DynamicTypeMap {}; +typedef llvm::ImmutableMap<const MemRegion *, DynamicTypeInfo> + DynamicTypeMapImpl; +template <> +struct ProgramStateTrait<DynamicTypeMap> + : public ProgramStatePartialTrait<DynamicTypeMapImpl> { + static void *GDMIndex() { + static int index = 0; + return &index; + } +}; + +/// \brief Get dynamic type information for a region. +DynamicTypeInfo getDynamicTypeInfo(ProgramStateRef State, + const MemRegion *Reg); + +/// \brief Set dynamic type information of the region; return the new state. +ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *Reg, + DynamicTypeInfo NewTy); + +/// \brief Set dynamic type information of the region; return the new state. +inline ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, + const MemRegion *Reg, QualType NewTy, + bool CanBeSubClassed = true) { + return setDynamicTypeInfo(State, Reg, + DynamicTypeInfo(NewTy, CanBeSubClassed)); +} + +} // ento +} // clang + +#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICTYPEMAP_H diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h new file mode 100644 index 0000000..cc3779d --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h @@ -0,0 +1,127 @@ +//== Environment.h - Map from Stmt* to Locations/Values ---------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defined the Environment and EnvironmentManager classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ENVIRONMENT_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ENVIRONMENT_H + +#include "clang/Analysis/AnalysisContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" +#include "llvm/ADT/ImmutableMap.h" + +namespace clang { + +class LiveVariables; + +namespace ento { + +class EnvironmentManager; +class SValBuilder; + +/// An entry in the environment consists of a Stmt and an LocationContext. +/// This allows the environment to manage context-sensitive bindings, +/// which is essentially for modeling recursive function analysis, among +/// other things. +class EnvironmentEntry : public std::pair<const Stmt*, + const StackFrameContext *> { +public: + EnvironmentEntry(const Stmt *s, const LocationContext *L); + + const Stmt *getStmt() const { return first; } + const LocationContext *getLocationContext() const { return second; } + + /// Profile an EnvironmentEntry for inclusion in a FoldingSet. + static void Profile(llvm::FoldingSetNodeID &ID, + const EnvironmentEntry &E) { + ID.AddPointer(E.getStmt()); + ID.AddPointer(E.getLocationContext()); + } + + void Profile(llvm::FoldingSetNodeID &ID) const { + Profile(ID, *this); + } +}; + +/// An immutable map from EnvironemntEntries to SVals. +class Environment { +private: + friend class EnvironmentManager; + + // Type definitions. + typedef llvm::ImmutableMap<EnvironmentEntry, SVal> BindingsTy; + + // Data. + BindingsTy ExprBindings; + + Environment(BindingsTy eb) + : ExprBindings(eb) {} + + SVal lookupExpr(const EnvironmentEntry &E) const; + +public: + typedef BindingsTy::iterator iterator; + iterator begin() const { return ExprBindings.begin(); } + iterator end() const { return ExprBindings.end(); } + + /// Fetches the current binding of the expression in the + /// Environment. + SVal getSVal(const EnvironmentEntry &E, SValBuilder &svalBuilder) const; + + /// Profile - Profile the contents of an Environment object for use + /// in a FoldingSet. + static void Profile(llvm::FoldingSetNodeID& ID, const Environment* env) { + env->ExprBindings.Profile(ID); + } + + /// Profile - Used to profile the contents of this object for inclusion + /// in a FoldingSet. + void Profile(llvm::FoldingSetNodeID& ID) const { + Profile(ID, this); + } + + bool operator==(const Environment& RHS) const { + return ExprBindings == RHS.ExprBindings; + } + + void print(raw_ostream &Out, const char *NL, const char *Sep) const; + +private: + void printAux(raw_ostream &Out, bool printLocations, + const char *NL, const char *Sep) const; +}; + +class EnvironmentManager { +private: + typedef Environment::BindingsTy::Factory FactoryTy; + FactoryTy F; + +public: + EnvironmentManager(llvm::BumpPtrAllocator& Allocator) : F(Allocator) {} + + Environment getInitialEnvironment() { + return Environment(F.getEmptyMap()); + } + + /// Bind a symbolic value to the given environment entry. + Environment bindExpr(Environment Env, const EnvironmentEntry &E, SVal V, + bool Invalidate); + + Environment removeDeadBindings(Environment Env, + SymbolReaper &SymReaper, + ProgramStateRef state); +}; + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h new file mode 100644 index 0000000..cfb1b92 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h @@ -0,0 +1,497 @@ +//=-- ExplodedGraph.h - Local, Path-Sens. "Exploded Graph" -*- C++ -*-------==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the template classes ExplodedNode and ExplodedGraph, +// which represent a path-sensitive, intra-procedural "exploded graph." +// See "Precise interprocedural dataflow analysis via graph reachability" +// by Reps, Horwitz, and Sagiv +// (http://portal.acm.org/citation.cfm?id=199462) for the definition of an +// exploded graph. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPLODEDGRAPH_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPLODEDGRAPH_H + +#include "clang/AST/Decl.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/ProgramPoint.h" +#include "clang/Analysis/Support/BumpVector.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "llvm/ADT/DepthFirstIterator.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/GraphTraits.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Casting.h" +#include <memory> +#include <vector> + +namespace clang { + +class CFG; + +namespace ento { + +class ExplodedGraph; + +//===----------------------------------------------------------------------===// +// ExplodedGraph "implementation" classes. These classes are not typed to +// contain a specific kind of state. Typed-specialized versions are defined +// on top of these classes. +//===----------------------------------------------------------------------===// + +// ExplodedNode is not constified all over the engine because we need to add +// successors to it at any time after creating it. + +class ExplodedNode : public llvm::FoldingSetNode { + friend class ExplodedGraph; + friend class CoreEngine; + friend class NodeBuilder; + friend class BranchNodeBuilder; + friend class IndirectGotoNodeBuilder; + friend class SwitchNodeBuilder; + friend class EndOfFunctionNodeBuilder; + + /// Efficiently stores a list of ExplodedNodes, or an optional flag. + /// + /// NodeGroup provides opaque storage for a list of ExplodedNodes, optimizing + /// for the case when there is only one node in the group. This is a fairly + /// common case in an ExplodedGraph, where most nodes have only one + /// predecessor and many have only one successor. It can also be used to + /// store a flag rather than a node list, which ExplodedNode uses to mark + /// whether a node is a sink. If the flag is set, the group is implicitly + /// empty and no nodes may be added. + class NodeGroup { + // Conceptually a discriminated union. If the low bit is set, the node is + // a sink. If the low bit is not set, the pointer refers to the storage + // for the nodes in the group. + // This is not a PointerIntPair in order to keep the storage type opaque. + uintptr_t P; + + public: + NodeGroup(bool Flag = false) : P(Flag) { + assert(getFlag() == Flag); + } + + ExplodedNode * const *begin() const; + + ExplodedNode * const *end() const; + + unsigned size() const; + + bool empty() const { return P == 0 || getFlag() != 0; } + + /// Adds a node to the list. + /// + /// The group must not have been created with its flag set. + void addNode(ExplodedNode *N, ExplodedGraph &G); + + /// Replaces the single node in this group with a new node. + /// + /// Note that this should only be used when you know the group was not + /// created with its flag set, and that the group is empty or contains + /// only a single node. + void replaceNode(ExplodedNode *node); + + /// Returns whether this group was created with its flag set. + bool getFlag() const { + return (P & 1); + } + }; + + /// Location - The program location (within a function body) associated + /// with this node. + const ProgramPoint Location; + + /// State - The state associated with this node. + ProgramStateRef State; + + /// Preds - The predecessors of this node. + NodeGroup Preds; + + /// Succs - The successors of this node. + NodeGroup Succs; + +public: + + explicit ExplodedNode(const ProgramPoint &loc, ProgramStateRef state, + bool IsSink) + : Location(loc), State(state), Succs(IsSink) { + assert(isSink() == IsSink); + } + + /// getLocation - Returns the edge associated with the given node. + ProgramPoint getLocation() const { return Location; } + + const LocationContext *getLocationContext() const { + return getLocation().getLocationContext(); + } + + const StackFrameContext *getStackFrame() const { + return getLocationContext()->getCurrentStackFrame(); + } + + const Decl &getCodeDecl() const { return *getLocationContext()->getDecl(); } + + CFG &getCFG() const { return *getLocationContext()->getCFG(); } + + ParentMap &getParentMap() const {return getLocationContext()->getParentMap();} + + template <typename T> + T &getAnalysis() const { + return *getLocationContext()->getAnalysis<T>(); + } + + const ProgramStateRef &getState() const { return State; } + + template <typename T> + Optional<T> getLocationAs() const LLVM_LVALUE_FUNCTION { + return Location.getAs<T>(); + } + + static void Profile(llvm::FoldingSetNodeID &ID, + const ProgramPoint &Loc, + const ProgramStateRef &state, + bool IsSink) { + ID.Add(Loc); + ID.AddPointer(state.get()); + ID.AddBoolean(IsSink); + } + + void Profile(llvm::FoldingSetNodeID& ID) const { + // We avoid copy constructors by not using accessors. + Profile(ID, Location, State, isSink()); + } + + /// addPredeccessor - Adds a predecessor to the current node, and + /// in tandem add this node as a successor of the other node. + void addPredecessor(ExplodedNode *V, ExplodedGraph &G); + + unsigned succ_size() const { return Succs.size(); } + unsigned pred_size() const { return Preds.size(); } + bool succ_empty() const { return Succs.empty(); } + bool pred_empty() const { return Preds.empty(); } + + bool isSink() const { return Succs.getFlag(); } + + bool hasSinglePred() const { + return (pred_size() == 1); + } + + ExplodedNode *getFirstPred() { + return pred_empty() ? nullptr : *(pred_begin()); + } + + const ExplodedNode *getFirstPred() const { + return const_cast<ExplodedNode*>(this)->getFirstPred(); + } + + const ExplodedNode *getFirstSucc() const { + return succ_empty() ? nullptr : *(succ_begin()); + } + + // Iterators over successor and predecessor vertices. + typedef ExplodedNode* const * succ_iterator; + typedef const ExplodedNode* const * const_succ_iterator; + typedef ExplodedNode* const * pred_iterator; + typedef const ExplodedNode* const * const_pred_iterator; + + pred_iterator pred_begin() { return Preds.begin(); } + pred_iterator pred_end() { return Preds.end(); } + + const_pred_iterator pred_begin() const { + return const_cast<ExplodedNode*>(this)->pred_begin(); + } + const_pred_iterator pred_end() const { + return const_cast<ExplodedNode*>(this)->pred_end(); + } + + succ_iterator succ_begin() { return Succs.begin(); } + succ_iterator succ_end() { return Succs.end(); } + + const_succ_iterator succ_begin() const { + return const_cast<ExplodedNode*>(this)->succ_begin(); + } + const_succ_iterator succ_end() const { + return const_cast<ExplodedNode*>(this)->succ_end(); + } + + // For debugging. + +public: + + class Auditor { + public: + virtual ~Auditor(); + virtual void AddEdge(ExplodedNode *Src, ExplodedNode *Dst) = 0; + }; + + static void SetAuditor(Auditor* A); + +private: + void replaceSuccessor(ExplodedNode *node) { Succs.replaceNode(node); } + void replacePredecessor(ExplodedNode *node) { Preds.replaceNode(node); } +}; + +typedef llvm::DenseMap<const ExplodedNode *, const ExplodedNode *> + InterExplodedGraphMap; + +class ExplodedGraph { +protected: + friend class CoreEngine; + + // Type definitions. + typedef std::vector<ExplodedNode *> NodeVector; + + /// The roots of the simulation graph. Usually there will be only + /// one, but clients are free to establish multiple subgraphs within a single + /// SimulGraph. Moreover, these subgraphs can often merge when paths from + /// different roots reach the same state at the same program location. + NodeVector Roots; + + /// The nodes in the simulation graph which have been + /// specially marked as the endpoint of an abstract simulation path. + NodeVector EndNodes; + + /// Nodes - The nodes in the graph. + llvm::FoldingSet<ExplodedNode> Nodes; + + /// BVC - Allocator and context for allocating nodes and their predecessor + /// and successor groups. + BumpVectorContext BVC; + + /// NumNodes - The number of nodes in the graph. + unsigned NumNodes; + + /// A list of recently allocated nodes that can potentially be recycled. + NodeVector ChangedNodes; + + /// A list of nodes that can be reused. + NodeVector FreeNodes; + + /// Determines how often nodes are reclaimed. + /// + /// If this is 0, nodes will never be reclaimed. + unsigned ReclaimNodeInterval; + + /// Counter to determine when to reclaim nodes. + unsigned ReclaimCounter; + +public: + + /// \brief Retrieve the node associated with a (Location,State) pair, + /// where the 'Location' is a ProgramPoint in the CFG. If no node for + /// this pair exists, it is created. IsNew is set to true if + /// the node was freshly created. + ExplodedNode *getNode(const ProgramPoint &L, ProgramStateRef State, + bool IsSink = false, + bool* IsNew = nullptr); + + std::unique_ptr<ExplodedGraph> MakeEmptyGraph() const { + return llvm::make_unique<ExplodedGraph>(); + } + + /// addRoot - Add an untyped node to the set of roots. + ExplodedNode *addRoot(ExplodedNode *V) { + Roots.push_back(V); + return V; + } + + /// addEndOfPath - Add an untyped node to the set of EOP nodes. + ExplodedNode *addEndOfPath(ExplodedNode *V) { + EndNodes.push_back(V); + return V; + } + + ExplodedGraph(); + + ~ExplodedGraph(); + + unsigned num_roots() const { return Roots.size(); } + unsigned num_eops() const { return EndNodes.size(); } + + bool empty() const { return NumNodes == 0; } + unsigned size() const { return NumNodes; } + + // Iterators. + typedef ExplodedNode NodeTy; + typedef llvm::FoldingSet<ExplodedNode> AllNodesTy; + typedef NodeVector::iterator roots_iterator; + typedef NodeVector::const_iterator const_roots_iterator; + typedef NodeVector::iterator eop_iterator; + typedef NodeVector::const_iterator const_eop_iterator; + typedef AllNodesTy::iterator node_iterator; + typedef AllNodesTy::const_iterator const_node_iterator; + + node_iterator nodes_begin() { return Nodes.begin(); } + + node_iterator nodes_end() { return Nodes.end(); } + + const_node_iterator nodes_begin() const { return Nodes.begin(); } + + const_node_iterator nodes_end() const { return Nodes.end(); } + + roots_iterator roots_begin() { return Roots.begin(); } + + roots_iterator roots_end() { return Roots.end(); } + + const_roots_iterator roots_begin() const { return Roots.begin(); } + + const_roots_iterator roots_end() const { return Roots.end(); } + + eop_iterator eop_begin() { return EndNodes.begin(); } + + eop_iterator eop_end() { return EndNodes.end(); } + + const_eop_iterator eop_begin() const { return EndNodes.begin(); } + + const_eop_iterator eop_end() const { return EndNodes.end(); } + + llvm::BumpPtrAllocator & getAllocator() { return BVC.getAllocator(); } + BumpVectorContext &getNodeAllocator() { return BVC; } + + typedef llvm::DenseMap<const ExplodedNode*, ExplodedNode*> NodeMap; + + /// Creates a trimmed version of the graph that only contains paths leading + /// to the given nodes. + /// + /// \param Nodes The nodes which must appear in the final graph. Presumably + /// these are end-of-path nodes (i.e. they have no successors). + /// \param[out] ForwardMap A optional map from nodes in this graph to nodes in + /// the returned graph. + /// \param[out] InverseMap An optional map from nodes in the returned graph to + /// nodes in this graph. + /// \returns The trimmed graph + std::unique_ptr<ExplodedGraph> + trim(ArrayRef<const NodeTy *> Nodes, + InterExplodedGraphMap *ForwardMap = nullptr, + InterExplodedGraphMap *InverseMap = nullptr) const; + + /// Enable tracking of recently allocated nodes for potential reclamation + /// when calling reclaimRecentlyAllocatedNodes(). + void enableNodeReclamation(unsigned Interval) { + ReclaimCounter = ReclaimNodeInterval = Interval; + } + + /// Reclaim "uninteresting" nodes created since the last time this method + /// was called. + void reclaimRecentlyAllocatedNodes(); + + /// \brief Returns true if nodes for the given expression kind are always + /// kept around. + static bool isInterestingLValueExpr(const Expr *Ex); + +private: + bool shouldCollect(const ExplodedNode *node); + void collectNode(ExplodedNode *node); +}; + +class ExplodedNodeSet { + typedef llvm::SmallPtrSet<ExplodedNode*,5> ImplTy; + ImplTy Impl; + +public: + ExplodedNodeSet(ExplodedNode *N) { + assert (N && !static_cast<ExplodedNode*>(N)->isSink()); + Impl.insert(N); + } + + ExplodedNodeSet() {} + + inline void Add(ExplodedNode *N) { + if (N && !static_cast<ExplodedNode*>(N)->isSink()) Impl.insert(N); + } + + typedef ImplTy::iterator iterator; + typedef ImplTy::const_iterator const_iterator; + + unsigned size() const { return Impl.size(); } + bool empty() const { return Impl.empty(); } + bool erase(ExplodedNode *N) { return Impl.erase(N); } + + void clear() { Impl.clear(); } + void insert(const ExplodedNodeSet &S) { + assert(&S != this); + if (empty()) + Impl = S.Impl; + else + Impl.insert(S.begin(), S.end()); + } + + inline iterator begin() { return Impl.begin(); } + inline iterator end() { return Impl.end(); } + + inline const_iterator begin() const { return Impl.begin(); } + inline const_iterator end() const { return Impl.end(); } +}; + +} // end GR namespace + +} // end clang namespace + +// GraphTraits + +namespace llvm { + template<> struct GraphTraits<clang::ento::ExplodedNode*> { + typedef clang::ento::ExplodedNode NodeType; + typedef NodeType::succ_iterator ChildIteratorType; + typedef llvm::df_iterator<NodeType*> nodes_iterator; + + static inline NodeType* getEntryNode(NodeType* N) { + return N; + } + + static inline ChildIteratorType child_begin(NodeType* N) { + return N->succ_begin(); + } + + static inline ChildIteratorType child_end(NodeType* N) { + return N->succ_end(); + } + + static inline nodes_iterator nodes_begin(NodeType* N) { + return df_begin(N); + } + + static inline nodes_iterator nodes_end(NodeType* N) { + return df_end(N); + } + }; + + template<> struct GraphTraits<const clang::ento::ExplodedNode*> { + typedef const clang::ento::ExplodedNode NodeType; + typedef NodeType::const_succ_iterator ChildIteratorType; + typedef llvm::df_iterator<NodeType*> nodes_iterator; + + static inline NodeType* getEntryNode(NodeType* N) { + return N; + } + + static inline ChildIteratorType child_begin(NodeType* N) { + return N->succ_begin(); + } + + static inline ChildIteratorType child_end(NodeType* N) { + return N->succ_end(); + } + + static inline nodes_iterator nodes_begin(NodeType* N) { + return df_begin(N); + } + + static inline nodes_iterator nodes_end(NodeType* N) { + return df_end(N); + } + }; + +} // end llvm namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h new file mode 100644 index 0000000..99083c9 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -0,0 +1,646 @@ +//===-- ExprEngine.h - Path-Sensitive Expression-Level Dataflow ---*- 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 meta-engine for path-sensitive dataflow analysis that +// is built on CoreEngine, but provides the boilerplate to execute transfer +// functions and build the ExplodedGraph at the expression level. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPRENGINE_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPRENGINE_H + +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "clang/Analysis/DomainSpecific/ObjCNoReturn.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h" + +namespace clang { + +class AnalysisDeclContextManager; +class CXXCatchStmt; +class CXXConstructExpr; +class CXXDeleteExpr; +class CXXNewExpr; +class CXXTemporaryObjectExpr; +class CXXThisExpr; +class MaterializeTemporaryExpr; +class ObjCAtSynchronizedStmt; +class ObjCForCollectionStmt; + +namespace ento { + +class AnalysisManager; +class CallEvent; +class CXXConstructorCall; + +class ExprEngine : public SubEngine { +public: + /// The modes of inlining, which override the default analysis-wide settings. + enum InliningModes { + /// Follow the default settings for inlining callees. + Inline_Regular = 0, + /// Do minimal inlining of callees. + Inline_Minimal = 0x1 + }; + +private: + AnalysisManager &AMgr; + + AnalysisDeclContextManager &AnalysisDeclContexts; + + CoreEngine Engine; + + /// G - the simulation graph. + ExplodedGraph& G; + + /// StateMgr - Object that manages the data for all created states. + ProgramStateManager StateMgr; + + /// SymMgr - Object that manages the symbol information. + SymbolManager& SymMgr; + + /// svalBuilder - SValBuilder object that creates SVals from expressions. + SValBuilder &svalBuilder; + + unsigned int currStmtIdx; + const NodeBuilderContext *currBldrCtx; + + /// Helper object to determine if an Objective-C message expression + /// implicitly never returns. + ObjCNoReturn ObjCNoRet; + + /// Whether or not GC is enabled in this analysis. + bool ObjCGCEnabled; + + /// The BugReporter associated with this engine. It is important that + /// this object be placed at the very end of member variables so that its + /// destructor is called before the rest of the ExprEngine is destroyed. + GRBugReporter BR; + + /// The functions which have been analyzed through inlining. This is owned by + /// AnalysisConsumer. It can be null. + SetOfConstDecls *VisitedCallees; + + /// The flag, which specifies the mode of inlining for the engine. + InliningModes HowToInline; + +public: + ExprEngine(AnalysisManager &mgr, bool gcEnabled, + SetOfConstDecls *VisitedCalleesIn, + FunctionSummariesTy *FS, + InliningModes HowToInlineIn); + + ~ExprEngine() override; + + /// Returns true if there is still simulation state on the worklist. + bool ExecuteWorkList(const LocationContext *L, unsigned Steps = 150000) { + return Engine.ExecuteWorkList(L, Steps, nullptr); + } + + /// Execute the work list with an initial state. Nodes that reaches the exit + /// of the function are added into the Dst set, which represent the exit + /// state of the function call. Returns true if there is still simulation + /// state on the worklist. + bool ExecuteWorkListWithInitialState(const LocationContext *L, unsigned Steps, + ProgramStateRef InitState, + ExplodedNodeSet &Dst) { + return Engine.ExecuteWorkListWithInitialState(L, Steps, InitState, Dst); + } + + /// getContext - Return the ASTContext associated with this analysis. + ASTContext &getContext() const { return AMgr.getASTContext(); } + + AnalysisManager &getAnalysisManager() override { return AMgr; } + + CheckerManager &getCheckerManager() const { + return *AMgr.getCheckerManager(); + } + + SValBuilder &getSValBuilder() { return svalBuilder; } + + BugReporter& getBugReporter() { return BR; } + + const NodeBuilderContext &getBuilderContext() { + assert(currBldrCtx); + return *currBldrCtx; + } + + bool isObjCGCEnabled() { return ObjCGCEnabled; } + + const Stmt *getStmt() const; + + void GenerateAutoTransition(ExplodedNode *N); + void enqueueEndOfPath(ExplodedNodeSet &S); + void GenerateCallExitNode(ExplodedNode *N); + + /// Visualize the ExplodedGraph created by executing the simulation. + void ViewGraph(bool trim = false); + + /// Visualize a trimmed ExplodedGraph that only contains paths to the given + /// nodes. + void ViewGraph(ArrayRef<const ExplodedNode*> Nodes); + + /// getInitialState - Return the initial state used for the root vertex + /// in the ExplodedGraph. + ProgramStateRef getInitialState(const LocationContext *InitLoc) override; + + ExplodedGraph& getGraph() { return G; } + const ExplodedGraph& getGraph() const { return G; } + + /// \brief Run the analyzer's garbage collection - remove dead symbols and + /// bindings from the state. + /// + /// Checkers can participate in this process with two callbacks: + /// \c checkLiveSymbols and \c checkDeadSymbols. See the CheckerDocumentation + /// class for more information. + /// + /// \param Node The predecessor node, from which the processing should start. + /// \param Out The returned set of output nodes. + /// \param ReferenceStmt The statement which is about to be processed. + /// Everything needed for this statement should be considered live. + /// A null statement means that everything in child LocationContexts + /// is dead. + /// \param LC The location context of the \p ReferenceStmt. A null location + /// context means that we have reached the end of analysis and that + /// all statements and local variables should be considered dead. + /// \param DiagnosticStmt Used as a location for any warnings that should + /// occur while removing the dead (e.g. leaks). By default, the + /// \p ReferenceStmt is used. + /// \param K Denotes whether this is a pre- or post-statement purge. This + /// must only be ProgramPoint::PostStmtPurgeDeadSymbolsKind if an + /// entire location context is being cleared, in which case the + /// \p ReferenceStmt must either be a ReturnStmt or \c NULL. Otherwise, + /// it must be ProgramPoint::PreStmtPurgeDeadSymbolsKind (the default) + /// and \p ReferenceStmt must be valid (non-null). + void removeDead(ExplodedNode *Node, ExplodedNodeSet &Out, + const Stmt *ReferenceStmt, const LocationContext *LC, + const Stmt *DiagnosticStmt = nullptr, + ProgramPoint::Kind K = ProgramPoint::PreStmtPurgeDeadSymbolsKind); + + /// processCFGElement - Called by CoreEngine. Used to generate new successor + /// nodes by processing the 'effects' of a CFG element. + void processCFGElement(const CFGElement E, ExplodedNode *Pred, + unsigned StmtIdx, NodeBuilderContext *Ctx) override; + + void ProcessStmt(const CFGStmt S, ExplodedNode *Pred); + + void ProcessInitializer(const CFGInitializer I, ExplodedNode *Pred); + + void ProcessImplicitDtor(const CFGImplicitDtor D, ExplodedNode *Pred); + + void ProcessNewAllocator(const CXXNewExpr *NE, ExplodedNode *Pred); + + void ProcessAutomaticObjDtor(const CFGAutomaticObjDtor D, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + void ProcessDeleteDtor(const CFGDeleteDtor D, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + void ProcessBaseDtor(const CFGBaseDtor D, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + void ProcessMemberDtor(const CFGMemberDtor D, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + void ProcessTemporaryDtor(const CFGTemporaryDtor D, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + + /// Called by CoreEngine when processing the entrance of a CFGBlock. + void processCFGBlockEntrance(const BlockEdge &L, + NodeBuilderWithSinks &nodeBuilder, + ExplodedNode *Pred) override; + + /// ProcessBranch - Called by CoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a branch condition. + void processBranch(const Stmt *Condition, const Stmt *Term, + NodeBuilderContext& BuilderCtx, + ExplodedNode *Pred, + ExplodedNodeSet &Dst, + const CFGBlock *DstT, + const CFGBlock *DstF) override; + + /// Called by CoreEngine. + /// Used to generate successor nodes for temporary destructors depending + /// on whether the corresponding constructor was visited. + void processCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE, + NodeBuilderContext &BldCtx, + ExplodedNode *Pred, ExplodedNodeSet &Dst, + const CFGBlock *DstT, + const CFGBlock *DstF) override; + + /// Called by CoreEngine. Used to processing branching behavior + /// at static initalizers. + void processStaticInitializer(const DeclStmt *DS, + NodeBuilderContext& BuilderCtx, + ExplodedNode *Pred, + ExplodedNodeSet &Dst, + const CFGBlock *DstT, + const CFGBlock *DstF) override; + + /// processIndirectGoto - Called by CoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a computed goto jump. + void processIndirectGoto(IndirectGotoNodeBuilder& builder) override; + + /// ProcessSwitch - Called by CoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a switch statement. + void processSwitch(SwitchNodeBuilder& builder) override; + + /// Called by CoreEngine. Used to generate end-of-path + /// nodes when the control reaches the end of a function. + void processEndOfFunction(NodeBuilderContext& BC, + ExplodedNode *Pred) override; + + /// Remove dead bindings/symbols before exiting a function. + void removeDeadOnEndOfFunction(NodeBuilderContext& BC, + ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// Generate the entry node of the callee. + void processCallEnter(CallEnter CE, ExplodedNode *Pred) override; + + /// Generate the sequence of nodes that simulate the call exit and the post + /// visit for CallExpr. + void processCallExit(ExplodedNode *Pred) override; + + /// Called by CoreEngine when the analysis worklist has terminated. + void processEndWorklist(bool hasWorkRemaining) override; + + /// evalAssume - Callback function invoked by the ConstraintManager when + /// making assumptions about state values. + ProgramStateRef processAssume(ProgramStateRef state, SVal cond, + bool assumption) override; + + /// wantsRegionChangeUpdate - Called by ProgramStateManager to determine if a + /// region change should trigger a processRegionChanges update. + bool wantsRegionChangeUpdate(ProgramStateRef state) override; + + /// processRegionChanges - Called by ProgramStateManager whenever a change is made + /// to the store. Used to update checkers that track region values. + ProgramStateRef + processRegionChanges(ProgramStateRef state, + const InvalidatedSymbols *invalidated, + ArrayRef<const MemRegion *> ExplicitRegions, + ArrayRef<const MemRegion *> Regions, + const CallEvent *Call) override; + + /// printState - Called by ProgramStateManager to print checker-specific data. + void printState(raw_ostream &Out, ProgramStateRef State, + const char *NL, const char *Sep) override; + + ProgramStateManager& getStateManager() override { return StateMgr; } + + StoreManager& getStoreManager() { return StateMgr.getStoreManager(); } + + ConstraintManager& getConstraintManager() { + return StateMgr.getConstraintManager(); + } + + // FIXME: Remove when we migrate over to just using SValBuilder. + BasicValueFactory& getBasicVals() { + return StateMgr.getBasicVals(); + } + + // FIXME: Remove when we migrate over to just using ValueManager. + SymbolManager& getSymbolManager() { return SymMgr; } + const SymbolManager& getSymbolManager() const { return SymMgr; } + + // Functions for external checking of whether we have unfinished work + bool wasBlocksExhausted() const { return Engine.wasBlocksExhausted(); } + bool hasEmptyWorkList() const { return !Engine.getWorkList()->hasWork(); } + bool hasWorkRemaining() const { return Engine.hasWorkRemaining(); } + + const CoreEngine &getCoreEngine() const { return Engine; } + +public: + /// Visit - Transfer function logic for all statements. Dispatches to + /// other functions that handle specific kinds of statements. + void Visit(const Stmt *S, ExplodedNode *Pred, ExplodedNodeSet &Dst); + + /// VisitArraySubscriptExpr - Transfer function for array accesses. + void VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *Ex, + ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// VisitGCCAsmStmt - Transfer function logic for inline asm. + void VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// VisitMSAsmStmt - Transfer function logic for MS inline asm. + void VisitMSAsmStmt(const MSAsmStmt *A, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// VisitBlockExpr - Transfer function logic for BlockExprs. + void VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// VisitLambdaExpr - Transfer function logic for LambdaExprs. + void VisitLambdaExpr(const LambdaExpr *LE, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// VisitBinaryOperator - Transfer function logic for binary operators. + void VisitBinaryOperator(const BinaryOperator* B, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + + /// VisitCall - Transfer function for function calls. + void VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// VisitCast - Transfer function logic for all casts (implicit and explicit). + void VisitCast(const CastExpr *CastE, const Expr *Ex, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// VisitCompoundLiteralExpr - Transfer function logic for compound literals. + void VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + + /// Transfer function logic for DeclRefExprs and BlockDeclRefExprs. + void VisitCommonDeclRefExpr(const Expr *DR, const NamedDecl *D, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + + /// VisitDeclStmt - Transfer function logic for DeclStmts. + void VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// VisitGuardedExpr - Transfer function logic for ?, __builtin_choose + void VisitGuardedExpr(const Expr *Ex, const Expr *L, const Expr *R, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + + void VisitInitListExpr(const InitListExpr *E, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// VisitLogicalExpr - Transfer function logic for '&&', '||' + void VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// VisitMemberExpr - Transfer function for member expressions. + void VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// Transfer function logic for ObjCAtSynchronizedStmts. + void VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + + /// Transfer function logic for computing the lvalue of an Objective-C ivar. + void VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr *DR, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// VisitObjCForCollectionStmt - Transfer function logic for + /// ObjCForCollectionStmt. + void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + + void VisitObjCMessage(const ObjCMessageExpr *ME, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// VisitReturnStmt - Transfer function logic for return statements. + void VisitReturnStmt(const ReturnStmt *R, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// VisitOffsetOfExpr - Transfer function for offsetof. + void VisitOffsetOfExpr(const OffsetOfExpr *Ex, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// VisitUnaryExprOrTypeTraitExpr - Transfer function for sizeof. + void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + + /// VisitUnaryOperator - Transfer function logic for unary operators. + void VisitUnaryOperator(const UnaryOperator* B, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// Handle ++ and -- (both pre- and post-increment). + void VisitIncrementDecrementOperator(const UnaryOperator* U, + ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE, + ExplodedNodeSet &PreVisit, + ExplodedNodeSet &Dst); + + void VisitCXXCatchStmt(const CXXCatchStmt *CS, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + void VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred, + ExplodedNodeSet & Dst); + + void VisitCXXConstructExpr(const CXXConstructExpr *E, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + void VisitCXXDestructor(QualType ObjectType, const MemRegion *Dest, + const Stmt *S, bool IsBaseDtor, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + + void VisitCXXNewAllocatorCall(const CXXNewExpr *CNE, + ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + void VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + void VisitCXXDeleteExpr(const CXXDeleteExpr *CDE, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// Create a C++ temporary object for an rvalue. + void CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME, + ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// evalEagerlyAssumeBinOpBifurcation - Given the nodes in 'Src', eagerly assume symbolic + /// expressions of the form 'x != 0' and generate new nodes (stored in Dst) + /// with those assumptions. + void evalEagerlyAssumeBinOpBifurcation(ExplodedNodeSet &Dst, ExplodedNodeSet &Src, + const Expr *Ex); + + std::pair<const ProgramPointTag *, const ProgramPointTag*> + geteagerlyAssumeBinOpBifurcationTags(); + + SVal evalMinus(SVal X) { + return X.isValid() ? svalBuilder.evalMinus(X.castAs<NonLoc>()) : X; + } + + SVal evalComplement(SVal X) { + return X.isValid() ? svalBuilder.evalComplement(X.castAs<NonLoc>()) : X; + } + +public: + + SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, + NonLoc L, NonLoc R, QualType T) { + return svalBuilder.evalBinOpNN(state, op, L, R, T); + } + + SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, + NonLoc L, SVal R, QualType T) { + return R.isValid() ? svalBuilder.evalBinOpNN(state, op, L, + R.castAs<NonLoc>(), T) : R; + } + + SVal evalBinOp(ProgramStateRef ST, BinaryOperator::Opcode Op, + SVal LHS, SVal RHS, QualType T) { + return svalBuilder.evalBinOp(ST, Op, LHS, RHS, T); + } + +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, const Stmt *StoreE, ExplodedNode *Pred, + SVal location, SVal Val, bool atDeclInit = false, + const ProgramPoint *PP = nullptr); + + /// Call PointerEscape callback when a value escapes as a result of bind. + ProgramStateRef processPointerEscapedOnBind(ProgramStateRef State, + SVal Loc, SVal Val) override; + /// Call PointerEscape callback when a value escapes as a result of + /// region invalidation. + /// \param[in] ITraits Specifies invalidation traits for regions/symbols. + ProgramStateRef notifyCheckersOfPointerEscape( + ProgramStateRef State, + const InvalidatedSymbols *Invalidated, + ArrayRef<const MemRegion *> ExplicitRegions, + ArrayRef<const MemRegion *> Regions, + const CallEvent *Call, + RegionAndSymbolInvalidationTraits &ITraits) override; + +public: + // FIXME: 'tag' should be removed, and a LocationContext should be used + // instead. + // FIXME: Comment on the meaning of the arguments, when 'St' may not + // be the same as Pred->state, and when 'location' may not be the + // same as state->getLValue(Ex). + /// Simulate a read of the result of Ex. + void evalLoad(ExplodedNodeSet &Dst, + const Expr *NodeEx, /* Eventually will be a CFGStmt */ + const Expr *BoundExpr, + ExplodedNode *Pred, + ProgramStateRef St, + SVal location, + const ProgramPointTag *tag = nullptr, + QualType LoadTy = QualType()); + + // FIXME: 'tag' should be removed, and a LocationContext should be used + // instead. + void evalStore(ExplodedNodeSet &Dst, const Expr *AssignE, const Expr *StoreE, + ExplodedNode *Pred, ProgramStateRef St, SVal TargetLV, SVal Val, + const ProgramPointTag *tag = nullptr); + + /// \brief Create a new state in which the call return value is binded to the + /// call origin expression. + ProgramStateRef bindReturnValue(const CallEvent &Call, + const LocationContext *LCtx, + ProgramStateRef State); + + /// Evaluate a call, running pre- and post-call checks and allowing checkers + /// to be responsible for handling the evaluation of the call itself. + void evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred, + const CallEvent &Call); + + /// \brief Default implementation of call evaluation. + void defaultEvalCall(NodeBuilder &B, ExplodedNode *Pred, + const CallEvent &Call); +private: + void evalLoadCommon(ExplodedNodeSet &Dst, + const Expr *NodeEx, /* Eventually will be a CFGStmt */ + const Expr *BoundEx, + ExplodedNode *Pred, + ProgramStateRef St, + SVal location, + const ProgramPointTag *tag, + QualType LoadTy); + + // FIXME: 'tag' should be removed, and a LocationContext should be used + // instead. + void evalLocation(ExplodedNodeSet &Dst, + const Stmt *NodeEx, /* This will eventually be a CFGStmt */ + const Stmt *BoundEx, + ExplodedNode *Pred, + ProgramStateRef St, SVal location, + const ProgramPointTag *tag, bool isLoad); + + /// Count the stack depth and determine if the call is recursive. + void examineStackFrames(const Decl *D, const LocationContext *LCtx, + bool &IsRecursive, unsigned &StackDepth); + + /// Checks our policies and decides weither the given call should be inlined. + bool shouldInlineCall(const CallEvent &Call, const Decl *D, + const ExplodedNode *Pred); + + bool inlineCall(const CallEvent &Call, const Decl *D, NodeBuilder &Bldr, + ExplodedNode *Pred, ProgramStateRef State); + + /// \brief Conservatively evaluate call by invalidating regions and binding + /// a conjured return value. + void conservativeEvalCall(const CallEvent &Call, NodeBuilder &Bldr, + ExplodedNode *Pred, ProgramStateRef State); + + /// \brief Either inline or process the call conservatively (or both), based + /// on DynamicDispatchBifurcation data. + void BifurcateCall(const MemRegion *BifurReg, + const CallEvent &Call, const Decl *D, NodeBuilder &Bldr, + ExplodedNode *Pred); + + bool replayWithoutInlining(ExplodedNode *P, const LocationContext *CalleeLC); + + /// Models a trivial copy or move constructor or trivial assignment operator + /// call with a simple bind. + void performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred, + const CallEvent &Call); + + /// If the value of the given expression is a NonLoc, copy it into a new + /// temporary object region, and replace the value of the expression with + /// that. + /// + /// If \p ResultE is provided, the new region will be bound to this expression + /// instead of \p E. + ProgramStateRef createTemporaryRegionIfNeeded(ProgramStateRef State, + const LocationContext *LC, + const Expr *E, + const Expr *ResultE = nullptr); + + /// For a DeclStmt or CXXInitCtorInitializer, walk backward in the current CFG + /// block to find the constructor expression that directly constructed into + /// the storage for this statement. Returns null if the constructor for this + /// statement created a temporary object region rather than directly + /// constructing into an existing region. + const CXXConstructExpr *findDirectConstructorForCurrentCFGElement(); + + /// For a CXXConstructExpr, walk forward in the current CFG block to find the + /// CFGElement for the DeclStmt or CXXInitCtorInitializer for which is + /// directly constructed by this constructor. Returns None if the current + /// constructor expression did not directly construct into an existing + /// region. + Optional<CFGElement> findElementDirectlyInitializedByCurrentConstructor(); + + /// For a given constructor, look forward in the current CFG block to + /// determine the region into which an object will be constructed by \p CE. + /// Returns either a field or local variable region if the object will be + /// directly constructed in an existing region or a temporary object region + /// if not. + const MemRegion *getRegionForConstructedObject(const CXXConstructExpr *CE, + ExplodedNode *Pred); +}; + +/// Traits for storing the call processing policy inside GDM. +/// The GDM stores the corresponding CallExpr pointer. +// FIXME: This does not use the nice trait macros because it must be accessible +// from multiple translation units. +struct ReplayWithoutInlining{}; +template <> +struct ProgramStateTrait<ReplayWithoutInlining> : + public ProgramStatePartialTrait<const void*> { + static void *GDMIndex() { static int index = 0; return &index; } +}; + +} // end ento namespace + +} // end clang namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h new file mode 100644 index 0000000..ce81c98 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h @@ -0,0 +1,140 @@ +//== FunctionSummary.h - Stores summaries of functions. ------------*- 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 summary of a function gathered/used by static analysis. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_FUNCTIONSUMMARY_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_FUNCTIONSUMMARY_H + +#include "clang/AST/Decl.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallBitVector.h" +#include <deque> + +namespace clang { + +namespace ento { +typedef std::deque<Decl*> SetOfDecls; +typedef llvm::DenseSet<const Decl*> SetOfConstDecls; + +class FunctionSummariesTy { + class FunctionSummary { + public: + /// Marks the IDs of the basic blocks visited during the analyzes. + llvm::SmallBitVector VisitedBasicBlocks; + + /// Total number of blocks in the function. + unsigned TotalBasicBlocks : 30; + + /// True if this function has been checked against the rules for which + /// functions may be inlined. + unsigned InlineChecked : 1; + + /// True if this function may be inlined. + unsigned MayInline : 1; + + /// The number of times the function has been inlined. + unsigned TimesInlined : 32; + + FunctionSummary() : + TotalBasicBlocks(0), + InlineChecked(0), + TimesInlined(0) {} + }; + + typedef llvm::DenseMap<const Decl *, FunctionSummary> MapTy; + MapTy Map; + +public: + MapTy::iterator findOrInsertSummary(const Decl *D) { + MapTy::iterator I = Map.find(D); + if (I != Map.end()) + return I; + + typedef std::pair<const Decl *, FunctionSummary> KVPair; + I = Map.insert(KVPair(D, FunctionSummary())).first; + assert(I != Map.end()); + return I; + } + + void markMayInline(const Decl *D) { + MapTy::iterator I = findOrInsertSummary(D); + I->second.InlineChecked = 1; + I->second.MayInline = 1; + } + + void markShouldNotInline(const Decl *D) { + MapTy::iterator I = findOrInsertSummary(D); + I->second.InlineChecked = 1; + I->second.MayInline = 0; + } + + void markReachedMaxBlockCount(const Decl *D) { + markShouldNotInline(D); + } + + Optional<bool> mayInline(const Decl *D) { + MapTy::const_iterator I = Map.find(D); + if (I != Map.end() && I->second.InlineChecked) + return I->second.MayInline; + return None; + } + + void markVisitedBasicBlock(unsigned ID, const Decl* D, unsigned TotalIDs) { + MapTy::iterator I = findOrInsertSummary(D); + llvm::SmallBitVector &Blocks = I->second.VisitedBasicBlocks; + assert(ID < TotalIDs); + if (TotalIDs > Blocks.size()) { + Blocks.resize(TotalIDs); + I->second.TotalBasicBlocks = TotalIDs; + } + Blocks.set(ID); + } + + unsigned getNumVisitedBasicBlocks(const Decl* D) { + MapTy::const_iterator I = Map.find(D); + if (I != Map.end()) + return I->second.VisitedBasicBlocks.count(); + return 0; + } + + unsigned getNumTimesInlined(const Decl* D) { + MapTy::const_iterator I = Map.find(D); + if (I != Map.end()) + return I->second.TimesInlined; + return 0; + } + + void bumpNumTimesInlined(const Decl* D) { + MapTy::iterator I = findOrInsertSummary(D); + I->second.TimesInlined++; + } + + /// Get the percentage of the reachable blocks. + unsigned getPercentBlocksReachable(const Decl *D) { + MapTy::const_iterator I = Map.find(D); + if (I != Map.end()) + return ((I->second.VisitedBasicBlocks.count() * 100) / + I->second.TotalBasicBlocks); + return 0; + } + + unsigned getTotalNumBasicBlocks(); + unsigned getTotalNumVisitedBasicBlocks(); + +}; + +}} // end clang ento namespaces + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h new file mode 100644 index 0000000..3168733 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h @@ -0,0 +1,36 @@ +//===--- LoopWidening.h - Widen loops ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// This header contains the declarations of functions which are used to widen +/// loops which do not otherwise exit. The widening is done by invalidating +/// anything which might be modified by the body of the loop. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_LOOPWIDENING_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_LOOPWIDENING_H + +#include "clang/Analysis/CFG.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" + +namespace clang { +namespace ento { + +/// \brief Get the states that result from widening the loop. +/// +/// Widen the loop by invalidating anything that might be modified +/// by the loop body in any iteration. +ProgramStateRef getWidenedLoopState(ProgramStateRef PrevState, + const LocationContext *LCtx, + unsigned BlockCount, const Stmt *LoopStmt); + +} // end namespace ento +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h new file mode 100644 index 0000000..bb835c4 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h @@ -0,0 +1,1370 @@ +//== MemRegion.h - Abstract memory regions for static analysis --*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines MemRegion and its subclasses. MemRegion defines a +// partially-typed abstraction of memory useful for path-sensitive dataflow +// analyses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_MEMREGION_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_MEMREGION_H + +#include "clang/AST/ASTContext.h" +#include "clang/AST/CharUnits.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/Basic/LLVM.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/ErrorHandling.h" +#include <string> + +namespace clang { + +class LocationContext; +class StackFrameContext; + +namespace ento { + +class CodeTextRegion; +class MemRegionManager; +class MemSpaceRegion; +class SValBuilder; +class SymbolicRegion; +class VarRegion; + +/// Represent a region's offset within the top level base region. +class RegionOffset { + /// The base region. + const MemRegion *R; + + /// The bit offset within the base region. Can be negative. + int64_t Offset; + +public: + // We're using a const instead of an enumeration due to the size required; + // Visual Studio will only create enumerations of size int, not long long. + static const int64_t Symbolic = INT64_MAX; + + RegionOffset() : R(nullptr) {} + RegionOffset(const MemRegion *r, int64_t off) : R(r), Offset(off) {} + + const MemRegion *getRegion() const { return R; } + + bool hasSymbolicOffset() const { return Offset == Symbolic; } + + int64_t getOffset() const { + assert(!hasSymbolicOffset()); + return Offset; + } + + bool isValid() const { return R; } +}; + +//===----------------------------------------------------------------------===// +// Base region classes. +//===----------------------------------------------------------------------===// + +/// MemRegion - The root abstract class for all memory regions. +class MemRegion : public llvm::FoldingSetNode { + friend class MemRegionManager; +public: + enum Kind { + // Memory spaces. + GenericMemSpaceRegionKind, + StackLocalsSpaceRegionKind, + StackArgumentsSpaceRegionKind, + HeapSpaceRegionKind, + UnknownSpaceRegionKind, + StaticGlobalSpaceRegionKind, + GlobalInternalSpaceRegionKind, + GlobalSystemSpaceRegionKind, + GlobalImmutableSpaceRegionKind, + BEG_NON_STATIC_GLOBAL_MEMSPACES = GlobalInternalSpaceRegionKind, + END_NON_STATIC_GLOBAL_MEMSPACES = GlobalImmutableSpaceRegionKind, + BEG_GLOBAL_MEMSPACES = StaticGlobalSpaceRegionKind, + END_GLOBAL_MEMSPACES = GlobalImmutableSpaceRegionKind, + BEG_MEMSPACES = GenericMemSpaceRegionKind, + END_MEMSPACES = GlobalImmutableSpaceRegionKind, + // Untyped regions. + SymbolicRegionKind, + AllocaRegionKind, + // Typed regions. + BEG_TYPED_REGIONS, + FunctionTextRegionKind = BEG_TYPED_REGIONS, + BlockTextRegionKind, + BlockDataRegionKind, + BEG_TYPED_VALUE_REGIONS, + CompoundLiteralRegionKind = BEG_TYPED_VALUE_REGIONS, + CXXThisRegionKind, + StringRegionKind, + ObjCStringRegionKind, + ElementRegionKind, + // Decl Regions. + BEG_DECL_REGIONS, + VarRegionKind = BEG_DECL_REGIONS, + FieldRegionKind, + ObjCIvarRegionKind, + END_DECL_REGIONS = ObjCIvarRegionKind, + CXXTempObjectRegionKind, + CXXBaseObjectRegionKind, + END_TYPED_VALUE_REGIONS = CXXBaseObjectRegionKind, + END_TYPED_REGIONS = CXXBaseObjectRegionKind + }; + +private: + const Kind kind; + +protected: + MemRegion(Kind k) : kind(k) {} + virtual ~MemRegion(); + +public: + ASTContext &getContext() const; + + virtual void Profile(llvm::FoldingSetNodeID& ID) const = 0; + + virtual MemRegionManager* getMemRegionManager() const = 0; + + const MemSpaceRegion *getMemorySpace() const; + + const MemRegion *getBaseRegion() const; + + /// Check if the region is a subregion of the given region. + virtual bool isSubRegionOf(const MemRegion *R) const; + + const MemRegion *StripCasts(bool StripBaseCasts = true) const; + + /// \brief If this is a symbolic region, returns the region. Otherwise, + /// goes up the base chain looking for the first symbolic base region. + const SymbolicRegion *getSymbolicBase() const; + + bool hasGlobalsOrParametersStorage() const; + + bool hasStackStorage() const; + + bool hasStackNonParametersStorage() const; + + bool hasStackParametersStorage() const; + + /// Compute the offset within the top level memory object. + RegionOffset getAsOffset() const; + + /// \brief Get a string representation of a region for debug use. + std::string getString() const; + + virtual void dumpToStream(raw_ostream &os) const; + + void dump() const; + + /// \brief Returns true if this region can be printed in a user-friendly way. + virtual bool canPrintPretty() const; + + /// \brief Print the region for use in diagnostics. + virtual void printPretty(raw_ostream &os) const; + + /// \brief Returns true if this region's textual representation can be used + /// as part of a larger expression. + virtual bool canPrintPrettyAsExpr() const; + + /// \brief Print the region as expression. + /// + /// When this region represents a subexpression, the method is for printing + /// an expression containing it. + virtual void printPrettyAsExpr(raw_ostream &os) const; + + Kind getKind() const { return kind; } + + template<typename RegionTy> const RegionTy* getAs() const; + + virtual bool isBoundable() const { return false; } +}; + +/// MemSpaceRegion - A memory region that represents a "memory space"; +/// for example, the set of global variables, the stack frame, etc. +class MemSpaceRegion : public MemRegion { +protected: + friend class MemRegionManager; + + MemRegionManager *Mgr; + + MemSpaceRegion(MemRegionManager *mgr, Kind k = GenericMemSpaceRegionKind) + : MemRegion(k), Mgr(mgr) { + assert(classof(this)); + } + + MemRegionManager* getMemRegionManager() const override { return Mgr; } + +public: + bool isBoundable() const override { return false; } + + void Profile(llvm::FoldingSetNodeID &ID) const override; + + static bool classof(const MemRegion *R) { + Kind k = R->getKind(); + return k >= BEG_MEMSPACES && k <= END_MEMSPACES; + } +}; + +class GlobalsSpaceRegion : public MemSpaceRegion { + virtual void anchor(); +protected: + GlobalsSpaceRegion(MemRegionManager *mgr, Kind k) + : MemSpaceRegion(mgr, k) {} +public: + static bool classof(const MemRegion *R) { + Kind k = R->getKind(); + return k >= BEG_GLOBAL_MEMSPACES && k <= END_GLOBAL_MEMSPACES; + } +}; + +/// \brief The region of the static variables within the current CodeTextRegion +/// scope. +/// +/// Currently, only the static locals are placed there, so we know that these +/// variables do not get invalidated by calls to other functions. +class StaticGlobalSpaceRegion : public GlobalsSpaceRegion { + friend class MemRegionManager; + + const CodeTextRegion *CR; + + StaticGlobalSpaceRegion(MemRegionManager *mgr, const CodeTextRegion *cr) + : GlobalsSpaceRegion(mgr, StaticGlobalSpaceRegionKind), CR(cr) {} + +public: + void Profile(llvm::FoldingSetNodeID &ID) const override; + + void dumpToStream(raw_ostream &os) const override; + + const CodeTextRegion *getCodeRegion() const { return CR; } + + static bool classof(const MemRegion *R) { + return R->getKind() == StaticGlobalSpaceRegionKind; + } +}; + +/// \brief The region for all the non-static global variables. +/// +/// This class is further split into subclasses for efficient implementation of +/// invalidating a set of related global values as is done in +/// RegionStoreManager::invalidateRegions (instead of finding all the dependent +/// globals, we invalidate the whole parent region). +class NonStaticGlobalSpaceRegion : public GlobalsSpaceRegion { + friend class MemRegionManager; + +protected: + NonStaticGlobalSpaceRegion(MemRegionManager *mgr, Kind k) + : GlobalsSpaceRegion(mgr, k) {} + +public: + + static bool classof(const MemRegion *R) { + Kind k = R->getKind(); + return k >= BEG_NON_STATIC_GLOBAL_MEMSPACES && + k <= END_NON_STATIC_GLOBAL_MEMSPACES; + } +}; + +/// \brief The region containing globals which are defined in system/external +/// headers and are considered modifiable by system calls (ex: errno). +class GlobalSystemSpaceRegion : public NonStaticGlobalSpaceRegion { + friend class MemRegionManager; + + GlobalSystemSpaceRegion(MemRegionManager *mgr) + : NonStaticGlobalSpaceRegion(mgr, GlobalSystemSpaceRegionKind) {} + +public: + + void dumpToStream(raw_ostream &os) const override; + + static bool classof(const MemRegion *R) { + return R->getKind() == GlobalSystemSpaceRegionKind; + } +}; + +/// \brief The region containing globals which are considered not to be modified +/// or point to data which could be modified as a result of a function call +/// (system or internal). Ex: Const global scalars would be modeled as part of +/// this region. This region also includes most system globals since they have +/// low chance of being modified. +class GlobalImmutableSpaceRegion : public NonStaticGlobalSpaceRegion { + friend class MemRegionManager; + + GlobalImmutableSpaceRegion(MemRegionManager *mgr) + : NonStaticGlobalSpaceRegion(mgr, GlobalImmutableSpaceRegionKind) {} + +public: + + void dumpToStream(raw_ostream &os) const override; + + static bool classof(const MemRegion *R) { + return R->getKind() == GlobalImmutableSpaceRegionKind; + } +}; + +/// \brief The region containing globals which can be modified by calls to +/// "internally" defined functions - (for now just) functions other then system +/// calls. +class GlobalInternalSpaceRegion : public NonStaticGlobalSpaceRegion { + friend class MemRegionManager; + + GlobalInternalSpaceRegion(MemRegionManager *mgr) + : NonStaticGlobalSpaceRegion(mgr, GlobalInternalSpaceRegionKind) {} + +public: + + void dumpToStream(raw_ostream &os) const override; + + static bool classof(const MemRegion *R) { + return R->getKind() == GlobalInternalSpaceRegionKind; + } +}; + +class HeapSpaceRegion : public MemSpaceRegion { + virtual void anchor(); + friend class MemRegionManager; + + HeapSpaceRegion(MemRegionManager *mgr) + : MemSpaceRegion(mgr, HeapSpaceRegionKind) {} +public: + + void dumpToStream(raw_ostream &os) const override; + + static bool classof(const MemRegion *R) { + return R->getKind() == HeapSpaceRegionKind; + } +}; + +class UnknownSpaceRegion : public MemSpaceRegion { + virtual void anchor(); + friend class MemRegionManager; + UnknownSpaceRegion(MemRegionManager *mgr) + : MemSpaceRegion(mgr, UnknownSpaceRegionKind) {} +public: + + void dumpToStream(raw_ostream &os) const override; + + static bool classof(const MemRegion *R) { + return R->getKind() == UnknownSpaceRegionKind; + } +}; + +class StackSpaceRegion : public MemSpaceRegion { +private: + const StackFrameContext *SFC; + +protected: + StackSpaceRegion(MemRegionManager *mgr, Kind k, const StackFrameContext *sfc) + : MemSpaceRegion(mgr, k), SFC(sfc) { + assert(classof(this)); + } + +public: + const StackFrameContext *getStackFrame() const { return SFC; } + + void Profile(llvm::FoldingSetNodeID &ID) const override; + + static bool classof(const MemRegion *R) { + Kind k = R->getKind(); + return k >= StackLocalsSpaceRegionKind && + k <= StackArgumentsSpaceRegionKind; + } +}; + +class StackLocalsSpaceRegion : public StackSpaceRegion { + virtual void anchor(); + friend class MemRegionManager; + StackLocalsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc) + : StackSpaceRegion(mgr, StackLocalsSpaceRegionKind, sfc) {} +public: + + void dumpToStream(raw_ostream &os) const override; + + static bool classof(const MemRegion *R) { + return R->getKind() == StackLocalsSpaceRegionKind; + } +}; + +class StackArgumentsSpaceRegion : public StackSpaceRegion { +private: + virtual void anchor(); + friend class MemRegionManager; + StackArgumentsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc) + : StackSpaceRegion(mgr, StackArgumentsSpaceRegionKind, sfc) {} +public: + + void dumpToStream(raw_ostream &os) const override; + + static bool classof(const MemRegion *R) { + return R->getKind() == StackArgumentsSpaceRegionKind; + } +}; + + +/// SubRegion - A region that subsets another larger region. Most regions +/// are subclasses of SubRegion. +class SubRegion : public MemRegion { +private: + virtual void anchor(); +protected: + const MemRegion* superRegion; + SubRegion(const MemRegion* sReg, Kind k) : MemRegion(k), superRegion(sReg) {} +public: + const MemRegion* getSuperRegion() const { + return superRegion; + } + + /// getExtent - Returns the size of the region in bytes. + virtual DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const { + return UnknownVal(); + } + + MemRegionManager* getMemRegionManager() const override; + + bool isSubRegionOf(const MemRegion* R) const override; + + static bool classof(const MemRegion* R) { + return R->getKind() > END_MEMSPACES; + } +}; + +//===----------------------------------------------------------------------===// +// MemRegion subclasses. +//===----------------------------------------------------------------------===// + +/// AllocaRegion - A region that represents an untyped blob of bytes created +/// by a call to 'alloca'. +class AllocaRegion : public SubRegion { + friend class MemRegionManager; +protected: + unsigned Cnt; // Block counter. Used to distinguish different pieces of + // memory allocated by alloca at the same call site. + const Expr *Ex; + + AllocaRegion(const Expr *ex, unsigned cnt, const MemRegion *superRegion) + : SubRegion(superRegion, AllocaRegionKind), Cnt(cnt), Ex(ex) {} + +public: + + const Expr *getExpr() const { return Ex; } + + bool isBoundable() const override { return true; } + + DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override; + + void Profile(llvm::FoldingSetNodeID& ID) const override; + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr *Ex, + unsigned Cnt, const MemRegion *superRegion); + + void dumpToStream(raw_ostream &os) const override; + + static bool classof(const MemRegion* R) { + return R->getKind() == AllocaRegionKind; + } +}; + +/// TypedRegion - An abstract class representing regions that are typed. +class TypedRegion : public SubRegion { +public: + void anchor() override; +protected: + TypedRegion(const MemRegion* sReg, Kind k) : SubRegion(sReg, k) {} + +public: + virtual QualType getLocationType() const = 0; + + QualType getDesugaredLocationType(ASTContext &Context) const { + return getLocationType().getDesugaredType(Context); + } + + bool isBoundable() const override { return true; } + + static bool classof(const MemRegion* R) { + unsigned k = R->getKind(); + return k >= BEG_TYPED_REGIONS && k <= END_TYPED_REGIONS; + } +}; + +/// TypedValueRegion - An abstract class representing regions having a typed value. +class TypedValueRegion : public TypedRegion { +public: + void anchor() override; +protected: + TypedValueRegion(const MemRegion* sReg, Kind k) : TypedRegion(sReg, k) {} + +public: + virtual QualType getValueType() const = 0; + + QualType getLocationType() const override { + // FIXME: We can possibly optimize this later to cache this value. + QualType T = getValueType(); + ASTContext &ctx = getContext(); + if (T->getAs<ObjCObjectType>()) + return ctx.getObjCObjectPointerType(T); + return ctx.getPointerType(getValueType()); + } + + QualType getDesugaredValueType(ASTContext &Context) const { + QualType T = getValueType(); + return T.getTypePtrOrNull() ? T.getDesugaredType(Context) : T; + } + + DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override; + + static bool classof(const MemRegion* R) { + unsigned k = R->getKind(); + return k >= BEG_TYPED_VALUE_REGIONS && k <= END_TYPED_VALUE_REGIONS; + } +}; + + +class CodeTextRegion : public TypedRegion { +public: + void anchor() override; +protected: + CodeTextRegion(const MemRegion *sreg, Kind k) : TypedRegion(sreg, k) {} +public: + bool isBoundable() const override { return false; } + + static bool classof(const MemRegion* R) { + Kind k = R->getKind(); + return k >= FunctionTextRegionKind && k <= BlockTextRegionKind; + } +}; + +/// FunctionTextRegion - A region that represents code texts of function. +class FunctionTextRegion : public CodeTextRegion { + const NamedDecl *FD; +public: + FunctionTextRegion(const NamedDecl *fd, const MemRegion* sreg) + : CodeTextRegion(sreg, FunctionTextRegionKind), FD(fd) { + assert(isa<ObjCMethodDecl>(fd) || isa<FunctionDecl>(fd)); + } + + QualType getLocationType() const override { + const ASTContext &Ctx = getContext(); + if (const FunctionDecl *D = dyn_cast<FunctionDecl>(FD)) { + return Ctx.getPointerType(D->getType()); + } + + assert(isa<ObjCMethodDecl>(FD)); + assert(false && "Getting the type of ObjCMethod is not supported yet"); + + // TODO: We might want to return a different type here (ex: id (*ty)(...)) + // depending on how it is used. + return QualType(); + } + + const NamedDecl *getDecl() const { + return FD; + } + + void dumpToStream(raw_ostream &os) const override; + + void Profile(llvm::FoldingSetNodeID& ID) const override; + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const NamedDecl *FD, + const MemRegion*); + + static bool classof(const MemRegion* R) { + return R->getKind() == FunctionTextRegionKind; + } +}; + + +/// BlockTextRegion - A region that represents code texts of blocks (closures). +/// Blocks are represented with two kinds of regions. BlockTextRegions +/// represent the "code", while BlockDataRegions represent instances of blocks, +/// which correspond to "code+data". The distinction is important, because +/// like a closure a block captures the values of externally referenced +/// variables. +class BlockTextRegion : public CodeTextRegion { + friend class MemRegionManager; + + const BlockDecl *BD; + AnalysisDeclContext *AC; + CanQualType locTy; + + BlockTextRegion(const BlockDecl *bd, CanQualType lTy, + AnalysisDeclContext *ac, const MemRegion* sreg) + : CodeTextRegion(sreg, BlockTextRegionKind), BD(bd), AC(ac), locTy(lTy) {} + +public: + QualType getLocationType() const override { + return locTy; + } + + const BlockDecl *getDecl() const { + return BD; + } + + AnalysisDeclContext *getAnalysisDeclContext() const { return AC; } + + void dumpToStream(raw_ostream &os) const override; + + void Profile(llvm::FoldingSetNodeID& ID) const override; + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const BlockDecl *BD, + CanQualType, const AnalysisDeclContext*, + const MemRegion*); + + static bool classof(const MemRegion* R) { + return R->getKind() == BlockTextRegionKind; + } +}; + +/// BlockDataRegion - A region that represents a block instance. +/// Blocks are represented with two kinds of regions. BlockTextRegions +/// represent the "code", while BlockDataRegions represent instances of blocks, +/// which correspond to "code+data". The distinction is important, because +/// like a closure a block captures the values of externally referenced +/// variables. +class BlockDataRegion : public TypedRegion { + friend class MemRegionManager; + const BlockTextRegion *BC; + const LocationContext *LC; // Can be null */ + unsigned BlockCount; + void *ReferencedVars; + void *OriginalVars; + + BlockDataRegion(const BlockTextRegion *bc, const LocationContext *lc, + unsigned count, const MemRegion *sreg) + : TypedRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc), + BlockCount(count), + ReferencedVars(nullptr), OriginalVars(nullptr) {} + +public: + const BlockTextRegion *getCodeRegion() const { return BC; } + + const BlockDecl *getDecl() const { return BC->getDecl(); } + + QualType getLocationType() const override { return BC->getLocationType(); } + + class referenced_vars_iterator { + const MemRegion * const *R; + const MemRegion * const *OriginalR; + public: + explicit referenced_vars_iterator(const MemRegion * const *r, + const MemRegion * const *originalR) + : R(r), OriginalR(originalR) {} + + const VarRegion *getCapturedRegion() const { + return cast<VarRegion>(*R); + } + const VarRegion *getOriginalRegion() const { + return cast<VarRegion>(*OriginalR); + } + + bool operator==(const referenced_vars_iterator &I) const { + assert((R == nullptr) == (I.R == nullptr)); + return I.R == R; + } + bool operator!=(const referenced_vars_iterator &I) const { + assert((R == nullptr) == (I.R == nullptr)); + return I.R != R; + } + referenced_vars_iterator &operator++() { + ++R; + ++OriginalR; + return *this; + } + }; + + /// Return the original region for a captured region, if + /// one exists. + const VarRegion *getOriginalRegion(const VarRegion *VR) const; + + referenced_vars_iterator referenced_vars_begin() const; + referenced_vars_iterator referenced_vars_end() const; + + void dumpToStream(raw_ostream &os) const override; + + void Profile(llvm::FoldingSetNodeID& ID) const override; + + static void ProfileRegion(llvm::FoldingSetNodeID&, const BlockTextRegion *, + const LocationContext *, unsigned, + const MemRegion *); + + static bool classof(const MemRegion* R) { + return R->getKind() == BlockDataRegionKind; + } +private: + void LazyInitializeReferencedVars(); + std::pair<const VarRegion *, const VarRegion *> + getCaptureRegions(const VarDecl *VD); +}; + +/// SymbolicRegion - A special, "non-concrete" region. Unlike other region +/// classes, SymbolicRegion represents a region that serves as an alias for +/// either a real region, a NULL pointer, etc. It essentially is used to +/// map the concept of symbolic values into the domain of regions. Symbolic +/// regions do not need to be typed. +class SymbolicRegion : public SubRegion { +protected: + const SymbolRef sym; + +public: + SymbolicRegion(const SymbolRef s, const MemRegion* sreg) + : SubRegion(sreg, SymbolicRegionKind), sym(s) {} + + SymbolRef getSymbol() const { + return sym; + } + + bool isBoundable() const override { return true; } + + DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override; + + void Profile(llvm::FoldingSetNodeID& ID) const override; + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, + SymbolRef sym, + const MemRegion* superRegion); + + void dumpToStream(raw_ostream &os) const override; + + static bool classof(const MemRegion* R) { + return R->getKind() == SymbolicRegionKind; + } +}; + +/// StringRegion - Region associated with a StringLiteral. +class StringRegion : public TypedValueRegion { + friend class MemRegionManager; + const StringLiteral* Str; +protected: + + StringRegion(const StringLiteral* str, const MemRegion* sreg) + : TypedValueRegion(sreg, StringRegionKind), Str(str) {} + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, + const StringLiteral* Str, + const MemRegion* superRegion); + +public: + + const StringLiteral* getStringLiteral() const { return Str; } + + QualType getValueType() const override { + return Str->getType(); + } + + DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override; + + bool isBoundable() const override { return false; } + + void Profile(llvm::FoldingSetNodeID& ID) const override { + ProfileRegion(ID, Str, superRegion); + } + + void dumpToStream(raw_ostream &os) const override; + + static bool classof(const MemRegion* R) { + return R->getKind() == StringRegionKind; + } +}; + +/// The region associated with an ObjCStringLiteral. +class ObjCStringRegion : public TypedValueRegion { + friend class MemRegionManager; + const ObjCStringLiteral* Str; +protected: + + ObjCStringRegion(const ObjCStringLiteral* str, const MemRegion* sreg) + : TypedValueRegion(sreg, ObjCStringRegionKind), Str(str) {} + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, + const ObjCStringLiteral* Str, + const MemRegion* superRegion); + +public: + + const ObjCStringLiteral* getObjCStringLiteral() const { return Str; } + + QualType getValueType() const override { + return Str->getType(); + } + + bool isBoundable() const override { return false; } + + void Profile(llvm::FoldingSetNodeID& ID) const override { + ProfileRegion(ID, Str, superRegion); + } + + void dumpToStream(raw_ostream &os) const override; + + static bool classof(const MemRegion* R) { + return R->getKind() == ObjCStringRegionKind; + } +}; + +/// CompoundLiteralRegion - A memory region representing a compound literal. +/// Compound literals are essentially temporaries that are stack allocated +/// or in the global constant pool. +class CompoundLiteralRegion : public TypedValueRegion { +private: + friend class MemRegionManager; + const CompoundLiteralExpr *CL; + + CompoundLiteralRegion(const CompoundLiteralExpr *cl, const MemRegion* sReg) + : TypedValueRegion(sReg, CompoundLiteralRegionKind), CL(cl) {} + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, + const CompoundLiteralExpr *CL, + const MemRegion* superRegion); +public: + QualType getValueType() const override { + return CL->getType(); + } + + bool isBoundable() const override { return !CL->isFileScope(); } + + void Profile(llvm::FoldingSetNodeID& ID) const override; + + void dumpToStream(raw_ostream &os) const override; + + const CompoundLiteralExpr *getLiteralExpr() const { return CL; } + + static bool classof(const MemRegion* R) { + return R->getKind() == CompoundLiteralRegionKind; + } +}; + +class DeclRegion : public TypedValueRegion { +protected: + const Decl *D; + + DeclRegion(const Decl *d, const MemRegion* sReg, Kind k) + : TypedValueRegion(sReg, k), D(d) {} + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl *D, + const MemRegion* superRegion, Kind k); + +public: + const Decl *getDecl() const { return D; } + void Profile(llvm::FoldingSetNodeID& ID) const override; + + static bool classof(const MemRegion* R) { + unsigned k = R->getKind(); + return k >= BEG_DECL_REGIONS && k <= END_DECL_REGIONS; + } +}; + +class VarRegion : public DeclRegion { + friend class MemRegionManager; + + // Constructors and private methods. + VarRegion(const VarDecl *vd, const MemRegion* sReg) + : DeclRegion(vd, sReg, VarRegionKind) {} + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const VarDecl *VD, + const MemRegion *superRegion) { + DeclRegion::ProfileRegion(ID, VD, superRegion, VarRegionKind); + } + + void Profile(llvm::FoldingSetNodeID& ID) const override; + +public: + const VarDecl *getDecl() const { return cast<VarDecl>(D); } + + const StackFrameContext *getStackFrame() const; + + QualType getValueType() const override { + // FIXME: We can cache this if needed. + return getDecl()->getType(); + } + + void dumpToStream(raw_ostream &os) const override; + + static bool classof(const MemRegion* R) { + return R->getKind() == VarRegionKind; + } + + bool canPrintPrettyAsExpr() const override; + + void printPrettyAsExpr(raw_ostream &os) const override; +}; + +/// CXXThisRegion - Represents the region for the implicit 'this' parameter +/// in a call to a C++ method. This region doesn't represent the object +/// referred to by 'this', but rather 'this' itself. +class CXXThisRegion : public TypedValueRegion { + friend class MemRegionManager; + CXXThisRegion(const PointerType *thisPointerTy, + const MemRegion *sReg) + : TypedValueRegion(sReg, CXXThisRegionKind), ThisPointerTy(thisPointerTy) {} + + static void ProfileRegion(llvm::FoldingSetNodeID &ID, + const PointerType *PT, + const MemRegion *sReg); + + void Profile(llvm::FoldingSetNodeID &ID) const override; + +public: + QualType getValueType() const override { + return QualType(ThisPointerTy, 0); + } + + void dumpToStream(raw_ostream &os) const override; + + static bool classof(const MemRegion* R) { + return R->getKind() == CXXThisRegionKind; + } + +private: + const PointerType *ThisPointerTy; +}; + +class FieldRegion : public DeclRegion { + friend class MemRegionManager; + + FieldRegion(const FieldDecl *fd, const MemRegion* sReg) + : DeclRegion(fd, sReg, FieldRegionKind) {} + +public: + const FieldDecl *getDecl() const { return cast<FieldDecl>(D); } + + QualType getValueType() const override { + // FIXME: We can cache this if needed. + return getDecl()->getType(); + } + + DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override; + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FieldDecl *FD, + const MemRegion* superRegion) { + DeclRegion::ProfileRegion(ID, FD, superRegion, FieldRegionKind); + } + + static bool classof(const MemRegion* R) { + return R->getKind() == FieldRegionKind; + } + + void dumpToStream(raw_ostream &os) const override; + + bool canPrintPretty() const override; + void printPretty(raw_ostream &os) const override; + bool canPrintPrettyAsExpr() const override; + void printPrettyAsExpr(raw_ostream &os) const override; +}; + +class ObjCIvarRegion : public DeclRegion { + + friend class MemRegionManager; + + ObjCIvarRegion(const ObjCIvarDecl *ivd, const MemRegion* sReg); + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const ObjCIvarDecl *ivd, + const MemRegion* superRegion); + +public: + const ObjCIvarDecl *getDecl() const; + QualType getValueType() const override; + + bool canPrintPrettyAsExpr() const override; + void printPrettyAsExpr(raw_ostream &os) const override; + + void dumpToStream(raw_ostream &os) const override; + + static bool classof(const MemRegion* R) { + return R->getKind() == ObjCIvarRegionKind; + } +}; +//===----------------------------------------------------------------------===// +// Auxiliary data classes for use with MemRegions. +//===----------------------------------------------------------------------===// + +class ElementRegion; + +class RegionRawOffset { +private: + friend class ElementRegion; + + const MemRegion *Region; + CharUnits Offset; + + RegionRawOffset(const MemRegion* reg, CharUnits offset = CharUnits::Zero()) + : Region(reg), Offset(offset) {} + +public: + // FIXME: Eventually support symbolic offsets. + CharUnits getOffset() const { return Offset; } + const MemRegion *getRegion() const { return Region; } + + void dumpToStream(raw_ostream &os) const; + void dump() const; +}; + +/// \brief ElementRegin is used to represent both array elements and casts. +class ElementRegion : public TypedValueRegion { + friend class MemRegionManager; + + QualType ElementType; + NonLoc Index; + + ElementRegion(QualType elementType, NonLoc Idx, const MemRegion* sReg) + : TypedValueRegion(sReg, ElementRegionKind), + ElementType(elementType), Index(Idx) { + assert((!Idx.getAs<nonloc::ConcreteInt>() || + Idx.castAs<nonloc::ConcreteInt>().getValue().isSigned()) && + "The index must be signed"); + } + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, QualType elementType, + SVal Idx, const MemRegion* superRegion); + +public: + + NonLoc getIndex() const { return Index; } + + QualType getValueType() const override { + return ElementType; + } + + QualType getElementType() const { + return ElementType; + } + /// Compute the offset within the array. The array might also be a subobject. + RegionRawOffset getAsArrayOffset() const; + + void dumpToStream(raw_ostream &os) const override; + + void Profile(llvm::FoldingSetNodeID& ID) const override; + + static bool classof(const MemRegion* R) { + return R->getKind() == ElementRegionKind; + } +}; + +// C++ temporary object associated with an expression. +class CXXTempObjectRegion : public TypedValueRegion { + friend class MemRegionManager; + + Expr const *Ex; + + CXXTempObjectRegion(Expr const *E, MemRegion const *sReg) + : TypedValueRegion(sReg, CXXTempObjectRegionKind), Ex(E) {} + + static void ProfileRegion(llvm::FoldingSetNodeID &ID, + Expr const *E, const MemRegion *sReg); + +public: + const Expr *getExpr() const { return Ex; } + + QualType getValueType() const override { + return Ex->getType(); + } + + void dumpToStream(raw_ostream &os) const override; + + void Profile(llvm::FoldingSetNodeID &ID) const override; + + static bool classof(const MemRegion* R) { + return R->getKind() == CXXTempObjectRegionKind; + } +}; + +// CXXBaseObjectRegion represents a base object within a C++ object. It is +// identified by the base class declaration and the region of its parent object. +class CXXBaseObjectRegion : public TypedValueRegion { + friend class MemRegionManager; + + llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> Data; + + CXXBaseObjectRegion(const CXXRecordDecl *RD, bool IsVirtual, + const MemRegion *SReg) + : TypedValueRegion(SReg, CXXBaseObjectRegionKind), Data(RD, IsVirtual) {} + + static void ProfileRegion(llvm::FoldingSetNodeID &ID, const CXXRecordDecl *RD, + bool IsVirtual, const MemRegion *SReg); + +public: + const CXXRecordDecl *getDecl() const { return Data.getPointer(); } + bool isVirtual() const { return Data.getInt(); } + + QualType getValueType() const override; + + void dumpToStream(raw_ostream &os) const override; + + void Profile(llvm::FoldingSetNodeID &ID) const override; + + static bool classof(const MemRegion *region) { + return region->getKind() == CXXBaseObjectRegionKind; + } + + bool canPrintPrettyAsExpr() const override; + + void printPrettyAsExpr(raw_ostream &os) const override; +}; + +template<typename RegionTy> +const RegionTy* MemRegion::getAs() const { + if (const RegionTy* RT = dyn_cast<RegionTy>(this)) + return RT; + + return nullptr; +} + +//===----------------------------------------------------------------------===// +// MemRegionManager - Factory object for creating regions. +//===----------------------------------------------------------------------===// + +class MemRegionManager { + ASTContext &C; + llvm::BumpPtrAllocator& A; + llvm::FoldingSet<MemRegion> Regions; + + GlobalInternalSpaceRegion *InternalGlobals; + GlobalSystemSpaceRegion *SystemGlobals; + GlobalImmutableSpaceRegion *ImmutableGlobals; + + + llvm::DenseMap<const StackFrameContext *, StackLocalsSpaceRegion *> + StackLocalsSpaceRegions; + llvm::DenseMap<const StackFrameContext *, StackArgumentsSpaceRegion *> + StackArgumentsSpaceRegions; + llvm::DenseMap<const CodeTextRegion *, StaticGlobalSpaceRegion *> + StaticsGlobalSpaceRegions; + + HeapSpaceRegion *heap; + UnknownSpaceRegion *unknown; + MemSpaceRegion *code; + +public: + MemRegionManager(ASTContext &c, llvm::BumpPtrAllocator &a) + : C(c), A(a), InternalGlobals(nullptr), SystemGlobals(nullptr), + ImmutableGlobals(nullptr), heap(nullptr), unknown(nullptr), + code(nullptr) {} + + ~MemRegionManager(); + + ASTContext &getContext() { return C; } + + llvm::BumpPtrAllocator &getAllocator() { return A; } + + /// getStackLocalsRegion - Retrieve the memory region associated with the + /// specified stack frame. + const StackLocalsSpaceRegion * + getStackLocalsRegion(const StackFrameContext *STC); + + /// getStackArgumentsRegion - Retrieve the memory region associated with + /// function/method arguments of the specified stack frame. + const StackArgumentsSpaceRegion * + getStackArgumentsRegion(const StackFrameContext *STC); + + /// getGlobalsRegion - Retrieve the memory region associated with + /// global variables. + const GlobalsSpaceRegion *getGlobalsRegion( + MemRegion::Kind K = MemRegion::GlobalInternalSpaceRegionKind, + const CodeTextRegion *R = nullptr); + + /// getHeapRegion - Retrieve the memory region associated with the + /// generic "heap". + const HeapSpaceRegion *getHeapRegion(); + + /// getUnknownRegion - Retrieve the memory region associated with unknown + /// memory space. + const MemSpaceRegion *getUnknownRegion(); + + const MemSpaceRegion *getCodeRegion(); + + /// getAllocaRegion - Retrieve a region associated with a call to alloca(). + const AllocaRegion *getAllocaRegion(const Expr *Ex, unsigned Cnt, + const LocationContext *LC); + + /// getCompoundLiteralRegion - Retrieve the region associated with a + /// given CompoundLiteral. + const CompoundLiteralRegion* + getCompoundLiteralRegion(const CompoundLiteralExpr *CL, + const LocationContext *LC); + + /// getCXXThisRegion - Retrieve the [artificial] region associated with the + /// parameter 'this'. + const CXXThisRegion *getCXXThisRegion(QualType thisPointerTy, + const LocationContext *LC); + + /// \brief Retrieve or create a "symbolic" memory region. + const SymbolicRegion* getSymbolicRegion(SymbolRef Sym); + + /// \brief Return a unique symbolic region belonging to heap memory space. + const SymbolicRegion *getSymbolicHeapRegion(SymbolRef sym); + + const StringRegion *getStringRegion(const StringLiteral* Str); + + const ObjCStringRegion *getObjCStringRegion(const ObjCStringLiteral *Str); + + /// getVarRegion - Retrieve or create the memory region associated with + /// a specified VarDecl and LocationContext. + const VarRegion* getVarRegion(const VarDecl *D, const LocationContext *LC); + + /// getVarRegion - Retrieve or create the memory region associated with + /// a specified VarDecl and super region. + const VarRegion* getVarRegion(const VarDecl *D, const MemRegion *superR); + + /// getElementRegion - Retrieve the memory region associated with the + /// associated element type, index, and super region. + const ElementRegion *getElementRegion(QualType elementType, NonLoc Idx, + const MemRegion *superRegion, + ASTContext &Ctx); + + const ElementRegion *getElementRegionWithSuper(const ElementRegion *ER, + const MemRegion *superRegion) { + return getElementRegion(ER->getElementType(), ER->getIndex(), + superRegion, ER->getContext()); + } + + /// getFieldRegion - Retrieve or create the memory region associated with + /// a specified FieldDecl. 'superRegion' corresponds to the containing + /// memory region (which typically represents the memory representing + /// a structure or class). + const FieldRegion *getFieldRegion(const FieldDecl *fd, + const MemRegion* superRegion); + + const FieldRegion *getFieldRegionWithSuper(const FieldRegion *FR, + const MemRegion *superRegion) { + return getFieldRegion(FR->getDecl(), superRegion); + } + + /// getObjCIvarRegion - Retrieve or create the memory region associated with + /// a specified Objective-c instance variable. 'superRegion' corresponds + /// to the containing region (which typically represents the Objective-C + /// object). + const ObjCIvarRegion *getObjCIvarRegion(const ObjCIvarDecl *ivd, + const MemRegion* superRegion); + + const CXXTempObjectRegion *getCXXTempObjectRegion(Expr const *Ex, + LocationContext const *LC); + + /// Create a CXXBaseObjectRegion with the given base class for region + /// \p Super. + /// + /// The type of \p Super is assumed be a class deriving from \p BaseClass. + const CXXBaseObjectRegion * + getCXXBaseObjectRegion(const CXXRecordDecl *BaseClass, const MemRegion *Super, + bool IsVirtual); + + /// Create a CXXBaseObjectRegion with the same CXXRecordDecl but a different + /// super region. + const CXXBaseObjectRegion * + getCXXBaseObjectRegionWithSuper(const CXXBaseObjectRegion *baseReg, + const MemRegion *superRegion) { + return getCXXBaseObjectRegion(baseReg->getDecl(), superRegion, + baseReg->isVirtual()); + } + + const FunctionTextRegion *getFunctionTextRegion(const NamedDecl *FD); + const BlockTextRegion *getBlockTextRegion(const BlockDecl *BD, + CanQualType locTy, + AnalysisDeclContext *AC); + + /// getBlockDataRegion - Get the memory region associated with an instance + /// of a block. Unlike many other MemRegions, the LocationContext* + /// argument is allowed to be NULL for cases where we have no known + /// context. + const BlockDataRegion *getBlockDataRegion(const BlockTextRegion *bc, + const LocationContext *lc, + unsigned blockCount); + + /// Create a CXXTempObjectRegion for temporaries which are lifetime-extended + /// by static references. This differs from getCXXTempObjectRegion in the + /// super-region used. + const CXXTempObjectRegion *getCXXStaticTempObjectRegion(const Expr *Ex); + +private: + template <typename RegionTy, typename A1> + RegionTy* getRegion(const A1 a1); + + template <typename RegionTy, typename A1> + RegionTy* getSubRegion(const A1 a1, const MemRegion* superRegion); + + template <typename RegionTy, typename A1, typename A2> + RegionTy* getRegion(const A1 a1, const A2 a2); + + template <typename RegionTy, typename A1, typename A2> + RegionTy* getSubRegion(const A1 a1, const A2 a2, + const MemRegion* superRegion); + + template <typename RegionTy, typename A1, typename A2, typename A3> + RegionTy* getSubRegion(const A1 a1, const A2 a2, const A3 a3, + const MemRegion* superRegion); + + template <typename REG> + const REG* LazyAllocate(REG*& region); + + template <typename REG, typename ARG> + const REG* LazyAllocate(REG*& region, ARG a); +}; + +//===----------------------------------------------------------------------===// +// Out-of-line member definitions. +//===----------------------------------------------------------------------===// + +inline ASTContext &MemRegion::getContext() const { + return getMemRegionManager()->getContext(); +} + +//===----------------------------------------------------------------------===// +// Means for storing region/symbol handling traits. +//===----------------------------------------------------------------------===// + +/// Information about invalidation for a particular region/symbol. +class RegionAndSymbolInvalidationTraits { + typedef unsigned char StorageTypeForKinds; + llvm::DenseMap<const MemRegion *, StorageTypeForKinds> MRTraitsMap; + llvm::DenseMap<SymbolRef, StorageTypeForKinds> SymTraitsMap; + + typedef llvm::DenseMap<const MemRegion *, StorageTypeForKinds>::const_iterator + const_region_iterator; + typedef llvm::DenseMap<SymbolRef, StorageTypeForKinds>::const_iterator + const_symbol_iterator; + +public: + /// \brief Describes different invalidation traits. + enum InvalidationKinds { + /// Tells that a region's contents is not changed. + TK_PreserveContents = 0x1, + /// Suppress pointer-escaping of a region. + TK_SuppressEscape = 0x2, + // Do not invalidate super region. + TK_DoNotInvalidateSuperRegion = 0x4, + /// When applied to a MemSpaceRegion, indicates the entire memory space + /// should be invalidated. + TK_EntireMemSpace = 0x8 + + // Do not forget to extend StorageTypeForKinds if number of traits exceed + // the number of bits StorageTypeForKinds can store. + }; + + void setTrait(SymbolRef Sym, InvalidationKinds IK); + void setTrait(const MemRegion *MR, InvalidationKinds IK); + bool hasTrait(SymbolRef Sym, InvalidationKinds IK); + bool hasTrait(const MemRegion *MR, InvalidationKinds IK); +}; + +} // end GR namespace + +} // end clang namespace + +//===----------------------------------------------------------------------===// +// Pretty-printing regions. +//===----------------------------------------------------------------------===// + +namespace llvm { +static inline raw_ostream &operator<<(raw_ostream &os, + const clang::ento::MemRegion* R) { + R->dumpToStream(os); + return os; +} +} // end llvm namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h new file mode 100644 index 0000000..c4a62ec --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h @@ -0,0 +1,854 @@ +//== ProgramState.h - Path-sensitive "State" for tracking values -*- C++ -*--=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the state of the program along the analysisa path. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATE_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATE_H + +#include "clang/Basic/LLVM.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/Environment.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/ImmutableMap.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/Support/Allocator.h" + +namespace llvm { +class APSInt; +} + +namespace clang { +class ASTContext; + +namespace ento { + +class CallEvent; +class CallEventManager; + +typedef std::unique_ptr<ConstraintManager>(*ConstraintManagerCreator)( + ProgramStateManager &, SubEngine *); +typedef std::unique_ptr<StoreManager>(*StoreManagerCreator)( + ProgramStateManager &); + +//===----------------------------------------------------------------------===// +// ProgramStateTrait - Traits used by the Generic Data Map of a ProgramState. +//===----------------------------------------------------------------------===// + +template <typename T> struct ProgramStatePartialTrait; + +template <typename T> struct ProgramStateTrait { + typedef typename T::data_type data_type; + static inline void *MakeVoidPtr(data_type D) { return (void*) D; } + static inline data_type MakeData(void *const* P) { + return P ? (data_type) *P : (data_type) 0; + } +}; + +/// \class ProgramState +/// ProgramState - This class encapsulates: +/// +/// 1. A mapping from expressions to values (Environment) +/// 2. A mapping from locations to values (Store) +/// 3. Constraints on symbolic values (GenericDataMap) +/// +/// Together these represent the "abstract state" of a program. +/// +/// ProgramState is intended to be used as a functional object; that is, +/// once it is created and made "persistent" in a FoldingSet, its +/// values will never change. +class ProgramState : public llvm::FoldingSetNode { +public: + typedef llvm::ImmutableSet<llvm::APSInt*> IntSetTy; + typedef llvm::ImmutableMap<void*, void*> GenericDataMap; + +private: + void operator=(const ProgramState& R) = delete; + + friend class ProgramStateManager; + friend class ExplodedGraph; + friend class ExplodedNode; + + ProgramStateManager *stateMgr; + Environment Env; // Maps a Stmt to its current SVal. + Store store; // Maps a location to its current value. + GenericDataMap GDM; // Custom data stored by a client of this class. + unsigned refCount; + + /// makeWithStore - Return a ProgramState with the same values as the current + /// state with the exception of using the specified Store. + ProgramStateRef makeWithStore(const StoreRef &store) const; + + void setStore(const StoreRef &storeRef); + +public: + /// This ctor is used when creating the first ProgramState object. + ProgramState(ProgramStateManager *mgr, const Environment& env, + StoreRef st, GenericDataMap gdm); + + /// Copy ctor - We must explicitly define this or else the "Next" ptr + /// in FoldingSetNode will also get copied. + ProgramState(const ProgramState &RHS); + + ~ProgramState(); + + /// Return the ProgramStateManager associated with this state. + ProgramStateManager &getStateManager() const { + return *stateMgr; + } + + /// Return the ConstraintManager. + ConstraintManager &getConstraintManager() const; + + /// getEnvironment - Return the environment associated with this state. + /// The environment is the mapping from expressions to values. + const Environment& getEnvironment() const { return Env; } + + /// Return the store associated with this state. The store + /// is a mapping from locations to values. + Store getStore() const { return store; } + + + /// getGDM - Return the generic data map associated with this state. + GenericDataMap getGDM() const { return GDM; } + + void setGDM(GenericDataMap gdm) { GDM = gdm; } + + /// Profile - Profile the contents of a ProgramState object for use in a + /// FoldingSet. Two ProgramState objects are considered equal if they + /// have the same Environment, Store, and GenericDataMap. + static void Profile(llvm::FoldingSetNodeID& ID, const ProgramState *V) { + V->Env.Profile(ID); + ID.AddPointer(V->store); + V->GDM.Profile(ID); + } + + /// Profile - Used to profile the contents of this object for inclusion + /// in a FoldingSet. + void Profile(llvm::FoldingSetNodeID& ID) const { + Profile(ID, this); + } + + BasicValueFactory &getBasicVals() const; + SymbolManager &getSymbolManager() const; + + //==---------------------------------------------------------------------==// + // Constraints on values. + //==---------------------------------------------------------------------==// + // + // Each ProgramState records constraints on symbolic values. These constraints + // are managed using the ConstraintManager associated with a ProgramStateManager. + // As constraints gradually accrue on symbolic values, added constraints + // may conflict and indicate that a state is infeasible (as no real values + // could satisfy all the constraints). This is the principal mechanism + // for modeling path-sensitivity in ExprEngine/ProgramState. + // + // Various "assume" methods form the interface for adding constraints to + // symbolic values. A call to 'assume' indicates an assumption being placed + // on one or symbolic values. 'assume' methods take the following inputs: + // + // (1) A ProgramState object representing the current state. + // + // (2) The assumed constraint (which is specific to a given "assume" method). + // + // (3) A binary value "Assumption" that indicates whether the constraint is + // assumed to be true or false. + // + // The output of "assume*" is a new ProgramState object with the added constraints. + // If no new state is feasible, NULL is returned. + // + + /// Assumes that the value of \p cond is zero (if \p assumption is "false") + /// or non-zero (if \p assumption is "true"). + /// + /// This returns a new state with the added constraint on \p cond. + /// If no new state is feasible, NULL is returned. + ProgramStateRef assume(DefinedOrUnknownSVal cond, bool assumption) const; + + /// Assumes both "true" and "false" for \p cond, and returns both + /// corresponding states (respectively). + /// + /// This is more efficient than calling assume() twice. Note that one (but not + /// both) of the returned states may be NULL. + std::pair<ProgramStateRef, ProgramStateRef> + assume(DefinedOrUnknownSVal cond) const; + + ProgramStateRef assumeInBound(DefinedOrUnknownSVal idx, + DefinedOrUnknownSVal upperBound, + bool assumption, + QualType IndexType = QualType()) const; + + /// Assumes that the value of \p Val is bounded with [\p From; \p To] + /// (if \p assumption is "true") or it is fully out of this range + /// (if \p assumption is "false"). + /// + /// This returns a new state with the added constraint on \p cond. + /// If no new state is feasible, NULL is returned. + ProgramStateRef assumeWithinInclusiveRange(DefinedOrUnknownSVal Val, + const llvm::APSInt &From, + const llvm::APSInt &To, + bool assumption) const; + + /// Assumes given range both "true" and "false" for \p Val, and returns both + /// corresponding states (respectively). + /// + /// This is more efficient than calling assume() twice. Note that one (but not + /// both) of the returned states may be NULL. + std::pair<ProgramStateRef, ProgramStateRef> + assumeWithinInclusiveRange(DefinedOrUnknownSVal Val, const llvm::APSInt &From, + const llvm::APSInt &To) const; + + + /// \brief Check if the given SVal is constrained to zero or is a zero + /// constant. + ConditionTruthVal isNull(SVal V) const; + + /// Utility method for getting regions. + const VarRegion* getRegion(const VarDecl *D, const LocationContext *LC) const; + + //==---------------------------------------------------------------------==// + // Binding and retrieving values to/from the environment and symbolic store. + //==---------------------------------------------------------------------==// + + /// Create a new state by binding the value 'V' to the statement 'S' in the + /// state's environment. + ProgramStateRef BindExpr(const Stmt *S, const LocationContext *LCtx, + SVal V, bool Invalidate = true) const; + + ProgramStateRef bindLoc(Loc location, + SVal V, + bool notifyChanges = true) const; + + ProgramStateRef bindLoc(SVal location, SVal V) const; + + ProgramStateRef bindDefault(SVal loc, SVal V) const; + + ProgramStateRef killBinding(Loc LV) const; + + /// \brief Returns the state with bindings for the given regions + /// cleared from the store. + /// + /// Optionally invalidates global regions as well. + /// + /// \param Regions the set of regions to be invalidated. + /// \param E the expression that caused the invalidation. + /// \param BlockCount The number of times the current basic block has been + // visited. + /// \param CausesPointerEscape the flag is set to true when + /// the invalidation entails escape of a symbol (representing a + /// pointer). For example, due to it being passed as an argument in a + /// call. + /// \param IS the set of invalidated symbols. + /// \param Call if non-null, the invalidated regions represent parameters to + /// the call and should be considered directly invalidated. + /// \param ITraits information about special handling for a particular + /// region/symbol. + ProgramStateRef + invalidateRegions(ArrayRef<const MemRegion *> Regions, const Expr *E, + unsigned BlockCount, const LocationContext *LCtx, + bool CausesPointerEscape, InvalidatedSymbols *IS = nullptr, + const CallEvent *Call = nullptr, + RegionAndSymbolInvalidationTraits *ITraits = nullptr) const; + + ProgramStateRef + invalidateRegions(ArrayRef<SVal> Regions, const Expr *E, + unsigned BlockCount, const LocationContext *LCtx, + bool CausesPointerEscape, InvalidatedSymbols *IS = nullptr, + const CallEvent *Call = nullptr, + RegionAndSymbolInvalidationTraits *ITraits = nullptr) const; + + /// enterStackFrame - Returns the state for entry to the given stack frame, + /// preserving the current state. + ProgramStateRef enterStackFrame(const CallEvent &Call, + const StackFrameContext *CalleeCtx) const; + + /// Get the lvalue for a variable reference. + Loc getLValue(const VarDecl *D, const LocationContext *LC) const; + + Loc getLValue(const CompoundLiteralExpr *literal, + const LocationContext *LC) const; + + /// Get the lvalue for an ivar reference. + SVal getLValue(const ObjCIvarDecl *decl, SVal base) const; + + /// Get the lvalue for a field reference. + SVal getLValue(const FieldDecl *decl, SVal Base) const; + + /// Get the lvalue for an indirect field reference. + SVal getLValue(const IndirectFieldDecl *decl, SVal Base) const; + + /// Get the lvalue for an array index. + SVal getLValue(QualType ElementType, SVal Idx, SVal Base) const; + + /// Returns the SVal bound to the statement 'S' in the state's environment. + SVal getSVal(const Stmt *S, const LocationContext *LCtx) const; + + SVal getSValAsScalarOrLoc(const Stmt *Ex, const LocationContext *LCtx) const; + + /// \brief Return the value bound to the specified location. + /// Returns UnknownVal() if none found. + SVal getSVal(Loc LV, QualType T = QualType()) const; + + /// Returns the "raw" SVal bound to LV before any value simplfication. + SVal getRawSVal(Loc LV, QualType T= QualType()) const; + + /// \brief Return the value bound to the specified location. + /// Returns UnknownVal() if none found. + SVal getSVal(const MemRegion* R) const; + + SVal getSValAsScalarOrLoc(const MemRegion *R) const; + + /// \brief Visits the symbols reachable from the given SVal using the provided + /// SymbolVisitor. + /// + /// This is a convenience API. Consider using ScanReachableSymbols class + /// directly when making multiple scans on the same state with the same + /// visitor to avoid repeated initialization cost. + /// \sa ScanReachableSymbols + bool scanReachableSymbols(SVal val, SymbolVisitor& visitor) const; + + /// \brief Visits the symbols reachable from the SVals in the given range + /// using the provided SymbolVisitor. + bool scanReachableSymbols(const SVal *I, const SVal *E, + SymbolVisitor &visitor) const; + + /// \brief Visits the symbols reachable from the regions in the given + /// MemRegions range using the provided SymbolVisitor. + bool scanReachableSymbols(const MemRegion * const *I, + const MemRegion * const *E, + SymbolVisitor &visitor) const; + + template <typename CB> CB scanReachableSymbols(SVal val) const; + template <typename CB> CB scanReachableSymbols(const SVal *beg, + const SVal *end) const; + + template <typename CB> CB + scanReachableSymbols(const MemRegion * const *beg, + const MemRegion * const *end) const; + + /// Create a new state in which the statement is marked as tainted. + ProgramStateRef addTaint(const Stmt *S, const LocationContext *LCtx, + TaintTagType Kind = TaintTagGeneric) const; + + /// Create a new state in which the symbol is marked as tainted. + ProgramStateRef addTaint(SymbolRef S, + TaintTagType Kind = TaintTagGeneric) const; + + /// Create a new state in which the region symbol is marked as tainted. + ProgramStateRef addTaint(const MemRegion *R, + TaintTagType Kind = TaintTagGeneric) const; + + /// Check if the statement is tainted in the current state. + bool isTainted(const Stmt *S, const LocationContext *LCtx, + TaintTagType Kind = TaintTagGeneric) const; + bool isTainted(SVal V, TaintTagType Kind = TaintTagGeneric) const; + bool isTainted(SymbolRef Sym, TaintTagType Kind = TaintTagGeneric) const; + bool isTainted(const MemRegion *Reg, TaintTagType Kind=TaintTagGeneric) const; + + //==---------------------------------------------------------------------==// + // Accessing the Generic Data Map (GDM). + //==---------------------------------------------------------------------==// + + void *const* FindGDM(void *K) const; + + template<typename T> + ProgramStateRef add(typename ProgramStateTrait<T>::key_type K) const; + + template <typename T> + typename ProgramStateTrait<T>::data_type + get() const { + return ProgramStateTrait<T>::MakeData(FindGDM(ProgramStateTrait<T>::GDMIndex())); + } + + template<typename T> + typename ProgramStateTrait<T>::lookup_type + get(typename ProgramStateTrait<T>::key_type key) const { + void *const* d = FindGDM(ProgramStateTrait<T>::GDMIndex()); + return ProgramStateTrait<T>::Lookup(ProgramStateTrait<T>::MakeData(d), key); + } + + template <typename T> + typename ProgramStateTrait<T>::context_type get_context() const; + + + template<typename T> + ProgramStateRef remove(typename ProgramStateTrait<T>::key_type K) const; + + template<typename T> + ProgramStateRef remove(typename ProgramStateTrait<T>::key_type K, + typename ProgramStateTrait<T>::context_type C) const; + template <typename T> + ProgramStateRef remove() const; + + template<typename T> + ProgramStateRef set(typename ProgramStateTrait<T>::data_type D) const; + + template<typename T> + ProgramStateRef set(typename ProgramStateTrait<T>::key_type K, + typename ProgramStateTrait<T>::value_type E) const; + + template<typename T> + ProgramStateRef set(typename ProgramStateTrait<T>::key_type K, + typename ProgramStateTrait<T>::value_type E, + typename ProgramStateTrait<T>::context_type C) const; + + template<typename T> + bool contains(typename ProgramStateTrait<T>::key_type key) const { + void *const* d = FindGDM(ProgramStateTrait<T>::GDMIndex()); + return ProgramStateTrait<T>::Contains(ProgramStateTrait<T>::MakeData(d), key); + } + + // Pretty-printing. + void print(raw_ostream &Out, const char *nl = "\n", + const char *sep = "") const; + void printDOT(raw_ostream &Out) const; + void printTaint(raw_ostream &Out, const char *nl = "\n", + const char *sep = "") const; + + void dump() const; + void dumpTaint() const; + +private: + friend void ProgramStateRetain(const ProgramState *state); + friend void ProgramStateRelease(const ProgramState *state); + + /// \sa invalidateValues() + /// \sa invalidateRegions() + ProgramStateRef + invalidateRegionsImpl(ArrayRef<SVal> Values, + const Expr *E, unsigned BlockCount, + const LocationContext *LCtx, + bool ResultsInSymbolEscape, + InvalidatedSymbols *IS, + RegionAndSymbolInvalidationTraits *HTraits, + const CallEvent *Call) const; +}; + +//===----------------------------------------------------------------------===// +// ProgramStateManager - Factory object for ProgramStates. +//===----------------------------------------------------------------------===// + +class ProgramStateManager { + friend class ProgramState; + friend void ProgramStateRelease(const ProgramState *state); +private: + /// Eng - The SubEngine that owns this state manager. + SubEngine *Eng; /* Can be null. */ + + EnvironmentManager EnvMgr; + std::unique_ptr<StoreManager> StoreMgr; + std::unique_ptr<ConstraintManager> ConstraintMgr; + + ProgramState::GenericDataMap::Factory GDMFactory; + + typedef llvm::DenseMap<void*,std::pair<void*,void (*)(void*)> > GDMContextsTy; + GDMContextsTy GDMContexts; + + /// StateSet - FoldingSet containing all the states created for analyzing + /// a particular function. This is used to unique states. + llvm::FoldingSet<ProgramState> StateSet; + + /// Object that manages the data for all created SVals. + std::unique_ptr<SValBuilder> svalBuilder; + + /// Manages memory for created CallEvents. + std::unique_ptr<CallEventManager> CallEventMgr; + + /// A BumpPtrAllocator to allocate states. + llvm::BumpPtrAllocator &Alloc; + + /// A vector of ProgramStates that we can reuse. + std::vector<ProgramState *> freeStates; + +public: + ProgramStateManager(ASTContext &Ctx, + StoreManagerCreator CreateStoreManager, + ConstraintManagerCreator CreateConstraintManager, + llvm::BumpPtrAllocator& alloc, + SubEngine *subeng); + + ~ProgramStateManager(); + + ProgramStateRef getInitialState(const LocationContext *InitLoc); + + ASTContext &getContext() { return svalBuilder->getContext(); } + const ASTContext &getContext() const { return svalBuilder->getContext(); } + + BasicValueFactory &getBasicVals() { + return svalBuilder->getBasicValueFactory(); + } + + SValBuilder &getSValBuilder() { + return *svalBuilder; + } + + SymbolManager &getSymbolManager() { + return svalBuilder->getSymbolManager(); + } + const SymbolManager &getSymbolManager() const { + return svalBuilder->getSymbolManager(); + } + + llvm::BumpPtrAllocator& getAllocator() { return Alloc; } + + MemRegionManager& getRegionManager() { + return svalBuilder->getRegionManager(); + } + const MemRegionManager& getRegionManager() const { + return svalBuilder->getRegionManager(); + } + + CallEventManager &getCallEventManager() { return *CallEventMgr; } + + StoreManager& getStoreManager() { return *StoreMgr; } + ConstraintManager& getConstraintManager() { return *ConstraintMgr; } + SubEngine* getOwningEngine() { return Eng; } + + ProgramStateRef removeDeadBindings(ProgramStateRef St, + const StackFrameContext *LCtx, + SymbolReaper& SymReaper); + +public: + + SVal ArrayToPointer(Loc Array, QualType ElementTy) { + return StoreMgr->ArrayToPointer(Array, ElementTy); + } + + // Methods that manipulate the GDM. + ProgramStateRef addGDM(ProgramStateRef St, void *Key, void *Data); + ProgramStateRef removeGDM(ProgramStateRef state, void *Key); + + // Methods that query & manipulate the Store. + + void iterBindings(ProgramStateRef state, StoreManager::BindingsHandler& F) { + StoreMgr->iterBindings(state->getStore(), F); + } + + ProgramStateRef getPersistentState(ProgramState &Impl); + ProgramStateRef getPersistentStateWithGDM(ProgramStateRef FromState, + ProgramStateRef GDMState); + + bool haveEqualEnvironments(ProgramStateRef S1, ProgramStateRef S2) { + return S1->Env == S2->Env; + } + + bool haveEqualStores(ProgramStateRef S1, ProgramStateRef S2) { + return S1->store == S2->store; + } + + //==---------------------------------------------------------------------==// + // Generic Data Map methods. + //==---------------------------------------------------------------------==// + // + // ProgramStateManager and ProgramState support a "generic data map" that allows + // different clients of ProgramState objects to embed arbitrary data within a + // ProgramState object. The generic data map is essentially an immutable map + // from a "tag" (that acts as the "key" for a client) and opaque values. + // Tags/keys and values are simply void* values. The typical way that clients + // generate unique tags are by taking the address of a static variable. + // Clients are responsible for ensuring that data values referred to by a + // the data pointer are immutable (and thus are essentially purely functional + // data). + // + // The templated methods below use the ProgramStateTrait<T> class + // to resolve keys into the GDM and to return data values to clients. + // + + // Trait based GDM dispatch. + template <typename T> + ProgramStateRef set(ProgramStateRef st, typename ProgramStateTrait<T>::data_type D) { + return addGDM(st, ProgramStateTrait<T>::GDMIndex(), + ProgramStateTrait<T>::MakeVoidPtr(D)); + } + + template<typename T> + ProgramStateRef set(ProgramStateRef st, + typename ProgramStateTrait<T>::key_type K, + typename ProgramStateTrait<T>::value_type V, + typename ProgramStateTrait<T>::context_type C) { + + return addGDM(st, ProgramStateTrait<T>::GDMIndex(), + ProgramStateTrait<T>::MakeVoidPtr(ProgramStateTrait<T>::Set(st->get<T>(), K, V, C))); + } + + template <typename T> + ProgramStateRef add(ProgramStateRef st, + typename ProgramStateTrait<T>::key_type K, + typename ProgramStateTrait<T>::context_type C) { + return addGDM(st, ProgramStateTrait<T>::GDMIndex(), + ProgramStateTrait<T>::MakeVoidPtr(ProgramStateTrait<T>::Add(st->get<T>(), K, C))); + } + + template <typename T> + ProgramStateRef remove(ProgramStateRef st, + typename ProgramStateTrait<T>::key_type K, + typename ProgramStateTrait<T>::context_type C) { + + return addGDM(st, ProgramStateTrait<T>::GDMIndex(), + ProgramStateTrait<T>::MakeVoidPtr(ProgramStateTrait<T>::Remove(st->get<T>(), K, C))); + } + + template <typename T> + ProgramStateRef remove(ProgramStateRef st) { + return removeGDM(st, ProgramStateTrait<T>::GDMIndex()); + } + + void *FindGDMContext(void *index, + void *(*CreateContext)(llvm::BumpPtrAllocator&), + void (*DeleteContext)(void*)); + + template <typename T> + typename ProgramStateTrait<T>::context_type get_context() { + void *p = FindGDMContext(ProgramStateTrait<T>::GDMIndex(), + ProgramStateTrait<T>::CreateContext, + ProgramStateTrait<T>::DeleteContext); + + return ProgramStateTrait<T>::MakeContext(p); + } + + void EndPath(ProgramStateRef St) { + ConstraintMgr->EndPath(St); + } +}; + + +//===----------------------------------------------------------------------===// +// Out-of-line method definitions for ProgramState. +//===----------------------------------------------------------------------===// + +inline ConstraintManager &ProgramState::getConstraintManager() const { + return stateMgr->getConstraintManager(); +} + +inline const VarRegion* ProgramState::getRegion(const VarDecl *D, + const LocationContext *LC) const +{ + return getStateManager().getRegionManager().getVarRegion(D, LC); +} + +inline ProgramStateRef ProgramState::assume(DefinedOrUnknownSVal Cond, + bool Assumption) const { + if (Cond.isUnknown()) + return this; + + return getStateManager().ConstraintMgr + ->assume(this, Cond.castAs<DefinedSVal>(), Assumption); +} + +inline std::pair<ProgramStateRef , ProgramStateRef > +ProgramState::assume(DefinedOrUnknownSVal Cond) const { + if (Cond.isUnknown()) + return std::make_pair(this, this); + + return getStateManager().ConstraintMgr + ->assumeDual(this, Cond.castAs<DefinedSVal>()); +} + +inline ProgramStateRef +ProgramState::assumeWithinInclusiveRange(DefinedOrUnknownSVal Val, + const llvm::APSInt &From, + const llvm::APSInt &To, + bool Assumption) const { + if (Val.isUnknown()) + return this; + + assert(Val.getAs<NonLoc>() && "Only NonLocs are supported!"); + + return getStateManager().ConstraintMgr->assumeWithinInclusiveRange( + this, Val.castAs<NonLoc>(), From, To, Assumption); +} + +inline std::pair<ProgramStateRef, ProgramStateRef> +ProgramState::assumeWithinInclusiveRange(DefinedOrUnknownSVal Val, + const llvm::APSInt &From, + const llvm::APSInt &To) const { + if (Val.isUnknown()) + return std::make_pair(this, this); + + assert(Val.getAs<NonLoc>() && "Only NonLocs are supported!"); + + return getStateManager().ConstraintMgr + ->assumeWithinInclusiveRangeDual(this, Val.castAs<NonLoc>(), From, To); +} + +inline ProgramStateRef ProgramState::bindLoc(SVal LV, SVal V) const { + if (Optional<Loc> L = LV.getAs<Loc>()) + return bindLoc(*L, V); + return this; +} + +inline Loc ProgramState::getLValue(const VarDecl *VD, + const LocationContext *LC) const { + return getStateManager().StoreMgr->getLValueVar(VD, LC); +} + +inline Loc ProgramState::getLValue(const CompoundLiteralExpr *literal, + const LocationContext *LC) const { + return getStateManager().StoreMgr->getLValueCompoundLiteral(literal, LC); +} + +inline SVal ProgramState::getLValue(const ObjCIvarDecl *D, SVal Base) const { + return getStateManager().StoreMgr->getLValueIvar(D, Base); +} + +inline SVal ProgramState::getLValue(const FieldDecl *D, SVal Base) const { + return getStateManager().StoreMgr->getLValueField(D, Base); +} + +inline SVal ProgramState::getLValue(const IndirectFieldDecl *D, + SVal Base) const { + StoreManager &SM = *getStateManager().StoreMgr; + for (const auto *I : D->chain()) { + Base = SM.getLValueField(cast<FieldDecl>(I), Base); + } + + return Base; +} + +inline SVal ProgramState::getLValue(QualType ElementType, SVal Idx, SVal Base) const{ + if (Optional<NonLoc> N = Idx.getAs<NonLoc>()) + return getStateManager().StoreMgr->getLValueElement(ElementType, *N, Base); + return UnknownVal(); +} + +inline SVal ProgramState::getSVal(const Stmt *Ex, + const LocationContext *LCtx) const{ + return Env.getSVal(EnvironmentEntry(Ex, LCtx), + *getStateManager().svalBuilder); +} + +inline SVal +ProgramState::getSValAsScalarOrLoc(const Stmt *S, + const LocationContext *LCtx) const { + if (const Expr *Ex = dyn_cast<Expr>(S)) { + QualType T = Ex->getType(); + if (Ex->isGLValue() || Loc::isLocType(T) || + T->isIntegralOrEnumerationType()) + return getSVal(S, LCtx); + } + + return UnknownVal(); +} + +inline SVal ProgramState::getRawSVal(Loc LV, QualType T) const { + return getStateManager().StoreMgr->getBinding(getStore(), LV, T); +} + +inline SVal ProgramState::getSVal(const MemRegion* R) const { + return getStateManager().StoreMgr->getBinding(getStore(), + loc::MemRegionVal(R)); +} + +inline BasicValueFactory &ProgramState::getBasicVals() const { + return getStateManager().getBasicVals(); +} + +inline SymbolManager &ProgramState::getSymbolManager() const { + return getStateManager().getSymbolManager(); +} + +template<typename T> +ProgramStateRef ProgramState::add(typename ProgramStateTrait<T>::key_type K) const { + return getStateManager().add<T>(this, K, get_context<T>()); +} + +template <typename T> +typename ProgramStateTrait<T>::context_type ProgramState::get_context() const { + return getStateManager().get_context<T>(); +} + +template<typename T> +ProgramStateRef ProgramState::remove(typename ProgramStateTrait<T>::key_type K) const { + return getStateManager().remove<T>(this, K, get_context<T>()); +} + +template<typename T> +ProgramStateRef ProgramState::remove(typename ProgramStateTrait<T>::key_type K, + typename ProgramStateTrait<T>::context_type C) const { + return getStateManager().remove<T>(this, K, C); +} + +template <typename T> +ProgramStateRef ProgramState::remove() const { + return getStateManager().remove<T>(this); +} + +template<typename T> +ProgramStateRef ProgramState::set(typename ProgramStateTrait<T>::data_type D) const { + return getStateManager().set<T>(this, D); +} + +template<typename T> +ProgramStateRef ProgramState::set(typename ProgramStateTrait<T>::key_type K, + typename ProgramStateTrait<T>::value_type E) const { + return getStateManager().set<T>(this, K, E, get_context<T>()); +} + +template<typename T> +ProgramStateRef ProgramState::set(typename ProgramStateTrait<T>::key_type K, + typename ProgramStateTrait<T>::value_type E, + typename ProgramStateTrait<T>::context_type C) const { + return getStateManager().set<T>(this, K, E, C); +} + +template <typename CB> +CB ProgramState::scanReachableSymbols(SVal val) const { + CB cb(this); + scanReachableSymbols(val, cb); + return cb; +} + +template <typename CB> +CB ProgramState::scanReachableSymbols(const SVal *beg, const SVal *end) const { + CB cb(this); + scanReachableSymbols(beg, end, cb); + return cb; +} + +template <typename CB> +CB ProgramState::scanReachableSymbols(const MemRegion * const *beg, + const MemRegion * const *end) const { + CB cb(this); + scanReachableSymbols(beg, end, cb); + return cb; +} + +/// \class ScanReachableSymbols +/// A Utility class that allows to visit the reachable symbols using a custom +/// SymbolVisitor. +class ScanReachableSymbols { + typedef llvm::DenseSet<const void*> VisitedItems; + + VisitedItems visited; + ProgramStateRef state; + SymbolVisitor &visitor; +public: + + ScanReachableSymbols(ProgramStateRef st, SymbolVisitor& v) + : state(st), visitor(v) {} + + bool scan(nonloc::LazyCompoundVal val); + bool scan(nonloc::CompoundVal val); + bool scan(SVal val); + bool scan(const MemRegion *R); + bool scan(const SymExpr *sym); +}; + +} // end ento namespace + +} // end clang namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h new file mode 100644 index 0000000..6b4da7d --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h @@ -0,0 +1,245 @@ +//ProgramStateTrait.h - Partial implementations of ProgramStateTrait -*- 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 partial implementations of template specializations of +// the class ProgramStateTrait<>. ProgramStateTrait<> is used by ProgramState +// to implement set/get methods for manipulating a ProgramState's +// generic data map. +// +//===----------------------------------------------------------------------===// + + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATETRAIT_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATETRAIT_H + +#include "llvm/Support/Allocator.h" +#include "llvm/Support/DataTypes.h" + +namespace llvm { + template <typename K, typename D, typename I> class ImmutableMap; + template <typename K, typename I> class ImmutableSet; + template <typename T> class ImmutableList; + template <typename T> class ImmutableListImpl; +} + +namespace clang { + +namespace ento { + template <typename T> struct ProgramStatePartialTrait; + + /// Declares a program state trait for type \p Type called \p Name, and + /// introduce a typedef named \c NameTy. + /// The macro should not be used inside namespaces, or for traits that must + /// be accessible from more than one translation unit. + #define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type) \ + namespace { \ + class Name {}; \ + typedef Type Name ## Ty; \ + } \ + namespace clang { \ + namespace ento { \ + template <> \ + struct ProgramStateTrait<Name> \ + : public ProgramStatePartialTrait<Name ## Ty> { \ + static void *GDMIndex() { static int Index; return &Index; } \ + }; \ + } \ + } + + + // Partial-specialization for ImmutableMap. + + template <typename Key, typename Data, typename Info> + struct ProgramStatePartialTrait< llvm::ImmutableMap<Key,Data,Info> > { + typedef llvm::ImmutableMap<Key,Data,Info> data_type; + typedef typename data_type::Factory& context_type; + typedef Key key_type; + typedef Data value_type; + typedef const value_type* lookup_type; + + static inline data_type MakeData(void *const* p) { + return p ? data_type((typename data_type::TreeTy*) *p) + : data_type(nullptr); + } + static inline void *MakeVoidPtr(data_type B) { + return B.getRoot(); + } + static lookup_type Lookup(data_type B, key_type K) { + return B.lookup(K); + } + static data_type Set(data_type B, key_type K, value_type E,context_type F){ + return F.add(B, K, E); + } + + static data_type Remove(data_type B, key_type K, context_type F) { + return F.remove(B, K); + } + + static inline context_type MakeContext(void *p) { + return *((typename data_type::Factory*) p); + } + + static void *CreateContext(llvm::BumpPtrAllocator& Alloc) { + return new typename data_type::Factory(Alloc); + } + + static void DeleteContext(void *Ctx) { + delete (typename data_type::Factory*) Ctx; + } + }; + + /// Helper for registering a map trait. + /// + /// If the map type were written directly in the invocation of + /// REGISTER_TRAIT_WITH_PROGRAMSTATE, the comma in the template arguments + /// would be treated as a macro argument separator, which is wrong. + /// This allows the user to specify a map type in a way that the preprocessor + /// can deal with. + #define CLANG_ENTO_PROGRAMSTATE_MAP(Key, Value) llvm::ImmutableMap<Key, Value> + + + // Partial-specialization for ImmutableSet. + + template <typename Key, typename Info> + struct ProgramStatePartialTrait< llvm::ImmutableSet<Key,Info> > { + typedef llvm::ImmutableSet<Key,Info> data_type; + typedef typename data_type::Factory& context_type; + typedef Key key_type; + + static inline data_type MakeData(void *const* p) { + return p ? data_type((typename data_type::TreeTy*) *p) + : data_type(nullptr); + } + + static inline void *MakeVoidPtr(data_type B) { + return B.getRoot(); + } + + static data_type Add(data_type B, key_type K, context_type F) { + return F.add(B, K); + } + + static data_type Remove(data_type B, key_type K, context_type F) { + return F.remove(B, K); + } + + static bool Contains(data_type B, key_type K) { + return B.contains(K); + } + + static inline context_type MakeContext(void *p) { + return *((typename data_type::Factory*) p); + } + + static void *CreateContext(llvm::BumpPtrAllocator& Alloc) { + return new typename data_type::Factory(Alloc); + } + + static void DeleteContext(void *Ctx) { + delete (typename data_type::Factory*) Ctx; + } + }; + + + // Partial-specialization for ImmutableList. + + template <typename T> + struct ProgramStatePartialTrait< llvm::ImmutableList<T> > { + typedef llvm::ImmutableList<T> data_type; + typedef T key_type; + typedef typename data_type::Factory& context_type; + + static data_type Add(data_type L, key_type K, context_type F) { + return F.add(K, L); + } + + static bool Contains(data_type L, key_type K) { + return L.contains(K); + } + + static inline data_type MakeData(void *const* p) { + return p ? data_type((const llvm::ImmutableListImpl<T>*) *p) + : data_type(nullptr); + } + + static inline void *MakeVoidPtr(data_type D) { + return const_cast<llvm::ImmutableListImpl<T> *>(D.getInternalPointer()); + } + + static inline context_type MakeContext(void *p) { + return *((typename data_type::Factory*) p); + } + + static void *CreateContext(llvm::BumpPtrAllocator& Alloc) { + return new typename data_type::Factory(Alloc); + } + + static void DeleteContext(void *Ctx) { + delete (typename data_type::Factory*) Ctx; + } + }; + + + // Partial specialization for bool. + template <> struct ProgramStatePartialTrait<bool> { + typedef bool data_type; + + static inline data_type MakeData(void *const* p) { + return p ? (data_type) (uintptr_t) *p + : data_type(); + } + static inline void *MakeVoidPtr(data_type d) { + return (void*) (uintptr_t) d; + } + }; + + // Partial specialization for unsigned. + template <> struct ProgramStatePartialTrait<unsigned> { + typedef unsigned data_type; + + static inline data_type MakeData(void *const* p) { + return p ? (data_type) (uintptr_t) *p + : data_type(); + } + static inline void *MakeVoidPtr(data_type d) { + return (void*) (uintptr_t) d; + } + }; + + // Partial specialization for void*. + template <> struct ProgramStatePartialTrait<void*> { + typedef void *data_type; + + static inline data_type MakeData(void *const* p) { + return p ? *p + : data_type(); + } + static inline void *MakeVoidPtr(data_type d) { + return d; + } + }; + + // Partial specialization for const void *. + template <> struct ProgramStatePartialTrait<const void *> { + typedef const void *data_type; + + static inline data_type MakeData(void * const *p) { + return p ? *p : data_type(); + } + + static inline void *MakeVoidPtr(data_type d) { + return const_cast<void *>(d); + } + }; + +} // end ento namespace + +} // end clang namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h new file mode 100644 index 0000000..415bb77 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h @@ -0,0 +1,43 @@ +//== ProgramState_Fwd.h - Incomplete declarations of ProgramState -*- 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_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATE_FWD_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATE_FWD_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" + +namespace clang { +namespace ento { + class ProgramState; + class ProgramStateManager; + void ProgramStateRetain(const ProgramState *state); + void ProgramStateRelease(const ProgramState *state); +} +} + +namespace llvm { + template <> struct IntrusiveRefCntPtrInfo<const clang::ento::ProgramState> { + static void retain(const clang::ento::ProgramState *state) { + clang::ento::ProgramStateRetain(state); + } + static void release(const clang::ento::ProgramState *state) { + clang::ento::ProgramStateRelease(state); + } + }; +} + +namespace clang { +namespace ento { + typedef IntrusiveRefCntPtr<const ProgramState> ProgramStateRef; +} +} + +#endif + diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h new file mode 100644 index 0000000..a68d341 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h @@ -0,0 +1,333 @@ +// SValBuilder.h - Construction of SVals from evaluating expressions -*- 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 SValBuilder, a class that defines the interface for +// "symbolical evaluators" which construct an SVal from an expression. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALBUILDER_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALBUILDER_H + +#include "clang/AST/ASTContext.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprObjC.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" + +namespace clang { + +class CXXBoolLiteralExpr; + +namespace ento { + +class SValBuilder { + virtual void anchor(); +protected: + ASTContext &Context; + + /// Manager of APSInt values. + BasicValueFactory BasicVals; + + /// Manages the creation of symbols. + SymbolManager SymMgr; + + /// Manages the creation of memory regions. + MemRegionManager MemMgr; + + ProgramStateManager &StateMgr; + + /// The scalar type to use for array indices. + const QualType ArrayIndexTy; + + /// The width of the scalar type used for array indices. + const unsigned ArrayIndexWidth; + + virtual SVal evalCastFromNonLoc(NonLoc val, QualType castTy) = 0; + virtual SVal evalCastFromLoc(Loc val, QualType castTy) = 0; + +public: + // FIXME: Make these protected again once RegionStoreManager correctly + // handles loads from different bound value types. + virtual SVal dispatchCast(SVal val, QualType castTy) = 0; + +public: + SValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context, + ProgramStateManager &stateMgr) + : Context(context), BasicVals(context, alloc), + SymMgr(context, BasicVals, alloc), + MemMgr(context, alloc), + StateMgr(stateMgr), + ArrayIndexTy(context.IntTy), + ArrayIndexWidth(context.getTypeSize(ArrayIndexTy)) {} + + virtual ~SValBuilder() {} + + bool haveSameType(const SymExpr *Sym1, const SymExpr *Sym2) { + return haveSameType(Sym1->getType(), Sym2->getType()); + } + + bool haveSameType(QualType Ty1, QualType Ty2) { + // FIXME: Remove the second disjunct when we support symbolic + // truncation/extension. + return (Context.getCanonicalType(Ty1) == Context.getCanonicalType(Ty2) || + (Ty1->isIntegralOrEnumerationType() && + Ty2->isIntegralOrEnumerationType())); + } + + SVal evalCast(SVal val, QualType castTy, QualType originalType); + + virtual SVal evalMinus(NonLoc val) = 0; + + virtual SVal evalComplement(NonLoc val) = 0; + + /// Create a new value which represents a binary expression with two non- + /// location operands. + virtual SVal evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op, + NonLoc lhs, NonLoc rhs, QualType resultTy) = 0; + + /// Create a new value which represents a binary expression with two memory + /// location operands. + virtual SVal evalBinOpLL(ProgramStateRef state, BinaryOperator::Opcode op, + Loc lhs, Loc rhs, QualType resultTy) = 0; + + /// Create a new value which represents a binary expression with a memory + /// location and non-location operands. For example, this would be used to + /// evaluate a pointer arithmetic operation. + virtual SVal evalBinOpLN(ProgramStateRef state, BinaryOperator::Opcode op, + Loc lhs, NonLoc rhs, QualType resultTy) = 0; + + /// Evaluates a given SVal. If the SVal has only one possible (integer) value, + /// that value is returned. Otherwise, returns NULL. + virtual const llvm::APSInt *getKnownValue(ProgramStateRef state, SVal val) = 0; + + /// Constructs a symbolic expression for two non-location values. + SVal makeSymExprValNN(ProgramStateRef state, BinaryOperator::Opcode op, + NonLoc lhs, NonLoc rhs, QualType resultTy); + + SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, + SVal lhs, SVal rhs, QualType type); + + DefinedOrUnknownSVal evalEQ(ProgramStateRef state, DefinedOrUnknownSVal lhs, + DefinedOrUnknownSVal rhs); + + ASTContext &getContext() { return Context; } + const ASTContext &getContext() const { return Context; } + + ProgramStateManager &getStateManager() { return StateMgr; } + + QualType getConditionType() const { + return Context.getLangOpts().CPlusPlus ? Context.BoolTy : Context.IntTy; + } + + QualType getArrayIndexType() const { + return ArrayIndexTy; + } + + BasicValueFactory &getBasicValueFactory() { return BasicVals; } + const BasicValueFactory &getBasicValueFactory() const { return BasicVals; } + + SymbolManager &getSymbolManager() { return SymMgr; } + const SymbolManager &getSymbolManager() const { return SymMgr; } + + MemRegionManager &getRegionManager() { return MemMgr; } + const MemRegionManager &getRegionManager() const { return MemMgr; } + + // Forwarding methods to SymbolManager. + + const SymbolConjured* conjureSymbol(const Stmt *stmt, + const LocationContext *LCtx, + QualType type, + unsigned visitCount, + const void *symbolTag = nullptr) { + return SymMgr.conjureSymbol(stmt, LCtx, type, visitCount, symbolTag); + } + + const SymbolConjured* conjureSymbol(const Expr *expr, + const LocationContext *LCtx, + unsigned visitCount, + const void *symbolTag = nullptr) { + return SymMgr.conjureSymbol(expr, LCtx, visitCount, symbolTag); + } + + /// Construct an SVal representing '0' for the specified type. + DefinedOrUnknownSVal makeZeroVal(QualType type); + + /// Make a unique symbol for value of region. + DefinedOrUnknownSVal getRegionValueSymbolVal(const TypedValueRegion *region); + + /// \brief Create a new symbol with a unique 'name'. + /// + /// We resort to conjured symbols when we cannot construct a derived symbol. + /// The advantage of symbols derived/built from other symbols is that we + /// preserve the relation between related(or even equivalent) expressions, so + /// conjured symbols should be used sparingly. + DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag, + const Expr *expr, + const LocationContext *LCtx, + unsigned count); + DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag, + const Expr *expr, + const LocationContext *LCtx, + QualType type, + unsigned count); + + DefinedOrUnknownSVal conjureSymbolVal(const Stmt *stmt, + const LocationContext *LCtx, + QualType type, + unsigned visitCount); + /// \brief Conjure a symbol representing heap allocated memory region. + /// + /// Note, the expression should represent a location. + DefinedOrUnknownSVal getConjuredHeapSymbolVal(const Expr *E, + const LocationContext *LCtx, + unsigned Count); + + DefinedOrUnknownSVal getDerivedRegionValueSymbolVal( + SymbolRef parentSymbol, const TypedValueRegion *region); + + DefinedSVal getMetadataSymbolVal( + const void *symbolTag, const MemRegion *region, + const Expr *expr, QualType type, unsigned count); + + DefinedSVal getFunctionPointer(const FunctionDecl *func); + + DefinedSVal getBlockPointer(const BlockDecl *block, CanQualType locTy, + const LocationContext *locContext, + unsigned blockCount); + + /// Returns the value of \p E, if it can be determined in a non-path-sensitive + /// manner. + /// + /// If \p E is not a constant or cannot be modeled, returns \c None. + Optional<SVal> getConstantVal(const Expr *E); + + NonLoc makeCompoundVal(QualType type, llvm::ImmutableList<SVal> vals) { + return nonloc::CompoundVal(BasicVals.getCompoundValData(type, vals)); + } + + NonLoc makeLazyCompoundVal(const StoreRef &store, + const TypedValueRegion *region) { + return nonloc::LazyCompoundVal( + BasicVals.getLazyCompoundValData(store, region)); + } + + NonLoc makeZeroArrayIndex() { + return nonloc::ConcreteInt(BasicVals.getValue(0, ArrayIndexTy)); + } + + NonLoc makeArrayIndex(uint64_t idx) { + return nonloc::ConcreteInt(BasicVals.getValue(idx, ArrayIndexTy)); + } + + SVal convertToArrayIndex(SVal val); + + nonloc::ConcreteInt makeIntVal(const IntegerLiteral* integer) { + return nonloc::ConcreteInt( + BasicVals.getValue(integer->getValue(), + integer->getType()->isUnsignedIntegerOrEnumerationType())); + } + + nonloc::ConcreteInt makeBoolVal(const ObjCBoolLiteralExpr *boolean) { + return makeTruthVal(boolean->getValue(), boolean->getType()); + } + + nonloc::ConcreteInt makeBoolVal(const CXXBoolLiteralExpr *boolean); + + nonloc::ConcreteInt makeIntVal(const llvm::APSInt& integer) { + return nonloc::ConcreteInt(BasicVals.getValue(integer)); + } + + loc::ConcreteInt makeIntLocVal(const llvm::APSInt &integer) { + return loc::ConcreteInt(BasicVals.getValue(integer)); + } + + NonLoc makeIntVal(const llvm::APInt& integer, bool isUnsigned) { + return nonloc::ConcreteInt(BasicVals.getValue(integer, isUnsigned)); + } + + DefinedSVal makeIntVal(uint64_t integer, QualType type) { + if (Loc::isLocType(type)) + return loc::ConcreteInt(BasicVals.getValue(integer, type)); + + return nonloc::ConcreteInt(BasicVals.getValue(integer, type)); + } + + NonLoc makeIntVal(uint64_t integer, bool isUnsigned) { + return nonloc::ConcreteInt(BasicVals.getIntValue(integer, isUnsigned)); + } + + NonLoc makeIntValWithPtrWidth(uint64_t integer, bool isUnsigned) { + return nonloc::ConcreteInt( + BasicVals.getIntWithPtrWidth(integer, isUnsigned)); + } + + NonLoc makeLocAsInteger(Loc loc, unsigned bits) { + return nonloc::LocAsInteger(BasicVals.getPersistentSValWithData(loc, bits)); + } + + NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op, + const llvm::APSInt& rhs, QualType type); + + NonLoc makeNonLoc(const llvm::APSInt& rhs, BinaryOperator::Opcode op, + const SymExpr *lhs, QualType type); + + NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op, + const SymExpr *rhs, QualType type); + + /// \brief Create a NonLoc value for cast. + NonLoc makeNonLoc(const SymExpr *operand, QualType fromTy, QualType toTy); + + nonloc::ConcreteInt makeTruthVal(bool b, QualType type) { + return nonloc::ConcreteInt(BasicVals.getTruthValue(b, type)); + } + + nonloc::ConcreteInt makeTruthVal(bool b) { + return nonloc::ConcreteInt(BasicVals.getTruthValue(b)); + } + + Loc makeNull() { + return loc::ConcreteInt(BasicVals.getZeroWithPtrWidth()); + } + + Loc makeLoc(SymbolRef sym) { + return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym)); + } + + Loc makeLoc(const MemRegion* region) { + return loc::MemRegionVal(region); + } + + Loc makeLoc(const AddrLabelExpr *expr) { + return loc::GotoLabel(expr->getLabel()); + } + + Loc makeLoc(const llvm::APSInt& integer) { + return loc::ConcreteInt(BasicVals.getValue(integer)); + } + + /// Return a memory region for the 'this' object reference. + loc::MemRegionVal getCXXThis(const CXXMethodDecl *D, + const StackFrameContext *SFC); + + /// Return a memory region for the 'this' object reference. + loc::MemRegionVal getCXXThis(const CXXRecordDecl *D, + const StackFrameContext *SFC); +}; + +SValBuilder* createSimpleSValBuilder(llvm::BumpPtrAllocator &alloc, + ASTContext &context, + ProgramStateManager &stateMgr); + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h new file mode 100644 index 0000000..642e11a --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h @@ -0,0 +1,574 @@ +//== SVals.h - Abstract Values for Static Analysis ---------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines SVal, Loc, and NonLoc, classes that represent +// abstract r-values for use with path-sensitive value tracking. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALS_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALS_H + +#include "clang/Basic/LLVM.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" +#include "llvm/ADT/ImmutableList.h" + +//==------------------------------------------------------------------------==// +// Base SVal types. +//==------------------------------------------------------------------------==// + +namespace clang { + +namespace ento { + +class CompoundValData; +class LazyCompoundValData; +class ProgramState; +class BasicValueFactory; +class MemRegion; +class TypedValueRegion; +class MemRegionManager; +class ProgramStateManager; +class SValBuilder; + +/// SVal - This represents a symbolic expression, which can be either +/// an L-value or an R-value. +/// +class SVal { +public: + enum BaseKind { + // The enumerators must be representable using 2 bits. + UndefinedKind = 0, // for subclass UndefinedVal (an uninitialized value) + UnknownKind = 1, // for subclass UnknownVal (a void value) + LocKind = 2, // for subclass Loc (an L-value) + NonLocKind = 3 // for subclass NonLoc (an R-value that's not + // an L-value) + }; + enum { BaseBits = 2, BaseMask = 0x3 }; + +protected: + const void *Data; + + /// The lowest 2 bits are a BaseKind (0 -- 3). + /// The higher bits are an unsigned "kind" value. + unsigned Kind; + + explicit SVal(const void *d, bool isLoc, unsigned ValKind) + : Data(d), Kind((isLoc ? LocKind : NonLocKind) | (ValKind << BaseBits)) {} + + explicit SVal(BaseKind k, const void *D = nullptr) + : Data(D), Kind(k) {} + +public: + explicit SVal() : Data(nullptr), Kind(0) {} + + /// \brief Convert to the specified SVal type, asserting that this SVal is of + /// the desired type. + template<typename T> + T castAs() const { + assert(T::isKind(*this)); + T t; + SVal& sv = t; + sv = *this; + return t; + } + + /// \brief Convert to the specified SVal type, returning None if this SVal is + /// not of the desired type. + template<typename T> + Optional<T> getAs() const { + if (!T::isKind(*this)) + return None; + T t; + SVal& sv = t; + sv = *this; + return t; + } + + /// BufferTy - A temporary buffer to hold a set of SVals. + typedef SmallVector<SVal,5> BufferTy; + + inline unsigned getRawKind() const { return Kind; } + inline BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); } + inline unsigned getSubKind() const { return (Kind & ~BaseMask) >> BaseBits; } + + // This method is required for using SVal in a FoldingSetNode. It + // extracts a unique signature for this SVal object. + inline void Profile(llvm::FoldingSetNodeID& ID) const { + ID.AddInteger((unsigned) getRawKind()); + ID.AddPointer(Data); + } + + inline bool operator==(const SVal& R) const { + return getRawKind() == R.getRawKind() && Data == R.Data; + } + + inline bool operator!=(const SVal& R) const { + return !(*this == R); + } + + inline bool isUnknown() const { + return getRawKind() == UnknownKind; + } + + inline bool isUndef() const { + return getRawKind() == UndefinedKind; + } + + inline bool isUnknownOrUndef() const { + return getRawKind() <= UnknownKind; + } + + inline bool isValid() const { + return getRawKind() > UnknownKind; + } + + bool isConstant() const; + + bool isConstant(int I) const; + + bool isZeroConstant() const; + + /// hasConjuredSymbol - If this SVal wraps a conjured symbol, return true; + bool hasConjuredSymbol() const; + + /// getAsFunctionDecl - If this SVal is a MemRegionVal and wraps a + /// CodeTextRegion wrapping a FunctionDecl, return that FunctionDecl. + /// Otherwise return 0. + const FunctionDecl *getAsFunctionDecl() const; + + /// \brief If this SVal is a location and wraps a symbol, return that + /// SymbolRef. Otherwise return 0. + /// + /// Casts are ignored during lookup. + /// \param IncludeBaseRegions The boolean that controls whether the search + /// should continue to the base regions if the region is not symbolic. + SymbolRef getAsLocSymbol(bool IncludeBaseRegions = false) const; + + /// Get the symbol in the SVal or its base region. + SymbolRef getLocSymbolInBase() const; + + /// \brief If this SVal wraps a symbol return that SymbolRef. + /// Otherwise, return 0. + /// + /// Casts are ignored during lookup. + /// \param IncludeBaseRegions The boolean that controls whether the search + /// should continue to the base regions if the region is not symbolic. + SymbolRef getAsSymbol(bool IncludeBaseRegions = false) const; + + /// getAsSymbolicExpression - If this Sval wraps a symbolic expression then + /// return that expression. Otherwise return NULL. + const SymExpr *getAsSymbolicExpression() const; + + const SymExpr* getAsSymExpr() const; + + const MemRegion *getAsRegion() const; + + void dumpToStream(raw_ostream &OS) const; + void dump() const; + + SymExpr::symbol_iterator symbol_begin() const { + const SymExpr *SE = getAsSymbolicExpression(); + if (SE) + return SE->symbol_begin(); + else + return SymExpr::symbol_iterator(); + } + + SymExpr::symbol_iterator symbol_end() const { + return SymExpr::symbol_end(); + } +}; + + +class UndefinedVal : public SVal { +public: + UndefinedVal() : SVal(UndefinedKind) {} + +private: + friend class SVal; + static bool isKind(const SVal& V) { + return V.getBaseKind() == UndefinedKind; + } +}; + +class DefinedOrUnknownSVal : public SVal { +private: + // We want calling these methods to be a compiler error since they are + // tautologically false. + bool isUndef() const = delete; + bool isValid() const = delete; + +protected: + DefinedOrUnknownSVal() {} + explicit DefinedOrUnknownSVal(const void *d, bool isLoc, unsigned ValKind) + : SVal(d, isLoc, ValKind) {} + + explicit DefinedOrUnknownSVal(BaseKind k, void *D = nullptr) + : SVal(k, D) {} + +private: + friend class SVal; + static bool isKind(const SVal& V) { + return !V.isUndef(); + } +}; + +class UnknownVal : public DefinedOrUnknownSVal { +public: + explicit UnknownVal() : DefinedOrUnknownSVal(UnknownKind) {} + +private: + friend class SVal; + static bool isKind(const SVal &V) { + return V.getBaseKind() == UnknownKind; + } +}; + +class DefinedSVal : public DefinedOrUnknownSVal { +private: + // We want calling these methods to be a compiler error since they are + // tautologically true/false. + bool isUnknown() const = delete; + bool isUnknownOrUndef() const = delete; + bool isValid() const = delete; +protected: + DefinedSVal() {} + explicit DefinedSVal(const void *d, bool isLoc, unsigned ValKind) + : DefinedOrUnknownSVal(d, isLoc, ValKind) {} +private: + friend class SVal; + static bool isKind(const SVal& V) { + return !V.isUnknownOrUndef(); + } +}; + + +/// \brief Represents an SVal that is guaranteed to not be UnknownVal. +class KnownSVal : public SVal { + KnownSVal() {} + friend class SVal; + static bool isKind(const SVal &V) { + return !V.isUnknown(); + } +public: + KnownSVal(const DefinedSVal &V) : SVal(V) {} + KnownSVal(const UndefinedVal &V) : SVal(V) {} +}; + +class NonLoc : public DefinedSVal { +protected: + NonLoc() {} + explicit NonLoc(unsigned SubKind, const void *d) + : DefinedSVal(d, false, SubKind) {} + +public: + void dumpToStream(raw_ostream &Out) const; + +private: + friend class SVal; + static bool isKind(const SVal& V) { + return V.getBaseKind() == NonLocKind; + } +}; + +class Loc : public DefinedSVal { +protected: + Loc() {} + explicit Loc(unsigned SubKind, const void *D) + : DefinedSVal(const_cast<void*>(D), true, SubKind) {} + +public: + void dumpToStream(raw_ostream &Out) const; + + static inline bool isLocType(QualType T) { + return T->isAnyPointerType() || T->isBlockPointerType() || + T->isReferenceType() || T->isNullPtrType(); + } + +private: + friend class SVal; + static bool isKind(const SVal& V) { + return V.getBaseKind() == LocKind; + } +}; + +//==------------------------------------------------------------------------==// +// Subclasses of NonLoc. +//==------------------------------------------------------------------------==// + +namespace nonloc { + +enum Kind { ConcreteIntKind, SymbolValKind, + LocAsIntegerKind, CompoundValKind, LazyCompoundValKind }; + +/// \brief Represents symbolic expression. +class SymbolVal : public NonLoc { +public: + SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) {} + + SymbolRef getSymbol() const { + return (const SymExpr*) Data; + } + + bool isExpression() const { + return !isa<SymbolData>(getSymbol()); + } + +private: + friend class SVal; + SymbolVal() {} + static bool isKind(const SVal& V) { + return V.getBaseKind() == NonLocKind && + V.getSubKind() == SymbolValKind; + } + + static bool isKind(const NonLoc& V) { + return V.getSubKind() == SymbolValKind; + } +}; + +/// \brief Value representing integer constant. +class ConcreteInt : public NonLoc { +public: + explicit ConcreteInt(const llvm::APSInt& V) : NonLoc(ConcreteIntKind, &V) {} + + const llvm::APSInt& getValue() const { + return *static_cast<const llvm::APSInt*>(Data); + } + + // Transfer functions for binary/unary operations on ConcreteInts. + SVal evalBinOp(SValBuilder &svalBuilder, BinaryOperator::Opcode Op, + const ConcreteInt& R) const; + + ConcreteInt evalComplement(SValBuilder &svalBuilder) const; + + ConcreteInt evalMinus(SValBuilder &svalBuilder) const; + +private: + friend class SVal; + ConcreteInt() {} + static bool isKind(const SVal& V) { + return V.getBaseKind() == NonLocKind && + V.getSubKind() == ConcreteIntKind; + } + + static bool isKind(const NonLoc& V) { + return V.getSubKind() == ConcreteIntKind; + } +}; + +class LocAsInteger : public NonLoc { + friend class ento::SValBuilder; + + explicit LocAsInteger(const std::pair<SVal, uintptr_t> &data) + : NonLoc(LocAsIntegerKind, &data) { + assert (data.first.getAs<Loc>()); + } + +public: + + Loc getLoc() const { + const std::pair<SVal, uintptr_t> *D = + static_cast<const std::pair<SVal, uintptr_t> *>(Data); + return D->first.castAs<Loc>(); + } + + Loc getPersistentLoc() const { + const std::pair<SVal, uintptr_t> *D = + static_cast<const std::pair<SVal, uintptr_t> *>(Data); + const SVal& V = D->first; + return V.castAs<Loc>(); + } + + unsigned getNumBits() const { + const std::pair<SVal, uintptr_t> *D = + static_cast<const std::pair<SVal, uintptr_t> *>(Data); + return D->second; + } + +private: + friend class SVal; + LocAsInteger() {} + static bool isKind(const SVal& V) { + return V.getBaseKind() == NonLocKind && + V.getSubKind() == LocAsIntegerKind; + } + + static bool isKind(const NonLoc& V) { + return V.getSubKind() == LocAsIntegerKind; + } +}; + +class CompoundVal : public NonLoc { + friend class ento::SValBuilder; + + explicit CompoundVal(const CompoundValData* D) : NonLoc(CompoundValKind, D) {} + +public: + const CompoundValData* getValue() const { + return static_cast<const CompoundValData*>(Data); + } + + typedef llvm::ImmutableList<SVal>::iterator iterator; + iterator begin() const; + iterator end() const; + +private: + friend class SVal; + CompoundVal() {} + static bool isKind(const SVal& V) { + return V.getBaseKind() == NonLocKind && V.getSubKind() == CompoundValKind; + } + + static bool isKind(const NonLoc& V) { + return V.getSubKind() == CompoundValKind; + } +}; + +class LazyCompoundVal : public NonLoc { + friend class ento::SValBuilder; + + explicit LazyCompoundVal(const LazyCompoundValData *D) + : NonLoc(LazyCompoundValKind, D) {} +public: + const LazyCompoundValData *getCVData() const { + return static_cast<const LazyCompoundValData*>(Data); + } + const void *getStore() const; + const TypedValueRegion *getRegion() const; + +private: + friend class SVal; + LazyCompoundVal() {} + static bool isKind(const SVal& V) { + return V.getBaseKind() == NonLocKind && + V.getSubKind() == LazyCompoundValKind; + } + static bool isKind(const NonLoc& V) { + return V.getSubKind() == LazyCompoundValKind; + } +}; + +} // end namespace ento::nonloc + +//==------------------------------------------------------------------------==// +// Subclasses of Loc. +//==------------------------------------------------------------------------==// + +namespace loc { + +enum Kind { GotoLabelKind, MemRegionKind, ConcreteIntKind }; + +class GotoLabel : public Loc { +public: + explicit GotoLabel(LabelDecl *Label) : Loc(GotoLabelKind, Label) {} + + const LabelDecl *getLabel() const { + return static_cast<const LabelDecl*>(Data); + } + +private: + friend class SVal; + GotoLabel() {} + static bool isKind(const SVal& V) { + return V.getBaseKind() == LocKind && V.getSubKind() == GotoLabelKind; + } + + static bool isKind(const Loc& V) { + return V.getSubKind() == GotoLabelKind; + } +}; + + +class MemRegionVal : public Loc { +public: + explicit MemRegionVal(const MemRegion* r) : Loc(MemRegionKind, r) {} + + /// \brief Get the underlining region. + const MemRegion* getRegion() const { + return static_cast<const MemRegion*>(Data); + } + + /// \brief Get the underlining region and strip casts. + const MemRegion* stripCasts(bool StripBaseCasts = true) const; + + template <typename REGION> + const REGION* getRegionAs() const { + return dyn_cast<REGION>(getRegion()); + } + + inline bool operator==(const MemRegionVal& R) const { + return getRegion() == R.getRegion(); + } + + inline bool operator!=(const MemRegionVal& R) const { + return getRegion() != R.getRegion(); + } + +private: + friend class SVal; + MemRegionVal() {} + static bool isKind(const SVal& V) { + return V.getBaseKind() == LocKind && + V.getSubKind() == MemRegionKind; + } + + static bool isKind(const Loc& V) { + return V.getSubKind() == MemRegionKind; + } +}; + +class ConcreteInt : public Loc { +public: + explicit ConcreteInt(const llvm::APSInt& V) : Loc(ConcreteIntKind, &V) {} + + const llvm::APSInt& getValue() const { + return *static_cast<const llvm::APSInt*>(Data); + } + + // Transfer functions for binary/unary operations on ConcreteInts. + SVal evalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op, + const ConcreteInt& R) const; + +private: + friend class SVal; + ConcreteInt() {} + static bool isKind(const SVal& V) { + return V.getBaseKind() == LocKind && + V.getSubKind() == ConcreteIntKind; + } + + static bool isKind(const Loc& V) { + return V.getSubKind() == ConcreteIntKind; + } +}; + +} // end ento::loc namespace + +} // end ento namespace + +} // end clang namespace + +namespace llvm { +static inline raw_ostream &operator<<(raw_ostream &os, + clang::ento::SVal V) { + V.dumpToStream(os); + return os; +} + +template <typename T> struct isPodLike; +template <> struct isPodLike<clang::ento::SVal> { + static const bool value = true; +}; + +} // end llvm namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h new file mode 100644 index 0000000..a03b630 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h @@ -0,0 +1,288 @@ +//== Store.h - Interface for maps from Locations to Values ------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defined the types Store and StoreManager. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_STORE_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_STORE_H + +#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/Optional.h" + +namespace clang { + +class Stmt; +class Expr; +class ObjCIvarDecl; +class CXXBasePath; +class StackFrameContext; + +namespace ento { + +class CallEvent; +class ProgramState; +class ProgramStateManager; +class ScanReachableSymbols; + +typedef llvm::DenseSet<SymbolRef> InvalidatedSymbols; + +class StoreManager { +protected: + SValBuilder &svalBuilder; + ProgramStateManager &StateMgr; + + /// MRMgr - Manages region objects associated with this StoreManager. + MemRegionManager &MRMgr; + ASTContext &Ctx; + + StoreManager(ProgramStateManager &stateMgr); + +public: + virtual ~StoreManager() {} + + /// Return the value bound to specified location in a given state. + /// \param[in] store The analysis state. + /// \param[in] loc The symbolic memory location. + /// \param[in] T An optional type that provides a hint indicating the + /// expected type of the returned value. This is used if the value is + /// lazily computed. + /// \return The value bound to the location \c loc. + virtual SVal getBinding(Store store, Loc loc, QualType T = QualType()) = 0; + + /// Return a state with the specified value bound to the given location. + /// \param[in] store The analysis state. + /// \param[in] loc The symbolic memory location. + /// \param[in] val The value to bind to location \c loc. + /// \return A pointer to a ProgramState object that contains the same + /// bindings as \c state with the addition of having the value specified + /// by \c val bound to the location given for \c loc. + virtual StoreRef Bind(Store store, Loc loc, SVal val) = 0; + + virtual StoreRef BindDefault(Store store, const MemRegion *R, SVal V); + + /// \brief Create a new store with the specified binding removed. + /// \param ST the original store, that is the basis for the new store. + /// \param L the location whose binding should be removed. + virtual StoreRef killBinding(Store ST, Loc L) = 0; + + /// getInitialStore - Returns the initial "empty" store representing the + /// value bindings upon entry to an analyzed function. + virtual StoreRef getInitialStore(const LocationContext *InitLoc) = 0; + + /// getRegionManager - Returns the internal RegionManager object that is + /// used to query and manipulate MemRegion objects. + MemRegionManager& getRegionManager() { return MRMgr; } + + virtual Loc getLValueVar(const VarDecl *VD, const LocationContext *LC) { + return svalBuilder.makeLoc(MRMgr.getVarRegion(VD, LC)); + } + + Loc getLValueCompoundLiteral(const CompoundLiteralExpr *CL, + const LocationContext *LC) { + return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)); + } + + virtual SVal getLValueIvar(const ObjCIvarDecl *decl, SVal base); + + virtual SVal getLValueField(const FieldDecl *D, SVal Base) { + return getLValueFieldOrIvar(D, Base); + } + + virtual SVal getLValueElement(QualType elementType, NonLoc offset, SVal Base); + + // FIXME: This should soon be eliminated altogether; clients should deal with + // region extents directly. + virtual DefinedOrUnknownSVal getSizeInElements(ProgramStateRef state, + const MemRegion *region, + QualType EleTy) { + return UnknownVal(); + } + + /// ArrayToPointer - Used by ExprEngine::VistCast to handle implicit + /// conversions between arrays and pointers. + virtual SVal ArrayToPointer(Loc Array, QualType ElementTy) = 0; + + /// Evaluates a chain of derived-to-base casts through the path specified in + /// \p Cast. + SVal evalDerivedToBase(SVal Derived, const CastExpr *Cast); + + /// Evaluates a chain of derived-to-base casts through the specified path. + SVal evalDerivedToBase(SVal Derived, const CXXBasePath &CastPath); + + /// Evaluates a derived-to-base cast through a single level of derivation. + SVal evalDerivedToBase(SVal Derived, QualType DerivedPtrType, + bool IsVirtual); + + /// \brief Evaluates C++ dynamic_cast cast. + /// The callback may result in the following 3 scenarios: + /// - Successful cast (ex: derived is subclass of base). + /// - Failed cast (ex: derived is definitely not a subclass of base). + /// - We don't know (base is a symbolic region and we don't have + /// enough info to determine if the cast will succeed at run time). + /// The function returns an SVal representing the derived class; it's + /// valid only if Failed flag is set to false. + SVal evalDynamicCast(SVal Base, QualType DerivedPtrType, bool &Failed); + + const ElementRegion *GetElementZeroRegion(const MemRegion *R, QualType T); + + /// castRegion - Used by ExprEngine::VisitCast to handle casts from + /// a MemRegion* to a specific location type. 'R' is the region being + /// casted and 'CastToTy' the result type of the cast. + const MemRegion *castRegion(const MemRegion *region, QualType CastToTy); + + virtual StoreRef removeDeadBindings(Store store, const StackFrameContext *LCtx, + SymbolReaper& SymReaper) = 0; + + virtual bool includedInBindings(Store store, + const MemRegion *region) const = 0; + + /// If the StoreManager supports it, increment the reference count of + /// the specified Store object. + virtual void incrementReferenceCount(Store store) {} + + /// If the StoreManager supports it, decrement the reference count of + /// the specified Store object. If the reference count hits 0, the memory + /// associated with the object is recycled. + virtual void decrementReferenceCount(Store store) {} + + typedef SmallVector<const MemRegion *, 8> InvalidatedRegions; + + /// invalidateRegions - Clears out the specified regions from the store, + /// marking their values as unknown. Depending on the store, this may also + /// invalidate additional regions that may have changed based on accessing + /// the given regions. Optionally, invalidates non-static globals as well. + /// \param[in] store The initial store + /// \param[in] Values The values to invalidate. + /// \param[in] E The current statement being evaluated. Used to conjure + /// symbols to mark the values of invalidated regions. + /// \param[in] Count The current block count. Used to conjure + /// symbols to mark the values of invalidated regions. + /// \param[in] Call The call expression which will be used to determine which + /// globals should get invalidated. + /// \param[in,out] IS A set to fill with any symbols that are no longer + /// accessible. Pass \c NULL if this information will not be used. + /// \param[in] ITraits Information about invalidation for a particular + /// region/symbol. + /// \param[in,out] InvalidatedTopLevel A vector to fill with regions + //// explicitly being invalidated. Pass \c NULL if this + /// information will not be used. + /// \param[in,out] Invalidated A vector to fill with any regions being + /// invalidated. This should include any regions explicitly invalidated + /// even if they do not currently have bindings. Pass \c NULL if this + /// information will not be used. + virtual StoreRef invalidateRegions(Store store, + ArrayRef<SVal> Values, + const Expr *E, unsigned Count, + const LocationContext *LCtx, + const CallEvent *Call, + InvalidatedSymbols &IS, + RegionAndSymbolInvalidationTraits &ITraits, + InvalidatedRegions *InvalidatedTopLevel, + InvalidatedRegions *Invalidated) = 0; + + /// enterStackFrame - Let the StoreManager to do something when execution + /// engine is about to execute into a callee. + StoreRef enterStackFrame(Store store, + const CallEvent &Call, + const StackFrameContext *CalleeCtx); + + /// Finds the transitive closure of symbols within the given region. + /// + /// Returns false if the visitor aborted the scan. + virtual bool scanReachableSymbols(Store S, const MemRegion *R, + ScanReachableSymbols &Visitor) = 0; + + virtual void print(Store store, raw_ostream &Out, + const char* nl, const char *sep) = 0; + + class BindingsHandler { + public: + virtual ~BindingsHandler(); + virtual bool HandleBinding(StoreManager& SMgr, Store store, + const MemRegion *region, SVal val) = 0; + }; + + class FindUniqueBinding : + public BindingsHandler { + SymbolRef Sym; + const MemRegion* Binding; + bool First; + + public: + FindUniqueBinding(SymbolRef sym) + : Sym(sym), Binding(nullptr), First(true) {} + + bool HandleBinding(StoreManager& SMgr, Store store, const MemRegion* R, + SVal val) override; + explicit operator bool() { return First && Binding; } + const MemRegion *getRegion() { return Binding; } + }; + + /// iterBindings - Iterate over the bindings in the Store. + virtual void iterBindings(Store store, BindingsHandler& f) = 0; + +protected: + const MemRegion *MakeElementRegion(const MemRegion *baseRegion, + QualType pointeeTy, uint64_t index = 0); + + /// CastRetrievedVal - Used by subclasses of StoreManager to implement + /// implicit casts that arise from loads from regions that are reinterpreted + /// as another region. + SVal CastRetrievedVal(SVal val, const TypedValueRegion *region, + QualType castTy, bool performTestOnly = true); + +private: + SVal getLValueFieldOrIvar(const Decl *decl, SVal base); +}; + + +inline StoreRef::StoreRef(Store store, StoreManager & smgr) + : store(store), mgr(smgr) { + if (store) + mgr.incrementReferenceCount(store); +} + +inline StoreRef::StoreRef(const StoreRef &sr) + : store(sr.store), mgr(sr.mgr) +{ + if (store) + mgr.incrementReferenceCount(store); +} + +inline StoreRef::~StoreRef() { + if (store) + mgr.decrementReferenceCount(store); +} + +inline StoreRef &StoreRef::operator=(StoreRef const &newStore) { + assert(&newStore.mgr == &mgr); + if (store != newStore.store) { + mgr.incrementReferenceCount(newStore.store); + mgr.decrementReferenceCount(store); + store = newStore.getStore(); + } + return *this; +} + +// FIXME: Do we need to pass ProgramStateManager anymore? +std::unique_ptr<StoreManager> +CreateRegionStoreManager(ProgramStateManager &StMgr); +std::unique_ptr<StoreManager> +CreateFieldsOnlyRegionStoreManager(ProgramStateManager &StMgr); + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h new file mode 100644 index 0000000..958c8c3 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h @@ -0,0 +1,51 @@ +//== StoreRef.h - Smart pointer for store objects ---------------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defined the type StoreRef. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_STOREREF_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_STOREREF_H + +#include <cassert> + +namespace clang { +namespace ento { + +/// Store - This opaque type encapsulates an immutable mapping from +/// locations to values. At a high-level, it represents the symbolic +/// memory model. Different subclasses of StoreManager may choose +/// different types to represent the locations and values. +typedef const void *Store; + +class StoreManager; + +class StoreRef { + Store store; + StoreManager &mgr; +public: + StoreRef(Store, StoreManager &); + StoreRef(const StoreRef &); + StoreRef &operator=(StoreRef const &); + + bool operator==(const StoreRef &x) const { + assert(&mgr == &x.mgr); + return x.store == store; + } + bool operator!=(const StoreRef &x) const { return !operator==(x); } + + ~StoreRef(); + + Store getStore() const { return store; } + const StoreManager &getStoreManager() const { return mgr; } +}; + +}} +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h new file mode 100644 index 0000000..741ba0e --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h @@ -0,0 +1,162 @@ +//== SubEngine.h - Interface of the subengine of CoreEngine --------*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interface of a subengine of the CoreEngine. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SUBENGINE_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SUBENGINE_H + +#include "clang/Analysis/ProgramPoint.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" + +namespace clang { + +class CFGBlock; +class CFGElement; +class LocationContext; +class Stmt; + +namespace ento { + +struct NodeBuilderContext; +class AnalysisManager; +class ExplodedNodeSet; +class ExplodedNode; +class ProgramState; +class ProgramStateManager; +class BlockCounter; +class BranchNodeBuilder; +class IndirectGotoNodeBuilder; +class SwitchNodeBuilder; +class EndOfFunctionNodeBuilder; +class NodeBuilderWithSinks; +class MemRegion; + +class SubEngine { + virtual void anchor(); +public: + virtual ~SubEngine() {} + + virtual ProgramStateRef getInitialState(const LocationContext *InitLoc) = 0; + + virtual AnalysisManager &getAnalysisManager() = 0; + + virtual ProgramStateManager &getStateManager() = 0; + + /// Called by CoreEngine. Used to generate new successor + /// nodes by processing the 'effects' of a block-level statement. + virtual void processCFGElement(const CFGElement E, ExplodedNode* Pred, + unsigned StmtIdx, NodeBuilderContext *Ctx)=0; + + /// Called by CoreEngine when it starts processing a CFGBlock. The + /// SubEngine is expected to populate dstNodes with new nodes representing + /// updated analysis state, or generate no nodes at all if it doesn't. + virtual void processCFGBlockEntrance(const BlockEdge &L, + NodeBuilderWithSinks &nodeBuilder, + ExplodedNode *Pred) = 0; + + /// Called by CoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a branch condition. + virtual void processBranch(const Stmt *Condition, const Stmt *Term, + NodeBuilderContext& BuilderCtx, + ExplodedNode *Pred, + ExplodedNodeSet &Dst, + const CFGBlock *DstT, + const CFGBlock *DstF) = 0; + + /// Called by CoreEngine. + /// Used to generate successor nodes for temporary destructors depending + /// on whether the corresponding constructor was visited. + virtual void processCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE, + NodeBuilderContext &BldCtx, + ExplodedNode *Pred, + ExplodedNodeSet &Dst, + const CFGBlock *DstT, + const CFGBlock *DstF) = 0; + + /// Called by CoreEngine. Used to processing branching behavior + /// at static initalizers. + virtual void processStaticInitializer(const DeclStmt *DS, + NodeBuilderContext& BuilderCtx, + ExplodedNode *Pred, + ExplodedNodeSet &Dst, + const CFGBlock *DstT, + const CFGBlock *DstF) = 0; + + /// Called by CoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a computed goto jump. + virtual void processIndirectGoto(IndirectGotoNodeBuilder& builder) = 0; + + /// Called by CoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a switch statement. + virtual void processSwitch(SwitchNodeBuilder& builder) = 0; + + /// Called by CoreEngine. Used to generate end-of-path + /// nodes when the control reaches the end of a function. + virtual void processEndOfFunction(NodeBuilderContext& BC, + ExplodedNode *Pred) = 0; + + // Generate the entry node of the callee. + virtual void processCallEnter(CallEnter CE, ExplodedNode *Pred) = 0; + + // Generate the first post callsite node. + virtual void processCallExit(ExplodedNode *Pred) = 0; + + /// Called by ConstraintManager. Used to call checker-specific + /// logic for handling assumptions on symbolic values. + virtual ProgramStateRef processAssume(ProgramStateRef state, + SVal cond, bool assumption) = 0; + + /// wantsRegionChangeUpdate - Called by ProgramStateManager to determine if a + /// region change should trigger a processRegionChanges update. + virtual bool wantsRegionChangeUpdate(ProgramStateRef state) = 0; + + /// processRegionChanges - Called by ProgramStateManager whenever a change is + /// made to the store. Used to update checkers that track region values. + virtual ProgramStateRef + processRegionChanges(ProgramStateRef state, + const InvalidatedSymbols *invalidated, + ArrayRef<const MemRegion *> ExplicitRegions, + ArrayRef<const MemRegion *> Regions, + const CallEvent *Call) = 0; + + + inline ProgramStateRef + processRegionChange(ProgramStateRef state, + const MemRegion* MR) { + return processRegionChanges(state, nullptr, MR, MR, nullptr); + } + + virtual ProgramStateRef + processPointerEscapedOnBind(ProgramStateRef State, SVal Loc, SVal Val) = 0; + + virtual ProgramStateRef + notifyCheckersOfPointerEscape(ProgramStateRef State, + const InvalidatedSymbols *Invalidated, + ArrayRef<const MemRegion *> ExplicitRegions, + ArrayRef<const MemRegion *> Regions, + const CallEvent *Call, + RegionAndSymbolInvalidationTraits &HTraits) = 0; + + /// printState - Called by ProgramStateManager to print checker-specific data. + virtual void printState(raw_ostream &Out, ProgramStateRef State, + const char *NL, const char *Sep) = 0; + + /// Called by CoreEngine when the analysis worklist is either empty or the + // maximum number of analysis steps have been reached. + virtual void processEndWorklist(bool hasWorkRemaining) = 0; +}; + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SummaryManager.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SummaryManager.h new file mode 100644 index 0000000..ed87851 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SummaryManager.h @@ -0,0 +1,61 @@ +//== SummaryManager.h - Generic handling of function summaries --*- 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 SummaryManager and related classes, which provides +// a generic mechanism for managing function summaries. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_SUMMARY +#define LLVM_CLANG_GR_SUMMARY + +#include "llvm/ADT/FoldingSet.h" +#include "llvm/Support/Allocator.h" + +namespace clang { + +namespace ento { + +namespace summMgr { + + +/* Key kinds: + + - C functions + - C++ functions (name + parameter types) + - ObjC methods: + - Class, selector (class method) + - Class, selector (instance method) + - Category, selector (instance method) + - Protocol, selector (instance method) + - C++ methods + - Class, function name + parameter types + const + */ + +class SummaryKey { + +}; + +} // end namespace clang::summMgr + +class SummaryManagerImpl { + +}; + + +template <typename T> +class SummaryManager : SummaryManagerImpl { + +}; + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h new file mode 100644 index 0000000..9dbfab2 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h @@ -0,0 +1,681 @@ +//== SymbolManager.h - Management of Symbolic Values ------------*- 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 SymbolManager, a class that manages symbolic values +// created for use by ExprEngine and related classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SYMBOLMANAGER_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SYMBOLMANAGER_H + +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Basic/LLVM.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/DataTypes.h" + +namespace clang { + class ASTContext; + class StackFrameContext; + +namespace ento { + class BasicValueFactory; + class MemRegion; + class SubRegion; + class TypedValueRegion; + class VarRegion; + +/// \brief Symbolic value. These values used to capture symbolic execution of +/// the program. +class SymExpr : public llvm::FoldingSetNode { + virtual void anchor(); +public: + enum Kind { RegionValueKind, ConjuredKind, DerivedKind, ExtentKind, + MetadataKind, + BEGIN_SYMBOLS = RegionValueKind, + END_SYMBOLS = MetadataKind, + SymIntKind, IntSymKind, SymSymKind, + BEGIN_BINARYSYMEXPRS = SymIntKind, + END_BINARYSYMEXPRS = SymSymKind, + CastSymbolKind }; +private: + Kind K; + +protected: + SymExpr(Kind k) : K(k) {} + +public: + virtual ~SymExpr() {} + + Kind getKind() const { return K; } + + virtual void dump() const; + + virtual void dumpToStream(raw_ostream &os) const {} + + virtual QualType getType() const = 0; + virtual void Profile(llvm::FoldingSetNodeID& profile) = 0; + + /// \brief Iterator over symbols that the current symbol depends on. + /// + /// For SymbolData, it's the symbol itself; for expressions, it's the + /// expression symbol and all the operands in it. Note, SymbolDerived is + /// treated as SymbolData - the iterator will NOT visit the parent region. + class symbol_iterator { + SmallVector<const SymExpr*, 5> itr; + void expand(); + public: + symbol_iterator() {} + symbol_iterator(const SymExpr *SE); + + symbol_iterator &operator++(); + const SymExpr* operator*(); + + bool operator==(const symbol_iterator &X) const; + bool operator!=(const symbol_iterator &X) const; + }; + + symbol_iterator symbol_begin() const { + return symbol_iterator(this); + } + static symbol_iterator symbol_end() { return symbol_iterator(); } + + unsigned computeComplexity() const; +}; + +typedef const SymExpr* SymbolRef; +typedef SmallVector<SymbolRef, 2> SymbolRefSmallVectorTy; + +typedef unsigned SymbolID; +/// \brief A symbol representing data which can be stored in a memory location +/// (region). +class SymbolData : public SymExpr { + void anchor() override; + const SymbolID Sym; + +protected: + SymbolData(Kind k, SymbolID sym) : SymExpr(k), Sym(sym) {} + +public: + ~SymbolData() override {} + + SymbolID getSymbolID() const { return Sym; } + + // Implement isa<T> support. + static inline bool classof(const SymExpr *SE) { + Kind k = SE->getKind(); + return k >= BEGIN_SYMBOLS && k <= END_SYMBOLS; + } +}; + +///\brief A symbol representing the value stored at a MemRegion. +class SymbolRegionValue : public SymbolData { + const TypedValueRegion *R; + +public: + SymbolRegionValue(SymbolID sym, const TypedValueRegion *r) + : SymbolData(RegionValueKind, sym), R(r) {} + + const TypedValueRegion* getRegion() const { return R; } + + static void Profile(llvm::FoldingSetNodeID& profile, const TypedValueRegion* R) { + profile.AddInteger((unsigned) RegionValueKind); + profile.AddPointer(R); + } + + void Profile(llvm::FoldingSetNodeID& profile) override { + Profile(profile, R); + } + + void dumpToStream(raw_ostream &os) const override; + + QualType getType() const override; + + // Implement isa<T> support. + static inline bool classof(const SymExpr *SE) { + return SE->getKind() == RegionValueKind; + } +}; + +/// A symbol representing the result of an expression in the case when we do +/// not know anything about what the expression is. +class SymbolConjured : public SymbolData { + const Stmt *S; + QualType T; + unsigned Count; + const LocationContext *LCtx; + const void *SymbolTag; + +public: + SymbolConjured(SymbolID sym, const Stmt *s, const LocationContext *lctx, + QualType t, unsigned count, + const void *symbolTag) + : SymbolData(ConjuredKind, sym), S(s), T(t), Count(count), + LCtx(lctx), + SymbolTag(symbolTag) {} + + const Stmt *getStmt() const { return S; } + unsigned getCount() const { return Count; } + const void *getTag() const { return SymbolTag; } + + QualType getType() const override; + + void dumpToStream(raw_ostream &os) const override; + + static void Profile(llvm::FoldingSetNodeID& profile, const Stmt *S, + QualType T, unsigned Count, const LocationContext *LCtx, + const void *SymbolTag) { + profile.AddInteger((unsigned) ConjuredKind); + profile.AddPointer(S); + profile.AddPointer(LCtx); + profile.Add(T); + profile.AddInteger(Count); + profile.AddPointer(SymbolTag); + } + + void Profile(llvm::FoldingSetNodeID& profile) override { + Profile(profile, S, T, Count, LCtx, SymbolTag); + } + + // Implement isa<T> support. + static inline bool classof(const SymExpr *SE) { + return SE->getKind() == ConjuredKind; + } +}; + +/// A symbol representing the value of a MemRegion whose parent region has +/// symbolic value. +class SymbolDerived : public SymbolData { + SymbolRef parentSymbol; + const TypedValueRegion *R; + +public: + SymbolDerived(SymbolID sym, SymbolRef parent, const TypedValueRegion *r) + : SymbolData(DerivedKind, sym), parentSymbol(parent), R(r) {} + + SymbolRef getParentSymbol() const { return parentSymbol; } + const TypedValueRegion *getRegion() const { return R; } + + QualType getType() const override; + + void dumpToStream(raw_ostream &os) const override; + + static void Profile(llvm::FoldingSetNodeID& profile, SymbolRef parent, + const TypedValueRegion *r) { + profile.AddInteger((unsigned) DerivedKind); + profile.AddPointer(r); + profile.AddPointer(parent); + } + + void Profile(llvm::FoldingSetNodeID& profile) override { + Profile(profile, parentSymbol, R); + } + + // Implement isa<T> support. + static inline bool classof(const SymExpr *SE) { + return SE->getKind() == DerivedKind; + } +}; + +/// SymbolExtent - Represents the extent (size in bytes) of a bounded region. +/// Clients should not ask the SymbolManager for a region's extent. Always use +/// SubRegion::getExtent instead -- the value returned may not be a symbol. +class SymbolExtent : public SymbolData { + const SubRegion *R; + +public: + SymbolExtent(SymbolID sym, const SubRegion *r) + : SymbolData(ExtentKind, sym), R(r) {} + + const SubRegion *getRegion() const { return R; } + + QualType getType() const override; + + void dumpToStream(raw_ostream &os) const override; + + static void Profile(llvm::FoldingSetNodeID& profile, const SubRegion *R) { + profile.AddInteger((unsigned) ExtentKind); + profile.AddPointer(R); + } + + void Profile(llvm::FoldingSetNodeID& profile) override { + Profile(profile, R); + } + + // Implement isa<T> support. + static inline bool classof(const SymExpr *SE) { + return SE->getKind() == ExtentKind; + } +}; + +/// SymbolMetadata - Represents path-dependent metadata about a specific region. +/// Metadata symbols remain live as long as they are marked as in use before +/// dead-symbol sweeping AND their associated regions are still alive. +/// Intended for use by checkers. +class SymbolMetadata : public SymbolData { + const MemRegion* R; + const Stmt *S; + QualType T; + unsigned Count; + const void *Tag; +public: + SymbolMetadata(SymbolID sym, const MemRegion* r, const Stmt *s, QualType t, + unsigned count, const void *tag) + : SymbolData(MetadataKind, sym), R(r), S(s), T(t), Count(count), Tag(tag) {} + + const MemRegion *getRegion() const { return R; } + const Stmt *getStmt() const { return S; } + unsigned getCount() const { return Count; } + const void *getTag() const { return Tag; } + + QualType getType() const override; + + void dumpToStream(raw_ostream &os) const override; + + static void Profile(llvm::FoldingSetNodeID& profile, const MemRegion *R, + const Stmt *S, QualType T, unsigned Count, + const void *Tag) { + profile.AddInteger((unsigned) MetadataKind); + profile.AddPointer(R); + profile.AddPointer(S); + profile.Add(T); + profile.AddInteger(Count); + profile.AddPointer(Tag); + } + + void Profile(llvm::FoldingSetNodeID& profile) override { + Profile(profile, R, S, T, Count, Tag); + } + + // Implement isa<T> support. + static inline bool classof(const SymExpr *SE) { + return SE->getKind() == MetadataKind; + } +}; + +/// \brief Represents a cast expression. +class SymbolCast : public SymExpr { + const SymExpr *Operand; + /// Type of the operand. + QualType FromTy; + /// The type of the result. + QualType ToTy; + +public: + SymbolCast(const SymExpr *In, QualType From, QualType To) : + SymExpr(CastSymbolKind), Operand(In), FromTy(From), ToTy(To) { } + + QualType getType() const override { return ToTy; } + + const SymExpr *getOperand() const { return Operand; } + + void dumpToStream(raw_ostream &os) const override; + + static void Profile(llvm::FoldingSetNodeID& ID, + const SymExpr *In, QualType From, QualType To) { + ID.AddInteger((unsigned) CastSymbolKind); + ID.AddPointer(In); + ID.Add(From); + ID.Add(To); + } + + void Profile(llvm::FoldingSetNodeID& ID) override { + Profile(ID, Operand, FromTy, ToTy); + } + + // Implement isa<T> support. + static inline bool classof(const SymExpr *SE) { + return SE->getKind() == CastSymbolKind; + } +}; + +/// \brief Represents a symbolic expression involving a binary operator +class BinarySymExpr : public SymExpr { + BinaryOperator::Opcode Op; + QualType T; + +protected: + BinarySymExpr(Kind k, BinaryOperator::Opcode op, QualType t) + : SymExpr(k), Op(op), T(t) {} + +public: + // FIXME: We probably need to make this out-of-line to avoid redundant + // generation of virtual functions. + QualType getType() const override { return T; } + + BinaryOperator::Opcode getOpcode() const { return Op; } + + // Implement isa<T> support. + static inline bool classof(const SymExpr *SE) { + Kind k = SE->getKind(); + return k >= BEGIN_BINARYSYMEXPRS && k <= END_BINARYSYMEXPRS; + } +}; + +/// \brief Represents a symbolic expression like 'x' + 3. +class SymIntExpr : public BinarySymExpr { + const SymExpr *LHS; + const llvm::APSInt& RHS; + +public: + SymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op, + const llvm::APSInt& rhs, QualType t) + : BinarySymExpr(SymIntKind, op, t), LHS(lhs), RHS(rhs) {} + + void dumpToStream(raw_ostream &os) const override; + + const SymExpr *getLHS() const { return LHS; } + const llvm::APSInt &getRHS() const { return RHS; } + + static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs, + BinaryOperator::Opcode op, const llvm::APSInt& rhs, + QualType t) { + ID.AddInteger((unsigned) SymIntKind); + ID.AddPointer(lhs); + ID.AddInteger(op); + ID.AddPointer(&rhs); + ID.Add(t); + } + + void Profile(llvm::FoldingSetNodeID& ID) override { + Profile(ID, LHS, getOpcode(), RHS, getType()); + } + + // Implement isa<T> support. + static inline bool classof(const SymExpr *SE) { + return SE->getKind() == SymIntKind; + } +}; + +/// \brief Represents a symbolic expression like 3 - 'x'. +class IntSymExpr : public BinarySymExpr { + const llvm::APSInt& LHS; + const SymExpr *RHS; + +public: + IntSymExpr(const llvm::APSInt& lhs, BinaryOperator::Opcode op, + const SymExpr *rhs, QualType t) + : BinarySymExpr(IntSymKind, op, t), LHS(lhs), RHS(rhs) {} + + void dumpToStream(raw_ostream &os) const override; + + const SymExpr *getRHS() const { return RHS; } + const llvm::APSInt &getLHS() const { return LHS; } + + static void Profile(llvm::FoldingSetNodeID& ID, const llvm::APSInt& lhs, + BinaryOperator::Opcode op, const SymExpr *rhs, + QualType t) { + ID.AddInteger((unsigned) IntSymKind); + ID.AddPointer(&lhs); + ID.AddInteger(op); + ID.AddPointer(rhs); + ID.Add(t); + } + + void Profile(llvm::FoldingSetNodeID& ID) override { + Profile(ID, LHS, getOpcode(), RHS, getType()); + } + + // Implement isa<T> support. + static inline bool classof(const SymExpr *SE) { + return SE->getKind() == IntSymKind; + } +}; + +/// \brief Represents a symbolic expression like 'x' + 'y'. +class SymSymExpr : public BinarySymExpr { + const SymExpr *LHS; + const SymExpr *RHS; + +public: + SymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op, const SymExpr *rhs, + QualType t) + : BinarySymExpr(SymSymKind, op, t), LHS(lhs), RHS(rhs) {} + + const SymExpr *getLHS() const { return LHS; } + const SymExpr *getRHS() const { return RHS; } + + void dumpToStream(raw_ostream &os) const override; + + static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs, + BinaryOperator::Opcode op, const SymExpr *rhs, QualType t) { + ID.AddInteger((unsigned) SymSymKind); + ID.AddPointer(lhs); + ID.AddInteger(op); + ID.AddPointer(rhs); + ID.Add(t); + } + + void Profile(llvm::FoldingSetNodeID& ID) override { + Profile(ID, LHS, getOpcode(), RHS, getType()); + } + + // Implement isa<T> support. + static inline bool classof(const SymExpr *SE) { + return SE->getKind() == SymSymKind; + } +}; + +class SymbolManager { + typedef llvm::FoldingSet<SymExpr> DataSetTy; + typedef llvm::DenseMap<SymbolRef, SymbolRefSmallVectorTy*> SymbolDependTy; + + DataSetTy DataSet; + /// Stores the extra dependencies between symbols: the data should be kept + /// alive as long as the key is live. + SymbolDependTy SymbolDependencies; + unsigned SymbolCounter; + llvm::BumpPtrAllocator& BPAlloc; + BasicValueFactory &BV; + ASTContext &Ctx; + +public: + SymbolManager(ASTContext &ctx, BasicValueFactory &bv, + llvm::BumpPtrAllocator& bpalloc) + : SymbolDependencies(16), SymbolCounter(0), + BPAlloc(bpalloc), BV(bv), Ctx(ctx) {} + + ~SymbolManager(); + + static bool canSymbolicate(QualType T); + + /// \brief Make a unique symbol for MemRegion R according to its kind. + const SymbolRegionValue* getRegionValueSymbol(const TypedValueRegion* R); + + const SymbolConjured* conjureSymbol(const Stmt *E, + const LocationContext *LCtx, + QualType T, + unsigned VisitCount, + const void *SymbolTag = nullptr); + + const SymbolConjured* conjureSymbol(const Expr *E, + const LocationContext *LCtx, + unsigned VisitCount, + const void *SymbolTag = nullptr) { + return conjureSymbol(E, LCtx, E->getType(), VisitCount, SymbolTag); + } + + const SymbolDerived *getDerivedSymbol(SymbolRef parentSymbol, + const TypedValueRegion *R); + + const SymbolExtent *getExtentSymbol(const SubRegion *R); + + /// \brief Creates a metadata symbol associated with a specific region. + /// + /// VisitCount can be used to differentiate regions corresponding to + /// different loop iterations, thus, making the symbol path-dependent. + const SymbolMetadata *getMetadataSymbol(const MemRegion *R, const Stmt *S, + QualType T, unsigned VisitCount, + const void *SymbolTag = nullptr); + + const SymbolCast* getCastSymbol(const SymExpr *Operand, + QualType From, QualType To); + + const SymIntExpr *getSymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op, + const llvm::APSInt& rhs, QualType t); + + const SymIntExpr *getSymIntExpr(const SymExpr &lhs, BinaryOperator::Opcode op, + const llvm::APSInt& rhs, QualType t) { + return getSymIntExpr(&lhs, op, rhs, t); + } + + const IntSymExpr *getIntSymExpr(const llvm::APSInt& lhs, + BinaryOperator::Opcode op, + const SymExpr *rhs, QualType t); + + const SymSymExpr *getSymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op, + const SymExpr *rhs, QualType t); + + QualType getType(const SymExpr *SE) const { + return SE->getType(); + } + + /// \brief Add artificial symbol dependency. + /// + /// The dependent symbol should stay alive as long as the primary is alive. + void addSymbolDependency(const SymbolRef Primary, const SymbolRef Dependent); + + const SymbolRefSmallVectorTy *getDependentSymbols(const SymbolRef Primary); + + ASTContext &getContext() { return Ctx; } + BasicValueFactory &getBasicVals() { return BV; } +}; + +/// \brief A class responsible for cleaning up unused symbols. +class SymbolReaper { + enum SymbolStatus { + NotProcessed, + HaveMarkedDependents + }; + + typedef llvm::DenseSet<SymbolRef> SymbolSetTy; + typedef llvm::DenseMap<SymbolRef, SymbolStatus> SymbolMapTy; + typedef llvm::DenseSet<const MemRegion *> RegionSetTy; + + SymbolMapTy TheLiving; + SymbolSetTy MetadataInUse; + SymbolSetTy TheDead; + + RegionSetTy RegionRoots; + + const StackFrameContext *LCtx; + const Stmt *Loc; + SymbolManager& SymMgr; + StoreRef reapedStore; + llvm::DenseMap<const MemRegion *, unsigned> includedRegionCache; + +public: + /// \brief Construct a reaper object, which removes everything which is not + /// live before we execute statement s in the given location context. + /// + /// If the statement is NULL, everything is this and parent contexts is + /// considered live. + /// If the stack frame context is NULL, everything on stack is considered + /// dead. + SymbolReaper(const StackFrameContext *Ctx, const Stmt *s, SymbolManager& symmgr, + StoreManager &storeMgr) + : LCtx(Ctx), Loc(s), SymMgr(symmgr), + reapedStore(nullptr, storeMgr) {} + + const LocationContext *getLocationContext() const { return LCtx; } + + bool isLive(SymbolRef sym); + bool isLiveRegion(const MemRegion *region); + bool isLive(const Stmt *ExprVal, const LocationContext *LCtx) const; + bool isLive(const VarRegion *VR, bool includeStoreBindings = false) const; + + /// \brief Unconditionally marks a symbol as live. + /// + /// This should never be + /// used by checkers, only by the state infrastructure such as the store and + /// environment. Checkers should instead use metadata symbols and markInUse. + void markLive(SymbolRef sym); + + /// \brief Marks a symbol as important to a checker. + /// + /// For metadata symbols, + /// this will keep the symbol alive as long as its associated region is also + /// live. For other symbols, this has no effect; checkers are not permitted + /// to influence the life of other symbols. This should be used before any + /// symbol marking has occurred, i.e. in the MarkLiveSymbols callback. + void markInUse(SymbolRef sym); + + /// \brief If a symbol is known to be live, marks the symbol as live. + /// + /// Otherwise, if the symbol cannot be proven live, it is marked as dead. + /// Returns true if the symbol is dead, false if live. + bool maybeDead(SymbolRef sym); + + typedef SymbolSetTy::const_iterator dead_iterator; + dead_iterator dead_begin() const { return TheDead.begin(); } + dead_iterator dead_end() const { return TheDead.end(); } + + bool hasDeadSymbols() const { + return !TheDead.empty(); + } + + typedef RegionSetTy::const_iterator region_iterator; + region_iterator region_begin() const { return RegionRoots.begin(); } + region_iterator region_end() const { return RegionRoots.end(); } + + /// \brief Returns whether or not a symbol has been confirmed dead. + /// + /// This should only be called once all marking of dead symbols has completed. + /// (For checkers, this means only in the evalDeadSymbols callback.) + bool isDead(SymbolRef sym) const { + return TheDead.count(sym); + } + + void markLive(const MemRegion *region); + void markElementIndicesLive(const MemRegion *region); + + /// \brief Set to the value of the symbolic store after + /// StoreManager::removeDeadBindings has been called. + void setReapedStore(StoreRef st) { reapedStore = st; } + +private: + /// Mark the symbols dependent on the input symbol as live. + void markDependentsLive(SymbolRef sym); +}; + +class SymbolVisitor { +protected: + ~SymbolVisitor() = default; + +public: + SymbolVisitor() = default; + SymbolVisitor(const SymbolVisitor &) = default; + SymbolVisitor(SymbolVisitor &&) {} + + /// \brief A visitor method invoked by ProgramStateManager::scanReachableSymbols. + /// + /// The method returns \c true if symbols should continue be scanned and \c + /// false otherwise. + virtual bool VisitSymbol(SymbolRef sym) = 0; + virtual bool VisitMemRegion(const MemRegion *region) { return true; } +}; + +} // end GR namespace + +} // end clang namespace + +namespace llvm { +static inline raw_ostream &operator<<(raw_ostream &os, + const clang::ento::SymExpr *SE) { + SE->dumpToStream(os); + return os; +} +} // end llvm namespace +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h new file mode 100644 index 0000000..d39b501 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h @@ -0,0 +1,46 @@ +//== TaintManager.h - Managing taint --------------------------- -*- 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 APIs for adding, removing, querying symbol taint. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_TAINTMANAGER_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_TAINTMANAGER_H + +#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h" +#include "llvm/ADT/ImmutableMap.h" + +namespace clang { +namespace ento { + +/// The GDM component containing the tainted root symbols. We lazily infer the +/// taint of the dependent symbols. Currently, this is a map from a symbol to +/// tag kind. TODO: Should support multiple tag kinds. +// FIXME: This does not use the nice trait macros because it must be accessible +// from multiple translation units. +struct TaintMap {}; +typedef llvm::ImmutableMap<SymbolRef, TaintTagType> TaintMapImpl; +template<> struct ProgramStateTrait<TaintMap> + : public ProgramStatePartialTrait<TaintMapImpl> { + static void *GDMIndex() { static int index = 0; return &index; } +}; + +class TaintManager { + + TaintManager() {} +}; + +} +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h new file mode 100644 index 0000000..0c56e7d --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h @@ -0,0 +1,27 @@ +//== TaintTag.h - Path-sensitive "State" for tracking values -*- C++ -*--=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Defines a set of taint tags. Several tags are used to differentiate kinds +// of taint. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_TAINTTAG_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_TAINTTAG_H + +namespace clang { +namespace ento { + +/// The type of taint, which helps to differentiate between different types of +/// taint. +typedef unsigned TaintTagType; +static const TaintTagType TaintTagGeneric = 0; + +}} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h new file mode 100644 index 0000000..4f1a60e --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h @@ -0,0 +1,100 @@ +//==- WorkList.h - Worklist class used by CoreEngine ---------------*- 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 WorkList, a pure virtual class that represents an opaque +// worklist used by CoreEngine to explore the reachability state space. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_WORKLIST_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_WORKLIST_H + +#include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" +#include <cassert> + +namespace clang { + +class CFGBlock; + +namespace ento { + +class WorkListUnit { + ExplodedNode *node; + BlockCounter counter; + const CFGBlock *block; + unsigned blockIdx; // This is the index of the next statement. + +public: + WorkListUnit(ExplodedNode *N, BlockCounter C, + const CFGBlock *B, unsigned idx) + : node(N), + counter(C), + block(B), + blockIdx(idx) {} + + explicit WorkListUnit(ExplodedNode *N, BlockCounter C) + : node(N), + counter(C), + block(nullptr), + blockIdx(0) {} + + /// Returns the node associated with the worklist unit. + ExplodedNode *getNode() const { return node; } + + /// Returns the block counter map associated with the worklist unit. + BlockCounter getBlockCounter() const { return counter; } + + /// Returns the CFGblock associated with the worklist unit. + const CFGBlock *getBlock() const { return block; } + + /// Return the index within the CFGBlock for the worklist unit. + unsigned getIndex() const { return blockIdx; } +}; + +class WorkList { + BlockCounter CurrentCounter; +public: + virtual ~WorkList(); + virtual bool hasWork() const = 0; + + virtual void enqueue(const WorkListUnit& U) = 0; + + void enqueue(ExplodedNode *N, const CFGBlock *B, unsigned idx) { + enqueue(WorkListUnit(N, CurrentCounter, B, idx)); + } + + void enqueue(ExplodedNode *N) { + assert(N->getLocation().getKind() != ProgramPoint::PostStmtKind); + enqueue(WorkListUnit(N, CurrentCounter)); + } + + virtual WorkListUnit dequeue() = 0; + + void setBlockCounter(BlockCounter C) { CurrentCounter = C; } + BlockCounter getBlockCounter() const { return CurrentCounter; } + + class Visitor { + public: + Visitor() {} + virtual ~Visitor(); + virtual bool visit(const WorkListUnit &U) = 0; + }; + virtual bool visitItemsInWorkList(Visitor &V) = 0; + + static WorkList *makeDFS(); + static WorkList *makeBFS(); + static WorkList *makeBFSBlockDFSContents(); +}; + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h new file mode 100644 index 0000000..37ea05f --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h @@ -0,0 +1,49 @@ +//===--- AnalysisConsumer.h - Front-end Analysis Engine Hooks ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header contains the functions necessary for a front-end to run various +// analyses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_FRONTEND_ANALYSISCONSUMER_H +#define LLVM_CLANG_STATICANALYZER_FRONTEND_ANALYSISCONSUMER_H + +#include "clang/AST/ASTConsumer.h" +#include "clang/Basic/LLVM.h" +#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" +#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" +#include <string> + +namespace clang { + +class Preprocessor; +class DiagnosticsEngine; +class CodeInjector; +class CompilerInstance; + +namespace ento { +class CheckerManager; + +class AnalysisASTConsumer : public ASTConsumer { +public: + virtual void AddDiagnosticConsumer(PathDiagnosticConsumer *Consumer) = 0; +}; + +/// CreateAnalysisConsumer - Creates an ASTConsumer to run various code +/// analysis passes. (The set of analyses run is controlled by command-line +/// options.) +std::unique_ptr<AnalysisASTConsumer> +CreateAnalysisConsumer(CompilerInstance &CI); + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h new file mode 100644 index 0000000..2985b7c --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h @@ -0,0 +1,33 @@ +//===-- CheckerRegistration.h - Checker Registration Function ---*- 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_STATICANALYZER_FRONTEND_CHECKERREGISTRATION_H +#define LLVM_CLANG_STATICANALYZER_FRONTEND_CHECKERREGISTRATION_H + +#include "clang/Basic/LLVM.h" +#include <memory> +#include <string> + +namespace clang { + class AnalyzerOptions; + class LangOptions; + class DiagnosticsEngine; + +namespace ento { + class CheckerManager; + + std::unique_ptr<CheckerManager> + createCheckerManager(AnalyzerOptions &opts, const LangOptions &langOpts, + ArrayRef<std::string> plugins, DiagnosticsEngine &diags); + +} // end ento namespace + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Frontend/FrontendActions.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Frontend/FrontendActions.h new file mode 100644 index 0000000..36afb4b --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Frontend/FrontendActions.h @@ -0,0 +1,60 @@ +//===-- FrontendActions.h - Useful Frontend Actions -------------*- 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_STATICANALYZER_FRONTEND_FRONTENDACTIONS_H +#define LLVM_CLANG_STATICANALYZER_FRONTEND_FRONTENDACTIONS_H + +#include "clang/Frontend/FrontendAction.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { + +class Stmt; + +namespace ento { + +//===----------------------------------------------------------------------===// +// AST Consumer Actions +//===----------------------------------------------------------------------===// + +class AnalysisAction : public ASTFrontendAction { +protected: + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override; +}; + +/// \brief Frontend action to parse model files. +/// +/// This frontend action is responsible for parsing model files. Model files can +/// not be parsed on their own, they rely on type information that is available +/// in another translation unit. The parsing of model files is done by a +/// separate compiler instance that reuses the ASTContext and othen information +/// from the main translation unit that is being compiled. After a model file is +/// parsed, the function definitions will be collected into a StringMap. +class ParseModelFileAction : public ASTFrontendAction { +public: + ParseModelFileAction(llvm::StringMap<Stmt *> &Bodies); + bool isModelParsingAction() const override { return true; } + +protected: + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override; + +private: + llvm::StringMap<Stmt *> &Bodies; +}; + +void printCheckerHelp(raw_ostream &OS, ArrayRef<std::string> plugins); + +} // end GR namespace + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Frontend/ModelConsumer.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Frontend/ModelConsumer.h new file mode 100644 index 0000000..24f8042 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Frontend/ModelConsumer.h @@ -0,0 +1,44 @@ +//===-- ModelConsumer.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file implements clang::ento::ModelConsumer which is an +/// ASTConsumer for model files. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_MODELCONSUMER_H +#define LLVM_CLANG_GR_MODELCONSUMER_H + +#include "clang/AST/ASTConsumer.h" +#include "llvm/ADT/StringMap.h" + +namespace clang { + +class Stmt; + +namespace ento { + +/// \brief ASTConsumer to consume model files' AST. +/// +/// This consumer collects the bodies of function definitions into a StringMap +/// from a model file. +class ModelConsumer : public ASTConsumer { +public: + ModelConsumer(llvm::StringMap<Stmt *> &Bodies); + + bool HandleTopLevelDecl(DeclGroupRef D) override; + +private: + llvm::StringMap<Stmt *> &Bodies; +}; +} +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/ArgumentsAdjusters.h b/contrib/llvm/tools/clang/include/clang/Tooling/ArgumentsAdjusters.h new file mode 100644 index 0000000..1fd7be6 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Tooling/ArgumentsAdjusters.h @@ -0,0 +1,69 @@ +//===--- ArgumentsAdjusters.h - Command line arguments adjuster -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares typedef ArgumentsAdjuster and functions to create several +// useful argument adjusters. +// ArgumentsAdjusters modify command line arguments obtained from a compilation +// database before they are used to run a frontend action. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_ARGUMENTSADJUSTERS_H +#define LLVM_CLANG_TOOLING_ARGUMENTSADJUSTERS_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/StringRef.h" +#include <functional> +#include <string> +#include <vector> + +namespace clang { +namespace tooling { + +/// \brief A sequence of command line arguments. +typedef std::vector<std::string> CommandLineArguments; + +/// \brief A prototype of a command line adjuster. +/// +/// Command line argument adjuster is responsible for command line arguments +/// modification before the arguments are used to run a frontend action. +typedef std::function<CommandLineArguments( + const CommandLineArguments &, StringRef Filename)> ArgumentsAdjuster; + +/// \brief Gets an argument adjuster that converts input command line arguments +/// to the "syntax check only" variant. +ArgumentsAdjuster getClangSyntaxOnlyAdjuster(); + +/// \brief Gets an argument adjuster which removes output-related command line +/// arguments. +ArgumentsAdjuster getClangStripOutputAdjuster(); + +enum class ArgumentInsertPosition { BEGIN, END }; + +/// \brief Gets an argument adjuster which inserts \p Extra arguments in the +/// specified position. +ArgumentsAdjuster getInsertArgumentAdjuster(const CommandLineArguments &Extra, + ArgumentInsertPosition Pos); + +/// \brief Gets an argument adjuster which inserts an \p Extra argument in the +/// specified position. +ArgumentsAdjuster getInsertArgumentAdjuster( + const char *Extra, + ArgumentInsertPosition Pos = ArgumentInsertPosition::END); + +/// \brief Gets an argument adjuster which adjusts the arguments in sequence +/// with the \p First adjuster and then with the \p Second one. +ArgumentsAdjuster combineAdjusters(ArgumentsAdjuster First, + ArgumentsAdjuster Second); + +} // namespace tooling +} // namespace clang + +#endif // LLVM_CLANG_TOOLING_ARGUMENTSADJUSTERS_H + diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/CommonOptionsParser.h b/contrib/llvm/tools/clang/include/clang/Tooling/CommonOptionsParser.h new file mode 100644 index 0000000..1e8462c --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Tooling/CommonOptionsParser.h @@ -0,0 +1,117 @@ +//===- CommonOptionsParser.h - common options for clang tools -*- C++ -*-=====// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the CommonOptionsParser class used to parse common +// command-line options for clang tools, so that they can be run as separate +// command-line applications with a consistent common interface for handling +// compilation database and input files. +// +// It provides a common subset of command-line options, common algorithm +// for locating a compilation database and source files, and help messages +// for the basic command-line interface. +// +// It creates a CompilationDatabase and reads common command-line options. +// +// This class uses the Clang Tooling infrastructure, see +// http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html +// for details on setting it up with LLVM source tree. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_COMMONOPTIONSPARSER_H +#define LLVM_CLANG_TOOLING_COMMONOPTIONSPARSER_H + +#include "clang/Tooling/CompilationDatabase.h" +#include "llvm/Support/CommandLine.h" + +namespace clang { +namespace tooling { +/// \brief A parser for options common to all command-line Clang tools. +/// +/// Parses a common subset of command-line arguments, locates and loads a +/// compilation commands database and runs a tool with user-specified action. It +/// also contains a help message for the common command-line options. +/// +/// An example of usage: +/// \code +/// #include "clang/Frontend/FrontendActions.h" +/// #include "clang/Tooling/CommonOptionsParser.h" +/// #include "clang/Tooling/Tooling.h" +/// #include "llvm/Support/CommandLine.h" +/// +/// using namespace clang::tooling; +/// using namespace llvm; +/// +/// static cl::OptionCategory MyToolCategory("My tool options"); +/// static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage); +/// static cl::extrahelp MoreHelp("\nMore help text..."); +/// static cl::opt<bool> YourOwnOption(...); +/// ... +/// +/// int main(int argc, const char **argv) { +/// CommonOptionsParser OptionsParser(argc, argv, MyToolCategory); +/// ClangTool Tool(OptionsParser.getCompilations(), +/// OptionsParser.getSourcePathList()); +/// return Tool.run(newFrontendActionFactory<SyntaxOnlyAction>().get()); +/// } +/// \endcode +class CommonOptionsParser { +public: + /// \brief Parses command-line, initializes a compilation database. + /// + /// This constructor can change argc and argv contents, e.g. consume + /// command-line options used for creating FixedCompilationDatabase. + /// + /// All options not belonging to \p Category become hidden. + /// + /// This constructor exits program in case of error. + CommonOptionsParser(int &argc, const char **argv, + llvm::cl::OptionCategory &Category, + const char *Overview = nullptr) + : CommonOptionsParser(argc, argv, Category, llvm::cl::OneOrMore, + Overview) {} + + /// \brief Parses command-line, initializes a compilation database. + /// + /// This constructor can change argc and argv contents, e.g. consume + /// command-line options used for creating FixedCompilationDatabase. + /// + /// All options not belonging to \p Category become hidden. + /// + /// I also allows calls to set the required number of positional parameters. + /// + /// This constructor exits program in case of error. + CommonOptionsParser(int &argc, const char **argv, + llvm::cl::OptionCategory &Category, + llvm::cl::NumOccurrencesFlag OccurrencesFlag, + const char *Overview = nullptr); + + /// Returns a reference to the loaded compilations database. + CompilationDatabase &getCompilations() { + return *Compilations; + } + + /// Returns a list of source file paths to process. + std::vector<std::string> getSourcePathList() { + return SourcePathList; + } + + static const char *const HelpMessage; + +private: + std::unique_ptr<CompilationDatabase> Compilations; + std::vector<std::string> SourcePathList; + std::vector<std::string> ExtraArgsBefore; + std::vector<std::string> ExtraArgsAfter; +}; + +} // namespace tooling +} // namespace clang + +#endif // LLVM_TOOLS_CLANG_INCLUDE_CLANG_TOOLING_COMMONOPTIONSPARSER_H diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/CompilationDatabase.h b/contrib/llvm/tools/clang/include/clang/Tooling/CompilationDatabase.h new file mode 100644 index 0000000..08a0ffe --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Tooling/CompilationDatabase.h @@ -0,0 +1,222 @@ +//===--- CompilationDatabase.h - --------------------------------*- 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 an interface and multiple implementations for +// CompilationDatabases. +// +// While C++ refactoring and analysis tools are not compilers, and thus +// don't run as part of the build system, they need the exact information +// of a build in order to be able to correctly understand the C++ code of +// the project. This information is provided via the CompilationDatabase +// interface. +// +// To create a CompilationDatabase from a build directory one can call +// CompilationDatabase::loadFromDirectory(), which deduces the correct +// compilation database from the root of the build tree. +// +// See the concrete subclasses of CompilationDatabase for currently supported +// formats. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_COMPILATIONDATABASE_H +#define LLVM_CLANG_TOOLING_COMPILATIONDATABASE_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include <memory> +#include <string> +#include <vector> + +namespace clang { +namespace tooling { + +/// \brief Specifies the working directory and command of a compilation. +struct CompileCommand { + CompileCommand() {} + CompileCommand(Twine Directory, Twine Filename, + std::vector<std::string> CommandLine) + : Directory(Directory.str()), + Filename(Filename.str()), + CommandLine(std::move(CommandLine)) {} + + /// \brief The working directory the command was executed from. + std::string Directory; + + /// The source file associated with the command. + std::string Filename; + + /// \brief The command line that was executed. + std::vector<std::string> CommandLine; + + /// \brief An optional mapping from each file's path to its content for all + /// files needed for the compilation that are not available via the file + /// system. + /// + /// Note that a tool implementation is required to fall back to the file + /// system if a source file is not provided in the mapped sources, as + /// compilation databases will usually not provide all files in mapped sources + /// for performance reasons. + std::vector<std::pair<std::string, std::string> > MappedSources; +}; + +/// \brief Interface for compilation databases. +/// +/// A compilation database allows the user to retrieve all compile command lines +/// that a specified file is compiled with in a project. +/// The retrieved compile command lines can be used to run clang tools over +/// a subset of the files in a project. +class CompilationDatabase { +public: + virtual ~CompilationDatabase(); + + /// \brief Loads a compilation database from a build directory. + /// + /// Looks at the specified 'BuildDirectory' and creates a compilation database + /// that allows to query compile commands for source files in the + /// corresponding source tree. + /// + /// Returns NULL and sets ErrorMessage if we were not able to build up a + /// compilation database for the build directory. + /// + /// FIXME: Currently only supports JSON compilation databases, which + /// are named 'compile_commands.json' in the given directory. Extend this + /// for other build types (like ninja build files). + static std::unique_ptr<CompilationDatabase> + loadFromDirectory(StringRef BuildDirectory, std::string &ErrorMessage); + + /// \brief Tries to detect a compilation database location and load it. + /// + /// Looks for a compilation database in all parent paths of file 'SourceFile' + /// by calling loadFromDirectory. + static std::unique_ptr<CompilationDatabase> + autoDetectFromSource(StringRef SourceFile, std::string &ErrorMessage); + + /// \brief Tries to detect a compilation database location and load it. + /// + /// Looks for a compilation database in directory 'SourceDir' and all + /// its parent paths by calling loadFromDirectory. + static std::unique_ptr<CompilationDatabase> + autoDetectFromDirectory(StringRef SourceDir, std::string &ErrorMessage); + + /// \brief Returns all compile commands in which the specified file was + /// compiled. + /// + /// This includes compile comamnds that span multiple source files. + /// For example, consider a project with the following compilations: + /// $ clang++ -o test a.cc b.cc t.cc + /// $ clang++ -o production a.cc b.cc -DPRODUCTION + /// A compilation database representing the project would return both command + /// lines for a.cc and b.cc and only the first command line for t.cc. + virtual std::vector<CompileCommand> getCompileCommands( + StringRef FilePath) const = 0; + + /// \brief Returns the list of all files available in the compilation database. + virtual std::vector<std::string> getAllFiles() const = 0; + + /// \brief Returns all compile commands for all the files in the compilation + /// database. + /// + /// FIXME: Add a layer in Tooling that provides an interface to run a tool + /// over all files in a compilation database. Not all build systems have the + /// ability to provide a feasible implementation for \c getAllCompileCommands. + virtual std::vector<CompileCommand> getAllCompileCommands() const = 0; +}; + +/// \brief Interface for compilation database plugins. +/// +/// A compilation database plugin allows the user to register custom compilation +/// databases that are picked up as compilation database if the corresponding +/// library is linked in. To register a plugin, declare a static variable like: +/// +/// \code +/// static CompilationDatabasePluginRegistry::Add<MyDatabasePlugin> +/// X("my-compilation-database", "Reads my own compilation database"); +/// \endcode +class CompilationDatabasePlugin { +public: + virtual ~CompilationDatabasePlugin(); + + /// \brief Loads a compilation database from a build directory. + /// + /// \see CompilationDatabase::loadFromDirectory(). + virtual std::unique_ptr<CompilationDatabase> + loadFromDirectory(StringRef Directory, std::string &ErrorMessage) = 0; +}; + +/// \brief A compilation database that returns a single compile command line. +/// +/// Useful when we want a tool to behave more like a compiler invocation. +class FixedCompilationDatabase : public CompilationDatabase { +public: + /// \brief Creates a FixedCompilationDatabase from the arguments after "--". + /// + /// Parses the given command line for "--". If "--" is found, the rest of + /// the arguments will make up the command line in the returned + /// FixedCompilationDatabase. + /// The arguments after "--" must not include positional parameters or the + /// argv[0] of the tool. Those will be added by the FixedCompilationDatabase + /// when a CompileCommand is requested. The argv[0] of the returned command + /// line will be "clang-tool". + /// + /// Returns NULL in case "--" is not found. + /// + /// The argument list is meant to be compatible with normal llvm command line + /// parsing in main methods. + /// int main(int argc, char **argv) { + /// std::unique_ptr<FixedCompilationDatabase> Compilations( + /// FixedCompilationDatabase::loadFromCommandLine(argc, argv)); + /// cl::ParseCommandLineOptions(argc, argv); + /// ... + /// } + /// + /// \param Argc The number of command line arguments - will be changed to + /// the number of arguments before "--", if "--" was found in the argument + /// list. + /// \param Argv Points to the command line arguments. + /// \param Directory The base directory used in the FixedCompilationDatabase. + static FixedCompilationDatabase *loadFromCommandLine(int &Argc, + const char *const *Argv, + Twine Directory = "."); + + /// \brief Constructs a compilation data base from a specified directory + /// and command line. + FixedCompilationDatabase(Twine Directory, ArrayRef<std::string> CommandLine); + + /// \brief Returns the given compile command. + /// + /// Will always return a vector with one entry that contains the directory + /// and command line specified at construction with "clang-tool" as argv[0] + /// and 'FilePath' as positional argument. + std::vector<CompileCommand> + getCompileCommands(StringRef FilePath) const override; + + /// \brief Returns the list of all files available in the compilation database. + /// + /// Note: This is always an empty list for the fixed compilation database. + std::vector<std::string> getAllFiles() const override; + + /// \brief Returns all compile commands for all the files in the compilation + /// database. + /// + /// Note: This is always an empty list for the fixed compilation database. + std::vector<CompileCommand> getAllCompileCommands() const override; + +private: + /// This is built up to contain a single entry vector to be returned from + /// getCompileCommands after adding the positional argument. + std::vector<CompileCommand> CompileCommands; +}; + +} // end namespace tooling +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/CompilationDatabasePluginRegistry.h b/contrib/llvm/tools/clang/include/clang/Tooling/CompilationDatabasePluginRegistry.h new file mode 100644 index 0000000..7323ec8 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Tooling/CompilationDatabasePluginRegistry.h @@ -0,0 +1,27 @@ +//===--- CompilationDatabasePluginRegistry.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_TOOLING_COMPILATIONDATABASEPLUGINREGISTRY_H +#define LLVM_CLANG_TOOLING_COMPILATIONDATABASEPLUGINREGISTRY_H + +#include "clang/Tooling/CompilationDatabase.h" +#include "llvm/Support/Registry.h" + +namespace clang { +namespace tooling { + +class CompilationDatabasePlugin; + +typedef llvm::Registry<CompilationDatabasePlugin> + CompilationDatabasePluginRegistry; + +} // end namespace tooling +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Core/Lookup.h b/contrib/llvm/tools/clang/include/clang/Tooling/Core/Lookup.h new file mode 100644 index 0000000..bc2b4db --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Tooling/Core/Lookup.h @@ -0,0 +1,48 @@ +//===--- Lookup.h - Framework for clang refactoring tools --*- 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 helper methods for clang tools performing name lookup. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_CORE_LOOKUP_H +#define LLVM_CLANG_TOOLING_CORE_LOOKUP_H + +#include "clang/Basic/LLVM.h" +#include <string> + +namespace clang { + +class DeclContext; +class NamedDecl; +class NestedNameSpecifier; + +namespace tooling { + +/// Emulate a lookup to replace one nested name specifier with another using as +/// few additional namespace qualifications as possible. +/// +/// This does not perform a full C++ lookup so ADL will not work. +/// +/// \param Use The nested name to be replaced. +/// \param UseContext The context in which the nested name is contained. This +/// will be used to minimize namespace qualifications. +/// \param FromDecl The declaration to which the nested name points. +/// \param ReplacementString The replacement nested name. Must be fully +/// qualified including a leading "::". +/// \returns The new name to be inserted in place of the current nested name. +std::string replaceNestedName(const NestedNameSpecifier *Use, + const DeclContext *UseContext, + const NamedDecl *FromDecl, + StringRef ReplacementString); + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_CORE_LOOKUP_H diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Core/Replacement.h b/contrib/llvm/tools/clang/include/clang/Tooling/Core/Replacement.h new file mode 100644 index 0000000..37389ac --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Tooling/Core/Replacement.h @@ -0,0 +1,241 @@ +//===--- Replacement.h - Framework for clang refactoring tools --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Classes supporting refactorings that span multiple translation units. +// While single translation unit refactorings are supported via the Rewriter, +// when refactoring multiple translation units changes must be stored in a +// SourceManager independent form, duplicate changes need to be removed, and +// all changes must be applied at once at the end of the refactoring so that +// the code is always parseable. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_CORE_REPLACEMENT_H +#define LLVM_CLANG_TOOLING_CORE_REPLACEMENT_H + +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/StringRef.h" +#include <set> +#include <string> +#include <vector> + +namespace clang { + +class Rewriter; + +namespace tooling { + +/// \brief A source range independent of the \c SourceManager. +class Range { +public: + Range() : Offset(0), Length(0) {} + Range(unsigned Offset, unsigned Length) : Offset(Offset), Length(Length) {} + + /// \brief Accessors. + /// @{ + unsigned getOffset() const { return Offset; } + unsigned getLength() const { return Length; } + /// @} + + /// \name Range Predicates + /// @{ + /// \brief Whether this range overlaps with \p RHS or not. + bool overlapsWith(Range RHS) const { + return Offset + Length > RHS.Offset && Offset < RHS.Offset + RHS.Length; + } + + /// \brief Whether this range contains \p RHS or not. + bool contains(Range RHS) const { + return RHS.Offset >= Offset && + (RHS.Offset + RHS.Length) <= (Offset + Length); + } + /// @} + +private: + unsigned Offset; + unsigned Length; +}; + +/// \brief A text replacement. +/// +/// Represents a SourceManager independent replacement of a range of text in a +/// specific file. +class Replacement { +public: + /// \brief Creates an invalid (not applicable) replacement. + Replacement(); + + /// \brief Creates a replacement of the range [Offset, Offset+Length) in + /// FilePath with ReplacementText. + /// + /// \param FilePath A source file accessible via a SourceManager. + /// \param Offset The byte offset of the start of the range in the file. + /// \param Length The length of the range in bytes. + Replacement(StringRef FilePath, unsigned Offset, unsigned Length, + StringRef ReplacementText); + + /// \brief Creates a Replacement of the range [Start, Start+Length) with + /// ReplacementText. + Replacement(const SourceManager &Sources, SourceLocation Start, + unsigned Length, StringRef ReplacementText); + + /// \brief Creates a Replacement of the given range with ReplacementText. + Replacement(const SourceManager &Sources, const CharSourceRange &Range, + StringRef ReplacementText, + const LangOptions &LangOpts = LangOptions()); + + /// \brief Creates a Replacement of the node with ReplacementText. + template <typename Node> + Replacement(const SourceManager &Sources, const Node &NodeToReplace, + StringRef ReplacementText, + const LangOptions &LangOpts = LangOptions()); + + /// \brief Returns whether this replacement can be applied to a file. + /// + /// Only replacements that are in a valid file can be applied. + bool isApplicable() const; + + /// \brief Accessors. + /// @{ + StringRef getFilePath() const { return FilePath; } + unsigned getOffset() const { return ReplacementRange.getOffset(); } + unsigned getLength() const { return ReplacementRange.getLength(); } + StringRef getReplacementText() const { return ReplacementText; } + /// @} + + /// \brief Applies the replacement on the Rewriter. + bool apply(Rewriter &Rewrite) const; + + /// \brief Returns a human readable string representation. + std::string toString() const; + + private: + void setFromSourceLocation(const SourceManager &Sources, + SourceLocation Start, unsigned Length, + StringRef ReplacementText); + void setFromSourceRange(const SourceManager &Sources, + const CharSourceRange &Range, + StringRef ReplacementText, + const LangOptions &LangOpts); + + std::string FilePath; + Range ReplacementRange; + std::string ReplacementText; +}; + +/// \brief Less-than operator between two Replacements. +bool operator<(const Replacement &LHS, const Replacement &RHS); + +/// \brief Equal-to operator between two Replacements. +bool operator==(const Replacement &LHS, const Replacement &RHS); + +/// \brief A set of Replacements. +/// FIXME: Change to a vector and deduplicate in the RefactoringTool. +typedef std::set<Replacement> Replacements; + +/// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite. +/// +/// Replacement applications happen independently of the success of +/// other applications. +/// +/// \returns true if all replacements apply. false otherwise. +bool applyAllReplacements(const Replacements &Replaces, Rewriter &Rewrite); + +/// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite. +/// +/// Replacement applications happen independently of the success of +/// other applications. +/// +/// \returns true if all replacements apply. false otherwise. +bool applyAllReplacements(const std::vector<Replacement> &Replaces, + Rewriter &Rewrite); + +/// \brief Applies all replacements in \p Replaces to \p Code. +/// +/// This completely ignores the path stored in each replacement. If one or more +/// replacements cannot be applied, this returns an empty \c string. +std::string applyAllReplacements(StringRef Code, const Replacements &Replaces); + +/// \brief Calculates how a code \p Position is shifted when \p Replaces are +/// applied. +unsigned shiftedCodePosition(const Replacements& Replaces, unsigned Position); + +/// \brief Calculates how a code \p Position is shifted when \p Replaces are +/// applied. +/// +/// \pre Replaces[i].getOffset() <= Replaces[i+1].getOffset(). +unsigned shiftedCodePosition(const std::vector<Replacement> &Replaces, + unsigned Position); + +/// \brief Removes duplicate Replacements and reports if Replacements conflict +/// with one another. All Replacements are assumed to be in the same file. +/// +/// \post Replaces[i].getOffset() <= Replaces[i+1].getOffset(). +/// +/// This function sorts \p Replaces so that conflicts can be reported simply by +/// offset into \p Replaces and number of elements in the conflict. +void deduplicate(std::vector<Replacement> &Replaces, + std::vector<Range> &Conflicts); + +/// \brief Collection of Replacements generated from a single translation unit. +struct TranslationUnitReplacements { + /// Name of the main source for the translation unit. + std::string MainSourceFile; + + /// A freeform chunk of text to describe the context of the replacements. + /// Will be printed, for example, when detecting conflicts during replacement + /// deduplication. + std::string Context; + + std::vector<Replacement> Replacements; +}; + +/// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite. +/// +/// Replacement applications happen independently of the success of +/// other applications. +/// +/// \returns true if all replacements apply. false otherwise. +bool applyAllReplacements(const Replacements &Replaces, Rewriter &Rewrite); + +/// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite. +/// +/// Replacement applications happen independently of the success of +/// other applications. +/// +/// \returns true if all replacements apply. false otherwise. +bool applyAllReplacements(const std::vector<Replacement> &Replaces, + Rewriter &Rewrite); + +/// \brief Applies all replacements in \p Replaces to \p Code. +/// +/// This completely ignores the path stored in each replacement. If one or more +/// replacements cannot be applied, this returns an empty \c string. +std::string applyAllReplacements(StringRef Code, const Replacements &Replaces); + +/// \brief Merges two sets of replacements with the second set referring to the +/// code after applying the first set. Within both 'First' and 'Second', +/// replacements must not overlap. +Replacements mergeReplacements(const Replacements &First, + const Replacements &Second); + +template <typename Node> +Replacement::Replacement(const SourceManager &Sources, + const Node &NodeToReplace, StringRef ReplacementText, + const LangOptions &LangOpts) { + const CharSourceRange Range = + CharSourceRange::getTokenRange(NodeToReplace->getSourceRange()); + setFromSourceRange(Sources, Range, ReplacementText, LangOpts); +} + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_CORE_REPLACEMENT_H diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/FileMatchTrie.h b/contrib/llvm/tools/clang/include/clang/Tooling/FileMatchTrie.h new file mode 100644 index 0000000..745c164 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Tooling/FileMatchTrie.h @@ -0,0 +1,89 @@ +//===--- FileMatchTrie.h - --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements a match trie to find the matching file in a compilation +// database based on a given path in the presence of symlinks. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_FILEMATCHTRIE_H +#define LLVM_CLANG_TOOLING_FILEMATCHTRIE_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/StringRef.h" +#include <memory> +#include <string> +#include <vector> + +namespace clang { +namespace tooling { + +struct PathComparator { + virtual ~PathComparator() {} + virtual bool equivalent(StringRef FileA, StringRef FileB) const = 0; +}; +class FileMatchTrieNode; + +/// \brief A trie to efficiently match against the entries of the compilation +/// database in order of matching suffix length. +/// +/// When a clang tool is supposed to operate on a specific file, we have to +/// find the corresponding file in the compilation database. Although entries +/// in the compilation database are keyed by filename, a simple string match +/// is insufficient because of symlinks. Commonly, a project hierarchy looks +/// like this: +/// /<project-root>/src/<path>/<somefile>.cc (used as input for the tool) +/// /<project-root>/build/<symlink-to-src>/<path>/<somefile>.cc (stored in DB) +/// +/// Furthermore, there might be symlinks inside the source folder or inside the +/// database, so that the same source file is translated with different build +/// options. +/// +/// For a given input file, the \c FileMatchTrie finds its entries in order +/// of matching suffix length. For each suffix length, there might be one or +/// more entries in the database. For each of those entries, it calls +/// \c llvm::sys::fs::equivalent() (injected as \c PathComparator). There might +/// be zero or more entries with the same matching suffix length that are +/// equivalent to the input file. Three cases are distinguished: +/// 0 equivalent files: Continue with the next suffix length. +/// 1 equivalent file: Best match found, return it. +/// >1 equivalent files: Match is ambiguous, return error. +class FileMatchTrie { +public: + FileMatchTrie(); + + /// \brief Construct a new \c FileMatchTrie with the given \c PathComparator. + /// + /// The \c FileMatchTrie takes ownership of 'Comparator'. Used for testing. + FileMatchTrie(PathComparator* Comparator); + + ~FileMatchTrie(); + + /// \brief Insert a new absolute path. Relative paths are ignored. + void insert(StringRef NewPath); + + /// \brief Finds the corresponding file in this trie. + /// + /// Returns file name stored in this trie that is equivalent to 'FileName' + /// according to 'Comparator', if it can be uniquely identified. If there + /// are no matches an empty \c StringRef is returned. If there are ambigious + /// matches, an empty \c StringRef is returned and a corresponding message + /// written to 'Error'. + StringRef findEquivalent(StringRef FileName, + raw_ostream &Error) const; +private: + FileMatchTrieNode *Root; + std::unique_ptr<PathComparator> Comparator; +}; + + +} // end namespace tooling +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/JSONCompilationDatabase.h b/contrib/llvm/tools/clang/include/clang/Tooling/JSONCompilationDatabase.h new file mode 100644 index 0000000..2a13fc1 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Tooling/JSONCompilationDatabase.h @@ -0,0 +1,133 @@ +//===--- JSONCompilationDatabase.h - ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// The JSONCompilationDatabase finds compilation databases supplied as a file +// 'compile_commands.json'. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_JSONCOMPILATIONDATABASE_H +#define LLVM_CLANG_TOOLING_JSONCOMPILATIONDATABASE_H + +#include "clang/Basic/LLVM.h" +#include "clang/Tooling/CompilationDatabase.h" +#include "clang/Tooling/FileMatchTrie.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/YAMLParser.h" +#include <memory> +#include <string> +#include <vector> + +namespace clang { +namespace tooling { + +/// \brief A JSON based compilation database. +/// +/// JSON compilation database files must contain a list of JSON objects which +/// provide the command lines in the attributes 'directory', 'command', +/// 'arguments' and 'file': +/// [ +/// { "directory": "<working directory of the compile>", +/// "command": "<compile command line>", +/// "file": "<path to source file>" +/// }, +/// { "directory": "<working directory of the compile>", +/// "arguments": ["<raw>", "<command>" "<line>" "<parameters>"], +/// "file": "<path to source file>" +/// }, +/// ... +/// ] +/// Each object entry defines one compile action. The specified file is +/// considered to be the main source file for the translation unit. +/// +/// 'command' is a full command line that will be unescaped. +/// +/// 'arguments' is a list of command line arguments that will not be unescaped. +/// +/// JSON compilation databases can for example be generated in CMake projects +/// by setting the flag -DCMAKE_EXPORT_COMPILE_COMMANDS. +class JSONCompilationDatabase : public CompilationDatabase { +public: + /// \brief Loads a JSON compilation database from the specified file. + /// + /// Returns NULL and sets ErrorMessage if the database could not be + /// loaded from the given file. + static std::unique_ptr<JSONCompilationDatabase> + loadFromFile(StringRef FilePath, std::string &ErrorMessage); + + /// \brief Loads a JSON compilation database from a data buffer. + /// + /// Returns NULL and sets ErrorMessage if the database could not be loaded. + static std::unique_ptr<JSONCompilationDatabase> + loadFromBuffer(StringRef DatabaseString, std::string &ErrorMessage); + + /// \brief Returns all compile comamnds in which the specified file was + /// compiled. + /// + /// FIXME: Currently FilePath must be an absolute path inside the + /// source directory which does not have symlinks resolved. + std::vector<CompileCommand> + getCompileCommands(StringRef FilePath) const override; + + /// \brief Returns the list of all files available in the compilation database. + /// + /// These are the 'file' entries of the JSON objects. + std::vector<std::string> getAllFiles() const override; + + /// \brief Returns all compile commands for all the files in the compilation + /// database. + std::vector<CompileCommand> getAllCompileCommands() const override; + +private: + /// \brief Constructs a JSON compilation database on a memory buffer. + JSONCompilationDatabase(std::unique_ptr<llvm::MemoryBuffer> Database) + : Database(std::move(Database)), + YAMLStream(this->Database->getBuffer(), SM) {} + + /// \brief Parses the database file and creates the index. + /// + /// Returns whether parsing succeeded. Sets ErrorMessage if parsing + /// failed. + bool parse(std::string &ErrorMessage); + + // Tuple (directory, filename, commandline) where 'commandline' points to the + // corresponding scalar nodes in the YAML stream. + // If the command line contains a single argument, it is a shell-escaped + // command line. + // Otherwise, each entry in the command line vector is a literal + // argument to the compiler. + typedef std::tuple<llvm::yaml::ScalarNode *, + llvm::yaml::ScalarNode *, + std::vector<llvm::yaml::ScalarNode *>> CompileCommandRef; + + /// \brief Converts the given array of CompileCommandRefs to CompileCommands. + void getCommands(ArrayRef<CompileCommandRef> CommandsRef, + std::vector<CompileCommand> &Commands) const; + + // Maps file paths to the compile command lines for that file. + llvm::StringMap<std::vector<CompileCommandRef>> IndexByFile; + + /// All the compile commands in the order that they were provided in the + /// JSON stream. + std::vector<CompileCommandRef> AllCommands; + + FileMatchTrie MatchTrie; + + std::unique_ptr<llvm::MemoryBuffer> Database; + llvm::SourceMgr SM; + llvm::yaml::Stream YAMLStream; +}; + +} // end namespace tooling +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring.h b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring.h new file mode 100644 index 0000000..54deff6 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring.h @@ -0,0 +1,74 @@ +//===--- Refactoring.h - Framework for clang refactoring tools --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Interfaces supporting refactorings that span multiple translation units. +// While single translation unit refactorings are supported via the Rewriter, +// when refactoring multiple translation units changes must be stored in a +// SourceManager independent form, duplicate changes need to be removed, and +// all changes must be applied at once at the end of the refactoring so that +// the code is always parseable. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTORING_H +#define LLVM_CLANG_TOOLING_REFACTORING_H + +#include "clang/Tooling/Core/Replacement.h" +#include "clang/Tooling/Tooling.h" +#include <string> + +namespace clang { + +class Rewriter; + +namespace tooling { + +/// \brief A tool to run refactorings. +/// +/// This is a refactoring specific version of \see ClangTool. FrontendActions +/// passed to run() and runAndSave() should add replacements to +/// getReplacements(). +class RefactoringTool : public ClangTool { +public: + /// \see ClangTool::ClangTool. + RefactoringTool(const CompilationDatabase &Compilations, + ArrayRef<std::string> SourcePaths, + std::shared_ptr<PCHContainerOperations> PCHContainerOps = + std::make_shared<PCHContainerOperations>()); + + /// \brief Returns the set of replacements to which replacements should + /// be added during the run of the tool. + Replacements &getReplacements(); + + /// \brief Call run(), apply all generated replacements, and immediately save + /// the results to disk. + /// + /// \returns 0 upon success. Non-zero upon failure. + int runAndSave(FrontendActionFactory *ActionFactory); + + /// \brief Apply all stored replacements to the given Rewriter. + /// + /// Replacement applications happen independently of the success of other + /// applications. + /// + /// \returns true if all replacements apply. false otherwise. + bool applyAllReplacements(Rewriter &Rewrite); + +private: + /// \brief Write all refactored files to disk. + int saveRewrittenFiles(Rewriter &Rewrite); + +private: + Replacements Replace; +}; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTORING_H diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/RefactoringCallbacks.h b/contrib/llvm/tools/clang/include/clang/Tooling/RefactoringCallbacks.h new file mode 100644 index 0000000..6ef9ea1 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Tooling/RefactoringCallbacks.h @@ -0,0 +1,90 @@ +//===--- RefactoringCallbacks.h - Structural query framework ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Provides callbacks to make common kinds of refactorings easy. +// +// The general idea is to construct a matcher expression that describes a +// subtree match on the AST and then replace the corresponding source code +// either by some specific text or some other AST node. +// +// Example: +// int main(int argc, char **argv) { +// ClangTool Tool(argc, argv); +// MatchFinder Finder; +// ReplaceStmtWithText Callback("integer", "42"); +// Finder.AddMatcher(id("integer", expression(integerLiteral())), Callback); +// return Tool.run(newFrontendActionFactory(&Finder)); +// } +// +// This will replace all integer literals with "42". +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTORINGCALLBACKS_H +#define LLVM_CLANG_TOOLING_REFACTORINGCALLBACKS_H + +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Tooling/Refactoring.h" + +namespace clang { +namespace tooling { + +/// \brief Base class for RefactoringCallbacks. +/// +/// Collects \c tooling::Replacements while running. +class RefactoringCallback : public ast_matchers::MatchFinder::MatchCallback { +public: + RefactoringCallback(); + Replacements &getReplacements(); + +protected: + Replacements Replace; +}; + +/// \brief Replace the text of the statement bound to \c FromId with the text in +/// \c ToText. +class ReplaceStmtWithText : public RefactoringCallback { +public: + ReplaceStmtWithText(StringRef FromId, StringRef ToText); + void run(const ast_matchers::MatchFinder::MatchResult &Result) override; + +private: + std::string FromId; + std::string ToText; +}; + +/// \brief Replace the text of the statement bound to \c FromId with the text of +/// the statement bound to \c ToId. +class ReplaceStmtWithStmt : public RefactoringCallback { +public: + ReplaceStmtWithStmt(StringRef FromId, StringRef ToId); + void run(const ast_matchers::MatchFinder::MatchResult &Result) override; + +private: + std::string FromId; + std::string ToId; +}; + +/// \brief Replace an if-statement bound to \c Id with the outdented text of its +/// body, choosing the consequent or the alternative based on whether +/// \c PickTrueBranch is true. +class ReplaceIfStmtWithItsBody : public RefactoringCallback { +public: + ReplaceIfStmtWithItsBody(StringRef Id, bool PickTrueBranch); + void run(const ast_matchers::MatchFinder::MatchResult &Result) override; + +private: + std::string Id; + const bool PickTrueBranch; +}; + +} // end namespace tooling +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/ReplacementsYaml.h b/contrib/llvm/tools/clang/include/clang/Tooling/ReplacementsYaml.h new file mode 100644 index 0000000..4a7666d --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Tooling/ReplacementsYaml.h @@ -0,0 +1,76 @@ +//===-- ReplacementsYaml.h -- Serialiazation for Replacements ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file defines the structure of a YAML document for serializing +/// replacements. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REPLACEMENTSYAML_H +#define LLVM_CLANG_TOOLING_REPLACEMENTSYAML_H + +#include "clang/Tooling/Refactoring.h" +#include "llvm/Support/YAMLTraits.h" +#include <string> +#include <vector> + +LLVM_YAML_IS_SEQUENCE_VECTOR(clang::tooling::Replacement) + +namespace llvm { +namespace yaml { + +/// \brief Specialized MappingTraits to describe how a Replacement is +/// (de)serialized. +template <> struct MappingTraits<clang::tooling::Replacement> { + /// \brief Helper to (de)serialize a Replacement since we don't have direct + /// access to its data members. + struct NormalizedReplacement { + NormalizedReplacement(const IO &) + : FilePath(""), Offset(0), Length(0), ReplacementText("") {} + + NormalizedReplacement(const IO &, const clang::tooling::Replacement &R) + : FilePath(R.getFilePath()), Offset(R.getOffset()), + Length(R.getLength()), ReplacementText(R.getReplacementText()) {} + + clang::tooling::Replacement denormalize(const IO &) { + return clang::tooling::Replacement(FilePath, Offset, Length, + ReplacementText); + } + + std::string FilePath; + unsigned int Offset; + unsigned int Length; + std::string ReplacementText; + }; + + static void mapping(IO &Io, clang::tooling::Replacement &R) { + MappingNormalization<NormalizedReplacement, clang::tooling::Replacement> + Keys(Io, R); + Io.mapRequired("FilePath", Keys->FilePath); + Io.mapRequired("Offset", Keys->Offset); + Io.mapRequired("Length", Keys->Length); + Io.mapRequired("ReplacementText", Keys->ReplacementText); + } +}; + +/// \brief Specialized MappingTraits to describe how a +/// TranslationUnitReplacements is (de)serialized. +template <> struct MappingTraits<clang::tooling::TranslationUnitReplacements> { + static void mapping(IO &Io, + clang::tooling::TranslationUnitReplacements &Doc) { + Io.mapRequired("MainSourceFile", Doc.MainSourceFile); + Io.mapOptional("Context", Doc.Context, std::string()); + Io.mapRequired("Replacements", Doc.Replacements); + } +}; +} // end namespace yaml +} // end namespace llvm + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Tooling.h b/contrib/llvm/tools/clang/include/clang/Tooling/Tooling.h new file mode 100644 index 0000000..b7a9b25 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Tooling/Tooling.h @@ -0,0 +1,455 @@ +//===--- Tooling.h - Framework for standalone Clang tools -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements functions to run clang tools standalone instead +// of running them as a plugin. +// +// A ClangTool is initialized with a CompilationDatabase and a set of files +// to run over. The tool will then run a user-specified FrontendAction over +// all TUs in which the given files are compiled. +// +// It is also possible to run a FrontendAction over a snippet of code by +// calling runToolOnCode, which is useful for unit testing. +// +// Applications that need more fine grained control over how to run +// multiple FrontendActions over code can use ToolInvocation. +// +// Example tools: +// - running clang -fsyntax-only over source code from an editor to get +// fast syntax checks +// - running match/replace tools over C++ code +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_TOOLING_H +#define LLVM_CLANG_TOOLING_TOOLING_H + +#include "clang/AST/ASTConsumer.h" +#include "clang/Frontend/PCHContainerOperations.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/LLVM.h" +#include "clang/Driver/Util.h" +#include "clang/Frontend/FrontendAction.h" +#include "clang/Lex/ModuleLoader.h" +#include "clang/Tooling/ArgumentsAdjusters.h" +#include "clang/Tooling/CompilationDatabase.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Option/Option.h" +#include <memory> +#include <string> +#include <vector> + +namespace clang { + +namespace driver { +class Compilation; +} // end namespace driver + +class CompilerInvocation; +class SourceManager; +class FrontendAction; + +namespace tooling { + +/// \brief Interface to process a clang::CompilerInvocation. +/// +/// If your tool is based on FrontendAction, you should be deriving from +/// FrontendActionFactory instead. +class ToolAction { +public: + virtual ~ToolAction(); + + /// \brief Perform an action for an invocation. + virtual bool + runInvocation(clang::CompilerInvocation *Invocation, FileManager *Files, + std::shared_ptr<PCHContainerOperations> PCHContainerOps, + DiagnosticConsumer *DiagConsumer) = 0; +}; + +/// \brief Interface to generate clang::FrontendActions. +/// +/// Having a factory interface allows, for example, a new FrontendAction to be +/// created for each translation unit processed by ClangTool. This class is +/// also a ToolAction which uses the FrontendActions created by create() to +/// process each translation unit. +class FrontendActionFactory : public ToolAction { +public: + ~FrontendActionFactory() override; + + /// \brief Invokes the compiler with a FrontendAction created by create(). + bool runInvocation(clang::CompilerInvocation *Invocation, FileManager *Files, + std::shared_ptr<PCHContainerOperations> PCHContainerOps, + DiagnosticConsumer *DiagConsumer) override; + + /// \brief Returns a new clang::FrontendAction. + /// + /// The caller takes ownership of the returned action. + virtual clang::FrontendAction *create() = 0; +}; + +/// \brief Returns a new FrontendActionFactory for a given type. +/// +/// T must derive from clang::FrontendAction. +/// +/// Example: +/// FrontendActionFactory *Factory = +/// newFrontendActionFactory<clang::SyntaxOnlyAction>(); +template <typename T> +std::unique_ptr<FrontendActionFactory> newFrontendActionFactory(); + +/// \brief Callbacks called before and after each source file processed by a +/// FrontendAction created by the FrontedActionFactory returned by \c +/// newFrontendActionFactory. +class SourceFileCallbacks { +public: + virtual ~SourceFileCallbacks() {} + + /// \brief Called before a source file is processed by a FrontEndAction. + /// \see clang::FrontendAction::BeginSourceFileAction + virtual bool handleBeginSource(CompilerInstance &CI, StringRef Filename) { + return true; + } + + /// \brief Called after a source file is processed by a FrontendAction. + /// \see clang::FrontendAction::EndSourceFileAction + virtual void handleEndSource() {} +}; + +/// \brief Returns a new FrontendActionFactory for any type that provides an +/// implementation of newASTConsumer(). +/// +/// FactoryT must implement: ASTConsumer *newASTConsumer(). +/// +/// Example: +/// struct ProvidesASTConsumers { +/// clang::ASTConsumer *newASTConsumer(); +/// } Factory; +/// std::unique_ptr<FrontendActionFactory> FactoryAdapter( +/// newFrontendActionFactory(&Factory)); +template <typename FactoryT> +inline std::unique_ptr<FrontendActionFactory> newFrontendActionFactory( + FactoryT *ConsumerFactory, SourceFileCallbacks *Callbacks = nullptr); + +/// \brief Runs (and deletes) the tool on 'Code' with the -fsyntax-only flag. +/// +/// \param ToolAction The action to run over the code. +/// \param Code C++ code. +/// \param FileName The file name which 'Code' will be mapped as. +/// \param PCHContainerOps The PCHContainerOperations for loading and creating +/// clang modules. +/// +/// \return - True if 'ToolAction' was successfully executed. +bool runToolOnCode(clang::FrontendAction *ToolAction, const Twine &Code, + const Twine &FileName = "input.cc", + std::shared_ptr<PCHContainerOperations> PCHContainerOps = + std::make_shared<PCHContainerOperations>()); + +/// The first part of the pair is the filename, the second part the +/// file-content. +typedef std::vector<std::pair<std::string, std::string>> FileContentMappings; + +/// \brief Runs (and deletes) the tool on 'Code' with the -fsyntax-only flag and +/// with additional other flags. +/// +/// \param ToolAction The action to run over the code. +/// \param Code C++ code. +/// \param Args Additional flags to pass on. +/// \param FileName The file name which 'Code' will be mapped as. +/// \param PCHContainerOps The PCHContainerOperations for loading and creating +/// clang modules. +/// +/// \return - True if 'ToolAction' was successfully executed. +bool runToolOnCodeWithArgs( + clang::FrontendAction *ToolAction, const Twine &Code, + const std::vector<std::string> &Args, const Twine &FileName = "input.cc", + std::shared_ptr<PCHContainerOperations> PCHContainerOps = + std::make_shared<PCHContainerOperations>(), + const FileContentMappings &VirtualMappedFiles = FileContentMappings()); + +/// \brief Builds an AST for 'Code'. +/// +/// \param Code C++ code. +/// \param FileName The file name which 'Code' will be mapped as. +/// \param PCHContainerOps The PCHContainerOperations for loading and creating +/// clang modules. +/// +/// \return The resulting AST or null if an error occurred. +std::unique_ptr<ASTUnit> +buildASTFromCode(const Twine &Code, const Twine &FileName = "input.cc", + std::shared_ptr<PCHContainerOperations> PCHContainerOps = + std::make_shared<PCHContainerOperations>()); + +/// \brief Builds an AST for 'Code' with additional flags. +/// +/// \param Code C++ code. +/// \param Args Additional flags to pass on. +/// \param FileName The file name which 'Code' will be mapped as. +/// \param PCHContainerOps The PCHContainerOperations for loading and creating +/// clang modules. +/// +/// \return The resulting AST or null if an error occurred. +std::unique_ptr<ASTUnit> buildASTFromCodeWithArgs( + const Twine &Code, const std::vector<std::string> &Args, + const Twine &FileName = "input.cc", + std::shared_ptr<PCHContainerOperations> PCHContainerOps = + std::make_shared<PCHContainerOperations>()); + +/// \brief Utility to run a FrontendAction in a single clang invocation. +class ToolInvocation { +public: + /// \brief Create a tool invocation. + /// + /// \param CommandLine The command line arguments to clang. Note that clang + /// uses its binary name (CommandLine[0]) to locate its builtin headers. + /// Callers have to ensure that they are installed in a compatible location + /// (see clang driver implementation) or mapped in via mapVirtualFile. + /// \param FAction The action to be executed. Class takes ownership. + /// \param Files The FileManager used for the execution. Class does not take + /// ownership. + /// \param PCHContainerOps The PCHContainerOperations for loading and creating + /// clang modules. + ToolInvocation(std::vector<std::string> CommandLine, FrontendAction *FAction, + FileManager *Files, + std::shared_ptr<PCHContainerOperations> PCHContainerOps = + std::make_shared<PCHContainerOperations>()); + + /// \brief Create a tool invocation. + /// + /// \param CommandLine The command line arguments to clang. + /// \param Action The action to be executed. + /// \param Files The FileManager used for the execution. + /// \param PCHContainerOps The PCHContainerOperations for loading and creating + /// clang modules. + ToolInvocation(std::vector<std::string> CommandLine, ToolAction *Action, + FileManager *Files, + std::shared_ptr<PCHContainerOperations> PCHContainerOps); + + ~ToolInvocation(); + + /// \brief Set a \c DiagnosticConsumer to use during parsing. + void setDiagnosticConsumer(DiagnosticConsumer *DiagConsumer) { + this->DiagConsumer = DiagConsumer; + } + + /// \brief Map a virtual file to be used while running the tool. + /// + /// \param FilePath The path at which the content will be mapped. + /// \param Content A null terminated buffer of the file's content. + // FIXME: remove this when all users have migrated! + void mapVirtualFile(StringRef FilePath, StringRef Content); + + /// \brief Run the clang invocation. + /// + /// \returns True if there were no errors during execution. + bool run(); + + private: + void addFileMappingsTo(SourceManager &SourceManager); + + bool runInvocation(const char *BinaryName, + clang::driver::Compilation *Compilation, + clang::CompilerInvocation *Invocation, + std::shared_ptr<PCHContainerOperations> PCHContainerOps); + + std::vector<std::string> CommandLine; + ToolAction *Action; + bool OwnsAction; + FileManager *Files; + std::shared_ptr<PCHContainerOperations> PCHContainerOps; + // Maps <file name> -> <file content>. + llvm::StringMap<StringRef> MappedFileContents; + DiagnosticConsumer *DiagConsumer; +}; + +/// \brief Utility to run a FrontendAction over a set of files. +/// +/// This class is written to be usable for command line utilities. +/// By default the class uses ClangSyntaxOnlyAdjuster to modify +/// command line arguments before the arguments are used to run +/// a frontend action. One could install an additional command line +/// arguments adjuster by calling the appendArgumentsAdjuster() method. +class ClangTool { + public: + /// \brief Constructs a clang tool to run over a list of files. + /// + /// \param Compilations The CompilationDatabase which contains the compile + /// command lines for the given source paths. + /// \param SourcePaths The source files to run over. If a source files is + /// not found in Compilations, it is skipped. + /// \param PCHContainerOps The PCHContainerOperations for loading and creating + /// clang modules. + ClangTool(const CompilationDatabase &Compilations, + ArrayRef<std::string> SourcePaths, + std::shared_ptr<PCHContainerOperations> PCHContainerOps = + std::make_shared<PCHContainerOperations>()); + + ~ClangTool(); + + /// \brief Set a \c DiagnosticConsumer to use during parsing. + void setDiagnosticConsumer(DiagnosticConsumer *DiagConsumer) { + this->DiagConsumer = DiagConsumer; + } + + /// \brief Map a virtual file to be used while running the tool. + /// + /// \param FilePath The path at which the content will be mapped. + /// \param Content A null terminated buffer of the file's content. + void mapVirtualFile(StringRef FilePath, StringRef Content); + + /// \brief Append a command line arguments adjuster to the adjuster chain. + /// + /// \param Adjuster An argument adjuster, which will be run on the output of + /// previous argument adjusters. + void appendArgumentsAdjuster(ArgumentsAdjuster Adjuster); + + /// \brief Clear the command line arguments adjuster chain. + void clearArgumentsAdjusters(); + + /// Runs an action over all files specified in the command line. + /// + /// \param Action Tool action. + int run(ToolAction *Action); + + /// \brief Create an AST for each file specified in the command line and + /// append them to ASTs. + int buildASTs(std::vector<std::unique_ptr<ASTUnit>> &ASTs); + + /// \brief Returns the file manager used in the tool. + /// + /// The file manager is shared between all translation units. + FileManager &getFiles() { return *Files; } + + private: + const CompilationDatabase &Compilations; + std::vector<std::string> SourcePaths; + std::shared_ptr<PCHContainerOperations> PCHContainerOps; + + llvm::IntrusiveRefCntPtr<vfs::OverlayFileSystem> OverlayFileSystem; + llvm::IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem; + llvm::IntrusiveRefCntPtr<FileManager> Files; + // Contains a list of pairs (<file name>, <file content>). + std::vector< std::pair<StringRef, StringRef> > MappedFileContents; + llvm::StringSet<> SeenWorkingDirectories; + + ArgumentsAdjuster ArgsAdjuster; + + DiagnosticConsumer *DiagConsumer; +}; + +template <typename T> +std::unique_ptr<FrontendActionFactory> newFrontendActionFactory() { + class SimpleFrontendActionFactory : public FrontendActionFactory { + public: + clang::FrontendAction *create() override { return new T; } + }; + + return std::unique_ptr<FrontendActionFactory>( + new SimpleFrontendActionFactory); +} + +template <typename FactoryT> +inline std::unique_ptr<FrontendActionFactory> newFrontendActionFactory( + FactoryT *ConsumerFactory, SourceFileCallbacks *Callbacks) { + class FrontendActionFactoryAdapter : public FrontendActionFactory { + public: + explicit FrontendActionFactoryAdapter(FactoryT *ConsumerFactory, + SourceFileCallbacks *Callbacks) + : ConsumerFactory(ConsumerFactory), Callbacks(Callbacks) {} + + clang::FrontendAction *create() override { + return new ConsumerFactoryAdaptor(ConsumerFactory, Callbacks); + } + + private: + class ConsumerFactoryAdaptor : public clang::ASTFrontendAction { + public: + ConsumerFactoryAdaptor(FactoryT *ConsumerFactory, + SourceFileCallbacks *Callbacks) + : ConsumerFactory(ConsumerFactory), Callbacks(Callbacks) {} + + std::unique_ptr<clang::ASTConsumer> + CreateASTConsumer(clang::CompilerInstance &, StringRef) override { + return ConsumerFactory->newASTConsumer(); + } + + protected: + bool BeginSourceFileAction(CompilerInstance &CI, + StringRef Filename) override { + if (!clang::ASTFrontendAction::BeginSourceFileAction(CI, Filename)) + return false; + if (Callbacks) + return Callbacks->handleBeginSource(CI, Filename); + return true; + } + void EndSourceFileAction() override { + if (Callbacks) + Callbacks->handleEndSource(); + clang::ASTFrontendAction::EndSourceFileAction(); + } + + private: + FactoryT *ConsumerFactory; + SourceFileCallbacks *Callbacks; + }; + FactoryT *ConsumerFactory; + SourceFileCallbacks *Callbacks; + }; + + return std::unique_ptr<FrontendActionFactory>( + new FrontendActionFactoryAdapter(ConsumerFactory, Callbacks)); +} + +/// \brief Returns the absolute path of \c File, by prepending it with +/// the current directory if \c File is not absolute. +/// +/// Otherwise returns \c File. +/// If 'File' starts with "./", the returned path will not contain the "./". +/// Otherwise, the returned path will contain the literal path-concatenation of +/// the current directory and \c File. +/// +/// The difference to llvm::sys::fs::make_absolute is the canonicalization this +/// does by removing "./" and computing native paths. +/// +/// \param File Either an absolute or relative path. +std::string getAbsolutePath(StringRef File); + +/// \brief Changes CommandLine to contain implicit flags that would have been +/// defined had the compiler driver been invoked through the path InvokedAs. +/// +/// For example, when called with \c InvokedAs set to `i686-linux-android-g++`, +/// the arguments '-target', 'i686-linux-android`, `--driver-mode=g++` will +/// be inserted after the first argument in \c CommandLine. +/// +/// This function will not add new `-target` or `--driver-mode` flags if they +/// are already present in `CommandLine` (even if they have different settings +/// than would have been inserted). +/// +/// \pre `llvm::InitializeAllTargets()` has been called. +/// +/// \param CommandLine the command line used to invoke the compiler driver or +/// Clang tool, including the path to the executable as \c CommandLine[0]. +/// \param InvokedAs the path to the driver used to infer implicit flags. +/// +/// \note This will not set \c CommandLine[0] to \c InvokedAs. The tooling +/// infrastructure expects that CommandLine[0] is a tool path relative to which +/// the builtin headers can be found. +void addTargetAndModeForProgramName(std::vector<std::string> &CommandLine, + StringRef InvokedAs); + +/// \brief Creates a \c CompilerInvocation. +clang::CompilerInvocation *newInvocation( + clang::DiagnosticsEngine *Diagnostics, + const llvm::opt::ArgStringList &CC1Args); + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_TOOLING_H diff --git a/contrib/llvm/tools/clang/include/clang/module.modulemap b/contrib/llvm/tools/clang/include/clang/module.modulemap new file mode 100644 index 0000000..28b6d16 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/module.modulemap @@ -0,0 +1,134 @@ +module Clang_Analysis { + requires cplusplus + umbrella "Analysis" + + textual header "Analysis/Analyses/ThreadSafetyOps.def" + + module * { export * } +} + +module Clang_AST { + requires cplusplus + umbrella "AST" + + textual header "AST/BuiltinTypes.def" + textual header "AST/TypeLocNodes.def" + textual header "AST/TypeNodes.def" + + module * { export * } +} + +module Clang_ASTMatchers { requires cplusplus umbrella "ASTMatchers" module * { export * } } + +module Clang_Basic { + requires cplusplus + umbrella "Basic" + + textual header "Basic/BuiltinsAArch64.def" + textual header "Basic/BuiltinsAMDGPU.def" + textual header "Basic/BuiltinsARM.def" + textual header "Basic/Builtins.def" + textual header "Basic/BuiltinsHexagon.def" + textual header "Basic/BuiltinsLe64.def" + textual header "Basic/BuiltinsMips.def" + textual header "Basic/BuiltinsNEON.def" + textual header "Basic/BuiltinsNVPTX.def" + textual header "Basic/BuiltinsPPC.def" + textual header "Basic/BuiltinsSystemZ.def" + textual header "Basic/BuiltinsWebAssembly.def" + textual header "Basic/BuiltinsX86.def" + textual header "Basic/BuiltinsXCore.def" + textual header "Basic/DiagnosticOptions.def" + textual header "Basic/LangOptions.def" + textual header "Basic/OpenCLExtensions.def" + textual header "Basic/OpenMPKinds.def" + textual header "Basic/OperatorKinds.def" + textual header "Basic/Sanitizers.def" + textual header "Basic/TokenKinds.def" + + module * { export * } +} + +module Clang_CodeGen { requires cplusplus umbrella "CodeGen" module * { export * } } +module Clang_Config { requires cplusplus umbrella "Config" module * { export * } } + +// Files for diagnostic groups are spread all over the include/clang/ tree, but +// logically form a single module. +module Clang_Diagnostics { + requires cplusplus + + module All { header "Basic/AllDiagnostics.h" export * } + module Analysis { header "Analysis/AnalysisDiagnostic.h" export * } + module AST { header "AST/ASTDiagnostic.h" export * } + module Comment { header "AST/CommentDiagnostic.h" export * } + module Driver { header "Driver/DriverDiagnostic.h" export * } + module Frontend { header "Frontend/FrontendDiagnostic.h" export * } + module Lex { header "Lex/LexDiagnostic.h" export * } + module Parse { header "Parse/ParseDiagnostic.h" export * } + // FIXME: This breaks the build of Clang_Sema, for unknown reasons. + //module Sema { header "Sema/SemaDiagnostic.h" export * } + module Serialization { header "Serialization/SerializationDiagnostic.h" export * } +} + +module Clang_Driver { + requires cplusplus + umbrella "Driver" + + textual header "Driver/Types.def" + + module * { export * } +} + +module Clang_Edit { requires cplusplus umbrella "Edit" module * { export * } } +module Clang_Format { requires cplusplus umbrella "Format" module * { export * } } + +module Clang_Frontend { + requires cplusplus + umbrella "Frontend" + + textual header "Frontend/CodeGenOptions.def" + textual header "Frontend/LangStandards.def" + + module * { export * } + + // FIXME: This violates layers. + exclude header "Frontend/PCHContainerOperations.h" +} + +module Clang_FrontendTool { requires cplusplus umbrella "FrontendTool" module * { export * } } +module Clang_Index { requires cplusplus umbrella "Index" module * { export * } } +module Clang_Lex { requires cplusplus umbrella "Lex" module * { export * } } +module Clang_Parse { requires cplusplus umbrella "Parse" module * { export * } } +module Clang_Rewrite { requires cplusplus umbrella "Rewrite" module * { export * } } +module Clang_Sema { requires cplusplus umbrella "Sema" module * { export * } } +module Clang_Serialization { requires cplusplus umbrella "Serialization" module * { export * } } + +module Clang_StaticAnalyzer_Core { + requires cplusplus + umbrella "StaticAnalyzer/Core" + + textual header "StaticAnalyzer/Core/Analyses.def" + + module * { export * } +} + +module Clang_StaticAnalyzer_Checkers { + requires cplusplus + umbrella "StaticAnalyzer/Checkers" + module * { export * } +} + +module Clang_StaticAnalyzer_Frontend { + requires cplusplus + umbrella "StaticAnalyzer/Frontend" + module * { export * } +} + +module Clang_Tooling { + requires cplusplus umbrella "Tooling" module * { export * } + // FIXME: Exclude this header to avoid pulling all of the AST matchers + // library into clang-format. Due to inline key functions in the headers, + // importing the AST matchers library gives a link dependency on the AST + // matchers (and thus the AST), which clang-format should not have. + exclude header "Tooling/RefactoringCallbacks.h" +} |