summaryrefslogtreecommitdiffstats
path: root/include/clang/AST
diff options
context:
space:
mode:
Diffstat (limited to 'include/clang/AST')
-rw-r--r--include/clang/AST/ASTContext.h41
-rw-r--r--include/clang/AST/ASTDiagnostic.h12
-rw-r--r--include/clang/AST/ASTDumperUtils.h181
-rw-r--r--include/clang/AST/ASTImporter.h167
-rw-r--r--include/clang/AST/CanonicalType.h2
-rw-r--r--include/clang/AST/CommentDiagnostic.h15
-rw-r--r--include/clang/AST/CommentVisitor.h34
-rw-r--r--include/clang/AST/Decl.h40
-rw-r--r--include/clang/AST/DeclBase.h8
-rw-r--r--include/clang/AST/DeclCXX.h10
-rw-r--r--include/clang/AST/DeclTemplate.h3
-rw-r--r--include/clang/AST/DeclVisitor.h13
-rw-r--r--include/clang/AST/EvaluatedExprVisitor.h18
-rw-r--r--include/clang/AST/Expr.h848
-rw-r--r--include/clang/AST/ExprCXX.h298
-rw-r--r--include/clang/AST/FormatString.h752
-rw-r--r--include/clang/AST/GlobalDecl.h28
-rw-r--r--include/clang/AST/NestedNameSpecifier.h11
-rw-r--r--include/clang/AST/OSLog.h161
-rw-r--r--include/clang/AST/OpenMPClause.h189
-rw-r--r--include/clang/AST/OperationKinds.def16
-rw-r--r--include/clang/AST/PrettyPrinter.h35
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h36
-rw-r--r--include/clang/AST/Stmt.h1479
-rw-r--r--include/clang/AST/StmtDataCollectors.td2
-rw-r--r--include/clang/AST/StmtOpenMP.h36
-rw-r--r--include/clang/AST/StmtVisitor.h16
-rw-r--r--include/clang/AST/TextNodeDumper.h87
-rw-r--r--include/clang/AST/Type.h566
29 files changed, 3889 insertions, 1215 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 5b693eb97f..7edf3b3fed 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -569,26 +569,6 @@ public:
IntrusiveRefCntPtr<ExternalASTSource> ExternalSource;
ASTMutationListener *Listener = nullptr;
- /// Contains parents of a node.
- using ParentVector = llvm::SmallVector<ast_type_traits::DynTypedNode, 2>;
-
- /// Maps from a node to its parents. This is used for nodes that have
- /// pointer identity only, which are more common and we can save space by
- /// only storing a unique pointer to them.
- using ParentMapPointers =
- llvm::DenseMap<const void *,
- llvm::PointerUnion4<const Decl *, const Stmt *,
- ast_type_traits::DynTypedNode *,
- ParentVector *>>;
-
- /// Parent map for nodes without pointer identity. We store a full
- /// DynTypedNode for all keys.
- using ParentMapOtherNodes =
- llvm::DenseMap<ast_type_traits::DynTypedNode,
- llvm::PointerUnion4<const Decl *, const Stmt *,
- ast_type_traits::DynTypedNode *,
- ParentVector *>>;
-
/// Container for either a single DynTypedNode or for an ArrayRef to
/// DynTypedNode. For use with ParentMap.
class DynTypedNodeList {
@@ -630,7 +610,17 @@ public:
}
};
- /// Returns the parents of the given node.
+ // A traversal scope limits the parts of the AST visible to certain analyses.
+ // RecursiveASTVisitor::TraverseAST will only visit reachable nodes, and
+ // getParents() will only observe reachable parent edges.
+ //
+ // The scope is defined by a set of "top-level" declarations.
+ // Initially, it is the entire TU: {getTranslationUnitDecl()}.
+ // Changing the scope clears the parent cache, which is expensive to rebuild.
+ std::vector<Decl *> getTraversalScope() const { return TraversalScope; }
+ void setTraversalScope(const std::vector<Decl *> &);
+
+ /// Returns the parents of the given node (within the traversal scope).
///
/// Note that this will lazily compute the parents of all nodes
/// and store them for later retrieval. Thus, the first call is O(n)
@@ -1062,6 +1052,9 @@ public:
CanQualType OCLSamplerTy, OCLEventTy, OCLClkEventTy;
CanQualType OCLQueueTy, OCLReserveIDTy;
CanQualType OMPArraySectionTy;
+#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
+ CanQualType Id##Ty;
+#include "clang/Basic/OpenCLExtensionTypes.def"
// Types for deductions in C++0x [stmt.ranged]'s desugaring. Built on demand.
mutable QualType AutoDeductTy; // Deduction against 'auto'.
@@ -2921,13 +2914,13 @@ private:
// but we include it here so that ASTContext can quickly deallocate them.
llvm::PointerIntPair<StoredDeclsMap *, 1> LastSDM;
- std::unique_ptr<ParentMapPointers> PointerParents;
- std::unique_ptr<ParentMapOtherNodes> OtherParents;
+ std::vector<Decl *> TraversalScope;
+ class ParentMap;
+ std::unique_ptr<ParentMap> Parents;
std::unique_ptr<VTableContextBase> VTContext;
void ReleaseDeclContextMaps();
- void ReleaseParentMapEntries();
public:
enum PragmaSectionFlag : unsigned {
diff --git a/include/clang/AST/ASTDiagnostic.h b/include/clang/AST/ASTDiagnostic.h
index 2534272da3..fe92604587 100644
--- a/include/clang/AST/ASTDiagnostic.h
+++ b/include/clang/AST/ASTDiagnostic.h
@@ -11,19 +11,9 @@
#define LLVM_CLANG_AST_ASTDIAGNOSTIC_H
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticAST.h"
namespace clang {
- namespace diag {
- enum {
-#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
- SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
-#define ASTSTART
-#include "clang/Basic/DiagnosticASTKinds.inc"
-#undef DIAG
- NUM_BUILTIN_AST_DIAGNOSTICS
- };
- } // end namespace diag
-
/// DiagnosticsEngine argument formatting function for diagnostics that
/// involve AST nodes.
///
diff --git a/include/clang/AST/ASTDumperUtils.h b/include/clang/AST/ASTDumperUtils.h
new file mode 100644
index 0000000000..129c40ce3e
--- /dev/null
+++ b/include/clang/AST/ASTDumperUtils.h
@@ -0,0 +1,181 @@
+//===--- ASTDumperUtils.h - Printing of AST nodes -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements AST utilities for traversal down the tree.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_ASTDUMPERUTILS_H
+#define LLVM_CLANG_AST_ASTDUMPERUTILS_H
+
+#include "clang/AST/ASTContext.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+
+// Colors used for various parts of the AST dump
+// Do not use bold yellow for any text. It is hard to read on white screens.
+
+struct TerminalColor {
+ raw_ostream::Colors Color;
+ bool Bold;
+};
+
+// Red - CastColor
+// Green - TypeColor
+// Bold Green - DeclKindNameColor, UndeserializedColor
+// Yellow - AddressColor, LocationColor
+// Blue - CommentColor, NullColor, IndentColor
+// Bold Blue - AttrColor
+// Bold Magenta - StmtColor
+// Cyan - ValueKindColor, ObjectKindColor
+// Bold Cyan - ValueColor, DeclNameColor
+
+// Decl kind names (VarDecl, FunctionDecl, etc)
+static const TerminalColor DeclKindNameColor = {raw_ostream::GREEN, true};
+// Attr names (CleanupAttr, GuardedByAttr, etc)
+static const TerminalColor AttrColor = {raw_ostream::BLUE, true};
+// Statement names (DeclStmt, ImplicitCastExpr, etc)
+static const TerminalColor StmtColor = {raw_ostream::MAGENTA, true};
+// Comment names (FullComment, ParagraphComment, TextComment, etc)
+static const TerminalColor CommentColor = {raw_ostream::BLUE, false};
+
+// Type names (int, float, etc, plus user defined types)
+static const TerminalColor TypeColor = {raw_ostream::GREEN, false};
+
+// Pointer address
+static const TerminalColor AddressColor = {raw_ostream::YELLOW, false};
+// Source locations
+static const TerminalColor LocationColor = {raw_ostream::YELLOW, false};
+
+// lvalue/xvalue
+static const TerminalColor ValueKindColor = {raw_ostream::CYAN, false};
+// bitfield/objcproperty/objcsubscript/vectorcomponent
+static const TerminalColor ObjectKindColor = {raw_ostream::CYAN, false};
+
+// Null statements
+static const TerminalColor NullColor = {raw_ostream::BLUE, false};
+
+// Undeserialized entities
+static const TerminalColor UndeserializedColor = {raw_ostream::GREEN, true};
+
+// CastKind from CastExpr's
+static const TerminalColor CastColor = {raw_ostream::RED, false};
+
+// Value of the statement
+static const TerminalColor ValueColor = {raw_ostream::CYAN, true};
+// Decl names
+static const TerminalColor DeclNameColor = {raw_ostream::CYAN, true};
+
+// Indents ( `, -. | )
+static const TerminalColor IndentColor = {raw_ostream::BLUE, false};
+
+class ColorScope {
+ raw_ostream &OS;
+ const bool ShowColors;
+
+public:
+ ColorScope(raw_ostream &OS, bool ShowColors, TerminalColor Color)
+ : OS(OS), ShowColors(ShowColors) {
+ if (ShowColors)
+ OS.changeColor(Color.Color, Color.Bold);
+ }
+ ~ColorScope() {
+ if (ShowColors)
+ OS.resetColor();
+ }
+};
+
+class TextTreeStructure {
+ raw_ostream &OS;
+ const bool ShowColors;
+
+ /// Pending[i] is an action to dump an entity at level i.
+ llvm::SmallVector<std::function<void(bool isLastChild)>, 32> Pending;
+
+ /// Indicates whether we're at the top level.
+ bool TopLevel = true;
+
+ /// Indicates if we're handling the first child after entering a new depth.
+ bool FirstChild = true;
+
+ /// Prefix for currently-being-dumped entity.
+ std::string Prefix;
+
+public:
+ /// Add a child of the current node. Calls doAddChild without arguments
+ template <typename Fn> void addChild(Fn doAddChild) {
+ // If we're at the top level, there's nothing interesting to do; just
+ // run the dumper.
+ if (TopLevel) {
+ TopLevel = false;
+ doAddChild();
+ while (!Pending.empty()) {
+ Pending.back()(true);
+ Pending.pop_back();
+ }
+ Prefix.clear();
+ OS << "\n";
+ TopLevel = true;
+ return;
+ }
+
+ auto dumpWithIndent = [this, doAddChild](bool isLastChild) {
+ // Print out the appropriate tree structure and work out the prefix for
+ // children of this node. For instance:
+ //
+ // A Prefix = ""
+ // |-B Prefix = "| "
+ // | `-C Prefix = "| "
+ // `-D Prefix = " "
+ // |-E Prefix = " | "
+ // `-F Prefix = " "
+ // G Prefix = ""
+ //
+ // Note that the first level gets no prefix.
+ {
+ OS << '\n';
+ ColorScope Color(OS, ShowColors, IndentColor);
+ OS << Prefix << (isLastChild ? '`' : '|') << '-';
+ this->Prefix.push_back(isLastChild ? ' ' : '|');
+ this->Prefix.push_back(' ');
+ }
+
+ FirstChild = true;
+ unsigned Depth = Pending.size();
+
+ doAddChild();
+
+ // If any children are left, they're the last at their nesting level.
+ // Dump those ones out now.
+ while (Depth < Pending.size()) {
+ Pending.back()(true);
+ this->Pending.pop_back();
+ }
+
+ // Restore the old prefix.
+ this->Prefix.resize(Prefix.size() - 2);
+ };
+
+ if (FirstChild) {
+ Pending.push_back(std::move(dumpWithIndent));
+ } else {
+ Pending.back()(false);
+ Pending.back() = std::move(dumpWithIndent);
+ }
+ FirstChild = false;
+ }
+
+ TextTreeStructure(raw_ostream &OS, bool ShowColors)
+ : OS(OS), ShowColors(ShowColors) {}
+};
+
+} // namespace clang
+
+#endif // LLVM_CLANG_AST_ASTDUMPERUTILS_H
diff --git a/include/clang/AST/ASTImporter.h b/include/clang/AST/ASTImporter.h
index 311d64e7cb..cbd5c3414b 100644
--- a/include/clang/AST/ASTImporter.h
+++ b/include/clang/AST/ASTImporter.h
@@ -25,7 +25,9 @@
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Error.h"
#include <utility>
namespace clang {
@@ -43,6 +45,29 @@ class TagDecl;
class TypeSourceInfo;
class Attr;
+ class ImportError : public llvm::ErrorInfo<ImportError> {
+ public:
+ /// \brief Kind of error when importing an AST component.
+ enum ErrorKind {
+ NameConflict, /// Naming ambiguity (likely ODR violation).
+ UnsupportedConstruct, /// Not supported node or case.
+ Unknown /// Other error.
+ };
+
+ ErrorKind Error;
+
+ static char ID;
+
+ ImportError() : Error(Unknown) { }
+ ImportError(const ImportError &Other) : Error(Other.Error) { }
+ ImportError(ErrorKind Error) : Error(Error) { }
+
+ std::string toString() const;
+
+ void log(raw_ostream &OS) const override;
+ std::error_code convertToErrorCode() const override;
+ };
+
// \brief Returns with a list of declarations started from the canonical decl
// then followed by subsequent decls in the translation unit.
// This gives a canonical list for each entry in the redecl chain.
@@ -122,31 +147,60 @@ class Attr;
/// to-be-completed forward declarations when possible.
bool isMinimalImport() const { return Minimal; }
+ /// \brief Import the given object, returns the result.
+ ///
+ /// \param To Import the object into this variable.
+ /// \param From Object to import.
+ /// \return Error information (success or error).
+ template <typename ImportT>
+ LLVM_NODISCARD llvm::Error importInto(ImportT &To, const ImportT &From) {
+ To = Import(From);
+ if (From && !To)
+ return llvm::make_error<ImportError>();
+ return llvm::Error::success();
+ // FIXME: this should be the final code
+ //auto ToOrErr = Import(From);
+ //if (ToOrErr)
+ // To = *ToOrErr;
+ //return ToOrErr.takeError();
+ }
+
/// Import the given type from the "from" context into the "to"
- /// context.
+ /// context. A null type is imported as a null type (no error).
///
- /// \returns the equivalent type in the "to" context, or a NULL type if
- /// an error occurred.
+ /// \returns The equivalent type in the "to" context, or the import error.
+ llvm::Expected<QualType> Import_New(QualType FromT);
+ // FIXME: Remove this version.
QualType Import(QualType FromT);
/// Import the given type source information from the
/// "from" context into the "to" context.
///
- /// \returns the equivalent type source information in the "to"
- /// context, or NULL if an error occurred.
+ /// \returns The equivalent type source information in the "to"
+ /// context, or the import error.
+ llvm::Expected<TypeSourceInfo *> Import_New(TypeSourceInfo *FromTSI);
+ // FIXME: Remove this version.
TypeSourceInfo *Import(TypeSourceInfo *FromTSI);
/// Import the given attribute from the "from" context into the
/// "to" context.
///
- /// \returns the equivalent attribute in the "to" context.
+ /// \returns The equivalent attribute in the "to" context, or the import
+ /// error.
+ llvm::Expected<Attr *> Import_New(const Attr *FromAttr);
+ // FIXME: Remove this version.
Attr *Import(const Attr *FromAttr);
/// Import the given declaration from the "from" context into the
/// "to" context.
///
- /// \returns the equivalent declaration in the "to" context, or a NULL type
- /// if an error occurred.
+ /// \returns The equivalent declaration in the "to" context, or the import
+ /// error.
+ llvm::Expected<Decl *> Import_New(Decl *FromD);
+ llvm::Expected<Decl *> Import_New(const Decl *FromD) {
+ return Import_New(const_cast<Decl *>(FromD));
+ }
+ // FIXME: Remove this version.
Decl *Import(Decl *FromD);
Decl *Import(const Decl *FromD) {
return Import(const_cast<Decl *>(FromD));
@@ -155,104 +209,137 @@ class Attr;
/// Return the copy of the given declaration in the "to" context if
/// it has already been imported from the "from" context. Otherwise return
/// NULL.
- Decl *GetAlreadyImportedOrNull(Decl *FromD);
+ Decl *GetAlreadyImportedOrNull(const Decl *FromD) const;
/// Import the given declaration context from the "from"
/// AST context into the "to" AST context.
///
/// \returns the equivalent declaration context in the "to"
- /// context, or a NULL type if an error occurred.
- DeclContext *ImportContext(DeclContext *FromDC);
+ /// context, or error value.
+ llvm::Expected<DeclContext *> ImportContext(DeclContext *FromDC);
/// Import the given expression from the "from" context into the
/// "to" context.
///
- /// \returns the equivalent expression in the "to" context, or NULL if
- /// an error occurred.
+ /// \returns The equivalent expression in the "to" context, or the import
+ /// error.
+ llvm::Expected<Expr *> Import_New(Expr *FromE);
+ // FIXME: Remove this version.
Expr *Import(Expr *FromE);
/// Import the given statement from the "from" context into the
/// "to" context.
///
- /// \returns the equivalent statement in the "to" context, or NULL if
- /// an error occurred.
+ /// \returns The equivalent statement in the "to" context, or the import
+ /// error.
+ llvm::Expected<Stmt *> Import_New(Stmt *FromS);
+ // FIXME: Remove this version.
Stmt *Import(Stmt *FromS);
/// Import the given nested-name-specifier from the "from"
/// context into the "to" context.
///
- /// \returns the equivalent nested-name-specifier in the "to"
- /// context, or NULL if an error occurred.
+ /// \returns The equivalent nested-name-specifier in the "to"
+ /// context, or the import error.
+ llvm::Expected<NestedNameSpecifier *>
+ Import_New(NestedNameSpecifier *FromNNS);
+ // FIXME: Remove this version.
NestedNameSpecifier *Import(NestedNameSpecifier *FromNNS);
- /// Import the given nested-name-specifier from the "from"
+ /// Import the given nested-name-specifier-loc from the "from"
/// context into the "to" context.
///
- /// \returns the equivalent nested-name-specifier in the "to"
- /// context.
+ /// \returns The equivalent nested-name-specifier-loc in the "to"
+ /// context, or the import error.
+ llvm::Expected<NestedNameSpecifierLoc>
+ Import_New(NestedNameSpecifierLoc FromNNS);
+ // FIXME: Remove this version.
NestedNameSpecifierLoc Import(NestedNameSpecifierLoc FromNNS);
- /// Import the goven template name from the "from" context into the
- /// "to" context.
+ /// Import the given template name from the "from" context into the
+ /// "to" context, or the import error.
+ llvm::Expected<TemplateName> Import_New(TemplateName From);
+ // FIXME: Remove this version.
TemplateName Import(TemplateName From);
/// Import the given source location from the "from" context into
/// the "to" context.
///
- /// \returns the equivalent source location in the "to" context, or an
- /// invalid source location if an error occurred.
+ /// \returns The equivalent source location in the "to" context, or the
+ /// import error.
+ llvm::Expected<SourceLocation> Import_New(SourceLocation FromLoc);
+ // FIXME: Remove this version.
SourceLocation Import(SourceLocation FromLoc);
/// Import the given source range from the "from" context into
/// the "to" context.
///
- /// \returns the equivalent source range in the "to" context, or an
- /// invalid source location if an error occurred.
+ /// \returns The equivalent source range in the "to" context, or the import
+ /// error.
+ llvm::Expected<SourceRange> Import_New(SourceRange FromRange);
+ // FIXME: Remove this version.
SourceRange Import(SourceRange FromRange);
/// Import the given declaration name from the "from"
/// context into the "to" context.
///
- /// \returns the equivalent declaration name in the "to" context,
- /// or an empty declaration name if an error occurred.
+ /// \returns The equivalent declaration name in the "to" context, or the
+ /// import error.
+ llvm::Expected<DeclarationName> Import_New(DeclarationName FromName);
+ // FIXME: Remove this version.
DeclarationName Import(DeclarationName FromName);
/// Import the given identifier from the "from" context
/// into the "to" context.
///
- /// \returns the equivalent identifier in the "to" context.
+ /// \returns The equivalent identifier in the "to" context. Note: It
+ /// returns nullptr only if the FromId was nullptr.
IdentifierInfo *Import(const IdentifierInfo *FromId);
/// Import the given Objective-C selector from the "from"
/// context into the "to" context.
///
- /// \returns the equivalent selector in the "to" context.
+ /// \returns The equivalent selector in the "to" context, or the import
+ /// error.
+ llvm::Expected<Selector> Import_New(Selector FromSel);
+ // FIXME: Remove this version.
Selector Import(Selector FromSel);
/// Import the given file ID from the "from" context into the
/// "to" context.
///
- /// \returns the equivalent file ID in the source manager of the "to"
- /// context.
+ /// \returns The equivalent file ID in the source manager of the "to"
+ /// context, or the import error.
+ llvm::Expected<FileID> Import_New(FileID);
+ // FIXME: Remove this version.
FileID Import(FileID);
/// Import the given C++ constructor initializer from the "from"
/// context into the "to" context.
///
- /// \returns the equivalent initializer in the "to" context.
+ /// \returns The equivalent initializer in the "to" context, or the import
+ /// error.
+ llvm::Expected<CXXCtorInitializer *>
+ Import_New(CXXCtorInitializer *FromInit);
+ // FIXME: Remove this version.
CXXCtorInitializer *Import(CXXCtorInitializer *FromInit);
/// Import the given CXXBaseSpecifier from the "from" context into
/// the "to" context.
///
- /// \returns the equivalent CXXBaseSpecifier in the source manager of the
- /// "to" context.
+ /// \returns The equivalent CXXBaseSpecifier in the source manager of the
+ /// "to" context, or the import error.
+ llvm::Expected<CXXBaseSpecifier *>
+ Import_New(const CXXBaseSpecifier *FromSpec);
+ // FIXME: Remove this version.
CXXBaseSpecifier *Import(const CXXBaseSpecifier *FromSpec);
/// Import the definition of the given declaration, including all of
/// the declarations it contains.
- ///
- /// This routine is intended to be used
+ LLVM_NODISCARD llvm::Error ImportDefinition_New(Decl *From);
+
+ // FIXME: Compatibility function.
+ // Usages of this should be changed to ImportDefinition_New.
void ImportDefinition(Decl *From);
/// Cope with a name conflict when importing a declaration into the
@@ -336,9 +423,9 @@ class Attr;
/// Determine the index of a field in its parent record.
/// F should be a field (or indirect field) declaration.
- /// \returns The index of the field in its parent context, starting from 1.
- /// 0 is returned on error (parent context is non-record).
- static unsigned getFieldIndex(Decl *F);
+ /// \returns The index of the field in its parent context (starting from 0).
+ /// On error `None` is returned (parent context is non-record).
+ static llvm::Optional<unsigned> getFieldIndex(Decl *F);
};
diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h
index 0e738da43a..c2f01e7d54 100644
--- a/include/clang/AST/CanonicalType.h
+++ b/include/clang/AST/CanonicalType.h
@@ -510,7 +510,7 @@ struct CanProxyAdaptor<FunctionProtoType>
}
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVariadic)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getTypeQuals)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getTypeQuals)
using param_type_iterator =
CanTypeIterator<FunctionProtoType::param_type_iterator>;
diff --git a/include/clang/AST/CommentDiagnostic.h b/include/clang/AST/CommentDiagnostic.h
index f3a209bf6e..b9816f1a8e 100644
--- a/include/clang/AST/CommentDiagnostic.h
+++ b/include/clang/AST/CommentDiagnostic.h
@@ -10,20 +10,7 @@
#ifndef LLVM_CLANG_AST_COMMENTDIAGNOSTIC_H
#define LLVM_CLANG_AST_COMMENTDIAGNOSTIC_H
-#include "clang/Basic/Diagnostic.h"
-
-namespace clang {
- namespace diag {
- enum {
-#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
- SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
-#define COMMENTSTART
-#include "clang/Basic/DiagnosticCommentKinds.inc"
-#undef DIAG
- NUM_BUILTIN_COMMENT_DIAGNOSTICS
- };
- } // end namespace diag
-} // end namespace clang
+#include "clang/Basic/DiagnosticComment.h"
#endif
diff --git a/include/clang/AST/CommentVisitor.h b/include/clang/AST/CommentVisitor.h
index d1cc2d0a4e..e37e9d6cd2 100644
--- a/include/clang/AST/CommentVisitor.h
+++ b/include/clang/AST/CommentVisitor.h
@@ -11,22 +11,21 @@
#define LLVM_CLANG_AST_COMMENTVISITOR_H
#include "clang/AST/Comment.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/ErrorHandling.h"
namespace clang {
namespace comments {
-
-template <typename T> struct make_ptr { using type = T *; };
-template <typename T> struct make_const_ptr { using type = const T *; };
-
-template<template <typename> class Ptr, typename ImplClass, typename RetTy=void>
+template <template <typename> class Ptr, typename ImplClass,
+ typename RetTy = void, class... ParamTys>
class CommentVisitorBase {
public:
#define PTR(CLASS) typename Ptr<CLASS>::type
-#define DISPATCH(NAME, CLASS) \
- return static_cast<ImplClass*>(this)->visit ## NAME(static_cast<PTR(CLASS)>(C))
+#define DISPATCH(NAME, CLASS) \
+ return static_cast<ImplClass *>(this)->visit##NAME( \
+ static_cast<PTR(CLASS)>(C), std::forward<ParamTys>(P)...)
- RetTy visit(PTR(Comment) C) {
+ RetTy visit(PTR(Comment) C, ParamTys... P) {
if (!C)
return RetTy();
@@ -44,25 +43,26 @@ public:
// If the derived class does not implement a certain Visit* method, fall back
// on Visit* method for the superclass.
#define ABSTRACT_COMMENT(COMMENT) COMMENT
-#define COMMENT(CLASS, PARENT) \
- RetTy visit ## CLASS(PTR(CLASS) C) { DISPATCH(PARENT, PARENT); }
+#define COMMENT(CLASS, PARENT) \
+ RetTy visit##CLASS(PTR(CLASS) C, ParamTys... P) { DISPATCH(PARENT, PARENT); }
#include "clang/AST/CommentNodes.inc"
#undef ABSTRACT_COMMENT
#undef COMMENT
- RetTy visitComment(PTR(Comment) C) { return RetTy(); }
+ RetTy visitComment(PTR(Comment) C, ParamTys... P) { return RetTy(); }
#undef PTR
#undef DISPATCH
};
-template<typename ImplClass, typename RetTy=void>
-class CommentVisitor :
- public CommentVisitorBase<make_ptr, ImplClass, RetTy> {};
+template <typename ImplClass, typename RetTy = void, class... ParamTys>
+class CommentVisitor : public CommentVisitorBase<std::add_pointer, ImplClass,
+ RetTy, ParamTys...> {};
-template<typename ImplClass, typename RetTy=void>
-class ConstCommentVisitor :
- public CommentVisitorBase<make_const_ptr, ImplClass, RetTy> {};
+template <typename ImplClass, typename RetTy = void, class... ParamTys>
+class ConstCommentVisitor
+ : public CommentVisitorBase<llvm::make_const_ptr, ImplClass, RetTy,
+ ParamTys...> {};
} // namespace comments
} // namespace clang
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 2b6e111106..3145f35ead 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -965,6 +965,8 @@ protected:
/// Defines kind of the ImplicitParamDecl: 'this', 'self', 'vtt', '_cmd' or
/// something else.
unsigned ImplicitParamKind : 3;
+
+ unsigned EscapingByref : 1;
};
union {
@@ -1407,6 +1409,19 @@ public:
NonParmVarDeclBits.PreviousDeclInSameBlockScope = Same;
}
+ /// Indicates the capture is a __block variable that is captured by a block
+ /// that can potentially escape (a block for which BlockDecl::doesNotEscape
+ /// returns false).
+ bool isEscapingByref() const;
+
+ /// Indicates the capture is a __block variable that is never captured by an
+ /// escaping block.
+ bool isNonEscapingByref() const;
+
+ void setEscapingByref() {
+ NonParmVarDeclBits.EscapingByref = true;
+ }
+
/// Retrieve the variable declaration from which this variable could
/// be instantiated, if it is an instantiation (rather than a non-template).
VarDecl *getTemplateInstantiationPattern() const;
@@ -1704,6 +1719,13 @@ private:
unsigned getParameterIndexLarge() const;
};
+enum class MultiVersionKind {
+ None,
+ Target,
+ CPUSpecific,
+ CPUDispatch
+};
+
/// Represents a function declaration or definition.
///
/// Since a given function can be declared several times in a program,
@@ -2211,6 +2233,12 @@ public:
getCanonicalDecl()->FunctionDeclBits.IsMultiVersion = V;
}
+ /// Gets the kind of multiversioning attribute this declaration has. Note that
+ /// this can return a value even if the function is not multiversion, such as
+ /// the case of 'target'.
+ MultiVersionKind getMultiVersionKind() const;
+
+
/// True if this function is a multiversioned dispatch function as a part of
/// the cpu_specific/cpu_dispatch functionality.
bool isCPUDispatchMultiVersion() const;
@@ -2218,6 +2246,10 @@ public:
/// part of the cpu_specific/cpu_dispatch functionality.
bool isCPUSpecificMultiVersion() const;
+ /// True if this function is a multiversioned dispatch function as a part of
+ /// the target functionality.
+ bool isTargetMultiVersion() const;
+
void setPreviousDeclaration(FunctionDecl * PrevDecl);
FunctionDecl *getCanonicalDecl() override;
@@ -3865,6 +3897,14 @@ public:
/// variable.
bool isByRef() const { return VariableAndFlags.getInt() & flag_isByRef; }
+ bool isEscapingByref() const {
+ return getVariable()->isEscapingByref();
+ }
+
+ bool isNonEscapingByref() const {
+ return getVariable()->isNonEscapingByref();
+ }
+
/// Whether this is a nested capture, i.e. the variable captured
/// is not from outside the immediately enclosing function/block.
bool isNested() const { return VariableAndFlags.getInt() & flag_isNested; }
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index 23870400a3..8405a43fa0 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -1065,11 +1065,11 @@ public:
unsigned OldNS = IdentifierNamespace;
assert((OldNS & (IDNS_Tag | IDNS_Ordinary |
IDNS_TagFriend | IDNS_OrdinaryFriend |
- IDNS_LocalExtern)) &&
+ IDNS_LocalExtern | IDNS_NonMemberOperator)) &&
"namespace includes neither ordinary nor tag");
assert(!(OldNS & ~(IDNS_Tag | IDNS_Ordinary | IDNS_Type |
IDNS_TagFriend | IDNS_OrdinaryFriend |
- IDNS_LocalExtern)) &&
+ IDNS_LocalExtern | IDNS_NonMemberOperator)) &&
"namespace includes other than ordinary or tag");
Decl *Prev = getPreviousDecl();
@@ -1082,7 +1082,8 @@ public:
IdentifierNamespace |= IDNS_Tag | IDNS_Type;
}
- if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend | IDNS_LocalExtern)) {
+ if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend |
+ IDNS_LocalExtern | IDNS_NonMemberOperator)) {
IdentifierNamespace |= IDNS_OrdinaryFriend;
if (PerformFriendInjection ||
(Prev && Prev->getIdentifierNamespace() & IDNS_Ordinary))
@@ -1212,7 +1213,6 @@ public:
value_type SingleElement;
public:
- iterator() = default;
explicit iterator(pointer Pos, value_type Single = nullptr)
: IteratorBase(Pos), SingleElement(Single) {}
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index cb1de0bc57..58e01bf0f0 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -1541,7 +1541,7 @@ public:
///
/// C++11 [class]p6:
/// "A trivial class is a class that has a trivial default constructor and
- /// is trivially copiable."
+ /// is trivially copyable."
bool isTrivial() const {
return isTriviallyCopyable() && hasTrivialDefaultConstructor();
}
@@ -2182,7 +2182,10 @@ public:
/// 'this' type.
QualType getThisType(ASTContext &C) const;
- unsigned getTypeQualifiers() const {
+ static QualType getThisType(const FunctionProtoType *FPT,
+ const CXXRecordDecl *Decl);
+
+ Qualifiers getTypeQualifiers() const {
return getType()->getAs<FunctionProtoType>()->getTypeQuals();
}
@@ -2315,6 +2318,9 @@ public:
CXXCtorInitializer(ASTContext &Context, TypeSourceInfo *TInfo,
SourceLocation L, Expr *Init, SourceLocation R);
+ /// \return Unique reproducible object identifier.
+ int64_t getID(const ASTContext &Context) const;
+
/// Determine whether this initializer is initializing a base class.
bool isBaseInitializer() const {
return Initializee.is<TypeSourceInfo*>() && !IsDelegating;
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index e0ea7cb8b1..9e01c4950d 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -1093,6 +1093,9 @@ public:
/// template.
ArrayRef<TemplateArgument> getInjectedTemplateArgs();
+ /// Merge \p Prev with our RedeclarableTemplateDecl::Common.
+ void mergePrevDecl(FunctionTemplateDecl *Prev);
+
/// Create a function template node.
static FunctionTemplateDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
diff --git a/include/clang/AST/DeclVisitor.h b/include/clang/AST/DeclVisitor.h
index 520a4a10bf..c6cbc9ff7f 100644
--- a/include/clang/AST/DeclVisitor.h
+++ b/include/clang/AST/DeclVisitor.h
@@ -21,15 +21,12 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclOpenMP.h"
#include "clang/AST/DeclTemplate.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/ErrorHandling.h"
namespace clang {
namespace declvisitor {
-
-template <typename T> struct make_ptr { using type = T *; };
-template <typename T> struct make_const_ptr { using type = const T *; };
-
/// A simple visitor class that helps create declaration visitors.
template<template <typename> class Ptr, typename ImplClass, typename RetTy=void>
class Base {
@@ -66,16 +63,16 @@ public:
///
/// This class does not preserve constness of Decl pointers (see also
/// ConstDeclVisitor).
-template<typename ImplClass, typename RetTy = void>
+template <typename ImplClass, typename RetTy = void>
class DeclVisitor
- : public declvisitor::Base<declvisitor::make_ptr, ImplClass, RetTy> {};
+ : public declvisitor::Base<std::add_pointer, ImplClass, RetTy> {};
/// A simple visitor class that helps create declaration visitors.
///
/// This class preserves constness of Decl pointers (see also DeclVisitor).
-template<typename ImplClass, typename RetTy = void>
+template <typename ImplClass, typename RetTy = void>
class ConstDeclVisitor
- : public declvisitor::Base<declvisitor::make_const_ptr, ImplClass, RetTy> {};
+ : public declvisitor::Base<llvm::make_const_ptr, ImplClass, RetTy> {};
} // namespace clang
diff --git a/include/clang/AST/EvaluatedExprVisitor.h b/include/clang/AST/EvaluatedExprVisitor.h
index 1aec5ae842..f356584144 100644
--- a/include/clang/AST/EvaluatedExprVisitor.h
+++ b/include/clang/AST/EvaluatedExprVisitor.h
@@ -19,6 +19,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtVisitor.h"
+#include "llvm/ADT/STLExtras.h"
namespace clang {
@@ -107,23 +108,22 @@ public:
};
/// EvaluatedExprVisitor - This class visits 'Expr *'s
-template<typename ImplClass>
+template <typename ImplClass>
class EvaluatedExprVisitor
- : public EvaluatedExprVisitorBase<make_ptr, ImplClass> {
+ : public EvaluatedExprVisitorBase<std::add_pointer, ImplClass> {
public:
- explicit EvaluatedExprVisitor(const ASTContext &Context) :
- EvaluatedExprVisitorBase<make_ptr, ImplClass>(Context) { }
+ explicit EvaluatedExprVisitor(const ASTContext &Context)
+ : EvaluatedExprVisitorBase<std::add_pointer, ImplClass>(Context) {}
};
/// ConstEvaluatedExprVisitor - This class visits 'const Expr *'s.
-template<typename ImplClass>
+template <typename ImplClass>
class ConstEvaluatedExprVisitor
- : public EvaluatedExprVisitorBase<make_const_ptr, ImplClass> {
+ : public EvaluatedExprVisitorBase<llvm::make_const_ptr, ImplClass> {
public:
- explicit ConstEvaluatedExprVisitor(const ASTContext &Context) :
- EvaluatedExprVisitorBase<make_const_ptr, ImplClass>(Context) { }
+ explicit ConstEvaluatedExprVisitor(const ASTContext &Context)
+ : EvaluatedExprVisitorBase<llvm::make_const_ptr, ImplClass>(Context) {}
};
-
}
#endif // LLVM_CLANG_AST_EVALUATEDEXPRVISITOR_H
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index 8bc14e12df..d57c45eec0 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -32,6 +32,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/AtomicOrdering.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/Support/TrailingObjects.h"
namespace clang {
class APValue;
@@ -582,7 +583,8 @@ public:
/// this function returns true, it returns the folded constant in Result. If
/// the expression is a glvalue, an lvalue-to-rvalue conversion will be
/// applied.
- bool EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx) const;
+ bool EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx,
+ bool InConstantContext = false) const;
/// EvaluateAsBooleanCondition - Return true if this is a constant
/// which we can fold and convert to a boolean condition using
@@ -599,7 +601,7 @@ public:
/// EvaluateAsInt - Return true if this is a constant which we can fold and
/// convert to an integer, using any crazy technique that we want to.
- bool EvaluateAsInt(llvm::APSInt &Result, const ASTContext &Ctx,
+ bool EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx,
SideEffectsKind AllowSideEffects = SE_NoSideEffects) const;
/// EvaluateAsFloat - Return true if this is a constant which we can fold and
@@ -631,8 +633,13 @@ public:
/// EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded
/// integer. This must be called on an expression that constant folds to an
/// integer.
- llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx,
- SmallVectorImpl<PartialDiagnosticAt> *Diag = nullptr) const;
+ llvm::APSInt EvaluateKnownConstInt(
+ const ASTContext &Ctx,
+ SmallVectorImpl<PartialDiagnosticAt> *Diag = nullptr) const;
+
+ llvm::APSInt EvaluateKnownConstIntCheckOverflow(
+ const ASTContext &Ctx,
+ SmallVectorImpl<PartialDiagnosticAt> *Diag = nullptr) const;
void EvaluateForOverflow(const ASTContext &Ctx) const;
@@ -863,6 +870,70 @@ public:
};
//===----------------------------------------------------------------------===//
+// Wrapper Expressions.
+//===----------------------------------------------------------------------===//
+
+/// FullExpr - Represents a "full-expression" node.
+class FullExpr : public Expr {
+protected:
+ Stmt *SubExpr;
+
+ FullExpr(StmtClass SC, Expr *subexpr)
+ : Expr(SC, subexpr->getType(),
+ subexpr->getValueKind(), subexpr->getObjectKind(),
+ subexpr->isTypeDependent(), subexpr->isValueDependent(),
+ subexpr->isInstantiationDependent(),
+ subexpr->containsUnexpandedParameterPack()), SubExpr(subexpr) {}
+ FullExpr(StmtClass SC, EmptyShell Empty)
+ : Expr(SC, Empty) {}
+public:
+ const Expr *getSubExpr() const { return cast<Expr>(SubExpr); }
+ Expr *getSubExpr() { return cast<Expr>(SubExpr); }
+
+ /// As with any mutator of the AST, be very careful when modifying an
+ /// existing AST to preserve its invariants.
+ void setSubExpr(Expr *E) { SubExpr = E; }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() >= firstFullExprConstant &&
+ T->getStmtClass() <= lastFullExprConstant;
+ }
+};
+
+/// ConstantExpr - An expression that occurs in a constant context.
+class ConstantExpr : public FullExpr {
+ ConstantExpr(Expr *subexpr)
+ : FullExpr(ConstantExprClass, subexpr) {}
+
+public:
+ static ConstantExpr *Create(const ASTContext &Context, Expr *E) {
+ assert(!isa<ConstantExpr>(E));
+ return new (Context) ConstantExpr(E);
+ }
+
+ /// Build an empty constant expression wrapper.
+ explicit ConstantExpr(EmptyShell Empty)
+ : FullExpr(ConstantExprClass, Empty) {}
+
+ SourceLocation getBeginLoc() const LLVM_READONLY {
+ return SubExpr->getBeginLoc();
+ }
+ SourceLocation getEndLoc() const LLVM_READONLY {
+ return SubExpr->getEndLoc();
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ConstantExprClass;
+ }
+
+ // Iterators
+ child_range children() { return child_range(&SubExpr, &SubExpr+1); }
+ const_child_range children() const {
+ return const_child_range(&SubExpr, &SubExpr + 1);
+ }
+};
+
+//===----------------------------------------------------------------------===//
// Primary Expressions.
//===----------------------------------------------------------------------===//
@@ -973,61 +1044,60 @@ class DeclRefExpr final
private llvm::TrailingObjects<DeclRefExpr, NestedNameSpecifierLoc,
NamedDecl *, ASTTemplateKWAndArgsInfo,
TemplateArgumentLoc> {
+ friend class ASTStmtReader;
+ friend class ASTStmtWriter;
+ friend TrailingObjects;
+
/// The declaration that we are referencing.
ValueDecl *D;
- /// The location of the declaration name itself.
- SourceLocation Loc;
-
/// Provides source/type location info for the declaration name
/// embedded in D.
DeclarationNameLoc DNLoc;
size_t numTrailingObjects(OverloadToken<NestedNameSpecifierLoc>) const {
- return hasQualifier() ? 1 : 0;
+ return hasQualifier();
}
size_t numTrailingObjects(OverloadToken<NamedDecl *>) const {
- return hasFoundDecl() ? 1 : 0;
+ return hasFoundDecl();
}
size_t numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const {
- return hasTemplateKWAndArgsInfo() ? 1 : 0;
+ return hasTemplateKWAndArgsInfo();
}
/// Test whether there is a distinct FoundDecl attached to the end of
/// this DRE.
bool hasFoundDecl() const { return DeclRefExprBits.HasFoundDecl; }
- DeclRefExpr(const ASTContext &Ctx,
- NestedNameSpecifierLoc QualifierLoc,
- SourceLocation TemplateKWLoc,
- ValueDecl *D, bool RefersToEnlosingVariableOrCapture,
- const DeclarationNameInfo &NameInfo,
- NamedDecl *FoundD,
- const TemplateArgumentListInfo *TemplateArgs,
- QualType T, ExprValueKind VK);
+ DeclRefExpr(const ASTContext &Ctx, NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc, ValueDecl *D,
+ bool RefersToEnlosingVariableOrCapture,
+ const DeclarationNameInfo &NameInfo, NamedDecl *FoundD,
+ const TemplateArgumentListInfo *TemplateArgs, QualType T,
+ ExprValueKind VK);
/// Construct an empty declaration reference expression.
- explicit DeclRefExpr(EmptyShell Empty)
- : Expr(DeclRefExprClass, Empty) { }
+ explicit DeclRefExpr(EmptyShell Empty) : Expr(DeclRefExprClass, Empty) {}
/// Computes the type- and value-dependence flags for this
/// declaration reference expression.
- void computeDependence(const ASTContext &C);
+ void computeDependence(const ASTContext &Ctx);
public:
DeclRefExpr(ValueDecl *D, bool RefersToEnclosingVariableOrCapture, QualType T,
ExprValueKind VK, SourceLocation L,
const DeclarationNameLoc &LocInfo = DeclarationNameLoc())
- : Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false, false),
- D(D), Loc(L), DNLoc(LocInfo) {
- DeclRefExprBits.HasQualifier = 0;
- DeclRefExprBits.HasTemplateKWAndArgsInfo = 0;
- DeclRefExprBits.HasFoundDecl = 0;
- DeclRefExprBits.HadMultipleCandidates = 0;
+ : Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false, false),
+ D(D), DNLoc(LocInfo) {
+ DeclRefExprBits.HasQualifier = false;
+ DeclRefExprBits.HasTemplateKWAndArgsInfo = false;
+ DeclRefExprBits.HasFoundDecl = false;
+ DeclRefExprBits.HadMultipleCandidates = false;
DeclRefExprBits.RefersToEnclosingVariableOrCapture =
RefersToEnclosingVariableOrCapture;
+ DeclRefExprBits.Loc = L;
computeDependence(D->getASTContext());
}
@@ -1047,8 +1117,7 @@ public:
const TemplateArgumentListInfo *TemplateArgs = nullptr);
/// Construct an empty declaration reference expression.
- static DeclRefExpr *CreateEmpty(const ASTContext &Context,
- bool HasQualifier,
+ static DeclRefExpr *CreateEmpty(const ASTContext &Context, bool HasQualifier,
bool HasFoundDecl,
bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs);
@@ -1058,11 +1127,11 @@ public:
void setDecl(ValueDecl *NewD) { D = NewD; }
DeclarationNameInfo getNameInfo() const {
- return DeclarationNameInfo(getDecl()->getDeclName(), Loc, DNLoc);
+ return DeclarationNameInfo(getDecl()->getDeclName(), getLocation(), DNLoc);
}
- SourceLocation getLocation() const { return Loc; }
- void setLocation(SourceLocation L) { Loc = L; }
+ SourceLocation getLocation() const { return DeclRefExprBits.Loc; }
+ void setLocation(SourceLocation L) { DeclRefExprBits.Loc = L; }
SourceLocation getBeginLoc() const LLVM_READONLY;
SourceLocation getEndLoc() const LLVM_READONLY;
@@ -1107,21 +1176,24 @@ public:
/// Retrieve the location of the template keyword preceding
/// this name, if any.
SourceLocation getTemplateKeywordLoc() const {
- if (!hasTemplateKWAndArgsInfo()) return SourceLocation();
+ if (!hasTemplateKWAndArgsInfo())
+ return SourceLocation();
return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->TemplateKWLoc;
}
/// Retrieve the location of the left angle bracket starting the
/// explicit template argument list following the name, if any.
SourceLocation getLAngleLoc() const {
- if (!hasTemplateKWAndArgsInfo()) return SourceLocation();
+ if (!hasTemplateKWAndArgsInfo())
+ return SourceLocation();
return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->LAngleLoc;
}
/// Retrieve the location of the right angle bracket ending the
/// explicit template argument list following the name, if any.
SourceLocation getRAngleLoc() const {
- if (!hasTemplateKWAndArgsInfo()) return SourceLocation();
+ if (!hasTemplateKWAndArgsInfo())
+ return SourceLocation();
return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->RAngleLoc;
}
@@ -1146,7 +1218,6 @@ public:
const TemplateArgumentLoc *getTemplateArgs() const {
if (!hasExplicitTemplateArgs())
return nullptr;
-
return getTrailingObjects<TemplateArgumentLoc>();
}
@@ -1155,7 +1226,6 @@ public:
unsigned getNumTemplateArgs() const {
if (!hasExplicitTemplateArgs())
return 0;
-
return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->NumTemplateArgs;
}
@@ -1193,68 +1263,6 @@ public:
const_child_range children() const {
return const_child_range(const_child_iterator(), const_child_iterator());
}
-
- friend TrailingObjects;
- friend class ASTStmtReader;
- friend class ASTStmtWriter;
-};
-
-/// [C99 6.4.2.2] - A predefined identifier such as __func__.
-class PredefinedExpr : public Expr {
-public:
- enum IdentType {
- Func,
- Function,
- LFunction, // Same as Function, but as wide string.
- FuncDName,
- FuncSig,
- LFuncSig, // Same as FuncSig, but as as wide string
- PrettyFunction,
- /// The same as PrettyFunction, except that the
- /// 'virtual' keyword is omitted for virtual member functions.
- PrettyFunctionNoVirtual
- };
-
-private:
- SourceLocation Loc;
- IdentType Type;
- Stmt *FnName;
-
-public:
- PredefinedExpr(SourceLocation L, QualType FNTy, IdentType IT,
- StringLiteral *SL);
-
- /// Construct an empty predefined expression.
- explicit PredefinedExpr(EmptyShell Empty)
- : Expr(PredefinedExprClass, Empty), Loc(), Type(Func), FnName(nullptr) {}
-
- IdentType getIdentType() const { return Type; }
-
- SourceLocation getLocation() const { return Loc; }
- void setLocation(SourceLocation L) { Loc = L; }
-
- StringLiteral *getFunctionName();
- const StringLiteral *getFunctionName() const {
- return const_cast<PredefinedExpr *>(this)->getFunctionName();
- }
-
- static StringRef getIdentTypeName(IdentType IT);
- static std::string ComputeName(IdentType IT, const Decl *CurrentDecl);
-
- SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; }
- SourceLocation getEndLoc() const LLVM_READONLY { return Loc; }
-
- static bool classof(const Stmt *T) {
- return T->getStmtClass() == PredefinedExprClass;
- }
-
- // Iterators
- child_range children() { return child_range(&FnName, &FnName + 1); }
- const_child_range children() const {
- return const_child_range(&FnName, &FnName + 1);
- }
-
- friend class ASTStmtReader;
};
/// Used by IntegerLiteral/FloatingLiteral to store the numeric without
@@ -1550,14 +1558,15 @@ public:
};
/// StringLiteral - This represents a string literal expression, e.g. "foo"
-/// or L"bar" (wide strings). The actual string is returned by getBytes()
-/// is NOT null-terminated, and the length of the string is determined by
-/// calling getByteLength(). The C type for a string is always a
-/// ConstantArrayType. In C++, the char type is const qualified, in C it is
-/// not.
+/// or L"bar" (wide strings). The actual string data can be obtained with
+/// getBytes() and is NOT null-terminated. The length of the string data is
+/// determined by calling getByteLength().
+///
+/// The C type for a string is always a ConstantArrayType. In C++, the char
+/// type is const qualified, in C it is not.
///
/// Note that strings in C can be formed by concatenation of multiple string
-/// literal pptokens in translation phase #6. This keeps track of the locations
+/// literal pptokens in translation phase #6. This keeps track of the locations
/// of each of these pieces.
///
/// Strings in C can also be truncated and extended by assigning into arrays,
@@ -1565,131 +1574,156 @@ public:
/// char X[2] = "foobar";
/// In this case, getByteLength() will return 6, but the string literal will
/// have type "char[2]".
-class StringLiteral : public Expr {
+class StringLiteral final
+ : public Expr,
+ private llvm::TrailingObjects<StringLiteral, unsigned, SourceLocation,
+ char> {
+ friend class ASTStmtReader;
+ friend TrailingObjects;
+
+ /// StringLiteral is followed by several trailing objects. They are in order:
+ ///
+ /// * A single unsigned storing the length in characters of this string. The
+ /// length in bytes is this length times the width of a single character.
+ /// Always present and stored as a trailing objects because storing it in
+ /// StringLiteral would increase the size of StringLiteral by sizeof(void *)
+ /// due to alignment requirements. If you add some data to StringLiteral,
+ /// consider moving it inside StringLiteral.
+ ///
+ /// * An array of getNumConcatenated() SourceLocation, one for each of the
+ /// token this string is made of.
+ ///
+ /// * An array of getByteLength() char used to store the string data.
+
public:
- enum StringKind {
- Ascii,
- Wide,
- UTF8,
- UTF16,
- UTF32
- };
+ enum StringKind { Ascii, Wide, UTF8, UTF16, UTF32 };
private:
- friend class ASTStmtReader;
+ unsigned numTrailingObjects(OverloadToken<unsigned>) const { return 1; }
+ unsigned numTrailingObjects(OverloadToken<SourceLocation>) const {
+ return getNumConcatenated();
+ }
- union {
- const char *asChar;
- const uint16_t *asUInt16;
- const uint32_t *asUInt32;
- } StrData;
- unsigned Length;
- unsigned CharByteWidth : 4;
- unsigned Kind : 3;
- unsigned IsPascal : 1;
- unsigned NumConcatenated;
- SourceLocation TokLocs[1];
-
- StringLiteral(QualType Ty) :
- Expr(StringLiteralClass, Ty, VK_LValue, OK_Ordinary, false, false, false,
- false) {}
-
- static int mapCharByteWidth(TargetInfo const &target,StringKind k);
+ unsigned numTrailingObjects(OverloadToken<char>) const {
+ return getByteLength();
+ }
+
+ char *getStrDataAsChar() { return getTrailingObjects<char>(); }
+ const char *getStrDataAsChar() const { return getTrailingObjects<char>(); }
+
+ const uint16_t *getStrDataAsUInt16() const {
+ return reinterpret_cast<const uint16_t *>(getTrailingObjects<char>());
+ }
+
+ const uint32_t *getStrDataAsUInt32() const {
+ return reinterpret_cast<const uint32_t *>(getTrailingObjects<char>());
+ }
+
+ /// Build a string literal.
+ StringLiteral(const ASTContext &Ctx, StringRef Str, StringKind Kind,
+ bool Pascal, QualType Ty, const SourceLocation *Loc,
+ unsigned NumConcatenated);
+
+ /// Build an empty string literal.
+ StringLiteral(EmptyShell Empty, unsigned NumConcatenated, unsigned Length,
+ unsigned CharByteWidth);
+
+ /// Map a target and string kind to the appropriate character width.
+ static unsigned mapCharByteWidth(TargetInfo const &Target, StringKind SK);
+
+ /// Set one of the string literal token.
+ void setStrTokenLoc(unsigned TokNum, SourceLocation L) {
+ assert(TokNum < getNumConcatenated() && "Invalid tok number");
+ getTrailingObjects<SourceLocation>()[TokNum] = L;
+ }
public:
/// This is the "fully general" constructor that allows representation of
/// strings formed from multiple concatenated tokens.
- static StringLiteral *Create(const ASTContext &C, StringRef Str,
+ static StringLiteral *Create(const ASTContext &Ctx, StringRef Str,
StringKind Kind, bool Pascal, QualType Ty,
- const SourceLocation *Loc, unsigned NumStrs);
+ const SourceLocation *Loc,
+ unsigned NumConcatenated);
/// Simple constructor for string literals made from one token.
- static StringLiteral *Create(const ASTContext &C, StringRef Str,
+ static StringLiteral *Create(const ASTContext &Ctx, StringRef Str,
StringKind Kind, bool Pascal, QualType Ty,
SourceLocation Loc) {
- return Create(C, Str, Kind, Pascal, Ty, &Loc, 1);
+ return Create(Ctx, Str, Kind, Pascal, Ty, &Loc, 1);
}
/// Construct an empty string literal.
- static StringLiteral *CreateEmpty(const ASTContext &C, unsigned NumStrs);
+ static StringLiteral *CreateEmpty(const ASTContext &Ctx,
+ unsigned NumConcatenated, unsigned Length,
+ unsigned CharByteWidth);
StringRef getString() const {
- assert(CharByteWidth==1
- && "This function is used in places that assume strings use char");
- return StringRef(StrData.asChar, getByteLength());
+ assert(getCharByteWidth() == 1 &&
+ "This function is used in places that assume strings use char");
+ return StringRef(getStrDataAsChar(), getByteLength());
}
/// Allow access to clients that need the byte representation, such as
/// ASTWriterStmt::VisitStringLiteral().
StringRef getBytes() const {
// FIXME: StringRef may not be the right type to use as a result for this.
- if (CharByteWidth == 1)
- return StringRef(StrData.asChar, getByteLength());
- if (CharByteWidth == 4)
- return StringRef(reinterpret_cast<const char*>(StrData.asUInt32),
- getByteLength());
- assert(CharByteWidth == 2 && "unsupported CharByteWidth");
- return StringRef(reinterpret_cast<const char*>(StrData.asUInt16),
- getByteLength());
+ return StringRef(getStrDataAsChar(), getByteLength());
}
void outputString(raw_ostream &OS) const;
uint32_t getCodeUnit(size_t i) const {
- assert(i < Length && "out of bounds access");
- if (CharByteWidth == 1)
- return static_cast<unsigned char>(StrData.asChar[i]);
- if (CharByteWidth == 4)
- return StrData.asUInt32[i];
- assert(CharByteWidth == 2 && "unsupported CharByteWidth");
- return StrData.asUInt16[i];
+ assert(i < getLength() && "out of bounds access");
+ switch (getCharByteWidth()) {
+ case 1:
+ return static_cast<unsigned char>(getStrDataAsChar()[i]);
+ case 2:
+ return getStrDataAsUInt16()[i];
+ case 4:
+ return getStrDataAsUInt32()[i];
+ }
+ llvm_unreachable("Unsupported character width!");
}
- unsigned getByteLength() const { return CharByteWidth*Length; }
- unsigned getLength() const { return Length; }
- unsigned getCharByteWidth() const { return CharByteWidth; }
-
- /// Sets the string data to the given string data.
- void setString(const ASTContext &C, StringRef Str,
- StringKind Kind, bool IsPascal);
-
- StringKind getKind() const { return static_cast<StringKind>(Kind); }
+ unsigned getByteLength() const { return getCharByteWidth() * getLength(); }
+ unsigned getLength() const { return *getTrailingObjects<unsigned>(); }
+ unsigned getCharByteWidth() const { return StringLiteralBits.CharByteWidth; }
+ StringKind getKind() const {
+ return static_cast<StringKind>(StringLiteralBits.Kind);
+ }
- bool isAscii() const { return Kind == Ascii; }
- bool isWide() const { return Kind == Wide; }
- bool isUTF8() const { return Kind == UTF8; }
- bool isUTF16() const { return Kind == UTF16; }
- bool isUTF32() const { return Kind == UTF32; }
- bool isPascal() const { return IsPascal; }
+ bool isAscii() const { return getKind() == Ascii; }
+ bool isWide() const { return getKind() == Wide; }
+ bool isUTF8() const { return getKind() == UTF8; }
+ bool isUTF16() const { return getKind() == UTF16; }
+ bool isUTF32() const { return getKind() == UTF32; }
+ bool isPascal() const { return StringLiteralBits.IsPascal; }
bool containsNonAscii() const {
- StringRef Str = getString();
- for (unsigned i = 0, e = Str.size(); i != e; ++i)
- if (!isASCII(Str[i]))
+ for (auto c : getString())
+ if (!isASCII(c))
return true;
return false;
}
bool containsNonAsciiOrNull() const {
- StringRef Str = getString();
- for (unsigned i = 0, e = Str.size(); i != e; ++i)
- if (!isASCII(Str[i]) || !Str[i])
+ for (auto c : getString())
+ if (!isASCII(c) || !c)
return true;
return false;
}
/// getNumConcatenated - Get the number of string literal tokens that were
/// concatenated in translation phase #6 to form this string literal.
- unsigned getNumConcatenated() const { return NumConcatenated; }
+ unsigned getNumConcatenated() const {
+ return StringLiteralBits.NumConcatenated;
+ }
+ /// Get one of the string literal token.
SourceLocation getStrTokenLoc(unsigned TokNum) const {
- assert(TokNum < NumConcatenated && "Invalid tok number");
- return TokLocs[TokNum];
- }
- void setStrTokenLoc(unsigned TokNum, SourceLocation L) {
- assert(TokNum < NumConcatenated && "Invalid tok number");
- TokLocs[TokNum] = L;
+ assert(TokNum < getNumConcatenated() && "Invalid tok number");
+ return getTrailingObjects<SourceLocation>()[TokNum];
}
/// getLocationOfByte - Return a source location that points to the specified
@@ -1706,14 +1740,18 @@ public:
unsigned *StartTokenByteOffset = nullptr) const;
typedef const SourceLocation *tokloc_iterator;
- tokloc_iterator tokloc_begin() const { return TokLocs; }
- tokloc_iterator tokloc_end() const { return TokLocs + NumConcatenated; }
- SourceLocation getBeginLoc() const LLVM_READONLY { return TokLocs[0]; }
- SourceLocation getEndLoc() const LLVM_READONLY {
- return TokLocs[NumConcatenated - 1];
+ tokloc_iterator tokloc_begin() const {
+ return getTrailingObjects<SourceLocation>();
+ }
+
+ tokloc_iterator tokloc_end() const {
+ return getTrailingObjects<SourceLocation>() + getNumConcatenated();
}
+ SourceLocation getBeginLoc() const LLVM_READONLY { return *tokloc_begin(); }
+ SourceLocation getEndLoc() const LLVM_READONLY { return *(tokloc_end() - 1); }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == StringLiteralClass;
}
@@ -1727,6 +1765,91 @@ public:
}
};
+/// [C99 6.4.2.2] - A predefined identifier such as __func__.
+class PredefinedExpr final
+ : public Expr,
+ private llvm::TrailingObjects<PredefinedExpr, Stmt *> {
+ friend class ASTStmtReader;
+ friend TrailingObjects;
+
+ // PredefinedExpr is optionally followed by a single trailing
+ // "Stmt *" for the predefined identifier. It is present if and only if
+ // hasFunctionName() is true and is always a "StringLiteral *".
+
+public:
+ enum IdentKind {
+ Func,
+ Function,
+ LFunction, // Same as Function, but as wide string.
+ FuncDName,
+ FuncSig,
+ LFuncSig, // Same as FuncSig, but as as wide string
+ PrettyFunction,
+ /// The same as PrettyFunction, except that the
+ /// 'virtual' keyword is omitted for virtual member functions.
+ PrettyFunctionNoVirtual
+ };
+
+private:
+ PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK,
+ StringLiteral *SL);
+
+ explicit PredefinedExpr(EmptyShell Empty, bool HasFunctionName);
+
+ /// True if this PredefinedExpr has storage for a function name.
+ bool hasFunctionName() const { return PredefinedExprBits.HasFunctionName; }
+
+ void setFunctionName(StringLiteral *SL) {
+ assert(hasFunctionName() &&
+ "This PredefinedExpr has no storage for a function name!");
+ *getTrailingObjects<Stmt *>() = SL;
+ }
+
+public:
+ /// Create a PredefinedExpr.
+ static PredefinedExpr *Create(const ASTContext &Ctx, SourceLocation L,
+ QualType FNTy, IdentKind IK, StringLiteral *SL);
+
+ /// Create an empty PredefinedExpr.
+ static PredefinedExpr *CreateEmpty(const ASTContext &Ctx,
+ bool HasFunctionName);
+
+ IdentKind getIdentKind() const {
+ return static_cast<IdentKind>(PredefinedExprBits.Kind);
+ }
+
+ SourceLocation getLocation() const { return PredefinedExprBits.Loc; }
+ void setLocation(SourceLocation L) { PredefinedExprBits.Loc = L; }
+
+ StringLiteral *getFunctionName() {
+ return hasFunctionName()
+ ? static_cast<StringLiteral *>(*getTrailingObjects<Stmt *>())
+ : nullptr;
+ }
+
+ const StringLiteral *getFunctionName() const {
+ return hasFunctionName()
+ ? static_cast<StringLiteral *>(*getTrailingObjects<Stmt *>())
+ : nullptr;
+ }
+
+ static StringRef getIdentKindName(IdentKind IK);
+ static std::string ComputeName(IdentKind IK, const Decl *CurrentDecl);
+
+ SourceLocation getBeginLoc() const { return getLocation(); }
+ SourceLocation getEndLoc() const { return getLocation(); }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == PredefinedExprClass;
+ }
+
+ // Iterators
+ child_range children() {
+ return child_range(getTrailingObjects<Stmt *>(),
+ getTrailingObjects<Stmt *>() + hasFunctionName());
+ }
+};
+
/// ParenExpr - This represents a parethesized expression, e.g. "(1)". This
/// AST node is only formed if full location information is requested.
class ParenExpr : public Expr {
@@ -1782,15 +1905,11 @@ public:
/// later returns zero in the type of the operand.
///
class UnaryOperator : public Expr {
+ Stmt *Val;
+
public:
typedef UnaryOperatorKind Opcode;
-private:
- unsigned Opc : 5;
- unsigned CanOverflow : 1;
- SourceLocation Loc;
- Stmt *Val;
-public:
UnaryOperator(Expr *input, Opcode opc, QualType type, ExprValueKind VK,
ExprObjectKind OK, SourceLocation l, bool CanOverflow)
: Expr(UnaryOperatorClass, type, VK, OK,
@@ -1799,21 +1918,28 @@ public:
(input->isInstantiationDependent() ||
type->isInstantiationDependentType()),
input->containsUnexpandedParameterPack()),
- Opc(opc), CanOverflow(CanOverflow), Loc(l), Val(input) {}
+ Val(input) {
+ UnaryOperatorBits.Opc = opc;
+ UnaryOperatorBits.CanOverflow = CanOverflow;
+ UnaryOperatorBits.Loc = l;
+ }
/// Build an empty unary operator.
- explicit UnaryOperator(EmptyShell Empty)
- : Expr(UnaryOperatorClass, Empty), Opc(UO_AddrOf) { }
+ explicit UnaryOperator(EmptyShell Empty) : Expr(UnaryOperatorClass, Empty) {
+ UnaryOperatorBits.Opc = UO_AddrOf;
+ }
- Opcode getOpcode() const { return static_cast<Opcode>(Opc); }
- void setOpcode(Opcode O) { Opc = O; }
+ Opcode getOpcode() const {
+ return static_cast<Opcode>(UnaryOperatorBits.Opc);
+ }
+ void setOpcode(Opcode Opc) { UnaryOperatorBits.Opc = Opc; }
Expr *getSubExpr() const { return cast<Expr>(Val); }
void setSubExpr(Expr *E) { Val = E; }
/// getOperatorLoc - Return the location of the operator.
- SourceLocation getOperatorLoc() const { return Loc; }
- void setOperatorLoc(SourceLocation L) { Loc = L; }
+ SourceLocation getOperatorLoc() const { return UnaryOperatorBits.Loc; }
+ void setOperatorLoc(SourceLocation L) { UnaryOperatorBits.Loc = L; }
/// Returns true if the unary operator can cause an overflow. For instance,
/// signed int i = INT_MAX; i++;
@@ -1821,8 +1947,8 @@ public:
/// Due to integer promotions, c++ is promoted to an int before the postfix
/// increment, and the result is an int that cannot overflow. However, i++
/// can overflow.
- bool canOverflow() const { return CanOverflow; }
- void setCanOverflow(bool C) { CanOverflow = C; }
+ bool canOverflow() const { return UnaryOperatorBits.CanOverflow; }
+ void setCanOverflow(bool C) { UnaryOperatorBits.CanOverflow = C; }
/// isPostfix - Return true if this is a postfix operation, like x++.
static bool isPostfix(Opcode Op) {
@@ -1874,12 +2000,12 @@ public:
static OverloadedOperatorKind getOverloadedOperator(Opcode Opc);
SourceLocation getBeginLoc() const LLVM_READONLY {
- return isPostfix() ? Val->getBeginLoc() : Loc;
+ return isPostfix() ? Val->getBeginLoc() : getOperatorLoc();
}
SourceLocation getEndLoc() const LLVM_READONLY {
- return isPostfix() ? Loc : Val->getEndLoc();
+ return isPostfix() ? getOperatorLoc() : Val->getEndLoc();
}
- SourceLocation getExprLoc() const LLVM_READONLY { return Loc; }
+ SourceLocation getExprLoc() const { return getOperatorLoc(); }
static bool classof(const Stmt *T) {
return T->getStmtClass() == UnaryOperatorClass;
@@ -2195,9 +2321,11 @@ public:
/// ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
class ArraySubscriptExpr : public Expr {
- enum { LHS, RHS, END_EXPR=2 };
- Stmt* SubExprs[END_EXPR];
- SourceLocation RBracketLoc;
+ enum { LHS, RHS, END_EXPR };
+ Stmt *SubExprs[END_EXPR];
+
+ bool lhsIsBase() const { return getRHS()->getType()->isIntegerType(); }
+
public:
ArraySubscriptExpr(Expr *lhs, Expr *rhs, QualType t,
ExprValueKind VK, ExprObjectKind OK,
@@ -2208,10 +2336,10 @@ public:
(lhs->isInstantiationDependent() ||
rhs->isInstantiationDependent()),
(lhs->containsUnexpandedParameterPack() ||
- rhs->containsUnexpandedParameterPack())),
- RBracketLoc(rbracketloc) {
+ rhs->containsUnexpandedParameterPack())) {
SubExprs[LHS] = lhs;
SubExprs[RHS] = rhs;
+ ArraySubscriptExprBits.RBracketLoc = rbracketloc;
}
/// Create an empty array subscript expression.
@@ -2235,29 +2363,23 @@ public:
const Expr *getRHS() const { return cast<Expr>(SubExprs[RHS]); }
void setRHS(Expr *E) { SubExprs[RHS] = E; }
- Expr *getBase() {
- return getRHS()->getType()->isIntegerType() ? getLHS() : getRHS();
- }
-
- const Expr *getBase() const {
- return getRHS()->getType()->isIntegerType() ? getLHS() : getRHS();
- }
-
- Expr *getIdx() {
- return getRHS()->getType()->isIntegerType() ? getRHS() : getLHS();
- }
+ Expr *getBase() { return lhsIsBase() ? getLHS() : getRHS(); }
+ const Expr *getBase() const { return lhsIsBase() ? getLHS() : getRHS(); }
- const Expr *getIdx() const {
- return getRHS()->getType()->isIntegerType() ? getRHS() : getLHS();
- }
+ Expr *getIdx() { return lhsIsBase() ? getRHS() : getLHS(); }
+ const Expr *getIdx() const { return lhsIsBase() ? getRHS() : getLHS(); }
SourceLocation getBeginLoc() const LLVM_READONLY {
return getLHS()->getBeginLoc();
}
- SourceLocation getEndLoc() const LLVM_READONLY { return RBracketLoc; }
+ SourceLocation getEndLoc() const { return getRBracketLoc(); }
- SourceLocation getRBracketLoc() const { return RBracketLoc; }
- void setRBracketLoc(SourceLocation L) { RBracketLoc = L; }
+ SourceLocation getRBracketLoc() const {
+ return ArraySubscriptExprBits.RBracketLoc;
+ }
+ void setRBracketLoc(SourceLocation L) {
+ ArraySubscriptExprBits.RBracketLoc = L;
+ }
SourceLocation getExprLoc() const LLVM_READONLY {
return getBase()->getExprLoc();
@@ -2290,15 +2412,22 @@ class CallExpr : public Expr {
void updateDependenciesFromArg(Expr *Arg);
+public:
+ enum class ADLCallKind : bool { NotADL, UsesADL };
+ static constexpr ADLCallKind NotADL = ADLCallKind::NotADL;
+ static constexpr ADLCallKind UsesADL = ADLCallKind::UsesADL;
+
protected:
// These versions of the constructor are for derived classes.
CallExpr(const ASTContext &C, StmtClass SC, Expr *fn,
ArrayRef<Expr *> preargs, ArrayRef<Expr *> args, QualType t,
- ExprValueKind VK, SourceLocation rparenloc);
+ ExprValueKind VK, SourceLocation rparenloc, unsigned MinNumArgs = 0,
+ ADLCallKind UsesADL = NotADL);
CallExpr(const ASTContext &C, StmtClass SC, Expr *fn, ArrayRef<Expr *> args,
- QualType t, ExprValueKind VK, SourceLocation rparenloc);
+ QualType t, ExprValueKind VK, SourceLocation rparenloc,
+ unsigned MinNumArgs = 0, ADLCallKind UsesADL = NotADL);
CallExpr(const ASTContext &C, StmtClass SC, unsigned NumPreArgs,
- EmptyShell Empty);
+ unsigned NumArgs, EmptyShell Empty);
Stmt *getPreArg(unsigned i) {
assert(i < getNumPreArgs() && "Prearg access out of range!");
@@ -2316,16 +2445,28 @@ protected:
unsigned getNumPreArgs() const { return CallExprBits.NumPreArgs; }
public:
- CallExpr(const ASTContext& C, Expr *fn, ArrayRef<Expr*> args, QualType t,
- ExprValueKind VK, SourceLocation rparenloc);
+ /// Build a call expression. MinNumArgs specifies the minimum number of
+ /// arguments. The actual number of arguments will be the greater of
+ /// args.size() and MinNumArgs.
+ CallExpr(const ASTContext &C, Expr *fn, ArrayRef<Expr *> args, QualType t,
+ ExprValueKind VK, SourceLocation rparenloc, unsigned MinNumArgs = 0,
+ ADLCallKind UsesADL = NotADL);
/// Build an empty call expression.
- CallExpr(const ASTContext &C, StmtClass SC, EmptyShell Empty);
+ CallExpr(const ASTContext &C, unsigned NumArgs, EmptyShell Empty);
const Expr *getCallee() const { return cast<Expr>(SubExprs[FN]); }
Expr *getCallee() { return cast<Expr>(SubExprs[FN]); }
void setCallee(Expr *F) { SubExprs[FN] = F; }
+ ADLCallKind getADLCallKind() const {
+ return static_cast<ADLCallKind>(CallExprBits.UsesADL);
+ }
+ void setADLCallKind(ADLCallKind V = UsesADL) {
+ CallExprBits.UsesADL = static_cast<bool>(V);
+ }
+ bool usesADL() const { return getADLCallKind() == UsesADL; }
+
Decl *getCalleeDecl();
const Decl *getCalleeDecl() const {
return const_cast<CallExpr*>(this)->getCalleeDecl();
@@ -2366,10 +2507,18 @@ public:
SubExprs[Arg+getNumPreArgs()+PREARGS_START] = ArgExpr;
}
- /// setNumArgs - This changes the number of arguments present in this call.
- /// Any orphaned expressions are deleted by this, and any new operands are set
- /// to null.
- void setNumArgs(const ASTContext& C, unsigned NumArgs);
+ /// Reduce the number of arguments in this call expression. This is used for
+ /// example during error recovery to drop extra arguments. There is no way
+ /// to perform the opposite because: 1.) We don't track how much storage
+ /// we have for the argument array 2.) This would potentially require growing
+ /// the argument array, something we cannot support since the arguments will
+ /// be stored in a trailing array in the future.
+ /// (TODO: update this comment when this is done).
+ void shrinkNumArgs(unsigned NewNumArgs) {
+ assert((NewNumArgs <= NumArgs) &&
+ "shrinkNumArgs cannot increase the number of arguments!");
+ NumArgs = NewNumArgs;
+ }
typedef ExprIterator arg_iterator;
typedef ConstExprIterator const_arg_iterator;
@@ -2469,6 +2618,10 @@ class MemberExpr final
private llvm::TrailingObjects<MemberExpr, MemberExprNameQualifier,
ASTTemplateKWAndArgsInfo,
TemplateArgumentLoc> {
+ friend class ASTReader;
+ friend class ASTStmtWriter;
+ friend TrailingObjects;
+
/// Base - the expression for the base pointer or structure references. In
/// X.F, this is "X".
Stmt *Base;
@@ -2484,35 +2637,20 @@ class MemberExpr final
/// MemberLoc - This is the location of the member name.
SourceLocation MemberLoc;
- /// This is the location of the -> or . in the expression.
- SourceLocation OperatorLoc;
-
- /// IsArrow - True if this is "X->F", false if this is "X.F".
- bool IsArrow : 1;
-
- /// True if this member expression used a nested-name-specifier to
- /// refer to the member, e.g., "x->Base::f", or found its member via a using
- /// declaration. When true, a MemberExprNameQualifier
- /// structure is allocated immediately after the MemberExpr.
- bool HasQualifierOrFoundDecl : 1;
-
- /// True if this member expression specified a template keyword
- /// and/or a template argument list explicitly, e.g., x->f<int>,
- /// x->template f, x->template f<int>.
- /// When true, an ASTTemplateKWAndArgsInfo structure and its
- /// TemplateArguments (if any) are present.
- bool HasTemplateKWAndArgsInfo : 1;
-
- /// True if this member expression refers to a method that
- /// was resolved from an overloaded set having size greater than 1.
- bool HadMultipleCandidates : 1;
-
size_t numTrailingObjects(OverloadToken<MemberExprNameQualifier>) const {
- return HasQualifierOrFoundDecl ? 1 : 0;
+ return hasQualifierOrFoundDecl();
}
size_t numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const {
- return HasTemplateKWAndArgsInfo ? 1 : 0;
+ return hasTemplateKWAndArgsInfo();
+ }
+
+ bool hasQualifierOrFoundDecl() const {
+ return MemberExprBits.HasQualifierOrFoundDecl;
+ }
+
+ bool hasTemplateKWAndArgsInfo() const {
+ return MemberExprBits.HasTemplateKWAndArgsInfo;
}
public:
@@ -2523,10 +2661,13 @@ public:
base->isValueDependent(), base->isInstantiationDependent(),
base->containsUnexpandedParameterPack()),
Base(base), MemberDecl(memberdecl), MemberDNLoc(NameInfo.getInfo()),
- MemberLoc(NameInfo.getLoc()), OperatorLoc(operatorloc),
- IsArrow(isarrow), HasQualifierOrFoundDecl(false),
- HasTemplateKWAndArgsInfo(false), HadMultipleCandidates(false) {
+ MemberLoc(NameInfo.getLoc()) {
assert(memberdecl->getDeclName() == NameInfo.getName());
+ MemberExprBits.IsArrow = isarrow;
+ MemberExprBits.HasQualifierOrFoundDecl = false;
+ MemberExprBits.HasTemplateKWAndArgsInfo = false;
+ MemberExprBits.HadMultipleCandidates = false;
+ MemberExprBits.OperatorLoc = operatorloc;
}
// NOTE: this constructor should be used only when it is known that
@@ -2539,10 +2680,13 @@ public:
: Expr(MemberExprClass, ty, VK, OK, base->isTypeDependent(),
base->isValueDependent(), base->isInstantiationDependent(),
base->containsUnexpandedParameterPack()),
- Base(base), MemberDecl(memberdecl), MemberDNLoc(), MemberLoc(l),
- OperatorLoc(operatorloc), IsArrow(isarrow),
- HasQualifierOrFoundDecl(false), HasTemplateKWAndArgsInfo(false),
- HadMultipleCandidates(false) {}
+ Base(base), MemberDecl(memberdecl), MemberDNLoc(), MemberLoc(l) {
+ MemberExprBits.IsArrow = isarrow;
+ MemberExprBits.HasQualifierOrFoundDecl = false;
+ MemberExprBits.HasTemplateKWAndArgsInfo = false;
+ MemberExprBits.HadMultipleCandidates = false;
+ MemberExprBits.OperatorLoc = operatorloc;
+ }
static MemberExpr *Create(const ASTContext &C, Expr *base, bool isarrow,
SourceLocation OperatorLoc,
@@ -2565,7 +2709,7 @@ public:
/// Retrieves the declaration found by lookup.
DeclAccessPair getFoundDecl() const {
- if (!HasQualifierOrFoundDecl)
+ if (!hasQualifierOrFoundDecl())
return DeclAccessPair::make(getMemberDecl(),
getMemberDecl()->getAccess());
return getTrailingObjects<MemberExprNameQualifier>()->FoundDecl;
@@ -2580,9 +2724,8 @@ public:
/// nested-name-specifier that precedes the member name, with source-location
/// information.
NestedNameSpecifierLoc getQualifierLoc() const {
- if (!HasQualifierOrFoundDecl)
+ if (!hasQualifierOrFoundDecl())
return NestedNameSpecifierLoc();
-
return getTrailingObjects<MemberExprNameQualifier>()->QualifierLoc;
}
@@ -2596,21 +2739,24 @@ public:
/// Retrieve the location of the template keyword preceding
/// the member name, if any.
SourceLocation getTemplateKeywordLoc() const {
- if (!HasTemplateKWAndArgsInfo) return SourceLocation();
+ if (!hasTemplateKWAndArgsInfo())
+ return SourceLocation();
return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->TemplateKWLoc;
}
/// Retrieve the location of the left angle bracket starting the
/// explicit template argument list following the member name, if any.
SourceLocation getLAngleLoc() const {
- if (!HasTemplateKWAndArgsInfo) return SourceLocation();
+ if (!hasTemplateKWAndArgsInfo())
+ return SourceLocation();
return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->LAngleLoc;
}
/// Retrieve the location of the right angle bracket ending the
/// explicit template argument list following the member name, if any.
SourceLocation getRAngleLoc() const {
- if (!HasTemplateKWAndArgsInfo) return SourceLocation();
+ if (!hasTemplateKWAndArgsInfo())
+ return SourceLocation();
return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->RAngleLoc;
}
@@ -2657,10 +2803,10 @@ public:
MemberLoc, MemberDNLoc);
}
- SourceLocation getOperatorLoc() const LLVM_READONLY { return OperatorLoc; }
+ SourceLocation getOperatorLoc() const { return MemberExprBits.OperatorLoc; }
- bool isArrow() const { return IsArrow; }
- void setArrow(bool A) { IsArrow = A; }
+ bool isArrow() const { return MemberExprBits.IsArrow; }
+ void setArrow(bool A) { MemberExprBits.IsArrow = A; }
/// getMemberLoc - Return the location of the "member", in X->F, it is the
/// location of 'F'.
@@ -2680,13 +2826,13 @@ public:
/// Returns true if this member expression refers to a method that
/// was resolved from an overloaded set having size greater than 1.
bool hadMultipleCandidates() const {
- return HadMultipleCandidates;
+ return MemberExprBits.HadMultipleCandidates;
}
/// Sets the flag telling whether this expression refers to
/// a method that was resolved from an overloaded set having size
/// greater than 1.
void setHadMultipleCandidates(bool V = true) {
- HadMultipleCandidates = V;
+ MemberExprBits.HadMultipleCandidates = V;
}
/// Returns true if virtual dispatch is performed.
@@ -2706,10 +2852,6 @@ public:
const_child_range children() const {
return const_child_range(&Base, &Base + 1);
}
-
- friend TrailingObjects;
- friend class ASTReader;
- friend class ASTStmtWriter;
};
/// CompoundLiteralExpr - [C99 6.5.2.5]
@@ -2932,8 +3074,7 @@ class ImplicitCastExpr final
private:
ImplicitCastExpr(QualType ty, CastKind kind, Expr *op,
unsigned BasePathLength, ExprValueKind VK)
- : CastExpr(ImplicitCastExprClass, ty, VK, kind, op, BasePathLength) {
- }
+ : CastExpr(ImplicitCastExprClass, ty, VK, kind, op, BasePathLength) { }
/// Construct an empty implicit cast.
explicit ImplicitCastExpr(EmptyShell Shell, unsigned PathSize)
@@ -2976,8 +3117,13 @@ public:
inline Expr *Expr::IgnoreImpCasts() {
Expr *e = this;
- while (ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(e))
- e = ice->getSubExpr();
+ while (true)
+ if (ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(e))
+ e = ice->getSubExpr();
+ else if (FullExpr *fe = dyn_cast<FullExpr>(e))
+ e = fe->getSubExpr();
+ else
+ break;
return e;
}
@@ -3100,20 +3246,11 @@ public:
/// "+" resolves to an overloaded operator, CXXOperatorCallExpr will
/// be used to express the computation.
class BinaryOperator : public Expr {
-public:
- typedef BinaryOperatorKind Opcode;
-
-private:
- unsigned Opc : 6;
-
- // This is only meaningful for operations on floating point types and 0
- // otherwise.
- unsigned FPFeatures : 3;
- SourceLocation OpLoc;
-
enum { LHS, RHS, END_EXPR };
- Stmt* SubExprs[END_EXPR];
+ Stmt *SubExprs[END_EXPR];
+
public:
+ typedef BinaryOperatorKind Opcode;
BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy,
ExprValueKind VK, ExprObjectKind OK,
@@ -3124,8 +3261,10 @@ public:
(lhs->isInstantiationDependent() ||
rhs->isInstantiationDependent()),
(lhs->containsUnexpandedParameterPack() ||
- rhs->containsUnexpandedParameterPack())),
- Opc(opc), FPFeatures(FPFeatures.getInt()), OpLoc(opLoc) {
+ rhs->containsUnexpandedParameterPack())) {
+ BinaryOperatorBits.Opc = opc;
+ BinaryOperatorBits.FPFeatures = FPFeatures.getInt();
+ BinaryOperatorBits.OpLoc = opLoc;
SubExprs[LHS] = lhs;
SubExprs[RHS] = rhs;
assert(!isCompoundAssignmentOp() &&
@@ -3133,15 +3272,18 @@ public:
}
/// Construct an empty binary operator.
- explicit BinaryOperator(EmptyShell Empty)
- : Expr(BinaryOperatorClass, Empty), Opc(BO_Comma) { }
+ explicit BinaryOperator(EmptyShell Empty) : Expr(BinaryOperatorClass, Empty) {
+ BinaryOperatorBits.Opc = BO_Comma;
+ }
- SourceLocation getExprLoc() const LLVM_READONLY { return OpLoc; }
- SourceLocation getOperatorLoc() const { return OpLoc; }
- void setOperatorLoc(SourceLocation L) { OpLoc = L; }
+ SourceLocation getExprLoc() const { return getOperatorLoc(); }
+ SourceLocation getOperatorLoc() const { return BinaryOperatorBits.OpLoc; }
+ void setOperatorLoc(SourceLocation L) { BinaryOperatorBits.OpLoc = L; }
- Opcode getOpcode() const { return static_cast<Opcode>(Opc); }
- void setOpcode(Opcode O) { Opc = O; }
+ Opcode getOpcode() const {
+ return static_cast<Opcode>(BinaryOperatorBits.Opc);
+ }
+ void setOpcode(Opcode Opc) { BinaryOperatorBits.Opc = Opc; }
Expr *getLHS() const { return cast<Expr>(SubExprs[LHS]); }
void setLHS(Expr *E) { SubExprs[LHS] = E; }
@@ -3170,7 +3312,11 @@ public:
static OverloadedOperatorKind getOverloadedOperator(Opcode Opc);
/// predicates to categorize the respective opcodes.
- bool isPtrMemOp() const { return Opc == BO_PtrMemD || Opc == BO_PtrMemI; }
+ static bool isPtrMemOp(Opcode Opc) {
+ return Opc == BO_PtrMemD || Opc == BO_PtrMemI;
+ }
+ bool isPtrMemOp() const { return isPtrMemOp(getOpcode()); }
+
static bool isMultiplicativeOp(Opcode Opc) {
return Opc >= BO_Mul && Opc <= BO_Rem;
}
@@ -3269,21 +3415,23 @@ public:
// Set the FP contractability status of this operator. Only meaningful for
// operations on floating point types.
- void setFPFeatures(FPOptions F) { FPFeatures = F.getInt(); }
+ void setFPFeatures(FPOptions F) {
+ BinaryOperatorBits.FPFeatures = F.getInt();
+ }
- FPOptions getFPFeatures() const { return FPOptions(FPFeatures); }
+ FPOptions getFPFeatures() const {
+ return FPOptions(BinaryOperatorBits.FPFeatures);
+ }
// Get the FP contractability status of this operator. Only meaningful for
// operations on floating point types.
bool isFPContractableWithinStatement() const {
- return FPOptions(FPFeatures).allowFPContractWithinStatement();
+ return getFPFeatures().allowFPContractWithinStatement();
}
// Get the FENV_ACCESS status of this operator. Only meaningful for
// operations on floating point types.
- bool isFEnvAccessOn() const {
- return FPOptions(FPFeatures).allowFEnvAccess();
- }
+ bool isFEnvAccessOn() const { return getFPFeatures().allowFEnvAccess(); }
protected:
BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy,
@@ -3295,14 +3443,17 @@ protected:
(lhs->isInstantiationDependent() ||
rhs->isInstantiationDependent()),
(lhs->containsUnexpandedParameterPack() ||
- rhs->containsUnexpandedParameterPack())),
- Opc(opc), FPFeatures(FPFeatures.getInt()), OpLoc(opLoc) {
+ rhs->containsUnexpandedParameterPack())) {
+ BinaryOperatorBits.Opc = opc;
+ BinaryOperatorBits.FPFeatures = FPFeatures.getInt();
+ BinaryOperatorBits.OpLoc = opLoc;
SubExprs[LHS] = lhs;
SubExprs[RHS] = rhs;
}
- BinaryOperator(StmtClass SC, EmptyShell Empty)
- : Expr(SC, Empty), Opc(BO_MulAssign) { }
+ BinaryOperator(StmtClass SC, EmptyShell Empty) : Expr(SC, Empty) {
+ BinaryOperatorBits.Opc = BO_MulAssign;
+ }
};
/// CompoundAssignOperator - For compound assignments (e.g. +=), we keep
@@ -4726,31 +4877,46 @@ public:
}
};
-class ParenListExpr : public Expr {
- Stmt **Exprs;
- unsigned NumExprs;
+class ParenListExpr final
+ : public Expr,
+ private llvm::TrailingObjects<ParenListExpr, Stmt *> {
+ friend class ASTStmtReader;
+ friend TrailingObjects;
+
+ /// The location of the left and right parentheses.
SourceLocation LParenLoc, RParenLoc;
-public:
- ParenListExpr(const ASTContext& C, SourceLocation lparenloc,
- ArrayRef<Expr*> exprs, SourceLocation rparenloc);
+ /// Build a paren list.
+ ParenListExpr(SourceLocation LParenLoc, ArrayRef<Expr *> Exprs,
+ SourceLocation RParenLoc);
/// Build an empty paren list.
- explicit ParenListExpr(EmptyShell Empty) : Expr(ParenListExprClass, Empty) { }
+ ParenListExpr(EmptyShell Empty, unsigned NumExprs);
+
+public:
+ /// Create a paren list.
+ static ParenListExpr *Create(const ASTContext &Ctx, SourceLocation LParenLoc,
+ ArrayRef<Expr *> Exprs,
+ SourceLocation RParenLoc);
+
+ /// Create an empty paren list.
+ static ParenListExpr *CreateEmpty(const ASTContext &Ctx, unsigned NumExprs);
- unsigned getNumExprs() const { return NumExprs; }
+ /// Return the number of expressions in this paren list.
+ unsigned getNumExprs() const { return ParenListExprBits.NumExprs; }
- const Expr* getExpr(unsigned Init) const {
+ Expr *getExpr(unsigned Init) {
assert(Init < getNumExprs() && "Initializer access out of range!");
- return cast_or_null<Expr>(Exprs[Init]);
+ return getExprs()[Init];
}
- Expr* getExpr(unsigned Init) {
- assert(Init < getNumExprs() && "Initializer access out of range!");
- return cast_or_null<Expr>(Exprs[Init]);
+ const Expr *getExpr(unsigned Init) const {
+ return const_cast<ParenListExpr *>(this)->getExpr(Init);
}
- Expr **getExprs() { return reinterpret_cast<Expr **>(Exprs); }
+ Expr **getExprs() {
+ return reinterpret_cast<Expr **>(getTrailingObjects<Stmt *>());
+ }
ArrayRef<Expr *> exprs() {
return llvm::makeArrayRef(getExprs(), getNumExprs());
@@ -4758,9 +4924,8 @@ public:
SourceLocation getLParenLoc() const { return LParenLoc; }
SourceLocation getRParenLoc() const { return RParenLoc; }
-
- SourceLocation getBeginLoc() const LLVM_READONLY { return LParenLoc; }
- SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; }
+ SourceLocation getBeginLoc() const { return getLParenLoc(); }
+ SourceLocation getEndLoc() const { return getRParenLoc(); }
static bool classof(const Stmt *T) {
return T->getStmtClass() == ParenListExprClass;
@@ -4768,14 +4933,13 @@ public:
// Iterators
child_range children() {
- return child_range(&Exprs[0], &Exprs[0]+NumExprs);
+ return child_range(getTrailingObjects<Stmt *>(),
+ getTrailingObjects<Stmt *>() + getNumExprs());
}
const_child_range children() const {
- return const_child_range(&Exprs[0], &Exprs[0] + NumExprs);
+ return const_child_range(getTrailingObjects<Stmt *>(),
+ getTrailingObjects<Stmt *>() + getNumExprs());
}
-
- friend class ASTStmtReader;
- friend class ASTStmtWriter;
};
/// Represents a C11 generic selection.
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index 8fbd53798a..f39bddb040 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -90,16 +90,20 @@ public:
friend class ASTStmtReader;
friend class ASTStmtWriter;
- CXXOperatorCallExpr(ASTContext& C, OverloadedOperatorKind Op, Expr *fn,
- ArrayRef<Expr*> args, QualType t, ExprValueKind VK,
- SourceLocation operatorloc, FPOptions FPFeatures)
- : CallExpr(C, CXXOperatorCallExprClass, fn, args, t, VK, operatorloc),
+ CXXOperatorCallExpr(ASTContext &C, OverloadedOperatorKind Op, Expr *fn,
+ ArrayRef<Expr *> args, QualType t, ExprValueKind VK,
+ SourceLocation operatorloc, FPOptions FPFeatures,
+ ADLCallKind UsesADL = NotADL)
+ : CallExpr(C, CXXOperatorCallExprClass, fn, args, t, VK, operatorloc,
+ /*MinNumArgs=*/0, UsesADL),
Operator(Op), FPFeatures(FPFeatures) {
Range = getSourceRangeImpl();
}
- explicit CXXOperatorCallExpr(ASTContext& C, EmptyShell Empty)
- : CallExpr(C, CXXOperatorCallExprClass, Empty) {}
+ explicit CXXOperatorCallExpr(ASTContext &C, unsigned NumArgs,
+ EmptyShell Empty)
+ : CallExpr(C, CXXOperatorCallExprClass, /*NumPreArgs=*/0, NumArgs,
+ Empty) {}
/// Returns the kind of overloaded operator that this
/// expression refers to.
@@ -163,12 +167,14 @@ public:
/// the object argument).
class CXXMemberCallExpr : public CallExpr {
public:
- CXXMemberCallExpr(ASTContext &C, Expr *fn, ArrayRef<Expr*> args,
- QualType t, ExprValueKind VK, SourceLocation RP)
- : CallExpr(C, CXXMemberCallExprClass, fn, args, t, VK, RP) {}
+ CXXMemberCallExpr(ASTContext &C, Expr *fn, ArrayRef<Expr *> args, QualType t,
+ ExprValueKind VK, SourceLocation RP,
+ unsigned MinNumArgs = 0)
+ : CallExpr(C, CXXMemberCallExprClass, fn, args, t, VK, RP, MinNumArgs,
+ NotADL) {}
- CXXMemberCallExpr(ASTContext &C, EmptyShell Empty)
- : CallExpr(C, CXXMemberCallExprClass, Empty) {}
+ CXXMemberCallExpr(ASTContext &C, unsigned NumArgs, EmptyShell Empty)
+ : CallExpr(C, CXXMemberCallExprClass, /*NumPreArgs=*/0, NumArgs, Empty) {}
/// Retrieves the implicit object argument for the member call.
///
@@ -206,12 +212,14 @@ private:
public:
CUDAKernelCallExpr(ASTContext &C, Expr *fn, CallExpr *Config,
- ArrayRef<Expr*> args, QualType t, ExprValueKind VK,
- SourceLocation RP)
- : CallExpr(C, CUDAKernelCallExprClass, fn, Config, args, t, VK, RP) {}
+ ArrayRef<Expr *> args, QualType t, ExprValueKind VK,
+ SourceLocation RP, unsigned MinNumArgs = 0)
+ : CallExpr(C, CUDAKernelCallExprClass, fn, Config, args, t, VK, RP,
+ MinNumArgs, NotADL) {}
- CUDAKernelCallExpr(ASTContext &C, EmptyShell Empty)
- : CallExpr(C, CUDAKernelCallExprClass, END_PREARG, Empty) {}
+ CUDAKernelCallExpr(ASTContext &C, unsigned NumArgs, EmptyShell Empty)
+ : CallExpr(C, CUDAKernelCallExprClass, /*NumPreArgs=*/END_PREARG, NumArgs,
+ Empty) {}
const CallExpr *getConfig() const {
return cast_or_null<CallExpr>(getPreArg(CONFIG));
@@ -482,14 +490,17 @@ public:
friend class ASTStmtReader;
friend class ASTStmtWriter;
- UserDefinedLiteral(const ASTContext &C, Expr *Fn, ArrayRef<Expr*> Args,
+ UserDefinedLiteral(const ASTContext &C, Expr *Fn, ArrayRef<Expr *> Args,
QualType T, ExprValueKind VK, SourceLocation LitEndLoc,
SourceLocation SuffixLoc)
- : CallExpr(C, UserDefinedLiteralClass, Fn, Args, T, VK, LitEndLoc),
+ : CallExpr(C, UserDefinedLiteralClass, Fn, Args, T, VK, LitEndLoc,
+ /*MinNumArgs=*/0, NotADL),
UDSuffixLoc(SuffixLoc) {}
- explicit UserDefinedLiteral(const ASTContext &C, EmptyShell Empty)
- : CallExpr(C, UserDefinedLiteralClass, Empty) {}
+ explicit UserDefinedLiteral(const ASTContext &C, unsigned NumArgs,
+ EmptyShell Empty)
+ : CallExpr(C, UserDefinedLiteralClass, /*NumPreArgs=*/0, NumArgs, Empty) {
+ }
/// The kind of literal operator which is invoked.
enum LiteralOperatorKind {
@@ -548,26 +559,25 @@ public:
/// A boolean literal, per ([C++ lex.bool] Boolean literals).
class CXXBoolLiteralExpr : public Expr {
- bool Value;
- SourceLocation Loc;
-
public:
- CXXBoolLiteralExpr(bool val, QualType Ty, SourceLocation l)
+ CXXBoolLiteralExpr(bool Val, QualType Ty, SourceLocation Loc)
: Expr(CXXBoolLiteralExprClass, Ty, VK_RValue, OK_Ordinary, false, false,
- false, false),
- Value(val), Loc(l) {}
+ false, false) {
+ CXXBoolLiteralExprBits.Value = Val;
+ CXXBoolLiteralExprBits.Loc = Loc;
+ }
explicit CXXBoolLiteralExpr(EmptyShell Empty)
: Expr(CXXBoolLiteralExprClass, Empty) {}
- bool getValue() const { return Value; }
- void setValue(bool V) { Value = V; }
+ bool getValue() const { return CXXBoolLiteralExprBits.Value; }
+ void setValue(bool V) { CXXBoolLiteralExprBits.Value = V; }
- SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; }
- SourceLocation getEndLoc() const LLVM_READONLY { return Loc; }
+ SourceLocation getBeginLoc() const { return getLocation(); }
+ SourceLocation getEndLoc() const { return getLocation(); }
- SourceLocation getLocation() const { return Loc; }
- void setLocation(SourceLocation L) { Loc = L; }
+ SourceLocation getLocation() const { return CXXBoolLiteralExprBits.Loc; }
+ void setLocation(SourceLocation L) { CXXBoolLiteralExprBits.Loc = L; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXBoolLiteralExprClass;
@@ -583,22 +593,21 @@ public:
///
/// Introduced in C++11, the only literal of type \c nullptr_t is \c nullptr.
class CXXNullPtrLiteralExpr : public Expr {
- SourceLocation Loc;
-
public:
- CXXNullPtrLiteralExpr(QualType Ty, SourceLocation l)
+ CXXNullPtrLiteralExpr(QualType Ty, SourceLocation Loc)
: Expr(CXXNullPtrLiteralExprClass, Ty, VK_RValue, OK_Ordinary, false,
- false, false, false),
- Loc(l) {}
+ false, false, false) {
+ CXXNullPtrLiteralExprBits.Loc = Loc;
+ }
explicit CXXNullPtrLiteralExpr(EmptyShell Empty)
: Expr(CXXNullPtrLiteralExprClass, Empty) {}
- SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; }
- SourceLocation getEndLoc() const LLVM_READONLY { return Loc; }
+ SourceLocation getBeginLoc() const { return getLocation(); }
+ SourceLocation getEndLoc() const { return getLocation(); }
- SourceLocation getLocation() const { return Loc; }
- void setLocation(SourceLocation L) { Loc = L; }
+ SourceLocation getLocation() const { return CXXNullPtrLiteralExprBits.Loc; }
+ void setLocation(SourceLocation L) { CXXNullPtrLiteralExprBits.Loc = L; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXNullPtrLiteralExprClass;
@@ -964,29 +973,28 @@ public:
/// };
/// \endcode
class CXXThisExpr : public Expr {
- SourceLocation Loc;
- bool Implicit : 1;
-
public:
- CXXThisExpr(SourceLocation L, QualType Type, bool isImplicit)
- : Expr(CXXThisExprClass, Type, VK_RValue, OK_Ordinary,
+ CXXThisExpr(SourceLocation L, QualType Ty, bool IsImplicit)
+ : Expr(CXXThisExprClass, Ty, VK_RValue, OK_Ordinary,
// 'this' is type-dependent if the class type of the enclosing
// member function is dependent (C++ [temp.dep.expr]p2)
- Type->isDependentType(), Type->isDependentType(),
- Type->isInstantiationDependentType(),
- /*ContainsUnexpandedParameterPack=*/false),
- Loc(L), Implicit(isImplicit) {}
+ Ty->isDependentType(), Ty->isDependentType(),
+ Ty->isInstantiationDependentType(),
+ /*ContainsUnexpandedParameterPack=*/false) {
+ CXXThisExprBits.IsImplicit = IsImplicit;
+ CXXThisExprBits.Loc = L;
+ }
CXXThisExpr(EmptyShell Empty) : Expr(CXXThisExprClass, Empty) {}
- SourceLocation getLocation() const { return Loc; }
- void setLocation(SourceLocation L) { Loc = L; }
+ SourceLocation getLocation() const { return CXXThisExprBits.Loc; }
+ void setLocation(SourceLocation L) { CXXThisExprBits.Loc = L; }
- SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; }
- SourceLocation getEndLoc() const LLVM_READONLY { return Loc; }
+ SourceLocation getBeginLoc() const { return getLocation(); }
+ SourceLocation getEndLoc() const { return getLocation(); }
- bool isImplicit() const { return Implicit; }
- void setImplicit(bool I) { Implicit = I; }
+ bool isImplicit() const { return CXXThisExprBits.IsImplicit; }
+ void setImplicit(bool I) { CXXThisExprBits.IsImplicit = I; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXThisExprClass;
@@ -1006,42 +1014,43 @@ public:
class CXXThrowExpr : public Expr {
friend class ASTStmtReader;
- Stmt *Op;
- SourceLocation ThrowLoc;
-
- /// Whether the thrown variable (if any) is in scope.
- unsigned IsThrownVariableInScope : 1;
+ /// The optional expression in the throw statement.
+ Stmt *Operand;
public:
// \p Ty is the void type which is used as the result type of the
- // expression. The \p l is the location of the throw keyword. \p expr
- // can by null, if the optional expression to throw isn't present.
- CXXThrowExpr(Expr *expr, QualType Ty, SourceLocation l,
+ // expression. The \p Loc is the location of the throw keyword.
+ // \p Operand is the expression in the throw statement, and can be
+ // null if not present.
+ CXXThrowExpr(Expr *Operand, QualType Ty, SourceLocation Loc,
bool IsThrownVariableInScope)
: Expr(CXXThrowExprClass, Ty, VK_RValue, OK_Ordinary, false, false,
- expr && expr->isInstantiationDependent(),
- expr && expr->containsUnexpandedParameterPack()),
- Op(expr), ThrowLoc(l),
- IsThrownVariableInScope(IsThrownVariableInScope) {}
+ Operand && Operand->isInstantiationDependent(),
+ Operand && Operand->containsUnexpandedParameterPack()),
+ Operand(Operand) {
+ CXXThrowExprBits.ThrowLoc = Loc;
+ CXXThrowExprBits.IsThrownVariableInScope = IsThrownVariableInScope;
+ }
CXXThrowExpr(EmptyShell Empty) : Expr(CXXThrowExprClass, Empty) {}
- const Expr *getSubExpr() const { return cast_or_null<Expr>(Op); }
- Expr *getSubExpr() { return cast_or_null<Expr>(Op); }
+ const Expr *getSubExpr() const { return cast_or_null<Expr>(Operand); }
+ Expr *getSubExpr() { return cast_or_null<Expr>(Operand); }
- SourceLocation getThrowLoc() const { return ThrowLoc; }
+ SourceLocation getThrowLoc() const { return CXXThrowExprBits.ThrowLoc; }
/// Determines whether the variable thrown by this expression (if any!)
/// is within the innermost try block.
///
/// This information is required to determine whether the NRVO can apply to
/// this variable.
- bool isThrownVariableInScope() const { return IsThrownVariableInScope; }
-
- SourceLocation getBeginLoc() const LLVM_READONLY { return ThrowLoc; }
+ bool isThrownVariableInScope() const {
+ return CXXThrowExprBits.IsThrownVariableInScope;
+ }
+ SourceLocation getBeginLoc() const { return getThrowLoc(); }
SourceLocation getEndLoc() const LLVM_READONLY {
if (!getSubExpr())
- return ThrowLoc;
+ return getThrowLoc();
return getSubExpr()->getEndLoc();
}
@@ -1051,7 +1060,7 @@ public:
// Iterators
child_range children() {
- return child_range(&Op, Op ? &Op+1 : &Op);
+ return child_range(&Operand, Operand ? &Operand + 1 : &Operand);
}
};
@@ -1061,26 +1070,24 @@ public:
/// corresponding parameter's default argument, when the call did not
/// explicitly supply arguments for all of the parameters.
class CXXDefaultArgExpr final : public Expr {
+ friend class ASTStmtReader;
+
/// The parameter whose default is being used.
ParmVarDecl *Param;
- /// The location where the default argument expression was used.
- SourceLocation Loc;
-
- CXXDefaultArgExpr(StmtClass SC, SourceLocation Loc, ParmVarDecl *param)
+ CXXDefaultArgExpr(StmtClass SC, SourceLocation Loc, ParmVarDecl *Param)
: Expr(SC,
- param->hasUnparsedDefaultArg()
- ? param->getType().getNonReferenceType()
- : param->getDefaultArg()->getType(),
- param->getDefaultArg()->getValueKind(),
- param->getDefaultArg()->getObjectKind(), false, false, false,
+ Param->hasUnparsedDefaultArg()
+ ? Param->getType().getNonReferenceType()
+ : Param->getDefaultArg()->getType(),
+ Param->getDefaultArg()->getValueKind(),
+ Param->getDefaultArg()->getObjectKind(), false, false, false,
false),
- Param(param), Loc(Loc) {}
+ Param(Param) {
+ CXXDefaultArgExprBits.Loc = Loc;
+ }
public:
- friend class ASTStmtReader;
- friend class ASTStmtWriter;
-
CXXDefaultArgExpr(EmptyShell Empty) : Expr(CXXDefaultArgExprClass, Empty) {}
// \p Param is the parameter whose default argument is used by this
@@ -1095,23 +1102,18 @@ public:
ParmVarDecl *getParam() { return Param; }
// Retrieve the actual argument to the function call.
- const Expr *getExpr() const {
- return getParam()->getDefaultArg();
- }
- Expr *getExpr() {
- return getParam()->getDefaultArg();
- }
+ const Expr *getExpr() const { return getParam()->getDefaultArg(); }
+ Expr *getExpr() { return getParam()->getDefaultArg(); }
- /// Retrieve the location where this default argument was actually
- /// used.
- SourceLocation getUsedLocation() const { return Loc; }
+ /// Retrieve the location where this default argument was actually used.
+ SourceLocation getUsedLocation() const { return CXXDefaultArgExprBits.Loc; }
/// Default argument expressions have no representation in the
/// source, so they have an empty source range.
- SourceLocation getBeginLoc() const LLVM_READONLY { return SourceLocation(); }
- SourceLocation getEndLoc() const LLVM_READONLY { return SourceLocation(); }
+ SourceLocation getBeginLoc() const { return SourceLocation(); }
+ SourceLocation getEndLoc() const { return SourceLocation(); }
- SourceLocation getExprLoc() const LLVM_READONLY { return Loc; }
+ SourceLocation getExprLoc() const { return getUsedLocation(); }
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXDefaultArgExprClass;
@@ -1132,26 +1134,23 @@ public:
/// (C++11 [class.base.init]p8) or in aggregate initialization
/// (C++1y [dcl.init.aggr]p7).
class CXXDefaultInitExpr : public Expr {
+ friend class ASTReader;
+ friend class ASTStmtReader;
+
/// The field whose default is being used.
FieldDecl *Field;
- /// The location where the default initializer expression was used.
- SourceLocation Loc;
-
- CXXDefaultInitExpr(const ASTContext &C, SourceLocation Loc, FieldDecl *Field,
- QualType T);
+ CXXDefaultInitExpr(const ASTContext &Ctx, SourceLocation Loc,
+ FieldDecl *Field, QualType Ty);
CXXDefaultInitExpr(EmptyShell Empty) : Expr(CXXDefaultInitExprClass, Empty) {}
public:
- friend class ASTReader;
- friend class ASTStmtReader;
-
/// \p Field is the non-static data member whose default initializer is used
/// by this expression.
- static CXXDefaultInitExpr *Create(const ASTContext &C, SourceLocation Loc,
+ static CXXDefaultInitExpr *Create(const ASTContext &Ctx, SourceLocation Loc,
FieldDecl *Field) {
- return new (C) CXXDefaultInitExpr(C, Loc, Field, Field->getType());
+ return new (Ctx) CXXDefaultInitExpr(Ctx, Loc, Field, Field->getType());
}
/// Get the field whose initializer will be used.
@@ -1168,8 +1167,8 @@ public:
return Field->getInClassInitializer();
}
- SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; }
- SourceLocation getEndLoc() const LLVM_READONLY { return Loc; }
+ SourceLocation getBeginLoc() const { return CXXDefaultInitExprBits.Loc; }
+ SourceLocation getEndLoc() const { return CXXDefaultInitExprBits.Loc; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXDefaultInitExprClass;
@@ -2098,55 +2097,43 @@ public:
/// Represents a \c delete expression for memory deallocation and
/// destructor calls, e.g. "delete[] pArray".
class CXXDeleteExpr : public Expr {
+ friend class ASTStmtReader;
+
/// Points to the operator delete overload that is used. Could be a member.
FunctionDecl *OperatorDelete = nullptr;
/// The pointer expression to be deleted.
Stmt *Argument = nullptr;
- /// Location of the expression.
- SourceLocation Loc;
-
- /// Is this a forced global delete, i.e. "::delete"?
- bool GlobalDelete : 1;
-
- /// Is this the array form of delete, i.e. "delete[]"?
- bool ArrayForm : 1;
-
- /// ArrayFormAsWritten can be different from ArrayForm if 'delete' is applied
- /// to pointer-to-array type (ArrayFormAsWritten will be false while ArrayForm
- /// will be true).
- bool ArrayFormAsWritten : 1;
-
- /// Does the usual deallocation function for the element type require
- /// a size_t argument?
- bool UsualArrayDeleteWantsSize : 1;
-
public:
- friend class ASTStmtReader;
+ CXXDeleteExpr(QualType Ty, bool GlobalDelete, bool ArrayForm,
+ bool ArrayFormAsWritten, bool UsualArrayDeleteWantsSize,
+ FunctionDecl *OperatorDelete, Expr *Arg, SourceLocation Loc)
+ : Expr(CXXDeleteExprClass, Ty, VK_RValue, OK_Ordinary, false, false,
+ Arg->isInstantiationDependent(),
+ Arg->containsUnexpandedParameterPack()),
+ OperatorDelete(OperatorDelete), Argument(Arg) {
+ CXXDeleteExprBits.GlobalDelete = GlobalDelete;
+ CXXDeleteExprBits.ArrayForm = ArrayForm;
+ CXXDeleteExprBits.ArrayFormAsWritten = ArrayFormAsWritten;
+ CXXDeleteExprBits.UsualArrayDeleteWantsSize = UsualArrayDeleteWantsSize;
+ CXXDeleteExprBits.Loc = Loc;
+ }
- CXXDeleteExpr(QualType ty, bool globalDelete, bool arrayForm,
- bool arrayFormAsWritten, bool usualArrayDeleteWantsSize,
- FunctionDecl *operatorDelete, Expr *arg, SourceLocation loc)
- : Expr(CXXDeleteExprClass, ty, VK_RValue, OK_Ordinary, false, false,
- arg->isInstantiationDependent(),
- arg->containsUnexpandedParameterPack()),
- OperatorDelete(operatorDelete), Argument(arg), Loc(loc),
- GlobalDelete(globalDelete),
- ArrayForm(arrayForm), ArrayFormAsWritten(arrayFormAsWritten),
- UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize) {}
explicit CXXDeleteExpr(EmptyShell Shell) : Expr(CXXDeleteExprClass, Shell) {}
- bool isGlobalDelete() const { return GlobalDelete; }
- bool isArrayForm() const { return ArrayForm; }
- bool isArrayFormAsWritten() const { return ArrayFormAsWritten; }
+ bool isGlobalDelete() const { return CXXDeleteExprBits.GlobalDelete; }
+ bool isArrayForm() const { return CXXDeleteExprBits.ArrayForm; }
+ bool isArrayFormAsWritten() const {
+ return CXXDeleteExprBits.ArrayFormAsWritten;
+ }
/// Answers whether the usual array deallocation function for the
/// allocated type expects the size of the allocation as a
/// parameter. This can be true even if the actual deallocation
/// function that we're using doesn't want a size.
bool doesUsualArrayDeleteWantSize() const {
- return UsualArrayDeleteWantsSize;
+ return CXXDeleteExprBits.UsualArrayDeleteWantsSize;
}
FunctionDecl *getOperatorDelete() const { return OperatorDelete; }
@@ -2160,7 +2147,7 @@ public:
/// be a pointer, return an invalid type.
QualType getDestroyedType() const;
- SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; }
+ SourceLocation getBeginLoc() const { return CXXDeleteExprBits.Loc; }
SourceLocation getEndLoc() const LLVM_READONLY {
return Argument->getEndLoc();
}
@@ -2170,7 +2157,7 @@ public:
}
// Iterators
- child_range children() { return child_range(&Argument, &Argument+1); }
+ child_range children() { return child_range(&Argument, &Argument + 1); }
};
/// Stores the type being destroyed by a pseudo-destructor expression.
@@ -2472,8 +2459,6 @@ class ArrayTypeTraitExpr : public Expr {
/// The type being queried.
TypeSourceInfo *QueriedType = nullptr;
- virtual void anchor();
-
public:
friend class ASTStmtReader;
@@ -2491,8 +2476,6 @@ public:
explicit ArrayTypeTraitExpr(EmptyShell Empty)
: Expr(ArrayTypeTraitExprClass, Empty), ATT(0) {}
- virtual ~ArrayTypeTraitExpr() = default;
-
SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; }
SourceLocation getEndLoc() const LLVM_READONLY { return RParen; }
@@ -3031,7 +3014,7 @@ public:
/// potentially-evaluated block literal. The lifetime of a block
/// literal is the extent of the enclosing scope.
class ExprWithCleanups final
- : public Expr,
+ : public FullExpr,
private llvm::TrailingObjects<ExprWithCleanups, BlockDecl *> {
public:
/// The type of objects that are kept in the cleanup.
@@ -3044,8 +3027,6 @@ private:
friend class ASTStmtReader;
friend TrailingObjects;
- Stmt *SubExpr;
-
ExprWithCleanups(EmptyShell, unsigned NumObjects);
ExprWithCleanups(Expr *SubExpr, bool CleanupsHaveSideEffects,
ArrayRef<CleanupObject> Objects);
@@ -3070,17 +3051,10 @@ public:
return getObjects()[i];
}
- Expr *getSubExpr() { return cast<Expr>(SubExpr); }
- const Expr *getSubExpr() const { return cast<Expr>(SubExpr); }
-
bool cleanupsHaveSideEffects() const {
return ExprWithCleanupsBits.CleanupsHaveSideEffects;
}
- /// As with any mutator of the AST, be very careful
- /// when modifying an existing AST to preserve its invariants.
- void setSubExpr(Expr *E) { SubExpr = E; }
-
SourceLocation getBeginLoc() const LLVM_READONLY {
return SubExpr->getBeginLoc();
}
diff --git a/include/clang/AST/FormatString.h b/include/clang/AST/FormatString.h
new file mode 100644
index 0000000000..4a89c797b6
--- /dev/null
+++ b/include/clang/AST/FormatString.h
@@ -0,0 +1,752 @@
+//= FormatString.h - Analysis of printf/fprintf format strings --*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines APIs for analyzing the format strings of printf, fscanf,
+// and friends.
+//
+// The structure of format strings for fprintf are described in C99 7.19.6.1.
+//
+// The structure of format strings for fscanf are described in C99 7.19.6.2.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H
+
+#include "clang/AST/CanonicalType.h"
+
+namespace clang {
+
+class TargetInfo;
+
+//===----------------------------------------------------------------------===//
+/// Common components of both fprintf and fscanf format strings.
+namespace analyze_format_string {
+
+/// Class representing optional flags with location and representation
+/// information.
+class OptionalFlag {
+public:
+ OptionalFlag(const char *Representation)
+ : representation(Representation), flag(false) {}
+ bool isSet() const { return flag; }
+ void set() { flag = true; }
+ void clear() { flag = false; }
+ void setPosition(const char *position) {
+ assert(position);
+ flag = true;
+ this->position = position;
+ }
+ const char *getPosition() const {
+ assert(position);
+ return position;
+ }
+ const char *toString() const { return representation; }
+
+ // Overloaded operators for bool like qualities
+ explicit operator bool() const { return flag; }
+ OptionalFlag& operator=(const bool &rhs) {
+ flag = rhs;
+ return *this; // Return a reference to myself.
+ }
+private:
+ const char *representation;
+ const char *position;
+ bool flag;
+};
+
+/// Represents the length modifier in a format string in scanf/printf.
+class LengthModifier {
+public:
+ enum Kind {
+ None,
+ AsChar, // 'hh'
+ AsShort, // 'h'
+ AsLong, // 'l'
+ AsLongLong, // 'll'
+ AsQuad, // 'q' (BSD, deprecated, for 64-bit integer types)
+ AsIntMax, // 'j'
+ AsSizeT, // 'z'
+ AsPtrDiff, // 't'
+ AsInt32, // 'I32' (MSVCRT, like __int32)
+ AsInt3264, // 'I' (MSVCRT, like __int3264 from MIDL)
+ AsInt64, // 'I64' (MSVCRT, like __int64)
+ AsLongDouble, // 'L'
+ AsAllocate, // for '%as', GNU extension to C90 scanf
+ AsMAllocate, // for '%ms', GNU extension to scanf
+ AsWide, // 'w' (MSVCRT, like l but only for c, C, s, S, or Z
+ AsWideChar = AsLong // for '%ls', only makes sense for printf
+ };
+
+ LengthModifier()
+ : Position(nullptr), kind(None) {}
+ LengthModifier(const char *pos, Kind k)
+ : Position(pos), kind(k) {}
+
+ const char *getStart() const {
+ return Position;
+ }
+
+ unsigned getLength() const {
+ switch (kind) {
+ default:
+ return 1;
+ case AsLongLong:
+ case AsChar:
+ return 2;
+ case AsInt32:
+ case AsInt64:
+ return 3;
+ case None:
+ return 0;
+ }
+ }
+
+ Kind getKind() const { return kind; }
+ void setKind(Kind k) { kind = k; }
+
+ const char *toString() const;
+
+private:
+ const char *Position;
+ Kind kind;
+};
+
+class ConversionSpecifier {
+public:
+ enum Kind {
+ InvalidSpecifier = 0,
+ // C99 conversion specifiers.
+ cArg,
+ dArg,
+ DArg, // Apple extension
+ iArg,
+ IntArgBeg = dArg,
+ IntArgEnd = iArg,
+
+ oArg,
+ OArg, // Apple extension
+ uArg,
+ UArg, // Apple extension
+ xArg,
+ XArg,
+ UIntArgBeg = oArg,
+ UIntArgEnd = XArg,
+
+ fArg,
+ FArg,
+ eArg,
+ EArg,
+ gArg,
+ GArg,
+ aArg,
+ AArg,
+ DoubleArgBeg = fArg,
+ DoubleArgEnd = AArg,
+
+ sArg,
+ pArg,
+ nArg,
+ PercentArg,
+ CArg,
+ SArg,
+
+ // Apple extension: P specifies to os_log that the data being pointed to is
+ // to be copied by os_log. The precision indicates the number of bytes to
+ // copy.
+ PArg,
+
+ // ** Printf-specific **
+
+ ZArg, // MS extension
+
+ // Objective-C specific specifiers.
+ ObjCObjArg, // '@'
+ ObjCBeg = ObjCObjArg,
+ ObjCEnd = ObjCObjArg,
+
+ // FreeBSD kernel specific specifiers.
+ FreeBSDbArg,
+ FreeBSDDArg,
+ FreeBSDrArg,
+ FreeBSDyArg,
+
+ // GlibC specific specifiers.
+ PrintErrno, // 'm'
+
+ PrintfConvBeg = ObjCObjArg,
+ PrintfConvEnd = PrintErrno,
+
+ // ** Scanf-specific **
+ ScanListArg, // '['
+ ScanfConvBeg = ScanListArg,
+ ScanfConvEnd = ScanListArg
+ };
+
+ ConversionSpecifier(bool isPrintf = true)
+ : IsPrintf(isPrintf), Position(nullptr), EndScanList(nullptr),
+ kind(InvalidSpecifier) {}
+
+ ConversionSpecifier(bool isPrintf, const char *pos, Kind k)
+ : IsPrintf(isPrintf), Position(pos), EndScanList(nullptr), kind(k) {}
+
+ const char *getStart() const {
+ return Position;
+ }
+
+ StringRef getCharacters() const {
+ return StringRef(getStart(), getLength());
+ }
+
+ bool consumesDataArgument() const {
+ switch (kind) {
+ case PrintErrno:
+ assert(IsPrintf);
+ return false;
+ case PercentArg:
+ return false;
+ case InvalidSpecifier:
+ return false;
+ default:
+ return true;
+ }
+ }
+
+ Kind getKind() const { return kind; }
+ void setKind(Kind k) { kind = k; }
+ unsigned getLength() const {
+ return EndScanList ? EndScanList - Position : 1;
+ }
+ void setEndScanList(const char *pos) { EndScanList = pos; }
+
+ bool isIntArg() const { return (kind >= IntArgBeg && kind <= IntArgEnd) ||
+ kind == FreeBSDrArg || kind == FreeBSDyArg; }
+ bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }
+ bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; }
+ bool isDoubleArg() const {
+ return kind >= DoubleArgBeg && kind <= DoubleArgEnd;
+ }
+
+ const char *toString() const;
+
+ bool isPrintfKind() const { return IsPrintf; }
+
+ Optional<ConversionSpecifier> getStandardSpecifier() const;
+
+protected:
+ bool IsPrintf;
+ const char *Position;
+ const char *EndScanList;
+ Kind kind;
+};
+
+class ArgType {
+public:
+ enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy,
+ AnyCharTy, CStrTy, WCStrTy, WIntTy };
+
+ enum MatchKind { NoMatch = 0, Match = 1, NoMatchPedantic };
+
+private:
+ const Kind K;
+ QualType T;
+ const char *Name = nullptr;
+ bool Ptr = false;
+
+ /// The TypeKind identifies certain well-known types like size_t and
+ /// ptrdiff_t.
+ enum class TypeKind { DontCare, SizeT, PtrdiffT };
+ TypeKind TK = TypeKind::DontCare;
+
+public:
+ ArgType(Kind K = UnknownTy, const char *N = nullptr) : K(K), Name(N) {}
+ ArgType(QualType T, const char *N = nullptr) : K(SpecificTy), T(T), Name(N) {}
+ ArgType(CanQualType T) : K(SpecificTy), T(T) {}
+
+ static ArgType Invalid() { return ArgType(InvalidTy); }
+ bool isValid() const { return K != InvalidTy; }
+
+ bool isSizeT() const { return TK == TypeKind::SizeT; }
+
+ bool isPtrdiffT() const { return TK == TypeKind::PtrdiffT; }
+
+ /// Create an ArgType which corresponds to the type pointer to A.
+ static ArgType PtrTo(const ArgType& A) {
+ assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown");
+ ArgType Res = A;
+ Res.Ptr = true;
+ return Res;
+ }
+
+ /// Create an ArgType which corresponds to the size_t/ssize_t type.
+ static ArgType makeSizeT(const ArgType &A) {
+ ArgType Res = A;
+ Res.TK = TypeKind::SizeT;
+ return Res;
+ }
+
+ /// Create an ArgType which corresponds to the ptrdiff_t/unsigned ptrdiff_t
+ /// type.
+ static ArgType makePtrdiffT(const ArgType &A) {
+ ArgType Res = A;
+ Res.TK = TypeKind::PtrdiffT;
+ return Res;
+ }
+
+ MatchKind matchesType(ASTContext &C, QualType argTy) const;
+
+ QualType getRepresentativeType(ASTContext &C) const;
+
+ ArgType makeVectorType(ASTContext &C, unsigned NumElts) const;
+
+ std::string getRepresentativeTypeName(ASTContext &C) const;
+};
+
+class OptionalAmount {
+public:
+ enum HowSpecified { NotSpecified, Constant, Arg, Invalid };
+
+ OptionalAmount(HowSpecified howSpecified,
+ unsigned amount,
+ const char *amountStart,
+ unsigned amountLength,
+ bool usesPositionalArg)
+ : start(amountStart), length(amountLength), hs(howSpecified), amt(amount),
+ UsesPositionalArg(usesPositionalArg), UsesDotPrefix(0) {}
+
+ OptionalAmount(bool valid = true)
+ : start(nullptr),length(0), hs(valid ? NotSpecified : Invalid), amt(0),
+ UsesPositionalArg(0), UsesDotPrefix(0) {}
+
+ explicit OptionalAmount(unsigned Amount)
+ : start(nullptr), length(0), hs(Constant), amt(Amount),
+ UsesPositionalArg(false), UsesDotPrefix(false) {}
+
+ bool isInvalid() const {
+ return hs == Invalid;
+ }
+
+ HowSpecified getHowSpecified() const { return hs; }
+ void setHowSpecified(HowSpecified h) { hs = h; }
+
+ bool hasDataArgument() const { return hs == Arg; }
+
+ unsigned getArgIndex() const {
+ assert(hasDataArgument());
+ return amt;
+ }
+
+ unsigned getConstantAmount() const {
+ assert(hs == Constant);
+ return amt;
+ }
+
+ const char *getStart() const {
+ // We include the . character if it is given.
+ return start - UsesDotPrefix;
+ }
+
+ unsigned getConstantLength() const {
+ assert(hs == Constant);
+ return length + UsesDotPrefix;
+ }
+
+ ArgType getArgType(ASTContext &Ctx) const;
+
+ void toString(raw_ostream &os) const;
+
+ bool usesPositionalArg() const { return (bool) UsesPositionalArg; }
+ unsigned getPositionalArgIndex() const {
+ assert(hasDataArgument());
+ return amt + 1;
+ }
+
+ bool usesDotPrefix() const { return UsesDotPrefix; }
+ void setUsesDotPrefix() { UsesDotPrefix = true; }
+
+private:
+ const char *start;
+ unsigned length;
+ HowSpecified hs;
+ unsigned amt;
+ bool UsesPositionalArg : 1;
+ bool UsesDotPrefix;
+};
+
+
+class FormatSpecifier {
+protected:
+ LengthModifier LM;
+ OptionalAmount FieldWidth;
+ ConversionSpecifier CS;
+ OptionalAmount VectorNumElts;
+
+ /// Positional arguments, an IEEE extension:
+ /// IEEE Std 1003.1, 2004 Edition
+ /// http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
+ bool UsesPositionalArg;
+ unsigned argIndex;
+public:
+ FormatSpecifier(bool isPrintf)
+ : CS(isPrintf), VectorNumElts(false),
+ UsesPositionalArg(false), argIndex(0) {}
+
+ void setLengthModifier(LengthModifier lm) {
+ LM = lm;
+ }
+
+ void setUsesPositionalArg() { UsesPositionalArg = true; }
+
+ void setArgIndex(unsigned i) {
+ argIndex = i;
+ }
+
+ unsigned getArgIndex() const {
+ return argIndex;
+ }
+
+ unsigned getPositionalArgIndex() const {
+ return argIndex + 1;
+ }
+
+ const LengthModifier &getLengthModifier() const {
+ return LM;
+ }
+
+ const OptionalAmount &getFieldWidth() const {
+ return FieldWidth;
+ }
+
+ void setVectorNumElts(const OptionalAmount &Amt) {
+ VectorNumElts = Amt;
+ }
+
+ const OptionalAmount &getVectorNumElts() const {
+ return VectorNumElts;
+ }
+
+ void setFieldWidth(const OptionalAmount &Amt) {
+ FieldWidth = Amt;
+ }
+
+ bool usesPositionalArg() const { return UsesPositionalArg; }
+
+ bool hasValidLengthModifier(const TargetInfo &Target) const;
+
+ bool hasStandardLengthModifier() const;
+
+ Optional<LengthModifier> getCorrectedLengthModifier() const;
+
+ bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const;
+
+ bool hasStandardLengthConversionCombination() const;
+
+ /// For a TypedefType QT, if it is a named integer type such as size_t,
+ /// assign the appropriate value to LM and return true.
+ static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM);
+};
+
+} // end analyze_format_string namespace
+
+//===----------------------------------------------------------------------===//
+/// Pieces specific to fprintf format strings.
+
+namespace analyze_printf {
+
+class PrintfConversionSpecifier :
+ public analyze_format_string::ConversionSpecifier {
+public:
+ PrintfConversionSpecifier()
+ : ConversionSpecifier(true, nullptr, InvalidSpecifier) {}
+
+ PrintfConversionSpecifier(const char *pos, Kind k)
+ : ConversionSpecifier(true, pos, k) {}
+
+ bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; }
+ bool isDoubleArg() const { return kind >= DoubleArgBeg &&
+ kind <= DoubleArgEnd; }
+
+ static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
+ return CS->isPrintfKind();
+ }
+};
+
+using analyze_format_string::ArgType;
+using analyze_format_string::LengthModifier;
+using analyze_format_string::OptionalAmount;
+using analyze_format_string::OptionalFlag;
+
+class PrintfSpecifier : public analyze_format_string::FormatSpecifier {
+ OptionalFlag HasThousandsGrouping; // ''', POSIX extension.
+ OptionalFlag IsLeftJustified; // '-'
+ OptionalFlag HasPlusPrefix; // '+'
+ OptionalFlag HasSpacePrefix; // ' '
+ OptionalFlag HasAlternativeForm; // '#'
+ OptionalFlag HasLeadingZeroes; // '0'
+ OptionalFlag HasObjCTechnicalTerm; // '[tt]'
+ OptionalFlag IsPrivate; // '{private}'
+ OptionalFlag IsPublic; // '{public}'
+ OptionalFlag IsSensitive; // '{sensitive}'
+ OptionalAmount Precision;
+ StringRef MaskType;
+
+ ArgType getScalarArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
+
+public:
+ PrintfSpecifier()
+ : FormatSpecifier(/* isPrintf = */ true), HasThousandsGrouping("'"),
+ IsLeftJustified("-"), HasPlusPrefix("+"), HasSpacePrefix(" "),
+ HasAlternativeForm("#"), HasLeadingZeroes("0"),
+ HasObjCTechnicalTerm("tt"), IsPrivate("private"), IsPublic("public"),
+ IsSensitive("sensitive") {}
+
+ static PrintfSpecifier Parse(const char *beg, const char *end);
+
+ // Methods for incrementally constructing the PrintfSpecifier.
+ void setConversionSpecifier(const PrintfConversionSpecifier &cs) {
+ CS = cs;
+ }
+ void setHasThousandsGrouping(const char *position) {
+ HasThousandsGrouping.setPosition(position);
+ }
+ void setIsLeftJustified(const char *position) {
+ IsLeftJustified.setPosition(position);
+ }
+ void setHasPlusPrefix(const char *position) {
+ HasPlusPrefix.setPosition(position);
+ }
+ void setHasSpacePrefix(const char *position) {
+ HasSpacePrefix.setPosition(position);
+ }
+ void setHasAlternativeForm(const char *position) {
+ HasAlternativeForm.setPosition(position);
+ }
+ void setHasLeadingZeros(const char *position) {
+ HasLeadingZeroes.setPosition(position);
+ }
+ void setHasObjCTechnicalTerm(const char *position) {
+ HasObjCTechnicalTerm.setPosition(position);
+ }
+ void setIsPrivate(const char *position) { IsPrivate.setPosition(position); }
+ void setIsPublic(const char *position) { IsPublic.setPosition(position); }
+ void setIsSensitive(const char *position) {
+ IsSensitive.setPosition(position);
+ }
+ void setUsesPositionalArg() { UsesPositionalArg = true; }
+
+ // Methods for querying the format specifier.
+
+ const PrintfConversionSpecifier &getConversionSpecifier() const {
+ return cast<PrintfConversionSpecifier>(CS);
+ }
+
+ void setPrecision(const OptionalAmount &Amt) {
+ Precision = Amt;
+ Precision.setUsesDotPrefix();
+ }
+
+ const OptionalAmount &getPrecision() const {
+ return Precision;
+ }
+
+ bool consumesDataArgument() const {
+ return getConversionSpecifier().consumesDataArgument();
+ }
+
+ /// Returns the builtin type that a data argument
+ /// paired with this format specifier should have. This method
+ /// will return null if the format specifier does not have
+ /// a matching data argument or the matching argument matches
+ /// more than one type.
+ ArgType getArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
+
+ const OptionalFlag &hasThousandsGrouping() const {
+ return HasThousandsGrouping;
+ }
+ const OptionalFlag &isLeftJustified() const { return IsLeftJustified; }
+ const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; }
+ const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; }
+ const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; }
+ const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; }
+ const OptionalFlag &hasObjCTechnicalTerm() const { return HasObjCTechnicalTerm; }
+ const OptionalFlag &isPrivate() const { return IsPrivate; }
+ const OptionalFlag &isPublic() const { return IsPublic; }
+ const OptionalFlag &isSensitive() const { return IsSensitive; }
+ bool usesPositionalArg() const { return UsesPositionalArg; }
+
+ StringRef getMaskType() const { return MaskType; }
+ void setMaskType(StringRef S) { MaskType = S; }
+
+ /// Changes the specifier and length according to a QualType, retaining any
+ /// flags or options. Returns true on success, or false when a conversion
+ /// was not successful.
+ bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx,
+ bool IsObjCLiteral);
+
+ void toString(raw_ostream &os) const;
+
+ // Validation methods - to check if any element results in undefined behavior
+ bool hasValidPlusPrefix() const;
+ bool hasValidAlternativeForm() const;
+ bool hasValidLeadingZeros() const;
+ bool hasValidSpacePrefix() const;
+ bool hasValidLeftJustified() const;
+ bool hasValidThousandsGroupingPrefix() const;
+
+ bool hasValidPrecision() const;
+ bool hasValidFieldWidth() const;
+};
+} // end analyze_printf namespace
+
+//===----------------------------------------------------------------------===//
+/// Pieces specific to fscanf format strings.
+
+namespace analyze_scanf {
+
+class ScanfConversionSpecifier :
+ public analyze_format_string::ConversionSpecifier {
+public:
+ ScanfConversionSpecifier()
+ : ConversionSpecifier(false, nullptr, InvalidSpecifier) {}
+
+ ScanfConversionSpecifier(const char *pos, Kind k)
+ : ConversionSpecifier(false, pos, k) {}
+
+ static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
+ return !CS->isPrintfKind();
+ }
+};
+
+using analyze_format_string::ArgType;
+using analyze_format_string::LengthModifier;
+using analyze_format_string::OptionalAmount;
+using analyze_format_string::OptionalFlag;
+
+class ScanfSpecifier : public analyze_format_string::FormatSpecifier {
+ OptionalFlag SuppressAssignment; // '*'
+public:
+ ScanfSpecifier() :
+ FormatSpecifier(/* isPrintf = */ false),
+ SuppressAssignment("*") {}
+
+ void setSuppressAssignment(const char *position) {
+ SuppressAssignment.setPosition(position);
+ }
+
+ const OptionalFlag &getSuppressAssignment() const {
+ return SuppressAssignment;
+ }
+
+ void setConversionSpecifier(const ScanfConversionSpecifier &cs) {
+ CS = cs;
+ }
+
+ const ScanfConversionSpecifier &getConversionSpecifier() const {
+ return cast<ScanfConversionSpecifier>(CS);
+ }
+
+ bool consumesDataArgument() const {
+ return CS.consumesDataArgument() && !SuppressAssignment;
+ }
+
+ ArgType getArgType(ASTContext &Ctx) const;
+
+ bool fixType(QualType QT, QualType RawQT, const LangOptions &LangOpt,
+ ASTContext &Ctx);
+
+ void toString(raw_ostream &os) const;
+
+ static ScanfSpecifier Parse(const char *beg, const char *end);
+};
+
+} // end analyze_scanf namespace
+
+//===----------------------------------------------------------------------===//
+// Parsing and processing of format strings (both fprintf and fscanf).
+
+namespace analyze_format_string {
+
+enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 };
+
+class FormatStringHandler {
+public:
+ FormatStringHandler() {}
+ virtual ~FormatStringHandler();
+
+ virtual void HandleNullChar(const char *nullCharacter) {}
+
+ virtual void HandlePosition(const char *startPos, unsigned posLen) {}
+
+ virtual void HandleInvalidPosition(const char *startPos, unsigned posLen,
+ PositionContext p) {}
+
+ virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {}
+
+ virtual void HandleIncompleteSpecifier(const char *startSpecifier,
+ unsigned specifierLen) {}
+
+ virtual void HandleEmptyObjCModifierFlag(const char *startFlags,
+ unsigned flagsLen) {}
+
+ virtual void HandleInvalidObjCModifierFlag(const char *startFlag,
+ unsigned flagLen) {}
+
+ virtual void HandleObjCFlagsWithNonObjCConversion(const char *flagsStart,
+ const char *flagsEnd,
+ const char *conversionPosition) {}
+ // Printf-specific handlers.
+
+ virtual bool HandleInvalidPrintfConversionSpecifier(
+ const analyze_printf::PrintfSpecifier &FS,
+ const char *startSpecifier,
+ unsigned specifierLen) {
+ return true;
+ }
+
+ virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
+ const char *startSpecifier,
+ unsigned specifierLen) {
+ return true;
+ }
+
+ /// Handle mask types whose sizes are not between one and eight bytes.
+ virtual void handleInvalidMaskType(StringRef MaskType) {}
+
+ // Scanf-specific handlers.
+
+ virtual bool HandleInvalidScanfConversionSpecifier(
+ const analyze_scanf::ScanfSpecifier &FS,
+ const char *startSpecifier,
+ unsigned specifierLen) {
+ return true;
+ }
+
+ virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
+ const char *startSpecifier,
+ unsigned specifierLen) {
+ return true;
+ }
+
+ virtual void HandleIncompleteScanList(const char *start, const char *end) {}
+};
+
+bool ParsePrintfString(FormatStringHandler &H,
+ const char *beg, const char *end, const LangOptions &LO,
+ const TargetInfo &Target, bool isFreeBSDKPrintf);
+
+bool ParseFormatStringHasSArg(const char *beg, const char *end,
+ const LangOptions &LO, const TargetInfo &Target);
+
+bool ParseScanfString(FormatStringHandler &H,
+ const char *beg, const char *end, const LangOptions &LO,
+ const TargetInfo &Target);
+
+} // end analyze_format_string namespace
+} // end clang namespace
+#endif
diff --git a/include/clang/AST/GlobalDecl.h b/include/clang/AST/GlobalDecl.h
index 7f01799421..a3c0cab379 100644
--- a/include/clang/AST/GlobalDecl.h
+++ b/include/clang/AST/GlobalDecl.h
@@ -34,6 +34,7 @@ namespace clang {
/// a VarDecl, a FunctionDecl or a BlockDecl.
class GlobalDecl {
llvm::PointerIntPair<const Decl *, 2> Value;
+ unsigned MultiVersionIndex = 0;
void Init(const Decl *D) {
assert(!isa<CXXConstructorDecl>(D) && "Use other ctor with ctor decls!");
@@ -45,7 +46,10 @@ class GlobalDecl {
public:
GlobalDecl() = default;
GlobalDecl(const VarDecl *D) { Init(D);}
- GlobalDecl(const FunctionDecl *D) { Init(D); }
+ GlobalDecl(const FunctionDecl *D, unsigned MVIndex = 0)
+ : MultiVersionIndex(MVIndex) {
+ Init(D);
+ }
GlobalDecl(const BlockDecl *D) { Init(D); }
GlobalDecl(const CapturedDecl *D) { Init(D); }
GlobalDecl(const ObjCMethodDecl *D) { Init(D); }
@@ -57,6 +61,7 @@ public:
GlobalDecl CanonGD;
CanonGD.Value.setPointer(Value.getPointer()->getCanonicalDecl());
CanonGD.Value.setInt(Value.getInt());
+ CanonGD.MultiVersionIndex = MultiVersionIndex;
return CanonGD;
}
@@ -73,8 +78,17 @@ public:
return static_cast<CXXDtorType>(Value.getInt());
}
+ unsigned getMultiVersionIndex() const {
+ assert(isa<FunctionDecl>(getDecl()) &&
+ !isa<CXXConstructorDecl>(getDecl()) &&
+ !isa<CXXDestructorDecl>(getDecl()) &&
+ "Decl is not a plain FunctionDecl!");
+ return MultiVersionIndex;
+ }
+
friend bool operator==(const GlobalDecl &LHS, const GlobalDecl &RHS) {
- return LHS.Value == RHS.Value;
+ return LHS.Value == RHS.Value &&
+ LHS.MultiVersionIndex == RHS.MultiVersionIndex;
}
void *getAsOpaquePtr() const { return Value.getOpaqueValue(); }
@@ -90,6 +104,16 @@ public:
Result.Value.setPointer(D);
return Result;
}
+
+ GlobalDecl getWithMultiVersionIndex(unsigned Index) {
+ assert(isa<FunctionDecl>(getDecl()) &&
+ !isa<CXXConstructorDecl>(getDecl()) &&
+ !isa<CXXDestructorDecl>(getDecl()) &&
+ "Decl is not a plain FunctionDecl!");
+ GlobalDecl Result(*this);
+ Result.MultiVersionIndex = Index;
+ return Result;
+ }
};
} // namespace clang
diff --git a/include/clang/AST/NestedNameSpecifier.h b/include/clang/AST/NestedNameSpecifier.h
index 3a7b45767d..8befe9ae42 100644
--- a/include/clang/AST/NestedNameSpecifier.h
+++ b/include/clang/AST/NestedNameSpecifier.h
@@ -212,9 +212,12 @@ public:
/// parameter pack (for C++11 variadic templates).
bool containsUnexpandedParameterPack() const;
- /// Print this nested name specifier to the given output
- /// stream.
- void print(raw_ostream &OS, const PrintingPolicy &Policy) const;
+ /// Print this nested name specifier to the given output stream. If
+ /// `ResolveTemplateArguments` is true, we'll print actual types, e.g.
+ /// `ns::SomeTemplate<int, MyClass>` instead of
+ /// `ns::SomeTemplate<Container::value_type, T>`.
+ void print(raw_ostream &OS, const PrintingPolicy &Policy,
+ bool ResolveTemplateArguments = false) const;
void Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddPointer(Prefix.getOpaqueValue());
@@ -225,6 +228,8 @@ public:
/// in debugging.
void dump(const LangOptions &LO) const;
void dump() const;
+ void dump(llvm::raw_ostream &OS) const;
+ void dump(llvm::raw_ostream &OS, const LangOptions &LO) const;
};
/// A C++ nested-name-specifier augmented with source location
diff --git a/include/clang/AST/OSLog.h b/include/clang/AST/OSLog.h
new file mode 100644
index 0000000000..2b21855e7a
--- /dev/null
+++ b/include/clang/AST/OSLog.h
@@ -0,0 +1,161 @@
+//= OSLog.h - Analysis of calls to os_log builtins --*- C++ -*-===============//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines APIs for determining the layout of the data buffer for
+// os_log() and os_trace().
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_OSLOG_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_OSLOG_H
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+
+namespace clang {
+namespace analyze_os_log {
+
+/// An OSLogBufferItem represents a single item in the data written by a call
+/// to os_log() or os_trace().
+class OSLogBufferItem {
+public:
+ enum Kind {
+ // The item is a scalar (int, float, raw pointer, etc.). No further copying
+ // is required. This is the only kind allowed by os_trace().
+ ScalarKind = 0,
+
+ // The item is a count, which describes the length of the following item to
+ // be copied. A count may only be followed by an item of kind StringKind,
+ // WideStringKind, or PointerKind.
+ CountKind,
+
+ // The item is a pointer to a C string. If preceded by a count 'n',
+ // os_log() will copy at most 'n' bytes from the pointer.
+ StringKind,
+
+ // The item is a pointer to a block of raw data. This item must be preceded
+ // by a count 'n'. os_log() will copy exactly 'n' bytes from the pointer.
+ PointerKind,
+
+ // The item is a pointer to an Objective-C object. os_log() may retain the
+ // object for later processing.
+ ObjCObjKind,
+
+ // The item is a pointer to wide-char string.
+ WideStringKind,
+
+ // The item is corresponding to the '%m' format specifier, no value is
+ // populated in the buffer and the runtime is loading the errno value.
+ ErrnoKind,
+
+ // The item is a mask type.
+ MaskKind
+ };
+
+ enum {
+ // The item is marked "private" in the format string.
+ IsPrivate = 0x1,
+
+ // The item is marked "public" in the format string.
+ IsPublic = 0x2,
+
+ // The item is marked "sensitive" in the format string.
+ IsSensitive = 0x4 | IsPrivate
+ };
+
+private:
+ Kind TheKind = ScalarKind;
+ const Expr *TheExpr = nullptr;
+ CharUnits ConstValue;
+ CharUnits Size; // size of the data, not including the header bytes
+ unsigned Flags = 0;
+ StringRef MaskType;
+
+public:
+ OSLogBufferItem(Kind kind, const Expr *expr, CharUnits size, unsigned flags,
+ StringRef maskType = StringRef())
+ : TheKind(kind), TheExpr(expr), Size(size), Flags(flags),
+ MaskType(maskType) {
+ assert(((Flags == 0) || (Flags == IsPrivate) || (Flags == IsPublic) ||
+ (Flags == IsSensitive)) &&
+ "unexpected privacy flag");
+ }
+
+ OSLogBufferItem(ASTContext &Ctx, CharUnits value, unsigned flags)
+ : TheKind(CountKind), ConstValue(value),
+ Size(Ctx.getTypeSizeInChars(Ctx.IntTy)), Flags(flags) {}
+
+ unsigned char getDescriptorByte() const {
+ unsigned char result = Flags;
+ result |= ((unsigned)getKind()) << 4;
+ return result;
+ }
+
+ unsigned char getSizeByte() const { return size().getQuantity(); }
+
+ Kind getKind() const { return TheKind; }
+ bool getIsPrivate() const { return (Flags & IsPrivate) != 0; }
+
+ const Expr *getExpr() const { return TheExpr; }
+ CharUnits getConstValue() const { return ConstValue; }
+ CharUnits size() const { return Size; }
+
+ StringRef getMaskType() const { return MaskType; }
+};
+
+class OSLogBufferLayout {
+public:
+ SmallVector<OSLogBufferItem, 4> Items;
+
+ enum Flags { HasPrivateItems = 1, HasNonScalarItems = 1 << 1 };
+
+ CharUnits size() const {
+ CharUnits result;
+ result += CharUnits::fromQuantity(2); // summary byte, num-args byte
+ for (auto &item : Items) {
+ // descriptor byte, size byte
+ result += item.size() + CharUnits::fromQuantity(2);
+ }
+ return result;
+ }
+
+ bool hasPrivateItems() const {
+ return llvm::any_of(
+ Items, [](const OSLogBufferItem &Item) { return Item.getIsPrivate(); });
+ }
+
+ bool hasNonScalarOrMask() const {
+ return llvm::any_of(Items, [](const OSLogBufferItem &Item) {
+ return Item.getKind() != OSLogBufferItem::ScalarKind ||
+ !Item.getMaskType().empty();
+ });
+ }
+
+ unsigned char getSummaryByte() const {
+ unsigned char result = 0;
+ if (hasPrivateItems())
+ result |= HasPrivateItems;
+ if (hasNonScalarOrMask())
+ result |= HasNonScalarItems;
+ return result;
+ }
+
+ unsigned char getNumArgsByte() const { return Items.size(); }
+};
+
+// Given a call 'E' to one of the builtins __builtin_os_log_format() or
+// __builtin_os_log_format_buffer_size(), compute the layout of the buffer that
+// the call will write into and store it in 'layout'. Returns 'false' if there
+// was some error encountered while computing the layout, and 'true' otherwise.
+bool computeOSLogBufferLayout(clang::ASTContext &Ctx, const clang::CallExpr *E,
+ OSLogBufferLayout &layout);
+
+} // namespace analyze_os_log
+} // namespace clang
+#endif
diff --git a/include/clang/AST/OpenMPClause.h b/include/clang/AST/OpenMPClause.h
index 6a2c806bb6..e93f7e2b3e 100644
--- a/include/clang/AST/OpenMPClause.h
+++ b/include/clang/AST/OpenMPClause.h
@@ -765,6 +765,179 @@ public:
}
};
+/// This represents 'unified_shared_memory' clause in the '#pragma omp requires'
+/// directive.
+///
+/// \code
+/// #pragma omp requires unified_shared_memory
+/// \endcode
+/// In this example directive '#pragma omp requires' has 'unified_shared_memory'
+/// clause.
+class OMPUnifiedSharedMemoryClause final : public OMPClause {
+public:
+ friend class OMPClauseReader;
+ /// Build 'unified_shared_memory' clause.
+ ///
+ /// \param StartLoc Starting location of the clause.
+ /// \param EndLoc Ending location of the clause.
+ OMPUnifiedSharedMemoryClause(SourceLocation StartLoc, SourceLocation EndLoc)
+ : OMPClause(OMPC_unified_shared_memory, StartLoc, EndLoc) {}
+
+ /// Build an empty clause.
+ OMPUnifiedSharedMemoryClause()
+ : OMPClause(OMPC_unified_shared_memory, SourceLocation(), SourceLocation()) {}
+
+ child_range children() {
+ return child_range(child_iterator(), child_iterator());
+ }
+
+ static bool classof(const OMPClause *T) {
+ return T->getClauseKind() == OMPC_unified_shared_memory;
+ }
+};
+
+/// This represents 'reverse_offload' clause in the '#pragma omp requires'
+/// directive.
+///
+/// \code
+/// #pragma omp requires reverse_offload
+/// \endcode
+/// In this example directive '#pragma omp requires' has 'reverse_offload'
+/// clause.
+class OMPReverseOffloadClause final : public OMPClause {
+public:
+ friend class OMPClauseReader;
+ /// Build 'reverse_offload' clause.
+ ///
+ /// \param StartLoc Starting location of the clause.
+ /// \param EndLoc Ending location of the clause.
+ OMPReverseOffloadClause(SourceLocation StartLoc, SourceLocation EndLoc)
+ : OMPClause(OMPC_reverse_offload, StartLoc, EndLoc) {}
+
+ /// Build an empty clause.
+ OMPReverseOffloadClause()
+ : OMPClause(OMPC_reverse_offload, SourceLocation(), SourceLocation()) {}
+
+ child_range children() {
+ return child_range(child_iterator(), child_iterator());
+ }
+
+ static bool classof(const OMPClause *T) {
+ return T->getClauseKind() == OMPC_reverse_offload;
+ }
+};
+
+/// This represents 'dynamic_allocators' clause in the '#pragma omp requires'
+/// directive.
+///
+/// \code
+/// #pragma omp requires dynamic_allocators
+/// \endcode
+/// In this example directive '#pragma omp requires' has 'dynamic_allocators'
+/// clause.
+class OMPDynamicAllocatorsClause final : public OMPClause {
+public:
+ friend class OMPClauseReader;
+ /// Build 'dynamic_allocators' clause.
+ ///
+ /// \param StartLoc Starting location of the clause.
+ /// \param EndLoc Ending location of the clause.
+ OMPDynamicAllocatorsClause(SourceLocation StartLoc, SourceLocation EndLoc)
+ : OMPClause(OMPC_dynamic_allocators, StartLoc, EndLoc) {}
+
+ /// Build an empty clause.
+ OMPDynamicAllocatorsClause()
+ : OMPClause(OMPC_dynamic_allocators, SourceLocation(), SourceLocation()) {
+ }
+
+ child_range children() {
+ return child_range(child_iterator(), child_iterator());
+ }
+
+ static bool classof(const OMPClause *T) {
+ return T->getClauseKind() == OMPC_dynamic_allocators;
+ }
+};
+
+/// This represents 'atomic_default_mem_order' clause in the '#pragma omp
+/// requires' directive.
+///
+/// \code
+/// #pragma omp requires atomic_default_mem_order(seq_cst)
+/// \endcode
+/// In this example directive '#pragma omp requires' has simple
+/// atomic_default_mem_order' clause with kind 'seq_cst'.
+class OMPAtomicDefaultMemOrderClause final : public OMPClause {
+ friend class OMPClauseReader;
+
+ /// Location of '('
+ SourceLocation LParenLoc;
+
+ /// A kind of the 'atomic_default_mem_order' clause.
+ OpenMPAtomicDefaultMemOrderClauseKind Kind =
+ OMPC_ATOMIC_DEFAULT_MEM_ORDER_unknown;
+
+ /// Start location of the kind in source code.
+ SourceLocation KindKwLoc;
+
+ /// Set kind of the clause.
+ ///
+ /// \param K Kind of clause.
+ void setAtomicDefaultMemOrderKind(OpenMPAtomicDefaultMemOrderClauseKind K) {
+ Kind = K;
+ }
+
+ /// Set clause kind location.
+ ///
+ /// \param KLoc Kind location.
+ void setAtomicDefaultMemOrderKindKwLoc(SourceLocation KLoc) {
+ KindKwLoc = KLoc;
+ }
+
+public:
+ /// Build 'atomic_default_mem_order' clause with argument \a A ('seq_cst',
+ /// 'acq_rel' or 'relaxed').
+ ///
+ /// \param A Argument of the clause ('seq_cst', 'acq_rel' or 'relaxed').
+ /// \param ALoc Starting location of the argument.
+ /// \param StartLoc Starting location of the clause.
+ /// \param LParenLoc Location of '('.
+ /// \param EndLoc Ending location of the clause.
+ OMPAtomicDefaultMemOrderClause(OpenMPAtomicDefaultMemOrderClauseKind A,
+ SourceLocation ALoc, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc)
+ : OMPClause(OMPC_atomic_default_mem_order, StartLoc, EndLoc),
+ LParenLoc(LParenLoc), Kind(A), KindKwLoc(ALoc) {}
+
+ /// Build an empty clause.
+ OMPAtomicDefaultMemOrderClause()
+ : OMPClause(OMPC_atomic_default_mem_order, SourceLocation(),
+ SourceLocation()) {}
+
+ /// Sets the location of '('.
+ void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
+
+ /// Returns the locaiton of '('.
+ SourceLocation getLParenLoc() const { return LParenLoc; }
+
+ /// Returns kind of the clause.
+ OpenMPAtomicDefaultMemOrderClauseKind getAtomicDefaultMemOrderKind() const {
+ return Kind;
+ }
+
+ /// Returns location of clause kind.
+ SourceLocation getAtomicDefaultMemOrderKindKwLoc() const { return KindKwLoc; }
+
+ child_range children() {
+ return child_range(child_iterator(), child_iterator());
+ }
+
+ static bool classof(const OMPClause *T) {
+ return T->getClauseKind() == OMPC_atomic_default_mem_order;
+ }
+};
+
/// This represents 'schedule' clause in the '#pragma omp ...' directive.
///
/// \code
@@ -5109,6 +5282,22 @@ class OMPClauseVisitor :
template<class ImplClass, typename RetTy = void>
class ConstOMPClauseVisitor :
public OMPClauseVisitorBase <ImplClass, const_ptr, RetTy> {};
+
+class OMPClausePrinter final : public OMPClauseVisitor<OMPClausePrinter> {
+ raw_ostream &OS;
+ const PrintingPolicy &Policy;
+
+ /// Process clauses with list of variables.
+ template <typename T> void VisitOMPClauseList(T *Node, char StartSym);
+
+public:
+ OMPClausePrinter(raw_ostream &OS, const PrintingPolicy &Policy)
+ : OS(OS), Policy(Policy) {}
+
+#define OPENMP_CLAUSE(Name, Class) void Visit##Class(Class *S);
+#include "clang/Basic/OpenMPKinds.def"
+};
+
} // namespace clang
#endif // LLVM_CLANG_AST_OPENMPCLAUSE_H
diff --git a/include/clang/AST/OperationKinds.def b/include/clang/AST/OperationKinds.def
index e2d65d8488..cd19091e31 100644
--- a/include/clang/AST/OperationKinds.def
+++ b/include/clang/AST/OperationKinds.def
@@ -197,6 +197,14 @@ CAST_OPERATION(IntegralToBoolean)
/// float f = i;
CAST_OPERATION(IntegralToFloating)
+/// CK_FixedPointCast - Fixed point to fixed point.
+/// (_Accum) 0.5r
+CAST_OPERATION(FixedPointCast)
+
+/// CK_FixedPointToBoolean - Fixed point to boolean.
+/// (bool) 0.5r
+CAST_OPERATION(FixedPointToBoolean)
+
/// CK_FloatingToIntegral - Floating point to integral. Rounds
/// towards zero, discarding any fractional component.
/// (int) f
@@ -318,11 +326,9 @@ CAST_OPERATION(CopyAndAutoreleaseBlockObject)
// callee of a call expression.
CAST_OPERATION(BuiltinFnToFnPtr)
-// Convert a zero value for OpenCL event_t initialization.
-CAST_OPERATION(ZeroToOCLEvent)
-
-// Convert a zero value for OpenCL queue_t initialization.
-CAST_OPERATION(ZeroToOCLQueue)
+// Convert a zero value for OpenCL opaque types initialization (event_t,
+// queue_t, etc.)
+CAST_OPERATION(ZeroToOCLOpaqueType)
// Convert a pointer to a different address space.
CAST_OPERATION(AddressSpaceConversion)
diff --git a/include/clang/AST/PrettyPrinter.h b/include/clang/AST/PrettyPrinter.h
index ed6b97f9b9..0a4dc42898 100644
--- a/include/clang/AST/PrettyPrinter.h
+++ b/include/clang/AST/PrettyPrinter.h
@@ -38,21 +38,20 @@ public:
struct PrintingPolicy {
/// Create a default printing policy for the specified language.
PrintingPolicy(const LangOptions &LO)
- : Indentation(2), SuppressSpecifiers(false),
- SuppressTagKeyword(LO.CPlusPlus),
- IncludeTagDefinition(false), SuppressScope(false),
- SuppressUnwrittenScope(false), SuppressInitializers(false),
- ConstantArraySizeAsWritten(false), AnonymousTagLocations(true),
- SuppressStrongLifetime(false), SuppressLifetimeQualifiers(false),
- SuppressTemplateArgsInCXXConstructors(false),
- Bool(LO.Bool), Restrict(LO.C99),
- Alignof(LO.CPlusPlus11), UnderscoreAlignof(LO.C11),
- UseVoidForZeroParams(!LO.CPlusPlus),
- TerseOutput(false), PolishForDeclaration(false),
- Half(LO.Half), MSWChar(LO.MicrosoftExt && !LO.WChar),
- IncludeNewlines(true), MSVCFormatting(false),
- ConstantsAsWritten(false), SuppressImplicitBase(false),
- FullyQualifiedName(false) { }
+ : Indentation(2), SuppressSpecifiers(false),
+ SuppressTagKeyword(LO.CPlusPlus), IncludeTagDefinition(false),
+ SuppressScope(false), SuppressUnwrittenScope(false),
+ SuppressInitializers(false), ConstantArraySizeAsWritten(false),
+ AnonymousTagLocations(true), SuppressStrongLifetime(false),
+ SuppressLifetimeQualifiers(false),
+ SuppressTemplateArgsInCXXConstructors(false), Bool(LO.Bool),
+ Restrict(LO.C99), Alignof(LO.CPlusPlus11), UnderscoreAlignof(LO.C11),
+ UseVoidForZeroParams(!LO.CPlusPlus), TerseOutput(false),
+ PolishForDeclaration(false), Half(LO.Half),
+ MSWChar(LO.MicrosoftExt && !LO.WChar), IncludeNewlines(true),
+ MSVCFormatting(false), ConstantsAsWritten(false),
+ SuppressImplicitBase(false), FullyQualifiedName(false),
+ RemapFilePaths(false) {}
/// Adjust this printing policy for cases where it's known that we're
/// printing C++ code (for instance, if AST dumping reaches a C++-only
@@ -225,6 +224,12 @@ struct PrintingPolicy {
/// When true, print the fully qualified name of function declarations.
/// This is the opposite of SuppressScope and thus overrules it.
unsigned FullyQualifiedName : 1;
+
+ /// Whether to apply -fdebug-prefix-map to any file paths.
+ unsigned RemapFilePaths : 1;
+
+ /// When RemapFilePaths is true, this function performs the action.
+ std::function<std::string(StringRef)> remapPath;
};
} // end namespace clang
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 436425a9ee..eb582c7a7a 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -176,6 +176,16 @@ public:
/// Return whether this visitor should traverse post-order.
bool shouldTraversePostOrder() const { return false; }
+ /// Recursively visits an entire AST, starting from the top-level Decls
+ /// in the AST traversal scope (by default, the TranslationUnitDecl).
+ /// \returns false if visitation was terminated early.
+ bool TraverseAST(ASTContext &AST) {
+ for (Decl *D : AST.getTraversalScope())
+ if (!getDerived().TraverseDecl(D))
+ return false;
+ return true;
+ }
+
/// Recursively visit a statement or expression, by
/// dispatching to Traverse*() based on the argument's dynamic type.
///
@@ -2199,6 +2209,8 @@ DEF_TRAVERSE_STMT(ReturnStmt, {})
DEF_TRAVERSE_STMT(SwitchStmt, {})
DEF_TRAVERSE_STMT(WhileStmt, {})
+DEF_TRAVERSE_STMT(ConstantExpr, {})
+
DEF_TRAVERSE_STMT(CXXDependentScopeMemberExpr, {
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
TRY_TO(TraverseDeclarationNameInfo(S->getMemberNameInfo()));
@@ -2868,6 +2880,30 @@ bool RecursiveASTVisitor<Derived>::VisitOMPUnifiedAddressClause(
}
template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPUnifiedSharedMemoryClause(
+ OMPUnifiedSharedMemoryClause *) {
+ return true;
+}
+
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPReverseOffloadClause(
+ OMPReverseOffloadClause *) {
+ return true;
+}
+
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPDynamicAllocatorsClause(
+ OMPDynamicAllocatorsClause *) {
+ return true;
+}
+
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPAtomicDefaultMemOrderClause(
+ OMPAtomicDefaultMemOrderClause *) {
+ return true;
+}
+
+template <typename Derived>
bool
RecursiveASTVisitor<Derived>::VisitOMPScheduleClause(OMPScheduleClause *C) {
TRY_TO(VisitOMPClauseWithPreInit(C));
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index b4e0fd561e..23ac5af7ae 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -89,6 +89,8 @@ protected:
llvm_unreachable("Stmts cannot be released with regular 'delete'.");
}
+ //===--- Statement bitfields classes ---===//
+
class StmtBitfields {
friend class Stmt;
@@ -97,22 +99,186 @@ protected:
};
enum { NumStmtBits = 8 };
+ class NullStmtBitfields {
+ friend class ASTStmtReader;
+ friend class ASTStmtWriter;
+ friend class NullStmt;
+
+ unsigned : NumStmtBits;
+
+ /// True if the null statement was preceded by an empty macro, e.g:
+ /// @code
+ /// #define CALL(x)
+ /// CALL(0);
+ /// @endcode
+ unsigned HasLeadingEmptyMacro : 1;
+
+ /// The location of the semi-colon.
+ SourceLocation SemiLoc;
+ };
+
class CompoundStmtBitfields {
+ friend class ASTStmtReader;
friend class CompoundStmt;
unsigned : NumStmtBits;
unsigned NumStmts : 32 - NumStmtBits;
+
+ /// The location of the opening "{".
+ SourceLocation LBraceLoc;
+ };
+
+ class LabelStmtBitfields {
+ friend class LabelStmt;
+
+ unsigned : NumStmtBits;
+
+ SourceLocation IdentLoc;
+ };
+
+ class AttributedStmtBitfields {
+ friend class ASTStmtReader;
+ friend class AttributedStmt;
+
+ unsigned : NumStmtBits;
+
+ /// Number of attributes.
+ unsigned NumAttrs : 32 - NumStmtBits;
+
+ /// The location of the attribute.
+ SourceLocation AttrLoc;
};
class IfStmtBitfields {
+ friend class ASTStmtReader;
friend class IfStmt;
unsigned : NumStmtBits;
+ /// True if this if statement is a constexpr if.
unsigned IsConstexpr : 1;
+
+ /// True if this if statement has storage for an else statement.
+ unsigned HasElse : 1;
+
+ /// True if this if statement has storage for a variable declaration.
+ unsigned HasVar : 1;
+
+ /// True if this if statement has storage for an init statement.
+ unsigned HasInit : 1;
+
+ /// The location of the "if".
+ SourceLocation IfLoc;
+ };
+
+ class SwitchStmtBitfields {
+ friend class SwitchStmt;
+
+ unsigned : NumStmtBits;
+
+ /// True if the SwitchStmt has storage for an init statement.
+ unsigned HasInit : 1;
+
+ /// True if the SwitchStmt has storage for a condition variable.
+ unsigned HasVar : 1;
+
+ /// If the SwitchStmt is a switch on an enum value, records whether all
+ /// the enum values were covered by CaseStmts. The coverage information
+ /// value is meant to be a hint for possible clients.
+ unsigned AllEnumCasesCovered : 1;
+
+ /// The location of the "switch".
+ SourceLocation SwitchLoc;
+ };
+
+ class WhileStmtBitfields {
+ friend class ASTStmtReader;
+ friend class WhileStmt;
+
+ unsigned : NumStmtBits;
+
+ /// True if the WhileStmt has storage for a condition variable.
+ unsigned HasVar : 1;
+
+ /// The location of the "while".
+ SourceLocation WhileLoc;
+ };
+
+ class DoStmtBitfields {
+ friend class DoStmt;
+
+ unsigned : NumStmtBits;
+
+ /// The location of the "do".
+ SourceLocation DoLoc;
+ };
+
+ class ForStmtBitfields {
+ friend class ForStmt;
+
+ unsigned : NumStmtBits;
+
+ /// The location of the "for".
+ SourceLocation ForLoc;
+ };
+
+ class GotoStmtBitfields {
+ friend class GotoStmt;
+ friend class IndirectGotoStmt;
+
+ unsigned : NumStmtBits;
+
+ /// The location of the "goto".
+ SourceLocation GotoLoc;
+ };
+
+ class ContinueStmtBitfields {
+ friend class ContinueStmt;
+
+ unsigned : NumStmtBits;
+
+ /// The location of the "continue".
+ SourceLocation ContinueLoc;
+ };
+
+ class BreakStmtBitfields {
+ friend class BreakStmt;
+
+ unsigned : NumStmtBits;
+
+ /// The location of the "break".
+ SourceLocation BreakLoc;
+ };
+
+ class ReturnStmtBitfields {
+ friend class ReturnStmt;
+
+ unsigned : NumStmtBits;
+
+ /// True if this ReturnStmt has storage for an NRVO candidate.
+ unsigned HasNRVOCandidate : 1;
+
+ /// The location of the "return".
+ SourceLocation RetLoc;
+ };
+
+ class SwitchCaseBitfields {
+ friend class SwitchCase;
+ friend class CaseStmt;
+
+ unsigned : NumStmtBits;
+
+ /// Used by CaseStmt to store whether it is a case statement
+ /// of the form case LHS ... RHS (a GNU extension).
+ unsigned CaseStmtIsGNURange : 1;
+
+ /// The location of the "case" or "default" keyword.
+ SourceLocation KeywordLoc;
};
+ //===--- Expression bitfields classes ---===//
+
class ExprBitfields {
friend class ASTStmtReader; // deserialization
friend class AtomicExpr; // ctor
@@ -146,14 +312,40 @@ protected:
unsigned InstantiationDependent : 1;
unsigned ContainsUnexpandedParameterPack : 1;
};
- enum { NumExprBits = 17 };
+ enum { NumExprBits = NumStmtBits + 9 };
- class CharacterLiteralBitfields {
- friend class CharacterLiteral;
+ class PredefinedExprBitfields {
+ friend class ASTStmtReader;
+ friend class PredefinedExpr;
unsigned : NumExprBits;
- unsigned Kind : 3;
+ /// The kind of this PredefinedExpr. One of the enumeration values
+ /// in PredefinedExpr::IdentKind.
+ unsigned Kind : 4;
+
+ /// True if this PredefinedExpr has a trailing "StringLiteral *"
+ /// for the predefined identifier.
+ unsigned HasFunctionName : 1;
+
+ /// The location of this PredefinedExpr.
+ SourceLocation Loc;
+ };
+
+ class DeclRefExprBitfields {
+ friend class ASTStmtReader; // deserialization
+ friend class DeclRefExpr;
+
+ unsigned : NumExprBits;
+
+ unsigned HasQualifier : 1;
+ unsigned HasTemplateKWAndArgsInfo : 1;
+ unsigned HasFoundDecl : 1;
+ unsigned HadMultipleCandidates : 1;
+ unsigned RefersToEnclosingVariableOrCapture : 1;
+
+ /// The location of the declaration name itself.
+ SourceLocation Loc;
};
enum APFloatSemantics {
@@ -174,26 +366,102 @@ protected:
unsigned IsExact : 1;
};
+ class StringLiteralBitfields {
+ friend class ASTStmtReader;
+ friend class StringLiteral;
+
+ unsigned : NumExprBits;
+
+ /// The kind of this string literal.
+ /// One of the enumeration values of StringLiteral::StringKind.
+ unsigned Kind : 3;
+
+ /// The width of a single character in bytes. Only values of 1, 2,
+ /// and 4 bytes are supported. StringLiteral::mapCharByteWidth maps
+ /// the target + string kind to the appropriate CharByteWidth.
+ unsigned CharByteWidth : 3;
+
+ unsigned IsPascal : 1;
+
+ /// The number of concatenated token this string is made of.
+ /// This is the number of trailing SourceLocation.
+ unsigned NumConcatenated;
+ };
+
+ class CharacterLiteralBitfields {
+ friend class CharacterLiteral;
+
+ unsigned : NumExprBits;
+
+ unsigned Kind : 3;
+ };
+
+ class UnaryOperatorBitfields {
+ friend class UnaryOperator;
+
+ unsigned : NumExprBits;
+
+ unsigned Opc : 5;
+ unsigned CanOverflow : 1;
+
+ SourceLocation Loc;
+ };
+
class UnaryExprOrTypeTraitExprBitfields {
friend class UnaryExprOrTypeTraitExpr;
unsigned : NumExprBits;
- unsigned Kind : 2;
+ unsigned Kind : 3;
unsigned IsType : 1; // true if operand is a type, false if an expression.
};
- class DeclRefExprBitfields {
- friend class ASTStmtReader; // deserialization
- friend class DeclRefExpr;
+ class ArraySubscriptExprBitfields {
+ friend class ArraySubscriptExpr;
unsigned : NumExprBits;
- unsigned HasQualifier : 1;
+ SourceLocation RBracketLoc;
+ };
+
+ class CallExprBitfields {
+ friend class CallExpr;
+
+ unsigned : NumExprBits;
+
+ unsigned NumPreArgs : 1;
+
+ /// True if the callee of the call expression was found using ADL.
+ unsigned UsesADL : 1;
+ };
+
+ class MemberExprBitfields {
+ friend class MemberExpr;
+
+ unsigned : NumExprBits;
+
+ /// IsArrow - True if this is "X->F", false if this is "X.F".
+ unsigned IsArrow : 1;
+
+ /// True if this member expression used a nested-name-specifier to
+ /// refer to the member, e.g., "x->Base::f", or found its member via
+ /// a using declaration. When true, a MemberExprNameQualifier
+ /// structure is allocated immediately after the MemberExpr.
+ unsigned HasQualifierOrFoundDecl : 1;
+
+ /// True if this member expression specified a template keyword
+ /// and/or a template argument list explicitly, e.g., x->f<int>,
+ /// x->template f, x->template f<int>.
+ /// When true, an ASTTemplateKWAndArgsInfo structure and its
+ /// TemplateArguments (if any) are present.
unsigned HasTemplateKWAndArgsInfo : 1;
- unsigned HasFoundDecl : 1;
+
+ /// True if this member expression refers to a method that
+ /// was resolved from an overloaded set having size greater than 1.
unsigned HadMultipleCandidates : 1;
- unsigned RefersToEnclosingVariableOrCapture : 1;
+
+ /// This is the location of the -> or . in the expression.
+ SourceLocation OperatorLoc;
};
class CastExprBitfields {
@@ -207,24 +475,38 @@ protected:
unsigned BasePathIsEmpty : 1;
};
- class CallExprBitfields {
- friend class CallExpr;
+ class BinaryOperatorBitfields {
+ friend class BinaryOperator;
unsigned : NumExprBits;
- unsigned NumPreArgs : 1;
+ unsigned Opc : 6;
+
+ /// This is only meaningful for operations on floating point
+ /// types and 0 otherwise.
+ unsigned FPFeatures : 3;
+
+ SourceLocation OpLoc;
};
- class ExprWithCleanupsBitfields {
- friend class ASTStmtReader; // deserialization
- friend class ExprWithCleanups;
+ class InitListExprBitfields {
+ friend class InitListExpr;
unsigned : NumExprBits;
- // When false, it must not have side effects.
- unsigned CleanupsHaveSideEffects : 1;
+ /// Whether this initializer list originally had a GNU array-range
+ /// designator in it. This is a temporary marker used by CodeGen.
+ unsigned HadArrayRangeDesignator : 1;
+ };
- unsigned NumObjects : 32 - 1 - NumExprBits;
+ class ParenListExprBitfields {
+ friend class ASTStmtReader;
+ friend class ParenListExpr;
+
+ unsigned : NumExprBits;
+
+ /// The number of expressions in the paren list.
+ unsigned NumExprs;
};
class PseudoObjectExprBitfields {
@@ -239,32 +521,97 @@ protected:
unsigned ResultIndex : 32 - 8 - NumExprBits;
};
- class OpaqueValueExprBitfields {
- friend class OpaqueValueExpr;
+ //===--- C++ Expression bitfields classes ---===//
+
+ class CXXBoolLiteralExprBitfields {
+ friend class CXXBoolLiteralExpr;
unsigned : NumExprBits;
- /// The OVE is a unique semantic reference to its source expressio if this
- /// bit is set to true.
- unsigned IsUnique : 1;
+ /// The value of the boolean literal.
+ unsigned Value : 1;
+
+ /// The location of the boolean literal.
+ SourceLocation Loc;
};
- class ObjCIndirectCopyRestoreExprBitfields {
- friend class ObjCIndirectCopyRestoreExpr;
+ class CXXNullPtrLiteralExprBitfields {
+ friend class CXXNullPtrLiteralExpr;
unsigned : NumExprBits;
- unsigned ShouldCopy : 1;
+ /// The location of the null pointer literal.
+ SourceLocation Loc;
};
- class InitListExprBitfields {
- friend class InitListExpr;
+ class CXXThisExprBitfields {
+ friend class CXXThisExpr;
unsigned : NumExprBits;
- /// Whether this initializer list originally had a GNU array-range
- /// designator in it. This is a temporary marker used by CodeGen.
- unsigned HadArrayRangeDesignator : 1;
+ /// Whether this is an implicit "this".
+ unsigned IsImplicit : 1;
+
+ /// The location of the "this".
+ SourceLocation Loc;
+ };
+
+ class CXXThrowExprBitfields {
+ friend class ASTStmtReader;
+ friend class CXXThrowExpr;
+
+ unsigned : NumExprBits;
+
+ /// Whether the thrown variable (if any) is in scope.
+ unsigned IsThrownVariableInScope : 1;
+
+ /// The location of the "throw".
+ SourceLocation ThrowLoc;
+ };
+
+ class CXXDefaultArgExprBitfields {
+ friend class ASTStmtReader;
+ friend class CXXDefaultArgExpr;
+
+ unsigned : NumExprBits;
+
+ /// The location where the default argument expression was used.
+ SourceLocation Loc;
+ };
+
+ class CXXDefaultInitExprBitfields {
+ friend class ASTStmtReader;
+ friend class CXXDefaultInitExpr;
+
+ unsigned : NumExprBits;
+
+ /// The location where the default initializer expression was used.
+ SourceLocation Loc;
+ };
+
+ class CXXDeleteExprBitfields {
+ friend class ASTStmtReader;
+ friend class CXXDeleteExpr;
+
+ unsigned : NumExprBits;
+
+ /// Is this a forced global delete, i.e. "::delete"?
+ unsigned GlobalDelete : 1;
+
+ /// Is this the array form of delete, i.e. "delete[]"?
+ unsigned ArrayForm : 1;
+
+ /// ArrayFormAsWritten can be different from ArrayForm if 'delete' is
+ /// applied to pointer-to-array type (ArrayFormAsWritten will be false
+ /// while ArrayForm will be true).
+ unsigned ArrayFormAsWritten : 1;
+
+ /// Does the usual deallocation function for the element type require
+ /// a size_t argument?
+ unsigned UsualArrayDeleteWantsSize : 1;
+
+ /// Location of the expression.
+ SourceLocation Loc;
};
class TypeTraitExprBitfields {
@@ -285,6 +632,20 @@ protected:
unsigned NumArgs : 32 - 8 - 1 - NumExprBits;
};
+ class ExprWithCleanupsBitfields {
+ friend class ASTStmtReader; // deserialization
+ friend class ExprWithCleanups;
+
+ unsigned : NumExprBits;
+
+ // When false, it must not have side effects.
+ unsigned CleanupsHaveSideEffects : 1;
+
+ unsigned NumObjects : 32 - 1 - NumExprBits;
+ };
+
+ //===--- C++ Coroutines TS bitfields classes ---===//
+
class CoawaitExprBitfields {
friend class CoawaitExpr;
@@ -293,24 +654,84 @@ protected:
unsigned IsImplicit : 1;
};
+ //===--- Obj-C Expression bitfields classes ---===//
+
+ class ObjCIndirectCopyRestoreExprBitfields {
+ friend class ObjCIndirectCopyRestoreExpr;
+
+ unsigned : NumExprBits;
+
+ unsigned ShouldCopy : 1;
+ };
+
+ //===--- Clang Extensions bitfields classes ---===//
+
+ class OpaqueValueExprBitfields {
+ friend class OpaqueValueExpr;
+
+ unsigned : NumExprBits;
+
+ /// The OVE is a unique semantic reference to its source expressio if this
+ /// bit is set to true.
+ unsigned IsUnique : 1;
+ };
+
union {
+ // Same order as in StmtNodes.td.
+ // Statements
StmtBitfields StmtBits;
+ NullStmtBitfields NullStmtBits;
CompoundStmtBitfields CompoundStmtBits;
+ LabelStmtBitfields LabelStmtBits;
+ AttributedStmtBitfields AttributedStmtBits;
IfStmtBitfields IfStmtBits;
+ SwitchStmtBitfields SwitchStmtBits;
+ WhileStmtBitfields WhileStmtBits;
+ DoStmtBitfields DoStmtBits;
+ ForStmtBitfields ForStmtBits;
+ GotoStmtBitfields GotoStmtBits;
+ ContinueStmtBitfields ContinueStmtBits;
+ BreakStmtBitfields BreakStmtBits;
+ ReturnStmtBitfields ReturnStmtBits;
+ SwitchCaseBitfields SwitchCaseBits;
+
+ // Expressions
ExprBitfields ExprBits;
- CharacterLiteralBitfields CharacterLiteralBits;
+ PredefinedExprBitfields PredefinedExprBits;
+ DeclRefExprBitfields DeclRefExprBits;
FloatingLiteralBitfields FloatingLiteralBits;
+ StringLiteralBitfields StringLiteralBits;
+ CharacterLiteralBitfields CharacterLiteralBits;
+ UnaryOperatorBitfields UnaryOperatorBits;
UnaryExprOrTypeTraitExprBitfields UnaryExprOrTypeTraitExprBits;
- DeclRefExprBitfields DeclRefExprBits;
- CastExprBitfields CastExprBits;
+ ArraySubscriptExprBitfields ArraySubscriptExprBits;
CallExprBitfields CallExprBits;
- ExprWithCleanupsBitfields ExprWithCleanupsBits;
- PseudoObjectExprBitfields PseudoObjectExprBits;
- OpaqueValueExprBitfields OpaqueValueExprBits;
- ObjCIndirectCopyRestoreExprBitfields ObjCIndirectCopyRestoreExprBits;
+ MemberExprBitfields MemberExprBits;
+ CastExprBitfields CastExprBits;
+ BinaryOperatorBitfields BinaryOperatorBits;
InitListExprBitfields InitListExprBits;
+ ParenListExprBitfields ParenListExprBits;
+ PseudoObjectExprBitfields PseudoObjectExprBits;
+
+ // C++ Expressions
+ CXXBoolLiteralExprBitfields CXXBoolLiteralExprBits;
+ CXXNullPtrLiteralExprBitfields CXXNullPtrLiteralExprBits;
+ CXXThisExprBitfields CXXThisExprBits;
+ CXXThrowExprBitfields CXXThrowExprBits;
+ CXXDefaultArgExprBitfields CXXDefaultArgExprBits;
+ CXXDefaultInitExprBitfields CXXDefaultInitExprBits;
+ CXXDeleteExprBitfields CXXDeleteExprBits;
TypeTraitExprBitfields TypeTraitExprBits;
+ ExprWithCleanupsBitfields ExprWithCleanupsBits;
+
+ // C++ Coroutines TS expressions
CoawaitExprBitfields CoawaitBits;
+
+ // Obj-C Expressions
+ ObjCIndirectCopyRestoreExprBitfields ObjCIndirectCopyRestoreExprBits;
+
+ // Clang Extensions
+ OpaqueValueExprBitfields OpaqueValueExprBits;
};
public:
@@ -380,7 +801,7 @@ protected:
public:
Stmt(StmtClass SC) {
- static_assert(sizeof(*this) == sizeof(void *),
+ static_assert(sizeof(*this) <= 8,
"changing bitfields changed sizeof(Stmt)");
static_assert(sizeof(*this) % alignof(void *) == 0,
"Insufficient alignment!");
@@ -515,9 +936,7 @@ public:
/// isSingleDecl - This method returns true if this DeclStmt refers
/// to a single Decl.
- bool isSingleDecl() const {
- return DG.isSingleDecl();
- }
+ bool isSingleDecl() const { return DG.isSingleDecl(); }
const Decl *getSingleDecl() const { return DG.getSingleDecl(); }
Decl *getSingleDecl() { return DG.getSingleDecl(); }
@@ -572,33 +991,25 @@ public:
/// NullStmt - This is the null statement ";": C99 6.8.3p3.
///
class NullStmt : public Stmt {
- SourceLocation SemiLoc;
-
- /// True if the null statement was preceded by an empty macro, e.g:
- /// @code
- /// #define CALL(x)
- /// CALL(0);
- /// @endcode
- bool HasLeadingEmptyMacro = false;
-
public:
- friend class ASTStmtReader;
- friend class ASTStmtWriter;
-
NullStmt(SourceLocation L, bool hasLeadingEmptyMacro = false)
- : Stmt(NullStmtClass), SemiLoc(L),
- HasLeadingEmptyMacro(hasLeadingEmptyMacro) {}
+ : Stmt(NullStmtClass) {
+ NullStmtBits.HasLeadingEmptyMacro = hasLeadingEmptyMacro;
+ setSemiLoc(L);
+ }
/// Build an empty null statement.
explicit NullStmt(EmptyShell Empty) : Stmt(NullStmtClass, Empty) {}
- SourceLocation getSemiLoc() const { return SemiLoc; }
- void setSemiLoc(SourceLocation L) { SemiLoc = L; }
+ SourceLocation getSemiLoc() const { return NullStmtBits.SemiLoc; }
+ void setSemiLoc(SourceLocation L) { NullStmtBits.SemiLoc = L; }
- bool hasLeadingEmptyMacro() const { return HasLeadingEmptyMacro; }
+ bool hasLeadingEmptyMacro() const {
+ return NullStmtBits.HasLeadingEmptyMacro;
+ }
- SourceLocation getBeginLoc() const LLVM_READONLY { return SemiLoc; }
- SourceLocation getEndLoc() const LLVM_READONLY { return SemiLoc; }
+ SourceLocation getBeginLoc() const { return getSemiLoc(); }
+ SourceLocation getEndLoc() const { return getSemiLoc(); }
static bool classof(const Stmt *T) {
return T->getStmtClass() == NullStmtClass;
@@ -615,7 +1026,8 @@ class CompoundStmt final : public Stmt,
friend class ASTStmtReader;
friend TrailingObjects;
- SourceLocation LBraceLoc, RBraceLoc;
+ /// The location of the closing "}". LBraceLoc is stored in CompoundStmtBits.
+ SourceLocation RBraceLoc;
CompoundStmt(ArrayRef<Stmt *> Stmts, SourceLocation LB, SourceLocation RB);
explicit CompoundStmt(EmptyShell Empty) : Stmt(CompoundStmtClass, Empty) {}
@@ -628,8 +1040,9 @@ public:
// Build an empty compound statement with a location.
explicit CompoundStmt(SourceLocation Loc)
- : Stmt(CompoundStmtClass), LBraceLoc(Loc), RBraceLoc(Loc) {
+ : Stmt(CompoundStmtClass), RBraceLoc(Loc) {
CompoundStmtBits.NumStmts = 0;
+ CompoundStmtBits.LBraceLoc = Loc;
}
// Build an empty compound statement.
@@ -655,7 +1068,7 @@ public:
body_begin()[size() - 1] = S;
}
- using const_body_iterator = Stmt* const *;
+ using const_body_iterator = Stmt *const *;
using body_const_range = llvm::iterator_range<const_body_iterator>;
body_const_range body() const {
@@ -697,10 +1110,10 @@ public:
return const_reverse_body_iterator(body_begin());
}
- SourceLocation getBeginLoc() const LLVM_READONLY { return LBraceLoc; }
- SourceLocation getEndLoc() const LLVM_READONLY { return RBraceLoc; }
+ SourceLocation getBeginLoc() const { return CompoundStmtBits.LBraceLoc; }
+ SourceLocation getEndLoc() const { return RBraceLoc; }
- SourceLocation getLBracLoc() const { return LBraceLoc; }
+ SourceLocation getLBracLoc() const { return CompoundStmtBits.LBraceLoc; }
SourceLocation getRBracLoc() const { return RBraceLoc; }
static bool classof(const Stmt *T) {
@@ -718,36 +1131,40 @@ public:
// SwitchCase is the base class for CaseStmt and DefaultStmt,
class SwitchCase : public Stmt {
protected:
- // A pointer to the following CaseStmt or DefaultStmt class,
- // used by SwitchStmt.
- SwitchCase *NextSwitchCase = nullptr;
- SourceLocation KeywordLoc;
+ /// The location of the ":".
SourceLocation ColonLoc;
+ // The location of the "case" or "default" keyword. Stored in SwitchCaseBits.
+ // SourceLocation KeywordLoc;
+
+ /// A pointer to the following CaseStmt or DefaultStmt class,
+ /// used by SwitchStmt.
+ SwitchCase *NextSwitchCase = nullptr;
+
SwitchCase(StmtClass SC, SourceLocation KWLoc, SourceLocation ColonLoc)
- : Stmt(SC), KeywordLoc(KWLoc), ColonLoc(ColonLoc) {}
+ : Stmt(SC), ColonLoc(ColonLoc) {
+ setKeywordLoc(KWLoc);
+ }
SwitchCase(StmtClass SC, EmptyShell) : Stmt(SC) {}
public:
const SwitchCase *getNextSwitchCase() const { return NextSwitchCase; }
-
SwitchCase *getNextSwitchCase() { return NextSwitchCase; }
-
void setNextSwitchCase(SwitchCase *SC) { NextSwitchCase = SC; }
- SourceLocation getKeywordLoc() const { return KeywordLoc; }
- void setKeywordLoc(SourceLocation L) { KeywordLoc = L; }
+ SourceLocation getKeywordLoc() const { return SwitchCaseBits.KeywordLoc; }
+ void setKeywordLoc(SourceLocation L) { SwitchCaseBits.KeywordLoc = L; }
SourceLocation getColonLoc() const { return ColonLoc; }
void setColonLoc(SourceLocation L) { ColonLoc = L; }
- Stmt *getSubStmt();
+ inline Stmt *getSubStmt();
const Stmt *getSubStmt() const {
- return const_cast<SwitchCase*>(this)->getSubStmt();
+ return const_cast<SwitchCase *>(this)->getSubStmt();
}
- SourceLocation getBeginLoc() const LLVM_READONLY { return KeywordLoc; }
- SourceLocation getEndLoc() const LLVM_READONLY;
+ SourceLocation getBeginLoc() const { return getKeywordLoc(); }
+ inline SourceLocation getEndLoc() const LLVM_READONLY;
static bool classof(const Stmt *T) {
return T->getStmtClass() == CaseStmtClass ||
@@ -755,52 +1172,137 @@ public:
}
};
-class CaseStmt : public SwitchCase {
- SourceLocation EllipsisLoc;
- enum { LHS, RHS, SUBSTMT, END_EXPR };
- Stmt* SubExprs[END_EXPR]; // The expression for the RHS is Non-null for
- // GNU "case 1 ... 4" extension
+/// CaseStmt - Represent a case statement. It can optionally be a GNU case
+/// statement of the form LHS ... RHS representing a range of cases.
+class CaseStmt final
+ : public SwitchCase,
+ private llvm::TrailingObjects<CaseStmt, Stmt *, SourceLocation> {
+ friend TrailingObjects;
-public:
+ // CaseStmt is followed by several trailing objects, some of which optional.
+ // Note that it would be more convenient to put the optional trailing objects
+ // at the end but this would impact children().
+ // The trailing objects are in order:
+ //
+ // * A "Stmt *" for the LHS of the case statement. Always present.
+ //
+ // * A "Stmt *" for the RHS of the case statement. This is a GNU extension
+ // which allow ranges in cases statement of the form LHS ... RHS.
+ // Present if and only if caseStmtIsGNURange() is true.
+ //
+ // * A "Stmt *" for the substatement of the case statement. Always present.
+ //
+ // * A SourceLocation for the location of the ... if this is a case statement
+ // with a range. Present if and only if caseStmtIsGNURange() is true.
+ enum { LhsOffset = 0, SubStmtOffsetFromRhs = 1 };
+ enum { NumMandatoryStmtPtr = 2 };
+
+ unsigned numTrailingObjects(OverloadToken<Stmt *>) const {
+ return NumMandatoryStmtPtr + caseStmtIsGNURange();
+ }
+
+ unsigned numTrailingObjects(OverloadToken<SourceLocation>) const {
+ return caseStmtIsGNURange();
+ }
+
+ unsigned lhsOffset() const { return LhsOffset; }
+ unsigned rhsOffset() const { return LhsOffset + caseStmtIsGNURange(); }
+ unsigned subStmtOffset() const { return rhsOffset() + SubStmtOffsetFromRhs; }
+
+ /// Build a case statement assuming that the storage for the
+ /// trailing objects has been properly allocated.
CaseStmt(Expr *lhs, Expr *rhs, SourceLocation caseLoc,
SourceLocation ellipsisLoc, SourceLocation colonLoc)
- : SwitchCase(CaseStmtClass, caseLoc, colonLoc) {
- SubExprs[SUBSTMT] = nullptr;
- SubExprs[LHS] = reinterpret_cast<Stmt*>(lhs);
- SubExprs[RHS] = reinterpret_cast<Stmt*>(rhs);
- EllipsisLoc = ellipsisLoc;
+ : SwitchCase(CaseStmtClass, caseLoc, colonLoc) {
+ // Handle GNU case statements of the form LHS ... RHS.
+ bool IsGNURange = rhs != nullptr;
+ SwitchCaseBits.CaseStmtIsGNURange = IsGNURange;
+ setLHS(lhs);
+ setSubStmt(nullptr);
+ if (IsGNURange) {
+ setRHS(rhs);
+ setEllipsisLoc(ellipsisLoc);
+ }
}
/// Build an empty switch case statement.
- explicit CaseStmt(EmptyShell Empty) : SwitchCase(CaseStmtClass, Empty) {}
+ explicit CaseStmt(EmptyShell Empty, bool CaseStmtIsGNURange)
+ : SwitchCase(CaseStmtClass, Empty) {
+ SwitchCaseBits.CaseStmtIsGNURange = CaseStmtIsGNURange;
+ }
- SourceLocation getCaseLoc() const { return KeywordLoc; }
- void setCaseLoc(SourceLocation L) { KeywordLoc = L; }
- SourceLocation getEllipsisLoc() const { return EllipsisLoc; }
- void setEllipsisLoc(SourceLocation L) { EllipsisLoc = L; }
- SourceLocation getColonLoc() const { return ColonLoc; }
- void setColonLoc(SourceLocation L) { ColonLoc = L; }
+public:
+ /// Build a case statement.
+ static CaseStmt *Create(const ASTContext &Ctx, Expr *lhs, Expr *rhs,
+ SourceLocation caseLoc, SourceLocation ellipsisLoc,
+ SourceLocation colonLoc);
+
+ /// Build an empty case statement.
+ static CaseStmt *CreateEmpty(const ASTContext &Ctx, bool CaseStmtIsGNURange);
+
+ /// True if this case statement is of the form case LHS ... RHS, which
+ /// is a GNU extension. In this case the RHS can be obtained with getRHS()
+ /// and the location of the ellipsis can be obtained with getEllipsisLoc().
+ bool caseStmtIsGNURange() const { return SwitchCaseBits.CaseStmtIsGNURange; }
+
+ SourceLocation getCaseLoc() const { return getKeywordLoc(); }
+ void setCaseLoc(SourceLocation L) { setKeywordLoc(L); }
- Expr *getLHS() { return reinterpret_cast<Expr*>(SubExprs[LHS]); }
- Expr *getRHS() { return reinterpret_cast<Expr*>(SubExprs[RHS]); }
- Stmt *getSubStmt() { return SubExprs[SUBSTMT]; }
+ /// Get the location of the ... in a case statement of the form LHS ... RHS.
+ SourceLocation getEllipsisLoc() const {
+ return caseStmtIsGNURange() ? *getTrailingObjects<SourceLocation>()
+ : SourceLocation();
+ }
+
+ /// Set the location of the ... in a case statement of the form LHS ... RHS.
+ /// Assert that this case statement is of this form.
+ void setEllipsisLoc(SourceLocation L) {
+ assert(
+ caseStmtIsGNURange() &&
+ "setEllipsisLoc but this is not a case stmt of the form LHS ... RHS!");
+ *getTrailingObjects<SourceLocation>() = L;
+ }
+
+ Expr *getLHS() {
+ return reinterpret_cast<Expr *>(getTrailingObjects<Stmt *>()[lhsOffset()]);
+ }
const Expr *getLHS() const {
- return reinterpret_cast<const Expr*>(SubExprs[LHS]);
+ return reinterpret_cast<Expr *>(getTrailingObjects<Stmt *>()[lhsOffset()]);
+ }
+
+ void setLHS(Expr *Val) {
+ getTrailingObjects<Stmt *>()[lhsOffset()] = reinterpret_cast<Stmt *>(Val);
+ }
+
+ Expr *getRHS() {
+ return caseStmtIsGNURange() ? reinterpret_cast<Expr *>(
+ getTrailingObjects<Stmt *>()[rhsOffset()])
+ : nullptr;
}
const Expr *getRHS() const {
- return reinterpret_cast<const Expr*>(SubExprs[RHS]);
+ return caseStmtIsGNURange() ? reinterpret_cast<Expr *>(
+ getTrailingObjects<Stmt *>()[rhsOffset()])
+ : nullptr;
}
- const Stmt *getSubStmt() const { return SubExprs[SUBSTMT]; }
+ void setRHS(Expr *Val) {
+ assert(caseStmtIsGNURange() &&
+ "setRHS but this is not a case stmt of the form LHS ... RHS!");
+ getTrailingObjects<Stmt *>()[rhsOffset()] = reinterpret_cast<Stmt *>(Val);
+ }
- void setSubStmt(Stmt *S) { SubExprs[SUBSTMT] = S; }
- void setLHS(Expr *Val) { SubExprs[LHS] = reinterpret_cast<Stmt*>(Val); }
- void setRHS(Expr *Val) { SubExprs[RHS] = reinterpret_cast<Stmt*>(Val); }
+ Stmt *getSubStmt() { return getTrailingObjects<Stmt *>()[subStmtOffset()]; }
+ const Stmt *getSubStmt() const {
+ return getTrailingObjects<Stmt *>()[subStmtOffset()];
+ }
- SourceLocation getBeginLoc() const LLVM_READONLY { return KeywordLoc; }
+ void setSubStmt(Stmt *S) {
+ getTrailingObjects<Stmt *>()[subStmtOffset()] = S;
+ }
+ SourceLocation getBeginLoc() const { return getKeywordLoc(); }
SourceLocation getEndLoc() const LLVM_READONLY {
// Handle deeply nested case statements with iteration instead of recursion.
const CaseStmt *CS = this;
@@ -816,16 +1318,18 @@ public:
// Iterators
child_range children() {
- return child_range(&SubExprs[0], &SubExprs[END_EXPR]);
+ return child_range(getTrailingObjects<Stmt *>(),
+ getTrailingObjects<Stmt *>() +
+ numTrailingObjects(OverloadToken<Stmt *>()));
}
};
class DefaultStmt : public SwitchCase {
- Stmt* SubStmt;
+ Stmt *SubStmt;
public:
- DefaultStmt(SourceLocation DL, SourceLocation CL, Stmt *substmt) :
- SwitchCase(DefaultStmtClass, DL, CL), SubStmt(substmt) {}
+ DefaultStmt(SourceLocation DL, SourceLocation CL, Stmt *substmt)
+ : SwitchCase(DefaultStmtClass, DL, CL), SubStmt(substmt) {}
/// Build an empty default statement.
explicit DefaultStmt(EmptyShell Empty)
@@ -835,12 +1339,10 @@ public:
const Stmt *getSubStmt() const { return SubStmt; }
void setSubStmt(Stmt *S) { SubStmt = S; }
- SourceLocation getDefaultLoc() const { return KeywordLoc; }
- void setDefaultLoc(SourceLocation L) { KeywordLoc = L; }
- SourceLocation getColonLoc() const { return ColonLoc; }
- void setColonLoc(SourceLocation L) { ColonLoc = L; }
+ SourceLocation getDefaultLoc() const { return getKeywordLoc(); }
+ void setDefaultLoc(SourceLocation L) { setKeywordLoc(L); }
- SourceLocation getBeginLoc() const LLVM_READONLY { return KeywordLoc; }
+ SourceLocation getBeginLoc() const { return getKeywordLoc(); }
SourceLocation getEndLoc() const LLVM_READONLY {
return SubStmt->getEndLoc();
}
@@ -850,48 +1352,57 @@ public:
}
// Iterators
- child_range children() { return child_range(&SubStmt, &SubStmt+1); }
+ child_range children() { return child_range(&SubStmt, &SubStmt + 1); }
};
-inline SourceLocation SwitchCase::getEndLoc() const {
+SourceLocation SwitchCase::getEndLoc() const {
if (const auto *CS = dyn_cast<CaseStmt>(this))
return CS->getEndLoc();
- return cast<DefaultStmt>(this)->getEndLoc();
+ else if (const auto *DS = dyn_cast<DefaultStmt>(this))
+ return DS->getEndLoc();
+ llvm_unreachable("SwitchCase is neither a CaseStmt nor a DefaultStmt!");
+}
+
+Stmt *SwitchCase::getSubStmt() {
+ if (auto *CS = dyn_cast<CaseStmt>(this))
+ return CS->getSubStmt();
+ else if (auto *DS = dyn_cast<DefaultStmt>(this))
+ return DS->getSubStmt();
+ llvm_unreachable("SwitchCase is neither a CaseStmt nor a DefaultStmt!");
}
/// LabelStmt - Represents a label, which has a substatement. For example:
/// foo: return;
class LabelStmt : public Stmt {
- SourceLocation IdentLoc;
LabelDecl *TheDecl;
Stmt *SubStmt;
public:
+ /// Build a label statement.
LabelStmt(SourceLocation IL, LabelDecl *D, Stmt *substmt)
- : Stmt(LabelStmtClass), IdentLoc(IL), TheDecl(D), SubStmt(substmt) {
- static_assert(sizeof(LabelStmt) ==
- 2 * sizeof(SourceLocation) + 2 * sizeof(void *),
- "LabelStmt too big");
+ : Stmt(LabelStmtClass), TheDecl(D), SubStmt(substmt) {
+ setIdentLoc(IL);
}
- // Build an empty label statement.
+ /// Build an empty label statement.
explicit LabelStmt(EmptyShell Empty) : Stmt(LabelStmtClass, Empty) {}
- SourceLocation getIdentLoc() const { return IdentLoc; }
+ SourceLocation getIdentLoc() const { return LabelStmtBits.IdentLoc; }
+ void setIdentLoc(SourceLocation L) { LabelStmtBits.IdentLoc = L; }
+
LabelDecl *getDecl() const { return TheDecl; }
void setDecl(LabelDecl *D) { TheDecl = D; }
+
const char *getName() const;
Stmt *getSubStmt() { return SubStmt; }
+
const Stmt *getSubStmt() const { return SubStmt; }
- void setIdentLoc(SourceLocation L) { IdentLoc = L; }
void setSubStmt(Stmt *SS) { SubStmt = SS; }
- SourceLocation getBeginLoc() const LLVM_READONLY { return IdentLoc; }
- SourceLocation getEndLoc() const LLVM_READONLY {
- return SubStmt->getEndLoc();
- }
+ SourceLocation getBeginLoc() const { return getIdentLoc(); }
+ SourceLocation getEndLoc() const LLVM_READONLY { return SubStmt->getEndLoc();}
- child_range children() { return child_range(&SubStmt, &SubStmt+1); }
+ child_range children() { return child_range(&SubStmt, &SubStmt + 1); }
static bool classof(const Stmt *T) {
return T->getStmtClass() == LabelStmtClass;
@@ -909,17 +1420,19 @@ class AttributedStmt final
friend TrailingObjects;
Stmt *SubStmt;
- SourceLocation AttrLoc;
- unsigned NumAttrs;
- AttributedStmt(SourceLocation Loc, ArrayRef<const Attr*> Attrs, Stmt *SubStmt)
- : Stmt(AttributedStmtClass), SubStmt(SubStmt), AttrLoc(Loc),
- NumAttrs(Attrs.size()) {
+ AttributedStmt(SourceLocation Loc, ArrayRef<const Attr *> Attrs,
+ Stmt *SubStmt)
+ : Stmt(AttributedStmtClass), SubStmt(SubStmt) {
+ AttributedStmtBits.NumAttrs = Attrs.size();
+ AttributedStmtBits.AttrLoc = Loc;
std::copy(Attrs.begin(), Attrs.end(), getAttrArrayPtr());
}
explicit AttributedStmt(EmptyShell Empty, unsigned NumAttrs)
- : Stmt(AttributedStmtClass, Empty), NumAttrs(NumAttrs) {
+ : Stmt(AttributedStmtClass, Empty) {
+ AttributedStmtBits.NumAttrs = NumAttrs;
+ AttributedStmtBits.AttrLoc = SourceLocation{};
std::fill_n(getAttrArrayPtr(), NumAttrs, nullptr);
}
@@ -930,23 +1443,21 @@ class AttributedStmt final
public:
static AttributedStmt *Create(const ASTContext &C, SourceLocation Loc,
- ArrayRef<const Attr*> Attrs, Stmt *SubStmt);
+ ArrayRef<const Attr *> Attrs, Stmt *SubStmt);
// Build an empty attributed statement.
static AttributedStmt *CreateEmpty(const ASTContext &C, unsigned NumAttrs);
- SourceLocation getAttrLoc() const { return AttrLoc; }
- ArrayRef<const Attr*> getAttrs() const {
- return llvm::makeArrayRef(getAttrArrayPtr(), NumAttrs);
+ SourceLocation getAttrLoc() const { return AttributedStmtBits.AttrLoc; }
+ ArrayRef<const Attr *> getAttrs() const {
+ return llvm::makeArrayRef(getAttrArrayPtr(), AttributedStmtBits.NumAttrs);
}
Stmt *getSubStmt() { return SubStmt; }
const Stmt *getSubStmt() const { return SubStmt; }
- SourceLocation getBeginLoc() const LLVM_READONLY { return AttrLoc; }
- SourceLocation getEndLoc() const LLVM_READONLY {
- return SubStmt->getEndLoc();
- }
+ SourceLocation getBeginLoc() const { return getAttrLoc(); }
+ SourceLocation getEndLoc() const LLVM_READONLY { return SubStmt->getEndLoc();}
child_range children() { return child_range(&SubStmt, &SubStmt + 1); }
@@ -956,21 +1467,117 @@ public:
};
/// IfStmt - This represents an if/then/else.
-class IfStmt : public Stmt {
- enum { INIT, VAR, COND, THEN, ELSE, END_EXPR };
- Stmt* SubExprs[END_EXPR];
+class IfStmt final
+ : public Stmt,
+ private llvm::TrailingObjects<IfStmt, Stmt *, SourceLocation> {
+ friend TrailingObjects;
- SourceLocation IfLoc;
- SourceLocation ElseLoc;
+ // IfStmt is followed by several trailing objects, some of which optional.
+ // Note that it would be more convenient to put the optional trailing
+ // objects at then end but this would change the order of the children.
+ // The trailing objects are in order:
+ //
+ // * A "Stmt *" for the init statement.
+ // Present if and only if hasInitStorage().
+ //
+ // * A "Stmt *" for the condition variable.
+ // Present if and only if hasVarStorage(). This is in fact a "DeclStmt *".
+ //
+ // * A "Stmt *" for the condition.
+ // Always present. This is in fact a "Expr *".
+ //
+ // * A "Stmt *" for the then statement.
+ // Always present.
+ //
+ // * A "Stmt *" for the else statement.
+ // Present if and only if hasElseStorage().
+ //
+ // * A "SourceLocation" for the location of the "else".
+ // Present if and only if hasElseStorage().
+ enum { InitOffset = 0, ThenOffsetFromCond = 1, ElseOffsetFromCond = 2 };
+ enum { NumMandatoryStmtPtr = 2 };
+
+ unsigned numTrailingObjects(OverloadToken<Stmt *>) const {
+ return NumMandatoryStmtPtr + hasElseStorage() + hasVarStorage() +
+ hasInitStorage();
+ }
+
+ unsigned numTrailingObjects(OverloadToken<SourceLocation>) const {
+ return hasElseStorage();
+ }
+
+ unsigned initOffset() const { return InitOffset; }
+ unsigned varOffset() const { return InitOffset + hasInitStorage(); }
+ unsigned condOffset() const {
+ return InitOffset + hasInitStorage() + hasVarStorage();
+ }
+ unsigned thenOffset() const { return condOffset() + ThenOffsetFromCond; }
+ unsigned elseOffset() const { return condOffset() + ElseOffsetFromCond; }
+
+ /// Build an if/then/else statement.
+ IfStmt(const ASTContext &Ctx, SourceLocation IL, bool IsConstexpr, Stmt *Init,
+ VarDecl *Var, Expr *Cond, Stmt *Then, SourceLocation EL, Stmt *Else);
+
+ /// Build an empty if/then/else statement.
+ explicit IfStmt(EmptyShell Empty, bool HasElse, bool HasVar, bool HasInit);
public:
- IfStmt(const ASTContext &C, SourceLocation IL,
- bool IsConstexpr, Stmt *init, VarDecl *var, Expr *cond,
- Stmt *then, SourceLocation EL = SourceLocation(),
- Stmt *elsev = nullptr);
+ /// Create an IfStmt.
+ static IfStmt *Create(const ASTContext &Ctx, SourceLocation IL,
+ bool IsConstexpr, Stmt *Init, VarDecl *Var, Expr *Cond,
+ Stmt *Then, SourceLocation EL = SourceLocation(),
+ Stmt *Else = nullptr);
+
+ /// Create an empty IfStmt optionally with storage for an else statement,
+ /// condition variable and init expression.
+ static IfStmt *CreateEmpty(const ASTContext &Ctx, bool HasElse, bool HasVar,
+ bool HasInit);
+
+ /// True if this IfStmt has the storage for an init statement.
+ bool hasInitStorage() const { return IfStmtBits.HasInit; }
+
+ /// True if this IfStmt has storage for a variable declaration.
+ bool hasVarStorage() const { return IfStmtBits.HasVar; }
+
+ /// True if this IfStmt has storage for an else statement.
+ bool hasElseStorage() const { return IfStmtBits.HasElse; }
+
+ Expr *getCond() {
+ return reinterpret_cast<Expr *>(getTrailingObjects<Stmt *>()[condOffset()]);
+ }
+
+ const Expr *getCond() const {
+ return reinterpret_cast<Expr *>(getTrailingObjects<Stmt *>()[condOffset()]);
+ }
+
+ void setCond(Expr *Cond) {
+ getTrailingObjects<Stmt *>()[condOffset()] = reinterpret_cast<Stmt *>(Cond);
+ }
- /// Build an empty if/then/else statement
- explicit IfStmt(EmptyShell Empty) : Stmt(IfStmtClass, Empty) {}
+ Stmt *getThen() { return getTrailingObjects<Stmt *>()[thenOffset()]; }
+ const Stmt *getThen() const {
+ return getTrailingObjects<Stmt *>()[thenOffset()];
+ }
+
+ void setThen(Stmt *Then) {
+ getTrailingObjects<Stmt *>()[thenOffset()] = Then;
+ }
+
+ Stmt *getElse() {
+ return hasElseStorage() ? getTrailingObjects<Stmt *>()[elseOffset()]
+ : nullptr;
+ }
+
+ const Stmt *getElse() const {
+ return hasElseStorage() ? getTrailingObjects<Stmt *>()[elseOffset()]
+ : nullptr;
+ }
+
+ void setElse(Stmt *Else) {
+ assert(hasElseStorage() &&
+ "This if statement has no storage for an else statement!");
+ getTrailingObjects<Stmt *>()[elseOffset()] = Else;
+ }
/// Retrieve the variable declared in this "if" statement, if any.
///
@@ -980,52 +1587,77 @@ public:
/// printf("x is %d", x);
/// }
/// \endcode
- VarDecl *getConditionVariable() const;
- void setConditionVariable(const ASTContext &C, VarDecl *V);
+ VarDecl *getConditionVariable();
+ const VarDecl *getConditionVariable() const {
+ return const_cast<IfStmt *>(this)->getConditionVariable();
+ }
+
+ /// Set the condition variable for this if statement.
+ /// The if statement must have storage for the condition variable.
+ void setConditionVariable(const ASTContext &Ctx, VarDecl *V);
/// If this IfStmt has a condition variable, return the faux DeclStmt
/// associated with the creation of that condition variable.
+ DeclStmt *getConditionVariableDeclStmt() {
+ return hasVarStorage() ? static_cast<DeclStmt *>(
+ getTrailingObjects<Stmt *>()[varOffset()])
+ : nullptr;
+ }
+
const DeclStmt *getConditionVariableDeclStmt() const {
- return reinterpret_cast<DeclStmt*>(SubExprs[VAR]);
+ return hasVarStorage() ? static_cast<DeclStmt *>(
+ getTrailingObjects<Stmt *>()[varOffset()])
+ : nullptr;
}
- Stmt *getInit() { return SubExprs[INIT]; }
- const Stmt *getInit() const { return SubExprs[INIT]; }
- void setInit(Stmt *S) { SubExprs[INIT] = S; }
- const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);}
- void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt *>(E); }
- const Stmt *getThen() const { return SubExprs[THEN]; }
- void setThen(Stmt *S) { SubExprs[THEN] = S; }
- const Stmt *getElse() const { return SubExprs[ELSE]; }
- void setElse(Stmt *S) { SubExprs[ELSE] = S; }
+ Stmt *getInit() {
+ return hasInitStorage() ? getTrailingObjects<Stmt *>()[initOffset()]
+ : nullptr;
+ }
- Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); }
- Stmt *getThen() { return SubExprs[THEN]; }
- Stmt *getElse() { return SubExprs[ELSE]; }
+ const Stmt *getInit() const {
+ return hasInitStorage() ? getTrailingObjects<Stmt *>()[initOffset()]
+ : nullptr;
+ }
- SourceLocation getIfLoc() const { return IfLoc; }
- void setIfLoc(SourceLocation L) { IfLoc = L; }
- SourceLocation getElseLoc() const { return ElseLoc; }
- void setElseLoc(SourceLocation L) { ElseLoc = L; }
+ void setInit(Stmt *Init) {
+ assert(hasInitStorage() &&
+ "This if statement has no storage for an init statement!");
+ getTrailingObjects<Stmt *>()[initOffset()] = Init;
+ }
+
+ SourceLocation getIfLoc() const { return IfStmtBits.IfLoc; }
+ void setIfLoc(SourceLocation IfLoc) { IfStmtBits.IfLoc = IfLoc; }
+
+ SourceLocation getElseLoc() const {
+ return hasElseStorage() ? *getTrailingObjects<SourceLocation>()
+ : SourceLocation();
+ }
+
+ void setElseLoc(SourceLocation ElseLoc) {
+ assert(hasElseStorage() &&
+ "This if statement has no storage for an else statement!");
+ *getTrailingObjects<SourceLocation>() = ElseLoc;
+ }
bool isConstexpr() const { return IfStmtBits.IsConstexpr; }
void setConstexpr(bool C) { IfStmtBits.IsConstexpr = C; }
bool isObjCAvailabilityCheck() const;
- SourceLocation getBeginLoc() const LLVM_READONLY { return IfLoc; }
-
+ SourceLocation getBeginLoc() const { return getIfLoc(); }
SourceLocation getEndLoc() const LLVM_READONLY {
- if (SubExprs[ELSE])
- return SubExprs[ELSE]->getEndLoc();
- else
- return SubExprs[THEN]->getEndLoc();
+ if (getElse())
+ return getElse()->getEndLoc();
+ return getThen()->getEndLoc();
}
// Iterators over subexpressions. The iterators will include iterating
// over the initialization expression referenced by the condition variable.
child_range children() {
- return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR);
+ return child_range(getTrailingObjects<Stmt *>(),
+ getTrailingObjects<Stmt *>() +
+ numTrailingObjects(OverloadToken<Stmt *>()));
}
static bool classof(const Stmt *T) {
@@ -1034,22 +1666,102 @@ public:
};
/// SwitchStmt - This represents a 'switch' stmt.
-class SwitchStmt : public Stmt {
- SourceLocation SwitchLoc;
- enum { INIT, VAR, COND, BODY, END_EXPR };
- Stmt* SubExprs[END_EXPR];
+class SwitchStmt final : public Stmt,
+ private llvm::TrailingObjects<SwitchStmt, Stmt *> {
+ friend TrailingObjects;
+
+ /// Points to a linked list of case and default statements.
+ SwitchCase *FirstCase;
+
+ // SwitchStmt is followed by several trailing objects,
+ // some of which optional. Note that it would be more convenient to
+ // put the optional trailing objects at the end but this would change
+ // the order in children().
+ // The trailing objects are in order:
+ //
+ // * A "Stmt *" for the init statement.
+ // Present if and only if hasInitStorage().
+ //
+ // * A "Stmt *" for the condition variable.
+ // Present if and only if hasVarStorage(). This is in fact a "DeclStmt *".
+ //
+ // * A "Stmt *" for the condition.
+ // Always present. This is in fact an "Expr *".
+ //
+ // * A "Stmt *" for the body.
+ // Always present.
+ enum { InitOffset = 0, BodyOffsetFromCond = 1 };
+ enum { NumMandatoryStmtPtr = 2 };
+
+ unsigned numTrailingObjects(OverloadToken<Stmt *>) const {
+ return NumMandatoryStmtPtr + hasInitStorage() + hasVarStorage();
+ }
+
+ unsigned initOffset() const { return InitOffset; }
+ unsigned varOffset() const { return InitOffset + hasInitStorage(); }
+ unsigned condOffset() const {
+ return InitOffset + hasInitStorage() + hasVarStorage();
+ }
+ unsigned bodyOffset() const { return condOffset() + BodyOffsetFromCond; }
+
+ /// Build a switch statement.
+ SwitchStmt(const ASTContext &Ctx, Stmt *Init, VarDecl *Var, Expr *Cond);
- // This points to a linked list of case and default statements and, if the
- // SwitchStmt is a switch on an enum value, records whether all the enum
- // values were covered by CaseStmts. The coverage information value is meant
- // to be a hint for possible clients.
- llvm::PointerIntPair<SwitchCase *, 1, bool> FirstCase;
+ /// Build a empty switch statement.
+ explicit SwitchStmt(EmptyShell Empty, bool HasInit, bool HasVar);
public:
- SwitchStmt(const ASTContext &C, Stmt *Init, VarDecl *Var, Expr *cond);
+ /// Create a switch statement.
+ static SwitchStmt *Create(const ASTContext &Ctx, Stmt *Init, VarDecl *Var,
+ Expr *Cond);
- /// Build a empty switch statement.
- explicit SwitchStmt(EmptyShell Empty) : Stmt(SwitchStmtClass, Empty) {}
+ /// Create an empty switch statement optionally with storage for
+ /// an init expression and a condition variable.
+ static SwitchStmt *CreateEmpty(const ASTContext &Ctx, bool HasInit,
+ bool HasVar);
+
+ /// True if this SwitchStmt has storage for an init statement.
+ bool hasInitStorage() const { return SwitchStmtBits.HasInit; }
+
+ /// True if this SwitchStmt has storage for a condition variable.
+ bool hasVarStorage() const { return SwitchStmtBits.HasVar; }
+
+ Expr *getCond() {
+ return reinterpret_cast<Expr *>(getTrailingObjects<Stmt *>()[condOffset()]);
+ }
+
+ const Expr *getCond() const {
+ return reinterpret_cast<Expr *>(getTrailingObjects<Stmt *>()[condOffset()]);
+ }
+
+ void setCond(Expr *Cond) {
+ getTrailingObjects<Stmt *>()[condOffset()] = reinterpret_cast<Stmt *>(Cond);
+ }
+
+ Stmt *getBody() { return getTrailingObjects<Stmt *>()[bodyOffset()]; }
+ const Stmt *getBody() const {
+ return getTrailingObjects<Stmt *>()[bodyOffset()];
+ }
+
+ void setBody(Stmt *Body) {
+ getTrailingObjects<Stmt *>()[bodyOffset()] = Body;
+ }
+
+ Stmt *getInit() {
+ return hasInitStorage() ? getTrailingObjects<Stmt *>()[initOffset()]
+ : nullptr;
+ }
+
+ const Stmt *getInit() const {
+ return hasInitStorage() ? getTrailingObjects<Stmt *>()[initOffset()]
+ : nullptr;
+ }
+
+ void setInit(Stmt *Init) {
+ assert(hasInitStorage() &&
+ "This switch statement has no storage for an init statement!");
+ getTrailingObjects<Stmt *>()[initOffset()] = Init;
+ }
/// Retrieve the variable declared in this "switch" statement, if any.
///
@@ -1060,64 +1772,69 @@ public:
/// // ...
/// }
/// \endcode
- VarDecl *getConditionVariable() const;
- void setConditionVariable(const ASTContext &C, VarDecl *V);
+ VarDecl *getConditionVariable();
+ const VarDecl *getConditionVariable() const {
+ return const_cast<SwitchStmt *>(this)->getConditionVariable();
+ }
+
+ /// Set the condition variable in this switch statement.
+ /// The switch statement must have storage for it.
+ void setConditionVariable(const ASTContext &Ctx, VarDecl *VD);
/// If this SwitchStmt has a condition variable, return the faux DeclStmt
/// associated with the creation of that condition variable.
- const DeclStmt *getConditionVariableDeclStmt() const {
- return reinterpret_cast<DeclStmt*>(SubExprs[VAR]);
+ DeclStmt *getConditionVariableDeclStmt() {
+ return hasVarStorage() ? static_cast<DeclStmt *>(
+ getTrailingObjects<Stmt *>()[varOffset()])
+ : nullptr;
}
- Stmt *getInit() { return SubExprs[INIT]; }
- const Stmt *getInit() const { return SubExprs[INIT]; }
- void setInit(Stmt *S) { SubExprs[INIT] = S; }
- const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);}
- const Stmt *getBody() const { return SubExprs[BODY]; }
- const SwitchCase *getSwitchCaseList() const { return FirstCase.getPointer(); }
-
- Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]);}
- void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt *>(E); }
- Stmt *getBody() { return SubExprs[BODY]; }
- void setBody(Stmt *S) { SubExprs[BODY] = S; }
- SwitchCase *getSwitchCaseList() { return FirstCase.getPointer(); }
+ const DeclStmt *getConditionVariableDeclStmt() const {
+ return hasVarStorage() ? static_cast<DeclStmt *>(
+ getTrailingObjects<Stmt *>()[varOffset()])
+ : nullptr;
+ }
- /// Set the case list for this switch statement.
- void setSwitchCaseList(SwitchCase *SC) { FirstCase.setPointer(SC); }
+ SwitchCase *getSwitchCaseList() { return FirstCase; }
+ const SwitchCase *getSwitchCaseList() const { return FirstCase; }
+ void setSwitchCaseList(SwitchCase *SC) { FirstCase = SC; }
- SourceLocation getSwitchLoc() const { return SwitchLoc; }
- void setSwitchLoc(SourceLocation L) { SwitchLoc = L; }
+ SourceLocation getSwitchLoc() const { return SwitchStmtBits.SwitchLoc; }
+ void setSwitchLoc(SourceLocation L) { SwitchStmtBits.SwitchLoc = L; }
void setBody(Stmt *S, SourceLocation SL) {
- SubExprs[BODY] = S;
- SwitchLoc = SL;
+ setBody(S);
+ setSwitchLoc(SL);
}
void addSwitchCase(SwitchCase *SC) {
- assert(!SC->getNextSwitchCase()
- && "case/default already added to a switch");
- SC->setNextSwitchCase(FirstCase.getPointer());
- FirstCase.setPointer(SC);
+ assert(!SC->getNextSwitchCase() &&
+ "case/default already added to a switch");
+ SC->setNextSwitchCase(FirstCase);
+ FirstCase = SC;
}
/// Set a flag in the SwitchStmt indicating that if the 'switch (X)' is a
/// switch over an enum value then all cases have been explicitly covered.
- void setAllEnumCasesCovered() { FirstCase.setInt(true); }
+ void setAllEnumCasesCovered() { SwitchStmtBits.AllEnumCasesCovered = true; }
/// Returns true if the SwitchStmt is a switch of an enum value and all cases
/// have been explicitly covered.
- bool isAllEnumCasesCovered() const { return FirstCase.getInt(); }
-
- SourceLocation getBeginLoc() const LLVM_READONLY { return SwitchLoc; }
+ bool isAllEnumCasesCovered() const {
+ return SwitchStmtBits.AllEnumCasesCovered;
+ }
+ SourceLocation getBeginLoc() const { return getSwitchLoc(); }
SourceLocation getEndLoc() const LLVM_READONLY {
- return SubExprs[BODY] ? SubExprs[BODY]->getEndLoc()
- : SubExprs[COND]->getEndLoc();
+ return getBody() ? getBody()->getEndLoc()
+ : reinterpret_cast<const Stmt *>(getCond())->getEndLoc();
}
// Iterators
child_range children() {
- return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR);
+ return child_range(getTrailingObjects<Stmt *>(),
+ getTrailingObjects<Stmt *>() +
+ numTrailingObjects(OverloadToken<Stmt *>()));
}
static bool classof(const Stmt *T) {
@@ -1126,17 +1843,75 @@ public:
};
/// WhileStmt - This represents a 'while' stmt.
-class WhileStmt : public Stmt {
- SourceLocation WhileLoc;
- enum { VAR, COND, BODY, END_EXPR };
- Stmt* SubExprs[END_EXPR];
+class WhileStmt final : public Stmt,
+ private llvm::TrailingObjects<WhileStmt, Stmt *> {
+ friend TrailingObjects;
-public:
- WhileStmt(const ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body,
+ // WhileStmt is followed by several trailing objects,
+ // some of which optional. Note that it would be more
+ // convenient to put the optional trailing object at the end
+ // but this would affect children().
+ // The trailing objects are in order:
+ //
+ // * A "Stmt *" for the condition variable.
+ // Present if and only if hasVarStorage(). This is in fact a "DeclStmt *".
+ //
+ // * A "Stmt *" for the condition.
+ // Always present. This is in fact an "Expr *".
+ //
+ // * A "Stmt *" for the body.
+ // Always present.
+ //
+ enum { VarOffset = 0, BodyOffsetFromCond = 1 };
+ enum { NumMandatoryStmtPtr = 2 };
+
+ unsigned varOffset() const { return VarOffset; }
+ unsigned condOffset() const { return VarOffset + hasVarStorage(); }
+ unsigned bodyOffset() const { return condOffset() + BodyOffsetFromCond; }
+
+ unsigned numTrailingObjects(OverloadToken<Stmt *>) const {
+ return NumMandatoryStmtPtr + hasVarStorage();
+ }
+
+ /// Build a while statement.
+ WhileStmt(const ASTContext &Ctx, VarDecl *Var, Expr *Cond, Stmt *Body,
SourceLocation WL);
/// Build an empty while statement.
- explicit WhileStmt(EmptyShell Empty) : Stmt(WhileStmtClass, Empty) {}
+ explicit WhileStmt(EmptyShell Empty, bool HasVar);
+
+public:
+ /// Create a while statement.
+ static WhileStmt *Create(const ASTContext &Ctx, VarDecl *Var, Expr *Cond,
+ Stmt *Body, SourceLocation WL);
+
+ /// Create an empty while statement optionally with storage for
+ /// a condition variable.
+ static WhileStmt *CreateEmpty(const ASTContext &Ctx, bool HasVar);
+
+ /// True if this WhileStmt has storage for a condition variable.
+ bool hasVarStorage() const { return WhileStmtBits.HasVar; }
+
+ Expr *getCond() {
+ return reinterpret_cast<Expr *>(getTrailingObjects<Stmt *>()[condOffset()]);
+ }
+
+ const Expr *getCond() const {
+ return reinterpret_cast<Expr *>(getTrailingObjects<Stmt *>()[condOffset()]);
+ }
+
+ void setCond(Expr *Cond) {
+ getTrailingObjects<Stmt *>()[condOffset()] = reinterpret_cast<Stmt *>(Cond);
+ }
+
+ Stmt *getBody() { return getTrailingObjects<Stmt *>()[bodyOffset()]; }
+ const Stmt *getBody() const {
+ return getTrailingObjects<Stmt *>()[bodyOffset()];
+ }
+
+ void setBody(Stmt *Body) {
+ getTrailingObjects<Stmt *>()[bodyOffset()] = Body;
+ }
/// Retrieve the variable declared in this "while" statement, if any.
///
@@ -1146,29 +1921,35 @@ public:
/// // ...
/// }
/// \endcode
- VarDecl *getConditionVariable() const;
- void setConditionVariable(const ASTContext &C, VarDecl *V);
+ VarDecl *getConditionVariable();
+ const VarDecl *getConditionVariable() const {
+ return const_cast<WhileStmt *>(this)->getConditionVariable();
+ }
+
+ /// Set the condition variable of this while statement.
+ /// The while statement must have storage for it.
+ void setConditionVariable(const ASTContext &Ctx, VarDecl *V);
/// If this WhileStmt has a condition variable, return the faux DeclStmt
/// associated with the creation of that condition variable.
- const DeclStmt *getConditionVariableDeclStmt() const {
- return reinterpret_cast<DeclStmt*>(SubExprs[VAR]);
+ DeclStmt *getConditionVariableDeclStmt() {
+ return hasVarStorage() ? static_cast<DeclStmt *>(
+ getTrailingObjects<Stmt *>()[varOffset()])
+ : nullptr;
}
- Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); }
- const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);}
- void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(E); }
- Stmt *getBody() { return SubExprs[BODY]; }
- const Stmt *getBody() const { return SubExprs[BODY]; }
- void setBody(Stmt *S) { SubExprs[BODY] = S; }
-
- SourceLocation getWhileLoc() const { return WhileLoc; }
- void setWhileLoc(SourceLocation L) { WhileLoc = L; }
+ const DeclStmt *getConditionVariableDeclStmt() const {
+ return hasVarStorage() ? static_cast<DeclStmt *>(
+ getTrailingObjects<Stmt *>()[varOffset()])
+ : nullptr;
+ }
- SourceLocation getBeginLoc() const LLVM_READONLY { return WhileLoc; }
+ SourceLocation getWhileLoc() const { return WhileStmtBits.WhileLoc; }
+ void setWhileLoc(SourceLocation L) { WhileStmtBits.WhileLoc = L; }
+ SourceLocation getBeginLoc() const { return getWhileLoc(); }
SourceLocation getEndLoc() const LLVM_READONLY {
- return SubExprs[BODY]->getEndLoc();
+ return getBody()->getEndLoc();
}
static bool classof(const Stmt *T) {
@@ -1177,46 +1958,51 @@ public:
// Iterators
child_range children() {
- return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR);
+ return child_range(getTrailingObjects<Stmt *>(),
+ getTrailingObjects<Stmt *>() +
+ numTrailingObjects(OverloadToken<Stmt *>()));
}
};
/// DoStmt - This represents a 'do/while' stmt.
class DoStmt : public Stmt {
- SourceLocation DoLoc;
enum { BODY, COND, END_EXPR };
- Stmt* SubExprs[END_EXPR];
+ Stmt *SubExprs[END_EXPR];
SourceLocation WhileLoc;
- SourceLocation RParenLoc; // Location of final ')' in do stmt condition.
+ SourceLocation RParenLoc; // Location of final ')' in do stmt condition.
public:
- DoStmt(Stmt *body, Expr *cond, SourceLocation DL, SourceLocation WL,
+ DoStmt(Stmt *Body, Expr *Cond, SourceLocation DL, SourceLocation WL,
SourceLocation RP)
- : Stmt(DoStmtClass), DoLoc(DL), WhileLoc(WL), RParenLoc(RP) {
- SubExprs[COND] = reinterpret_cast<Stmt*>(cond);
- SubExprs[BODY] = body;
+ : Stmt(DoStmtClass), WhileLoc(WL), RParenLoc(RP) {
+ setCond(Cond);
+ setBody(Body);
+ setDoLoc(DL);
}
/// Build an empty do-while statement.
explicit DoStmt(EmptyShell Empty) : Stmt(DoStmtClass, Empty) {}
- Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); }
- const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);}
- void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(E); }
+ Expr *getCond() { return reinterpret_cast<Expr *>(SubExprs[COND]); }
+ const Expr *getCond() const {
+ return reinterpret_cast<Expr *>(SubExprs[COND]);
+ }
+
+ void setCond(Expr *Cond) { SubExprs[COND] = reinterpret_cast<Stmt *>(Cond); }
+
Stmt *getBody() { return SubExprs[BODY]; }
const Stmt *getBody() const { return SubExprs[BODY]; }
- void setBody(Stmt *S) { SubExprs[BODY] = S; }
+ void setBody(Stmt *Body) { SubExprs[BODY] = Body; }
- SourceLocation getDoLoc() const { return DoLoc; }
- void setDoLoc(SourceLocation L) { DoLoc = L; }
+ SourceLocation getDoLoc() const { return DoStmtBits.DoLoc; }
+ void setDoLoc(SourceLocation L) { DoStmtBits.DoLoc = L; }
SourceLocation getWhileLoc() const { return WhileLoc; }
void setWhileLoc(SourceLocation L) { WhileLoc = L; }
-
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
- SourceLocation getBeginLoc() const LLVM_READONLY { return DoLoc; }
- SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; }
+ SourceLocation getBeginLoc() const { return getDoLoc(); }
+ SourceLocation getEndLoc() const { return getRParenLoc(); }
static bool classof(const Stmt *T) {
return T->getStmtClass() == DoStmtClass;
@@ -1224,7 +2010,7 @@ public:
// Iterators
child_range children() {
- return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR);
+ return child_range(&SubExprs[0], &SubExprs[0] + END_EXPR);
}
};
@@ -1232,7 +2018,6 @@ public:
/// the init/cond/inc parts of the ForStmt will be null if they were not
/// specified in the source.
class ForStmt : public Stmt {
- SourceLocation ForLoc;
enum { INIT, CONDVAR, COND, INC, BODY, END_EXPR };
Stmt* SubExprs[END_EXPR]; // SubExprs[INIT] is an expression or declstmt.
SourceLocation LParenLoc, RParenLoc;
@@ -1278,18 +2063,15 @@ public:
void setInc(Expr *E) { SubExprs[INC] = reinterpret_cast<Stmt*>(E); }
void setBody(Stmt *S) { SubExprs[BODY] = S; }
- SourceLocation getForLoc() const { return ForLoc; }
- void setForLoc(SourceLocation L) { ForLoc = L; }
+ SourceLocation getForLoc() const { return ForStmtBits.ForLoc; }
+ void setForLoc(SourceLocation L) { ForStmtBits.ForLoc = L; }
SourceLocation getLParenLoc() const { return LParenLoc; }
void setLParenLoc(SourceLocation L) { LParenLoc = L; }
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
- SourceLocation getBeginLoc() const LLVM_READONLY { return ForLoc; }
-
- SourceLocation getEndLoc() const LLVM_READONLY {
- return SubExprs[BODY]->getEndLoc();
- }
+ SourceLocation getBeginLoc() const { return getForLoc(); }
+ SourceLocation getEndLoc() const { return getBody()->getEndLoc(); }
static bool classof(const Stmt *T) {
return T->getStmtClass() == ForStmtClass;
@@ -1304,12 +2086,13 @@ public:
/// GotoStmt - This represents a direct goto.
class GotoStmt : public Stmt {
LabelDecl *Label;
- SourceLocation GotoLoc;
SourceLocation LabelLoc;
public:
GotoStmt(LabelDecl *label, SourceLocation GL, SourceLocation LL)
- : Stmt(GotoStmtClass), Label(label), GotoLoc(GL), LabelLoc(LL) {}
+ : Stmt(GotoStmtClass), Label(label), LabelLoc(LL) {
+ setGotoLoc(GL);
+ }
/// Build an empty goto statement.
explicit GotoStmt(EmptyShell Empty) : Stmt(GotoStmtClass, Empty) {}
@@ -1317,13 +2100,13 @@ public:
LabelDecl *getLabel() const { return Label; }
void setLabel(LabelDecl *D) { Label = D; }
- SourceLocation getGotoLoc() const { return GotoLoc; }
- void setGotoLoc(SourceLocation L) { GotoLoc = L; }
+ SourceLocation getGotoLoc() const { return GotoStmtBits.GotoLoc; }
+ void setGotoLoc(SourceLocation L) { GotoStmtBits.GotoLoc = L; }
SourceLocation getLabelLoc() const { return LabelLoc; }
void setLabelLoc(SourceLocation L) { LabelLoc = L; }
- SourceLocation getBeginLoc() const LLVM_READONLY { return GotoLoc; }
- SourceLocation getEndLoc() const LLVM_READONLY { return LabelLoc; }
+ SourceLocation getBeginLoc() const { return getGotoLoc(); }
+ SourceLocation getEndLoc() const { return getLabelLoc(); }
static bool classof(const Stmt *T) {
return T->getStmtClass() == GotoStmtClass;
@@ -1337,37 +2120,39 @@ public:
/// IndirectGotoStmt - This represents an indirect goto.
class IndirectGotoStmt : public Stmt {
- SourceLocation GotoLoc;
SourceLocation StarLoc;
Stmt *Target;
public:
- IndirectGotoStmt(SourceLocation gotoLoc, SourceLocation starLoc,
- Expr *target)
- : Stmt(IndirectGotoStmtClass), GotoLoc(gotoLoc), StarLoc(starLoc),
- Target((Stmt*)target) {}
+ IndirectGotoStmt(SourceLocation gotoLoc, SourceLocation starLoc, Expr *target)
+ : Stmt(IndirectGotoStmtClass), StarLoc(starLoc) {
+ setTarget(target);
+ setGotoLoc(gotoLoc);
+ }
/// Build an empty indirect goto statement.
explicit IndirectGotoStmt(EmptyShell Empty)
: Stmt(IndirectGotoStmtClass, Empty) {}
- void setGotoLoc(SourceLocation L) { GotoLoc = L; }
- SourceLocation getGotoLoc() const { return GotoLoc; }
+ void setGotoLoc(SourceLocation L) { GotoStmtBits.GotoLoc = L; }
+ SourceLocation getGotoLoc() const { return GotoStmtBits.GotoLoc; }
void setStarLoc(SourceLocation L) { StarLoc = L; }
SourceLocation getStarLoc() const { return StarLoc; }
- Expr *getTarget() { return reinterpret_cast<Expr*>(Target); }
- const Expr *getTarget() const {return reinterpret_cast<const Expr*>(Target);}
- void setTarget(Expr *E) { Target = reinterpret_cast<Stmt*>(E); }
+ Expr *getTarget() { return reinterpret_cast<Expr *>(Target); }
+ const Expr *getTarget() const {
+ return reinterpret_cast<const Expr *>(Target);
+ }
+ void setTarget(Expr *E) { Target = reinterpret_cast<Stmt *>(E); }
/// getConstantTarget - Returns the fixed target of this indirect
/// goto, if one exists.
LabelDecl *getConstantTarget();
const LabelDecl *getConstantTarget() const {
- return const_cast<IndirectGotoStmt*>(this)->getConstantTarget();
+ return const_cast<IndirectGotoStmt *>(this)->getConstantTarget();
}
- SourceLocation getBeginLoc() const LLVM_READONLY { return GotoLoc; }
+ SourceLocation getBeginLoc() const { return getGotoLoc(); }
SourceLocation getEndLoc() const LLVM_READONLY { return Target->getEndLoc(); }
static bool classof(const Stmt *T) {
@@ -1375,24 +2160,24 @@ public:
}
// Iterators
- child_range children() { return child_range(&Target, &Target+1); }
+ child_range children() { return child_range(&Target, &Target + 1); }
};
/// ContinueStmt - This represents a continue.
class ContinueStmt : public Stmt {
- SourceLocation ContinueLoc;
-
public:
- ContinueStmt(SourceLocation CL) : Stmt(ContinueStmtClass), ContinueLoc(CL) {}
+ ContinueStmt(SourceLocation CL) : Stmt(ContinueStmtClass) {
+ setContinueLoc(CL);
+ }
/// Build an empty continue statement.
explicit ContinueStmt(EmptyShell Empty) : Stmt(ContinueStmtClass, Empty) {}
- SourceLocation getContinueLoc() const { return ContinueLoc; }
- void setContinueLoc(SourceLocation L) { ContinueLoc = L; }
+ SourceLocation getContinueLoc() const { return ContinueStmtBits.ContinueLoc; }
+ void setContinueLoc(SourceLocation L) { ContinueStmtBits.ContinueLoc = L; }
- SourceLocation getBeginLoc() const LLVM_READONLY { return ContinueLoc; }
- SourceLocation getEndLoc() const LLVM_READONLY { return ContinueLoc; }
+ SourceLocation getBeginLoc() const { return getContinueLoc(); }
+ SourceLocation getEndLoc() const { return getContinueLoc(); }
static bool classof(const Stmt *T) {
return T->getStmtClass() == ContinueStmtClass;
@@ -1406,22 +2191,19 @@ public:
/// BreakStmt - This represents a break.
class BreakStmt : public Stmt {
- SourceLocation BreakLoc;
-
public:
- BreakStmt(SourceLocation BL) : Stmt(BreakStmtClass), BreakLoc(BL) {
- static_assert(sizeof(BreakStmt) == 2 * sizeof(SourceLocation),
- "BreakStmt too large");
+ BreakStmt(SourceLocation BL) : Stmt(BreakStmtClass) {
+ setBreakLoc(BL);
}
/// Build an empty break statement.
explicit BreakStmt(EmptyShell Empty) : Stmt(BreakStmtClass, Empty) {}
- SourceLocation getBreakLoc() const { return BreakLoc; }
- void setBreakLoc(SourceLocation L) { BreakLoc = L; }
+ SourceLocation getBreakLoc() const { return BreakStmtBits.BreakLoc; }
+ void setBreakLoc(SourceLocation L) { BreakStmtBits.BreakLoc = L; }
- SourceLocation getBeginLoc() const LLVM_READONLY { return BreakLoc; }
- SourceLocation getEndLoc() const LLVM_READONLY { return BreakLoc; }
+ SourceLocation getBeginLoc() const { return getBreakLoc(); }
+ SourceLocation getEndLoc() const { return getBreakLoc(); }
static bool classof(const Stmt *T) {
return T->getStmtClass() == BreakStmtClass;
@@ -1441,40 +2223,68 @@ public:
/// return a value, and it allows returning a value in functions declared to
/// return void. We explicitly model this in the AST, which means you can't
/// depend on the return type of the function and the presence of an argument.
-class ReturnStmt : public Stmt {
- SourceLocation RetLoc;
+class ReturnStmt final
+ : public Stmt,
+ private llvm::TrailingObjects<ReturnStmt, const VarDecl *> {
+ friend TrailingObjects;
+
+ /// The return expression.
Stmt *RetExpr;
- const VarDecl *NRVOCandidate;
-public:
- explicit ReturnStmt(SourceLocation RL) : ReturnStmt(RL, nullptr, nullptr) {}
+ // ReturnStmt is followed optionally by a trailing "const VarDecl *"
+ // for the NRVO candidate. Present if and only if hasNRVOCandidate().
- ReturnStmt(SourceLocation RL, Expr *E, const VarDecl *NRVOCandidate)
- : Stmt(ReturnStmtClass), RetLoc(RL), RetExpr((Stmt *)E),
- NRVOCandidate(NRVOCandidate) {}
+ /// True if this ReturnStmt has storage for an NRVO candidate.
+ bool hasNRVOCandidate() const { return ReturnStmtBits.HasNRVOCandidate; }
- /// Build an empty return expression.
- explicit ReturnStmt(EmptyShell Empty) : Stmt(ReturnStmtClass, Empty) {}
+ unsigned numTrailingObjects(OverloadToken<const VarDecl *>) const {
+ return hasNRVOCandidate();
+ }
- const Expr *getRetValue() const;
- Expr *getRetValue();
- void setRetValue(Expr *E) { RetExpr = reinterpret_cast<Stmt*>(E); }
+ /// Build a return statement.
+ ReturnStmt(SourceLocation RL, Expr *E, const VarDecl *NRVOCandidate);
- SourceLocation getReturnLoc() const { return RetLoc; }
- void setReturnLoc(SourceLocation L) { RetLoc = L; }
+ /// Build an empty return statement.
+ explicit ReturnStmt(EmptyShell Empty, bool HasNRVOCandidate);
+
+public:
+ /// Create a return statement.
+ static ReturnStmt *Create(const ASTContext &Ctx, SourceLocation RL, Expr *E,
+ const VarDecl *NRVOCandidate);
+
+ /// Create an empty return statement, optionally with
+ /// storage for an NRVO candidate.
+ static ReturnStmt *CreateEmpty(const ASTContext &Ctx, bool HasNRVOCandidate);
+
+ Expr *getRetValue() { return reinterpret_cast<Expr *>(RetExpr); }
+ const Expr *getRetValue() const { return reinterpret_cast<Expr *>(RetExpr); }
+ void setRetValue(Expr *E) { RetExpr = reinterpret_cast<Stmt *>(E); }
/// Retrieve the variable that might be used for the named return
/// value optimization.
///
/// The optimization itself can only be performed if the variable is
/// also marked as an NRVO object.
- const VarDecl *getNRVOCandidate() const { return NRVOCandidate; }
- void setNRVOCandidate(const VarDecl *Var) { NRVOCandidate = Var; }
+ const VarDecl *getNRVOCandidate() const {
+ return hasNRVOCandidate() ? *getTrailingObjects<const VarDecl *>()
+ : nullptr;
+ }
+
+ /// Set the variable that might be used for the named return value
+ /// optimization. The return statement must have storage for it,
+ /// which is the case if and only if hasNRVOCandidate() is true.
+ void setNRVOCandidate(const VarDecl *Var) {
+ assert(hasNRVOCandidate() &&
+ "This return statement has no storage for an NRVO candidate!");
+ *getTrailingObjects<const VarDecl *>() = Var;
+ }
- SourceLocation getBeginLoc() const LLVM_READONLY { return RetLoc; }
+ SourceLocation getReturnLoc() const { return ReturnStmtBits.RetLoc; }
+ void setReturnLoc(SourceLocation L) { ReturnStmtBits.RetLoc = L; }
+ SourceLocation getBeginLoc() const { return getReturnLoc(); }
SourceLocation getEndLoc() const LLVM_READONLY {
- return RetExpr ? RetExpr->getEndLoc() : RetLoc;
+ return RetExpr ? RetExpr->getEndLoc() : getReturnLoc();
}
static bool classof(const Stmt *T) {
@@ -1483,7 +2293,8 @@ public:
// Iterators
child_range children() {
- if (RetExpr) return child_range(&RetExpr, &RetExpr+1);
+ if (RetExpr)
+ return child_range(&RetExpr, &RetExpr + 1);
return child_range(child_iterator(), child_iterator());
}
};
diff --git a/include/clang/AST/StmtDataCollectors.td b/include/clang/AST/StmtDataCollectors.td
index e1929fe30b..90ca080273 100644
--- a/include/clang/AST/StmtDataCollectors.td
+++ b/include/clang/AST/StmtDataCollectors.td
@@ -27,7 +27,7 @@ class ExpressionTraitExpr {
}
class PredefinedExpr {
code Code = [{
- addData(S->getIdentType());
+ addData(S->getIdentKind());
}];
}
class TypeTraitExpr {
diff --git a/include/clang/AST/StmtOpenMP.h b/include/clang/AST/StmtOpenMP.h
index 170c78cf6b..d1eedd62b3 100644
--- a/include/clang/AST/StmtOpenMP.h
+++ b/include/clang/AST/StmtOpenMP.h
@@ -392,9 +392,11 @@ class OMPLoopDirective : public OMPExecutableDirective {
CombinedConditionOffset = 25,
CombinedNextLowerBoundOffset = 26,
CombinedNextUpperBoundOffset = 27,
+ CombinedDistConditionOffset = 28,
+ CombinedParForInDistConditionOffset = 29,
// Offset to the end (and start of the following counters/updates/finals
// arrays) for combined distribute loop directives.
- CombinedDistributeEnd = 28,
+ CombinedDistributeEnd = 30,
};
/// Get the counters storage.
@@ -605,6 +607,17 @@ protected:
"expected loop bound sharing directive");
*std::next(child_begin(), CombinedNextUpperBoundOffset) = CombNUB;
}
+ void setCombinedDistCond(Expr *CombDistCond) {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound distribute sharing directive");
+ *std::next(child_begin(), CombinedDistConditionOffset) = CombDistCond;
+ }
+ void setCombinedParForInDistCond(Expr *CombParForInDistCond) {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound distribute sharing directive");
+ *std::next(child_begin(),
+ CombinedParForInDistConditionOffset) = CombParForInDistCond;
+ }
void setCounters(ArrayRef<Expr *> A);
void setPrivateCounters(ArrayRef<Expr *> A);
void setInits(ArrayRef<Expr *> A);
@@ -637,6 +650,13 @@ public:
/// Update of UpperBound for statically scheduled omp loops for
/// outer loop in combined constructs (e.g. 'distribute parallel for')
Expr *NUB;
+ /// Distribute Loop condition used when composing 'omp distribute'
+ /// with 'omp for' in a same construct when schedule is chunked.
+ Expr *DistCond;
+ /// 'omp parallel for' loop condition used when composed with
+ /// 'omp distribute' in the same construct and when schedule is
+ /// chunked and the chunk size is 1.
+ Expr *ParForInDistCond;
};
/// The expressions built for the OpenMP loop CodeGen for the
@@ -754,6 +774,8 @@ public:
DistCombinedFields.Cond = nullptr;
DistCombinedFields.NLB = nullptr;
DistCombinedFields.NUB = nullptr;
+ DistCombinedFields.DistCond = nullptr;
+ DistCombinedFields.ParForInDistCond = nullptr;
}
};
@@ -922,6 +944,18 @@ public:
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
*std::next(child_begin(), CombinedNextUpperBoundOffset)));
}
+ Expr *getCombinedDistCond() const {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound distribute sharing directive");
+ return const_cast<Expr *>(reinterpret_cast<const Expr *>(
+ *std::next(child_begin(), CombinedDistConditionOffset)));
+ }
+ Expr *getCombinedParForInDistCond() const {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound distribute sharing directive");
+ return const_cast<Expr *>(reinterpret_cast<const Expr *>(
+ *std::next(child_begin(), CombinedParForInDistConditionOffset)));
+ }
const Stmt *getBody() const {
// This relies on the loop form is already checked by Sema.
const Stmt *Body =
diff --git a/include/clang/AST/StmtVisitor.h b/include/clang/AST/StmtVisitor.h
index bbfffe8186..ea40e04973 100644
--- a/include/clang/AST/StmtVisitor.h
+++ b/include/clang/AST/StmtVisitor.h
@@ -22,15 +22,12 @@
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtOpenMP.h"
#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include <utility>
namespace clang {
-
-template <typename T> struct make_ptr { using type = T *; };
-template <typename T> struct make_const_ptr { using type = const T *; };
-
/// StmtVisitorBase - This class implements a simple visitor for Stmt
/// subclasses. Since Expr derives from Stmt, this also includes support for
/// visiting Exprs.
@@ -182,18 +179,19 @@ public:
///
/// This class does not preserve constness of Stmt pointers (see also
/// ConstStmtVisitor).
-template<typename ImplClass, typename RetTy=void, typename... ParamTys>
+template <typename ImplClass, typename RetTy = void, typename... ParamTys>
class StmtVisitor
- : public StmtVisitorBase<make_ptr, ImplClass, RetTy, ParamTys...> {};
+ : public StmtVisitorBase<std::add_pointer, ImplClass, RetTy, ParamTys...> {
+};
/// ConstStmtVisitor - This class implements a simple visitor for Stmt
/// subclasses. Since Expr derives from Stmt, this also includes support for
/// visiting Exprs.
///
/// This class preserves constness of Stmt pointers (see also StmtVisitor).
-template<typename ImplClass, typename RetTy=void, typename... ParamTys>
-class ConstStmtVisitor
- : public StmtVisitorBase<make_const_ptr, ImplClass, RetTy, ParamTys...> {};
+template <typename ImplClass, typename RetTy = void, typename... ParamTys>
+class ConstStmtVisitor : public StmtVisitorBase<llvm::make_const_ptr, ImplClass,
+ RetTy, ParamTys...> {};
} // namespace clang
diff --git a/include/clang/AST/TextNodeDumper.h b/include/clang/AST/TextNodeDumper.h
new file mode 100644
index 0000000000..5a1dbb40fa
--- /dev/null
+++ b/include/clang/AST/TextNodeDumper.h
@@ -0,0 +1,87 @@
+//===--- TextNodeDumper.h - Printing of AST nodes -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements AST dumping of components of individual AST nodes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_TEXTNODEDUMPER_H
+#define LLVM_CLANG_AST_TEXTNODEDUMPER_H
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTDumperUtils.h"
+#include "clang/AST/CommentCommandTraits.h"
+#include "clang/AST/CommentVisitor.h"
+#include "clang/AST/ExprCXX.h"
+
+namespace clang {
+
+class TextNodeDumper
+ : public comments::ConstCommentVisitor<TextNodeDumper, void,
+ const comments::FullComment *> {
+ raw_ostream &OS;
+ const bool ShowColors;
+
+ /// Keep track of the last location we print out so that we can
+ /// print out deltas from then on out.
+ const char *LastLocFilename = "";
+ unsigned LastLocLine = ~0U;
+
+ const SourceManager *SM;
+
+ /// The policy to use for printing; can be defaulted.
+ PrintingPolicy PrintPolicy;
+
+ const comments::CommandTraits *Traits;
+
+ const char *getCommandName(unsigned CommandID);
+
+public:
+ TextNodeDumper(raw_ostream &OS, bool ShowColors, const SourceManager *SM,
+ const PrintingPolicy &PrintPolicy,
+ const comments::CommandTraits *Traits);
+
+ void Visit(const comments::Comment *C, const comments::FullComment *FC);
+
+ void dumpPointer(const void *Ptr);
+ void dumpLocation(SourceLocation Loc);
+ void dumpSourceRange(SourceRange R);
+ void dumpBareType(QualType T, bool Desugar = true);
+ void dumpType(QualType T);
+ void dumpBareDeclRef(const Decl *D);
+ void dumpName(const NamedDecl *ND);
+ void dumpAccessSpecifier(AccessSpecifier AS);
+ void dumpCXXTemporary(const CXXTemporary *Temporary);
+
+ void visitTextComment(const comments::TextComment *C,
+ const comments::FullComment *);
+ void visitInlineCommandComment(const comments::InlineCommandComment *C,
+ const comments::FullComment *);
+ void visitHTMLStartTagComment(const comments::HTMLStartTagComment *C,
+ const comments::FullComment *);
+ void visitHTMLEndTagComment(const comments::HTMLEndTagComment *C,
+ const comments::FullComment *);
+ void visitBlockCommandComment(const comments::BlockCommandComment *C,
+ const comments::FullComment *);
+ void visitParamCommandComment(const comments::ParamCommandComment *C,
+ const comments::FullComment *FC);
+ void visitTParamCommandComment(const comments::TParamCommandComment *C,
+ const comments::FullComment *FC);
+ void visitVerbatimBlockComment(const comments::VerbatimBlockComment *C,
+ const comments::FullComment *);
+ void
+ visitVerbatimBlockLineComment(const comments::VerbatimBlockLineComment *C,
+ const comments::FullComment *);
+ void visitVerbatimLineComment(const comments::VerbatimLineComment *C,
+ const comments::FullComment *);
+};
+
+} // namespace clang
+
+#endif // LLVM_CLANG_AST_TEXTNODEDUMPER_H
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 28cfa00789..5b69570aab 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -256,28 +256,24 @@ public:
}
bool hasConst() const { return Mask & Const; }
- void setConst(bool flag) {
- Mask = (Mask & ~Const) | (flag ? Const : 0);
- }
+ bool hasOnlyConst() const { return Mask == Const; }
void removeConst() { Mask &= ~Const; }
void addConst() { Mask |= Const; }
bool hasVolatile() const { return Mask & Volatile; }
- void setVolatile(bool flag) {
- Mask = (Mask & ~Volatile) | (flag ? Volatile : 0);
- }
+ bool hasOnlyVolatile() const { return Mask == Volatile; }
void removeVolatile() { Mask &= ~Volatile; }
void addVolatile() { Mask |= Volatile; }
bool hasRestrict() const { return Mask & Restrict; }
- void setRestrict(bool flag) {
- Mask = (Mask & ~Restrict) | (flag ? Restrict : 0);
- }
+ bool hasOnlyRestrict() const { return Mask == Restrict; }
void removeRestrict() { Mask &= ~Restrict; }
void addRestrict() { Mask |= Restrict; }
bool hasCVRQualifiers() const { return getCVRQualifiers(); }
unsigned getCVRQualifiers() const { return Mask & CVRMask; }
+ unsigned getCVRUQualifiers() const { return Mask & (CVRMask | UMask); }
+
void setCVRQualifiers(unsigned mask) {
assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits");
Mask = (Mask & ~CVRMask) | mask;
@@ -1502,6 +1498,9 @@ protected:
unsigned Kind : 8;
};
+ /// FunctionTypeBitfields store various bits belonging to FunctionProtoType.
+ /// Only common bits are stored here. Additional uncommon bits are stored
+ /// in a trailing object after FunctionProtoType.
class FunctionTypeBitfields {
friend class FunctionProtoType;
friend class FunctionType;
@@ -1512,18 +1511,38 @@ protected:
/// regparm and the calling convention.
unsigned ExtInfo : 12;
+ /// The ref-qualifier associated with a \c FunctionProtoType.
+ ///
+ /// This is a value of type \c RefQualifierKind.
+ unsigned RefQualifier : 2;
+
/// Used only by FunctionProtoType, put here to pack with the
/// other bitfields.
/// The qualifiers are part of FunctionProtoType because...
///
/// C++ 8.3.5p4: The return type, the parameter type list and the
/// cv-qualifier-seq, [...], are part of the function type.
- unsigned TypeQuals : 4;
+ unsigned FastTypeQuals : Qualifiers::FastWidth;
+ /// Whether this function has extended Qualifiers.
+ unsigned HasExtQuals : 1;
- /// The ref-qualifier associated with a \c FunctionProtoType.
- ///
- /// This is a value of type \c RefQualifierKind.
- unsigned RefQualifier : 2;
+ /// The number of parameters this function has, not counting '...'.
+ /// According to [implimits] 8 bits should be enough here but this is
+ /// somewhat easy to exceed with metaprogramming and so we would like to
+ /// keep NumParams as wide as reasonably possible.
+ unsigned NumParams : 16;
+
+ /// The type of exception specification this function has.
+ unsigned ExceptionSpecType : 4;
+
+ /// Whether this function has extended parameter information.
+ unsigned HasExtParameterInfos : 1;
+
+ /// Whether the function is variadic.
+ unsigned Variadic : 1;
+
+ /// Whether this function has a trailing return type.
+ unsigned HasTrailingReturn : 1;
};
class ObjCObjectTypeBitfields {
@@ -2025,6 +2044,13 @@ public:
bool isQueueT() const; // OpenCL queue_t
bool isReserveIDT() const; // OpenCL reserve_id_t
+#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
+ bool is##Id##Type() const;
+#include "clang/Basic/OpenCLExtensionTypes.def"
+ // Type defined in cl_intel_device_side_avc_motion_estimation OpenCL extension
+ bool isOCLIntelSubgroupAVCType() const;
+ bool isOCLExtOpaqueType() const; // Any OpenCL extension type
+
bool isPipeType() const; // OpenCL pipe type
bool isOpenCLSpecificType() const; // Any OpenCL specific type
@@ -2045,7 +2071,8 @@ public:
STK_Integral,
STK_Floating,
STK_IntegralComplex,
- STK_FloatingComplex
+ STK_FloatingComplex,
+ STK_FixedPoint
};
/// Given that this is a scalar type, classify it.
@@ -2371,6 +2398,9 @@ public:
// OpenCL image types
#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) Id,
#include "clang/Basic/OpenCLImageTypes.def"
+// OpenCL extension types
+#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) Id,
+#include "clang/Basic/OpenCLExtensionTypes.def"
// All other builtin types
#define BUILTIN_TYPE(Id, SingletonId) Id,
#define LAST_BUILTIN_TYPE(Id) LastKind = Id
@@ -3331,6 +3361,92 @@ class FunctionType : public Type {
QualType ResultType;
public:
+ /// Interesting information about a specific parameter that can't simply
+ /// be reflected in parameter's type. This is only used by FunctionProtoType
+ /// but is in FunctionType to make this class available during the
+ /// specification of the bases of FunctionProtoType.
+ ///
+ /// It makes sense to model language features this way when there's some
+ /// sort of parameter-specific override (such as an attribute) that
+ /// affects how the function is called. For example, the ARC ns_consumed
+ /// attribute changes whether a parameter is passed at +0 (the default)
+ /// or +1 (ns_consumed). This must be reflected in the function type,
+ /// but isn't really a change to the parameter type.
+ ///
+ /// One serious disadvantage of modelling language features this way is
+ /// that they generally do not work with language features that attempt
+ /// to destructure types. For example, template argument deduction will
+ /// not be able to match a parameter declared as
+ /// T (*)(U)
+ /// against an argument of type
+ /// void (*)(__attribute__((ns_consumed)) id)
+ /// because the substitution of T=void, U=id into the former will
+ /// not produce the latter.
+ class ExtParameterInfo {
+ enum {
+ ABIMask = 0x0F,
+ IsConsumed = 0x10,
+ HasPassObjSize = 0x20,
+ IsNoEscape = 0x40,
+ };
+ unsigned char Data = 0;
+
+ public:
+ ExtParameterInfo() = default;
+
+ /// Return the ABI treatment of this parameter.
+ ParameterABI getABI() const { return ParameterABI(Data & ABIMask); }
+ ExtParameterInfo withABI(ParameterABI kind) const {
+ ExtParameterInfo copy = *this;
+ copy.Data = (copy.Data & ~ABIMask) | unsigned(kind);
+ return copy;
+ }
+
+ /// Is this parameter considered "consumed" by Objective-C ARC?
+ /// Consumed parameters must have retainable object type.
+ bool isConsumed() const { return (Data & IsConsumed); }
+ ExtParameterInfo withIsConsumed(bool consumed) const {
+ ExtParameterInfo copy = *this;
+ if (consumed)
+ copy.Data |= IsConsumed;
+ else
+ copy.Data &= ~IsConsumed;
+ return copy;
+ }
+
+ bool hasPassObjectSize() const { return Data & HasPassObjSize; }
+ ExtParameterInfo withHasPassObjectSize() const {
+ ExtParameterInfo Copy = *this;
+ Copy.Data |= HasPassObjSize;
+ return Copy;
+ }
+
+ bool isNoEscape() const { return Data & IsNoEscape; }
+ ExtParameterInfo withIsNoEscape(bool NoEscape) const {
+ ExtParameterInfo Copy = *this;
+ if (NoEscape)
+ Copy.Data |= IsNoEscape;
+ else
+ Copy.Data &= ~IsNoEscape;
+ return Copy;
+ }
+
+ unsigned char getOpaqueValue() const { return Data; }
+ static ExtParameterInfo getFromOpaqueValue(unsigned char data) {
+ ExtParameterInfo result;
+ result.Data = data;
+ return result;
+ }
+
+ friend bool operator==(ExtParameterInfo lhs, ExtParameterInfo rhs) {
+ return lhs.Data == rhs.Data;
+ }
+
+ friend bool operator!=(ExtParameterInfo lhs, ExtParameterInfo rhs) {
+ return lhs.Data != rhs.Data;
+ }
+ };
+
/// A class which abstracts out some details necessary for
/// making a call.
///
@@ -3465,6 +3581,22 @@ public:
}
};
+ /// A simple holder for a QualType representing a type in an
+ /// exception specification. Unfortunately needed by FunctionProtoType
+ /// because TrailingObjects cannot handle repeated types.
+ struct ExceptionType { QualType Type; };
+
+ /// A simple holder for various uncommon bits which do not fit in
+ /// FunctionTypeBitfields. Aligned to alignof(void *) to maintain the
+ /// alignment of subsequent objects in TrailingObjects. You must update
+ /// hasExtraBitfields in FunctionProtoType after adding extra data here.
+ struct alignas(void *) FunctionTypeExtraBitfields {
+ /// The number of types in the exception specification.
+ /// A whole unsigned is not needed here and according to
+ /// [implimits] 8 bits would be enough here.
+ unsigned NumExceptionType;
+ };
+
protected:
FunctionType(TypeClass tc, QualType res,
QualType Canonical, bool Dependent,
@@ -3477,7 +3609,9 @@ protected:
FunctionTypeBits.ExtInfo = Info.Bits;
}
- unsigned getTypeQuals() const { return FunctionTypeBits.TypeQuals; }
+ Qualifiers getFastTypeQuals() const {
+ return Qualifiers::fromFastMask(FunctionTypeBits.FastTypeQuals);
+ }
public:
QualType getReturnType() const { return ResultType; }
@@ -3492,9 +3626,14 @@ public:
CallingConv getCallConv() const { return getExtInfo().getCC(); }
ExtInfo getExtInfo() const { return ExtInfo(FunctionTypeBits.ExtInfo); }
- bool isConst() const { return getTypeQuals() & Qualifiers::Const; }
- bool isVolatile() const { return getTypeQuals() & Qualifiers::Volatile; }
- bool isRestrict() const { return getTypeQuals() & Qualifiers::Restrict; }
+
+ static_assert((~Qualifiers::FastMask & Qualifiers::CVRMask) == 0,
+ "Const, volatile and restrict are assumed to be a subset of "
+ "the fast qualifiers.");
+
+ bool isConst() const { return getFastTypeQuals().hasConst(); }
+ bool isVolatile() const { return getFastTypeQuals().hasVolatile(); }
+ bool isRestrict() const { return getFastTypeQuals().hasRestrict(); }
/// Determine the type of an expression that calls a function of
/// this type.
@@ -3544,104 +3683,65 @@ public:
/// Represents a prototype with parameter type info, e.g.
/// 'int foo(int)' or 'int foo(void)'. 'void' is represented as having no
-/// parameters, not as having a single void parameter. Such a type can have an
-/// exception specification, but this specification is not part of the canonical
-/// type.
-class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
-public:
- /// Interesting information about a specific parameter that can't simply
- /// be reflected in parameter's type.
- ///
- /// It makes sense to model language features this way when there's some
- /// sort of parameter-specific override (such as an attribute) that
- /// affects how the function is called. For example, the ARC ns_consumed
- /// attribute changes whether a parameter is passed at +0 (the default)
- /// or +1 (ns_consumed). This must be reflected in the function type,
- /// but isn't really a change to the parameter type.
- ///
- /// One serious disadvantage of modelling language features this way is
- /// that they generally do not work with language features that attempt
- /// to destructure types. For example, template argument deduction will
- /// not be able to match a parameter declared as
- /// T (*)(U)
- /// against an argument of type
- /// void (*)(__attribute__((ns_consumed)) id)
- /// because the substitution of T=void, U=id into the former will
- /// not produce the latter.
- class ExtParameterInfo {
- enum {
- ABIMask = 0x0F,
- IsConsumed = 0x10,
- HasPassObjSize = 0x20,
- IsNoEscape = 0x40,
- };
- unsigned char Data = 0;
-
- public:
- ExtParameterInfo() = default;
-
- /// Return the ABI treatment of this parameter.
- ParameterABI getABI() const {
- return ParameterABI(Data & ABIMask);
- }
- ExtParameterInfo withABI(ParameterABI kind) const {
- ExtParameterInfo copy = *this;
- copy.Data = (copy.Data & ~ABIMask) | unsigned(kind);
- return copy;
- }
-
- /// Is this parameter considered "consumed" by Objective-C ARC?
- /// Consumed parameters must have retainable object type.
- bool isConsumed() const {
- return (Data & IsConsumed);
- }
- ExtParameterInfo withIsConsumed(bool consumed) const {
- ExtParameterInfo copy = *this;
- if (consumed) {
- copy.Data |= IsConsumed;
- } else {
- copy.Data &= ~IsConsumed;
- }
- return copy;
- }
-
- bool hasPassObjectSize() const {
- return Data & HasPassObjSize;
- }
- ExtParameterInfo withHasPassObjectSize() const {
- ExtParameterInfo Copy = *this;
- Copy.Data |= HasPassObjSize;
- return Copy;
- }
-
- bool isNoEscape() const {
- return Data & IsNoEscape;
- }
-
- ExtParameterInfo withIsNoEscape(bool NoEscape) const {
- ExtParameterInfo Copy = *this;
- if (NoEscape)
- Copy.Data |= IsNoEscape;
- else
- Copy.Data &= ~IsNoEscape;
- return Copy;
- }
-
- unsigned char getOpaqueValue() const { return Data; }
- static ExtParameterInfo getFromOpaqueValue(unsigned char data) {
- ExtParameterInfo result;
- result.Data = data;
- return result;
- }
+/// 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. FunctionProtoType has several trailing objects, some of
+/// which optional. For more information about the trailing objects see
+/// the first comment inside FunctionProtoType.
+class FunctionProtoType final
+ : public FunctionType,
+ public llvm::FoldingSetNode,
+ private llvm::TrailingObjects<
+ FunctionProtoType, QualType, FunctionType::FunctionTypeExtraBitfields,
+ FunctionType::ExceptionType, Expr *, FunctionDecl *,
+ FunctionType::ExtParameterInfo, Qualifiers> {
+ friend class ASTContext; // ASTContext creates these.
+ friend TrailingObjects;
- friend bool operator==(ExtParameterInfo lhs, ExtParameterInfo rhs) {
- return lhs.Data == rhs.Data;
- }
- friend bool operator!=(ExtParameterInfo lhs, ExtParameterInfo rhs) {
- return lhs.Data != rhs.Data;
- }
- };
+ // FunctionProtoType is followed by several trailing objects, some of
+ // which optional. They are in order:
+ //
+ // * An array of getNumParams() QualType holding the parameter types.
+ // Always present. Note that for the vast majority of FunctionProtoType,
+ // these will be the only trailing objects.
+ //
+ // * Optionally if some extra data is stored in FunctionTypeExtraBitfields
+ // (see FunctionTypeExtraBitfields and FunctionTypeBitfields):
+ // a single FunctionTypeExtraBitfields. Present if and only if
+ // hasExtraBitfields() is true.
+ //
+ // * Optionally exactly one of:
+ // * an array of getNumExceptions() ExceptionType,
+ // * a single Expr *,
+ // * a pair of FunctionDecl *,
+ // * a single FunctionDecl *
+ // used to store information about the various types of exception
+ // specification. See getExceptionSpecSize for the details.
+ //
+ // * Optionally an array of getNumParams() ExtParameterInfo holding
+ // an ExtParameterInfo for each of the parameters. Present if and
+ // only if hasExtParameterInfos() is true.
+ //
+ // * Optionally a Qualifiers object to represent extra qualifiers that can't
+ // be represented by FunctionTypeBitfields.FastTypeQuals. Present if and only
+ // if hasExtQualifiers() is true.
+ //
+ // The optional FunctionTypeExtraBitfields has to be before the data
+ // related to the exception specification since it contains the number
+ // of exception types.
+ //
+ // We put the ExtParameterInfos last. If all were equal, it would make
+ // more sense to put these before the exception specification, because
+ // it's much easier to skip past them compared to the elaborate switch
+ // required to skip the exception specification. However, all is not
+ // equal; ExtParameterInfos are used to model very uncommon features,
+ // and it's better not to burden the more common paths.
+public:
+ /// Holds information about the various types of exception specification.
+ /// ExceptionSpecInfo is not stored as such in FunctionProtoType but is
+ /// used to group together the various bits of information about the
+ /// exception specification.
struct ExceptionSpecInfo {
/// The kind of exception specification this is.
ExceptionSpecificationType Type = EST_None;
@@ -3665,31 +3765,54 @@ public:
ExceptionSpecInfo(ExceptionSpecificationType EST) : Type(EST) {}
};
- /// Extra information about a function prototype.
+ /// Extra information about a function prototype. ExtProtoInfo is not
+ /// stored as such in FunctionProtoType but is used to group together
+ /// the various bits of extra information about a function prototype.
struct ExtProtoInfo {
FunctionType::ExtInfo ExtInfo;
bool Variadic : 1;
bool HasTrailingReturn : 1;
- unsigned char TypeQuals = 0;
+ Qualifiers TypeQuals;
RefQualifierKind RefQualifier = RQ_None;
ExceptionSpecInfo ExceptionSpec;
const ExtParameterInfo *ExtParameterInfos = nullptr;
- ExtProtoInfo()
- : Variadic(false), HasTrailingReturn(false) {}
+ ExtProtoInfo() : Variadic(false), HasTrailingReturn(false) {}
ExtProtoInfo(CallingConv CC)
: ExtInfo(CC), Variadic(false), HasTrailingReturn(false) {}
- ExtProtoInfo withExceptionSpec(const ExceptionSpecInfo &O) {
+ ExtProtoInfo withExceptionSpec(const ExceptionSpecInfo &ESI) {
ExtProtoInfo Result(*this);
- Result.ExceptionSpec = O;
+ Result.ExceptionSpec = ESI;
return Result;
}
};
private:
- friend class ASTContext; // ASTContext creates these.
+ unsigned numTrailingObjects(OverloadToken<QualType>) const {
+ return getNumParams();
+ }
+
+ unsigned numTrailingObjects(OverloadToken<FunctionTypeExtraBitfields>) const {
+ return hasExtraBitfields();
+ }
+
+ unsigned numTrailingObjects(OverloadToken<ExceptionType>) const {
+ return getExceptionSpecSize().NumExceptionType;
+ }
+
+ unsigned numTrailingObjects(OverloadToken<Expr *>) const {
+ return getExceptionSpecSize().NumExprPtr;
+ }
+
+ unsigned numTrailingObjects(OverloadToken<FunctionDecl *>) const {
+ return getExceptionSpecSize().NumFunctionDeclPtr;
+ }
+
+ unsigned numTrailingObjects(OverloadToken<ExtParameterInfo>) const {
+ return hasExtParameterInfos() ? getNumParams() : 0;
+ }
/// Determine whether there are any argument types that
/// contain an unexpanded parameter pack.
@@ -3705,88 +3828,71 @@ private:
FunctionProtoType(QualType result, ArrayRef<QualType> params,
QualType canonical, const ExtProtoInfo &epi);
- /// The number of parameters this function has, not counting '...'.
- unsigned NumParams : 15;
-
- /// The number of types in the exception spec, if any.
- unsigned NumExceptions : 9;
-
- /// The type of exception specification this function has.
- unsigned ExceptionSpecType : 4;
-
- /// Whether this function has extended parameter information.
- unsigned HasExtParameterInfos : 1;
-
- /// Whether the function is variadic.
- unsigned Variadic : 1;
-
- /// Whether this function has a trailing return type.
- unsigned HasTrailingReturn : 1;
-
- // ParamInfo - There is an variable size array after the class in memory that
- // holds the parameter types.
-
- // Exceptions - There is another variable size array after ArgInfo that
- // holds the exception types.
-
- // NoexceptExpr - Instead of Exceptions, there may be a single Expr* pointing
- // to the expression in the noexcept() specifier.
-
- // ExceptionSpecDecl, ExceptionSpecTemplate - Instead of Exceptions, there may
- // be a pair of FunctionDecl* pointing to the function which should be used to
- // instantiate this function type's exception specification, and the function
- // from which it should be instantiated.
-
- // ExtParameterInfos - A variable size array, following the exception
- // specification and of length NumParams, holding an ExtParameterInfo
- // for each of the parameters. This only appears if HasExtParameterInfos
- // is true.
-
- const ExtParameterInfo *getExtParameterInfosBuffer() const {
- assert(hasExtParameterInfos());
-
- // Find the end of the exception specification.
- const auto *ptr = reinterpret_cast<const char *>(exception_begin());
- ptr += getExceptionSpecSize();
-
- return reinterpret_cast<const ExtParameterInfo *>(ptr);
- }
+ /// This struct is returned by getExceptionSpecSize and is used to
+ /// translate an ExceptionSpecificationType to the number and kind
+ /// of trailing objects related to the exception specification.
+ struct ExceptionSpecSizeHolder {
+ unsigned NumExceptionType;
+ unsigned NumExprPtr;
+ unsigned NumFunctionDeclPtr;
+ };
- static size_t getExceptionSpecSize(ExceptionSpecificationType EST,
- unsigned NumExceptions) {
+ /// Return the number and kind of trailing objects
+ /// related to the exception specification.
+ static ExceptionSpecSizeHolder
+ getExceptionSpecSize(ExceptionSpecificationType EST, unsigned NumExceptions) {
switch (EST) {
case EST_None:
case EST_DynamicNone:
case EST_MSAny:
case EST_BasicNoexcept:
case EST_Unparsed:
- return 0;
+ return {0, 0, 0};
case EST_Dynamic:
- return NumExceptions * sizeof(QualType);
+ return {NumExceptions, 0, 0};
case EST_DependentNoexcept:
case EST_NoexceptFalse:
case EST_NoexceptTrue:
- return sizeof(Expr *);
+ return {0, 1, 0};
case EST_Uninstantiated:
- return 2 * sizeof(FunctionDecl *);
+ return {0, 0, 2};
case EST_Unevaluated:
- return sizeof(FunctionDecl *);
+ return {0, 0, 1};
}
llvm_unreachable("bad exception specification kind");
}
- size_t getExceptionSpecSize() const {
+
+ /// Return the number and kind of trailing objects
+ /// related to the exception specification.
+ ExceptionSpecSizeHolder getExceptionSpecSize() const {
return getExceptionSpecSize(getExceptionSpecType(), getNumExceptions());
}
+ /// Whether the trailing FunctionTypeExtraBitfields is present.
+ static bool hasExtraBitfields(ExceptionSpecificationType EST) {
+ // If the exception spec type is EST_Dynamic then we have > 0 exception
+ // types and the exact number is stored in FunctionTypeExtraBitfields.
+ return EST == EST_Dynamic;
+ }
+
+ /// Whether the trailing FunctionTypeExtraBitfields is present.
+ bool hasExtraBitfields() const {
+ return hasExtraBitfields(getExceptionSpecType());
+ }
+
+ bool hasExtQualifiers() const {
+ return FunctionTypeBits.HasExtQuals;
+ }
+
public:
- unsigned getNumParams() const { return NumParams; }
+ unsigned getNumParams() const { return FunctionTypeBits.NumParams; }
QualType getParamType(unsigned i) const {
- assert(i < NumParams && "invalid parameter index");
+ assert(i < getNumParams() && "invalid parameter index");
return param_type_begin()[i];
}
@@ -3800,7 +3906,7 @@ public:
EPI.Variadic = isVariadic();
EPI.HasTrailingReturn = hasTrailingReturn();
EPI.ExceptionSpec.Type = getExceptionSpecType();
- EPI.TypeQuals = static_cast<unsigned char>(getTypeQuals());
+ EPI.TypeQuals = getTypeQuals();
EPI.RefQualifier = getRefQualifier();
if (EPI.ExceptionSpec.Type == EST_Dynamic) {
EPI.ExceptionSpec.Exceptions = exceptions();
@@ -3812,20 +3918,18 @@ public:
} else if (EPI.ExceptionSpec.Type == EST_Unevaluated) {
EPI.ExceptionSpec.SourceDecl = getExceptionSpecDecl();
}
- if (hasExtParameterInfos())
- EPI.ExtParameterInfos = getExtParameterInfosBuffer();
+ EPI.ExtParameterInfos = getExtParameterInfosOrNull();
return EPI;
}
/// Get the kind of exception specification on this function.
ExceptionSpecificationType getExceptionSpecType() const {
- return static_cast<ExceptionSpecificationType>(ExceptionSpecType);
+ return static_cast<ExceptionSpecificationType>(
+ FunctionTypeBits.ExceptionSpecType);
}
/// Return whether this function has any kind of exception spec.
- bool hasExceptionSpec() const {
- return getExceptionSpecType() != EST_None;
- }
+ bool hasExceptionSpec() const { return getExceptionSpecType() != EST_None; }
/// Return whether this function has a dynamic (throw) exception spec.
bool hasDynamicExceptionSpec() const {
@@ -3844,16 +3948,26 @@ public:
/// spec.
bool hasInstantiationDependentExceptionSpec() const;
- unsigned getNumExceptions() const { return NumExceptions; }
+ /// Return the number of types in the exception specification.
+ unsigned getNumExceptions() const {
+ return getExceptionSpecType() == EST_Dynamic
+ ? getTrailingObjects<FunctionTypeExtraBitfields>()
+ ->NumExceptionType
+ : 0;
+ }
+
+ /// Return the ith exception type, where 0 <= i < getNumExceptions().
QualType getExceptionType(unsigned i) const {
- assert(i < NumExceptions && "Invalid exception number!");
+ assert(i < getNumExceptions() && "Invalid exception number!");
return exception_begin()[i];
}
+
+ /// Return the expression inside noexcept(expression), or a null pointer
+ /// if there is none (because the exception spec is not of this form).
Expr *getNoexceptExpr() const {
if (!isComputedNoexcept(getExceptionSpecType()))
return nullptr;
- // NoexceptExpr sits where the arguments end.
- return *reinterpret_cast<Expr *const *>(param_type_end());
+ return *getTrailingObjects<Expr *>();
}
/// If this function type has an exception specification which hasn't
@@ -3864,7 +3978,7 @@ public:
if (getExceptionSpecType() != EST_Uninstantiated &&
getExceptionSpecType() != EST_Unevaluated)
return nullptr;
- return reinterpret_cast<FunctionDecl *const *>(param_type_end())[0];
+ return getTrailingObjects<FunctionDecl *>()[0];
}
/// If this function type has an uninstantiated exception
@@ -3874,7 +3988,7 @@ public:
FunctionDecl *getExceptionSpecTemplate() const {
if (getExceptionSpecType() != EST_Uninstantiated)
return nullptr;
- return reinterpret_cast<FunctionDecl *const *>(param_type_end())[1];
+ return getTrailingObjects<FunctionDecl *>()[1];
}
/// Determine whether this function type has a non-throwing exception
@@ -3885,11 +3999,11 @@ public:
/// specification. If this depends on template arguments, returns
/// \c ResultIfDependent.
bool isNothrow(bool ResultIfDependent = false) const {
- return ResultIfDependent ? canThrow() != CT_Can
- : canThrow() == CT_Cannot;
+ return ResultIfDependent ? canThrow() != CT_Can : canThrow() == CT_Cannot;
}
- bool isVariadic() const { return Variadic; }
+ /// Whether this function prototype is variadic.
+ bool isVariadic() const { return FunctionTypeBits.Variadic; }
/// Determines whether this function prototype contains a
/// parameter pack at the end.
@@ -3899,9 +4013,15 @@ public:
/// function.
bool isTemplateVariadic() const;
- bool hasTrailingReturn() const { return HasTrailingReturn; }
+ /// Whether this function prototype has a trailing return type.
+ bool hasTrailingReturn() const { return FunctionTypeBits.HasTrailingReturn; }
- unsigned getTypeQuals() const { return FunctionType::getTypeQuals(); }
+ Qualifiers getTypeQuals() const {
+ if (hasExtQualifiers())
+ return *getTrailingObjects<Qualifiers>();
+ else
+ return getFastTypeQuals();
+ }
/// Retrieve the ref-qualifier associated with this function type.
RefQualifierKind getRefQualifier() const {
@@ -3916,11 +4036,11 @@ public:
}
param_type_iterator param_type_begin() const {
- return reinterpret_cast<const QualType *>(this+1);
+ return getTrailingObjects<QualType>();
}
param_type_iterator param_type_end() const {
- return param_type_begin() + NumParams;
+ return param_type_begin() + getNumParams();
}
using exception_iterator = const QualType *;
@@ -3930,22 +4050,23 @@ public:
}
exception_iterator exception_begin() const {
- // exceptions begin where arguments end
- return param_type_end();
+ return reinterpret_cast<exception_iterator>(
+ getTrailingObjects<ExceptionType>());
}
exception_iterator exception_end() const {
- if (getExceptionSpecType() != EST_Dynamic)
- return exception_begin();
- return exception_begin() + NumExceptions;
+ return exception_begin() + getNumExceptions();
}
/// Is there any interesting extra information for any of the parameters
/// of this function type?
- bool hasExtParameterInfos() const { return HasExtParameterInfos; }
+ bool hasExtParameterInfos() const {
+ return FunctionTypeBits.HasExtParameterInfos;
+ }
+
ArrayRef<ExtParameterInfo> getExtParameterInfos() const {
assert(hasExtParameterInfos());
- return ArrayRef<ExtParameterInfo>(getExtParameterInfosBuffer(),
+ return ArrayRef<ExtParameterInfo>(getTrailingObjects<ExtParameterInfo>(),
getNumParams());
}
@@ -3955,27 +4076,27 @@ public:
const ExtParameterInfo *getExtParameterInfosOrNull() const {
if (!hasExtParameterInfos())
return nullptr;
- return getExtParameterInfosBuffer();
+ return getTrailingObjects<ExtParameterInfo>();
}
ExtParameterInfo getExtParameterInfo(unsigned I) const {
assert(I < getNumParams() && "parameter index out of range");
if (hasExtParameterInfos())
- return getExtParameterInfosBuffer()[I];
+ return getTrailingObjects<ExtParameterInfo>()[I];
return ExtParameterInfo();
}
ParameterABI getParameterABI(unsigned I) const {
assert(I < getNumParams() && "parameter index out of range");
if (hasExtParameterInfos())
- return getExtParameterInfosBuffer()[I].getABI();
+ return getTrailingObjects<ExtParameterInfo>()[I].getABI();
return ParameterABI::Ordinary;
}
bool isParamConsumed(unsigned I) const {
assert(I < getNumParams() && "parameter index out of range");
if (hasExtParameterInfos())
- return getExtParameterInfosBuffer()[I].isConsumed();
+ return getTrailingObjects<ExtParameterInfo>()[I].isConsumed();
return false;
}
@@ -4808,7 +4929,9 @@ public:
return !isDependentType() || isCurrentInstantiation() || isTypeAlias();
}
- QualType desugar() const { return getCanonicalTypeInternal(); }
+ QualType desugar() const {
+ return isTypeAlias() ? getAliasedType() : getCanonicalTypeInternal();
+ }
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) {
Profile(ID, Template, template_arguments(), Ctx);
@@ -6359,9 +6482,30 @@ inline bool Type::isPipeType() const {
return isa<PipeType>(CanonicalType);
}
+#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
+ inline bool Type::is##Id##Type() const { \
+ return isSpecificBuiltinType(BuiltinType::Id); \
+ }
+#include "clang/Basic/OpenCLExtensionTypes.def"
+
+inline bool Type::isOCLIntelSubgroupAVCType() const {
+#define INTEL_SUBGROUP_AVC_TYPE(ExtType, Id) \
+ isOCLIntelSubgroupAVC##Id##Type() ||
+ return
+#include "clang/Basic/OpenCLExtensionTypes.def"
+ false; // end of boolean or operation
+}
+
+inline bool Type::isOCLExtOpaqueType() const {
+#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) is##Id##Type() ||
+ return
+#include "clang/Basic/OpenCLExtensionTypes.def"
+ false; // end of boolean or operation
+}
+
inline bool Type::isOpenCLSpecificType() const {
return isSamplerT() || isEventT() || isImageType() || isClkEventT() ||
- isQueueT() || isReserveIDT() || isPipeType();
+ isQueueT() || isReserveIDT() || isPipeType() || isOCLExtOpaqueType();
}
inline bool Type::isTemplateTypeParmType() const {