Merge clang 3.5.0 release from ^/vendor/clang/dist, resolve conflicts,
and preserve our customizations, where necessary.
This commit is contained in:
commit
59d1ed5b20
contrib/llvm/tools/clang
LICENSE.TXT
include
clang-c
clang
ARCMigrate
AST
APValue.hASTConsumer.hASTContext.hASTDiagnostic.hASTImporter.hASTLambda.hASTMutationListener.hASTTypeTraits.hASTUnresolvedSet.hASTVector.hAttr.hAttrIterator.hCXXInheritance.hCanonicalType.hCharUnits.hComment.hCommentCommands.tdCommentHTMLTags.tdCommentLexer.hCommentSema.hDataRecursiveASTVisitor.hDecl.hDeclBase.hDeclCXX.hDeclContextInternals.hDeclFriend.hDeclGroup.hDeclLookups.hDeclObjC.hDeclOpenMP.hDeclTemplate.hDeclarationName.hDependentDiagnostic.hExpr.hExprCXX.hExprObjC.hExternalASTSource.hLambdaCapture.hMangle.hMangleNumberingContext.hNestedNameSpecifier.hOpenMPClause.hOperationKinds.hParentMap.hPrettyPrinter.hRawCommentList.hRecordLayout.hRecursiveASTVisitor.hRedeclarable.hStmt.hStmtCXX.hStmtIterator.hStmtObjC.hStmtOpenMP.hTemplateBase.hTemplateName.hType.hTypeLoc.hTypeNodes.defUnresolvedSet.hVTableBuilder.h
ASTMatchers
Analysis
Analyses
Consumed.hDominators.hFormatString.hLiveVariables.hPostOrderCFGView.hReachableCode.hThreadSafety.hThreadSafetyCommon.hThreadSafetyLogical.hThreadSafetyOps.defThreadSafetyTIL.hThreadSafetyTraverse.hThreadSafetyUtil.h
AnalysisContext.hCFG.hFlowSensitive
ProgramPoint.hSupport
Basic
@ -4,7 +4,7 @@ LLVM Release License
|
||||
University of Illinois/NCSA
|
||||
Open Source License
|
||||
|
||||
Copyright (c) 2007-2013 University of Illinois at Urbana-Champaign.
|
||||
Copyright (c) 2007-2014 University of Illinois at Urbana-Champaign.
|
||||
All rights reserved.
|
||||
|
||||
Developed by:
|
||||
|
148
contrib/llvm/tools/clang/include/clang-c/BuildSystem.h
Normal file
148
contrib/llvm/tools/clang/include/clang-c/BuildSystem.h
Normal file
@ -0,0 +1,148 @@
|
||||
/*==-- 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 CLANG_C_BUILD_SYSTEM_H
|
||||
#define CLANG_C_BUILD_SYSTEM_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 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 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 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 */
|
||||
|
64
contrib/llvm/tools/clang/include/clang-c/CXErrorCode.h
Normal file
64
contrib/llvm/tools/clang/include/clang-c/CXErrorCode.h
Normal file
@ -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 CLANG_C_CXERRORCODE_H
|
||||
#define 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
|
||||
|
@ -31,7 +31,7 @@ extern "C" {
|
||||
* \brief A character string.
|
||||
*
|
||||
* The \c CXString type is used to return strings from the interface when
|
||||
* the ownership of that string might different from one call to the next.
|
||||
* 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.
|
||||
*/
|
||||
|
554
contrib/llvm/tools/clang/include/clang-c/Documentation.h
Normal file
554
contrib/llvm/tools/clang/include/clang-c/Documentation.h
Normal file
@ -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 CLANG_C_DOCUMENTATION_H
|
||||
#define 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 */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,4 @@
|
||||
module Clang_C {
|
||||
umbrella "."
|
||||
module * { export * }
|
||||
}
|
@ -113,7 +113,7 @@ class MigrationProcess {
|
||||
virtual void remove(CharSourceRange range) { }
|
||||
};
|
||||
|
||||
bool applyTransform(TransformFn trans, RewriteListener *listener = 0);
|
||||
bool applyTransform(TransformFn trans, RewriteListener *listener = nullptr);
|
||||
|
||||
FileRemapper &getRemapper() { return Remapper; }
|
||||
};
|
||||
|
@ -12,14 +12,14 @@
|
||||
|
||||
#include "clang/ARCMigrate/FileRemapper.h"
|
||||
#include "clang/Frontend/FrontendAction.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include <memory>
|
||||
|
||||
namespace clang {
|
||||
namespace arcmt {
|
||||
|
||||
class CheckAction : public WrapperFrontendAction {
|
||||
protected:
|
||||
virtual bool BeginInvocation(CompilerInstance &CI);
|
||||
bool BeginInvocation(CompilerInstance &CI) override;
|
||||
|
||||
public:
|
||||
CheckAction(FrontendAction *WrappedAction);
|
||||
@ -27,7 +27,7 @@ class CheckAction : public WrapperFrontendAction {
|
||||
|
||||
class ModifyAction : public WrapperFrontendAction {
|
||||
protected:
|
||||
virtual bool BeginInvocation(CompilerInstance &CI);
|
||||
bool BeginInvocation(CompilerInstance &CI) override;
|
||||
|
||||
public:
|
||||
ModifyAction(FrontendAction *WrappedAction);
|
||||
@ -36,9 +36,9 @@ class ModifyAction : public WrapperFrontendAction {
|
||||
class MigrateSourceAction : public ASTFrontendAction {
|
||||
FileRemapper Remapper;
|
||||
protected:
|
||||
virtual bool BeginInvocation(CompilerInstance &CI);
|
||||
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
|
||||
StringRef InFile);
|
||||
bool BeginInvocation(CompilerInstance &CI) override;
|
||||
ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
|
||||
StringRef InFile) override;
|
||||
};
|
||||
|
||||
class MigrateAction : public WrapperFrontendAction {
|
||||
@ -46,7 +46,7 @@ class MigrateAction : public WrapperFrontendAction {
|
||||
std::string PlistOut;
|
||||
bool EmitPremigrationARCErros;
|
||||
protected:
|
||||
virtual bool BeginInvocation(CompilerInstance &CI);
|
||||
bool BeginInvocation(CompilerInstance &CI) override;
|
||||
|
||||
public:
|
||||
MigrateAction(FrontendAction *WrappedAction, StringRef migrateDir,
|
||||
@ -65,8 +65,9 @@ class ObjCMigrateAction : public WrapperFrontendAction {
|
||||
unsigned migrateAction);
|
||||
|
||||
protected:
|
||||
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,StringRef InFile);
|
||||
virtual bool BeginInvocation(CompilerInstance &CI);
|
||||
ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
|
||||
StringRef InFile) override;
|
||||
bool BeginInvocation(CompilerInstance &CI) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -12,9 +12,9 @@
|
||||
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include <memory>
|
||||
|
||||
namespace llvm {
|
||||
class MemoryBuffer;
|
||||
@ -30,7 +30,7 @@ namespace arcmt {
|
||||
|
||||
class FileRemapper {
|
||||
// FIXME: Reuse the same FileManager for multiple ASTContexts.
|
||||
OwningPtr<FileManager> FileMgr;
|
||||
std::unique_ptr<FileManager> FileMgr;
|
||||
|
||||
typedef llvm::PointerUnion<const FileEntry *, llvm::MemoryBuffer *> Target;
|
||||
typedef llvm::DenseMap<const FileEntry *, Target> MappingsTy;
|
||||
@ -56,8 +56,6 @@ class FileRemapper {
|
||||
|
||||
void applyMappings(PreprocessorOptions &PPOpts) const;
|
||||
|
||||
void transferMappingsAndClear(PreprocessorOptions &PPOpts);
|
||||
|
||||
void clear(StringRef outputDir = StringRef());
|
||||
|
||||
private:
|
||||
|
@ -80,7 +80,7 @@ class APValue {
|
||||
struct Vec {
|
||||
APValue *Elts;
|
||||
unsigned NumElts;
|
||||
Vec() : Elts(0), NumElts(0) {}
|
||||
Vec() : Elts(nullptr), NumElts(0) {}
|
||||
~Vec() { delete[] Elts; }
|
||||
};
|
||||
struct Arr {
|
||||
@ -108,34 +108,33 @@ class APValue {
|
||||
};
|
||||
struct MemberPointerData;
|
||||
|
||||
enum {
|
||||
MaxSize = (sizeof(ComplexAPSInt) > sizeof(ComplexAPFloat) ?
|
||||
sizeof(ComplexAPSInt) : sizeof(ComplexAPFloat))
|
||||
};
|
||||
// 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);
|
||||
|
||||
union {
|
||||
void *Aligner;
|
||||
char Data[MaxSize];
|
||||
};
|
||||
DataType Data;
|
||||
|
||||
public:
|
||||
APValue() : Kind(Uninitialized) {}
|
||||
explicit APValue(const APSInt &I) : Kind(Uninitialized) {
|
||||
MakeInt(); setInt(I);
|
||||
explicit APValue(APSInt I) : Kind(Uninitialized) {
|
||||
MakeInt(); setInt(std::move(I));
|
||||
}
|
||||
explicit APValue(const APFloat &F) : Kind(Uninitialized) {
|
||||
MakeFloat(); setFloat(F);
|
||||
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(const APSInt &R, const APSInt &I) : Kind(Uninitialized) {
|
||||
MakeComplexInt(); setComplexInt(R, I);
|
||||
APValue(APSInt R, APSInt I) : Kind(Uninitialized) {
|
||||
MakeComplexInt(); setComplexInt(std::move(R), std::move(I));
|
||||
}
|
||||
APValue(const APFloat &R, const APFloat &I) : Kind(Uninitialized) {
|
||||
MakeComplexFloat(); setComplexFloat(R, 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);
|
||||
@ -200,7 +199,7 @@ class APValue {
|
||||
|
||||
APSInt &getInt() {
|
||||
assert(isInt() && "Invalid accessor");
|
||||
return *(APSInt*)(char*)Data;
|
||||
return *(APSInt*)(char*)Data.buffer;
|
||||
}
|
||||
const APSInt &getInt() const {
|
||||
return const_cast<APValue*>(this)->getInt();
|
||||
@ -208,7 +207,7 @@ class APValue {
|
||||
|
||||
APFloat &getFloat() {
|
||||
assert(isFloat() && "Invalid accessor");
|
||||
return *(APFloat*)(char*)Data;
|
||||
return *(APFloat*)(char*)Data.buffer;
|
||||
}
|
||||
const APFloat &getFloat() const {
|
||||
return const_cast<APValue*>(this)->getFloat();
|
||||
@ -216,7 +215,7 @@ class APValue {
|
||||
|
||||
APSInt &getComplexIntReal() {
|
||||
assert(isComplexInt() && "Invalid accessor");
|
||||
return ((ComplexAPSInt*)(char*)Data)->Real;
|
||||
return ((ComplexAPSInt*)(char*)Data.buffer)->Real;
|
||||
}
|
||||
const APSInt &getComplexIntReal() const {
|
||||
return const_cast<APValue*>(this)->getComplexIntReal();
|
||||
@ -224,7 +223,7 @@ class APValue {
|
||||
|
||||
APSInt &getComplexIntImag() {
|
||||
assert(isComplexInt() && "Invalid accessor");
|
||||
return ((ComplexAPSInt*)(char*)Data)->Imag;
|
||||
return ((ComplexAPSInt*)(char*)Data.buffer)->Imag;
|
||||
}
|
||||
const APSInt &getComplexIntImag() const {
|
||||
return const_cast<APValue*>(this)->getComplexIntImag();
|
||||
@ -232,7 +231,7 @@ class APValue {
|
||||
|
||||
APFloat &getComplexFloatReal() {
|
||||
assert(isComplexFloat() && "Invalid accessor");
|
||||
return ((ComplexAPFloat*)(char*)Data)->Real;
|
||||
return ((ComplexAPFloat*)(char*)Data.buffer)->Real;
|
||||
}
|
||||
const APFloat &getComplexFloatReal() const {
|
||||
return const_cast<APValue*>(this)->getComplexFloatReal();
|
||||
@ -240,7 +239,7 @@ class APValue {
|
||||
|
||||
APFloat &getComplexFloatImag() {
|
||||
assert(isComplexFloat() && "Invalid accessor");
|
||||
return ((ComplexAPFloat*)(char*)Data)->Imag;
|
||||
return ((ComplexAPFloat*)(char*)Data.buffer)->Imag;
|
||||
}
|
||||
const APFloat &getComplexFloatImag() const {
|
||||
return const_cast<APValue*>(this)->getComplexFloatImag();
|
||||
@ -259,20 +258,20 @@ class APValue {
|
||||
APValue &getVectorElt(unsigned I) {
|
||||
assert(isVector() && "Invalid accessor");
|
||||
assert(I < getVectorLength() && "Index out of range");
|
||||
return ((Vec*)(char*)Data)->Elts[I];
|
||||
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)->NumElts;
|
||||
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)->Elts[I];
|
||||
return ((Arr*)(char*)Data.buffer)->Elts[I];
|
||||
}
|
||||
const APValue &getArrayInitializedElt(unsigned I) const {
|
||||
return const_cast<APValue*>(this)->getArrayInitializedElt(I);
|
||||
@ -283,35 +282,35 @@ class APValue {
|
||||
APValue &getArrayFiller() {
|
||||
assert(isArray() && "Invalid accessor");
|
||||
assert(hasArrayFiller() && "No array filler");
|
||||
return ((Arr*)(char*)Data)->Elts[getArrayInitializedElts()];
|
||||
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)->NumElts;
|
||||
return ((const Arr*)(const void *)Data.buffer)->NumElts;
|
||||
}
|
||||
unsigned getArraySize() const {
|
||||
assert(isArray() && "Invalid accessor");
|
||||
return ((const Arr*)(const void *)Data)->ArrSize;
|
||||
return ((const Arr*)(const void *)Data.buffer)->ArrSize;
|
||||
}
|
||||
|
||||
unsigned getStructNumBases() const {
|
||||
assert(isStruct() && "Invalid accessor");
|
||||
return ((const StructData*)(const char*)Data)->NumBases;
|
||||
return ((const StructData*)(const char*)Data.buffer)->NumBases;
|
||||
}
|
||||
unsigned getStructNumFields() const {
|
||||
assert(isStruct() && "Invalid accessor");
|
||||
return ((const StructData*)(const char*)Data)->NumFields;
|
||||
return ((const StructData*)(const char*)Data.buffer)->NumFields;
|
||||
}
|
||||
APValue &getStructBase(unsigned i) {
|
||||
assert(isStruct() && "Invalid accessor");
|
||||
return ((StructData*)(char*)Data)->Elts[i];
|
||||
return ((StructData*)(char*)Data.buffer)->Elts[i];
|
||||
}
|
||||
APValue &getStructField(unsigned i) {
|
||||
assert(isStruct() && "Invalid accessor");
|
||||
return ((StructData*)(char*)Data)->Elts[getStructNumBases() + i];
|
||||
return ((StructData*)(char*)Data.buffer)->Elts[getStructNumBases() + i];
|
||||
}
|
||||
const APValue &getStructBase(unsigned i) const {
|
||||
return const_cast<APValue*>(this)->getStructBase(i);
|
||||
@ -322,11 +321,11 @@ class APValue {
|
||||
|
||||
const FieldDecl *getUnionField() const {
|
||||
assert(isUnion() && "Invalid accessor");
|
||||
return ((const UnionData*)(const char*)Data)->Field;
|
||||
return ((const UnionData*)(const char*)Data.buffer)->Field;
|
||||
}
|
||||
APValue &getUnionValue() {
|
||||
assert(isUnion() && "Invalid accessor");
|
||||
return *((UnionData*)(char*)Data)->Value;
|
||||
return *((UnionData*)(char*)Data.buffer)->Value;
|
||||
}
|
||||
const APValue &getUnionValue() const {
|
||||
return const_cast<APValue*>(this)->getUnionValue();
|
||||
@ -338,41 +337,41 @@ class APValue {
|
||||
|
||||
const AddrLabelExpr* getAddrLabelDiffLHS() const {
|
||||
assert(isAddrLabelDiff() && "Invalid accessor");
|
||||
return ((const AddrLabelDiffData*)(const char*)Data)->LHSExpr;
|
||||
return ((const AddrLabelDiffData*)(const char*)Data.buffer)->LHSExpr;
|
||||
}
|
||||
const AddrLabelExpr* getAddrLabelDiffRHS() const {
|
||||
assert(isAddrLabelDiff() && "Invalid accessor");
|
||||
return ((const AddrLabelDiffData*)(const char*)Data)->RHSExpr;
|
||||
return ((const AddrLabelDiffData*)(const char*)Data.buffer)->RHSExpr;
|
||||
}
|
||||
|
||||
void setInt(const APSInt &I) {
|
||||
void setInt(APSInt I) {
|
||||
assert(isInt() && "Invalid accessor");
|
||||
*(APSInt*)(char*)Data = I;
|
||||
*(APSInt *)(char *)Data.buffer = std::move(I);
|
||||
}
|
||||
void setFloat(const APFloat &F) {
|
||||
void setFloat(APFloat F) {
|
||||
assert(isFloat() && "Invalid accessor");
|
||||
*(APFloat*)(char*)Data = F;
|
||||
*(APFloat *)(char *)Data.buffer = std::move(F);
|
||||
}
|
||||
void setVector(const APValue *E, unsigned N) {
|
||||
assert(isVector() && "Invalid accessor");
|
||||
((Vec*)(char*)Data)->Elts = new APValue[N];
|
||||
((Vec*)(char*)Data)->NumElts = N;
|
||||
((Vec*)(char*)Data.buffer)->Elts = new APValue[N];
|
||||
((Vec*)(char*)Data.buffer)->NumElts = N;
|
||||
for (unsigned i = 0; i != N; ++i)
|
||||
((Vec*)(char*)Data)->Elts[i] = E[i];
|
||||
((Vec*)(char*)Data.buffer)->Elts[i] = E[i];
|
||||
}
|
||||
void setComplexInt(const APSInt &R, const APSInt &I) {
|
||||
void setComplexInt(APSInt R, APSInt I) {
|
||||
assert(R.getBitWidth() == I.getBitWidth() &&
|
||||
"Invalid complex int (type mismatch).");
|
||||
assert(isComplexInt() && "Invalid accessor");
|
||||
((ComplexAPSInt*)(char*)Data)->Real = R;
|
||||
((ComplexAPSInt*)(char*)Data)->Imag = I;
|
||||
((ComplexAPSInt *)(char *)Data.buffer)->Real = std::move(R);
|
||||
((ComplexAPSInt *)(char *)Data.buffer)->Imag = std::move(I);
|
||||
}
|
||||
void setComplexFloat(const APFloat &R, const APFloat &I) {
|
||||
void setComplexFloat(APFloat R, APFloat I) {
|
||||
assert(&R.getSemantics() == &I.getSemantics() &&
|
||||
"Invalid complex float (type mismatch).");
|
||||
assert(isComplexFloat() && "Invalid accessor");
|
||||
((ComplexAPFloat*)(char*)Data)->Real = R;
|
||||
((ComplexAPFloat*)(char*)Data)->Imag = I;
|
||||
((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);
|
||||
@ -381,13 +380,13 @@ class APValue {
|
||||
unsigned CallIndex);
|
||||
void setUnion(const FieldDecl *Field, const APValue &Value) {
|
||||
assert(isUnion() && "Invalid accessor");
|
||||
((UnionData*)(char*)Data)->Field = Field;
|
||||
*((UnionData*)(char*)Data)->Value = Value;
|
||||
((UnionData*)(char*)Data.buffer)->Field = Field;
|
||||
*((UnionData*)(char*)Data.buffer)->Value = Value;
|
||||
}
|
||||
void setAddrLabelDiff(const AddrLabelExpr* LHSExpr,
|
||||
const AddrLabelExpr* RHSExpr) {
|
||||
((AddrLabelDiffData*)(char*)Data)->LHSExpr = LHSExpr;
|
||||
((AddrLabelDiffData*)(char*)Data)->RHSExpr = RHSExpr;
|
||||
((AddrLabelDiffData*)(char*)Data.buffer)->LHSExpr = LHSExpr;
|
||||
((AddrLabelDiffData*)(char*)Data.buffer)->RHSExpr = RHSExpr;
|
||||
}
|
||||
|
||||
/// Assign by swapping from a copy of the RHS.
|
||||
@ -404,46 +403,46 @@ class APValue {
|
||||
}
|
||||
void MakeInt() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((void*)Data) APSInt(1);
|
||||
new ((void*)Data.buffer) APSInt(1);
|
||||
Kind = Int;
|
||||
}
|
||||
void MakeFloat() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((void*)(char*)Data) APFloat(0.0);
|
||||
new ((void*)(char*)Data.buffer) APFloat(0.0);
|
||||
Kind = Float;
|
||||
}
|
||||
void MakeVector() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((void*)(char*)Data) Vec();
|
||||
new ((void*)(char*)Data.buffer) Vec();
|
||||
Kind = Vector;
|
||||
}
|
||||
void MakeComplexInt() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((void*)(char*)Data) ComplexAPSInt();
|
||||
new ((void*)(char*)Data.buffer) ComplexAPSInt();
|
||||
Kind = ComplexInt;
|
||||
}
|
||||
void MakeComplexFloat() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((void*)(char*)Data) ComplexAPFloat();
|
||||
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) StructData(B, M);
|
||||
new ((void*)(char*)Data.buffer) StructData(B, M);
|
||||
Kind = Struct;
|
||||
}
|
||||
void MakeUnion() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((void*)(char*)Data) UnionData();
|
||||
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) AddrLabelDiffData();
|
||||
new ((void*)(char*)Data.buffer) AddrLabelDiffData();
|
||||
Kind = AddrLabelDiff;
|
||||
}
|
||||
};
|
||||
|
@ -18,10 +18,10 @@
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class CXXMethodDecl;
|
||||
class CXXRecordDecl;
|
||||
class Decl;
|
||||
class DeclGroupRef;
|
||||
class HandleTagDeclDefinition;
|
||||
class ASTMutationListener;
|
||||
class ASTDeserializationListener; // layering violation because void* is ugly
|
||||
class SemaConsumer; // layering violation required for safe SemaConsumer
|
||||
@ -50,13 +50,15 @@ class ASTConsumer {
|
||||
virtual void Initialize(ASTContext &Context) {}
|
||||
|
||||
/// HandleTopLevelDecl - Handle the specified top-level declaration. This is
|
||||
/// called by the parser to process every top-level Decl*. Note that D can be
|
||||
/// the head of a chain of Decls (e.g. for `int a, b` the chain will have two
|
||||
/// elements). Use Decl::getNextDeclarator() to walk the chain.
|
||||
/// 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.
|
||||
@ -136,12 +138,12 @@ class ASTConsumer {
|
||||
/// \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 0; }
|
||||
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 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// PrintStats - If desired, print any statistics.
|
||||
|
@ -19,6 +19,7 @@
|
||||
#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"
|
||||
@ -33,10 +34,10 @@
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/TinyPtrVector.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
@ -51,7 +52,6 @@ namespace clang {
|
||||
class CharUnits;
|
||||
class DiagnosticsEngine;
|
||||
class Expr;
|
||||
class ExternalASTSource;
|
||||
class ASTMutationListener;
|
||||
class IdentifierTable;
|
||||
class MaterializeTemporaryExpr;
|
||||
@ -66,6 +66,7 @@ namespace clang {
|
||||
class UnresolvedSetIterator;
|
||||
class UsingDecl;
|
||||
class UsingShadowDecl;
|
||||
class VTableContextBase;
|
||||
|
||||
namespace Builtin { class Context; }
|
||||
|
||||
@ -82,7 +83,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
mutable llvm::FoldingSet<ExtQuals> ExtQualNodes;
|
||||
mutable llvm::FoldingSet<ComplexType> ComplexTypes;
|
||||
mutable llvm::FoldingSet<PointerType> PointerTypes;
|
||||
mutable llvm::FoldingSet<DecayedType> DecayedTypes;
|
||||
mutable llvm::FoldingSet<AdjustedType> AdjustedTypes;
|
||||
mutable llvm::FoldingSet<BlockPointerType> BlockPointerTypes;
|
||||
mutable llvm::FoldingSet<LValueReferenceType> LValueReferenceTypes;
|
||||
mutable llvm::FoldingSet<RValueReferenceType> RValueReferenceTypes;
|
||||
@ -364,6 +365,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
/// \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.
|
||||
@ -392,7 +394,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
PartialDiagnostic::StorageAllocator DiagAllocator;
|
||||
|
||||
/// \brief The current C++ ABI.
|
||||
OwningPtr<CXXABI> ABI;
|
||||
std::unique_ptr<CXXABI> ABI;
|
||||
CXXABI *createCXXABI(const TargetInfo &T);
|
||||
|
||||
/// \brief The logical -> physical address space map.
|
||||
@ -415,14 +417,16 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
SelectorTable &Selectors;
|
||||
Builtin::Context &BuiltinInfo;
|
||||
mutable DeclarationNameTable DeclarationNames;
|
||||
OwningPtr<ExternalASTSource> ExternalSource;
|
||||
IntrusiveRefCntPtr<ExternalASTSource> ExternalSource;
|
||||
ASTMutationListener *Listener;
|
||||
|
||||
/// \brief Contains parents of a node.
|
||||
typedef llvm::SmallVector<ast_type_traits::DynTypedNode, 1> ParentVector;
|
||||
typedef llvm::SmallVector<ast_type_traits::DynTypedNode, 2> ParentVector;
|
||||
|
||||
/// \brief Maps from a node to its parents.
|
||||
typedef llvm::DenseMap<const void *, ParentVector> ParentMap;
|
||||
typedef llvm::DenseMap<const void *,
|
||||
llvm::PointerUnion<ast_type_traits::DynTypedNode *,
|
||||
ParentVector *>> ParentMap;
|
||||
|
||||
/// \brief Returns the parents of the given node.
|
||||
///
|
||||
@ -601,9 +605,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
///
|
||||
/// \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 = NULL) const;
|
||||
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.
|
||||
@ -624,6 +628,43 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
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;
|
||||
@ -710,47 +751,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
return Import->NextLocalImport;
|
||||
}
|
||||
|
||||
/// \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;
|
||||
}
|
||||
};
|
||||
|
||||
import_iterator local_import_begin() const {
|
||||
return import_iterator(FirstLocalImport);
|
||||
typedef llvm::iterator_range<import_iterator> import_range;
|
||||
import_range local_imports() const {
|
||||
return import_range(import_iterator(FirstLocalImport), import_iterator());
|
||||
}
|
||||
import_iterator local_import_end() const { return import_iterator(); }
|
||||
|
||||
Decl *getPrimaryMergedDecl(Decl *D) {
|
||||
Decl *Result = MergedDecls.lookup(D);
|
||||
@ -797,11 +801,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
// The type is built when constructing 'BuiltinVaListDecl'.
|
||||
mutable QualType VaListTagTy;
|
||||
|
||||
ASTContext(LangOptions& LOpts, SourceManager &SM, const TargetInfo *t,
|
||||
IdentifierTable &idents, SelectorTable &sels,
|
||||
Builtin::Context &builtins,
|
||||
unsigned size_reserve,
|
||||
bool DelayInitialization = false);
|
||||
ASTContext(LangOptions &LOpts, SourceManager &SM, IdentifierTable &idents,
|
||||
SelectorTable &sels, Builtin::Context &builtins);
|
||||
|
||||
~ASTContext();
|
||||
|
||||
@ -810,11 +811,13 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
/// 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(OwningPtr<ExternalASTSource> &Source);
|
||||
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(); }
|
||||
ExternalASTSource *getExternalSource() const {
|
||||
return ExternalSource.get();
|
||||
}
|
||||
|
||||
/// \brief Attach an AST mutation listener to the AST context.
|
||||
///
|
||||
@ -832,6 +835,14 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
void PrintStats() const;
|
||||
const SmallVectorImpl<Type *>& getTypes() const { return Types; }
|
||||
|
||||
/// \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;
|
||||
|
||||
@ -840,7 +851,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
|
||||
/// \brief Retrieve the declaration for a 128-bit float stub type.
|
||||
TypeDecl *getFloat128StubType() const;
|
||||
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Type Constructors
|
||||
//===--------------------------------------------------------------------===//
|
||||
@ -915,6 +926,14 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
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.
|
||||
@ -1041,7 +1060,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
/// \brief Return the unique reference to the type for the specified type
|
||||
/// declaration.
|
||||
QualType getTypeDeclType(const TypeDecl *Decl,
|
||||
const TypeDecl *PrevDecl = 0) const {
|
||||
const TypeDecl *PrevDecl = nullptr) const {
|
||||
assert(Decl && "Passed null for Decl param");
|
||||
if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
|
||||
|
||||
@ -1075,9 +1094,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
const TemplateTypeParmType *Replaced,
|
||||
const TemplateArgument &ArgPack);
|
||||
|
||||
QualType getTemplateTypeParmType(unsigned Depth, unsigned Index,
|
||||
bool ParameterPack,
|
||||
TemplateTypeParmDecl *ParmDecl = 0) const;
|
||||
QualType
|
||||
getTemplateTypeParmType(unsigned Depth, unsigned Index,
|
||||
bool ParameterPack,
|
||||
TemplateTypeParmDecl *ParmDecl = nullptr) const;
|
||||
|
||||
QualType getTemplateSpecializationType(TemplateName T,
|
||||
const TemplateArgument *Args,
|
||||
@ -1121,11 +1141,18 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
Optional<unsigned> NumExpansions);
|
||||
|
||||
QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl,
|
||||
ObjCInterfaceDecl *PrevDecl = 0) const;
|
||||
ObjCInterfaceDecl *PrevDecl = nullptr) const;
|
||||
|
||||
QualType getObjCObjectType(QualType Base,
|
||||
ObjCProtocolDecl * const *Protocols,
|
||||
unsigned NumProtocols) 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;
|
||||
@ -1344,7 +1371,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
///
|
||||
/// If \p Field is specified then record field names are also encoded.
|
||||
void getObjCEncodingForType(QualType T, std::string &S,
|
||||
const FieldDecl *Field=0) const;
|
||||
const FieldDecl *Field=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;
|
||||
|
||||
@ -1382,6 +1413,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
|
||||
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.
|
||||
@ -1542,7 +1577,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
/// arguments to the builtin that are required to be integer constant
|
||||
/// expressions.
|
||||
QualType GetBuiltinType(unsigned ID, GetBuiltinTypeError &Error,
|
||||
unsigned *IntegerConstantArgs = 0) const;
|
||||
unsigned *IntegerConstantArgs = nullptr) const;
|
||||
|
||||
private:
|
||||
CanQualType getFromTargetType(unsigned Type) const;
|
||||
@ -1704,6 +1739,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
|
||||
bool isNearlyEmpty(const CXXRecordDecl *RD) const;
|
||||
|
||||
VTableContextBase *getVTableContext();
|
||||
|
||||
MangleContext *createMangleContext();
|
||||
|
||||
void DeepCollectObjCIvars(const ObjCInterfaceDecl *OI, bool leafClass,
|
||||
@ -1745,6 +1782,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
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.
|
||||
///
|
||||
@ -1994,9 +2035,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
bool Unqualified = false, bool BlockReturnType = false);
|
||||
QualType mergeFunctionTypes(QualType, QualType, bool OfBlockPointer=false,
|
||||
bool Unqualified = false);
|
||||
QualType mergeFunctionArgumentTypes(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);
|
||||
@ -2008,7 +2049,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
const FunctionProtoType *ToFunctionType);
|
||||
|
||||
void ResetObjCLayout(const ObjCContainerDecl *CD) {
|
||||
ObjCLayouts[CD] = 0;
|
||||
ObjCLayouts[CD] = nullptr;
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
@ -2027,14 +2068,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Type Iterators.
|
||||
//===--------------------------------------------------------------------===//
|
||||
typedef llvm::iterator_range<SmallVectorImpl<Type *>::const_iterator>
|
||||
type_const_range;
|
||||
|
||||
typedef SmallVectorImpl<Type *>::iterator type_iterator;
|
||||
typedef SmallVectorImpl<Type *>::const_iterator const_type_iterator;
|
||||
|
||||
type_iterator types_begin() { return Types.begin(); }
|
||||
type_iterator types_end() { return Types.end(); }
|
||||
const_type_iterator types_begin() const { return Types.begin(); }
|
||||
const_type_iterator types_end() const { return Types.end(); }
|
||||
type_const_range types() const {
|
||||
return type_const_range(Types.begin(), Types.end());
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Integer Values
|
||||
@ -2125,7 +2164,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
/// when it is called.
|
||||
void AddDeallocation(void (*Callback)(void*), void *Data);
|
||||
|
||||
GVALinkage GetGVALinkageForFunction(const FunctionDecl *FD);
|
||||
GVALinkage GetGVALinkageForFunction(const FunctionDecl *FD) const;
|
||||
GVALinkage GetGVALinkageForVariable(const VarDecl *VD);
|
||||
|
||||
/// \brief Determines if the decl can be CodeGen'ed or deserialized from PCH
|
||||
@ -2139,6 +2178,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
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);
|
||||
@ -2212,9 +2254,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
/// \brief Initialize built-in types.
|
||||
///
|
||||
/// This routine may only be invoked once for a given ASTContext object.
|
||||
/// It is normally invoked by the ASTContext constructor. However, the
|
||||
/// constructor can be asked to delay initialization, which places the burden
|
||||
/// of calling this function on the user of that object.
|
||||
/// It is normally invoked after ASTContext construction.
|
||||
///
|
||||
/// \param Target The target
|
||||
void InitBuiltinTypes(const TargetInfo &Target);
|
||||
@ -2238,17 +2278,21 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
void getObjCEncodingForStructureImpl(RecordDecl *RD, std::string &S,
|
||||
const FieldDecl *Field,
|
||||
bool includeVBases = true) 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;
|
||||
|
||||
private:
|
||||
/// \brief A set of deallocations that should be performed when the
|
||||
/// ASTContext is destroyed.
|
||||
typedef llvm::SmallDenseMap<void(*)(void*), llvm::SmallVector<void*, 16> >
|
||||
@ -2263,8 +2307,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
friend class DeclContext;
|
||||
friend class DeclarationNameTable;
|
||||
void ReleaseDeclContextMaps();
|
||||
void ReleaseParentMapEntries();
|
||||
|
||||
llvm::OwningPtr<ParentMap> AllParents;
|
||||
std::unique_ptr<ParentMap> AllParents;
|
||||
|
||||
std::unique_ptr<VTableContextBase> VTContext;
|
||||
};
|
||||
|
||||
/// \brief Utility function for constructing a nullary selector.
|
||||
@ -2363,4 +2410,18 @@ 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
|
||||
|
@ -36,12 +36,9 @@ namespace clang {
|
||||
void FormatASTNodeDiagnosticArgument(
|
||||
DiagnosticsEngine::ArgumentKind Kind,
|
||||
intptr_t Val,
|
||||
const char *Modifier,
|
||||
unsigned ModLen,
|
||||
const char *Argument,
|
||||
unsigned ArgLen,
|
||||
const DiagnosticsEngine::ArgumentValue *PrevArgs,
|
||||
unsigned NumPrevArgs,
|
||||
StringRef Modifier,
|
||||
StringRef Argument,
|
||||
ArrayRef<DiagnosticsEngine::ArgumentValue> PrevArgs,
|
||||
SmallVectorImpl<char> &Output,
|
||||
void *Cookie,
|
||||
ArrayRef<intptr_t> QualTypeVals);
|
||||
|
@ -278,7 +278,7 @@ namespace clang {
|
||||
/// 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 NULL; }
|
||||
virtual Decl *GetOriginalDecl(Decl *To) { return nullptr; }
|
||||
|
||||
/// \brief Determine whether the given types are structurally
|
||||
/// equivalent.
|
||||
|
@ -36,9 +36,9 @@ inline bool isLambdaCallOperator(const DeclContext *DC) {
|
||||
return isLambdaCallOperator(cast<CXXMethodDecl>(DC));
|
||||
}
|
||||
|
||||
inline bool isGenericLambdaCallOperatorSpecialization(CXXMethodDecl *MD) {
|
||||
inline bool isGenericLambdaCallOperatorSpecialization(const CXXMethodDecl *MD) {
|
||||
if (!MD) return false;
|
||||
CXXRecordDecl *LambdaClass = MD->getParent();
|
||||
const CXXRecordDecl *LambdaClass = MD->getParent();
|
||||
if (LambdaClass && LambdaClass->isGenericLambda())
|
||||
return isLambdaCallOperator(MD) &&
|
||||
MD->isFunctionTemplateSpecialization();
|
||||
|
@ -65,6 +65,10 @@ class ASTMutationListener {
|
||||
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);
|
||||
|
||||
@ -74,6 +78,9 @@ class ASTMutationListener {
|
||||
/// \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) {}
|
||||
|
@ -57,11 +57,18 @@ class ASTNodeKind {
|
||||
bool isSame(ASTNodeKind Other) const;
|
||||
|
||||
/// \brief Returns \c true if \c this is a base kind of (or same as) \c Other.
|
||||
bool isBaseOf(ASTNodeKind Other) const;
|
||||
/// \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;
|
||||
}
|
||||
|
||||
private:
|
||||
/// \brief Kind ids.
|
||||
///
|
||||
@ -91,7 +98,9 @@ class ASTNodeKind {
|
||||
|
||||
/// \brief Returns \c true if \c Base is a base kind of (or same as) \c
|
||||
/// Derived.
|
||||
static bool isBaseOf(NodeKindId Base, NodeKindId 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.
|
||||
///
|
||||
@ -133,6 +142,11 @@ KIND_TO_KIND_ID(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
|
||||
@ -198,8 +212,8 @@ class DynTypedNode {
|
||||
return getMemoizationData() < Other.getMemoizationData();
|
||||
}
|
||||
bool operator==(const DynTypedNode &Other) const {
|
||||
// Nodes with different types cannot be equal.
|
||||
if (!NodeKind.isSame(Other.NodeKind))
|
||||
if (!NodeKind.isBaseOf(Other.NodeKind) &&
|
||||
!Other.NodeKind.isBaseOf(NodeKind))
|
||||
return false;
|
||||
|
||||
// FIXME: Implement for other types.
|
||||
@ -223,7 +237,7 @@ class DynTypedNode {
|
||||
static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
|
||||
if (ASTNodeKind::getFromNodeKind<BaseT>().isBaseOf(NodeKind))
|
||||
return dyn_cast<T>(*reinterpret_cast<BaseT *const *>(Storage));
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
static DynTypedNode create(const BaseT &Node) {
|
||||
DynTypedNode Result;
|
||||
@ -238,7 +252,7 @@ class DynTypedNode {
|
||||
static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
|
||||
if (ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind))
|
||||
return *reinterpret_cast<T *const *>(Storage);
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
static DynTypedNode create(const T &Node) {
|
||||
DynTypedNode Result;
|
||||
@ -253,7 +267,7 @@ class DynTypedNode {
|
||||
static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
|
||||
if (ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind))
|
||||
return reinterpret_cast<const T *>(Storage);
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
static DynTypedNode create(const T &Node) {
|
||||
DynTypedNode Result;
|
||||
@ -283,18 +297,18 @@ class DynTypedNode {
|
||||
|
||||
template <typename T>
|
||||
struct DynTypedNode::BaseConverter<
|
||||
T, typename llvm::enable_if<llvm::is_base_of<
|
||||
Decl, T> >::type> : public DynCastPtrConverter<T, Decl> {};
|
||||
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 llvm::enable_if<llvm::is_base_of<
|
||||
Stmt, T> >::type> : public DynCastPtrConverter<T, Stmt> {};
|
||||
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 llvm::enable_if<llvm::is_base_of<
|
||||
Type, T> >::type> : public DynCastPtrConverter<T, Type> {};
|
||||
T, typename std::enable_if<std::is_base_of<Type, T>::value>::type>
|
||||
: public DynCastPtrConverter<T, Type> {};
|
||||
|
||||
template <>
|
||||
struct DynTypedNode::BaseConverter<
|
||||
@ -341,7 +355,7 @@ inline const void *DynTypedNode::getMemoizationData() const {
|
||||
} else if (ASTNodeKind::getFromNodeKind<NestedNameSpecifier>().isBaseOf(NodeKind)) {
|
||||
return BaseConverter<NestedNameSpecifier>::get(NodeKind, Storage.buffer);
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // end namespace ast_type_traits
|
||||
|
@ -32,9 +32,6 @@ class ASTUnresolvedSet {
|
||||
|
||||
DeclsTy Decls;
|
||||
|
||||
ASTUnresolvedSet(const ASTUnresolvedSet &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const ASTUnresolvedSet &) LLVM_DELETED_FUNCTION;
|
||||
|
||||
friend class LazyASTUnresolvedSet;
|
||||
|
||||
public:
|
||||
|
@ -26,30 +26,6 @@
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
namespace std {
|
||||
#if _MSC_VER <= 1310
|
||||
// Work around flawed VC++ implementation of std::uninitialized_copy. Define
|
||||
// additional overloads so that elements with pointer types are recognized as
|
||||
// scalars and not objects, causing bizarre type conversion errors.
|
||||
template<class T1, class T2>
|
||||
inline _Scalar_ptr_iterator_tag _Ptr_cat(T1 **, T2 **) {
|
||||
_Scalar_ptr_iterator_tag _Cat;
|
||||
return _Cat;
|
||||
}
|
||||
|
||||
template<class T1, class T2>
|
||||
inline _Scalar_ptr_iterator_tag _Ptr_cat(T1* const *, T2 **) {
|
||||
_Scalar_ptr_iterator_tag _Cat;
|
||||
return _Cat;
|
||||
}
|
||||
#else
|
||||
// FIXME: It is not clear if the problem is fixed in VS 2005. What is clear
|
||||
// is that the above hack won't work if it wasn't fixed.
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
|
||||
@ -69,15 +45,30 @@ class ASTVector {
|
||||
|
||||
public:
|
||||
// Default ctor - Initialize to empty.
|
||||
ASTVector() : Begin(0), End(0), Capacity(0, false) {}
|
||||
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(0), End(0), Capacity(0, false) {
|
||||
: 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 (llvm::is_class<T>::value) {
|
||||
if (std::is_class<T>::value) {
|
||||
// Destroy the constructed elements in the vector.
|
||||
destroy_range(Begin, End);
|
||||
}
|
||||
@ -147,7 +138,7 @@ class ASTVector {
|
||||
}
|
||||
|
||||
void clear() {
|
||||
if (llvm::is_class<T>::value) {
|
||||
if (std::is_class<T>::value) {
|
||||
destroy_range(Begin, End);
|
||||
}
|
||||
End = Begin;
|
||||
@ -392,7 +383,7 @@ void ASTVector<T>::grow(const ASTContext &C, size_t MinSize) {
|
||||
T *NewElts = new (C, llvm::alignOf<T>()) T[NewCapacity];
|
||||
|
||||
// Copy the elements over.
|
||||
if (llvm::is_class<T>::value) {
|
||||
if (std::is_class<T>::value) {
|
||||
std::uninitialized_copy(Begin, End, NewElts);
|
||||
// Destroy the original elements.
|
||||
destroy_range(Begin, End);
|
||||
|
@ -26,8 +26,8 @@
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
@ -48,10 +48,9 @@ class Attr {
|
||||
/// 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;
|
||||
|
||||
virtual ~Attr();
|
||||
|
||||
@ -76,7 +75,7 @@ class Attr {
|
||||
protected:
|
||||
Attr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex = 0)
|
||||
: Range(R), AttrKind(AK), SpellingListIndex(SpellingListIndex),
|
||||
Inherited(false), IsPackExpansion(false) {}
|
||||
Inherited(false), IsPackExpansion(false), Implicit(false) {}
|
||||
|
||||
public:
|
||||
|
||||
@ -85,6 +84,7 @@ class Attr {
|
||||
}
|
||||
|
||||
unsigned getSpellingListIndex() const { return SpellingListIndex; }
|
||||
virtual const char *getSpelling() const = 0;
|
||||
|
||||
SourceLocation getLocation() const { return Range.getBegin(); }
|
||||
SourceRange getRange() const { return Range; }
|
||||
@ -92,6 +92,11 @@ class Attr {
|
||||
|
||||
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; }
|
||||
|
||||
@ -103,6 +108,11 @@ class Attr {
|
||||
// Pretty print this attribute.
|
||||
virtual void printPretty(raw_ostream &OS,
|
||||
const PrintingPolicy &Policy) const = 0;
|
||||
|
||||
/// \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.
|
||||
virtual bool duplicatesAllowed() const { return false; }
|
||||
};
|
||||
|
||||
class InheritableAttr : public Attr {
|
||||
@ -121,7 +131,7 @@ class InheritableAttr : public Attr {
|
||||
};
|
||||
|
||||
class InheritableParamAttr : public InheritableAttr {
|
||||
virtual void anchor();
|
||||
void anchor() override;
|
||||
protected:
|
||||
InheritableParamAttr(attr::Kind AK, SourceRange R,
|
||||
unsigned SpellingListIndex = 0)
|
||||
@ -136,23 +146,21 @@ class InheritableParamAttr : public InheritableAttr {
|
||||
}
|
||||
};
|
||||
|
||||
class MSInheritanceAttr : public InheritableAttr {
|
||||
virtual void anchor();
|
||||
protected:
|
||||
MSInheritanceAttr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex = 0)
|
||||
: InheritableAttr(AK, R, SpellingListIndex) {}
|
||||
|
||||
public:
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
// Relies on relative order of enum emission with respect to param attrs.
|
||||
return (A->getKind() <= attr::LAST_MS_INHERITANCE &&
|
||||
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
|
||||
|
@ -43,7 +43,7 @@ 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 specifc type.
|
||||
/// providing attributes that are of a specific type.
|
||||
template <typename SpecificAttr, typename Container = AttrVec>
|
||||
class specific_attr_iterator {
|
||||
typedef typename Container::const_iterator Iterator;
|
||||
@ -53,7 +53,7 @@ class specific_attr_iterator {
|
||||
/// 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 dererence a
|
||||
/// 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;
|
||||
|
||||
@ -98,7 +98,7 @@ class specific_attr_iterator {
|
||||
|
||||
friend bool operator==(specific_attr_iterator Left,
|
||||
specific_attr_iterator Right) {
|
||||
assert((Left.Current == 0) == (Right.Current == 0));
|
||||
assert((Left.Current == nullptr) == (Right.Current == nullptr));
|
||||
if (Left.Current < Right.Current)
|
||||
Left.AdvanceToNext(Right.Current);
|
||||
else
|
||||
@ -134,7 +134,7 @@ inline SpecificAttr *getSpecificAttr(const Container& container) {
|
||||
if (i != specific_attr_end<SpecificAttr>(container))
|
||||
return *i;
|
||||
else
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // end namespace clang
|
||||
|
@ -177,8 +177,8 @@ class CXXBasePaths {
|
||||
bool RecordPaths = true,
|
||||
bool DetectVirtual = true)
|
||||
: FindAmbiguities(FindAmbiguities), RecordPaths(RecordPaths),
|
||||
DetectVirtual(DetectVirtual), DetectedVirtual(0), DeclsFound(0),
|
||||
NumDeclsFound(0) { }
|
||||
DetectVirtual(DetectVirtual), DetectedVirtual(nullptr),
|
||||
DeclsFound(nullptr), NumDeclsFound(0) { }
|
||||
|
||||
~CXXBasePaths() { delete [] DeclsFound; }
|
||||
|
||||
@ -190,8 +190,8 @@ class CXXBasePaths {
|
||||
CXXBasePath& front() { return Paths.front(); }
|
||||
const CXXBasePath& front() const { return Paths.front(); }
|
||||
|
||||
decl_iterator found_decls_begin();
|
||||
decl_iterator found_decls_end();
|
||||
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
|
||||
@ -232,7 +232,8 @@ class CXXBasePaths {
|
||||
/// \brief Uniquely identifies a virtual method within a class
|
||||
/// hierarchy by the method itself and a class subobject number.
|
||||
struct UniqueVirtualMethod {
|
||||
UniqueVirtualMethod() : Method(0), Subobject(0), InVirtualSubobject(0) { }
|
||||
UniqueVirtualMethod()
|
||||
: Method(nullptr), Subobject(0), InVirtualSubobject(nullptr) { }
|
||||
|
||||
UniqueVirtualMethod(CXXMethodDecl *Method, unsigned Subobject,
|
||||
const CXXRecordDecl *InVirtualSubobject)
|
||||
|
@ -17,7 +17,6 @@
|
||||
|
||||
#include "clang/AST/Type.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/type_traits.h"
|
||||
#include <iterator>
|
||||
|
||||
namespace clang {
|
||||
@ -60,9 +59,9 @@ class CanQual {
|
||||
|
||||
/// \brief Converting constructor that permits implicit upcasting of
|
||||
/// canonical type pointers.
|
||||
template<typename U>
|
||||
CanQual(const CanQual<U>& Other,
|
||||
typename llvm::enable_if<llvm::is_base_of<T, U>, int>::type = 0);
|
||||
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.
|
||||
@ -541,39 +540,39 @@ struct CanProxyAdaptor<ExtVectorType> : public CanProxyBase<ExtVectorType> {
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<FunctionType> : public CanProxyBase<FunctionType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType)
|
||||
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(getResultType)
|
||||
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(getResultType)
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getReturnType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(FunctionType::ExtInfo, getExtInfo)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumArgs)
|
||||
CanQualType getArgType(unsigned i) const {
|
||||
return CanQualType::CreateUnsafe(this->getTypePtr()->getArgType(i));
|
||||
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::arg_type_iterator>
|
||||
arg_type_iterator;
|
||||
typedef CanTypeIterator<FunctionProtoType::param_type_iterator>
|
||||
param_type_iterator;
|
||||
|
||||
arg_type_iterator arg_type_begin() const {
|
||||
return arg_type_iterator(this->getTypePtr()->arg_type_begin());
|
||||
param_type_iterator param_type_begin() const {
|
||||
return param_type_iterator(this->getTypePtr()->param_type_begin());
|
||||
}
|
||||
|
||||
arg_type_iterator arg_type_end() const {
|
||||
return arg_type_iterator(this->getTypePtr()->arg_type_end());
|
||||
param_type_iterator param_type_end() const {
|
||||
return param_type_iterator(this->getTypePtr()->param_type_end());
|
||||
}
|
||||
|
||||
// Note: canonical function types never have exception specifications
|
||||
|
@ -165,7 +165,7 @@ namespace clang {
|
||||
/// 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) {
|
||||
CharUnits RoundUpToAlignment(const CharUnits &Align) const {
|
||||
return CharUnits(llvm::RoundUpToAlignment(Quantity,
|
||||
Align.Quantity));
|
||||
}
|
||||
@ -173,12 +173,7 @@ namespace clang {
|
||||
/// Given that this is a non-zero alignment value, what is the
|
||||
/// alignment at the given offset?
|
||||
CharUnits alignmentAtOffset(CharUnits offset) {
|
||||
// alignment: 0010000
|
||||
// offset: 1011100
|
||||
// lowBits: 0001011
|
||||
// result: 0000100
|
||||
QuantityType lowBits = (Quantity-1) & (offset.Quantity-1);
|
||||
return CharUnits((lowBits + 1) & ~lowBits);
|
||||
return CharUnits(llvm::MinAlign(Quantity, offset.Quantity));
|
||||
}
|
||||
|
||||
|
||||
|
@ -100,16 +100,26 @@ class Comment {
|
||||
};
|
||||
enum { NumInlineCommandCommentBits = NumInlineContentCommentBits + 10 };
|
||||
|
||||
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 : NumInlineContentCommentBits;
|
||||
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 = NumInlineContentCommentBits + 1 };
|
||||
enum { NumHTMLStartTagCommentBits = NumHTMLTagCommentBits + 1 };
|
||||
|
||||
class ParagraphCommentBitfields {
|
||||
friend class ParagraphComment;
|
||||
@ -155,6 +165,7 @@ class Comment {
|
||||
InlineContentCommentBitfields InlineContentCommentBits;
|
||||
TextCommentBitfields TextCommentBits;
|
||||
InlineCommandCommentBitfields InlineCommandCommentBits;
|
||||
HTMLTagCommentBitfields HTMLTagCommentBits;
|
||||
HTMLStartTagCommentBitfields HTMLStartTagCommentBits;
|
||||
ParagraphCommentBitfields ParagraphCommentBits;
|
||||
BlockCommandCommentBitfields BlockCommandCommentBits;
|
||||
@ -194,9 +205,9 @@ class Comment {
|
||||
|
||||
const char *getCommentKindName() const;
|
||||
|
||||
LLVM_ATTRIBUTE_USED void dump() const;
|
||||
LLVM_ATTRIBUTE_USED void dumpColor() const;
|
||||
LLVM_ATTRIBUTE_USED void dump(const ASTContext &Context) 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;
|
||||
|
||||
@ -267,9 +278,9 @@ class TextComment : public InlineContentComment {
|
||||
return C->getCommentKind() == TextCommentKind;
|
||||
}
|
||||
|
||||
child_iterator child_begin() const { return NULL; }
|
||||
child_iterator child_begin() const { return nullptr; }
|
||||
|
||||
child_iterator child_end() const { return NULL; }
|
||||
child_iterator child_end() const { return nullptr; }
|
||||
|
||||
StringRef getText() const LLVM_READONLY { return Text; }
|
||||
|
||||
@ -325,9 +336,9 @@ class InlineCommandComment : public InlineContentComment {
|
||||
return C->getCommentKind() == InlineCommandCommentKind;
|
||||
}
|
||||
|
||||
child_iterator child_begin() const { return NULL; }
|
||||
child_iterator child_begin() const { return nullptr; }
|
||||
|
||||
child_iterator child_end() const { return NULL; }
|
||||
child_iterator child_end() const { return nullptr; }
|
||||
|
||||
unsigned getCommandID() const {
|
||||
return InlineCommandCommentBits.CommandID;
|
||||
@ -360,8 +371,7 @@ class InlineCommandComment : public InlineContentComment {
|
||||
};
|
||||
|
||||
/// Abstract class for opening and closing HTML tags. HTML tags are always
|
||||
/// treated as inline content (regardless HTML semantics); opening and closing
|
||||
/// tags are not matched.
|
||||
/// treated as inline content (regardless HTML semantics).
|
||||
class HTMLTagComment : public InlineContentComment {
|
||||
protected:
|
||||
StringRef TagName;
|
||||
@ -377,6 +387,7 @@ class HTMLTagComment : public InlineContentComment {
|
||||
TagName(TagName),
|
||||
TagNameRange(TagNameBegin, TagNameEnd) {
|
||||
setLocation(TagNameBegin);
|
||||
HTMLTagCommentBits.IsMalformed = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
@ -392,6 +403,14 @@ class HTMLTagComment : public InlineContentComment {
|
||||
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.
|
||||
@ -450,9 +469,9 @@ class HTMLStartTagComment : public HTMLTagComment {
|
||||
return C->getCommentKind() == HTMLStartTagCommentKind;
|
||||
}
|
||||
|
||||
child_iterator child_begin() const { return NULL; }
|
||||
child_iterator child_begin() const { return nullptr; }
|
||||
|
||||
child_iterator child_end() const { return NULL; }
|
||||
child_iterator child_end() const { return nullptr; }
|
||||
|
||||
unsigned getNumAttrs() const {
|
||||
return Attributes.size();
|
||||
@ -505,9 +524,9 @@ class HTMLEndTagComment : public HTMLTagComment {
|
||||
return C->getCommentKind() == HTMLEndTagCommentKind;
|
||||
}
|
||||
|
||||
child_iterator child_begin() const { return NULL; }
|
||||
child_iterator child_begin() const { return nullptr; }
|
||||
|
||||
child_iterator child_end() const { return NULL; }
|
||||
child_iterator child_end() const { return nullptr; }
|
||||
};
|
||||
|
||||
/// Block content (contains inline content).
|
||||
@ -601,7 +620,7 @@ class BlockCommandComment : public BlockContentComment {
|
||||
unsigned CommandID,
|
||||
CommandMarkerKind CommandMarker) :
|
||||
BlockContentComment(K, LocBegin, LocEnd),
|
||||
Paragraph(NULL) {
|
||||
Paragraph(nullptr) {
|
||||
setLocation(getCommandNameBeginLoc());
|
||||
BlockCommandCommentBits.CommandID = CommandID;
|
||||
BlockCommandCommentBits.CommandMarker = CommandMarker;
|
||||
@ -613,7 +632,7 @@ class BlockCommandComment : public BlockContentComment {
|
||||
unsigned CommandID,
|
||||
CommandMarkerKind CommandMarker) :
|
||||
BlockContentComment(BlockCommandCommentKind, LocBegin, LocEnd),
|
||||
Paragraph(NULL) {
|
||||
Paragraph(nullptr) {
|
||||
setLocation(getCommandNameBeginLoc());
|
||||
BlockCommandCommentBits.CommandID = CommandID;
|
||||
BlockCommandCommentBits.CommandMarker = CommandMarker;
|
||||
@ -699,7 +718,7 @@ class ParamCommandComment : public BlockCommandComment {
|
||||
unsigned ParamIndex;
|
||||
|
||||
public:
|
||||
enum LLVM_ENUM_INT_TYPE(unsigned) {
|
||||
enum : unsigned {
|
||||
InvalidParamIndex = ~0U,
|
||||
VarArgParamIndex = ~0U/*InvalidParamIndex*/ - 1U
|
||||
};
|
||||
@ -861,9 +880,9 @@ class VerbatimBlockLineComment : public Comment {
|
||||
return C->getCommentKind() == VerbatimBlockLineCommentKind;
|
||||
}
|
||||
|
||||
child_iterator child_begin() const { return NULL; }
|
||||
child_iterator child_begin() const { return nullptr; }
|
||||
|
||||
child_iterator child_end() const { return NULL; }
|
||||
child_iterator child_end() const { return nullptr; }
|
||||
|
||||
StringRef getText() const LLVM_READONLY {
|
||||
return Text;
|
||||
@ -948,9 +967,9 @@ class VerbatimLineComment : public BlockCommandComment {
|
||||
return C->getCommentKind() == VerbatimLineCommentKind;
|
||||
}
|
||||
|
||||
child_iterator child_begin() const { return NULL; }
|
||||
child_iterator child_begin() const { return nullptr; }
|
||||
|
||||
child_iterator child_end() const { return NULL; }
|
||||
child_iterator child_end() const { return nullptr; }
|
||||
|
||||
StringRef getText() const {
|
||||
return Text;
|
||||
@ -981,9 +1000,9 @@ struct DeclInfo {
|
||||
/// that we consider a "function".
|
||||
ArrayRef<const ParmVarDecl *> ParamVars;
|
||||
|
||||
/// Function result type if \c CommentDecl is something that we consider
|
||||
/// Function return type if \c CommentDecl is something that we consider
|
||||
/// a "function".
|
||||
QualType ResultType;
|
||||
QualType ReturnType;
|
||||
|
||||
/// Template parameters that can be referenced by \\tparam if \c CommentDecl is
|
||||
/// a template (\c IsTemplateDecl or \c IsTemplatePartialSpecialization is
|
||||
|
@ -146,7 +146,7 @@ def Todo : BlockCommand<"todo">;
|
||||
def Version : BlockCommand<"version">;
|
||||
def Warning : BlockCommand<"warning">;
|
||||
// HeaderDoc commands
|
||||
def Abstract : BlockCommand<"abstract">;
|
||||
def Abstract : BlockCommand<"abstract"> { let IsBriefCommand = 1; }
|
||||
def ClassDesign : RecordLikeDetailCommand<"classdesign">;
|
||||
def CoClass : RecordLikeDetailCommand<"coclass">;
|
||||
def Dependency : RecordLikeDetailCommand<"dependency">;
|
||||
|
@ -52,3 +52,16 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -14,8 +14,8 @@
|
||||
#ifndef LLVM_CLANG_AST_COMMENT_LEXER_H
|
||||
#define LLVM_CLANG_AST_COMMENT_LEXER_H
|
||||
|
||||
#include "clang/Basic/SourceManager.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"
|
||||
@ -293,17 +293,7 @@ class Lexer {
|
||||
StringRef resolveHTMLHexCharacterReference(StringRef Name) const;
|
||||
|
||||
void formTokenWithChars(Token &Result, const char *TokEnd,
|
||||
tok::TokenKind Kind) {
|
||||
const unsigned TokLen = TokEnd - BufferPtr;
|
||||
Result.setLocation(getSourceLocation(BufferPtr));
|
||||
Result.setKind(Kind);
|
||||
Result.setLength(TokLen);
|
||||
#ifndef NDEBUG
|
||||
Result.TextPtr = "<UNSET>";
|
||||
Result.IntVal = 7;
|
||||
#endif
|
||||
BufferPtr = TokEnd;
|
||||
}
|
||||
tok::TokenKind Kind);
|
||||
|
||||
void formTextToken(Token &Result, const char *TokEnd) {
|
||||
StringRef Text(BufferPtr, TokEnd - BufferPtr);
|
||||
@ -362,7 +352,7 @@ class Lexer {
|
||||
|
||||
StringRef getSpelling(const Token &Tok,
|
||||
const SourceManager &SourceMgr,
|
||||
bool *Invalid = NULL) const;
|
||||
bool *Invalid = nullptr) const;
|
||||
};
|
||||
|
||||
} // end namespace comments
|
||||
|
@ -84,8 +84,8 @@ class Sema {
|
||||
T *Mem = Allocator.Allocate<T>(Size);
|
||||
std::uninitialized_copy(Source.begin(), Source.end(), Mem);
|
||||
return llvm::makeArrayRef(Mem, Size);
|
||||
} else
|
||||
return llvm::makeArrayRef(static_cast<T *>(NULL), 0);
|
||||
}
|
||||
return ArrayRef<T>();
|
||||
}
|
||||
|
||||
ParagraphComment *actOnParagraphComment(
|
||||
|
2519
contrib/llvm/tools/clang/include/clang/AST/DataRecursiveASTVisitor.h
Normal file
2519
contrib/llvm/tools/clang/include/clang/AST/DataRecursiveASTVisitor.h
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -16,9 +16,9 @@
|
||||
|
||||
#include "clang/AST/AttrIterator.h"
|
||||
#include "clang/AST/DeclarationName.h"
|
||||
#include "clang/Basic/Linkage.h"
|
||||
#include "clang/Basic/Specifiers.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/PrettyStackTrace.h"
|
||||
|
||||
@ -32,6 +32,8 @@ class DeclarationName;
|
||||
class DependentDiagnostic;
|
||||
class EnumDecl;
|
||||
class FunctionDecl;
|
||||
class FunctionType;
|
||||
enum Linkage : unsigned char;
|
||||
class LinkageComputer;
|
||||
class LinkageSpecDecl;
|
||||
class Module;
|
||||
@ -52,20 +54,6 @@ class TranslationUnitDecl;
|
||||
class UsingDirectiveDecl;
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
// DeclContext* is only 4-byte aligned on 32-bit systems.
|
||||
template<>
|
||||
class PointerLikeTypeTraits<clang::DeclContext*> {
|
||||
typedef clang::DeclContext* PT;
|
||||
public:
|
||||
static inline void *getAsVoidPointer(PT P) { return P; }
|
||||
static inline PT getFromVoidPointer(void *P) {
|
||||
return static_cast<PT>(P);
|
||||
}
|
||||
enum { NumLowBitsAvailable = 2 };
|
||||
};
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// \brief Captures the result of checking the availability of a
|
||||
@ -302,8 +290,24 @@ class Decl {
|
||||
|
||||
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:
|
||||
void CheckAccessDeclContext() const;
|
||||
bool AccessDeclContextSanity() const;
|
||||
|
||||
protected:
|
||||
|
||||
@ -330,18 +334,6 @@ class Decl {
|
||||
|
||||
virtual ~Decl();
|
||||
|
||||
/// \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 Context The context in which we will allocate memory.
|
||||
/// \param ID The global ID of the deserialized declaration.
|
||||
/// \param Size The size of the allocated object.
|
||||
static void *AllocateDeserializedDecl(const ASTContext &Context,
|
||||
unsigned ID,
|
||||
unsigned Size);
|
||||
|
||||
/// \brief Update a potentially out-of-date declaration.
|
||||
void updateOutOfDate(IdentifierInfo &II) const;
|
||||
|
||||
@ -405,19 +397,17 @@ class Decl {
|
||||
|
||||
bool isInAnonymousNamespace() const;
|
||||
|
||||
bool isInStdNamespace() const;
|
||||
|
||||
ASTContext &getASTContext() const LLVM_READONLY;
|
||||
|
||||
void setAccess(AccessSpecifier AS) {
|
||||
Access = AS;
|
||||
#ifndef NDEBUG
|
||||
CheckAccessDeclContext();
|
||||
#endif
|
||||
assert(AccessDeclContextSanity());
|
||||
}
|
||||
|
||||
AccessSpecifier getAccess() const {
|
||||
#ifndef NDEBUG
|
||||
CheckAccessDeclContext();
|
||||
#endif
|
||||
assert(AccessDeclContextSanity());
|
||||
return AccessSpecifier(Access);
|
||||
}
|
||||
|
||||
@ -445,14 +435,17 @@ class Decl {
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
// FIXME: Do not rely on iterators having comparable singular values.
|
||||
// Note that this should error out if they do not.
|
||||
attr_iterator attr_begin() const {
|
||||
return hasAttrs() ? getAttrs().begin() : 0;
|
||||
return hasAttrs() ? getAttrs().begin() : nullptr;
|
||||
}
|
||||
attr_iterator attr_end() const {
|
||||
return hasAttrs() ? getAttrs().end() : 0;
|
||||
return hasAttrs() ? getAttrs().end() : nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -466,6 +459,12 @@ class Decl {
|
||||
HasAttrs = false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
llvm::iterator_range<specific_attr_iterator<T>> specific_attrs() const {
|
||||
return llvm::iterator_range<specific_attr_iterator<T>>(
|
||||
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());
|
||||
@ -476,7 +475,7 @@ class Decl {
|
||||
}
|
||||
|
||||
template<typename T> T *getAttr() const {
|
||||
return hasAttrs() ? getSpecificAttr<T>(getAttrs()) : 0;
|
||||
return hasAttrs() ? getSpecificAttr<T>(getAttrs()) : nullptr;
|
||||
}
|
||||
template<typename T> bool hasAttr() const {
|
||||
return hasAttrs() && hasSpecificAttr<T>(getAttrs());
|
||||
@ -573,14 +572,14 @@ class Decl {
|
||||
/// 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 = 0) const;
|
||||
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 = 0) const {
|
||||
bool isDeprecated(std::string *Message = nullptr) const {
|
||||
return getAvailability(Message) == AR_Deprecated;
|
||||
}
|
||||
|
||||
@ -589,7 +588,7 @@ class Decl {
|
||||
/// \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 = 0) const {
|
||||
bool isUnavailable(std::string *Message = nullptr) const {
|
||||
return getAvailability(Message) == AR_Unavailable;
|
||||
}
|
||||
|
||||
@ -636,7 +635,7 @@ class Decl {
|
||||
public:
|
||||
Module *getOwningModule() const {
|
||||
if (!isFromASTFile())
|
||||
return 0;
|
||||
return nullptr;
|
||||
|
||||
return getOwningModuleSlow();
|
||||
}
|
||||
@ -691,7 +690,7 @@ class Decl {
|
||||
/// roughly global variables and functions, but also handles enums (which
|
||||
/// could be defined inside or outside a function etc).
|
||||
bool isDefinedOutsideFunctionOrMethod() const {
|
||||
return getParentFunctionOrMethod() == 0;
|
||||
return getParentFunctionOrMethod() == nullptr;
|
||||
}
|
||||
|
||||
/// \brief If this decl is defined inside a function/method/block it returns
|
||||
@ -716,16 +715,16 @@ class Decl {
|
||||
///
|
||||
/// Decl subclasses that can be redeclared should override this method so that
|
||||
/// Decl::redecl_iterator can iterate over them.
|
||||
virtual Decl *getNextRedeclaration() { return this; }
|
||||
virtual Decl *getNextRedeclarationImpl() { return this; }
|
||||
|
||||
/// \brief Implementation of getPreviousDecl(), to be overridden by any
|
||||
/// subclass that has a redeclaration chain.
|
||||
virtual Decl *getPreviousDeclImpl() { return 0; }
|
||||
|
||||
virtual Decl *getPreviousDeclImpl() { return nullptr; }
|
||||
|
||||
/// \brief Implementation of getMostRecentDecl(), to be overridden by any
|
||||
/// subclass that has a redeclaration chain.
|
||||
/// 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 {
|
||||
@ -740,7 +739,7 @@ class Decl {
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
|
||||
redecl_iterator() : Current(0) { }
|
||||
redecl_iterator() : Current(nullptr) { }
|
||||
explicit redecl_iterator(Decl *C) : Current(C), Starter(C) { }
|
||||
|
||||
reference operator*() const { return Current; }
|
||||
@ -749,9 +748,9 @@ class Decl {
|
||||
redecl_iterator& operator++() {
|
||||
assert(Current && "Advancing while iterator has reached end");
|
||||
// Get either previous decl or latest decl.
|
||||
Decl *Next = Current->getNextRedeclaration();
|
||||
Decl *Next = Current->getNextRedeclarationImpl();
|
||||
assert(Next && "Should return next redeclaration or itself, never null!");
|
||||
Current = (Next != Starter ? Next : 0);
|
||||
Current = (Next != Starter) ? Next : nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -769,10 +768,16 @@ class Decl {
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Returns iterator for all the redeclarations of the same decl.
|
||||
/// It will iterate at least once (when this decl is the only one).
|
||||
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));
|
||||
return redecl_iterator(const_cast<Decl *>(this));
|
||||
}
|
||||
redecl_iterator redecls_end() const { return redecl_iterator(); }
|
||||
|
||||
@ -788,7 +793,7 @@ class Decl {
|
||||
|
||||
/// \brief True if this is the first declaration in its redeclaration chain.
|
||||
bool isFirstDecl() const {
|
||||
return getPreviousDecl() == 0;
|
||||
return getPreviousDecl() == nullptr;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the most recent declaration that declares the same entity
|
||||
@ -804,13 +809,13 @@ class Decl {
|
||||
/// 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 0; }
|
||||
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() != 0; }
|
||||
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.
|
||||
@ -836,7 +841,19 @@ class Decl {
|
||||
bool isTemplateDecl() const;
|
||||
|
||||
/// \brief Whether this declaration is a function or function template.
|
||||
bool isFunctionOrFunctionTemplate() const;
|
||||
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.
|
||||
@ -938,11 +955,16 @@ class Decl {
|
||||
raw_ostream &Out, const PrintingPolicy &Policy,
|
||||
unsigned Indentation = 0);
|
||||
// Debuggers don't usually respect default arguments.
|
||||
LLVM_ATTRIBUTE_USED void dump() const;
|
||||
void dump() const;
|
||||
// Same as dump(), but forces color printing.
|
||||
LLVM_ATTRIBUTE_USED void dumpColor() const;
|
||||
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,
|
||||
@ -975,10 +997,10 @@ class PrettyStackTraceDecl : public llvm::PrettyStackTraceEntry {
|
||||
SourceManager &sm, const char *Msg)
|
||||
: TheDecl(theDecl), Loc(L), SM(sm), Message(Msg) {}
|
||||
|
||||
virtual void print(raw_ostream &OS) const;
|
||||
void print(raw_ostream &OS) const override;
|
||||
};
|
||||
|
||||
typedef llvm::MutableArrayRef<NamedDecl*> DeclContextLookupResult;
|
||||
typedef MutableArrayRef<NamedDecl *> DeclContextLookupResult;
|
||||
|
||||
typedef ArrayRef<NamedDecl *> DeclContextLookupConstResult;
|
||||
|
||||
@ -1048,8 +1070,8 @@ class DeclContext {
|
||||
DeclContext(Decl::Kind K)
|
||||
: DeclKind(K), ExternalLexicalStorage(false),
|
||||
ExternalVisibleStorage(false),
|
||||
NeedToReconcileExternalVisibleStorage(false), LookupPtr(0, false),
|
||||
FirstDecl(0), LastDecl(0) {}
|
||||
NeedToReconcileExternalVisibleStorage(false), LookupPtr(nullptr, false),
|
||||
FirstDecl(nullptr), LastDecl(nullptr) {}
|
||||
|
||||
public:
|
||||
~DeclContext();
|
||||
@ -1136,6 +1158,8 @@ class DeclContext {
|
||||
return DeclKind == Decl::Namespace;
|
||||
}
|
||||
|
||||
bool isStdNamespace() const;
|
||||
|
||||
bool isInlineNamespace() const;
|
||||
|
||||
/// \brief Determines whether this context is dependent on a
|
||||
@ -1256,7 +1280,7 @@ class DeclContext {
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
|
||||
decl_iterator() : Current(0) { }
|
||||
decl_iterator() : Current(nullptr) { }
|
||||
explicit decl_iterator(Decl *C) : Current(C) { }
|
||||
|
||||
reference operator*() const { return Current; }
|
||||
@ -1282,8 +1306,11 @@ class DeclContext {
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
@ -1291,7 +1318,10 @@ class DeclContext {
|
||||
/// 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_iterator noload_decls_begin() const;
|
||||
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
|
||||
@ -1537,6 +1567,11 @@ class DeclContext {
|
||||
/// 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;
|
||||
@ -1547,26 +1582,15 @@ class DeclContext {
|
||||
all_lookups_iterator noload_lookups_begin() const;
|
||||
all_lookups_iterator noload_lookups_end() const;
|
||||
|
||||
/// udir_iterator - Iterates through the using-directives stored
|
||||
/// within this context.
|
||||
typedef UsingDirectiveDecl * const * udir_iterator;
|
||||
typedef llvm::iterator_range<UsingDirectiveDecl * const *> udir_range;
|
||||
|
||||
typedef std::pair<udir_iterator, udir_iterator> udir_iterator_range;
|
||||
|
||||
udir_iterator_range getUsingDirectives() const;
|
||||
|
||||
udir_iterator using_directives_begin() const {
|
||||
return getUsingDirectives().first;
|
||||
}
|
||||
|
||||
udir_iterator using_directives_end() const {
|
||||
return getUsingDirectives().second;
|
||||
}
|
||||
udir_range using_directives() const;
|
||||
|
||||
// These are all defined in DependentDiagnostic.h.
|
||||
class ddiag_iterator;
|
||||
inline ddiag_iterator ddiag_begin() const;
|
||||
inline ddiag_iterator ddiag_end() const;
|
||||
typedef llvm::iterator_range<DeclContext::ddiag_iterator> ddiag_range;
|
||||
|
||||
inline ddiag_range ddiags() const;
|
||||
|
||||
// Low-level accessors
|
||||
|
||||
@ -1616,12 +1640,12 @@ class DeclContext {
|
||||
static bool classof(const Decl *D);
|
||||
static bool classof(const DeclContext *D) { return true; }
|
||||
|
||||
LLVM_ATTRIBUTE_USED void dumpDeclContext() const;
|
||||
LLVM_ATTRIBUTE_USED void dumpLookups() const;
|
||||
LLVM_ATTRIBUTE_USED void dumpLookups(llvm::raw_ostream &OS) const;
|
||||
void dumpDeclContext() const;
|
||||
void dumpLookups() const;
|
||||
void dumpLookups(llvm::raw_ostream &OS) const;
|
||||
|
||||
private:
|
||||
void reconcileExternalVisibleStorage();
|
||||
void reconcileExternalVisibleStorage() const;
|
||||
void LoadLexicalDeclsFromExternalStorage() const;
|
||||
|
||||
/// @brief Makes a declaration visible within this context, but
|
||||
@ -1650,7 +1674,7 @@ inline bool Decl::isTemplateParameter() const {
|
||||
|
||||
// Specialization selected when ToTy is not a known subclass of DeclContext.
|
||||
template <class ToTy,
|
||||
bool IsKnownSubtype = ::llvm::is_base_of< DeclContext, ToTy>::value>
|
||||
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));
|
||||
|
@ -17,13 +17,12 @@
|
||||
#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/ExprCXX.h"
|
||||
#include "clang/AST/TypeLoc.h"
|
||||
#include "clang/AST/LambdaCapture.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
namespace clang {
|
||||
@ -122,14 +121,14 @@ class AccessSpecDecl : public Decl {
|
||||
/// \brief Sets the location of the colon.
|
||||
void setColonLoc(SourceLocation CLoc) { ColonLoc = CLoc; }
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
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) AccessSpecDecl(AS, DC, ASLoc, ColonLoc);
|
||||
return new (C, DC) AccessSpecDecl(AS, DC, ASLoc, ColonLoc);
|
||||
}
|
||||
static AccessSpecDecl *CreateDeserialized(ASTContext &C, unsigned ID);
|
||||
|
||||
@ -258,20 +257,31 @@ class CXXBaseSpecifier {
|
||||
TypeSourceInfo *getTypeSourceInfo() const { return BaseTypeInfo; }
|
||||
};
|
||||
|
||||
/// The inheritance model to use for member pointers of a given CXXRecordDecl.
|
||||
enum MSInheritanceModel {
|
||||
MSIM_Single,
|
||||
MSIM_SinglePolymorphic,
|
||||
MSIM_Multiple,
|
||||
MSIM_MultiplePolymorphic,
|
||||
MSIM_Virtual,
|
||||
MSIM_Unspecified
|
||||
/// \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.
|
||||
///
|
||||
/// FIXME: This class will disappear once we've properly taught RecordDecl
|
||||
/// to deal with C++-specific things.
|
||||
class CXXRecordDecl : public RecordDecl {
|
||||
|
||||
friend void TagDecl::startDefinition();
|
||||
@ -350,10 +360,15 @@ class CXXRecordDecl : public RecordDecl {
|
||||
/// \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.
|
||||
/// \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
|
||||
@ -409,7 +424,7 @@ class CXXRecordDecl : public RecordDecl {
|
||||
/// \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..
|
||||
/// or an implicitly declared constexpr default constructor.
|
||||
bool HasConstexprDefaultConstructor : 1;
|
||||
|
||||
/// \brief True when this class contains at least one non-static data
|
||||
@ -447,6 +462,9 @@ class CXXRecordDecl : public RecordDecl {
|
||||
/// \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;
|
||||
|
||||
@ -486,33 +504,39 @@ class CXXRecordDecl : public RecordDecl {
|
||||
/// \brief Retrieve the set of direct base classes.
|
||||
CXXBaseSpecifier *getBases() const {
|
||||
if (!Bases.isOffset())
|
||||
return Bases.get(0);
|
||||
return Bases.get(nullptr);
|
||||
return getBasesSlowCase();
|
||||
}
|
||||
|
||||
/// \brief Retrieve the set of virtual base classes.
|
||||
CXXBaseSpecifier *getVBases() const {
|
||||
if (!VBases.isOffset())
|
||||
return VBases.get(0);
|
||||
return VBases.get(nullptr);
|
||||
return getVBasesSlowCase();
|
||||
}
|
||||
|
||||
private:
|
||||
CXXBaseSpecifier *getBasesSlowCase() const;
|
||||
CXXBaseSpecifier *getVBasesSlowCase() const;
|
||||
} *DefinitionData;
|
||||
};
|
||||
|
||||
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 LambdaExpr::Capture Capture;
|
||||
|
||||
LambdaDefinitionData(CXXRecordDecl *D, TypeSourceInfo *Info,
|
||||
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(0), Captures(0), MethodTyInfo(Info)
|
||||
{
|
||||
ManglingNumber(0), ContextDecl(nullptr), Captures(nullptr),
|
||||
MethodTyInfo(Info) {
|
||||
IsLambda = true;
|
||||
}
|
||||
|
||||
@ -557,23 +581,20 @@ class CXXRecordDecl : public RecordDecl {
|
||||
|
||||
};
|
||||
|
||||
struct DefinitionData &data() {
|
||||
assert(DefinitionData && "queried property of class with no definition");
|
||||
return *DefinitionData;
|
||||
}
|
||||
|
||||
const struct DefinitionData &data() const {
|
||||
assert(DefinitionData && "queried property of class with no definition");
|
||||
return *DefinitionData;
|
||||
struct DefinitionData &data() const {
|
||||
auto *DD = DefinitionData.get();
|
||||
assert(DD && "queried property of class with no definition");
|
||||
return *DD;
|
||||
}
|
||||
|
||||
struct LambdaDefinitionData &getLambdaData() const {
|
||||
assert(DefinitionData && "queried property of lambda with no definition");
|
||||
assert(DefinitionData->IsLambda &&
|
||||
"queried lambda property of non-lambda class");
|
||||
return static_cast<LambdaDefinitionData &>(*DefinitionData);
|
||||
// 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.
|
||||
///
|
||||
@ -610,7 +631,7 @@ class CXXRecordDecl : public RecordDecl {
|
||||
FriendDecl *getFirstFriend() const;
|
||||
|
||||
protected:
|
||||
CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
|
||||
CXXRecordDecl(Kind K, TagKind TK, const ASTContext &C, DeclContext *DC,
|
||||
SourceLocation StartLoc, SourceLocation IdLoc,
|
||||
IdentifierInfo *Id, CXXRecordDecl *PrevDecl);
|
||||
|
||||
@ -621,17 +642,7 @@ class CXXRecordDecl : public RecordDecl {
|
||||
/// \brief Iterator that traverses the base classes of a class.
|
||||
typedef const CXXBaseSpecifier* base_class_const_iterator;
|
||||
|
||||
/// \brief Iterator that traverses the base classes of a class in reverse
|
||||
/// order.
|
||||
typedef std::reverse_iterator<base_class_iterator>
|
||||
reverse_base_class_iterator;
|
||||
|
||||
/// \brief Iterator that traverses the base classes of a class in reverse
|
||||
/// order.
|
||||
typedef std::reverse_iterator<base_class_const_iterator>
|
||||
reverse_base_class_const_iterator;
|
||||
|
||||
virtual CXXRecordDecl *getCanonicalDecl() {
|
||||
CXXRecordDecl *getCanonicalDecl() override {
|
||||
return cast<CXXRecordDecl>(RecordDecl::getCanonicalDecl());
|
||||
}
|
||||
virtual const CXXRecordDecl *getCanonicalDecl() const {
|
||||
@ -656,19 +667,20 @@ class CXXRecordDecl : public RecordDecl {
|
||||
}
|
||||
|
||||
CXXRecordDecl *getDefinition() const {
|
||||
if (!DefinitionData) return 0;
|
||||
return data().Definition;
|
||||
auto *DD = DefinitionData.get();
|
||||
return DD ? DD->Definition : nullptr;
|
||||
}
|
||||
|
||||
bool hasDefinition() const { return DefinitionData != 0; }
|
||||
bool hasDefinition() const { return DefinitionData.get(); }
|
||||
|
||||
static CXXRecordDecl *Create(const ASTContext &C, TagKind TK, DeclContext *DC,
|
||||
SourceLocation StartLoc, SourceLocation IdLoc,
|
||||
IdentifierInfo *Id, CXXRecordDecl* PrevDecl=0,
|
||||
IdentifierInfo *Id,
|
||||
CXXRecordDecl *PrevDecl = nullptr,
|
||||
bool DelayTypeCreation = false);
|
||||
static CXXRecordDecl *CreateLambda(const ASTContext &C, DeclContext *DC,
|
||||
TypeSourceInfo *Info, SourceLocation Loc,
|
||||
bool DependentLambda, bool IsGeneric,
|
||||
bool DependentLambda, bool IsGeneric,
|
||||
LambdaCaptureDefault CaptureDefault);
|
||||
static CXXRecordDecl *CreateDeserialized(const ASTContext &C, unsigned ID);
|
||||
|
||||
@ -676,52 +688,52 @@ class CXXRecordDecl : public RecordDecl {
|
||||
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;
|
||||
}
|
||||
reverse_base_class_iterator bases_rbegin() {
|
||||
return reverse_base_class_iterator(bases_end());
|
||||
}
|
||||
reverse_base_class_const_iterator bases_rbegin() const {
|
||||
return reverse_base_class_const_iterator(bases_end());
|
||||
}
|
||||
reverse_base_class_iterator bases_rend() {
|
||||
return reverse_base_class_iterator(bases_begin());
|
||||
}
|
||||
reverse_base_class_const_iterator bases_rend() const {
|
||||
return reverse_base_class_const_iterator(bases_begin());
|
||||
}
|
||||
|
||||
/// \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;
|
||||
}
|
||||
reverse_base_class_iterator vbases_rbegin() {
|
||||
return reverse_base_class_iterator(vbases_end());
|
||||
}
|
||||
reverse_base_class_const_iterator vbases_rbegin() const {
|
||||
return reverse_base_class_const_iterator(vbases_end());
|
||||
}
|
||||
reverse_base_class_iterator vbases_rend() {
|
||||
return reverse_base_class_iterator(vbases_begin());
|
||||
}
|
||||
reverse_base_class_const_iterator vbases_rend() const {
|
||||
return reverse_base_class_const_iterator(vbases_begin());
|
||||
}
|
||||
|
||||
/// \brief Determine whether this class has any dependent base classes which
|
||||
/// are not the current instantiation.
|
||||
@ -731,6 +743,12 @@ class CXXRecordDecl : public RecordDecl {
|
||||
/// 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.
|
||||
@ -744,6 +762,10 @@ class CXXRecordDecl : public RecordDecl {
|
||||
|
||||
/// 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());
|
||||
@ -755,6 +777,9 @@ class CXXRecordDecl : public RecordDecl {
|
||||
/// 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);
|
||||
@ -984,7 +1009,11 @@ class CXXRecordDecl : public RecordDecl {
|
||||
}
|
||||
|
||||
/// \brief Determine whether this class describes a lambda function object.
|
||||
bool isLambda() const { return hasDefinition() && data().IsLambda; }
|
||||
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
|
||||
@ -1025,12 +1054,18 @@ class CXXRecordDecl : public RecordDecl {
|
||||
void getCaptureFields(llvm::DenseMap<const VarDecl *, FieldDecl *> &Captures,
|
||||
FieldDecl *&ThisCapture) const;
|
||||
|
||||
typedef const LambdaExpr::Capture* capture_const_iterator;
|
||||
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 : NULL;
|
||||
return isLambda() ? getLambdaData().Captures : nullptr;
|
||||
}
|
||||
capture_const_iterator captures_end() const {
|
||||
return isLambda() ? captures_begin() + getLambdaData().NumCaptures : NULL;
|
||||
return isLambda() ? captures_begin() + getLambdaData().NumCaptures
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
typedef UnresolvedSetIterator conversion_iterator;
|
||||
@ -1058,7 +1093,8 @@ class CXXRecordDecl : public RecordDecl {
|
||||
bool isAggregate() const { return data().Aggregate; }
|
||||
|
||||
/// \brief Whether this class has any in-class initializers
|
||||
/// for non-static data members.
|
||||
/// 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
|
||||
@ -1117,6 +1153,9 @@ class CXXRecordDecl : public RecordDecl {
|
||||
/// 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 {
|
||||
@ -1144,7 +1183,7 @@ class CXXRecordDecl : public RecordDecl {
|
||||
/// would be constexpr.
|
||||
bool defaultedDefaultConstructorIsConstexpr() const {
|
||||
return data().DefaultedDefaultConstructorIsConstexpr &&
|
||||
(!isUnion() || hasInClassInitializer());
|
||||
(!isUnion() || hasInClassInitializer() || !hasVariantMembers());
|
||||
}
|
||||
|
||||
/// \brief Determine whether this class has a constexpr default constructor.
|
||||
@ -1546,7 +1585,7 @@ class CXXRecordDecl : public RecordDecl {
|
||||
void finishedDefaultedOrDeletedMember(CXXMethodDecl *MD);
|
||||
|
||||
/// \brief Indicates that the definition of this class is now complete.
|
||||
virtual void completeDefinition();
|
||||
void completeDefinition() override;
|
||||
|
||||
/// \brief Indicates that the definition of this class is now complete,
|
||||
/// and provides a final overrider map to help determine
|
||||
@ -1599,7 +1638,25 @@ class CXXRecordDecl : public RecordDecl {
|
||||
}
|
||||
|
||||
/// \brief Returns the inheritance model used for this record.
|
||||
MSInheritanceModel getMSInheritanceModel() const;
|
||||
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
|
||||
@ -1636,14 +1693,14 @@ class CXXRecordDecl : public RecordDecl {
|
||||
/// In the terminology of the C++ Standard, these are the (static and
|
||||
/// non-static) member functions, whether virtual or not.
|
||||
class CXXMethodDecl : public FunctionDecl {
|
||||
virtual void anchor();
|
||||
void anchor() override;
|
||||
protected:
|
||||
CXXMethodDecl(Kind DK, CXXRecordDecl *RD, SourceLocation StartLoc,
|
||||
const DeclarationNameInfo &NameInfo,
|
||||
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, RD, StartLoc, NameInfo, T, TInfo,
|
||||
: FunctionDecl(DK, C, RD, StartLoc, NameInfo, T, TInfo,
|
||||
SC, isInline, isConstexpr) {
|
||||
if (EndLocation.isValid())
|
||||
setRangeEnd(EndLocation);
|
||||
@ -1683,9 +1740,9 @@ class CXXMethodDecl : public FunctionDecl {
|
||||
CXXMethodDecl *CD =
|
||||
cast<CXXMethodDecl>(const_cast<CXXMethodDecl*>(this)->getCanonicalDecl());
|
||||
|
||||
// Methods declared in interfaces are automatically (pure) virtual.
|
||||
if (CD->isVirtualAsWritten() ||
|
||||
(CD->getParent()->isInterface() && CD->isUserProvided()))
|
||||
// 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());
|
||||
@ -1703,10 +1760,10 @@ class CXXMethodDecl : public FunctionDecl {
|
||||
/// \brief Determine whether this is a move assignment operator.
|
||||
bool isMoveAssignmentOperator() const;
|
||||
|
||||
CXXMethodDecl *getCanonicalDecl() {
|
||||
CXXMethodDecl *getCanonicalDecl() override {
|
||||
return cast<CXXMethodDecl>(FunctionDecl::getCanonicalDecl());
|
||||
}
|
||||
const CXXMethodDecl *getCanonicalDecl() const {
|
||||
const CXXMethodDecl *getCanonicalDecl() const override {
|
||||
return const_cast<CXXMethodDecl*>(this)->getCanonicalDecl();
|
||||
}
|
||||
|
||||
@ -1921,7 +1978,7 @@ class CXXCtorInitializer {
|
||||
/// In-class member initializers (also known as "non-static data member
|
||||
/// initializations", NSDMIs) were introduced in C++11.
|
||||
bool isInClassMemberInitializer() const {
|
||||
return isa<CXXDefaultInitExpr>(Init);
|
||||
return Init->getStmtClass() == Stmt::CXXDefaultInitExprClass;
|
||||
}
|
||||
|
||||
/// \brief Determine whether this initializer is creating a delegating
|
||||
@ -1968,20 +2025,20 @@ class CXXCtorInitializer {
|
||||
FieldDecl *getMember() const {
|
||||
if (isMemberInitializer())
|
||||
return Initializee.get<FieldDecl*>();
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
FieldDecl *getAnyMember() const {
|
||||
if (isMemberInitializer())
|
||||
return Initializee.get<FieldDecl*>();
|
||||
if (isIndirectMemberInitializer())
|
||||
return Initializee.get<IndirectFieldDecl*>()->getAnonField();
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IndirectFieldDecl *getIndirectMember() const {
|
||||
if (isIndirectMemberInitializer())
|
||||
return Initializee.get<IndirectFieldDecl*>();
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SourceLocation getMemberLocation() const {
|
||||
@ -2066,7 +2123,7 @@ class CXXCtorInitializer {
|
||||
/// };
|
||||
/// \endcode
|
||||
class CXXConstructorDecl : public CXXMethodDecl {
|
||||
virtual void anchor();
|
||||
void anchor() override;
|
||||
/// \brief Whether this constructor declaration has the \c explicit keyword
|
||||
/// specified.
|
||||
bool IsExplicitSpecified : 1;
|
||||
@ -2078,14 +2135,14 @@ class CXXConstructorDecl : public CXXMethodDecl {
|
||||
unsigned NumCtorInitializers;
|
||||
/// \}
|
||||
|
||||
CXXConstructorDecl(CXXRecordDecl *RD, SourceLocation StartLoc,
|
||||
CXXConstructorDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
|
||||
const DeclarationNameInfo &NameInfo,
|
||||
QualType T, TypeSourceInfo *TInfo,
|
||||
bool isExplicitSpecified, bool isInline,
|
||||
bool isImplicitlyDeclared, bool isConstexpr)
|
||||
: CXXMethodDecl(CXXConstructor, RD, StartLoc, NameInfo, T, TInfo,
|
||||
: CXXMethodDecl(CXXConstructor, C, RD, StartLoc, NameInfo, T, TInfo,
|
||||
SC_None, isInline, isConstexpr, SourceLocation()),
|
||||
IsExplicitSpecified(isExplicitSpecified), CtorInitializers(0),
|
||||
IsExplicitSpecified(isExplicitSpecified), CtorInitializers(nullptr),
|
||||
NumCtorInitializers(0) {
|
||||
setImplicit(isImplicitlyDeclared);
|
||||
}
|
||||
@ -2115,6 +2172,14 @@ class CXXConstructorDecl : public CXXMethodDecl {
|
||||
/// \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() { return CtorInitializers; }
|
||||
/// \brief Retrieve an iterator to the first initializer.
|
||||
@ -2240,10 +2305,10 @@ class CXXConstructorDecl : public CXXMethodDecl {
|
||||
/// \brief Set the constructor that this inheriting constructor is based on.
|
||||
void setInheritedConstructor(const CXXConstructorDecl *BaseCtor);
|
||||
|
||||
const CXXConstructorDecl *getCanonicalDecl() const {
|
||||
const CXXConstructorDecl *getCanonicalDecl() const override {
|
||||
return cast<CXXConstructorDecl>(FunctionDecl::getCanonicalDecl());
|
||||
}
|
||||
CXXConstructorDecl *getCanonicalDecl() {
|
||||
CXXConstructorDecl *getCanonicalDecl() override {
|
||||
return cast<CXXConstructorDecl>(FunctionDecl::getCanonicalDecl());
|
||||
}
|
||||
|
||||
@ -2266,17 +2331,17 @@ class CXXConstructorDecl : public CXXMethodDecl {
|
||||
/// };
|
||||
/// \endcode
|
||||
class CXXDestructorDecl : public CXXMethodDecl {
|
||||
virtual void anchor();
|
||||
void anchor() override;
|
||||
|
||||
FunctionDecl *OperatorDelete;
|
||||
|
||||
CXXDestructorDecl(CXXRecordDecl *RD, SourceLocation StartLoc,
|
||||
CXXDestructorDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
|
||||
const DeclarationNameInfo &NameInfo,
|
||||
QualType T, TypeSourceInfo *TInfo,
|
||||
bool isInline, bool isImplicitlyDeclared)
|
||||
: CXXMethodDecl(CXXDestructor, RD, StartLoc, NameInfo, T, TInfo,
|
||||
: CXXMethodDecl(CXXDestructor, C, RD, StartLoc, NameInfo, T, TInfo,
|
||||
SC_None, isInline, /*isConstexpr=*/false, SourceLocation()),
|
||||
OperatorDelete(0) {
|
||||
OperatorDelete(nullptr) {
|
||||
setImplicit(isImplicitlyDeclared);
|
||||
}
|
||||
|
||||
@ -2289,8 +2354,12 @@ class CXXDestructorDecl : public CXXMethodDecl {
|
||||
bool isImplicitlyDeclared);
|
||||
static CXXDestructorDecl *CreateDeserialized(ASTContext & C, unsigned ID);
|
||||
|
||||
void setOperatorDelete(FunctionDecl *OD) { OperatorDelete = OD; }
|
||||
const FunctionDecl *getOperatorDelete() const { return OperatorDelete; }
|
||||
void setOperatorDelete(FunctionDecl *OD) {
|
||||
cast<CXXDestructorDecl>(getFirstDecl())->OperatorDelete = 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()); }
|
||||
@ -2311,18 +2380,18 @@ class CXXDestructorDecl : public CXXMethodDecl {
|
||||
/// };
|
||||
/// \endcode
|
||||
class CXXConversionDecl : public CXXMethodDecl {
|
||||
virtual void anchor();
|
||||
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++0x feature.
|
||||
bool IsExplicitSpecified : 1;
|
||||
|
||||
CXXConversionDecl(CXXRecordDecl *RD, SourceLocation StartLoc,
|
||||
CXXConversionDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
|
||||
const DeclarationNameInfo &NameInfo,
|
||||
QualType T, TypeSourceInfo *TInfo,
|
||||
bool isInline, bool isExplicitSpecified,
|
||||
bool isConstexpr, SourceLocation EndLocation)
|
||||
: CXXMethodDecl(CXXConversion, RD, StartLoc, NameInfo, T, TInfo,
|
||||
: CXXMethodDecl(CXXConversion, C, RD, StartLoc, NameInfo, T, TInfo,
|
||||
SC_None, isInline, isConstexpr, EndLocation),
|
||||
IsExplicitSpecified(isExplicitSpecified) { }
|
||||
|
||||
@ -2351,7 +2420,7 @@ class CXXConversionDecl : public CXXMethodDecl {
|
||||
|
||||
/// \brief Returns the type that this conversion function is converting to.
|
||||
QualType getConversionType() const {
|
||||
return getType()->getAs<FunctionType>()->getResultType();
|
||||
return getType()->getAs<FunctionType>()->getReturnType();
|
||||
}
|
||||
|
||||
/// \brief Determine whether this conversion function is a conversion from
|
||||
@ -2440,7 +2509,7 @@ class LinkageSpecDecl : public Decl, public DeclContext {
|
||||
return decls_empty() ? getLocation() : decls_begin()->getLocEnd();
|
||||
}
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
SourceRange getSourceRange() const override LLVM_READONLY {
|
||||
return SourceRange(ExternLoc, getLocEnd());
|
||||
}
|
||||
|
||||
@ -2465,7 +2534,7 @@ class LinkageSpecDecl : public Decl, public DeclContext {
|
||||
/// artificial names for all using-directives in order to store
|
||||
/// them in DeclContext effectively.
|
||||
class UsingDirectiveDecl : public NamedDecl {
|
||||
virtual void anchor();
|
||||
void anchor() override;
|
||||
/// \brief The location of the \c using keyword.
|
||||
SourceLocation UsingLoc;
|
||||
|
||||
@ -2546,8 +2615,8 @@ class UsingDirectiveDecl : public NamedDecl {
|
||||
NamedDecl *Nominated,
|
||||
DeclContext *CommonAncestor);
|
||||
static UsingDirectiveDecl *CreateDeserialized(ASTContext &C, unsigned ID);
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
|
||||
SourceRange getSourceRange() const override LLVM_READONLY {
|
||||
return SourceRange(UsingLoc, getLocation());
|
||||
}
|
||||
|
||||
@ -2568,7 +2637,7 @@ class UsingDirectiveDecl : public NamedDecl {
|
||||
/// namespace Foo = Bar;
|
||||
/// \endcode
|
||||
class NamespaceAliasDecl : public NamedDecl {
|
||||
virtual void anchor();
|
||||
void anchor() override;
|
||||
|
||||
/// \brief The location of the \c namespace keyword.
|
||||
SourceLocation NamespaceLoc;
|
||||
@ -2641,8 +2710,8 @@ class NamespaceAliasDecl : public NamedDecl {
|
||||
NamedDecl *Namespace);
|
||||
|
||||
static NamespaceAliasDecl *CreateDeserialized(ASTContext &C, unsigned ID);
|
||||
|
||||
virtual SourceRange getSourceRange() const LLVM_READONLY {
|
||||
|
||||
SourceRange getSourceRange() const override LLVM_READONLY {
|
||||
return SourceRange(NamespaceLoc, IdentLoc);
|
||||
}
|
||||
|
||||
@ -2664,7 +2733,7 @@ class NamespaceAliasDecl : public NamedDecl {
|
||||
/// }
|
||||
/// \endcode
|
||||
class UsingShadowDecl : public NamedDecl, public Redeclarable<UsingShadowDecl> {
|
||||
virtual void anchor();
|
||||
void anchor() override;
|
||||
|
||||
/// The referenced declaration.
|
||||
NamedDecl *Underlying;
|
||||
@ -2674,10 +2743,10 @@ class UsingShadowDecl : public NamedDecl, public Redeclarable<UsingShadowDecl> {
|
||||
NamedDecl *UsingOrNextShadow;
|
||||
friend class UsingDecl;
|
||||
|
||||
UsingShadowDecl(DeclContext *DC, SourceLocation Loc, UsingDecl *Using,
|
||||
NamedDecl *Target)
|
||||
UsingShadowDecl(ASTContext &C, DeclContext *DC, SourceLocation Loc,
|
||||
UsingDecl *Using, NamedDecl *Target)
|
||||
: NamedDecl(UsingShadow, DC, Loc, DeclarationName()),
|
||||
Underlying(Target),
|
||||
redeclarable_base(C), Underlying(Target),
|
||||
UsingOrNextShadow(reinterpret_cast<NamedDecl *>(Using)) {
|
||||
if (Target) {
|
||||
setDeclName(Target->getDeclName());
|
||||
@ -2687,13 +2756,13 @@ class UsingShadowDecl : public NamedDecl, public Redeclarable<UsingShadowDecl> {
|
||||
}
|
||||
|
||||
typedef Redeclarable<UsingShadowDecl> redeclarable_base;
|
||||
virtual UsingShadowDecl *getNextRedeclaration() {
|
||||
return RedeclLink.getNext();
|
||||
UsingShadowDecl *getNextRedeclarationImpl() override {
|
||||
return getNextRedeclaration();
|
||||
}
|
||||
virtual UsingShadowDecl *getPreviousDeclImpl() {
|
||||
UsingShadowDecl *getPreviousDeclImpl() override {
|
||||
return getPreviousDecl();
|
||||
}
|
||||
virtual UsingShadowDecl *getMostRecentDeclImpl() {
|
||||
UsingShadowDecl *getMostRecentDeclImpl() override {
|
||||
return getMostRecentDecl();
|
||||
}
|
||||
|
||||
@ -2701,21 +2770,23 @@ class UsingShadowDecl : public NamedDecl, public Redeclarable<UsingShadowDecl> {
|
||||
static UsingShadowDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation Loc, UsingDecl *Using,
|
||||
NamedDecl *Target) {
|
||||
return new (C) UsingShadowDecl(DC, Loc, Using, 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;
|
||||
|
||||
virtual UsingShadowDecl *getCanonicalDecl() {
|
||||
UsingShadowDecl *getCanonicalDecl() override {
|
||||
return getFirstDecl();
|
||||
}
|
||||
virtual const UsingShadowDecl *getCanonicalDecl() const {
|
||||
const UsingShadowDecl *getCanonicalDecl() const {
|
||||
return getFirstDecl();
|
||||
}
|
||||
|
||||
@ -2754,7 +2825,7 @@ class UsingShadowDecl : public NamedDecl, public Redeclarable<UsingShadowDecl> {
|
||||
/// using someNameSpace::someIdentifier;
|
||||
/// \endcode
|
||||
class UsingDecl : public NamedDecl {
|
||||
virtual void anchor();
|
||||
void anchor() override;
|
||||
|
||||
/// \brief The source location of the 'using' keyword itself.
|
||||
SourceLocation UsingLocation;
|
||||
@ -2778,7 +2849,7 @@ class UsingDecl : public NamedDecl {
|
||||
const DeclarationNameInfo &NameInfo, bool HasTypenameKeyword)
|
||||
: NamedDecl(Using, DC, NameInfo.getLoc(), NameInfo.getName()),
|
||||
UsingLocation(UL), QualifierLoc(QualifierLoc),
|
||||
DNLoc(NameInfo.getInfo()), FirstUsingShadow(0, HasTypenameKeyword) {
|
||||
DNLoc(NameInfo.getInfo()), FirstUsingShadow(nullptr, HasTypenameKeyword) {
|
||||
}
|
||||
|
||||
public:
|
||||
@ -2823,7 +2894,7 @@ class UsingDecl : public NamedDecl {
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
|
||||
shadow_iterator() : Current(0) { }
|
||||
shadow_iterator() : Current(nullptr) { }
|
||||
explicit shadow_iterator(UsingShadowDecl *C) : Current(C) { }
|
||||
|
||||
reference operator*() const { return Current; }
|
||||
@ -2848,6 +2919,11 @@ class UsingDecl : public NamedDecl {
|
||||
}
|
||||
};
|
||||
|
||||
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());
|
||||
}
|
||||
@ -2870,7 +2946,7 @@ class UsingDecl : public NamedDecl {
|
||||
|
||||
static UsingDecl *CreateDeserialized(ASTContext &C, unsigned ID);
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY;
|
||||
SourceRange getSourceRange() const override LLVM_READONLY;
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classofKind(Kind K) { return K == Using; }
|
||||
@ -2891,7 +2967,7 @@ class UsingDecl : public NamedDecl {
|
||||
/// };
|
||||
/// \endcode
|
||||
class UnresolvedUsingValueDecl : public ValueDecl {
|
||||
virtual void anchor();
|
||||
void anchor() override;
|
||||
|
||||
/// \brief The source location of the 'using' keyword
|
||||
SourceLocation UsingLocation;
|
||||
@ -2944,7 +3020,7 @@ class UnresolvedUsingValueDecl : public ValueDecl {
|
||||
static UnresolvedUsingValueDecl *
|
||||
CreateDeserialized(ASTContext &C, unsigned ID);
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY;
|
||||
SourceRange getSourceRange() const override LLVM_READONLY;
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classofKind(Kind K) { return K == UnresolvedUsingValue; }
|
||||
@ -2965,7 +3041,7 @@ class UnresolvedUsingValueDecl : public ValueDecl {
|
||||
/// The type associated with an unresolved using typename decl is
|
||||
/// currently always a typename type.
|
||||
class UnresolvedUsingTypenameDecl : public TypeDecl {
|
||||
virtual void anchor();
|
||||
void anchor() override;
|
||||
|
||||
/// \brief The source location of the 'typename' keyword
|
||||
SourceLocation TypenameLocation;
|
||||
@ -3043,7 +3119,7 @@ class StaticAssertDecl : public Decl {
|
||||
|
||||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
SourceRange getSourceRange() const override LLVM_READONLY {
|
||||
return SourceRange(getLocation(), getRParenLoc());
|
||||
}
|
||||
|
||||
@ -3083,21 +3159,24 @@ class StaticAssertDecl : public Decl {
|
||||
class MSPropertyDecl : public DeclaratorDecl {
|
||||
IdentifierInfo *GetterId, *SetterId;
|
||||
|
||||
public:
|
||||
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) {}
|
||||
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 != NULL; }
|
||||
bool hasGetter() const { return GetterId != nullptr; }
|
||||
IdentifierInfo* getGetterId() const { return GetterId; }
|
||||
bool hasSetter() const { return SetterId != NULL; }
|
||||
bool hasSetter() const { return SetterId != nullptr; }
|
||||
IdentifierInfo* getSetterId() const { return SetterId; }
|
||||
|
||||
friend class ASTDeclReader;
|
||||
|
@ -46,10 +46,8 @@ struct StoredDeclsList {
|
||||
public:
|
||||
StoredDeclsList() {}
|
||||
|
||||
StoredDeclsList(const StoredDeclsList &RHS) : Data(RHS.Data) {
|
||||
if (DeclsTy *RHSVec = RHS.getAsVector())
|
||||
Data = DeclsAndHasExternalTy(new DeclsTy(*RHSVec),
|
||||
RHS.hasExternalDecls());
|
||||
StoredDeclsList(StoredDeclsList &&RHS) : Data(RHS.Data) {
|
||||
RHS.Data = (NamedDecl *)nullptr;
|
||||
}
|
||||
|
||||
~StoredDeclsList() {
|
||||
@ -58,12 +56,11 @@ struct StoredDeclsList {
|
||||
delete Vector;
|
||||
}
|
||||
|
||||
StoredDeclsList &operator=(const StoredDeclsList &RHS) {
|
||||
StoredDeclsList &operator=(StoredDeclsList &&RHS) {
|
||||
if (DeclsTy *Vector = getAsVector())
|
||||
delete Vector;
|
||||
Data = RHS.Data;
|
||||
if (DeclsTy *RHSVec = RHS.getAsVector())
|
||||
Data = DeclsAndHasExternalTy(new DeclsTy(*RHSVec), hasExternalDecls());
|
||||
RHS.Data = (NamedDecl *)nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -110,7 +107,7 @@ struct StoredDeclsList {
|
||||
if (NamedDecl *Singleton = getAsDecl()) {
|
||||
assert(Singleton == D && "list is different singleton");
|
||||
(void)Singleton;
|
||||
Data = (NamedDecl *)0;
|
||||
Data = (NamedDecl *)nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -145,8 +142,8 @@ struct StoredDeclsList {
|
||||
/// represents.
|
||||
DeclContext::lookup_result getLookupResult() {
|
||||
if (isNull())
|
||||
return DeclContext::lookup_result(DeclContext::lookup_iterator(0),
|
||||
DeclContext::lookup_iterator(0));
|
||||
return DeclContext::lookup_result(DeclContext::lookup_iterator(nullptr),
|
||||
DeclContext::lookup_iterator(nullptr));
|
||||
|
||||
// If we have a single NamedDecl, return it.
|
||||
if (getAsDecl()) {
|
||||
@ -255,7 +252,7 @@ class StoredDeclsMap
|
||||
|
||||
class DependentStoredDeclsMap : public StoredDeclsMap {
|
||||
public:
|
||||
DependentStoredDeclsMap() : FirstDiagnostic(0) {}
|
||||
DependentStoredDeclsMap() : FirstDiagnostic(nullptr) {}
|
||||
|
||||
private:
|
||||
friend class DependentDiagnostic;
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "clang/AST/TypeLoc.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
namespace clang {
|
||||
@ -91,7 +92,7 @@ class FriendDecl : public Decl {
|
||||
|
||||
FriendDecl *getNextFriend() {
|
||||
if (!NextFriend.isOffset())
|
||||
return cast_or_null<FriendDecl>(NextFriend.get(0));
|
||||
return cast_or_null<FriendDecl>(NextFriend.get(nullptr));
|
||||
return getNextFriendSlowCase();
|
||||
}
|
||||
FriendDecl *getNextFriendSlowCase();
|
||||
@ -132,10 +133,14 @@ class FriendDecl : public Decl {
|
||||
}
|
||||
|
||||
/// Retrieves the source range for the friend declaration.
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
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();
|
||||
@ -224,7 +229,11 @@ inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_begin() const {
|
||||
}
|
||||
|
||||
inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_end() const {
|
||||
return friend_iterator(0);
|
||||
return friend_iterator(nullptr);
|
||||
}
|
||||
|
||||
inline CXXRecordDecl::friend_range CXXRecordDecl::friends() const {
|
||||
return friend_range(friend_begin(), friend_end());
|
||||
}
|
||||
|
||||
inline void CXXRecordDecl::pushFriendDecl(FriendDecl *FD) {
|
||||
|
@ -63,7 +63,7 @@ class DeclGroupRef {
|
||||
}
|
||||
|
||||
public:
|
||||
DeclGroupRef() : D(0) {}
|
||||
DeclGroupRef() : D(nullptr) {}
|
||||
|
||||
explicit DeclGroupRef(Decl* d) : D(d) {}
|
||||
explicit DeclGroupRef(DeclGroup* dg)
|
||||
@ -80,7 +80,7 @@ class DeclGroupRef {
|
||||
typedef Decl** iterator;
|
||||
typedef Decl* const * const_iterator;
|
||||
|
||||
bool isNull() const { return D == 0; }
|
||||
bool isNull() const { return D == nullptr; }
|
||||
bool isSingleDecl() const { return getKind() == SingleDeclKind; }
|
||||
bool isDeclGroup() const { return getKind() == DeclGroupKind; }
|
||||
|
||||
@ -102,26 +102,26 @@ class DeclGroupRef {
|
||||
|
||||
iterator begin() {
|
||||
if (isSingleDecl())
|
||||
return D ? &D : 0;
|
||||
return D ? &D : nullptr;
|
||||
return &getDeclGroup()[0];
|
||||
}
|
||||
|
||||
iterator end() {
|
||||
if (isSingleDecl())
|
||||
return D ? &D+1 : 0;
|
||||
return D ? &D+1 : nullptr;
|
||||
DeclGroup &G = getDeclGroup();
|
||||
return &G[0] + G.size();
|
||||
}
|
||||
|
||||
const_iterator begin() const {
|
||||
if (isSingleDecl())
|
||||
return D ? &D : 0;
|
||||
return D ? &D : nullptr;
|
||||
return &getDeclGroup()[0];
|
||||
}
|
||||
|
||||
const_iterator end() const {
|
||||
if (isSingleDecl())
|
||||
return D ? &D+1 : 0;
|
||||
return D ? &D+1 : nullptr;
|
||||
const DeclGroup &G = getDeclGroup();
|
||||
return &G[0] + G.size();
|
||||
}
|
||||
|
@ -68,38 +68,40 @@ class DeclContext::all_lookups_iterator {
|
||||
}
|
||||
};
|
||||
|
||||
inline DeclContext::all_lookups_iterator DeclContext::lookups_begin() const {
|
||||
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 all_lookups_iterator(Map->begin(), Map->end());
|
||||
return all_lookups_iterator();
|
||||
return lookups_range(all_lookups_iterator(Map->begin(), Map->end()),
|
||||
all_lookups_iterator(Map->end(), Map->end()));
|
||||
return lookups_range();
|
||||
}
|
||||
|
||||
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 (Primary->hasExternalVisibleStorage())
|
||||
getParentASTContext().getExternalSource()->completeVisibleDeclsMap(Primary);
|
||||
if (StoredDeclsMap *Map = Primary->buildLookup())
|
||||
return all_lookups_iterator(Map->end(), Map->end());
|
||||
return all_lookups_iterator();
|
||||
if (StoredDeclsMap *Map = Primary->getLookupPtr())
|
||||
return lookups_range(all_lookups_iterator(Map->begin(), Map->end()),
|
||||
all_lookups_iterator(Map->end(), Map->end()));
|
||||
return lookups_range();
|
||||
}
|
||||
|
||||
inline
|
||||
DeclContext::all_lookups_iterator DeclContext::noload_lookups_begin() const {
|
||||
DeclContext *Primary = const_cast<DeclContext*>(this)->getPrimaryContext();
|
||||
if (StoredDeclsMap *Map = Primary->getLookupPtr())
|
||||
return all_lookups_iterator(Map->begin(), Map->end());
|
||||
return all_lookups_iterator();
|
||||
return noload_lookups().begin();
|
||||
}
|
||||
|
||||
inline
|
||||
DeclContext::all_lookups_iterator DeclContext::noload_lookups_end() const {
|
||||
DeclContext *Primary = const_cast<DeclContext*>(this)->getPrimaryContext();
|
||||
if (StoredDeclsMap *Map = Primary->getLookupPtr())
|
||||
return all_lookups_iterator(Map->end(), Map->end());
|
||||
return all_lookups_iterator();
|
||||
return noload_lookups().end();
|
||||
}
|
||||
|
||||
} // end namespace clang
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -47,10 +47,10 @@ class OMPThreadPrivateDecl : public Decl {
|
||||
NumVars);
|
||||
}
|
||||
|
||||
llvm::MutableArrayRef<Expr *> getVars() {
|
||||
return llvm::MutableArrayRef<Expr *>(
|
||||
reinterpret_cast<Expr **>(this + 1),
|
||||
NumVars);
|
||||
MutableArrayRef<Expr *> getVars() {
|
||||
return MutableArrayRef<Expr *>(
|
||||
reinterpret_cast<Expr **>(this + 1),
|
||||
NumVars);
|
||||
}
|
||||
|
||||
void setVars(ArrayRef<Expr *> VL);
|
||||
@ -62,11 +62,20 @@ class OMPThreadPrivateDecl : public Decl {
|
||||
static OMPThreadPrivateDecl *CreateDeserialized(ASTContext &C,
|
||||
unsigned ID, unsigned N);
|
||||
|
||||
typedef llvm::MutableArrayRef<Expr *>::iterator varlist_iterator;
|
||||
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(); }
|
||||
|
@ -86,11 +86,11 @@ class TemplateParameterList {
|
||||
|
||||
unsigned size() const { return NumParams; }
|
||||
|
||||
llvm::ArrayRef<NamedDecl*> asArray() {
|
||||
return llvm::ArrayRef<NamedDecl*>(begin(), size());
|
||||
ArrayRef<NamedDecl*> asArray() {
|
||||
return ArrayRef<NamedDecl*>(begin(), size());
|
||||
}
|
||||
llvm::ArrayRef<const NamedDecl*> asArray() const {
|
||||
return llvm::ArrayRef<const NamedDecl*>(begin(), size());
|
||||
ArrayRef<const NamedDecl*> asArray() const {
|
||||
return ArrayRef<const NamedDecl*>(begin(), size());
|
||||
}
|
||||
|
||||
NamedDecl* getParam(unsigned Idx) {
|
||||
@ -203,8 +203,8 @@ class TemplateArgumentList {
|
||||
const TemplateArgument &operator[](unsigned Idx) const { return get(Idx); }
|
||||
|
||||
/// \brief Produce this as an array ref.
|
||||
llvm::ArrayRef<TemplateArgument> asArray() const {
|
||||
return llvm::ArrayRef<TemplateArgument>(data(), size());
|
||||
ArrayRef<TemplateArgument> asArray() const {
|
||||
return ArrayRef<TemplateArgument>(data(), size());
|
||||
}
|
||||
|
||||
/// \brief Retrieve the number of template arguments in this
|
||||
@ -227,18 +227,20 @@ class TemplateArgumentList {
|
||||
/// 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 {
|
||||
virtual void anchor();
|
||||
void anchor() override;
|
||||
protected:
|
||||
// This is probably never used.
|
||||
TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L,
|
||||
DeclarationName Name)
|
||||
: NamedDecl(DK, DC, L, Name), TemplatedDecl(0), TemplateParams(0) { }
|
||||
: 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, alias?).
|
||||
TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L,
|
||||
DeclarationName Name, TemplateParameterList *Params)
|
||||
: NamedDecl(DK, DC, L, Name), TemplatedDecl(0), TemplateParams(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,
|
||||
@ -261,7 +263,7 @@ class TemplateDecl : public NamedDecl {
|
||||
return K >= firstTemplate && K <= lastTemplate;
|
||||
}
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
SourceRange getSourceRange() const override LLVM_READONLY {
|
||||
return SourceRange(TemplateParams->getTemplateLoc(),
|
||||
TemplatedDecl->getSourceRange().getEnd());
|
||||
}
|
||||
@ -274,8 +276,8 @@ class TemplateDecl : public NamedDecl {
|
||||
/// \brief Initialize the underlying templated declaration and
|
||||
/// template parameters.
|
||||
void init(NamedDecl *templatedDecl, TemplateParameterList* templateParams) {
|
||||
assert(TemplatedDecl == 0 && "TemplatedDecl already set!");
|
||||
assert(TemplateParams == 0 && "TemplateParams already set!");
|
||||
assert(!TemplatedDecl && "TemplatedDecl already set!");
|
||||
assert(!TemplateParams && "TemplateParams already set!");
|
||||
TemplatedDecl = templatedDecl;
|
||||
TemplateParams = templateParams;
|
||||
}
|
||||
@ -378,16 +380,15 @@ class FunctionTemplateSpecializationInfo : public llvm::FoldingSetNode {
|
||||
}
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, TemplateArguments->data(),
|
||||
TemplateArguments->size(),
|
||||
Profile(ID, TemplateArguments->asArray(),
|
||||
Function->getASTContext());
|
||||
}
|
||||
|
||||
static void
|
||||
Profile(llvm::FoldingSetNodeID &ID, const TemplateArgument *TemplateArgs,
|
||||
unsigned NumTemplateArgs, ASTContext &Context) {
|
||||
ID.AddInteger(NumTemplateArgs);
|
||||
for (unsigned Arg = 0; Arg != NumTemplateArgs; ++Arg)
|
||||
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);
|
||||
}
|
||||
};
|
||||
@ -530,13 +531,13 @@ class RedeclarableTemplateDecl : public TemplateDecl,
|
||||
public Redeclarable<RedeclarableTemplateDecl>
|
||||
{
|
||||
typedef Redeclarable<RedeclarableTemplateDecl> redeclarable_base;
|
||||
virtual RedeclarableTemplateDecl *getNextRedeclaration() {
|
||||
return RedeclLink.getNext();
|
||||
RedeclarableTemplateDecl *getNextRedeclarationImpl() override {
|
||||
return getNextRedeclaration();
|
||||
}
|
||||
virtual RedeclarableTemplateDecl *getPreviousDeclImpl() {
|
||||
RedeclarableTemplateDecl *getPreviousDeclImpl() override {
|
||||
return getPreviousDecl();
|
||||
}
|
||||
virtual RedeclarableTemplateDecl *getMostRecentDeclImpl() {
|
||||
RedeclarableTemplateDecl *getMostRecentDeclImpl() override {
|
||||
return getMostRecentDecl();
|
||||
}
|
||||
|
||||
@ -595,11 +596,10 @@ class RedeclarableTemplateDecl : public TemplateDecl,
|
||||
|
||||
template <class EntryType> typename SpecEntryTraits<EntryType>::DeclType*
|
||||
findSpecializationImpl(llvm::FoldingSetVector<EntryType> &Specs,
|
||||
const TemplateArgument *Args, unsigned NumArgs,
|
||||
void *&InsertPos);
|
||||
ArrayRef<TemplateArgument> Args, void *&InsertPos);
|
||||
|
||||
struct CommonBase {
|
||||
CommonBase() : InstantiatedFromMember(0, false) { }
|
||||
CommonBase() : InstantiatedFromMember(nullptr, false) { }
|
||||
|
||||
/// \brief The template from which this was most
|
||||
/// directly instantiated (or null).
|
||||
@ -622,16 +622,19 @@ class RedeclarableTemplateDecl : public TemplateDecl,
|
||||
virtual CommonBase *newCommon(ASTContext &C) const = 0;
|
||||
|
||||
// Construct a template decl with name, parameters, and templated element.
|
||||
RedeclarableTemplateDecl(Kind DK, DeclContext *DC, SourceLocation L,
|
||||
DeclarationName Name, TemplateParameterList *Params,
|
||||
NamedDecl *Decl)
|
||||
: TemplateDecl(DK, DC, L, Name, Params, Decl), Common() { }
|
||||
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() { return getFirstDecl(); }
|
||||
RedeclarableTemplateDecl *getCanonicalDecl() override {
|
||||
return getFirstDecl();
|
||||
}
|
||||
const RedeclarableTemplateDecl *getCanonicalDecl() const {
|
||||
return getFirstDecl();
|
||||
}
|
||||
@ -710,9 +713,11 @@ class RedeclarableTemplateDecl : public TemplateDecl,
|
||||
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;
|
||||
@ -769,11 +774,13 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl {
|
||||
uint32_t *LazySpecializations;
|
||||
};
|
||||
|
||||
FunctionTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
|
||||
TemplateParameterList *Params, NamedDecl *Decl)
|
||||
: RedeclarableTemplateDecl(FunctionTemplate, DC, L, Name, Params, Decl) { }
|
||||
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;
|
||||
CommonBase *newCommon(ASTContext &C) const override;
|
||||
|
||||
Common *getCommonPtr() const {
|
||||
return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr());
|
||||
@ -810,10 +817,10 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl {
|
||||
|
||||
/// \brief Return the specialization with the provided arguments if it exists,
|
||||
/// otherwise return the insertion point.
|
||||
FunctionDecl *findSpecialization(const TemplateArgument *Args,
|
||||
unsigned NumArgs, void *&InsertPos);
|
||||
FunctionDecl *findSpecialization(ArrayRef<TemplateArgument> Args,
|
||||
void *&InsertPos);
|
||||
|
||||
FunctionTemplateDecl *getCanonicalDecl() {
|
||||
FunctionTemplateDecl *getCanonicalDecl() override {
|
||||
return cast<FunctionTemplateDecl>(
|
||||
RedeclarableTemplateDecl::getCanonicalDecl());
|
||||
}
|
||||
@ -842,7 +849,11 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl {
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@ -892,12 +903,9 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl {
|
||||
/// This class is inheritedly privately by different kinds of template
|
||||
/// parameters and is not part of the Decl hierarchy. Just a facility.
|
||||
class TemplateParmPosition {
|
||||
protected:
|
||||
// FIXME: This should probably never be called, but it's here as
|
||||
TemplateParmPosition()
|
||||
: Depth(0), Position(0)
|
||||
{ /* llvm_unreachable("Cannot create positionless template parameter"); */ }
|
||||
TemplateParmPosition() LLVM_DELETED_FUNCTION;
|
||||
|
||||
protected:
|
||||
TemplateParmPosition(unsigned D, unsigned P)
|
||||
: Depth(D), Position(P)
|
||||
{ }
|
||||
@ -967,7 +975,7 @@ class TemplateTypeParmDecl : public TypeDecl {
|
||||
|
||||
/// \brief Determine whether this template parameter has a default
|
||||
/// argument.
|
||||
bool hasDefaultArgument() const { return DefaultArgument != 0; }
|
||||
bool hasDefaultArgument() const { return DefaultArgument != nullptr; }
|
||||
|
||||
/// \brief Retrieve the default argument, if any.
|
||||
QualType getDefaultArgument() const { return DefaultArgument->getType(); }
|
||||
@ -992,7 +1000,7 @@ class TemplateTypeParmDecl : public TypeDecl {
|
||||
|
||||
/// \brief Removes the default argument of this template parameter.
|
||||
void removeDefaultArgument() {
|
||||
DefaultArgument = 0;
|
||||
DefaultArgument = nullptr;
|
||||
InheritedDefault = false;
|
||||
}
|
||||
|
||||
@ -1009,7 +1017,7 @@ class TemplateTypeParmDecl : public TypeDecl {
|
||||
/// \brief Returns whether this is a parameter pack.
|
||||
bool isParameterPack() const;
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY;
|
||||
SourceRange getSourceRange() const override LLVM_READONLY;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
@ -1046,7 +1054,7 @@ class NonTypeTemplateParmDecl
|
||||
IdentifierInfo *Id, QualType T,
|
||||
bool ParameterPack, TypeSourceInfo *TInfo)
|
||||
: DeclaratorDecl(NonTypeTemplateParm, DC, IdLoc, Id, T, TInfo, StartLoc),
|
||||
TemplateParmPosition(D, P), DefaultArgumentAndInherited(0, false),
|
||||
TemplateParmPosition(D, P), DefaultArgumentAndInherited(nullptr, false),
|
||||
ParameterPack(ParameterPack), ExpandedParameterPack(false),
|
||||
NumExpandedTypes(0)
|
||||
{ }
|
||||
@ -1086,12 +1094,12 @@ class NonTypeTemplateParmDecl
|
||||
using TemplateParmPosition::setPosition;
|
||||
using TemplateParmPosition::getIndex;
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY;
|
||||
SourceRange getSourceRange() const override LLVM_READONLY;
|
||||
|
||||
/// \brief Determine whether this template parameter has a default
|
||||
/// argument.
|
||||
bool hasDefaultArgument() const {
|
||||
return DefaultArgumentAndInherited.getPointer() != 0;
|
||||
return DefaultArgumentAndInherited.getPointer() != nullptr;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the default argument, if any.
|
||||
@ -1118,7 +1126,7 @@ class NonTypeTemplateParmDecl
|
||||
|
||||
/// \brief Removes the default argument of this template parameter.
|
||||
void removeDefaultArgument() {
|
||||
DefaultArgumentAndInherited.setPointer(0);
|
||||
DefaultArgumentAndInherited.setPointer(nullptr);
|
||||
DefaultArgumentAndInherited.setInt(false);
|
||||
}
|
||||
|
||||
@ -1206,7 +1214,7 @@ class NonTypeTemplateParmDecl
|
||||
class TemplateTemplateParmDecl : public TemplateDecl,
|
||||
protected TemplateParmPosition
|
||||
{
|
||||
virtual void anchor();
|
||||
void anchor() override;
|
||||
|
||||
/// DefaultArgument - The default template argument, if any.
|
||||
TemplateArgumentLoc DefaultArgument;
|
||||
@ -1347,7 +1355,7 @@ class TemplateTemplateParmDecl : public TemplateDecl,
|
||||
DefaultArgumentWasInherited = false;
|
||||
}
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
SourceRange getSourceRange() const override LLVM_READONLY {
|
||||
SourceLocation End = getLocation();
|
||||
if (hasDefaultArgument() && !defaultArgumentWasInherited())
|
||||
End = getDefaultArgument().getSourceRange().getEnd();
|
||||
@ -1405,7 +1413,7 @@ class ClassTemplateSpecializationDecl
|
||||
SourceLocation TemplateKeywordLoc;
|
||||
|
||||
ExplicitSpecializationInfo()
|
||||
: TypeAsWritten(0), ExternLoc(), TemplateKeywordLoc() {}
|
||||
: TypeAsWritten(nullptr), ExternLoc(), TemplateKeywordLoc() {}
|
||||
};
|
||||
|
||||
/// \brief Further info for explicit template specialization/instantiation.
|
||||
@ -1431,7 +1439,7 @@ class ClassTemplateSpecializationDecl
|
||||
unsigned NumArgs,
|
||||
ClassTemplateSpecializationDecl *PrevDecl);
|
||||
|
||||
explicit ClassTemplateSpecializationDecl(Kind DK);
|
||||
explicit ClassTemplateSpecializationDecl(ASTContext &C, Kind DK);
|
||||
|
||||
public:
|
||||
static ClassTemplateSpecializationDecl *
|
||||
@ -1444,10 +1452,14 @@ class ClassTemplateSpecializationDecl
|
||||
static ClassTemplateSpecializationDecl *
|
||||
CreateDeserialized(ASTContext &C, unsigned ID);
|
||||
|
||||
virtual void getNameForDiagnostic(raw_ostream &OS,
|
||||
const PrintingPolicy &Policy,
|
||||
bool Qualified) const;
|
||||
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();
|
||||
@ -1516,17 +1528,11 @@ class ClassTemplateSpecializationDecl
|
||||
llvm::PointerUnion<ClassTemplateDecl *,
|
||||
ClassTemplatePartialSpecializationDecl *>
|
||||
getInstantiatedFrom() const {
|
||||
if (getSpecializationKind() != TSK_ImplicitInstantiation &&
|
||||
getSpecializationKind() != TSK_ExplicitInstantiationDefinition &&
|
||||
getSpecializationKind() != TSK_ExplicitInstantiationDeclaration)
|
||||
if (!isTemplateInstantiation(getSpecializationKind()))
|
||||
return llvm::PointerUnion<ClassTemplateDecl *,
|
||||
ClassTemplatePartialSpecializationDecl *>();
|
||||
|
||||
if (SpecializedPartialSpecialization *PartialSpec
|
||||
= SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization*>())
|
||||
return PartialSpec->PartialSpecialization;
|
||||
|
||||
return SpecializedTemplate.get<ClassTemplateDecl*>();
|
||||
return getSpecializedTemplateOrPartial();
|
||||
}
|
||||
|
||||
/// \brief Retrieve the class template or class template partial
|
||||
@ -1592,7 +1598,7 @@ class ClassTemplateSpecializationDecl
|
||||
/// \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 : 0;
|
||||
return ExplicitInfo ? ExplicitInfo->TypeAsWritten : nullptr;
|
||||
}
|
||||
|
||||
/// \brief Gets the location of the extern keyword, if present.
|
||||
@ -1617,17 +1623,17 @@ class ClassTemplateSpecializationDecl
|
||||
return ExplicitInfo ? ExplicitInfo->TemplateKeywordLoc : SourceLocation();
|
||||
}
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY;
|
||||
SourceRange getSourceRange() const override LLVM_READONLY;
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) const {
|
||||
Profile(ID, TemplateArgs->data(), TemplateArgs->size(), getASTContext());
|
||||
Profile(ID, TemplateArgs->asArray(), getASTContext());
|
||||
}
|
||||
|
||||
static void
|
||||
Profile(llvm::FoldingSetNodeID &ID, const TemplateArgument *TemplateArgs,
|
||||
unsigned NumTemplateArgs, ASTContext &Context) {
|
||||
ID.AddInteger(NumTemplateArgs);
|
||||
for (unsigned Arg = 0; Arg != NumTemplateArgs; ++Arg)
|
||||
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);
|
||||
}
|
||||
|
||||
@ -1643,7 +1649,7 @@ class ClassTemplateSpecializationDecl
|
||||
|
||||
class ClassTemplatePartialSpecializationDecl
|
||||
: public ClassTemplateSpecializationDecl {
|
||||
virtual void anchor();
|
||||
void anchor() override;
|
||||
|
||||
/// \brief The list of template parameters
|
||||
TemplateParameterList* TemplateParams;
|
||||
@ -1671,9 +1677,10 @@ class ClassTemplatePartialSpecializationDecl
|
||||
const ASTTemplateArgumentListInfo *ArgsAsWritten,
|
||||
ClassTemplatePartialSpecializationDecl *PrevDecl);
|
||||
|
||||
ClassTemplatePartialSpecializationDecl()
|
||||
: ClassTemplateSpecializationDecl(ClassTemplatePartialSpecialization),
|
||||
TemplateParams(0), ArgsAsWritten(0), InstantiatedFromMember(0, false) { }
|
||||
ClassTemplatePartialSpecializationDecl(ASTContext &C)
|
||||
: ClassTemplateSpecializationDecl(C, ClassTemplatePartialSpecialization),
|
||||
TemplateParams(nullptr), ArgsAsWritten(nullptr),
|
||||
InstantiatedFromMember(nullptr, false) {}
|
||||
|
||||
public:
|
||||
static ClassTemplatePartialSpecializationDecl *
|
||||
@ -1832,15 +1839,12 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
|
||||
llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> &
|
||||
getPartialSpecializations();
|
||||
|
||||
ClassTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
|
||||
TemplateParameterList *Params, NamedDecl *Decl)
|
||||
: RedeclarableTemplateDecl(ClassTemplate, DC, L, Name, Params, Decl) { }
|
||||
ClassTemplateDecl(ASTContext &C, DeclContext *DC, SourceLocation L,
|
||||
DeclarationName Name, TemplateParameterList *Params,
|
||||
NamedDecl *Decl)
|
||||
: RedeclarableTemplateDecl(ClassTemplate, C, DC, L, Name, Params, Decl) {}
|
||||
|
||||
ClassTemplateDecl(EmptyShell Empty)
|
||||
: RedeclarableTemplateDecl(ClassTemplate, 0, SourceLocation(),
|
||||
DeclarationName(), 0, 0) { }
|
||||
|
||||
CommonBase *newCommon(ASTContext &C) const;
|
||||
CommonBase *newCommon(ASTContext &C) const override;
|
||||
|
||||
Common *getCommonPtr() const {
|
||||
return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr());
|
||||
@ -1872,14 +1876,13 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
|
||||
/// \brief Return the specialization with the provided arguments if it exists,
|
||||
/// otherwise return the insertion point.
|
||||
ClassTemplateSpecializationDecl *
|
||||
findSpecialization(const TemplateArgument *Args, unsigned NumArgs,
|
||||
void *&InsertPos);
|
||||
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() {
|
||||
ClassTemplateDecl *getCanonicalDecl() override {
|
||||
return cast<ClassTemplateDecl>(
|
||||
RedeclarableTemplateDecl::getCanonicalDecl());
|
||||
}
|
||||
@ -1919,8 +1922,7 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
|
||||
/// \brief Return the partial specialization with the provided arguments if it
|
||||
/// exists, otherwise return the insertion point.
|
||||
ClassTemplatePartialSpecializationDecl *
|
||||
findPartialSpecialization(const TemplateArgument *Args, unsigned NumArgs,
|
||||
void *&InsertPos);
|
||||
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.
|
||||
@ -1970,6 +1972,11 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
|
||||
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);
|
||||
@ -1979,17 +1986,6 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
|
||||
return makeSpecIterator(getSpecializations(), true);
|
||||
}
|
||||
|
||||
typedef SpecIterator<ClassTemplatePartialSpecializationDecl>
|
||||
partial_spec_iterator;
|
||||
|
||||
partial_spec_iterator partial_spec_begin() {
|
||||
return makeSpecIterator(getPartialSpecializations(), false);
|
||||
}
|
||||
|
||||
partial_spec_iterator partial_spec_end() {
|
||||
return makeSpecIterator(getPartialSpecializations(), true);
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast support
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classofKind(Kind K) { return K == ClassTemplate; }
|
||||
@ -2045,7 +2041,7 @@ class FriendTemplateDecl : public Decl {
|
||||
FriendTemplateDecl(EmptyShell Empty)
|
||||
: Decl(Decl::FriendTemplate, Empty),
|
||||
NumParams(0),
|
||||
Params(0)
|
||||
Params(nullptr)
|
||||
{}
|
||||
|
||||
public:
|
||||
@ -2105,11 +2101,13 @@ class TypeAliasTemplateDecl : public RedeclarableTemplateDecl {
|
||||
protected:
|
||||
typedef CommonBase Common;
|
||||
|
||||
TypeAliasTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
|
||||
TemplateParameterList *Params, NamedDecl *Decl)
|
||||
: RedeclarableTemplateDecl(TypeAliasTemplate, DC, L, Name, Params, Decl) { }
|
||||
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;
|
||||
CommonBase *newCommon(ASTContext &C) const override;
|
||||
|
||||
Common *getCommonPtr() {
|
||||
return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr());
|
||||
@ -2122,7 +2120,7 @@ class TypeAliasTemplateDecl : public RedeclarableTemplateDecl {
|
||||
}
|
||||
|
||||
|
||||
TypeAliasTemplateDecl *getCanonicalDecl() {
|
||||
TypeAliasTemplateDecl *getCanonicalDecl() override {
|
||||
return cast<TypeAliasTemplateDecl>(
|
||||
RedeclarableTemplateDecl::getCanonicalDecl());
|
||||
}
|
||||
@ -2172,7 +2170,7 @@ class TypeAliasTemplateDecl : public RedeclarableTemplateDecl {
|
||||
|
||||
/// \brief Declaration of a function specialization at template class scope.
|
||||
///
|
||||
/// This is a non standard extension needed to support MSVC.
|
||||
/// This is a non-standard extension needed to support MSVC.
|
||||
///
|
||||
/// For example:
|
||||
/// \code
|
||||
@ -2214,9 +2212,8 @@ class ClassScopeFunctionSpecializationDecl : public Decl {
|
||||
CXXMethodDecl *FD,
|
||||
bool HasExplicitTemplateArgs,
|
||||
TemplateArgumentListInfo TemplateArgs) {
|
||||
return new (C) ClassScopeFunctionSpecializationDecl(DC , Loc, FD,
|
||||
HasExplicitTemplateArgs,
|
||||
TemplateArgs);
|
||||
return new (C, DC) ClassScopeFunctionSpecializationDecl(
|
||||
DC, Loc, FD, HasExplicitTemplateArgs, TemplateArgs);
|
||||
}
|
||||
|
||||
static ClassScopeFunctionSpecializationDecl *
|
||||
@ -2279,7 +2276,7 @@ class VarTemplateSpecializationDecl : public VarDecl,
|
||||
SourceLocation TemplateKeywordLoc;
|
||||
|
||||
ExplicitSpecializationInfo()
|
||||
: TypeAsWritten(0), ExternLoc(), TemplateKeywordLoc() {}
|
||||
: TypeAsWritten(nullptr), ExternLoc(), TemplateKeywordLoc() {}
|
||||
};
|
||||
|
||||
/// \brief Further info for explicit template specialization/instantiation.
|
||||
@ -2298,14 +2295,14 @@ class VarTemplateSpecializationDecl : public VarDecl,
|
||||
unsigned SpecializationKind : 3;
|
||||
|
||||
protected:
|
||||
VarTemplateSpecializationDecl(ASTContext &Context, Kind DK, DeclContext *DC,
|
||||
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);
|
||||
explicit VarTemplateSpecializationDecl(Kind DK, ASTContext &Context);
|
||||
|
||||
public:
|
||||
static VarTemplateSpecializationDecl *
|
||||
@ -2316,9 +2313,8 @@ class VarTemplateSpecializationDecl : public VarDecl,
|
||||
static VarTemplateSpecializationDecl *CreateDeserialized(ASTContext &C,
|
||||
unsigned ID);
|
||||
|
||||
virtual void getNameForDiagnostic(raw_ostream &OS,
|
||||
const PrintingPolicy &Policy,
|
||||
bool Qualified) const;
|
||||
void getNameForDiagnostic(raw_ostream &OS, const PrintingPolicy &Policy,
|
||||
bool Qualified) const override;
|
||||
|
||||
VarTemplateSpecializationDecl *getMostRecentDecl() {
|
||||
VarDecl *Recent = static_cast<VarDecl *>(this)->getMostRecentDecl();
|
||||
@ -2461,7 +2457,7 @@ class VarTemplateSpecializationDecl : public VarDecl,
|
||||
/// \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 : 0;
|
||||
return ExplicitInfo ? ExplicitInfo->TypeAsWritten : nullptr;
|
||||
}
|
||||
|
||||
/// \brief Gets the location of the extern keyword, if present.
|
||||
@ -2487,14 +2483,14 @@ class VarTemplateSpecializationDecl : public VarDecl,
|
||||
}
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) const {
|
||||
Profile(ID, TemplateArgs->data(), TemplateArgs->size(), getASTContext());
|
||||
Profile(ID, TemplateArgs->asArray(), getASTContext());
|
||||
}
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID,
|
||||
const TemplateArgument *TemplateArgs,
|
||||
unsigned NumTemplateArgs, ASTContext &Context) {
|
||||
ID.AddInteger(NumTemplateArgs);
|
||||
for (unsigned Arg = 0; Arg != NumTemplateArgs; ++Arg)
|
||||
ArrayRef<TemplateArgument> TemplateArgs,
|
||||
ASTContext &Context) {
|
||||
ID.AddInteger(TemplateArgs.size());
|
||||
for (unsigned Arg = 0; Arg != TemplateArgs.size(); ++Arg)
|
||||
TemplateArgs[Arg].Profile(ID, Context);
|
||||
}
|
||||
|
||||
@ -2510,7 +2506,7 @@ class VarTemplateSpecializationDecl : public VarDecl,
|
||||
|
||||
class VarTemplatePartialSpecializationDecl
|
||||
: public VarTemplateSpecializationDecl {
|
||||
virtual void anchor();
|
||||
void anchor() override;
|
||||
|
||||
/// \brief The list of template parameters
|
||||
TemplateParameterList *TemplateParams;
|
||||
@ -2534,9 +2530,10 @@ class VarTemplatePartialSpecializationDecl
|
||||
StorageClass S, const TemplateArgument *Args, unsigned NumArgs,
|
||||
const ASTTemplateArgumentListInfo *ArgInfos);
|
||||
|
||||
VarTemplatePartialSpecializationDecl()
|
||||
: VarTemplateSpecializationDecl(VarTemplatePartialSpecialization),
|
||||
TemplateParams(0), ArgsAsWritten(0), InstantiatedFromMember(0, false) {}
|
||||
VarTemplatePartialSpecializationDecl(ASTContext &Context)
|
||||
: VarTemplateSpecializationDecl(VarTemplatePartialSpecialization, Context),
|
||||
TemplateParams(nullptr), ArgsAsWritten(nullptr),
|
||||
InstantiatedFromMember(nullptr, false) {}
|
||||
|
||||
public:
|
||||
static VarTemplatePartialSpecializationDecl *
|
||||
@ -2677,15 +2674,12 @@ class VarTemplateDecl : public RedeclarableTemplateDecl {
|
||||
llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> &
|
||||
getPartialSpecializations();
|
||||
|
||||
VarTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
|
||||
TemplateParameterList *Params, NamedDecl *Decl)
|
||||
: RedeclarableTemplateDecl(VarTemplate, DC, L, Name, Params, Decl) {}
|
||||
VarTemplateDecl(ASTContext &C, DeclContext *DC, SourceLocation L,
|
||||
DeclarationName Name, TemplateParameterList *Params,
|
||||
NamedDecl *Decl)
|
||||
: RedeclarableTemplateDecl(VarTemplate, C, DC, L, Name, Params, Decl) {}
|
||||
|
||||
VarTemplateDecl(EmptyShell Empty)
|
||||
: RedeclarableTemplateDecl(VarTemplate, 0, SourceLocation(),
|
||||
DeclarationName(), 0, 0) {}
|
||||
|
||||
CommonBase *newCommon(ASTContext &C) const;
|
||||
CommonBase *newCommon(ASTContext &C) const override;
|
||||
|
||||
Common *getCommonPtr() const {
|
||||
return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr());
|
||||
@ -2708,8 +2702,8 @@ class VarTemplateDecl : public RedeclarableTemplateDecl {
|
||||
/// \brief Create a variable template node.
|
||||
static VarTemplateDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L, DeclarationName Name,
|
||||
TemplateParameterList *Params, NamedDecl *Decl,
|
||||
VarTemplateDecl *PrevDecl);
|
||||
TemplateParameterList *Params,
|
||||
VarDecl *Decl);
|
||||
|
||||
/// \brief Create an empty variable template node.
|
||||
static VarTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID);
|
||||
@ -2717,14 +2711,13 @@ class VarTemplateDecl : public RedeclarableTemplateDecl {
|
||||
/// \brief Return the specialization with the provided arguments if it exists,
|
||||
/// otherwise return the insertion point.
|
||||
VarTemplateSpecializationDecl *
|
||||
findSpecialization(const TemplateArgument *Args, unsigned NumArgs,
|
||||
void *&InsertPos);
|
||||
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() {
|
||||
VarTemplateDecl *getCanonicalDecl() override {
|
||||
return cast<VarTemplateDecl>(RedeclarableTemplateDecl::getCanonicalDecl());
|
||||
}
|
||||
const VarTemplateDecl *getCanonicalDecl() const {
|
||||
@ -2754,8 +2747,7 @@ class VarTemplateDecl : public RedeclarableTemplateDecl {
|
||||
/// \brief Return the partial specialization with the provided arguments if it
|
||||
/// exists, otherwise return the insertion point.
|
||||
VarTemplatePartialSpecializationDecl *
|
||||
findPartialSpecialization(const TemplateArgument *Args, unsigned NumArgs,
|
||||
void *&InsertPos);
|
||||
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.
|
||||
@ -2780,6 +2772,11 @@ class VarTemplateDecl : public RedeclarableTemplateDecl {
|
||||
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);
|
||||
@ -2789,17 +2786,6 @@ class VarTemplateDecl : public RedeclarableTemplateDecl {
|
||||
return makeSpecIterator(getSpecializations(), true);
|
||||
}
|
||||
|
||||
typedef SpecIterator<VarTemplatePartialSpecializationDecl>
|
||||
partial_spec_iterator;
|
||||
|
||||
partial_spec_iterator partial_spec_begin() {
|
||||
return makeSpecIterator(getPartialSpecializations(), false);
|
||||
}
|
||||
|
||||
partial_spec_iterator partial_spec_end() {
|
||||
return makeSpecIterator(getPartialSpecializations(), true);
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast support
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classofKind(Kind K) { return K == VarTemplate; }
|
||||
|
@ -29,6 +29,7 @@ namespace clang {
|
||||
class DeclarationNameExtra;
|
||||
class IdentifierInfo;
|
||||
class MultiKeywordSelector;
|
||||
enum OverloadedOperatorKind : int;
|
||||
class QualType;
|
||||
class Type;
|
||||
class TypeSourceInfo;
|
||||
@ -116,20 +117,20 @@ class DeclarationName {
|
||||
NameKind Kind = getNameKind();
|
||||
if (Kind >= CXXConstructorName && Kind <= CXXConversionFunctionName)
|
||||
return reinterpret_cast<CXXSpecialName *>(Ptr & ~PtrMask);
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// getAsCXXOperatorIdName
|
||||
CXXOperatorIdName *getAsCXXOperatorIdName() const {
|
||||
if (getNameKind() == CXXOperatorName)
|
||||
return reinterpret_cast<CXXOperatorIdName *>(Ptr & ~PtrMask);
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CXXLiteralOperatorIdName *getAsCXXLiteralOperatorIdName() const {
|
||||
if (getNameKind() == CXXLiteralOperatorName)
|
||||
return reinterpret_cast<CXXLiteralOperatorIdName *>(Ptr & ~PtrMask);
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Construct a declaration name from the name of a C++ constructor,
|
||||
@ -221,7 +222,7 @@ class DeclarationName {
|
||||
IdentifierInfo *getAsIdentifierInfo() const {
|
||||
if (isIdentifier())
|
||||
return reinterpret_cast<IdentifierInfo *>(Ptr);
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// getAsOpaqueInteger - Get the representation of this declaration
|
||||
|
@ -123,7 +123,7 @@ class DependentDiagnostic {
|
||||
/// An iterator over the dependent diagnostics in a dependent context.
|
||||
class DeclContext::ddiag_iterator {
|
||||
public:
|
||||
ddiag_iterator() : Ptr(0) {}
|
||||
ddiag_iterator() : Ptr(nullptr) {}
|
||||
explicit ddiag_iterator(DependentDiagnostic *Ptr) : Ptr(Ptr) {}
|
||||
|
||||
typedef DependentDiagnostic *value_type;
|
||||
@ -171,18 +171,16 @@ class DeclContext::ddiag_iterator {
|
||||
DependentDiagnostic *Ptr;
|
||||
};
|
||||
|
||||
inline DeclContext::ddiag_iterator DeclContext::ddiag_begin() const {
|
||||
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 ddiag_iterator();
|
||||
return ddiag_iterator(Map->FirstDiagnostic);
|
||||
}
|
||||
if (!Map)
|
||||
return ddiag_range();
|
||||
|
||||
inline DeclContext::ddiag_iterator DeclContext::ddiag_end() const {
|
||||
return ddiag_iterator();
|
||||
return ddiag_range(ddiag_iterator(Map->FirstDiagnostic), ddiag_iterator());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -293,8 +293,8 @@ class Expr : public Stmt {
|
||||
/// \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 = 0) const;
|
||||
isModifiableLvalueResult
|
||||
isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc = nullptr) const;
|
||||
|
||||
/// \brief The return type of classify(). Represents the C++11 expression
|
||||
/// taxonomy.
|
||||
@ -372,7 +372,7 @@ class Expr : public Stmt {
|
||||
/// lvalues and xvalues are collectively referred to as glvalues, while
|
||||
/// prvalues and xvalues together form rvalues.
|
||||
Classification Classify(ASTContext &Ctx) const {
|
||||
return ClassifyImpl(Ctx, 0);
|
||||
return ClassifyImpl(Ctx, nullptr);
|
||||
}
|
||||
|
||||
/// \brief ClassifyModifiable - Classify this expression according to the
|
||||
@ -483,10 +483,10 @@ class Expr : public Stmt {
|
||||
/// 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 = 0,
|
||||
SourceLocation *Loc = nullptr,
|
||||
bool isEvaluated = true) const;
|
||||
bool isIntegerConstantExpr(const ASTContext &Ctx,
|
||||
SourceLocation *Loc = 0) const;
|
||||
SourceLocation *Loc = nullptr) const;
|
||||
|
||||
/// isCXX98IntegralConstantExpr - Return true if this expression is an
|
||||
/// integral constant expression in C++98. Can only be used in C++.
|
||||
@ -497,8 +497,8 @@ class Expr : public Stmt {
|
||||
///
|
||||
/// Note: This does not perform the implicit conversions required by C++11
|
||||
/// [expr.const]p5.
|
||||
bool isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result = 0,
|
||||
SourceLocation *Loc = 0) const;
|
||||
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
|
||||
@ -508,9 +508,22 @@ class Expr : public Stmt {
|
||||
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.
|
||||
bool isConstantInitializer(ASTContext &Ctx, bool ForRef) const;
|
||||
/// 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 {
|
||||
@ -527,7 +540,7 @@ class Expr : public Stmt {
|
||||
/// expression *is* a constant expression, no notes will be produced.
|
||||
SmallVectorImpl<PartialDiagnosticAt> *Diag;
|
||||
|
||||
EvalStatus() : HasSideEffects(false), Diag(0) {}
|
||||
EvalStatus() : HasSideEffects(false), Diag(nullptr) {}
|
||||
|
||||
// hasSideEffects - Return true if the evaluated expression has
|
||||
// side effects.
|
||||
@ -584,7 +597,7 @@ class Expr : public Stmt {
|
||||
/// integer. This must be called on an expression that constant folds to an
|
||||
/// integer.
|
||||
llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx,
|
||||
SmallVectorImpl<PartialDiagnosticAt> *Diag=0) const;
|
||||
SmallVectorImpl<PartialDiagnosticAt> *Diag = nullptr) const;
|
||||
|
||||
void EvaluateForOverflow(const ASTContext &Ctx) const;
|
||||
|
||||
@ -600,6 +613,14 @@ class Expr : public Stmt {
|
||||
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 Enumeration used to describe the kind of Null pointer constant
|
||||
/// returned from \c isNullPointerConstant().
|
||||
enum NullPointerConstantKind {
|
||||
@ -681,6 +702,9 @@ class Expr : public Stmt {
|
||||
/// 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;
|
||||
@ -742,6 +766,11 @@ class Expr : public Stmt {
|
||||
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);
|
||||
}
|
||||
@ -764,11 +793,6 @@ class Expr : public Stmt {
|
||||
SmallVectorImpl<const Expr *> &CommaLHS,
|
||||
SmallVectorImpl<SubobjectAdjustment> &Adjustments) const;
|
||||
|
||||
/// Skip irrelevant expressions to find what should be materialize for
|
||||
/// binding with a reference.
|
||||
const Expr *
|
||||
findMaterializedTemporary(const MaterializeTemporaryExpr *&MTE) const;
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() >= firstExprConstant &&
|
||||
T->getStmtClass() <= lastExprConstant;
|
||||
@ -793,7 +817,7 @@ class OpaqueValueExpr : public Expr {
|
||||
public:
|
||||
OpaqueValueExpr(SourceLocation Loc, QualType T, ExprValueKind VK,
|
||||
ExprObjectKind OK = OK_Ordinary,
|
||||
Expr *SourceExpr = 0)
|
||||
Expr *SourceExpr = nullptr)
|
||||
: Expr(OpaqueValueExprClass, T, VK, OK,
|
||||
T->isDependentType(),
|
||||
T->isDependentType() ||
|
||||
@ -937,25 +961,19 @@ class DeclRefExpr : public Expr {
|
||||
computeDependence(D->getASTContext());
|
||||
}
|
||||
|
||||
static DeclRefExpr *Create(const ASTContext &Context,
|
||||
NestedNameSpecifierLoc QualifierLoc,
|
||||
SourceLocation TemplateKWLoc,
|
||||
ValueDecl *D,
|
||||
bool isEnclosingLocal,
|
||||
SourceLocation NameLoc,
|
||||
QualType T, ExprValueKind VK,
|
||||
NamedDecl *FoundD = 0,
|
||||
const TemplateArgumentListInfo *TemplateArgs = 0);
|
||||
static DeclRefExpr *
|
||||
Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc,
|
||||
SourceLocation TemplateKWLoc, ValueDecl *D, bool isEnclosingLocal,
|
||||
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 isEnclosingLocal,
|
||||
const DeclarationNameInfo &NameInfo,
|
||||
QualType T, ExprValueKind VK,
|
||||
NamedDecl *FoundD = 0,
|
||||
const TemplateArgumentListInfo *TemplateArgs = 0);
|
||||
static DeclRefExpr *
|
||||
Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc,
|
||||
SourceLocation TemplateKWLoc, ValueDecl *D, bool isEnclosingLocal,
|
||||
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,
|
||||
@ -985,7 +1003,7 @@ class DeclRefExpr : public Expr {
|
||||
/// that precedes the name. Otherwise, returns NULL.
|
||||
NestedNameSpecifier *getQualifier() const {
|
||||
if (!hasQualifier())
|
||||
return 0;
|
||||
return nullptr;
|
||||
|
||||
return getInternalQualifierLoc().getNestedNameSpecifier();
|
||||
}
|
||||
@ -1021,7 +1039,7 @@ class DeclRefExpr : public Expr {
|
||||
/// \brief Return the optional template keyword and arguments info.
|
||||
ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo() {
|
||||
if (!hasTemplateKWAndArgsInfo())
|
||||
return 0;
|
||||
return nullptr;
|
||||
|
||||
if (hasFoundDecl())
|
||||
return reinterpret_cast<ASTTemplateKWAndArgsInfo *>(
|
||||
@ -1085,7 +1103,7 @@ class DeclRefExpr : public Expr {
|
||||
/// This points to the same data as getExplicitTemplateArgs(), but
|
||||
/// returns null if there are no explicit template arguments.
|
||||
const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() const {
|
||||
if (!hasExplicitTemplateArgs()) return 0;
|
||||
if (!hasExplicitTemplateArgs()) return nullptr;
|
||||
return &getExplicitTemplateArgs();
|
||||
}
|
||||
|
||||
@ -1100,7 +1118,7 @@ class DeclRefExpr : public Expr {
|
||||
/// template-id.
|
||||
const TemplateArgumentLoc *getTemplateArgs() const {
|
||||
if (!hasExplicitTemplateArgs())
|
||||
return 0;
|
||||
return nullptr;
|
||||
|
||||
return getExplicitTemplateArgs().getTemplateArgs();
|
||||
}
|
||||
@ -1151,6 +1169,7 @@ class PredefinedExpr : public Expr {
|
||||
Function,
|
||||
LFunction, // Same as Function, but as wide string.
|
||||
FuncDName,
|
||||
FuncSig,
|
||||
PrettyFunction,
|
||||
/// PrettyFunctionNoVirtual - The same as PrettyFunction, except that the
|
||||
/// 'virtual' keyword is omitted for virtual member functions.
|
||||
@ -1862,7 +1881,7 @@ class OffsetOfExpr : public Expr {
|
||||
|
||||
explicit OffsetOfExpr(unsigned numComps, unsigned numExprs)
|
||||
: Expr(OffsetOfExprClass, EmptyShell()),
|
||||
TSInfo(0), NumComps(numComps), NumExprs(numExprs) {}
|
||||
TSInfo(nullptr), NumComps(numComps), NumExprs(numExprs) {}
|
||||
|
||||
public:
|
||||
|
||||
@ -2213,6 +2232,13 @@ class CallExpr : public Expr {
|
||||
|
||||
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() {
|
||||
@ -2238,9 +2264,9 @@ class CallExpr : public Expr {
|
||||
/// this function call.
|
||||
unsigned getNumCommas() const { return NumArgs ? NumArgs - 1 : 0; }
|
||||
|
||||
/// isBuiltinCall - If this is a call to a builtin, return the builtin ID. If
|
||||
/// not, return 0.
|
||||
unsigned isBuiltinCall() const;
|
||||
/// 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.
|
||||
@ -2392,14 +2418,14 @@ class MemberExpr : public Expr {
|
||||
/// \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() != 0; }
|
||||
bool hasQualifier() const { return getQualifier() != nullptr; }
|
||||
|
||||
/// \brief If the member name was qualified, retrieves the
|
||||
/// nested-name-specifier that precedes the member name. Otherwise, returns
|
||||
/// NULL.
|
||||
NestedNameSpecifier *getQualifier() const {
|
||||
if (!HasQualifierOrFoundDecl)
|
||||
return 0;
|
||||
return nullptr;
|
||||
|
||||
return getMemberQualifier()->QualifierLoc.getNestedNameSpecifier();
|
||||
}
|
||||
@ -2417,7 +2443,7 @@ class MemberExpr : public Expr {
|
||||
/// \brief Return the optional template keyword and arguments info.
|
||||
ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo() {
|
||||
if (!HasTemplateKWAndArgsInfo)
|
||||
return 0;
|
||||
return nullptr;
|
||||
|
||||
if (!HasQualifierOrFoundDecl)
|
||||
return reinterpret_cast<ASTTemplateKWAndArgsInfo *>(this + 1);
|
||||
@ -2485,7 +2511,7 @@ class MemberExpr : public Expr {
|
||||
/// This points to the same data as getExplicitTemplateArgs(), but
|
||||
/// returns null if there are no explicit template arguments.
|
||||
const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() const {
|
||||
if (!hasExplicitTemplateArgs()) return 0;
|
||||
if (!hasExplicitTemplateArgs()) return nullptr;
|
||||
return &getExplicitTemplateArgs();
|
||||
}
|
||||
|
||||
@ -2493,7 +2519,7 @@ class MemberExpr : public Expr {
|
||||
/// template-id.
|
||||
const TemplateArgumentLoc *getTemplateArgs() const {
|
||||
if (!hasExplicitTemplateArgs())
|
||||
return 0;
|
||||
return nullptr;
|
||||
|
||||
return getExplicitTemplateArgs().getTemplateArgs();
|
||||
}
|
||||
@ -2633,7 +2659,7 @@ class CastExpr : public Expr {
|
||||
private:
|
||||
Stmt *Op;
|
||||
|
||||
void CheckCastConsistency() const;
|
||||
bool CastConsistency() const;
|
||||
|
||||
const CXXBaseSpecifier * const *path_buffer() const {
|
||||
return const_cast<CastExpr*>(this)->path_buffer();
|
||||
@ -2664,9 +2690,7 @@ class CastExpr : public Expr {
|
||||
assert(kind != CK_Invalid && "creating cast with invalid cast kind");
|
||||
CastExprBits.Kind = kind;
|
||||
setBasePathSize(BasePathSize);
|
||||
#ifndef NDEBUG
|
||||
CheckCastConsistency();
|
||||
#endif
|
||||
assert(CastConsistency());
|
||||
}
|
||||
|
||||
/// \brief Construct an empty cast.
|
||||
@ -3422,7 +3446,7 @@ class ShuffleVectorExpr : public Expr {
|
||||
|
||||
/// \brief Build an empty vector-shuffle expression.
|
||||
explicit ShuffleVectorExpr(EmptyShell Empty)
|
||||
: Expr(ShuffleVectorExprClass, Empty), SubExprs(0) { }
|
||||
: Expr(ShuffleVectorExprClass, Empty), SubExprs(nullptr) { }
|
||||
|
||||
SourceLocation getBuiltinLoc() const { return BuiltinLoc; }
|
||||
void setBuiltinLoc(SourceLocation L) { BuiltinLoc = L; }
|
||||
@ -3774,6 +3798,14 @@ class InitListExpr : public Expr {
|
||||
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.
|
||||
@ -3824,8 +3856,8 @@ class InitListExpr : public Expr {
|
||||
return const_cast<InitListExpr *>(this)->getInitializedFieldInUnion();
|
||||
}
|
||||
void setInitializedFieldInUnion(FieldDecl *FD) {
|
||||
assert((FD == 0
|
||||
|| getInitializedFieldInUnion() == 0
|
||||
assert((FD == nullptr
|
||||
|| getInitializedFieldInUnion() == nullptr
|
||||
|| getInitializedFieldInUnion() == FD)
|
||||
&& "Only one field of a union may be initialized at a time!");
|
||||
ArrayFillerOrUnionFieldInit = FD;
|
||||
@ -3848,10 +3880,10 @@ class InitListExpr : public Expr {
|
||||
|
||||
bool isSemanticForm() const { return AltForm.getInt(); }
|
||||
InitListExpr *getSemanticForm() const {
|
||||
return isSemanticForm() ? 0 : AltForm.getPointer();
|
||||
return isSemanticForm() ? nullptr : AltForm.getPointer();
|
||||
}
|
||||
InitListExpr *getSyntacticForm() const {
|
||||
return isSemanticForm() ? AltForm.getPointer() : 0;
|
||||
return isSemanticForm() ? AltForm.getPointer() : nullptr;
|
||||
}
|
||||
|
||||
void setSyntacticForm(InitListExpr *Init) {
|
||||
@ -3877,6 +3909,7 @@ class InitListExpr : public Expr {
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
// FIXME: This does not include the array filler expression.
|
||||
if (InitExprs.empty()) return child_range();
|
||||
return child_range(&InitExprs[0], &InitExprs[0] + InitExprs.size());
|
||||
}
|
||||
@ -3953,7 +3986,7 @@ class DesignatedInitExpr : public Expr {
|
||||
|
||||
explicit DesignatedInitExpr(unsigned NumSubExprs)
|
||||
: Expr(DesignatedInitExprClass, EmptyShell()),
|
||||
NumDesignators(0), NumSubExprs(NumSubExprs), Designators(0) { }
|
||||
NumDesignators(0), NumSubExprs(NumSubExprs), Designators(nullptr) { }
|
||||
|
||||
public:
|
||||
/// A field designator, e.g., ".x".
|
||||
@ -4050,7 +4083,7 @@ class DesignatedInitExpr : public Expr {
|
||||
FieldDecl *getField() const {
|
||||
assert(Kind == FieldDesignator && "Only valid on a field designator");
|
||||
if (Field.NameOrField & 0x01)
|
||||
return 0;
|
||||
return nullptr;
|
||||
else
|
||||
return reinterpret_cast<FieldDecl *>(Field.NameOrField);
|
||||
}
|
||||
@ -4134,6 +4167,17 @@ class DesignatedInitExpr : public Expr {
|
||||
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() {
|
||||
@ -4186,18 +4230,14 @@ class DesignatedInitExpr : public Expr {
|
||||
/// and array-range designators.
|
||||
unsigned getNumSubExprs() const { return NumSubExprs; }
|
||||
|
||||
Expr *getSubExpr(unsigned Idx) {
|
||||
Expr *getSubExpr(unsigned Idx) const {
|
||||
assert(Idx < NumSubExprs && "Subscript out of range");
|
||||
char* Ptr = static_cast<char*>(static_cast<void *>(this));
|
||||
Ptr += sizeof(DesignatedInitExpr);
|
||||
return reinterpret_cast<Expr**>(reinterpret_cast<void**>(Ptr))[Idx];
|
||||
return cast<Expr>(reinterpret_cast<Stmt *const *>(this + 1)[Idx]);
|
||||
}
|
||||
|
||||
void setSubExpr(unsigned Idx, Expr *E) {
|
||||
assert(Idx < NumSubExprs && "Subscript out of range");
|
||||
char* Ptr = static_cast<char*>(static_cast<void *>(this));
|
||||
Ptr += sizeof(DesignatedInitExpr);
|
||||
reinterpret_cast<Expr**>(reinterpret_cast<void**>(Ptr))[Idx] = E;
|
||||
reinterpret_cast<Stmt **>(this + 1)[Idx] = E;
|
||||
}
|
||||
|
||||
/// \brief Replaces the designator at index @p Idx with the series
|
||||
@ -4621,7 +4661,7 @@ class PseudoObjectExpr : public Expr {
|
||||
public:
|
||||
/// NoResult - A value for the result index indicating that there is
|
||||
/// no semantic result.
|
||||
enum LLVM_ENUM_INT_TYPE(unsigned) { NoResult = ~0U };
|
||||
enum : unsigned { NoResult = ~0U };
|
||||
|
||||
static PseudoObjectExpr *Create(const ASTContext &Context, Expr *syntactic,
|
||||
ArrayRef<Expr*> semantic,
|
||||
@ -4646,7 +4686,7 @@ class PseudoObjectExpr : public Expr {
|
||||
/// Return the result-bearing expression, or null if there is none.
|
||||
Expr *getResultExpr() {
|
||||
if (PseudoObjectExprBits.ResultIndex == 0)
|
||||
return 0;
|
||||
return nullptr;
|
||||
return getSubExprsBuffer()[PseudoObjectExprBits.ResultIndex];
|
||||
}
|
||||
const Expr *getResultExpr() const {
|
||||
@ -4713,6 +4753,16 @@ class AtomicExpr : public Expr {
|
||||
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];
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include "clang/AST/TemplateBase.h"
|
||||
#include "clang/AST/UnresolvedSet.h"
|
||||
#include "clang/Basic/ExpressionTraits.h"
|
||||
#include "clang/Basic/Lambda.h"
|
||||
#include "clang/AST/LambdaCapture.h"
|
||||
#include "clang/Basic/TypeTraits.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
@ -486,7 +486,7 @@ class CXXStdInitializerListExpr : public Expr {
|
||||
Stmt *SubExpr;
|
||||
|
||||
CXXStdInitializerListExpr(EmptyShell Empty)
|
||||
: Expr(CXXStdInitializerListExprClass, Empty), SubExpr(0) {}
|
||||
: Expr(CXXStdInitializerListExprClass, Empty), SubExpr(nullptr) {}
|
||||
|
||||
public:
|
||||
CXXStdInitializerListExpr(QualType Ty, Expr *SubExpr)
|
||||
@ -553,9 +553,9 @@ class CXXTypeidExpr : public Expr {
|
||||
CXXTypeidExpr(EmptyShell Empty, bool isExpr)
|
||||
: Expr(CXXTypeidExprClass, Empty) {
|
||||
if (isExpr)
|
||||
Operand = (Expr*)0;
|
||||
Operand = (Expr*)nullptr;
|
||||
else
|
||||
Operand = (TypeSourceInfo*)0;
|
||||
Operand = (TypeSourceInfo*)nullptr;
|
||||
}
|
||||
|
||||
/// Determine whether this typeid has a type operand which is potentially
|
||||
@ -692,9 +692,9 @@ class CXXUuidofExpr : public Expr {
|
||||
CXXUuidofExpr(EmptyShell Empty, bool isExpr)
|
||||
: Expr(CXXUuidofExprClass, Empty) {
|
||||
if (isExpr)
|
||||
Operand = (Expr*)0;
|
||||
Operand = (Expr*)nullptr;
|
||||
else
|
||||
Operand = (TypeSourceInfo*)0;
|
||||
Operand = (TypeSourceInfo*)nullptr;
|
||||
}
|
||||
|
||||
bool isTypeOperand() const { return Operand.is<TypeSourceInfo *>(); }
|
||||
@ -737,8 +737,8 @@ class CXXUuidofExpr : public Expr {
|
||||
|
||||
/// Grabs __declspec(uuid()) off a type, or returns 0 if we cannot resolve to
|
||||
/// a single GUID.
|
||||
static UuidAttr *GetUuidAttrOfType(QualType QT,
|
||||
bool *HasMultipleGUIDsPtr = 0);
|
||||
static const UuidAttr *GetUuidAttrOfType(QualType QT,
|
||||
bool *HasMultipleGUIDsPtr = nullptr);
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
@ -832,7 +832,7 @@ class CXXThrowExpr : public Expr {
|
||||
|
||||
SourceLocation getLocStart() const LLVM_READONLY { return ThrowLoc; }
|
||||
SourceLocation getLocEnd() const LLVM_READONLY {
|
||||
if (getSubExpr() == 0)
|
||||
if (!getSubExpr())
|
||||
return ThrowLoc;
|
||||
return getSubExpr()->getLocEnd();
|
||||
}
|
||||
@ -1031,7 +1031,7 @@ class CXXBindTemporaryExpr : public Expr {
|
||||
|
||||
public:
|
||||
CXXBindTemporaryExpr(EmptyShell Empty)
|
||||
: Expr(CXXBindTemporaryExprClass, Empty), Temp(0), SubExpr(0) {}
|
||||
: Expr(CXXBindTemporaryExprClass, Empty), Temp(nullptr), SubExpr(nullptr) {}
|
||||
|
||||
static CXXBindTemporaryExpr *Create(const ASTContext &C, CXXTemporary *Temp,
|
||||
Expr* SubExpr);
|
||||
@ -1077,6 +1077,7 @@ class CXXConstructExpr : public Expr {
|
||||
bool Elidable : 1;
|
||||
bool HadMultipleCandidates : 1;
|
||||
bool ListInitialization : 1;
|
||||
bool StdInitListInitialization : 1;
|
||||
bool ZeroInitialization : 1;
|
||||
unsigned ConstructKind : 2;
|
||||
Stmt **Args;
|
||||
@ -1088,24 +1089,25 @@ class CXXConstructExpr : public Expr {
|
||||
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(0), NumArgs(0), Elidable(false),
|
||||
: Expr(SC, Empty), Constructor(nullptr), NumArgs(0), Elidable(false),
|
||||
HadMultipleCandidates(false), ListInitialization(false),
|
||||
ZeroInitialization(false), ConstructKind(0), Args(0)
|
||||
ZeroInitialization(false), ConstructKind(0), Args(nullptr)
|
||||
{ }
|
||||
|
||||
public:
|
||||
/// \brief Construct an empty C++ construction expression.
|
||||
explicit CXXConstructExpr(EmptyShell Empty)
|
||||
: Expr(CXXConstructExprClass, Empty), Constructor(0),
|
||||
: Expr(CXXConstructExprClass, Empty), Constructor(nullptr),
|
||||
NumArgs(0), Elidable(false), HadMultipleCandidates(false),
|
||||
ListInitialization(false), ZeroInitialization(false),
|
||||
ConstructKind(0), Args(0)
|
||||
ConstructKind(0), Args(nullptr)
|
||||
{ }
|
||||
|
||||
static CXXConstructExpr *Create(const ASTContext &C, QualType T,
|
||||
@ -1114,6 +1116,7 @@ class CXXConstructExpr : public Expr {
|
||||
ArrayRef<Expr *> Args,
|
||||
bool HadMultipleCandidates,
|
||||
bool ListInitialization,
|
||||
bool StdInitListInitialization,
|
||||
bool ZeroInitialization,
|
||||
ConstructionKind ConstructKind,
|
||||
SourceRange ParenOrBraceRange);
|
||||
@ -1137,6 +1140,13 @@ class CXXConstructExpr : public Expr {
|
||||
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; }
|
||||
@ -1161,7 +1171,10 @@ class CXXConstructExpr : public Expr {
|
||||
const_arg_iterator arg_begin() const { return Args; }
|
||||
const_arg_iterator arg_end() const { return Args + NumArgs; }
|
||||
|
||||
Expr **getArgs() const { return reinterpret_cast<Expr **>(Args); }
|
||||
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.
|
||||
@ -1269,6 +1282,7 @@ class CXXTemporaryObjectExpr : public CXXConstructExpr {
|
||||
SourceRange ParenOrBraceRange,
|
||||
bool HadMultipleCandidates,
|
||||
bool ListInitialization,
|
||||
bool StdInitListInitialization,
|
||||
bool ZeroInitialization);
|
||||
explicit CXXTemporaryObjectExpr(EmptyShell Empty)
|
||||
: CXXConstructExpr(CXXTemporaryObjectExprClass, Empty), Type() { }
|
||||
@ -1307,18 +1321,6 @@ class CXXTemporaryObjectExpr : public CXXConstructExpr {
|
||||
/// includes an initializing expression (rather than capturing a variable),
|
||||
/// and which can never occur implicitly.
|
||||
class LambdaExpr : public Expr {
|
||||
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
|
||||
};
|
||||
|
||||
/// \brief The source range that covers the lambda introducer ([...]).
|
||||
SourceRange IntroducerRange;
|
||||
|
||||
@ -1357,93 +1359,8 @@ class LambdaExpr : public Expr {
|
||||
// expression, along with the index variables used to initialize by-copy
|
||||
// array captures.
|
||||
|
||||
public:
|
||||
/// \brief Describes the capture of a variable or of \c this, or of a
|
||||
/// C++1y init-capture.
|
||||
class Capture {
|
||||
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.
|
||||
Capture(SourceLocation Loc, bool Implicit,
|
||||
LambdaCaptureKind Kind, VarDecl *Var = 0,
|
||||
SourceLocation EllipsisLoc = SourceLocation());
|
||||
typedef LambdaCapture Capture;
|
||||
|
||||
/// \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() == 0; }
|
||||
|
||||
/// \brief Determine whether this capture handles a variable.
|
||||
bool capturesVariable() const {
|
||||
return dyn_cast_or_null<VarDecl>(DeclAndBits.getPointer());
|
||||
}
|
||||
|
||||
/// \brief Determine whether this is an init-capture.
|
||||
bool isInitCapture() const {
|
||||
return capturesVariable() && getCapturedVar()->isInitCapture();
|
||||
}
|
||||
|
||||
/// \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;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
/// \brief Construct a lambda expression.
|
||||
LambdaExpr(QualType T, SourceRange IntroducerRange,
|
||||
LambdaCaptureDefault CaptureDefault,
|
||||
@ -1462,7 +1379,7 @@ class LambdaExpr : public Expr {
|
||||
: Expr(LambdaExprClass, Empty),
|
||||
NumCaptures(NumCaptures), CaptureDefault(LCD_None), ExplicitParams(false),
|
||||
ExplicitResultType(false), HasArrayIndexVars(true) {
|
||||
getStoredStmts()[NumCaptures] = 0;
|
||||
getStoredStmts()[NumCaptures] = nullptr;
|
||||
}
|
||||
|
||||
Stmt **getStoredStmts() const {
|
||||
@ -1520,6 +1437,12 @@ class LambdaExpr : public Expr {
|
||||
/// both implicit and explicit.
|
||||
typedef const Capture *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;
|
||||
|
||||
@ -1529,6 +1452,9 @@ class LambdaExpr : public Expr {
|
||||
|
||||
/// \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.
|
||||
@ -1538,6 +1464,9 @@ class LambdaExpr : public Expr {
|
||||
/// 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;
|
||||
@ -1550,6 +1479,12 @@ class LambdaExpr : public Expr {
|
||||
/// arguments.
|
||||
typedef Expr **capture_init_iterator;
|
||||
|
||||
/// \brief Retrieve the initialization expressions for this lambda's captures.
|
||||
llvm::iterator_range<capture_init_iterator> capture_inits() const {
|
||||
return llvm::iterator_range<capture_init_iterator>(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() const {
|
||||
@ -1717,7 +1652,7 @@ class CXXNewExpr : public Expr {
|
||||
QualType ty, TypeSourceInfo *AllocatedTypeInfo,
|
||||
SourceRange Range, SourceRange directInitRange);
|
||||
explicit CXXNewExpr(EmptyShell Shell)
|
||||
: Expr(CXXNewExprClass, Shell), SubExprs(0) { }
|
||||
: Expr(CXXNewExprClass, Shell), SubExprs(nullptr) { }
|
||||
|
||||
void AllocateArgsArray(const ASTContext &C, bool isArray,
|
||||
unsigned numPlaceArgs, bool hasInitializer);
|
||||
@ -1751,10 +1686,10 @@ class CXXNewExpr : public Expr {
|
||||
|
||||
bool isArray() const { return Array; }
|
||||
Expr *getArraySize() {
|
||||
return Array ? cast<Expr>(SubExprs[0]) : 0;
|
||||
return Array ? cast<Expr>(SubExprs[0]) : nullptr;
|
||||
}
|
||||
const Expr *getArraySize() const {
|
||||
return Array ? cast<Expr>(SubExprs[0]) : 0;
|
||||
return Array ? cast<Expr>(SubExprs[0]) : nullptr;
|
||||
}
|
||||
|
||||
unsigned getNumPlacementArgs() const { return NumPlacementArgs; }
|
||||
@ -1788,10 +1723,10 @@ class CXXNewExpr : public Expr {
|
||||
|
||||
/// \brief The initializer of this new-expression.
|
||||
Expr *getInitializer() {
|
||||
return hasInitializer() ? cast<Expr>(SubExprs[Array]) : 0;
|
||||
return hasInitializer() ? cast<Expr>(SubExprs[Array]) : nullptr;
|
||||
}
|
||||
const Expr *getInitializer() const {
|
||||
return hasInitializer() ? cast<Expr>(SubExprs[Array]) : 0;
|
||||
return hasInitializer() ? cast<Expr>(SubExprs[Array]) : nullptr;
|
||||
}
|
||||
|
||||
/// \brief Returns the CXXConstructExpr from this new-expression, or null.
|
||||
@ -1885,7 +1820,8 @@ class CXXDeleteExpr : public Expr {
|
||||
ArrayForm(arrayForm), ArrayFormAsWritten(arrayFormAsWritten),
|
||||
UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize) { }
|
||||
explicit CXXDeleteExpr(EmptyShell Shell)
|
||||
: Expr(CXXDeleteExprClass, Shell), OperatorDelete(0), Argument(0) { }
|
||||
: Expr(CXXDeleteExprClass, Shell), OperatorDelete(nullptr),
|
||||
Argument(nullptr) {}
|
||||
|
||||
bool isGlobalDelete() const { return GlobalDelete; }
|
||||
bool isArrayForm() const { return ArrayForm; }
|
||||
@ -2017,7 +1953,7 @@ class CXXPseudoDestructorExpr : public Expr {
|
||||
|
||||
explicit CXXPseudoDestructorExpr(EmptyShell Shell)
|
||||
: Expr(CXXPseudoDestructorExprClass, Shell),
|
||||
Base(0), IsArrow(false), QualifierLoc(), ScopeType(0) { }
|
||||
Base(nullptr), IsArrow(false), QualifierLoc(), ScopeType(nullptr) { }
|
||||
|
||||
Expr *getBase() const { return cast<Expr>(Base); }
|
||||
|
||||
@ -2110,138 +2046,12 @@ class CXXPseudoDestructorExpr : public Expr {
|
||||
child_range children() { return child_range(&Base, &Base + 1); }
|
||||
};
|
||||
|
||||
/// \brief Represents a GCC or MS unary type trait, as used in the
|
||||
/// implementation of TR1/C++11 type trait templates.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// __is_pod(int) == true
|
||||
/// __is_enum(std::string) == false
|
||||
/// \endcode
|
||||
class UnaryTypeTraitExpr : public Expr {
|
||||
/// \brief The trait. A UnaryTypeTrait enum in MSVC compatible unsigned.
|
||||
unsigned UTT : 31;
|
||||
/// 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 type being queried.
|
||||
TypeSourceInfo *QueriedType;
|
||||
|
||||
public:
|
||||
UnaryTypeTraitExpr(SourceLocation loc, UnaryTypeTrait utt,
|
||||
TypeSourceInfo *queried, bool value,
|
||||
SourceLocation rparen, QualType ty)
|
||||
: Expr(UnaryTypeTraitExprClass, ty, VK_RValue, OK_Ordinary,
|
||||
false, queried->getType()->isDependentType(),
|
||||
queried->getType()->isInstantiationDependentType(),
|
||||
queried->getType()->containsUnexpandedParameterPack()),
|
||||
UTT(utt), Value(value), Loc(loc), RParen(rparen), QueriedType(queried) { }
|
||||
|
||||
explicit UnaryTypeTraitExpr(EmptyShell Empty)
|
||||
: Expr(UnaryTypeTraitExprClass, Empty), UTT(0), Value(false),
|
||||
QueriedType() { }
|
||||
|
||||
SourceLocation getLocStart() const LLVM_READONLY { return Loc; }
|
||||
SourceLocation getLocEnd() const LLVM_READONLY { return RParen; }
|
||||
|
||||
UnaryTypeTrait getTrait() const { return static_cast<UnaryTypeTrait>(UTT); }
|
||||
|
||||
QualType getQueriedType() const { return QueriedType->getType(); }
|
||||
|
||||
TypeSourceInfo *getQueriedTypeSourceInfo() const { return QueriedType; }
|
||||
|
||||
bool getValue() const { return Value; }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == UnaryTypeTraitExprClass;
|
||||
}
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
|
||||
friend class ASTStmtReader;
|
||||
};
|
||||
|
||||
/// \brief Represents a GCC or MS binary type trait, as used in the
|
||||
/// implementation of TR1/C++11 type trait templates.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// __is_base_of(Base, Derived) == true
|
||||
/// \endcode
|
||||
class BinaryTypeTraitExpr : public Expr {
|
||||
/// \brief The trait. A BinaryTypeTrait enum in MSVC compatible unsigned.
|
||||
unsigned BTT : 8;
|
||||
|
||||
/// 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 lhs type being queried.
|
||||
TypeSourceInfo *LhsType;
|
||||
|
||||
/// \brief The rhs type being queried.
|
||||
TypeSourceInfo *RhsType;
|
||||
|
||||
public:
|
||||
BinaryTypeTraitExpr(SourceLocation loc, BinaryTypeTrait btt,
|
||||
TypeSourceInfo *lhsType, TypeSourceInfo *rhsType,
|
||||
bool value, SourceLocation rparen, QualType ty)
|
||||
: Expr(BinaryTypeTraitExprClass, ty, VK_RValue, OK_Ordinary, false,
|
||||
lhsType->getType()->isDependentType() ||
|
||||
rhsType->getType()->isDependentType(),
|
||||
(lhsType->getType()->isInstantiationDependentType() ||
|
||||
rhsType->getType()->isInstantiationDependentType()),
|
||||
(lhsType->getType()->containsUnexpandedParameterPack() ||
|
||||
rhsType->getType()->containsUnexpandedParameterPack())),
|
||||
BTT(btt), Value(value), Loc(loc), RParen(rparen),
|
||||
LhsType(lhsType), RhsType(rhsType) { }
|
||||
|
||||
|
||||
explicit BinaryTypeTraitExpr(EmptyShell Empty)
|
||||
: Expr(BinaryTypeTraitExprClass, Empty), BTT(0), Value(false),
|
||||
LhsType(), RhsType() { }
|
||||
|
||||
SourceLocation getLocStart() const LLVM_READONLY { return Loc; }
|
||||
SourceLocation getLocEnd() const LLVM_READONLY { return RParen; }
|
||||
|
||||
BinaryTypeTrait getTrait() const {
|
||||
return static_cast<BinaryTypeTrait>(BTT);
|
||||
}
|
||||
|
||||
QualType getLhsType() const { return LhsType->getType(); }
|
||||
QualType getRhsType() const { return RhsType->getType(); }
|
||||
|
||||
TypeSourceInfo *getLhsTypeSourceInfo() const { return LhsType; }
|
||||
TypeSourceInfo *getRhsTypeSourceInfo() const { return RhsType; }
|
||||
|
||||
bool getValue() const { assert(!isTypeDependent()); return Value; }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == BinaryTypeTraitExprClass;
|
||||
}
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
|
||||
friend class ASTStmtReader;
|
||||
};
|
||||
|
||||
/// \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 : public Expr {
|
||||
@ -2334,7 +2144,7 @@ class TypeTraitExpr : public Expr {
|
||||
friend class ASTStmtWriter;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/// \brief An Embarcadero array type trait, as used in the implementation of
|
||||
/// __array_rank and __array_extent.
|
||||
///
|
||||
@ -2504,7 +2314,7 @@ class OverloadExpr : public Expr {
|
||||
bool KnownContainsUnexpandedParameterPack);
|
||||
|
||||
OverloadExpr(StmtClass K, EmptyShell Empty)
|
||||
: Expr(K, Empty), QualifierLoc(), Results(0), NumResults(0),
|
||||
: Expr(K, Empty), QualifierLoc(), Results(nullptr), NumResults(0),
|
||||
HasTemplateKWAndArgsInfo(false) { }
|
||||
|
||||
void initializeResults(const ASTContext &C,
|
||||
@ -2554,6 +2364,9 @@ class OverloadExpr : public Expr {
|
||||
decls_iterator decls_end() const {
|
||||
return UnresolvedSetIterator(Results + NumResults);
|
||||
}
|
||||
llvm::iterator_range<decls_iterator> decls() const {
|
||||
return llvm::iterator_range<decls_iterator>(decls_begin(), decls_end());
|
||||
}
|
||||
|
||||
/// \brief Gets the number of declarations in the unresolved set.
|
||||
unsigned getNumDecls() const { return NumResults; }
|
||||
@ -2634,7 +2447,7 @@ class OverloadExpr : public Expr {
|
||||
/// This points to the same data as getExplicitTemplateArgs(), but
|
||||
/// returns null if there are no explicit template arguments.
|
||||
const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() const {
|
||||
if (!hasExplicitTemplateArgs()) return 0;
|
||||
if (!hasExplicitTemplateArgs()) return nullptr;
|
||||
return &getExplicitTemplateArgs();
|
||||
}
|
||||
|
||||
@ -2691,7 +2504,7 @@ class UnresolvedLookupExpr : public OverloadExpr {
|
||||
|
||||
UnresolvedLookupExpr(EmptyShell Empty)
|
||||
: OverloadExpr(UnresolvedLookupExprClass, Empty),
|
||||
RequiresADL(false), Overloaded(false), NamingClass(0)
|
||||
RequiresADL(false), Overloaded(false), NamingClass(nullptr)
|
||||
{}
|
||||
|
||||
friend class ASTStmtReader;
|
||||
@ -2706,7 +2519,7 @@ class UnresolvedLookupExpr : public OverloadExpr {
|
||||
UnresolvedSetIterator End) {
|
||||
return new(C) UnresolvedLookupExpr(C, NamingClass, QualifierLoc,
|
||||
SourceLocation(), NameInfo,
|
||||
ADL, Overloaded, 0, Begin, End);
|
||||
ADL, Overloaded, nullptr, Begin, End);
|
||||
}
|
||||
|
||||
static UnresolvedLookupExpr *Create(const ASTContext &C,
|
||||
@ -2781,7 +2594,7 @@ class DependentScopeDeclRefExpr : public Expr {
|
||||
|
||||
/// \brief Return the optional template keyword and arguments info.
|
||||
ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo() {
|
||||
if (!HasTemplateKWAndArgsInfo) return 0;
|
||||
if (!HasTemplateKWAndArgsInfo) return nullptr;
|
||||
return reinterpret_cast<ASTTemplateKWAndArgsInfo*>(this + 1);
|
||||
}
|
||||
/// \brief Return the optional template keyword and arguments info.
|
||||
@ -2875,7 +2688,7 @@ class DependentScopeDeclRefExpr : public Expr {
|
||||
/// This points to the same data as getExplicitTemplateArgs(), but
|
||||
/// returns null if there are no explicit template arguments.
|
||||
const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() const {
|
||||
if (!hasExplicitTemplateArgs()) return 0;
|
||||
if (!hasExplicitTemplateArgs()) return nullptr;
|
||||
return &getExplicitTemplateArgs();
|
||||
}
|
||||
|
||||
@ -3151,7 +2964,7 @@ class CXXDependentScopeMemberExpr : public Expr {
|
||||
|
||||
/// \brief Return the optional template keyword and arguments info.
|
||||
ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo() {
|
||||
if (!HasTemplateKWAndArgsInfo) return 0;
|
||||
if (!HasTemplateKWAndArgsInfo) return nullptr;
|
||||
return reinterpret_cast<ASTTemplateKWAndArgsInfo*>(this + 1);
|
||||
}
|
||||
/// \brief Return the optional template keyword and arguments info.
|
||||
@ -3296,7 +3109,7 @@ class CXXDependentScopeMemberExpr : public Expr {
|
||||
/// This points to the same data as getExplicitTemplateArgs(), but
|
||||
/// returns null if there are no explicit template arguments.
|
||||
const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() const {
|
||||
if (!hasExplicitTemplateArgs()) return 0;
|
||||
if (!hasExplicitTemplateArgs()) return nullptr;
|
||||
return &getExplicitTemplateArgs();
|
||||
}
|
||||
|
||||
@ -3398,7 +3211,7 @@ class UnresolvedMemberExpr : public OverloadExpr {
|
||||
|
||||
UnresolvedMemberExpr(EmptyShell Empty)
|
||||
: OverloadExpr(UnresolvedMemberExprClass, Empty), IsArrow(false),
|
||||
HasUnresolvedUsing(false), Base(0) { }
|
||||
HasUnresolvedUsing(false), Base(nullptr) { }
|
||||
|
||||
friend class ASTStmtReader;
|
||||
|
||||
@ -3612,7 +3425,7 @@ class PackExpansionExpr : public Expr {
|
||||
};
|
||||
|
||||
inline ASTTemplateKWAndArgsInfo *OverloadExpr::getTemplateKWAndArgsInfo() {
|
||||
if (!HasTemplateKWAndArgsInfo) return 0;
|
||||
if (!HasTemplateKWAndArgsInfo) return nullptr;
|
||||
if (isa<UnresolvedLookupExpr>(this))
|
||||
return reinterpret_cast<ASTTemplateKWAndArgsInfo*>
|
||||
(cast<UnresolvedLookupExpr>(this) + 1);
|
||||
@ -3904,39 +3717,51 @@ class FunctionParmPackExpr : public Expr {
|
||||
/// temporary. When either happens, the expression will also track the
|
||||
/// declaration which is responsible for the lifetime extension.
|
||||
class MaterializeTemporaryExpr : public Expr {
|
||||
public:
|
||||
/// \brief The temporary-generating expression whose value will be
|
||||
/// materialized.
|
||||
Stmt *Temporary;
|
||||
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;
|
||||
/// \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,
|
||||
const ValueDecl *ExtendedBy)
|
||||
bool BoundToLvalueReference)
|
||||
: Expr(MaterializeTemporaryExprClass, T,
|
||||
BoundToLvalueReference? VK_LValue : VK_XValue, OK_Ordinary,
|
||||
Temporary->isTypeDependent(), Temporary->isValueDependent(),
|
||||
Temporary->isInstantiationDependent(),
|
||||
Temporary->containsUnexpandedParameterPack()),
|
||||
Temporary(Temporary), ExtendingDecl(ExtendedBy) {
|
||||
}
|
||||
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 *>(Temporary); }
|
||||
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
|
||||
@ -3948,10 +3773,15 @@ class MaterializeTemporaryExpr : public Expr {
|
||||
|
||||
/// \brief Get the declaration which triggered the lifetime-extension of this
|
||||
/// temporary, if any.
|
||||
const ValueDecl *getExtendingDecl() const { return ExtendingDecl; }
|
||||
const ValueDecl *getExtendingDecl() const {
|
||||
return State.is<Stmt *>() ? nullptr
|
||||
: State.get<ExtraState *>()->ExtendingDecl;
|
||||
}
|
||||
|
||||
void setExtendingDecl(const ValueDecl *ExtendedBy) {
|
||||
ExtendingDecl = ExtendedBy;
|
||||
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
|
||||
@ -3961,10 +3791,10 @@ class MaterializeTemporaryExpr : public Expr {
|
||||
}
|
||||
|
||||
SourceLocation getLocStart() const LLVM_READONLY {
|
||||
return Temporary->getLocStart();
|
||||
return getTemporary()->getLocStart();
|
||||
}
|
||||
SourceLocation getLocEnd() const LLVM_READONLY {
|
||||
return Temporary->getLocEnd();
|
||||
return getTemporary()->getLocEnd();
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
@ -3972,7 +3802,13 @@ class MaterializeTemporaryExpr : public Expr {
|
||||
}
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&Temporary, &Temporary + 1); }
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
@ -215,7 +215,7 @@ struct ObjCDictionaryElement {
|
||||
} // end namespace clang
|
||||
|
||||
namespace llvm {
|
||||
template <> struct isPodLike<clang::ObjCDictionaryElement> : llvm::true_type {};
|
||||
template <> struct isPodLike<clang::ObjCDictionaryElement> : std::true_type {};
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
@ -277,14 +277,14 @@ class ObjCDictionaryLiteral : public Expr {
|
||||
|
||||
ExpansionData *getExpansionData() {
|
||||
if (!HasPackExpansions)
|
||||
return 0;
|
||||
return nullptr;
|
||||
|
||||
return reinterpret_cast<ExpansionData *>(getKeyValues() + NumElements);
|
||||
}
|
||||
|
||||
const ExpansionData *getExpansionData() const {
|
||||
if (!HasPackExpansions)
|
||||
return 0;
|
||||
return nullptr;
|
||||
|
||||
return reinterpret_cast<const ExpansionData *>(getKeyValues()+NumElements);
|
||||
}
|
||||
@ -683,13 +683,13 @@ class ObjCPropertyRefExpr : public Expr {
|
||||
if (isExplicitProperty()) {
|
||||
const ObjCPropertyDecl *PDecl = getExplicitProperty();
|
||||
if (const ObjCMethodDecl *Getter = PDecl->getGetterMethodDecl())
|
||||
ResultType = Getter->getResultType();
|
||||
ResultType = Getter->getReturnType();
|
||||
else
|
||||
ResultType = PDecl->getType();
|
||||
} else {
|
||||
const ObjCMethodDecl *Getter = getImplicitPropertyGetter();
|
||||
if (Getter)
|
||||
ResultType = Getter->getResultType(); // with reference!
|
||||
ResultType = Getter->getReturnType(); // with reference!
|
||||
}
|
||||
return ResultType;
|
||||
}
|
||||
@ -743,7 +743,7 @@ class ObjCPropertyRefExpr : public Expr {
|
||||
void setExplicitProperty(ObjCPropertyDecl *D, unsigned methRefFlags) {
|
||||
PropertyOrGetter.setPointer(D);
|
||||
PropertyOrGetter.setInt(false);
|
||||
SetterAndMethodRefFlags.setPointer(0);
|
||||
SetterAndMethodRefFlags.setPointer(nullptr);
|
||||
SetterAndMethodRefFlags.setInt(methRefFlags);
|
||||
}
|
||||
void setImplicitProperty(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter,
|
||||
@ -1174,7 +1174,7 @@ class ObjCMessageExpr : public Expr {
|
||||
if (getReceiverKind() == Instance)
|
||||
return static_cast<Expr *>(getReceiverPointer());
|
||||
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
const Expr *getInstanceReceiver() const {
|
||||
return const_cast<ObjCMessageExpr*>(this)->getInstanceReceiver();
|
||||
@ -1201,7 +1201,7 @@ class ObjCMessageExpr : public Expr {
|
||||
TypeSourceInfo *getClassReceiverTypeInfo() const {
|
||||
if (getReceiverKind() == Class)
|
||||
return reinterpret_cast<TypeSourceInfo *>(getReceiverPointer());
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void setClassReceiver(TypeSourceInfo *TSInfo) {
|
||||
@ -1270,14 +1270,14 @@ class ObjCMessageExpr : public Expr {
|
||||
if (HasMethod)
|
||||
return reinterpret_cast<const ObjCMethodDecl *>(SelectorOrMethod);
|
||||
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ObjCMethodDecl *getMethodDecl() {
|
||||
if (HasMethod)
|
||||
return reinterpret_cast<ObjCMethodDecl *>(SelectorOrMethod);
|
||||
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void setMethodDecl(ObjCMethodDecl *MD) {
|
||||
|
@ -45,7 +45,7 @@ enum ExternalLoadResult {
|
||||
/// no additional processing is required.
|
||||
ELR_AlreadyLoaded
|
||||
};
|
||||
|
||||
|
||||
/// \brief Abstract interface for external sources of AST nodes.
|
||||
///
|
||||
/// External AST sources provide AST nodes constructed from some
|
||||
@ -53,7 +53,11 @@ enum ExternalLoadResult {
|
||||
/// sources can resolve types and declarations from abstract IDs into
|
||||
/// actual type and declaration nodes, and read parts of declaration
|
||||
/// contexts.
|
||||
class ExternalASTSource {
|
||||
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;
|
||||
@ -61,7 +65,7 @@ class ExternalASTSource {
|
||||
friend class ExternalSemaSource;
|
||||
|
||||
public:
|
||||
ExternalASTSource() : SemaSource(false) { }
|
||||
ExternalASTSource() : CurrentGeneration(0), SemaSource(false) { }
|
||||
|
||||
virtual ~ExternalASTSource();
|
||||
|
||||
@ -79,6 +83,11 @@ class ExternalASTSource {
|
||||
}
|
||||
};
|
||||
|
||||
/// \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.
|
||||
///
|
||||
@ -138,7 +147,7 @@ class ExternalASTSource {
|
||||
virtual void completeVisibleDeclsMap(const DeclContext *DC);
|
||||
|
||||
/// \brief Retrieve the module that corresponds to the given module ID.
|
||||
virtual Module *getModule(unsigned ID) { return 0; }
|
||||
virtual Module *getModule(unsigned ID) { return nullptr; }
|
||||
|
||||
/// \brief Finds all declarations lexically contained within the given
|
||||
/// DeclContext, after applying an optional filter predicate.
|
||||
@ -160,7 +169,7 @@ class ExternalASTSource {
|
||||
/// \return true if an error occurred
|
||||
ExternalLoadResult FindExternalLexicalDecls(const DeclContext *DC,
|
||||
SmallVectorImpl<Decl*> &Result) {
|
||||
return FindExternalLexicalDecls(DC, 0, Result);
|
||||
return FindExternalLexicalDecls(DC, nullptr, Result);
|
||||
}
|
||||
|
||||
template <typename DeclTy>
|
||||
@ -171,43 +180,50 @@ class ExternalASTSource {
|
||||
|
||||
/// \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) {}
|
||||
/// 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) {}
|
||||
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
|
||||
/// set on the ObjCInterfaceDecl via the function
|
||||
/// \c ObjCInterfaceDecl::setExternallyCompleted().
|
||||
virtual void CompleteType(ObjCInterfaceDecl *Class) { }
|
||||
virtual void CompleteType(ObjCInterfaceDecl *Class);
|
||||
|
||||
/// \brief Loads comment ranges.
|
||||
virtual void ReadComments() { }
|
||||
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() { }
|
||||
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() { }
|
||||
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) { }
|
||||
virtual void StartTranslationUnit(ASTConsumer *Consumer);
|
||||
|
||||
/// \brief Print any statistics that have been gathered regarding
|
||||
/// the external AST source.
|
||||
@ -243,16 +259,12 @@ class ExternalASTSource {
|
||||
/// 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)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
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.
|
||||
//===--------------------------------------------------------------------===//
|
||||
@ -284,6 +296,9 @@ class ExternalASTSource {
|
||||
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
|
||||
@ -354,6 +369,100 @@ struct LazyOffsetPtr {
|
||||
}
|
||||
};
|
||||
|
||||
/// \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
|
||||
@ -519,7 +628,7 @@ class LazyVector {
|
||||
|
||||
if (From.Position < 0) {
|
||||
Loaded.erase(Loaded.end() + From.Position, Loaded.end());
|
||||
From = begin(0, true);
|
||||
From = begin(nullptr, true);
|
||||
}
|
||||
|
||||
Local.erase(Local.begin() + From.Position, Local.begin() + To.Position);
|
||||
|
123
contrib/llvm/tools/clang/include/clang/AST/LambdaCapture.h
Normal file
123
contrib/llvm/tools/clang/include/clang/AST/LambdaCapture.h
Normal file
@ -0,0 +1,123 @@
|
||||
//===--- 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; }
|
||||
|
||||
/// \brief Determine whether this capture handles a variable.
|
||||
bool capturesVariable() const {
|
||||
return dyn_cast_or_null<VarDecl>(DeclAndBits.getPointer());
|
||||
}
|
||||
|
||||
/// \brief Determine whether this is an init-capture.
|
||||
bool isInitCapture() const {
|
||||
return capturesVariable() && getCapturedVar()->isInitCapture();
|
||||
}
|
||||
|
||||
/// \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
|
@ -31,36 +31,10 @@ namespace clang {
|
||||
class FunctionDecl;
|
||||
class NamedDecl;
|
||||
class ObjCMethodDecl;
|
||||
class VarDecl;
|
||||
class StringLiteral;
|
||||
struct ThisAdjustment;
|
||||
struct ThunkInfo;
|
||||
|
||||
/// MangleBuffer - a convenient class for storing a name which is
|
||||
/// either the result of a mangling or is a constant string with
|
||||
/// external memory ownership.
|
||||
class MangleBuffer {
|
||||
public:
|
||||
void setString(StringRef Ref) {
|
||||
String = Ref;
|
||||
}
|
||||
|
||||
SmallVectorImpl<char> &getBuffer() {
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
StringRef getString() const {
|
||||
if (!String.empty()) return String;
|
||||
return Buffer.str();
|
||||
}
|
||||
|
||||
operator StringRef() const {
|
||||
return getString();
|
||||
}
|
||||
|
||||
private:
|
||||
StringRef String;
|
||||
SmallString<256> Buffer;
|
||||
};
|
||||
class VarDecl;
|
||||
|
||||
/// MangleContext - Context for tracking state which persists across multiple
|
||||
/// calls to the C++ name mangler.
|
||||
@ -80,6 +54,7 @@ class MangleContext {
|
||||
|
||||
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; }
|
||||
@ -104,12 +79,19 @@ class MangleContext {
|
||||
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 &);
|
||||
@ -121,6 +103,7 @@ class MangleContext {
|
||||
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;
|
||||
@ -128,6 +111,7 @@ class MangleContext {
|
||||
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,
|
||||
@ -200,9 +184,23 @@ class MicrosoftMangleContext : public MangleContext {
|
||||
raw_ostream &Out) = 0;
|
||||
|
||||
virtual void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD,
|
||||
uint64_t OffsetInVFTable,
|
||||
raw_ostream &) = 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;
|
||||
}
|
||||
|
@ -33,7 +33,6 @@ class VarDecl;
|
||||
class MangleNumberingContext
|
||||
: public RefCountedBase<MangleNumberingContext> {
|
||||
llvm::DenseMap<const Type *, unsigned> ManglingNumbers;
|
||||
llvm::DenseMap<IdentifierInfo*, unsigned> TagManglingNumbers;
|
||||
|
||||
public:
|
||||
virtual ~MangleNumberingContext() {}
|
||||
@ -46,13 +45,18 @@ class MangleNumberingContext
|
||||
/// context.
|
||||
unsigned getManglingNumber(const BlockDecl *BD);
|
||||
|
||||
/// \brief Retrieve the mangling number of a static local variable within
|
||||
/// this context.
|
||||
virtual unsigned getManglingNumber(const VarDecl *VD) = 0;
|
||||
/// Static locals are numbered by source order.
|
||||
unsigned getStaticLocalNumber(const VarDecl *VD);
|
||||
|
||||
/// \brief Retrieve the mangling number of a static local variable within
|
||||
/// this context.
|
||||
unsigned getManglingNumber(const TagDecl *TD);
|
||||
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
|
||||
|
@ -88,7 +88,8 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
|
||||
|
||||
private:
|
||||
/// \brief Builds the global specifier.
|
||||
NestedNameSpecifier() : Prefix(0, StoredIdentifier), Specifier(0) { }
|
||||
NestedNameSpecifier()
|
||||
: Prefix(nullptr, StoredIdentifier), Specifier(nullptr) {}
|
||||
|
||||
/// \brief Copy constructor used internally to clone nested name
|
||||
/// specifiers.
|
||||
@ -160,7 +161,7 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
|
||||
if (Prefix.getInt() == StoredIdentifier)
|
||||
return (IdentifierInfo *)Specifier;
|
||||
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the namespace stored in this nested name
|
||||
@ -177,7 +178,7 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
|
||||
Prefix.getInt() == StoredTypeSpecWithTemplate)
|
||||
return (const Type *)Specifier;
|
||||
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// \brief Whether this nested name specifier refers to a dependent
|
||||
@ -222,7 +223,7 @@ class NestedNameSpecifierLoc {
|
||||
|
||||
public:
|
||||
/// \brief Construct an empty nested-name-specifier.
|
||||
NestedNameSpecifierLoc() : Qualifier(0), Data(0) { }
|
||||
NestedNameSpecifierLoc() : Qualifier(nullptr), Data(nullptr) { }
|
||||
|
||||
/// \brief Construct a nested-name-specifier with source location information
|
||||
/// from
|
||||
@ -344,7 +345,8 @@ class NestedNameSpecifierLocBuilder {
|
||||
|
||||
public:
|
||||
NestedNameSpecifierLocBuilder()
|
||||
: Representation(0), Buffer(0), BufferSize(0), BufferCapacity(0) { }
|
||||
: Representation(nullptr), Buffer(nullptr), BufferSize(0),
|
||||
BufferCapacity(0) {}
|
||||
|
||||
NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other);
|
||||
|
||||
@ -457,7 +459,7 @@ class NestedNameSpecifierLocBuilder {
|
||||
/// \brief Clear out this builder, and prepare it to build another
|
||||
/// nested-name-specifier with source-location information.
|
||||
void Clear() {
|
||||
Representation = 0;
|
||||
Representation = nullptr;
|
||||
BufferSize = 0;
|
||||
}
|
||||
|
||||
|
1455
contrib/llvm/tools/clang/include/clang/AST/OpenMPClause.h
Normal file
1455
contrib/llvm/tools/clang/include/clang/AST/OpenMPClause.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -295,7 +295,10 @@ enum CastKind {
|
||||
CK_BuiltinFnToFnPtr,
|
||||
|
||||
// Convert a zero value for OpenCL event_t initialization.
|
||||
CK_ZeroToOCLEvent
|
||||
CK_ZeroToOCLEvent,
|
||||
|
||||
// Convert a pointer to a different address space.
|
||||
CK_AddressSpaceConversion
|
||||
};
|
||||
|
||||
static const CastKind CK_Invalid = static_cast<CastKind>(-1);
|
||||
|
@ -53,7 +53,7 @@ class ParentMap {
|
||||
}
|
||||
|
||||
bool hasParent(Stmt* S) const {
|
||||
return getParent(S) != 0;
|
||||
return getParent(S) != nullptr;
|
||||
}
|
||||
|
||||
bool isConsumedExpr(Expr *E) const;
|
||||
|
@ -41,7 +41,8 @@ struct PrintingPolicy {
|
||||
ConstantArraySizeAsWritten(false), AnonymousTagLocations(true),
|
||||
SuppressStrongLifetime(false), SuppressLifetimeQualifiers(false),
|
||||
Bool(LO.Bool), TerseOutput(false), PolishForDeclaration(false),
|
||||
MSWChar(LO.MicrosoftExt && !LO.WChar) { }
|
||||
Half(LO.Half), MSWChar(LO.MicrosoftExt && !LO.WChar),
|
||||
IncludeNewlines(true) { }
|
||||
|
||||
/// \brief What language we're printing.
|
||||
LangOptions LangOpts;
|
||||
@ -125,7 +126,7 @@ struct PrintingPolicy {
|
||||
|
||||
/// \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.
|
||||
/// prints "(anonymous)" for the name.
|
||||
bool AnonymousTagLocations : 1;
|
||||
|
||||
/// \brief When true, suppress printing of the __strong lifetime qualifier in
|
||||
@ -152,9 +153,16 @@ struct PrintingPolicy {
|
||||
///
|
||||
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;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
@ -193,9 +193,7 @@ class RawCommentList {
|
||||
SourceManager &SourceMgr;
|
||||
std::vector<RawComment *> Comments;
|
||||
|
||||
void addCommentsToFront(const std::vector<RawComment *> &C) {
|
||||
Comments.insert(Comments.begin(), C.begin(), C.end());
|
||||
}
|
||||
void addDeserializedComments(ArrayRef<RawComment *> DeserializedComments);
|
||||
|
||||
friend class ASTReader;
|
||||
};
|
||||
|
@ -66,6 +66,10 @@ class ASTRecordLayout {
|
||||
// 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;
|
||||
|
||||
@ -78,9 +82,9 @@ class ASTRecordLayout {
|
||||
/// the size of the object without virtual bases.
|
||||
CharUnits NonVirtualSize;
|
||||
|
||||
/// NonVirtualAlign - The non-virtual alignment (in chars) of an object,
|
||||
/// NonVirtualAlignment - The non-virtual alignment (in chars) of an object,
|
||||
/// which is the alignment of the object without virtual bases.
|
||||
CharUnits NonVirtualAlign;
|
||||
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
|
||||
@ -100,10 +104,15 @@ class ASTRecordLayout {
|
||||
/// a primary base class.
|
||||
bool HasExtendableVFPtr : 1;
|
||||
|
||||
/// AlignAfterVBases - Force appropriate alignment after virtual bases are
|
||||
/// laid out in MS-C++-ABI.
|
||||
bool AlignAfterVBases : 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;
|
||||
|
||||
@ -127,6 +136,7 @@ class ASTRecordLayout {
|
||||
friend class ASTContext;
|
||||
|
||||
ASTRecordLayout(const ASTContext &Ctx, CharUnits size, CharUnits alignment,
|
||||
CharUnits requiredAlignment,
|
||||
CharUnits datasize, const uint64_t *fieldoffsets,
|
||||
unsigned fieldcount);
|
||||
|
||||
@ -134,16 +144,18 @@ class ASTRecordLayout {
|
||||
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 nonvirtualalign,
|
||||
CharUnits nonvirtualsize, CharUnits nonvirtualalignment,
|
||||
CharUnits SizeOfLargestEmptySubobject,
|
||||
const CXXRecordDecl *PrimaryBase,
|
||||
bool IsPrimaryBaseVirtual,
|
||||
const CXXRecordDecl *BaseSharingVBPtr,
|
||||
bool ForceAlign,
|
||||
bool HasZeroSizedSubObject,
|
||||
bool LeadsWithZeroSizedBase,
|
||||
const BaseOffsetsMapTy& BaseOffsets,
|
||||
const VBaseOffsetsMapTy& VBaseOffsets);
|
||||
|
||||
@ -187,10 +199,10 @@ class ASTRecordLayout {
|
||||
|
||||
/// getNonVirtualSize - Get the non-virtual alignment (in chars) of an object,
|
||||
/// which is the alignment of the object without virtual bases.
|
||||
CharUnits getNonVirtualAlign() const {
|
||||
CharUnits getNonVirtualAlignment() const {
|
||||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||
|
||||
return CXXInfo->NonVirtualAlign;
|
||||
return CXXInfo->NonVirtualAlignment;
|
||||
}
|
||||
|
||||
/// getPrimaryBase - Get the primary base for this record.
|
||||
@ -267,9 +279,17 @@ class ASTRecordLayout {
|
||||
return !CXXInfo->VBPtrOffset.isNegative();
|
||||
}
|
||||
|
||||
bool getAlignAfterVBases() const {
|
||||
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->AlignAfterVBases;
|
||||
return CXXInfo->LeadsWithZeroSizedBase;
|
||||
}
|
||||
|
||||
/// getVBPtrOffset - Get the offset for virtual base table pointer.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -14,6 +14,7 @@
|
||||
#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>
|
||||
@ -23,26 +24,82 @@ namespace clang {
|
||||
/// \brief Provides common interface for the Decls that can be redeclared.
|
||||
template<typename decl_type>
|
||||
class Redeclarable {
|
||||
|
||||
protected:
|
||||
class DeclLink {
|
||||
llvm::PointerIntPair<decl_type *, 1, bool> NextAndIsPrevious;
|
||||
public:
|
||||
DeclLink(decl_type *D, bool isLatest)
|
||||
: NextAndIsPrevious(D, isLatest) { }
|
||||
/// 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;
|
||||
|
||||
bool NextIsPrevious() const { return !NextAndIsPrevious.getInt(); }
|
||||
bool NextIsLatest() const { return NextAndIsPrevious.getInt(); }
|
||||
decl_type *getNext() const { return NextAndIsPrevious.getPointer(); }
|
||||
void setNext(decl_type *D) { NextAndIsPrevious.setPointer(D); }
|
||||
typedef const ASTContext *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(&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(*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(*NKL.get<UninitializedLatest>(), D);
|
||||
} else {
|
||||
auto Latest = Next.get<KnownLatest>();
|
||||
Latest.set(D);
|
||||
Next = Latest;
|
||||
}
|
||||
}
|
||||
|
||||
void markIncomplete() { Next.get<KnownLatest>().markIncomplete(); }
|
||||
};
|
||||
|
||||
static DeclLink PreviousDeclLink(decl_type *D) {
|
||||
return DeclLink(D, false);
|
||||
return DeclLink(DeclLink::PreviousLink, D);
|
||||
}
|
||||
|
||||
static DeclLink LatestDeclLink(decl_type *D) {
|
||||
return DeclLink(D, true);
|
||||
static DeclLink LatestDeclLink(const ASTContext &Ctx) {
|
||||
return DeclLink(DeclLink::LatestLink, Ctx);
|
||||
}
|
||||
|
||||
/// \brief Points to the next redeclaration in the chain.
|
||||
@ -58,15 +115,20 @@ class Redeclarable {
|
||||
/// If there is only one declaration, it is <pointer to self, true>
|
||||
DeclLink RedeclLink;
|
||||
|
||||
decl_type *getNextRedeclaration() const {
|
||||
return RedeclLink.getNext(static_cast<const decl_type *>(this));
|
||||
}
|
||||
|
||||
public:
|
||||
Redeclarable() : RedeclLink(LatestDeclLink(static_cast<decl_type*>(this))) { }
|
||||
Redeclarable(const ASTContext &Ctx)
|
||||
: RedeclLink(LatestDeclLink(Ctx)) {}
|
||||
|
||||
/// \brief Return the previous declaration of this declaration or NULL if this
|
||||
/// is the first declaration.
|
||||
decl_type *getPreviousDecl() {
|
||||
if (RedeclLink.NextIsPrevious())
|
||||
return RedeclLink.getNext();
|
||||
return 0;
|
||||
return getNextRedeclaration();
|
||||
return nullptr;
|
||||
}
|
||||
const decl_type *getPreviousDecl() const {
|
||||
return const_cast<decl_type *>(
|
||||
@ -96,14 +158,14 @@ class Redeclarable {
|
||||
|
||||
/// \brief Returns the most recent (re)declaration of this declaration.
|
||||
decl_type *getMostRecentDecl() {
|
||||
return getFirstDecl()->RedeclLink.getNext();
|
||||
return getFirstDecl()->getNextRedeclaration();
|
||||
}
|
||||
|
||||
/// \brief Returns the most recent (re)declaration of this declaration.
|
||||
const decl_type *getMostRecentDecl() const {
|
||||
return getFirstDecl()->RedeclLink.getNext();
|
||||
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);
|
||||
@ -122,7 +184,7 @@ class Redeclarable {
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
|
||||
redecl_iterator() : Current(0) { }
|
||||
redecl_iterator() : Current(nullptr) { }
|
||||
explicit redecl_iterator(decl_type *C)
|
||||
: Current(C), Starter(C), PassedFirst(false) { }
|
||||
|
||||
@ -135,15 +197,15 @@ class Redeclarable {
|
||||
if (Current->isFirstDecl()) {
|
||||
if (PassedFirst) {
|
||||
assert(0 && "Passed first decl twice, invalid redecl chain!");
|
||||
Current = 0;
|
||||
Current = nullptr;
|
||||
return *this;
|
||||
}
|
||||
PassedFirst = true;
|
||||
}
|
||||
|
||||
// Get either previous decl or latest decl.
|
||||
decl_type *Next = Current->RedeclLink.getNext();
|
||||
Current = (Next != Starter ? Next : 0);
|
||||
decl_type *Next = Current->getNextRedeclaration();
|
||||
Current = (Next != Starter) ? Next : nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -161,13 +223,18 @@ class Redeclarable {
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Returns iterator for all the redeclarations of the same decl.
|
||||
/// It will iterate at least once (when this decl is the only one).
|
||||
redecl_iterator redecls_begin() const {
|
||||
return redecl_iterator(const_cast<decl_type*>(
|
||||
static_cast<const decl_type*>(this)));
|
||||
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_end() const { return redecl_iterator(); }
|
||||
|
||||
redecl_iterator redecls_begin() const { return redecls().begin(); }
|
||||
redecl_iterator redecls_end() const { return redecls().end(); }
|
||||
|
||||
friend class ASTDeclReader;
|
||||
friend class ASTDeclWriter;
|
||||
|
@ -62,7 +62,7 @@ namespace clang {
|
||||
Stmt** I;
|
||||
public:
|
||||
ExprIterator(Stmt** i) : I(i) {}
|
||||
ExprIterator() : I(0) {}
|
||||
ExprIterator() : I(nullptr) {}
|
||||
ExprIterator& operator++() { ++I; return *this; }
|
||||
ExprIterator operator-(size_t i) { return I-i; }
|
||||
ExprIterator operator+(size_t i) { return I+i; }
|
||||
@ -81,7 +81,7 @@ namespace clang {
|
||||
const Stmt * const *I;
|
||||
public:
|
||||
ConstExprIterator(const Stmt * const *i) : I(i) {}
|
||||
ConstExprIterator() : I(0) {}
|
||||
ConstExprIterator() : I(nullptr) {}
|
||||
ConstExprIterator& operator++() { ++I; return *this; }
|
||||
ConstExprIterator operator+(size_t i) const { return I+i; }
|
||||
ConstExprIterator operator-(size_t i) const { return I-i; }
|
||||
@ -371,12 +371,12 @@ class Stmt {
|
||||
|
||||
/// \brief Dumps the specified AST fragment and all subtrees to
|
||||
/// \c llvm::errs().
|
||||
LLVM_ATTRIBUTE_USED void dump() const;
|
||||
LLVM_ATTRIBUTE_USED void dump(SourceManager &SM) const;
|
||||
void dump() const;
|
||||
void dump(SourceManager &SM) const;
|
||||
void dump(raw_ostream &OS, SourceManager &SM) const;
|
||||
|
||||
/// dumpColor - same as dump(), but forces color highlighting.
|
||||
LLVM_ATTRIBUTE_USED void dumpColor() const;
|
||||
void dumpColor() const;
|
||||
|
||||
/// dumpPretty/printPretty - These two methods do a "pretty print" of the AST
|
||||
/// back to its original source language syntax.
|
||||
@ -485,7 +485,13 @@ class DeclStmt : public Stmt {
|
||||
|
||||
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(); }
|
||||
@ -549,13 +555,13 @@ class CompoundStmt : public Stmt {
|
||||
|
||||
// \brief Build an empty compound statement with a location.
|
||||
explicit CompoundStmt(SourceLocation Loc)
|
||||
: Stmt(CompoundStmtClass), Body(0), LBracLoc(Loc), RBracLoc(Loc) {
|
||||
: Stmt(CompoundStmtClass), Body(nullptr), LBracLoc(Loc), RBracLoc(Loc) {
|
||||
CompoundStmtBits.NumStmts = 0;
|
||||
}
|
||||
|
||||
// \brief Build an empty compound statement.
|
||||
explicit CompoundStmt(EmptyShell Empty)
|
||||
: Stmt(CompoundStmtClass, Empty), Body(0) {
|
||||
: Stmt(CompoundStmtClass, Empty), Body(nullptr) {
|
||||
CompoundStmtBits.NumStmts = 0;
|
||||
}
|
||||
|
||||
@ -565,9 +571,12 @@ class CompoundStmt : public Stmt {
|
||||
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_back() { return !body_empty() ? Body[size()-1] : 0; }
|
||||
Stmt *body_back() { return !body_empty() ? Body[size()-1] : nullptr; }
|
||||
|
||||
void setLastStmt(Stmt *S) {
|
||||
assert(!body_empty() && "setLastStmt");
|
||||
@ -575,9 +584,16 @@ class CompoundStmt : public Stmt {
|
||||
}
|
||||
|
||||
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_back() const { return !body_empty() ? Body[size()-1] : 0; }
|
||||
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() {
|
||||
@ -612,11 +628,11 @@ class CompoundStmt : public Stmt {
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
return child_range(&Body[0], &Body[0]+CompoundStmtBits.NumStmts);
|
||||
return child_range(Body, Body + CompoundStmtBits.NumStmts);
|
||||
}
|
||||
|
||||
const_child_range children() const {
|
||||
return child_range(&Body[0], &Body[0]+CompoundStmtBits.NumStmts);
|
||||
return child_range(Body, Body + CompoundStmtBits.NumStmts);
|
||||
}
|
||||
};
|
||||
|
||||
@ -630,10 +646,11 @@ class SwitchCase : public Stmt {
|
||||
SourceLocation ColonLoc;
|
||||
|
||||
SwitchCase(StmtClass SC, SourceLocation KWLoc, SourceLocation ColonLoc)
|
||||
: Stmt(SC), NextSwitchCase(0), KeywordLoc(KWLoc), ColonLoc(ColonLoc) {}
|
||||
: Stmt(SC), NextSwitchCase(nullptr), KeywordLoc(KWLoc), ColonLoc(ColonLoc) {
|
||||
}
|
||||
|
||||
SwitchCase(StmtClass SC, EmptyShell)
|
||||
: Stmt(SC), NextSwitchCase(0) {}
|
||||
: Stmt(SC), NextSwitchCase(nullptr) {}
|
||||
|
||||
public:
|
||||
const SwitchCase *getNextSwitchCase() const { return NextSwitchCase; }
|
||||
@ -670,7 +687,7 @@ class CaseStmt : public SwitchCase {
|
||||
CaseStmt(Expr *lhs, Expr *rhs, SourceLocation caseLoc,
|
||||
SourceLocation ellipsisLoc, SourceLocation colonLoc)
|
||||
: SwitchCase(CaseStmtClass, caseLoc, colonLoc) {
|
||||
SubExprs[SUBSTMT] = 0;
|
||||
SubExprs[SUBSTMT] = nullptr;
|
||||
SubExprs[LHS] = reinterpret_cast<Stmt*>(lhs);
|
||||
SubExprs[RHS] = reinterpret_cast<Stmt*>(rhs);
|
||||
EllipsisLoc = ellipsisLoc;
|
||||
@ -802,21 +819,25 @@ class AttributedStmt : public Stmt {
|
||||
Stmt *SubStmt;
|
||||
SourceLocation AttrLoc;
|
||||
unsigned NumAttrs;
|
||||
const Attr *Attrs[1];
|
||||
|
||||
friend class ASTStmtReader;
|
||||
|
||||
AttributedStmt(SourceLocation Loc, ArrayRef<const Attr*> Attrs, Stmt *SubStmt)
|
||||
: Stmt(AttributedStmtClass), SubStmt(SubStmt), AttrLoc(Loc),
|
||||
NumAttrs(Attrs.size()) {
|
||||
memcpy(this->Attrs, Attrs.data(), Attrs.size() * sizeof(Attr*));
|
||||
memcpy(getAttrArrayPtr(), Attrs.data(), Attrs.size() * sizeof(Attr *));
|
||||
}
|
||||
|
||||
explicit AttributedStmt(EmptyShell Empty, unsigned NumAttrs)
|
||||
: Stmt(AttributedStmtClass, Empty), NumAttrs(NumAttrs) {
|
||||
memset(Attrs, 0, NumAttrs * sizeof(Attr*));
|
||||
memset(getAttrArrayPtr(), 0, NumAttrs * sizeof(Attr *));
|
||||
}
|
||||
|
||||
Attr *const *getAttrArrayPtr() const {
|
||||
return reinterpret_cast<Attr *const *>(this + 1);
|
||||
}
|
||||
Attr **getAttrArrayPtr() { return reinterpret_cast<Attr **>(this + 1); }
|
||||
|
||||
public:
|
||||
static AttributedStmt *Create(const ASTContext &C, SourceLocation Loc,
|
||||
ArrayRef<const Attr*> Attrs, Stmt *SubStmt);
|
||||
@ -825,7 +846,7 @@ class AttributedStmt : public Stmt {
|
||||
|
||||
SourceLocation getAttrLoc() const { return AttrLoc; }
|
||||
ArrayRef<const Attr*> getAttrs() const {
|
||||
return ArrayRef<const Attr*>(Attrs, NumAttrs);
|
||||
return ArrayRef<const Attr*>(getAttrArrayPtr(), NumAttrs);
|
||||
}
|
||||
Stmt *getSubStmt() { return SubStmt; }
|
||||
const Stmt *getSubStmt() const { return SubStmt; }
|
||||
@ -852,7 +873,8 @@ class IfStmt : public Stmt {
|
||||
|
||||
public:
|
||||
IfStmt(const ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond,
|
||||
Stmt *then, SourceLocation EL = SourceLocation(), Stmt *elsev = 0);
|
||||
Stmt *then, SourceLocation EL = SourceLocation(),
|
||||
Stmt *elsev = nullptr);
|
||||
|
||||
/// \brief Build an empty if/then/else statement
|
||||
explicit IfStmt(EmptyShell Empty) : Stmt(IfStmtClass, Empty) { }
|
||||
@ -1320,7 +1342,8 @@ class ReturnStmt : public Stmt {
|
||||
|
||||
public:
|
||||
ReturnStmt(SourceLocation RL)
|
||||
: Stmt(ReturnStmtClass), RetExpr(0), RetLoc(RL), NRVOCandidate(0) { }
|
||||
: Stmt(ReturnStmtClass), RetExpr(nullptr), RetLoc(RL),
|
||||
NRVOCandidate(nullptr) {}
|
||||
|
||||
ReturnStmt(SourceLocation RL, Expr *E, const VarDecl *NRVOCandidate)
|
||||
: Stmt(ReturnStmtClass), RetExpr((Stmt*) E), RetLoc(RL),
|
||||
@ -1389,7 +1412,7 @@ class AsmStmt : public Stmt {
|
||||
public:
|
||||
/// \brief Build an empty inline-assembly statement.
|
||||
explicit AsmStmt(StmtClass SC, EmptyShell Empty) :
|
||||
Stmt(SC, Empty), Exprs(0) { }
|
||||
Stmt(SC, Empty), Exprs(nullptr) { }
|
||||
|
||||
SourceLocation getAsmLoc() const { return AsmLoc; }
|
||||
void setAsmLoc(SourceLocation L) { AsmLoc = L; }
|
||||
@ -1454,6 +1477,8 @@ class AsmStmt : public Stmt {
|
||||
|
||||
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;
|
||||
@ -1463,6 +1488,8 @@ class AsmStmt : public Stmt {
|
||||
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;
|
||||
}
|
||||
@ -1471,10 +1498,16 @@ class AsmStmt : public Stmt {
|
||||
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];
|
||||
@ -1482,6 +1515,9 @@ class AsmStmt : public Stmt {
|
||||
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];
|
||||
@ -1489,6 +1525,9 @@ class AsmStmt : public Stmt {
|
||||
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);
|
||||
@ -1517,7 +1556,7 @@ class GCCAsmStmt : public AsmStmt {
|
||||
|
||||
/// \brief Build an empty inline-assembly statement.
|
||||
explicit GCCAsmStmt(EmptyShell Empty) : AsmStmt(GCCAsmStmtClass, Empty),
|
||||
Constraints(0), Clobbers(0), Names(0) { }
|
||||
Constraints(nullptr), Clobbers(nullptr), Names(nullptr) { }
|
||||
|
||||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
|
||||
@ -1693,7 +1732,7 @@ class MSAsmStmt : public AsmStmt {
|
||||
|
||||
/// \brief Build an empty MS-style inline-assembly statement.
|
||||
explicit MSAsmStmt(EmptyShell Empty) : AsmStmt(MSAsmStmtClass, Empty),
|
||||
NumAsmToks(0), AsmToks(0), Constraints(0), Clobbers(0) { }
|
||||
NumAsmToks(0), AsmToks(nullptr), Constraints(nullptr), Clobbers(nullptr) { }
|
||||
|
||||
SourceLocation getLBraceLoc() const { return LBraceLoc; }
|
||||
void setLBraceLoc(SourceLocation L) { LBraceLoc = L; }
|
||||
@ -1767,7 +1806,7 @@ class MSAsmStmt : public AsmStmt {
|
||||
}
|
||||
|
||||
child_range children() {
|
||||
return child_range(&Exprs[0], &Exprs[0]);
|
||||
return child_range(&Exprs[0], &Exprs[NumInputs + NumOutputs]);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1853,22 +1892,24 @@ class SEHTryStmt : public Stmt {
|
||||
bool IsCXXTry;
|
||||
SourceLocation TryLoc;
|
||||
Stmt *Children[2];
|
||||
int HandlerIndex;
|
||||
int HandlerParentIndex;
|
||||
|
||||
enum { TRY = 0, HANDLER = 1 };
|
||||
|
||||
SEHTryStmt(bool isCXXTry, // true if 'try' otherwise '__try'
|
||||
SourceLocation TryLoc,
|
||||
Stmt *TryBlock,
|
||||
Stmt *Handler);
|
||||
SourceLocation TryLoc, Stmt *TryBlock, Stmt *Handler,
|
||||
int HandlerIndex, int HandlerParentIndex);
|
||||
|
||||
friend class ASTReader;
|
||||
friend class ASTStmtReader;
|
||||
explicit SEHTryStmt(EmptyShell E) : Stmt(SEHTryStmtClass, E) { }
|
||||
|
||||
public:
|
||||
static SEHTryStmt* Create(const ASTContext &C, bool isCXXTry,
|
||||
static SEHTryStmt *Create(const ASTContext &C, bool isCXXTry,
|
||||
SourceLocation TryLoc, Stmt *TryBlock,
|
||||
Stmt *Handler);
|
||||
Stmt *Handler, int HandlerIndex,
|
||||
int HandlerParentIndex);
|
||||
|
||||
SourceLocation getLocStart() const LLVM_READONLY { return getTryLoc(); }
|
||||
SourceLocation getLocEnd() const LLVM_READONLY { return getEndLoc(); }
|
||||
@ -1895,6 +1936,34 @@ class SEHTryStmt : public Stmt {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == SEHTryStmtClass;
|
||||
}
|
||||
|
||||
int getHandlerIndex() const { return HandlerIndex; }
|
||||
int getHandlerParentIndex() const { return HandlerParentIndex; }
|
||||
};
|
||||
|
||||
/// 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(); }
|
||||
};
|
||||
|
||||
/// \brief This captures a statement into a function. For example, the following
|
||||
@ -1928,11 +1997,12 @@ class CapturedStmt : public Stmt {
|
||||
///
|
||||
/// \param Var The variable being captured, or null if capturing this.
|
||||
///
|
||||
Capture(SourceLocation Loc, VariableCaptureKind Kind, VarDecl *Var = 0)
|
||||
Capture(SourceLocation Loc, VariableCaptureKind Kind,
|
||||
VarDecl *Var = nullptr)
|
||||
: VarAndKind(Var, Kind), Loc(Loc) {
|
||||
switch (Kind) {
|
||||
case VCK_This:
|
||||
assert(Var == 0 && "'this' capture cannot have a variable!");
|
||||
assert(!Var && "'this' capture cannot have a variable!");
|
||||
break;
|
||||
case VCK_ByRef:
|
||||
assert(Var && "capturing by reference must have a variable!");
|
||||
@ -2042,6 +2112,15 @@ class CapturedStmt : public Stmt {
|
||||
/// \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(); }
|
||||
@ -2058,6 +2137,11 @@ class CapturedStmt : public Stmt {
|
||||
|
||||
/// \brief Iterator that walks over the capture initialization arguments.
|
||||
typedef Expr **capture_init_iterator;
|
||||
typedef llvm::iterator_range<capture_init_iterator> capture_init_range;
|
||||
|
||||
capture_init_range capture_inits() const {
|
||||
return capture_init_range(capture_init_begin(), capture_init_end());
|
||||
}
|
||||
|
||||
/// \brief Retrieve the first initialization argument.
|
||||
capture_init_iterator capture_init_begin() const {
|
||||
|
@ -39,7 +39,7 @@ class CXXCatchStmt : public Stmt {
|
||||
HandlerBlock(handlerBlock) {}
|
||||
|
||||
CXXCatchStmt(EmptyShell Empty)
|
||||
: Stmt(CXXCatchStmtClass), ExceptionDecl(0), HandlerBlock(0) {}
|
||||
: Stmt(CXXCatchStmtClass), ExceptionDecl(nullptr), HandlerBlock(nullptr) {}
|
||||
|
||||
SourceLocation getLocStart() const LLVM_READONLY { return CatchLoc; }
|
||||
SourceLocation getLocEnd() const LLVM_READONLY {
|
||||
|
@ -14,8 +14,8 @@
|
||||
#ifndef LLVM_CLANG_AST_STMT_ITR_H
|
||||
#define LLVM_CLANG_AST_STMT_ITR_H
|
||||
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
@ -64,10 +64,10 @@ class StmtIteratorBase {
|
||||
|
||||
Stmt*& GetDeclExpr() const;
|
||||
|
||||
StmtIteratorBase(Stmt **s) : stmt(s), DGI(0), RawVAPtr(0) {}
|
||||
StmtIteratorBase(Stmt **s) : stmt(s), DGI(nullptr), RawVAPtr(0) {}
|
||||
StmtIteratorBase(const VariableArrayType *t);
|
||||
StmtIteratorBase(Decl **dgi, Decl **dge);
|
||||
StmtIteratorBase() : stmt(0), DGI(0), RawVAPtr(0) {}
|
||||
StmtIteratorBase() : stmt(nullptr), DGI(nullptr), RawVAPtr(0) {}
|
||||
};
|
||||
|
||||
|
||||
|
@ -107,7 +107,7 @@ class ObjCAtCatchStmt : public Stmt {
|
||||
SourceLocation getLocStart() const LLVM_READONLY { return AtCatchLoc; }
|
||||
SourceLocation getLocEnd() const LLVM_READONLY { return Body->getLocEnd(); }
|
||||
|
||||
bool hasEllipsis() const { return getCatchParamDecl() == 0; }
|
||||
bool hasEllipsis() const { return getCatchParamDecl() == nullptr; }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCAtCatchStmtClass;
|
||||
@ -222,13 +222,13 @@ class ObjCAtTryStmt : public Stmt {
|
||||
/// \brief Retrieve the \@finally statement, if any.
|
||||
const ObjCAtFinallyStmt *getFinallyStmt() const {
|
||||
if (!HasFinally)
|
||||
return 0;
|
||||
return nullptr;
|
||||
|
||||
return cast_or_null<ObjCAtFinallyStmt>(getStmts()[1 + NumCatchStmts]);
|
||||
}
|
||||
ObjCAtFinallyStmt *getFinallyStmt() {
|
||||
if (!HasFinally)
|
||||
return 0;
|
||||
return nullptr;
|
||||
|
||||
return cast_or_null<ObjCAtFinallyStmt>(getStmts()[1 + NumCatchStmts]);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -18,6 +18,7 @@
|
||||
#include "clang/AST/TemplateName.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "llvm/ADT/APSInt.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
@ -34,8 +35,7 @@ struct PrintingPolicy;
|
||||
class TypeSourceInfo;
|
||||
class ValueDecl;
|
||||
|
||||
/// \brief Represents a template argument within a class template
|
||||
/// specialization.
|
||||
/// \brief Represents a template argument.
|
||||
class TemplateArgument {
|
||||
public:
|
||||
/// \brief The kind of template argument we're storing.
|
||||
@ -52,16 +52,19 @@ class TemplateArgument {
|
||||
/// 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.
|
||||
/// that was provided for an integral non-type template parameter.
|
||||
Integral,
|
||||
/// The template argument is a template name that was provided for a
|
||||
/// 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
|
||||
/// The template argument is a pack expansion of a template name that was
|
||||
/// provided for a template template parameter.
|
||||
TemplateExpansion,
|
||||
/// The template argument is a value- or type-dependent expression or a
|
||||
/// non-dependent __uuidof expression stored in an Expr*.
|
||||
/// 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.
|
||||
@ -202,7 +205,7 @@ class TemplateArgument {
|
||||
}
|
||||
|
||||
static TemplateArgument getEmptyPack() {
|
||||
return TemplateArgument((TemplateArgument*)0, 0);
|
||||
return TemplateArgument((TemplateArgument*)nullptr, 0);
|
||||
}
|
||||
|
||||
/// \brief Create a new template argument pack by copying the given set of
|
||||
@ -325,6 +328,12 @@ class TemplateArgument {
|
||||
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 {
|
||||
@ -333,9 +342,9 @@ class TemplateArgument {
|
||||
}
|
||||
|
||||
/// \brief Return the array of arguments in this template argument pack.
|
||||
llvm::ArrayRef<TemplateArgument> getPackAsArray() const {
|
||||
ArrayRef<TemplateArgument> getPackAsArray() const {
|
||||
assert(getKind() == Pack);
|
||||
return llvm::ArrayRef<TemplateArgument>(Args.Args, Args.NumArgs);
|
||||
return ArrayRef<TemplateArgument>(Args.Args, Args.NumArgs);
|
||||
}
|
||||
|
||||
/// \brief Determines whether two template arguments are superficially the
|
||||
@ -541,6 +550,10 @@ class TemplateArgumentListInfo {
|
||||
return Arguments[I];
|
||||
}
|
||||
|
||||
TemplateArgumentLoc &operator[](unsigned I) {
|
||||
return Arguments[I];
|
||||
}
|
||||
|
||||
void addArgument(const TemplateArgumentLoc &Loc) {
|
||||
Arguments.push_back(Loc);
|
||||
}
|
||||
@ -565,7 +578,8 @@ struct ASTTemplateArgumentListInfo {
|
||||
|
||||
/// Force ASTTemplateArgumentListInfo to the right alignment
|
||||
/// for the following array of TemplateArgumentLocs.
|
||||
void *Aligner;
|
||||
llvm::AlignedCharArray<
|
||||
llvm::AlignOf<TemplateArgumentLoc>::Alignment, 1> Aligner;
|
||||
};
|
||||
|
||||
/// \brief Retrieve the template arguments
|
||||
|
@ -15,7 +15,6 @@
|
||||
#define LLVM_CLANG_AST_TEMPLATENAME_H
|
||||
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "clang/Basic/OperatorKinds.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
|
||||
@ -25,13 +24,14 @@ class ASTContext;
|
||||
class DependentTemplateName;
|
||||
class DiagnosticBuilder;
|
||||
class IdentifierInfo;
|
||||
class NamedDecl;
|
||||
class NestedNameSpecifier;
|
||||
enum OverloadedOperatorKind : int;
|
||||
class OverloadedTemplateStorage;
|
||||
struct PrintingPolicy;
|
||||
class QualifiedTemplateName;
|
||||
class NamedDecl;
|
||||
class SubstTemplateTemplateParmStorage;
|
||||
class SubstTemplateTemplateParmPackStorage;
|
||||
class SubstTemplateTemplateParmStorage;
|
||||
class TemplateArgument;
|
||||
class TemplateDecl;
|
||||
class TemplateTemplateParmDecl;
|
||||
@ -71,19 +71,19 @@ class UncommonTemplateNameStorage {
|
||||
OverloadedTemplateStorage *getAsOverloadedStorage() {
|
||||
return Bits.Kind == Overloaded
|
||||
? reinterpret_cast<OverloadedTemplateStorage *>(this)
|
||||
: 0;
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
SubstTemplateTemplateParmStorage *getAsSubstTemplateTemplateParm() {
|
||||
return Bits.Kind == SubstTemplateTemplateParm
|
||||
? reinterpret_cast<SubstTemplateTemplateParmStorage *>(this)
|
||||
: 0;
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
SubstTemplateTemplateParmPackStorage *getAsSubstTemplateTemplateParmPack() {
|
||||
return Bits.Kind == SubstTemplateTemplateParmPack
|
||||
? reinterpret_cast<SubstTemplateTemplateParmPackStorage *>(this)
|
||||
: 0;
|
||||
: nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
@ -243,7 +243,7 @@ class TemplateName {
|
||||
Storage.dyn_cast<UncommonTemplateNameStorage *>())
|
||||
return Uncommon->getAsOverloadedStorage();
|
||||
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the substituted template template parameter, if
|
||||
@ -256,7 +256,7 @@ class TemplateName {
|
||||
Storage.dyn_cast<UncommonTemplateNameStorage *>())
|
||||
return uncommon->getAsSubstTemplateTemplateParm();
|
||||
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the substituted template template parameter pack, if
|
||||
@ -270,7 +270,7 @@ class TemplateName {
|
||||
Storage.dyn_cast<UncommonTemplateNameStorage *>())
|
||||
return Uncommon->getAsSubstTemplateTemplateParmPack();
|
||||
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the underlying qualified template name
|
||||
|
@ -18,20 +18,19 @@
|
||||
#include "clang/AST/TemplateName.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/ExceptionSpecificationType.h"
|
||||
#include "clang/Basic/IdentifierTable.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/APSInt.h"
|
||||
#include "llvm/ADT/APInt.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "llvm/ADT/Twine.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/type_traits.h"
|
||||
|
||||
namespace clang {
|
||||
enum {
|
||||
@ -500,14 +499,14 @@ struct SplitQualType {
|
||||
/// The local qualifiers.
|
||||
Qualifiers Quals;
|
||||
|
||||
SplitQualType() : Ty(0), Quals() {}
|
||||
SplitQualType() : Ty(nullptr), Quals() {}
|
||||
SplitQualType(const Type *ty, Qualifiers qs) : Ty(ty), Quals(qs) {}
|
||||
|
||||
SplitQualType getSingleStepDesugaredType() const; // end of this file
|
||||
|
||||
// Make llvm::tie work.
|
||||
operator std::pair<const Type *,Qualifiers>() const {
|
||||
return std::pair<const Type *,Qualifiers>(Ty, Quals);
|
||||
// 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) {
|
||||
@ -1438,7 +1437,7 @@ class Type : public ExtQualsTypeCommonBase {
|
||||
/// \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 = 0) const;
|
||||
bool isIncompleteType(NamedDecl **Def = nullptr) const;
|
||||
|
||||
/// isIncompleteOrObjectType - Return true if this is an incomplete or object
|
||||
/// type, in other words, not a function type.
|
||||
@ -1797,7 +1796,7 @@ class Type : public ExtQualsTypeCommonBase {
|
||||
return CanonicalType;
|
||||
}
|
||||
CanQualType getCanonicalTypeUnqualified() const; // in CanonicalType.h
|
||||
LLVM_ATTRIBUTE_USED void dump() const;
|
||||
void dump() const;
|
||||
|
||||
friend class ASTReader;
|
||||
friend class ASTWriter;
|
||||
@ -1996,39 +1995,59 @@ class PointerType : public Type, public llvm::FoldingSetNode {
|
||||
static bool classof(const Type *T) { return T->getTypeClass() == Pointer; }
|
||||
};
|
||||
|
||||
/// \brief Represents a pointer type decayed from an array or function type.
|
||||
class DecayedType : public Type, public llvm::FoldingSetNode {
|
||||
QualType OriginalType;
|
||||
QualType DecayedPointer;
|
||||
/// \brief 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;
|
||||
|
||||
DecayedType(QualType OriginalType, QualType DecayedPointer,
|
||||
QualType CanonicalPtr)
|
||||
: Type(Decayed, CanonicalPtr, OriginalType->isDependentType(),
|
||||
OriginalType->isInstantiationDependentType(),
|
||||
OriginalType->isVariablyModifiedType(),
|
||||
OriginalType->containsUnexpandedParameterPack()),
|
||||
OriginalType(OriginalType), DecayedPointer(DecayedPointer) {
|
||||
assert(isa<PointerType>(DecayedPointer));
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief 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 DecayedPointer; }
|
||||
QualType getOriginalType() const { return OriginalType; }
|
||||
QualType getDecayedType() const { return getAdjustedType(); }
|
||||
|
||||
QualType getPointeeType() const {
|
||||
return cast<PointerType>(DecayedPointer)->getPointeeType();
|
||||
}
|
||||
|
||||
bool isSugared() const { return true; }
|
||||
QualType desugar() const { return DecayedPointer; }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, OriginalType);
|
||||
}
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, QualType OriginalType) {
|
||||
ID.AddPointer(OriginalType.getAsOpaquePtr());
|
||||
return cast<PointerType>(getDecayedType())->getPointeeType();
|
||||
}
|
||||
|
||||
static bool classof(const Type *T) { return T->getTypeClass() == Decayed; }
|
||||
@ -2185,6 +2204,7 @@ class MemberPointerType : public Type, public llvm::FoldingSetNode {
|
||||
}
|
||||
|
||||
const Type *getClass() const { return Class; }
|
||||
CXXRecordDecl *getMostRecentCXXRecordDecl() const;
|
||||
|
||||
bool isSugared() const { return false; }
|
||||
QualType desugar() const { return QualType(this, 0); }
|
||||
@ -2758,8 +2778,7 @@ class FunctionType : public Type {
|
||||
unsigned getTypeQuals() const { return FunctionTypeBits.TypeQuals; }
|
||||
|
||||
public:
|
||||
|
||||
QualType getResultType() const { return ResultType; }
|
||||
QualType getReturnType() const { return ResultType; }
|
||||
|
||||
bool getHasRegParm() const { return getExtInfo().getHasRegParm(); }
|
||||
unsigned getRegParmType() const { return getExtInfo().getRegParm(); }
|
||||
@ -2776,7 +2795,7 @@ class FunctionType : public Type {
|
||||
/// \brief Determine the type of an expression that calls a function of
|
||||
/// this type.
|
||||
QualType getCallResultType(ASTContext &Context) const {
|
||||
return getResultType().getNonLValueExprType(Context);
|
||||
return getReturnType().getNonLValueExprType(Context);
|
||||
}
|
||||
|
||||
static StringRef getNameForCallConv(CallingConv CC);
|
||||
@ -2805,7 +2824,7 @@ class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode {
|
||||
QualType desugar() const { return QualType(this, 0); }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, getResultType(), getExtInfo());
|
||||
Profile(ID, getReturnType(), getExtInfo());
|
||||
}
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, QualType ResultType,
|
||||
ExtInfo Info) {
|
||||
@ -2818,27 +2837,28 @@ class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode {
|
||||
}
|
||||
};
|
||||
|
||||
/// FunctionProtoType - Represents a prototype with argument type info, e.g.
|
||||
/// FunctionProtoType - Represents a prototype with parameter type info, e.g.
|
||||
/// 'int foo(int)' or 'int foo(void)'. 'void' is represented as having no
|
||||
/// arguments, not as having a single void argument. Such a type can have an
|
||||
/// 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:
|
||||
/// ExtProtoInfo - Extra information about a function prototype.
|
||||
struct ExtProtoInfo {
|
||||
ExtProtoInfo() :
|
||||
Variadic(false), HasTrailingReturn(false), TypeQuals(0),
|
||||
ExceptionSpecType(EST_None), RefQualifier(RQ_None),
|
||||
NumExceptions(0), Exceptions(0), NoexceptExpr(0),
|
||||
ExceptionSpecDecl(0), ExceptionSpecTemplate(0),
|
||||
ConsumedArguments(0) {}
|
||||
ExtProtoInfo()
|
||||
: Variadic(false), HasTrailingReturn(false), TypeQuals(0),
|
||||
ExceptionSpecType(EST_None), RefQualifier(RQ_None), NumExceptions(0),
|
||||
Exceptions(nullptr), NoexceptExpr(nullptr),
|
||||
ExceptionSpecDecl(nullptr), ExceptionSpecTemplate(nullptr),
|
||||
ConsumedParameters(nullptr) {}
|
||||
|
||||
ExtProtoInfo(CallingConv CC)
|
||||
: ExtInfo(CC), Variadic(false), HasTrailingReturn(false), TypeQuals(0),
|
||||
ExceptionSpecType(EST_None), RefQualifier(RQ_None), NumExceptions(0),
|
||||
Exceptions(0), NoexceptExpr(0), ExceptionSpecDecl(0),
|
||||
ExceptionSpecTemplate(0), ConsumedArguments(0) {}
|
||||
Exceptions(nullptr), NoexceptExpr(nullptr),
|
||||
ExceptionSpecDecl(nullptr), ExceptionSpecTemplate(nullptr),
|
||||
ConsumedParameters(nullptr) {}
|
||||
|
||||
FunctionType::ExtInfo ExtInfo;
|
||||
bool Variadic : 1;
|
||||
@ -2851,7 +2871,7 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
|
||||
Expr *NoexceptExpr;
|
||||
FunctionDecl *ExceptionSpecDecl;
|
||||
FunctionDecl *ExceptionSpecTemplate;
|
||||
const bool *ConsumedArguments;
|
||||
const bool *ConsumedParameters;
|
||||
};
|
||||
|
||||
private:
|
||||
@ -2866,11 +2886,11 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
|
||||
return false;
|
||||
}
|
||||
|
||||
FunctionProtoType(QualType result, ArrayRef<QualType> args,
|
||||
FunctionProtoType(QualType result, ArrayRef<QualType> params,
|
||||
QualType canonical, const ExtProtoInfo &epi);
|
||||
|
||||
/// NumArgs - The number of arguments this function has, not counting '...'.
|
||||
unsigned NumArgs : 15;
|
||||
/// The number of parameters this function has, not counting '...'.
|
||||
unsigned NumParams : 15;
|
||||
|
||||
/// NumExceptions - The number of types in the exception spec, if any.
|
||||
unsigned NumExceptions : 9;
|
||||
@ -2878,8 +2898,8 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
|
||||
/// ExceptionSpecType - The type of exception specification this function has.
|
||||
unsigned ExceptionSpecType : 3;
|
||||
|
||||
/// HasAnyConsumedArgs - Whether this function has any consumed arguments.
|
||||
unsigned HasAnyConsumedArgs : 1;
|
||||
/// HasAnyConsumedParams - Whether this function has any consumed parameters.
|
||||
unsigned HasAnyConsumedParams : 1;
|
||||
|
||||
/// Variadic - Whether the function is variadic.
|
||||
unsigned Variadic : 1;
|
||||
@ -2892,8 +2912,8 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
|
||||
/// This is a value of type \c RefQualifierKind.
|
||||
unsigned RefQualifier : 2;
|
||||
|
||||
// ArgInfo - There is an variable size array after the class in memory that
|
||||
// holds the argument types.
|
||||
// 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.
|
||||
@ -2906,17 +2926,17 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
|
||||
// instantiate this function type's exception specification, and the function
|
||||
// from which it should be instantiated.
|
||||
|
||||
// ConsumedArgs - A variable size array, following Exceptions
|
||||
// and of length NumArgs, holding flags indicating which arguments
|
||||
// are consumed. This only appears if HasAnyConsumedArgs is true.
|
||||
// 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 *getConsumedArgsBuffer() const {
|
||||
assert(hasAnyConsumedArgs());
|
||||
const bool *getConsumedParamsBuffer() const {
|
||||
assert(hasAnyConsumedParams());
|
||||
|
||||
// Find the end of the exceptions.
|
||||
Expr * const *eh_end = reinterpret_cast<Expr * const *>(arg_type_end());
|
||||
Expr *const *eh_end = reinterpret_cast<Expr *const *>(param_type_end());
|
||||
if (getExceptionSpecType() != EST_ComputedNoexcept)
|
||||
eh_end += NumExceptions;
|
||||
else
|
||||
@ -2926,13 +2946,13 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
|
||||
}
|
||||
|
||||
public:
|
||||
unsigned getNumArgs() const { return NumArgs; }
|
||||
QualType getArgType(unsigned i) const {
|
||||
assert(i < NumArgs && "Invalid argument number!");
|
||||
return arg_type_begin()[i];
|
||||
unsigned getNumParams() const { return NumParams; }
|
||||
QualType getParamType(unsigned i) const {
|
||||
assert(i < NumParams && "invalid parameter index");
|
||||
return param_type_begin()[i];
|
||||
}
|
||||
ArrayRef<QualType> getArgTypes() const {
|
||||
return ArrayRef<QualType>(arg_type_begin(), arg_type_end());
|
||||
ArrayRef<QualType> getParamTypes() const {
|
||||
return ArrayRef<QualType>(param_type_begin(), param_type_end());
|
||||
}
|
||||
|
||||
ExtProtoInfo getExtProtoInfo() const {
|
||||
@ -2954,8 +2974,8 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
|
||||
} else if (EPI.ExceptionSpecType == EST_Unevaluated) {
|
||||
EPI.ExceptionSpecDecl = getExceptionSpecDecl();
|
||||
}
|
||||
if (hasAnyConsumedArgs())
|
||||
EPI.ConsumedArguments = getConsumedArgsBuffer();
|
||||
if (hasAnyConsumedParams())
|
||||
EPI.ConsumedParameters = getConsumedParamsBuffer();
|
||||
return EPI;
|
||||
}
|
||||
|
||||
@ -2992,9 +3012,9 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
|
||||
}
|
||||
Expr *getNoexceptExpr() const {
|
||||
if (getExceptionSpecType() != EST_ComputedNoexcept)
|
||||
return 0;
|
||||
return nullptr;
|
||||
// NoexceptExpr sits where the arguments end.
|
||||
return *reinterpret_cast<Expr *const *>(arg_type_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
|
||||
@ -3003,8 +3023,8 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
|
||||
FunctionDecl *getExceptionSpecDecl() const {
|
||||
if (getExceptionSpecType() != EST_Uninstantiated &&
|
||||
getExceptionSpecType() != EST_Unevaluated)
|
||||
return 0;
|
||||
return reinterpret_cast<FunctionDecl * const *>(arg_type_end())[0];
|
||||
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
|
||||
@ -3012,18 +3032,13 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
|
||||
/// this type.
|
||||
FunctionDecl *getExceptionSpecTemplate() const {
|
||||
if (getExceptionSpecType() != EST_Uninstantiated)
|
||||
return 0;
|
||||
return reinterpret_cast<FunctionDecl * const *>(arg_type_end())[1];
|
||||
}
|
||||
bool isNothrow(const ASTContext &Ctx) const {
|
||||
ExceptionSpecificationType EST = getExceptionSpecType();
|
||||
assert(EST != EST_Unevaluated && EST != EST_Uninstantiated);
|
||||
if (EST == EST_DynamicNone || EST == EST_BasicNoexcept)
|
||||
return true;
|
||||
if (EST != EST_ComputedNoexcept)
|
||||
return false;
|
||||
return getNoexceptSpec(Ctx) == NR_Nothrow;
|
||||
return nullptr;
|
||||
return reinterpret_cast<FunctionDecl *const *>(param_type_end())[1];
|
||||
}
|
||||
/// \brief 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; }
|
||||
|
||||
@ -3045,16 +3060,28 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
|
||||
return static_cast<RefQualifierKind>(RefQualifier);
|
||||
}
|
||||
|
||||
typedef const QualType *arg_type_iterator;
|
||||
arg_type_iterator arg_type_begin() const {
|
||||
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);
|
||||
}
|
||||
arg_type_iterator arg_type_end() const { return arg_type_begin()+NumArgs; }
|
||||
param_type_iterator param_type_end() const {
|
||||
return param_type_begin() + NumParams;
|
||||
}
|
||||
|
||||
typedef const QualType *exception_iterator;
|
||||
typedef llvm::iterator_range<exception_iterator> exception_range;
|
||||
|
||||
exception_range exceptions() const {
|
||||
return exception_range(exception_begin(), exception_end());
|
||||
}
|
||||
exception_iterator exception_begin() const {
|
||||
// exceptions begin where arguments end
|
||||
return arg_type_end();
|
||||
return param_type_end();
|
||||
}
|
||||
exception_iterator exception_end() const {
|
||||
if (getExceptionSpecType() != EST_Dynamic)
|
||||
@ -3062,13 +3089,11 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
|
||||
return exception_begin() + NumExceptions;
|
||||
}
|
||||
|
||||
bool hasAnyConsumedArgs() const {
|
||||
return HasAnyConsumedArgs;
|
||||
}
|
||||
bool isArgConsumed(unsigned I) const {
|
||||
assert(I < getNumArgs() && "argument index out of range!");
|
||||
if (hasAnyConsumedArgs())
|
||||
return getConsumedArgsBuffer()[I];
|
||||
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;
|
||||
}
|
||||
|
||||
@ -3084,7 +3109,7 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx);
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, QualType Result,
|
||||
arg_type_iterator ArgTys, unsigned NumArgs,
|
||||
param_type_iterator ArgTys, unsigned NumArgs,
|
||||
const ExtProtoInfo &EPI, const ASTContext &Context);
|
||||
};
|
||||
|
||||
@ -3495,7 +3520,7 @@ class TemplateTypeParmType : public Type, public llvm::FoldingSetNode {
|
||||
bool isParameterPack() const { return getCanTTPTInfo().ParameterPack; }
|
||||
|
||||
TemplateTypeParmDecl *getDecl() const {
|
||||
return isCanonicalUnqualified() ? 0 : TTPDecl;
|
||||
return isCanonicalUnqualified() ? nullptr : TTPDecl;
|
||||
}
|
||||
|
||||
IdentifierInfo *getIdentifier() const;
|
||||
@ -3956,9 +3981,9 @@ class TypeWithKeyword : public Type {
|
||||
|
||||
static bool KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword);
|
||||
|
||||
static const char *getKeywordName(ElaboratedTypeKeyword Keyword);
|
||||
static StringRef getKeywordName(ElaboratedTypeKeyword Keyword);
|
||||
|
||||
static const char *getTagTypeKindName(TagTypeKind Kind) {
|
||||
static StringRef getTagTypeKindName(TagTypeKind Kind) {
|
||||
return getKeywordName(getKeywordForTagTypeKind(Kind));
|
||||
}
|
||||
|
||||
@ -3990,7 +4015,7 @@ class ElaboratedType : public TypeWithKeyword, public llvm::FoldingSetNode {
|
||||
NamedType->isVariablyModifiedType(),
|
||||
NamedType->containsUnexpandedParameterPack()),
|
||||
NNS(NNS), NamedType(NamedType) {
|
||||
assert(!(Keyword == ETK_None && NNS == 0) &&
|
||||
assert(!(Keyword == ETK_None && NNS == nullptr) &&
|
||||
"ElaboratedType cannot have elaborated type keyword "
|
||||
"and name qualifier both null.");
|
||||
}
|
||||
@ -4032,11 +4057,14 @@ class ElaboratedType : public TypeWithKeyword, public llvm::FoldingSetNode {
|
||||
/// dependent.
|
||||
///
|
||||
/// DependentNameType represents a class of dependent types that involve a
|
||||
/// dependent nested-name-specifier (e.g., "T::") followed by a (dependent)
|
||||
/// 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.
|
||||
@ -4051,10 +4079,7 @@ class DependentNameType : public TypeWithKeyword, public llvm::FoldingSetNode {
|
||||
/*InstantiationDependent=*/true,
|
||||
/*VariablyModified=*/false,
|
||||
NNS->containsUnexpandedParameterPack()),
|
||||
NNS(NNS), Name(Name) {
|
||||
assert(NNS->isDependent() &&
|
||||
"DependentNameType requires a dependent nested-name-specifier");
|
||||
}
|
||||
NNS(NNS), Name(Name) {}
|
||||
|
||||
friend class ASTContext; // ASTContext creates these
|
||||
|
||||
@ -4199,7 +4224,7 @@ class PackExpansionType : public Type, public llvm::FoldingSetNode {
|
||||
Optional<unsigned> NumExpansions)
|
||||
: Type(PackExpansion, Canon, /*Dependent=*/Pattern->isDependentType(),
|
||||
/*InstantiationDependent=*/true,
|
||||
/*VariableModified=*/Pattern->isVariablyModifiedType(),
|
||||
/*VariablyModified=*/Pattern->isVariablyModifiedType(),
|
||||
/*ContainsUnexpandedParameterPack=*/false),
|
||||
Pattern(Pattern),
|
||||
NumExpansions(NumExpansions? *NumExpansions + 1: 0) { }
|
||||
@ -4326,7 +4351,9 @@ class ObjCObjectType : public Type {
|
||||
ObjCInterfaceDecl *getInterface() const;
|
||||
|
||||
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(); }
|
||||
|
||||
@ -4430,7 +4457,7 @@ inline ObjCInterfaceDecl *ObjCObjectType::getInterface() const {
|
||||
if (const ObjCInterfaceType *T =
|
||||
getBaseType()->getAs<ObjCInterfaceType>())
|
||||
return T->getDecl();
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// ObjCObjectPointerType - Used to represent a pointer to an
|
||||
@ -4528,7 +4555,9 @@ class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode {
|
||||
/// 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();
|
||||
}
|
||||
@ -4633,7 +4662,7 @@ inline const Type *QualType::getTypePtr() const {
|
||||
}
|
||||
|
||||
inline const Type *QualType::getTypePtrOrNull() const {
|
||||
return (isNull() ? 0 : getCommonPtr()->BaseType);
|
||||
return (isNull() ? nullptr : getCommonPtr()->BaseType);
|
||||
}
|
||||
|
||||
inline SplitQualType QualType::split() const {
|
||||
@ -5022,7 +5051,7 @@ inline const BuiltinType *Type::getAsPlaceholderType() const {
|
||||
if (const BuiltinType *BT = dyn_cast<BuiltinType>(this))
|
||||
if (BT->isPlaceholderType())
|
||||
return BT;
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline bool Type::isSpecificPlaceholderType(unsigned K) const {
|
||||
@ -5159,10 +5188,9 @@ inline const PartialDiagnostic &operator<<(const PartialDiagnostic &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 = (llvm::is_same<T, ArrayType>::value ||
|
||||
llvm::is_base_of<ArrayType, T>::value)>
|
||||
struct ArrayType_cannot_be_used_with_getAs { };
|
||||
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>;
|
||||
@ -5178,7 +5206,7 @@ template <typename T> const T *Type::getAs() const {
|
||||
|
||||
// If the canonical form of this type isn't the right kind, reject it.
|
||||
if (!isa<T>(CanonicalType))
|
||||
return 0;
|
||||
return nullptr;
|
||||
|
||||
// If this is a typedef for the type, strip the typedef off without
|
||||
// losing all typedef information.
|
||||
@ -5192,7 +5220,7 @@ inline const ArrayType *Type::getAsArrayTypeUnsafe() const {
|
||||
|
||||
// If the canonical form of this type isn't the right kind, reject it.
|
||||
if (!isa<ArrayType>(CanonicalType))
|
||||
return 0;
|
||||
return nullptr;
|
||||
|
||||
// If this is a typedef for the type, strip the typedef off without
|
||||
// losing all typedef information.
|
||||
|
@ -81,7 +81,7 @@ class TypeLoc {
|
||||
Qualified
|
||||
};
|
||||
|
||||
TypeLoc() : Ty(0), Data(0) { }
|
||||
TypeLoc() : Ty(nullptr), Data(nullptr) { }
|
||||
TypeLoc(QualType ty, void *opaqueData)
|
||||
: Ty(ty.getAsOpaquePtr()), Data(opaqueData) { }
|
||||
TypeLoc(const Type *ty, void *opaqueData)
|
||||
@ -631,7 +631,7 @@ class TagTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
||||
bool isDefinition() const {
|
||||
TagDecl *D = getDecl();
|
||||
return D->isCompleteDefinition() &&
|
||||
(D->getIdentifier() == 0 || D->getLocation() == getNameLoc());
|
||||
(D->getIdentifier() == nullptr || D->getLocation() == getNameLoc());
|
||||
}
|
||||
};
|
||||
|
||||
@ -786,7 +786,7 @@ class AttributedTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
|
||||
setAttrNameLoc(loc);
|
||||
if (hasAttrExprOperand()) {
|
||||
setAttrOperandParensRange(SourceRange(loc));
|
||||
setAttrExprOperand(0);
|
||||
setAttrExprOperand(nullptr);
|
||||
} else if (hasAttrEnumOperand()) {
|
||||
setAttrOperandParensRange(SourceRange(loc));
|
||||
setAttrEnumOperandLoc(loc);
|
||||
@ -978,12 +978,10 @@ inline TypeLoc TypeLoc::IgnoreParens() const {
|
||||
}
|
||||
|
||||
|
||||
struct DecayedLocInfo { }; // Nothing.
|
||||
struct AdjustedLocInfo { }; // Nothing.
|
||||
|
||||
/// \brief Wrapper for source info for pointers decayed from arrays and
|
||||
/// functions.
|
||||
class DecayedTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, DecayedTypeLoc,
|
||||
DecayedType, DecayedLocInfo> {
|
||||
class AdjustedTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, AdjustedTypeLoc,
|
||||
AdjustedType, AdjustedLocInfo> {
|
||||
public:
|
||||
TypeLoc getOriginalLoc() const {
|
||||
return getInnerTypeLoc();
|
||||
@ -1004,12 +1002,17 @@ class DecayedTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, DecayedTypeLoc,
|
||||
}
|
||||
|
||||
unsigned getLocalDataSize() const {
|
||||
// sizeof(DecayedLocInfo) is 1, but we don't need its address to be unique
|
||||
// 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;
|
||||
@ -1098,7 +1101,7 @@ class MemberPointerTypeLoc : public PointerLikeTypeLoc<MemberPointerTypeLoc,
|
||||
|
||||
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
|
||||
setSigilLoc(Loc);
|
||||
setClassTInfo(0);
|
||||
setClassTInfo(nullptr);
|
||||
}
|
||||
|
||||
SourceRange getLocalSourceRange() const {
|
||||
@ -1205,23 +1208,23 @@ class FunctionTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
|
||||
}
|
||||
|
||||
ArrayRef<ParmVarDecl *> getParams() const {
|
||||
return ArrayRef<ParmVarDecl *>(getParmArray(), getNumArgs());
|
||||
return ArrayRef<ParmVarDecl *>(getParmArray(), getNumParams());
|
||||
}
|
||||
|
||||
// ParmVarDecls* are stored after Info, one for each argument.
|
||||
// ParmVarDecls* are stored after Info, one for each parameter.
|
||||
ParmVarDecl **getParmArray() const {
|
||||
return (ParmVarDecl**) getExtraLocalData();
|
||||
}
|
||||
|
||||
unsigned getNumArgs() const {
|
||||
unsigned getNumParams() const {
|
||||
if (isa<FunctionNoProtoType>(getTypePtr()))
|
||||
return 0;
|
||||
return cast<FunctionProtoType>(getTypePtr())->getNumArgs();
|
||||
return cast<FunctionProtoType>(getTypePtr())->getNumParams();
|
||||
}
|
||||
ParmVarDecl *getArg(unsigned i) const { return getParmArray()[i]; }
|
||||
void setArg(unsigned i, ParmVarDecl *VD) { getParmArray()[i] = VD; }
|
||||
ParmVarDecl *getParam(unsigned i) const { return getParmArray()[i]; }
|
||||
void setParam(unsigned i, ParmVarDecl *VD) { getParmArray()[i] = VD; }
|
||||
|
||||
TypeLoc getResultLoc() const {
|
||||
TypeLoc getReturnLoc() const {
|
||||
return getInnerTypeLoc();
|
||||
}
|
||||
|
||||
@ -1234,21 +1237,21 @@ class FunctionTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
|
||||
setLParenLoc(Loc);
|
||||
setRParenLoc(Loc);
|
||||
setLocalRangeEnd(Loc);
|
||||
for (unsigned i = 0, e = getNumArgs(); i != e; ++i)
|
||||
setArg(i, NULL);
|
||||
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 getNumArgs() * sizeof(ParmVarDecl*);
|
||||
return getNumParams() * sizeof(ParmVarDecl *);
|
||||
}
|
||||
|
||||
unsigned getExtraLocalDataAlignment() const {
|
||||
return llvm::alignOf<ParmVarDecl*>();
|
||||
}
|
||||
|
||||
QualType getInnerType() const { return getTypePtr()->getResultType(); }
|
||||
QualType getInnerType() const { return getTypePtr()->getReturnType(); }
|
||||
};
|
||||
|
||||
class FunctionProtoTypeLoc :
|
||||
@ -1311,7 +1314,7 @@ class ArrayTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
|
||||
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
|
||||
setLBracketLoc(Loc);
|
||||
setRBracketLoc(Loc);
|
||||
setSizeExpr(NULL);
|
||||
setSizeExpr(nullptr);
|
||||
}
|
||||
|
||||
QualType getInnerType() const { return getTypePtr()->getElementType(); }
|
||||
@ -1771,7 +1774,7 @@ class DependentTemplateSpecializationTypeLoc :
|
||||
// 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 = 0;
|
||||
getLocalData()->QualifierData = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,8 @@ TYPE(FunctionNoProto, FunctionType)
|
||||
DEPENDENT_TYPE(UnresolvedUsing, Type)
|
||||
NON_CANONICAL_TYPE(Paren, Type)
|
||||
NON_CANONICAL_TYPE(Typedef, Type)
|
||||
NON_CANONICAL_TYPE(Decayed, 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)
|
||||
|
@ -27,7 +27,7 @@ namespace clang {
|
||||
/// non-const iterator.
|
||||
class UnresolvedSetIterator {
|
||||
private:
|
||||
typedef llvm::MutableArrayRef<DeclAccessPair> DeclsTy;
|
||||
typedef MutableArrayRef<DeclAccessPair> DeclsTy;
|
||||
typedef DeclsTy::iterator IteratorTy;
|
||||
|
||||
IteratorTy ir;
|
||||
|
@ -19,8 +19,9 @@
|
||||
#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 "llvm/ADT/DenseSet.h"
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
namespace clang {
|
||||
@ -208,11 +209,11 @@ class VTableLayout {
|
||||
typedef llvm::DenseMap<BaseSubobject, uint64_t> AddressPointsMapTy;
|
||||
private:
|
||||
uint64_t NumVTableComponents;
|
||||
llvm::OwningArrayPtr<VTableComponent> VTableComponents;
|
||||
std::unique_ptr<VTableComponent[]> VTableComponents;
|
||||
|
||||
/// \brief Contains thunks needed by vtables, sorted by indices.
|
||||
uint64_t NumVTableThunks;
|
||||
llvm::OwningArrayPtr<VTableThunkTy> VTableThunks;
|
||||
std::unique_ptr<VTableThunkTy[]> VTableThunks;
|
||||
|
||||
/// \brief Address points for all vtables.
|
||||
AddressPointsMapTy AddressPoints;
|
||||
@ -270,6 +271,10 @@ class VTableContextBase {
|
||||
public:
|
||||
typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy;
|
||||
|
||||
bool isMicrosoft() const { return IsMicrosoftABI; }
|
||||
|
||||
virtual ~VTableContextBase() {}
|
||||
|
||||
protected:
|
||||
typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy;
|
||||
|
||||
@ -280,7 +285,7 @@ class VTableContextBase {
|
||||
/// offset offsets, thunks etc) for the given record decl.
|
||||
virtual void computeVTableRelatedInformation(const CXXRecordDecl *RD) = 0;
|
||||
|
||||
virtual ~VTableContextBase() {}
|
||||
VTableContextBase(bool MS) : IsMicrosoftABI(MS) {}
|
||||
|
||||
public:
|
||||
virtual const ThunkInfoVectorTy *getThunkInfo(GlobalDecl GD) {
|
||||
@ -292,16 +297,17 @@ class VTableContextBase {
|
||||
ThunksMapTy::const_iterator I = Thunks.find(MD);
|
||||
if (I == Thunks.end()) {
|
||||
// We did not find a thunk for this method.
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &I->second;
|
||||
}
|
||||
|
||||
bool IsMicrosoftABI;
|
||||
};
|
||||
|
||||
class ItaniumVTableContext : public VTableContextBase {
|
||||
private:
|
||||
bool IsMicrosoftABI;
|
||||
|
||||
/// \brief Contains the index (relative to the vtable address point)
|
||||
/// where the function pointer for a virtual function is stored.
|
||||
@ -323,7 +329,7 @@ class ItaniumVTableContext : public VTableContextBase {
|
||||
VirtualBaseClassOffsetOffsetsMapTy;
|
||||
VirtualBaseClassOffsetOffsetsMapTy VirtualBaseClassOffsetOffsets;
|
||||
|
||||
void computeVTableRelatedInformation(const CXXRecordDecl *RD);
|
||||
void computeVTableRelatedInformation(const CXXRecordDecl *RD) override;
|
||||
|
||||
public:
|
||||
ItaniumVTableContext(ASTContext &Context);
|
||||
@ -355,49 +361,83 @@ class ItaniumVTableContext : public VTableContextBase {
|
||||
/// 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();
|
||||
}
|
||||
};
|
||||
|
||||
struct VFPtrInfo {
|
||||
/// 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;
|
||||
|
||||
// Don't pass the PathToMangle as it should be calculated later.
|
||||
VFPtrInfo(CharUnits VFPtrOffset, const BasePath &PathToBaseWithVFPtr)
|
||||
: VBTableIndex(0), LastVBase(0), VFPtrOffset(VFPtrOffset),
|
||||
PathToBaseWithVFPtr(PathToBaseWithVFPtr), VFPtrFullOffset(VFPtrOffset) {
|
||||
}
|
||||
VPtrInfo(const CXXRecordDecl *RD)
|
||||
: ReusingBase(RD), BaseWithVPtr(RD), NextBaseToMangle(RD) {}
|
||||
|
||||
// Don't pass the PathToMangle as it should be calculated later.
|
||||
VFPtrInfo(uint64_t VBTableIndex, const CXXRecordDecl *LastVBase,
|
||||
CharUnits VFPtrOffset, const BasePath &PathToBaseWithVFPtr,
|
||||
CharUnits VFPtrFullOffset)
|
||||
: VBTableIndex(VBTableIndex), LastVBase(LastVBase),
|
||||
VFPtrOffset(VFPtrOffset), PathToBaseWithVFPtr(PathToBaseWithVFPtr),
|
||||
VFPtrFullOffset(VFPtrFullOffset) {
|
||||
assert(VBTableIndex && "The full constructor should only be used "
|
||||
"for vfptrs in virtual bases");
|
||||
assert(LastVBase);
|
||||
}
|
||||
// Copy constructor.
|
||||
// FIXME: Uncomment when we've moved to C++11.
|
||||
// VPtrInfo(const VPtrInfo &) = default;
|
||||
|
||||
/// If nonzero, holds the vbtable index of the virtual base with the vfptr.
|
||||
uint64_t VBTableIndex;
|
||||
/// 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;
|
||||
|
||||
/// Stores the last vbase on the path from the complete type to the vfptr.
|
||||
const CXXRecordDecl *LastVBase;
|
||||
/// BaseWithVPtr is at this offset from its containing complete object or
|
||||
/// virtual base.
|
||||
CharUnits NonVirtualOffset;
|
||||
|
||||
/// 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;
|
||||
/// 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.
|
||||
BasePath PathToBaseWithVFPtr;
|
||||
/// with the given vfptr offset, in the base-to-derived order. Only used for
|
||||
/// vftables.
|
||||
BasePath PathToBaseWithVPtr;
|
||||
|
||||
/// This holds the subset of records that need to be mangled into the vftable
|
||||
/// symbol name in order to get a unique name, in the derived-to-base order.
|
||||
BasePath PathToMangle;
|
||||
/// Static offset from the top of the most derived class to this vfptr,
|
||||
/// including any virtual base offset. Only used for vftables.
|
||||
CharUnits FullOffsetInMDC;
|
||||
|
||||
/// This is the full offset of the vfptr from the start of the complete type.
|
||||
CharUnits VFPtrFullOffset;
|
||||
/// 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 {
|
||||
@ -418,7 +458,7 @@ class MicrosoftVTableContext : public VTableContextBase {
|
||||
uint64_t Index;
|
||||
|
||||
MethodVFTableLocation()
|
||||
: VBTableIndex(0), VBase(0), VFPtrOffset(CharUnits::Zero()),
|
||||
: VBTableIndex(0), VBase(nullptr), VFPtrOffset(CharUnits::Zero()),
|
||||
Index(0) {}
|
||||
|
||||
MethodVFTableLocation(uint64_t VBTableIndex, const CXXRecordDecl *VBase,
|
||||
@ -431,16 +471,11 @@ class MicrosoftVTableContext : public VTableContextBase {
|
||||
assert(VBase != other.VBase);
|
||||
return VBTableIndex < other.VBTableIndex;
|
||||
}
|
||||
if (VFPtrOffset != other.VFPtrOffset)
|
||||
return VFPtrOffset < other.VFPtrOffset;
|
||||
if (Index != other.Index)
|
||||
return Index < other.Index;
|
||||
return false;
|
||||
return std::tie(VFPtrOffset, Index) <
|
||||
std::tie(other.VFPtrOffset, other.Index);
|
||||
}
|
||||
};
|
||||
|
||||
typedef SmallVector<VFPtrInfo, 1> VFPtrListTy;
|
||||
|
||||
private:
|
||||
ASTContext &Context;
|
||||
|
||||
@ -448,7 +483,7 @@ class MicrosoftVTableContext : public VTableContextBase {
|
||||
MethodVFTableLocationsTy;
|
||||
MethodVFTableLocationsTy MethodVFTableLocations;
|
||||
|
||||
typedef llvm::DenseMap<const CXXRecordDecl *, VFPtrListTy>
|
||||
typedef llvm::DenseMap<const CXXRecordDecl *, VPtrInfoVector *>
|
||||
VFPtrLocationsMapTy;
|
||||
VFPtrLocationsMapTy VFPtrLocations;
|
||||
|
||||
@ -456,47 +491,40 @@ class MicrosoftVTableContext : public VTableContextBase {
|
||||
typedef llvm::DenseMap<VFTableIdTy, const VTableLayout *> VFTableLayoutMapTy;
|
||||
VFTableLayoutMapTy VFTableLayouts;
|
||||
|
||||
typedef llvm::SmallSetVector<const CXXRecordDecl *, 8> BasesSetVectorTy;
|
||||
void enumerateVFPtrs(const CXXRecordDecl *MostDerivedClass,
|
||||
const ASTRecordLayout &MostDerivedClassLayout,
|
||||
BaseSubobject Base, const CXXRecordDecl *LastVBase,
|
||||
const VFPtrInfo::BasePath &PathFromCompleteClass,
|
||||
BasesSetVectorTy &VisitedVBases,
|
||||
MicrosoftVTableContext::VFPtrListTy &Result);
|
||||
llvm::DenseMap<const CXXRecordDecl *, VirtualBaseInfo *> VBaseInfo;
|
||||
|
||||
void enumerateVFPtrs(const CXXRecordDecl *ForClass,
|
||||
MicrosoftVTableContext::VFPtrListTy &Result);
|
||||
void enumerateVFPtrs(const CXXRecordDecl *ForClass, VPtrInfoVector &Result);
|
||||
|
||||
void computeVTableRelatedInformation(const CXXRecordDecl *RD);
|
||||
void computeVTableRelatedInformation(const CXXRecordDecl *RD) override;
|
||||
|
||||
void dumpMethodLocations(const CXXRecordDecl *RD,
|
||||
const MethodVFTableLocationsTy &NewMethods,
|
||||
raw_ostream &);
|
||||
|
||||
typedef std::pair<const CXXRecordDecl *, const CXXRecordDecl *> ClassPairTy;
|
||||
typedef llvm::DenseMap<ClassPairTy, unsigned> VBTableIndicesTy;
|
||||
VBTableIndicesTy VBTableIndices;
|
||||
llvm::DenseSet<const CXXRecordDecl *> ComputedVBTableIndices;
|
||||
const VirtualBaseInfo *
|
||||
computeVBTableRelatedInformation(const CXXRecordDecl *RD);
|
||||
|
||||
void computeVBTableRelatedInformation(const CXXRecordDecl *RD);
|
||||
void computeVTablePaths(bool ForVBTables, const CXXRecordDecl *RD,
|
||||
VPtrInfoVector &Paths);
|
||||
|
||||
public:
|
||||
MicrosoftVTableContext(ASTContext &Context) : Context(Context) {}
|
||||
MicrosoftVTableContext(ASTContext &Context)
|
||||
: VTableContextBase(/*MS=*/true), Context(Context) {}
|
||||
|
||||
~MicrosoftVTableContext() { llvm::DeleteContainerSeconds(VFTableLayouts); }
|
||||
~MicrosoftVTableContext();
|
||||
|
||||
const VFPtrListTy &getVFPtrOffsets(const CXXRecordDecl *RD);
|
||||
const VPtrInfoVector &getVFPtrOffsets(const CXXRecordDecl *RD);
|
||||
|
||||
const VTableLayout &getVFTableLayout(const CXXRecordDecl *RD,
|
||||
CharUnits VFPtrOffset);
|
||||
|
||||
const MethodVFTableLocation &getMethodVFTableLocation(GlobalDecl GD);
|
||||
|
||||
const ThunkInfoVectorTy *getThunkInfo(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 0;
|
||||
return nullptr;
|
||||
return VTableContextBase::getThunkInfo(GD);
|
||||
}
|
||||
|
||||
@ -505,14 +533,13 @@ class MicrosoftVTableContext : public VTableContextBase {
|
||||
/// 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) {
|
||||
computeVBTableRelatedInformation(Derived);
|
||||
ClassPairTy Pair(Derived, VBase);
|
||||
assert(VBTableIndices.count(Pair) == 1 &&
|
||||
"VBase must be a vbase of Derived");
|
||||
return VBTableIndices[Pair];
|
||||
}
|
||||
const CXXRecordDecl *VBase);
|
||||
|
||||
const VPtrInfoVector &enumerateVBTables(const CXXRecordDecl *RD);
|
||||
|
||||
static bool classof(const VTableContextBase *VT) { return VT->isMicrosoft(); }
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace clang
|
||||
|
||||
#endif
|
||||
|
@ -222,13 +222,13 @@ selectFirst(StringRef BoundTo, const SmallVectorImpl<BoundNodes> &Results) {
|
||||
if (NodeT *Node = I->getNodeAs<NodeT>(BoundTo))
|
||||
return Node;
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
class CollectMatchesCallback : public MatchFinder::MatchCallback {
|
||||
public:
|
||||
virtual void run(const MatchFinder::MatchResult &Result) {
|
||||
void run(const MatchFinder::MatchResult &Result) override {
|
||||
Nodes.push_back(Result.Nodes);
|
||||
}
|
||||
SmallVector<BoundNodes, 1> Nodes;
|
||||
|
@ -311,6 +311,12 @@ 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.
|
||||
///
|
||||
@ -323,9 +329,13 @@ AST_MATCHER(Decl, isPrivate) {
|
||||
/// classTemplateSpecializationDecl(hasAnyTemplateArgument(
|
||||
/// refersToType(asString("int"))))
|
||||
/// matches the specialization \c A<int>
|
||||
AST_MATCHER_P(ClassTemplateSpecializationDecl, hasAnyTemplateArgument,
|
||||
internal::Matcher<TemplateArgument>, InnerMatcher) {
|
||||
llvm::ArrayRef<TemplateArgument> List = Node.getTemplateArgs().asArray();
|
||||
AST_POLYMORPHIC_MATCHER_P(
|
||||
hasAnyTemplateArgument,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES_2(ClassTemplateSpecializationDecl,
|
||||
TemplateSpecializationType),
|
||||
internal::Matcher<TemplateArgument>, InnerMatcher) {
|
||||
ArrayRef<TemplateArgument> List =
|
||||
internal::getTemplateSpecializationArgs(Node);
|
||||
return matchesFirstInRange(InnerMatcher, List.begin(), List.end(), Finder,
|
||||
Builder);
|
||||
}
|
||||
@ -419,12 +429,16 @@ AST_MATCHER_P(Expr, ignoringParenImpCasts,
|
||||
/// classTemplateSpecializationDecl(hasTemplateArgument(
|
||||
/// 1, refersToType(asString("int"))))
|
||||
/// matches the specialization \c A<bool, int>
|
||||
AST_MATCHER_P2(ClassTemplateSpecializationDecl, hasTemplateArgument,
|
||||
unsigned, N, internal::Matcher<TemplateArgument>, InnerMatcher) {
|
||||
const TemplateArgumentList &List = Node.getTemplateArgs();
|
||||
AST_POLYMORPHIC_MATCHER_P2(
|
||||
hasTemplateArgument,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES_2(ClassTemplateSpecializationDecl,
|
||||
TemplateSpecializationType),
|
||||
unsigned, N, internal::Matcher<TemplateArgument>, InnerMatcher) {
|
||||
ArrayRef<TemplateArgument> List =
|
||||
internal::getTemplateSpecializationArgs(Node);
|
||||
if (List.size() <= N)
|
||||
return false;
|
||||
return InnerMatcher.matches(List.get(N), Finder, Builder);
|
||||
return InnerMatcher.matches(List[N], Finder, Builder);
|
||||
}
|
||||
|
||||
/// \brief Matches a TemplateArgument that refers to a certain type.
|
||||
@ -445,7 +459,8 @@ AST_MATCHER_P(TemplateArgument, refersToType,
|
||||
return InnerMatcher.matches(Node.getAsType(), Finder, Builder);
|
||||
}
|
||||
|
||||
/// \brief Matches a TemplateArgument that refers to a certain declaration.
|
||||
/// \brief Matches a canonical TemplateArgument that refers to a certain
|
||||
/// declaration.
|
||||
///
|
||||
/// Given
|
||||
/// \code
|
||||
@ -464,6 +479,24 @@ AST_MATCHER_P(TemplateArgument, refersToDeclaration,
|
||||
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 C++ constructor declarations.
|
||||
///
|
||||
/// Example matches Foo::Foo() and Foo::Foo(int)
|
||||
@ -518,7 +551,7 @@ const internal::VariadicDynCastAllOfMatcher<
|
||||
///
|
||||
/// Example matches y
|
||||
/// \code
|
||||
/// class X { void y() };
|
||||
/// class X { void y(); };
|
||||
/// \endcode
|
||||
const internal::VariadicDynCastAllOfMatcher<Decl, CXXMethodDecl> methodDecl;
|
||||
|
||||
@ -635,6 +668,16 @@ const internal::VariadicDynCastAllOfMatcher<
|
||||
Stmt,
|
||||
CXXMemberCallExpr> memberCallExpr;
|
||||
|
||||
/// \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
|
||||
@ -643,10 +686,23 @@ const internal::VariadicDynCastAllOfMatcher<
|
||||
/// struct B { int x, y; };
|
||||
/// B b = { 5, 6 };
|
||||
/// \endcode
|
||||
/// initList()
|
||||
/// 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
|
||||
@ -658,6 +714,18 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, InitListExpr> initListExpr;
|
||||
/// 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
|
||||
@ -842,15 +910,6 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, IfStmt> ifStmt;
|
||||
/// \endcode
|
||||
const internal::VariadicDynCastAllOfMatcher<Stmt, ForStmt> forStmt;
|
||||
|
||||
/// \brief Matches range-based for statements.
|
||||
///
|
||||
/// forRangeStmt() 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> forRangeStmt;
|
||||
|
||||
/// \brief Matches the increment statement of a for loop.
|
||||
///
|
||||
/// Example:
|
||||
@ -862,7 +921,7 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, CXXForRangeStmt> forRangeStmt;
|
||||
AST_MATCHER_P(ForStmt, hasIncrement, internal::Matcher<Stmt>,
|
||||
InnerMatcher) {
|
||||
const Stmt *const Increment = Node.getInc();
|
||||
return (Increment != NULL &&
|
||||
return (Increment != nullptr &&
|
||||
InnerMatcher.matches(*Increment, Finder, Builder));
|
||||
}
|
||||
|
||||
@ -877,7 +936,44 @@ AST_MATCHER_P(ForStmt, hasIncrement, internal::Matcher<Stmt>,
|
||||
AST_MATCHER_P(ForStmt, hasLoopInit, internal::Matcher<Stmt>,
|
||||
InnerMatcher) {
|
||||
const Stmt *const Init = Node.getInit();
|
||||
return (Init != NULL && InnerMatcher.matches(*Init, Finder, Builder));
|
||||
return (Init != nullptr && InnerMatcher.matches(*Init, Finder, Builder));
|
||||
}
|
||||
|
||||
/// \brief Matches range-based for statements.
|
||||
///
|
||||
/// forRangeStmt() 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> forRangeStmt;
|
||||
|
||||
/// \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.
|
||||
@ -1317,21 +1413,21 @@ const internal::VariadicAllOfMatcher<TypeLoc> typeLoc;
|
||||
/// \c b.
|
||||
///
|
||||
/// Usable as: Any Matcher
|
||||
const internal::VariadicOperatorMatcherFunc eachOf = {
|
||||
const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> eachOf = {
|
||||
internal::EachOfVariadicOperator
|
||||
};
|
||||
|
||||
/// \brief Matches if any of the given matchers matches.
|
||||
///
|
||||
/// Usable as: Any Matcher
|
||||
const internal::VariadicOperatorMatcherFunc anyOf = {
|
||||
const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> anyOf = {
|
||||
internal::AnyOfVariadicOperator
|
||||
};
|
||||
|
||||
/// \brief Matches if all given matchers match.
|
||||
///
|
||||
/// Usable as: Any Matcher
|
||||
const internal::VariadicOperatorMatcherFunc allOf = {
|
||||
const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> allOf = {
|
||||
internal::AllOfVariadicOperator
|
||||
};
|
||||
|
||||
@ -1458,14 +1554,14 @@ AST_MATCHER_P(NamedDecl, matchesName, std::string, RegExp) {
|
||||
/// line and \c recordDecl(hasMethod(hasOverloadedOperatorName("*"))) matches
|
||||
/// the declaration of \c A.
|
||||
///
|
||||
/// Usable as: Matcher<CXXOperatorCallExpr>, Matcher<CXXMethodDecl>
|
||||
/// Usable as: Matcher<CXXOperatorCallExpr>, Matcher<FunctionDecl>
|
||||
inline internal::PolymorphicMatcherWithParam1<
|
||||
internal::HasOverloadedOperatorNameMatcher, StringRef,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES_2(CXXOperatorCallExpr, CXXMethodDecl)>
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES_2(CXXOperatorCallExpr, FunctionDecl)>
|
||||
hasOverloadedOperatorName(const StringRef Name) {
|
||||
return internal::PolymorphicMatcherWithParam1<
|
||||
internal::HasOverloadedOperatorNameMatcher, StringRef,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES_2(CXXOperatorCallExpr, CXXMethodDecl)>(
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES_2(CXXOperatorCallExpr, FunctionDecl)>(
|
||||
Name);
|
||||
}
|
||||
|
||||
@ -1671,12 +1767,9 @@ const internal::ArgumentAdaptingMatcherFunc<
|
||||
/// \endcode
|
||||
///
|
||||
/// Usable as: Any Matcher
|
||||
template <typename M>
|
||||
internal::PolymorphicMatcherWithParam1<internal::NotMatcher, M>
|
||||
unless(const M &InnerMatcher) {
|
||||
return internal::PolymorphicMatcherWithParam1<
|
||||
internal::NotMatcher, M>(InnerMatcher);
|
||||
}
|
||||
const internal::VariadicOperatorMatcherFunc<1, 1> unless = {
|
||||
internal::NotUnaryOperator
|
||||
};
|
||||
|
||||
/// \brief Matches a node if the declaration associated with that node
|
||||
/// matches the given matcher.
|
||||
@ -1718,7 +1811,7 @@ AST_MATCHER_P(CXXMemberCallExpr, on, internal::Matcher<Expr>,
|
||||
InnerMatcher) {
|
||||
const Expr *ExprNode = Node.getImplicitObjectArgument()
|
||||
->IgnoreParenImpCasts();
|
||||
return (ExprNode != NULL &&
|
||||
return (ExprNode != nullptr &&
|
||||
InnerMatcher.matches(*ExprNode, Finder, Builder));
|
||||
}
|
||||
|
||||
@ -1741,7 +1834,7 @@ AST_MATCHER_P(CXXMemberCallExpr, on, internal::Matcher<Expr>,
|
||||
AST_MATCHER_P(CallExpr, callee, internal::Matcher<Stmt>,
|
||||
InnerMatcher) {
|
||||
const Expr *ExprNode = Node.getCallee();
|
||||
return (ExprNode != NULL &&
|
||||
return (ExprNode != nullptr &&
|
||||
InnerMatcher.matches(*ExprNode, Finder, Builder));
|
||||
}
|
||||
|
||||
@ -1896,7 +1989,7 @@ AST_MATCHER_P_OVERLOAD(QualType, references, internal::Matcher<Decl>,
|
||||
AST_MATCHER_P(CXXMemberCallExpr, onImplicitObjectArgument,
|
||||
internal::Matcher<Expr>, InnerMatcher) {
|
||||
const Expr *ExprNode = Node.getImplicitObjectArgument();
|
||||
return (ExprNode != NULL &&
|
||||
return (ExprNode != nullptr &&
|
||||
InnerMatcher.matches(*ExprNode, Finder, Builder));
|
||||
}
|
||||
|
||||
@ -1929,7 +2022,7 @@ AST_MATCHER_P_OVERLOAD(CXXMemberCallExpr, thisPointerType,
|
||||
AST_MATCHER_P(DeclRefExpr, to, internal::Matcher<Decl>,
|
||||
InnerMatcher) {
|
||||
const Decl *DeclNode = Node.getDecl();
|
||||
return (DeclNode != NULL &&
|
||||
return (DeclNode != nullptr &&
|
||||
InnerMatcher.matches(*DeclNode, Finder, Builder));
|
||||
}
|
||||
|
||||
@ -1986,10 +2079,39 @@ AST_MATCHER_P(
|
||||
VarDecl, hasInitializer, internal::Matcher<Expr>,
|
||||
InnerMatcher) {
|
||||
const Expr *Initializer = Node.getAnyInitializer();
|
||||
return (Initializer != NULL &&
|
||||
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 Checks that a call expression or a constructor call expression has
|
||||
/// a specific number of arguments (including absent default arguments).
|
||||
///
|
||||
@ -2098,7 +2220,7 @@ AST_MATCHER_P(CXXConstructorDecl, hasAnyConstructorInitializer,
|
||||
AST_MATCHER_P(CXXCtorInitializer, forField,
|
||||
internal::Matcher<FieldDecl>, InnerMatcher) {
|
||||
const FieldDecl *NodeAsDecl = Node.getMember();
|
||||
return (NodeAsDecl != NULL &&
|
||||
return (NodeAsDecl != nullptr &&
|
||||
InnerMatcher.matches(*NodeAsDecl, Finder, Builder));
|
||||
}
|
||||
|
||||
@ -2118,7 +2240,7 @@ AST_MATCHER_P(CXXCtorInitializer, forField,
|
||||
AST_MATCHER_P(CXXCtorInitializer, withInitializer,
|
||||
internal::Matcher<Expr>, InnerMatcher) {
|
||||
const Expr* NodeAsExpr = Node.getInit();
|
||||
return (NodeAsExpr != NULL &&
|
||||
return (NodeAsExpr != nullptr &&
|
||||
InnerMatcher.matches(*NodeAsExpr, Finder, Builder));
|
||||
}
|
||||
|
||||
@ -2139,12 +2261,6 @@ AST_MATCHER(CXXCtorInitializer, isWritten) {
|
||||
return Node.isWritten();
|
||||
}
|
||||
|
||||
/// \brief Matches a constructor declaration that has been implicitly added
|
||||
/// by the compiler (eg. implicit default/copy constructors).
|
||||
AST_MATCHER(CXXConstructorDecl, isImplicit) {
|
||||
return Node.isImplicit();
|
||||
}
|
||||
|
||||
/// \brief Matches any argument of a call expression or a constructor call
|
||||
/// expression.
|
||||
///
|
||||
@ -2175,6 +2291,11 @@ AST_POLYMORPHIC_MATCHER_P(hasAnyArgument, AST_POLYMORPHIC_SUPPORTED_TYPES_2(
|
||||
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
|
||||
@ -2234,7 +2355,7 @@ AST_MATCHER_P(FunctionDecl, parameterCountIs, unsigned, N) {
|
||||
/// matches int f() { return 1; }
|
||||
AST_MATCHER_P(FunctionDecl, returns,
|
||||
internal::Matcher<QualType>, InnerMatcher) {
|
||||
return InnerMatcher.matches(Node.getResultType(), Finder, Builder);
|
||||
return InnerMatcher.matches(Node.getReturnType(), Finder, Builder);
|
||||
}
|
||||
|
||||
/// \brief Matches extern "C" function declarations.
|
||||
@ -2263,19 +2384,33 @@ AST_POLYMORPHIC_MATCHER_P(
|
||||
IfStmt, ForStmt, WhileStmt, DoStmt, ConditionalOperator),
|
||||
internal::Matcher<Expr>, InnerMatcher) {
|
||||
const Expr *const Condition = Node.getCond();
|
||||
return (Condition != NULL &&
|
||||
return (Condition != nullptr &&
|
||||
InnerMatcher.matches(*Condition, Finder, Builder));
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
struct NotEqualsBoundNodePredicate {
|
||||
bool operator()(const internal::BoundNodesMap &Nodes) const {
|
||||
return Nodes.getNode(ID) != Node;
|
||||
}
|
||||
std::string ID;
|
||||
ast_type_traits::DynTypedNode Node;
|
||||
};
|
||||
} // namespace internal
|
||||
/// \brief Matches the then-statement of an if statement.
|
||||
///
|
||||
/// Examples matches the if statement
|
||||
/// (matcher = ifStmt(hasThen(boolLiteral(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(boolLiteral(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.
|
||||
///
|
||||
@ -2325,7 +2460,7 @@ AST_MATCHER_P(IfStmt, hasConditionVariableStatement,
|
||||
internal::Matcher<DeclStmt>, InnerMatcher) {
|
||||
const DeclStmt* const DeclarationStatement =
|
||||
Node.getConditionVariableDeclStmt();
|
||||
return DeclarationStatement != NULL &&
|
||||
return DeclarationStatement != nullptr &&
|
||||
InnerMatcher.matches(*DeclarationStatement, Finder, Builder);
|
||||
}
|
||||
|
||||
@ -2373,11 +2508,13 @@ AST_MATCHER_P(ArraySubscriptExpr, hasBase,
|
||||
/// matches 'for (;;) {}'
|
||||
/// with compoundStmt()
|
||||
/// matching '{}'
|
||||
AST_POLYMORPHIC_MATCHER_P(
|
||||
hasBody, AST_POLYMORPHIC_SUPPORTED_TYPES_3(DoStmt, ForStmt, WhileStmt),
|
||||
internal::Matcher<Stmt>, InnerMatcher) {
|
||||
AST_POLYMORPHIC_MATCHER_P(hasBody,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES_4(DoStmt, ForStmt,
|
||||
WhileStmt,
|
||||
CXXForRangeStmt),
|
||||
internal::Matcher<Stmt>, InnerMatcher) {
|
||||
const Stmt *const Statement = Node.getBody();
|
||||
return (Statement != NULL &&
|
||||
return (Statement != nullptr &&
|
||||
InnerMatcher.matches(*Statement, Finder, Builder));
|
||||
}
|
||||
|
||||
@ -2451,7 +2588,7 @@ AST_POLYMORPHIC_MATCHER_P(hasOperatorName, AST_POLYMORPHIC_SUPPORTED_TYPES_2(
|
||||
AST_MATCHER_P(BinaryOperator, hasLHS,
|
||||
internal::Matcher<Expr>, InnerMatcher) {
|
||||
Expr *LeftHandSide = Node.getLHS();
|
||||
return (LeftHandSide != NULL &&
|
||||
return (LeftHandSide != nullptr &&
|
||||
InnerMatcher.matches(*LeftHandSide, Finder, Builder));
|
||||
}
|
||||
|
||||
@ -2464,7 +2601,7 @@ AST_MATCHER_P(BinaryOperator, hasLHS,
|
||||
AST_MATCHER_P(BinaryOperator, hasRHS,
|
||||
internal::Matcher<Expr>, InnerMatcher) {
|
||||
Expr *RightHandSide = Node.getRHS();
|
||||
return (RightHandSide != NULL &&
|
||||
return (RightHandSide != nullptr &&
|
||||
InnerMatcher.matches(*RightHandSide, Finder, Builder));
|
||||
}
|
||||
|
||||
@ -2484,7 +2621,7 @@ inline internal::Matcher<BinaryOperator> hasEitherOperand(
|
||||
AST_MATCHER_P(UnaryOperator, hasUnaryOperand,
|
||||
internal::Matcher<Expr>, InnerMatcher) {
|
||||
const Expr * const Operand = Node.getSubExpr();
|
||||
return (Operand != NULL &&
|
||||
return (Operand != nullptr &&
|
||||
InnerMatcher.matches(*Operand, Finder, Builder));
|
||||
}
|
||||
|
||||
@ -2498,7 +2635,7 @@ AST_MATCHER_P(UnaryOperator, hasUnaryOperand,
|
||||
AST_MATCHER_P(CastExpr, hasSourceExpression,
|
||||
internal::Matcher<Expr>, InnerMatcher) {
|
||||
const Expr* const SubExpression = Node.getSubExpr();
|
||||
return (SubExpression != NULL &&
|
||||
return (SubExpression != nullptr &&
|
||||
InnerMatcher.matches(*SubExpression, Finder, Builder));
|
||||
}
|
||||
|
||||
@ -2530,7 +2667,7 @@ AST_MATCHER_P(ImplicitCastExpr, hasImplicitDestinationType,
|
||||
AST_MATCHER_P(ConditionalOperator, hasTrueExpression,
|
||||
internal::Matcher<Expr>, InnerMatcher) {
|
||||
Expr *Expression = Node.getTrueExpr();
|
||||
return (Expression != NULL &&
|
||||
return (Expression != nullptr &&
|
||||
InnerMatcher.matches(*Expression, Finder, Builder));
|
||||
}
|
||||
|
||||
@ -2543,7 +2680,7 @@ AST_MATCHER_P(ConditionalOperator, hasTrueExpression,
|
||||
AST_MATCHER_P(ConditionalOperator, hasFalseExpression,
|
||||
internal::Matcher<Expr>, InnerMatcher) {
|
||||
Expr *Expression = Node.getFalseExpr();
|
||||
return (Expression != NULL &&
|
||||
return (Expression != nullptr &&
|
||||
InnerMatcher.matches(*Expression, Finder, Builder));
|
||||
}
|
||||
|
||||
@ -2585,7 +2722,7 @@ AST_POLYMORPHIC_MATCHER(isDefinition, AST_POLYMORPHIC_SUPPORTED_TYPES_3(
|
||||
AST_MATCHER_P(CXXMethodDecl, ofClass,
|
||||
internal::Matcher<CXXRecordDecl>, InnerMatcher) {
|
||||
const CXXRecordDecl *Parent = Node.getParent();
|
||||
return (Parent != NULL &&
|
||||
return (Parent != nullptr &&
|
||||
InnerMatcher.matches(*Parent, Finder, Builder));
|
||||
}
|
||||
|
||||
@ -2603,6 +2740,20 @@ AST_MATCHER(CXXMethodDecl, isVirtual) {
|
||||
return Node.isVirtual();
|
||||
}
|
||||
|
||||
/// \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
|
||||
@ -2822,8 +2973,8 @@ AST_POLYMORPHIC_MATCHER(
|
||||
|
||||
/// \brief Matches \c TypeLocs for which the given inner
|
||||
/// QualType-matcher matches.
|
||||
inline internal::BindableMatcher<TypeLoc> loc(
|
||||
const internal::Matcher<QualType> &InnerMatcher) {
|
||||
AST_MATCHER_FUNCTION_P_OVERLOAD(internal::BindableMatcher<TypeLoc>, loc,
|
||||
internal::Matcher<QualType>, InnerMatcher, 0) {
|
||||
return internal::BindableMatcher<TypeLoc>(
|
||||
new internal::TypeLocTypeMatcher(InnerMatcher));
|
||||
}
|
||||
@ -3306,8 +3457,9 @@ const internal::VariadicAllOfMatcher<
|
||||
|
||||
/// \brief Matches \c NestedNameSpecifierLocs for which the given inner
|
||||
/// NestedNameSpecifier-matcher matches.
|
||||
inline internal::BindableMatcher<NestedNameSpecifierLoc> loc(
|
||||
const internal::Matcher<NestedNameSpecifier> &InnerMatcher) {
|
||||
AST_MATCHER_FUNCTION_P_OVERLOAD(
|
||||
internal::BindableMatcher<NestedNameSpecifierLoc>, loc,
|
||||
internal::Matcher<NestedNameSpecifier>, InnerMatcher, 1) {
|
||||
return internal::BindableMatcher<NestedNameSpecifierLoc>(
|
||||
new internal::LocMatcher<NestedNameSpecifierLoc, NestedNameSpecifier>(
|
||||
InnerMatcher));
|
||||
@ -3325,7 +3477,7 @@ inline internal::BindableMatcher<NestedNameSpecifierLoc> loc(
|
||||
/// matches "A::"
|
||||
AST_MATCHER_P(NestedNameSpecifier, specifiesType,
|
||||
internal::Matcher<QualType>, InnerMatcher) {
|
||||
if (Node.getAsType() == NULL)
|
||||
if (!Node.getAsType())
|
||||
return false;
|
||||
return InnerMatcher.matches(QualType(Node.getAsType(), 0), Finder, Builder);
|
||||
}
|
||||
@ -3343,7 +3495,7 @@ AST_MATCHER_P(NestedNameSpecifier, specifiesType,
|
||||
/// matches "A::"
|
||||
AST_MATCHER_P(NestedNameSpecifierLoc, specifiesTypeLoc,
|
||||
internal::Matcher<TypeLoc>, InnerMatcher) {
|
||||
return InnerMatcher.matches(Node.getTypeLoc(), Finder, Builder);
|
||||
return Node && InnerMatcher.matches(Node.getTypeLoc(), Finder, Builder);
|
||||
}
|
||||
|
||||
/// \brief Matches on the prefix of a \c NestedNameSpecifier.
|
||||
@ -3359,7 +3511,7 @@ AST_MATCHER_P_OVERLOAD(NestedNameSpecifier, hasPrefix,
|
||||
internal::Matcher<NestedNameSpecifier>, InnerMatcher,
|
||||
0) {
|
||||
NestedNameSpecifier *NextNode = Node.getPrefix();
|
||||
if (NextNode == NULL)
|
||||
if (!NextNode)
|
||||
return false;
|
||||
return InnerMatcher.matches(*NextNode, Finder, Builder);
|
||||
}
|
||||
@ -3394,7 +3546,7 @@ AST_MATCHER_P_OVERLOAD(NestedNameSpecifierLoc, hasPrefix,
|
||||
/// matches "ns::"
|
||||
AST_MATCHER_P(NestedNameSpecifier, specifiesNamespace,
|
||||
internal::Matcher<NamespaceDecl>, InnerMatcher) {
|
||||
if (Node.getAsNamespace() == NULL)
|
||||
if (!Node.getAsNamespace())
|
||||
return false;
|
||||
return InnerMatcher.matches(*Node.getAsNamespace(), Finder, Builder);
|
||||
}
|
||||
@ -3406,14 +3558,14 @@ AST_MATCHER_P(NestedNameSpecifier, specifiesNamespace,
|
||||
/// \brief Matches if a node equals another node.
|
||||
///
|
||||
/// \c Decl has pointer identity in the AST.
|
||||
AST_MATCHER_P_OVERLOAD(Decl, equalsNode, Decl*, Other, 0) {
|
||||
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, Stmt*, Other, 1) {
|
||||
AST_MATCHER_P_OVERLOAD(Stmt, equalsNode, const Stmt*, Other, 1) {
|
||||
return &Node == Other;
|
||||
}
|
||||
|
||||
@ -3463,11 +3615,9 @@ AST_MATCHER_P(CXXConstructorDecl, forEachConstructorInitializer,
|
||||
internal::Matcher<CXXCtorInitializer>, InnerMatcher) {
|
||||
BoundNodesTreeBuilder Result;
|
||||
bool Matched = false;
|
||||
for (CXXConstructorDecl::init_const_iterator I = Node.init_begin(),
|
||||
E = Node.init_end();
|
||||
I != E; ++I) {
|
||||
for (const auto *I : Node.inits()) {
|
||||
BoundNodesTreeBuilder InitBuilder(*Builder);
|
||||
if (InnerMatcher.matches(**I, Finder, &InitBuilder)) {
|
||||
if (InnerMatcher.matches(*I, Finder, &InitBuilder)) {
|
||||
Matched = true;
|
||||
Result.addMatch(InitBuilder);
|
||||
}
|
||||
|
@ -44,7 +44,6 @@
|
||||
#include "clang/AST/Type.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/VariadicFunction.h"
|
||||
#include "llvm/Support/type_traits.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@ -52,11 +51,6 @@
|
||||
namespace clang {
|
||||
namespace ast_matchers {
|
||||
|
||||
/// FIXME: Move into the llvm support library.
|
||||
template <bool> struct CompileAssert {};
|
||||
#define TOOLING_COMPILE_ASSERT(Expr, Msg) \
|
||||
typedef CompileAssert<(bool(Expr))> Msg[bool(Expr) ? 1 : -1]
|
||||
|
||||
class BoundNodes;
|
||||
|
||||
namespace internal {
|
||||
@ -80,7 +74,7 @@ class BoundNodesMap {
|
||||
const T *getNodeAs(StringRef ID) const {
|
||||
IDToNodeMap::const_iterator It = NodeMap.find(ID);
|
||||
if (It == NodeMap.end()) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
return It->second.get<T>();
|
||||
}
|
||||
@ -198,9 +192,9 @@ class SingleNodeMatcherInterface : public MatcherInterface<T> {
|
||||
|
||||
private:
|
||||
/// Implements MatcherInterface::Matches.
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder * /* Finder */,
|
||||
BoundNodesTreeBuilder * /* Builder */) const {
|
||||
bool matches(const T &Node,
|
||||
ASTMatchFinder * /* Finder */,
|
||||
BoundNodesTreeBuilder * /* Builder */) const override {
|
||||
return matchesNode(Node);
|
||||
}
|
||||
};
|
||||
@ -225,9 +219,8 @@ class Matcher {
|
||||
/// Requires \c T to be derived from \c From.
|
||||
template <typename From>
|
||||
Matcher(const Matcher<From> &Other,
|
||||
typename llvm::enable_if_c<
|
||||
llvm::is_base_of<From, T>::value &&
|
||||
!llvm::is_same<From, T>::value >::type* = 0)
|
||||
typename std::enable_if<std::is_base_of<From, T>::value &&
|
||||
!std::is_same<From, T>::value>::type * = 0)
|
||||
: Implementation(new ImplicitCastMatcher<From>(Other)) {}
|
||||
|
||||
/// \brief Implicitly converts \c Matcher<Type> to \c Matcher<QualType>.
|
||||
@ -235,9 +228,9 @@ class Matcher {
|
||||
/// The resulting matcher is not strict, i.e. ignores qualifiers.
|
||||
template <typename TypeT>
|
||||
Matcher(const Matcher<TypeT> &Other,
|
||||
typename llvm::enable_if_c<
|
||||
llvm::is_same<T, QualType>::value &&
|
||||
llvm::is_same<TypeT, Type>::value >::type* = 0)
|
||||
typename std::enable_if<
|
||||
std::is_same<T, QualType>::value &&
|
||||
std::is_same<TypeT, Type>::value>::type* = 0)
|
||||
: Implementation(new TypeToQualType<TypeT>(Other)) {}
|
||||
|
||||
/// \brief Forwards the call to the underlying MatcherInterface<T> pointer.
|
||||
@ -257,7 +250,7 @@ class Matcher {
|
||||
uint64_t getID() const {
|
||||
/// FIXME: Document the requirements this imposes on matcher
|
||||
/// implementations (no new() implementation_ during a Matches()).
|
||||
return reinterpret_cast<uint64_t>(Implementation.getPtr());
|
||||
return reinterpret_cast<uint64_t>(Implementation.get());
|
||||
}
|
||||
|
||||
/// \brief Allows the conversion of a \c Matcher<Type> to a \c
|
||||
@ -272,9 +265,8 @@ class Matcher {
|
||||
TypeToQualType(const Matcher<TypeT> &InnerMatcher)
|
||||
: InnerMatcher(InnerMatcher) {}
|
||||
|
||||
virtual bool matches(const QualType &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
bool matches(const QualType &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const override {
|
||||
if (Node.isNull())
|
||||
return false;
|
||||
return InnerMatcher.matches(*Node, Finder, Builder);
|
||||
@ -292,9 +284,8 @@ class Matcher {
|
||||
explicit ImplicitCastMatcher(const Matcher<Base> &From)
|
||||
: From(From) {}
|
||||
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
bool matches(const T &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const override {
|
||||
return From.matches(Node, Finder, Builder);
|
||||
}
|
||||
|
||||
@ -379,9 +370,7 @@ class DynTypedMatcher {
|
||||
/// 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 {
|
||||
return Matcher<T>(new WrappedMatcher<T>(*this));
|
||||
}
|
||||
template <typename T> Matcher<T> unconditionalConvertTo() const;
|
||||
|
||||
private:
|
||||
class MatcherStorage : public RefCountedBaseVPTR {
|
||||
@ -410,9 +399,6 @@ class DynTypedMatcher {
|
||||
/// \brief Typed implementation of \c MatcherStorage.
|
||||
template <typename T> class TypedMatcherStorage;
|
||||
|
||||
/// \brief Simple MatcherInterface<T> wrapper around a DynTypedMatcher.
|
||||
template <typename T> class WrappedMatcher;
|
||||
|
||||
IntrusiveRefCntPtr<const MatcherStorage> Storage;
|
||||
};
|
||||
|
||||
@ -425,15 +411,15 @@ class DynTypedMatcher::TypedMatcherStorage : public MatcherStorage {
|
||||
InnerMatcher(Other), AllowBind(AllowBind) {}
|
||||
|
||||
bool matches(const ast_type_traits::DynTypedNode DynNode,
|
||||
ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const
|
||||
LLVM_OVERRIDE {
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const override {
|
||||
if (const T *Node = DynNode.get<T>()) {
|
||||
return InnerMatcher.matches(*Node, Finder, Builder);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
llvm::Optional<DynTypedMatcher> tryBind(StringRef ID) const LLVM_OVERRIDE {
|
||||
llvm::Optional<DynTypedMatcher> tryBind(StringRef ID) const override {
|
||||
if (!AllowBind)
|
||||
return llvm::Optional<DynTypedMatcher>();
|
||||
return DynTypedMatcher(BindableMatcher<T>(InnerMatcher).bind(ID));
|
||||
@ -452,22 +438,6 @@ template <typename T>
|
||||
inline DynTypedMatcher::DynTypedMatcher(const BindableMatcher<T> &M)
|
||||
: Storage(new TypedMatcherStorage<T>(M, true)) {}
|
||||
|
||||
template <typename T>
|
||||
class DynTypedMatcher::WrappedMatcher : public MatcherInterface<T> {
|
||||
public:
|
||||
explicit WrappedMatcher(const DynTypedMatcher &Matcher) : Inner(Matcher) {}
|
||||
virtual ~WrappedMatcher() {}
|
||||
|
||||
bool matches(const T &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return Inner.matches(ast_type_traits::DynTypedNode::create(Node), Finder,
|
||||
Builder);
|
||||
}
|
||||
|
||||
private:
|
||||
const DynTypedMatcher Inner;
|
||||
};
|
||||
|
||||
/// \brief Specialization of the conversion functions for QualType.
|
||||
///
|
||||
/// These specializations provide the Matcher<Type>->Matcher<QualType>
|
||||
@ -537,7 +507,7 @@ template <typename T> struct has_getDecl {
|
||||
static char (&f(CheckT<int Default::*, &C::getDecl>*))[1];
|
||||
template<typename C> static char (&f(...))[2];
|
||||
|
||||
static bool const value = sizeof(f<Derived>(0)) == 2;
|
||||
static bool const value = sizeof(f<Derived>(nullptr)) == 2;
|
||||
};
|
||||
|
||||
/// \brief Matches overloaded operators with a specific name.
|
||||
@ -546,16 +516,17 @@ template <typename T> struct has_getDecl {
|
||||
/// PolymorphicMatcherWithParam1 and should be StringRef.
|
||||
template <typename T, typename ArgT>
|
||||
class HasOverloadedOperatorNameMatcher : public SingleNodeMatcherInterface<T> {
|
||||
TOOLING_COMPILE_ASSERT((llvm::is_same<T, CXXOperatorCallExpr>::value ||
|
||||
llvm::is_same<T, CXXMethodDecl>::value),
|
||||
unsupported_class_for_matcher);
|
||||
TOOLING_COMPILE_ASSERT((llvm::is_same<ArgT, StringRef>::value),
|
||||
argument_type_must_be_StringRef);
|
||||
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) {}
|
||||
|
||||
virtual bool matchesNode(const T &Node) const LLVM_OVERRIDE {
|
||||
bool matchesNode(const T &Node) const override {
|
||||
return matchesSpecialized(Node);
|
||||
}
|
||||
|
||||
@ -570,7 +541,7 @@ class HasOverloadedOperatorNameMatcher : public SingleNodeMatcherInterface<T> {
|
||||
|
||||
/// \brief Returns true only if CXXMethodDecl represents an overloaded
|
||||
/// operator and has the given operator name.
|
||||
bool matchesSpecialized(const CXXMethodDecl &Node) const {
|
||||
bool matchesSpecialized(const FunctionDecl &Node) const {
|
||||
return Node.isOverloadedOperator() &&
|
||||
getOperatorSpelling(Node.getOverloadedOperator()) == Name;
|
||||
}
|
||||
@ -584,16 +555,15 @@ class HasOverloadedOperatorNameMatcher : public SingleNodeMatcherInterface<T> {
|
||||
/// not actually used.
|
||||
template <typename T, typename DeclMatcherT>
|
||||
class HasDeclarationMatcher : public MatcherInterface<T> {
|
||||
TOOLING_COMPILE_ASSERT((llvm::is_same< DeclMatcherT,
|
||||
Matcher<Decl> >::value),
|
||||
instantiated_with_wrong_types);
|
||||
static_assert(std::is_same<DeclMatcherT, Matcher<Decl>>::value,
|
||||
"instantiated with wrong types");
|
||||
|
||||
public:
|
||||
explicit HasDeclarationMatcher(const Matcher<Decl> &InnerMatcher)
|
||||
: InnerMatcher(InnerMatcher) {}
|
||||
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
bool matches(const T &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const override {
|
||||
return matchesSpecialized(Node, Finder, Builder);
|
||||
}
|
||||
|
||||
@ -603,7 +573,7 @@ class HasDeclarationMatcher : public MatcherInterface<T> {
|
||||
template <typename U>
|
||||
bool matchesSpecialized(
|
||||
const U &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder,
|
||||
typename llvm::enable_if<has_getDecl<U>, int>::type = 0) const {
|
||||
typename std::enable_if<has_getDecl<U>::value, int>::type = 0) const {
|
||||
return matchesDecl(Node.getDecl(), Finder, Builder);
|
||||
}
|
||||
|
||||
@ -656,7 +626,7 @@ class HasDeclarationMatcher : public MatcherInterface<T> {
|
||||
bool matchesDecl(const Decl *Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return Node != NULL && InnerMatcher.matches(*Node, Finder, Builder);
|
||||
return Node != nullptr && InnerMatcher.matches(*Node, Finder, Builder);
|
||||
}
|
||||
|
||||
const Matcher<Decl> InnerMatcher;
|
||||
@ -667,14 +637,14 @@ class HasDeclarationMatcher : public MatcherInterface<T> {
|
||||
template <typename T>
|
||||
struct IsBaseType {
|
||||
static const bool value =
|
||||
(llvm::is_same<T, Decl>::value ||
|
||||
llvm::is_same<T, Stmt>::value ||
|
||||
llvm::is_same<T, QualType>::value ||
|
||||
llvm::is_same<T, Type>::value ||
|
||||
llvm::is_same<T, TypeLoc>::value ||
|
||||
llvm::is_same<T, NestedNameSpecifier>::value ||
|
||||
llvm::is_same<T, NestedNameSpecifierLoc>::value ||
|
||||
llvm::is_same<T, CXXCtorInitializer>::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;
|
||||
@ -740,14 +710,13 @@ class ASTMatchFinder {
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
TraversalKind Traverse,
|
||||
BindKind Bind) {
|
||||
TOOLING_COMPILE_ASSERT(
|
||||
(llvm::is_base_of<Decl, T>::value ||
|
||||
llvm::is_base_of<Stmt, T>::value ||
|
||||
llvm::is_base_of<NestedNameSpecifier, T>::value ||
|
||||
llvm::is_base_of<NestedNameSpecifierLoc, T>::value ||
|
||||
llvm::is_base_of<TypeLoc, T>::value ||
|
||||
llvm::is_base_of<QualType, T>::value),
|
||||
unsupported_type_for_recursive_matching);
|
||||
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);
|
||||
}
|
||||
@ -757,14 +726,13 @@ class ASTMatchFinder {
|
||||
const DynTypedMatcher &Matcher,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
BindKind Bind) {
|
||||
TOOLING_COMPILE_ASSERT(
|
||||
(llvm::is_base_of<Decl, T>::value ||
|
||||
llvm::is_base_of<Stmt, T>::value ||
|
||||
llvm::is_base_of<NestedNameSpecifier, T>::value ||
|
||||
llvm::is_base_of<NestedNameSpecifierLoc, T>::value ||
|
||||
llvm::is_base_of<TypeLoc, T>::value ||
|
||||
llvm::is_base_of<QualType, T>::value),
|
||||
unsupported_type_for_recursive_matching);
|
||||
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);
|
||||
}
|
||||
@ -775,9 +743,9 @@ class ASTMatchFinder {
|
||||
const DynTypedMatcher &Matcher,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
AncestorMatchMode MatchMode) {
|
||||
TOOLING_COMPILE_ASSERT((llvm::is_base_of<Decl, T>::value ||
|
||||
llvm::is_base_of<Stmt, T>::value),
|
||||
only_Decl_or_Stmt_allowed_for_recursive_matching);
|
||||
static_assert(std::is_base_of<Decl, T>::value ||
|
||||
std::is_base_of<Stmt, T>::value,
|
||||
"only Decl or Stmt allowed for recursive matching");
|
||||
return matchesAncestorOf(ast_type_traits::DynTypedNode::create(Node),
|
||||
Matcher, Builder, MatchMode);
|
||||
}
|
||||
@ -820,7 +788,7 @@ struct TypeList {
|
||||
/// \brief The first type on the list.
|
||||
typedef T1 head;
|
||||
|
||||
/// \brief A sub list with the tail. ie everything but the 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.
|
||||
@ -852,7 +820,7 @@ typedef TypeList<> EmptyTypeList;
|
||||
template <typename AnyTypeList, typename T>
|
||||
struct TypeListContainsSuperOf {
|
||||
static const bool value =
|
||||
llvm::is_base_of<typename AnyTypeList::head, T>::value ||
|
||||
std::is_base_of<typename AnyTypeList::head, T>::value ||
|
||||
TypeListContainsSuperOf<typename AnyTypeList::tail, T>::value;
|
||||
};
|
||||
template <typename T>
|
||||
@ -952,8 +920,8 @@ class PolymorphicMatcherWithParam0 {
|
||||
typedef typename ExtractFunctionArgMeta<ReturnTypesF>::type ReturnTypes;
|
||||
template <typename T>
|
||||
operator Matcher<T>() const {
|
||||
TOOLING_COMPILE_ASSERT((TypeListContainsSuperOf<ReturnTypes, T>::value),
|
||||
right_polymorphic_conversion);
|
||||
static_assert(TypeListContainsSuperOf<ReturnTypes, T>::value,
|
||||
"right polymorphic conversion");
|
||||
return Matcher<T>(new MatcherT<T>());
|
||||
}
|
||||
};
|
||||
@ -970,8 +938,8 @@ class PolymorphicMatcherWithParam1 {
|
||||
|
||||
template <typename T>
|
||||
operator Matcher<T>() const {
|
||||
TOOLING_COMPILE_ASSERT((TypeListContainsSuperOf<ReturnTypes, T>::value),
|
||||
right_polymorphic_conversion);
|
||||
static_assert(TypeListContainsSuperOf<ReturnTypes, T>::value,
|
||||
"right polymorphic conversion");
|
||||
return Matcher<T>(new MatcherT<T, P1>(Param1));
|
||||
}
|
||||
|
||||
@ -991,8 +959,8 @@ class PolymorphicMatcherWithParam2 {
|
||||
|
||||
template <typename T>
|
||||
operator Matcher<T>() const {
|
||||
TOOLING_COMPILE_ASSERT((TypeListContainsSuperOf<ReturnTypes, T>::value),
|
||||
right_polymorphic_conversion);
|
||||
static_assert(TypeListContainsSuperOf<ReturnTypes, T>::value,
|
||||
"right polymorphic conversion");
|
||||
return Matcher<T>(new MatcherT<T, P1, P2>(Param1, Param2));
|
||||
}
|
||||
|
||||
@ -1018,7 +986,7 @@ class PolymorphicMatcherWithParam2 {
|
||||
template <typename T>
|
||||
class TrueMatcher : public SingleNodeMatcherInterface<T> {
|
||||
public:
|
||||
virtual bool matchesNode(const T &Node) const {
|
||||
bool matchesNode(const T &Node) const override {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@ -1033,9 +1001,8 @@ class IdMatcher : public MatcherInterface<T> {
|
||||
IdMatcher(StringRef ID, const Matcher<T> &InnerMatcher)
|
||||
: ID(ID), InnerMatcher(InnerMatcher) {}
|
||||
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
bool matches(const T &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const override {
|
||||
bool Result = InnerMatcher.matches(Node, Finder, Builder);
|
||||
if (Result) {
|
||||
Builder->setBinding(ID, &Node);
|
||||
@ -1074,15 +1041,15 @@ class BindableMatcher : public Matcher<T> {
|
||||
/// ChildT must be an AST base type.
|
||||
template <typename T, typename ChildT>
|
||||
class HasMatcher : public MatcherInterface<T> {
|
||||
TOOLING_COMPILE_ASSERT(IsBaseType<ChildT>::value,
|
||||
has_only_accepts_base_type_matcher);
|
||||
static_assert(IsBaseType<ChildT>::value,
|
||||
"has only accepts base type matcher");
|
||||
|
||||
public:
|
||||
explicit HasMatcher(const Matcher<ChildT> &ChildMatcher)
|
||||
: ChildMatcher(ChildMatcher) {}
|
||||
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
bool matches(const T &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const override {
|
||||
return Finder->matchesChildOf(
|
||||
Node, ChildMatcher, Builder,
|
||||
ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses,
|
||||
@ -1100,15 +1067,15 @@ class HasMatcher : public MatcherInterface<T> {
|
||||
/// for each child that matches.
|
||||
template <typename T, typename ChildT>
|
||||
class ForEachMatcher : public MatcherInterface<T> {
|
||||
TOOLING_COMPILE_ASSERT(IsBaseType<ChildT>::value,
|
||||
for_each_only_accepts_base_type_matcher);
|
||||
static_assert(IsBaseType<ChildT>::value,
|
||||
"for each only accepts base type matcher");
|
||||
|
||||
public:
|
||||
explicit ForEachMatcher(const Matcher<ChildT> &ChildMatcher)
|
||||
: ChildMatcher(ChildMatcher) {}
|
||||
|
||||
virtual bool matches(const T& Node,
|
||||
ASTMatchFinder* Finder,
|
||||
BoundNodesTreeBuilder* Builder) const {
|
||||
bool matches(const T& Node, ASTMatchFinder* Finder,
|
||||
BoundNodesTreeBuilder* Builder) const override {
|
||||
return Finder->matchesChildOf(
|
||||
Node, ChildMatcher, Builder,
|
||||
ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses,
|
||||
@ -1119,38 +1086,6 @@ class ForEachMatcher : public MatcherInterface<T> {
|
||||
const Matcher<ChildT> ChildMatcher;
|
||||
};
|
||||
|
||||
/// \brief Matches nodes of type T if the given Matcher<T> does not match.
|
||||
///
|
||||
/// Type argument MatcherT is required by PolymorphicMatcherWithParam1
|
||||
/// but not actually used. It will always be instantiated with a type
|
||||
/// convertible to Matcher<T>.
|
||||
template <typename T, typename MatcherT>
|
||||
class NotMatcher : public MatcherInterface<T> {
|
||||
public:
|
||||
explicit NotMatcher(const Matcher<T> &InnerMatcher)
|
||||
: InnerMatcher(InnerMatcher) {}
|
||||
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
// The 'unless' matcher will always discard the result:
|
||||
// If the inner matcher doesn't match, unless returns true,
|
||||
// but the inner matcher cannot have bound anything.
|
||||
// If the inner matcher matches, the result is false, and
|
||||
// any possible binding will be discarded.
|
||||
// We still need to hand in all the bound nodes up to this
|
||||
// point so the inner matcher can depend on bound nodes,
|
||||
// and we need to actively discard the bound nodes, otherwise
|
||||
// the inner matcher will reset the bound nodes if it doesn't
|
||||
// match, but this would be inversed by 'unless'.
|
||||
BoundNodesTreeBuilder Discard(*Builder);
|
||||
return !InnerMatcher.matches(Node, Finder, &Discard);
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<T> InnerMatcher;
|
||||
};
|
||||
|
||||
/// \brief VariadicOperatorMatcher related types.
|
||||
/// @{
|
||||
|
||||
@ -1165,22 +1100,18 @@ template <typename T>
|
||||
class VariadicOperatorMatcherInterface : public MatcherInterface<T> {
|
||||
public:
|
||||
VariadicOperatorMatcherInterface(VariadicOperatorFunction Func,
|
||||
ArrayRef<const Matcher<T> *> InputMatchers)
|
||||
: Func(Func) {
|
||||
for (size_t i = 0, e = InputMatchers.size(); i != e; ++i) {
|
||||
InnerMatchers.push_back(*InputMatchers[i]);
|
||||
}
|
||||
}
|
||||
std::vector<DynTypedMatcher> InnerMatchers)
|
||||
: Func(Func), InnerMatchers(std::move(InnerMatchers)) {}
|
||||
|
||||
virtual bool matches(const T &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
bool matches(const T &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const override {
|
||||
return Func(ast_type_traits::DynTypedNode::create(Node), Finder, Builder,
|
||||
InnerMatchers);
|
||||
}
|
||||
|
||||
private:
|
||||
const VariadicOperatorFunction Func;
|
||||
std::vector<DynTypedMatcher> InnerMatchers;
|
||||
const std::vector<DynTypedMatcher> InnerMatchers;
|
||||
};
|
||||
|
||||
/// \brief "No argument" placeholder to use as template paratemers.
|
||||
@ -1192,46 +1123,55 @@ struct VariadicOperatorNoArg {};
|
||||
/// 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 P1, typename P2,
|
||||
template <typename P1, typename P2 = VariadicOperatorNoArg,
|
||||
typename P3 = VariadicOperatorNoArg,
|
||||
typename P4 = VariadicOperatorNoArg,
|
||||
typename P5 = VariadicOperatorNoArg>
|
||||
typename P5 = VariadicOperatorNoArg,
|
||||
typename P6 = VariadicOperatorNoArg,
|
||||
typename P7 = VariadicOperatorNoArg,
|
||||
typename P8 = VariadicOperatorNoArg,
|
||||
typename P9 = VariadicOperatorNoArg>
|
||||
class VariadicOperatorMatcher {
|
||||
public:
|
||||
VariadicOperatorMatcher(VariadicOperatorFunction Func, const P1 &Param1,
|
||||
const P2 &Param2,
|
||||
const P2 &Param2 = VariadicOperatorNoArg(),
|
||||
const P3 &Param3 = VariadicOperatorNoArg(),
|
||||
const P4 &Param4 = VariadicOperatorNoArg(),
|
||||
const P5 &Param5 = VariadicOperatorNoArg())
|
||||
const P5 &Param5 = VariadicOperatorNoArg(),
|
||||
const P6 &Param6 = VariadicOperatorNoArg(),
|
||||
const P7 &Param7 = VariadicOperatorNoArg(),
|
||||
const P8 &Param8 = VariadicOperatorNoArg(),
|
||||
const P9 &Param9 = VariadicOperatorNoArg())
|
||||
: Func(Func), Param1(Param1), Param2(Param2), Param3(Param3),
|
||||
Param4(Param4), Param5(Param5) {}
|
||||
Param4(Param4), Param5(Param5), Param6(Param6), Param7(Param7),
|
||||
Param8(Param8), Param9(Param9) {}
|
||||
|
||||
template <typename T> operator Matcher<T>() const {
|
||||
Matcher<T> *Array[5];
|
||||
size_t Size = 0;
|
||||
|
||||
addMatcher<T>(Param1, Array, Size);
|
||||
addMatcher<T>(Param2, Array, Size);
|
||||
addMatcher<T>(Param3, Array, Size);
|
||||
addMatcher<T>(Param4, Array, Size);
|
||||
addMatcher<T>(Param5, Array, Size);
|
||||
Matcher<T> Result(new VariadicOperatorMatcherInterface<T>(
|
||||
Func, ArrayRef<const Matcher<T> *>(Array, Size)));
|
||||
for (size_t i = 0, e = Size; i != e; ++i) delete Array[i];
|
||||
return Result;
|
||||
std::vector<DynTypedMatcher> Matchers;
|
||||
addMatcher<T>(Param1, Matchers);
|
||||
addMatcher<T>(Param2, Matchers);
|
||||
addMatcher<T>(Param3, Matchers);
|
||||
addMatcher<T>(Param4, Matchers);
|
||||
addMatcher<T>(Param5, Matchers);
|
||||
addMatcher<T>(Param6, Matchers);
|
||||
addMatcher<T>(Param7, Matchers);
|
||||
addMatcher<T>(Param8, Matchers);
|
||||
addMatcher<T>(Param9, Matchers);
|
||||
return Matcher<T>(
|
||||
new VariadicOperatorMatcherInterface<T>(Func, std::move(Matchers)));
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
static void addMatcher(const Matcher<T> &M, Matcher<T> **Array,
|
||||
size_t &Size) {
|
||||
Array[Size++] = new Matcher<T>(M);
|
||||
static void addMatcher(const Matcher<T> &M,
|
||||
std::vector<DynTypedMatcher> &Matchers) {
|
||||
Matchers.push_back(M);
|
||||
}
|
||||
|
||||
/// \brief Overload to ignore \c VariadicOperatorNoArg arguments.
|
||||
template <typename T>
|
||||
static void addMatcher(VariadicOperatorNoArg, Matcher<T> **Array,
|
||||
size_t &Size) {}
|
||||
static void addMatcher(VariadicOperatorNoArg,
|
||||
std::vector<DynTypedMatcher> &Matchers) {}
|
||||
|
||||
const VariadicOperatorFunction Func;
|
||||
const P1 Param1;
|
||||
@ -1239,40 +1179,100 @@ class VariadicOperatorMatcher {
|
||||
const P3 Param3;
|
||||
const P4 Param4;
|
||||
const P5 Param5;
|
||||
const P6 Param6;
|
||||
const P7 Param7;
|
||||
const P8 Param8;
|
||||
const P9 Param9;
|
||||
};
|
||||
|
||||
/// \brief Overloaded function object to generate VariadicOperatorMatcher
|
||||
/// objects from arbitrary matchers.
|
||||
///
|
||||
/// It supports 2-5 argument overloaded operator(). More can be added if needed.
|
||||
/// It supports 1-9 argument overloaded operator(). More can be added if needed.
|
||||
template <unsigned MinCount, unsigned MaxCount>
|
||||
struct VariadicOperatorMatcherFunc {
|
||||
VariadicOperatorFunction Func;
|
||||
|
||||
template <unsigned Count, typename T>
|
||||
struct EnableIfValidArity
|
||||
: public std::enable_if<MinCount <= Count && Count <= MaxCount, T> {};
|
||||
|
||||
template <typename M1>
|
||||
typename EnableIfValidArity<1, VariadicOperatorMatcher<M1> >::type
|
||||
operator()(const M1 &P1) const {
|
||||
return VariadicOperatorMatcher<M1>(Func, P1);
|
||||
}
|
||||
template <typename M1, typename M2>
|
||||
VariadicOperatorMatcher<M1, M2> operator()(const M1 &P1, const M2 &P2) const {
|
||||
typename EnableIfValidArity<2, VariadicOperatorMatcher<M1, M2> >::type
|
||||
operator()(const M1 &P1, const M2 &P2) const {
|
||||
return VariadicOperatorMatcher<M1, M2>(Func, P1, P2);
|
||||
}
|
||||
template <typename M1, typename M2, typename M3>
|
||||
VariadicOperatorMatcher<M1, M2, M3> operator()(const M1 &P1, const M2 &P2,
|
||||
const M3 &P3) const {
|
||||
typename EnableIfValidArity<3, VariadicOperatorMatcher<M1, M2, M3> >::type
|
||||
operator()(const M1 &P1, const M2 &P2, const M3 &P3) const {
|
||||
return VariadicOperatorMatcher<M1, M2, M3>(Func, P1, P2, P3);
|
||||
}
|
||||
template <typename M1, typename M2, typename M3, typename M4>
|
||||
VariadicOperatorMatcher<M1, M2, M3, M4>
|
||||
typename EnableIfValidArity<4, VariadicOperatorMatcher<M1, M2, M3, M4> >::type
|
||||
operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4) const {
|
||||
return VariadicOperatorMatcher<M1, M2, M3, M4>(Func, P1, P2, P3, P4);
|
||||
}
|
||||
template <typename M1, typename M2, typename M3, typename M4, typename M5>
|
||||
VariadicOperatorMatcher<M1, M2, M3, M4, M5>
|
||||
typename EnableIfValidArity<
|
||||
5, VariadicOperatorMatcher<M1, M2, M3, M4, M5> >::type
|
||||
operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4,
|
||||
const M5 &P5) const {
|
||||
return VariadicOperatorMatcher<M1, M2, M3, M4, M5>(Func, P1, P2, P3, P4,
|
||||
P5);
|
||||
}
|
||||
template <typename M1, typename M2, typename M3, typename M4, typename M5,
|
||||
typename M6>
|
||||
typename EnableIfValidArity<
|
||||
6, VariadicOperatorMatcher<M1, M2, M3, M4, M5, M6> >::type
|
||||
operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4,
|
||||
const M5 &P5, const M6 &P6) const {
|
||||
return VariadicOperatorMatcher<M1, M2, M3, M4, M5, M6>(
|
||||
Func, P1, P2, P3, P4, P5, P6);
|
||||
}
|
||||
template <typename M1, typename M2, typename M3, typename M4, typename M5,
|
||||
typename M6, typename M7>
|
||||
typename EnableIfValidArity<
|
||||
7, VariadicOperatorMatcher<M1, M2, M3, M4, M5, M6, M7> >::type
|
||||
operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4,
|
||||
const M5 &P5, const M6 &P6, const M7 &P7) const {
|
||||
return VariadicOperatorMatcher<M1, M2, M3, M4, M5, M6, M7>(
|
||||
Func, P1, P2, P3, P4, P5, P6, P7);
|
||||
}
|
||||
template <typename M1, typename M2, typename M3, typename M4, typename M5,
|
||||
typename M6, typename M7, typename M8>
|
||||
typename EnableIfValidArity<
|
||||
8, VariadicOperatorMatcher<M1, M2, M3, M4, M5, M6, M7, M8> >::type
|
||||
operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4,
|
||||
const M5 &P5, const M6 &P6, const M7 &P7, const M8 &P8) const {
|
||||
return VariadicOperatorMatcher<M1, M2, M3, M4, M5, M6, M7, M8>(
|
||||
Func, P1, P2, P3, P4, P5, P6, P7, P8);
|
||||
}
|
||||
template <typename M1, typename M2, typename M3, typename M4, typename M5,
|
||||
typename M6, typename M7, typename M8, typename M9>
|
||||
typename EnableIfValidArity<
|
||||
9, VariadicOperatorMatcher<M1, M2, M3, M4, M5, M6, M7, M8, M9> >::type
|
||||
operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4,
|
||||
const M5 &P5, const M6 &P6, const M7 &P7, const M8 &P8,
|
||||
const M9 &P9) const {
|
||||
return VariadicOperatorMatcher<M1, M2, M3, M4, M5, M6, M7, M8, M9>(
|
||||
Func, P1, P2, P3, P4, P5, P6, P7, P8, P9);
|
||||
}
|
||||
};
|
||||
|
||||
/// @}
|
||||
|
||||
/// \brief Matches nodes that do not match the provided matcher.
|
||||
///
|
||||
/// Uses the variadic matcher interface, but fails if InnerMatchers.size()!=1.
|
||||
bool NotUnaryOperator(const ast_type_traits::DynTypedNode DynNode,
|
||||
ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder,
|
||||
ArrayRef<DynTypedMatcher> InnerMatchers);
|
||||
|
||||
/// \brief Matches nodes for which all provided matchers match.
|
||||
bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
|
||||
ASTMatchFinder *Finder,
|
||||
@ -1293,12 +1293,22 @@ bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
ArrayRef<DynTypedMatcher> InnerMatchers);
|
||||
|
||||
template <typename T>
|
||||
inline Matcher<T> DynTypedMatcher::unconditionalConvertTo() const {
|
||||
return Matcher<T>(new VariadicOperatorMatcherInterface<T>(
|
||||
AllOfVariadicOperator, llvm::makeArrayRef(*this)));
|
||||
}
|
||||
|
||||
/// \brief Creates a Matcher<T> that matches if all inner matchers match.
|
||||
template<typename T>
|
||||
BindableMatcher<T> makeAllOfComposite(
|
||||
ArrayRef<const Matcher<T> *> InnerMatchers) {
|
||||
std::vector<DynTypedMatcher> DynMatchers;
|
||||
for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) {
|
||||
DynMatchers.push_back(*InnerMatchers[i]);
|
||||
}
|
||||
return BindableMatcher<T>(new VariadicOperatorMatcherInterface<T>(
|
||||
AllOfVariadicOperator, InnerMatchers));
|
||||
AllOfVariadicOperator, std::move(DynMatchers)));
|
||||
}
|
||||
|
||||
/// \brief Creates a Matcher<T> that matches if
|
||||
@ -1320,15 +1330,15 @@ BindableMatcher<T> makeDynCastAllOfComposite(
|
||||
/// DescendantT must be an AST base type.
|
||||
template <typename T, typename DescendantT>
|
||||
class HasDescendantMatcher : public MatcherInterface<T> {
|
||||
TOOLING_COMPILE_ASSERT(IsBaseType<DescendantT>::value,
|
||||
has_descendant_only_accepts_base_type_matcher);
|
||||
static_assert(IsBaseType<DescendantT>::value,
|
||||
"has descendant only accepts base type matcher");
|
||||
|
||||
public:
|
||||
explicit HasDescendantMatcher(const Matcher<DescendantT> &DescendantMatcher)
|
||||
: DescendantMatcher(DescendantMatcher) {}
|
||||
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
bool matches(const T &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const override {
|
||||
return Finder->matchesDescendantOf(
|
||||
Node, DescendantMatcher, Builder, ASTMatchFinder::BK_First);
|
||||
}
|
||||
@ -1343,15 +1353,15 @@ class HasDescendantMatcher : public MatcherInterface<T> {
|
||||
/// \c ParentT must be an AST base type.
|
||||
template <typename T, typename ParentT>
|
||||
class HasParentMatcher : public MatcherInterface<T> {
|
||||
TOOLING_COMPILE_ASSERT(IsBaseType<ParentT>::value,
|
||||
has_parent_only_accepts_base_type_matcher);
|
||||
static_assert(IsBaseType<ParentT>::value,
|
||||
"has parent only accepts base type matcher");
|
||||
|
||||
public:
|
||||
explicit HasParentMatcher(const Matcher<ParentT> &ParentMatcher)
|
||||
: ParentMatcher(ParentMatcher) {}
|
||||
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
bool matches(const T &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const override {
|
||||
return Finder->matchesAncestorOf(
|
||||
Node, ParentMatcher, Builder, ASTMatchFinder::AMM_ParentOnly);
|
||||
}
|
||||
@ -1366,15 +1376,15 @@ class HasParentMatcher : public MatcherInterface<T> {
|
||||
/// \c AncestorT must be an AST base type.
|
||||
template <typename T, typename AncestorT>
|
||||
class HasAncestorMatcher : public MatcherInterface<T> {
|
||||
TOOLING_COMPILE_ASSERT(IsBaseType<AncestorT>::value,
|
||||
has_ancestor_only_accepts_base_type_matcher);
|
||||
static_assert(IsBaseType<AncestorT>::value,
|
||||
"has ancestor only accepts base type matcher");
|
||||
|
||||
public:
|
||||
explicit HasAncestorMatcher(const Matcher<AncestorT> &AncestorMatcher)
|
||||
: AncestorMatcher(AncestorMatcher) {}
|
||||
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
bool matches(const T &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const override {
|
||||
return Finder->matchesAncestorOf(
|
||||
Node, AncestorMatcher, Builder, ASTMatchFinder::AMM_All);
|
||||
}
|
||||
@ -1391,16 +1401,16 @@ class HasAncestorMatcher : public MatcherInterface<T> {
|
||||
/// for each descendant node that matches instead of only for the first.
|
||||
template <typename T, typename DescendantT>
|
||||
class ForEachDescendantMatcher : public MatcherInterface<T> {
|
||||
TOOLING_COMPILE_ASSERT(IsBaseType<DescendantT>::value,
|
||||
for_each_descendant_only_accepts_base_type_matcher);
|
||||
static_assert(IsBaseType<DescendantT>::value,
|
||||
"for each descendant only accepts base type matcher");
|
||||
|
||||
public:
|
||||
explicit ForEachDescendantMatcher(
|
||||
const Matcher<DescendantT>& DescendantMatcher)
|
||||
: DescendantMatcher(DescendantMatcher) {}
|
||||
|
||||
virtual bool matches(const T& Node,
|
||||
ASTMatchFinder* Finder,
|
||||
BoundNodesTreeBuilder* Builder) const {
|
||||
bool matches(const T& Node, ASTMatchFinder* Finder,
|
||||
BoundNodesTreeBuilder* Builder) const override {
|
||||
return Finder->matchesDescendantOf(Node, DescendantMatcher, Builder,
|
||||
ASTMatchFinder::BK_All);
|
||||
}
|
||||
@ -1413,17 +1423,17 @@ class ForEachDescendantMatcher : public MatcherInterface<T> {
|
||||
/// the value the ValueEqualsMatcher was constructed with.
|
||||
template <typename T, typename ValueT>
|
||||
class ValueEqualsMatcher : public SingleNodeMatcherInterface<T> {
|
||||
TOOLING_COMPILE_ASSERT((llvm::is_base_of<CharacterLiteral, T>::value ||
|
||||
llvm::is_base_of<CXXBoolLiteralExpr,
|
||||
T>::value ||
|
||||
llvm::is_base_of<FloatingLiteral, T>::value ||
|
||||
llvm::is_base_of<IntegerLiteral, T>::value),
|
||||
the_node_must_have_a_getValue_method);
|
||||
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) {}
|
||||
|
||||
virtual bool matchesNode(const T &Node) const {
|
||||
bool matchesNode(const T &Node) const override {
|
||||
return Node.getValue() == ExpectedValue;
|
||||
}
|
||||
|
||||
@ -1478,9 +1488,8 @@ class LocMatcher : public MatcherInterface<TLoc> {
|
||||
explicit LocMatcher(const Matcher<T> &InnerMatcher)
|
||||
: InnerMatcher(InnerMatcher) {}
|
||||
|
||||
virtual bool matches(const TLoc &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
bool matches(const TLoc &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const override {
|
||||
if (!Node)
|
||||
return false;
|
||||
return InnerMatcher.matches(*extract(Node), Finder, Builder);
|
||||
@ -1503,9 +1512,8 @@ class TypeLocTypeMatcher : public MatcherInterface<TypeLoc> {
|
||||
explicit TypeLocTypeMatcher(const Matcher<QualType> &InnerMatcher)
|
||||
: InnerMatcher(InnerMatcher) {}
|
||||
|
||||
virtual bool matches(const TypeLoc &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
bool matches(const TypeLoc &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const override {
|
||||
if (!Node)
|
||||
return false;
|
||||
return InnerMatcher.matches(Node.getType(), Finder, Builder);
|
||||
@ -1525,9 +1533,8 @@ class TypeTraverseMatcher : public MatcherInterface<T> {
|
||||
QualType (T::*TraverseFunction)() const)
|
||||
: InnerMatcher(InnerMatcher), TraverseFunction(TraverseFunction) {}
|
||||
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
bool matches(const T &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const override {
|
||||
QualType NextNode = (Node.*TraverseFunction)();
|
||||
if (NextNode.isNull())
|
||||
return false;
|
||||
@ -1549,9 +1556,8 @@ class TypeLocTraverseMatcher : public MatcherInterface<T> {
|
||||
TypeLoc (T::*TraverseFunction)() const)
|
||||
: InnerMatcher(InnerMatcher), TraverseFunction(TraverseFunction) {}
|
||||
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
bool matches(const T &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const override {
|
||||
TypeLoc NextNode = (Node.*TraverseFunction)();
|
||||
if (!NextNode)
|
||||
return false;
|
||||
@ -1612,6 +1618,26 @@ TypeTraversePolymorphicMatcher<
|
||||
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 ArrayRef<TemplateArgument>(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
|
||||
|
@ -37,6 +37,25 @@
|
||||
#ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H
|
||||
#define LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H
|
||||
|
||||
/// \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.
|
||||
@ -53,8 +72,8 @@
|
||||
class matcher_##DefineMatcher##Matcher : public MatcherInterface<Type> { \
|
||||
public: \
|
||||
explicit matcher_##DefineMatcher##Matcher() {} \
|
||||
virtual bool matches(const Type &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const; \
|
||||
bool matches(const Type &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const override; \
|
||||
}; \
|
||||
} \
|
||||
inline internal::Matcher<Type> DefineMatcher() { \
|
||||
@ -88,21 +107,21 @@
|
||||
: public MatcherInterface<Type> { \
|
||||
public: \
|
||||
explicit matcher_##DefineMatcher##OverloadId##Matcher( \
|
||||
const ParamType &A##Param) \
|
||||
ParamType const &A##Param) \
|
||||
: Param(A##Param) {} \
|
||||
virtual bool matches(const Type &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const; \
|
||||
bool matches(const Type &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const override; \
|
||||
\
|
||||
private: \
|
||||
const ParamType Param; \
|
||||
ParamType const Param; \
|
||||
}; \
|
||||
} \
|
||||
inline internal::Matcher<Type> DefineMatcher(const ParamType &Param) { \
|
||||
inline internal::Matcher<Type> DefineMatcher(ParamType const &Param) { \
|
||||
return internal::makeMatcher( \
|
||||
new internal::matcher_##DefineMatcher##OverloadId##Matcher(Param)); \
|
||||
} \
|
||||
typedef internal::Matcher<Type>(&DefineMatcher##_Type##OverloadId)( \
|
||||
const ParamType &Param); \
|
||||
ParamType const &Param); \
|
||||
inline bool internal::matcher_##DefineMatcher##OverloadId##Matcher::matches( \
|
||||
const Type &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const
|
||||
@ -132,25 +151,25 @@
|
||||
class matcher_##DefineMatcher##OverloadId##Matcher \
|
||||
: public MatcherInterface<Type> { \
|
||||
public: \
|
||||
matcher_##DefineMatcher##OverloadId##Matcher(const ParamType1 &A##Param1, \
|
||||
const ParamType2 &A##Param2) \
|
||||
matcher_##DefineMatcher##OverloadId##Matcher(ParamType1 const &A##Param1, \
|
||||
ParamType2 const &A##Param2) \
|
||||
: Param1(A##Param1), Param2(A##Param2) {} \
|
||||
virtual bool matches(const Type &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const; \
|
||||
bool matches(const Type &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const override; \
|
||||
\
|
||||
private: \
|
||||
const ParamType1 Param1; \
|
||||
const ParamType2 Param2; \
|
||||
ParamType1 const Param1; \
|
||||
ParamType2 const Param2; \
|
||||
}; \
|
||||
} \
|
||||
inline internal::Matcher<Type> DefineMatcher(const ParamType1 &Param1, \
|
||||
const ParamType2 &Param2) { \
|
||||
inline internal::Matcher<Type> DefineMatcher(ParamType1 const &Param1, \
|
||||
ParamType2 const &Param2) { \
|
||||
return internal::makeMatcher( \
|
||||
new internal::matcher_##DefineMatcher##OverloadId##Matcher(Param1, \
|
||||
Param2)); \
|
||||
} \
|
||||
typedef internal::Matcher<Type>(&DefineMatcher##_Type##OverloadId)( \
|
||||
const ParamType1 &Param1, const ParamType2 &Param2); \
|
||||
ParamType1 const &Param1, ParamType2 const &Param2); \
|
||||
inline bool internal::matcher_##DefineMatcher##OverloadId##Matcher::matches( \
|
||||
const Type &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const
|
||||
@ -184,8 +203,8 @@
|
||||
template <typename NodeType> \
|
||||
class matcher_##DefineMatcher##Matcher : public MatcherInterface<NodeType> { \
|
||||
public: \
|
||||
virtual bool matches(const NodeType &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const; \
|
||||
bool matches(const NodeType &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const override; \
|
||||
}; \
|
||||
} \
|
||||
inline internal::PolymorphicMatcherWithParam0< \
|
||||
@ -221,18 +240,18 @@
|
||||
: public MatcherInterface<NodeType> { \
|
||||
public: \
|
||||
explicit matcher_##DefineMatcher##OverloadId##Matcher( \
|
||||
const ParamType &A##Param) \
|
||||
ParamType const &A##Param) \
|
||||
: Param(A##Param) {} \
|
||||
virtual bool matches(const NodeType &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const; \
|
||||
bool matches(const NodeType &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const override; \
|
||||
\
|
||||
private: \
|
||||
const ParamType Param; \
|
||||
ParamType const Param; \
|
||||
}; \
|
||||
} \
|
||||
inline internal::PolymorphicMatcherWithParam1< \
|
||||
internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType, \
|
||||
ReturnTypesF> DefineMatcher(const ParamType &Param) { \
|
||||
ReturnTypesF> DefineMatcher(ParamType const &Param) { \
|
||||
return internal::PolymorphicMatcherWithParam1< \
|
||||
internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType, \
|
||||
ReturnTypesF>(Param); \
|
||||
@ -240,7 +259,7 @@
|
||||
typedef internal::PolymorphicMatcherWithParam1< \
|
||||
internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType, \
|
||||
ReturnTypesF>(&DefineMatcher##_Type##OverloadId)( \
|
||||
const ParamType &Param); \
|
||||
ParamType const &Param); \
|
||||
template <typename NodeType, typename ParamT> \
|
||||
bool internal::matcher_##DefineMatcher##OverloadId##Matcher< \
|
||||
NodeType, ParamT>::matches(const NodeType &Node, ASTMatchFinder *Finder, \
|
||||
@ -267,21 +286,21 @@
|
||||
class matcher_##DefineMatcher##OverloadId##Matcher \
|
||||
: public MatcherInterface<NodeType> { \
|
||||
public: \
|
||||
matcher_##DefineMatcher##OverloadId##Matcher(const ParamType1 &A##Param1, \
|
||||
const ParamType2 &A##Param2) \
|
||||
matcher_##DefineMatcher##OverloadId##Matcher(ParamType1 const &A##Param1, \
|
||||
ParamType2 const &A##Param2) \
|
||||
: Param1(A##Param1), Param2(A##Param2) {} \
|
||||
virtual bool matches(const NodeType &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const; \
|
||||
bool matches(const NodeType &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const override; \
|
||||
\
|
||||
private: \
|
||||
const ParamType1 Param1; \
|
||||
const ParamType2 Param2; \
|
||||
ParamType1 const Param1; \
|
||||
ParamType2 const Param2; \
|
||||
}; \
|
||||
} \
|
||||
inline internal::PolymorphicMatcherWithParam2< \
|
||||
internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType1, \
|
||||
ParamType2, ReturnTypesF> DefineMatcher(const ParamType1 &Param1, \
|
||||
const ParamType2 &Param2) { \
|
||||
ParamType2, ReturnTypesF> DefineMatcher(ParamType1 const &Param1, \
|
||||
ParamType2 const &Param2) { \
|
||||
return internal::PolymorphicMatcherWithParam2< \
|
||||
internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType1, \
|
||||
ParamType2, ReturnTypesF>(Param1, Param2); \
|
||||
@ -289,7 +308,7 @@
|
||||
typedef internal::PolymorphicMatcherWithParam2< \
|
||||
internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType1, \
|
||||
ParamType2, ReturnTypesF>(&DefineMatcher##_Type##OverloadId)( \
|
||||
const ParamType1 &Param1, const ParamType2 &Param2); \
|
||||
ParamType1 const &Param1, ParamType2 const &Param2); \
|
||||
template <typename NodeType, typename ParamT1, typename ParamT2> \
|
||||
bool internal::matcher_##DefineMatcher##OverloadId##Matcher< \
|
||||
NodeType, ParamT1, ParamT2>::matches( \
|
||||
|
@ -15,15 +15,14 @@
|
||||
#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_DIAGNOSTICS_H
|
||||
#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_DIAGNOSTICS_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#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 {
|
||||
@ -61,11 +60,12 @@ class Diagnostics {
|
||||
enum ErrorType {
|
||||
ET_None = 0,
|
||||
|
||||
ET_RegistryNotFound = 1,
|
||||
ET_RegistryMatcherNotFound = 1,
|
||||
ET_RegistryWrongArgCount = 2,
|
||||
ET_RegistryWrongArgType = 3,
|
||||
ET_RegistryNotBindable = 4,
|
||||
ET_RegistryAmbiguousOverload = 5,
|
||||
ET_RegistryValueNotFound = 6,
|
||||
|
||||
ET_ParserStringError = 100,
|
||||
ET_ParserNoOpenParen = 101,
|
||||
|
@ -18,13 +18,14 @@
|
||||
///
|
||||
/// \code
|
||||
/// Grammar for the expressions supported:
|
||||
/// <Expression> := <Literal> | <MatcherExpression>
|
||||
/// <Expression> := <Literal> | <NamedValue> | <MatcherExpression>
|
||||
/// <Literal> := <StringLiteral> | <Unsigned>
|
||||
/// <StringLiteral> := "quoted string"
|
||||
/// <Unsigned> := [0-9]+
|
||||
/// <MatcherExpression> := <MatcherName>(<ArgumentList>) |
|
||||
/// <MatcherName>(<ArgumentList>).bind(<StringLiteral>)
|
||||
/// <MatcherName> := [a-zA-Z]+
|
||||
/// <NamedValue> := <Identifier>
|
||||
/// <MatcherExpression> := <Identifier>(<ArgumentList>) |
|
||||
/// <Identifier>(<ArgumentList>).bind(<StringLiteral>)
|
||||
/// <Identifier> := [a-zA-Z]+
|
||||
/// <ArgumentList> := <Expression> | <Expression>,<ArgumentList>
|
||||
/// \endcode
|
||||
///
|
||||
@ -34,6 +35,7 @@
|
||||
#define LLVM_CLANG_AST_MATCHERS_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"
|
||||
@ -61,11 +63,22 @@ class Parser {
|
||||
public:
|
||||
virtual ~Sema();
|
||||
|
||||
/// \brief Lookup a value by name.
|
||||
///
|
||||
/// This can be used in the Sema layer to declare known constants or to
|
||||
/// allow to split an expression in pieces.
|
||||
///
|
||||
/// \param Name The name of the value to lookup.
|
||||
///
|
||||
/// \return The named value. It could be any type that VariantValue
|
||||
/// supports. An empty value means that the name is not recognized.
|
||||
virtual VariantValue getNamedValue(StringRef Name);
|
||||
|
||||
/// \brief Process a matcher expression.
|
||||
///
|
||||
/// All the arguments passed here have already been processed.
|
||||
///
|
||||
/// \param MatcherName The matcher name found by the parser.
|
||||
/// \param Ctor A matcher constructor looked up by lookupMatcherCtor.
|
||||
///
|
||||
/// \param NameRange The location of the name in the matcher source.
|
||||
/// Useful for error reporting.
|
||||
@ -78,11 +91,36 @@ class Parser {
|
||||
/// \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(StringRef MatcherName,
|
||||
virtual VariantMatcher actOnMatcherExpression(MatcherCtor Ctor,
|
||||
const 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 Sema implementation that uses the matcher registry to process the
|
||||
/// tokens.
|
||||
class RegistrySema : public Parser::Sema {
|
||||
public:
|
||||
virtual ~RegistrySema();
|
||||
|
||||
llvm::Optional<MatcherCtor>
|
||||
lookupMatcherCtor(StringRef MatcherName) override;
|
||||
|
||||
VariantMatcher actOnMatcherExpression(MatcherCtor Ctor,
|
||||
const SourceRange &NameRange,
|
||||
StringRef BindID,
|
||||
ArrayRef<ParserValue> Args,
|
||||
Diagnostics *Error) override;
|
||||
};
|
||||
|
||||
/// \brief Parse a matcher expression, creating matchers from the registry.
|
||||
@ -129,19 +167,37 @@ class Parser {
|
||||
static bool parseExpression(StringRef Code, Sema *S,
|
||||
VariantValue *Value, Diagnostics *Error);
|
||||
|
||||
/// \brief Complete an expression at the given offset.
|
||||
///
|
||||
/// \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);
|
||||
|
||||
private:
|
||||
class CodeTokenizer;
|
||||
struct ScopedContextEntry;
|
||||
struct TokenInfo;
|
||||
|
||||
Parser(CodeTokenizer *Tokenizer, Sema *S,
|
||||
Diagnostics *Error);
|
||||
|
||||
bool parseExpressionImpl(VariantValue *Value);
|
||||
bool parseMatcherExpressionImpl(VariantValue *Value);
|
||||
bool parseMatcherExpressionImpl(const TokenInfo &NameToken,
|
||||
VariantValue *Value);
|
||||
bool parseIdentifierPrefixImpl(VariantValue *Value);
|
||||
|
||||
void addCompletion(const TokenInfo &CompToken, StringRef TypedText,
|
||||
StringRef Decl);
|
||||
void addExpressionCompletions();
|
||||
|
||||
CodeTokenizer *const Tokenizer;
|
||||
Sema *const S;
|
||||
Diagnostics *const Error;
|
||||
|
||||
typedef std::vector<std::pair<MatcherCtor, unsigned> > ContextStackTy;
|
||||
ContextStackTy ContextStack;
|
||||
std::vector<MatcherCompletion> Completions;
|
||||
};
|
||||
|
||||
} // namespace dynamic
|
||||
|
@ -21,20 +21,69 @@
|
||||
#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)
|
||||
: TypedText(TypedText), MatcherDecl(MatcherDecl) {}
|
||||
|
||||
/// \brief The text to type to select this matcher.
|
||||
std::string TypedText;
|
||||
|
||||
/// \brief The "declaration" of the matcher, with type information.
|
||||
std::string MatcherDecl;
|
||||
|
||||
bool operator==(const MatcherCompletion &Other) const {
|
||||
return TypedText == Other.TypedText && MatcherDecl == Other.MatcherDecl;
|
||||
}
|
||||
};
|
||||
|
||||
class Registry {
|
||||
public:
|
||||
/// \brief Construct a matcher from the registry by name.
|
||||
/// \brief Look up a matcher in the registry by name,
|
||||
///
|
||||
/// Consult the registry of known matchers and construct the appropriate
|
||||
/// matcher 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 completions for \p Context.
|
||||
///
|
||||
/// \param MatcherName The name of the matcher to instantiate.
|
||||
/// 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.
|
||||
///
|
||||
/// The completions are ordered first by decreasing relevance, then
|
||||
/// alphabetically. Relevance is determined by how closely the matcher's
|
||||
/// type matches that of the context. For example, if the innermost matcher
|
||||
/// takes a FunctionDecl matcher, the FunctionDecl matchers are returned
|
||||
/// first, followed by the ValueDecl matchers, then NamedDecl, then Decl, then
|
||||
/// polymorphic matchers.
|
||||
///
|
||||
/// Matchers which are technically convertible to the innermost context but
|
||||
/// which would match either all or no nodes are excluded. For example,
|
||||
/// namedDecl and varDecl are excluded in a FunctionDecl context, because
|
||||
/// those matchers would match respectively all or no nodes in such a context.
|
||||
static std::vector<MatcherCompletion>
|
||||
getCompletions(ArrayRef<std::pair<MatcherCtor, unsigned> > Context);
|
||||
|
||||
/// \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.
|
||||
@ -44,10 +93,10 @@ class Registry {
|
||||
/// will return an error.
|
||||
///
|
||||
/// \return The matcher object constructed if no error was found.
|
||||
/// A null matcher if the matcher is not found, or 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(StringRef MatcherName,
|
||||
/// 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,
|
||||
const SourceRange &NameRange,
|
||||
ArrayRef<ParserValue> Args,
|
||||
Diagnostics *Error);
|
||||
@ -58,7 +107,7 @@ class Registry {
|
||||
/// 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(StringRef MatcherName,
|
||||
static VariantMatcher constructBoundMatcher(MatcherCtor Ctor,
|
||||
const SourceRange &NameRange,
|
||||
StringRef BindID,
|
||||
ArrayRef<ParserValue> Args,
|
||||
|
@ -17,14 +17,13 @@
|
||||
#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_VARIANT_VALUE_H
|
||||
#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_VARIANT_VALUE_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#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 "llvm/Support/type_traits.h"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
namespace ast_matchers {
|
||||
@ -50,7 +49,8 @@ class VariantMatcher {
|
||||
class MatcherOps {
|
||||
public:
|
||||
virtual ~MatcherOps();
|
||||
virtual bool canConstructFrom(const DynTypedMatcher &Matcher) const = 0;
|
||||
virtual bool canConstructFrom(const DynTypedMatcher &Matcher,
|
||||
bool &IsExactMatch) const = 0;
|
||||
virtual void constructFrom(const DynTypedMatcher &Matcher) = 0;
|
||||
virtual void constructVariadicOperator(
|
||||
ast_matchers::internal::VariadicOperatorFunction Func,
|
||||
@ -78,14 +78,15 @@ class VariantMatcher {
|
||||
/// \brief Clones the provided matchers.
|
||||
///
|
||||
/// They should be the result of a polymorphic matcher.
|
||||
static VariantMatcher PolymorphicMatcher(ArrayRef<DynTypedMatcher> Matchers);
|
||||
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(
|
||||
ast_matchers::internal::VariadicOperatorFunction Func,
|
||||
ArrayRef<VariantMatcher> Args);
|
||||
std::vector<VariantMatcher> Args);
|
||||
|
||||
/// \brief Makes the matcher the "null" matcher.
|
||||
void reset();
|
||||
@ -145,7 +146,10 @@ class VariantMatcher {
|
||||
public:
|
||||
typedef ast_matchers::internal::Matcher<T> MatcherT;
|
||||
|
||||
virtual bool canConstructFrom(const DynTypedMatcher &Matcher) const {
|
||||
virtual bool canConstructFrom(const DynTypedMatcher &Matcher,
|
||||
bool &IsExactMatch) const {
|
||||
IsExactMatch = Matcher.getSupportedKind().isSame(
|
||||
ast_type_traits::ASTNodeKind::getFromNodeKind<T>());
|
||||
return Matcher.canConvertTo<T>();
|
||||
}
|
||||
|
||||
@ -156,34 +160,25 @@ class VariantMatcher {
|
||||
virtual void constructVariadicOperator(
|
||||
ast_matchers::internal::VariadicOperatorFunction Func,
|
||||
ArrayRef<VariantMatcher> InnerMatchers) {
|
||||
const size_t NumArgs = InnerMatchers.size();
|
||||
MatcherT **InnerArgs = new MatcherT *[NumArgs]();
|
||||
bool HasError = false;
|
||||
for (size_t i = 0; i != NumArgs; ++i) {
|
||||
std::vector<DynTypedMatcher> DynMatchers;
|
||||
for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) {
|
||||
// Abort if any of the inner matchers can't be converted to
|
||||
// Matcher<T>.
|
||||
if (!InnerMatchers[i].hasTypedMatcher<T>()) {
|
||||
HasError = true;
|
||||
break;
|
||||
return;
|
||||
}
|
||||
InnerArgs[i] = new MatcherT(InnerMatchers[i].getTypedMatcher<T>());
|
||||
DynMatchers.push_back(InnerMatchers[i].getTypedMatcher<T>());
|
||||
}
|
||||
if (!HasError) {
|
||||
Out.reset(new MatcherT(
|
||||
new ast_matchers::internal::VariadicOperatorMatcherInterface<T>(
|
||||
Func, ArrayRef<const MatcherT *>(InnerArgs, NumArgs))));
|
||||
}
|
||||
for (size_t i = 0; i != NumArgs; ++i) {
|
||||
delete InnerArgs[i];
|
||||
}
|
||||
delete[] InnerArgs;
|
||||
Out.reset(new MatcherT(
|
||||
new ast_matchers::internal::VariadicOperatorMatcherInterface<T>(
|
||||
Func, DynMatchers)));
|
||||
}
|
||||
|
||||
bool hasMatcher() const { return Out.get() != NULL; }
|
||||
bool hasMatcher() const { return Out.get() != nullptr; }
|
||||
const MatcherT &matcher() const { return *Out; }
|
||||
|
||||
private:
|
||||
OwningPtr<MatcherT> Out;
|
||||
std::unique_ptr<MatcherT> Out;
|
||||
};
|
||||
|
||||
IntrusiveRefCntPtr<const Payload> Value;
|
||||
@ -214,6 +209,10 @@ class VariantValue {
|
||||
VariantValue(const std::string &String);
|
||||
VariantValue(const VariantMatcher &Matchers);
|
||||
|
||||
/// \brief Returns true iff this is not an empty value.
|
||||
LLVM_EXPLICIT operator bool() const { return hasValue(); }
|
||||
bool hasValue() const { return Type != VT_Nothing; }
|
||||
|
||||
/// \brief Unsigned value functions.
|
||||
bool isUnsigned() const;
|
||||
unsigned getUnsigned() const;
|
||||
|
@ -18,8 +18,8 @@
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/StmtCXX.h"
|
||||
#include "clang/Analysis/AnalysisContext.h"
|
||||
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
|
||||
#include "clang/Analysis/AnalysisContext.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
|
||||
namespace clang {
|
||||
@ -142,7 +142,7 @@ namespace consumed {
|
||||
TmpMapType TmpMap;
|
||||
|
||||
public:
|
||||
ConsumedStateMap() : Reachable(true), From(NULL) {}
|
||||
ConsumedStateMap() : Reachable(true), From(nullptr) {}
|
||||
ConsumedStateMap(const ConsumedStateMap &Other)
|
||||
: Reachable(Other.Reachable), From(Other.From), VarMap(Other.VarMap),
|
||||
TmpMap() {}
|
||||
@ -185,8 +185,8 @@ namespace consumed {
|
||||
/// \brief Set the consumed state of a given temporary value.
|
||||
void setState(const CXXBindTemporaryExpr *Tmp, ConsumedState State);
|
||||
|
||||
/// \brief Remove the variable from our state map.
|
||||
void remove(const VarDecl *Var);
|
||||
/// \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.
|
||||
@ -201,9 +201,10 @@ namespace consumed {
|
||||
|
||||
public:
|
||||
ConsumedBlockInfo() { }
|
||||
|
||||
~ConsumedBlockInfo() { llvm::DeleteContainerPointers(StateMapsArray); }
|
||||
|
||||
ConsumedBlockInfo(unsigned int NumBlocks, PostOrderCFGView *SortedGraph)
|
||||
: StateMapsArray(NumBlocks, 0), VisitOrder(NumBlocks, 0) {
|
||||
: StateMapsArray(NumBlocks, nullptr), VisitOrder(NumBlocks, 0) {
|
||||
unsigned int VisitOrderCounter = 0;
|
||||
for (PostOrderCFGView::iterator BI = SortedGraph->begin(),
|
||||
BE = SortedGraph->end(); BI != BE; ++BI) {
|
||||
|
@ -17,9 +17,15 @@
|
||||
#include "clang/Analysis/AnalysisContext.h"
|
||||
#include "clang/Analysis/CFG.h"
|
||||
#include "llvm/ADT/GraphTraits.h"
|
||||
#include "llvm/Analysis/DominatorInternals.h"
|
||||
#include "llvm/Analysis/Dominators.h"
|
||||
#include "llvm/IR/Module.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 {
|
||||
|
||||
@ -147,7 +153,7 @@ class DominatorTree : public ManagedAnalysis {
|
||||
|
||||
/// \brief This method converts the dominator tree to human readable form.
|
||||
///
|
||||
virtual void print(raw_ostream &OS, const llvm::Module* M= 0) const {
|
||||
virtual void print(raw_ostream &OS, const llvm::Module* M= nullptr) const {
|
||||
DT->print(OS);
|
||||
}
|
||||
|
||||
@ -155,11 +161,6 @@ class DominatorTree : public ManagedAnalysis {
|
||||
CFG *cfg;
|
||||
};
|
||||
|
||||
inline void WriteAsOperand(raw_ostream &OS, const CFGBlock *BB,
|
||||
bool t) {
|
||||
OS << "BB#" << BB->getBlockID();
|
||||
}
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
//===-------------------------------------
|
||||
|
@ -83,7 +83,7 @@ class LengthModifier {
|
||||
};
|
||||
|
||||
LengthModifier()
|
||||
: Position(0), kind(None) {}
|
||||
: Position(nullptr), kind(None) {}
|
||||
LengthModifier(const char *pos, Kind k)
|
||||
: Position(pos), kind(k) {}
|
||||
|
||||
@ -174,10 +174,11 @@ class ConversionSpecifier {
|
||||
};
|
||||
|
||||
ConversionSpecifier(bool isPrintf = true)
|
||||
: IsPrintf(isPrintf), Position(0), EndScanList(0), kind(InvalidSpecifier) {}
|
||||
: IsPrintf(isPrintf), Position(nullptr), EndScanList(nullptr),
|
||||
kind(InvalidSpecifier) {}
|
||||
|
||||
ConversionSpecifier(bool isPrintf, const char *pos, Kind k)
|
||||
: IsPrintf(isPrintf), Position(pos), EndScanList(0), kind(k) {}
|
||||
: IsPrintf(isPrintf), Position(pos), EndScanList(nullptr), kind(k) {}
|
||||
|
||||
const char *getStart() const {
|
||||
return Position;
|
||||
@ -231,10 +232,11 @@ class ArgType {
|
||||
const char *Name;
|
||||
bool Ptr;
|
||||
public:
|
||||
ArgType(Kind k = UnknownTy, const char *n = 0) : K(k), Name(n), Ptr(false) {}
|
||||
ArgType(QualType t, const char *n = 0)
|
||||
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(0), 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; }
|
||||
@ -267,7 +269,7 @@ class OptionalAmount {
|
||||
UsesPositionalArg(usesPositionalArg), UsesDotPrefix(0) {}
|
||||
|
||||
OptionalAmount(bool valid = true)
|
||||
: start(0),length(0), hs(valid ? NotSpecified : Invalid), amt(0),
|
||||
: start(nullptr),length(0), hs(valid ? NotSpecified : Invalid), amt(0),
|
||||
UsesPositionalArg(0), UsesDotPrefix(0) {}
|
||||
|
||||
bool isInvalid() const {
|
||||
@ -394,7 +396,7 @@ class PrintfConversionSpecifier :
|
||||
public analyze_format_string::ConversionSpecifier {
|
||||
public:
|
||||
PrintfConversionSpecifier()
|
||||
: ConversionSpecifier(true, 0, InvalidSpecifier) {}
|
||||
: ConversionSpecifier(true, nullptr, InvalidSpecifier) {}
|
||||
|
||||
PrintfConversionSpecifier(const char *pos, Kind k)
|
||||
: ConversionSpecifier(true, pos, k) {}
|
||||
@ -530,7 +532,7 @@ class ScanfConversionSpecifier :
|
||||
public analyze_format_string::ConversionSpecifier {
|
||||
public:
|
||||
ScanfConversionSpecifier()
|
||||
: ConversionSpecifier(false, 0, InvalidSpecifier) {}
|
||||
: ConversionSpecifier(false, nullptr, InvalidSpecifier) {}
|
||||
|
||||
ScanfConversionSpecifier(const char *pos, Kind k)
|
||||
: ConversionSpecifier(false, pos, k) {}
|
||||
@ -577,7 +579,8 @@ class ScanfSpecifier : public analyze_format_string::FormatSpecifier {
|
||||
|
||||
ArgType getArgType(ASTContext &Ctx) const;
|
||||
|
||||
bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx);
|
||||
bool fixType(QualType QT, QualType RawQT, const LangOptions &LangOpt,
|
||||
ASTContext &Ctx);
|
||||
|
||||
void toString(raw_ostream &os) const;
|
||||
|
||||
|
@ -38,7 +38,7 @@ class LiveVariables : public ManagedAnalysis {
|
||||
bool equals(const LivenessValues &V) const;
|
||||
|
||||
LivenessValues()
|
||||
: liveStmts(0), liveDecls(0) {}
|
||||
: liveStmts(nullptr), liveDecls(nullptr) {}
|
||||
|
||||
LivenessValues(llvm::ImmutableSet<const Stmt *> LiveStmts,
|
||||
llvm::ImmutableSet<const VarDecl *> LiveDecls)
|
||||
|
@ -52,7 +52,7 @@ class PostOrderCFGView : public ManagedAnalysis {
|
||||
// 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 == 0)
|
||||
if (!Block)
|
||||
return false; // if an edge is trivially false.
|
||||
if (VisitedBlockIDs.test(Block->getBlockID()))
|
||||
return false;
|
||||
@ -76,14 +76,18 @@ class PostOrderCFGView : public ManagedAnalysis {
|
||||
BlockOrderTy BlockOrder;
|
||||
|
||||
public:
|
||||
typedef std::vector<const CFGBlock*>::reverse_iterator iterator;
|
||||
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(); }
|
||||
|
||||
bool empty() { return begin() == end(); }
|
||||
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;
|
||||
|
@ -27,6 +27,7 @@ namespace llvm {
|
||||
namespace clang {
|
||||
class AnalysisDeclContext;
|
||||
class CFGBlock;
|
||||
class Preprocessor;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -36,11 +37,22 @@ namespace clang {
|
||||
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(SourceLocation L, SourceRange R1,
|
||||
virtual void HandleUnreachable(UnreachableKind UK,
|
||||
SourceLocation L,
|
||||
SourceRange ConditionVal,
|
||||
SourceRange R1,
|
||||
SourceRange R2) = 0;
|
||||
};
|
||||
|
||||
@ -49,7 +61,8 @@ class Callback {
|
||||
unsigned ScanReachableFromBlock(const CFGBlock *Start,
|
||||
llvm::BitVector &Reachable);
|
||||
|
||||
void FindUnreachableCode(AnalysisDeclContext &AC, Callback &CB);
|
||||
void FindUnreachableCode(AnalysisDeclContext &AC, Preprocessor &PP,
|
||||
Callback &CB);
|
||||
|
||||
}} // end namespace clang::reachable_code
|
||||
|
||||
|
@ -39,7 +39,8 @@ enum ProtectedOperationKind {
|
||||
/// mutex.
|
||||
enum LockKind {
|
||||
LK_Shared, ///< Shared/reader lock of a mutex.
|
||||
LK_Exclusive ///< Exclusive/writer 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
|
||||
@ -72,27 +73,46 @@ class ThreadSafetyHandler {
|
||||
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(SourceLocation Loc) {}
|
||||
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(Name LockName, SourceLocation Loc) {}
|
||||
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(Name LockName, SourceLocation Loc) {}
|
||||
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
|
||||
@ -100,50 +120,56 @@ class ThreadSafetyHandler {
|
||||
/// \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(Name LockName,
|
||||
virtual void handleMutexHeldEndOfScope(StringRef Kind, Name LockName,
|
||||
SourceLocation LocLocked,
|
||||
SourceLocation LocEndOfScope,
|
||||
LockErrorKind LEK){}
|
||||
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(Name LockName, SourceLocation Loc1,
|
||||
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(const NamedDecl *D, ProtectedOperationKind POK,
|
||||
AccessKind AK, SourceLocation Loc) {}
|
||||
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(const NamedDecl *D,
|
||||
virtual void handleMutexNotHeld(StringRef Kind, const NamedDecl *D,
|
||||
ProtectedOperationKind POK, Name LockName,
|
||||
LockKind LK, SourceLocation Loc,
|
||||
Name *PossibleMatch=0) {}
|
||||
Name *PossibleMatch = nullptr) {}
|
||||
|
||||
/// 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(Name FunName, Name LockName,
|
||||
SourceLocation Loc) {}
|
||||
virtual void handleFunExcludesLock(StringRef Kind, Name FunName,
|
||||
Name LockName, SourceLocation Loc) {}
|
||||
|
||||
bool issueBetaWarnings() { return IssueBetaWarnings; }
|
||||
void setIssueBetaWarnings(bool b) { IssueBetaWarnings = b; }
|
||||
|
@ -0,0 +1,393 @@
|
||||
//===- 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_THREAD_SAFETY_COMMON_H
|
||||
#define LLVM_CLANG_THREAD_SAFETY_COMMON_H
|
||||
|
||||
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
|
||||
#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
|
||||
#include "clang/Analysis/AnalysisContext.h"
|
||||
#include "clang/Basic/OperatorKinds.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace clang {
|
||||
namespace threadSafety {
|
||||
|
||||
// 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;
|
||||
};
|
||||
|
||||
|
||||
// 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 {
|
||||
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
|
||||
CallingContext *Prev; // The previous context; or 0 if none.
|
||||
bool SelfArrow; // is Self referred to with -> or .?
|
||||
|
||||
CallingContext(const NamedDecl *D = nullptr, const Expr *S = nullptr,
|
||||
unsigned N = 0, const Expr *const *A = nullptr,
|
||||
CallingContext *P = nullptr)
|
||||
: AttrDecl(D), SelfArg(S), NumArgs(N), FunArgs(A), Prev(P),
|
||||
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 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);
|
||||
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 *translateConditionalOperator(const ConditionalOperator *C,
|
||||
CallingContext *Ctx);
|
||||
til::SExpr *translateBinaryConditionalOperator(
|
||||
const BinaryConditionalOperator *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 &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const BlockInfo &) LLVM_DELETED_FUNCTION;
|
||||
};
|
||||
|
||||
// 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:
|
||||
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.
|
||||
std::unique_ptr<SExprBuilder::CallingContext> CallCtx; // Root calling context
|
||||
|
||||
LVarDefinitionMap CurrentLVarMap;
|
||||
std::vector<til::Variable*> CurrentArguments;
|
||||
std::vector<til::Variable*> CurrentInstructions;
|
||||
std::vector<til::Variable*> 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
|
@ -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_THREAD_SAFETY_LOGICAL_H
|
||||
#define LLVM_CLANG_THREAD_SAFETY_LOGICAL_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::SExprRef Expr;
|
||||
|
||||
public:
|
||||
Terminal(til::SExpr *Expr) : LExpr(LExpr::Terminal), Expr(Expr) {}
|
||||
|
||||
const til::SExpr *expr() const { return Expr.get(); }
|
||||
til::SExpr *expr() { return Expr.get(); }
|
||||
|
||||
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 // LLVM_CLANG_THREAD_SAFETY_LOGICAL_H
|
||||
|
@ -0,0 +1,54 @@
|
||||
//===- 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)
|
||||
TIL_OPCODE_DEF(Goto)
|
||||
TIL_OPCODE_DEF(Branch)
|
||||
|
||||
// pseudo-terms
|
||||
TIL_OPCODE_DEF(Identifier)
|
||||
TIL_OPCODE_DEF(IfThenElse)
|
||||
TIL_OPCODE_DEF(Let)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,936 @@
|
||||
//===- 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_THREAD_SAFETY_TRAVERSE_H
|
||||
#define LLVM_CLANG_THREAD_SAFETY_TRAVERSE_H
|
||||
|
||||
#include "ThreadSafetyTIL.h"
|
||||
|
||||
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.
|
||||
typename R::R_SExpr traverse(SExprRef &E, typename R::R_Ctx Ctx) {
|
||||
return traverse(E.get(), Ctx);
|
||||
}
|
||||
|
||||
typename R::R_SExpr traverse(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
|
||||
}
|
||||
}
|
||||
|
||||
// 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,
|
||||
TRV_Decl,
|
||||
TRV_Lazy,
|
||||
TRV_Type
|
||||
};
|
||||
|
||||
// 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;
|
||||
};
|
||||
|
||||
|
||||
// Implements a traversal that makes a deep copy of an SExpr.
|
||||
// The default behavior of reduce##X(...) is to create a copy of the original.
|
||||
// Subclasses can override reduce##X to implement non-destructive rewriting
|
||||
// passes.
|
||||
template<class Self>
|
||||
class CopyReducer : public Traversal<Self, CopyReducerBase>,
|
||||
public CopyReducerBase {
|
||||
public:
|
||||
CopyReducer(MemRegionRef A) : CopyReducerBase(A) {}
|
||||
|
||||
public:
|
||||
R_SExpr reduceNull() {
|
||||
return nullptr;
|
||||
}
|
||||
// R_SExpr reduceFuture(...) is never used.
|
||||
|
||||
R_SExpr reduceUndefined(Undefined &Orig) {
|
||||
return new (Arena) Undefined(Orig);
|
||||
}
|
||||
R_SExpr reduceWildcard(Wildcard &Orig) {
|
||||
return new (Arena) Wildcard(Orig);
|
||||
}
|
||||
|
||||
R_SExpr reduceLiteral(Literal &Orig) {
|
||||
return new (Arena) Literal(Orig);
|
||||
}
|
||||
template<class T>
|
||||
R_SExpr reduceLiteralT(LiteralT<T> &Orig) {
|
||||
return new (Arena) LiteralT<T>(Orig);
|
||||
}
|
||||
R_SExpr reduceLiteralPtr(LiteralPtr &Orig) {
|
||||
return new (Arena) LiteralPtr(Orig);
|
||||
}
|
||||
|
||||
R_SExpr reduceFunction(Function &Orig, Variable *Nvd, R_SExpr E0) {
|
||||
return new (Arena) Function(Orig, Nvd, E0);
|
||||
}
|
||||
R_SExpr reduceSFunction(SFunction &Orig, Variable *Nvd, R_SExpr E0) {
|
||||
return new (Arena) SFunction(Orig, Nvd, E0);
|
||||
}
|
||||
R_SExpr reduceCode(Code &Orig, R_SExpr E0, R_SExpr E1) {
|
||||
return new (Arena) Code(Orig, E0, E1);
|
||||
}
|
||||
R_SExpr reduceField(Field &Orig, R_SExpr E0, R_SExpr E1) {
|
||||
return new (Arena) Field(Orig, E0, E1);
|
||||
}
|
||||
|
||||
R_SExpr reduceApply(Apply &Orig, R_SExpr E0, R_SExpr E1) {
|
||||
return new (Arena) Apply(Orig, E0, E1);
|
||||
}
|
||||
R_SExpr reduceSApply(SApply &Orig, R_SExpr E0, R_SExpr E1) {
|
||||
return new (Arena) SApply(Orig, E0, E1);
|
||||
}
|
||||
R_SExpr reduceProject(Project &Orig, R_SExpr E0) {
|
||||
return new (Arena) Project(Orig, E0);
|
||||
}
|
||||
R_SExpr reduceCall(Call &Orig, R_SExpr E0) {
|
||||
return new (Arena) Call(Orig, E0);
|
||||
}
|
||||
|
||||
R_SExpr reduceAlloc(Alloc &Orig, R_SExpr E0) {
|
||||
return new (Arena) Alloc(Orig, E0);
|
||||
}
|
||||
R_SExpr reduceLoad(Load &Orig, R_SExpr E0) {
|
||||
return new (Arena) Load(Orig, E0);
|
||||
}
|
||||
R_SExpr reduceStore(Store &Orig, R_SExpr E0, R_SExpr E1) {
|
||||
return new (Arena) Store(Orig, E0, E1);
|
||||
}
|
||||
R_SExpr reduceArrayIndex(ArrayIndex &Orig, R_SExpr E0, R_SExpr E1) {
|
||||
return new (Arena) ArrayIndex(Orig, E0, E1);
|
||||
}
|
||||
R_SExpr reduceArrayAdd(ArrayAdd &Orig, R_SExpr E0, R_SExpr E1) {
|
||||
return new (Arena) ArrayAdd(Orig, E0, E1);
|
||||
}
|
||||
R_SExpr reduceUnaryOp(UnaryOp &Orig, R_SExpr E0) {
|
||||
return new (Arena) UnaryOp(Orig, E0);
|
||||
}
|
||||
R_SExpr reduceBinaryOp(BinaryOp &Orig, R_SExpr E0, R_SExpr E1) {
|
||||
return new (Arena) BinaryOp(Orig, E0, E1);
|
||||
}
|
||||
R_SExpr reduceCast(Cast &Orig, R_SExpr E0) {
|
||||
return new (Arena) Cast(Orig, E0);
|
||||
}
|
||||
|
||||
R_SExpr reduceSCFG(SCFG &Orig, Container<BasicBlock *> &Bbs) {
|
||||
return nullptr; // FIXME: implement CFG rewriting
|
||||
}
|
||||
R_BasicBlock reduceBasicBlock(BasicBlock &Orig, Container<Variable *> &As,
|
||||
Container<Variable *> &Is, R_SExpr T) {
|
||||
return nullptr; // FIXME: implement CFG rewriting
|
||||
}
|
||||
R_SExpr reducePhi(Phi &Orig, Container<R_SExpr> &As) {
|
||||
return new (Arena) Phi(Orig, std::move(As.Elems));
|
||||
}
|
||||
R_SExpr reduceGoto(Goto &Orig, BasicBlock *B) {
|
||||
return new (Arena) Goto(Orig, B, 0); // FIXME: set index
|
||||
}
|
||||
R_SExpr reduceBranch(Branch &O, R_SExpr C, BasicBlock *B0, BasicBlock *B1) {
|
||||
return new (Arena) Branch(O, C, B0, B1, 0, 0); // FIXME: set indices
|
||||
}
|
||||
|
||||
R_SExpr reduceIdentifier(Identifier &Orig) {
|
||||
return new (Arena) Identifier(Orig);
|
||||
}
|
||||
R_SExpr reduceIfThenElse(IfThenElse &Orig, R_SExpr C, R_SExpr T, R_SExpr E) {
|
||||
return new (Arena) IfThenElse(Orig, C, T, E);
|
||||
}
|
||||
R_SExpr reduceLet(Let &Orig, Variable *Nvd, R_SExpr B) {
|
||||
return new (Arena) Let(Orig, Nvd, B);
|
||||
}
|
||||
|
||||
// Create a new variable from orig, and push it onto the lexical scope.
|
||||
Variable *enterScope(Variable &Orig, R_SExpr E0) {
|
||||
return new (Arena) Variable(Orig, E0);
|
||||
}
|
||||
// Exit the lexical scope of orig.
|
||||
void exitScope(const Variable &Orig) {}
|
||||
|
||||
void enterCFG(SCFG &Cfg) {}
|
||||
void exitCFG(SCFG &Cfg) {}
|
||||
void enterBasicBlock(BasicBlock &BB) {}
|
||||
void exitBasicBlock(BasicBlock &BB) {}
|
||||
|
||||
// Map Variable references to their rewritten definitions.
|
||||
Variable *reduceVariableRef(Variable *Ovd) { return Ovd; }
|
||||
|
||||
// Map BasicBlock references to their rewritten definitions.
|
||||
BasicBlock *reduceBasicBlockRef(BasicBlock *Obb) { return Obb; }
|
||||
};
|
||||
|
||||
|
||||
class SExprCopier : public CopyReducer<SExprCopier> {
|
||||
public:
|
||||
typedef SExpr *R_SExpr;
|
||||
|
||||
SExprCopier(MemRegionRef A) : CopyReducer(A) { }
|
||||
|
||||
// Create a copy of e in region a.
|
||||
static SExpr *copy(SExpr *E, MemRegionRef A) {
|
||||
SExprCopier Copier(A);
|
||||
return Copier.traverse(E, TRV_Normal);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
// 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<Variable *> &As,
|
||||
Container<Variable *> &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 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(SExpr *E1, 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
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
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(SExpr *E1, SExpr* E2) {
|
||||
if (E1->opcode() != E2->opcode())
|
||||
return false;
|
||||
return compareByCase(E1, E2);
|
||||
}
|
||||
|
||||
// TODO -- handle alpha-renaming of variables
|
||||
void enterScope(Variable* V1, Variable* V2) { }
|
||||
void leaveScope() { }
|
||||
|
||||
bool compareVariableRefs(Variable* V1, Variable* V2) {
|
||||
return V1 == V2;
|
||||
}
|
||||
|
||||
static bool compareExprs(SExpr *E1, SExpr* E2) {
|
||||
EqualsComparator Eq;
|
||||
return Eq.compare(E1, E2);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Pretty printer for TIL expressions
|
||||
template <typename Self, typename StreamType>
|
||||
class PrettyPrinter {
|
||||
private:
|
||||
bool Verbose; // Print out additional information
|
||||
bool Cleanup; // Omit redundant decls.
|
||||
|
||||
public:
|
||||
PrettyPrinter(bool V = false, bool C = true) : Verbose(V), Cleanup(C) { }
|
||||
|
||||
static void print(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(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_Unary;
|
||||
|
||||
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_Identifier: return Prec_Atom;
|
||||
case COP_IfThenElse: return Prec_Other;
|
||||
case COP_Let: return Prec_Decl;
|
||||
}
|
||||
return Prec_MAX;
|
||||
}
|
||||
|
||||
void printBlockLabel(StreamType & SS, BasicBlock *BB, unsigned index) {
|
||||
if (!BB) {
|
||||
SS << "BB_null";
|
||||
return;
|
||||
}
|
||||
SS << "BB_";
|
||||
SS << BB->blockID();
|
||||
SS << ":";
|
||||
SS << index;
|
||||
}
|
||||
|
||||
void printSExpr(SExpr *E, StreamType &SS, unsigned P) {
|
||||
if (!E) {
|
||||
self()->printNull(SS);
|
||||
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(Future *E, StreamType &SS) {
|
||||
self()->printSExpr(E->maybeGetResult(), SS, Prec_Atom);
|
||||
}
|
||||
|
||||
void printUndefined(Undefined *E, StreamType &SS) {
|
||||
SS << "#undefined";
|
||||
}
|
||||
|
||||
void printWildcard(Wildcard *E, StreamType &SS) {
|
||||
SS << "_";
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void printLiteralT(LiteralT<T> *E, StreamType &SS) {
|
||||
SS << E->value();
|
||||
}
|
||||
|
||||
void printLiteralT(LiteralT<uint8_t> *E, StreamType &SS) {
|
||||
SS << "'" << E->value() << "'";
|
||||
}
|
||||
|
||||
void printLiteral(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(LiteralPtr *E, StreamType &SS) {
|
||||
SS << E->clangDecl()->getNameAsString();
|
||||
}
|
||||
|
||||
void printVariable(Variable *V, StreamType &SS, bool IsVarDecl = false) {
|
||||
if (!IsVarDecl && Cleanup) {
|
||||
SExpr* E = getCanonicalVal(V);
|
||||
if (E != V) {
|
||||
printSExpr(E, SS, Prec_Atom);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (V->kind() == Variable::VK_LetBB)
|
||||
SS << V->name() << V->getBlockID() << "_" << V->getID();
|
||||
else
|
||||
SS << V->name() << V->getID();
|
||||
}
|
||||
|
||||
void printFunction(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);
|
||||
|
||||
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(SFunction *E, StreamType &SS) {
|
||||
SS << "@";
|
||||
self()->printVariable(E->variableDecl(), SS, true);
|
||||
SS << " ";
|
||||
self()->printSExpr(E->body(), SS, Prec_Decl);
|
||||
}
|
||||
|
||||
void printCode(Code *E, StreamType &SS) {
|
||||
SS << ": ";
|
||||
self()->printSExpr(E->returnType(), SS, Prec_Decl-1);
|
||||
SS << " -> ";
|
||||
self()->printSExpr(E->body(), SS, Prec_Decl);
|
||||
}
|
||||
|
||||
void printField(Field *E, StreamType &SS) {
|
||||
SS << ": ";
|
||||
self()->printSExpr(E->range(), SS, Prec_Decl-1);
|
||||
SS << " = ";
|
||||
self()->printSExpr(E->body(), SS, Prec_Decl);
|
||||
}
|
||||
|
||||
void printApply(Apply *E, StreamType &SS, bool sugared = false) {
|
||||
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(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(Project *E, StreamType &SS) {
|
||||
self()->printSExpr(E->record(), SS, Prec_Postfix);
|
||||
SS << ".";
|
||||
SS << E->slotName();
|
||||
}
|
||||
|
||||
void printCall(Call *E, StreamType &SS) {
|
||||
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(Alloc *E, StreamType &SS) {
|
||||
SS << "new ";
|
||||
self()->printSExpr(E->dataType(), SS, Prec_Other-1);
|
||||
}
|
||||
|
||||
void printLoad(Load *E, StreamType &SS) {
|
||||
self()->printSExpr(E->pointer(), SS, Prec_Postfix);
|
||||
SS << "^";
|
||||
}
|
||||
|
||||
void printStore(Store *E, StreamType &SS) {
|
||||
self()->printSExpr(E->destination(), SS, Prec_Other-1);
|
||||
SS << " := ";
|
||||
self()->printSExpr(E->source(), SS, Prec_Other-1);
|
||||
}
|
||||
|
||||
void printArrayIndex(ArrayIndex *E, StreamType &SS) {
|
||||
self()->printSExpr(E->array(), SS, Prec_Postfix);
|
||||
SS << "[";
|
||||
self()->printSExpr(E->index(), SS, Prec_MAX);
|
||||
SS << "]";
|
||||
}
|
||||
|
||||
void printArrayAdd(ArrayAdd *E, StreamType &SS) {
|
||||
self()->printSExpr(E->array(), SS, Prec_Postfix);
|
||||
SS << " + ";
|
||||
self()->printSExpr(E->index(), SS, Prec_Atom);
|
||||
}
|
||||
|
||||
void printUnaryOp(UnaryOp *E, StreamType &SS) {
|
||||
SS << getUnaryOpcodeString(E->unaryOpcode());
|
||||
self()->printSExpr(E->expr(), SS, Prec_Unary);
|
||||
}
|
||||
|
||||
void printBinaryOp(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(Cast *E, StreamType &SS) {
|
||||
SS << "%";
|
||||
self()->printSExpr(E->expr(), SS, Prec_Unary);
|
||||
}
|
||||
|
||||
void printSCFG(SCFG *E, StreamType &SS) {
|
||||
SS << "CFG {\n";
|
||||
for (auto BBI : *E) {
|
||||
printBasicBlock(BBI, SS);
|
||||
}
|
||||
SS << "}";
|
||||
newline(SS);
|
||||
}
|
||||
|
||||
void printBasicBlock(BasicBlock *E, StreamType &SS) {
|
||||
SS << "BB_" << E->blockID() << ":";
|
||||
if (E->parent())
|
||||
SS << " BB_" << E->parent()->blockID();
|
||||
newline(SS);
|
||||
for (auto *A : E->arguments()) {
|
||||
SS << "let ";
|
||||
self()->printVariable(A, SS, true);
|
||||
SS << " = ";
|
||||
self()->printSExpr(A->definition(), SS, Prec_MAX);
|
||||
SS << ";";
|
||||
newline(SS);
|
||||
}
|
||||
for (auto *I : E->instructions()) {
|
||||
if (I->definition()->opcode() != COP_Store) {
|
||||
SS << "let ";
|
||||
self()->printVariable(I, SS, true);
|
||||
SS << " = ";
|
||||
}
|
||||
self()->printSExpr(I->definition(), SS, Prec_MAX);
|
||||
SS << ";";
|
||||
newline(SS);
|
||||
}
|
||||
SExpr *T = E->terminator();
|
||||
if (T) {
|
||||
self()->printSExpr(T, SS, Prec_MAX);
|
||||
SS << ";";
|
||||
newline(SS);
|
||||
}
|
||||
newline(SS);
|
||||
}
|
||||
|
||||
void printPhi(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(Goto *E, StreamType &SS) {
|
||||
SS << "goto ";
|
||||
printBlockLabel(SS, E->targetBlock(), E->index());
|
||||
}
|
||||
|
||||
void printBranch(Branch *E, StreamType &SS) {
|
||||
SS << "branch (";
|
||||
self()->printSExpr(E->condition(), SS, Prec_MAX);
|
||||
SS << ") ";
|
||||
printBlockLabel(SS, E->thenBlock(), E->thenIndex());
|
||||
SS << " ";
|
||||
printBlockLabel(SS, E->elseBlock(), E->elseIndex());
|
||||
}
|
||||
|
||||
void printIdentifier(Identifier *E, StreamType &SS) {
|
||||
SS << E->name();
|
||||
}
|
||||
|
||||
void printIfThenElse(IfThenElse *E, StreamType &SS) {
|
||||
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(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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // end namespace til
|
||||
} // end namespace threadSafety
|
||||
} // end namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_THREAD_SAFETY_TRAVERSE_H
|
@ -0,0 +1,316 @@
|
||||
//===- 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_THREAD_SAFETY_UTIL_H
|
||||
#define LLVM_CLANG_THREAD_SAFETY_UTIL_H
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/AlignOf.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
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;
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
iterator begin() { return Data; }
|
||||
iterator end() { return Data + Size; }
|
||||
|
||||
const_iterator cbegin() const { return Data; }
|
||||
const_iterator cend() const { return Data + Size; }
|
||||
|
||||
void push_back(const T &Elem) {
|
||||
assert(Size < Capacity);
|
||||
Data[Size++] = Elem;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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) LLVM_DELETED_FUNCTION;
|
||||
|
||||
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) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const CopyOnWriteVector &V) LLVM_DELETED_FUNCTION;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
} // end namespace threadSafety
|
||||
} // end namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_THREAD_SAFETY_UTIL_H
|
@ -19,8 +19,8 @@
|
||||
#include "clang/Analysis/CFG.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include <memory>
|
||||
|
||||
namespace clang {
|
||||
|
||||
@ -69,16 +69,16 @@ class AnalysisDeclContext {
|
||||
|
||||
const Decl * const D;
|
||||
|
||||
OwningPtr<CFG> cfg, completeCFG;
|
||||
OwningPtr<CFGStmtMap> cfgStmtMap;
|
||||
std::unique_ptr<CFG> cfg, completeCFG;
|
||||
std::unique_ptr<CFGStmtMap> cfgStmtMap;
|
||||
|
||||
CFG::BuildOptions cfgBuildOptions;
|
||||
CFG::BuildOptions::ForcedBlkExprs *forcedBlkExprs;
|
||||
|
||||
bool builtCFG, builtCompleteCFG;
|
||||
OwningPtr<ParentMap> PM;
|
||||
OwningPtr<PseudoConstantAnalysis> PCA;
|
||||
OwningPtr<CFGReverseBlockReachabilityAnalysis> CFA;
|
||||
std::unique_ptr<ParentMap> PM;
|
||||
std::unique_ptr<PseudoConstantAnalysis> PCA;
|
||||
std::unique_ptr<CFGReverseBlockReachabilityAnalysis> CFA;
|
||||
|
||||
llvm::BumpPtrAllocator A;
|
||||
|
||||
@ -252,7 +252,7 @@ class LocationContext : public llvm::FoldingSetNode {
|
||||
virtual void Profile(llvm::FoldingSetNodeID &ID) = 0;
|
||||
|
||||
void dumpStack(raw_ostream &OS, StringRef Indent = "") const;
|
||||
LLVM_ATTRIBUTE_USED void dumpStack() const;
|
||||
void dumpStack() const;
|
||||
|
||||
public:
|
||||
static void ProfileCommon(llvm::FoldingSetNodeID &ID,
|
||||
@ -287,11 +287,11 @@ class StackFrameContext : public LocationContext {
|
||||
const CFGBlock *getCallSiteBlock() const { return Block; }
|
||||
|
||||
/// Return true if the current LocationContext has no caller context.
|
||||
virtual bool inTopFrame() const { return getParent() == 0; }
|
||||
bool inTopFrame() const override { return getParent() == nullptr; }
|
||||
|
||||
unsigned getIndex() const { return Index; }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID);
|
||||
void Profile(llvm::FoldingSetNodeID &ID) override;
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx,
|
||||
const LocationContext *parent, const Stmt *s,
|
||||
@ -317,7 +317,7 @@ class ScopeContext : public LocationContext {
|
||||
public:
|
||||
~ScopeContext() {}
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID);
|
||||
void Profile(llvm::FoldingSetNodeID &ID) override;
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx,
|
||||
const LocationContext *parent, const Stmt *s) {
|
||||
@ -349,7 +349,7 @@ class BlockInvocationContext : public LocationContext {
|
||||
|
||||
const void *getContextData() const { return ContextData; }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID);
|
||||
void Profile(llvm::FoldingSetNodeID &ID) override;
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx,
|
||||
const LocationContext *parent, const BlockDecl *bd,
|
||||
@ -409,7 +409,8 @@ class AnalysisDeclContextManager {
|
||||
bool addInitializers = false,
|
||||
bool addTemporaryDtors = false,
|
||||
bool synthesizeBodies = false,
|
||||
bool addStaticInitBranches = false);
|
||||
bool addStaticInitBranches = false,
|
||||
bool addCXXNewAllocator = true);
|
||||
|
||||
~AnalysisDeclContextManager();
|
||||
|
||||
@ -437,7 +438,8 @@ class AnalysisDeclContextManager {
|
||||
|
||||
// Get the top level stack frame.
|
||||
const StackFrameContext *getStackFrame(const Decl *D) {
|
||||
return LocContexts.getStackFrame(getContext(D), 0, 0, 0, 0);
|
||||
return LocContexts.getStackFrame(getContext(D), nullptr, nullptr, nullptr,
|
||||
0);
|
||||
}
|
||||
|
||||
// Get a stack frame with parent.
|
||||
|
@ -21,13 +21,14 @@
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/GraphTraits.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/OwningPtr.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;
|
||||
@ -45,6 +46,8 @@ namespace clang {
|
||||
class ASTContext;
|
||||
class CXXRecordDecl;
|
||||
class CXXDeleteExpr;
|
||||
class CXXNewExpr;
|
||||
class BinaryOperator;
|
||||
|
||||
/// CFGElement - Represents a top-level expression in a basic block.
|
||||
class CFGElement {
|
||||
@ -53,6 +56,7 @@ class CFGElement {
|
||||
// main kind
|
||||
Statement,
|
||||
Initializer,
|
||||
NewAllocator,
|
||||
// dtor kind
|
||||
AutomaticObjectDtor,
|
||||
DeleteDtor,
|
||||
@ -68,9 +72,11 @@ class CFGElement {
|
||||
llvm::PointerIntPair<void *, 2> Data1;
|
||||
llvm::PointerIntPair<void *, 2> Data2;
|
||||
|
||||
CFGElement(Kind kind, const void *Ptr1, const void *Ptr2 = 0)
|
||||
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) {}
|
||||
Data2(const_cast<void*>(Ptr2), (((unsigned) kind) >> 2) & 0x3) {
|
||||
assert(getKind() == kind);
|
||||
}
|
||||
|
||||
CFGElement() {}
|
||||
public:
|
||||
@ -141,12 +147,31 @@ class CFGInitializer : public CFGElement {
|
||||
}
|
||||
};
|
||||
|
||||
/// 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 = 0)
|
||||
CFGImplicitDtor(Kind kind, const void *data1, const void *data2 = nullptr)
|
||||
: CFGElement(kind, data1, data2) {
|
||||
assert(kind >= DTOR_BEGIN && kind <= DTOR_END);
|
||||
}
|
||||
@ -237,7 +262,7 @@ class CFGBaseDtor : public CFGImplicitDtor {
|
||||
class CFGMemberDtor : public CFGImplicitDtor {
|
||||
public:
|
||||
CFGMemberDtor(const FieldDecl *field)
|
||||
: CFGImplicitDtor(MemberDtor, field, 0) {}
|
||||
: CFGImplicitDtor(MemberDtor, field, nullptr) {}
|
||||
|
||||
const FieldDecl *getFieldDecl() const {
|
||||
return static_cast<const FieldDecl*>(Data1.getPointer());
|
||||
@ -256,7 +281,7 @@ class CFGMemberDtor : public CFGImplicitDtor {
|
||||
class CFGTemporaryDtor : public CFGImplicitDtor {
|
||||
public:
|
||||
CFGTemporaryDtor(CXXBindTemporaryExpr *expr)
|
||||
: CFGImplicitDtor(TemporaryDtor, expr, 0) {}
|
||||
: CFGImplicitDtor(TemporaryDtor, expr, nullptr) {}
|
||||
|
||||
const CXXBindTemporaryExpr *getBindTemporaryExpr() const {
|
||||
return static_cast<const CXXBindTemporaryExpr *>(Data1.getPointer());
|
||||
@ -388,9 +413,64 @@ class CFGBlock {
|
||||
/// 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<CFGBlock*> AdjacentBlocks;
|
||||
typedef BumpVector<AdjacentBlock> AdjacentBlocks;
|
||||
AdjacentBlocks Preds;
|
||||
AdjacentBlocks Succs;
|
||||
|
||||
@ -410,7 +490,7 @@ class CFGBlock {
|
||||
|
||||
public:
|
||||
explicit CFGBlock(unsigned blockid, BumpVectorContext &C, CFG *parent)
|
||||
: Elements(C), Label(NULL), Terminator(NULL), LoopTarget(NULL),
|
||||
: Elements(C), Label(nullptr), Terminator(nullptr), LoopTarget(nullptr),
|
||||
BlockID(blockid), Preds(C, 1), Succs(C, 1), HasNoReturnElement(false),
|
||||
Parent(parent) {}
|
||||
~CFGBlock() {}
|
||||
@ -480,9 +560,11 @@ class CFGBlock {
|
||||
class FilterOptions {
|
||||
public:
|
||||
FilterOptions() {
|
||||
IgnoreNullPredecessors = 1;
|
||||
IgnoreDefaultsWithCoveredEnums = 0;
|
||||
}
|
||||
|
||||
unsigned IgnoreNullPredecessors : 1;
|
||||
unsigned IgnoreDefaultsWithCoveredEnums : 1;
|
||||
};
|
||||
|
||||
@ -495,11 +577,14 @@ class CFGBlock {
|
||||
IMPL I, E;
|
||||
const FilterOptions F;
|
||||
const CFGBlock *From;
|
||||
public:
|
||||
public:
|
||||
explicit FilteredCFGBlockIterator(const IMPL &i, const IMPL &e,
|
||||
const CFGBlock *from,
|
||||
const FilterOptions &f)
|
||||
: I(i), E(e), F(f), From(from) {}
|
||||
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; }
|
||||
|
||||
@ -531,7 +616,7 @@ class CFGBlock {
|
||||
|
||||
// Manipulation of block contents
|
||||
|
||||
void setTerminator(Stmt *Statement) { Terminator = Statement; }
|
||||
void setTerminator(CFGTerminator Term) { Terminator = Term; }
|
||||
void setLabel(Stmt *Statement) { Label = Statement; }
|
||||
void setLoopTarget(const Stmt *loopTarget) { LoopTarget = loopTarget; }
|
||||
void setHasNoReturnElement() { HasNoReturnElement = true; }
|
||||
@ -539,10 +624,10 @@ class CFGBlock {
|
||||
CFGTerminator getTerminator() { return Terminator; }
|
||||
const CFGTerminator getTerminator() const { return Terminator; }
|
||||
|
||||
Stmt *getTerminatorCondition();
|
||||
Stmt *getTerminatorCondition(bool StripParens = true);
|
||||
|
||||
const Stmt *getTerminatorCondition() const {
|
||||
return const_cast<CFGBlock*>(this)->getTerminatorCondition();
|
||||
const Stmt *getTerminatorCondition(bool StripParens = true) const {
|
||||
return const_cast<CFGBlock*>(this)->getTerminatorCondition(StripParens);
|
||||
}
|
||||
|
||||
const Stmt *getLoopTarget() const { return LoopTarget; }
|
||||
@ -556,17 +641,19 @@ class CFGBlock {
|
||||
|
||||
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 addSuccessor(CFGBlock *Block, BumpVectorContext &C) {
|
||||
if (Block)
|
||||
Block->Preds.push_back(this, C);
|
||||
Succs.push_back(Block, C);
|
||||
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);
|
||||
}
|
||||
@ -576,6 +663,11 @@ class CFGBlock {
|
||||
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);
|
||||
}
|
||||
@ -601,7 +693,8 @@ class CFGBlock {
|
||||
// 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(0, 0), C));
|
||||
return iterator(Elements.insert(I.base(), Cnt,
|
||||
CFGAutomaticObjDtor(nullptr, 0), C));
|
||||
}
|
||||
iterator insertAutomaticObjDtor(iterator I, VarDecl *VD, Stmt *S) {
|
||||
*I = CFGAutomaticObjDtor(VD, S);
|
||||
@ -609,6 +702,17 @@ class CFGBlock {
|
||||
}
|
||||
};
|
||||
|
||||
/// \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
|
||||
@ -627,13 +731,14 @@ class CFG {
|
||||
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 alwaysAdd(const Stmt *stmt) const {
|
||||
return alwaysAddMask[stmt->getStmtClass()];
|
||||
@ -650,12 +755,11 @@ class CFG {
|
||||
}
|
||||
|
||||
BuildOptions()
|
||||
: forcedBlkExprs(0), PruneTriviallyFalseEdges(true)
|
||||
,AddEHEdges(false)
|
||||
,AddInitializers(false)
|
||||
,AddImplicitDtors(false)
|
||||
,AddTemporaryDtors(false)
|
||||
,AddStaticInitBranches(false) {}
|
||||
: forcedBlkExprs(nullptr), Observer(nullptr),
|
||||
PruneTriviallyFalseEdges(true), AddEHEdges(false),
|
||||
AddInitializers(false), AddImplicitDtors(false),
|
||||
AddTemporaryDtors(false), AddStaticInitBranches(false),
|
||||
AddCXXNewAllocator(false) {}
|
||||
};
|
||||
|
||||
/// \brief Provides a custom implementation of the iterator class to have the
|
||||
@ -845,8 +949,9 @@ class CFG {
|
||||
// Internal: constructors and data.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
CFG() : Entry(NULL), Exit(NULL), IndirectGotoBlock(NULL), NumBlockIDs(0),
|
||||
Blocks(BlkBVC, 10) {}
|
||||
CFG()
|
||||
: Entry(nullptr), Exit(nullptr), IndirectGotoBlock(nullptr), NumBlockIDs(0),
|
||||
Blocks(BlkBVC, 10) {}
|
||||
|
||||
llvm::BumpPtrAllocator& getAllocator() {
|
||||
return BlkBVC.getAllocator();
|
||||
|
@ -1,342 +0,0 @@
|
||||
//===--- DataflowSolver.h - Skeleton Dataflow Analysis Code -----*- 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 skeleton code for implementing dataflow analyses.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSES_DATAFLOW_SOLVER
|
||||
#define LLVM_CLANG_ANALYSES_DATAFLOW_SOLVER
|
||||
|
||||
#include "functional" // STL
|
||||
#include "clang/Analysis/CFG.h"
|
||||
#include "clang/Analysis/FlowSensitive/DataflowValues.h"
|
||||
#include "clang/Analysis/ProgramPoint.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// DataflowWorkListTy - Data structure representing the worklist used for
|
||||
/// dataflow algorithms.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class DataflowWorkListTy {
|
||||
llvm::DenseMap<const CFGBlock*, unsigned char> BlockSet;
|
||||
SmallVector<const CFGBlock *, 10> BlockQueue;
|
||||
public:
|
||||
/// enqueue - Add a block to the worklist. Blocks already on the
|
||||
/// worklist are not added a second time.
|
||||
void enqueue(const CFGBlock *B) {
|
||||
unsigned char &x = BlockSet[B];
|
||||
if (x == 1)
|
||||
return;
|
||||
x = 1;
|
||||
BlockQueue.push_back(B);
|
||||
}
|
||||
|
||||
/// dequeue - Remove a block from the worklist.
|
||||
const CFGBlock *dequeue() {
|
||||
assert(!BlockQueue.empty());
|
||||
const CFGBlock *B = BlockQueue.pop_back_val();
|
||||
BlockSet[B] = 0;
|
||||
return B;
|
||||
}
|
||||
|
||||
/// isEmpty - Return true if the worklist is empty.
|
||||
bool isEmpty() const { return BlockQueue.empty(); }
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// BlockItrTraits - Traits classes that allow transparent iteration
|
||||
// over successors/predecessors of a block depending on the direction
|
||||
// of our dataflow analysis.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace dataflow {
|
||||
template<typename Tag> struct ItrTraits {};
|
||||
|
||||
template <> struct ItrTraits<forward_analysis_tag> {
|
||||
typedef CFGBlock::const_pred_iterator PrevBItr;
|
||||
typedef CFGBlock::const_succ_iterator NextBItr;
|
||||
typedef CFGBlock::const_iterator StmtItr;
|
||||
|
||||
static PrevBItr PrevBegin(const CFGBlock *B) { return B->pred_begin(); }
|
||||
static PrevBItr PrevEnd(const CFGBlock *B) { return B->pred_end(); }
|
||||
|
||||
static NextBItr NextBegin(const CFGBlock *B) { return B->succ_begin(); }
|
||||
static NextBItr NextEnd(const CFGBlock *B) { return B->succ_end(); }
|
||||
|
||||
static StmtItr StmtBegin(const CFGBlock *B) { return B->begin(); }
|
||||
static StmtItr StmtEnd(const CFGBlock *B) { return B->end(); }
|
||||
|
||||
static BlockEdge PrevEdge(const CFGBlock *B, const CFGBlock *Prev) {
|
||||
return BlockEdge(Prev, B, 0);
|
||||
}
|
||||
|
||||
static BlockEdge NextEdge(const CFGBlock *B, const CFGBlock *Next) {
|
||||
return BlockEdge(B, Next, 0);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct ItrTraits<backward_analysis_tag> {
|
||||
typedef CFGBlock::const_succ_iterator PrevBItr;
|
||||
typedef CFGBlock::const_pred_iterator NextBItr;
|
||||
typedef CFGBlock::const_reverse_iterator StmtItr;
|
||||
|
||||
static PrevBItr PrevBegin(const CFGBlock *B) { return B->succ_begin(); }
|
||||
static PrevBItr PrevEnd(const CFGBlock *B) { return B->succ_end(); }
|
||||
|
||||
static NextBItr NextBegin(const CFGBlock *B) { return B->pred_begin(); }
|
||||
static NextBItr NextEnd(const CFGBlock *B) { return B->pred_end(); }
|
||||
|
||||
static StmtItr StmtBegin(const CFGBlock *B) { return B->rbegin(); }
|
||||
static StmtItr StmtEnd(const CFGBlock *B) { return B->rend(); }
|
||||
|
||||
static BlockEdge PrevEdge(const CFGBlock *B, const CFGBlock *Prev) {
|
||||
return BlockEdge(B, Prev, 0);
|
||||
}
|
||||
|
||||
static BlockEdge NextEdge(const CFGBlock *B, const CFGBlock *Next) {
|
||||
return BlockEdge(Next, B, 0);
|
||||
}
|
||||
};
|
||||
} // end namespace dataflow
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// DataflowSolverTy - Generic dataflow solver.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
template <typename _DFValuesTy, // Usually a subclass of DataflowValues
|
||||
typename _TransferFuncsTy,
|
||||
typename _MergeOperatorTy,
|
||||
typename _Equal = std::equal_to<typename _DFValuesTy::ValTy> >
|
||||
class DataflowSolver {
|
||||
|
||||
//===----------------------------------------------------===//
|
||||
// Type declarations.
|
||||
//===----------------------------------------------------===//
|
||||
|
||||
public:
|
||||
typedef _DFValuesTy DFValuesTy;
|
||||
typedef _TransferFuncsTy TransferFuncsTy;
|
||||
typedef _MergeOperatorTy MergeOperatorTy;
|
||||
|
||||
typedef typename _DFValuesTy::AnalysisDirTag AnalysisDirTag;
|
||||
typedef typename _DFValuesTy::ValTy ValTy;
|
||||
typedef typename _DFValuesTy::EdgeDataMapTy EdgeDataMapTy;
|
||||
typedef typename _DFValuesTy::BlockDataMapTy BlockDataMapTy;
|
||||
|
||||
typedef dataflow::ItrTraits<AnalysisDirTag> ItrTraits;
|
||||
typedef typename ItrTraits::NextBItr NextBItr;
|
||||
typedef typename ItrTraits::PrevBItr PrevBItr;
|
||||
typedef typename ItrTraits::StmtItr StmtItr;
|
||||
|
||||
//===----------------------------------------------------===//
|
||||
// External interface: constructing and running the solver.
|
||||
//===----------------------------------------------------===//
|
||||
|
||||
public:
|
||||
DataflowSolver(DFValuesTy& d) : D(d), TF(d.getAnalysisData()) {}
|
||||
~DataflowSolver() {}
|
||||
|
||||
/// runOnCFG - Computes dataflow values for all blocks in a CFG.
|
||||
void runOnCFG(CFG& cfg, bool recordStmtValues = false) {
|
||||
// Set initial dataflow values and boundary conditions.
|
||||
D.InitializeValues(cfg);
|
||||
// Solve the dataflow equations. This will populate D.EdgeDataMap
|
||||
// with dataflow values.
|
||||
SolveDataflowEquations(cfg, recordStmtValues);
|
||||
}
|
||||
|
||||
/// runOnBlock - Computes dataflow values for a given block. This
|
||||
/// should usually be invoked only after previously computing
|
||||
/// dataflow values using runOnCFG, as runOnBlock is intended to
|
||||
/// only be used for querying the dataflow values within a block
|
||||
/// with and Observer object.
|
||||
void runOnBlock(const CFGBlock *B, bool recordStmtValues) {
|
||||
BlockDataMapTy& M = D.getBlockDataMap();
|
||||
typename BlockDataMapTy::iterator I = M.find(B);
|
||||
|
||||
if (I != M.end()) {
|
||||
TF.getVal().copyValues(I->second);
|
||||
ProcessBlock(B, recordStmtValues, AnalysisDirTag());
|
||||
}
|
||||
}
|
||||
|
||||
void runOnBlock(const CFGBlock &B, bool recordStmtValues) {
|
||||
runOnBlock(&B, recordStmtValues);
|
||||
}
|
||||
void runOnBlock(CFG::iterator &I, bool recordStmtValues) {
|
||||
runOnBlock(*I, recordStmtValues);
|
||||
}
|
||||
void runOnBlock(CFG::const_iterator &I, bool recordStmtValues) {
|
||||
runOnBlock(*I, recordStmtValues);
|
||||
}
|
||||
|
||||
void runOnAllBlocks(const CFG& cfg, bool recordStmtValues = false) {
|
||||
for (CFG::const_iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I)
|
||||
runOnBlock(I, recordStmtValues);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------===//
|
||||
// Internal solver logic.
|
||||
//===----------------------------------------------------===//
|
||||
|
||||
private:
|
||||
|
||||
/// SolveDataflowEquations - Perform the actual worklist algorithm
|
||||
/// to compute dataflow values.
|
||||
void SolveDataflowEquations(CFG& cfg, bool recordStmtValues) {
|
||||
EnqueueBlocksOnWorklist(cfg, AnalysisDirTag());
|
||||
|
||||
while (!WorkList.isEmpty()) {
|
||||
const CFGBlock *B = WorkList.dequeue();
|
||||
ProcessMerge(cfg, B);
|
||||
ProcessBlock(B, recordStmtValues, AnalysisDirTag());
|
||||
UpdateEdges(cfg, B, TF.getVal());
|
||||
}
|
||||
}
|
||||
|
||||
void EnqueueBlocksOnWorklist(CFG &cfg, dataflow::forward_analysis_tag) {
|
||||
// Enqueue all blocks to ensure the dataflow values are computed
|
||||
// for every block. Not all blocks are guaranteed to reach the exit block.
|
||||
for (CFG::iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I)
|
||||
WorkList.enqueue(&**I);
|
||||
}
|
||||
|
||||
void EnqueueBlocksOnWorklist(CFG &cfg, dataflow::backward_analysis_tag) {
|
||||
// Enqueue all blocks to ensure the dataflow values are computed
|
||||
// for every block. Not all blocks are guaranteed to reach the exit block.
|
||||
// Enqueue in reverse order since that will more likely match with
|
||||
// the order they should ideally processed by the dataflow algorithm.
|
||||
for (CFG::reverse_iterator I=cfg.rbegin(), E=cfg.rend(); I!=E; ++I)
|
||||
WorkList.enqueue(&**I);
|
||||
}
|
||||
|
||||
void ProcessMerge(CFG& cfg, const CFGBlock *B) {
|
||||
ValTy& V = TF.getVal();
|
||||
TF.SetTopValue(V);
|
||||
|
||||
// Merge dataflow values from all predecessors of this block.
|
||||
MergeOperatorTy Merge;
|
||||
|
||||
EdgeDataMapTy& M = D.getEdgeDataMap();
|
||||
bool firstMerge = true;
|
||||
bool noEdges = true;
|
||||
for (PrevBItr I=ItrTraits::PrevBegin(B),E=ItrTraits::PrevEnd(B); I!=E; ++I){
|
||||
|
||||
CFGBlock *PrevBlk = *I;
|
||||
|
||||
if (!PrevBlk)
|
||||
continue;
|
||||
|
||||
typename EdgeDataMapTy::iterator EI =
|
||||
M.find(ItrTraits::PrevEdge(B, PrevBlk));
|
||||
|
||||
if (EI != M.end()) {
|
||||
noEdges = false;
|
||||
if (firstMerge) {
|
||||
firstMerge = false;
|
||||
V.copyValues(EI->second);
|
||||
}
|
||||
else
|
||||
Merge(V, EI->second);
|
||||
}
|
||||
}
|
||||
|
||||
bool isInitialized = true;
|
||||
typename BlockDataMapTy::iterator BI = D.getBlockDataMap().find(B);
|
||||
if(BI == D.getBlockDataMap().end()) {
|
||||
isInitialized = false;
|
||||
BI = D.getBlockDataMap().insert( std::make_pair(B,ValTy()) ).first;
|
||||
}
|
||||
// If no edges have been found, it means this is the first time the solver
|
||||
// has been called on block B, we copy the initialization values (if any)
|
||||
// as current value for V (which will be used as edge data)
|
||||
if(noEdges && isInitialized)
|
||||
Merge(V, BI->second);
|
||||
|
||||
// Set the data for the block.
|
||||
BI->second.copyValues(V);
|
||||
}
|
||||
|
||||
/// ProcessBlock - Process the transfer functions for a given block.
|
||||
void ProcessBlock(const CFGBlock *B, bool recordStmtValues,
|
||||
dataflow::forward_analysis_tag) {
|
||||
|
||||
TF.setCurrentBlock(B);
|
||||
|
||||
for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I) {
|
||||
CFGElement El = *I;
|
||||
if (const CFGStmt *S = El.getAs<CFGStmt>())
|
||||
ProcessStmt(S->getStmt(), recordStmtValues, AnalysisDirTag());
|
||||
}
|
||||
|
||||
TF.VisitTerminator(const_cast<CFGBlock*>(B));
|
||||
}
|
||||
|
||||
void ProcessBlock(const CFGBlock *B, bool recordStmtValues,
|
||||
dataflow::backward_analysis_tag) {
|
||||
|
||||
TF.setCurrentBlock(B);
|
||||
|
||||
TF.VisitTerminator(const_cast<CFGBlock*>(B));
|
||||
|
||||
for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I) {
|
||||
CFGElement El = *I;
|
||||
if (const CFGStmt *S = El.getAs<CFGStmt>())
|
||||
ProcessStmt(S->getStmt(), recordStmtValues, AnalysisDirTag());
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessStmt(const Stmt *S, bool record, dataflow::forward_analysis_tag) {
|
||||
if (record) D.getStmtDataMap()[S] = TF.getVal();
|
||||
TF.BlockStmt_Visit(const_cast<Stmt*>(S));
|
||||
}
|
||||
|
||||
void ProcessStmt(const Stmt *S, bool record, dataflow::backward_analysis_tag){
|
||||
TF.BlockStmt_Visit(const_cast<Stmt*>(S));
|
||||
if (record) D.getStmtDataMap()[S] = TF.getVal();
|
||||
}
|
||||
|
||||
/// UpdateEdges - After processing the transfer functions for a
|
||||
/// block, update the dataflow value associated with the block's
|
||||
/// outgoing/incoming edges (depending on whether we do a
|
||||
// forward/backward analysis respectively)
|
||||
void UpdateEdges(CFG& cfg, const CFGBlock *B, ValTy& V) {
|
||||
for (NextBItr I=ItrTraits::NextBegin(B), E=ItrTraits::NextEnd(B); I!=E; ++I)
|
||||
if (CFGBlock *NextBlk = *I)
|
||||
UpdateEdgeValue(ItrTraits::NextEdge(B, NextBlk),V, NextBlk);
|
||||
}
|
||||
|
||||
/// UpdateEdgeValue - Update the value associated with a given edge.
|
||||
void UpdateEdgeValue(BlockEdge E, ValTy& V, const CFGBlock *TargetBlock) {
|
||||
EdgeDataMapTy& M = D.getEdgeDataMap();
|
||||
typename EdgeDataMapTy::iterator I = M.find(E);
|
||||
|
||||
if (I == M.end()) { // First computed value for this edge?
|
||||
M[E].copyValues(V);
|
||||
WorkList.enqueue(TargetBlock);
|
||||
}
|
||||
else if (!_Equal()(V,I->second)) {
|
||||
I->second.copyValues(V);
|
||||
WorkList.enqueue(TargetBlock);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
DFValuesTy& D;
|
||||
DataflowWorkListTy WorkList;
|
||||
TransferFuncsTy TF;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
#endif
|
@ -77,9 +77,9 @@ class ProgramPoint {
|
||||
ProgramPoint(const void *P,
|
||||
Kind k,
|
||||
const LocationContext *l,
|
||||
const ProgramPointTag *tag = 0)
|
||||
const ProgramPointTag *tag = nullptr)
|
||||
: Data1(P),
|
||||
Data2(0, (((unsigned) k) >> 0) & 0x3),
|
||||
Data2(nullptr, (((unsigned) k) >> 0) & 0x3),
|
||||
L(l, (((unsigned) k) >> 2) & 0x3),
|
||||
Tag(tag, (((unsigned) k) >> 4) & 0x3) {
|
||||
assert(getKind() == k);
|
||||
@ -91,7 +91,7 @@ class ProgramPoint {
|
||||
const void *P2,
|
||||
Kind k,
|
||||
const LocationContext *l,
|
||||
const ProgramPointTag *tag = 0)
|
||||
const ProgramPointTag *tag = nullptr)
|
||||
: Data1(P1),
|
||||
Data2(P2, (((unsigned) k) >> 0) & 0x3),
|
||||
L(l, (((unsigned) k) >> 2) & 0x3),
|
||||
@ -193,7 +193,7 @@ class ProgramPoint {
|
||||
class BlockEntrance : public ProgramPoint {
|
||||
public:
|
||||
BlockEntrance(const CFGBlock *B, const LocationContext *L,
|
||||
const ProgramPointTag *tag = 0)
|
||||
const ProgramPointTag *tag = nullptr)
|
||||
: ProgramPoint(B, BlockEntranceKind, L, tag) {
|
||||
assert(B && "BlockEntrance requires non-null block");
|
||||
}
|
||||
@ -263,7 +263,7 @@ class StmtPoint : public ProgramPoint {
|
||||
class PreStmt : public StmtPoint {
|
||||
public:
|
||||
PreStmt(const Stmt *S, const LocationContext *L, const ProgramPointTag *tag,
|
||||
const Stmt *SubStmt = 0)
|
||||
const Stmt *SubStmt = nullptr)
|
||||
: StmtPoint(S, SubStmt, PreStmtKind, L, tag) {}
|
||||
|
||||
const Stmt *getSubStmt() const { return (const Stmt*) getData2(); }
|
||||
@ -280,17 +280,17 @@ class PostStmt : public StmtPoint {
|
||||
protected:
|
||||
PostStmt() {}
|
||||
PostStmt(const Stmt *S, const void *data, Kind k, const LocationContext *L,
|
||||
const ProgramPointTag *tag = 0)
|
||||
const ProgramPointTag *tag = nullptr)
|
||||
: StmtPoint(S, data, k, L, tag) {}
|
||||
|
||||
public:
|
||||
explicit PostStmt(const Stmt *S, Kind k,
|
||||
const LocationContext *L, const ProgramPointTag *tag = 0)
|
||||
: StmtPoint(S, NULL, k, L, tag) {}
|
||||
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 = 0)
|
||||
: StmtPoint(S, NULL, PostStmtKind, L, tag) {}
|
||||
const ProgramPointTag *tag = nullptr)
|
||||
: StmtPoint(S, nullptr, PostStmtKind, L, tag) {}
|
||||
|
||||
private:
|
||||
friend class ProgramPoint;
|
||||
@ -304,7 +304,7 @@ class PostStmt : public StmtPoint {
|
||||
class PostCondition : public PostStmt {
|
||||
public:
|
||||
PostCondition(const Stmt *S, const LocationContext *L,
|
||||
const ProgramPointTag *tag = 0)
|
||||
const ProgramPointTag *tag = nullptr)
|
||||
: PostStmt(S, PostConditionKind, L, tag) {}
|
||||
|
||||
private:
|
||||
@ -320,7 +320,7 @@ class LocationCheck : public StmtPoint {
|
||||
LocationCheck() {}
|
||||
LocationCheck(const Stmt *S, const LocationContext *L,
|
||||
ProgramPoint::Kind K, const ProgramPointTag *tag)
|
||||
: StmtPoint(S, NULL, K, L, tag) {}
|
||||
: StmtPoint(S, nullptr, K, L, tag) {}
|
||||
|
||||
private:
|
||||
friend class ProgramPoint;
|
||||
@ -333,7 +333,7 @@ class LocationCheck : public StmtPoint {
|
||||
class PreLoad : public LocationCheck {
|
||||
public:
|
||||
PreLoad(const Stmt *S, const LocationContext *L,
|
||||
const ProgramPointTag *tag = 0)
|
||||
const ProgramPointTag *tag = nullptr)
|
||||
: LocationCheck(S, L, PreLoadKind, tag) {}
|
||||
|
||||
private:
|
||||
@ -347,7 +347,7 @@ class PreLoad : public LocationCheck {
|
||||
class PreStore : public LocationCheck {
|
||||
public:
|
||||
PreStore(const Stmt *S, const LocationContext *L,
|
||||
const ProgramPointTag *tag = 0)
|
||||
const ProgramPointTag *tag = nullptr)
|
||||
: LocationCheck(S, L, PreStoreKind, tag) {}
|
||||
|
||||
private:
|
||||
@ -361,7 +361,7 @@ class PreStore : public LocationCheck {
|
||||
class PostLoad : public PostStmt {
|
||||
public:
|
||||
PostLoad(const Stmt *S, const LocationContext *L,
|
||||
const ProgramPointTag *tag = 0)
|
||||
const ProgramPointTag *tag = nullptr)
|
||||
: PostStmt(S, PostLoadKind, L, tag) {}
|
||||
|
||||
private:
|
||||
@ -379,9 +379,9 @@ class PostStore : public PostStmt {
|
||||
/// \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 = 0)
|
||||
const ProgramPointTag *tag = nullptr)
|
||||
: PostStmt(S, PostStoreKind, L, tag) {
|
||||
assert(getData2() == 0);
|
||||
assert(getData2() == nullptr);
|
||||
setData2(Loc);
|
||||
}
|
||||
|
||||
@ -402,7 +402,7 @@ class PostStore : public PostStmt {
|
||||
class PostLValue : public PostStmt {
|
||||
public:
|
||||
PostLValue(const Stmt *S, const LocationContext *L,
|
||||
const ProgramPointTag *tag = 0)
|
||||
const ProgramPointTag *tag = nullptr)
|
||||
: PostStmt(S, PostLValueKind, L, tag) {}
|
||||
|
||||
private:
|
||||
@ -418,8 +418,8 @@ class PostLValue : public PostStmt {
|
||||
class PreStmtPurgeDeadSymbols : public StmtPoint {
|
||||
public:
|
||||
PreStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L,
|
||||
const ProgramPointTag *tag = 0)
|
||||
: StmtPoint(S, 0, PreStmtPurgeDeadSymbolsKind, L, tag) { }
|
||||
const ProgramPointTag *tag = nullptr)
|
||||
: StmtPoint(S, nullptr, PreStmtPurgeDeadSymbolsKind, L, tag) { }
|
||||
|
||||
private:
|
||||
friend class ProgramPoint;
|
||||
@ -434,8 +434,8 @@ class PreStmtPurgeDeadSymbols : public StmtPoint {
|
||||
class PostStmtPurgeDeadSymbols : public StmtPoint {
|
||||
public:
|
||||
PostStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L,
|
||||
const ProgramPointTag *tag = 0)
|
||||
: StmtPoint(S, 0, PostStmtPurgeDeadSymbolsKind, L, tag) { }
|
||||
const ProgramPointTag *tag = nullptr)
|
||||
: StmtPoint(S, nullptr, PostStmtPurgeDeadSymbolsKind, L, tag) { }
|
||||
|
||||
private:
|
||||
friend class ProgramPoint;
|
||||
@ -527,8 +527,8 @@ class ImplicitCallPoint : public ProgramPoint {
|
||||
/// 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 = 0)
|
||||
PreImplicitCall(const Decl *D, SourceLocation Loc, const LocationContext *L,
|
||||
const ProgramPointTag *Tag = nullptr)
|
||||
: ImplicitCallPoint(D, Loc, PreImplicitCallKind, L, Tag) {}
|
||||
|
||||
private:
|
||||
@ -544,8 +544,8 @@ class PreImplicitCall : public ImplicitCallPoint {
|
||||
/// 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 = 0)
|
||||
PostImplicitCall(const Decl *D, SourceLocation Loc, const LocationContext *L,
|
||||
const ProgramPointTag *Tag = nullptr)
|
||||
: ImplicitCallPoint(D, Loc, PostImplicitCallKind, L, Tag) {}
|
||||
|
||||
private:
|
||||
@ -562,7 +562,7 @@ class CallEnter : public ProgramPoint {
|
||||
public:
|
||||
CallEnter(const Stmt *stmt, const StackFrameContext *calleeCtx,
|
||||
const LocationContext *callerCtx)
|
||||
: ProgramPoint(stmt, calleeCtx, CallEnterKind, callerCtx, 0) {}
|
||||
: ProgramPoint(stmt, calleeCtx, CallEnterKind, callerCtx, nullptr) {}
|
||||
|
||||
const Stmt *getCallExpr() const {
|
||||
return static_cast<const Stmt *>(getData1());
|
||||
@ -593,7 +593,7 @@ class CallExitBegin : public ProgramPoint {
|
||||
public:
|
||||
// CallExitBegin uses the callee's location context.
|
||||
CallExitBegin(const StackFrameContext *L)
|
||||
: ProgramPoint(0, CallExitBeginKind, L, 0) {}
|
||||
: ProgramPoint(nullptr, CallExitBeginKind, L, nullptr) {}
|
||||
|
||||
private:
|
||||
friend class ProgramPoint;
|
||||
@ -610,7 +610,7 @@ class CallExitEnd : public ProgramPoint {
|
||||
// CallExitEnd uses the caller's location context.
|
||||
CallExitEnd(const StackFrameContext *CalleeCtx,
|
||||
const LocationContext *CallerCtx)
|
||||
: ProgramPoint(CalleeCtx, CallExitEndKind, CallerCtx, 0) {}
|
||||
: ProgramPoint(CalleeCtx, CallExitEndKind, CallerCtx, nullptr) {}
|
||||
|
||||
const StackFrameContext *getCalleeContext() const {
|
||||
return static_cast<const StackFrameContext *>(getData1());
|
||||
@ -629,7 +629,8 @@ class CallExitEnd : public ProgramPoint {
|
||||
class EpsilonPoint : public ProgramPoint {
|
||||
public:
|
||||
EpsilonPoint(const LocationContext *L, const void *Data1,
|
||||
const void *Data2 = 0, const ProgramPointTag *tag = 0)
|
||||
const void *Data2 = nullptr,
|
||||
const ProgramPointTag *tag = nullptr)
|
||||
: ProgramPoint(Data1, Data2, EpsilonKind, L, tag) {}
|
||||
|
||||
const void *getData() const { return getData1(); }
|
||||
@ -647,7 +648,7 @@ class EpsilonPoint : public ProgramPoint {
|
||||
/// description and potentially other information.
|
||||
class ProgramPointTag {
|
||||
public:
|
||||
ProgramPointTag(void *tagKind = 0) : TagKind(tagKind) {}
|
||||
ProgramPointTag(void *tagKind = nullptr) : TagKind(tagKind) {}
|
||||
virtual ~ProgramPointTag();
|
||||
virtual StringRef getTagDescription() const = 0;
|
||||
|
||||
@ -658,12 +659,12 @@ class ProgramPointTag {
|
||||
private:
|
||||
const void *TagKind;
|
||||
};
|
||||
|
||||
|
||||
class SimpleProgramPointTag : public ProgramPointTag {
|
||||
std::string desc;
|
||||
std::string Desc;
|
||||
public:
|
||||
SimpleProgramPointTag(StringRef description);
|
||||
StringRef getTagDescription() const;
|
||||
SimpleProgramPointTag(StringRef MsgProvider, StringRef Msg);
|
||||
StringRef getTagDescription() const override;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
@ -676,13 +677,13 @@ 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), 0);
|
||||
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), 0);
|
||||
return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), nullptr);
|
||||
}
|
||||
|
||||
static unsigned getHashValue(const clang::ProgramPoint &Loc) {
|
||||
|
@ -55,12 +55,12 @@ class BumpVector {
|
||||
public:
|
||||
// Default ctor - Initialize to empty.
|
||||
explicit BumpVector(BumpVectorContext &C, unsigned N)
|
||||
: Begin(NULL), End(NULL), Capacity(NULL) {
|
||||
: Begin(nullptr), End(nullptr), Capacity(nullptr) {
|
||||
reserve(C, N);
|
||||
}
|
||||
|
||||
~BumpVector() {
|
||||
if (llvm::is_class<T>::value) {
|
||||
if (std::is_class<T>::value) {
|
||||
// Destroy the constructed elements in the vector.
|
||||
destroy_range(Begin, End);
|
||||
}
|
||||
@ -130,7 +130,7 @@ class BumpVector {
|
||||
}
|
||||
|
||||
void clear() {
|
||||
if (llvm::is_class<T>::value) {
|
||||
if (std::is_class<T>::value) {
|
||||
destroy_range(Begin, End);
|
||||
}
|
||||
End = Begin;
|
||||
@ -223,7 +223,7 @@ void BumpVector<T>::grow(BumpVectorContext &C, size_t MinSize) {
|
||||
T *NewElts = C.getAllocator().template Allocate<T>(NewCapacity);
|
||||
|
||||
// Copy the elements over.
|
||||
if (llvm::is_class<T>::value) {
|
||||
if (std::is_class<T>::value) {
|
||||
std::uninitialized_copy(Begin, End, NewElts);
|
||||
// Destroy the original elements.
|
||||
destroy_range(Begin, End);
|
||||
|
@ -186,10 +186,10 @@ struct ThunkInfo {
|
||||
/// an ABI-specific comparator.
|
||||
const CXXMethodDecl *Method;
|
||||
|
||||
ThunkInfo() : Method(0) { }
|
||||
ThunkInfo() : Method(nullptr) { }
|
||||
|
||||
ThunkInfo(const ThisAdjustment &This, const ReturnAdjustment &Return,
|
||||
const CXXMethodDecl *Method = 0)
|
||||
const CXXMethodDecl *Method = nullptr)
|
||||
: This(This), Return(Return), Method(Method) {}
|
||||
|
||||
friend bool operator==(const ThunkInfo &LHS, const ThunkInfo &RHS) {
|
||||
@ -197,7 +197,9 @@ struct ThunkInfo {
|
||||
LHS.Method == RHS.Method;
|
||||
}
|
||||
|
||||
bool isEmpty() const { return This.isEmpty() && Return.isEmpty() && Method == 0; }
|
||||
bool isEmpty() const {
|
||||
return This.isEmpty() && Return.isEmpty() && Method == nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
File diff suppressed because it is too large
Load Diff
1105
contrib/llvm/tools/clang/include/clang/Basic/AttrDocs.td
Normal file
1105
contrib/llvm/tools/clang/include/clang/Basic/AttrDocs.td
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user