diff options
author | Abdoulaye Walsimou Gaye <awg@embtoolkit.org> | 2013-05-15 21:40:27 +0200 |
---|---|---|
committer | Abdoulaye Walsimou Gaye <awg@embtoolkit.org> | 2013-05-15 21:40:27 +0200 |
commit | b0274c7c30af17c0255846bcd53cac4f7d76ddea (patch) | |
tree | 4243e33459039a96c26557de48f989e85c925a4c | |
parent | 38f7a3147aad1e25d0738356519cf9235f5c80b7 (diff) | |
parent | cce70c7c5f0f4c1a41658fbed845f8b3a565c99c (diff) | |
download | clang-embtk-support-master.tar.gz clang-embtk-support-master.tar.bz2 clang-embtk-support-master.tar.xz |
Merge branch 'master' into embtk-support-masterembtk-support-master
Signed-off-by: Abdoulaye Walsimou Gaye <awg@embtoolkit.org>
184 files changed, 4480 insertions, 965 deletions
diff --git a/docs/LeakSanitizer.rst b/docs/LeakSanitizer.rst new file mode 100644 index 0000000000..09d02cfcd5 --- /dev/null +++ b/docs/LeakSanitizer.rst @@ -0,0 +1,28 @@ +================ +LeakSanitizer +================ + +.. contents:: + :local: + +Introduction +============ + +LeakSanitizer is a heap leak detector which is designed to be used on top of +:doc:`AddressSanitizer` / :doc:`MemorySanitizer`, or as a standalone library. +LeakSanitizer is a run-time tool which doesn't require compiler +instrumentation. + +Current status +============== + +LeakSanitizer is a work in progress, currently under development for +x86\_64 Linux. + +More Information +================ + +Design wiki: +`https://code.google.com/p/address-sanitizer/wiki/LeakSanitizerDesignDocument +<https://code.google.com/p/address-sanitizer/wiki/LeakSanitizerDesignDocument>`_ + diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h index 27dcef2a1e..e07e84a783 100644 --- a/include/clang/AST/Attr.h +++ b/include/clang/AST/Attr.h @@ -145,7 +145,7 @@ public: // Implement isa/cast/dyncast/etc. static bool classof(const Attr *A) { // Relies on relative order of enum emission with respect to param attrs. - return (A->getKind() <= attr::LAST_MS_INHERITABLE && + return (A->getKind() <= attr::LAST_MS_INHERITANCE && A->getKind() > attr::LAST_INHERITABLE_PARAM); } }; diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h index 946075739d..9c699b7e0a 100644 --- a/include/clang/AST/CanonicalType.h +++ b/include/clang/AST/CanonicalType.h @@ -81,7 +81,7 @@ public: operator QualType() const { return Stored; } /// \brief Implicit conversion to bool. - operator bool() const { return !isNull(); } + LLVM_EXPLICIT operator bool() const { return !isNull(); } bool isNull() const { return Stored.isNull(); diff --git a/include/clang/AST/CharUnits.h b/include/clang/AST/CharUnits.h index 082c672c21..09ff6828ef 100644 --- a/include/clang/AST/CharUnits.h +++ b/include/clang/AST/CharUnits.h @@ -19,21 +19,20 @@ #include "llvm/Support/MathExtras.h" namespace clang { - + /// CharUnits - This is an opaque type for sizes expressed in character units. - /// Instances of this type represent a quantity as a multiple of the size + /// Instances of this type represent a quantity as a multiple of the size /// of the standard C type, char, on the target architecture. As an opaque /// type, CharUnits protects you from accidentally combining operations on - /// quantities in bit units and character units. + /// quantities in bit units and character units. + /// + /// In both C and C++, an object of type 'char', 'signed char', or 'unsigned + /// char' occupies exactly one byte, so 'character unit' and 'byte' refer to + /// the same quantity of storage. However, we use the term 'character unit' + /// rather than 'byte' to avoid an implication that a character unit is + /// exactly 8 bits. /// - /// It should be noted that characters and bytes are distinct concepts. Bytes - /// refer to addressable units of data storage on the target machine, and - /// characters are members of a set of elements used for the organization, - /// control, or representation of data. According to C99, bytes are allowed - /// to exceed characters in size, although currently, clang only supports - /// architectures where the two are the same size. - /// - /// For portability, never assume that a target character is 8 bits wide. Use + /// For portability, never assume that a target character is 8 bits wide. Use /// CharUnit values wherever you calculate sizes, offsets, or alignments /// in character units. class CharUnits { diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index d5e6ebee4a..aafd0bc530 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -24,6 +24,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/raw_ostream.h" namespace clang { struct ASTTemplateArgumentListInfo; @@ -142,7 +143,7 @@ public: // FIXME: Deprecated, move clients to getName(). std::string getNameAsString() const { return Name.getAsString(); } - void printName(raw_ostream &os) const { return Name.printName(os); } + void printName(raw_ostream &os) const { os << Name; } /// getDeclName - Get the actual, stored name of the declaration, /// which may be a special name. @@ -212,11 +213,26 @@ public: bool isCXXInstanceMember() const; /// \brief Determine what kind of linkage this entity has. - Linkage getLinkage() const; + /// This is not the linkage as defined by the standard or the codegen notion + /// of linkage. It is just an implementation detail that is used to compute + /// those. + Linkage getLinkageInternal() const; + + /// \brief Get the linkage from a semantic point of view. Entities in + /// anonymous namespaces are external (in c++98). + Linkage getFormalLinkage() const { + Linkage L = getLinkageInternal(); + if (L == UniqueExternalLinkage) + return ExternalLinkage; + return L; + } /// \brief True if this decl has external linkage. - bool hasExternalLinkage() const { - return getLinkage() == ExternalLinkage; + bool hasExternalFormalLinkage() const { + return getFormalLinkage() == ExternalLinkage; + } + bool isExternallyVisible() const { + return getLinkageInternal() == ExternalLinkage; } /// \brief Determines the visibility of this entity. diff --git a/include/clang/AST/DeclFriend.h b/include/clang/AST/DeclFriend.h index 3a12878e74..589178ec6e 100644 --- a/include/clang/AST/DeclFriend.h +++ b/include/clang/AST/DeclFriend.h @@ -228,7 +228,7 @@ inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_end() const { } inline void CXXRecordDecl::pushFriendDecl(FriendDecl *FD) { - assert(FD->NextFriend == 0 && "friend already has next friend?"); + assert(!FD->NextFriend && "friend already has next friend?"); FD->NextFriend = data().FirstFriend; data().FirstFriend = FD; } diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index 40de0135a7..0028240349 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -452,7 +452,7 @@ public: } /// \brief Determine whether this method has a body. - virtual bool hasBody() const { return Body; } + virtual bool hasBody() const { return Body.isValid(); } /// \brief Retrieve the body of this method, if it has one. virtual Stmt *getBody() const; @@ -463,7 +463,7 @@ public: void setBody(Stmt *B) { Body = B; } /// \brief Returns whether this specific method is a definition. - bool isThisDeclarationADefinition() const { return Body; } + bool isThisDeclarationADefinition() const { return hasBody(); } // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } diff --git a/include/clang/AST/DeclOpenMP.h b/include/clang/AST/DeclOpenMP.h index ca92040c32..42fe907aa1 100644 --- a/include/clang/AST/DeclOpenMP.h +++ b/include/clang/AST/DeclOpenMP.h @@ -1,4 +1,4 @@ -//===--- OpenMP.h - Classes for representing OpenMP directives ---*- C++ -*-===// +//===- DeclOpenMP.h - Classes for representing OpenMP directives -*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// \brief This file defines OpenMP nodes. +/// \brief This file defines OpenMP nodes for declarative directives. /// //===----------------------------------------------------------------------===// @@ -20,8 +20,6 @@ namespace clang { -class DeclRefExpr; - /// \brief This represents '#pragma omp threadprivate ...' directive. /// For example, in the following, both 'a' and 'A::b' are threadprivate: /// @@ -43,29 +41,29 @@ class OMPThreadPrivateDecl : public Decl { OMPThreadPrivateDecl(Kind DK, DeclContext *DC, SourceLocation L) : Decl(DK, DC, L), NumVars(0) { } - ArrayRef<const DeclRefExpr *> getVars() const { - return ArrayRef<const DeclRefExpr *>( - reinterpret_cast<const DeclRefExpr * const *>(this + 1), + ArrayRef<const Expr *> getVars() const { + return ArrayRef<const Expr *>( + reinterpret_cast<const Expr * const *>(this + 1), NumVars); } - llvm::MutableArrayRef<DeclRefExpr *> getVars() { - return llvm::MutableArrayRef<DeclRefExpr *>( - reinterpret_cast<DeclRefExpr **>(this + 1), + llvm::MutableArrayRef<Expr *> getVars() { + return llvm::MutableArrayRef<Expr *>( + reinterpret_cast<Expr **>(this + 1), NumVars); } - void setVars(ArrayRef<DeclRefExpr *> VL); + void setVars(ArrayRef<Expr *> VL); public: static OMPThreadPrivateDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, - ArrayRef<DeclRefExpr *> VL); + ArrayRef<Expr *> VL); static OMPThreadPrivateDecl *CreateDeserialized(ASTContext &C, unsigned ID, unsigned N); - typedef llvm::MutableArrayRef<DeclRefExpr *>::iterator varlist_iterator; - typedef ArrayRef<const DeclRefExpr *>::iterator varlist_const_iterator; + typedef llvm::MutableArrayRef<Expr *>::iterator varlist_iterator; + typedef ArrayRef<const Expr *>::iterator varlist_const_iterator; unsigned varlist_size() const { return NumVars; } bool varlist_empty() const { return NumVars == 0; } diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h index f28882b3bf..00766c27c1 100644 --- a/include/clang/AST/DeclarationName.h +++ b/include/clang/AST/DeclarationName.h @@ -182,11 +182,16 @@ public: // operator bool() - Evaluates true when this declaration name is // non-empty. - operator bool() const { + LLVM_EXPLICIT operator bool() const { return ((Ptr & PtrMask) != 0) || (reinterpret_cast<IdentifierInfo *>(Ptr & ~PtrMask)); } + /// \brief Evaluates true when this declaration name is empty. + bool isEmpty() const { + return !*this; + } + /// Predicate functions for querying what type of name this is. bool isIdentifier() const { return getStoredNameKind() == StoredIdentifier; } bool isObjCZeroArgSelector() const { @@ -210,9 +215,6 @@ public: /// getNameAsString - Retrieve the human-readable string for this name. std::string getAsString() const; - /// printName - Print the human-readable name to a stream. - void printName(raw_ostream &OS) const; - /// getAsIdentifierInfo - Retrieve the IdentifierInfo * stored in /// this declaration name, or NULL if this declaration name isn't a /// simple identifier. @@ -302,6 +304,8 @@ public: void dump() const; }; +raw_ostream &operator<<(raw_ostream &OS, DeclarationName N); + /// Ordering on two declaration names. If both names are identifiers, /// this provides a lexicographical ordering. inline bool operator<(DeclarationName LHS, DeclarationName RHS) { diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 91e5b21eac..a4f296c988 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -1935,7 +1935,7 @@ public: /// \brief Determines whether this member expression actually had /// a C++ nested-name-specifier prior to the name of the member, e.g., /// x->Base::foo. - bool hasQualifier() const { return QualifierLoc; } + bool hasQualifier() const { return QualifierLoc.hasQualifier(); } /// \brief Retrieves the nested-name-specifier that qualifies the type name, /// with source-location information. diff --git a/include/clang/AST/ExternalASTSource.h b/include/clang/AST/ExternalASTSource.h index 81fcf242b6..b077426e6a 100644 --- a/include/clang/AST/ExternalASTSource.h +++ b/include/clang/AST/ExternalASTSource.h @@ -329,7 +329,12 @@ public: /// \brief Whether this pointer is non-NULL. /// /// This operation does not require the AST node to be deserialized. - operator bool() const { return Ptr != 0; } + LLVM_EXPLICIT operator bool() const { return Ptr != 0; } + + /// \brief Whether this pointer is non-NULL. + /// + /// This operation does not require the AST node to be deserialized. + bool isValid() const { return Ptr != 0; } /// \brief Whether this pointer is currently stored as an offset. bool isOffset() const { return Ptr & 0x01; } diff --git a/include/clang/AST/NestedNameSpecifier.h b/include/clang/AST/NestedNameSpecifier.h index 58f39862b1..b332b153fe 100644 --- a/include/clang/AST/NestedNameSpecifier.h +++ b/include/clang/AST/NestedNameSpecifier.h @@ -231,7 +231,11 @@ public: /// \brief Evalutes true when this nested-name-specifier location is /// non-empty. - operator bool() const { return Qualifier; } + LLVM_EXPLICIT operator bool() const { return Qualifier; } + + /// \brief Evalutes true when this nested-name-specifier location is + /// empty. + bool hasQualifier() const { return Qualifier; } /// \brief Retrieve the nested-name-specifier to which this instance /// refers. diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index 74c9ec2053..b2ab672627 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -967,9 +967,6 @@ public: SwitchCase *getSwitchCaseList() { return FirstCase; } /// \brief Set the case list for this switch statement. - /// - /// The caller is responsible for incrementing the retain counts on - /// all of the SwitchCase statements in this list. void setSwitchCaseList(SwitchCase *SC) { FirstCase = SC; } SourceLocation getSwitchLoc() const { return SwitchLoc; } diff --git a/include/clang/AST/StmtIterator.h b/include/clang/AST/StmtIterator.h index b933ed0762..fc25fa9a6e 100644 --- a/include/clang/AST/StmtIterator.h +++ b/include/clang/AST/StmtIterator.h @@ -15,6 +15,7 @@ #define LLVM_CLANG_AST_STMT_ITR_H #include "llvm/Support/DataTypes.h" +#include "llvm/Support/Compiler.h" #include <cassert> #include <cstddef> #include <iterator> @@ -156,7 +157,7 @@ struct StmtRange : std::pair<StmtIterator,StmtIterator> { : std::pair<StmtIterator,StmtIterator>(begin, end) {} bool empty() const { return first == second; } - operator bool() const { return !empty(); } + LLVM_EXPLICIT operator bool() const { return !empty(); } Stmt *operator->() const { return first.operator->(); } Stmt *&operator*() const { return first.operator*(); } @@ -199,7 +200,7 @@ struct ConstStmtRange : std::pair<ConstStmtIterator,ConstStmtIterator> { : std::pair<ConstStmtIterator,ConstStmtIterator>(begin, end) {} bool empty() const { return first == second; } - operator bool() const { return !empty(); } + LLVM_EXPLICIT operator bool() const { return !empty(); } const Stmt *operator->() const { return first.operator->(); } const Stmt *operator*() const { return first.operator*(); } diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 39f10d3393..93c287fd18 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -441,7 +441,7 @@ public: bool operator==(Qualifiers Other) const { return Mask == Other.Mask; } bool operator!=(Qualifiers Other) const { return Mask != Other.Mask; } - operator bool() const { return hasQualifiers(); } + LLVM_EXPLICIT operator bool() const { return hasQualifiers(); } Qualifiers &operator+=(Qualifiers R) { addQualifiers(R); diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h index 11cad9bb9d..9e2d3bffb9 100644 --- a/include/clang/AST/TypeLoc.h +++ b/include/clang/AST/TypeLoc.h @@ -90,7 +90,7 @@ public: } bool isNull() const { return !Ty; } - operator bool() const { return Ty; } + LLVM_EXPLICIT operator bool() const { return Ty; } /// \brief Returns the size of type source info data block for the given type. static unsigned getFullDataSizeForType(QualType Ty); diff --git a/include/clang/ASTMatchers/ASTMatchFinder.h b/include/clang/ASTMatchers/ASTMatchFinder.h index 870a39b391..be58afffd1 100644 --- a/include/clang/ASTMatchers/ASTMatchFinder.h +++ b/include/clang/ASTMatchers/ASTMatchFinder.h @@ -131,6 +131,17 @@ public: MatchCallback *Action); /// @} + /// \brief Adds a matcher to execute when running over the AST. + /// + /// This is similar to \c addMatcher(), but it uses the dynamic interface. It + /// is more flexible, but the lost type information enables a caller to pass + /// a matcher that cannot match anything. + /// + /// \returns \c true if the matcher is a valid top-level matcher, \c false + /// otherwise. + bool addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch, + MatchCallback *Action); + /// \brief Creates a clang ASTConsumer that finds all matches. clang::ASTConsumer *newASTConsumer(); diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h index 30691ad8f9..bc4ddce36f 100644 --- a/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -239,6 +239,9 @@ public: ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const = 0; + /// \brief Makes a copy of this matcher object. + virtual DynTypedMatcher *clone() const = 0; + /// \brief Returns a unique ID for the matcher. virtual uint64_t getID() const = 0; }; @@ -301,6 +304,9 @@ public: return matches(*Node, Finder, Builder); } + /// \brief Makes a copy of this matcher object. + virtual Matcher<T> *clone() const { return new Matcher<T>(*this); } + /// \brief Allows the conversion of a \c Matcher<Type> to a \c /// Matcher<QualType>. /// diff --git a/include/clang/ASTMatchers/Dynamic/Diagnostics.h b/include/clang/ASTMatchers/Dynamic/Diagnostics.h new file mode 100644 index 0000000000..417bc67967 --- /dev/null +++ b/include/clang/ASTMatchers/Dynamic/Diagnostics.h @@ -0,0 +1,109 @@ +//===--- Diagnostics.h - Helper class for error diagnostics -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Diagnostics class to manage error messages. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_DIAGNOSTICS_H +#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_DIAGNOSTICS_H + +#include <string> +#include <vector> + +#include "clang/ASTMatchers/Dynamic/VariantValue.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" + +namespace clang { +namespace ast_matchers { +namespace dynamic { + +struct SourceLocation { + SourceLocation() : Line(), Column() {} + unsigned Line; + unsigned Column; +}; + +struct SourceRange { + SourceLocation Start; + SourceLocation End; +}; + +/// \brief A VariantValue instance annotated with its parser context. +struct ParserValue { + ParserValue() : Text(), Range(), Value() {} + StringRef Text; + SourceRange Range; + VariantValue Value; +}; + +/// \brief Helper class to manage error messages. +class Diagnostics { + public: + /// \brief All errors from the system. + enum ErrorType { + ET_None = 0, + + ET_RegistryNotFound = 1, + ET_RegistryWrongArgCount = 2, + ET_RegistryWrongArgType = 3, + + ET_ParserStringError = 100, + ET_ParserMatcherArgFailure = 101, + ET_ParserMatcherFailure = 102, + ET_ParserNoOpenParen = 103, + ET_ParserNoCloseParen = 104, + ET_ParserNoComma = 105, + ET_ParserNoCode = 106, + ET_ParserNotAMatcher = 107, + ET_ParserInvalidToken = 108 + }; + + /// \brief Helper stream class. + struct ArgStream { + template <class T> ArgStream &operator<<(const T &Arg) { + return operator<<(Twine(Arg)); + } + ArgStream &operator<<(const Twine &Arg); + std::vector<std::string> *Out; + }; + + /// \brief Push a frame to the beginning of the list + /// + /// Returns a helper class to allow the caller to pass the arguments for the + /// error message, using the << operator. + ArgStream pushErrorFrame(const SourceRange &Range, ErrorType Error); + + struct ErrorFrame { + SourceRange Range; + ErrorType Type; + std::vector<std::string> Args; + + std::string ToString() const; + }; + ArrayRef<ErrorFrame> frames() const { return Frames; } + + /// \brief Returns a string representation of the last frame. + std::string ToString() const; + /// \brief Returns a string representation of the whole frame stack. + std::string ToStringFull() const; + + private: + std::vector<ErrorFrame> Frames; +}; + +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang + +#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_DIAGNOSTICS_H diff --git a/include/clang/ASTMatchers/Dynamic/Parser.h b/include/clang/ASTMatchers/Dynamic/Parser.h new file mode 100644 index 0000000000..f981c6055e --- /dev/null +++ b/include/clang/ASTMatchers/Dynamic/Parser.h @@ -0,0 +1,143 @@ +//===--- Parser.h - Matcher expression parser -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Simple matcher expression parser. +/// +/// The parser understands matcher expressions of the form: +/// MatcherName(Arg0, Arg1, ..., ArgN) +/// as well as simple types like strings. +/// The parser does not know how to process the matchers. It delegates this task +/// to a Sema object received as an argument. +/// +/// \code +/// Grammar for the expressions supported: +/// <Expression> := <StringLiteral> | <MatcherExpression> +/// <StringLiteral> := "quoted string" +/// <MatcherExpression> := <MatcherName>(<ArgumentList>) +/// <MatcherName> := [a-zA-Z]+ +/// <ArgumentList> := <Expression> | <Expression>,<ArgumentList> +/// \endcode +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_PARSER_H +#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_PARSER_H + +#include "clang/ASTMatchers/Dynamic/Diagnostics.h" +#include "clang/ASTMatchers/Dynamic/VariantValue.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { +namespace ast_matchers { +namespace dynamic { + +/// \brief Matcher expression parser. +class Parser { +public: + /// \brief Interface to connect the parser with the registry and more. + /// + /// The parser uses the Sema instance passed into + /// parseMatcherExpression() to handle all matcher tokens. The simplest + /// processor implementation would simply call into the registry to create + /// the matchers. + /// However, a more complex processor might decide to intercept the matcher + /// creation and do some extra work. For example, it could apply some + /// transformation to the matcher by adding some id() nodes, or could detect + /// specific matcher nodes for more efficient lookup. + class Sema { + public: + virtual ~Sema(); + + /// \brief Process a matcher expression. + /// + /// All the arguments passed here have already been processed. + /// + /// \param MatcherName The matcher name found by the parser. + /// + /// \param NameRange The location of the name in the matcher source. + /// Useful for error reporting. + /// + /// \param Args The argument list for the matcher. + /// + /// \return The matcher object constructed by the processor, or NULL + /// if an error occurred. In that case, \c Error will contain a + /// description of the error. + /// The caller takes ownership of the DynTypedMatcher object returned. + virtual DynTypedMatcher * + actOnMatcherExpression(StringRef MatcherName, const SourceRange &NameRange, + ArrayRef<ParserValue> Args, Diagnostics *Error) = 0; + }; + + /// \brief Parse a matcher expression, creating matchers from the registry. + /// + /// This overload creates matchers calling directly into the registry. If the + /// caller needs more control over how the matchers are created, then it can + /// use the overload below that takes a Sema. + /// + /// \param MatcherCode The matcher expression to parse. + /// + /// \return The matcher object constructed, or NULL if an error occurred. + // In that case, \c Error will contain a description of the error. + /// The caller takes ownership of the DynTypedMatcher object returned. + static DynTypedMatcher *parseMatcherExpression(StringRef MatcherCode, + Diagnostics *Error); + + /// \brief Parse a matcher expression. + /// + /// \param MatcherCode The matcher expression to parse. + /// + /// \param S The Sema instance that will help the parser + /// construct the matchers. + /// \return The matcher object constructed by the processor, or NULL + /// if an error occurred. In that case, \c Error will contain a + /// description of the error. + /// The caller takes ownership of the DynTypedMatcher object returned. + static DynTypedMatcher *parseMatcherExpression(StringRef MatcherCode, + Sema *S, + Diagnostics *Error); + + /// \brief Parse an expression, creating matchers from the registry. + /// + /// Parses any expression supported by this parser. In general, the + /// \c parseMatcherExpression function is a better approach to get a matcher + /// object. + static bool parseExpression(StringRef Code, VariantValue *Value, + Diagnostics *Error); + + /// \brief Parse an expression. + /// + /// Parses any expression supported by this parser. In general, the + /// \c parseMatcherExpression function is a better approach to get a matcher + /// object. + static bool parseExpression(StringRef Code, Sema *S, + VariantValue *Value, Diagnostics *Error); + +private: + class CodeTokenizer; + struct TokenInfo; + + Parser(CodeTokenizer *Tokenizer, Sema *S, + Diagnostics *Error); + + bool parseExpressionImpl(VariantValue *Value); + bool parseMatcherExpressionImpl(VariantValue *Value); + + CodeTokenizer *const Tokenizer; + Sema *const S; + Diagnostics *const Error; +}; + +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang + +#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_PARSER_H diff --git a/include/clang/ASTMatchers/Dynamic/Registry.h b/include/clang/ASTMatchers/Dynamic/Registry.h new file mode 100644 index 0000000000..b092ed8fe1 --- /dev/null +++ b/include/clang/ASTMatchers/Dynamic/Registry.h @@ -0,0 +1,63 @@ +//===--- Registry.h - Matcher registry -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Registry of all known matchers. +/// +/// The registry provides a generic interface to construct any matcher by name. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_REGISTRY_H +#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_REGISTRY_H + +#include "clang/ASTMatchers/Dynamic/Diagnostics.h" +#include "clang/ASTMatchers/Dynamic/VariantValue.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { +namespace ast_matchers { +namespace dynamic { + +class Registry { +public: + /// \brief Construct a matcher from the registry by name. + /// + /// Consult the registry of known matchers and construct the appropriate + /// matcher by name. + /// + /// \param MatcherName The name of the matcher to instantiate. + /// + /// \param NameRange The location of the name in the matcher source. + /// Useful for error reporting. + /// + /// \param Args The argument list for the matcher. The number and types of the + /// values must be valid for the matcher requested. Otherwise, the function + /// will return an error. + /// + /// \return The matcher if no error was found. NULL if the matcher is not + // found, or if the number of arguments or argument types do not + /// match the signature. In that case \c Error will contain the description + /// of the error. + static DynTypedMatcher *constructMatcher(StringRef MatcherName, + const SourceRange &NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error); + +private: + Registry() LLVM_DELETED_FUNCTION; +}; + +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang + +#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_REGISTRY_H diff --git a/include/clang/ASTMatchers/Dynamic/VariantValue.h b/include/clang/ASTMatchers/Dynamic/VariantValue.h new file mode 100644 index 0000000000..9a41b448cf --- /dev/null +++ b/include/clang/ASTMatchers/Dynamic/VariantValue.h @@ -0,0 +1,125 @@ +//===--- VariantValue.h - Polymorphic value type -*- C++ -*-===/ +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Polymorphic value type. +/// +/// Supports all the types required for dynamic Matcher construction. +/// Used by the registry to construct matchers in a generic way. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_VARIANT_VALUE_H +#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_VARIANT_VALUE_H + +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/ASTMatchers/ASTMatchersInternal.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/type_traits.h" + +namespace clang { +namespace ast_matchers { +namespace dynamic { + +using ast_matchers::internal::DynTypedMatcher; + +/// \brief Variant value class. +/// +/// Basically, a tagged union with value type semantics. +/// It is used by the registry as the return value and argument type for the +/// matcher factory methods. +/// It can be constructed from any of the supported types. It supports +/// copy/assignment. +/// +/// Supported types: +/// - \c std::string +/// - \c DynTypedMatcher, and any \c Matcher<T> +class VariantValue { +public: + VariantValue() : Type(VT_Nothing) {} + + VariantValue(const VariantValue &Other); + ~VariantValue(); + VariantValue &operator=(const VariantValue &Other); + + /// \brief Specific constructors for each supported type. + VariantValue(const std::string &String); + VariantValue(const DynTypedMatcher &Matcher); + + /// \brief String value functions. + bool isString() const; + const std::string &getString() const; + void setString(const std::string &String); + + /// \brief Matcher value functions. + bool isMatcher() const; + const DynTypedMatcher &getMatcher() const; + void setMatcher(const DynTypedMatcher &Matcher); + /// \brief Set the value to be \c Matcher by taking ownership of the object. + void takeMatcher(DynTypedMatcher *Matcher); + + /// \brief Specialized Matcher<T> is/get functions. + template <class T> + bool isTypedMatcher() const { + // TODO: Add some logic to test if T is actually valid for the underlying + // type of the matcher. + return isMatcher(); + } + + template <class T> + ast_matchers::internal::Matcher<T> getTypedMatcher() const { + return ast_matchers::internal::makeMatcher( + new DerivedTypeMatcher<T>(getMatcher())); + } + +private: + void reset(); + + /// \brief Matcher bridge between a Matcher<T> and a generic DynTypedMatcher. + template <class T> + class DerivedTypeMatcher : + public ast_matchers::internal::MatcherInterface<T> { + public: + explicit DerivedTypeMatcher(const DynTypedMatcher &DynMatcher) + : DynMatcher(DynMatcher.clone()) {} + virtual ~DerivedTypeMatcher() {} + + typedef ast_matchers::internal::ASTMatchFinder ASTMatchFinder; + typedef ast_matchers::internal::BoundNodesTreeBuilder BoundNodesTreeBuilder; + bool matches(const T &Node, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const { + return DynMatcher->matches(ast_type_traits::DynTypedNode::create(Node), + Finder, Builder); + } + + private: + const OwningPtr<DynTypedMatcher> DynMatcher; + }; + + /// \brief All supported value types. + enum ValueType { + VT_Nothing, + VT_String, + VT_Matcher + }; + + /// \brief All supported value types. + union AllValues { + std::string *String; + DynTypedMatcher *Matcher; + }; + + ValueType Type; + AllValues Value; +}; + +} // end namespace dynamic +} // end namespace ast_matchers +} // end namespace clang + +#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_VARIANT_VALUE_H diff --git a/include/clang/Analysis/Analyses/FormatString.h b/include/clang/Analysis/Analyses/FormatString.h index 4bd989cf4e..6ad89aec0a 100644 --- a/include/clang/Analysis/Analyses/FormatString.h +++ b/include/clang/Analysis/Analyses/FormatString.h @@ -49,7 +49,7 @@ public: const char *toString() const { return representation; } // Overloaded operators for bool like qualities - operator bool() const { return flag; } + LLVM_EXPLICIT operator bool() const { return flag; } OptionalFlag& operator=(const bool &rhs) { flag = rhs; return *this; // Return a reference to myself. diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h index ee0be736dd..01480ed3b4 100644 --- a/include/clang/Analysis/CFG.h +++ b/include/clang/Analysis/CFG.h @@ -269,7 +269,7 @@ public: Stmt &operator*() { return *getStmt(); } const Stmt &operator*() const { return *getStmt(); } - operator bool() const { return getStmt(); } + LLVM_EXPLICIT operator bool() const { return getStmt(); } }; /// CFGBlock - Represents a single basic block in a source-level CFG. diff --git a/include/clang/Basic/AttrKinds.h b/include/clang/Basic/AttrKinds.h index bd090ecc0d..7c4e2c75f0 100644 --- a/include/clang/Basic/AttrKinds.h +++ b/include/clang/Basic/AttrKinds.h @@ -24,7 +24,7 @@ enum Kind { #define ATTR(X) X, #define LAST_INHERITABLE_ATTR(X) X, LAST_INHERITABLE = X, #define LAST_INHERITABLE_PARAM_ATTR(X) X, LAST_INHERITABLE_PARAM = X, -#define LAST_MS_INHERITABLE_ATTR(X) X, LAST_MS_INHERITABLE = X, +#define LAST_MS_INHERITANCE_ATTR(X) X, LAST_MS_INHERITANCE = X, #include "clang/Basic/AttrList.inc" NUM_ATTRS }; diff --git a/include/clang/Basic/BuiltinsARM.def b/include/clang/Basic/BuiltinsARM.def index 888e529111..fad9007e04 100644 --- a/include/clang/Basic/BuiltinsARM.def +++ b/include/clang/Basic/BuiltinsARM.def @@ -15,7 +15,7 @@ // The format of this database matches clang/Basic/Builtins.def. // In libgcc -BUILTIN(__clear_cache, "v.", "") +BUILTIN(__clear_cache, "vv*v*", "") BUILTIN(__builtin_thread_pointer, "v*", "") // Saturating arithmetic diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h index 3e125944a3..1354120ea5 100644 --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -1212,7 +1212,7 @@ public: ~StoredDiagnostic(); /// \brief Evaluates true when this object stores a diagnostic. - operator bool() const { return Message.size() > 0; } + LLVM_EXPLICIT operator bool() const { return Message.size() > 0; } unsigned getID() const { return ID; } DiagnosticsEngine::Level getLevel() const { return Level; } diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index e001bd46a2..a4b8d1810c 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -819,13 +819,14 @@ def err_seh___finally_block : Error< def warn_pragma_omp_ignored : Warning < "unexpected '#pragma omp ...' in program">, InGroup<SourceUsesOpenMP>, DefaultIgnore; def warn_omp_extra_tokens_at_eol : Warning < - "extra tokens at end of '#pragma omp %0' are ignored">, + "extra tokens at the end of '#pragma omp %0' are ignored">, InGroup<ExtraTokens>; def err_omp_unknown_directive : Error < "expected an OpenMP directive">; def err_omp_unexpected_directive : Error < "unexpected OpenMP directive '#pragma omp %0'">; - +def err_omp_expected_var : Error < + "expected '#pragma omp %0' argument to be a variable name">; } // end of Parse Issue category. let CategoryName = "Modules Issue" in { diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 18d5796ea1..55f237736c 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -499,6 +499,8 @@ def note_while_in_implementation : Note< "detected while default synthesizing properties in class implementation">; def note_class_declared : Note< "class is declared here">; +def note_receiver_class_declared : Note< + "receiver is instance of class declared here">; def note_receiver_is_id : Note< "receiver is treated with 'id' type for purpose of method lookup">; def note_suppressed_class_declare : Note< @@ -4280,7 +4282,13 @@ def err_typecheck_incomplete_array_needs_initializer : Error< "or an initializer">; def err_array_init_not_init_list : Error< "array initializer must be an initializer " - "list%select{| or string literal}0">; + "list%select{| or string literal| or wide string literal}0">; +def err_array_init_narrow_string_into_wchar : Error< + "initializing wide char array with non-wide string literal">; +def err_array_init_wide_string_into_char : Error< + "initializing char array with wide string literal">; +def err_array_init_incompat_wide_string_into_wchar : Error< + "initializing wide char array with incompatible wide string literal">; def err_array_init_different_type : Error< "cannot initialize array %diff{of type $ with array of type $|" "with different type of array}0,1">; @@ -6336,24 +6344,26 @@ def err_wrong_sampler_addressspace: Error< "sampler type cannot be used with the __local and __global address space qualifiers">; def err_opencl_global_invalid_addr_space : Error< "global variables must have a constant address space qualifier">; - + +} // end of sema category + +let CategoryName = "OpenMP Issue" in { // OpenMP support. def err_omp_expected_var_arg_suggest : Error< "%0 is not a global variable, static local variable or static data member%select{|; did you mean %2?}1">; def err_omp_global_var_arg : Error< "arguments of '#pragma omp %0' must have %select{global storage|static storage duration}1">; def err_omp_ref_type_arg : Error< - "arguments of '#pragma omp %0' cannot be of reference type %1">; + "arguments of '#pragma omp %0' cannot be of reference type">; def err_omp_var_scope : Error< - "'#pragma omp %0' must appear in the scope of the %1 variable declaration">; + "'#pragma omp %0' must appear in the scope of the %q1 variable declaration">; def err_omp_var_used : Error< - "'#pragma omp %0' must precede all references to variable %1">; + "'#pragma omp %0' must precede all references to variable %q1">; def err_omp_var_thread_local : Error< "variable %0 cannot be threadprivate because it is thread-local">; -def err_omp_incomplete_type : Error< - "a threadprivate variable must not have incomplete type %0">; - -} // end of sema category +def err_omp_threadprivate_incomplete_type : Error< + "threadprivate variable with incomplete type %0">; +} // end of OpenMP category let CategoryName = "Related Result Type Issue" in { // Objective-C related result type compatibility diff --git a/include/clang/Basic/Linkage.h b/include/clang/Basic/Linkage.h index 01b8db15f5..13d2d24d8e 100644 --- a/include/clang/Basic/Linkage.h +++ b/include/clang/Basic/Linkage.h @@ -62,11 +62,6 @@ enum GVALinkage { GVA_ExplicitTemplateInstantiation }; -/// \brief Determine whether the given linkage is semantically external. -inline bool isExternalLinkage(Linkage L) { - return L == UniqueExternalLinkage || L == ExternalLinkage; -} - /// \brief Compute the minimum linkage given two linages. inline Linkage minLinkage(Linkage L1, Linkage L2) { return L1 < L2? L1 : L2; diff --git a/include/clang/Format/Format.h b/include/clang/Format/Format.h index 9d17c77db7..ba44c04024 100644 --- a/include/clang/Format/Format.h +++ b/include/clang/Format/Format.h @@ -94,6 +94,27 @@ struct FormatStyle { /// Otherwise puts them into the right-most column. bool AlignEscapedNewlinesLeft; + /// \brief The number of characters to use for indentation. + unsigned IndentWidth; + + /// \brief If true, \c IndentWidth consecutive spaces will be replaced with + /// tab characters. + bool UseTab; + + /// \brief Different ways to attach braces to their surrounding context. + enum BraceBreakingStyle { + /// Always attach braces to surrounding context. + BS_Attach, + /// Like \c Attach, but break before braces on function, namespace and + /// class definitions. + BS_Linux, + /// Like \c Attach, but break before function definitions. + BS_Stroustrup + }; + + /// \brief The brace breaking style to use. + BraceBreakingStyle BreakBeforeBraces; + bool operator==(const FormatStyle &R) const { return AccessModifierOffset == R.AccessModifierOffset && AlignEscapedNewlinesLeft == R.AlignEscapedNewlinesLeft && @@ -113,7 +134,10 @@ struct FormatStyle { PenaltyReturnTypeOnItsOwnLine == R.PenaltyReturnTypeOnItsOwnLine && PointerBindsToType == R.PointerBindsToType && SpacesBeforeTrailingComments == R.SpacesBeforeTrailingComments && - Standard == R.Standard; + Standard == R.Standard && + IndentWidth == R.IndentWidth && + UseTab == R.UseTab && + BreakBeforeBraces == R.BreakBeforeBraces; } }; @@ -153,15 +177,11 @@ std::string configurationAsText(const FormatStyle &Style); /// everything that might influence its formatting or might be influenced by its /// formatting. /// -/// \param DiagClient A custom DiagnosticConsumer. Can be 0, in this case -/// diagnostic is output to llvm::errs(). -/// /// Returns the \c Replacements necessary to make all \p Ranges comply with /// \p Style. tooling::Replacements reformat(const FormatStyle &Style, Lexer &Lex, SourceManager &SourceMgr, - std::vector<CharSourceRange> Ranges, - DiagnosticConsumer *DiagClient = 0); + std::vector<CharSourceRange> Ranges); /// \brief Returns the \c LangOpts that the formatter expects you to set. LangOptions getFormattingLangOpts(); diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index 9bd0ef31e0..1fc56ce5f3 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -456,7 +456,7 @@ public: void setASTContext(ASTContext *ctx) { Ctx = ctx; } void setPreprocessor(Preprocessor *pp); - bool hasSema() const { return TheSema; } + bool hasSema() const { return TheSema.isValid(); } Sema &getSema() const { assert(TheSema && "ASTUnit does not have a Sema object!"); return *TheSema; diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h index dbd76066b9..ee4850580d 100644 --- a/include/clang/Frontend/CompilerInstance.h +++ b/include/clang/Frontend/CompilerInstance.h @@ -395,7 +395,7 @@ public: /// @name ASTConsumer /// { - bool hasASTConsumer() const { return Consumer != 0; } + bool hasASTConsumer() const { return Consumer.isValid(); } ASTConsumer &getASTConsumer() const { assert(Consumer && "Compiler instance has no AST consumer!"); @@ -413,7 +413,7 @@ public: /// } /// @name Semantic analysis /// { - bool hasSema() const { return TheSema != 0; } + bool hasSema() const { return TheSema.isValid(); } Sema &getSema() const { assert(TheSema && "Compiler instance has no Sema object!"); @@ -433,7 +433,9 @@ public: /// @name Code Completion /// { - bool hasCodeCompletionConsumer() const { return CompletionConsumer != 0; } + bool hasCodeCompletionConsumer() const { + return CompletionConsumer.isValid(); + } CodeCompleteConsumer &getCodeCompletionConsumer() const { assert(CompletionConsumer && @@ -455,7 +457,7 @@ public: /// @name Frontend timer /// { - bool hasFrontendTimer() const { return FrontendTimer != 0; } + bool hasFrontendTimer() const { return FrontendTimer.isValid(); } llvm::Timer &getFrontendTimer() const { assert(FrontendTimer && "Compiler instance has no frontend timer!"); diff --git a/include/clang/Frontend/FrontendAction.h b/include/clang/Frontend/FrontendAction.h index c67be92472..fee8d95a05 100644 --- a/include/clang/Frontend/FrontendAction.h +++ b/include/clang/Frontend/FrontendAction.h @@ -116,7 +116,7 @@ public: bool isCurrentFileAST() const { assert(!CurrentInput.isEmpty() && "No current file!"); - return CurrentASTUnit != 0; + return CurrentASTUnit.isValid(); } const FrontendInputFile &getCurrentInput() const { diff --git a/include/clang/Lex/HeaderSearch.h b/include/clang/Lex/HeaderSearch.h index c46c8ce6ef..498de09496 100644 --- a/include/clang/Lex/HeaderSearch.h +++ b/include/clang/Lex/HeaderSearch.h @@ -264,7 +264,7 @@ public: /// \brief Checks whether the map exists or not. bool HasIncludeAliasMap() const { - return IncludeAliases; + return IncludeAliases.isValid(); } /// \brief Map the source include name to the dest include name. diff --git a/include/clang/Lex/MacroInfo.h b/include/clang/Lex/MacroInfo.h index 64323b7c76..b4ce4db7dd 100644 --- a/include/clang/Lex/MacroInfo.h +++ b/include/clang/Lex/MacroInfo.h @@ -421,7 +421,7 @@ public: bool isValid() const { return DefDirective != 0; } bool isInvalid() const { return !isValid(); } - operator bool() const { return isValid(); } + LLVM_EXPLICIT operator bool() const { return isValid(); } inline DefInfo getPreviousDefinition(bool AllowHidden = false); const DefInfo getPreviousDefinition(bool AllowHidden = false) const { diff --git a/include/clang/Lex/ModuleMap.h b/include/clang/Lex/ModuleMap.h index 9fe97d0111..bd57ce4877 100644 --- a/include/clang/Lex/ModuleMap.h +++ b/include/clang/Lex/ModuleMap.h @@ -80,7 +80,7 @@ class ModuleMap { // \brief Whether this known header is valid (i.e., it has an // associated module). - operator bool() const { return Storage.getPointer() != 0; } + LLVM_EXPLICIT operator bool() const { return Storage.getPointer() != 0; } }; typedef llvm::DenseMap<const FileEntry *, KnownHeader> HeadersMap; diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index c5981777cd..89cb696f62 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -1400,7 +1400,7 @@ private: bool InCachingLexMode() const { // If the Lexer pointers are 0 and IncludeMacroStack is empty, it means // that we are past EOF, not that we are in CachingLex mode. - return CurPPLexer == 0 && CurTokenLexer == 0 && CurPTHLexer == 0 && + return !CurPPLexer && !CurTokenLexer && !CurPTHLexer && !IncludeMacroStack.empty(); } void EnterCachingLexMode(); diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 72acacf5ae..1a1d6d2ae1 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -2138,9 +2138,18 @@ private: //===--------------------------------------------------------------------===// // OpenMP: Directives and clauses. + /// \brief Parses declarative OpenMP directives. DeclGroupPtrTy ParseOpenMPDeclarativeDirective(); + /// \brief Parses simple list of variables. + /// + /// \param Kind Kind of the directive. + /// \param [out] VarList List of referenced variables. + /// \param AllowScopeSpecifier true, if the variables can have fully + /// qualified names. + /// bool ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind, - SmallVectorImpl<DeclarationNameInfo> &IdList); + SmallVectorImpl<Expr *> &VarList, + bool AllowScopeSpecifier); public: bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, bool AllowDestructorName, diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h index 58781ac628..727ceebe8b 100644 --- a/include/clang/Sema/Initialization.h +++ b/include/clang/Sema/Initialization.h @@ -706,6 +706,16 @@ public: /// \brief Array must be initialized with an initializer list or a /// string literal. FK_ArrayNeedsInitListOrStringLiteral, + /// \brief Array must be initialized with an initializer list or a + /// wide string literal. + FK_ArrayNeedsInitListOrWideStringLiteral, + /// \brief Initializing a wide char array with narrow string literal. + FK_NarrowStringIntoWideCharArray, + /// \brief Initializing char array with wide string literal. + FK_WideStringIntoCharArray, + /// \brief Initializing wide char array with incompatible wide string + /// literal. + FK_IncompatWideStringIntoWideChar, /// \brief Array type mismatch. FK_ArrayTypeMismatch, /// \brief Non-constant array initializer @@ -841,7 +851,7 @@ public: void setSequenceKind(enum SequenceKind SK) { SequenceKind = SK; } /// \brief Determine whether the initialization sequence is valid. - operator bool() const { return !Failed(); } + LLVM_EXPLICIT operator bool() const { return !Failed(); } /// \brief Determine whether the initialization sequence is invalid. bool Failed() const { return SequenceKind == FailedSequence; } diff --git a/include/clang/Sema/Ownership.h b/include/clang/Sema/Ownership.h index c3d1f4e0b7..92c486db36 100644 --- a/include/clang/Sema/Ownership.h +++ b/include/clang/Sema/Ownership.h @@ -65,7 +65,7 @@ namespace clang { Ptr = Traits::getAsVoidPointer(P); } - operator bool() const { return Ptr != 0; } + LLVM_EXPLICIT operator bool() const { return Ptr != 0; } void *getAsOpaquePtr() const { return Ptr; } static OpaquePtr getFromOpaquePtr(void *P) { return OpaquePtr(P); } diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 8e1ebd844e..61b91c5962 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -216,7 +216,7 @@ class Sema { // it will keep having external linkage. If it has internal linkage, we // will not link it. Since it has no previous decls, it will remain // with internal linkage. - return !Old->isHidden() || New->hasExternalLinkage(); + return !Old->isHidden() || New->isExternallyVisible(); } public: @@ -5994,7 +5994,7 @@ public: /// \brief Determines whether we have exceeded the maximum /// recursive template instantiations. - operator bool() const { return Invalid; } + LLVM_EXPLICIT operator bool() const { return Invalid; } private: Sema &SemaRef; @@ -6682,16 +6682,19 @@ public: unsigned SpellingListIndex, bool IsPackExpansion); // OpenMP directives and clauses. - + /// \brief Called on correct id-expression from the '#pragma omp + /// threadprivate'. + ExprResult ActOnOpenMPIdExpression(Scope *CurScope, + CXXScopeSpec &ScopeSpec, + const DeclarationNameInfo &Id); /// \brief Called on well-formed '#pragma omp threadprivate'. DeclGroupPtrTy ActOnOpenMPThreadprivateDirective( - SourceLocation Loc, - Scope *CurScope, - ArrayRef<DeclarationNameInfo> IdList); - /// \brief Build a new OpenMPThreadPrivateDecl and check its correctness. + SourceLocation Loc, + ArrayRef<Expr *> VarList); + // \brief Builds a new OpenMPThreadPrivateDecl and checks its correctness. OMPThreadPrivateDecl *CheckOMPThreadPrivateDecl( - SourceLocation Loc, - ArrayRef<DeclRefExpr *> VarList); + SourceLocation Loc, + ArrayRef<Expr *> VarList); /// \brief The kind of conversion being performed. enum CheckedConversionKind { diff --git a/include/clang/Sema/TypoCorrection.h b/include/clang/Sema/TypoCorrection.h index 5fbfba2d5d..59f3417605 100644 --- a/include/clang/Sema/TypoCorrection.h +++ b/include/clang/Sema/TypoCorrection.h @@ -140,7 +140,7 @@ public: } /// \brief Returns whether this TypoCorrection has a non-empty DeclarationName - operator bool() const { return bool(CorrectionName); } + LLVM_EXPLICIT operator bool() const { return bool(CorrectionName); } /// \brief Mark this TypoCorrection as being a keyword. /// Since addCorrectionDeclsand setCorrectionDecl don't allow NULL to be diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index bb59784dff..073baf514c 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -1232,7 +1232,7 @@ public: void setDeserializationListener(ASTDeserializationListener *Listener); /// \brief Determine whether this AST reader has a global index. - bool hasGlobalIndex() const { return GlobalIndex; } + bool hasGlobalIndex() const { return GlobalIndex.isValid(); } /// \brief Attempts to load the global index. /// diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h index a80b5a7a24..09ee005af7 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h @@ -504,7 +504,7 @@ public: } bool hasCallStackHint() { - return (CallStackHint != 0); + return CallStackHint.isValid(); } /// Produce the hint for the given node. The node contains diff --git a/include/clang/StaticAnalyzer/Core/Checker.h b/include/clang/StaticAnalyzer/Core/Checker.h index 0dbaab033d..219e99cfd4 100644 --- a/include/clang/StaticAnalyzer/Core/Checker.h +++ b/include/clang/StaticAnalyzer/Core/Checker.h @@ -502,10 +502,14 @@ struct ImplicitNullDerefEvent { }; /// \brief A helper class which wraps a boolean value set to false by default. +/// +/// This class should behave exactly like 'bool' except that it doesn't need to +/// be explicitly initialized. struct DefaultBool { bool val; DefaultBool() : val(false) {} - operator bool() const { return val; } + /*implicit*/ operator bool&() { return val; } + /*implicit*/ operator const bool&() const { return val; } DefaultBool &operator=(bool b) { val = b; return *this; } }; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h index b219495d5f..230ce1ea5c 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h @@ -231,7 +231,7 @@ public: bool HandleBinding(StoreManager& SMgr, Store store, const MemRegion* R, SVal val); - operator bool() { return First && Binding; } + LLVM_EXPLICIT operator bool() { return First && Binding; } const MemRegion *getRegion() { return Binding; } }; diff --git a/lib/ARCMigrate/TransUnbridgedCasts.cpp b/lib/ARCMigrate/TransUnbridgedCasts.cpp index fc4a75fdb8..a5752f8157 100644 --- a/lib/ARCMigrate/TransUnbridgedCasts.cpp +++ b/lib/ARCMigrate/TransUnbridgedCasts.cpp @@ -148,7 +148,7 @@ private: if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 && FD->getParent()->isTranslationUnit() && - FD->hasExternalLinkage()) { + FD->isExternallyVisible()) { Expr *Arg = callE->getArg(0); if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) { const Expr *sub = ICE->getSubExpr(); @@ -413,7 +413,7 @@ private: FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 && FD->getParent()->isTranslationUnit() && - FD->hasExternalLinkage()) + FD->isExternallyVisible()) return true; return false; diff --git a/lib/ARCMigrate/Transforms.cpp b/lib/ARCMigrate/Transforms.cpp index 087219535a..6c724af53a 100644 --- a/lib/ARCMigrate/Transforms.cpp +++ b/lib/ARCMigrate/Transforms.cpp @@ -94,7 +94,7 @@ bool trans::isPlusOne(const Expr *E) { if (FD->isGlobal() && FD->getIdentifier() && FD->getParent()->isTranslationUnit() && - FD->hasExternalLinkage() && + FD->isExternallyVisible() && ento::cocoa::isRefType(callE->getType(), "CF", FD->getIdentifier()->getName())) { StringRef fname = FD->getIdentifier()->getName(); @@ -198,7 +198,7 @@ bool trans::isGlobalVar(Expr *E) { E = E->IgnoreParenCasts(); if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) return DRE->getDecl()->getDeclContext()->isFileContext() && - DRE->getDecl()->hasExternalLinkage(); + DRE->getDecl()->isExternallyVisible(); if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E)) return isGlobalVar(condOp->getTrueExpr()) && isGlobalVar(condOp->getFalseExpr()); diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 986bb8c3d2..b19150f048 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -409,6 +409,8 @@ comments::FullComment *ASTContext::cloneFullComment(comments::FullComment *FC, comments::FullComment *ASTContext::getCommentForDecl( const Decl *D, const Preprocessor *PP) const { + if (D->isInvalidDecl()) + return NULL; D = adjustDeclToTemplate(D); const Decl *Canonical = D->getCanonicalDecl(); @@ -1343,8 +1345,28 @@ ASTContext::getTypeInfoDataSizeInChars(QualType T) const { return sizeAndAlign; } +/// getConstantArrayInfoInChars - Performing the computation in CharUnits +/// instead of in bits prevents overflowing the uint64_t for some large arrays. +std::pair<CharUnits, CharUnits> +static getConstantArrayInfoInChars(const ASTContext &Context, + const ConstantArrayType *CAT) { + std::pair<CharUnits, CharUnits> EltInfo = + Context.getTypeInfoInChars(CAT->getElementType()); + uint64_t Size = CAT->getSize().getZExtValue(); + assert((Size == 0 || static_cast<uint64_t>(EltInfo.first.getQuantity()) <= + (uint64_t)(-1)/Size) && + "Overflow in array type char size evaluation"); + uint64_t Width = EltInfo.first.getQuantity() * Size; + unsigned Align = EltInfo.second.getQuantity(); + Width = llvm::RoundUpToAlignment(Width, Align); + return std::make_pair(CharUnits::fromQuantity(Width), + CharUnits::fromQuantity(Align)); +} + std::pair<CharUnits, CharUnits> ASTContext::getTypeInfoInChars(const Type *T) const { + if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(T)) + return getConstantArrayInfoInChars(*this, CAT); std::pair<uint64_t, unsigned> Info = getTypeInfo(T); return std::make_pair(toCharUnitsFromBits(Info.first), toCharUnitsFromBits(Info.second)); @@ -1700,10 +1722,10 @@ int64_t ASTContext::toBits(CharUnits CharSize) const { /// getTypeSizeInChars - Return the size of the specified type, in characters. /// This method does not work on incomplete types. CharUnits ASTContext::getTypeSizeInChars(QualType T) const { - return toCharUnitsFromBits(getTypeSize(T)); + return getTypeInfoInChars(T).first; } CharUnits ASTContext::getTypeSizeInChars(const Type *T) const { - return toCharUnitsFromBits(getTypeSize(T)); + return getTypeInfoInChars(T).first; } /// getTypeAlignInChars - Return the ABI-specified alignment of a type, in @@ -7767,30 +7789,23 @@ QualType ASTContext::GetBuiltinType(unsigned Id, } GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) { - GVALinkage External = GVA_StrongExternal; - - Linkage L = FD->getLinkage(); - switch (L) { - case NoLinkage: - case InternalLinkage: - case UniqueExternalLinkage: + if (!FD->isExternallyVisible()) return GVA_Internal; - - case ExternalLinkage: - switch (FD->getTemplateSpecializationKind()) { - case TSK_Undeclared: - case TSK_ExplicitSpecialization: - External = GVA_StrongExternal; - break; - case TSK_ExplicitInstantiationDefinition: - return GVA_ExplicitTemplateInstantiation; + GVALinkage External = GVA_StrongExternal; + switch (FD->getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + External = GVA_StrongExternal; + break; + + case TSK_ExplicitInstantiationDefinition: + return GVA_ExplicitTemplateInstantiation; - case TSK_ExplicitInstantiationDeclaration: - case TSK_ImplicitInstantiation: - External = GVA_TemplateInstantiation; - break; - } + case TSK_ExplicitInstantiationDeclaration: + case TSK_ImplicitInstantiation: + External = GVA_TemplateInstantiation; + break; } if (!FD->isInlined()) @@ -7820,6 +7835,9 @@ GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) { } GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) { + if (!VD->isExternallyVisible()) + return GVA_Internal; + // If this is a static data member, compute the kind of template // specialization. Otherwise, this variable is not part of a // template. @@ -7827,30 +7845,20 @@ GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) { if (VD->isStaticDataMember()) TSK = VD->getTemplateSpecializationKind(); - Linkage L = VD->getLinkage(); + switch (TSK) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + return GVA_StrongExternal; - switch (L) { - case NoLinkage: - case InternalLinkage: - case UniqueExternalLinkage: - return GVA_Internal; + case TSK_ExplicitInstantiationDeclaration: + llvm_unreachable("Variable should not be instantiated"); + // Fall through to treat this like any other instantiation. - case ExternalLinkage: - switch (TSK) { - case TSK_Undeclared: - case TSK_ExplicitSpecialization: - return GVA_StrongExternal; + case TSK_ExplicitInstantiationDefinition: + return GVA_ExplicitTemplateInstantiation; - case TSK_ExplicitInstantiationDeclaration: - llvm_unreachable("Variable should not be instantiated"); - // Fall through to treat this like any other instantiation. - - case TSK_ExplicitInstantiationDefinition: - return GVA_ExplicitTemplateInstantiation; - - case TSK_ImplicitInstantiation: - return GVA_TemplateInstantiation; - } + case TSK_ImplicitInstantiation: + return GVA_TemplateInstantiation; } llvm_unreachable("Invalid Linkage!"); @@ -7986,7 +7994,8 @@ size_t ASTContext::getSideTableAllocatedMemory() const { void ASTContext::addUnnamedTag(const TagDecl *Tag) { // FIXME: This mangling should be applied to function local classes too if (!Tag->getName().empty() || Tag->getTypedefNameForAnonDecl() || - !isa<CXXRecordDecl>(Tag->getParent()) || Tag->getLinkage() != ExternalLinkage) + !isa<CXXRecordDecl>(Tag->getParent()) || + !Tag->isExternallyVisible()) return; std::pair<llvm::DenseMap<const DeclContext *, unsigned>::iterator, bool> P = diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp index 766a7a995b..e0f552ba67 100644 --- a/lib/AST/ASTDiagnostic.cpp +++ b/lib/AST/ASTDiagnostic.cpp @@ -300,8 +300,7 @@ void clang::FormatASTNodeDiagnosticArgument( assert(ModLen == 0 && ArgLen == 0 && "Invalid modifier for DeclarationName argument"); - DeclarationName N = DeclarationName::getFromOpaqueInteger(Val); - N.printName(OS); + OS << DeclarationName::getFromOpaqueInteger(Val); break; } case DiagnosticsEngine::ak_nameddecl: { diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 340cc41f7e..cd974f0d02 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -449,9 +449,7 @@ void ASTDumper::dumpBareDeclRef(const Decl *D) { if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) { ColorScope Color(*this, DeclNameColor); - OS << " '"; - ND->getDeclName().printName(OS); - OS << "'"; + OS << " '" << ND->getDeclName() << '\''; } if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) @@ -1331,7 +1329,7 @@ void ASTDumper::dumpStmt(const Stmt *S) { return; } - setMoreChildren(S->children()); + setMoreChildren(!S->children().empty()); ConstStmtVisitor<ASTDumper>::Visit(S); setMoreChildren(false); for (Stmt::const_child_range CI = S->children(); CI; ++CI) { diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 915eb6feb8..204b9d001c 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -2610,8 +2610,8 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { continue; if (FunctionDecl *FoundFunction = dyn_cast<FunctionDecl>(FoundDecls[I])) { - if (isExternalLinkage(FoundFunction->getLinkage()) && - isExternalLinkage(D->getLinkage())) { + if (FoundFunction->hasExternalFormalLinkage() && + D->hasExternalFormalLinkage()) { if (Importer.IsStructurallyEquivalent(D->getType(), FoundFunction->getType())) { // FIXME: Actually try to merge the body and other attributes. @@ -2878,7 +2878,7 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { if (Importer.IsStructurallyEquivalent(D->getType(), FoundField->getType(), - Name)) { + !Name.isEmpty())) { Importer.Imported(D, FoundField); return FoundField; } @@ -2995,8 +2995,8 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) { if (VarDecl *FoundVar = dyn_cast<VarDecl>(FoundDecls[I])) { // We have found a variable that we may need to merge with. Check it. - if (isExternalLinkage(FoundVar->getLinkage()) && - isExternalLinkage(D->getLinkage())) { + if (FoundVar->hasExternalFormalLinkage() && + D->hasExternalFormalLinkage()) { if (Importer.IsStructurallyEquivalent(D->getType(), FoundVar->getType())) { MergeWithVar = FoundVar; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index ab9d73b917..b8f478728f 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -483,6 +483,10 @@ static bool isSingleLineExternC(const Decl &D) { return false; } +static bool isExternalLinkage(Linkage L) { + return L == UniqueExternalLinkage || L == ExternalLinkage; +} + static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVComputationKind computation) { assert(D->getDeclContext()->getRedeclContext()->isFileContext() && @@ -660,9 +664,20 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // this translation unit. However, we should use the C linkage // rules instead for extern "C" declarations. if (Context.getLangOpts().CPlusPlus && - !Function->isInExternCContext() && - Function->getType()->getLinkage() == UniqueExternalLinkage) - return LinkageInfo::uniqueExternal(); + !Function->isInExternCContext()) { + // Only look at the type-as-written. If this function has an auto-deduced + // return type, we can't compute the linkage of that type because it could + // require looking at the linkage of this function, and we don't need this + // for correctness because the type is not part of the function's + // signature. + // FIXME: This is a hack. We should be able to solve this circularity some + // other way. + QualType TypeAsWritten = Function->getType(); + if (TypeSourceInfo *TSI = Function->getTypeSourceInfo()) + TypeAsWritten = TSI->getType(); + if (TypeAsWritten->getLinkage() == UniqueExternalLinkage) + return LinkageInfo::uniqueExternal(); + } // Consider LV from the template and the template arguments. // We're at file scope, so we do not need to worry about nested @@ -874,7 +889,7 @@ bool NamedDecl::isLinkageValid() const { Linkage(CachedLinkage); } -Linkage NamedDecl::getLinkage() const { +Linkage NamedDecl::getLinkageInternal() const { if (HasCachedLinkage) return Linkage(CachedLinkage); @@ -1278,7 +1293,7 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const { } bool NamedDecl::hasLinkage() const { - return getLinkage() != NoLinkage; + return getLinkageInternal() != NoLinkage; } NamedDecl *NamedDecl::getUnderlyingDeclImpl() { @@ -1502,7 +1517,7 @@ template<typename T> static LanguageLinkage getLanguageLinkageTemplate(const T &D) { // C++ [dcl.link]p1: All function types, function names with external linkage, // and variable names with external linkage have a language linkage. - if (!isExternalLinkage(D.getLinkage())) + if (!D.hasExternalFormalLinkage()) return NoLanguageLinkage; // Language linkage is a C++ concept, but saying that everything else in C has @@ -2304,7 +2319,7 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const { const FunctionDecl *Prev = this; bool FoundBody = false; while ((Prev = Prev->getPreviousDecl())) { - FoundBody |= Prev->Body; + FoundBody |= Prev->Body.isValid(); if (Prev->Body) { // If it's not the case that both 'inline' and 'extern' are @@ -2332,7 +2347,7 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const { const FunctionDecl *Prev = this; bool FoundBody = false; while ((Prev = Prev->getPreviousDecl())) { - FoundBody |= Prev->Body; + FoundBody |= Prev->Body.isValid(); if (RedeclForcesDefC99(Prev)) return false; } diff --git a/lib/AST/DeclOpenMP.cpp b/lib/AST/DeclOpenMP.cpp index c0d10a0f41..522caefe3b 100644 --- a/lib/AST/DeclOpenMP.cpp +++ b/lib/AST/DeclOpenMP.cpp @@ -28,9 +28,9 @@ void OMPThreadPrivateDecl::anchor() { } OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, - ArrayRef<DeclRefExpr *> VL) { + ArrayRef<Expr *> VL) { unsigned Size = sizeof(OMPThreadPrivateDecl) + - (VL.size() * sizeof(DeclRefExpr *)); + (VL.size() * sizeof(Expr *)); void *Mem = C.Allocate(Size, llvm::alignOf<OMPThreadPrivateDecl>()); OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate, @@ -43,7 +43,7 @@ OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C, OMPThreadPrivateDecl *OMPThreadPrivateDecl::CreateDeserialized(ASTContext &C, unsigned ID, unsigned N) { - unsigned Size = sizeof(OMPThreadPrivateDecl) + (N * sizeof(DeclRefExpr *)); + unsigned Size = sizeof(OMPThreadPrivateDecl) + (N * sizeof(Expr *)); void *Mem = AllocateDeserializedDecl(C, ID, Size); OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate, @@ -52,9 +52,9 @@ OMPThreadPrivateDecl *OMPThreadPrivateDecl::CreateDeserialized(ASTContext &C, return D; } -void OMPThreadPrivateDecl::setVars(ArrayRef<DeclRefExpr *> VL) { +void OMPThreadPrivateDecl::setVars(ArrayRef<Expr *> VL) { assert(VL.size() == NumVars && "Number of variables is not the same as the preallocated buffer"); - DeclRefExpr **Vars = reinterpret_cast<DeclRefExpr **>(this + 1); + Expr **Vars = reinterpret_cast<Expr **>(this + 1); std::copy(VL.begin(), VL.end(), Vars); } diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index d47972bc61..1c9fd2d5f6 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -1180,9 +1180,9 @@ void DeclPrinter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) { if (!D->varlist_empty()) { for (OMPThreadPrivateDecl::varlist_iterator I = D->varlist_begin(), E = D->varlist_end(); - I != E; ++I) { + I != E; ++I) { Out << (I == D->varlist_begin() ? '(' : ',') - << *cast<NamedDecl>((*I)->getDecl()); + << *cast<NamedDecl>(cast<DeclRefExpr>(*I)->getDecl()); } Out << ")"; } diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index e4a41b6ffb..e064e23a0a 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -133,6 +133,66 @@ int DeclarationName::compare(DeclarationName LHS, DeclarationName RHS) { llvm_unreachable("Invalid DeclarationName Kind!"); } +raw_ostream &operator<<(raw_ostream &OS, DeclarationName N) { + switch (N.getNameKind()) { + case DeclarationName::Identifier: + if (const IdentifierInfo *II = N.getAsIdentifierInfo()) + OS << II->getName(); + return OS; + + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + return OS << N.getObjCSelector().getAsString(); + + case DeclarationName::CXXConstructorName: { + QualType ClassType = N.getCXXNameType(); + if (const RecordType *ClassRec = ClassType->getAs<RecordType>()) + return OS << *ClassRec->getDecl(); + return OS << ClassType.getAsString(); + } + + case DeclarationName::CXXDestructorName: { + OS << '~'; + QualType Type = N.getCXXNameType(); + if (const RecordType *Rec = Type->getAs<RecordType>()) + return OS << *Rec->getDecl(); + return OS << Type.getAsString(); + } + + case DeclarationName::CXXOperatorName: { + static const char* const OperatorNames[NUM_OVERLOADED_OPERATORS] = { + 0, +#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ + Spelling, +#include "clang/Basic/OperatorKinds.def" + }; + const char *OpName = OperatorNames[N.getCXXOverloadedOperator()]; + assert(OpName && "not an overloaded operator"); + + OS << "operator"; + if (OpName[0] >= 'a' && OpName[0] <= 'z') + OS << ' '; + return OS << OpName; + } + + case DeclarationName::CXXLiteralOperatorName: + return OS << "operator \"\" " << N.getCXXLiteralIdentifier()->getName(); + + case DeclarationName::CXXConversionFunctionName: { + OS << "operator "; + QualType Type = N.getCXXNameType(); + if (const RecordType *Rec = Type->getAs<RecordType>()) + return OS << *Rec->getDecl(); + return OS << Type.getAsString(); + } + case DeclarationName::CXXUsingDirective: + return OS << "<using-directive>"; + } + + llvm_unreachable("Unexpected declaration name kind"); +} + } // end namespace clang DeclarationName::NameKind DeclarationName::getNameKind() const { @@ -180,80 +240,10 @@ bool DeclarationName::isDependentName() const { std::string DeclarationName::getAsString() const { std::string Result; llvm::raw_string_ostream OS(Result); - printName(OS); + OS << *this; return OS.str(); } -void DeclarationName::printName(raw_ostream &OS) const { - switch (getNameKind()) { - case Identifier: - if (const IdentifierInfo *II = getAsIdentifierInfo()) - OS << II->getName(); - return; - - case ObjCZeroArgSelector: - case ObjCOneArgSelector: - case ObjCMultiArgSelector: - OS << getObjCSelector().getAsString(); - return; - - case CXXConstructorName: { - QualType ClassType = getCXXNameType(); - if (const RecordType *ClassRec = ClassType->getAs<RecordType>()) - OS << *ClassRec->getDecl(); - else - OS << ClassType.getAsString(); - return; - } - - case CXXDestructorName: { - OS << '~'; - QualType Type = getCXXNameType(); - if (const RecordType *Rec = Type->getAs<RecordType>()) - OS << *Rec->getDecl(); - else - OS << Type.getAsString(); - return; - } - - case CXXOperatorName: { - static const char* const OperatorNames[NUM_OVERLOADED_OPERATORS] = { - 0, -#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ - Spelling, -#include "clang/Basic/OperatorKinds.def" - }; - const char *OpName = OperatorNames[getCXXOverloadedOperator()]; - assert(OpName && "not an overloaded operator"); - - OS << "operator"; - if (OpName[0] >= 'a' && OpName[0] <= 'z') - OS << ' '; - OS << OpName; - return; - } - - case CXXLiteralOperatorName: - OS << "operator \"\" " << getCXXLiteralIdentifier()->getName(); - return; - - case CXXConversionFunctionName: { - OS << "operator "; - QualType Type = getCXXNameType(); - if (const RecordType *Rec = Type->getAs<RecordType>()) - OS << *Rec->getDecl(); - else - OS << Type.getAsString(); - return; - } - case CXXUsingDirective: - OS << "<using-directive>"; - return; - } - - llvm_unreachable("Unexpected declaration name kind"); -} - QualType DeclarationName::getCXXNameType() const { if (CXXSpecialName *CXXName = getAsCXXSpecialName()) return CXXName->Type; @@ -336,8 +326,7 @@ DeclarationName DeclarationName::getUsingDirectiveName() { } void DeclarationName::dump() const { - printName(llvm::errs()); - llvm::errs() << '\n'; + llvm::errs() << *this << '\n'; } DeclarationNameTable::DeclarationNameTable(const ASTContext &C) : Ctx(C) { @@ -537,7 +526,7 @@ void DeclarationNameInfo::printName(raw_ostream &OS) const { case DeclarationName::CXXOperatorName: case DeclarationName::CXXLiteralOperatorName: case DeclarationName::CXXUsingDirective: - Name.printName(OS); + OS << Name; return; case DeclarationName::CXXConstructorName: @@ -549,9 +538,8 @@ void DeclarationNameInfo::printName(raw_ostream &OS) const { else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) OS << "operator "; OS << TInfo->getType().getAsString(); - } - else - Name.printName(OS); + } else + OS << Name; return; } llvm_unreachable("Unexpected declaration name kind"); diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 15cf5ac4ab..f587dfa93e 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -423,7 +423,7 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, FoundD = 0; std::size_t Size = sizeof(DeclRefExpr); - if (QualifierLoc != 0) + if (QualifierLoc) Size += sizeof(NestedNameSpecifierLoc); if (FoundD) Size += sizeof(NamedDecl *); diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index bf967961aa..3741bf12d5 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -1809,7 +1809,7 @@ struct CompleteObject { assert(Value && "missing value for complete object"); } - operator bool() const { return Value; } + LLVM_EXPLICIT operator bool() const { return Value; } }; /// Find the designated sub-object of an rvalue. @@ -2769,7 +2769,9 @@ enum EvalStmtResult { /// Hit a 'continue' statement. ESR_Continue, /// Hit a 'break' statement. - ESR_Break + ESR_Break, + /// Still scanning for 'case' or 'default' statement. + ESR_CaseNotFound }; } @@ -2803,12 +2805,13 @@ static bool EvaluateCond(EvalInfo &Info, const VarDecl *CondDecl, } static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, - const Stmt *S); + const Stmt *S, const SwitchCase *SC = 0); /// Evaluate the body of a loop, and translate the result as appropriate. static EvalStmtResult EvaluateLoopBody(APValue &Result, EvalInfo &Info, - const Stmt *Body) { - switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, Body)) { + const Stmt *Body, + const SwitchCase *Case = 0) { + switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, Body, Case)) { case ESR_Break: return ESR_Succeeded; case ESR_Succeeded: @@ -2816,17 +2819,127 @@ static EvalStmtResult EvaluateLoopBody(APValue &Result, EvalInfo &Info, return ESR_Continue; case ESR_Failed: case ESR_Returned: + case ESR_CaseNotFound: return ESR; } llvm_unreachable("Invalid EvalStmtResult!"); } +/// Evaluate a switch statement. +static EvalStmtResult EvaluateSwitch(APValue &Result, EvalInfo &Info, + const SwitchStmt *SS) { + // Evaluate the switch condition. + if (SS->getConditionVariable() && + !EvaluateDecl(Info, SS->getConditionVariable())) + return ESR_Failed; + APSInt Value; + if (!EvaluateInteger(SS->getCond(), Value, Info)) + return ESR_Failed; + + // Find the switch case corresponding to the value of the condition. + // FIXME: Cache this lookup. + const SwitchCase *Found = 0; + for (const SwitchCase *SC = SS->getSwitchCaseList(); SC; + SC = SC->getNextSwitchCase()) { + if (isa<DefaultStmt>(SC)) { + Found = SC; + continue; + } + + const CaseStmt *CS = cast<CaseStmt>(SC); + APSInt LHS = CS->getLHS()->EvaluateKnownConstInt(Info.Ctx); + APSInt RHS = CS->getRHS() ? CS->getRHS()->EvaluateKnownConstInt(Info.Ctx) + : LHS; + if (LHS <= Value && Value <= RHS) { + Found = SC; + break; + } + } + + if (!Found) + return ESR_Succeeded; + + // Search the switch body for the switch case and evaluate it from there. + switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, SS->getBody(), Found)) { + case ESR_Break: + return ESR_Succeeded; + case ESR_Succeeded: + case ESR_Continue: + case ESR_Failed: + case ESR_Returned: + return ESR; + case ESR_CaseNotFound: + llvm_unreachable("couldn't find switch case"); + } + llvm_unreachable("Invalid EvalStmtResult!"); +} + // Evaluate a statement. static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, - const Stmt *S) { + const Stmt *S, const SwitchCase *Case) { if (!Info.nextStep(S)) return ESR_Failed; + // If we're hunting down a 'case' or 'default' label, recurse through + // substatements until we hit the label. + if (Case) { + // FIXME: We don't start the lifetime of objects whose initialization we + // jump over. However, such objects must be of class type with a trivial + // default constructor that initialize all subobjects, so must be empty, + // so this almost never matters. + switch (S->getStmtClass()) { + case Stmt::CompoundStmtClass: + // FIXME: Precompute which substatement of a compound statement we + // would jump to, and go straight there rather than performing a + // linear scan each time. + case Stmt::LabelStmtClass: + case Stmt::AttributedStmtClass: + case Stmt::DoStmtClass: + break; + + case Stmt::CaseStmtClass: + case Stmt::DefaultStmtClass: + if (Case == S) + Case = 0; + break; + + case Stmt::IfStmtClass: { + // FIXME: Precompute which side of an 'if' we would jump to, and go + // straight there rather than scanning both sides. + const IfStmt *IS = cast<IfStmt>(S); + EvalStmtResult ESR = EvaluateStmt(Result, Info, IS->getThen(), Case); + if (ESR != ESR_CaseNotFound || !IS->getElse()) + return ESR; + return EvaluateStmt(Result, Info, IS->getElse(), Case); + } + + case Stmt::WhileStmtClass: { + EvalStmtResult ESR = + EvaluateLoopBody(Result, Info, cast<WhileStmt>(S)->getBody(), Case); + if (ESR != ESR_Continue) + return ESR; + break; + } + + case Stmt::ForStmtClass: { + const ForStmt *FS = cast<ForStmt>(S); + EvalStmtResult ESR = + EvaluateLoopBody(Result, Info, FS->getBody(), Case); + if (ESR != ESR_Continue) + return ESR; + if (FS->getInc() && !EvaluateIgnoredValue(Info, FS->getInc())) + return ESR_Failed; + break; + } + + case Stmt::DeclStmtClass: + // FIXME: If the variable has initialization that can't be jumped over, + // bail out of any immediately-surrounding compound-statement too. + default: + return ESR_CaseNotFound; + } + } + // FIXME: Mark all temporaries in the current frame as destroyed at // the end of each full-expression. switch (S->getStmtClass()) { @@ -2865,11 +2978,13 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, const CompoundStmt *CS = cast<CompoundStmt>(S); for (CompoundStmt::const_body_iterator BI = CS->body_begin(), BE = CS->body_end(); BI != BE; ++BI) { - EvalStmtResult ESR = EvaluateStmt(Result, Info, *BI); - if (ESR != ESR_Succeeded) + EvalStmtResult ESR = EvaluateStmt(Result, Info, *BI, Case); + if (ESR == ESR_Succeeded) + Case = 0; + else if (ESR != ESR_CaseNotFound) return ESR; } - return ESR_Succeeded; + return Case ? ESR_CaseNotFound : ESR_Succeeded; } case Stmt::IfStmtClass: { @@ -2909,9 +3024,10 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, const DoStmt *DS = cast<DoStmt>(S); bool Continue; do { - EvalStmtResult ESR = EvaluateLoopBody(Result, Info, DS->getBody()); + EvalStmtResult ESR = EvaluateLoopBody(Result, Info, DS->getBody(), Case); if (ESR != ESR_Continue) return ESR; + Case = 0; if (!EvaluateAsBooleanCondition(DS->getCond(), Continue, Info)) return ESR_Failed; @@ -2983,11 +3099,27 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, return ESR_Succeeded; } + case Stmt::SwitchStmtClass: + return EvaluateSwitch(Result, Info, cast<SwitchStmt>(S)); + case Stmt::ContinueStmtClass: return ESR_Continue; case Stmt::BreakStmtClass: return ESR_Break; + + case Stmt::LabelStmtClass: + return EvaluateStmt(Result, Info, cast<LabelStmt>(S)->getSubStmt(), Case); + + case Stmt::AttributedStmtClass: + // As a general principle, C++11 attributes can be ignored without + // any semantic impact. + return EvaluateStmt(Result, Info, cast<AttributedStmt>(S)->getSubStmt(), + Case); + + case Stmt::CaseStmtClass: + case Stmt::DefaultStmtClass: + return EvaluateStmt(Result, Info, cast<SwitchCase>(S)->getSubStmt(), Case); } } @@ -3029,6 +3161,11 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc, Declaration->isConstexpr()) return false; + // Bail out with no diagnostic if the function declaration itself is invalid. + // We will have produced a relevant diagnostic while parsing it. + if (Declaration->isInvalidDecl()) + return false; + // Can we evaluate this function call? if (Definition && Definition->isConstexpr() && !Definition->isInvalidDecl()) return true; diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index d28aced172..3137f3c8fd 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -405,7 +405,7 @@ bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) { if (DC->isFunctionOrMethod() && D->hasLinkage()) while (!DC->isNamespace() && !DC->isTranslationUnit()) DC = getEffectiveParentContext(DC); - if (DC->isTranslationUnit() && D->getLinkage() != InternalLinkage) + if (DC->isTranslationUnit() && D->getFormalLinkage() != InternalLinkage) return false; } @@ -1053,7 +1053,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, // static void foo(); // This naming convention is the same as that followed by GCC, // though it shouldn't actually matter. - if (ND && ND->getLinkage() == InternalLinkage && + if (ND && ND->getFormalLinkage() == InternalLinkage && getEffectiveDeclContext(ND)->isFileContext()) Out << 'L'; diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index 7c797eef4d..d03060b391 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/lib/AST/MicrosoftMangle.cpp @@ -22,6 +22,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/Basic/ABI.h" #include "clang/Basic/DiagnosticOptions.h" +#include "clang/Basic/TargetInfo.h" #include <map> using namespace clang; @@ -58,19 +59,27 @@ class MicrosoftCXXNameMangler { ASTContext &getASTContext() const { return Context.getASTContext(); } + // FIXME: If we add support for __ptr32/64 qualifiers, then we should push + // this check into mangleQualifiers(). + const bool PointersAre64Bit; + public: enum QualifierMangleMode { QMM_Drop, QMM_Mangle, QMM_Escape, QMM_Result }; MicrosoftCXXNameMangler(MangleContext &C, raw_ostream &Out_) : Context(C), Out(Out_), Structor(0), StructorType(-1), - UseNameBackReferences(true) { } + UseNameBackReferences(true), + PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) == + 64) { } MicrosoftCXXNameMangler(MangleContext &C, raw_ostream &Out_, const CXXDestructorDecl *D, CXXDtorType Type) : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type), - UseNameBackReferences(true) { } + UseNameBackReferences(true), + PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) == + 64) { } raw_ostream &getStream() const { return Out; } @@ -199,7 +208,7 @@ bool MicrosoftMangleContext::shouldMangleDeclName(const NamedDecl *D) { // Variables at global scope with internal linkage are not mangled. if (!FD) { const DeclContext *DC = D->getDeclContext(); - if (DC->isTranslationUnit() && D->getLinkage() == InternalLinkage) + if (DC->isTranslationUnit() && D->getFormalLinkage() == InternalLinkage) return false; } @@ -1228,32 +1237,36 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T, } void MicrosoftCXXNameMangler::mangleFunctionClass(const FunctionDecl *FD) { - // <function-class> ::= A # private: near - // ::= B # private: far - // ::= C # private: static near - // ::= D # private: static far - // ::= E # private: virtual near - // ::= F # private: virtual far - // ::= G # private: thunk near - // ::= H # private: thunk far - // ::= I # protected: near - // ::= J # protected: far - // ::= K # protected: static near - // ::= L # protected: static far - // ::= M # protected: virtual near - // ::= N # protected: virtual far - // ::= O # protected: thunk near - // ::= P # protected: thunk far - // ::= Q # public: near - // ::= R # public: far - // ::= S # public: static near - // ::= T # public: static far - // ::= U # public: virtual near - // ::= V # public: virtual far - // ::= W # public: thunk near - // ::= X # public: thunk far - // ::= Y # global near - // ::= Z # global far + // <function-class> ::= <member-function> E? # E designates a 64-bit 'this' + // # pointer. in 64-bit mode *all* + // # 'this' pointers are 64-bit. + // ::= <global-function> + // <member-function> ::= A # private: near + // ::= B # private: far + // ::= C # private: static near + // ::= D # private: static far + // ::= E # private: virtual near + // ::= F # private: virtual far + // ::= G # private: thunk near + // ::= H # private: thunk far + // ::= I # protected: near + // ::= J # protected: far + // ::= K # protected: static near + // ::= L # protected: static far + // ::= M # protected: virtual near + // ::= N # protected: virtual far + // ::= O # protected: thunk near + // ::= P # protected: thunk far + // ::= Q # public: near + // ::= R # public: far + // ::= S # public: static near + // ::= T # public: static far + // ::= U # public: virtual near + // ::= V # public: virtual far + // ::= W # public: thunk near + // ::= X # public: thunk far + // <global-function> ::= Y # global near + // ::= Z # global far if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { switch (MD->getAccess()) { default: @@ -1281,6 +1294,8 @@ void MicrosoftCXXNameMangler::mangleFunctionClass(const FunctionDecl *FD) { else Out << 'Q'; } + if (PointersAre64Bit && !MD->isStatic()) + Out << 'E'; } else Out << 'Y'; } @@ -1380,9 +1395,9 @@ void MicrosoftCXXNameMangler::mangleType(const TagType *T) { // <type> ::= <array-type> // <array-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers> // [Y <dimension-count> <dimension>+] -// <element-type> # as global -// ::= Q <cvr-qualifiers> [Y <dimension-count> <dimension>+] -// <element-type> # as param +// <element-type> # as global, E is never required +// ::= Q E? <cvr-qualifiers> [Y <dimension-count> <dimension>+] +// <element-type> # as param, E is required for 64-bit // It's supposed to be the other way around, but for some strange reason, it // isn't. Today this behavior is retained for the sole purpose of backwards // compatibility. @@ -1394,6 +1409,8 @@ void MicrosoftCXXNameMangler::mangleDecayedArrayType(const ArrayType *T, manglePointerQualifiers(T->getElementType().getQualifiers()); } else { Out << 'Q'; + if (PointersAre64Bit) + Out << 'E'; } mangleType(T->getElementType(), SourceRange()); } @@ -1494,10 +1511,13 @@ void MicrosoftCXXNameMangler::mangleType( } // <type> ::= <pointer-type> -// <pointer-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers> <type> +// <pointer-type> ::= E? <pointer-cvr-qualifiers> <cvr-qualifiers> <type> +// # the E is required for 64-bit non static pointers void MicrosoftCXXNameMangler::mangleType(const PointerType *T, SourceRange Range) { QualType PointeeTy = T->getPointeeType(); + if (PointersAre64Bit && !T->getPointeeType()->isFunctionType()) + Out << 'E'; mangleType(PointeeTy, Range); } void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T, @@ -1508,18 +1528,24 @@ void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T, } // <type> ::= <reference-type> -// <reference-type> ::= A <cvr-qualifiers> <type> +// <reference-type> ::= A E? <cvr-qualifiers> <type> +// # the E is required for 64-bit non static lvalue references void MicrosoftCXXNameMangler::mangleType(const LValueReferenceType *T, SourceRange Range) { Out << 'A'; + if (PointersAre64Bit && !T->getPointeeType()->isFunctionType()) + Out << 'E'; mangleType(T->getPointeeType(), Range); } // <type> ::= <r-value-reference-type> -// <r-value-reference-type> ::= $$Q <cvr-qualifiers> <type> +// <r-value-reference-type> ::= $$Q E? <cvr-qualifiers> <type> +// # the E is required for 64-bit non static rvalue references void MicrosoftCXXNameMangler::mangleType(const RValueReferenceType *T, SourceRange Range) { Out << "$$Q"; + if (PointersAre64Bit && !T->getPointeeType()->isFunctionType()) + Out << 'E'; mangleType(T->getPointeeType(), Range); } diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index 42c3ba31bc..eb39d08424 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -211,7 +211,7 @@ void EmptySubobjectMap::AddSubobjectAtOffset(const CXXRecordDecl *RD, if (!RD->isEmpty()) return; - // If we have empty structures inside an union, we can assign both + // If we have empty structures inside a union, we can assign both // the same offset. Just avoid pushing them twice in the list. ClassVectorTy& Classes = EmptyClassOffsets[Offset]; if (std::find(Classes.begin(), Classes.end(), RD) != Classes.end()) @@ -2354,7 +2354,7 @@ static const CXXMethodDecl *computeKeyFunction(ASTContext &Context, // A class that is not externally visible doesn't have a key function. (Or // at least, there's no point to assigning a key function to such a class; // this doesn't affect the ABI.) - if (RD->getLinkage() != ExternalLinkage) + if (!RD->isExternallyVisible()) return 0; // Template instantiations don't have key functions,see Itanium C++ ABI 5.2.6. diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index a1f0b08494..eacf367818 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -2124,7 +2124,7 @@ static CachedProperties computeCachedProperties(const Type *T) { // - it is a class or enumeration type that is named (or has a name // for linkage purposes (7.1.3)) and the name has linkage; or // - it is a specialization of a class template (14); or - Linkage L = Tag->getLinkage(); + Linkage L = Tag->getLinkageInternal(); bool IsLocalOrUnnamed = Tag->getDeclContext()->isFunctionOrMethod() || !Tag->hasNameForLinkage(); @@ -2166,7 +2166,7 @@ static CachedProperties computeCachedProperties(const Type *T) { return result; } case Type::ObjCInterface: { - Linkage L = cast<ObjCInterfaceType>(T)->getDecl()->getLinkage(); + Linkage L = cast<ObjCInterfaceType>(T)->getDecl()->getLinkageInternal(); return CachedProperties(L, false); } case Type::ObjCObject: diff --git a/lib/ASTMatchers/ASTMatchFinder.cpp b/lib/ASTMatchers/ASTMatchFinder.cpp index 6ebd736e3c..eccc9cd4d3 100644 --- a/lib/ASTMatchers/ASTMatchFinder.cpp +++ b/lib/ASTMatchers/ASTMatchFinder.cpp @@ -744,6 +744,14 @@ void MatchFinder::addMatcher(const TypeLocMatcher &NodeMatch, new TypeLocMatcher(NodeMatch), Action)); } +bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch, + MatchCallback *Action) { + MatcherCallbackPairs.push_back(std::make_pair(NodeMatch.clone(), Action)); + // TODO: Do runtime type checking to make sure the matcher is one of the valid + // top-level matchers. + return true; +} + ASTConsumer *MatchFinder::newASTConsumer() { return new internal::MatchASTConsumer(&MatcherCallbackPairs, ParsingDone); } diff --git a/lib/ASTMatchers/CMakeLists.txt b/lib/ASTMatchers/CMakeLists.txt index 86560d61c9..4a390a8fc3 100644 --- a/lib/ASTMatchers/CMakeLists.txt +++ b/lib/ASTMatchers/CMakeLists.txt @@ -1,3 +1,5 @@ +add_subdirectory(Dynamic) + set(LLVM_LINK_COMPONENTS support) add_clang_library(clangASTMatchers diff --git a/lib/ASTMatchers/Dynamic/CMakeLists.txt b/lib/ASTMatchers/Dynamic/CMakeLists.txt new file mode 100644 index 0000000000..843341b297 --- /dev/null +++ b/lib/ASTMatchers/Dynamic/CMakeLists.txt @@ -0,0 +1,16 @@ +set(LLVM_LINK_COMPONENTS support) + +add_clang_library(clangDynamicASTMatchers + Diagnostics.cpp + VariantValue.cpp + Parser.cpp + Registry.cpp + ) + +add_dependencies(clangDynamicASTMatchers + clangASTMatchers + ) + +target_link_libraries(clangDynamicASTMatchers + clangASTMatchers + ) diff --git a/lib/ASTMatchers/Dynamic/Diagnostics.cpp b/lib/ASTMatchers/Dynamic/Diagnostics.cpp new file mode 100644 index 0000000000..fb3cac370f --- /dev/null +++ b/lib/ASTMatchers/Dynamic/Diagnostics.cpp @@ -0,0 +1,113 @@ +//===--- Diagnostics.cpp - Helper class for error diagnostics -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/ASTMatchers/Dynamic/Diagnostics.h" + +namespace clang { +namespace ast_matchers { +namespace dynamic { + +Diagnostics::ArgStream & +Diagnostics::ArgStream::operator<<(const Twine &Arg) { + Out->push_back(Arg.str()); + return *this; +} + +Diagnostics::ArgStream Diagnostics::pushErrorFrame(const SourceRange &Range, + ErrorType Error) { + Frames.insert(Frames.begin(), ErrorFrame()); + ErrorFrame &Last = Frames.front(); + Last.Range = Range; + Last.Type = Error; + ArgStream Out = { &Last.Args }; + return Out; +} + +StringRef ErrorTypeToString(Diagnostics::ErrorType Type) { + switch (Type) { + case Diagnostics::ET_RegistryNotFound: + return "Matcher not found: $0"; + case Diagnostics::ET_RegistryWrongArgCount: + return "Incorrect argument count. (Expected = $0) != (Actual = $1)"; + case Diagnostics::ET_RegistryWrongArgType: + return "Incorrect type on function $0 for arg $1."; + + case Diagnostics::ET_ParserStringError: + return "Error parsing string token: <$0>"; + case Diagnostics::ET_ParserMatcherArgFailure: + return "Error parsing argument $0 for matcher $1."; + case Diagnostics::ET_ParserMatcherFailure: + return "Error building matcher $0."; + case Diagnostics::ET_ParserNoOpenParen: + return "Error parsing matcher. Found token <$0> while looking for '('."; + case Diagnostics::ET_ParserNoCloseParen: + return "Error parsing matcher. Found end-of-code while looking for ')'."; + case Diagnostics::ET_ParserNoComma: + return "Error parsing matcher. Found token <$0> while looking for ','."; + case Diagnostics::ET_ParserNoCode: + return "End of code found while looking for token."; + case Diagnostics::ET_ParserNotAMatcher: + return "Input value is not a matcher expression."; + case Diagnostics::ET_ParserInvalidToken: + return "Invalid token <$0> found when looking for a value."; + + case Diagnostics::ET_None: + return "<N/A>"; + } + llvm_unreachable("Unknown ErrorType value."); +} + +std::string FormatErrorString(StringRef FormatString, + ArrayRef<std::string> Args) { + std::string Out; + while (!FormatString.empty()) { + std::pair<StringRef, StringRef> Pieces = FormatString.split("$"); + Out += Pieces.first.str(); + if (Pieces.second.empty()) break; + + const char Next = Pieces.second.front(); + FormatString = Pieces.second.drop_front(); + if (Next >= '0' && Next <= '9') { + const unsigned Index = Next - '0'; + if (Index < Args.size()) { + Out += Args[Index]; + } else { + Out += "<Argument_Not_Provided>"; + } + } + } + return Out; +} + +std::string Diagnostics::ErrorFrame::ToString() const { + StringRef FormatString = ErrorTypeToString(Type); + std::string ErrorOut = FormatErrorString(FormatString, Args); + if (Range.Start.Line > 0 && Range.Start.Column > 0) + return (Twine(Range.Start.Line) + ":" + Twine(Range.Start.Column) + ": " + + ErrorOut).str(); + return ErrorOut; +} + +std::string Diagnostics::ToString() const { + if (Frames.empty()) return ""; + return Frames[Frames.size() - 1].ToString(); +} + +std::string Diagnostics::ToStringFull() const { + std::string Result; + for (size_t i = 0, end = Frames.size(); i != end; ++i) { + if (i > 0) Result += "\n"; + Result += Frames[i].ToString(); + } + return Result; +} + +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang diff --git a/lib/ASTMatchers/Dynamic/Makefile b/lib/ASTMatchers/Dynamic/Makefile new file mode 100644 index 0000000000..a57d752229 --- /dev/null +++ b/lib/ASTMatchers/Dynamic/Makefile @@ -0,0 +1,13 @@ +##===- clang/lib/ASTMatchers/Dynamic/Makefile --------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +CLANG_LEVEL := ../../.. +LIBRARYNAME := clangDynamicASTMatchers + +include $(CLANG_LEVEL)/Makefile diff --git a/lib/ASTMatchers/Dynamic/Marshallers.h b/lib/ASTMatchers/Dynamic/Marshallers.h new file mode 100644 index 0000000000..e75a175738 --- /dev/null +++ b/lib/ASTMatchers/Dynamic/Marshallers.h @@ -0,0 +1,223 @@ +//===--- Marshallers.h - Generic matcher function marshallers -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Functions templates and classes to wrap matcher construct functions. +/// +/// A collection of template function and classes that provide a generic +/// marshalling layer on top of matcher construct functions. +/// These are used by the registry to export all marshaller constructors with +/// the same generic interface. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_MARSHALLERS_H +#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_MARSHALLERS_H + +#include <list> +#include <string> +#include <vector> + +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/ASTMatchers/Dynamic/Diagnostics.h" +#include "clang/ASTMatchers/Dynamic/VariantValue.h" +#include "clang/Basic/LLVM.h" +#include "llvm/Support/type_traits.h" + +namespace clang { +namespace ast_matchers { +namespace dynamic { + +namespace internal { + +/// \brief Helper template class to just from argument type to the right is/get +/// functions in VariantValue. +/// Used to verify and extract the matcher arguments below. +template <class T> struct ArgTypeTraits; +template <class T> struct ArgTypeTraits<const T &> : public ArgTypeTraits<T> { +}; + +template <> struct ArgTypeTraits<std::string> { + static bool is(const VariantValue &Value) { return Value.isString(); } + static const std::string &get(const VariantValue &Value) { + return Value.getString(); + } +}; + +template <class T> struct ArgTypeTraits<ast_matchers::internal::Matcher<T> > { + static bool is(const VariantValue &Value) { return Value.isMatcher(); } + static ast_matchers::internal::Matcher<T> get(const VariantValue &Value) { + return Value.getTypedMatcher<T>(); + } + +}; + +/// \brief Generic MatcherCreate interface. +/// +/// Provides a \c run() method that constructs the matcher from the provided +/// arguments. +class MatcherCreateCallback { +public: + virtual ~MatcherCreateCallback() {} + virtual DynTypedMatcher *run(const SourceRange &NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error) const = 0; +}; + +/// \brief Simple callback implementation. Marshaller and function are provided. +/// +/// \param Marshaller Function to unpack the arguments and call \c Func +/// \param Func Matcher construct function. This is the function that +/// compile-time matcher expressions would use to create the matcher. +template <typename MarshallerType, typename FuncType> +class FixedArgCountMatcherCreateCallback : public MatcherCreateCallback { +public: + FixedArgCountMatcherCreateCallback(MarshallerType Marshaller, FuncType Func, + StringRef MatcherName) + : Marshaller(Marshaller), Func(Func), MatcherName(MatcherName.str()) {} + + DynTypedMatcher *run(const SourceRange &NameRange, + ArrayRef<ParserValue> Args, Diagnostics *Error) const { + return Marshaller(Func, MatcherName, NameRange, Args, Error); + } + +private: + const MarshallerType Marshaller; + const FuncType Func; + const std::string MatcherName; +}; + +/// \brief Helper function to do template argument deduction. +template <typename MarshallerType, typename FuncType> +MatcherCreateCallback * +createMarshallerCallback(MarshallerType Marshaller, FuncType Func, + StringRef MatcherName) { + return new FixedArgCountMatcherCreateCallback<MarshallerType, FuncType>( + Marshaller, Func, MatcherName); +} + +/// \brief Helper macros to check the arguments on all marshaller functions. +#define CHECK_ARG_COUNT(count) \ + if (Args.size() != count) { \ + Error->pushErrorFrame(NameRange, Error->ET_RegistryWrongArgCount) \ + << count << Args.size(); \ + return NULL; \ + } + +#define CHECK_ARG_TYPE(index, type) \ + if (!ArgTypeTraits<type>::is(Args[index].Value)) { \ + Error->pushErrorFrame(Args[index].Range, Error->ET_RegistryWrongArgType) \ + << MatcherName << (index + 1); \ + return NULL; \ + } + +/// \brief Metafunction to normalize argument types. +/// +/// We need to remove the const& out of the function parameters to be able to +/// find values on VariantValue. +template <typename T> +struct remove_const_ref : + public llvm::remove_const<typename llvm::remove_reference<T>::type> { +}; + +/// \brief 0-arg marshaller function. +template <typename ReturnType> +DynTypedMatcher *matcherMarshall0(ReturnType (*Func)(), StringRef MatcherName, + const SourceRange &NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error) { + CHECK_ARG_COUNT(0); + return Func().clone(); +} + +/// \brief 1-arg marshaller function. +template <typename ReturnType, typename InArgType1> +DynTypedMatcher *matcherMarshall1(ReturnType (*Func)(InArgType1), + StringRef MatcherName, + const SourceRange &NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error) { + typedef typename remove_const_ref<InArgType1>::type ArgType1; + CHECK_ARG_COUNT(1); + CHECK_ARG_TYPE(0, ArgType1); + return Func(ArgTypeTraits<ArgType1>::get(Args[0].Value)).clone(); +} + +/// \brief Variadic marshaller function. +template <typename BaseType, typename DerivedType> +class VariadicMatcherCreateCallback : public MatcherCreateCallback { +public: + explicit VariadicMatcherCreateCallback(StringRef MatcherName) + : MatcherName(MatcherName.str()) {} + + typedef ast_matchers::internal::Matcher<DerivedType> DerivedMatcherType; + + DynTypedMatcher *run(const SourceRange &NameRange, ArrayRef<ParserValue> Args, + Diagnostics *Error) const { + std::list<DerivedMatcherType> References; + std::vector<const DerivedMatcherType *> InnerArgs(Args.size()); + for (size_t i = 0, e = Args.size(); i != e; ++i) { + CHECK_ARG_TYPE(i, DerivedMatcherType); + References.push_back( + ArgTypeTraits<DerivedMatcherType>::get(Args[i].Value)); + InnerArgs[i] = &References.back(); + } + return ast_matchers::internal::makeDynCastAllOfComposite<BaseType>( + ArrayRef<const DerivedMatcherType *>(InnerArgs)).clone(); + } + +private: + const std::string MatcherName; +}; + +#undef CHECK_ARG_COUNT +#undef CHECK_ARG_TYPE + +/// Helper functions to select the appropriate marshaller functions. +/// They detects the number of arguments, arguments types and return type. + +/// \brief 0-arg overload +template <typename ReturnType> +MatcherCreateCallback *makeMatcherAutoMarshall(ReturnType (*Func)(), + StringRef MatcherName) { + return createMarshallerCallback(matcherMarshall0<ReturnType>, Func, + MatcherName); +} + +/// \brief 1-arg overload +template <typename ReturnType, typename ArgType1> +MatcherCreateCallback *makeMatcherAutoMarshall(ReturnType (*Func)(ArgType1), + StringRef MatcherName) { + return createMarshallerCallback(matcherMarshall1<ReturnType, ArgType1>, Func, + MatcherName); +} + +/// \brief Variadic overload. +template <typename MatcherType> +MatcherCreateCallback *makeMatcherAutoMarshall( + ast_matchers::internal::VariadicAllOfMatcher<MatcherType> Func, + StringRef MatcherName) { + return new VariadicMatcherCreateCallback<MatcherType, MatcherType>( + MatcherName); +} + +template <typename BaseType, typename MatcherType> +MatcherCreateCallback * +makeMatcherAutoMarshall(ast_matchers::internal::VariadicDynCastAllOfMatcher< + BaseType, MatcherType> Func, + StringRef MatcherName) { + return new VariadicMatcherCreateCallback<BaseType, MatcherType>(MatcherName); +} + +} // namespace internal +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang + +#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_MARSHALLERS_H diff --git a/lib/ASTMatchers/Dynamic/Parser.cpp b/lib/ASTMatchers/Dynamic/Parser.cpp new file mode 100644 index 0000000000..1678820da0 --- /dev/null +++ b/lib/ASTMatchers/Dynamic/Parser.cpp @@ -0,0 +1,332 @@ +//===--- Parser.cpp - Matcher expression parser -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Recursive parser implementation for the matcher expression grammar. +/// +//===----------------------------------------------------------------------===// + +#include <string> +#include <vector> + +#include "clang/ASTMatchers/Dynamic/Parser.h" +#include "clang/ASTMatchers/Dynamic/Registry.h" +#include "clang/Basic/CharInfo.h" +#include "llvm/ADT/Twine.h" + +namespace clang { +namespace ast_matchers { +namespace dynamic { + +/// \brief Simple structure to hold information for one token from the parser. +struct Parser::TokenInfo { + /// \brief Different possible tokens. + enum TokenKind { + TK_Eof = 0, + TK_OpenParen = 1, + TK_CloseParen = 2, + TK_Comma = 3, + TK_Literal = 4, + TK_Ident = 5, + TK_InvalidChar = 6, + TK_Error = 7 + }; + + TokenInfo() : Text(), Kind(TK_Eof), Range(), Value() {} + + StringRef Text; + TokenKind Kind; + SourceRange Range; + VariantValue Value; +}; + +/// \brief Simple tokenizer for the parser. +class Parser::CodeTokenizer { +public: + explicit CodeTokenizer(StringRef MatcherCode, Diagnostics *Error) + : Code(MatcherCode), StartOfLine(MatcherCode), Line(1), Error(Error) { + NextToken = getNextToken(); + } + + /// \brief Returns but doesn't consume the next token. + const TokenInfo &peekNextToken() const { return NextToken; } + + /// \brief Consumes and returns the next token. + TokenInfo consumeNextToken() { + TokenInfo ThisToken = NextToken; + NextToken = getNextToken(); + return ThisToken; + } + + TokenInfo::TokenKind nextTokenKind() const { return NextToken.Kind; } + +private: + TokenInfo getNextToken() { + consumeWhitespace(); + TokenInfo Result; + Result.Range.Start = currentLocation(); + + if (Code.empty()) { + Result.Kind = TokenInfo::TK_Eof; + Result.Text = ""; + return Result; + } + + switch (Code[0]) { + case ',': + Result.Kind = TokenInfo::TK_Comma; + Result.Text = Code.substr(0, 1); + Code = Code.drop_front(); + break; + case '(': + Result.Kind = TokenInfo::TK_OpenParen; + Result.Text = Code.substr(0, 1); + Code = Code.drop_front(); + break; + case ')': + Result.Kind = TokenInfo::TK_CloseParen; + Result.Text = Code.substr(0, 1); + Code = Code.drop_front(); + break; + + case '"': + case '\'': + // Parse a string literal. + consumeStringLiteral(&Result); + break; + + default: + if (isAlphanumeric(Code[0])) { + // Parse an identifier + size_t TokenLength = 1; + while (TokenLength < Code.size() && isAlphanumeric(Code[TokenLength])) + ++TokenLength; + Result.Kind = TokenInfo::TK_Ident; + Result.Text = Code.substr(0, TokenLength); + Code = Code.drop_front(TokenLength); + } else { + Result.Kind = TokenInfo::TK_InvalidChar; + Result.Text = Code.substr(0, 1); + Code = Code.drop_front(1); + } + break; + } + + Result.Range.End = currentLocation(); + return Result; + } + + /// \brief Consume a string literal. + /// + /// \c Code must be positioned at the start of the literal (the opening + /// quote). Consumed until it finds the same closing quote character. + void consumeStringLiteral(TokenInfo *Result) { + bool InEscape = false; + const char Marker = Code[0]; + for (size_t Length = 1, Size = Code.size(); Length != Size; ++Length) { + if (InEscape) { + InEscape = false; + continue; + } + if (Code[Length] == '\\') { + InEscape = true; + continue; + } + if (Code[Length] == Marker) { + Result->Kind = TokenInfo::TK_Literal; + Result->Text = Code.substr(0, Length + 1); + Result->Value = Code.substr(1, Length - 1).str(); + Code = Code.drop_front(Length + 1); + return; + } + } + + StringRef ErrorText = Code; + Code = Code.drop_front(Code.size()); + SourceRange Range; + Range.Start = Result->Range.Start; + Range.End = currentLocation(); + Error->pushErrorFrame(Range, Error->ET_ParserStringError) + << ErrorText; + Result->Kind = TokenInfo::TK_Error; + } + + /// \brief Consume all leading whitespace from \c Code. + void consumeWhitespace() { + while (!Code.empty() && isWhitespace(Code[0])) { + if (Code[0] == '\n') { + ++Line; + StartOfLine = Code.drop_front(); + } + Code = Code.drop_front(); + } + } + + SourceLocation currentLocation() { + SourceLocation Location; + Location.Line = Line; + Location.Column = Code.data() - StartOfLine.data() + 1; + return Location; + } + + StringRef Code; + StringRef StartOfLine; + unsigned Line; + Diagnostics *Error; + TokenInfo NextToken; +}; + +Parser::Sema::~Sema() {} + +/// \brief Parse and validate a matcher expression. +/// \return \c true on success, in which case \c Value has the matcher parsed. +/// If the input is malformed, or some argument has an error, it +/// returns \c false. +bool Parser::parseMatcherExpressionImpl(VariantValue *Value) { + const TokenInfo NameToken = Tokenizer->consumeNextToken(); + assert(NameToken.Kind == TokenInfo::TK_Ident); + const TokenInfo OpenToken = Tokenizer->consumeNextToken(); + if (OpenToken.Kind != TokenInfo::TK_OpenParen) { + Error->pushErrorFrame(OpenToken.Range, Error->ET_ParserNoOpenParen) + << OpenToken.Text; + return false; + } + + std::vector<ParserValue> Args; + TokenInfo EndToken; + while (Tokenizer->nextTokenKind() != TokenInfo::TK_Eof) { + if (Tokenizer->nextTokenKind() == TokenInfo::TK_CloseParen) { + // End of args. + EndToken = Tokenizer->consumeNextToken(); + break; + } + if (Args.size() > 0) { + // We must find a , token to continue. + const TokenInfo CommaToken = Tokenizer->consumeNextToken(); + if (CommaToken.Kind != TokenInfo::TK_Comma) { + Error->pushErrorFrame(CommaToken.Range, Error->ET_ParserNoComma) + << CommaToken.Text; + return false; + } + } + + ParserValue ArgValue; + ArgValue.Text = Tokenizer->peekNextToken().Text; + ArgValue.Range = Tokenizer->peekNextToken().Range; + if (!parseExpressionImpl(&ArgValue.Value)) { + Error->pushErrorFrame(NameToken.Range, + Error->ET_ParserMatcherArgFailure) + << (Args.size() + 1) << NameToken.Text; + return false; + } + + Args.push_back(ArgValue); + } + + if (EndToken.Kind == TokenInfo::TK_Eof) { + Error->pushErrorFrame(OpenToken.Range, Error->ET_ParserNoCloseParen); + return false; + } + + // Merge the start and end infos. + SourceRange MatcherRange = NameToken.Range; + MatcherRange.End = EndToken.Range.End; + DynTypedMatcher *Result = + S->actOnMatcherExpression(NameToken.Text, MatcherRange, Args, Error); + if (Result == NULL) { + Error->pushErrorFrame(NameToken.Range, Error->ET_ParserMatcherFailure) + << NameToken.Text; + return false; + } + + Value->takeMatcher(Result); + return true; +} + +/// \brief Parse an <Expresssion> +bool Parser::parseExpressionImpl(VariantValue *Value) { + switch (Tokenizer->nextTokenKind()) { + case TokenInfo::TK_Literal: + *Value = Tokenizer->consumeNextToken().Value; + return true; + + case TokenInfo::TK_Ident: + return parseMatcherExpressionImpl(Value); + + case TokenInfo::TK_Eof: + Error->pushErrorFrame(Tokenizer->consumeNextToken().Range, + Error->ET_ParserNoCode); + return false; + + case TokenInfo::TK_Error: + // This error was already reported by the tokenizer. + return false; + + case TokenInfo::TK_OpenParen: + case TokenInfo::TK_CloseParen: + case TokenInfo::TK_Comma: + case TokenInfo::TK_InvalidChar: + const TokenInfo Token = Tokenizer->consumeNextToken(); + Error->pushErrorFrame(Token.Range, Error->ET_ParserInvalidToken) + << Token.Text; + return false; + } + + llvm_unreachable("Unknown token kind."); +} + +Parser::Parser(CodeTokenizer *Tokenizer, Sema *S, + Diagnostics *Error) + : Tokenizer(Tokenizer), S(S), Error(Error) {} + +class RegistrySema : public Parser::Sema { +public: + virtual ~RegistrySema() {} + DynTypedMatcher *actOnMatcherExpression(StringRef MatcherName, + const SourceRange &NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error) { + return Registry::constructMatcher(MatcherName, NameRange, Args, Error); + } +}; + +bool Parser::parseExpression(StringRef Code, VariantValue *Value, + Diagnostics *Error) { + RegistrySema S; + return parseExpression(Code, &S, Value, Error); +} + +bool Parser::parseExpression(StringRef Code, Sema *S, + VariantValue *Value, Diagnostics *Error) { + CodeTokenizer Tokenizer(Code, Error); + return Parser(&Tokenizer, S, Error).parseExpressionImpl(Value); +} + +DynTypedMatcher *Parser::parseMatcherExpression(StringRef Code, + Diagnostics *Error) { + RegistrySema S; + return parseMatcherExpression(Code, &S, Error); +} + +DynTypedMatcher *Parser::parseMatcherExpression(StringRef Code, + Parser::Sema *S, + Diagnostics *Error) { + VariantValue Value; + if (!parseExpression(Code, S, &Value, Error)) + return NULL; + if (!Value.isMatcher()) { + Error->pushErrorFrame(SourceRange(), Error->ET_ParserNotAMatcher); + return NULL; + } + return Value.getMatcher().clone(); +} + +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp new file mode 100644 index 0000000000..53e90f1c77 --- /dev/null +++ b/lib/ASTMatchers/Dynamic/Registry.cpp @@ -0,0 +1,153 @@ +//===--- Registry.cpp - Matcher registry ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Registry map populated at static initialization time. +/// +//===----------------------------------------------------------------------===// + +#include "clang/ASTMatchers/Dynamic/Registry.h" + +#include <utility> + +#include "Marshallers.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/ManagedStatic.h" + +namespace clang { +namespace ast_matchers { +namespace dynamic { +namespace { + +using internal::MatcherCreateCallback; + +typedef llvm::StringMap<const MatcherCreateCallback *> ConstructorMap; +class RegistryMaps { +public: + RegistryMaps(); + ~RegistryMaps(); + + const ConstructorMap &constructors() const { return Constructors; } + +private: + void registerMatcher(StringRef MatcherName, MatcherCreateCallback *Callback); + ConstructorMap Constructors; +}; + +void RegistryMaps::registerMatcher(StringRef MatcherName, + MatcherCreateCallback *Callback) { + Constructors[MatcherName] = Callback; +} + +#define REGISTER_MATCHER(name) \ + registerMatcher(#name, internal::makeMatcherAutoMarshall( \ + ::clang::ast_matchers::name, #name)); + +/// \brief Generate a registry map with all the known matchers. +RegistryMaps::RegistryMaps() { + // TODO: This list is not complete. It only has non-overloaded matchers, + // which are the simplest to add to the system. Overloaded matchers require + // more supporting code that was omitted from the first revision for + // simplicitly of code review. + + REGISTER_MATCHER(binaryOperator); + REGISTER_MATCHER(bindTemporaryExpr); + REGISTER_MATCHER(boolLiteral); + REGISTER_MATCHER(callExpr); + REGISTER_MATCHER(characterLiteral); + REGISTER_MATCHER(compoundStmt); + REGISTER_MATCHER(conditionalOperator); + REGISTER_MATCHER(constCastExpr); + REGISTER_MATCHER(constructExpr); + REGISTER_MATCHER(constructorDecl); + REGISTER_MATCHER(declRefExpr); + REGISTER_MATCHER(declStmt); + REGISTER_MATCHER(defaultArgExpr); + REGISTER_MATCHER(doStmt); + REGISTER_MATCHER(dynamicCastExpr); + REGISTER_MATCHER(explicitCastExpr); + REGISTER_MATCHER(expr); + REGISTER_MATCHER(fieldDecl); + REGISTER_MATCHER(forStmt); + REGISTER_MATCHER(functionDecl); + REGISTER_MATCHER(hasAnyParameter); + REGISTER_MATCHER(hasAnySubstatement); + REGISTER_MATCHER(hasConditionVariableStatement); + REGISTER_MATCHER(hasDestinationType); + REGISTER_MATCHER(hasEitherOperand); + REGISTER_MATCHER(hasFalseExpression); + REGISTER_MATCHER(hasImplicitDestinationType); + REGISTER_MATCHER(hasInitializer); + REGISTER_MATCHER(hasLHS); + REGISTER_MATCHER(hasName); + REGISTER_MATCHER(hasObjectExpression); + REGISTER_MATCHER(hasRHS); + REGISTER_MATCHER(hasSourceExpression); + REGISTER_MATCHER(hasTrueExpression); + REGISTER_MATCHER(hasUnaryOperand); + REGISTER_MATCHER(ifStmt); + REGISTER_MATCHER(implicitCastExpr); + REGISTER_MATCHER(integerLiteral); + REGISTER_MATCHER(isArrow); + REGISTER_MATCHER(isConstQualified); + REGISTER_MATCHER(isImplicit); + REGISTER_MATCHER(member); + REGISTER_MATCHER(memberExpr); + REGISTER_MATCHER(methodDecl); + REGISTER_MATCHER(namedDecl); + REGISTER_MATCHER(newExpr); + REGISTER_MATCHER(ofClass); + REGISTER_MATCHER(on); + REGISTER_MATCHER(onImplicitObjectArgument); + REGISTER_MATCHER(operatorCallExpr); + REGISTER_MATCHER(recordDecl); + REGISTER_MATCHER(reinterpretCastExpr); + REGISTER_MATCHER(staticCastExpr); + REGISTER_MATCHER(stmt); + REGISTER_MATCHER(stringLiteral); + REGISTER_MATCHER(switchCase); + REGISTER_MATCHER(to); + REGISTER_MATCHER(unaryOperator); + REGISTER_MATCHER(varDecl); + REGISTER_MATCHER(whileStmt); +} + +RegistryMaps::~RegistryMaps() { + for (ConstructorMap::iterator it = Constructors.begin(), + end = Constructors.end(); + it != end; ++it) { + delete it->second; + } +} + +static llvm::ManagedStatic<RegistryMaps> RegistryData; + +} // anonymous namespace + +// static +DynTypedMatcher *Registry::constructMatcher(StringRef MatcherName, + const SourceRange &NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error) { + ConstructorMap::const_iterator it = + RegistryData->constructors().find(MatcherName); + if (it == RegistryData->constructors().end()) { + Error->pushErrorFrame(NameRange, Error->ET_RegistryNotFound) + << MatcherName; + return NULL; + } + + return it->second->run(NameRange, Args, Error); +} + +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang diff --git a/lib/ASTMatchers/Dynamic/VariantValue.cpp b/lib/ASTMatchers/Dynamic/VariantValue.cpp new file mode 100644 index 0000000000..e310fbfc58 --- /dev/null +++ b/lib/ASTMatchers/Dynamic/VariantValue.cpp @@ -0,0 +1,105 @@ +//===--- VariantValue.cpp - Polymorphic value type -*- C++ -*-===/ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Polymorphic value type. +/// +//===----------------------------------------------------------------------===// + +#include "clang/ASTMatchers/Dynamic/VariantValue.h" + +namespace clang { +namespace ast_matchers { +namespace dynamic { + +VariantValue::VariantValue(const VariantValue &Other) : Type(VT_Nothing) { + *this = Other; +} + +VariantValue::VariantValue(const DynTypedMatcher &Matcher) : Type(VT_Nothing) { + setMatcher(Matcher); +} + +VariantValue::VariantValue(const std::string &String) : Type(VT_Nothing) { + setString(String); +} + +VariantValue::~VariantValue() { reset(); } + +VariantValue &VariantValue::operator=(const VariantValue &Other) { + if (this == &Other) return *this; + reset(); + switch (Other.Type) { + case VT_String: + setString(Other.getString()); + break; + case VT_Matcher: + setMatcher(Other.getMatcher()); + break; + case VT_Nothing: + Type = VT_Nothing; + break; + } + return *this; +} + +void VariantValue::reset() { + switch (Type) { + case VT_String: + delete Value.String; + break; + case VT_Matcher: + delete Value.Matcher; + break; + // Cases that do nothing. + case VT_Nothing: + break; + } + Type = VT_Nothing; +} + +bool VariantValue::isString() const { + return Type == VT_String; +} + +const std::string &VariantValue::getString() const { + assert(isString()); + return *Value.String; +} + +void VariantValue::setString(const std::string &NewValue) { + reset(); + Type = VT_String; + Value.String = new std::string(NewValue); +} + +bool VariantValue::isMatcher() const { + return Type == VT_Matcher; +} + +const DynTypedMatcher &VariantValue::getMatcher() const { + assert(isMatcher()); + return *Value.Matcher; +} + +void VariantValue::setMatcher(const DynTypedMatcher &NewValue) { + reset(); + Type = VT_Matcher; + Value.Matcher = NewValue.clone(); +} + +void VariantValue::takeMatcher(DynTypedMatcher *NewValue) { + reset(); + Type = VT_Matcher; + Value.Matcher = NewValue; +} + +} // end namespace dynamic +} // end namespace ast_matchers +} // end namespace clang diff --git a/lib/ASTMatchers/Makefile b/lib/ASTMatchers/Makefile index 76d82719a1..3ee9ccb580 100644 --- a/lib/ASTMatchers/Makefile +++ b/lib/ASTMatchers/Makefile @@ -10,4 +10,6 @@ CLANG_LEVEL := ../.. LIBRARYNAME := clangASTMatchers +PARALLEL_DIRS = Dynamic + include $(CLANG_LEVEL)/Makefile diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index 096c7a080b..6eb84ce92c 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -155,7 +155,7 @@ public: return !(*this == rhs); } - operator bool() const { + LLVM_EXPLICIT operator bool() const { return *this != const_iterator(); } diff --git a/lib/Basic/OpenMPKinds.cpp b/lib/Basic/OpenMPKinds.cpp index 835908d2a1..b90fbc7a7c 100644 --- a/lib/Basic/OpenMPKinds.cpp +++ b/lib/Basic/OpenMPKinds.cpp @@ -32,7 +32,7 @@ const char *clang::getOpenMPDirectiveName(OpenMPDirectiveKind Kind) { assert(Kind < NUM_OPENMP_DIRECTIVES); switch (Kind) { case OMPD_unknown: - return ("unknown"); + return "unknown"; #define OPENMP_DIRECTIVE(Name) \ case OMPD_##Name : return #Name; #include "clang/Basic/OpenMPKinds.def" @@ -41,3 +41,4 @@ const char *clang::getOpenMPDirectiveName(OpenMPDirectiveKind Kind) { } llvm_unreachable("Invalid OpenMP directive kind"); } + diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 638d6a028c..6b376b30ad 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -3527,6 +3527,34 @@ class ARMTargetInfo : public TargetInfo { static const Builtin::Info BuiltinInfo[]; + static bool shouldUseInlineAtomic(const llvm::Triple &T) { + // On linux, binaries targeting old cpus call functions in libgcc to + // perform atomic operations. The implementation in libgcc then calls into + // the kernel which on armv6 and newer uses ldrex and strex. The net result + // is that if we assume the kernel is at least as recent as the hardware, + // it is safe to use atomic instructions on armv6 and newer. + if (T.getOS() != llvm::Triple::Linux) + return false; + StringRef ArchName = T.getArchName(); + if (T.getArch() == llvm::Triple::arm) { + if (!ArchName.startswith("armv")) + return false; + StringRef VersionStr = ArchName.substr(4); + unsigned Version; + if (VersionStr.getAsInteger(10, Version)) + return false; + return Version >= 6; + } + assert(T.getArch() == llvm::Triple::thumb); + if (!ArchName.startswith("thumbv")) + return false; + StringRef VersionStr = ArchName.substr(6); + unsigned Version; + if (VersionStr.getAsInteger(10, Version)) + return false; + return Version >= 7; + } + public: ARMTargetInfo(const std::string &TripleStr) : TargetInfo(TripleStr), ABI("aapcs-linux"), CPU("arm1136j-s"), IsAAPCS(true) @@ -3559,8 +3587,9 @@ public: TheCXXABI.set(TargetCXXABI::GenericARM); // ARM has atomics up to 8 bytes - // FIXME: Set MaxAtomicInlineWidth if we have the feature v6e - MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + MaxAtomicPromoteWidth = 64; + if (shouldUseInlineAtomic(getTriple())) + MaxAtomicInlineWidth = 64; // Do force alignment of members that follow zero length bitfields. If // the alignment of the zero-length bitfield is greater than the member @@ -4275,6 +4304,11 @@ public: // FIXME: Support Sparc quad-precision long double? DescriptionString = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32:64-S128"; + // This is an LP64 platform. + LongWidth = LongAlign = PointerWidth = PointerAlign = 64; + IntMaxType = SignedLong; + UIntMaxType = UnsignedLong; + Int64Type = SignedLong; } virtual void getTargetDefines(const LangOptions &Opts, diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index d18767897f..bd5afb6d17 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -1645,11 +1645,10 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, const CallExpr *E) { if (BuiltinID == ARM::BI__clear_cache) { + assert(E->getNumArgs() == 2 && "__clear_cache takes 2 arguments"); const FunctionDecl *FD = E->getDirectCallee(); - // Oddly people write this call without args on occasion and gcc accepts - // it - it's also marked as varargs in the description file. SmallVector<Value*, 2> Ops; - for (unsigned i = 0; i < E->getNumArgs(); i++) + for (unsigned i = 0; i < 2; i++) Ops.push_back(EmitScalarExpr(E->getArg(i))); llvm::Type *Ty = CGM.getTypes().ConvertType(FD->getType()); llvm::FunctionType *FTy = cast<llvm::FunctionType>(Ty); diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 7d5d260304..f6ad8f2cc5 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -1220,9 +1220,11 @@ CollectTemplateParams(const TemplateParameterList *TPList, V = CGM.GetAddrOfGlobalVar(VD); // Member function pointers have special support for building them, though // this is currently unsupported in LLVM CodeGen. - if (InstanceMember) + if (InstanceMember) { if (const CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(D)) V = CGM.getCXXABI().EmitMemberPointer(method); + } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + V = CGM.GetAddrOfFunction(FD); // Member data pointers have special handling too to compute the fixed // offset within the object. if (isa<FieldDecl>(D)) { @@ -2172,8 +2174,21 @@ llvm::DIType CGDebugInfo::CreateMemberType(llvm::DIFile Unit, QualType FType, } llvm::DIDescriptor CGDebugInfo::getDeclarationOrDefinition(const Decl *D) { - if (const TypeDecl *RD = dyn_cast<TypeDecl>(D)) - return CreatePointeeType(QualType(RD->getTypeForDecl(), 0), llvm::DIFile()); + // We only need a declaration (not a definition) of the type - so use whatever + // we would otherwise do to get a type for a pointee. (forward declarations in + // limited debug info, full definitions (if the type definition is available) + // in unlimited debug info) + if (const TypeDecl *TD = dyn_cast<TypeDecl>(D)) { + llvm::DIFile DefUnit = getOrCreateFile(TD->getLocation()); + return CreatePointeeType(CGM.getContext().getTypeDeclType(TD), DefUnit); + } + // Otherwise fall back to a fairly rudimentary cache of existing declarations. + // This doesn't handle providing declarations (for functions or variables) for + // entities without definitions in this TU, nor when the definition proceeds + // the call to this function. + // FIXME: This should be split out into more specific maps with support for + // emitting forward declarations and merging definitions with declarations, + // the same way as we do for types. llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator I = DeclCache.find(D->getCanonicalDecl()); if (I == DeclCache.end()) diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index e61a50eeb4..f221a0cd3e 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -95,6 +95,8 @@ class CGDebugInfo { llvm::DenseMap<const char *, llvm::WeakVH> DIFileCache; llvm::DenseMap<const FunctionDecl *, llvm::WeakVH> SPCache; + /// \brief Cache declarations relevant to DW_TAG_imported_declarations (C++ + /// using declarations) that aren't covered by other more specific caches. llvm::DenseMap<const Decl *, llvm::WeakVH> DeclCache; llvm::DenseMap<const NamespaceDecl *, llvm::WeakVH> NameSpaceCache; llvm::DenseMap<const Decl *, llvm::WeakVH> StaticDataMemberCache; diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp index 069cd5f9e7..9a345cf472 100644 --- a/lib/CodeGen/CGVTables.cpp +++ b/lib/CodeGen/CGVTables.cpp @@ -719,7 +719,7 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD, /// Note that we only call this at the end of the translation unit. llvm::GlobalVariable::LinkageTypes CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) { - if (RD->getLinkage() != ExternalLinkage) + if (!RD->isExternallyVisible()) return llvm::GlobalVariable::InternalLinkage; // We're at the end of the translation unit, so the current key diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 6caf1689a9..5a7c305c64 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -2422,7 +2422,7 @@ public: return ConstantEmission(C, false); } - operator bool() const { return ValueAndIsReference.getOpaqueValue() != 0; } + LLVM_EXPLICIT operator bool() const { return ValueAndIsReference.getOpaqueValue() != 0; } bool isReference() const { return ValueAndIsReference.getInt(); } LValue getReferenceLValue(CodeGenFunction &CGF, Expr *refExpr) const { diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 695048e5b3..0736879037 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -1763,7 +1763,7 @@ void CodeGenModule::MaybeHandleStaticInExternC(const SomeDecl *D, return; // Must have internal linkage and an ordinary name. - if (!D->getIdentifier() || D->getLinkage() != InternalLinkage) + if (!D->getIdentifier() || D->getFormalLinkage() != InternalLinkage) return; // Must be in an extern "C" context. Entities declared directly within diff --git a/lib/CodeGen/CodeGenTBAA.cpp b/lib/CodeGen/CodeGenTBAA.cpp index 5ff1560a48..3f0eaee536 100644 --- a/lib/CodeGen/CodeGenTBAA.cpp +++ b/lib/CodeGen/CodeGenTBAA.cpp @@ -162,8 +162,7 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) { // on their mangled names, if they're external. // TODO: Is there a way to get a program-wide unique name for a // decl with local linkage or no linkage? - if (Features.CPlusPlus && - ETy->getDecl()->getLinkage() != ExternalLinkage) + if (Features.CPlusPlus && !ETy->getDecl()->isExternallyVisible()) return MetadataCache[Ty] = getChar(); // TODO: This is using the RTTI name. Is there a better way to get diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp index 9a320f94bd..9fd8ac6916 100644 --- a/lib/Format/Format.cpp +++ b/lib/Format/Format.cpp @@ -19,11 +19,9 @@ #include "TokenAnnotator.h" #include "UnwrappedLineParser.h" #include "WhitespaceManager.h" -#include "clang/Basic/Diagnostic.h" #include "clang/Basic/OperatorPrecedence.h" #include "clang/Basic/SourceManager.h" #include "clang/Format/Format.h" -#include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Lex/Lexer.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Allocator.h" @@ -36,11 +34,21 @@ namespace llvm { namespace yaml { template <> struct ScalarEnumerationTraits<clang::format::FormatStyle::LanguageStandard> { - static void enumeration(IO &io, - clang::format::FormatStyle::LanguageStandard &value) { - io.enumCase(value, "C++03", clang::format::FormatStyle::LS_Cpp03); - io.enumCase(value, "C++11", clang::format::FormatStyle::LS_Cpp11); - io.enumCase(value, "Auto", clang::format::FormatStyle::LS_Auto); + static void enumeration(IO &IO, + clang::format::FormatStyle::LanguageStandard &Value) { + IO.enumCase(Value, "C++03", clang::format::FormatStyle::LS_Cpp03); + IO.enumCase(Value, "C++11", clang::format::FormatStyle::LS_Cpp11); + IO.enumCase(Value, "Auto", clang::format::FormatStyle::LS_Auto); + } +}; + +template <> +struct ScalarEnumerationTraits<clang::format::FormatStyle::BraceBreakingStyle> { + static void + enumeration(IO &IO, clang::format::FormatStyle::BraceBreakingStyle &Value) { + IO.enumCase(Value, "Attach", clang::format::FormatStyle::BS_Attach); + IO.enumCase(Value, "Linux", clang::format::FormatStyle::BS_Linux); + IO.enumCase(Value, "Stroustrup", clang::format::FormatStyle::BS_Stroustrup); } }; @@ -85,6 +93,9 @@ template <> struct MappingTraits<clang::format::FormatStyle> { IO.mapOptional("SpacesBeforeTrailingComments", Style.SpacesBeforeTrailingComments); IO.mapOptional("Standard", Style.Standard); + IO.mapOptional("IndentWidth", Style.IndentWidth); + IO.mapOptional("UseTab", Style.UseTab); + IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces); } }; } @@ -111,6 +122,9 @@ FormatStyle getLLVMStyle() { LLVMStyle.PointerBindsToType = false; LLVMStyle.SpacesBeforeTrailingComments = 1; LLVMStyle.Standard = FormatStyle::LS_Cpp03; + LLVMStyle.IndentWidth = 2; + LLVMStyle.UseTab = false; + LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach; return LLVMStyle; } @@ -132,6 +146,9 @@ FormatStyle getGoogleStyle() { GoogleStyle.PointerBindsToType = true; GoogleStyle.SpacesBeforeTrailingComments = 2; GoogleStyle.Standard = FormatStyle::LS_Auto; + GoogleStyle.IndentWidth = 2; + GoogleStyle.UseTab = false; + GoogleStyle.BreakBeforeBraces = FormatStyle::BS_Attach; return GoogleStyle; } @@ -185,7 +202,7 @@ std::string configurationAsText(const FormatStyle &Style) { // reference here. FormatStyle NonConstStyle = Style; Output << NonConstStyle; - return Text; + return Stream.str(); } // Returns the length of everything up to the first possible line break after @@ -267,7 +284,7 @@ private: AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false), NoLineBreak(NoLineBreak), ColonPos(0), StartOfFunctionCall(0), NestedNameSpecifierContinuation(0), CallContinuation(0), - VariablePos(0) {} + VariablePos(0), ForFakeParenthesis(false) {} /// \brief The position to which a specific parenthesis level needs to be /// indented. @@ -326,6 +343,13 @@ private: /// Used to align further variables if necessary. unsigned VariablePos; + /// \brief \c true if this \c ParenState was created for a fake parenthesis. + /// + /// Does not need to be considered for memoization / the comparison function + /// as otherwise identical states will have the same fake/non-fake + /// \c ParenStates. + bool ForFakeParenthesis; + bool operator<(const ParenState &Other) const { if (Indent != Other.Indent) return Indent < Other.Indent; @@ -429,7 +453,7 @@ private: if (Newline) { unsigned WhitespaceStartColumn = State.Column; if (Current.is(tok::r_brace)) { - State.Column = Line.Level * 2; + State.Column = Line.Level * Style.IndentWidth; } else if (Current.is(tok::string_literal) && State.StartOfStringLiteral != 0) { State.Column = State.StartOfStringLiteral; @@ -480,6 +504,8 @@ private: !State.Stack.back().AvoidBinPacking) || Previous.Type == TT_BinaryOperator) State.Stack.back().BreakBeforeParameter = false; + if (Previous.Type == TT_TemplateCloser && State.ParenLevel == 0) + State.Stack.back().BreakBeforeParameter = false; if (!DryRun) { unsigned NewLines = 1; @@ -507,6 +533,7 @@ private: } const AnnotatedToken *TokenBefore = Current.getPreviousNoneComment(); if (TokenBefore && !TokenBefore->isOneOf(tok::comma, tok::semi) && + TokenBefore->Type != TT_TemplateCloser && TokenBefore->Type != TT_BinaryOperator && !TokenBefore->opensScope()) State.Stack.back().BreakBeforeParameter = true; @@ -517,7 +544,8 @@ private: if (State.Stack.back().AvoidBinPacking) { // If we are breaking after '(', '{', '<', this is not bin packing // unless AllowAllParametersOfDeclarationOnNextLine is false. - if ((Previous.isNot(tok::l_paren) && Previous.isNot(tok::l_brace)) || + if (!(Previous.isOneOf(tok::l_paren, tok::l_brace) || + Previous.Type == TT_BinaryOperator) || (!Style.AllowAllParametersOfDeclarationOnNextLine && Line.MustBeDeclaration)) State.Stack.back().BreakBeforeParameter = true; @@ -604,6 +632,11 @@ private: Current.LastInChainOfCalls ? 0 : State.Column + Current.FormatTok.TokenLength; if (Current.Type == TT_CtorInitializerColon) { + // Indent 2 from the column, so: + // SomeClass::SomeClass() + // : First(...), ... + // Next(...) + // ^ line up here. State.Stack.back().Indent = State.Column + 2; if (Style.ConstructorInitializerAllOnOneLineOrOnePerLine) State.Stack.back().AvoidBinPacking = true; @@ -633,6 +666,7 @@ private: E = Current.FakeLParens.rend(); I != E; ++I) { ParenState NewParenState = State.Stack.back(); + NewParenState.ForFakeParenthesis = true; NewParenState.Indent = std::max(std::max(State.Column, NewParenState.Indent), State.Stack.back().LastSpace); @@ -654,27 +688,31 @@ private: // prepare for the following tokens. if (Current.opensScope()) { unsigned NewIndent; + unsigned LastSpace = State.Stack.back().LastSpace; bool AvoidBinPacking; if (Current.is(tok::l_brace)) { - NewIndent = 2 + State.Stack.back().LastSpace; + NewIndent = Style.IndentWidth + LastSpace; AvoidBinPacking = false; } else { - NewIndent = 4 + std::max(State.Stack.back().LastSpace, - State.Stack.back().StartOfFunctionCall); + NewIndent = + 4 + std::max(LastSpace, State.Stack.back().StartOfFunctionCall); AvoidBinPacking = !Style.BinPackParameters; } - State.Stack.push_back( - ParenState(NewIndent, State.Stack.back().LastSpace, AvoidBinPacking, - State.Stack.back().NoLineBreak)); if (Current.NoMoreTokensOnLevel && Current.FakeLParens.empty()) { // This parenthesis was the last token possibly making use of Indent and - // LastSpace of the next higher ParenLevel. Thus, erase them to acieve + // LastSpace of the next higher ParenLevel. Thus, erase them to achieve // better memoization results. - State.Stack[State.Stack.size() - 2].Indent = 0; - State.Stack[State.Stack.size() - 2].LastSpace = 0; + for (unsigned i = State.Stack.size() - 1; i > 0; --i) { + State.Stack[i].Indent = 0; + State.Stack[i].LastSpace = 0; + if (!State.Stack[i].ForFakeParenthesis) + break; + } } + State.Stack.push_back(ParenState(NewIndent, LastSpace, AvoidBinPacking, + State.Stack.back().NoLineBreak)); ++State.ParenLevel; } @@ -702,10 +740,10 @@ private: State.Stack.back().VariablePos = VariablePos; } - if (Current.is(tok::string_literal)) { + if (Current.is(tok::string_literal) && State.StartOfStringLiteral == 0) { State.StartOfStringLiteral = State.Column; - } else if (Current.isNot(tok::comment)) { - State.StartOfStringLiteral = 0; + } else if (!Current.isOneOf(tok::comment, tok::identifier, tok::hash, + tok::string_literal)) { } State.Column += Current.FormatTok.TokenLength; @@ -720,10 +758,18 @@ private: /// \brief If the current token sticks out over the end of the line, break /// it if possible. + /// + /// \returns An extra penalty if a token was broken, otherwise 0. + /// + /// Note that the penalty of the token protruding the allowed line length is + /// already handled in \c addNextStateToQueue; the returned penalty will only + /// cover the cost of the additional line breaks. unsigned breakProtrudingToken(const AnnotatedToken &Current, LineState &State, - bool DryRun) { + bool DryRun, + unsigned UnbreakableTailLength = 0) { llvm::OwningPtr<BreakableToken> Token; - unsigned StartColumn = State.Column - Current.FormatTok.TokenLength; + unsigned StartColumn = State.Column - Current.FormatTok.TokenLength - + UnbreakableTailLength; if (Current.is(tok::string_literal)) { // Only break up default narrow strings. const char *LiteralData = SourceMgr.getCharacterData( @@ -744,42 +790,55 @@ private: Current.Parent->Type != TT_ImplicitStringLiteral)) { Token.reset(new BreakableLineComment(SourceMgr, Current, StartColumn)); } else { - return 0; + // If a token that we cannot breaks protrudes, it means we were unable to + // break a sequence of tokens due to disallowed breaks between the tokens. + // Thus, we recursively search backwards to try to find a breakable token. + if (State.Column <= getColumnLimit() || + Current.CanBreakBefore || !Current.Parent) + return 0; + return breakProtrudingToken( + *Current.Parent, State, DryRun, + UnbreakableTailLength + Current.FormatTok.TokenLength); } + if (UnbreakableTailLength >= getColumnLimit()) + return 0; + unsigned RemainingSpace = getColumnLimit() - UnbreakableTailLength; bool BreakInserted = false; unsigned Penalty = 0; + unsigned PositionAfterLastLineInToken = 0; for (unsigned LineIndex = 0; LineIndex < Token->getLineCount(); ++LineIndex) { unsigned TailOffset = 0; - unsigned RemainingLength = + unsigned RemainingTokenLength = Token->getLineLengthAfterSplit(LineIndex, TailOffset); - while (RemainingLength > getColumnLimit()) { + while (RemainingTokenLength > RemainingSpace) { BreakableToken::Split Split = - Token->getSplit(LineIndex, TailOffset, getColumnLimit()); + Token->getSplit(LineIndex, TailOffset, RemainingSpace); if (Split.first == StringRef::npos) break; assert(Split.first != 0); - unsigned NewRemainingLength = Token->getLineLengthAfterSplit( + unsigned NewRemainingTokenLength = Token->getLineLengthAfterSplit( LineIndex, TailOffset + Split.first + Split.second); - if (NewRemainingLength >= RemainingLength) + if (NewRemainingTokenLength >= RemainingTokenLength) break; if (!DryRun) { Token->insertBreak(LineIndex, TailOffset, Split, Line.InPPDirective, Whitespaces); } TailOffset += Split.first + Split.second; - RemainingLength = NewRemainingLength; + RemainingTokenLength = NewRemainingTokenLength; Penalty += Style.PenaltyExcessCharacter; BreakInserted = true; } - State.Column = RemainingLength; + PositionAfterLastLineInToken = RemainingTokenLength; if (!DryRun) { Token->trimLine(LineIndex, TailOffset, Line.InPPDirective, Whitespaces); } } if (BreakInserted) { + State.Column = PositionAfterLastLineInToken + UnbreakableTailLength; for (unsigned i = 0, e = State.Stack.size(); i != e; ++i) State.Stack[i].BreakBeforeParameter = true; State.Stack.back().LastSpace = StartColumn; @@ -961,6 +1020,10 @@ private: getRemainingLength(State) + State.Column > getColumnLimit() && State.ParenLevel < State.StartOfLineLevel) return true; + + if (Current.Type == TT_StartOfName && Line.MightBeFunctionDecl && + State.Stack.back().BreakBeforeParameter && State.ParenLevel == 0) + return true; return false; } @@ -1082,17 +1145,16 @@ private: class Formatter : public UnwrappedLineConsumer { public: - Formatter(DiagnosticsEngine &Diag, const FormatStyle &Style, Lexer &Lex, - SourceManager &SourceMgr, + Formatter(const FormatStyle &Style, Lexer &Lex, SourceManager &SourceMgr, const std::vector<CharSourceRange> &Ranges) - : Diag(Diag), Style(Style), Lex(Lex), SourceMgr(SourceMgr), + : Style(Style), Lex(Lex), SourceMgr(SourceMgr), Whitespaces(SourceMgr, Style), Ranges(Ranges) {} virtual ~Formatter() {} tooling::Replacements format() { LexerBasedFormatTokenSource Tokens(Lex, SourceMgr); - UnwrappedLineParser Parser(Diag, Style, Tokens, *this); + UnwrappedLineParser Parser(Style, Tokens, *this); bool StructuralError = Parser.parse(); unsigned PreviousEndOfLineColumn = 0; TokenAnnotator Annotator(Style, SourceMgr, Lex, @@ -1136,9 +1198,15 @@ public: (touchesLine(TheLine) || touchesPPDirective(I + 1, E))) FormatPPDirective = true; + // Determine indent and try to merge multiple unwrapped lines. while (IndentForLevel.size() <= TheLine.Level) IndentForLevel.push_back(-1); IndentForLevel.resize(TheLine.Level + 1); + unsigned Indent = getIndent(IndentForLevel, TheLine.Level); + if (static_cast<int>(Indent) + Offset >= 0) + Indent += Offset; + tryFitMultipleLinesInOne(Indent, I, E); + bool WasMoved = PreviousLineWasTouched && FirstTok.NewlinesBefore == 0; if (TheLine.First.is(tok::eof)) { if (PreviousLineWasTouched) { @@ -1149,9 +1217,6 @@ public: } else if (TheLine.Type != LT_Invalid && (WasMoved || FormatPPDirective || touchesLine(TheLine))) { unsigned LevelIndent = getIndent(IndentForLevel, TheLine.Level); - unsigned Indent = LevelIndent; - if (static_cast<int>(Indent) + Offset >= 0) - Indent += Offset; if (FirstTok.WhiteSpaceStart.isValid() && // Insert a break even if there is a structural error in case where // we break apart a line consisting of multiple unwrapped lines. @@ -1162,7 +1227,6 @@ public: Indent = LevelIndent = SourceMgr.getSpellingColumnNumber(FirstTok.Tok.getLocation()) - 1; } - tryFitMultipleLinesInOne(Indent, I, E); UnwrappedLineFormatter Formatter(Style, SourceMgr, TheLine, Indent, TheLine.First, Whitespaces); PreviousEndOfLineColumn = @@ -1171,18 +1235,17 @@ public: PreviousLineWasTouched = true; } else { if (FirstTok.NewlinesBefore > 0 || FirstTok.IsFirst) { - unsigned Indent = + unsigned LevelIndent = SourceMgr.getSpellingColumnNumber(FirstTok.Tok.getLocation()) - 1; - unsigned LevelIndent = Indent; + // Remove trailing whitespace of the previous line if it was touched. + if (PreviousLineWasTouched || touchesEmptyLineBefore(TheLine)) + formatFirstToken(TheLine.First, PreviousLineLastToken, LevelIndent, + TheLine.InPPDirective, PreviousEndOfLineColumn); + if (static_cast<int>(LevelIndent) - Offset >= 0) LevelIndent -= Offset; if (TheLine.First.isNot(tok::comment)) IndentForLevel[TheLine.Level] = LevelIndent; - - // Remove trailing whitespace of the previous line if it was touched. - if (PreviousLineWasTouched || touchesEmptyLineBefore(TheLine)) - formatFirstToken(TheLine.First, PreviousLineLastToken, Indent, - TheLine.InPPDirective, PreviousEndOfLineColumn); } // If we did not reformat this unwrapped line, the column at the end of // the last token is unchanged - thus, we can calculate the end of the @@ -1253,7 +1316,7 @@ private: return IndentForLevel[Level]; if (Level == 0) return 0; - return getIndent(IndentForLevel, Level - 1) + 2; + return getIndent(IndentForLevel, Level - 1) + Style.IndentWidth; } /// \brief Get the offset of the line relatively to the level. @@ -1270,8 +1333,6 @@ private: /// /// This will change \c Line and \c AnnotatedLine to contain the merged line, /// if possible; note that \c I will be incremented when lines are merged. - /// - /// Returns whether the resulting \c Line can fit in a single line. void tryFitMultipleLinesInOne(unsigned Indent, std::vector<AnnotatedLine>::iterator &I, std::vector<AnnotatedLine>::iterator E) { @@ -1295,7 +1356,6 @@ private: I->First.FormatTok.IsFirst)) { tryMergeSimplePPDirective(I, E, Limit); } - return; } void tryMergeSimplePPDirective(std::vector<AnnotatedLine>::iterator &I, @@ -1341,13 +1401,17 @@ private: void tryMergeSimpleBlock(std::vector<AnnotatedLine>::iterator &I, std::vector<AnnotatedLine>::iterator E, unsigned Limit) { + // No merging if the brace already is on the next line. + if (Style.BreakBeforeBraces != FormatStyle::BS_Attach) + return; + // First, check that the current line allows merging. This is the case if // we're not in a control flow statement and the last token is an opening // brace. AnnotatedLine &Line = *I; if (Line.First.isOneOf(tok::kw_if, tok::kw_while, tok::kw_do, tok::r_brace, tok::kw_else, tok::kw_try, tok::kw_catch, - tok::kw_for, + tok::kw_for, tok::kw_namespace, // This gets rid of all ObjC @ keywords and methods. tok::at, tok::minus, tok::plus)) return; @@ -1418,9 +1482,9 @@ private: bool touchesLine(const AnnotatedLine &TheLine) { const FormatToken *First = &TheLine.First.FormatTok; const FormatToken *Last = &TheLine.Last->FormatTok; - CharSourceRange LineRange = CharSourceRange::getTokenRange( + CharSourceRange LineRange = CharSourceRange::getCharRange( First->WhiteSpaceStart.getLocWithOffset(First->LastNewlineOffset), - Last->Tok.getLocation()); + Last->Tok.getLocation().getLocWithOffset(Last->TokenLength - 1)); return touchesRanges(LineRange); } @@ -1473,7 +1537,6 @@ private: } } - DiagnosticsEngine &Diag; FormatStyle Style; Lexer &Lex; SourceManager &SourceMgr; @@ -1484,20 +1547,8 @@ private: tooling::Replacements reformat(const FormatStyle &Style, Lexer &Lex, SourceManager &SourceMgr, - std::vector<CharSourceRange> Ranges, - DiagnosticConsumer *DiagClient) { - IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); - OwningPtr<DiagnosticConsumer> DiagPrinter; - if (DiagClient == 0) { - DiagPrinter.reset(new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts)); - DiagPrinter->BeginSourceFile(Lex.getLangOpts(), Lex.getPP()); - DiagClient = DiagPrinter.get(); - } - DiagnosticsEngine Diagnostics( - IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts, - DiagClient, false); - Diagnostics.setSourceManager(&SourceMgr); - Formatter formatter(Diagnostics, Style, Lex, SourceMgr, Ranges); + std::vector<CharSourceRange> Ranges) { + Formatter formatter(Style, Lex, SourceMgr, Ranges); return formatter.format(); } diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index 12031166e2..21518c6824 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -101,8 +101,10 @@ private: return true; } if (CurrentToken->isOneOf(tok::r_paren, tok::r_square, tok::r_brace, - tok::pipepipe, tok::ampamp, tok::question, - tok::colon)) + tok::question, tok::colon)) + return false; + if (CurrentToken->isOneOf(tok::pipepipe, tok::ampamp) && + Line.First.isNot(tok::kw_template)) return false; updateParameterCount(Left, CurrentToken); if (!consumeToken()) @@ -155,6 +157,9 @@ private: } if (CurrentToken->is(tok::r_paren)) { + if (CurrentToken->Children.empty() || + !CurrentToken->Children[0].isOneOf(tok::l_paren, tok::l_square)) + Left->DefinesFunctionType = false; if (CurrentToken->Parent->closesScope()) CurrentToken->Parent->MatchingParen->NoMoreTokensOnLevel = true; Left->MatchingParen = CurrentToken; @@ -591,6 +596,7 @@ private: } } else if (Current.isOneOf(tok::kw_return, tok::kw_throw) || (Current.is(tok::l_paren) && !Line.MustBeDeclaration && + !Line.InPPDirective && (!Current.Parent || Current.Parent->isNot(tok::kw_for)))) { Contexts.back().IsExpression = true; } else if (Current.isOneOf(tok::r_paren, tok::greater, tok::comma)) { @@ -871,8 +877,6 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) { Line.First.SpacesRequiredBefore = 1; Line.First.MustBreakBefore = Line.First.FormatTok.MustBreakBefore; Line.First.CanBreakBefore = Line.First.MustBreakBefore; - - Line.First.TotalLength = Line.First.FormatTok.TokenLength; } void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) { diff --git a/lib/Format/TokenAnnotator.h b/lib/Format/TokenAnnotator.h index 5ea30159a2..227dd52396 100644 --- a/lib/Format/TokenAnnotator.h +++ b/lib/Format/TokenAnnotator.h @@ -75,10 +75,11 @@ public: : FormatTok(FormatTok), Type(TT_Unknown), SpacesRequiredBefore(0), CanBreakBefore(false), MustBreakBefore(false), ClosesTemplateDeclaration(false), MatchingParen(NULL), - ParameterCount(0), BindingStrength(0), SplitPenalty(0), - LongestObjCSelectorName(0), DefinesFunctionType(false), Parent(NULL), - FakeRParens(0), LastInChainOfCalls(false), - PartOfMultiVariableDeclStmt(false), NoMoreTokensOnLevel(false) {} + ParameterCount(0), TotalLength(FormatTok.TokenLength), + BindingStrength(0), SplitPenalty(0), LongestObjCSelectorName(0), + DefinesFunctionType(false), Parent(NULL), FakeRParens(0), + LastInChainOfCalls(false), PartOfMultiVariableDeclStmt(false), + NoMoreTokensOnLevel(false) {} bool is(tok::TokenKind Kind) const { return FormatTok.Tok.is(Kind); } diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp index 722af5d2b7..4138bb98ae 100644 --- a/lib/Format/UnwrappedLineParser.cpp +++ b/lib/Format/UnwrappedLineParser.cpp @@ -16,7 +16,6 @@ #define DEBUG_TYPE "format-parser" #include "UnwrappedLineParser.h" -#include "clang/Basic/Diagnostic.h" #include "llvm/Support/Debug.h" namespace clang { @@ -125,11 +124,11 @@ private: UnwrappedLine *PreBlockLine; }; -UnwrappedLineParser::UnwrappedLineParser( - clang::DiagnosticsEngine &Diag, const FormatStyle &Style, - FormatTokenSource &Tokens, UnwrappedLineConsumer &Callback) +UnwrappedLineParser::UnwrappedLineParser(const FormatStyle &Style, + FormatTokenSource &Tokens, + UnwrappedLineConsumer &Callback) : Line(new UnwrappedLine), MustBreakBeforeNextToken(false), - CurrentLines(&Lines), StructuralError(false), Diag(Diag), Style(Style), + CurrentLines(&Lines), StructuralError(false), Style(Style), Tokens(&Tokens), Callback(Callback) {} bool UnwrappedLineParser::parse() { @@ -173,9 +172,6 @@ void UnwrappedLineParser::parseLevel(bool HasOpeningBrace) { case tok::r_brace: if (HasOpeningBrace) return; - Diag.Report(FormatTok.Tok.getLocation(), - Diag.getCustomDiagID(clang::DiagnosticsEngine::Error, - "unexpected '}'")); StructuralError = true; nextToken(); addUnwrappedLine(); @@ -402,6 +398,10 @@ void UnwrappedLineParser::parseStructuralElement() { // structural element. // FIXME: Figure out cases where this is not true, and add projections for // them (the one we know is missing are lambdas). + if (Style.BreakBeforeBraces == FormatStyle::BS_Linux || + Style.BreakBeforeBraces == FormatStyle::BS_Stroustrup) + addUnwrappedLine(); + parseBlock(/*MustBeDeclaration=*/ false); addUnwrappedLine(); return; @@ -577,6 +577,9 @@ void UnwrappedLineParser::parseNamespace() { if (FormatTok.Tok.is(tok::identifier)) nextToken(); if (FormatTok.Tok.is(tok::l_brace)) { + if (Style.BreakBeforeBraces == FormatStyle::BS_Linux) + addUnwrappedLine(); + parseBlock(/*MustBeDeclaration=*/ true, 0); // Munch the semicolon after a namespace. This is more common than one would // think. Puttin the semicolon into its own line is very ugly. @@ -751,8 +754,12 @@ void UnwrappedLineParser::parseRecord() { } } } - if (FormatTok.Tok.is(tok::l_brace)) + if (FormatTok.Tok.is(tok::l_brace)) { + if (Style.BreakBeforeBraces == FormatStyle::BS_Linux) + addUnwrappedLine(); + parseBlock(/*MustBeDeclaration=*/ true); + } // We fall through to parsing a structural element afterwards, so // class A {} n, m; // will end up in one unwrapped line. diff --git a/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h index 0c618e24d4..82e93bef48 100644 --- a/lib/Format/UnwrappedLineParser.h +++ b/lib/Format/UnwrappedLineParser.h @@ -23,9 +23,6 @@ #include <list> namespace clang { - -class DiagnosticsEngine; - namespace format { /// \brief A wrapper around a \c Token storing information about the @@ -129,8 +126,7 @@ public: class UnwrappedLineParser { public: - UnwrappedLineParser(clang::DiagnosticsEngine &Diag, const FormatStyle &Style, - FormatTokenSource &Tokens, + UnwrappedLineParser(const FormatStyle &Style, FormatTokenSource &Tokens, UnwrappedLineConsumer &Callback); /// Returns true in case of a structural error. @@ -203,7 +199,6 @@ private: // indentation levels. bool StructuralError; - clang::DiagnosticsEngine &Diag; const FormatStyle &Style; FormatTokenSource *Tokens; UnwrappedLineConsumer &Callback; diff --git a/lib/Format/WhitespaceManager.cpp b/lib/Format/WhitespaceManager.cpp index a75c592bfe..7ffebacba5 100644 --- a/lib/Format/WhitespaceManager.cpp +++ b/lib/Format/WhitespaceManager.cpp @@ -122,7 +122,7 @@ void WhitespaceManager::addUntouchableComment(unsigned Column) { std::string WhitespaceManager::getNewLineText(unsigned NewLines, unsigned Spaces) { - return std::string(NewLines, '\n') + std::string(Spaces, ' '); + return std::string(NewLines, '\n') + getIndentText(Spaces); } std::string WhitespaceManager::getNewLineText(unsigned NewLines, @@ -139,7 +139,15 @@ std::string WhitespaceManager::getNewLineText(unsigned NewLines, Offset = 0; } } - return NewLineText + std::string(Spaces, ' '); + return NewLineText + getIndentText(Spaces); +} + +std::string WhitespaceManager::getIndentText(unsigned Spaces) { + if (!Style.UseTab) + return std::string(Spaces, ' '); + + return std::string(Spaces / Style.IndentWidth, '\t') + + std::string(Spaces % Style.IndentWidth, ' '); } void WhitespaceManager::alignComments() { diff --git a/lib/Format/WhitespaceManager.h b/lib/Format/WhitespaceManager.h index 5f3dc55eda..1b24b3f6d7 100644 --- a/lib/Format/WhitespaceManager.h +++ b/lib/Format/WhitespaceManager.h @@ -78,6 +78,8 @@ private: unsigned WhitespaceStartColumn, unsigned EscapedNewlineColumn); + std::string getIndentText(unsigned Spaces); + /// \brief Structure to store tokens for later layout and alignment. struct StoredToken { StoredToken(SourceLocation ReplacementLoc, unsigned ReplacementLength, diff --git a/lib/Lex/HeaderMap.cpp b/lib/Lex/HeaderMap.cpp index dcf1f0c70c..478462c3c2 100644 --- a/lib/Lex/HeaderMap.cpp +++ b/lib/Lex/HeaderMap.cpp @@ -82,7 +82,7 @@ const HeaderMap *HeaderMap::Create(const FileEntry *FE, FileManager &FM) { if (FileSize <= sizeof(HMapHeader)) return 0; OwningPtr<const llvm::MemoryBuffer> FileBuffer(FM.getBufferForFile(FE)); - if (FileBuffer == 0) return 0; // Unreadable file? + if (!FileBuffer) return 0; // Unreadable file? const char *FileStart = FileBuffer->getBufferStart(); // We know the file is at least as big as the header, check it now. diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index 50a0cb55f7..ba3291aa39 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -241,7 +241,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, bool FoundElse, SourceLocation ElseLoc) { ++NumSkipped; - assert(CurTokenLexer == 0 && CurPPLexer && "Lexing a macro, not a file?"); + assert(!CurTokenLexer && CurPPLexer && "Lexing a macro, not a file?"); CurPPLexer->pushConditionalLevel(IfTokenLoc, /*isSkipping*/false, FoundNonSkipPortion, FoundElse); diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp index be4defe786..a22d67a6ed 100644 --- a/lib/Lex/PPLexerChange.cpp +++ b/lib/Lex/PPLexerChange.cpp @@ -70,7 +70,7 @@ PreprocessorLexer *Preprocessor::getCurrentFileLexer() const { /// start lexing tokens from it instead of the current buffer. void Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir, SourceLocation Loc) { - assert(CurTokenLexer == 0 && "Cannot #include a file inside a macro!"); + assert(!CurTokenLexer && "Cannot #include a file inside a macro!"); ++NumEnteredSourceFiles; if (MaxIncludeStackDepth < IncludeMacroStack.size()) diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 6a87b78879..8ad028155a 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2524,7 +2524,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // erroneous: We already checked about that it has no type specifier, and // C++ doesn't have implicit int. Diagnose it as a typo w.r.t. to the // typename. - if (TypeRep == 0) { + if (!TypeRep) { ConsumeToken(); // Eat the scope spec so the identifier is current. ParsedAttributesWithRange Attrs(AttrFactory); if (ParseImplicitInt(DS, &SS, TemplateInfo, AS, DSContext, Attrs)) { diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp index 507a6b1bcd..e192ae2e23 100644 --- a/lib/Parse/ParseOpenMP.cpp +++ b/lib/Parse/ParseOpenMP.cpp @@ -12,8 +12,10 @@ //===----------------------------------------------------------------------===// #include "clang/AST/ASTConsumer.h" -#include "clang/Parse/Parser.h" #include "clang/Parse/ParseDiagnostic.h" +#include "clang/Parse/Parser.h" +#include "clang/Sema/Scope.h" +#include "llvm/ADT/PointerIntPair.h" #include "RAIIObjectsForParser.h" using namespace clang; @@ -21,22 +23,24 @@ using namespace clang; // OpenMP declarative directives. //===----------------------------------------------------------------------===// -/// \brief Parses OpenMP declarative directive -/// threadprivate-directive -/// annot_pragma_openmp threadprivate simple-variable-list +/// \brief Parsing of declarative OpenMP directives. +/// +/// threadprivate-directive: +/// annot_pragma_openmp 'threadprivate' simple-variable-list /// Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!"); SourceLocation Loc = ConsumeToken(); - SmallVector<DeclarationNameInfo, 5> Identifiers; - OpenMPDirectiveKind Kind = Tok.isAnnotation() ? - OMPD_unknown : - getOpenMPDirectiveKind(PP.getSpelling(Tok)); - switch(Kind) { + SmallVector<Expr *, 5> Identifiers; + OpenMPDirectiveKind DKind = Tok.isAnnotation() ? + OMPD_unknown : + getOpenMPDirectiveKind(PP.getSpelling(Tok)); + + switch (DKind) { case OMPD_threadprivate: ConsumeToken(); - if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers)) { + if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers, true)) { // The last seen token is annot_pragma_openmp_end - need to check for // extra tokens. if (Tok.isNot(tok::annot_pragma_openmp_end)) { @@ -44,9 +48,9 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { << getOpenMPDirectiveName(OMPD_threadprivate); SkipUntil(tok::annot_pragma_openmp_end, false, true); } + // Skip the last annot_pragma_openmp_end. ConsumeToken(); return Actions.ActOnOpenMPThreadprivateDirective(Loc, - getCurScope(), Identifiers); } break; @@ -55,7 +59,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { break; default: Diag(Tok, diag::err_omp_unexpected_directive) - << getOpenMPDirectiveName(Kind); + << getOpenMPDirectiveName(DKind); break; } SkipUntil(tok::annot_pragma_openmp_end, false); @@ -63,56 +67,69 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { } /// \brief Parses list of simple variables for '#pragma omp threadprivate' -/// directive -/// simple-variable-list: -/// ( unqualified-id {, unqualified-id} ) annot_pragma_openmp_end +/// directive. +/// +/// simple-variable-list: +/// '(' id-expression {, id-expression} ')' /// -bool Parser::ParseOpenMPSimpleVarList( - OpenMPDirectiveKind Kind, - SmallVectorImpl<DeclarationNameInfo> &IdList) { +bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind, + SmallVectorImpl<Expr *> &VarList, + bool AllowScopeSpecifier) { + VarList.clear(); // Parse '('. - bool IsCorrect = true; - BalancedDelimiterTracker T(*this, tok::l_paren); - if (T.expectAndConsume(diag::err_expected_lparen_after, - getOpenMPDirectiveName(Kind))) { - SkipUntil(tok::annot_pragma_openmp_end, false, true); - return false; - } + BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); + bool LParen = !T.expectAndConsume(diag::err_expected_lparen_after, + getOpenMPDirectiveName(Kind)); + bool IsCorrect = LParen; + bool NoIdentIsFound = true; // Read tokens while ')' or annot_pragma_openmp_end is not found. - do { + while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)) { CXXScopeSpec SS; SourceLocation TemplateKWLoc; UnqualifiedId Name; // Read var name. Token PrevTok = Tok; + NoIdentIsFound = false; - if (ParseUnqualifiedId(SS, false, false, false, ParsedType(), - TemplateKWLoc, Name)) { + if (AllowScopeSpecifier && getLangOpts().CPlusPlus && + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false)) { IsCorrect = false; SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, false, true); - } - else if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren) && - Tok.isNot(tok::annot_pragma_openmp_end)) { + } else if (ParseUnqualifiedId(SS, false, false, false, ParsedType(), + TemplateKWLoc, Name)) { + IsCorrect = false; + SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, + false, true); + } else if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren) && + Tok.isNot(tok::annot_pragma_openmp_end)) { IsCorrect = false; SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, false, true); - Diag(PrevTok.getLocation(), diag::err_expected_unqualified_id) - << getLangOpts().CPlusPlus + Diag(PrevTok.getLocation(), diag::err_expected_ident) << SourceRange(PrevTok.getLocation(), PrevTokLocation); } else { - IdList.push_back(Actions.GetNameFromUnqualifiedId(Name)); + DeclarationNameInfo NameInfo = Actions.GetNameFromUnqualifiedId(Name); + ExprResult Res = Actions.ActOnOpenMPIdExpression(getCurScope(), SS, + NameInfo); + if (Res.isUsable()) + VarList.push_back(Res.take()); } // Consume ','. if (Tok.is(tok::comma)) { ConsumeToken(); } - } while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)); + } - if (IsCorrect || Tok.is(tok::r_paren)) { - IsCorrect = !T.consumeClose() && IsCorrect; + if (NoIdentIsFound) { + Diag(Tok, diag::err_expected_ident); + IsCorrect = false; } - return !IsCorrect && IdList.empty(); + // Parse ')'. + IsCorrect = ((LParen || Tok.is(tok::r_paren)) && !T.consumeClose()) + && IsCorrect; + + return !IsCorrect && VarList.empty(); } diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 43b6965d31..f47b0e5435 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -2091,8 +2091,8 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { const std::string &TT = TheTriple.getTriple(); const llvm::Target *TheTarget = llvm::TargetRegistry::lookupTarget(TT, Error); - OwningPtr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TT)); OwningPtr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT)); + OwningPtr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TT)); OwningPtr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo()); OwningPtr<llvm::MCSubtargetInfo> STI(TheTarget->createMCSubtargetInfo(TT, "", "")); diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 2117df45f3..a5371f9e61 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -1897,7 +1897,7 @@ bool BalancedDelimiterTracker::diagnoseOverflow() { P.Diag(P.Tok, diag::err_bracket_depth_exceeded) << P.getLangOpts().BracketDepth; P.Diag(P.Tok, diag::note_bracket_depth); - P.SkipUntil(tok::eof); + P.SkipUntil(tok::eof, FinalToken); return true; } @@ -1927,7 +1927,8 @@ bool BalancedDelimiterTracker::diagnoseMissingClose() { } P.Diag(P.Tok, DID); P.Diag(LOpen, diag::note_matching) << LHSName; - if (P.SkipUntil(Close, /*StopAtSemi*/ true, /*DontConsume*/ true)) + if (P.SkipUntil(Close, FinalToken, /*StopAtSemi*/ true, /*DontConsume*/ true) + && P.Tok.is(Close)) LClose = P.ConsumeAnyToken(); return true; } diff --git a/lib/Parse/RAIIObjectsForParser.h b/lib/Parse/RAIIObjectsForParser.h index 213950a6db..f68a2e09fe 100644 --- a/lib/Parse/RAIIObjectsForParser.h +++ b/lib/Parse/RAIIObjectsForParser.h @@ -358,7 +358,7 @@ namespace clang { /// pair, such as braces { ... } or parentheses ( ... ). class BalancedDelimiterTracker : public GreaterThanIsOperatorScope { Parser& P; - tok::TokenKind Kind, Close; + tok::TokenKind Kind, Close, FinalToken; SourceLocation (Parser::*Consumer)(); SourceLocation LOpen, LClose; @@ -377,9 +377,10 @@ namespace clang { bool diagnoseMissingClose(); public: - BalancedDelimiterTracker(Parser& p, tok::TokenKind k) + BalancedDelimiterTracker(Parser& p, tok::TokenKind k, + tok::TokenKind FinalToken = tok::semi) : GreaterThanIsOperatorScope(p.GreaterThanIsOperator, true), - P(p), Kind(k) + P(p), Kind(k), FinalToken(FinalToken) { switch (Kind) { default: llvm_unreachable("Unexpected balanced token"); diff --git a/lib/Rewrite/Core/Rewriter.cpp b/lib/Rewrite/Core/Rewriter.cpp index c1c6595d16..540e8b27fd 100644 --- a/lib/Rewrite/Core/Rewriter.cpp +++ b/lib/Rewrite/Core/Rewriter.cpp @@ -463,7 +463,7 @@ public: } } - bool ok() { return FileStream; } + bool ok() { return FileStream.isValid(); } raw_ostream &getStream() { return *FileStream; } private: diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp index 3b3ab2c27b..dfce324b70 100644 --- a/lib/Sema/DeclSpec.cpp +++ b/lib/Sema/DeclSpec.cpp @@ -651,7 +651,7 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation TagKwLoc, DeclRep = Rep; TSTLoc = TagKwLoc; TSTNameLoc = TagNameLoc; - TypeSpecOwned = Owned; + TypeSpecOwned = Owned && Rep != 0; return false; } diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index e718be2f8b..b7810da98e 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -332,7 +332,7 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) { if (D->getMostRecentDecl()->isUsed()) return true; - if (D->hasExternalLinkage()) + if (D->isExternallyVisible()) return true; if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { @@ -402,13 +402,13 @@ void Sema::getUndefinedButUsed( if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { if (FD->isDefined()) continue; - if (FD->hasExternalLinkage() && + if (FD->isExternallyVisible() && !FD->getMostRecentDecl()->isInlined()) continue; } else { if (cast<VarDecl>(ND)->hasDefinition() != VarDecl::DeclarationOnly) continue; - if (ND->hasExternalLinkage()) + if (ND->isExternallyVisible()) continue; } @@ -435,7 +435,7 @@ static void checkUndefinedButUsed(Sema &S) { I = Undefined.begin(), E = Undefined.end(); I != E; ++I) { NamedDecl *ND = I->first; - if (ND->getLinkage() != ExternalLinkage) { + if (!ND->isExternallyVisible()) { S.Diag(ND->getLocation(), diag::warn_undefined_internal) << isa<VarDecl>(ND) << ND; } else { diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 5d8839a65b..49be515f0b 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1194,7 +1194,7 @@ bool Sema::mightHaveNonExternalLinkage(const DeclaratorDecl *D) { DC = DC->getParent(); } - return !D->hasExternalLinkage(); + return !D->isExternallyVisible(); } bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const { @@ -1614,7 +1614,7 @@ static void filterNonConflictingPreviousDecls(ASTContext &context, if (!old->isHidden()) continue; - if (old->getLinkage() != ExternalLinkage) + if (!old->isExternallyVisible()) filter.erase(); } @@ -2314,7 +2314,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) { // storage classes. if (!isa<CXXMethodDecl>(New) && !isa<CXXMethodDecl>(Old) && New->getStorageClass() == SC_Static && - isExternalLinkage(Old->getLinkage()) && + Old->hasExternalFormalLinkage() && !New->getTemplateSpecializationInfo() && !canRedefineFunction(Old, getLangOpts())) { if (getLangOpts().MicrosoftExt) { @@ -2923,7 +2923,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous, // [dcl.stc]p8: Check if we have a non-static decl followed by a static. if (New->getStorageClass() == SC_Static && !New->isStaticDataMember() && - isExternalLinkage(Old->getLinkage())) { + Old->hasExternalFormalLinkage()) { Diag(New->getLocation(), diag::err_static_non_static) << New->getDeclName(); Diag(Old->getLocation(), diag::note_previous_definition); return New->setInvalidDecl(); @@ -4625,13 +4625,13 @@ bool Sema::inferObjCARCLifetime(ValueDecl *decl) { static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) { // 'weak' only applies to declarations with external linkage. if (WeakAttr *Attr = ND.getAttr<WeakAttr>()) { - if (ND.getLinkage() != ExternalLinkage) { + if (!ND.isExternallyVisible()) { S.Diag(Attr->getLocation(), diag::err_attribute_weak_static); ND.dropAttr<WeakAttr>(); } } if (WeakRefAttr *Attr = ND.getAttr<WeakRefAttr>()) { - if (ND.hasExternalLinkage()) { + if (ND.isExternallyVisible()) { S.Diag(Attr->getLocation(), diag::err_attribute_weakref_not_static); ND.dropAttr<WeakRefAttr>(); } @@ -6579,7 +6579,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // If there's a #pragma GCC visibility in scope, and this isn't a class // member, set the visibility of this function. - if (!DC->isRecord() && NewFD->hasExternalLinkage()) + if (!DC->isRecord() && NewFD->isExternallyVisible()) AddPushedVisibilityAttribute(NewFD); // If there's a #pragma clang arc_cf_code_audited in scope, consider @@ -7816,7 +7816,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, // declared with no linkage (C99 6.2.2p6), the type for the // object shall be complete. if (!Type->isDependentType() && Var->isLocalVarDecl() && - !Var->getLinkage() && !Var->isInvalidDecl() && + !Var->hasLinkage() && !Var->isInvalidDecl() && RequireCompleteType(Var->getLocation(), Type, diag::err_typecheck_decl_incomplete_type)) Var->setInvalidDecl(); @@ -8029,7 +8029,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { } if (var->isThisDeclarationADefinition() && - var->hasExternalLinkage() && + var->isExternallyVisible() && getDiagnostics().getDiagnosticLevel( diag::warn_missing_variable_declarations, var->getLocation())) { @@ -8138,7 +8138,7 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) { const DeclContext *DC = VD->getDeclContext(); // If there's a #pragma GCC visibility in scope, and this isn't a class // member, set the visibility of this variable. - if (!DC->isRecord() && VD->hasExternalLinkage()) + if (!DC->isRecord() && VD->isExternallyVisible()) AddPushedVisibilityAttribute(VD); if (VD->isFileVarDecl()) @@ -8904,7 +8904,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, // ODR use before the definition. Avoid the expensive map lookup if this // is the first declaration. if (FD->getPreviousDecl() != 0 && FD->getPreviousDecl()->isUsed()) { - if (FD->getLinkage() != ExternalLinkage) + if (!FD->isExternallyVisible()) UndefinedButUsed.erase(FD); else if (FD->isInlined() && (LangOpts.CPlusPlus || !LangOpts.GNUInline) && diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index e5d0316f73..437a9da422 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -9307,7 +9307,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, ParmVarDecl *Other = MoveAssignOperator->getParamDecl(0); QualType OtherRefType = Other->getType()-> getAs<RValueReferenceType>()->getPointeeType(); - assert(OtherRefType.getQualifiers() == 0 && + assert(!OtherRefType.getQualifiers() && "Bad argument type of defaulted move assignment"); // Our location for everything implicitly-generated. @@ -11824,7 +11824,7 @@ bool Sema::DefineUsedVTables() { Consumer.HandleVTable(Class, VTablesUsed[Canonical]); // Optionally warn if we're emitting a weak vtable. - if (Class->hasExternalLinkage() && + if (Class->isExternallyVisible() && Class->getTemplateSpecializationKind() != TSK_ImplicitInstantiation) { const FunctionDecl *KeyFunctionDef = 0; if (!KeyFunction || diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index f33e7bcb16..3265ab02dc 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -2945,7 +2945,7 @@ Decl *Sema::ActOnMethodDeclaration( QualType ArgType; TypeSourceInfo *DI; - if (ArgInfo[i].Type == 0) { + if (!ArgInfo[i].Type) { ArgType = Context.getObjCIdType(); DI = 0; } else { @@ -3052,6 +3052,8 @@ Decl *Sema::ActOnMethodDeclaration( Diag(ObjCMethod->getLocation(), diag::err_duplicate_method_decl) << ObjCMethod->getDeclName(); Diag(PrevMethod->getLocation(), diag::note_previous_declaration); + ObjCMethod->setInvalidDecl(); + return ObjCMethod; } // If this Objective-C method does not have a related result type, but we diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index b6b6444738..fa2bfd260b 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -197,11 +197,11 @@ static void diagnoseUseOfInternalDeclInInlineFunction(Sema &S, return; if (!Current->isInlined()) return; - if (Current->getLinkage() != ExternalLinkage) + if (!Current->isExternallyVisible()) return; - + // Check if the decl has internal linkage. - if (D->getLinkage() != InternalLinkage) + if (D->getFormalLinkage() != InternalLinkage) return; // Downgrade from ExtWarn to Extension if @@ -4468,7 +4468,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, ExprResult Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, ParsedType Ty, SourceLocation RParenLoc, Expr *InitExpr) { - assert((Ty != 0) && "ActOnCompoundLiteral(): missing type"); + assert(Ty && "ActOnCompoundLiteral(): missing type"); // FIXME: put back this assert when initializers are worked out. //assert((InitExpr != 0) && "ActOnCompoundLiteral(): missing expression"); @@ -11459,7 +11459,7 @@ static void MarkVarDeclODRUsed(Sema &SemaRef, VarDecl *Var, // Keep track of used but undefined variables. // FIXME: We shouldn't suppress this warning for static data members. if (Var->hasDefinition(SemaRef.Context) == VarDecl::DeclarationOnly && - Var->getLinkage() != ExternalLinkage && + !Var->isExternallyVisible() && !(Var->isStaticDataMember() && Var->hasInit())) { SourceLocation &old = SemaRef.UndefinedButUsed[Var->getCanonicalDecl()]; if (old.isInvalid()) old = Loc; diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index d37f61ab8a..23116d84ad 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -1221,10 +1221,17 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, else DiagID = isClassMessage ? diag::warn_class_method_not_found : diag::warn_inst_method_not_found; - if (!getLangOpts().DebuggerSupport) + if (!getLangOpts().DebuggerSupport) { Diag(SelLoc, DiagID) << Sel << isClassMessage << SourceRange(SelectorLocs.front(), SelectorLocs.back()); + // Find the class to which we are sending this message. + if (ReceiverType->isObjCObjectPointerType()) { + if (ObjCInterfaceDecl *Class = + ReceiverType->getAs<ObjCObjectPointerType>()->getInterfaceDecl()) + Diag(Class->getLocation(), diag::note_receiver_class_declared); + } + } // In debuggers, we want to use __unknown_anytype for these // results so that clients can cast them. diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 7016e565da..a3b78787e4 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -32,54 +32,99 @@ using namespace clang; // Sema Initialization Checking //===----------------------------------------------------------------------===// -static Expr *IsStringInit(Expr *Init, const ArrayType *AT, - ASTContext &Context) { +/// \brief Check whether T is compatible with a wide character type (wchar_t, +/// char16_t or char32_t). +static bool IsWideCharCompatible(QualType T, ASTContext &Context) { + if (Context.typesAreCompatible(Context.getWideCharType(), T)) + return true; + if (Context.getLangOpts().CPlusPlus || Context.getLangOpts().C11) { + return Context.typesAreCompatible(Context.Char16Ty, T) || + Context.typesAreCompatible(Context.Char32Ty, T); + } + return false; +} + +enum StringInitFailureKind { + SIF_None, + SIF_NarrowStringIntoWideChar, + SIF_WideStringIntoChar, + SIF_IncompatWideStringIntoWideChar, + SIF_Other +}; + +/// \brief Check whether the array of type AT can be initialized by the Init +/// expression by means of string initialization. Returns SIF_None if so, +/// otherwise returns a StringInitFailureKind that describes why the +/// initialization would not work. +static StringInitFailureKind IsStringInit(Expr *Init, const ArrayType *AT, + ASTContext &Context) { if (!isa<ConstantArrayType>(AT) && !isa<IncompleteArrayType>(AT)) - return 0; + return SIF_Other; // See if this is a string literal or @encode. Init = Init->IgnoreParens(); // Handle @encode, which is a narrow string. if (isa<ObjCEncodeExpr>(Init) && AT->getElementType()->isCharType()) - return Init; + return SIF_None; // Otherwise we can only handle string literals. StringLiteral *SL = dyn_cast<StringLiteral>(Init); - if (SL == 0) return 0; + if (SL == 0) + return SIF_Other; - QualType ElemTy = Context.getCanonicalType(AT->getElementType()); + const QualType ElemTy = + Context.getCanonicalType(AT->getElementType()).getUnqualifiedType(); switch (SL->getKind()) { case StringLiteral::Ascii: case StringLiteral::UTF8: // char array can be initialized with a narrow string. // Only allow char x[] = "foo"; not char x[] = L"foo"; - return ElemTy->isCharType() ? Init : 0; + if (ElemTy->isCharType()) + return SIF_None; + if (IsWideCharCompatible(ElemTy, Context)) + return SIF_NarrowStringIntoWideChar; + return SIF_Other; + // C99 6.7.8p15 (with correction from DR343), or C11 6.7.9p15: + // "An array with element type compatible with a qualified or unqualified + // version of wchar_t, char16_t, or char32_t may be initialized by a wide + // string literal with the corresponding encoding prefix (L, u, or U, + // respectively), optionally enclosed in braces. case StringLiteral::UTF16: - return ElemTy->isChar16Type() ? Init : 0; + if (Context.typesAreCompatible(Context.Char16Ty, ElemTy)) + return SIF_None; + if (ElemTy->isCharType()) + return SIF_WideStringIntoChar; + if (IsWideCharCompatible(ElemTy, Context)) + return SIF_IncompatWideStringIntoWideChar; + return SIF_Other; case StringLiteral::UTF32: - return ElemTy->isChar32Type() ? Init : 0; + if (Context.typesAreCompatible(Context.Char32Ty, ElemTy)) + return SIF_None; + if (ElemTy->isCharType()) + return SIF_WideStringIntoChar; + if (IsWideCharCompatible(ElemTy, Context)) + return SIF_IncompatWideStringIntoWideChar; + return SIF_Other; case StringLiteral::Wide: - // wchar_t array can be initialized with a wide string: C99 6.7.8p15 (with - // correction from DR343): "An array with element type compatible with a - // qualified or unqualified version of wchar_t may be initialized by a wide - // string literal, optionally enclosed in braces." - if (Context.typesAreCompatible(Context.getWideCharType(), - ElemTy.getUnqualifiedType())) - return Init; - - return 0; + if (Context.typesAreCompatible(Context.getWideCharType(), ElemTy)) + return SIF_None; + if (ElemTy->isCharType()) + return SIF_WideStringIntoChar; + if (IsWideCharCompatible(ElemTy, Context)) + return SIF_IncompatWideStringIntoWideChar; + return SIF_Other; } llvm_unreachable("missed a StringLiteral kind?"); } -static Expr *IsStringInit(Expr *init, QualType declType, ASTContext &Context) { +static bool IsStringInit(Expr* init, QualType declType, ASTContext& Context) { const ArrayType *arrayType = Context.getAsArrayType(declType); - if (!arrayType) return 0; - - return IsStringInit(init, arrayType, Context); + if (!arrayType) + return false; + return IsStringInit(init, arrayType, Context) == SIF_None; } /// Update the type of a string literal, including any surrounding parentheses, @@ -806,10 +851,10 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, // array member. There's nothing we can do with the completed // type here, though. - if (Expr *Str = IsStringInit(expr, arrayType, SemaRef.Context)) { + if (IsStringInit(expr, arrayType, SemaRef.Context) == SIF_None) { if (!VerifyOnly) { - CheckStringInit(Str, ElemType, arrayType, SemaRef); - UpdateStructuredListElement(StructuredList, StructuredIndex, Str); + CheckStringInit(expr, ElemType, arrayType, SemaRef); + UpdateStructuredListElement(StructuredList, StructuredIndex, expr); } ++Index; return; @@ -1189,16 +1234,17 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity, // Check for the special-case of initializing an array with a string. if (Index < IList->getNumInits()) { - if (Expr *Str = IsStringInit(IList->getInit(Index), arrayType, - SemaRef.Context)) { + if (IsStringInit(IList->getInit(Index), arrayType, SemaRef.Context) == + SIF_None) { // We place the string literal directly into the resulting // initializer list. This is the only place where the structure // of the structured initializer list doesn't match exactly, // because doing so would involve allocating one character // constant for each string. if (!VerifyOnly) { - CheckStringInit(Str, DeclType, arrayType, SemaRef); - UpdateStructuredListElement(StructuredList, StructuredIndex, Str); + CheckStringInit(IList->getInit(Index), DeclType, arrayType, SemaRef); + UpdateStructuredListElement(StructuredList, StructuredIndex, + IList->getInit(Index)); StructuredList->resizeInits(SemaRef.Context, StructuredIndex); } ++Index; @@ -2507,6 +2553,10 @@ bool InitializationSequence::isAmbiguous() const { case FK_TooManyInitsForReference: case FK_ArrayNeedsInitList: case FK_ArrayNeedsInitListOrStringLiteral: + case FK_ArrayNeedsInitListOrWideStringLiteral: + case FK_NarrowStringIntoWideCharArray: + case FK_WideStringIntoCharArray: + case FK_IncompatWideStringIntoWideChar: case FK_AddressOfOverloadFailed: // FIXME: Could do better case FK_NonConstLValueReferenceBindingToTemporary: case FK_NonConstLValueReferenceBindingToUnrelated: @@ -4278,9 +4328,23 @@ InitializationSequence::InitializationSequence(Sema &S, return; } - if (Initializer && IsStringInit(Initializer, DestAT, Context)) { - TryStringLiteralInitialization(S, Entity, Kind, Initializer, *this); - return; + if (Initializer) { + switch (IsStringInit(Initializer, DestAT, Context)) { + case SIF_None: + TryStringLiteralInitialization(S, Entity, Kind, Initializer, *this); + return; + case SIF_NarrowStringIntoWideChar: + SetFailed(FK_NarrowStringIntoWideCharArray); + return; + case SIF_WideStringIntoChar: + SetFailed(FK_WideStringIntoCharArray); + return; + case SIF_IncompatWideStringIntoWideChar: + SetFailed(FK_IncompatWideStringIntoWideChar); + return; + case SIF_Other: + break; + } } // Note: as an GNU C extension, we allow initialization of an @@ -4307,8 +4371,10 @@ InitializationSequence::InitializationSequence(Sema &S, TryListInitialization(S, Entity, Kind, cast<InitListExpr>(Initializer), *this); AddParenthesizedArrayInitStep(DestType); - } else if (DestAT->getElementType()->isAnyCharacterType()) + } else if (DestAT->getElementType()->isCharType()) SetFailed(FK_ArrayNeedsInitListOrStringLiteral); + else if (IsWideCharCompatible(DestAT->getElementType(), Context)) + SetFailed(FK_ArrayNeedsInitListOrWideStringLiteral); else SetFailed(FK_ArrayNeedsInitList); @@ -5816,11 +5882,24 @@ bool InitializationSequence::Diagnose(Sema &S, break; case FK_ArrayNeedsInitList: + S.Diag(Kind.getLocation(), diag::err_array_init_not_init_list) << 0; + break; case FK_ArrayNeedsInitListOrStringLiteral: - S.Diag(Kind.getLocation(), diag::err_array_init_not_init_list) - << (Failure == FK_ArrayNeedsInitListOrStringLiteral); + S.Diag(Kind.getLocation(), diag::err_array_init_not_init_list) << 1; + break; + case FK_ArrayNeedsInitListOrWideStringLiteral: + S.Diag(Kind.getLocation(), diag::err_array_init_not_init_list) << 2; + break; + case FK_NarrowStringIntoWideCharArray: + S.Diag(Kind.getLocation(), diag::err_array_init_narrow_string_into_wchar); + break; + case FK_WideStringIntoCharArray: + S.Diag(Kind.getLocation(), diag::err_array_init_wide_string_into_char); + break; + case FK_IncompatWideStringIntoWideChar: + S.Diag(Kind.getLocation(), + diag::err_array_init_incompat_wide_string_into_wchar); break; - case FK_ArrayTypeMismatch: case FK_NonConstantArrayInit: S.Diag(Kind.getLocation(), @@ -6192,6 +6271,22 @@ void InitializationSequence::dump(raw_ostream &OS) const { OS << "array requires initializer list or string literal"; break; + case FK_ArrayNeedsInitListOrWideStringLiteral: + OS << "array requires initializer list or wide string literal"; + break; + + case FK_NarrowStringIntoWideCharArray: + OS << "narrow string into wide char array"; + break; + + case FK_WideStringIntoCharArray: + OS << "wide string into char array"; + break; + + case FK_IncompatWideStringIntoWideChar: + OS << "incompatible wide string into wide char array"; + break; + case FK_ArrayTypeMismatch: OS << "array type mismatch"; break; diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 9ab3b2d08e..c70367691f 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -4166,7 +4166,7 @@ std::string TypoCorrection::getAsString(const LangOptions &LO) const { std::string tmpBuffer; llvm::raw_string_ostream PrefixOStream(tmpBuffer); CorrectionNameSpec->print(PrefixOStream, PrintingPolicy(LO)); - CorrectionName.printName(PrefixOStream); + PrefixOStream << CorrectionName; return PrefixOStream.str(); } diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index c815d4f9ab..4953d2d14e 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// /// \file /// \brief This file implements semantic analysis for OpenMP directives and -/// clauses +/// clauses. /// //===----------------------------------------------------------------------===// @@ -22,117 +22,121 @@ using namespace clang; namespace { - class VarDeclFilterCCC : public CorrectionCandidateCallback { - private: - Sema &Actions; - public: - VarDeclFilterCCC(Sema &S) : Actions(S) { } - virtual bool ValidateCandidate(const TypoCorrection &Candidate) { - NamedDecl *ND = Candidate.getCorrectionDecl(); - if (VarDecl *VD = dyn_cast_or_null<VarDecl>(ND)) { - return VD->hasGlobalStorage() && - Actions.isDeclInScope(ND, Actions.getCurLexicalContext(), - Actions.getCurScope()); - } - return false; - } - }; +class VarDeclFilterCCC : public CorrectionCandidateCallback { +private: + Sema &Actions; +public: + VarDeclFilterCCC(Sema &S) : Actions(S) { } + virtual bool ValidateCandidate(const TypoCorrection &Candidate) { + NamedDecl *ND = Candidate.getCorrectionDecl(); + if (VarDecl *VD = dyn_cast_or_null<VarDecl>(ND)) { + return VD->hasGlobalStorage() && + Actions.isDeclInScope(ND, Actions.getCurLexicalContext(), + Actions.getCurScope()); + } + return false; + } +}; } -Sema::DeclGroupPtrTy Sema::ActOnOpenMPThreadprivateDirective( - SourceLocation Loc, - Scope *CurScope, - ArrayRef<DeclarationNameInfo> IdList) { - SmallVector<DeclRefExpr *, 5> Vars; - for (ArrayRef<DeclarationNameInfo>::iterator I = IdList.begin(), - E = IdList.end(); - I != E; ++I) { - LookupResult Lookup(*this, *I, LookupOrdinaryName); - LookupParsedName(Lookup, CurScope, NULL, true); - if (Lookup.isAmbiguous()) - continue; +ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope, + CXXScopeSpec &ScopeSpec, + const DeclarationNameInfo &Id) { + LookupResult Lookup(*this, Id, LookupOrdinaryName); + LookupParsedName(Lookup, CurScope, &ScopeSpec, true); - VarDecl *VD; - if (!Lookup.isSingleResult()) { - VarDeclFilterCCC Validator(*this); - TypoCorrection Corrected = CorrectTypo(*I, LookupOrdinaryName, CurScope, - 0, Validator); - std::string CorrectedStr = Corrected.getAsString(getLangOpts()); - std::string CorrectedQuotedStr = Corrected.getQuoted(getLangOpts()); - if (Lookup.empty()) { - if (Corrected.isResolved()) { - Diag(I->getLoc(), diag::err_undeclared_var_use_suggest) - << I->getName() << CorrectedQuotedStr - << FixItHint::CreateReplacement(I->getLoc(), CorrectedStr); - } else { - Diag(I->getLoc(), diag::err_undeclared_var_use) - << I->getName(); - } + if (Lookup.isAmbiguous()) + return ExprError(); + + VarDecl *VD; + if (!Lookup.isSingleResult()) { + VarDeclFilterCCC Validator(*this); + TypoCorrection Corrected = CorrectTypo(Id, LookupOrdinaryName, CurScope, + 0, Validator); + std::string CorrectedStr = Corrected.getAsString(getLangOpts()); + std::string CorrectedQuotedStr = Corrected.getQuoted(getLangOpts()); + if (Lookup.empty()) { + if (Corrected.isResolved()) { + Diag(Id.getLoc(), diag::err_undeclared_var_use_suggest) + << Id.getName() << CorrectedQuotedStr + << FixItHint::CreateReplacement(Id.getLoc(), CorrectedStr); } else { - Diag(I->getLoc(), diag::err_omp_expected_var_arg_suggest) - << I->getName() << Corrected.isResolved() << CorrectedQuotedStr - << FixItHint::CreateReplacement(I->getLoc(), CorrectedStr); + Diag(Id.getLoc(), diag::err_undeclared_var_use) + << Id.getName(); } - if (!Corrected.isResolved()) continue; - VD = Corrected.getCorrectionDeclAs<VarDecl>(); } else { - if (!(VD = Lookup.getAsSingle<VarDecl>())) { - Diag(I->getLoc(), diag::err_omp_expected_var_arg_suggest) - << I->getName() << 0; - Diag(Lookup.getFoundDecl()->getLocation(), diag::note_declared_at); - continue; - } + Diag(Id.getLoc(), diag::err_omp_expected_var_arg_suggest) + << Id.getName() << Corrected.isResolved() << CorrectedQuotedStr + << FixItHint::CreateReplacement(Id.getLoc(), CorrectedStr); } - - // OpenMP [2.9.2, Syntax, C/C++] - // Variables must be file-scope, namespace-scope, or static block-scope. - if (!VD->hasGlobalStorage()) { - Diag(I->getLoc(), diag::err_omp_global_var_arg) - << getOpenMPDirectiveName(OMPD_threadprivate) - << !VD->isStaticLocal(); - Diag(VD->getLocation(), diag::note_forward_declaration) << VD; - continue; + if (!Corrected.isResolved()) return ExprError(); + VD = Corrected.getCorrectionDeclAs<VarDecl>(); + } else { + if (!(VD = Lookup.getAsSingle<VarDecl>())) { + Diag(Id.getLoc(), diag::err_omp_expected_var_arg_suggest) + << Id.getName() << 0; + Diag(Lookup.getFoundDecl()->getLocation(), diag::note_declared_at); + return ExprError(); } + } + Lookup.suppressDiagnostics(); - // OpenMP [2.9.2, Restrictions, C/C++, p.2] - // A threadprivate directive for file-scope variables must appear outside - // any definition or declaration. - // OpenMP [2.9.2, Restrictions, C/C++, p.3] - // A threadprivate directive for static class member variables must appear - // in the class definition, in the same scope in which the member - // variables are declared. - // OpenMP [2.9.2, Restrictions, C/C++, p.4] - // A threadprivate directive for namespace-scope variables must appear - // outside any definition or declaration other than the namespace - // definition itself. - // OpenMP [2.9.2, Restrictions, C/C++, p.6] - // A threadprivate directive for static block-scope variables must appear - // in the scope of the variable and not in a nested scope. - NamedDecl *ND = cast<NamedDecl>(VD); - if (!isDeclInScope(ND, getCurLexicalContext(), CurScope)) { - Diag(I->getLoc(), diag::err_omp_var_scope) - << getOpenMPDirectiveName(OMPD_threadprivate) << VD; - Diag(VD->getLocation(), diag::note_forward_declaration) << VD; - continue; - } + // OpenMP [2.9.2, Syntax, C/C++] + // Variables must be file-scope, namespace-scope, or static block-scope. + if (!VD->hasGlobalStorage()) { + Diag(Id.getLoc(), diag::err_omp_global_var_arg) + << getOpenMPDirectiveName(OMPD_threadprivate) + << !VD->isStaticLocal(); + bool IsDecl = VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + Diag(VD->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; + return ExprError(); + } - // OpenMP [2.9.2, Restrictions, C/C++, p.2-6] - // A threadprivate directive must lexically precede all references to any - // of the variables in its list. - if (VD->isUsed()) { - Diag(I->getLoc(), diag::err_omp_var_used) - << getOpenMPDirectiveName(OMPD_threadprivate) << VD; - continue; - } + // OpenMP [2.9.2, Restrictions, C/C++, p.2] + // A threadprivate directive for file-scope variables must appear outside + // any definition or declaration. + // OpenMP [2.9.2, Restrictions, C/C++, p.3] + // A threadprivate directive for static class member variables must appear + // in the class definition, in the same scope in which the member + // variables are declared. + // OpenMP [2.9.2, Restrictions, C/C++, p.4] + // A threadprivate directive for namespace-scope variables must appear + // outside any definition or declaration other than the namespace + // definition itself. + // OpenMP [2.9.2, Restrictions, C/C++, p.6] + // A threadprivate directive for static block-scope variables must appear + // in the scope of the variable and not in a nested scope. + NamedDecl *ND = cast<NamedDecl>(VD); + if (!isDeclInScope(ND, getCurLexicalContext(), CurScope)) { + Diag(Id.getLoc(), diag::err_omp_var_scope) + << getOpenMPDirectiveName(OMPD_threadprivate) << VD; + bool IsDecl = VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : + diag::note_defined_here) << VD; + return ExprError(); + } - QualType ExprType = VD->getType().getNonReferenceType(); - DeclRefExpr *Var = cast<DeclRefExpr>(BuildDeclRefExpr(VD, - ExprType, - VK_RValue, - I->getLoc()).take()); - Vars.push_back(Var); + // OpenMP [2.9.2, Restrictions, C/C++, p.2-6] + // A threadprivate directive must lexically precede all references to any + // of the variables in its list. + if (VD->isUsed()) { + Diag(Id.getLoc(), diag::err_omp_var_used) + << getOpenMPDirectiveName(OMPD_threadprivate) << VD; + return ExprError(); } - if (OMPThreadPrivateDecl *D = CheckOMPThreadPrivateDecl(Loc, Vars)) { + + QualType ExprType = VD->getType().getNonReferenceType(); + ExprResult DE = BuildDeclRefExpr(VD, ExprType, VK_RValue, Id.getLoc()); + return DE; +} + +Sema::DeclGroupPtrTy Sema::ActOnOpenMPThreadprivateDirective( + SourceLocation Loc, + ArrayRef<Expr *> VarList) { + if (OMPThreadPrivateDecl *D = CheckOMPThreadPrivateDecl(Loc, VarList)) { CurContext->addDecl(D); return DeclGroupPtrTy::make(DeclGroupRef(D)); } @@ -141,18 +145,19 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPThreadprivateDirective( OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl( SourceLocation Loc, - ArrayRef<DeclRefExpr *> VarList) { - SmallVector<DeclRefExpr *, 5> Vars; - for (ArrayRef<DeclRefExpr *>::iterator I = VarList.begin(), + ArrayRef<Expr *> VarList) { + SmallVector<Expr *, 8> Vars; + for (ArrayRef<Expr *>::iterator I = VarList.begin(), E = VarList.end(); I != E; ++I) { - VarDecl *VD = cast<VarDecl>((*I)->getDecl()); - SourceLocation ILoc = (*I)->getLocation(); + DeclRefExpr *DE = cast<DeclRefExpr>(*I); + VarDecl *VD = cast<VarDecl>(DE->getDecl()); + SourceLocation ILoc = DE->getExprLoc(); // OpenMP [2.9.2, Restrictions, C/C++, p.10] // A threadprivate variable must not have an incomplete type. if (RequireCompleteType(ILoc, VD->getType(), - diag::err_omp_incomplete_type)) { + diag::err_omp_threadprivate_incomplete_type)) { continue; } @@ -160,15 +165,21 @@ OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl( // A threadprivate variable must not have a reference type. if (VD->getType()->isReferenceType()) { Diag(ILoc, diag::err_omp_ref_type_arg) - << getOpenMPDirectiveName(OMPD_threadprivate) << VD->getType(); - Diag(VD->getLocation(), diag::note_forward_declaration) << VD; + << getOpenMPDirectiveName(OMPD_threadprivate); + bool IsDecl = VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : + diag::note_defined_here) << VD; continue; } // Check if this is a TLS variable. if (VD->getTLSKind()) { Diag(ILoc, diag::err_omp_var_thread_local) << VD; - Diag(VD->getLocation(), diag::note_forward_declaration) << VD; + bool IsDecl = VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : + diag::note_defined_here) << VD; continue; } @@ -179,3 +190,4 @@ OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl( getCurLexicalContext(), Loc, Vars); } + diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index b9695cc1e1..7f1def7daf 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -3793,14 +3793,14 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, } // Address / reference template args must have external linkage in C++98. - if (Entity->getLinkage() == InternalLinkage) { + if (Entity->getFormalLinkage() == InternalLinkage) { S.Diag(Arg->getLocStart(), S.getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_template_arg_object_internal : diag::ext_template_arg_object_internal) << !Func << Entity << Arg->getSourceRange(); S.Diag(Entity->getLocation(), diag::note_template_arg_internal_object) << !Func; - } else if (Entity->getLinkage() == NoLinkage) { + } else if (!Entity->hasLinkage()) { S.Diag(Arg->getLocStart(), diag::err_template_arg_object_no_linkage) << !Func << Entity << Arg->getSourceRange(); S.Diag(Entity->getLocation(), diag::note_template_arg_internal_object) diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 42e1757bcb..ff59cdcbc4 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2231,13 +2231,13 @@ Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl( Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl( OMPThreadPrivateDecl *D) { - SmallVector<DeclRefExpr *, 5> Vars; - for (ArrayRef<DeclRefExpr *>::iterator I = D->varlist_begin(), - E = D->varlist_end(); + SmallVector<Expr *, 5> Vars; + for (ArrayRef<Expr *>::iterator I = D->varlist_begin(), + E = D->varlist_end(); I != E; ++I) { Expr *Var = SemaRef.SubstExpr(*I, TemplateArgs).take(); assert(isa<DeclRefExpr>(Var) && "threadprivate arg is not a DeclRefExpr"); - Vars.push_back(cast<DeclRefExpr>(Var)); + Vars.push_back(Var); } OMPThreadPrivateDecl *TD = diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 086acd261d..b117b733a4 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -1644,10 +1644,10 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *D, void ASTDeclReader::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) { VisitDecl(D); unsigned NumVars = D->varlist_size(); - SmallVector<DeclRefExpr *, 16> Vars; + SmallVector<Expr *, 16> Vars; Vars.reserve(NumVars); for (unsigned i = 0; i != NumVars; ++i) { - Vars.push_back(cast<DeclRefExpr>(Reader.ReadExpr(F))); + Vars.push_back(Reader.ReadExpr(F)); } D->setVars(Vars); } @@ -1783,14 +1783,14 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) { //prototyped/non-prototyped functions, etc. if (FunctionDecl *FuncX = dyn_cast<FunctionDecl>(X)) { FunctionDecl *FuncY = cast<FunctionDecl>(Y); - return (FuncX->getLinkage() == FuncY->getLinkage()) && + return (FuncX->getLinkageInternal() == FuncY->getLinkageInternal()) && FuncX->getASTContext().hasSameType(FuncX->getType(), FuncY->getType()); } // Variables with the same type and linkage match. if (VarDecl *VarX = dyn_cast<VarDecl>(X)) { VarDecl *VarY = cast<VarDecl>(Y); - return (VarX->getLinkage() == VarY->getLinkage()) && + return (VarX->getLinkageInternal() == VarY->getLinkageInternal()) && VarX->getASTContext().hasSameType(VarX->getType(), VarY->getType()); } diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 67349db687..7a22afaba7 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -334,7 +334,7 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) { Record.push_back(D->hasImplicitReturnZero()); Record.push_back(D->isConstexpr()); Record.push_back(D->HasSkippedBody); - Record.push_back(D->getLinkage()); + Record.push_back(D->getLinkageInternal()); Writer.AddSourceLocation(D->getLocEnd(), Record); Record.push_back(D->getTemplatedKind()); @@ -694,7 +694,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) { Record.push_back(D->isCXXForRangeDecl()); Record.push_back(D->isARCPseudoStrong()); Record.push_back(D->isConstexpr()); - Record.push_back(D->getLinkage()); + Record.push_back(D->getLinkageInternal()); if (D->getInit()) { Record.push_back(!D->isInitKnownICE() ? 1 : (D->isInitICE() ? 3 : 2)); diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp index 6388a8df64..ba779ff191 100644 --- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp +++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp @@ -90,20 +90,49 @@ static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID) { //===----------------------------------------------------------------------===// namespace { - class NilArgChecker : public Checker<check::PreObjCMessage> { + class NilArgChecker : public Checker<check::PreObjCMessage, + check::PostStmt<ObjCDictionaryLiteral>, + check::PostStmt<ObjCArrayLiteral> > { mutable OwningPtr<APIMisuse> BT; - void WarnIfNilArg(CheckerContext &C, - const ObjCMethodCall &msg, unsigned Arg, - FoundationClass Class, - bool CanBeSubscript = false) const; + void warnIfNilExpr(const Expr *E, + const char *Msg, + CheckerContext &C) const; + + void warnIfNilArg(CheckerContext &C, + const ObjCMethodCall &msg, unsigned Arg, + FoundationClass Class, + bool CanBeSubscript = false) const; + + void generateBugReport(ExplodedNode *N, + StringRef Msg, + SourceRange Range, + const Expr *Expr, + CheckerContext &C) const; public: void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const; + void checkPostStmt(const ObjCDictionaryLiteral *DL, + CheckerContext &C) const; + void checkPostStmt(const ObjCArrayLiteral *AL, + CheckerContext &C) const; }; } -void NilArgChecker::WarnIfNilArg(CheckerContext &C, +void NilArgChecker::warnIfNilExpr(const Expr *E, + const char *Msg, + CheckerContext &C) const { + ProgramStateRef State = C.getState(); + if (State->isNull(C.getSVal(E)).isConstrainedTrue()) { + + if (ExplodedNode *N = C.generateSink()) { + generateBugReport(N, Msg, E->getSourceRange(), E, C); + } + + } +} + +void NilArgChecker::warnIfNilArg(CheckerContext &C, const ObjCMethodCall &msg, unsigned int Arg, FoundationClass Class, @@ -113,9 +142,6 @@ void NilArgChecker::WarnIfNilArg(CheckerContext &C, if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue()) return; - if (!BT) - BT.reset(new APIMisuse("nil argument")); - if (ExplodedNode *N = C.generateSink()) { SmallString<128> sbuf; llvm::raw_svector_ostream os(sbuf); @@ -149,14 +175,26 @@ void NilArgChecker::WarnIfNilArg(CheckerContext &C, << msg.getSelector().getAsString() << "' cannot be nil"; } } - - BugReport *R = new BugReport(*BT, os.str(), N); - R->addRange(msg.getArgSourceRange(Arg)); - bugreporter::trackNullOrUndefValue(N, msg.getArgExpr(Arg), *R); - C.emitReport(R); + + generateBugReport(N, os.str(), msg.getArgSourceRange(Arg), + msg.getArgExpr(Arg), C); } } +void NilArgChecker::generateBugReport(ExplodedNode *N, + StringRef Msg, + SourceRange Range, + const Expr *E, + CheckerContext &C) const { + if (!BT) + BT.reset(new APIMisuse("nil argument")); + + BugReport *R = new BugReport(*BT, Msg, N); + R->addRange(Range); + bugreporter::trackNullOrUndefValue(N, E, *R); + C.emitReport(R); +} + void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const { const ObjCInterfaceDecl *ID = msg.getReceiverInterface(); @@ -225,28 +263,45 @@ void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg, if (S.getNameForSlot(0).equals("dictionaryWithObject") && S.getNameForSlot(1).equals("forKey")) { Arg = 0; - WarnIfNilArg(C, msg, /* Arg */1, Class); + warnIfNilArg(C, msg, /* Arg */1, Class); } else if (S.getNameForSlot(0).equals("setObject") && S.getNameForSlot(1).equals("forKey")) { Arg = 0; - WarnIfNilArg(C, msg, /* Arg */1, Class); + warnIfNilArg(C, msg, /* Arg */1, Class); } else if (S.getNameForSlot(0).equals("setObject") && S.getNameForSlot(1).equals("forKeyedSubscript")) { CanBeSubscript = true; Arg = 0; - WarnIfNilArg(C, msg, /* Arg */1, Class, CanBeSubscript); + warnIfNilArg(C, msg, /* Arg */1, Class, CanBeSubscript); } else if (S.getNameForSlot(0).equals("removeObjectForKey")) { Arg = 0; } } - // If argument is '0', report a warning. if ((Arg != InvalidArgIndex)) - WarnIfNilArg(C, msg, Arg, Class, CanBeSubscript); + warnIfNilArg(C, msg, Arg, Class, CanBeSubscript); } +void NilArgChecker::checkPostStmt(const ObjCArrayLiteral *AL, + CheckerContext &C) const { + unsigned NumOfElements = AL->getNumElements(); + for (unsigned i = 0; i < NumOfElements; ++i) { + warnIfNilExpr(AL->getElement(i), "Array element cannot be nil", C); + } +} + +void NilArgChecker::checkPostStmt(const ObjCDictionaryLiteral *DL, + CheckerContext &C) const { + unsigned NumOfElements = DL->getNumElements(); + for (unsigned i = 0; i < NumOfElements; ++i) { + ObjCDictionaryElement Element = DL->getKeyValueElement(i); + warnIfNilExpr(Element.Key, "Dictionary key cannot be nil", C); + warnIfNilExpr(Element.Value, "Dictionary value cannot be nil", C); + } +} + //===----------------------------------------------------------------------===// // Error reporting. //===----------------------------------------------------------------------===// diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index 00c92d8153..fe579a3fbf 100644 --- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -1465,9 +1465,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, SmallString<256> Buf; llvm::raw_svector_ostream Out(Buf); - Out << "Assuming '"; - VD->getDeclName().printName(Out); - Out << "' is "; + Out << "Assuming '" << VD->getDeclName() << "' is "; QualType VDTy = VD->getType(); diff --git a/lib/StaticAnalyzer/Core/CheckerContext.cpp b/lib/StaticAnalyzer/Core/CheckerContext.cpp index 74eeef1c67..6b22bf411c 100644 --- a/lib/StaticAnalyzer/Core/CheckerContext.cpp +++ b/lib/StaticAnalyzer/Core/CheckerContext.cpp @@ -68,7 +68,7 @@ bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD, // If this function is not externally visible, it is not a C library function. // Note that we make an exception for inline functions, which may be // declared in header files without external linkage. - if (!FD->isInlined() && FD->getLinkage() != ExternalLinkage) + if (!FD->isInlined() && !FD->isExternallyVisible()) return false; if (Name.empty()) diff --git a/test/Analysis/NSContainers.m b/test/Analysis/NSContainers.m index 6b4089b3e5..959f367d28 100644 --- a/test/Analysis/NSContainers.m +++ b/test/Analysis/NSContainers.m @@ -36,6 +36,10 @@ typedef struct _NSZone NSZone; - (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx __attribute__((availability(macosx,introduced=10.8))); @end +@interface NSArray (NSArrayCreation) ++ (instancetype)arrayWithObjects:(const id [])objects count:(NSUInteger)cnt; +@end + @interface NSMutableArray : NSArray - (void)addObject:(id)anObject; @@ -58,6 +62,8 @@ typedef struct _NSZone NSZone; + (id)dictionary; + (id)dictionaryWithObject:(id)object forKey:(id <NSCopying>)key; ++ (instancetype)dictionaryWithObjects:(const id [])objects forKeys:(const id <NSCopying> [])keys count:(NSUInteger)cnt; + @end @interface NSMutableDictionary : NSDictionary @@ -147,6 +153,33 @@ NSDictionary *testNilArgNSDictionary2(NSObject *obj) { return [NSDictionary dictionaryWithObject:obj forKey:0]; // expected-warning {{Key argument to 'dictionaryWithObject:forKey:' cannot be nil}} } +id testCreateDictionaryLiteralKey(id value, id nilKey) { + if (nilKey) + ; + return @{@"abc":value, nilKey:@"abc"}; // expected-warning {{Dictionary key cannot be nil}} +} + +id testCreateDictionaryLiteralValue(id nilValue) { + if (nilValue) + ; + return @{@"abc":nilValue}; // expected-warning {{Dictionary value cannot be nil}} +} + +id testCreateDictionaryLiteral(id nilValue, id nilKey) { + if (nilValue) + ; + if (nilKey) + ; + return @{@"abc":nilValue, nilKey:@"abc"}; // expected-warning {{Dictionary key cannot be nil}} + // expected-warning@-1 {{Dictionary value cannot be nil}} +} + +id testCreateArrayLiteral(id myNil) { + if (myNil) + ; + return @[ @"a", myNil, @"c" ]; // expected-warning {{Array element cannot be nil}} +} + // Test inline defensive checks suppression. void idc(id x) { if (x) diff --git a/test/Analysis/inlining/DynDispatchBifurcate.m b/test/Analysis/inlining/DynDispatchBifurcate.m index ab1dfc5ec1..0ce079654e 100644 --- a/test/Analysis/inlining/DynDispatchBifurcate.m +++ b/test/Analysis/inlining/DynDispatchBifurcate.m @@ -181,11 +181,11 @@ int testPropertySynthesized(PublicClass *p) { } // Test definition not available edge case. -@interface DefNotAvailClass : NSObject +@interface DefNotAvailClass : NSObject // expected-note {{receiver is instance of class declared here}} @end id testDefNotAvailableInlined(DefNotAvailClass *C) { return [C mem]; // expected-warning {{instance method '-mem' not found}} } id testDefNotAvailable(DefNotAvailClass *C) { return testDefNotAvailableInlined(C); -}
\ No newline at end of file +} diff --git a/test/Analysis/inlining/path-notes.m b/test/Analysis/inlining/path-notes.m index 74f088a382..602bad188a 100644 --- a/test/Analysis/inlining/path-notes.m +++ b/test/Analysis/inlining/path-notes.m @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -analyzer-config suppress-null-return-paths=false -fblocks -verify %s -// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config suppress-null-return-paths=false -fblocks %s -o %t.plist +// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NilArg -analyzer-output=text -analyzer-config suppress-null-return-paths=false -fblocks -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NilArg -analyzer-output=plist-multi-file -analyzer-config suppress-null-return-paths=false -fblocks %s -o %t.plist // RUN: FileCheck --input-file=%t.plist %s typedef struct dispatch_queue_s *dispatch_queue_t; @@ -11,6 +11,57 @@ void dispatch_sync(dispatch_queue_t, dispatch_block_t); @property int *p; @end +typedef unsigned long NSUInteger; +typedef signed char BOOL; +typedef struct _NSZone NSZone; +@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; +@protocol NSObject +@end +@protocol NSCopying +- (id)copyWithZone:(NSZone *)zone; +@end +@protocol NSMutableCopying +- (id)mutableCopyWithZone:(NSZone *)zone; +@end +@protocol NSCoding +- (void)encodeWithCoder:(NSCoder *)aCoder; +@end +@protocol NSFastEnumeration +@end +@protocol NSSecureCoding <NSCoding> +@required ++ (BOOL)supportsSecureCoding; +@end +@interface NSObject <NSObject> {} +- (id)init; ++ (id)alloc; +@end +@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSSecureCoding, NSFastEnumeration> + +- (NSUInteger)count; +- (id)objectAtIndex:(NSUInteger)index; + +@end + +@interface NSArray (NSExtendedArray) +- (NSArray *)arrayByAddingObject:(id)anObject; +- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx __attribute__((availability(macosx,introduced=10.8))); +@end + +@interface NSArray (NSArrayCreation) ++ (instancetype)arrayWithObjects:(const id [])objects count:(NSUInteger)cnt; +@end + +@interface NSMutableArray : NSArray + +- (void)addObject:(id)anObject; +- (void)insertObject:(id)anObject atIndex:(NSUInteger)index; +- (void)removeLastObject; +- (void)removeObjectAtIndex:(NSUInteger)index; +- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject; + +@end + int *getZeroIfNil(Test *x) { return x.p; // expected-note@-1 {{'p' not called because the receiver is nil}} @@ -89,6 +140,12 @@ void testNilReceiver(id *x) { // expected-note@-3 {{Calling 'testNilReceiverHelper'}} } +id testCreateArrayLiteral(id myNil) { + if (myNil) // expected-note {{Assuming 'myNil' is nil}} + ; // expected-note@-1 {{Taking false branch}} + return @[ @"a", myNil, @"c" ]; // expected-warning {{Array element cannot be nil}} + //expected-note@-1 {{Array element cannot be nil}} +} // CHECK: <key>diagnostics</key> // CHECK-NEXT: <array> @@ -103,12 +160,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>start</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>21</integer> +// CHECK-NEXT: <key>line</key><integer>72</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>21</integer> +// CHECK-NEXT: <key>line</key><integer>72</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -116,12 +173,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>end</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>21</integer> +// CHECK-NEXT: <key>line</key><integer>72</integer> // CHECK-NEXT: <key>col</key><integer>17</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>21</integer> +// CHECK-NEXT: <key>line</key><integer>72</integer> // CHECK-NEXT: <key>col</key><integer>17</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -133,7 +190,7 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>kind</key><string>event</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>21</integer> +// CHECK-NEXT: <key>line</key><integer>72</integer> // CHECK-NEXT: <key>col</key><integer>17</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -141,12 +198,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <array> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>21</integer> +// CHECK-NEXT: <key>line</key><integer>72</integer> // CHECK-NEXT: <key>col</key><integer>17</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>21</integer> +// CHECK-NEXT: <key>line</key><integer>72</integer> // CHECK-NEXT: <key>col</key><integer>17</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -166,12 +223,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>start</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>21</integer> +// CHECK-NEXT: <key>line</key><integer>72</integer> // CHECK-NEXT: <key>col</key><integer>17</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>21</integer> +// CHECK-NEXT: <key>line</key><integer>72</integer> // CHECK-NEXT: <key>col</key><integer>17</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -179,12 +236,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>end</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>21</integer> +// CHECK-NEXT: <key>line</key><integer>72</integer> // CHECK-NEXT: <key>col</key><integer>4</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>21</integer> +// CHECK-NEXT: <key>line</key><integer>72</integer> // CHECK-NEXT: <key>col</key><integer>15</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -196,7 +253,7 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>kind</key><string>event</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>21</integer> +// CHECK-NEXT: <key>line</key><integer>72</integer> // CHECK-NEXT: <key>col</key><integer>4</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -204,12 +261,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <array> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>21</integer> +// CHECK-NEXT: <key>line</key><integer>72</integer> // CHECK-NEXT: <key>col</key><integer>4</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>21</integer> +// CHECK-NEXT: <key>line</key><integer>72</integer> // CHECK-NEXT: <key>col</key><integer>18</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -225,7 +282,7 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>kind</key><string>event</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>14</integer> +// CHECK-NEXT: <key>line</key><integer>65</integer> // CHECK-NEXT: <key>col</key><integer>1</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -243,12 +300,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>start</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>14</integer> +// CHECK-NEXT: <key>line</key><integer>65</integer> // CHECK-NEXT: <key>col</key><integer>1</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>14</integer> +// CHECK-NEXT: <key>line</key><integer>65</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -256,12 +313,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>end</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>15</integer> +// CHECK-NEXT: <key>line</key><integer>66</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>15</integer> +// CHECK-NEXT: <key>line</key><integer>66</integer> // CHECK-NEXT: <key>col</key><integer>8</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -277,12 +334,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>start</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>15</integer> +// CHECK-NEXT: <key>line</key><integer>66</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>15</integer> +// CHECK-NEXT: <key>line</key><integer>66</integer> // CHECK-NEXT: <key>col</key><integer>8</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -290,12 +347,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>end</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>15</integer> +// CHECK-NEXT: <key>line</key><integer>66</integer> // CHECK-NEXT: <key>col</key><integer>10</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>15</integer> +// CHECK-NEXT: <key>line</key><integer>66</integer> // CHECK-NEXT: <key>col</key><integer>10</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -307,7 +364,7 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>kind</key><string>event</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>15</integer> +// CHECK-NEXT: <key>line</key><integer>66</integer> // CHECK-NEXT: <key>col</key><integer>10</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -315,12 +372,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <array> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>15</integer> +// CHECK-NEXT: <key>line</key><integer>66</integer> // CHECK-NEXT: <key>col</key><integer>10</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>15</integer> +// CHECK-NEXT: <key>line</key><integer>66</integer> // CHECK-NEXT: <key>col</key><integer>10</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -340,12 +397,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>start</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>15</integer> +// CHECK-NEXT: <key>line</key><integer>66</integer> // CHECK-NEXT: <key>col</key><integer>10</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>15</integer> +// CHECK-NEXT: <key>line</key><integer>66</integer> // CHECK-NEXT: <key>col</key><integer>10</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -353,12 +410,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>end</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>15</integer> +// CHECK-NEXT: <key>line</key><integer>66</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>15</integer> +// CHECK-NEXT: <key>line</key><integer>66</integer> // CHECK-NEXT: <key>col</key><integer>8</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -370,7 +427,7 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>kind</key><string>event</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>15</integer> +// CHECK-NEXT: <key>line</key><integer>66</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -378,12 +435,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <array> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>15</integer> +// CHECK-NEXT: <key>line</key><integer>66</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>15</integer> +// CHECK-NEXT: <key>line</key><integer>66</integer> // CHECK-NEXT: <key>col</key><integer>12</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -399,7 +456,7 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>kind</key><string>event</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>21</integer> +// CHECK-NEXT: <key>line</key><integer>72</integer> // CHECK-NEXT: <key>col</key><integer>4</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -407,12 +464,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <array> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>21</integer> +// CHECK-NEXT: <key>line</key><integer>72</integer> // CHECK-NEXT: <key>col</key><integer>4</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>21</integer> +// CHECK-NEXT: <key>line</key><integer>72</integer> // CHECK-NEXT: <key>col</key><integer>18</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -432,12 +489,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>start</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>21</integer> +// CHECK-NEXT: <key>line</key><integer>72</integer> // CHECK-NEXT: <key>col</key><integer>4</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>21</integer> +// CHECK-NEXT: <key>line</key><integer>72</integer> // CHECK-NEXT: <key>col</key><integer>15</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -445,12 +502,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>end</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>21</integer> +// CHECK-NEXT: <key>line</key><integer>72</integer> // CHECK-NEXT: <key>col</key><integer>20</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>21</integer> +// CHECK-NEXT: <key>line</key><integer>72</integer> // CHECK-NEXT: <key>col</key><integer>20</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -462,7 +519,7 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>kind</key><string>event</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>21</integer> +// CHECK-NEXT: <key>line</key><integer>72</integer> // CHECK-NEXT: <key>col</key><integer>20</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -470,12 +527,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <array> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>21</integer> +// CHECK-NEXT: <key>line</key><integer>72</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>21</integer> +// CHECK-NEXT: <key>line</key><integer>72</integer> // CHECK-NEXT: <key>col</key><integer>22</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -496,7 +553,7 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>issue_hash</key><string>1</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>21</integer> +// CHECK-NEXT: <key>line</key><integer>72</integer> // CHECK-NEXT: <key>col</key><integer>20</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -512,12 +569,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>start</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>30</integer> +// CHECK-NEXT: <key>line</key><integer>81</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>30</integer> +// CHECK-NEXT: <key>line</key><integer>81</integer> // CHECK-NEXT: <key>col</key><integer>8</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -525,12 +582,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>end</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>36</integer> +// CHECK-NEXT: <key>line</key><integer>87</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>36</integer> +// CHECK-NEXT: <key>line</key><integer>87</integer> // CHECK-NEXT: <key>col</key><integer>15</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -542,7 +599,7 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>kind</key><string>event</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>36</integer> +// CHECK-NEXT: <key>line</key><integer>87</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -550,12 +607,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <array> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>36</integer> +// CHECK-NEXT: <key>line</key><integer>87</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>41</integer> +// CHECK-NEXT: <key>line</key><integer>92</integer> // CHECK-NEXT: <key>col</key><integer>4</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -599,7 +656,7 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>kind</key><string>event</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>36</integer> +// CHECK-NEXT: <key>line</key><integer>87</integer> // CHECK-NEXT: <key>col</key><integer>30</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -617,12 +674,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>start</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>36</integer> +// CHECK-NEXT: <key>line</key><integer>87</integer> // CHECK-NEXT: <key>col</key><integer>30</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>36</integer> +// CHECK-NEXT: <key>line</key><integer>87</integer> // CHECK-NEXT: <key>col</key><integer>30</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -630,12 +687,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>end</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>38</integer> +// CHECK-NEXT: <key>line</key><integer>89</integer> // CHECK-NEXT: <key>col</key><integer>5</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>38</integer> +// CHECK-NEXT: <key>line</key><integer>89</integer> // CHECK-NEXT: <key>col</key><integer>5</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -647,7 +704,7 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>kind</key><string>event</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>38</integer> +// CHECK-NEXT: <key>line</key><integer>89</integer> // CHECK-NEXT: <key>col</key><integer>5</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -655,12 +712,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <array> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>38</integer> +// CHECK-NEXT: <key>line</key><integer>89</integer> // CHECK-NEXT: <key>col</key><integer>5</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>38</integer> +// CHECK-NEXT: <key>line</key><integer>89</integer> // CHECK-NEXT: <key>col</key><integer>9</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -690,7 +747,7 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>kind</key><string>event</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>36</integer> +// CHECK-NEXT: <key>line</key><integer>87</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -698,12 +755,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <array> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>36</integer> +// CHECK-NEXT: <key>line</key><integer>87</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>41</integer> +// CHECK-NEXT: <key>line</key><integer>92</integer> // CHECK-NEXT: <key>col</key><integer>4</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -723,12 +780,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>start</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>36</integer> +// CHECK-NEXT: <key>line</key><integer>87</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>36</integer> +// CHECK-NEXT: <key>line</key><integer>87</integer> // CHECK-NEXT: <key>col</key><integer>15</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -736,12 +793,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>end</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>43</integer> +// CHECK-NEXT: <key>line</key><integer>94</integer> // CHECK-NEXT: <key>col</key><integer>12</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>43</integer> +// CHECK-NEXT: <key>line</key><integer>94</integer> // CHECK-NEXT: <key>col</key><integer>12</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -753,7 +810,7 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>kind</key><string>event</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>43</integer> +// CHECK-NEXT: <key>line</key><integer>94</integer> // CHECK-NEXT: <key>col</key><integer>12</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -761,12 +818,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <array> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>43</integer> +// CHECK-NEXT: <key>line</key><integer>94</integer> // CHECK-NEXT: <key>col</key><integer>10</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>43</integer> +// CHECK-NEXT: <key>line</key><integer>94</integer> // CHECK-NEXT: <key>col</key><integer>14</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -787,7 +844,7 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>issue_hash</key><string>14</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>43</integer> +// CHECK-NEXT: <key>line</key><integer>94</integer> // CHECK-NEXT: <key>col</key><integer>12</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -803,12 +860,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>start</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>51</integer> +// CHECK-NEXT: <key>line</key><integer>102</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>51</integer> +// CHECK-NEXT: <key>line</key><integer>102</integer> // CHECK-NEXT: <key>col</key><integer>8</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -816,12 +873,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>end</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>56</integer> +// CHECK-NEXT: <key>line</key><integer>107</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>56</integer> +// CHECK-NEXT: <key>line</key><integer>107</integer> // CHECK-NEXT: <key>col</key><integer>15</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -833,7 +890,7 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>kind</key><string>event</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>56</integer> +// CHECK-NEXT: <key>line</key><integer>107</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -841,12 +898,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <array> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>56</integer> +// CHECK-NEXT: <key>line</key><integer>107</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>62</integer> +// CHECK-NEXT: <key>line</key><integer>113</integer> // CHECK-NEXT: <key>col</key><integer>4</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -890,7 +947,7 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>kind</key><string>event</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>56</integer> +// CHECK-NEXT: <key>line</key><integer>107</integer> // CHECK-NEXT: <key>col</key><integer>30</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -908,12 +965,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>start</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>56</integer> +// CHECK-NEXT: <key>line</key><integer>107</integer> // CHECK-NEXT: <key>col</key><integer>30</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>56</integer> +// CHECK-NEXT: <key>line</key><integer>107</integer> // CHECK-NEXT: <key>col</key><integer>30</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -921,12 +978,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>end</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>58</integer> +// CHECK-NEXT: <key>line</key><integer>109</integer> // CHECK-NEXT: <key>col</key><integer>5</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>58</integer> +// CHECK-NEXT: <key>line</key><integer>109</integer> // CHECK-NEXT: <key>col</key><integer>7</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -938,7 +995,7 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>kind</key><string>event</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>58</integer> +// CHECK-NEXT: <key>line</key><integer>109</integer> // CHECK-NEXT: <key>col</key><integer>5</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -946,12 +1003,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <array> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>58</integer> +// CHECK-NEXT: <key>line</key><integer>109</integer> // CHECK-NEXT: <key>col</key><integer>5</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>58</integer> +// CHECK-NEXT: <key>line</key><integer>109</integer> // CHECK-NEXT: <key>col</key><integer>9</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -971,12 +1028,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>start</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>58</integer> +// CHECK-NEXT: <key>line</key><integer>109</integer> // CHECK-NEXT: <key>col</key><integer>5</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>58</integer> +// CHECK-NEXT: <key>line</key><integer>109</integer> // CHECK-NEXT: <key>col</key><integer>7</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -984,12 +1041,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>end</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>60</integer> +// CHECK-NEXT: <key>line</key><integer>111</integer> // CHECK-NEXT: <key>col</key><integer>5</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>60</integer> +// CHECK-NEXT: <key>line</key><integer>111</integer> // CHECK-NEXT: <key>col</key><integer>5</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -1001,7 +1058,7 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>kind</key><string>event</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>60</integer> +// CHECK-NEXT: <key>line</key><integer>111</integer> // CHECK-NEXT: <key>col</key><integer>5</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -1009,12 +1066,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <array> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>60</integer> +// CHECK-NEXT: <key>line</key><integer>111</integer> // CHECK-NEXT: <key>col</key><integer>12</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>60</integer> +// CHECK-NEXT: <key>line</key><integer>111</integer> // CHECK-NEXT: <key>col</key><integer>12</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -1032,7 +1089,7 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>type</key><string>uninitialized variable captured by block</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>60</integer> +// CHECK-NEXT: <key>line</key><integer>111</integer> // CHECK-NEXT: <key>col</key><integer>5</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -1048,12 +1105,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>start</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>82</integer> +// CHECK-NEXT: <key>line</key><integer>133</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>82</integer> +// CHECK-NEXT: <key>line</key><integer>133</integer> // CHECK-NEXT: <key>col</key><integer>4</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -1061,12 +1118,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>end</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>86</integer> +// CHECK-NEXT: <key>line</key><integer>137</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>86</integer> +// CHECK-NEXT: <key>line</key><integer>137</integer> // CHECK-NEXT: <key>col</key><integer>23</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -1082,12 +1139,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>start</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>86</integer> +// CHECK-NEXT: <key>line</key><integer>137</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>86</integer> +// CHECK-NEXT: <key>line</key><integer>137</integer> // CHECK-NEXT: <key>col</key><integer>23</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -1095,12 +1152,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>end</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>86</integer> +// CHECK-NEXT: <key>line</key><integer>137</integer> // CHECK-NEXT: <key>col</key><integer>26</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>86</integer> +// CHECK-NEXT: <key>line</key><integer>137</integer> // CHECK-NEXT: <key>col</key><integer>26</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -1112,7 +1169,7 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>kind</key><string>event</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>86</integer> +// CHECK-NEXT: <key>line</key><integer>137</integer> // CHECK-NEXT: <key>col</key><integer>26</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -1120,12 +1177,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <array> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>86</integer> +// CHECK-NEXT: <key>line</key><integer>137</integer> // CHECK-NEXT: <key>col</key><integer>26</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>86</integer> +// CHECK-NEXT: <key>line</key><integer>137</integer> // CHECK-NEXT: <key>col</key><integer>27</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -1145,12 +1202,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>start</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>86</integer> +// CHECK-NEXT: <key>line</key><integer>137</integer> // CHECK-NEXT: <key>col</key><integer>26</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>86</integer> +// CHECK-NEXT: <key>line</key><integer>137</integer> // CHECK-NEXT: <key>col</key><integer>26</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -1158,12 +1215,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>end</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>86</integer> +// CHECK-NEXT: <key>line</key><integer>137</integer> // CHECK-NEXT: <key>col</key><integer>25</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>86</integer> +// CHECK-NEXT: <key>line</key><integer>137</integer> // CHECK-NEXT: <key>col</key><integer>25</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -1175,7 +1232,7 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>kind</key><string>event</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>86</integer> +// CHECK-NEXT: <key>line</key><integer>137</integer> // CHECK-NEXT: <key>col</key><integer>25</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -1183,12 +1240,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <array> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>86</integer> +// CHECK-NEXT: <key>line</key><integer>137</integer> // CHECK-NEXT: <key>col</key><integer>25</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>86</integer> +// CHECK-NEXT: <key>line</key><integer>137</integer> // CHECK-NEXT: <key>col</key><integer>35</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -1204,7 +1261,7 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>kind</key><string>event</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>86</integer> +// CHECK-NEXT: <key>line</key><integer>137</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -1212,12 +1269,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <array> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>86</integer> +// CHECK-NEXT: <key>line</key><integer>137</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>86</integer> +// CHECK-NEXT: <key>line</key><integer>137</integer> // CHECK-NEXT: <key>col</key><integer>36</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -1233,7 +1290,7 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>kind</key><string>event</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>76</integer> +// CHECK-NEXT: <key>line</key><integer>127</integer> // CHECK-NEXT: <key>col</key><integer>1</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -1251,12 +1308,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>start</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>76</integer> +// CHECK-NEXT: <key>line</key><integer>127</integer> // CHECK-NEXT: <key>col</key><integer>1</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>76</integer> +// CHECK-NEXT: <key>line</key><integer>127</integer> // CHECK-NEXT: <key>col</key><integer>4</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -1264,12 +1321,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>end</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>77</integer> +// CHECK-NEXT: <key>line</key><integer>128</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>77</integer> +// CHECK-NEXT: <key>line</key><integer>128</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -1285,12 +1342,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>start</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>77</integer> +// CHECK-NEXT: <key>line</key><integer>128</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>77</integer> +// CHECK-NEXT: <key>line</key><integer>128</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -1298,12 +1355,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>end</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>77</integer> +// CHECK-NEXT: <key>line</key><integer>128</integer> // CHECK-NEXT: <key>col</key><integer>6</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>77</integer> +// CHECK-NEXT: <key>line</key><integer>128</integer> // CHECK-NEXT: <key>col</key><integer>6</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -1315,7 +1372,7 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>kind</key><string>event</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>77</integer> +// CHECK-NEXT: <key>line</key><integer>128</integer> // CHECK-NEXT: <key>col</key><integer>6</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -1323,12 +1380,12 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <array> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>77</integer> +// CHECK-NEXT: <key>line</key><integer>128</integer> // CHECK-NEXT: <key>col</key><integer>4</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>77</integer> +// CHECK-NEXT: <key>line</key><integer>128</integer> // CHECK-NEXT: <key>col</key><integer>4</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -1349,9 +1406,186 @@ void testNilReceiver(id *x) { // CHECK-NEXT: <key>issue_hash</key><string>1</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>77</integer> +// CHECK-NEXT: <key>line</key><integer>128</integer> // CHECK-NEXT: <key>col</key><integer>6</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>path</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>kind</key><string>control</string> +// CHECK-NEXT: <key>edges</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>start</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>144</integer> +// CHECK-NEXT: <key>col</key><integer>3</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>144</integer> +// CHECK-NEXT: <key>col</key><integer>4</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: <key>end</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>144</integer> +// CHECK-NEXT: <key>col</key><integer>7</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>144</integer> +// CHECK-NEXT: <key>col</key><integer>11</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>kind</key><string>event</string> +// CHECK-NEXT: <key>location</key> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>144</integer> +// CHECK-NEXT: <key>col</key><integer>7</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <key>ranges</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>144</integer> +// CHECK-NEXT: <key>col</key><integer>7</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>144</integer> +// CHECK-NEXT: <key>col</key><integer>11</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: </array> +// CHECK-NEXT: <key>depth</key><integer>0</integer> +// CHECK-NEXT: <key>extended_message</key> +// CHECK-NEXT: <string>Assuming 'myNil' is nil</string> +// CHECK-NEXT: <key>message</key> +// CHECK-NEXT: <string>Assuming 'myNil' is nil</string> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>kind</key><string>control</string> +// CHECK-NEXT: <key>edges</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>start</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>144</integer> +// CHECK-NEXT: <key>col</key><integer>7</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>144</integer> +// CHECK-NEXT: <key>col</key><integer>11</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: <key>end</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>146</integer> +// CHECK-NEXT: <key>col</key><integer>3</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>146</integer> +// CHECK-NEXT: <key>col</key><integer>8</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>kind</key><string>control</string> +// CHECK-NEXT: <key>edges</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>start</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>146</integer> +// CHECK-NEXT: <key>col</key><integer>3</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>146</integer> +// CHECK-NEXT: <key>col</key><integer>8</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: <key>end</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>146</integer> +// CHECK-NEXT: <key>col</key><integer>10</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>146</integer> +// CHECK-NEXT: <key>col</key><integer>10</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>kind</key><string>event</string> +// CHECK-NEXT: <key>location</key> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>146</integer> +// CHECK-NEXT: <key>col</key><integer>10</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <key>ranges</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>146</integer> +// CHECK-NEXT: <key>col</key><integer>19</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>146</integer> +// CHECK-NEXT: <key>col</key><integer>23</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: </array> +// CHECK-NEXT: <key>depth</key><integer>0</integer> +// CHECK-NEXT: <key>extended_message</key> +// CHECK-NEXT: <string>Array element cannot be nil</string> +// CHECK-NEXT: <key>message</key> +// CHECK-NEXT: <string>Array element cannot be nil</string> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: <key>description</key><string>Array element cannot be nil</string> +// CHECK-NEXT: <key>category</key><string>API Misuse (Apple)</string> +// CHECK-NEXT: <key>type</key><string>nil argument</string> +// CHECK-NEXT: <key>issue_context_kind</key><string>function</string> +// CHECK-NEXT: <key>issue_context</key><string>testCreateArrayLiteral</string> +// CHECK-NEXT: <key>issue_hash</key><string>3</string> +// CHECK-NEXT: <key>location</key> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>146</integer> +// CHECK-NEXT: <key>col</key><integer>10</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </dict> // CHECK-NEXT: </array> diff --git a/test/Analysis/rdar-6540084.m b/test/Analysis/rdar-6540084.m index 7070709e57..e928710b38 100644 --- a/test/Analysis/rdar-6540084.m +++ b/test/Analysis/rdar-6540084.m @@ -9,13 +9,13 @@ typedef struct _NSZone NSZone; @protocol NSObject - (BOOL)isEqual:(id)object; @end @interface NSObject <NSObject> {} @end extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone); -@class NSArray; +@class NSArray; // expected-note {{receiver is instance of class declared here}} @class NSMutableArray, NSIndexSet, NSView, NSPredicate, NSString, NSViewAnimation, NSTimer; // expected-note{{forward declaration of class here}} @interface FooBazController : NSObject {} @end typedef struct {} TazVersion; @class TazNode; -@interface TazGuttenberg : NSObject {} typedef NSUInteger BugsBunnyType; @end +@interface TazGuttenberg : NSObject {} typedef NSUInteger BugsBunnyType; @end // expected-note {{receiver is instance of class declared here}} @interface FooBaz : NSObject {} @property (nonatomic) BugsBunnyType matchType; @property (nonatomic, retain) NSArray *papyrus; @end diff --git a/test/CodeGen/arm-clear.c b/test/CodeGen/arm-clear.c index 51506dfed1..8ef3675641 100644 --- a/test/CodeGen/arm-clear.c +++ b/test/CodeGen/arm-clear.c @@ -1,21 +1,8 @@ // REQUIRES: arm-registered-target // RUN: %clang_cc1 -triple armv7-apple-darwin9 -emit-llvm -w -o - %s | FileCheck %s -void clear0(void *ptr) { - // CHECK: clear0 - // CHECK-NOT: load i8** - __clear_cache(); -} - -void clear1(void *ptr) { - // CHECK: clear1 - // CHECK: load i8** - // CHECK-NOT: load i8** - __clear_cache(ptr); -} - -void clear2(void *ptr, void *ptr2) { - // CHECK: clear2 +void clear(void *ptr, void *ptr2) { + // CHECK: clear // CHECK: load i8** // CHECK: load i8** __clear_cache(ptr, ptr2); diff --git a/test/CodeGen/arm-neon-vget.c b/test/CodeGen/arm-neon-vget.c new file mode 100644 index 0000000000..4a710a2ad8 --- /dev/null +++ b/test/CodeGen/arm-neon-vget.c @@ -0,0 +1,124 @@ +// REQUIRES: arm-registered-target +// RUN: %clang_cc1 -triple thumbv7-apple-darwin \ +// RUN: -target-abi apcs-gnu \ +// RUN: -target-cpu cortex-a8 \ +// RUN: -mfloat-abi soft \ +// RUN: -target-feature +soft-float-abi \ +// RUN: -ffreestanding \ +// RUN: -emit-llvm -w -O1 -o - %s | FileCheck %s + +#include <arm_neon.h> + +// Check that the vget_low/vget_high intrinsics generate a single shuffle +// without any bitcasting. +int8x8_t low_s8(int8x16_t a) { +// CHECK: shufflevector <16 x i8> %a, <16 x i8> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7> + return vget_low_s8(a); +} + +uint8x8_t low_u8 (uint8x16_t a) { +// CHECK: shufflevector <16 x i8> %a, <16 x i8> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7> + return vget_low_u8(a); +} + +int16x4_t low_s16( int16x8_t a) { +// CHECK: shufflevector <8 x i16> %a, <8 x i16> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3> + return vget_low_s16(a); +} + +uint16x4_t low_u16(uint16x8_t a) { +// CHECK: shufflevector <8 x i16> %a, <8 x i16> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3> + return vget_low_u16(a); +} + +int32x2_t low_s32( int32x4_t a) { +// CHECK: shufflevector <4 x i32> %a, <4 x i32> undef, <2 x i32> <i32 0, i32 1> + return vget_low_s32(a); +} + +uint32x2_t low_u32(uint32x4_t a) { +// CHECK: shufflevector <4 x i32> %a, <4 x i32> undef, <2 x i32> <i32 0, i32 1> + return vget_low_u32(a); +} + +int64x1_t low_s64( int64x2_t a) { +// CHECK: shufflevector <2 x i64> %a, <2 x i64> undef, <1 x i32> zeroinitializer + return vget_low_s64(a); +} + +uint64x1_t low_u64(uint64x2_t a) { +// CHECK: shufflevector <2 x i64> %a, <2 x i64> undef, <1 x i32> zeroinitializer + return vget_low_u64(a); +} + +poly8x8_t low_p8 (poly8x16_t a) { +// CHECK: shufflevector <16 x i8> %a, <16 x i8> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7> + return vget_low_p8(a); +} + +poly16x4_t low_p16(poly16x8_t a) { +// CHECK: shufflevector <8 x i16> %a, <8 x i16> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3> + return vget_low_p16(a); +} + +float32x2_t low_f32(float32x4_t a) { +// CHECK: shufflevector <4 x float> %a, <4 x float> undef, <2 x i32> <i32 0, i32 1> + return vget_low_f32(a); +} + + +int8x8_t high_s8(int8x16_t a) { +// CHECK: shufflevector <16 x i8> %a, <16 x i8> undef, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15> + return vget_high_s8(a); +} + +uint8x8_t high_u8 (uint8x16_t a) { +// CHECK: shufflevector <16 x i8> %a, <16 x i8> undef, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15> + return vget_high_u8(a); +} + +int16x4_t high_s16( int16x8_t a) { +// CHECK: shufflevector <8 x i16> %a, <8 x i16> undef, <4 x i32> <i32 4, i32 5, i32 6, i32 7> + return vget_high_s16(a); +} + +uint16x4_t high_u16(uint16x8_t a) { +// CHECK: shufflevector <8 x i16> %a, <8 x i16> undef, <4 x i32> <i32 4, i32 5, i32 6, i32 7> + return vget_high_u16(a); +} + +int32x2_t high_s32( int32x4_t a) { +// CHECK: shufflevector <4 x i32> %a, <4 x i32> undef, <2 x i32> <i32 2, i32 3> + return vget_high_s32(a); +} + +uint32x2_t high_u32(uint32x4_t a) { +// CHECK: shufflevector <4 x i32> %a, <4 x i32> undef, <2 x i32> <i32 2, i32 3> + return vget_high_u32(a); +} + +int64x1_t high_s64( int64x2_t a) { +// CHECK: shufflevector <2 x i64> %a, <2 x i64> undef, <1 x i32> <i32 1> + return vget_high_s64(a); +} + +uint64x1_t high_u64(uint64x2_t a) { +// CHECK: shufflevector <2 x i64> %a, <2 x i64> undef, <1 x i32> <i32 1> + return vget_high_u64(a); +} + +poly8x8_t high_p8 (poly8x16_t a) { +// CHECK: shufflevector <16 x i8> %a, <16 x i8> undef, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15> + return vget_high_p8(a); +} + +poly16x4_t high_p16(poly16x8_t a) { +// CHECK: shufflevector <8 x i16> %a, <8 x i16> undef, <4 x i32> <i32 4, i32 5, i32 6, i32 7> + return vget_high_p16(a); +} + +float32x2_t high_f32(float32x4_t a) { +// CHECK: shufflevector <4 x float> %a, <4 x float> undef, <2 x i32> <i32 2, i32 3> + return vget_high_f32(a); +} + diff --git a/test/CodeGen/linux-arm-atomic.c b/test/CodeGen/linux-arm-atomic.c new file mode 100644 index 0000000000..c7ce1d228b --- /dev/null +++ b/test/CodeGen/linux-arm-atomic.c @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - -triple=armv7-unknown-linux | FileCheck %s +// RUN: %clang_cc1 %s -emit-llvm -o - -triple=armv6-unknown-linux | FileCheck %s +// RUN: %clang_cc1 %s -emit-llvm -o - -triple=thumbv7-unknown-linux | FileCheck %s + +typedef int _Atomic_word; +_Atomic_word exchange_and_add(volatile _Atomic_word *__mem, int __val) { + return __atomic_fetch_add(__mem, __val, __ATOMIC_ACQ_REL); +} + +// CHECK: define {{.*}} @exchange_and_add +// CHECK: atomicrmw {{.*}} add diff --git a/test/CodeGenCXX/captured-statements.cpp b/test/CodeGenCXX/captured-statements.cpp index 91c7ff28f0..cfa6936111 100644 --- a/test/CodeGenCXX/captured-statements.cpp +++ b/test/CodeGenCXX/captured-statements.cpp @@ -55,9 +55,9 @@ void test2(int x) { }(); // CHECK-2: define void @_Z5test2i - // CHECK-2: call i32 @[[Lambda:["$\w]+]] + // CHECK-2: call {{.*}} @[[Lambda:["$\w]+]] // - // CHECK-2: define internal i32 @[[Lambda]] + // CHECK-2: define internal {{.*}} @[[Lambda]] // CHECK-2: call void @[[HelperName:["$_A-Za-z0-9]+]](%[[Capture:.*]]* // // CHECK-2: define internal void @[[HelperName]] @@ -74,7 +74,7 @@ void test3(int x) { // CHECK-3: %[[Capture:struct\.anon[\.0-9]*]] = type { i32* } - // CHECK-3: define void @_Z5test3i(i32 %x) + // CHECK-3: define void @_Z5test3i // CHECK-3: store i32* // CHECK-3: call void @{{.*}}__captured_stmt // CHECK-3: ret void @@ -86,10 +86,7 @@ void test4() { Foo f; f.x = 5; } - // CHECK-4: %[[Capture:struct\.anon[\.0-9]*]] = type { i32* } - - // CHECK-4: define void @_Z5test3i(i32 %x) - // CHECK-4: store i32* + // CHECK-4: define void @_Z5test4v // CHECK-4: call void @[[HelperName:["$_A-Za-z0-9]+]](%[[Capture:.*]]* // CHECK-4: ret void // diff --git a/test/CodeGenCXX/cxx1y-deduced-return-type.cpp b/test/CodeGenCXX/cxx1y-deduced-return-type.cpp new file mode 100644 index 0000000000..6d15a2246d --- /dev/null +++ b/test/CodeGenCXX/cxx1y-deduced-return-type.cpp @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -std=c++1y -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s + +// CHECK: @x = global {{.*}} zeroinitializer + +// CHECK: define {{.*}} @_Z1fv +inline auto f() { + int n = 0; + // CHECK: load i32 + // CHECK: store i32 + // CHECK: ret + return [=] () mutable { return ++n; }; +} + +auto x = f(); + +template<typename T> auto *g(T t) { return t; } +template<typename T> decltype(auto) h(T t) { return t; } + +// CHECK: define {{.*}} @_Z1zv +void z() { + // CHECK: call {{.*}} @_Z1gIPZ1fvEUlvE_EPDaT_( + // CHECK: call {{.*}} @_Z1hIPZ1fvEUlvE_EDcT_( + g(&x); + h(&x); +} + +auto i() { return [] {}; } +// CHECK: define {{.*}} @_Z1jv +auto j() { + // CHECK: call {{.*}} @"_Z1hIZ1ivE3$_0EDcT_"() + h(i()); +} diff --git a/test/CodeGenCXX/debug-info-namespace.cpp b/test/CodeGenCXX/debug-info-namespace.cpp index 4b44661eb1..9eff818f87 100644 --- a/test/CodeGenCXX/debug-info-namespace.cpp +++ b/test/CodeGenCXX/debug-info-namespace.cpp @@ -8,6 +8,7 @@ void f1() { } void f1(int) { } struct foo; struct bar { }; +typedef bar baz; } using namespace B; } @@ -24,6 +25,7 @@ int func(bool b) { using B::bar; using B::f1; using B::i; + using B::baz; bar x; return i; } @@ -33,24 +35,27 @@ int func(bool b) { // CHECK: [[CU:![0-9]*]] = {{.*}}[[MODULES:![0-9]*]], metadata !""} ; [ DW_TAG_compile_unit ] // CHECK: [[FILE:![0-9]*]] {{.*}}debug-info-namespace.cpp" +// CHECK: [[FOOCPP:![0-9]*]] = metadata !{metadata !"foo.cpp", {{.*}} // CHECK: [[NS:![0-9]*]] = {{.*}}, metadata [[FILE2:![0-9]*]], metadata [[CTXT:![0-9]*]], {{.*}} ; [ DW_TAG_namespace ] [B] [line 1] // CHECK: [[CTXT]] = {{.*}}, metadata [[FILE]], null, {{.*}} ; [ DW_TAG_namespace ] [A] [line 3] // CHECK: [[F1:![0-9]*]] {{.*}} ; [ DW_TAG_subprogram ] [line 4] [def] [f1] -// CHECK: [[FUNC:![0-9]*]] {{.*}} ; [ DW_TAG_subprogram ] [line 13] [def] [func] +// CHECK: [[FUNC:![0-9]*]] {{.*}} ; [ DW_TAG_subprogram ] [line 14] [def] [func] // CHECK: [[FILE2]]} ; [ DW_TAG_file_type ] [{{.*}}foo.cpp] // CHECK: [[I:![0-9]*]] = {{.*}}, metadata [[NS]], metadata !"i", {{.*}} ; [ DW_TAG_variable ] [i] -// CHECK: [[MODULES]] = metadata !{metadata [[M1:![0-9]*]], metadata [[M2:![0-9]*]], metadata [[M3:![0-9]*]], metadata [[M4:![0-9]*]], metadata [[M5:![0-9]*]], metadata [[M6:![0-9]*]], metadata [[M7:![0-9]*]], metadata [[M8:![0-9]*]]} -// CHECK: [[M1]] = metadata !{i32 {{[0-9]*}}, metadata [[CTXT]], metadata [[NS]], i32 8} ; [ DW_TAG_imported_module ] -// CHECK: [[M2]] = metadata !{i32 {{[0-9]*}}, metadata [[CU]], metadata [[CTXT]], i32 11} ; [ DW_TAG_imported_module ] -// CHECK: [[M3]] = metadata !{i32 {{[0-9]*}}, metadata [[LEX:![0-9]*]], metadata [[NS]], i32 15} ; [ DW_TAG_imported_module ] -// CHECK: [[LEX]] = metadata !{i32 {{[0-9]*}}, metadata [[FILE2]], metadata [[FUNC]], i32 14, i32 0, i32 0} ; [ DW_TAG_lexical_block ] -// CHECK: [[M4]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[CTXT]], i32 18} ; [ DW_TAG_imported_module ] -// CHECK: [[M5]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[FOO:![0-9]*]], i32 19} ; [ DW_TAG_imported_declaration ] +// CHECK: [[MODULES]] = metadata !{metadata [[M1:![0-9]*]], metadata [[M2:![0-9]*]], metadata [[M3:![0-9]*]], metadata [[M4:![0-9]*]], metadata [[M5:![0-9]*]], metadata [[M6:![0-9]*]], metadata [[M7:![0-9]*]], metadata [[M8:![0-9]*]], metadata [[M9:![0-9]*]]} +// CHECK: [[M1]] = metadata !{i32 {{[0-9]*}}, metadata [[CTXT]], metadata [[NS]], i32 9} ; [ DW_TAG_imported_module ] +// CHECK: [[M2]] = metadata !{i32 {{[0-9]*}}, metadata [[CU]], metadata [[CTXT]], i32 12} ; [ DW_TAG_imported_module ] +// CHECK: [[M3]] = metadata !{i32 {{[0-9]*}}, metadata [[LEX:![0-9]*]], metadata [[NS]], i32 16} ; [ DW_TAG_imported_module ] +// CHECK: [[LEX]] = metadata !{i32 {{[0-9]*}}, metadata [[FILE2]], metadata [[FUNC]], i32 15, i32 0, i32 0} ; [ DW_TAG_lexical_block ] +// CHECK: [[M4]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[CTXT]], i32 19} ; [ DW_TAG_imported_module ] +// CHECK: [[M5]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[FOO:![0-9]*]], i32 20} ; [ DW_TAG_imported_declaration ] // CHECK: [[FOO]] {{.*}} ; [ DW_TAG_structure_type ] [foo] [line 5, size 0, align 0, offset 0] [fwd] [from ] -// CHECK: [[M6]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[BAR:![0-9]*]], i32 20} ; [ DW_TAG_imported_declaration ] +// CHECK: [[M6]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[BAR:![0-9]*]], i32 21} ; [ DW_TAG_imported_declaration ] // CHECK: [[BAR]] {{.*}} ; [ DW_TAG_structure_type ] [bar] [line 6, {{.*}}] [from ] -// CHECK: [[M7]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[F1]], i32 21} ; [ DW_TAG_imported_declaration ] -// CHECK: [[M8]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[I]], i32 22} ; [ DW_TAG_imported_declaration ] +// CHECK: [[M7]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[F1]], i32 22} ; [ DW_TAG_imported_declaration ] +// CHECK: [[M8]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[I]], i32 23} ; [ DW_TAG_imported_declaration ] +// CHECK: [[M9]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[BAZ:![0-9]*]], i32 24} ; [ DW_TAG_imported_declaration ] +// CHECK: [[BAZ]] = metadata !{i32 {{[0-9]*}}, metadata [[FOOCPP]], metadata [[NS]], {{.*}} ; [ DW_TAG_typedef ] [baz] {{.*}} [from bar] // FIXME: It is confused on win32 to generate file entry when dosish filename is given. // REQUIRES: shell diff --git a/test/CodeGenCXX/debug-info-template.cpp b/test/CodeGenCXX/debug-info-template.cpp index 1d2dc10cf2..a97c991f38 100644 --- a/test/CodeGenCXX/debug-info-template.cpp +++ b/test/CodeGenCXX/debug-info-template.cpp @@ -2,6 +2,9 @@ // CHECK: [[EMPTY:![0-9]*]] = metadata !{i32 0} +// CHECK: [[FUNTYPE:![0-9]*]] = {{.*}}, metadata [[FUNARGS:![0-9]*]], i32 0, i32 0} ; [ DW_TAG_subroutine_type ] +// CHECK: [[FUNARGS]] = metadata !{null} + // func<...> doesn't have any template arguments listed since we don't support // packs yet. This could be encoded with GNU's // DW_TAG_GNU_template_parameter_pack extension. @@ -9,8 +12,8 @@ // CHECK: [[INT:![0-9]*]] = {{.*}} ; [ DW_TAG_base_type ] [int] // CHECK: metadata [[TCI:![0-9]*]], i32 0, i32 1, %class.TC* @tci, null} ; [ DW_TAG_variable ] [tci] -// CHECK: [[TC:![0-9]*]] = {{.*}}, metadata [[TCARGS:![0-9]*]]} ; [ DW_TAG_class_type ] [TC<unsigned int, 2, &glb, &foo::e, &foo::f>] -// CHECK: [[TCARGS]] = metadata !{metadata [[TCARG1:![0-9]*]], metadata [[TCARG2:![0-9]*]], metadata [[TCARG3:![0-9]*]], metadata [[TCARG4:![0-9]*]], metadata [[TCARG5:![0-9]*]]} +// CHECK: [[TC:![0-9]*]] = {{.*}}, metadata [[TCARGS:![0-9]*]]} ; [ DW_TAG_class_type ] [TC<unsigned int, 2, &glb, &foo::e, &foo::f, &func>] +// CHECK: [[TCARGS]] = metadata !{metadata [[TCARG1:![0-9]*]], metadata [[TCARG2:![0-9]*]], metadata [[TCARG3:![0-9]*]], metadata [[TCARG4:![0-9]*]], metadata [[TCARG5:![0-9]*]], metadata [[TCARG6:![0-9]*]]} // // We seem to be missing file/line/col info on template value parameters - // metadata supports it but it's not populated. GCC doesn't emit it either, @@ -39,11 +42,13 @@ // // CHECK: [[TCARG5]] = {{.*}}metadata !"b", metadata [[MEMFUNPTR:![0-9]*]], { i64, i64 } { i64 ptrtoint (void (%struct.foo*)* @_ZN3foo1fEv to i64), i64 0 }, {{.*}} ; [ DW_TAG_template_value_parameter ] // CHECK: [[MEMFUNPTR]] = {{.*}}, metadata [[FTYPE]], metadata [[FOO]]} ; [ DW_TAG_ptr_to_member_type ] +// CHECK: [[TCARG6]] = {{.*}}metadata !"f", metadata [[FUNPTR:![0-9]*]], void ()* @_Z4funcv, {{.*}} ; [ DW_TAG_template_value_parameter ] +// CHECK: [[FUNPTR]] = {{.*}}, metadata [[FUNTYPE]]} ; [ DW_TAG_pointer_type ] // CHECK: metadata [[TCNT:![0-9]*]], i32 0, i32 1, %class.TC.0* @tcn, null} ; [ DW_TAG_variable ] [tcn] -// CHECK: [[TCNT:![0-9]*]] = {{.*}}, metadata [[TCNARGS:![0-9]*]]} ; [ DW_TAG_class_type ] [TC<int, -3, nullptr, nullptr, nullptr>] -// CHECK: [[TCNARGS]] = metadata !{metadata [[TCNARG1:![0-9]*]], metadata [[TCNARG2:![0-9]*]], metadata [[TCNARG3:![0-9]*]], metadata [[TCNARG4:![0-9]*]], metadata [[TCNARG5:![0-9]*]]} +// CHECK: [[TCNT:![0-9]*]] = {{.*}}, metadata [[TCNARGS:![0-9]*]]} ; [ DW_TAG_class_type ] [TC<int, -3, nullptr, nullptr, nullptr, nullptr>] +// CHECK: [[TCNARGS]] = metadata !{metadata [[TCNARG1:![0-9]*]], metadata [[TCNARG2:![0-9]*]], metadata [[TCNARG3:![0-9]*]], metadata [[TCNARG4:![0-9]*]], metadata [[TCNARG5:![0-9]*]], metadata [[TCNARG6:![0-9]*]]} // CHECK: [[TCNARG1]] = {{.*}}metadata !"T", metadata [[INT]], {{.*}} ; [ DW_TAG_template_type_parameter ] // CHECK: [[TCNARG2]] = {{.*}}metadata !"", metadata [[INT]], i32 -3, {{.*}} ; [ DW_TAG_template_value_parameter ] // CHECK: [[TCNARG3]] = {{.*}}metadata !"x", metadata [[INTPTR]], i8 0, {{.*}} ; [ DW_TAG_template_value_parameter ] @@ -59,21 +64,23 @@ // naturally from the LLVM CodeGen side once we decide how to handle non-null // member function pointers. For now, it's simpler just to emit the 'i8 0'. // -// CHECK: [[TCNARG5]] = {{.*}}metadata !"b", metadata [[MEMFUNPTR:![0-9]*]], i8 0, {{.*}} ; [ DW_TAG_template_value_parameter ] +// CHECK: [[TCNARG5]] = {{.*}}metadata !"b", metadata [[MEMFUNPTR]], i8 0, {{.*}} ; [ DW_TAG_template_value_parameter ] +// CHECK: [[TCNARG6]] = {{.*}}metadata !"f", metadata [[FUNPTR]], i8 0, {{.*}} ; [ DW_TAG_template_value_parameter ] struct foo { char pad[8]; // make the member pointer to 'e' a bit more interesting (nonzero) int e; void f(); }; -template<typename T, T, int *x, int foo::*a, void (foo::*b)()> +template<typename T, T, int *x, int foo::*a, void (foo::*b)(), void (*f)()> class TC { }; int glb; +void func(); -TC<unsigned, 2, &glb, &foo::e, &foo::f> tci; -TC<int, -3, nullptr, nullptr, nullptr> tcn; +TC<unsigned, 2, &glb, &foo::e, &foo::f, &func> tci; +TC<int, -3, nullptr, nullptr, nullptr, nullptr> tcn; template<typename ...Ts> int func() { return 0; } int anchor = func<int>(); diff --git a/test/CodeGenCXX/mangle-ms-arg-qualifiers.cpp b/test/CodeGenCXX/mangle-ms-arg-qualifiers.cpp index d03ba52649..ed7027d975 100644 --- a/test/CodeGenCXX/mangle-ms-arg-qualifiers.cpp +++ b/test/CodeGenCXX/mangle-ms-arg-qualifiers.cpp @@ -1,123 +1,164 @@ // RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s +// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=x86_64-pc-win32 | FileCheck -check-prefix=X64 %s void foo(const unsigned int) {} // CHECK: "\01?foo@@YAXI@Z" +// X64: "\01?foo@@YAXI@Z" void foo(const double) {} // CHECK: "\01?foo@@YAXN@Z" +// X64: "\01?foo@@YAXN@Z" void bar(const volatile double) {} // CHECK: "\01?bar@@YAXN@Z" +// X64: "\01?bar@@YAXN@Z" void foo_pad(char * x) {} // CHECK: "\01?foo_pad@@YAXPAD@Z" +// X64: "\01?foo_pad@@YAXPEAD@Z" void foo_pbd(const char * x) {} // CHECK: "\01?foo_pbd@@YAXPBD@Z" +// X64: "\01?foo_pbd@@YAXPEBD@Z" void foo_pcd(volatile char * x) {} // CHECK: "\01?foo_pcd@@YAXPCD@Z" +// X64: "\01?foo_pcd@@YAXPECD@Z" void foo_qad(char * const x) {} // CHECK: "\01?foo_qad@@YAXQAD@Z" +// X64: "\01?foo_qad@@YAXQEAD@Z" void foo_rad(char * volatile x) {} // CHECK: "\01?foo_rad@@YAXRAD@Z" +// X64: "\01?foo_rad@@YAXREAD@Z" void foo_sad(char * const volatile x) {} // CHECK: "\01?foo_sad@@YAXSAD@Z" +// X64: "\01?foo_sad@@YAXSEAD@Z" void foo_papad(char ** x) {} // CHECK: "\01?foo_papad@@YAXPAPAD@Z" +// X64: "\01?foo_papad@@YAXPEAPEAD@Z" void foo_papbd(char const ** x) {} // CHECK: "\01?foo_papbd@@YAXPAPBD@Z" +// X64: "\01?foo_papbd@@YAXPEAPEBD@Z" void foo_papcd(char volatile ** x) {} // CHECK: "\01?foo_papcd@@YAXPAPCD@Z" +// X64: "\01?foo_papcd@@YAXPEAPECD@Z" void foo_pbqad(char * const* x) {} // CHECK: "\01?foo_pbqad@@YAXPBQAD@Z" +// X64: "\01?foo_pbqad@@YAXPEBQEAD@Z" void foo_pcrad(char * volatile* x) {} // CHECK: "\01?foo_pcrad@@YAXPCRAD@Z" +// X64: "\01?foo_pcrad@@YAXPECREAD@Z" void foo_qapad(char ** const x) {} // CHECK: "\01?foo_qapad@@YAXQAPAD@Z" +// X64: "\01?foo_qapad@@YAXQEAPEAD@Z" void foo_rapad(char ** volatile x) {} // CHECK: "\01?foo_rapad@@YAXRAPAD@Z" +// X64: "\01?foo_rapad@@YAXREAPEAD@Z" void foo_pbqbd(const char * const* x) {} // CHECK: "\01?foo_pbqbd@@YAXPBQBD@Z" +// X64: "\01?foo_pbqbd@@YAXPEBQEBD@Z" void foo_pbqcd(volatile char * const* x) {} // CHECK: "\01?foo_pbqcd@@YAXPBQCD@Z" +// X64: "\01?foo_pbqcd@@YAXPEBQECD@Z" void foo_pcrbd(const char * volatile* x) {} // CHECK: "\01?foo_pcrbd@@YAXPCRBD@Z" +// X64: "\01?foo_pcrbd@@YAXPECREBD@Z" void foo_pcrcd(volatile char * volatile* x) {} // CHECK: "\01?foo_pcrcd@@YAXPCRCD@Z" +// X64: "\01?foo_pcrcd@@YAXPECRECD@Z" void foo_aad(char &x) {} // CHECK: "\01?foo_aad@@YAXAAD@Z" +// X64: "\01?foo_aad@@YAXAEAD@Z" void foo_abd(const char &x) {} // CHECK: "\01?foo_abd@@YAXABD@Z" +// X64: "\01?foo_abd@@YAXAEBD@Z" void foo_aapad(char *&x) {} // CHECK: "\01?foo_aapad@@YAXAAPAD@Z" +// X64: "\01?foo_aapad@@YAXAEAPEAD@Z" void foo_aapbd(const char *&x) {} // CHECK: "\01?foo_aapbd@@YAXAAPBD@Z" +// X64: "\01?foo_aapbd@@YAXAEAPEBD@Z" void foo_abqad(char * const &x) {} // CHECK: "\01?foo_abqad@@YAXABQAD@Z" +// X64: "\01?foo_abqad@@YAXAEBQEAD@Z" void foo_abqbd(const char * const &x) {} // CHECK: "\01?foo_abqbd@@YAXABQBD@Z" +// X64: "\01?foo_abqbd@@YAXAEBQEBD@Z" void foo_aay144h(int (&x)[5][5]) {} // CHECK: "\01?foo_aay144h@@YAXAAY144H@Z" +// X64: "\01?foo_aay144h@@YAXAEAY144H@Z" void foo_aay144cbh(const int (&x)[5][5]) {} // CHECK: "\01?foo_aay144cbh@@YAXAAY144$$CBH@Z" +// X64: "\01?foo_aay144cbh@@YAXAEAY144$$CBH@Z" void foo_qay144h(int (&&x)[5][5]) {} // CHECK: "\01?foo_qay144h@@YAX$$QAY144H@Z" +// X64: "\01?foo_qay144h@@YAX$$QEAY144H@Z" void foo_qay144cbh(const int (&&x)[5][5]) {} // CHECK: "\01?foo_qay144cbh@@YAX$$QAY144$$CBH@Z" +// X64: "\01?foo_qay144cbh@@YAX$$QEAY144$$CBH@Z" void foo_p6ahxz(int x()) {} // CHECK: "\01?foo_p6ahxz@@YAXP6AHXZ@Z" +// X64: "\01?foo_p6ahxz@@YAXP6AHXZ@Z" void foo_a6ahxz(int (&x)()) {} // CHECK: "\01?foo_a6ahxz@@YAXA6AHXZ@Z" +// X64: "\01?foo_a6ahxz@@YAXA6AHXZ@Z" void foo_q6ahxz(int (&&x)()) {} // CHECK: "\01?foo_q6ahxz@@YAX$$Q6AHXZ@Z" +// X64: "\01?foo_q6ahxz@@YAX$$Q6AHXZ@Z" void foo_qay04h(int x[5][5]) {} // CHECK: "\01?foo_qay04h@@YAXQAY04H@Z" +// X64: "\01?foo_qay04h@@YAXQEAY04H@Z" void foo_qay04cbh(const int x[5][5]) {} // CHECK: "\01?foo_qay04cbh@@YAXQAY04$$CBH@Z" +// X64: "\01?foo_qay04cbh@@YAXQEAY04$$CBH@Z" typedef double Vector[3]; void foo(Vector*) {} // CHECK: "\01?foo@@YAXPAY02N@Z" +// X64: "\01?foo@@YAXPEAY02N@Z" void foo(Vector) {} // CHECK: "\01?foo@@YAXQAN@Z" +// X64: "\01?foo@@YAXQEAN@Z" void foo_const(const Vector) {} // CHECK: "\01?foo_const@@YAXQBN@Z" +// X64: "\01?foo_const@@YAXQEBN@Z" void foo_volatile(volatile Vector) {} // CHECK: "\01?foo_volatile@@YAXQCN@Z" +// X64: "\01?foo_volatile@@YAXQECN@Z" void foo(Vector*, const Vector, const double) {} // CHECK: "\01?foo@@YAXPAY02NQBNN@Z" +// X64: "\01?foo@@YAXPEAY02NQEBNN@Z" diff --git a/test/CodeGenCXX/mangle-ms-templates.cpp b/test/CodeGenCXX/mangle-ms-templates.cpp index 10e68248dc..c52b6b4b7a 100644 --- a/test/CodeGenCXX/mangle-ms-templates.cpp +++ b/test/CodeGenCXX/mangle-ms-templates.cpp @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -fms-extensions -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s +// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s +// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=x86_64-pc-win32 | FileCheck -check-prefix X64 %s template<typename T> class Class { @@ -33,65 +34,87 @@ class BoolTemplate<true> { void template_mangling() { Class<Typename> c1; // CHECK: call {{.*}} @"\01??0?$Class@VTypename@@@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$Class@VTypename@@@@QEAA@XZ" Class<const Typename> c1_const; // CHECK: call {{.*}} @"\01??0?$Class@$$CBVTypename@@@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$Class@$$CBVTypename@@@@QEAA@XZ" Class<volatile Typename> c1_volatile; // CHECK: call {{.*}} @"\01??0?$Class@$$CCVTypename@@@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$Class@$$CCVTypename@@@@QEAA@XZ" Class<const volatile Typename> c1_cv; // CHECK: call {{.*}} @"\01??0?$Class@$$CDVTypename@@@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$Class@$$CDVTypename@@@@QEAA@XZ" Class<Nested<Typename> > c2; // CHECK: call {{.*}} @"\01??0?$Class@V?$Nested@VTypename@@@@@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$Class@V?$Nested@VTypename@@@@@@QEAA@XZ" Class<int * const> c_intpc; // CHECK: call {{.*}} @"\01??0?$Class@QAH@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$Class@QEAH@@QEAA@XZ" Class<int()> c_ft; // CHECK: call {{.*}} @"\01??0?$Class@$$A6AHXZ@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$Class@$$A6AHXZ@@QEAA@XZ" Class<int[]> c_inti; // CHECK: call {{.*}} @"\01??0?$Class@$$BY0A@H@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$Class@$$BY0A@H@@QEAA@XZ" Class<int[5]> c_int5; // CHECK: call {{.*}} @"\01??0?$Class@$$BY04H@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$Class@$$BY04H@@QEAA@XZ" Class<const int[5]> c_intc5; // CHECK: call {{.*}} @"\01??0?$Class@$$BY04$$CBH@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$Class@$$BY04$$CBH@@QEAA@XZ" Class<int * const[5]> c_intpc5; // CHECK: call {{.*}} @"\01??0?$Class@$$BY04QAH@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$Class@$$BY04QEAH@@QEAA@XZ" BoolTemplate<false> _false; // CHECK: call {{.*}} @"\01??0?$BoolTemplate@$0A@@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$BoolTemplate@$0A@@@QEAA@XZ" BoolTemplate<true> _true; // PR13158 _true.Foo(1); // CHECK: call {{.*}} @"\01??0?$BoolTemplate@$00@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$BoolTemplate@$00@@QEAA@XZ" // CHECK: call {{.*}} @"\01??$Foo@H@?$BoolTemplate@$00@@QAEXH@Z" +// X64: call {{.*}} @"\01??$Foo@H@?$BoolTemplate@$00@@QEAAXH@Z" IntTemplate<0> zero; // CHECK: call {{.*}} @"\01??0?$IntTemplate@$0A@@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$IntTemplate@$0A@@@QEAA@XZ" IntTemplate<5> five; // CHECK: call {{.*}} @"\01??0?$IntTemplate@$04@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$IntTemplate@$04@@QEAA@XZ" IntTemplate<11> eleven; // CHECK: call {{.*}} @"\01??0?$IntTemplate@$0L@@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$IntTemplate@$0L@@@QEAA@XZ" IntTemplate<256> _256; // CHECK: call {{.*}} @"\01??0?$IntTemplate@$0BAA@@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$IntTemplate@$0BAA@@@QEAA@XZ" IntTemplate<513> _513; // CHECK: call {{.*}} @"\01??0?$IntTemplate@$0CAB@@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$IntTemplate@$0CAB@@@QEAA@XZ" IntTemplate<1026> _1026; // CHECK: call {{.*}} @"\01??0?$IntTemplate@$0EAC@@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$IntTemplate@$0EAC@@@QEAA@XZ" IntTemplate<65535> ffff; // CHECK: call {{.*}} @"\01??0?$IntTemplate@$0PPPP@@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$IntTemplate@$0PPPP@@@QEAA@XZ" } namespace space { template<class T> const T& foo(const T& l) { return l; } } // CHECK: "\01??$foo@H@space@@YAABHABH@Z" +// X64: "\01??$foo@H@space@@YAAEBHAEBH@Z" void use() { space::foo(42); @@ -108,4 +131,5 @@ void FunctionPointerTemplate() { void spam() { FunctionPointerTemplate<spam>(); // CHECK: "\01??$FunctionPointerTemplate@$1?spam@@YAXXZ@@YAXXZ" +// X64: "\01??$FunctionPointerTemplate@$1?spam@@YAXXZ@@YAXXZ" } diff --git a/test/CodeGenCXX/mangle-ms.cpp b/test/CodeGenCXX/mangle-ms.cpp index 1b98a84823..3f80e54f43 100644 --- a/test/CodeGenCXX/mangle-ms.cpp +++ b/test/CodeGenCXX/mangle-ms.cpp @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -fms-extensions -fblocks -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s -// RUN: %clang_cc1 -fms-compatibility -fblocks -emit-llvm %s -o - -cxx-abi microsoft -triple=x86_64-pc-win32 | FileCheck -check-prefix X64 %s +// RUN: %clang_cc1 -fblocks -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s +// RUN: %clang_cc1 -fblocks -emit-llvm %s -o - -cxx-abi microsoft -triple=x86_64-pc-win32 | FileCheck -check-prefix X64 %s // CHECK: @"\01?a@@3HA" // CHECK: @"\01?b@N@@3HA" @@ -33,6 +33,7 @@ namespace N { static int c; int _c(void) {return N::anonymous + c;} // CHECK: @"\01?_c@@YAHXZ" +// X64: @"\01?_c@@YAHXZ" class foo { static const short d; @@ -43,15 +44,19 @@ public: int operator+(int a); foo(){} //CHECK: @"\01??0foo@@QAE@XZ" +//X64: @"\01??0foo@@QEAA@XZ" ~foo(){} //CHECK: @"\01??1foo@@QAE@XZ" +//X64: @"\01??1foo@@QEAA@XZ foo(int i){} //CHECK: @"\01??0foo@@QAE@H@Z" +//X64: @"\01??0foo@@QEAA@H@Z" foo(char *q){} //CHECK: @"\01??0foo@@QAE@PAD@Z" +//X64: @"\01??0foo@@QEAA@PEAD@Z" static foo* static_method() { return 0; } @@ -77,12 +82,15 @@ enum quux { foo bar() { return foo(); } //CHECK: @"\01?bar@@YA?AVfoo@@XZ" +//X64: @"\01?bar@@YA?AVfoo@@XZ" int foo::operator+(int a) { //CHECK: @"\01??Hfoo@@QAEHH@Z" +//X64: @"\01??Hfoo@@QEAAHH@Z" foo::static_method(); //CHECK: @"\01?static_method@foo@@SAPAV1@XZ" +//X64: @"\01?static_method@foo@@SAPEAV1@XZ" bar(); return a; } @@ -109,6 +117,7 @@ int (foo2::*l)(int); static void __stdcall alpha(float a, double b) throw() {} bool __fastcall beta(long long a, wchar_t b) throw(signed char, unsigned char) { // CHECK: @"\01?beta@@YI_N_J_W@Z" +// X64: @"\01?beta@@YA_N_J_W@Z" alpha(0.f, 0.0); return false; } @@ -119,17 +128,21 @@ bool __fastcall beta(long long a, wchar_t b) throw(signed char, unsigned char) { // Make sure tag-type mangling works. void gamma(class foo, struct bar, union baz, enum quux) {} // CHECK: @"\01?gamma@@YAXVfoo@@Ubar@@Tbaz@@W4quux@@@Z" +// X64: @"\01?gamma@@YAXVfoo@@Ubar@@Tbaz@@W4quux@@@Z" // Make sure pointer/reference-type mangling works. void delta(int * const a, const long &) {} // CHECK: @"\01?delta@@YAXQAHABJ@Z" +// X64: @"\01?delta@@YAXQEAHAEBJ@Z" // Array mangling. void epsilon(int a[][10][20]) {} // CHECK: @"\01?epsilon@@YAXQAY19BE@H@Z" +// X64: @"\01?epsilon@@YAXQEAY19BE@H@Z" void zeta(int (*)(int, int)) {} // CHECK: @"\01?zeta@@YAXP6AHHH@Z@Z" +// X64: @"\01?zeta@@YAXP6AHHH@Z@Z" // Blocks mangling (Clang extension). A block should be mangled slightly // differently from a similar function pointer. @@ -158,6 +171,7 @@ void operator_new_delete() { void (redundant_parens)(); void redundant_parens_use() { redundant_parens(); } // CHECK: @"\01?redundant_parens@@YAXXZ" +// X64: @"\01?redundant_parens@@YAXXZ" // PR13047 typedef double RGB[3]; @@ -169,10 +183,12 @@ extern RGB const ((color4)[5]) = {}; // PR12603 enum E {}; // CHECK: "\01?fooE@@YA?AW4E@@XZ" +// X64: "\01?fooE@@YA?AW4E@@XZ" E fooE() { return E(); } class X {}; // CHECK: "\01?fooX@@YA?AVX@@XZ" +// X64: "\01?fooX@@YA?AVX@@XZ" X fooX() { return X(); } namespace PR13182 { diff --git a/test/Format/diagnostic.cpp b/test/Format/diagnostic.cpp deleted file mode 100644 index 2e930ee5b7..0000000000 --- a/test/Format/diagnostic.cpp +++ /dev/null @@ -1,4 +0,0 @@ -// RUN: clang-format 2>&1 >/dev/null %s |FileCheck %s - -} -// CHECK: diagnostic.cpp:[[@LINE-1]]:1: error: unexpected '}' diff --git a/test/Index/comment-to-html-xml-conversion.cpp b/test/Index/comment-to-html-xml-conversion.cpp index c770ca8d30..ce64dd40b9 100644 --- a/test/Index/comment-to-html-xml-conversion.cpp +++ b/test/Index/comment-to-html-xml-conversion.cpp @@ -741,11 +741,11 @@ int comment_to_xml_conversion_12; /// Aaa. namespace comment_to_xml_conversion_13 { -// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:11: Namespace=comment_to_xml_conversion_13:{{.*}} FullCommentAsXML=[<Namespace file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="11"><Name>comment_to_xml_conversion_13</Name><USR>c:@N@comment_to_xml_conversion_13</USR><Declaration>namespace comment_to_xml_conversion_13 {}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Namespace>] +// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:11: Namespace=comment_to_xml_conversion_13:{{.*}} FullCommentAsXML=[<Namespace file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="11"><Name>comment_to_xml_conversion_13</Name><USR>c:@N@comment_to_xml_conversion_13</USR><Declaration>namespace comment_to_xml_conversion_13 {\n}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Namespace>] /// Aaa. namespace comment_to_xml_conversion_14 { -// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:13: Namespace=comment_to_xml_conversion_14:{{.*}} FullCommentAsXML=[<Namespace file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="13"><Name>comment_to_xml_conversion_14</Name><USR>c:@N@comment_to_xml_conversion_13@N@comment_to_xml_conversion_14</USR><Declaration>namespace comment_to_xml_conversion_14 {}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Namespace>] +// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:13: Namespace=comment_to_xml_conversion_14:{{.*}} FullCommentAsXML=[<Namespace file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="13"><Name>comment_to_xml_conversion_14</Name><USR>c:@N@comment_to_xml_conversion_13@N@comment_to_xml_conversion_14</USR><Declaration>namespace comment_to_xml_conversion_14 {\n}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Namespace>] } } diff --git a/test/Lexer/char-literal.cpp b/test/Lexer/char-literal.cpp index b2fab34e44..1cd14a9b01 100644 --- a/test/Lexer/char-literal.cpp +++ b/test/Lexer/char-literal.cpp @@ -36,8 +36,4 @@ char16_t p[2] = u"\U0000FFFF"; char16_t q[2] = u"\U00010000"; #ifdef __cplusplus // expected-error@-2 {{too long}} -#else -// FIXME: The above should be accepted in C11 mode. -// expected-error@-6 {{must be an initializer list}} -// expected-error@-6 {{must be an initializer list}} #endif diff --git a/test/Misc/ast-dump-templates.cpp b/test/Misc/ast-dump-templates.cpp index 7e28da95a1..b7aeca8d55 100644 --- a/test/Misc/ast-dump-templates.cpp +++ b/test/Misc/ast-dump-templates.cpp @@ -1,6 +1,7 @@ // RUN: %clang_cc1 -ast-print %s > %t // RUN: FileCheck < %t %s -check-prefix=CHECK1 // RUN: FileCheck < %t %s -check-prefix=CHECK2 +// RUN: %clang_cc1 -ast-dump %s | FileCheck --check-prefix=DUMP %s template <int X, typename Y, int Z = 5> struct foo { @@ -37,3 +38,14 @@ void baz() { // Template definition - bar // CHECK1: template <int A, typename B> B bar() // CHECK2: template <int A, typename B> B bar() + +namespace test2 { +void func(int); +void func(float); +template<typename T> +void tmpl() { + func(T()); +} + +// DUMP: UnresolvedLookupExpr {{.*}} <col:3> '<overloaded function type>' lvalue (ADL) = 'func' +} diff --git a/test/Modules/objc-categories.m b/test/Modules/objc-categories.m index 81fb28bafb..f08b13a78a 100644 --- a/test/Modules/objc-categories.m +++ b/test/Modules/objc-categories.m @@ -10,6 +10,7 @@ // expected-note@Inputs/category_left.h:14 {{previous definition}} // expected-warning@Inputs/category_right.h:11 {{duplicate definition of category}} +// expected-note@Inputs/category_top.h:1 {{receiver is instance of class declared here}} @interface Foo(Source) -(void)source; diff --git a/test/OpenMP/predefined_macro.c b/test/OpenMP/predefined_macro.c index cf6c0cc611..3a81186209 100644 --- a/test/OpenMP/predefined_macro.c +++ b/test/OpenMP/predefined_macro.c @@ -31,4 +31,3 @@ #error "_OPENMP macro is defined without -fopenmp option" #endif // _OPENMP #endif // FOPENMP - diff --git a/test/OpenMP/threadprivate_messages.cpp b/test/OpenMP/threadprivate_messages.cpp index 0c448b2ef2..1bfba6d864 100644 --- a/test/OpenMP/threadprivate_messages.cpp +++ b/test/OpenMP/threadprivate_messages.cpp @@ -1,8 +1,8 @@ // RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s -#pragma omp threadprivate // expected-error {{expected '(' after 'threadprivate'}} -#pragma omp threadprivate( // expected-error {{expected unqualified-id}} -#pragma omp threadprivate() // expected-error {{expected unqualified-id}} +#pragma omp threadprivate // expected-error {{expected '(' after 'threadprivate'}} expected-error {{expected identifier}} +#pragma omp threadprivate( // expected-error {{expected identifier}} expected-error {{expected ')'}} expected-note {{to match this '('}} +#pragma omp threadprivate() // expected-error {{expected identifier}} #pragma omp threadprivate(1) // expected-error {{expected unqualified-id}} struct CompleteSt{ int a; @@ -11,27 +11,27 @@ struct CompleteSt{ struct CompleteSt1{ #pragma omp threadprivate(1) // expected-error {{expected unqualified-id}} int a; -} d; // expected-note {{forward declaration of 'd'}} +} d; // expected-note {{'d' defined here}} -int a; // expected-note {{forward declaration of 'a'}} +int a; // expected-note {{'a' defined here}} #pragma omp threadprivate(a) #pragma omp threadprivate(u) // expected-error {{use of undeclared identifier 'u'}} #pragma omp threadprivate(d, a) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'a'}} int foo() { // expected-note {{declared here}} static int l; -#pragma omp threadprivate(l)) // expected-warning {{extra tokens at end of '#pragma omp threadprivate' are ignored}} +#pragma omp threadprivate(l)) // expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}} return (a); } -#pragma omp threadprivate a // expected-error {{expected '(' after 'threadprivate'}} +#pragma omp threadprivate a // expected-error {{expected '(' after 'threadprivate'}} expected-error {{'#pragma omp threadprivate' must precede all references to variable 'a'}} #pragma omp threadprivate(d // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{'#pragma omp threadprivate' must precede all references to variable 'd'}} -#pragma omp threadprivate(d)) +#pragma omp threadprivate(d)) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'd'}} expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}} int x, y; -#pragma omp threadprivate(x)) // expected-warning {{extra tokens at end of '#pragma omp threadprivate' are ignored}} -#pragma omp threadprivate(y)), // expected-warning {{extra tokens at end of '#pragma omp threadprivate' are ignored}} +#pragma omp threadprivate(x)) // expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}} +#pragma omp threadprivate(y)), // expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}} #pragma omp threadprivate(a,d) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'a'}} expected-error {{'#pragma omp threadprivate' must precede all references to variable 'd'}} -#pragma omp threadprivate(d.a) // expected-error {{expected unqualified-id}} +#pragma omp threadprivate(d.a) // expected-error {{expected identifier}} #pragma omp threadprivate((float)a) // expected-error {{expected unqualified-id}} int foa; #pragma omp threadprivate(faa) // expected-error {{use of undeclared identifier 'faa'; did you mean 'foa'?}} @@ -41,31 +41,31 @@ int foa; struct IncompleteSt; // expected-note {{forward declaration of 'IncompleteSt'}} extern IncompleteSt e; -#pragma omp threadprivate (e) // expected-error {{a threadprivate variable must not have incomplete type 'IncompleteSt'}} +#pragma omp threadprivate (e) // expected-error {{threadprivate variable with incomplete type 'IncompleteSt'}} -int &f = a; // expected-note {{forward declaration of 'f'}} -#pragma omp threadprivate (f) // expected-error {{arguments of '#pragma omp threadprivate' cannot be of reference type 'int &'}} +int &f = a; // expected-note {{'f' defined here}} +#pragma omp threadprivate (f) // expected-error {{arguments of '#pragma omp threadprivate' cannot be of reference type}} class Class { private: int a; // expected-note {{declared here}} - static int b; + static int b; // expected-note {{'b' declared here}} Class() : a(0){} public: Class (int aaa) : a(aaa) {} #pragma omp threadprivate (b, a) // expected-error {{'a' is not a global variable, static local variable or static data member}} } g(10); #pragma omp threadprivate (b) // expected-error {{use of undeclared identifier 'b'}} -#pragma omp threadprivate (Class::b) // expected-error {{expected unqualified-id}} +#pragma omp threadprivate (Class::b) // expected-error {{'#pragma omp threadprivate' must appear in the scope of the 'Class::b' variable declaration}} #pragma omp threadprivate (g) namespace ns { - int m; + int m; // expected-note 2 {{'m' defined here}} #pragma omp threadprivate (m) } #pragma omp threadprivate (m) // expected-error {{use of undeclared identifier 'm'}} -#pragma omp threadprivate (ns::m) // expected-error {{expected unqualified-id}} -#pragma omp threadprivate (ns:m) // expected-error {{expected unqualified-id}} +#pragma omp threadprivate (ns::m) // expected-error {{'#pragma omp threadprivate' must appear in the scope of the 'ns::m' variable declaration}} +#pragma omp threadprivate (ns:m) // expected-error {{unexpected ':' in nested name specifier; did you mean '::'?}} expected-error {{'#pragma omp threadprivate' must appear in the scope of the 'ns::m' variable declaration}} const int h = 12; const volatile int i = 10; @@ -84,26 +84,30 @@ class TempClass { }; #pragma omp threadprivate (s) // expected-error {{use of undeclared identifier 's'}} -static __thread int t; // expected-note {{forward declaration of 't'}} +static __thread int t; // expected-note {{'t' defined here}} #pragma omp threadprivate (t) // expected-error {{variable 't' cannot be threadprivate because it is thread-local}} int o; // expected-note {{candidate found by name lookup is 'o'}} +#pragma omp threadprivate (o) namespace { int o; // expected-note {{candidate found by name lookup is '<anonymous namespace>::o'}} +#pragma omp threadprivate (o) +#pragma omp threadprivate (o) // expected-error {{'#pragma omp threadprivate' must precede all references to variable '<anonymous namespace>::o'}} } #pragma omp threadprivate (o) // expected-error {{reference to 'o' is ambiguous}} +#pragma omp threadprivate (::o) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'o'}} -int main(int argc, char **argv) { // expected-note {{forward declaration of 'argc'}} +int main(int argc, char **argv) { // expected-note {{'argc' defined here}} - int x, y = argc; // expected-note {{forward declaration of 'y'}} + int x, y = argc; // expected-note {{'y' defined here}} static double d1; static double d2; - static double d3; // expected-note {{forward declaration of 'd3'}} + static double d3; // expected-note {{'d3' defined here}} d.a = a; d2++; ; -#pragma omp threadprivate(argc+y) // expected-error {{expected unqualified-id}} +#pragma omp threadprivate(argc+y) // expected-error {{expected identifier}} #pragma omp threadprivate(argc,y) // expected-error 2 {{arguments of '#pragma omp threadprivate' must have static storage duration}} #pragma omp threadprivate(d2) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'd2'}} #pragma omp threadprivate(d1) diff --git a/test/PCH/chain-categories2.m b/test/PCH/chain-categories2.m index f230bf9348..50eea2a560 100644 --- a/test/PCH/chain-categories2.m +++ b/test/PCH/chain-categories2.m @@ -45,6 +45,7 @@ #else //===----------------------------------------------------------------------===// +// expected-note@30 {{receiver is instance of class declared here}} void f(I* i) { [i meth]; // expected-warning {{not found}} } diff --git a/test/Preprocessor/init.c b/test/Preprocessor/init.c index 9671f7e232..b3af46e575 100644 --- a/test/Preprocessor/init.c +++ b/test/Preprocessor/init.c @@ -2688,6 +2688,14 @@ // X86_64-LINUX:#define __x86_64 1 // X86_64-LINUX:#define __x86_64__ 1 // +// RUN: %clang_cc1 -E -dM -ffreestanding -triple=sparc64-none-none < /dev/null | FileCheck -check-prefix SPARCV9 %s +// SPARCV9:#define __INTMAX_TYPE__ long int +// SPARCV9:#define __INTPTR_TYPE__ long int +// SPARCV9:#define __LONG_MAX__ 9223372036854775807L +// SPARCV9:#define __LP64__ 1 +// SPARCV9:#define __SIZEOF_LONG__ 8 +// SPARCV9:#define __SIZEOF_POINTER__ 8 +// // RUN: %clang_cc1 -x c++ -triple i686-pc-linux-gnu -fobjc-runtime=gcc -E -dM < /dev/null | FileCheck -check-prefix GNUSOURCE %s // GNUSOURCE:#define _GNU_SOURCE 1 // diff --git a/test/Sema/builtins-aarch64.c b/test/Sema/builtins-aarch64.c index 03e03343eb..b0557532fa 100644 --- a/test/Sema/builtins-aarch64.c +++ b/test/Sema/builtins-aarch64.c @@ -1,4 +1,9 @@ // RUN: %clang_cc1 -triple aarch64-none-linux-gnu -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -DTEST1 -fsyntax-only -verify %s + +#ifdef TEST1 +void __clear_cache(void *start, void *end); +#endif void test_clear_cache_chars(char *start, char *end) { __clear_cache(start, end); diff --git a/test/Sema/builtins-arm.c b/test/Sema/builtins-arm.c index 7b48af155e..3ac1da0aa9 100644 --- a/test/Sema/builtins-arm.c +++ b/test/Sema/builtins-arm.c @@ -1,15 +1,15 @@ -// RUN: %clang_cc1 -triple armv7 -fsyntax-only -verify -DTEST0 %s -// RUN: %clang_cc1 -triple armv7 -fsyntax-only -verify -DTEST1 %s +// RUN: %clang_cc1 -triple armv7 -fsyntax-only -verify %s // RUN: %clang_cc1 -triple armv7 -target-abi apcs-gnu \ -// RUN: -fsyntax-only -verify -DTEST1 %s +// RUN: -fsyntax-only -verify %s -#ifdef TEST0 -void __clear_cache(char*, char*); -#endif +void f(void *a, void *b) { + __clear_cache(); // expected-error {{too few arguments to function call, expected 2, have 0}} // expected-note {{'__clear_cache' is a builtin with type 'void (void *, void *)}} + __clear_cache(a); // expected-error {{too few arguments to function call, expected 2, have 1}} + __clear_cache(a, b); +} -#ifdef TEST1 +void __clear_cache(char*, char*); // expected-error {{conflicting types for '__clear_cache'}} void __clear_cache(void*, void*); -#endif #if defined(__ARM_PCS) || defined(__ARM_EABI__) // va_list on ARM AAPCS is struct { void* __ap }. diff --git a/test/Sema/ms-wchar.c b/test/Sema/ms-wchar.c index 52a736c640..febaf283b3 100644 --- a/test/Sema/ms-wchar.c +++ b/test/Sema/ms-wchar.c @@ -12,4 +12,7 @@ __wchar_t g = L'a'; // expected-note {{previous}} unsigned short g; // expected-error {{redefinition of 'g' with a different type: 'unsigned short' vs '__wchar_t'}} // The type of a wide string literal is actually not __wchar_t. -__wchar_t s[] = L"Hello world!"; // expected-error {{array initializer must be an initializer list}} +__wchar_t s[] = L"Hello world!"; // expected-error-re {{array initializer must be an initializer list$}} + +// Do not suggest initializing with a string here, because it would not work. +__wchar_t t[] = 1; // expected-error-re {{array initializer must be an initializer list$}} diff --git a/test/Sema/offsetof-64.c b/test/Sema/offsetof-64.c new file mode 100644 index 0000000000..1cabec9842 --- /dev/null +++ b/test/Sema/offsetof-64.c @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s -triple x86_64-linux-gnu +// expected-no-diagnostics + +// PR15216 +// Don't crash when taking computing the offset of structs with large arrays. +const unsigned long Size = (1l << 62); + +struct Chunk { + char padding[Size]; + char more_padding[1][Size]; + char data; +}; + +int test1 = __builtin_offsetof(struct Chunk, data); + diff --git a/test/Sema/offsetof.c b/test/Sema/offsetof.c index 46fb515c7f..9e876ad589 100644 --- a/test/Sema/offsetof.c +++ b/test/Sema/offsetof.c @@ -69,3 +69,4 @@ int test4 = __builtin_offsetof(Array, array); int test5() { return __builtin_offsetof(Array, array[*(int*)0]); // expected-warning{{indirection of non-volatile null pointer}} expected-note{{__builtin_trap}} } + diff --git a/test/Sema/string-init.c b/test/Sema/string-init.c new file mode 100644 index 0000000000..96ee360e44 --- /dev/null +++ b/test/Sema/string-init.c @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 -std=c11 -fsyntax-only -triple x86_64-pc-linux -verify %s + +// Note: these match the types specified by the target above. +typedef int wchar_t; +typedef unsigned short char16_t; +typedef unsigned int char32_t; + +void f() { + char a1[] = "a"; // No error. + char a2[] = u8"a"; // No error. + char a3[] = u"a"; // expected-error{{initializing char array with wide string literal}} + char a4[] = U"a"; // expected-error{{initializing char array with wide string literal}} + char a5[] = L"a"; // expected-error{{initializing char array with wide string literal}} + + wchar_t b1[] = "a"; // expected-error{{initializing wide char array with non-wide string literal}} + wchar_t b2[] = u8"a"; // expected-error{{initializing wide char array with non-wide string literal}} + wchar_t b3[] = u"a"; // expected-error{{initializing wide char array with incompatible wide string literal}} + wchar_t b4[] = U"a"; // expected-error{{initializing wide char array with incompatible wide string literal}} + wchar_t b5[] = L"a"; // No error. + + char16_t c1[] = "a"; // expected-error{{initializing wide char array with non-wide string literal}} + char16_t c2[] = u8"a"; // expected-error{{initializing wide char array with non-wide string literal}} + char16_t c3[] = u"a"; // No error. + char16_t c4[] = U"a"; // expected-error{{initializing wide char array with incompatible wide string literal}} + char16_t c5[] = L"a"; // expected-error{{initializing wide char array with incompatible wide string literal}} + + char32_t d1[] = "a"; // expected-error{{initializing wide char array with non-wide string literal}} + char32_t d2[] = u8"a"; // expected-error{{initializing wide char array with non-wide string literal}} + char32_t d3[] = u"a"; // expected-error{{initializing wide char array with incompatible wide string literal}} + char32_t d4[] = U"a"; // No error. + char32_t d5[] = L"a"; // expected-error{{initializing wide char array with incompatible wide string literal}} + + int e1[] = "a"; // expected-error{{initializing wide char array with non-wide string literal}} + int e2[] = u8"a"; // expected-error{{initializing wide char array with non-wide string literal}} + int e3[] = u"a"; // expected-error{{initializing wide char array with incompatible wide string literal}} + int e4[] = U"a"; // expected-error{{initializing wide char array with incompatible wide string literal}} + int e5[] = L"a"; // No error. + + long f1[] = "a"; // expected-error{{array initializer must be an initializer list}} + long f2[] = u8"a"; // expected-error{{array initializer must be an initializer list}}} + long f3[] = u"a"; // expected-error{{array initializer must be an initializer list}} + long f4[] = U"a"; // expected-error{{array initializer must be an initializer list}} + long f5[] = L"a"; // expected-error{{array initializer must be an initializer list}} +} + +void g() { + char a[] = 1; // expected-error{{array initializer must be an initializer list or string literal}} + wchar_t b[] = 1; // expected-error{{array initializer must be an initializer list or wide string literal}} + char16_t c[] = 1; // expected-error{{array initializer must be an initializer list or wide string literal}} + char32_t d[] = 1; // expected-error{{array initializer must be an initializer list or wide string literal}} +} diff --git a/test/Sema/warn-documentation.m b/test/Sema/warn-documentation.m index 14e0c347e3..2720480509 100644 --- a/test/Sema/warn-documentation.m +++ b/test/Sema/warn-documentation.m @@ -176,3 +176,24 @@ struct S; // expected-warning@+1 {{unknown command tag name}} /// \t bbb IS_DOXYGEN_END int FooBar(); + +// rdar://13836387 +/** \brief Module handling the incoming notifications from the system. + * + * This includes: + * - Network Reachability + * - Power State + * - Low Disk + */ +@interface BRC : NSObject +- (void)removeReach:(NSObject*)observer; +@end + +@implementation BRC : NSObject +- (void)removeReach:(NSObject*)observer // expected-note {{previous declaration is here}} +{ +} +- (void)removeReach:(NSObject*)observer // expected-error {{duplicate declaration of method 'removeReach:'}} +{ +} +@end diff --git a/test/Sema/wchar.c b/test/Sema/wchar.c index 816245f3c0..13c2f5855d 100644 --- a/test/Sema/wchar.c +++ b/test/Sema/wchar.c @@ -19,6 +19,6 @@ int check_wchar_size[sizeof(*L"") == sizeof(wchar_t) ? 1 : -1]; void foo() { WCHAR_T_TYPE t1[] = L"x"; wchar_t tab[] = L"x"; - WCHAR_T_TYPE t2[] = "x"; // expected-error {{initializer}} - char t3[] = L"x"; // expected-error {{initializer}} + WCHAR_T_TYPE t2[] = "x"; // expected-error {{initializing wide char array with non-wide string literal}} + char t3[] = L"x"; // expected-error {{initializing char array with wide string literal}} } diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp index 09a9cb5dd8..97b0b91b99 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -1503,3 +1503,11 @@ namespace PR15884 { // expected-note@-3 {{pointer to temporary is not a constant expression}} // expected-note@-4 {{temporary created here}} } + +namespace AfterError { + // FIXME: Suppress the 'no return statements' diagnostic if the body is invalid. + constexpr int error() { // expected-error {{no return statement}} + return foobar; // expected-error {{undeclared identifier}} + } + constexpr int k = error(); // expected-error {{must be initialized by a constant expression}} +} diff --git a/test/SemaCXX/constant-expression-cxx1y.cpp b/test/SemaCXX/constant-expression-cxx1y.cpp index 824a0e8b91..ea0c9e6526 100644 --- a/test/SemaCXX/constant-expression-cxx1y.cpp +++ b/test/SemaCXX/constant-expression-cxx1y.cpp @@ -250,11 +250,12 @@ namespace lifetime { } namespace const_modify { - constexpr int modify(int &n) { return n = 1; } // expected-note {{modification of object of const-qualified type 'const int'}} + constexpr int modify(int &n) { return n = 1; } // expected-note 2 {{modification of object of const-qualified type 'const int'}} constexpr int test1() { int k = 0; return modify(k); } - constexpr int test2() { const int k = 0; return modify(const_cast<int&>(k)); } // expected-note {{in call}} + constexpr int test2() { const int k = 0; return modify(const_cast<int&>(k)); } // expected-note 2 {{in call}} static_assert(test1() == 1, ""); static_assert(test2() == 1, ""); // expected-error {{constant expression}} expected-note {{in call}} + constexpr int i = test2(); // expected-error {{constant expression}} expected-note {{in call}} } namespace null { @@ -593,3 +594,117 @@ namespace assignment_op { } static_assert(testC(), ""); } + +namespace switch_stmt { + constexpr int f(char k) { + bool b = false; + int z = 6; + switch (k) { + return -1; + case 0: + if (false) { + case 1: + z = 1; + for (; b;) { + return 5; + while (0) + case 2: return 2; + case 7: z = 7; + do case 6: { + return z; + if (false) + case 3: return 3; + case 4: z = 4; + } while (1); + case 5: b = true; + case 9: z = 9; + } + return z; + } else if (false) case 8: z = 8; + else if (false) { + case 10: + z = -10; + break; + } + else z = 0; + return z; + default: + return -1; + } + return -z; + } + static_assert(f(0) == 0, ""); + static_assert(f(1) == 1, ""); + static_assert(f(2) == 2, ""); + static_assert(f(3) == 3, ""); + static_assert(f(4) == 4, ""); + static_assert(f(5) == 5, ""); + static_assert(f(6) == 6, ""); + static_assert(f(7) == 7, ""); + static_assert(f(8) == 8, ""); + static_assert(f(9) == 9, ""); + static_assert(f(10) == 10, ""); + + // Check that we can continue an outer loop from within a switch. + constexpr bool contin() { + for (int n = 0; n != 10; ++n) { + switch (n) { + case 0: + ++n; + continue; + case 1: + return false; + case 2: + return true; + } + } + return false; + } + static_assert(contin(), ""); + + constexpr bool switch_into_for() { + int n = 0; + switch (n) { + for (; n == 1; ++n) { + return n == 1; + case 0: ; + } + } + return false; + } + static_assert(switch_into_for(), ""); + + constexpr void duff_copy(char *a, const char *b, int n) { + switch ((n - 1) % 8 + 1) { + for ( ; n; n = (n - 1) & ~7) { + case 8: a[n-8] = b[n-8]; + case 7: a[n-7] = b[n-7]; + case 6: a[n-6] = b[n-6]; + case 5: a[n-5] = b[n-5]; + case 4: a[n-4] = b[n-4]; + case 3: a[n-3] = b[n-3]; + case 2: a[n-2] = b[n-2]; + case 1: a[n-1] = b[n-1]; + } + case 0: ; + } + } + + constexpr bool test_copy(const char *str, int n) { + char buffer[16] = {}; + duff_copy(buffer, str, n); + for (int i = 0; i != sizeof(buffer); ++i) + if (buffer[i] != (i < n ? str[i] : 0)) + return false; + return true; + } + static_assert(test_copy("foo", 0), ""); + static_assert(test_copy("foo", 1), ""); + static_assert(test_copy("foo", 2), ""); + static_assert(test_copy("hello world", 0), ""); + static_assert(test_copy("hello world", 7), ""); + static_assert(test_copy("hello world", 8), ""); + static_assert(test_copy("hello world", 9), ""); + static_assert(test_copy("hello world", 10), ""); + static_assert(test_copy("hello world", 10), ""); +} diff --git a/test/SemaCXX/enum-unscoped-nonexistent.cpp b/test/SemaCXX/enum-unscoped-nonexistent.cpp index e9da38f558..7da9a96d60 100644 --- a/test/SemaCXX/enum-unscoped-nonexistent.cpp +++ b/test/SemaCXX/enum-unscoped-nonexistent.cpp @@ -6,7 +6,7 @@ struct Base { template<typename T> struct S : Base { enum E : int; constexpr int f() const; - constexpr int g() const; // expected-note {{declared here}} + constexpr int g() const; void h(); }; template<> enum S<char>::E : int {}; // expected-note {{enum 'S<char>::E' was explicitly specialized here}} @@ -23,7 +23,7 @@ static_assert(S<int>().f() == 1, ""); // The unqualified-id here names a member of the current instantiation, which // bizarrely might not exist in some instantiations. template<typename T> constexpr int S<T>::g() const { return b; } // expected-error {{enumerator 'b' does not exist in instantiation of 'S<char>'}} -static_assert(S<char>().g() == 1, ""); // expected-note {{here}} expected-error {{not an integral constant expression}} expected-note {{undefined}} +static_assert(S<char>().g() == 1, ""); // expected-note {{here}} expected-error {{not an integral constant expression}} static_assert(S<short>().g() == 2, ""); static_assert(S<long>().g() == 8, ""); diff --git a/test/SemaCXX/ms-wchar.cpp b/test/SemaCXX/ms-wchar.cpp index 2cbf745d33..878d8cadce 100644 --- a/test/SemaCXX/ms-wchar.cpp +++ b/test/SemaCXX/ms-wchar.cpp @@ -7,3 +7,6 @@ __wchar_t g = L'a'; __wchar_t s[] = L"Hello world!"; unsigned short t[] = L"Hello world!"; // expected-error{{array initializer must be an initializer list}} + +wchar_t u[] = 1; // expected-error{{array initializer must be an initializer list or wide string literal}} +__wchar_t v[] = 1; // expected-error{{array initializer must be an initializer list or wide string literal}} diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp index 7239646d8d..228bc0ecbd 100644 --- a/test/SemaCXX/nested-name-spec.cpp +++ b/test/SemaCXX/nested-name-spec.cpp @@ -297,3 +297,13 @@ namespace NS { int foobar = a + longer_b; // expected-error {{use of undeclared identifier 'a'; did you mean 'NS::a'?}} \ // expected-error {{use of undeclared identifier 'longer_b'; did you mean 'NS::longer_b'?}} } + +// <rdar://problem/13853540> +namespace N { + struct X { }; + namespace N { + struct Foo { + struct N::X *foo(); // expected-error{{no struct named 'X' in namespace 'N::N'}} + }; + } +} diff --git a/test/SemaCXX/string-init.cpp b/test/SemaCXX/string-init.cpp new file mode 100644 index 0000000000..7e62d1855a --- /dev/null +++ b/test/SemaCXX/string-init.cpp @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s + +void f() { + char a1[] = "a"; // No error. + char a2[] = u8"a"; // No error. + char a3[] = u"a"; // expected-error{{initializing char array with wide string literal}} + char a4[] = U"a"; // expected-error{{initializing char array with wide string literal}} + char a5[] = L"a"; // expected-error{{initializing char array with wide string literal}} + + wchar_t b1[] = "a"; // expected-error{{initializing wide char array with non-wide string literal}} + wchar_t b2[] = u8"a"; // expected-error{{initializing wide char array with non-wide string literal}} + wchar_t b3[] = u"a"; // expected-error{{initializing wide char array with incompatible wide string literal}} + wchar_t b4[] = U"a"; // expected-error{{initializing wide char array with incompatible wide string literal}} + wchar_t b5[] = L"a"; // No error. + + char16_t c1[] = "a"; // expected-error{{initializing wide char array with non-wide string literal}} + char16_t c2[] = u8"a"; // expected-error{{initializing wide char array with non-wide string literal}} + char16_t c3[] = u"a"; // No error. + char16_t c4[] = U"a"; // expected-error{{initializing wide char array with incompatible wide string literal}} + char16_t c5[] = L"a"; // expected-error{{initializing wide char array with incompatible wide string literal}} + + char32_t d1[] = "a"; // expected-error{{initializing wide char array with non-wide string literal}} + char32_t d2[] = u8"a"; // expected-error{{initializing wide char array with non-wide string literal}} + char32_t d3[] = u"a"; // expected-error{{initializing wide char array with incompatible wide string literal}} + char32_t d4[] = U"a"; // No error. + char32_t d5[] = L"a"; // expected-error{{initializing wide char array with incompatible wide string literal}} + + int e1[] = "a"; // expected-error{{array initializer must be an initializer list}} + int e2[] = u8"a"; // expected-error{{array initializer must be an initializer list}} + int e3[] = u"a"; // expected-error{{array initializer must be an initializer list}} + int e4[] = U"a"; // expected-error{{array initializer must be an initializer list}} + int e5[] = L"a"; // expected-error{{array initializer must be an initializer list}} +} + +void g() { + char a[] = 1; // expected-error{{array initializer must be an initializer list or string literal}} + wchar_t b[] = 1; // expected-error{{array initializer must be an initializer list or wide string literal}} + char16_t c[] = 1; // expected-error{{array initializer must be an initializer list or wide string literal}} + char32_t d[] = 1; // expected-error{{array initializer must be an initializer list or wide string literal}} +} diff --git a/test/SemaObjC/call-super-2.m b/test/SemaObjC/call-super-2.m index 3c45a2c732..25cfbdd087 100644 --- a/test/SemaObjC/call-super-2.m +++ b/test/SemaObjC/call-super-2.m @@ -14,7 +14,7 @@ id objc_getClass(const char *s); - (int) instance_func0; @end -@interface Derived: Object +@interface Derived: Object // expected-note {{receiver is instance of class declared here}} + (int) class_func1; + (int) class_func2; + (int) class_func3; diff --git a/test/SemaObjC/compare-qualified-id.m b/test/SemaObjC/compare-qualified-id.m index 82868f8a16..02fa86ec8d 100644 --- a/test/SemaObjC/compare-qualified-id.m +++ b/test/SemaObjC/compare-qualified-id.m @@ -12,7 +12,7 @@ typedef struct _NSZone NSZone; typedef struct {} NSFastEnumerationState; @protocol NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len; @end @interface NSDictionary : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count; @end -@interface NSMutableDictionary : NSDictionary - (void)removeObjectForKey:(id)aKey; @end +@interface NSMutableDictionary : NSDictionary - (void)removeObjectForKey:(id)aKey; @end // expected-note {{receiver is instance of class declared here}} extern NSString * const NSTaskDidTerminateNotification; @interface XCPropertyExpansionContext : NSObject <NSCopying> { // expected-note {{required for direct or indirect protocol 'NSCopying'}} diff --git a/test/SemaObjC/conditional-expr.m b/test/SemaObjC/conditional-expr.m index ec1305dbe8..049a095ce3 100644 --- a/test/SemaObjC/conditional-expr.m +++ b/test/SemaObjC/conditional-expr.m @@ -33,7 +33,8 @@ @end // No @interface declaration for DTFilterOutputStream3 -@implementation DTFilterOutputStream3 // expected-warning {{cannot find interface declaration for 'DTFilterOutputStream3'}} +@implementation DTFilterOutputStream3 // expected-warning {{cannot find interface declaration for 'DTFilterOutputStream3'}} \ + // expected-note {{receiver is instance of class declared here}} - (id)initWithNextOutputStream:(id <DTOutputStreams>) outputStream { id <DTOutputStreams> nextOutputStream = [self nextOutputStream]; // expected-warning {{method '-nextOutputStream' not found (return type defaults to 'id')}} self = nextOutputStream; // expected-warning {{assigning to 'DTFilterOutputStream3 *' from incompatible type 'id<DTOutputStreams>'}} diff --git a/test/SemaObjC/error-outof-scope-property-use.m b/test/SemaObjC/error-outof-scope-property-use.m index c69a4055df..8ab9f55745 100644 --- a/test/SemaObjC/error-outof-scope-property-use.m +++ b/test/SemaObjC/error-outof-scope-property-use.m @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -x objective-c++ -fsyntax-only -fobjc-default-synthesize-properties -verify -Wno-objc-root-class %s // rdar://13178483 -@class NSMutableDictionary; +@class NSMutableDictionary; // expected-note {{receiver is instance of class declared here}} @interface LaunchdJobs diff --git a/test/SemaObjC/instancetype.m b/test/SemaObjC/instancetype.m index 8137964737..7811d3eba5 100644 --- a/test/SemaObjC/instancetype.m +++ b/test/SemaObjC/instancetype.m @@ -25,7 +25,7 @@ - (instancetype)otherMethodInProto2; // expected-note{{overridden method returns an instance of its class type}} @end -@interface Subclass1 : Root +@interface Subclass1 : Root // expected-note 4 {{receiver is instance of class declared here}} - (instancetype)initSubclass1; - (void)methodOnSubclass1; + (instancetype)allocSubclass1; diff --git a/test/SemaObjC/message.m b/test/SemaObjC/message.m index 40fa102f35..2c4d8066f6 100644 --- a/test/SemaObjC/message.m +++ b/test/SemaObjC/message.m @@ -107,7 +107,7 @@ void foo5(id p) { // expected-warning {{instance method '-bar' not found}} } -@interface I1 +@interface I1 // expected-note {{receiver is instance of class declared here}} -(void)unavail_meth __attribute__((unavailable)); // expected-note {{marked unavailable here}} @end diff --git a/test/SemaObjC/method-not-defined.m b/test/SemaObjC/method-not-defined.m index 22466f7dc3..792469b719 100644 --- a/test/SemaObjC/method-not-defined.m +++ b/test/SemaObjC/method-not-defined.m @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -@interface Foo +@interface Foo // expected-note {{receiver is instance of class declared here}} @end void test() { diff --git a/test/SemaObjC/missing-atend-metadata.m b/test/SemaObjC/missing-atend-metadata.m index f072981dc1..f235ab94d8 100644 --- a/test/SemaObjC/missing-atend-metadata.m +++ b/test/SemaObjC/missing-atend-metadata.m @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify -Wno-objc-root-class %s -@interface I0 +@interface I0 // expected-note {{receiver is instance of class declared here}} @end @implementation I0 // expected-note {{implementation started here}} diff --git a/test/SemaObjC/property-5.m b/test/SemaObjC/property-5.m index cd7cc2487a..cf4f87392b 100644 --- a/test/SemaObjC/property-5.m +++ b/test/SemaObjC/property-5.m @@ -8,7 +8,7 @@ @interface MutableNSData : NSData @end -@interface Base : NSData <P1> +@interface Base : NSData <P1> // expected-note {{receiver is instance of class declared here}} @property(readonly) id ref; @property(readonly) Base *p_base; @property(readonly) NSData *nsdata; diff --git a/test/SemaObjC/protocol-id-test-1.m b/test/SemaObjC/protocol-id-test-1.m index 19a4432de6..36e23ed9f2 100644 --- a/test/SemaObjC/protocol-id-test-1.m +++ b/test/SemaObjC/protocol-id-test-1.m @@ -7,7 +7,7 @@ @protocol P @end -@interface INTF<P> +@interface INTF<P> // expected-note {{receiver is instance of class declared here}} - (void)IMeth; @end diff --git a/test/SemaObjCXX/instancetype.mm b/test/SemaObjCXX/instancetype.mm index bbf100ef04..89ff2b4b03 100644 --- a/test/SemaObjCXX/instancetype.mm +++ b/test/SemaObjCXX/instancetype.mm @@ -25,7 +25,7 @@ - (instancetype)otherMethodInProto2; // expected-note{{overridden method returns an instance of its class type}} @end -@interface Subclass1 : Root +@interface Subclass1 : Root // expected-note 4 {{receiver is instance of class declared here}} - (instancetype)initSubclass1; - (void)methodOnSubclass1; + (instancetype)allocSubclass1; diff --git a/test/Tooling/auto-detect-from-source-parent-of-cwd.cpp b/test/Tooling/auto-detect-from-source-parent-of-cwd.cpp index 6b632b0a0d..b1778a65e7 100644 --- a/test/Tooling/auto-detect-from-source-parent-of-cwd.cpp +++ b/test/Tooling/auto-detect-from-source-parent-of-cwd.cpp @@ -2,7 +2,7 @@ // RUN: mkdir -p %t/abc/def/ijk/qwe // RUN: echo "[{\"directory\":\".\",\"command\":\"clang++ -c %t/abc/def/ijk/qwe/test.cpp\",\"file\":\"%t/abc/def/ijk/qwe/test.cpp\"}]" | sed -e 's/\\/\\\\/g' > %t/compile_commands.json // RUN: cp "%s" "%t/abc/def/ijk/qwe/test.cpp" -// RUN: PWD="%t/abc/def" clang-check "ijk/qwe/test.cpp" 2>&1 | FileCheck %s +// RUN: env PWD="%t/abc/def" clang-check "ijk/qwe/test.cpp" 2>&1 | FileCheck %s // CHECK: C++ requires invalid; diff --git a/test/Tooling/clang-check-pwd.cpp b/test/Tooling/clang-check-pwd.cpp index 463ed40b3e..ac245f7ec5 100644 --- a/test/Tooling/clang-check-pwd.cpp +++ b/test/Tooling/clang-check-pwd.cpp @@ -2,7 +2,7 @@ // RUN: mkdir %t // RUN: echo "[{\"directory\":\".\",\"command\":\"clang++ -c %t/test.cpp\",\"file\":\"%t/test.cpp\"}]" | sed -e 's/\\/\\\\/g' > %t/compile_commands.json // RUN: cp "%s" "%t/test.cpp" -// RUN: PWD="%t" clang-check -p "%t" "test.cpp" 2>&1|FileCheck %s +// RUN: env PWD="%t" clang-check -p "%t" "test.cpp" 2>&1|FileCheck %s // FIXME: Make the above easier. // CHECK: C++ requires diff --git a/tools/clang-format/clang-format.el b/tools/clang-format/clang-format.el index b76eb41d94..57475ac722 100644 --- a/tools/clang-format/clang-format.el +++ b/tools/clang-format/clang-format.el @@ -7,25 +7,39 @@ ;; (global-set-key [C-M-tab] 'clang-format-region) ;; ;; Depending on your configuration and coding style, you might need to modify -;; 'style' and 'binary' below. +;; 'style' in clang-format, below. + +;; *Location of the clang-format binary. If it is on your PATH, a full path name +;; need not be specified. +(defvar clang-format-binary "clang-format") + (defun clang-format-region () + "Use clang-format to format the currently active region." (interactive) + (let ((beg (if mark-active + (region-beginning) + (min (line-beginning-position) (1- (point-max))))) + (end (if mark-active + (region-end) + (line-end-position)))) + (clang-format beg end))) + +(defun clang-format-buffer () + "Use clang-format to format the current buffer." + (clang-format (point-min) (point-max))) +(defun clang-format (begin end) + "Use clang-format to format the code between BEGIN and END." (let* ((orig-windows (get-buffer-window-list (current-buffer))) (orig-window-starts (mapcar #'window-start orig-windows)) (orig-point (point)) - (binary "clang-format") (style "LLVM")) - (if mark-active - (setq beg (region-beginning) - end (region-end)) - (setq beg (min (line-beginning-position) (1- (point-max))) - end (line-end-position))) - (call-process-region (point-min) (point-max) binary t t nil - "-offset" (number-to-string (1- beg)) - "-length" (number-to-string (- end beg)) - "-style" style) - (goto-char orig-point) - (dotimes (index (length orig-windows)) - (set-window-start (nth index orig-windows) - (nth index orig-window-starts))))) + (unwind-protect + (call-process-region (point-min) (point-max) clang-format-binary t t nil + "-offset" (number-to-string (1- begin)) + "-length" (number-to-string (- end begin)) + "-style" style) + (goto-char orig-point) + (dotimes (index (length orig-windows)) + (set-window-start (nth index orig-windows) + (nth index orig-window-starts)))))) diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp index 232ea2f668..46ba2463f1 100644 --- a/tools/driver/cc1as_main.cpp +++ b/tools/driver/cc1as_main.cpp @@ -287,12 +287,12 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts, // it later. SrcMgr.setIncludeDirs(Opts.IncludePaths); - OwningPtr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(Opts.Triple)); - assert(MAI && "Unable to create target asm info!"); - OwningPtr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(Opts.Triple)); assert(MRI && "Unable to create target register info!"); + OwningPtr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, Opts.Triple)); + assert(MAI && "Unable to create target asm info!"); + bool IsBinary = Opts.OutputType == AssemblerInvocation::FT_Obj; formatted_raw_ostream *Out = GetOutputStream(Opts, Diags, IsBinary); if (!Out) diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index c25e625df5..71827f8a23 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -5681,7 +5681,7 @@ CXLinkageKind clang_getCursorLinkage(CXCursor cursor) { const Decl *D = cxcursor::getCursorDecl(cursor); if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(D)) - switch (ND->getLinkage()) { + switch (ND->getLinkageInternal()) { case NoLinkage: return CXLinkage_NoLinkage; case InternalLinkage: return CXLinkage_Internal; case UniqueExternalLinkage: return CXLinkage_UniqueExternal; diff --git a/tools/libclang/CIndexUSRs.cpp b/tools/libclang/CIndexUSRs.cpp index a911ce5e95..4e47435996 100644 --- a/tools/libclang/CIndexUSRs.cpp +++ b/tools/libclang/CIndexUSRs.cpp @@ -151,7 +151,7 @@ bool USRGenerator::EmitDeclName(const NamedDecl *D) { } static inline bool ShouldGenerateLocation(const NamedDecl *D) { - return D->getLinkage() != ExternalLinkage; + return !D->isExternallyVisible(); } void USRGenerator::VisitDeclContext(const DeclContext *DC) { @@ -309,9 +309,8 @@ void USRGenerator::VisitObjCMethodDecl(const ObjCMethodDecl *D) { // Ideally we would use 'GenObjCMethod', but this is such a hot path // for Objective-C code that we don't want to use // DeclarationName::getAsString(). - Out << (D->isInstanceMethod() ? "(im)" : "(cm)"); - DeclarationName N(D->getSelector()); - N.printName(Out); + Out << (D->isInstanceMethod() ? "(im)" : "(cm)") + << DeclarationName(D->getSelector()); } void USRGenerator::VisitObjCContainerDecl(const ObjCContainerDecl *D) { diff --git a/tools/libclang/IndexingContext.cpp b/tools/libclang/IndexingContext.cpp index 14b430c7dc..cb9b492586 100644 --- a/tools/libclang/IndexingContext.cpp +++ b/tools/libclang/IndexingContext.cpp @@ -210,11 +210,12 @@ bool IndexingContext::isFunctionLocalDecl(const Decl *D) { return false; if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) { - switch (ND->getLinkage()) { + switch (ND->getFormalLinkage()) { case NoLinkage: case InternalLinkage: return true; case UniqueExternalLinkage: + llvm_unreachable("Not a sema linkage"); case ExternalLinkage: return false; } diff --git a/unittests/ASTMatchers/ASTMatchersTest.h b/unittests/ASTMatchers/ASTMatchersTest.h index 5fed85bb30..05258f7fe2 100644 --- a/unittests/ASTMatchers/ASTMatchersTest.h +++ b/unittests/ASTMatchers/ASTMatchersTest.h @@ -84,6 +84,41 @@ testing::AssertionResult notMatches(const std::string &Code, return matchesConditionally(Code, AMatcher, false, "-std=c++11"); } +inline testing::AssertionResult +matchesConditionallyDynamic(const std::string &Code, + const internal::DynTypedMatcher &AMatcher, + bool ExpectMatch, llvm::StringRef CompileArg) { + bool Found = false; + MatchFinder Finder; + Finder.addDynamicMatcher(AMatcher, new VerifyMatch(0, &Found)); + OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder)); + // Some tests use typeof, which is a gnu extension. + std::vector<std::string> Args(1, CompileArg); + if (!runToolOnCodeWithArgs(Factory->create(), Code, Args)) { + return testing::AssertionFailure() << "Parsing error in \"" << Code << "\""; + } + if (!Found && ExpectMatch) { + return testing::AssertionFailure() + << "Could not find match in \"" << Code << "\""; + } else if (Found && !ExpectMatch) { + return testing::AssertionFailure() + << "Found unexpected match in \"" << Code << "\""; + } + return testing::AssertionSuccess(); +} + +inline testing::AssertionResult +matchesDynamic(const std::string &Code, + const internal::DynTypedMatcher &AMatcher) { + return matchesConditionallyDynamic(Code, AMatcher, true, "-std=c++11"); +} + +inline testing::AssertionResult +notMatchesDynamic(const std::string &Code, + const internal::DynTypedMatcher &AMatcher) { + return matchesConditionallyDynamic(Code, AMatcher, false, "-std=c++11"); +} + template <typename T> testing::AssertionResult matchAndVerifyResultConditionally(const std::string &Code, const T &AMatcher, diff --git a/unittests/ASTMatchers/CMakeLists.txt b/unittests/ASTMatchers/CMakeLists.txt index 91feaac4d9..862c6a0fd9 100644 --- a/unittests/ASTMatchers/CMakeLists.txt +++ b/unittests/ASTMatchers/CMakeLists.txt @@ -11,3 +11,5 @@ add_clang_unittest(ASTMatchersTests target_link_libraries(ASTMatchersTests gtest gtest_main clangASTMatchers clangTooling) + +add_subdirectory(Dynamic) diff --git a/unittests/ASTMatchers/Dynamic/CMakeLists.txt b/unittests/ASTMatchers/Dynamic/CMakeLists.txt new file mode 100644 index 0000000000..eb9fa549e1 --- /dev/null +++ b/unittests/ASTMatchers/Dynamic/CMakeLists.txt @@ -0,0 +1,7 @@ +add_clang_unittest(DynamicASTMatchersTests + VariantValueTest.cpp + ParserTest.cpp + RegistryTest.cpp) + +target_link_libraries(DynamicASTMatchersTests + gtest gtest_main clangASTMatchers clangDynamicASTMatchers clangTooling) diff --git a/unittests/ASTMatchers/Dynamic/Makefile b/unittests/ASTMatchers/Dynamic/Makefile new file mode 100644 index 0000000000..52a02d0ec5 --- /dev/null +++ b/unittests/ASTMatchers/Dynamic/Makefile @@ -0,0 +1,20 @@ +##===- unittests/ASTMatchers/Dynamic/Makefile --------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +CLANG_LEVEL = ../../.. + +TESTNAME = DynamicASTMatchers +include $(CLANG_LEVEL)/../../Makefile.config +LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc +USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \ + clangRewriteCore.a clangRewriteFrontend.a clangParse.a clangSema.a \ + clangAnalysis.a clangEdit.a clangAST.a clangASTMatchers.a \ + clangLex.a clangBasic.a clangDynamicASTMatchers.a + +include $(CLANG_LEVEL)/unittests/Makefile diff --git a/unittests/ASTMatchers/Dynamic/ParserTest.cpp b/unittests/ASTMatchers/Dynamic/ParserTest.cpp new file mode 100644 index 0000000000..41f522856d --- /dev/null +++ b/unittests/ASTMatchers/Dynamic/ParserTest.cpp @@ -0,0 +1,194 @@ +//===- unittest/ASTMatchers/Dynamic/ParserTest.cpp - Parser unit tests -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===-------------------------------------------------------------------===// + +#include <string> +#include <vector> + +#include "../ASTMatchersTest.h" +#include "clang/ASTMatchers/Dynamic/Parser.h" +#include "clang/ASTMatchers/Dynamic/Registry.h" +#include "gtest/gtest.h" +#include "llvm/ADT/StringMap.h" + +namespace clang { +namespace ast_matchers { +namespace dynamic { +namespace { + +class DummyDynTypedMatcher : public DynTypedMatcher { +public: + DummyDynTypedMatcher(uint64_t ID) : ID(ID) {} + + typedef ast_matchers::internal::ASTMatchFinder ASTMatchFinder; + typedef ast_matchers::internal::BoundNodesTreeBuilder BoundNodesTreeBuilder; + virtual bool matches(const ast_type_traits::DynTypedNode DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const { + return false; + } + + /// \brief Makes a copy of this matcher object. + virtual DynTypedMatcher *clone() const { + return new DummyDynTypedMatcher(ID); + } + + /// \brief Returns a unique ID for the matcher. + virtual uint64_t getID() const { return ID; } + +private: + uint64_t ID; +}; + +class MockSema : public Parser::Sema { +public: + virtual ~MockSema() {} + + uint64_t expectMatcher(StringRef MatcherName) { + uint64_t ID = ExpectedMatchers.size() + 1; + ExpectedMatchers[MatcherName] = ID; + return ID; + } + + void parse(StringRef Code) { + Diagnostics Error; + VariantValue Value; + Parser::parseExpression(Code, this, &Value, &Error); + Values.push_back(Value); + Errors.push_back(Error.ToStringFull()); + } + + DynTypedMatcher *actOnMatcherExpression(StringRef MatcherName, + const SourceRange &NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error) { + MatcherInfo ToStore = { MatcherName, NameRange, Args }; + Matchers.push_back(ToStore); + return new DummyDynTypedMatcher(ExpectedMatchers[MatcherName]); + } + + struct MatcherInfo { + StringRef MatcherName; + SourceRange NameRange; + std::vector<ParserValue> Args; + }; + + std::vector<std::string> Errors; + std::vector<VariantValue> Values; + std::vector<MatcherInfo> Matchers; + llvm::StringMap<uint64_t> ExpectedMatchers; +}; + +TEST(ParserTest, ParseString) { + MockSema Sema; + Sema.parse("\"Foo\""); + Sema.parse("\"\""); + Sema.parse("\"Baz"); + EXPECT_EQ(3ULL, Sema.Values.size()); + EXPECT_EQ("Foo", Sema.Values[0].getString()); + EXPECT_EQ("", Sema.Values[1].getString()); + EXPECT_EQ("1:1: Error parsing string token: <\"Baz>", Sema.Errors[2]); +} + +bool matchesRange(const SourceRange &Range, unsigned StartLine, + unsigned EndLine, unsigned StartColumn, unsigned EndColumn) { + EXPECT_EQ(StartLine, Range.Start.Line); + EXPECT_EQ(EndLine, Range.End.Line); + EXPECT_EQ(StartColumn, Range.Start.Column); + EXPECT_EQ(EndColumn, Range.End.Column); + return Range.Start.Line == StartLine && Range.End.Line == EndLine && + Range.Start.Column == StartColumn && Range.End.Column == EndColumn; +} + +TEST(ParserTest, ParseMatcher) { + MockSema Sema; + const uint64_t ExpectedFoo = Sema.expectMatcher("Foo"); + const uint64_t ExpectedBar = Sema.expectMatcher("Bar"); + const uint64_t ExpectedBaz = Sema.expectMatcher("Baz"); + Sema.parse(" Foo ( Bar (), Baz( \n \"B A,Z\") ) "); + for (size_t i = 0, e = Sema.Errors.size(); i != e; ++i) { + EXPECT_EQ("", Sema.Errors[i]); + } + + EXPECT_EQ(1ULL, Sema.Values.size()); + EXPECT_EQ(ExpectedFoo, Sema.Values[0].getMatcher().getID()); + + EXPECT_EQ(3ULL, Sema.Matchers.size()); + const MockSema::MatcherInfo Bar = Sema.Matchers[0]; + EXPECT_EQ("Bar", Bar.MatcherName); + EXPECT_TRUE(matchesRange(Bar.NameRange, 1, 1, 8, 14)); + EXPECT_EQ(0ULL, Bar.Args.size()); + + const MockSema::MatcherInfo Baz = Sema.Matchers[1]; + EXPECT_EQ("Baz", Baz.MatcherName); + EXPECT_TRUE(matchesRange(Baz.NameRange, 1, 2, 16, 10)); + EXPECT_EQ(1ULL, Baz.Args.size()); + EXPECT_EQ("B A,Z", Baz.Args[0].Value.getString()); + + const MockSema::MatcherInfo Foo = Sema.Matchers[2]; + EXPECT_EQ("Foo", Foo.MatcherName); + EXPECT_TRUE(matchesRange(Foo.NameRange, 1, 2, 2, 12)); + EXPECT_EQ(2ULL, Foo.Args.size()); + EXPECT_EQ(ExpectedBar, Foo.Args[0].Value.getMatcher().getID()); + EXPECT_EQ(ExpectedBaz, Foo.Args[1].Value.getMatcher().getID()); +} + +using ast_matchers::internal::Matcher; + +TEST(ParserTest, FullParserTest) { + OwningPtr<DynTypedMatcher> Matcher(Parser::parseMatcherExpression( + "hasInitializer(binaryOperator(hasLHS(integerLiteral())))", NULL)); + EXPECT_TRUE(matchesDynamic("int x = 1 + false;", *Matcher)); + EXPECT_FALSE(matchesDynamic("int x = true + 1;", *Matcher)); + + Diagnostics Error; + EXPECT_TRUE(Parser::parseMatcherExpression( + "hasInitializer(\n binaryOperator(hasLHS(\"A\")))", &Error) == NULL); + EXPECT_EQ("1:1: Error parsing argument 1 for matcher hasInitializer.\n" + "2:5: Error parsing argument 1 for matcher binaryOperator.\n" + "2:20: Error building matcher hasLHS.\n" + "2:27: Incorrect type on function hasLHS for arg 1.", + Error.ToStringFull()); +} + +std::string ParseWithError(StringRef Code) { + Diagnostics Error; + VariantValue Value; + Parser::parseExpression(Code, &Value, &Error); + return Error.ToStringFull(); +} + +std::string ParseMatcherWithError(StringRef Code) { + Diagnostics Error; + Parser::parseMatcherExpression(Code, &Error); + return Error.ToStringFull(); +} + +TEST(ParserTest, Errors) { + EXPECT_EQ( + "1:5: Error parsing matcher. Found token <123> while looking for '('.", + ParseWithError("Foo 123")); + EXPECT_EQ( + "1:9: Error parsing matcher. Found token <123> while looking for ','.", + ParseWithError("Foo(\"A\" 123)")); + EXPECT_EQ( + "1:4: Error parsing matcher. Found end-of-code while looking for ')'.", + ParseWithError("Foo(")); + EXPECT_EQ("1:1: End of code found while looking for token.", + ParseWithError("")); + EXPECT_EQ("Input value is not a matcher expression.", + ParseMatcherWithError("\"A\"")); + EXPECT_EQ("1:1: Error parsing argument 1 for matcher Foo.\n" + "1:5: Invalid token <(> found when looking for a value.", + ParseWithError("Foo((")); +} + +} // end anonymous namespace +} // end namespace dynamic +} // end namespace ast_matchers +} // end namespace clang diff --git a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp new file mode 100644 index 0000000000..64af120193 --- /dev/null +++ b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp @@ -0,0 +1,112 @@ +//===- unittest/ASTMatchers/Dynamic/RegistryTest.cpp - Registry unit tests -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===-----------------------------------------------------------------------===// + +#include <vector> + +#include "../ASTMatchersTest.h" +#include "clang/ASTMatchers/Dynamic/Registry.h" +#include "gtest/gtest.h" + +namespace clang { +namespace ast_matchers { +namespace dynamic { +namespace { + +using ast_matchers::internal::Matcher; + +DynTypedMatcher *constructMatcher(StringRef MatcherName, Diagnostics *Error) { + const std::vector<ParserValue> Args; + return Registry::constructMatcher(MatcherName, SourceRange(), Args, Error); +} + +DynTypedMatcher *constructMatcher(StringRef MatcherName, + const VariantValue &Arg1, + Diagnostics *Error) { + std::vector<ParserValue> Args(1); + Args[0].Value = Arg1; + return Registry::constructMatcher(MatcherName, SourceRange(), Args, Error); +} + +DynTypedMatcher *constructMatcher(StringRef MatcherName, + const VariantValue &Arg1, + const VariantValue &Arg2, + Diagnostics *Error) { + std::vector<ParserValue> Args(2); + Args[0].Value = Arg1; + Args[1].Value = Arg2; + return Registry::constructMatcher(MatcherName, SourceRange(), Args, Error); +} + +TEST(RegistryTest, CanConstructNoArgs) { + OwningPtr<DynTypedMatcher> IsArrowValue(constructMatcher("isArrow", NULL)); + OwningPtr<DynTypedMatcher> BoolValue(constructMatcher("boolLiteral", NULL)); + + const std::string ClassSnippet = "struct Foo { int x; };\n" + "Foo *foo = new Foo;\n" + "int i = foo->x;\n"; + const std::string BoolSnippet = "bool Foo = true;\n"; + + EXPECT_TRUE(matchesDynamic(ClassSnippet, *IsArrowValue)); + EXPECT_TRUE(matchesDynamic(BoolSnippet, *BoolValue)); + EXPECT_FALSE(matchesDynamic(ClassSnippet, *BoolValue)); + EXPECT_FALSE(matchesDynamic(BoolSnippet, *IsArrowValue)); +} + +TEST(RegistryTest, ConstructWithSimpleArgs) { + OwningPtr<DynTypedMatcher> Value( + constructMatcher("hasName", std::string("X"), NULL)); + EXPECT_TRUE(matchesDynamic("class X {};", *Value)); + EXPECT_FALSE(matchesDynamic("int x;", *Value)); +} + +TEST(RegistryTest, ConstructWithMatcherArgs) { + OwningPtr<DynTypedMatcher> HasInitializerSimple( + constructMatcher("hasInitializer", stmt(), NULL)); + OwningPtr<DynTypedMatcher> HasInitializerComplex( + constructMatcher("hasInitializer", callExpr(), NULL)); + + std::string code = "int i;"; + EXPECT_FALSE(matchesDynamic(code, *HasInitializerSimple)); + EXPECT_FALSE(matchesDynamic(code, *HasInitializerComplex)); + + code = "int i = 1;"; + EXPECT_TRUE(matchesDynamic(code, *HasInitializerSimple)); + EXPECT_FALSE(matchesDynamic(code, *HasInitializerComplex)); + + code = "int y(); int i = y();"; + EXPECT_TRUE(matchesDynamic(code, *HasInitializerSimple)); + EXPECT_TRUE(matchesDynamic(code, *HasInitializerComplex)); +} + +TEST(RegistryTest, Errors) { + // Incorrect argument count. + OwningPtr<Diagnostics> Error(new Diagnostics()); + EXPECT_TRUE(NULL == constructMatcher("hasInitializer", Error.get())); + EXPECT_EQ("Incorrect argument count. (Expected = 1) != (Actual = 0)", + Error->ToString()); + Error.reset(new Diagnostics()); + EXPECT_TRUE(NULL == constructMatcher("isArrow", std::string(), Error.get())); + EXPECT_EQ("Incorrect argument count. (Expected = 0) != (Actual = 1)", + Error->ToString()); + + // Bad argument type + Error.reset(new Diagnostics()); + EXPECT_TRUE(NULL == constructMatcher("ofClass", std::string(), Error.get())); + EXPECT_EQ("Incorrect type on function ofClass for arg 1.", Error->ToString()); + Error.reset(new Diagnostics()); + EXPECT_TRUE(NULL == constructMatcher("recordDecl", recordDecl(), + ::std::string(), Error.get())); + EXPECT_EQ("Incorrect type on function recordDecl for arg 2.", + Error->ToString()); +} + +} // end anonymous namespace +} // end namespace dynamic +} // end namespace ast_matchers +} // end namespace clang diff --git a/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp b/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp new file mode 100644 index 0000000000..6c202e52fa --- /dev/null +++ b/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp @@ -0,0 +1,97 @@ +//===- unittest/ASTMatchers/Dynamic/VariantValueTest.cpp - VariantValue unit tests -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===-----------------------------------------------------------------------------===// + +#include "../ASTMatchersTest.h" +#include "clang/ASTMatchers/Dynamic/VariantValue.h" +#include "gtest/gtest.h" + +namespace clang { +namespace ast_matchers { +namespace dynamic { +namespace { + +using ast_matchers::internal::DynTypedMatcher; +using ast_matchers::internal::Matcher; + +TEST(VariantValueTest, String) { + const ::std::string kString = "string"; + VariantValue Value = kString; + + EXPECT_TRUE(Value.isString()); + EXPECT_EQ(kString, Value.getString()); + + EXPECT_FALSE(Value.isMatcher()); + EXPECT_FALSE(Value.isTypedMatcher<clang::Decl>()); + EXPECT_FALSE(Value.isTypedMatcher<clang::UnaryOperator>()); +} + +TEST(VariantValueTest, DynTypedMatcher) { + VariantValue Value = stmt(); + + EXPECT_FALSE(Value.isString()); + + EXPECT_TRUE(Value.isMatcher()); + EXPECT_TRUE(Value.isTypedMatcher<clang::Decl>()); + EXPECT_TRUE(Value.isTypedMatcher<clang::UnaryOperator>()); + + // Conversion to any type of matcher works. + // If they are not compatible it would just return a matcher that matches + // nothing. We test this below. + Value = recordDecl(); + EXPECT_TRUE(Value.isMatcher()); + EXPECT_TRUE(Value.isTypedMatcher<clang::Decl>()); + EXPECT_TRUE(Value.isTypedMatcher<clang::UnaryOperator>()); + + Value = unaryOperator(); + EXPECT_TRUE(Value.isMatcher()); + EXPECT_TRUE(Value.isTypedMatcher<clang::Decl>()); + EXPECT_TRUE(Value.isTypedMatcher<clang::Stmt>()); + EXPECT_TRUE(Value.isTypedMatcher<clang::UnaryOperator>()); +} + +TEST(VariantValueTest, Assignment) { + VariantValue Value = std::string("A"); + EXPECT_TRUE(Value.isString()); + EXPECT_EQ("A", Value.getString()); + EXPECT_FALSE(Value.isMatcher()); + + Value = recordDecl(); + EXPECT_FALSE(Value.isString()); + EXPECT_TRUE(Value.isMatcher()); + EXPECT_TRUE(Value.isTypedMatcher<clang::Decl>()); + EXPECT_TRUE(Value.isTypedMatcher<clang::UnaryOperator>()); + + Value = VariantValue(); + EXPECT_FALSE(Value.isString()); + EXPECT_FALSE(Value.isMatcher()); +} + +TEST(GeneicValueTest, Matcher) { + EXPECT_TRUE(matchesDynamic( + "class X {};", VariantValue(recordDecl(hasName("X"))).getMatcher())); + EXPECT_TRUE(matchesDynamic( + "int x;", VariantValue(varDecl()).getTypedMatcher<clang::Decl>())); + EXPECT_TRUE(matchesDynamic("int foo() { return 1 + 1; }", + VariantValue(functionDecl()).getMatcher())); + // Going through the wrong Matcher<T> will fail to match, even if the + // underlying matcher is correct. + EXPECT_FALSE(matchesDynamic( + "int x;", VariantValue(varDecl()).getTypedMatcher<clang::Stmt>())); + + EXPECT_FALSE( + matchesDynamic("int x;", VariantValue(functionDecl()).getMatcher())); + EXPECT_FALSE(matchesDynamic( + "int foo() { return 1 + 1; }", + VariantValue(declRefExpr()).getTypedMatcher<clang::DeclRefExpr>())); +} + +} // end anonymous namespace +} // end namespace dynamic +} // end namespace ast_matchers +} // end namespace clang diff --git a/unittests/ASTMatchers/Makefile b/unittests/ASTMatchers/Makefile index 2abe6eeea5..7ff42f850c 100644 --- a/unittests/ASTMatchers/Makefile +++ b/unittests/ASTMatchers/Makefile @@ -9,6 +9,8 @@ CLANG_LEVEL = ../.. +PARALLEL_DIRS = Dynamic + TESTNAME = ASTMatchers include $(CLANG_LEVEL)/../../Makefile.config LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp index f694c5b214..58dbffd863 100644 --- a/unittests/Format/FormatTest.cpp +++ b/unittests/Format/FormatTest.cpp @@ -32,8 +32,8 @@ protected: CharSourceRange::getCharRange(Start, Start.getLocWithOffset(Length))); Lexer Lex(ID, Context.Sources.getBuffer(ID), Context.Sources, getFormattingLangOpts()); - tooling::Replacements Replace = reformat( - Style, Lex, Context.Sources, Ranges, new IgnoringDiagConsumer()); + tooling::Replacements Replace = + reformat(Style, Lex, Context.Sources, Ranges); ReplacementCount = Replace.size(); EXPECT_TRUE(applyAllReplacements(Replace, Context.Rewrite)); DEBUG(llvm::errs() << "\n" << Context.getRewrittenText(ID) << "\n\n"); @@ -218,7 +218,7 @@ TEST_F(FormatTest, ReformatsMovedLines) { // Tests for control statements. //===----------------------------------------------------------------------===// -TEST_F(FormatTest, FormatIfWithoutCompountStatement) { +TEST_F(FormatTest, FormatIfWithoutCompoundStatement) { verifyFormat("if (true)\n f();\ng();"); verifyFormat("if (a)\n if (b)\n if (c)\n g();\nh();"); verifyFormat("if (a)\n if (b) {\n f();\n }\ng();"); @@ -245,6 +245,10 @@ TEST_F(FormatTest, FormatIfWithoutCompountStatement) { "}", AllowsMergedIf); + EXPECT_EQ("if (a) return;", format("if(a)\nreturn;", 7, 1, AllowsMergedIf)); + EXPECT_EQ("if (a) return; // comment", + format("if(a)\nreturn; // comment", 20, 1, AllowsMergedIf)); + AllowsMergedIf.ColumnLimit = 14; verifyFormat("if (a) return;", AllowsMergedIf); verifyFormat("if (aaaaaaaaa)\n" @@ -741,11 +745,11 @@ TEST_F(FormatTest, SplitsLongCxxComments) { } TEST_F(FormatTest, ParsesCommentsAdjacentToPPDirectives) { - EXPECT_EQ("namespace {}\n// Test\n#define A", + EXPECT_EQ("namespace {\n}\n// Test\n#define A", format("namespace {}\n // Test\n#define A")); - EXPECT_EQ("namespace {}\n/* Test */\n#define A", + EXPECT_EQ("namespace {\n}\n/* Test */\n#define A", format("namespace {}\n /* Test */\n#define A")); - EXPECT_EQ("namespace {}\n/* Test */ #define A", + EXPECT_EQ("namespace {\n}\n/* Test */ #define A", format("namespace {}\n /* Test */ #define A")); } @@ -1106,7 +1110,7 @@ TEST_F(FormatTest, FormatsInlineASM) { "asm(\"movq\\t%%rbx, %%rsi\\n\\t\"\n" " \"cpuid\\n\\t\"\n" " \"xchgq\\t%%rbx, %%rsi\\n\\t\"\n" - " : \"=a\" (*rEAX), \"=S\" (*rEBX), \"=c\" (*rECX), \"=d\" (*rEDX)\n" + " : \"=a\"(*rEAX), \"=S\"(*rEBX), \"=c\"(*rECX), \"=d\"(*rEDX)\n" " : \"a\"(value));"); } @@ -1642,6 +1646,14 @@ TEST_F(FormatTest, LineBreakingInBinaryExpressions) { " SourceMgr.getSpellingColumnNumber(\n" " TheLine.Last->FormatTok.Tok.getLocation()) -\n" " 1);"); + + FormatStyle OnePerLine = getLLVMStyle(); + OnePerLine.BinPackParameters = false; + verifyFormat( + "if (aaaaaaaaaaaaaaaaaaaaaaaaaaaa || aaaaaaaaaaaaaaaaaaaaaaaaaaaa ||\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaa || aaaaaaaaaaaaaaaaaaaaaaaaaaaa ||\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaa) {\n}", + OnePerLine); } TEST_F(FormatTest, ExpressionIndentation) { @@ -1761,6 +1773,33 @@ TEST_F(FormatTest, MemoizationTests) { " aaaaa(aaaaa(aaaaa(aaaaa(aaaaa(aaaaa(aaaaa(aaaaa(aaaaa(\n" " aaaaa())))))))))))))))))))))))))))))))))))))));", getLLVMStyleWithColumns(65)); + verifyFormat( + "aaaaa(\n" + " aaaaa,\n" + " aaaaa(\n" + " aaaaa,\n" + " aaaaa(\n" + " aaaaa,\n" + " aaaaa(\n" + " aaaaa,\n" + " aaaaa(\n" + " aaaaa,\n" + " aaaaa(\n" + " aaaaa,\n" + " aaaaa(\n" + " aaaaa,\n" + " aaaaa(\n" + " aaaaa,\n" + " aaaaa(\n" + " aaaaa,\n" + " aaaaa(\n" + " aaaaa,\n" + " aaaaa(\n" + " aaaaa,\n" + " aaaaa(\n" + " aaaaa,\n" + " aaaaa))))))))))));", + getLLVMStyleWithColumns(65)); // This test takes VERY long when memoization is broken. FormatStyle OnePerLine = getLLVMStyle(); @@ -1963,7 +2002,7 @@ TEST_F(FormatTest, FormatsBuilderPattern) { " .StartsWith(\".eh_frame\", ORDER_EH_FRAME).StartsWith(\".init\", ORDER_INIT)\n" " .StartsWith(\".fini\", ORDER_FINI).StartsWith(\".hash\", ORDER_HASH)\n" " .Default(ORDER_TEXT);\n"); - + verifyFormat("return aaaaaaaaaaaaaaaaa->aaaaa().aaaaaaaaaaaaa().aaaaaa() <\n" " aaaaaaaaaaaaaaa->aaaaa().aaaaaaaaaaaaa().aaaaaa();"); verifyFormat( @@ -2204,6 +2243,14 @@ TEST_F(FormatTest, AlignsStringLiterals) { "#define LL_FORMAT \"ll\"\n" "printf(\"aaaaa: %d, bbbbbb: %\" LL_FORMAT \"d, cccccccc: %\" LL_FORMAT\n" " \"d, ddddddddd: %\" LL_FORMAT \"d\");"); + + verifyFormat("#define A(X) \\\n" + " \"aaaaa\" #X \"bbbbbb\" \\\n" + " \"ccccc\"", + getLLVMStyleWithColumns(23)); + verifyFormat("#define A \"def\"\n" + "f(\"abc\" A \"ghi\"\n" + " \"jkl\");"); } TEST_F(FormatTest, AlignsPipes) { @@ -2638,10 +2685,16 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) { verifyFormat("for (int i = a * a; i < 10; ++i) {\n}"); verifyFormat("for (int i = 0; i < a * a; ++i) {\n}"); + verifyFormat("#define MACRO \\\n" + " int *i = a * b; \\\n" + " void f(a *b);", + getLLVMStyleWithColumns(19)); + verifyIndependentOfContext("A = new SomeType *[Length];"); verifyIndependentOfContext("A = new SomeType *[Length]();"); verifyGoogleFormat("A = new SomeType* [Length]();"); verifyGoogleFormat("A = new SomeType* [Length];"); + FormatStyle PointerLeft = getLLVMStyle(); PointerLeft.PointerBindsToType = true; verifyFormat("delete *x;", PointerLeft); @@ -2749,6 +2802,10 @@ TEST_F(FormatTest, FormatsFunctionTypes) { verifyGoogleFormat("A<void*(int*, SomeType*)>;"); verifyGoogleFormat("void* (*a)(int);"); + + // Other constructs can look somewhat like function types: + verifyFormat("A<sizeof(*x)> a;"); + verifyFormat("#define DEREF_AND_CALL_F(x) f(*x)"); } TEST_F(FormatTest, BreaksLongDeclarations) { @@ -2778,6 +2835,10 @@ TEST_F(FormatTest, BreaksLongDeclarations) { " ReallyReallyLongParameterName,\n" " const SomeType<string, SomeOtherTemplateParameter> &\n" " AnotherLongParameterName) {}"); + verifyFormat("template <typename A>\n" + "SomeLoooooooooooooooooooooongType<\n" + " typename some_namespace::SomeOtherType<A>::Type>\n" + "Function() {}"); verifyFormat( "aaaaaaaaaaaaaaaa::aaaaaaaaaaaaaaaa<aaaaaaaaaaaaa, aaaaaaaaaaaa>\n" " aaaaaaaaaaaaaaaaaaaaaaa;"); @@ -2860,7 +2921,10 @@ TEST_F(FormatTest, IncorrectCodeMissingSemicolon) { " return\n" "}", format("void f ( ) { if ( a ) return }")); - EXPECT_EQ("namespace N { void f() }", format("namespace N { void f() }")); + EXPECT_EQ("namespace N {\n" + "void f()\n" + "}", + format("namespace N { void f() }")); EXPECT_EQ("namespace N {\n" "void f() {}\n" "void g()\n" @@ -3016,6 +3080,13 @@ TEST_F(FormatTest, UnderstandContextOfRecordTypeKeywords) { verifyFormat("class A::B::C {\n} n;"); // Template definitions. + verifyFormat( + "template <typename F>\n" + "Matcher(const Matcher<F> &Other,\n" + " typename enable_if_c<is_base_of<F, T>::value &&\n" + " !is_same<F, T>::value>::type * = 0)\n" + " : Implementation(new ImplicitCastMatcher<F>(Other)) {}"); + // FIXME: This is still incorrectly handled at the formatter side. verifyFormat("template <> struct X < 15, i < 3 && 42 < 50 && 33<28> {\n};"); @@ -3765,7 +3836,7 @@ TEST_F(FormatTest, ReformatRegionAdjustsIndent) { "a;\n" "}\n" "{\n" - " b;\n" + " b; //\n" "}\n" "}", format("{\n" @@ -3773,15 +3844,15 @@ TEST_F(FormatTest, ReformatRegionAdjustsIndent) { "a;\n" "}\n" "{\n" - " b;\n" + " b; //\n" "}\n" "}", 22, 2, getLLVMStyle())); EXPECT_EQ(" {\n" - " a;\n" + " a; //\n" " }", format(" {\n" - "a;\n" + "a; //\n" " }", 4, 2, getLLVMStyle())); EXPECT_EQ("void f() {}\n" @@ -3899,6 +3970,48 @@ TEST_F(FormatTest, BreakStringLiterals) { format("#define A \"some text other\";", AlignLeft)); } +TEST_F(FormatTest, BreakStringLiteralsBeforeUnbreakableTokenSequence) { + EXPECT_EQ("someFunction(\"aaabbbcccd\"\n" + " \"ddeeefff\");", + format("someFunction(\"aaabbbcccdddeeefff\");", + getLLVMStyleWithColumns(25))); + EXPECT_EQ("someFunction1234567890(\n" + " \"aaabbbcccdddeeefff\");", + format("someFunction1234567890(\"aaabbbcccdddeeefff\");", + getLLVMStyleWithColumns(26))); + EXPECT_EQ("someFunction1234567890(\n" + " \"aaabbbcccdddeeeff\"\n" + " \"f\");", + format("someFunction1234567890(\"aaabbbcccdddeeefff\");", + getLLVMStyleWithColumns(25))); + EXPECT_EQ("someFunction1234567890(\n" + " \"aaabbbcccdddeeeff\"\n" + " \"f\");", + format("someFunction1234567890(\"aaabbbcccdddeeefff\");", + getLLVMStyleWithColumns(24))); + EXPECT_EQ("someFunction(\n" + " \"aaabbbcc \"\n" + " \"dddeeefff\");", + format("someFunction(\"aaabbbcc dddeeefff\");", + getLLVMStyleWithColumns(25))); + EXPECT_EQ("someFunction(\"aaabbbccc \"\n" + " \"ddeeefff\");", + format("someFunction(\"aaabbbccc ddeeefff\");", + getLLVMStyleWithColumns(25))); + EXPECT_EQ("someFunction1234567890(\n" + " \"aaabb \"\n" + " \"cccdddeeefff\");", + format("someFunction1234567890(\"aaabb cccdddeeefff\");", + getLLVMStyleWithColumns(25))); + EXPECT_EQ("#define A \\\n" + " string s = \\\n" + " \"123456789\" \\\n" + " \"0\"; \\\n" + " int i;", + format("#define A string s = \"1234567890\"; int i;", + getLLVMStyleWithColumns(20))); +} + TEST_F(FormatTest, DoNotBreakStringLiteralsInEscapeSequence) { EXPECT_EQ("\"\\a\"", format("\"\\a\"", getLLVMStyleWithColumns(3))); @@ -3953,6 +4066,101 @@ TEST_F(FormatTest, DoNotCreateUnreasonableUnwrappedLines) { "}"); } +TEST_F(FormatTest, FormatsClosingBracesInEmptyNestedBlocks) { + verifyFormat("class X {\n" + " void f() {\n" + " }\n" + "};", + getLLVMStyleWithColumns(12)); +} + +TEST_F(FormatTest, ConfigurableIndentWidth) { + FormatStyle EightIndent = getLLVMStyleWithColumns(18); + EightIndent.IndentWidth = 8; + verifyFormat("void f() {\n" + " someFunction();\n" + " if (true) {\n" + " f();\n" + " }\n" + "}", + EightIndent); + verifyFormat("class X {\n" + " void f() {\n" + " }\n" + "};", + EightIndent); + verifyFormat("int x[] = {\n" + " call(),\n" + " call(),\n" + "};", + EightIndent); +} + +TEST_F(FormatTest, ConfigurableUseOfTab) { + FormatStyle Tab = getLLVMStyleWithColumns(42); + Tab.IndentWidth = 8; + Tab.UseTab = true; + Tab.AlignEscapedNewlinesLeft = true; + verifyFormat("class X {\n" + "\tvoid f() {\n" + "\t\tsomeFunction(parameter1,\n" + "\t\t\t parameter2);\n" + "\t}\n" + "};", + Tab); + verifyFormat("#define A \\\n" + "\tvoid f() { \\\n" + "\t\tsomeFunction( \\\n" + "\t\t parameter1, \\\n" + "\t\t parameter2); \\\n" + "\t}", + Tab); +} + +TEST_F(FormatTest, LinuxBraceBreaking) { + FormatStyle BreakBeforeBrace = getLLVMStyle(); + BreakBeforeBrace.BreakBeforeBraces = FormatStyle::BS_Linux; + verifyFormat("namespace a\n" + "{\n" + "class A\n" + "{\n" + " void f()\n" + " {\n" + " if (true) {\n" + " a();\n" + " b();\n" + " }\n" + " }\n" + " void g()\n" + " {\n" + " return;\n" + " }\n" + "}\n" + "}", + BreakBeforeBrace); +} + +TEST_F(FormatTest, StroustrupBraceBreaking) { + FormatStyle BreakBeforeBrace = getLLVMStyle(); + BreakBeforeBrace.BreakBeforeBraces = FormatStyle::BS_Stroustrup; + verifyFormat("namespace a {\n" + "class A {\n" + " void f()\n" + " {\n" + " if (true) {\n" + " a();\n" + " b();\n" + " }\n" + " }\n" + " void g()\n" + " {\n" + " return;\n" + " }\n" + "}\n" + "}", + BreakBeforeBrace); +} + bool allStylesEqual(ArrayRef<FormatStyle> Styles) { for (size_t i = 1; i < Styles.size(); ++i) if (!(Styles[0] == Styles[i])) @@ -3994,9 +4202,9 @@ TEST_F(FormatTest, ParsesConfiguration) { #define CHECK_PARSE_BOOL(FIELD) \ Style.FIELD = false; \ EXPECT_EQ(0, parseConfiguration(#FIELD ": true", &Style).value()); \ - EXPECT_EQ(true, Style.FIELD); \ + EXPECT_TRUE(Style.FIELD); \ EXPECT_EQ(0, parseConfiguration(#FIELD ": false", &Style).value()); \ - EXPECT_EQ(false, Style.FIELD); + EXPECT_FALSE(Style.FIELD); CHECK_PARSE_BOOL(AlignEscapedNewlinesLeft); CHECK_PARSE_BOOL(AllowAllParametersOfDeclarationOnNextLine); @@ -4007,6 +4215,7 @@ TEST_F(FormatTest, ParsesConfiguration) { CHECK_PARSE_BOOL(IndentCaseLabels); CHECK_PARSE_BOOL(ObjCSpaceBeforeProtocolList); CHECK_PARSE_BOOL(PointerBindsToType); + CHECK_PARSE_BOOL(UseTab); CHECK_PARSE("AccessModifierOffset: -1234", AccessModifierOffset, -1234); CHECK_PARSE("ColumnLimit: 1234", ColumnLimit, 1234u); @@ -4016,6 +4225,7 @@ TEST_F(FormatTest, ParsesConfiguration) { PenaltyReturnTypeOnItsOwnLine, 1234u); CHECK_PARSE("SpacesBeforeTrailingComments: 1234", SpacesBeforeTrailingComments, 1234u); + CHECK_PARSE("IndentWidth: 32", IndentWidth, 32u); Style.Standard = FormatStyle::LS_Auto; CHECK_PARSE("Standard: C++03", Standard, FormatStyle::LS_Cpp03); @@ -4027,6 +4237,14 @@ TEST_F(FormatTest, ParsesConfiguration) { CHECK_PARSE("BasedOnStyle: LLVM", ColumnLimit, BaseStyle.ColumnLimit); CHECK_PARSE("BasedOnStyle: LLVM\nColumnLimit: 1234", ColumnLimit, 1234u); + Style.BreakBeforeBraces = FormatStyle::BS_Stroustrup; + CHECK_PARSE("BreakBeforeBraces: Attach", BreakBeforeBraces, + FormatStyle::BS_Attach); + CHECK_PARSE("BreakBeforeBraces: Linux", BreakBeforeBraces, + FormatStyle::BS_Linux); + CHECK_PARSE("BreakBeforeBraces: Stroustrup", BreakBeforeBraces, + FormatStyle::BS_Stroustrup); + #undef CHECK_PARSE #undef CHECK_PARSE_BOOL } diff --git a/unittests/Tooling/CompilationDatabaseTest.cpp b/unittests/Tooling/CompilationDatabaseTest.cpp index c453b056d2..defde91b26 100644 --- a/unittests/Tooling/CompilationDatabaseTest.cpp +++ b/unittests/Tooling/CompilationDatabaseTest.cpp @@ -453,7 +453,7 @@ TEST(ParseFixedCompilationDatabase, ReturnsArgumentsAfterDoubleDash) { const char *Argv[] = { "1", "2", "--\0no-constant-folding", "3", "4" }; OwningPtr<FixedCompilationDatabase> Database( FixedCompilationDatabase::loadFromCommandLine(Argc, Argv)); - ASSERT_TRUE(Database); + ASSERT_TRUE(Database.isValid()); std::vector<CompileCommand> Result = Database->getCompileCommands("source"); ASSERT_EQ(1ul, Result.size()); @@ -472,7 +472,7 @@ TEST(ParseFixedCompilationDatabase, ReturnsEmptyCommandLine) { const char *Argv[] = { "1", "2", "--\0no-constant-folding" }; OwningPtr<FixedCompilationDatabase> Database( FixedCompilationDatabase::loadFromCommandLine(Argc, Argv)); - ASSERT_TRUE(Database); + ASSERT_TRUE(Database.isValid()); std::vector<CompileCommand> Result = Database->getCompileCommands("source"); ASSERT_EQ(1ul, Result.size()); diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp index eaf10a64a4..3982fc3f31 100644 --- a/utils/TableGen/ClangAttrEmitter.cpp +++ b/utils/TableGen/ClangAttrEmitter.cpp @@ -1094,13 +1094,13 @@ void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) { " INHERITABLE_PARAM_ATTR(NAME)\n"; OS << "#endif\n\n"; - OS << "#ifndef MS_INHERITABLE_ATTR\n"; - OS << "#define MS_INHERITABLE_ATTR(NAME) INHERITABLE_ATTR(NAME)\n"; + OS << "#ifndef MS_INHERITANCE_ATTR\n"; + OS << "#define MS_INHERITANCE_ATTR(NAME) INHERITABLE_ATTR(NAME)\n"; OS << "#endif\n\n"; - OS << "#ifndef LAST_MS_INHERITABLE_ATTR\n"; - OS << "#define LAST_MS_INHERITABLE_ATTR(NAME)" - " MS_INHERITABLE_ATTR(NAME)\n"; + OS << "#ifndef LAST_MS_INHERITANCE_ATTR\n"; + OS << "#define LAST_MS_INHERITANCE_ATTR(NAME)" + " MS_INHERITANCE_ATTR(NAME)\n"; OS << "#endif\n\n"; Record *InhClass = Records.getClass("InheritableAttr"); @@ -1124,16 +1124,16 @@ void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) { } EmitAttrList(OS, "INHERITABLE_PARAM_ATTR", InhParamAttrs); - EmitAttrList(OS, "MS_INHERITABLE_ATTR", MSInhAttrs); + EmitAttrList(OS, "MS_INHERITANCE_ATTR", MSInhAttrs); EmitAttrList(OS, "INHERITABLE_ATTR", InhAttrs); EmitAttrList(OS, "ATTR", NonInhAttrs); OS << "#undef LAST_ATTR\n"; OS << "#undef INHERITABLE_ATTR\n"; - OS << "#undef MS_INHERITABLE_ATTR\n"; + OS << "#undef MS_INHERITANCE_ATTR\n"; OS << "#undef LAST_INHERITABLE_ATTR\n"; OS << "#undef LAST_INHERITABLE_PARAM_ATTR\n"; - OS << "#undef LAST_MS_INHERITABLE_ATTR\n"; + OS << "#undef LAST_MS_INHERITANCE_ATTR\n"; OS << "#undef ATTR\n"; } diff --git a/utils/TableGen/NeonEmitter.cpp b/utils/TableGen/NeonEmitter.cpp index 34b955e8e9..05505c99c9 100644 --- a/utils/TableGen/NeonEmitter.cpp +++ b/utils/TableGen/NeonEmitter.cpp @@ -1410,12 +1410,17 @@ static std::string GenOpString(OpKind op, const std::string &proto, s += ", (int64x1_t)__b, 0, 1);"; break; case OpHi: - s += "(" + ts + - ")__builtin_shufflevector((int64x2_t)__a, (int64x2_t)__a, 1);"; + // nElts is for the result vector, so the source is twice that number. + s += "__builtin_shufflevector(__a, __a"; + for (unsigned i = nElts; i < nElts * 2; ++i) + s += ", " + utostr(i); + s+= ");"; break; case OpLo: - s += "(" + ts + - ")__builtin_shufflevector((int64x2_t)__a, (int64x2_t)__a, 0);"; + s += "__builtin_shufflevector(__a, __a"; + for (unsigned i = 0; i < nElts; ++i) + s += ", " + utostr(i); + s+= ");"; break; case OpDup: s += Duplicate(nElts, typestr, "__a") + ";"; diff --git a/www/cxx_status.html b/www/cxx_status.html index 7643c7a7b1..a0c697f149 100644 --- a/www/cxx_status.html +++ b/www/cxx_status.html @@ -467,7 +467,7 @@ available.</p> <tr> <td>Clarifying memory allocation</td> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3664.html">N3664</a></td> - <td class="full" align="center">Yes</td> + <td class="partial" align="center">Partial</td> </tr> </table> |