Propagating prior merge from 'llvm.org/release_40'.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..a0c1644
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,14 @@
+By submitting a pull request, you represent that you have the right to license
+your contribution to Apple and the community, and agree by submitting the patch
+that your contributions are licensed under the [Swift
+license](https://swift.org/LICENSE.txt).
+
+---
+
+Changes to this repository follow special considerations as described on
+Swift.org under "[LLVM and Swift](https://swift.org/contributing/#llvm-and-swift)".
+Please make sure your change is appropriate for this repository.
+
+Before submitting a pull request, please make sure you have tested your
+changes and that they follow the Swift project [guidelines for contributing
+code](https://swift.org/contributing/#contributing-code).
diff --git a/include/clang/APINotes/APINotesManager.h b/include/clang/APINotes/APINotesManager.h
new file mode 100644
index 0000000..2adc29c
--- /dev/null
+++ b/include/clang/APINotes/APINotesManager.h
@@ -0,0 +1,147 @@
+//===--- APINotesManager.h - Manage API Notes Files -------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the APINotesManager interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_APINOTES_APINOTESMANAGER_H
+#define LLVM_CLANG_APINOTES_APINOTESMANAGER_H
+
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/Module.h"
+#include "clang/Basic/VersionTuple.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/StringRef.h"
+#include <memory>
+#include <string>
+
+namespace clang {
+
+class DirectoryEntry;
+class FileEntry;
+class LangOptions;
+class SourceManager;
+
+namespace api_notes {
+
+class APINotesReader;
+
+/// The API notes manager helps find API notes associated with declarations.
+///
+/// API notes are externally-provided annotations for declarations that can
+/// introduce new attributes (covering availability, nullability of
+/// parameters/results, and so on) for specific declarations without directly
+/// modifying the headers that contain those declarations.
+///
+/// The API notes manager is responsible for finding and loading the
+/// external API notes files that correspond to a given header. Its primary
+/// operation is \c findAPINotes(), which finds the API notes reader that
+/// provides information about the declarations at that location.
+class APINotesManager {
+ typedef llvm::PointerUnion<const DirectoryEntry *, APINotesReader *>
+ ReaderEntry;
+
+ SourceManager &SourceMgr;
+
+ /// Whether to implicitly search for API notes files based on the
+ /// source file from which an entity was declared.
+ bool ImplicitAPINotes;
+
+ /// The Swift version to use when interpreting versioned API notes.
+ VersionTuple SwiftVersion;
+
+ /// API notes readers for the current module.
+ ///
+ /// There can be up to two of these, one for public headers and one
+ /// for private headers.
+ APINotesReader *CurrentModuleReaders[2] = { nullptr, nullptr };
+
+ /// Whether we have already pruned the API notes cache.
+ bool PrunedCache;
+
+ /// A mapping from header file directories to the API notes reader for
+ /// that directory, or a redirection to another directory entry that may
+ /// have more information, or NULL to indicate that there is no API notes
+ /// reader for this directory.
+ llvm::DenseMap<const DirectoryEntry *, ReaderEntry> Readers;
+
+ /// Load the API notes associated with the given file, whether it is
+ /// the binary or source form of API notes.
+ ///
+ /// \returns the API notes reader for this file, or null if there is
+ /// a failure.
+ std::unique_ptr<APINotesReader> loadAPINotes(const FileEntry *apiNotesFile);
+
+ /// Load the given API notes file for the given header directory.
+ ///
+ /// \param HeaderDir The directory at which we
+ ///
+ /// \returns true if an error occurred.
+ bool loadAPINotes(const DirectoryEntry *HeaderDir,
+ const FileEntry *APINotesFile);
+
+ /// Look for API notes in the given directory.
+ ///
+ /// This might find either a binary or source API notes.
+ const FileEntry *findAPINotesFile(const DirectoryEntry *directory,
+ StringRef filename,
+ bool wantPublic = true);
+
+ /// Attempt to load API notes for the given framework.
+ ///
+ /// \param FrameworkPath The path to the framework.
+ /// \param Public Whether to load the public API notes. Otherwise, attempt
+ /// to load the private API notes.
+ ///
+ /// \returns the header directory entry (e.g., for Headers or PrivateHeaders)
+ /// for which the API notes were successfully loaded, or NULL if API notes
+ /// could not be loaded for any reason.
+ const DirectoryEntry *loadFrameworkAPINotes(llvm::StringRef FrameworkPath,
+ llvm::StringRef FrameworkName,
+ bool Public);
+
+public:
+ APINotesManager(SourceManager &sourceMgr, const LangOptions &langOpts);
+ ~APINotesManager();
+
+ /// Set the Swift version to use when filtering API notes.
+ void setSwiftVersion(VersionTuple swiftVersion) {
+ SwiftVersion = swiftVersion;
+ }
+
+ /// Load the API notes for the current module.
+ ///
+ /// \param module The current module.
+ /// \param lookInModule Whether to look inside the module itself.
+ /// \param searchPaths The paths in which we should search for API notes
+ /// for the current module.
+ ///
+ /// \returns true if API notes were successfully loaded, \c false otherwise.
+ bool loadCurrentModuleAPINotes(const Module *module,
+ bool lookInModule,
+ ArrayRef<std::string> searchPaths);
+
+ /// Retrieve the set of API notes readers for the current module.
+ ArrayRef<APINotesReader *> getCurrentModuleReaders() const {
+ unsigned numReaders = static_cast<unsigned>(CurrentModuleReaders[0] != nullptr) +
+ static_cast<unsigned>(CurrentModuleReaders[1] != nullptr);
+ return llvm::makeArrayRef(CurrentModuleReaders).slice(0, numReaders);
+ }
+
+ /// Find the API notes readers that correspond to the given source location.
+ llvm::SmallVector<APINotesReader *, 2> findAPINotes(SourceLocation Loc);
+};
+
+} // end namespace api_notes
+} // end namespace clang
+
+#endif
diff --git a/include/clang/APINotes/APINotesOptions.h b/include/clang/APINotes/APINotesOptions.h
new file mode 100644
index 0000000..24bb913
--- /dev/null
+++ b/include/clang/APINotes/APINotesOptions.h
@@ -0,0 +1,41 @@
+//===--- APINotesOptions.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the APINotesOptions class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_APINOTES_APINOTESOPTIONS_H
+#define LLVM_CLANG_APINOTES_APINOTESOPTIONS_H
+
+#include "clang/Basic/VersionTuple.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+
+/// APINotesOptions - Track various options which control how API
+/// notes are found and handled.
+class APINotesOptions {
+public:
+ /// The Swift version which should be used for API notes.
+ VersionTuple SwiftVersion;
+
+ /// The set of search paths where we API notes can be found for
+ /// particular modules.
+ ///
+ /// The API notes in this directory are stored as
+ /// <ModuleName>.apinotes or <ModuleName>.apinotesc, and are only
+ /// applied when building the module <ModuleName>.
+ std::vector<std::string> ModuleSearchPaths;
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/APINotes/APINotesReader.h b/include/clang/APINotes/APINotesReader.h
new file mode 100644
index 0000000..2b985c6
--- /dev/null
+++ b/include/clang/APINotes/APINotesReader.h
@@ -0,0 +1,291 @@
+//===--- APINotesReader.h - API Notes Reader ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the \c APINotesReader class that reads source
+// API notes data providing additional information about source code as
+// a separate input, such as the non-nil/nilable annotations for
+// method parameters.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_API_NOTES_READER_H
+#define LLVM_CLANG_API_NOTES_READER_H
+
+#include "clang/APINotes/Types.h"
+#include "clang/Basic/VersionTuple.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <memory>
+
+namespace clang {
+namespace api_notes {
+
+/// Describes the role of a specific bit of versioned information.
+enum class VersionedInfoRole : unsigned {
+ /// Augment the AST, but do not override information explicitly specified
+ /// in the source code.
+ AugmentSource,
+
+ /// Replace information that may have been explicitly specified in the source
+ /// code.
+ ReplaceSource,
+
+ /// Describes an alternate version of this information.
+ Versioned,
+};
+
+/// A class that reads API notes data from a binary file that was written by
+/// the \c APINotesWriter.
+class APINotesReader {
+ class Implementation;
+
+ Implementation &Impl;
+
+ APINotesReader(llvm::MemoryBuffer *inputBuffer, bool ownsInputBuffer,
+ VersionTuple swiftVersion, bool &failed);
+
+public:
+ /// Create a new API notes reader from the given member buffer, which
+ /// contains the contents of a binary API notes file.
+ ///
+ /// \returns the new API notes reader, or null if an error occurred.
+ static std::unique_ptr<APINotesReader>
+ get(std::unique_ptr<llvm::MemoryBuffer> inputBuffer,
+ VersionTuple swiftVersion);
+
+ /// Create a new API notes reader from the given member buffer, which
+ /// contains the contents of a binary API notes file.
+ ///
+ /// \returns the new API notes reader, or null if an error occurred.
+ static std::unique_ptr<APINotesReader>
+ getUnmanaged(llvm::MemoryBuffer *inputBuffer,
+ VersionTuple swiftVersion);
+
+ ~APINotesReader();
+
+ APINotesReader(const APINotesReader &) = delete;
+ APINotesReader &operator=(const APINotesReader &) = delete;
+
+ /// Retrieve the name of the module for which this reader is providing API
+ /// notes.
+ StringRef getModuleName() const;
+
+ /// Retrieve the size and modification time of the source file from
+ /// which this API notes file was created, if known.
+ Optional<std::pair<off_t, time_t>> getSourceFileSizeAndModTime() const;
+
+ /// Retrieve the module options
+ ModuleOptions getModuleOptions() const;
+
+ /// Captures the completed versioned information for a particular part of
+ /// API notes, including both unversioned API notes and each versioned API
+ /// note for that particular entity.
+ template<typename T>
+ class VersionedInfo {
+ /// The complete set of results.
+ SmallVector<std::pair<VersionTuple, T>, 1> Results;
+
+ /// The index of the result that is the "selected" set based on the desired
+ /// Swift version, or \c Results.size() if nothing matched.
+ unsigned Selected;
+
+ /// The role of the selected index.
+ VersionedInfoRole SelectedRole;
+
+ public:
+ /// Form an empty set of versioned information.
+ VersionedInfo(llvm::NoneType) : Selected(0) { }
+
+ /// Form a versioned info set given the desired version and a set of
+ /// results.
+ VersionedInfo(VersionTuple version,
+ SmallVector<std::pair<VersionTuple, T>, 1> results);
+
+ /// Determine whether there is a result that should be applied directly
+ /// to the AST.
+ explicit operator bool() const { return Selected != size(); }
+
+ /// Retrieve the information to apply directly to the AST.
+ const T& operator*() const {
+ assert(*this && "No result to apply directly");
+ return (*this)[Selected].second;
+ }
+
+ /// Retrieve the selected index in the result set.
+ Optional<unsigned> getSelected() const {
+ if (Selected == Results.size()) return None;
+ return Selected;
+ }
+
+ /// Describes the role of the selected entity.
+ VersionedInfoRole getSelectedRole() const {
+ return SelectedRole;
+ }
+
+ /// Return the number of versioned results we know about.
+ unsigned size() const { return Results.size(); }
+
+ /// Access all versioned results.
+ const std::pair<VersionTuple, T> *begin() const { return Results.begin(); }
+ const std::pair<VersionTuple, T> *end() const { return Results.end(); }
+
+ /// Access a specific versioned result.
+ const std::pair<VersionTuple, T> &operator[](unsigned index) const {
+ return Results[index];
+ }
+ };
+
+ /// Look for the context ID of the given Objective-C class.
+ ///
+ /// \param name The name of the class we're looking for.
+ ///
+ /// \returns The ID, if known.
+ Optional<ContextID> lookupObjCClassID(StringRef name);
+
+ /// Look for information regarding the given Objective-C class.
+ ///
+ /// \param name The name of the class we're looking for.
+ ///
+ /// \returns The information about the class, if known.
+ VersionedInfo<ObjCContextInfo> lookupObjCClassInfo(StringRef name);
+
+ /// Look for the context ID of the given Objective-C protocol.
+ ///
+ /// \param name The name of the protocol we're looking for.
+ ///
+ /// \returns The ID of the protocol, if known.
+ Optional<ContextID> lookupObjCProtocolID(StringRef name);
+
+ /// Look for information regarding the given Objective-C protocol.
+ ///
+ /// \param name The name of the protocol we're looking for.
+ ///
+ /// \returns The information about the protocol, if known.
+ VersionedInfo<ObjCContextInfo> lookupObjCProtocolInfo(StringRef name);
+
+ /// Look for information regarding the given Objective-C property in
+ /// the given context.
+ ///
+ /// \param contextID The ID that references the context we are looking for.
+ /// \param name The name of the property we're looking for.
+ /// \param isInstance Whether we are looking for an instance property (vs.
+ /// a class property).
+ ///
+ /// \returns Information about the property, if known.
+ VersionedInfo<ObjCPropertyInfo> lookupObjCProperty(ContextID contextID,
+ StringRef name,
+ bool isInstance);
+
+ /// Look for information regarding the given Objective-C method in
+ /// the given context.
+ ///
+ /// \param contextID The ID that references the context we are looking for.
+ /// \param selector The selector naming the method we're looking for.
+ /// \param isInstanceMethod Whether we are looking for an instance method.
+ ///
+ /// \returns Information about the method, if known.
+ VersionedInfo<ObjCMethodInfo> lookupObjCMethod(ContextID contextID,
+ ObjCSelectorRef selector,
+ bool isInstanceMethod);
+
+ /// Look for information regarding the given global variable.
+ ///
+ /// \param name The name of the global variable.
+ ///
+ /// \returns information about the global variable, if known.
+ VersionedInfo<GlobalVariableInfo> lookupGlobalVariable(StringRef name);
+
+ /// Look for information regarding the given global function.
+ ///
+ /// \param name The name of the global function.
+ ///
+ /// \returns information about the global function, if known.
+ VersionedInfo<GlobalFunctionInfo> lookupGlobalFunction(StringRef name);
+
+ /// Look for information regarding the given enumerator.
+ ///
+ /// \param name The name of the enumerator.
+ ///
+ /// \returns information about the enumerator, if known.
+ VersionedInfo<EnumConstantInfo> lookupEnumConstant(StringRef name);
+
+ /// Look for information regarding the given tag
+ /// (struct/union/enum/C++ class).
+ ///
+ /// \param name The name of the tag.
+ ///
+ /// \returns information about the tag, if known.
+ VersionedInfo<TagInfo> lookupTag(StringRef name);
+
+ /// Look for information regarding the given typedef.
+ ///
+ /// \param name The name of the typedef.
+ ///
+ /// \returns information about the typedef, if known.
+ VersionedInfo<TypedefInfo> lookupTypedef(StringRef name);
+
+ /// Visitor used when walking the contents of the API notes file.
+ class Visitor {
+ public:
+ virtual ~Visitor();
+
+ /// Visit an Objective-C class.
+ virtual void visitObjCClass(ContextID contextID, StringRef name,
+ const ObjCContextInfo &info,
+ VersionTuple swiftVersion);
+
+ /// Visit an Objective-C protocol.
+ virtual void visitObjCProtocol(ContextID contextID, StringRef name,
+ const ObjCContextInfo &info,
+ VersionTuple swiftVersion);
+
+ /// Visit an Objective-C method.
+ virtual void visitObjCMethod(ContextID contextID, StringRef selector,
+ bool isInstanceMethod,
+ const ObjCMethodInfo &info,
+ VersionTuple swiftVersion);
+
+ /// Visit an Objective-C property.
+ virtual void visitObjCProperty(ContextID contextID, StringRef name,
+ bool isInstance,
+ const ObjCPropertyInfo &info,
+ VersionTuple swiftVersion);
+
+ /// Visit a global variable.
+ virtual void visitGlobalVariable(StringRef name,
+ const GlobalVariableInfo &info,
+ VersionTuple swiftVersion);
+
+ /// Visit a global function.
+ virtual void visitGlobalFunction(StringRef name,
+ const GlobalFunctionInfo &info,
+ VersionTuple swiftVersion);
+
+ /// Visit an enumerator.
+ virtual void visitEnumConstant(StringRef name,
+ const EnumConstantInfo &info,
+ VersionTuple swiftVersion);
+
+ /// Visit a tag.
+ virtual void visitTag(StringRef name, const TagInfo &info,
+ VersionTuple swiftVersion);
+
+ /// Visit a typedef.
+ virtual void visitTypedef(StringRef name, const TypedefInfo &info,
+ VersionTuple swiftVersion);
+ };
+
+ /// Visit the contents of the API notes file, passing each entity to the
+ /// given visitor.
+ void visit(Visitor &visitor);
+};
+
+} // end namespace api_notes
+} // end namespace clang
+
+#endif // LLVM_CLANG_API_NOTES_READER_H
diff --git a/include/clang/APINotes/APINotesWriter.h b/include/clang/APINotes/APINotesWriter.h
new file mode 100644
index 0000000..62defc1
--- /dev/null
+++ b/include/clang/APINotes/APINotesWriter.h
@@ -0,0 +1,126 @@
+//===--- APINotesWriter.h - API Notes Writer ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the \c APINotesWriter class that writes out source
+// API notes data providing additional information about source code as
+// a separate input, such as the non-nil/nilable annotations for
+// method parameters.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_API_NOTES_WRITER_H
+#define LLVM_CLANG_API_NOTES_WRITER_H
+
+#include "clang/Basic/VersionTuple.h"
+#include "clang/APINotes/Types.h"
+
+namespace llvm {
+ class raw_ostream;
+}
+
+namespace clang {
+
+class FileEntry;
+
+namespace api_notes {
+
+/// A class that writes API notes data to a binary representation that can be
+/// read by the \c APINotesReader.
+class APINotesWriter {
+ class Implementation;
+ Implementation &Impl;
+
+public:
+ /// Create a new API notes writer with the given module name and
+ /// (optional) source file.
+ APINotesWriter(StringRef moduleName, const FileEntry *sourceFile);
+ ~APINotesWriter();
+
+ APINotesWriter(const APINotesWriter &) = delete;
+ APINotesWriter &operator=(const APINotesWriter &) = delete;
+
+ /// Write the API notes data to the given stream.
+ void writeToStream(llvm::raw_ostream &os);
+
+ /// Add information about a specific Objective-C class or protocol.
+ ///
+ /// \param name The name of this class/protocol.
+ /// \param isClass Whether this is a class (vs. a protocol).
+ /// \param info Information about this class/protocol.
+ ///
+ /// \returns the ID of the class or protocol, which can be used to add
+ /// properties and methods to the class/protocol.
+ ContextID addObjCContext(StringRef name, bool isClass,
+ const ObjCContextInfo &info,
+ VersionTuple swiftVersion);
+
+ /// Add information about a specific Objective-C property.
+ ///
+ /// \param contextID The context in which this property resides.
+ /// \param name The name of this property.
+ /// \param info Information about this property.
+ void addObjCProperty(ContextID contextID, StringRef name,
+ bool isInstanceProperty,
+ const ObjCPropertyInfo &info,
+ VersionTuple swiftVersion);
+
+ /// Add information about a specific Objective-C method.
+ ///
+ /// \param contextID The context in which this method resides.
+ /// \param selector The selector that names this method.
+ /// \param isInstanceMethod Whether this method is an instance method
+ /// (vs. a class method).
+ /// \param info Information about this method.
+ void addObjCMethod(ContextID contextID, ObjCSelectorRef selector,
+ bool isInstanceMethod, const ObjCMethodInfo &info,
+ VersionTuple swiftVersion);
+
+ /// Add information about a global variable.
+ ///
+ /// \param name The name of this global variable.
+ /// \param info Information about this global variable.
+ void addGlobalVariable(StringRef name, const GlobalVariableInfo &info,
+ VersionTuple swiftVersion);
+
+ /// Add information about a global function.
+ ///
+ /// \param name The name of this global function.
+ /// \param info Information about this global function.
+ void addGlobalFunction(StringRef name, const GlobalFunctionInfo &info,
+ VersionTuple swiftVersion);
+
+ /// Add information about an enumerator.
+ ///
+ /// \param name The name of this enumerator.
+ /// \param info Information about this enumerator.
+ void addEnumConstant(StringRef name, const EnumConstantInfo &info,
+ VersionTuple swiftVersion);
+
+ /// Add information about a tag (struct/union/enum/C++ class).
+ ///
+ /// \param name The name of this tag.
+ /// \param info Information about this tag.
+ void addTag(StringRef name, const TagInfo &info,
+ VersionTuple swiftVersion);
+
+ /// Add information about a typedef.
+ ///
+ /// \param name The name of this typedef.
+ /// \param info Information about this typedef.
+ void addTypedef(StringRef name, const TypedefInfo &info,
+ VersionTuple swiftVersion);
+
+ /// Add module options
+ void addModuleOptions(ModuleOptions opts);
+};
+
+} // end namespace api_notes
+} // end namespace clang
+
+#endif // LLVM_CLANG_API_NOTES_WRITER_H
+
diff --git a/include/clang/APINotes/APINotesYAMLCompiler.h b/include/clang/APINotes/APINotesYAMLCompiler.h
new file mode 100644
index 0000000..508da65
--- /dev/null
+++ b/include/clang/APINotes/APINotesYAMLCompiler.h
@@ -0,0 +1,62 @@
+//=== APINotesYAMLCompiler.h - API Notes YAML to binary compiler *- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file reads sidecar API notes specified in YAML format.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_API_NOTES_YAML_COMPILER_H
+#define LLVM_CLANG_API_NOTES_YAML_COMPILER_H
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/SourceMgr.h"
+#include <memory>
+
+namespace llvm {
+ class raw_ostream;
+ class MemoryBuffer;
+}
+
+namespace clang {
+
+class FileEntry;
+
+namespace api_notes {
+
+ enum class ActionType {
+ None,
+ YAMLToBinary,
+ BinaryToYAML,
+ Dump,
+ };
+
+ enum class OSType {
+ OSX,
+ IOS,
+ TvOS,
+ WatchOS,
+ Absent
+ };
+
+ /// Converts API notes from YAML format to binary format.
+ bool compileAPINotes(llvm::StringRef yamlInput,
+ const FileEntry *sourceFile,
+ llvm::raw_ostream &os,
+ OSType targetOS,
+ llvm::SourceMgr::DiagHandlerTy diagHandler = nullptr,
+ void *diagHandlerCtxt = nullptr);
+
+ bool parseAndDumpAPINotes(llvm::StringRef yamlInput);
+
+ /// Converts API notes from the compiled binary format to the YAML format.
+ bool decompileAPINotes(std::unique_ptr<llvm::MemoryBuffer> input,
+ llvm::raw_ostream &os);
+} // end namespace api_notes
+} // end namespace clang
+
+#endif // LLVM_CLANG_API_NOTES_YAML_COMPILER_H
diff --git a/include/clang/APINotes/Types.h b/include/clang/APINotes/Types.h
new file mode 100644
index 0000000..6fbd5d8
--- /dev/null
+++ b/include/clang/APINotes/Types.h
@@ -0,0 +1,658 @@
+//===--- Types.h - API Notes Data Types --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines data types used in the representation of API notes data.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_API_NOTES_TYPES_H
+#define LLVM_CLANG_API_NOTES_TYPES_H
+#include "clang/Basic/Specifiers.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include <cassert>
+#include <climits>
+
+namespace llvm {
+ class raw_ostream;
+}
+
+namespace clang {
+namespace api_notes {
+
+/// The file extension used for the source representation of API notes.
+static const char SOURCE_APINOTES_EXTENSION[] = "apinotes";
+
+/// The file extension used for the binary representation of API notes.
+static const char BINARY_APINOTES_EXTENSION[] = "apinotesc";
+
+using llvm::ArrayRef;
+using llvm::StringRef;
+using llvm::Optional;
+using llvm::None;
+
+/// Describes whether to classify a factory method as an initializer.
+enum class FactoryAsInitKind {
+ /// Infer based on name and type (the default).
+ Infer,
+ /// Treat as a class method.
+ AsClassMethod,
+ /// Treat as an initializer.
+ AsInitializer
+};
+
+/// Opaque context ID used to refer to an Objective-C class or protocol.
+class ContextID {
+public:
+ unsigned Value;
+
+ explicit ContextID(unsigned value) : Value(value) { }
+};
+
+/// Describes API notes data for any entity.
+///
+/// This is used as the base of all API notes.
+class CommonEntityInfo {
+public:
+ /// Message to use when this entity is unavailable.
+ std::string UnavailableMsg;
+
+ /// Whether this entity is marked unavailable.
+ unsigned Unavailable : 1;
+
+ /// Whether this entity is marked unavailable in Swift.
+ unsigned UnavailableInSwift : 1;
+
+private:
+ /// Whether SwiftPrivate was specified.
+ unsigned SwiftPrivateSpecified : 1;
+
+ /// Whether this entity is considered "private" to a Swift overlay.
+ unsigned SwiftPrivate : 1;
+
+public:
+ /// Swift name of this entity.
+ std::string SwiftName;
+
+ CommonEntityInfo()
+ : Unavailable(0), UnavailableInSwift(0), SwiftPrivateSpecified(0),
+ SwiftPrivate(0) { }
+
+ Optional<bool> isSwiftPrivate() const {
+ if (!SwiftPrivateSpecified) return None;
+ return SwiftPrivate;
+ }
+
+ void setSwiftPrivate(Optional<bool> swiftPrivate) {
+ if (swiftPrivate) {
+ SwiftPrivateSpecified = 1;
+ SwiftPrivate = *swiftPrivate;
+ } else {
+ SwiftPrivateSpecified = 0;
+ SwiftPrivate = 0;
+ }
+ }
+
+ friend bool operator==(const CommonEntityInfo &lhs,
+ const CommonEntityInfo &rhs) {
+ return lhs.UnavailableMsg == rhs.UnavailableMsg &&
+ lhs.Unavailable == rhs.Unavailable &&
+ lhs.UnavailableInSwift == rhs.UnavailableInSwift &&
+ lhs.SwiftPrivateSpecified == rhs.SwiftPrivateSpecified &&
+ lhs.SwiftPrivate == rhs.SwiftPrivate &&
+ lhs.SwiftName == rhs.SwiftName;
+ }
+
+ friend bool operator!=(const CommonEntityInfo &lhs,
+ const CommonEntityInfo &rhs) {
+ return !(lhs == rhs);
+ }
+
+ friend CommonEntityInfo &operator|=(CommonEntityInfo &lhs,
+ const CommonEntityInfo &rhs) {
+ // Merge unavailability.
+ if (rhs.Unavailable) {
+ lhs.Unavailable = true;
+ if (rhs.UnavailableMsg.length() != 0 &&
+ lhs.UnavailableMsg.length() == 0) {
+ lhs.UnavailableMsg = rhs.UnavailableMsg;
+ }
+ }
+
+ if (rhs.UnavailableInSwift) {
+ lhs.UnavailableInSwift = true;
+ if (rhs.UnavailableMsg.length() != 0 &&
+ lhs.UnavailableMsg.length() == 0) {
+ lhs.UnavailableMsg = rhs.UnavailableMsg;
+ }
+ }
+
+ if (rhs.SwiftPrivateSpecified && !lhs.SwiftPrivateSpecified) {
+ lhs.SwiftPrivateSpecified = 1;
+ lhs.SwiftPrivate = rhs.SwiftPrivate;
+ }
+
+ if (rhs.SwiftName.length() != 0 &&
+ lhs.SwiftName.length() == 0)
+ lhs.SwiftName = rhs.SwiftName;
+
+ return lhs;
+ }
+};
+
+/// Describes API notes for types.
+class CommonTypeInfo : public CommonEntityInfo {
+ /// The Swift type to which a given type is bridged.
+ ///
+ /// Reflects the swift_bridge attribute.
+ Optional<std::string> SwiftBridge;
+
+ /// The NS error domain for this type.
+ Optional<std::string> NSErrorDomain;
+
+public:
+ CommonTypeInfo() : CommonEntityInfo() { }
+
+ const Optional<std::string> &getSwiftBridge() const { return SwiftBridge; }
+
+ void setSwiftBridge(const Optional<std::string> &swiftType) {
+ SwiftBridge = swiftType;
+ }
+
+ void setSwiftBridge(const Optional<StringRef> &swiftType) {
+ if (swiftType)
+ SwiftBridge = *swiftType;
+ else
+ SwiftBridge = None;
+ }
+
+ const Optional<std::string> &getNSErrorDomain() const {
+ return NSErrorDomain;
+ }
+
+ void setNSErrorDomain(const Optional<std::string> &domain) {
+ NSErrorDomain = domain;
+ }
+
+ void setNSErrorDomain(const Optional<StringRef> &domain) {
+ if (domain)
+ NSErrorDomain = *domain;
+ else
+ NSErrorDomain = None;
+ }
+
+ friend CommonTypeInfo &operator|=(CommonTypeInfo &lhs,
+ const CommonTypeInfo &rhs) {
+ static_cast<CommonEntityInfo &>(lhs) |= rhs;
+ if (!lhs.SwiftBridge && rhs.SwiftBridge)
+ lhs.SwiftBridge = rhs.SwiftBridge;
+ if (!lhs.NSErrorDomain && rhs.NSErrorDomain)
+ lhs.NSErrorDomain = rhs.NSErrorDomain;
+ return lhs;
+ }
+
+ friend bool operator==(const CommonTypeInfo &lhs,
+ const CommonTypeInfo &rhs) {
+ return static_cast<const CommonEntityInfo &>(lhs) == rhs &&
+ lhs.SwiftBridge == rhs.SwiftBridge &&
+ lhs.NSErrorDomain == rhs.NSErrorDomain;
+ }
+
+ friend bool operator!=(const CommonTypeInfo &lhs,
+ const CommonTypeInfo &rhs) {
+ return !(lhs == rhs);
+ }
+};
+
+/// Describes API notes data for an Objective-C class or protocol.
+class ObjCContextInfo : public CommonTypeInfo {
+ /// Whether this class has a default nullability.
+ unsigned HasDefaultNullability : 1;
+
+ /// The default nullability.
+ unsigned DefaultNullability : 2;
+
+ /// Whether this class has designated initializers recorded.
+ unsigned HasDesignatedInits : 1;
+
+public:
+ ObjCContextInfo()
+ : CommonTypeInfo(),
+ HasDefaultNullability(0),
+ DefaultNullability(0),
+ HasDesignatedInits(0)
+ { }
+
+ /// Determine the default nullability for properties and methods of this
+ /// class.
+ ///
+ /// \returns the default nullability, if implied, or None if there is no
+ Optional<NullabilityKind> getDefaultNullability() const {
+ if (HasDefaultNullability)
+ return static_cast<NullabilityKind>(DefaultNullability);
+
+ return None;
+ }
+
+ /// Set the default nullability for properties and methods of this class.
+ void setDefaultNullability(NullabilityKind kind) {
+ HasDefaultNullability = true;
+ DefaultNullability = static_cast<unsigned>(kind);
+ }
+
+ bool hasDesignatedInits() const { return HasDesignatedInits; }
+ void setHasDesignatedInits(bool value) { HasDesignatedInits = value; }
+
+ /// Strip off any information within the class information structure that is
+ /// module-local, such as 'audited' flags.
+ void stripModuleLocalInfo() {
+ HasDefaultNullability = false;
+ DefaultNullability = 0;
+ }
+
+ friend bool operator==(const ObjCContextInfo &lhs, const ObjCContextInfo &rhs) {
+ return static_cast<const CommonTypeInfo &>(lhs) == rhs &&
+ lhs.HasDefaultNullability == rhs.HasDefaultNullability &&
+ lhs.DefaultNullability == rhs.DefaultNullability &&
+ lhs.HasDesignatedInits == rhs.HasDesignatedInits;
+ }
+
+ friend bool operator!=(const ObjCContextInfo &lhs, const ObjCContextInfo &rhs) {
+ return !(lhs == rhs);
+ }
+
+ friend ObjCContextInfo &operator|=(ObjCContextInfo &lhs,
+ const ObjCContextInfo &rhs) {
+ // Merge inherited info.
+ static_cast<CommonTypeInfo &>(lhs) |= rhs;
+
+ // Merge nullability.
+ if (!lhs.getDefaultNullability()) {
+ if (auto nullable = rhs.getDefaultNullability()) {
+ lhs.setDefaultNullability(*nullable);
+ }
+ }
+
+ lhs.HasDesignatedInits |= rhs.HasDesignatedInits;
+
+ return lhs;
+ }
+
+ void dump(llvm::raw_ostream &os);
+};
+
+/// API notes for a variable/property.
+class VariableInfo : public CommonEntityInfo {
+ /// Whether this property has been audited for nullability.
+ unsigned NullabilityAudited : 1;
+
+ /// The kind of nullability for this property. Only valid if the nullability
+ /// has been audited.
+ unsigned Nullable : 2;
+
+ /// The C type of the variable, as a string.
+ std::string Type;
+
+public:
+ VariableInfo()
+ : CommonEntityInfo(),
+ NullabilityAudited(false),
+ Nullable(0) { }
+
+ Optional<NullabilityKind> getNullability() const {
+ if (NullabilityAudited)
+ return static_cast<NullabilityKind>(Nullable);
+
+ return None;
+ }
+
+ void setNullabilityAudited(NullabilityKind kind) {
+ NullabilityAudited = true;
+ Nullable = static_cast<unsigned>(kind);
+ }
+
+ const std::string &getType() const { return Type; }
+ void setType(const std::string &type) { Type = type; }
+
+ friend bool operator==(const VariableInfo &lhs, const VariableInfo &rhs) {
+ return static_cast<const CommonEntityInfo &>(lhs) == rhs &&
+ lhs.NullabilityAudited == rhs.NullabilityAudited &&
+ lhs.Nullable == rhs.Nullable &&
+ lhs.Type == rhs.Type;
+ }
+
+ friend bool operator!=(const VariableInfo &lhs, const VariableInfo &rhs) {
+ return !(lhs == rhs);
+ }
+
+ friend VariableInfo &operator|=(VariableInfo &lhs,
+ const VariableInfo &rhs) {
+ static_cast<CommonEntityInfo &>(lhs) |= rhs;
+ if (!lhs.NullabilityAudited && rhs.NullabilityAudited)
+ lhs.setNullabilityAudited(*rhs.getNullability());
+ if (lhs.Type.empty() && !rhs.Type.empty())
+ lhs.Type = rhs.Type;
+ return lhs;
+ }
+};
+
+/// Describes API notes data for an Objective-C property.
+class ObjCPropertyInfo : public VariableInfo {
+ unsigned SwiftImportAsAccessorsSpecified : 1;
+ unsigned SwiftImportAsAccessors : 1;
+
+public:
+ ObjCPropertyInfo()
+ : VariableInfo(), SwiftImportAsAccessorsSpecified(false),
+ SwiftImportAsAccessors(false) {}
+
+ /// Merge class-wide information into the given property.
+ friend ObjCPropertyInfo &operator|=(ObjCPropertyInfo &lhs,
+ const ObjCContextInfo &rhs) {
+ static_cast<VariableInfo &>(lhs) |= rhs;
+
+ // Merge nullability.
+ if (!lhs.getNullability()) {
+ if (auto nullable = rhs.getDefaultNullability()) {
+ lhs.setNullabilityAudited(*nullable);
+ }
+ }
+
+ return lhs;
+ }
+
+ Optional<bool> getSwiftImportAsAccessors() const {
+ if (SwiftImportAsAccessorsSpecified)
+ return SwiftImportAsAccessors;
+ return None;
+ }
+ void setSwiftImportAsAccessors(Optional<bool> value) {
+ if (value.hasValue()) {
+ SwiftImportAsAccessorsSpecified = true;
+ SwiftImportAsAccessors = value.getValue();
+ } else {
+ SwiftImportAsAccessorsSpecified = false;
+ SwiftImportAsAccessors = false;
+ }
+ }
+
+ friend ObjCPropertyInfo &operator|=(ObjCPropertyInfo &lhs,
+ const ObjCPropertyInfo &rhs) {
+ lhs |= static_cast<const VariableInfo &>(rhs);
+ if (!lhs.SwiftImportAsAccessorsSpecified &&
+ rhs.SwiftImportAsAccessorsSpecified) {
+ lhs.SwiftImportAsAccessorsSpecified = true;
+ lhs.SwiftImportAsAccessors = rhs.SwiftImportAsAccessors;
+ }
+ return lhs;
+ }
+};
+
+/// Describes a function or method parameter.
+class ParamInfo : public VariableInfo {
+ /// Whether noescape was specified.
+ unsigned NoEscapeSpecified : 1;
+
+ /// Whether the this parameter has the 'noescape' attribute.
+ unsigned NoEscape : 1;
+
+public:
+ ParamInfo() : VariableInfo(), NoEscapeSpecified(false), NoEscape(false) { }
+
+ Optional<bool> isNoEscape() const {
+ if (!NoEscapeSpecified) return None;
+ return NoEscape;
+ }
+ void setNoEscape(Optional<bool> noescape) {
+ if (noescape) {
+ NoEscapeSpecified = true;
+ NoEscape = *noescape;
+ } else {
+ NoEscapeSpecified = false;
+ NoEscape = false;
+ }
+ }
+
+ friend ParamInfo &operator|=(ParamInfo &lhs, const ParamInfo &rhs) {
+ static_cast<VariableInfo &>(lhs) |= rhs;
+ if (!lhs.NoEscapeSpecified && rhs.NoEscapeSpecified) {
+ lhs.NoEscapeSpecified = true;
+ lhs.NoEscape = rhs.NoEscape;
+ }
+ return lhs;
+ }
+
+ friend bool operator==(const ParamInfo &lhs, const ParamInfo &rhs) {
+ return static_cast<const VariableInfo &>(lhs) == rhs &&
+ lhs.NoEscapeSpecified == rhs.NoEscapeSpecified &&
+ lhs.NoEscape == rhs.NoEscape;
+ }
+
+ friend bool operator!=(const ParamInfo &lhs, const ParamInfo &rhs) {
+ return !(lhs == rhs);
+ }
+};
+
+/// A temporary reference to an Objective-C selector, suitable for
+/// referencing selector data on the stack.
+///
+/// Instances of this struct do not store references to any of the
+/// data they contain; it is up to the user to ensure that the data
+/// referenced by the identifier list persists.
+struct ObjCSelectorRef {
+ unsigned NumPieces;
+ ArrayRef<StringRef> Identifiers;
+};
+
+/// API notes for a function or method.
+class FunctionInfo : public CommonEntityInfo {
+private:
+ static unsigned const NullabilityKindMask = 0x3;
+ static unsigned const NullabilityKindSize = 2;
+
+public:
+ /// Whether the signature has been audited with respect to nullability.
+ /// If yes, we consider all types to be non-nullable unless otherwise noted.
+ /// If this flag is not set, the pointer types are considered to have
+ /// unknown nullability.
+ unsigned NullabilityAudited : 1;
+
+ /// Number of types whose nullability is encoded with the NullabilityPayload.
+ unsigned NumAdjustedNullable : 8;
+
+ /// Stores the nullability of the return type and the parameters.
+ // NullabilityKindSize bits are used to encode the nullability. The info
+ // about the return type is stored at position 0, followed by the nullability
+ // of the parameters.
+ uint64_t NullabilityPayload = 0;
+
+ /// The result type of this function, as a C type.
+ std::string ResultType;
+
+ /// The function parameters.
+ std::vector<ParamInfo> Params;
+
+ FunctionInfo()
+ : CommonEntityInfo(),
+ NullabilityAudited(false),
+ NumAdjustedNullable(0) { }
+
+ static unsigned getMaxNullabilityIndex() {
+ return ((sizeof(NullabilityPayload) * CHAR_BIT)/NullabilityKindSize);
+ }
+
+ void addTypeInfo(unsigned index, NullabilityKind kind) {
+ assert(index <= getMaxNullabilityIndex());
+ assert(static_cast<unsigned>(kind) < NullabilityKindMask);
+ NullabilityAudited = true;
+ if (NumAdjustedNullable < index + 1)
+ NumAdjustedNullable = index + 1;
+
+ // Mask the bits.
+ NullabilityPayload &= ~(NullabilityKindMask << (index * NullabilityKindSize));
+
+ // Set the value.
+ unsigned kindValue =
+ (static_cast<unsigned>(kind)) << (index * NullabilityKindSize);
+ NullabilityPayload |= kindValue;
+ }
+
+ /// Adds the return type info.
+ void addReturnTypeInfo(NullabilityKind kind) {
+ addTypeInfo(0, kind);
+ }
+
+ /// Adds the parameter type info.
+ void addParamTypeInfo(unsigned index, NullabilityKind kind) {
+ addTypeInfo(index + 1, kind);
+ }
+
+private:
+ NullabilityKind getTypeInfo(unsigned index) const {
+ assert(NullabilityAudited &&
+ "Checking the type adjustment on non-audited method.");
+ // If we don't have info about this parameter, return the default.
+ if (index > NumAdjustedNullable)
+ return NullabilityKind::NonNull;
+ return static_cast<NullabilityKind>(( NullabilityPayload
+ >> (index * NullabilityKindSize) )
+ & NullabilityKindMask);
+ }
+
+public:
+ NullabilityKind getParamTypeInfo(unsigned index) const {
+ return getTypeInfo(index + 1);
+ }
+
+ NullabilityKind getReturnTypeInfo() const {
+ return getTypeInfo(0);
+ }
+
+ friend bool operator==(const FunctionInfo &lhs, const FunctionInfo &rhs) {
+ return static_cast<const CommonEntityInfo &>(lhs) == rhs &&
+ lhs.NullabilityAudited == rhs.NullabilityAudited &&
+ lhs.NumAdjustedNullable == rhs.NumAdjustedNullable &&
+ lhs.NullabilityPayload == rhs.NullabilityPayload &&
+ lhs.ResultType == rhs.ResultType &&
+ lhs.Params == rhs.Params;
+ }
+
+ friend bool operator!=(const FunctionInfo &lhs, const FunctionInfo &rhs) {
+ return !(lhs == rhs);
+ }
+
+};
+
+/// Describes API notes data for an Objective-C method.
+class ObjCMethodInfo : public FunctionInfo {
+public:
+ /// Whether this is a designated initializer of its class.
+ unsigned DesignatedInit : 1;
+
+ /// Whether to treat this method as a factory or initializer.
+ unsigned FactoryAsInit : 2;
+
+ /// Whether this is a required initializer.
+ unsigned Required : 1;
+
+ ObjCMethodInfo()
+ : FunctionInfo(),
+ DesignatedInit(false),
+ FactoryAsInit(static_cast<unsigned>(FactoryAsInitKind::Infer)),
+ Required(false) { }
+
+ FactoryAsInitKind getFactoryAsInitKind() const {
+ return static_cast<FactoryAsInitKind>(FactoryAsInit);
+ }
+
+ void setFactoryAsInitKind(FactoryAsInitKind kind) {
+ FactoryAsInit = static_cast<unsigned>(kind);
+ }
+
+ friend bool operator==(const ObjCMethodInfo &lhs, const ObjCMethodInfo &rhs) {
+ return static_cast<const FunctionInfo &>(lhs) == rhs &&
+ lhs.DesignatedInit == rhs.DesignatedInit &&
+ lhs.FactoryAsInit == rhs.FactoryAsInit &&
+ lhs.Required == rhs.Required;
+ }
+
+ friend bool operator!=(const ObjCMethodInfo &lhs, const ObjCMethodInfo &rhs) {
+ return !(lhs == rhs);
+ }
+
+ void mergePropInfoIntoSetter(const ObjCPropertyInfo &pInfo);
+
+ void mergePropInfoIntoGetter(const ObjCPropertyInfo &pInfo);
+
+ /// Merge class-wide information into the given method.
+ friend ObjCMethodInfo &operator|=(ObjCMethodInfo &lhs,
+ const ObjCContextInfo &rhs) {
+ // Merge nullability.
+ if (!lhs.NullabilityAudited) {
+ if (auto nullable = rhs.getDefaultNullability()) {
+ lhs.NullabilityAudited = true;
+ lhs.addTypeInfo(0, *nullable);
+ }
+ }
+
+ return lhs;
+ }
+
+ void dump(llvm::raw_ostream &os);
+};
+
+/// Describes API notes data for a global variable.
+class GlobalVariableInfo : public VariableInfo {
+public:
+ GlobalVariableInfo() : VariableInfo() { }
+};
+
+/// Describes API notes data for a global function.
+class GlobalFunctionInfo : public FunctionInfo {
+public:
+ GlobalFunctionInfo() : FunctionInfo() { }
+};
+
+/// Describes API notes data for an enumerator.
+class EnumConstantInfo : public CommonEntityInfo {
+public:
+ EnumConstantInfo() : CommonEntityInfo() { }
+};
+
+/// Describes API notes data for a tag.
+class TagInfo : public CommonTypeInfo {
+public:
+ TagInfo() : CommonTypeInfo() { }
+};
+
+/// The kind of a swift_wrapper/swift_newtype.
+enum class SwiftWrapperKind {
+ None,
+ Struct,
+ Enum
+};
+
+/// Describes API notes data for a typedef.
+class TypedefInfo : public CommonTypeInfo {
+public:
+ Optional<SwiftWrapperKind> SwiftWrapper;
+
+ TypedefInfo() : CommonTypeInfo() { }
+};
+
+/// Descripts a series of options for a module
+struct ModuleOptions {
+ bool SwiftInferImportAsMember = false;
+};
+
+} // end namespace api_notes
+} // end namespace clang
+
+#endif // LLVM_CLANG_API_NOTES_TYPES_H
diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h
index bbe320c..58566db 100644
--- a/include/clang/AST/Attr.h
+++ b/include/clang/AST/Attr.h
@@ -24,6 +24,7 @@
#include "clang/Basic/Sanitizers.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/VersionTuple.h"
+#include "llvm/ADT/PointerEmbeddedInt.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/include/clang/AST/AttrIterator.h b/include/clang/AST/AttrIterator.h
index fb9b049..5ef250c 100644
--- a/include/clang/AST/AttrIterator.h
+++ b/include/clang/AST/AttrIterator.h
@@ -108,6 +108,8 @@
specific_attr_iterator Right) {
return !(Left == Right);
}
+
+ Iterator getCurrent() const { return Current; }
};
template <typename SpecificAttr, typename Container>
diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
index fa60d51..a4a88d0 100644
--- a/include/clang/Basic/Attr.td
+++ b/include/clang/Basic/Attr.td
@@ -87,6 +87,9 @@
def NonBitField : SubsetSubject<Field,
[{!S->isBitField()}]>;
+def ObjCClassMethod : SubsetSubject<ObjCMethod,
+ [{!S->isInstanceMethod()}]>;
+
def ObjCInstanceMethod : SubsetSubject<ObjCMethod,
[{S->isInstanceMethod()}]>;
@@ -192,6 +195,9 @@
list<string> Enums = enums;
}
+// Represents an attribute wrapped by another attribute.
+class AttrArgument<string name, bit opt = 0> : Argument<name, opt>;
+
// This handles one spelling of an attribute.
class Spelling<string name, string variety> {
string Name = name;
@@ -505,6 +511,7 @@
.Case("macos_app_extension", "macOS (App Extension)")
.Case("tvos_app_extension", "tvOS (App Extension)")
.Case("watchos_app_extension", "watchOS (App Extension)")
+ .Case("swift", "Swift")
.Default(llvm::StringRef());
} }];
let HasCustomParsing = 1;
@@ -1171,6 +1178,12 @@
let Documentation = [Undocumented];
}
+def NoEscape : InheritableAttr {
+ let Spellings = [GCC<"noescape">];
+ let Subjects = SubjectList<[ParmVar], WarnDiag, "ExpectedParameter">;
+ let Documentation = [Undocumented];
+}
+
def AssumeAligned : InheritableAttr {
let Spellings = [GCC<"assume_aligned">];
let Subjects = SubjectList<[ObjCMethod, Function]>;
@@ -1233,6 +1246,12 @@
let Documentation = [Undocumented];
}
+def NSErrorDomain : Attr {
+ let Spellings = [GNU<"ns_error_domain">];
+ let Args = [IdentifierArgument<"ErrorDomain">];
+ let Documentation = [NSErrorDomainDocs];
+}
+
def NSReturnsRetained : InheritableAttr {
let Spellings = [GNU<"ns_returns_retained">];
// let Subjects = SubjectList<[ObjCMethod, ObjCProperty, Function]>;
@@ -1319,6 +1338,12 @@
let Documentation = [ObjCSubclassingRestrictedDocs];
}
+def ObjCCompleteDefinition : InheritableAttr {
+ let Spellings = [GNU<"objc_complete_definition">];
+ let Subjects = SubjectList<[ObjCInterface], ErrorDiag>;
+ let Documentation = [Undocumented];
+}
+
def ObjCExplicitProtocolImpl : InheritableAttr {
let Spellings = [GNU<"objc_protocol_requires_explicit_implementation">];
let Subjects = SubjectList<[ObjCProtocol], ErrorDiag>;
@@ -1421,6 +1446,86 @@
let Documentation = [RegparmDocs];
}
+def SwiftBridge : Attr {
+ let Spellings = [GNU<"swift_bridge">];
+ let Subjects = SubjectList<[Tag, TypedefName, ObjCInterface, ObjCProtocol],
+ ErrorDiag, "ExpectedType">;
+ let Args = [StringArgument<"SwiftType">];
+ let Documentation = [SwiftBridgeDocs];
+}
+
+def SwiftError : InheritableAttr {
+ let Spellings = [GCC<"swift_error">];
+ let Args = [EnumArgument<"Convention", "ConventionKind",
+ ["none", "nonnull_error", "null_result", "zero_result", "nonzero_result"],
+ ["None", "NonNullError", "NullResult", "ZeroResult", "NonZeroResult"]>];
+ let Subjects = SubjectList<[ObjCMethod, Function], ErrorDiag>;
+ let Documentation = [SwiftErrorDocs];
+}
+
+def SwiftName : InheritableAttr {
+ let Spellings = [GCC<"swift_name">];
+ let Args = [StringArgument<"Name">];
+ // Proper subject list disabled because of the custom error needed.
+ // Let's avoid merge conflicts for now.
+// let Subjects = SubjectList<[EnumConstant, ObjCProtocol, ObjCClassMethod],
+// ErrorDiag, "ExpectedSwiftNameSubjects">;
+ let Documentation = [Undocumented];
+}
+
+def SwiftNewtype : Attr {
+ let Spellings = [GNU<"swift_newtype">, GNU<"swift_wrapper">];
+ let Subjects = SubjectList<[TypedefName], ErrorDiag, "ExpectedType">;
+ let Args = [EnumArgument<"NewtypeKind", "NewtypeKind",
+ ["struct", "enum"],
+ ["NK_Struct", "NK_Enum"]>];
+ let Documentation = [SwiftNewtypeDocs];
+}
+
+def SwiftPrivate : InheritableAttr {
+ let Spellings = [GCC<"swift_private">];
+ let Documentation = [Undocumented];
+}
+
+def SwiftSuppressFactoryAsInit : InheritableAttr {
+ // This attribute has no spellings as it is only ever created implicitly
+ // from API notes.
+ let Spellings = [];
+ let SemaHandler = 0;
+ let Documentation = [Undocumented];
+}
+
+def SwiftImportPropertyAsAccessors : InheritableAttr {
+ // This attribute has no spellings as it is only ever created implicitly
+ // from API notes.
+ let Spellings = [];
+ let SemaHandler = 0;
+ let Documentation = [Undocumented];
+}
+
+def SwiftVersioned : Attr {
+ // This attribute has no spellings as it is only ever created implicitly
+ // from API notes.
+ let Spellings = [];
+ let Args = [VersionArgument<"Version">, AttrArgument<"AttrToAdd">];
+ let SemaHandler = 0;
+ let Documentation = [Undocumented];
+}
+
+def SwiftVersionedRemoval : Attr {
+ // This attribute has no spellings as it is only ever created implicitly
+ // from API notes.
+ let Spellings = [];
+ let Args = [VersionArgument<"Version">, UnsignedArgument<"RawKind">];
+ let SemaHandler = 0;
+ let Documentation = [Undocumented];
+ let AdditionalMembers = [{
+ attr::Kind getAttrKindToRemove() const {
+ return static_cast<attr::Kind>(getRawKind());
+ }
+ }];
+}
+
def ReqdWorkGroupSize : InheritableAttr {
let Spellings = [GNU<"reqd_work_group_size">];
let Args = [UnsignedArgument<"XDim">, UnsignedArgument<"YDim">,
diff --git a/include/clang/Basic/AttrDocs.td b/include/clang/Basic/AttrDocs.td
index 8f6a7ea..ccf4778 100644
--- a/include/clang/Basic/AttrDocs.td
+++ b/include/clang/Basic/AttrDocs.td
@@ -2322,6 +2322,58 @@
}];
}
+def SwiftDocs : DocumentationCategory<"Controlling Swift Import"> {
+ let Content = [{
+Clang supports additional attributes for controlling how APIs are imported into Swift.
+ }];
+}
+
+def NSErrorDomainDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{
+The ``ns_error_domain`` attribute indicates a global constant representing the error domain.
+ }];
+}
+
+def SwiftBridgeDocs : Documentation {
+ let Category = SwiftDocs;
+ let Content = [{
+The ``swift_bridge`` attribute indicates that the type to which the attribute appertains is bridged to the named Swift type.
+ }];
+}
+
+def SwiftErrorDocs : Documentation {
+ let Category = SwiftDocs;
+ let Heading = "swift_error";
+ let Content = [{
+The ``swift_error`` attribute controls whether a particular function (or Objective-C method) is imported into Swift as a throwing function, and if so, the dynamic convention it uses.
+
+All of these conventions except ``none`` require the function to have an error parameter. Currently, the error parameter is always the last parameter of type ``NSError**`` or ``CFErrorRef*``. Swift will remove the error parameter from the imported API, and dynamically will always pass a valid address initialized to a null pointer.
+
+* ``swift_error(none)`` means that the function should not be imported as throwing. The error parameter and result type will be left alone.
+
+* ``swift_error(null_result)`` means that calls to the function should be considered to have thrown if they return a null value. The return type must be a pointer type, and it will be imported into Swift with a non-optional type. This is the default error convention for Objective-C methods that return pointers.
+
+* ``swift_error(zero_result)`` means that calls to the function should be considered to have thrown if they return a zero result. The return type must be an integral type. If the return type would have been imported as ``Bool``, it is instead imported as ``Void``. This is the default error convention for Objective-C methods that return a type that would be imported as ``Bool``.
+
+* ``swift_error(nonzero_result)`` means that calls to the function should be considered to have thrown if they return a non-zero result. The return type must be an integral type. If the return type would have been imported as ``Bool``, it is instead imported as ``Void``.
+
+* ``swift_error(nonnull_error)`` means that calls to the function should be considered to have thrown if they leave a non-null error in the error parameter. The return type is left unmodified.
+
+}];
+}
+
+def SwiftNewtypeDocs : Documentation {
+ let Category = SwiftDocs;
+ let Heading = "swift_newtype";
+ let Content = [{
+The ``swift_newtype`` attribute indicates that the typedef to which the attribute appertains is imported as a new Swift type of the typedef's name.
+* ``swift_newtype(struct)`` means that a Swift struct will be created for this typedef.
+* ``swift_newtype(enum)`` means that a Swift enum will be created for this typedef.
+ }];
+}
+
+
def OMPDeclareTargetDocs : Documentation {
let Category = DocCatFunction;
let Heading = "#pragma omp declare target";
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
index b83ef4d..ffce99b 100644
--- a/include/clang/Basic/Diagnostic.h
+++ b/include/clang/Basic/Diagnostic.h
@@ -29,6 +29,7 @@
#include <cassert>
#include <cstdint>
#include <list>
+#include <map>
#include <memory>
#include <string>
#include <type_traits>
@@ -232,59 +233,97 @@
/// \brief Keeps and automatically disposes all DiagStates that we create.
std::list<DiagState> DiagStates;
- /// \brief Represents a point in source where the diagnostic state was
- /// modified because of a pragma.
- ///
- /// 'Loc' can be null if the point represents the diagnostic state
- /// modifications done through the command-line.
- struct DiagStatePoint {
- DiagState *State;
- FullSourceLoc Loc;
- DiagStatePoint(DiagState *State, FullSourceLoc Loc)
- : State(State), Loc(Loc) { }
-
- bool operator<(const DiagStatePoint &RHS) const {
- // If Loc is invalid it means it came from <command-line>, in which case
- // we regard it as coming before any valid source location.
- if (RHS.Loc.isInvalid())
- return false;
- if (Loc.isInvalid())
- return true;
- return Loc.isBeforeInTranslationUnitThan(RHS.Loc);
+ /// A mapping from files to the diagnostic states for those files. Lazily
+ /// built on demand for files in which the diagnostic state has not changed.
+ class DiagStateMap {
+ public:
+ /// Add an initial diagnostic state.
+ void appendFirst(DiagState *State);
+ /// Add a new latest state point.
+ void append(SourceManager &SrcMgr, SourceLocation Loc, DiagState *State);
+ /// Look up the diagnostic state at a given source location.
+ DiagState *lookup(SourceManager &SrcMgr, SourceLocation Loc) const;
+ /// Determine whether this map is empty.
+ bool empty() const { return Files.empty(); }
+ /// Clear out this map.
+ void clear() {
+ Files.clear();
+ FirstDiagState = CurDiagState = nullptr;
+ CurDiagStateLoc = SourceLocation();
}
+
+ /// Grab the most-recently-added state point.
+ DiagState *getCurDiagState() const { return CurDiagState; }
+ /// Get the location at which a diagnostic state was last added.
+ SourceLocation getCurDiagStateLoc() const { return CurDiagStateLoc; }
+
+ private:
+ /// \brief Represents a point in source where the diagnostic state was
+ /// modified because of a pragma.
+ ///
+ /// 'Loc' can be null if the point represents the diagnostic state
+ /// modifications done through the command-line.
+ struct DiagStatePoint {
+ DiagState *State;
+ unsigned Offset;
+ DiagStatePoint(DiagState *State, unsigned Offset)
+ : State(State), Offset(Offset) { }
+ };
+
+ /// Description of the diagnostic states and state transitions for a
+ /// particular FileID.
+ struct File {
+ /// The diagnostic state for the parent file. This is strictly redundant,
+ /// as looking up the DecomposedIncludedLoc for the FileID in the Files
+ /// map would give us this, but we cache it here for performance.
+ File *Parent = nullptr;
+ /// The offset of this file within its parent.
+ unsigned ParentOffset = 0;
+ /// Whether this file has any local (not imported from an AST file)
+ /// diagnostic state transitions.
+ bool HasLocalTransitions = false;
+ /// The points within the file where the state changes. There will always
+ /// be at least one of these (the state on entry to the file).
+ llvm::SmallVector<DiagStatePoint, 4> StateTransitions;
+
+ DiagState *lookup(unsigned Offset) const;
+ };
+
+ /// The diagnostic states for each file.
+ mutable std::map<FileID, File> Files;
+
+ /// The initial diagnostic state.
+ DiagState *FirstDiagState;
+ /// The current diagnostic state.
+ DiagState *CurDiagState;
+ /// The location at which the current diagnostic state was established.
+ SourceLocation CurDiagStateLoc;
+
+ /// Get the diagnostic state information for a file.
+ File *getFile(SourceManager &SrcMgr, FileID ID) const;
+
+ friend class ASTReader;
+ friend class ASTWriter;
};
- /// \brief A sorted vector of all DiagStatePoints representing changes in
- /// diagnostic state due to diagnostic pragmas.
- ///
- /// The vector is always sorted according to the SourceLocation of the
- /// DiagStatePoint.
- typedef std::vector<DiagStatePoint> DiagStatePointsTy;
- mutable DiagStatePointsTy DiagStatePoints;
+ DiagStateMap DiagStatesByLoc;
/// \brief Keeps the DiagState that was active during each diagnostic 'push'
/// so we can get back at it when we 'pop'.
std::vector<DiagState *> DiagStateOnPushStack;
DiagState *GetCurDiagState() const {
- assert(!DiagStatePoints.empty());
- return DiagStatePoints.back().State;
+ return DiagStatesByLoc.getCurDiagState();
}
- void PushDiagStatePoint(DiagState *State, SourceLocation L) {
- FullSourceLoc Loc(L, getSourceManager());
- // Make sure that DiagStatePoints is always sorted according to Loc.
- assert(Loc.isValid() && "Adding invalid loc point");
- assert(!DiagStatePoints.empty() &&
- (DiagStatePoints.back().Loc.isInvalid() ||
- DiagStatePoints.back().Loc.isBeforeInTranslationUnitThan(Loc)) &&
- "Previous point loc comes after or is the same as new one");
- DiagStatePoints.push_back(DiagStatePoint(State, Loc));
- }
+ void PushDiagStatePoint(DiagState *State, SourceLocation L);
/// \brief Finds the DiagStatePoint that contains the diagnostic state of
/// the given source location.
- DiagStatePointsTy::iterator GetDiagStatePointForLoc(SourceLocation Loc) const;
+ DiagState *GetDiagStateForLoc(SourceLocation Loc) const {
+ return SourceMgr ? DiagStatesByLoc.lookup(*SourceMgr, Loc)
+ : DiagStatesByLoc.getCurDiagState();
+ }
/// \brief Sticky flag set to \c true when an error is emitted.
bool ErrorOccurred;
@@ -390,7 +429,11 @@
assert(SourceMgr && "SourceManager not set!");
return *SourceMgr;
}
- void setSourceManager(SourceManager *SrcMgr) { SourceMgr = SrcMgr; }
+ void setSourceManager(SourceManager *SrcMgr) {
+ assert(DiagStatesByLoc.empty() &&
+ "Leftover diag state from a different SourceManager.");
+ SourceMgr = SrcMgr;
+ }
//===--------------------------------------------------------------------===//
// DiagnosticsEngine characterization methods, used by a client to customize
diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td
index af0612a..fe83b85 100644
--- a/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/include/clang/Basic/DiagnosticCommonKinds.td
@@ -88,6 +88,8 @@
"module '%0' %select{is incompatible with|requires}1 feature '%2'">;
def err_module_header_missing : Error<
"%select{|umbrella }0header '%1' not found">;
+def err_module_shadowed : Error<
+ "import of shadowed module '%0'">;
def err_module_lock_failure : Error<
"could not acquire lock file for module '%0': %1">, DefaultFatal;
def err_module_lock_timeout : Error<
@@ -222,6 +224,11 @@
def warn_arcmt_nsalloc_realloc : Warning<"[rewriter] call returns pointer to GC managed memory; it will become unmanaged in ARC">;
def err_arcmt_nsinvocation_ownership : Error<"NSInvocation's %0 is not safe to be used with an object with ownership other than __unsafe_unretained">;
+// API notes
+def err_apinotes_message : Error<"%0">;
+def warn_apinotes_message : Warning<"%0">, InGroup<DiagGroup<"apinotes">>;
+def note_apinotes_message : Note<"%0">;
+
// OpenMP
def err_omp_more_one_clause : Error<
"directive '#pragma omp %0' cannot contain more than one '%1' clause%select{| with '%3' name modifier| with 'source' dependence}2">;
diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td
index 1267f8d..257448e 100644
--- a/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -222,6 +222,10 @@
def err_invalid_vfs_overlay : Error<
"invalid virtual filesystem overlay file '%0'">, DefaultFatal;
+def err_no_apinotes_cache_path : Error<
+ "-fapinotes was provided without -fapinotes-cache-path=<directory>">,
+ DefaultFatal;
+
def warn_option_invalid_ocl_version : Warning<
"OpenCL version %0 does not support the option '%1'">, InGroup<Deprecated>;
}
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 4173d03..6129b54 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -219,7 +219,6 @@
def DanglingElse: DiagGroup<"dangling-else">;
def DanglingField : DiagGroup<"dangling-field">;
def DistributedObjectModifiers : DiagGroup<"distributed-object-modifiers">;
-def ExpansionToDefined : DiagGroup<"expansion-to-defined">;
def FlagEnum : DiagGroup<"flag-enum">;
def IncrementBool : DiagGroup<"increment-bool", [DeprecatedIncrementBool]>;
def InfiniteRecursion : DiagGroup<"infinite-recursion">;
@@ -386,6 +385,9 @@
def StringPlusInt : DiagGroup<"string-plus-int">;
def StringPlusChar : DiagGroup<"string-plus-char">;
def StrncatSize : DiagGroup<"strncat-size">;
+
+def SwiftNameAttribute : DiagGroup<"swift-name-attribute">;
+
def TautologicalOutOfRangeCompare : DiagGroup<"tautological-constant-out-of-range-compare">;
def TautologicalPointerCompare : DiagGroup<"tautological-pointer-compare">;
def TautologicalOverlapCompare : DiagGroup<"tautological-overlap-compare">;
diff --git a/include/clang/Basic/DiagnosticIDs.h b/include/clang/Basic/DiagnosticIDs.h
index fcd04a0..d13ae4c 100644
--- a/include/clang/Basic/DiagnosticIDs.h
+++ b/include/clang/Basic/DiagnosticIDs.h
@@ -36,7 +36,7 @@
DIAG_START_AST = DIAG_START_PARSE + 500,
DIAG_START_COMMENT = DIAG_START_AST + 110,
DIAG_START_SEMA = DIAG_START_COMMENT + 100,
- DIAG_START_ANALYSIS = DIAG_START_SEMA + 3500,
+ DIAG_START_ANALYSIS = DIAG_START_SEMA + 4000,
DIAG_UPPER_LIMIT = DIAG_START_ANALYSIS + 100
};
diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td
index 7f7022b..aaabe7f 100644
--- a/include/clang/Basic/DiagnosticLexKinds.td
+++ b/include/clang/Basic/DiagnosticLexKinds.td
@@ -679,13 +679,6 @@
def note_header_guard : Note<
"%0 is defined here; did you mean %1?">;
-def warn_defined_in_object_type_macro : Warning<
- "macro expansion producing 'defined' has undefined behavior">,
- InGroup<ExpansionToDefined>;
-def warn_defined_in_function_type_macro : Extension<
- "macro expansion producing 'defined' has undefined behavior">,
- InGroup<ExpansionToDefined>;
-
let CategoryName = "Nullability Issue" in {
def err_pp_assume_nonnull_syntax : Error<"expected 'begin' or 'end'">;
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 0943fea..76e776c 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -1039,6 +1039,9 @@
def err_pragma_invalid_keyword : Error<
"invalid argument; expected 'enable'%select{|, 'full'}0%select{|, 'assume_safety'}1 or 'disable'">;
+// API notes.
+def err_type_unparsed : Error<"unparsed tokens following type">;
+
// Pragma unroll support.
def warn_pragma_unroll_cuda_value_in_parens : Warning<
"argument to '#pragma unroll' should not be in parentheses in CUDA C/C++">,
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index c934351..c28465a 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2735,6 +2735,9 @@
InGroup<Availability>;
def note_overridden_method : Note<
"overridden method is here">;
+def warn_availability_swift_unavailable_deprecated_only : Warning<
+ "only 'unavailable' and 'deprecated' are supported for Swift availability">,
+ InGroup<Availability>;
def note_protocol_method : Note<
"protocol method is here">;
@@ -3103,6 +3106,9 @@
def warn_attribute_nonnull_parm_no_args : Warning<
"'nonnull' attribute when used on parameters takes no arguments">,
InGroup<IgnoredAttributes>;
+def warn_attribute_noescape_non_pointer : Warning<
+ "'noescape' attribute ignored on parameter of non-pointer type %0">,
+ InGroup<IgnoredAttributes>;
def note_declared_nonnull : Note<
"declared %select{'returns_nonnull'|'nonnull'}0 here">;
def warn_attribute_sentinel_named_arguments : Warning<
@@ -3225,6 +3231,68 @@
def err_objc_attr_protocol_requires_definition : Error<
"attribute %0 can only be applied to @protocol definitions, not forward declarations">;
+// Swift attributes
+def warn_attr_swift_name_decl_kind : Warning<
+ "%0 attribute cannot be applied to this declaration">,
+ InGroup<SwiftNameAttribute>;
+def warn_attr_swift_name_function : Warning<
+ "parameter of %0 attribute must be a Swift function name string">,
+ InGroup<SwiftNameAttribute>;
+def warn_attr_swift_name_function_no_prototype : Warning<
+ "%0 attribute can only be applied to function declarations with prototypes">,
+ InGroup<SwiftNameAttribute>;
+def warn_attr_swift_name_context_name_invalid_identifier : Warning<
+ "%0 attribute has invalid identifier for context name">,
+ InGroup<SwiftNameAttribute>;
+def warn_attr_swift_name_basename_invalid_identifier : Warning<
+ "%0 attribute has invalid identifier for base name">,
+ InGroup<SwiftNameAttribute>;
+def warn_attr_swift_name_parameter_invalid_identifier : Warning<
+ "%0 attribute has invalid identifier for parameter name">,
+ InGroup<SwiftNameAttribute>;
+def warn_attr_swift_name_missing_parameters : Warning<
+ "%0 attribute is missing parameter label clause">,
+ InGroup<SwiftNameAttribute>;
+def warn_attr_swift_name_subscript_not_accessor : Warning<
+ "%0 attribute for 'subscript' must be a getter or setter">,
+ InGroup<SwiftNameAttribute>;
+def warn_attr_swift_name_subscript_no_parameter : Warning<
+ "%0 attribute for 'subscript' must take at least one parameter">,
+ InGroup<SwiftNameAttribute>;
+def warn_attr_swift_name_subscript_getter_newValue : Warning<
+ "%0 attribute for 'subscript' getter cannot take a 'newValue:' parameter">,
+ InGroup<SwiftNameAttribute>;
+def warn_attr_swift_name_subscript_setter_no_newValue : Warning<
+ "%0 attribute for 'subscript' setter must take a 'newValue:' parameter">,
+ InGroup<SwiftNameAttribute>;
+def warn_attr_swift_name_subscript_setter_multiple_newValues : Warning<
+ "%0 attribute for 'subscript' setter cannot take multiple 'newValue:' parameters">,
+ InGroup<SwiftNameAttribute>;
+def warn_attr_swift_name_getter_parameters : Warning<
+ "%0 attribute for getter must not take any parameters besides 'self:'">,
+ InGroup<SwiftNameAttribute>;
+def warn_attr_swift_name_setter_parameters : Warning<
+ "%0 attribute for setter must take one parameter for new value">,
+ InGroup<SwiftNameAttribute>;
+def warn_attr_swift_name_multiple_selfs : Warning<
+ "%0 attribute cannot specify more than one 'self:' parameter">,
+ InGroup<SwiftNameAttribute>;
+def warn_attr_swift_name_static_subscript : Warning<
+ "%0 attribute for 'subscript' must take a 'self:' parameter">,
+ InGroup<SwiftNameAttribute>;
+def warn_attr_swift_name_num_params : Warning<
+ "too %select{few|many}0 parameters in %1 attribute (expected %2; got %3)">,
+ InGroup<SwiftNameAttribute>;
+def err_attr_swift_error_no_error_parameter : Error<
+ "%0 attribute can only be applied to a %select{function|method}1 "
+ "with an error parameter">;
+def err_attr_swift_error_return_type : Error<
+ "%0 attribute with '%1' convention can only be applied to a "
+ "%select{function|method}2 returning %select{an integral type|a pointer}3">;
+def warn_swift_newtype_attribute_non_typedef : Warning<
+ "'swift_newtype' attribute may be put on a typedef only; "
+ "attribute is ignored">, InGroup<DiagGroup<"swift-newtype-attribute">>;
+
// Function Parameter Semantic Analysis.
def err_param_with_void_type : Error<"argument may not have 'void' type">;
def err_void_only_param : Error<
@@ -5164,7 +5232,7 @@
def warn_block_capture_autoreleasing : Warning<
"block captures an autoreleasing out-parameter, which may result in "
"use-after-free bugs">,
- InGroup<BlockCaptureAutoReleasing>, DefaultIgnore;
+ InGroup<BlockCaptureAutoReleasing>;
def note_declare_parameter_autoreleasing : Note<
"declare the parameter __autoreleasing explicitly to suppress this warning">;
def note_declare_parameter_strong : Note<
@@ -7979,6 +8047,14 @@
def err_nsreturns_retained_attribute_mismatch : Error<
"overriding method has mismatched ns_returns_%select{not_retained|retained}0"
" attributes">;
+
+def err_nserrordomain_not_tagdecl : Error<
+ "ns_error_domain attribute only valid on "
+ "%select{enums, structs, and unions|enums, structs, unions, and classes}0">;
+def err_nserrordomain_invalid_decl : Error<
+ "domain argument %0 does not refer to global constant">;
+def err_nserrordomain_requires_identifier : Error<
+ "domain argument must be an identifier">;
def note_getter_unavailable : Note<
"or because setter is declared here, but no getter method %0 is found">;
@@ -8237,6 +8313,13 @@
InGroup<OpenCLUnsupportedRGBA>;
} // end of sema category
+let CategoryName = "API Notes Issue" in {
+
+def err_incompatible_replacement_type : Error<
+ "API notes replacement type %0 has a different size from original type %1">;
+
+}
+
let CategoryName = "OpenMP Issue" in {
// OpenMP support.
def err_omp_expected_var_arg : Error<
diff --git a/include/clang/Basic/FileSystemOptions.h b/include/clang/Basic/FileSystemOptions.h
index 38f1346..1beb2e2 100644
--- a/include/clang/Basic/FileSystemOptions.h
+++ b/include/clang/Basic/FileSystemOptions.h
@@ -25,6 +25,9 @@
/// \brief If set, paths are resolved as if the working directory was
/// set to the value of WorkingDir.
std::string WorkingDir;
+
+ /// The path to the API notes cache.
+ std::string APINotesCachePath;
};
} // end namespace clang
diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h
index 3001d0b..52238f8 100644
--- a/include/clang/Basic/IdentifierTable.h
+++ b/include/clang/Basic/IdentifierTable.h
@@ -73,9 +73,6 @@
// partially) from an AST file.
bool ChangedAfterLoad : 1; // True if identifier has changed from the
// definition loaded from an AST file.
- bool FEChangedAfterLoad : 1; // True if identifier's frontend information
- // has changed from the definition loaded
- // from an AST file.
bool RevertedTokenID : 1; // True if revertTokenIDToIdentifier was
// called.
bool OutOfDate : 1; // True if there may be additional
@@ -83,7 +80,7 @@
// stored externally.
bool IsModulesImport : 1; // True if this is the 'import' contextual
// keyword.
- // 29 bit left in 64-bit word.
+ // 30 bit left in 64-bit word.
void *FETokenInfo; // Managed by the language front-end.
llvm::StringMapEntry<IdentifierInfo*> *Entry;
@@ -313,18 +310,6 @@
ChangedAfterLoad = true;
}
- /// \brief Determine whether the frontend token information for this
- /// identifier has changed since it was loaded from an AST file.
- bool hasFETokenInfoChangedSinceDeserialization() const {
- return FEChangedAfterLoad;
- }
-
- /// \brief Note that the frontend token information for this identifier has
- /// changed since it was loaded from an AST file.
- void setFETokenInfoChangedSinceDeserialization() {
- FEChangedAfterLoad = true;
- }
-
/// \brief Determine whether the information for this identifier is out of
/// date with respect to the external source.
bool isOutOfDate() const { return OutOfDate; }
diff --git a/include/clang/Basic/LangOptions.def b/include/clang/Basic/LangOptions.def
index d944a9d..19a081c 100644
--- a/include/clang/Basic/LangOptions.def
+++ b/include/clang/Basic/LangOptions.def
@@ -256,6 +256,8 @@
LANGOPT(ApplePragmaPack, 1, 0, "Apple gcc-compatible #pragma pack handling")
LANGOPT(RetainCommentsFromSystemHeaders, 1, 0, "retain documentation comments from system headers in the AST")
+LANGOPT(APINotes, 1, 0, "use external API notes")
+LANGOPT(APINotesModules, 1, 0, "use external API notes")
LANGOPT(SanitizeAddressFieldPadding, 2, 0, "controls how aggressive is ASan "
"field padding (0: none, 1:least "
diff --git a/include/clang/Basic/Module.h b/include/clang/Basic/Module.h
index 31c5c7e..ef50b5d 100644
--- a/include/clang/Basic/Module.h
+++ b/include/clang/Basic/Module.h
@@ -147,6 +147,9 @@
/// will be false to indicate that this (sub)module is not available.
SmallVector<Requirement, 2> Requirements;
+ /// \brief A module with the same name that shadows this module.
+ Module *ShadowingModule = nullptr;
+
/// \brief Whether this module is missing a feature from \c Requirements.
unsigned IsMissingRequirement : 1;
@@ -180,6 +183,9 @@
/// \brief Whether this is an inferred submodule (module * { ... }).
unsigned IsInferred : 1;
+ /// \brief Whether this is a module who has its swift_names inferred.
+ unsigned IsSwiftInferImportAsMember : 1;
+
/// \brief Whether we should infer submodules for this module based on
/// the headers.
///
@@ -325,13 +331,20 @@
///
/// \param Target The target options used for the current translation unit.
///
- /// \param Req If this module is unavailable, this parameter
- /// will be set to one of the requirements that is not met for use of
- /// this module.
+ /// \param Req If this module is unavailable because of a missing requirement,
+ /// this parameter will be set to one of the requirements that is not met for
+ /// use of this module.
+ ///
+ /// \param MissingHeader If this module is unavailable because of a missing
+ /// header, this parameter will be set to one of the missing headers.
+ ///
+ /// \param ShadowingModule If this module is unavailable because it is
+ /// shadowed, this parameter will be set to the shadowing module.
bool isAvailable(const LangOptions &LangOpts,
const TargetInfo &Target,
Requirement &Req,
- UnresolvedHeaderDirective &MissingHeader) const;
+ UnresolvedHeaderDirective &MissingHeader,
+ Module *&ShadowingModule) const;
/// \brief Determine whether this module is a submodule.
bool isSubModule() const { return Parent != nullptr; }
diff --git a/include/clang/Basic/SourceMgrAdapter.h b/include/clang/Basic/SourceMgrAdapter.h
new file mode 100644
index 0000000..dd7b83f
--- /dev/null
+++ b/include/clang/Basic/SourceMgrAdapter.h
@@ -0,0 +1,85 @@
+//=== SourceMgrAdapter.h - SourceMgr to SourceManager Adapter ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides an adapter that maps diagnostics from llvm::SourceMgr
+// to Clang's SourceManager.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SOURCEMGRADAPTER_H
+#define LLVM_CLANG_SOURCEMGRADAPTER_H
+
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/Support/SourceMgr.h"
+#include <string>
+#include <utility>
+
+namespace clang {
+
+class DiagnosticsEngine;
+class FileEntry;
+
+/// An adapter that can be used to translate diagnostics from one or more
+/// llvm::SourceMgr instances to a ,
+class SourceMgrAdapter {
+ /// Clang source manager.
+ SourceManager &SrcMgr;
+
+ /// Clang diagnostics engine.
+ DiagnosticsEngine &Diag;
+
+ /// Diagnostic IDs for errors, warnings, and notes.
+ unsigned ErrorDiagID, WarningDiagID, NoteDiagID;
+
+ /// The default file to use when mapping buffers.
+ const FileEntry *DefaultFile;
+
+ /// A mapping from (LLVM source manager, buffer ID) pairs to the
+ /// corresponding file ID within the Clang source manager.
+ llvm::DenseMap<std::pair<const llvm::SourceMgr *, unsigned>, FileID>
+ FileIDMapping;
+
+ /// Diagnostic handler.
+ static void handleDiag(const llvm::SMDiagnostic &diag, void *context);
+
+public:
+ /// Create a new \c SourceMgr adaptor that maps to the given source
+ /// manager and diagnostics engine.
+ SourceMgrAdapter(SourceManager &srcMgr, DiagnosticsEngine &diag,
+ unsigned errorDiagID, unsigned warningDiagID,
+ unsigned noteDiagID, const FileEntry *defaultFile = nullptr);
+
+ ~SourceMgrAdapter();
+
+ /// Map a source location in the given LLVM source manager to its
+ /// corresponding location in the Clang source manager.
+ SourceLocation mapLocation(const llvm::SourceMgr &llvmSrcMgr,llvm::SMLoc loc);
+
+ /// Map a source range in the given LLVM source manager to its corresponding
+ /// range in the Clang source manager.
+ SourceRange mapRange(const llvm::SourceMgr &llvmSrcMgr, llvm::SMRange range);
+
+ /// Handle the given diagnostic from an LLVM source manager.
+ void handleDiag(const llvm::SMDiagnostic &diag);
+
+ /// Retrieve the diagnostic handler to use with the underlying SourceMgr.
+ llvm::SourceMgr::DiagHandlerTy getDiagHandler() {
+ return &SourceMgrAdapter::handleDiag;
+ }
+
+ /// Retrieve the context to use with the diagnostic handler produced by
+ /// \c getDiagHandler().
+ void *getDiagContext() { return this; }
+};
+
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Basic/VersionTuple.h b/include/clang/Basic/VersionTuple.h
index da3b019..07315f0 100644
--- a/include/clang/Basic/VersionTuple.h
+++ b/include/clang/Basic/VersionTuple.h
@@ -17,6 +17,7 @@
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/DenseMapInfo.h"
#include <string>
#include <tuple>
@@ -70,6 +71,9 @@
return Major == 0 && Minor == 0 && Subminor == 0 && Build == 0;
}
+ /// Whether this is a non-empty version tuple.
+ explicit operator bool () const { return !empty(); }
+
/// \brief Retrieve the major version number.
unsigned getMajor() const { return Major; }
@@ -165,4 +169,35 @@
raw_ostream& operator<<(raw_ostream &Out, const VersionTuple &V);
} // end namespace clang
+
+namespace llvm {
+ // Provide DenseMapInfo for version tuples.
+ template<>
+ struct DenseMapInfo<clang::VersionTuple> {
+ static inline clang::VersionTuple getEmptyKey() {
+ return clang::VersionTuple(0x7FFFFFFF);
+ }
+ static inline clang::VersionTuple getTombstoneKey() {
+ return clang::VersionTuple(0x7FFFFFFE);
+ }
+ static unsigned getHashValue(const clang::VersionTuple& value) {
+ unsigned result = value.getMajor();
+ if (auto minor = value.getMinor())
+ result = combineHashValue(result, *minor);
+ if (auto subminor = value.getSubminor())
+ result = combineHashValue(result, *subminor);
+ if (auto build = value.getBuild())
+ result = combineHashValue(result, *build);
+
+ return result;
+ }
+
+ static bool isEqual(const clang::VersionTuple &lhs,
+ const clang::VersionTuple &rhs) {
+ return lhs == rhs;
+ }
+ };
+
+} // end namespace llvm
+
#endif // LLVM_CLANG_BASIC_VERSIONTUPLE_H
diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h
index 0ce461c..d38e63b 100644
--- a/include/clang/Driver/Driver.h
+++ b/include/clang/Driver/Driver.h
@@ -304,13 +304,8 @@
bool isSaveTempsObj() const { return SaveTemps == SaveTempsObj; }
bool embedBitcodeEnabled() const { return BitcodeEmbed != EmbedNone; }
- bool embedBitcodeInObject() const {
- // LTO has no object file output so ignore embed bitcode option in LTO.
- return (BitcodeEmbed == EmbedBitcode) && !isUsingLTO();
- }
- bool embedBitcodeMarkerOnly() const {
- return (BitcodeEmbed == EmbedMarker) && !isUsingLTO();
- }
+ bool embedBitcodeInObject() const { return (BitcodeEmbed == EmbedBitcode); }
+ bool embedBitcodeMarkerOnly() const { return (BitcodeEmbed == EmbedMarker); }
/// Compute the desired OpenMP runtime from the flags provided.
OpenMPRuntimeKind getOpenMPRuntime(const llvm::opt::ArgList &Args) const;
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 6be159f..77e6cf3 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -556,6 +556,21 @@
def fno_profile_use : Flag<["-"], "fno-profile-use">,
Alias<fno_profile_instr_use>;
+def fapinotes : Flag<["-"], "fapinotes">, Group<f_clang_Group>,
+ Flags<[CC1Option]>, HelpText<"Enable external API notes support">;
+def fapinotes_modules : Flag<["-"], "fapinotes-modules">, Group<f_clang_Group>,
+ Flags<[CC1Option]>, HelpText<"Enable module-based external API notes support">;
+def fno_apinotes : Flag<["-"], "fno-apinotes">, Group<f_clang_Group>,
+ Flags<[CC1Option]>, HelpText<"Disable external API notes support">;
+def fno_apinotes_modules : Flag<["-"], "fno-apinotes-modules">, Group<f_clang_Group>,
+ Flags<[CC1Option]>, HelpText<"Disable module-based external API notes support">;
+def fapinotes_cache_path : Joined<["-"], "fapinotes-cache-path=">,
+ Group<i_Group>, Flags<[DriverOption, CC1Option]>, MetaVarName<"<directory>">,
+ HelpText<"Specify the API notes cache path">;
+def fapinotes_swift_version : Joined<["-"], "fapinotes-swift-version=">,
+ Group<f_clang_Group>, Flags<[CC1Option]>, MetaVarName<"<version>">,
+ HelpText<"Specify the Swift version to use when filtering API notes">;
+
def fblocks : Flag<["-"], "fblocks">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Enable the 'blocks' language feature">;
def fbootclasspath_EQ : Joined<["-"], "fbootclasspath=">, Group<f_Group>;
@@ -1407,6 +1422,8 @@
HelpText<"Display available options">;
def index_header_map : Flag<["-"], "index-header-map">, Flags<[CC1Option]>,
HelpText<"Make the next included directory (-I or -F) an indexer header map">;
+def iapinotes_modules : JoinedOrSeparate<["-"], "iapinotes-modules">, Group<clang_i_Group>, Flags<[CC1Option]>,
+ HelpText<"Add directory to the API notes search path referenced by module name">, MetaVarName<"<directory>">;
def idirafter : JoinedOrSeparate<["-"], "idirafter">, Group<clang_i_Group>, Flags<[CC1Option]>,
HelpText<"Add directory to AFTER include search path">;
def iframework : JoinedOrSeparate<["-"], "iframework">, Group<clang_i_Group>, Flags<[CC1Option]>,
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index b1cdb46..03961f1 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -519,6 +519,8 @@
const FileSystemOptions &getFileSystemOpts() const { return FileSystemOpts; }
+ IntrusiveRefCntPtr<ASTReader> getASTReader() const;
+
StringRef getOriginalSourceFileName() {
return OriginalSourceFile;
}
diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h
index 3ebbc61..c549b08 100644
--- a/include/clang/Frontend/CompilerInstance.h
+++ b/include/clang/Frontend/CompilerInstance.h
@@ -292,6 +292,13 @@
return Invocation->getHeaderSearchOptsPtr();
}
+ APINotesOptions &getAPINotesOpts() {
+ return Invocation->getAPINotesOpts();
+ }
+ const APINotesOptions &getAPINotesOpts() const {
+ return Invocation->getAPINotesOpts();
+ }
+
LangOptions &getLangOpts() {
return *Invocation->getLangOpts();
}
diff --git a/include/clang/Frontend/CompilerInvocation.h b/include/clang/Frontend/CompilerInvocation.h
index cef7f73..239991d 100644
--- a/include/clang/Frontend/CompilerInvocation.h
+++ b/include/clang/Frontend/CompilerInvocation.h
@@ -10,6 +10,7 @@
#ifndef LLVM_CLANG_FRONTEND_COMPILERINVOCATION_H_
#define LLVM_CLANG_FRONTEND_COMPILERINVOCATION_H_
+#include "clang/APINotes/APINotesOptions.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileSystemOptions.h"
#include "clang/Basic/LangOptions.h"
@@ -113,6 +114,9 @@
MigratorOptions MigratorOpts;
+ /// Options controlling API notes.
+ APINotesOptions APINotesOpts;
+
/// Options controlling IRgen and the backend.
CodeGenOptions CodeGenOpts;
@@ -184,6 +188,11 @@
const MigratorOptions &getMigratorOpts() const {
return MigratorOpts;
}
+
+ APINotesOptions &getAPINotesOpts() { return APINotesOpts; }
+ const APINotesOptions &getAPINotesOpts() const {
+ return APINotesOpts;
+ }
CodeGenOptions &getCodeGenOpts() { return CodeGenOpts; }
const CodeGenOptions &getCodeGenOpts() const {
diff --git a/include/clang/Index/IndexSymbol.h b/include/clang/Index/IndexSymbol.h
index d19e5eb..16c3026 100644
--- a/include/clang/Index/IndexSymbol.h
+++ b/include/clang/Index/IndexSymbol.h
@@ -57,6 +57,7 @@
C,
ObjC,
CXX,
+ Swift,
};
/// Language specific sub-kinds.
@@ -66,6 +67,26 @@
CXXMoveConstructor,
AccessorGetter,
AccessorSetter,
+
+ // Swift sub-kinds
+
+ SwiftAccessorWillSet,
+ SwiftAccessorDidSet,
+ SwiftAccessorAddressor,
+ SwiftAccessorMutableAddressor,
+
+ SwiftExtensionOfStruct,
+ SwiftExtensionOfClass,
+ SwiftExtensionOfEnum,
+ SwiftExtensionOfProtocol,
+
+ SwiftPrefixOperator,
+ SwiftPostfixOperator,
+ SwiftInfixOperator,
+
+ SwiftSubscript,
+ SwiftAssociatedType,
+ SwiftGenericTypeParam,
};
/// Set of properties that provide additional info about a symbol.
diff --git a/include/clang/Index/IndexingAction.h b/include/clang/Index/IndexingAction.h
index e2e63dc..8eed33c 100644
--- a/include/clang/Index/IndexingAction.h
+++ b/include/clang/Index/IndexingAction.h
@@ -14,9 +14,14 @@
#include <memory>
namespace clang {
+ class ASTReader;
class ASTUnit;
class FrontendAction;
+namespace serialization {
+ class ModuleFile;
+}
+
namespace index {
class IndexDataConsumer;
@@ -42,6 +47,11 @@
std::shared_ptr<IndexDataConsumer> DataConsumer,
IndexingOptions Opts);
+void indexModuleFile(serialization::ModuleFile &Mod,
+ ASTReader &Reader,
+ std::shared_ptr<IndexDataConsumer> DataConsumer,
+ IndexingOptions Opts);
+
} // namespace index
} // namespace clang
diff --git a/include/clang/Index/USRGeneration.h b/include/clang/Index/USRGeneration.h
index be89068..61f2c9d 100644
--- a/include/clang/Index/USRGeneration.h
+++ b/include/clang/Index/USRGeneration.h
@@ -16,6 +16,7 @@
namespace clang {
class Decl;
class MacroDefinitionRecord;
+class SourceLocation;
class SourceManager;
namespace index {
@@ -54,6 +55,8 @@
/// \returns true on error, false on success.
bool generateUSRForMacro(const MacroDefinitionRecord *MD,
const SourceManager &SM, SmallVectorImpl<char> &Buf);
+bool generateUSRForMacro(StringRef MacroName, SourceLocation Loc,
+ const SourceManager &SM, SmallVectorImpl<char> &Buf);
} // namespace index
} // namespace clang
diff --git a/include/clang/Lex/Lexer.h b/include/clang/Lex/Lexer.h
index 830c25a..6f1f7c6 100644
--- a/include/clang/Lex/Lexer.h
+++ b/include/clang/Lex/Lexer.h
@@ -133,15 +133,17 @@
/// from. Currently this is only used by _Pragma handling.
SourceLocation getFileLoc() const { return FileLoc; }
-private:
/// Lex - Return the next token in the file. If this is the end of file, it
/// return the tok::eof token. This implicitly involves the preprocessor.
bool Lex(Token &Result);
-public:
/// isPragmaLexer - Returns true if this Lexer is being used to lex a pragma.
bool isPragmaLexer() const { return Is_PragmaLexer; }
+ /// Note that this Lexer is being used to lex a pragma, or something like it
+ /// that has simple end-of-file behavior.
+ void setIsPragmaLexer(bool value) { Is_PragmaLexer = value; }
+
private:
/// IndirectLex - An indirect call to 'Lex' that can be invoked via
/// the PreprocessorLexer interface.
diff --git a/include/clang/Lex/ModuleMap.h b/include/clang/Lex/ModuleMap.h
index 4613672..61df51e 100644
--- a/include/clang/Lex/ModuleMap.h
+++ b/include/clang/Lex/ModuleMap.h
@@ -92,7 +92,7 @@
// named LangOpts::CurrentModule, if we've loaded it).
Module *SourceModule;
- /// \brief The top-level modules that are known.
+ /// \brief The unshadowed top-level modules that are known.
llvm::StringMap<Module *> Modules;
/// \brief The number of modules we have created in total.
@@ -174,6 +174,15 @@
/// header.
llvm::DenseMap<const DirectoryEntry *, Module *> UmbrellaDirs;
+ /// \brief A generation counter that is used to test whether modules of the
+ /// same name may shadow or are illegal redefintions.
+ ///
+ /// Modules from earlier scopes may shadow modules from later ones.
+ /// Modules from the same scope may not have the same name.
+ unsigned CurrentModuleScopeID = 0;
+
+ llvm::DenseMap<Module *, unsigned> ModuleScopeIDs;
+
/// \brief The set of attributes that can be attached to a module.
struct Attributes {
Attributes()
@@ -188,6 +197,9 @@
/// \brief Whether this is an exhaustive set of configuration macros.
unsigned IsExhaustive : 1;
+ /// \brief Whether this is a module who has its swift_names inferred.
+ unsigned IsSwiftInferImportAsMember : 1;
+
/// \brief Whether files in this module can only include non-modular headers
/// and headers from used modules.
unsigned NoUndeclaredIncludes : 1;
@@ -440,6 +452,24 @@
Module *inferFrameworkModule(const DirectoryEntry *FrameworkDir,
bool IsSystem, Module *Parent);
+ /// \brief Create a new top-level module that is shadowed by
+ /// \p ShadowingModule.
+ Module *createShadowedModule(StringRef Name, bool IsFramework,
+ Module *ShadowingModule);
+
+ /// \brief Creates a new declaration scope for module names, allowing
+ /// previously defined modules to shadow definitions from the new scope.
+ ///
+ /// \note Module names from earlier scopes will shadow names from the new
+ /// scope, which is the opposite of how shadowing works for variables.
+ void finishModuleDeclarationScope() { CurrentModuleScopeID += 1; }
+
+ bool mayShadowNewModule(Module *ExistingModule) {
+ assert(!ExistingModule->Parent && "expected top-level module");
+ assert(ModuleScopeIDs.count(ExistingModule) && "unknown module");
+ return ModuleScopeIDs[ExistingModule] < CurrentModuleScopeID;
+ }
+
/// \brief Retrieve the module map file containing the definition of the given
/// module.
///
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index fe15902..2d31ba2 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -2282,6 +2282,14 @@
SourceLocation ScopeLoc,
AttributeList::Syntax Syntax);
+ void ParseSwiftNewtypeAttribute(IdentifierInfo &SwiftNewtype,
+ SourceLocation SwiftNewtypeLoc,
+ ParsedAttributes &attrs,
+ SourceLocation *endLoc,
+ IdentifierInfo *ScopeName,
+ SourceLocation ScopeLoc,
+ AttributeList::Syntax Syntax);
+
void ParseAttributeWithTypeArg(IdentifierInfo &AttrName,
SourceLocation AttrNameLoc,
ParsedAttributes &Attrs,
@@ -2706,7 +2714,19 @@
//===--------------------------------------------------------------------===//
// C++11/G++: Type Traits [Type-Traits.html in the GCC manual]
ExprResult ParseTypeTrait();
-
+
+ /// Parse the given string as a type.
+ ///
+ /// This is a dangerous utility function currently employed only by API notes.
+ /// It is not a general entry-point for safely parsing types from strings.
+ ///
+ /// \param typeStr The string to be parsed as a type.
+ /// \param context The name of the context in which this string is being
+ /// parsed, which will be used in diagnostics.
+ /// \param includeLoc The location at which this parse was triggered.
+ TypeResult parseTypeFromString(StringRef typeStr, StringRef context,
+ SourceLocation includeLoc);
+
//===--------------------------------------------------------------------===//
// Embarcadero: Arary and Expression Traits
ExprResult ParseArrayTypeTrait();
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 63d0784..ad4b934 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -27,6 +27,7 @@
#include "clang/AST/NSAPI.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/TypeLoc.h"
+#include "clang/APINotes/APINotesManager.h"
#include "clang/AST/TypeOrdering.h"
#include "clang/Basic/ExpressionTraits.h"
#include "clang/Basic/LangOptions.h"
@@ -54,6 +55,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/TinyPtrVector.h"
#include <deque>
+#include <functional>
#include <memory>
#include <string>
#include <vector>
@@ -304,6 +306,7 @@
ASTConsumer &Consumer;
DiagnosticsEngine &Diags;
SourceManager &SourceMgr;
+ api_notes::APINotesManager APINotes;
/// \brief Flag indicating whether or not to collect detailed statistics.
bool CollectStats;
@@ -573,6 +576,10 @@
OpaqueParser = P;
}
+ /// \brief Callback to the parser to parse a type expressed as a string.
+ std::function<TypeResult(StringRef, StringRef, SourceLocation)>
+ ParseTypeFromStringCallback;
+
class DelayedDiagnostics;
class DelayedDiagnosticsState {
@@ -1409,6 +1416,24 @@
}
};
+ /// Do a check to make sure \p Name looks like a legal swift_name
+ /// attribute for the decl \p D. Raise a diagnostic if the name is invalid
+ /// for the given declaration.
+ ///
+ /// For a function, this will validate a compound Swift name,
+ /// e.g. <code>init(foo:bar:baz:)</code> or <code>controllerForName(_:)</code>,
+ /// and the function will output the number of parameter names, and whether
+ /// this is a single-arg initializer.
+ ///
+ /// For a type, enum constant, property, or variable declaration, this will
+ /// validate either a simple identifier, or a qualified
+ /// <code>context.identifier</code> name.
+ ///
+ /// \returns true if the name is a valid swift name for \p D, false otherwise.
+ bool DiagnoseSwiftName(Decl *D, StringRef Name,
+ SourceLocation ArgLoc,
+ IdentifierInfo *AttrName);
+
private:
bool RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
TypeDiagnoser *Diagnoser);
@@ -1777,6 +1802,8 @@
ParmVarDecl *BuildParmVarDeclForTypedef(DeclContext *DC,
SourceLocation Loc,
QualType T);
+ QualType adjustParameterTypeForObjCAutoRefCount(QualType T,
+ SourceLocation Loc);
ParmVarDecl *CheckParameter(DeclContext *DC, SourceLocation StartLoc,
SourceLocation NameLoc, IdentifierInfo *Name,
QualType T, TypeSourceInfo *TSInfo,
@@ -2263,6 +2290,9 @@
unsigned AttrSpellingListIndex);
OptimizeNoneAttr *mergeOptimizeNoneAttr(Decl *D, SourceRange Range,
unsigned AttrSpellingListIndex);
+ SwiftNameAttr *mergeSwiftNameAttr(Decl *D, SourceRange Range,
+ StringRef Name, bool Override,
+ unsigned AttrSpellingListIndex);
InternalLinkageAttr *mergeInternalLinkageAttr(Decl *D, SourceRange Range,
IdentifierInfo *Ident,
unsigned AttrSpellingListIndex);
@@ -3105,6 +3135,12 @@
void checkUnusedDeclAttributes(Declarator &D);
+ /// Map any API notes provided for this declaration to attributes on the
+ /// declaration.
+ ///
+ /// Triggered by declaration-attribute processing.
+ void ProcessAPINotes(Decl *D);
+
/// Determine if type T is a valid subject for a nonnull and similar
/// attributes. By default, we look through references (the behavior used by
/// nonnull), but if the second parameter is true, then we treat a reference
@@ -3159,11 +3195,16 @@
/// \param allowArrayTypes Whether to accept nullability specifiers on an
/// array type (e.g., because it will decay to a pointer).
///
+ /// \param overrideExisting Whether to override an existing, locally-specified
+ /// nullability specifier rather than complaining about the conflict.
+ ///
/// \returns true if nullability cannot be applied, false otherwise.
bool checkNullabilityTypeSpecifier(QualType &type, NullabilityKind nullability,
SourceLocation nullabilityLoc,
bool isContextSensitive,
- bool allowArrayTypes);
+ bool allowArrayTypes,
+ bool implicit,
+ bool overrideExisting = false);
/// \brief Stmt attributes - this routine is the top level dispatcher.
StmtResult ProcessStmtAttributes(Stmt *Stmt, AttributeList *Attrs,
@@ -7928,6 +7969,12 @@
RTC_Unknown
};
+ /// Check whether the declared result type of the given Objective-C
+ /// method declaration is compatible with the method's class.
+ ResultTypeCompatibilityKind
+ checkRelatedResultTypeCompatibility(const ObjCMethodDecl *Method,
+ const ObjCInterfaceDecl *CurrentClass);
+
void CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod,
ObjCInterfaceDecl *CurrentClass,
ResultTypeCompatibilityKind RTC);
@@ -10107,6 +10154,7 @@
/// The struct behind the CFErrorRef pointer.
RecordDecl *CFError = nullptr;
+ bool isCFError(RecordDecl *D);
/// Retrieve the identifier "NSError".
IdentifierInfo *getNSErrorIdent();
diff --git a/include/clang/Serialization/ASTDeserializationListener.h b/include/clang/Serialization/ASTDeserializationListener.h
index 4b10c39..c26f3e0 100644
--- a/include/clang/Serialization/ASTDeserializationListener.h
+++ b/include/clang/Serialization/ASTDeserializationListener.h
@@ -26,6 +26,7 @@
class MacroDefinitionRecord;
class MacroInfo;
class Module;
+class SourceLocation;
class ASTDeserializationListener {
public:
@@ -52,6 +53,9 @@
MacroDefinitionRecord *MD) {}
/// \brief A module definition was read from the AST file.
virtual void ModuleRead(serialization::SubmoduleID ID, Module *Mod) {}
+ /// \brief A module import was read from the AST file.
+ virtual void ModuleImportRead(serialization::SubmoduleID ID,
+ SourceLocation ImportLoc) {}
};
}
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h
index 93994e2..3282eb0 100644
--- a/include/clang/Serialization/ASTReader.h
+++ b/include/clang/Serialization/ASTReader.h
@@ -1268,6 +1268,7 @@
llvm::iterator_range<PreprocessingRecord::iterator>
getModulePreprocessedEntities(ModuleFile &Mod) const;
+public:
class ModuleDeclIterator
: public llvm::iterator_adaptor_base<
ModuleDeclIterator, const serialization::LocalDeclID *,
@@ -1298,6 +1299,7 @@
llvm::iterator_range<ModuleDeclIterator>
getModuleFileLevelDecls(ModuleFile &Mod);
+private:
void PassInterestingDeclsToConsumer();
void PassInterestingDeclToConsumer(Decl *D);
@@ -2189,6 +2191,12 @@
/// \brief Loads comments ranges.
void ReadComments() override;
+ /// Visit all the input files of the given module file.
+ void visitInputFiles(serialization::ModuleFile &MF,
+ bool IncludeSystem, bool Complain,
+ llvm::function_ref<void(const serialization::InputFile &IF,
+ bool isSystem)> Visitor);
+
bool isProcessingUpdateRecords() { return ProcessingUpdateRecords; }
};
diff --git a/include/clang/Serialization/Module.h b/include/clang/Serialization/Module.h
index 58b3149..f0629ed 100644
--- a/include/clang/Serialization/Module.h
+++ b/include/clang/Serialization/Module.h
@@ -210,6 +210,10 @@
/// \brief The input files that have been loaded from this AST file.
std::vector<InputFile> InputFilesLoaded;
+ // All user input files reside at the index range [0, NumUserInputFiles), and
+ // system input files reside at [NumUserInputFiles, InputFilesLoaded.size()).
+ unsigned NumUserInputFiles = 0;
+
/// \brief If non-zero, specifies the time when we last validated input
/// files. Zero means we never validated them.
///
diff --git a/lib/APINotes/APINotesFormat.h b/lib/APINotes/APINotesFormat.h
new file mode 100644
index 0000000..ef3ef73
--- /dev/null
+++ b/lib/APINotes/APINotesFormat.h
@@ -0,0 +1,308 @@
+//===--- APINotesFormat.h - The internals of API notes files ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Contains various constants and helper types to deal with API notes
+/// files.
+///
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_API_NOTES_FORMAT_H
+#define LLVM_CLANG_API_NOTES_FORMAT_H
+
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/PointerEmbeddedInt.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Bitcode/RecordLayout.h"
+
+namespace clang {
+namespace api_notes {
+
+using namespace llvm;
+
+/// Magic number for API notes files.
+const unsigned char API_NOTES_SIGNATURE[] = { 0xE2, 0x9C, 0xA8, 0x01 };
+
+/// API notes file major version number.
+///
+const uint16_t VERSION_MAJOR = 0;
+
+/// API notes file minor version number.
+///
+/// When the format changes IN ANY WAY, this number should be incremented.
+const uint16_t VERSION_MINOR = 21; // Override types
+
+using IdentifierID = PointerEmbeddedInt<unsigned, 31>;
+using IdentifierIDField = BCVBR<16>;
+
+using SelectorID = PointerEmbeddedInt<unsigned, 31>;
+using SelectorIDField = BCVBR<16>;
+
+using StoredContextID = PointerEmbeddedInt<unsigned, 31>;
+
+/// The various types of blocks that can occur within a API notes file.
+///
+/// These IDs must \em not be renumbered or reordered without incrementing
+/// VERSION_MAJOR.
+enum BlockID {
+ /// The control block, which contains all of the information that needs to
+ /// be validated prior to committing to loading the API notes file.
+ ///
+ /// \sa control_block
+ CONTROL_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID,
+
+ /// The identifier data block, which maps identifier strings to IDs.
+ IDENTIFIER_BLOCK_ID,
+
+ /// The Objective-C context data block, which contains information about
+ /// Objective-C classes and protocols.
+ OBJC_CONTEXT_BLOCK_ID,
+
+ /// The Objective-C property data block, which maps Objective-C
+ /// (class name, property name) pairs to information about the
+ /// property.
+ OBJC_PROPERTY_BLOCK_ID,
+
+ /// The Objective-C property data block, which maps Objective-C
+ /// (class name, selector, is_instance_method) tuples to information
+ /// about the method.
+ OBJC_METHOD_BLOCK_ID,
+
+ /// The Objective-C selector data block, which maps Objective-C
+ /// selector names (# of pieces, identifier IDs) to the selector ID
+ /// used in other tables.
+ OBJC_SELECTOR_BLOCK_ID,
+
+ /// The global variables data block, which maps global variable names to
+ /// information about the global variable.
+ GLOBAL_VARIABLE_BLOCK_ID,
+
+ /// The (global) functions data block, which maps global function names to
+ /// information about the global function.
+ GLOBAL_FUNCTION_BLOCK_ID,
+
+ /// The tag data block, which maps tag names to information about
+ /// the tags.
+ TAG_BLOCK_ID,
+
+ /// The typedef data block, which maps typedef names to information about
+ /// the typedefs.
+ TYPEDEF_BLOCK_ID,
+
+ /// The enum constant data block, which maps enumerator names to
+ /// information about the enumerators.
+ ENUM_CONSTANT_BLOCK_ID,
+};
+
+namespace control_block {
+ // These IDs must \em not be renumbered or reordered without incrementing
+ // VERSION_MAJOR.
+ enum {
+ METADATA = 1,
+ MODULE_NAME = 2,
+ MODULE_OPTIONS = 3,
+ SOURCE_FILE = 4,
+ };
+
+ using MetadataLayout = BCRecordLayout<
+ METADATA, // ID
+ BCFixed<16>, // Module format major version
+ BCFixed<16> // Module format minor version
+ >;
+
+ using ModuleNameLayout = BCRecordLayout<
+ MODULE_NAME,
+ BCBlob // Module name
+ >;
+
+ using ModuleOptionsLayout = BCRecordLayout<
+ MODULE_OPTIONS,
+ BCFixed<1> // SwiftInferImportAsMember
+ >;
+
+ using SourceFileLayout = BCRecordLayout<
+ SOURCE_FILE,
+ BCVBR<16>, // file size
+ BCVBR<16> // creation time
+ >;
+}
+
+namespace identifier_block {
+ enum {
+ IDENTIFIER_DATA = 1,
+ };
+
+ using IdentifierDataLayout = BCRecordLayout<
+ IDENTIFIER_DATA, // record ID
+ BCVBR<16>, // table offset within the blob (see below)
+ BCBlob // map from identifier strings to decl kinds / decl IDs
+ >;
+}
+
+namespace objc_context_block {
+ enum {
+ OBJC_CONTEXT_ID_DATA = 1,
+ OBJC_CONTEXT_INFO_DATA = 2,
+ };
+
+ using ObjCContextIDLayout = BCRecordLayout<
+ OBJC_CONTEXT_ID_DATA, // record ID
+ BCVBR<16>, // table offset within the blob (see below)
+ BCBlob // map from ObjC class names/protocol (as IDs) to context IDs
+ >;
+
+ using ObjCContextInfoLayout = BCRecordLayout<
+ OBJC_CONTEXT_INFO_DATA, // record ID
+ BCVBR<16>, // table offset within the blob (see below)
+ BCBlob // map from ObjC context IDs to context information.
+ >;
+}
+
+namespace objc_property_block {
+ enum {
+ OBJC_PROPERTY_DATA = 1,
+ };
+
+ using ObjCPropertyDataLayout = BCRecordLayout<
+ OBJC_PROPERTY_DATA, // record ID
+ BCVBR<16>, // table offset within the blob (see below)
+ BCBlob // map from ObjC (class name, property name) pairs to ObjC
+ // property information
+ >;
+}
+
+namespace objc_method_block {
+ enum {
+ OBJC_METHOD_DATA = 1,
+ };
+
+ using ObjCMethodDataLayout = BCRecordLayout<
+ OBJC_METHOD_DATA, // record ID
+ BCVBR<16>, // table offset within the blob (see below)
+ BCBlob // map from ObjC (class names, selector,
+ // is-instance-method) tuples to ObjC method information
+ >;
+}
+
+namespace objc_selector_block {
+ enum {
+ OBJC_SELECTOR_DATA = 1,
+ };
+
+ using ObjCSelectorDataLayout = BCRecordLayout<
+ OBJC_SELECTOR_DATA, // record ID
+ BCVBR<16>, // table offset within the blob (see below)
+ BCBlob // map from (# pieces, identifier IDs) to Objective-C selector ID.
+ >;
+}
+
+namespace global_variable_block {
+ enum {
+ GLOBAL_VARIABLE_DATA = 1
+ };
+
+ using GlobalVariableDataLayout = BCRecordLayout<
+ GLOBAL_VARIABLE_DATA, // record ID
+ BCVBR<16>, // table offset within the blob (see below)
+ BCBlob // map from name to global variable information
+ >;
+}
+
+namespace global_function_block {
+ enum {
+ GLOBAL_FUNCTION_DATA = 1
+ };
+
+ using GlobalFunctionDataLayout = BCRecordLayout<
+ GLOBAL_FUNCTION_DATA, // record ID
+ BCVBR<16>, // table offset within the blob (see below)
+ BCBlob // map from name to global function information
+ >;
+}
+
+namespace tag_block {
+ enum {
+ TAG_DATA = 1
+ };
+
+ using TagDataLayout = BCRecordLayout<
+ TAG_DATA, // record ID
+ BCVBR<16>, // table offset within the blob (see below)
+ BCBlob // map from name to tag information
+ >;
+};
+
+namespace typedef_block {
+ enum {
+ TYPEDEF_DATA = 1
+ };
+
+ using TypedefDataLayout = BCRecordLayout<
+ TYPEDEF_DATA, // record ID
+ BCVBR<16>, // table offset within the blob (see below)
+ BCBlob // map from name to typedef information
+ >;
+};
+
+namespace enum_constant_block {
+ enum {
+ ENUM_CONSTANT_DATA = 1
+ };
+
+ using EnumConstantDataLayout = BCRecordLayout<
+ ENUM_CONSTANT_DATA, // record ID
+ BCVBR<16>, // table offset within the blob (see below)
+ BCBlob // map from name to enumerator information
+ >;
+}
+
+/// A stored Objective-C selector.
+struct StoredObjCSelector {
+ unsigned NumPieces;
+ llvm::SmallVector<IdentifierID, 2> Identifiers;
+};
+
+} // end namespace api_notes
+} // end namespace clang
+
+namespace llvm {
+ template<>
+ struct DenseMapInfo<clang::api_notes::StoredObjCSelector> {
+ typedef DenseMapInfo<unsigned> UnsignedInfo;
+
+ static inline clang::api_notes::StoredObjCSelector getEmptyKey() {
+ return clang::api_notes::StoredObjCSelector{
+ UnsignedInfo::getEmptyKey(), { } };
+ }
+
+ static inline clang::api_notes::StoredObjCSelector getTombstoneKey() {
+ return clang::api_notes::StoredObjCSelector{
+ UnsignedInfo::getTombstoneKey(), { } };
+ }
+
+ static unsigned getHashValue(
+ const clang::api_notes::StoredObjCSelector& value) {
+ auto hash = llvm::hash_value(value.NumPieces);
+ hash = hash_combine(hash, value.Identifiers.size());
+ for (auto piece : value.Identifiers)
+ hash = hash_combine(hash, static_cast<unsigned>(piece));
+ // FIXME: Mix upper/lower 32-bit values together to produce
+ // unsigned rather than truncating.
+ return hash;
+ }
+
+ static bool isEqual(const clang::api_notes::StoredObjCSelector &lhs,
+ const clang::api_notes::StoredObjCSelector &rhs) {
+ return lhs.NumPieces == rhs.NumPieces &&
+ lhs.Identifiers == rhs.Identifiers;
+ }
+ };
+}
+
+#endif // LLVM_CLANG_API_NOTES_FORMAT_H
diff --git a/lib/APINotes/APINotesManager.cpp b/lib/APINotes/APINotesManager.cpp
new file mode 100644
index 0000000..832f454
--- /dev/null
+++ b/lib/APINotes/APINotesManager.cpp
@@ -0,0 +1,587 @@
+//===--- APINotesManager.cpp - Manage API Notes Files ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the APINotesManager class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/APINotes/APINotesManager.h"
+#include "clang/APINotes/APINotesOptions.h"
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/APINotes/APINotesYAMLCompiler.h"
+#include "clang/Basic/DiagnosticIDs.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/SourceMgrAdapter.h"
+#include "clang/Basic/Version.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include <sys/stat.h>
+
+using namespace clang;
+using namespace api_notes;
+
+#define DEBUG_TYPE "API Notes"
+STATISTIC(NumHeaderAPINotes,
+ "non-framework API notes files loaded");
+STATISTIC(NumPublicFrameworkAPINotes,
+ "framework public API notes loaded");
+STATISTIC(NumPrivateFrameworkAPINotes,
+ "framework private API notes loaded");
+STATISTIC(NumFrameworksSearched,
+ "frameworks searched");
+STATISTIC(NumDirectoriesSearched,
+ "header directories searched");
+STATISTIC(NumDirectoryCacheHits,
+ "directory cache hits");
+STATISTIC(NumBinaryCacheHits,
+ "binary form cache hits");
+STATISTIC(NumBinaryCacheMisses,
+ "binary form cache misses");
+STATISTIC(NumBinaryCacheRebuilds,
+ "binary form cache rebuilds");
+
+namespace {
+ /// Prints two successive strings, which much be kept alive as long as the
+ /// PrettyStackTrace entry.
+ class PrettyStackTraceDoubleString : public llvm::PrettyStackTraceEntry {
+ StringRef First, Second;
+ public:
+ PrettyStackTraceDoubleString(StringRef first, StringRef second)
+ : First(first), Second(second) {}
+ void print(raw_ostream &OS) const override {
+ OS << First << Second;
+ }
+ };
+}
+
+APINotesManager::APINotesManager(SourceManager &sourceMgr,
+ const LangOptions &langOpts)
+ : SourceMgr(sourceMgr), ImplicitAPINotes(langOpts.APINotes),
+ PrunedCache(false) { }
+
+APINotesManager::~APINotesManager() {
+ // Free the API notes readers.
+ for (const auto &entry : Readers) {
+ if (auto reader = entry.second.dyn_cast<APINotesReader *>()) {
+ delete reader;
+ }
+ }
+
+ delete CurrentModuleReaders[0];
+ delete CurrentModuleReaders[1];
+}
+
+/// \brief Write a new timestamp file with the given path.
+static void writeTimestampFile(StringRef TimestampFile) {
+ std::error_code EC;
+ llvm::raw_fd_ostream Out(TimestampFile.str(), EC, llvm::sys::fs::F_None);
+}
+
+/// \brief Prune the API notes cache of API notes that haven't been accessed in
+/// a long time.
+static void pruneAPINotesCache(StringRef APINotesCachePath) {
+ struct stat StatBuf;
+ llvm::SmallString<128> TimestampFile;
+ TimestampFile = APINotesCachePath;
+ llvm::sys::path::append(TimestampFile, "APINotes.timestamp");
+
+ // Try to stat() the timestamp file.
+ if (::stat(TimestampFile.c_str(), &StatBuf)) {
+ // If the timestamp file wasn't there, create one now.
+ if (errno == ENOENT) {
+ llvm::sys::fs::create_directories(APINotesCachePath);
+ writeTimestampFile(TimestampFile);
+ }
+ return;
+ }
+
+ const unsigned APINotesCachePruneInterval = 7 * 24 * 60 * 60;
+ const unsigned APINotesCachePruneAfter = 31 * 24 * 60 * 60;
+
+ // Check whether the time stamp is older than our pruning interval.
+ // If not, do nothing.
+ time_t TimeStampModTime = StatBuf.st_mtime;
+ time_t CurrentTime = time(nullptr);
+ if (CurrentTime - TimeStampModTime <= time_t(APINotesCachePruneInterval))
+ return;
+
+ // Write a new timestamp file so that nobody else attempts to prune.
+ // There is a benign race condition here, if two Clang instances happen to
+ // notice at the same time that the timestamp is out-of-date.
+ writeTimestampFile(TimestampFile);
+
+ // Walk the entire API notes cache, looking for unused compiled API notes.
+ std::error_code EC;
+ SmallString<128> APINotesCachePathNative;
+ llvm::sys::path::native(APINotesCachePath, APINotesCachePathNative);
+ for (llvm::sys::fs::directory_iterator
+ File(APINotesCachePathNative.str(), EC), DirEnd;
+ File != DirEnd && !EC; File.increment(EC)) {
+ StringRef Extension = llvm::sys::path::extension(File->path());
+ if (Extension.empty())
+ continue;
+
+ if (Extension.substr(1) != BINARY_APINOTES_EXTENSION)
+ continue;
+
+ // Look at this file. If we can't stat it, there's nothing interesting
+ // there.
+ if (::stat(File->path().c_str(), &StatBuf))
+ continue;
+
+ // If the file has been used recently enough, leave it there.
+ time_t FileAccessTime = StatBuf.st_atime;
+ if (CurrentTime - FileAccessTime <= time_t(APINotesCachePruneAfter)) {
+ continue;
+ }
+
+ // Remove the file.
+ llvm::sys::fs::remove(File->path());
+ }
+}
+
+std::unique_ptr<APINotesReader>
+APINotesManager::loadAPINotes(const FileEntry *apiNotesFile) {
+ FileManager &fileMgr = SourceMgr.getFileManager();
+ PrettyStackTraceDoubleString trace("Loading API notes from ",
+ apiNotesFile->getName());
+
+ // If the API notes file is already in the binary form, load it directly.
+ StringRef apiNotesFileName = apiNotesFile->getName();
+ StringRef apiNotesFileExt = llvm::sys::path::extension(apiNotesFileName);
+ if (!apiNotesFileExt.empty() &&
+ apiNotesFileExt.substr(1) == BINARY_APINOTES_EXTENSION) {
+ auto compiledFileID = SourceMgr.createFileID(apiNotesFile, SourceLocation(), SrcMgr::C_User);
+
+ // Load the file.
+ auto buffer = SourceMgr.getBuffer(compiledFileID, SourceLocation());
+ if (!buffer) return nullptr;
+
+ // Load the binary form.
+ return APINotesReader::getUnmanaged(buffer, SwiftVersion);
+ }
+
+ // If we haven't pruned the API notes cache yet during this execution, do
+ // so now.
+ if (!PrunedCache) {
+ pruneAPINotesCache(fileMgr.getFileSystemOpts().APINotesCachePath);
+ PrunedCache = true;
+ }
+
+ // Compute a hash of the API notes file's directory and the Clang version,
+ // to be used as part of the filename for the cached binary copy.
+ auto code = llvm::hash_value(StringRef(apiNotesFile->getDir()->getName()));
+ code = hash_combine(code, getClangFullRepositoryVersion());
+
+ // Determine the file name for the cached binary form.
+ SmallString<128> compiledFileName;
+ compiledFileName += fileMgr.getFileSystemOpts().APINotesCachePath;
+ assert(!compiledFileName.empty() && "No API notes cache path provided?");
+ llvm::sys::path::append(compiledFileName,
+ (llvm::Twine(llvm::sys::path::stem(apiNotesFileName)) + "-"
+ + llvm::APInt(64, code).toString(36, /*Signed=*/false) + "."
+ + BINARY_APINOTES_EXTENSION));
+
+ // Try to open the cached binary form.
+ if (const FileEntry *compiledFile = fileMgr.getFile(compiledFileName,
+ /*openFile=*/true,
+ /*cacheFailure=*/false)) {
+ // Load the file contents.
+ if (auto buffer = fileMgr.getBufferForFile(compiledFile)) {
+ // Load the file.
+ if (auto reader = APINotesReader::get(std::move(buffer.get()),
+ SwiftVersion)) {
+ bool outOfDate = false;
+ if (auto sizeAndModTime = reader->getSourceFileSizeAndModTime()) {
+ if (sizeAndModTime->first != apiNotesFile->getSize() ||
+ sizeAndModTime->second != apiNotesFile->getModificationTime())
+ outOfDate = true;
+ }
+
+ if (!outOfDate) {
+ // Success.
+ ++NumBinaryCacheHits;
+ return reader;
+ }
+ }
+ }
+
+ // The cache entry was somehow broken; delete this one so we can build a
+ // new one below.
+ llvm::sys::fs::remove(compiledFileName.str());
+ ++NumBinaryCacheRebuilds;
+ } else {
+ ++NumBinaryCacheMisses;
+ }
+
+ // Open the source file.
+ auto sourceFileID = SourceMgr.createFileID(apiNotesFile, SourceLocation(), SrcMgr::C_User);
+ auto sourceBuffer = SourceMgr.getBuffer(sourceFileID, SourceLocation());
+ if (!sourceBuffer) return nullptr;
+
+ // Compile the API notes source into a buffer.
+ // FIXME: Either propagate OSType through or, better yet, improve the binary
+ // APINotes format to maintain complete availability information.
+ llvm::SmallVector<char, 1024> apiNotesBuffer;
+ std::unique_ptr<llvm::MemoryBuffer> compiledBuffer;
+ {
+ SourceMgrAdapter srcMgrAdapter(SourceMgr, SourceMgr.getDiagnostics(),
+ diag::err_apinotes_message,
+ diag::warn_apinotes_message,
+ diag::note_apinotes_message,
+ apiNotesFile);
+ llvm::raw_svector_ostream OS(apiNotesBuffer);
+ if (api_notes::compileAPINotes(sourceBuffer->getBuffer(),
+ SourceMgr.getFileEntryForID(sourceFileID),
+ OS,
+ api_notes::OSType::Absent,
+ srcMgrAdapter.getDiagHandler(),
+ srcMgrAdapter.getDiagContext()))
+ return nullptr;
+
+ // Make a copy of the compiled form into the buffer.
+ compiledBuffer = llvm::MemoryBuffer::getMemBufferCopy(
+ StringRef(apiNotesBuffer.data(), apiNotesBuffer.size()));
+ }
+
+ // Save the binary form into the cache. Perform this operation
+ // atomically.
+ SmallString<64> temporaryBinaryFileName = compiledFileName.str();
+ temporaryBinaryFileName.erase(
+ temporaryBinaryFileName.end()
+ - llvm::sys::path::extension(temporaryBinaryFileName).size(),
+ temporaryBinaryFileName.end());
+ temporaryBinaryFileName += "-%%%%%%.";
+ temporaryBinaryFileName += BINARY_APINOTES_EXTENSION;
+
+ int temporaryFD;
+ llvm::sys::fs::create_directories(
+ fileMgr.getFileSystemOpts().APINotesCachePath);
+ if (!llvm::sys::fs::createUniqueFile(temporaryBinaryFileName.str(),
+ temporaryFD, temporaryBinaryFileName)) {
+ // Write the contents of the buffer.
+ bool hadError;
+ {
+ llvm::raw_fd_ostream out(temporaryFD, /*shouldClose=*/true);
+ out.write(compiledBuffer.get()->getBufferStart(),
+ compiledBuffer.get()->getBufferSize());
+ out.flush();
+
+ hadError = out.has_error();
+ }
+
+ if (!hadError) {
+ // Rename the temporary file to the actual compiled file.
+ llvm::sys::fs::rename(temporaryBinaryFileName.str(),
+ compiledFileName.str());
+ }
+ }
+
+ // Load the binary form we just compiled.
+ auto reader = APINotesReader::get(std::move(compiledBuffer), SwiftVersion);
+ assert(reader && "Could not load the API notes we just generated?");
+ return reader;
+}
+
+bool APINotesManager::loadAPINotes(const DirectoryEntry *HeaderDir,
+ const FileEntry *APINotesFile) {
+ assert(Readers.find(HeaderDir) == Readers.end());
+ if (auto reader = loadAPINotes(APINotesFile)) {
+ Readers[HeaderDir] = reader.release();
+ return false;
+ }
+
+ Readers[HeaderDir] = nullptr;
+ return true;
+}
+
+const FileEntry *APINotesManager::findAPINotesFile(const DirectoryEntry *directory,
+ StringRef basename,
+ bool wantPublic) {
+ FileManager &fileMgr = SourceMgr.getFileManager();
+
+ llvm::SmallString<128> path;
+ path += directory->getName();
+
+ unsigned pathLen = path.size();
+
+ StringRef basenameSuffix = "";
+ if (!wantPublic) basenameSuffix = "_private";
+
+ // Look for a binary API notes file.
+ llvm::sys::path::append(path,
+ llvm::Twine(basename) + basenameSuffix + "." + BINARY_APINOTES_EXTENSION);
+ if (const FileEntry *binaryFile = fileMgr.getFile(path))
+ return binaryFile;
+
+ // Go back to the original path.
+ path.resize(pathLen);
+
+ // Look for the source API notes file.
+ llvm::sys::path::append(path,
+ llvm::Twine(basename) + basenameSuffix + "." + SOURCE_APINOTES_EXTENSION);
+ return fileMgr.getFile(path);
+}
+
+const DirectoryEntry *APINotesManager::loadFrameworkAPINotes(
+ llvm::StringRef FrameworkPath,
+ llvm::StringRef FrameworkName,
+ bool Public) {
+ FileManager &FileMgr = SourceMgr.getFileManager();
+
+ llvm::SmallString<128> Path;
+ Path += FrameworkPath;
+ unsigned FrameworkNameLength = Path.size();
+
+ // Form the path to the APINotes file.
+ llvm::sys::path::append(Path, "APINotes");
+ if (Public)
+ llvm::sys::path::append(Path,
+ (llvm::Twine(FrameworkName) + "."
+ + SOURCE_APINOTES_EXTENSION));
+ else
+ llvm::sys::path::append(Path,
+ (llvm::Twine(FrameworkName) + "_private."
+ + SOURCE_APINOTES_EXTENSION));
+
+ // Try to open the APINotes file.
+ const FileEntry *APINotesFile = FileMgr.getFile(Path);
+ if (!APINotesFile)
+ return nullptr;
+
+ // Form the path to the corresponding header directory.
+ Path.resize(FrameworkNameLength);
+ if (Public)
+ llvm::sys::path::append(Path, "Headers");
+ else
+ llvm::sys::path::append(Path, "PrivateHeaders");
+
+ // Try to access the header directory.
+ const DirectoryEntry *HeaderDir = FileMgr.getDirectory(Path);
+ if (!HeaderDir)
+ return nullptr;
+
+ // Try to load the API notes.
+ if (loadAPINotes(HeaderDir, APINotesFile))
+ return nullptr;
+
+ // Success: return the header directory.
+ if (Public)
+ ++NumPublicFrameworkAPINotes;
+ else
+ ++NumPrivateFrameworkAPINotes;
+ return HeaderDir;
+}
+
+bool APINotesManager::loadCurrentModuleAPINotes(
+ const Module *module,
+ bool lookInModule,
+ ArrayRef<std::string> searchPaths) {
+ assert(!CurrentModuleReaders[0] &&
+ "Already loaded API notes for the current module?");
+
+ FileManager &fileMgr = SourceMgr.getFileManager();
+ auto moduleName = module->getTopLevelModuleName();
+
+ // First, look relative to the module itself.
+ if (lookInModule) {
+ bool foundAny = false;
+ unsigned numReaders = 0;
+
+ // Local function to try loading an API notes file in the given directory.
+ auto tryAPINotes = [&](const DirectoryEntry *dir, bool wantPublic) {
+ if (auto file = findAPINotesFile(dir, moduleName, wantPublic)) {
+ foundAny = true;
+
+ // Try to load the API notes file.
+ CurrentModuleReaders[numReaders] = loadAPINotes(file).release();
+ if (CurrentModuleReaders[numReaders])
+ ++numReaders;
+ }
+ };
+
+ if (module->IsFramework) {
+ // For frameworks, we search in the "Headers" or "PrivateHeaders"
+ // subdirectory.
+ llvm::SmallString<128> path;
+ path += module->Directory->getName();
+ unsigned pathLen = path.size();
+
+ llvm::sys::path::append(path, "Headers");
+ if (auto apinotesDir = fileMgr.getDirectory(path))
+ tryAPINotes(apinotesDir, /*wantPublic=*/true);
+
+ path.resize(pathLen);
+ llvm::sys::path::append(path, "PrivateHeaders");
+ if (auto privateAPINotesDir = fileMgr.getDirectory(path))
+ tryAPINotes(privateAPINotesDir, /*wantPublic=*/false);
+ } else {
+ tryAPINotes(module->Directory, /*wantPublic=*/true);
+ tryAPINotes(module->Directory, /*wantPublic=*/false);
+ }
+
+ if (foundAny)
+ return numReaders > 0;
+ }
+
+ // Second, look for API notes for this module in the module API
+ // notes search paths.
+ for (const auto &searchPath : searchPaths) {
+ if (auto searchDir = fileMgr.getDirectory(searchPath)) {
+ if (auto file = findAPINotesFile(searchDir, moduleName)) {
+ CurrentModuleReaders[0] = loadAPINotes(file).release();
+ return !getCurrentModuleReaders().empty();
+ }
+ }
+ }
+
+ // Didn't find any API notes.
+ return false;
+}
+
+llvm::SmallVector<APINotesReader *, 2> APINotesManager::findAPINotes(SourceLocation Loc) {
+ llvm::SmallVector<APINotesReader *, 2> Results;
+
+ // If there are readers for the current module, return them.
+ if (!getCurrentModuleReaders().empty()) {
+ Results.append(getCurrentModuleReaders().begin(), getCurrentModuleReaders().end());
+ return Results;
+ }
+
+ // If we're not allowed to implicitly load API notes files, we're done.
+ if (!ImplicitAPINotes) return Results;
+
+ // If we don't have source location information, we're done.
+ if (Loc.isInvalid()) return Results;
+
+ // API notes are associated with the expansion location. Retrieve the
+ // file for this location.
+ SourceLocation ExpansionLoc = SourceMgr.getExpansionLoc(Loc);
+ FileID ID = SourceMgr.getFileID(ExpansionLoc);
+ if (ID.isInvalid()) return Results;
+ const FileEntry *File = SourceMgr.getFileEntryForID(ID);
+ if (!File) return Results;
+
+ // Look for API notes in the directory corresponding to this file, or one of
+ // its its parent directories.
+ const DirectoryEntry *Dir = File->getDir();
+ FileManager &FileMgr = SourceMgr.getFileManager();
+ llvm::SetVector<const DirectoryEntry *,
+ SmallVector<const DirectoryEntry *, 4>,
+ llvm::SmallPtrSet<const DirectoryEntry *, 4>> DirsVisited;
+ do {
+ // Look for an API notes reader for this header search directory.
+ auto Known = Readers.find(Dir);
+
+ // If we already know the answer, chase it.
+ if (Known != Readers.end()) {
+ ++NumDirectoryCacheHits;
+
+ // We've been redirected to another directory for answers. Follow it.
+ if (auto OtherDir = Known->second.dyn_cast<const DirectoryEntry *>()) {
+ DirsVisited.insert(Dir);
+ Dir = OtherDir;
+ continue;
+ }
+
+ // We have the answer.
+ if (auto Reader = Known->second.dyn_cast<APINotesReader *>())
+ Results.push_back(Reader);
+ break;
+ }
+
+ // Look for API notes corresponding to this directory.
+ StringRef Path = Dir->getName();
+ if (llvm::sys::path::extension(Path) == ".framework") {
+ // If this is a framework directory, check whether there are API notes
+ // in the APINotes subdirectory.
+ auto FrameworkName = llvm::sys::path::stem(Path);
+ ++NumFrameworksSearched;
+
+ // Look for API notes for both the public and private headers.
+ const DirectoryEntry *PublicDir
+ = loadFrameworkAPINotes(Path, FrameworkName, /*Public=*/true);
+ const DirectoryEntry *PrivateDir
+ = loadFrameworkAPINotes(Path, FrameworkName, /*Public=*/false);
+
+ if (PublicDir || PrivateDir) {
+ // We found API notes: don't ever look past the framework directory.
+ Readers[Dir] = nullptr;
+
+ // Pretend we found the result in the public or private directory,
+ // as appropriate. All headers should be in one of those two places,
+ // but be defensive here.
+ if (!DirsVisited.empty()) {
+ if (DirsVisited.back() == PublicDir) {
+ DirsVisited.pop_back();
+ Dir = PublicDir;
+ } else if (DirsVisited.back() == PrivateDir) {
+ DirsVisited.pop_back();
+ Dir = PrivateDir;
+ }
+ }
+
+ // Grab the result.
+ if (auto Reader = Readers[Dir].dyn_cast<APINotesReader *>())
+ Results.push_back(Reader);
+ break;
+ }
+ } else {
+ // Look for an APINotes file in this directory.
+ llvm::SmallString<128> APINotesPath;
+ APINotesPath += Dir->getName();
+ llvm::sys::path::append(APINotesPath,
+ (llvm::Twine("APINotes.")
+ + SOURCE_APINOTES_EXTENSION));
+
+ // If there is an API notes file here, try to load it.
+ ++NumDirectoriesSearched;
+ if (const FileEntry *APINotesFile = FileMgr.getFile(APINotesPath)) {
+ if (!loadAPINotes(Dir, APINotesFile)) {
+ ++NumHeaderAPINotes;
+ if (auto Reader = Readers[Dir].dyn_cast<APINotesReader *>())
+ Results.push_back(Reader);
+ break;
+ }
+ }
+ }
+
+ // We didn't find anything. Look at the parent directory.
+ if (!DirsVisited.insert(Dir)) {
+ Dir = 0;
+ break;
+ }
+
+ StringRef ParentPath = llvm::sys::path::parent_path(Path);
+ while (llvm::sys::path::stem(ParentPath) == "..") {
+ ParentPath = llvm::sys::path::parent_path(ParentPath);
+ }
+ if (ParentPath.empty()) {
+ Dir = nullptr;
+ } else {
+ Dir = FileMgr.getDirectory(ParentPath);
+ }
+ } while (Dir);
+
+ // Path compression for all of the directories we visited, redirecting
+ // them to the directory we ended on. If no API notes were found, the
+ // resulting directory will be NULL, indicating no API notes.
+ for (const auto Visited : DirsVisited) {
+ Readers[Visited] = Dir;
+ }
+
+ return Results;
+}
diff --git a/lib/APINotes/APINotesReader.cpp b/lib/APINotes/APINotesReader.cpp
new file mode 100644
index 0000000..8fbe2a1
--- /dev/null
+++ b/lib/APINotes/APINotesReader.cpp
@@ -0,0 +1,1864 @@
+//===--- APINotesReader.cpp - Side Car Reader --------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the \c APINotesReader class that reads source
+// API notes data providing additional information about source code as
+// a separate input, such as the non-nil/nilable annotations for
+// method parameters.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/APINotes/APINotesReader.h"
+#include "APINotesFormat.h"
+#include "llvm/Bitcode/BitstreamReader.h"
+#include "llvm/Support/EndianStream.h"
+#include "llvm/Support/OnDiskHashTable.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/StringExtras.h"
+
+using namespace clang;
+using namespace api_notes;
+using namespace llvm::support;
+using namespace llvm;
+
+namespace {
+ /// Deserialize a version tuple.
+ VersionTuple readVersionTuple(const uint8_t *&data) {
+ uint8_t numVersions = (*data++) & 0x03;
+
+ unsigned major = endian::readNext<uint32_t, little, unaligned>(data);
+ if (numVersions == 0)
+ return VersionTuple(major);
+
+ unsigned minor = endian::readNext<uint32_t, little, unaligned>(data);
+ if (numVersions == 1)
+ return VersionTuple(major, minor);
+
+ unsigned subminor = endian::readNext<uint32_t, little, unaligned>(data);
+ if (numVersions == 2)
+ return VersionTuple(major, minor, subminor);
+
+ unsigned build = endian::readNext<uint32_t, little, unaligned>(data);
+ return VersionTuple(major, minor, subminor, build);
+ }
+
+ /// An on-disk hash table whose data is versioned based on the Swift version.
+ template<typename Derived, typename KeyType, typename UnversionedDataType>
+ class VersionedTableInfo {
+ public:
+ using internal_key_type = KeyType;
+ using external_key_type = KeyType;
+ using data_type = SmallVector<std::pair<VersionTuple, UnversionedDataType>, 1>;
+ using hash_value_type = size_t;
+ using offset_type = unsigned;
+
+ internal_key_type GetInternalKey(external_key_type key) {
+ return key;
+ }
+
+ external_key_type GetExternalKey(internal_key_type key) {
+ return key;
+ }
+
+ hash_value_type ComputeHash(internal_key_type key) {
+ return static_cast<size_t>(llvm::hash_value(key));
+ }
+
+ static bool EqualKey(internal_key_type lhs, internal_key_type rhs) {
+ return lhs == rhs;
+ }
+
+ static std::pair<unsigned, unsigned>
+ ReadKeyDataLength(const uint8_t *&data) {
+ unsigned keyLength = endian::readNext<uint16_t, little, unaligned>(data);
+ unsigned dataLength = endian::readNext<uint16_t, little, unaligned>(data);
+ return { keyLength, dataLength };
+ }
+
+ static data_type ReadData(internal_key_type key, const uint8_t *data,
+ unsigned length) {
+ unsigned numElements = endian::readNext<uint16_t, little, unaligned>(data);
+ data_type result;
+ result.reserve(numElements);
+ for (unsigned i = 0; i != numElements; ++i) {
+ auto version = readVersionTuple(data);
+ auto dataBefore = data; (void)dataBefore;
+ auto unversionedData = Derived::readUnversioned(key, data);
+ assert(data != dataBefore
+ && "Unversioned data reader didn't move pointer");
+ result.push_back({version, unversionedData});
+ }
+ return result;
+ }
+ };
+
+
+ /// Read serialized CommonEntityInfo.
+ void readCommonEntityInfo(const uint8_t *&data, CommonEntityInfo &info) {
+ uint8_t unavailableBits = *data++;
+ info.Unavailable = (unavailableBits >> 1) & 0x01;
+ info.UnavailableInSwift = unavailableBits & 0x01;
+ if ((unavailableBits >> 2) & 0x01)
+ info.setSwiftPrivate(static_cast<bool>((unavailableBits >> 3) & 0x01));
+
+ unsigned msgLength = endian::readNext<uint16_t, little, unaligned>(data);
+ info.UnavailableMsg
+ = std::string(reinterpret_cast<const char *>(data),
+ reinterpret_cast<const char *>(data) + msgLength);
+ data += msgLength;
+
+ unsigned swiftNameLength
+ = endian::readNext<uint16_t, little, unaligned>(data);
+ info.SwiftName
+ = std::string(reinterpret_cast<const char *>(data),
+ reinterpret_cast<const char *>(data) + swiftNameLength);
+ data += swiftNameLength;
+ }
+
+ /// Read serialized CommonTypeInfo.
+ void readCommonTypeInfo(const uint8_t *&data, CommonTypeInfo &info) {
+ readCommonEntityInfo(data, info);
+
+ unsigned swiftBridgeLength =
+ endian::readNext<uint16_t, little, unaligned>(data);
+ if (swiftBridgeLength > 0) {
+ info.setSwiftBridge(
+ std::string(reinterpret_cast<const char *>(data), swiftBridgeLength-1));
+ data += swiftBridgeLength-1;
+ }
+
+ unsigned errorDomainLength =
+ endian::readNext<uint16_t, little, unaligned>(data);
+ if (errorDomainLength > 0) {
+ info.setNSErrorDomain(
+ std::string(reinterpret_cast<const char *>(data), errorDomainLength-1));
+ data += errorDomainLength-1;
+ }
+ }
+
+ /// Used to deserialize the on-disk identifier table.
+ class IdentifierTableInfo {
+ public:
+ using internal_key_type = StringRef;
+ using external_key_type = StringRef;
+ using data_type = IdentifierID;
+ using hash_value_type = uint32_t;
+ using offset_type = unsigned;
+
+ internal_key_type GetInternalKey(external_key_type key) {
+ return key;
+ }
+
+ external_key_type GetExternalKey(internal_key_type key) {
+ return key;
+ }
+
+ hash_value_type ComputeHash(internal_key_type key) {
+ return llvm::HashString(key);
+ }
+
+ static bool EqualKey(internal_key_type lhs, internal_key_type rhs) {
+ return lhs == rhs;
+ }
+
+ static std::pair<unsigned, unsigned>
+ ReadKeyDataLength(const uint8_t *&data) {
+ unsigned keyLength = endian::readNext<uint16_t, little, unaligned>(data);
+ unsigned dataLength = endian::readNext<uint16_t, little, unaligned>(data);
+ return { keyLength, dataLength };
+ }
+
+ static internal_key_type ReadKey(const uint8_t *data, unsigned length) {
+ return StringRef(reinterpret_cast<const char *>(data), length);
+ }
+
+ static data_type ReadData(internal_key_type key, const uint8_t *data,
+ unsigned length) {
+ return endian::readNext<uint32_t, little, unaligned>(data);
+ }
+ };
+
+ /// Used to deserialize the on-disk Objective-C class table.
+ class ObjCContextIDTableInfo {
+ public:
+ // identifier ID, is-protocol
+ using internal_key_type = std::pair<unsigned, char>;
+ using external_key_type = internal_key_type;
+ using data_type = unsigned;
+ using hash_value_type = size_t;
+ using offset_type = unsigned;
+
+ internal_key_type GetInternalKey(external_key_type key) {
+ return key;
+ }
+
+ external_key_type GetExternalKey(internal_key_type key) {
+ return key;
+ }
+
+ hash_value_type ComputeHash(internal_key_type key) {
+ return static_cast<size_t>(llvm::hash_value(key));
+ }
+
+ static bool EqualKey(internal_key_type lhs, internal_key_type rhs) {
+ return lhs == rhs;
+ }
+
+ static std::pair<unsigned, unsigned>
+ ReadKeyDataLength(const uint8_t *&data) {
+ unsigned keyLength = endian::readNext<uint16_t, little, unaligned>(data);
+ unsigned dataLength = endian::readNext<uint16_t, little, unaligned>(data);
+ return { keyLength, dataLength };
+ }
+
+ static internal_key_type ReadKey(const uint8_t *data, unsigned length) {
+ auto nameID
+ = endian::readNext<uint32_t, little, unaligned>(data);
+ auto isProtocol = endian::readNext<uint8_t, little, unaligned>(data);
+ return { nameID, isProtocol };
+ }
+
+ static data_type ReadData(internal_key_type key, const uint8_t *data,
+ unsigned length) {
+ return endian::readNext<uint32_t, little, unaligned>(data);
+ }
+ };
+
+ /// Used to deserialize the on-disk Objective-C property table.
+ class ObjCContextInfoTableInfo
+ : public VersionedTableInfo<ObjCContextInfoTableInfo,
+ unsigned,
+ ObjCContextInfo>
+ {
+ public:
+ static internal_key_type ReadKey(const uint8_t *data, unsigned length) {
+ return endian::readNext<uint32_t, little, unaligned>(data);
+ }
+
+ static ObjCContextInfo readUnversioned(internal_key_type key,
+ const uint8_t *&data) {
+ ObjCContextInfo info;
+ readCommonTypeInfo(data, info);
+ uint8_t payload = *data++;
+
+ if (payload & 0x01)
+ info.setHasDesignatedInits(true);
+ payload = payload >> 1;
+
+ if (payload & 0x4)
+ info.setDefaultNullability(static_cast<NullabilityKind>(payload&0x03));
+
+ return info;
+ }
+ };
+
+ /// Read serialized VariableInfo.
+ void readVariableInfo(const uint8_t *&data, VariableInfo &info) {
+ readCommonEntityInfo(data, info);
+ if (*data++) {
+ info.setNullabilityAudited(static_cast<NullabilityKind>(*data));
+ }
+ ++data;
+
+ auto typeLen
+ = endian::readNext<uint16_t, little, unaligned>(data);
+ info.setType(std::string(data, data + typeLen));
+ data += typeLen;
+ }
+
+ /// Used to deserialize the on-disk Objective-C property table.
+ class ObjCPropertyTableInfo
+ : public VersionedTableInfo<ObjCPropertyTableInfo,
+ std::tuple<unsigned, unsigned, char>,
+ ObjCPropertyInfo>
+ {
+ public:
+ static internal_key_type ReadKey(const uint8_t *data, unsigned length) {
+ auto classID = endian::readNext<uint32_t, little, unaligned>(data);
+ auto nameID = endian::readNext<uint32_t, little, unaligned>(data);
+ char isInstance = endian::readNext<uint8_t, little, unaligned>(data);
+ return std::make_tuple(classID, nameID, isInstance);
+ }
+
+ static ObjCPropertyInfo readUnversioned(internal_key_type key,
+ const uint8_t *&data) {
+ ObjCPropertyInfo info;
+ readVariableInfo(data, info);
+ uint8_t flags = *data++;
+ if (flags & (1 << 0))
+ info.setSwiftImportAsAccessors(flags & (1 << 1));
+ return info;
+ }
+ };
+
+ /// Read serialized ParamInfo.
+ void readParamInfo(const uint8_t *&data, ParamInfo &info) {
+ readVariableInfo(data, info);
+
+ uint8_t payload = endian::readNext<uint8_t, little, unaligned>(data);
+ if (payload & 0x01) {
+ info.setNoEscape(payload & 0x02);
+ }
+ payload >>= 2; assert(payload == 0 && "Bad API notes");
+ }
+
+ /// Read serialized FunctionInfo.
+ void readFunctionInfo(const uint8_t *&data, FunctionInfo &info) {
+ readCommonEntityInfo(data, info);
+ info.NullabilityAudited
+ = endian::readNext<uint8_t, little, unaligned>(data);
+ info.NumAdjustedNullable
+ = endian::readNext<uint8_t, little, unaligned>(data);
+ info.NullabilityPayload
+ = endian::readNext<uint64_t, little, unaligned>(data);
+
+ unsigned numParams = endian::readNext<uint16_t, little, unaligned>(data);
+ while (numParams > 0) {
+ ParamInfo pi;
+ readParamInfo(data, pi);
+ info.Params.push_back(pi);
+ --numParams;
+ }
+
+ unsigned resultTypeLen
+ = endian::readNext<uint16_t, little, unaligned>(data);
+ info.ResultType = std::string(data, data + resultTypeLen);
+ data += resultTypeLen;
+ }
+
+ /// Used to deserialize the on-disk Objective-C method table.
+ class ObjCMethodTableInfo
+ : public VersionedTableInfo<ObjCMethodTableInfo,
+ std::tuple<unsigned, unsigned, char>,
+ ObjCMethodInfo> {
+ public:
+ static internal_key_type ReadKey(const uint8_t *data, unsigned length) {
+ auto classID = endian::readNext<uint32_t, little, unaligned>(data);
+ auto selectorID = endian::readNext<uint32_t, little, unaligned>(data);
+ auto isInstance = endian::readNext<uint8_t, little, unaligned>(data);
+ return internal_key_type{ classID, selectorID, isInstance };
+ }
+
+ static ObjCMethodInfo readUnversioned(internal_key_type key,
+ const uint8_t *&data) {
+ ObjCMethodInfo info;
+ uint8_t payload = *data++;
+ info.Required = payload & 0x01;
+ payload >>= 1;
+ info.DesignatedInit = payload & 0x01;
+ payload >>= 1;
+ info.FactoryAsInit = payload & 0x03;
+ payload >>= 2;
+
+ readFunctionInfo(data, info);
+ return info;
+ }
+ };
+
+ /// Used to deserialize the on-disk Objective-C selector table.
+ class ObjCSelectorTableInfo {
+ public:
+ using internal_key_type = StoredObjCSelector;
+ using external_key_type = internal_key_type;
+ using data_type = SelectorID;
+ using hash_value_type = unsigned;
+ using offset_type = unsigned;
+
+ internal_key_type GetInternalKey(external_key_type key) {
+ return key;
+ }
+
+ external_key_type GetExternalKey(internal_key_type key) {
+ return key;
+ }
+
+ hash_value_type ComputeHash(internal_key_type key) {
+ return llvm::DenseMapInfo<StoredObjCSelector>::getHashValue(key);
+ }
+
+ static bool EqualKey(internal_key_type lhs, internal_key_type rhs) {
+ return llvm::DenseMapInfo<StoredObjCSelector>::isEqual(lhs, rhs);
+ }
+
+ static std::pair<unsigned, unsigned>
+ ReadKeyDataLength(const uint8_t *&data) {
+ unsigned keyLength = endian::readNext<uint16_t, little, unaligned>(data);
+ unsigned dataLength = endian::readNext<uint16_t, little, unaligned>(data);
+ return { keyLength, dataLength };
+ }
+
+ static internal_key_type ReadKey(const uint8_t *data, unsigned length) {
+ internal_key_type key;
+ key.NumPieces = endian::readNext<uint16_t, little, unaligned>(data);
+ unsigned numIdents = (length - sizeof(uint16_t)) / sizeof(uint32_t);
+ for (unsigned i = 0; i != numIdents; ++i) {
+ key.Identifiers.push_back(
+ endian::readNext<uint32_t, little, unaligned>(data));
+ }
+ return key;
+ }
+
+ static data_type ReadData(internal_key_type key, const uint8_t *data,
+ unsigned length) {
+ return endian::readNext<uint32_t, little, unaligned>(data);
+ }
+ };
+
+ /// Used to deserialize the on-disk global variable table.
+ class GlobalVariableTableInfo
+ : public VersionedTableInfo<GlobalVariableTableInfo, unsigned,
+ GlobalVariableInfo> {
+ public:
+ static internal_key_type ReadKey(const uint8_t *data, unsigned length) {
+ auto nameID = endian::readNext<uint32_t, little, unaligned>(data);
+ return nameID;
+ }
+
+ static GlobalVariableInfo readUnversioned(internal_key_type key,
+ const uint8_t *&data) {
+ GlobalVariableInfo info;
+ readVariableInfo(data, info);
+ return info;
+ }
+ };
+
+ /// Used to deserialize the on-disk global function table.
+ class GlobalFunctionTableInfo
+ : public VersionedTableInfo<GlobalFunctionTableInfo, unsigned,
+ GlobalFunctionInfo> {
+ public:
+ static internal_key_type ReadKey(const uint8_t *data, unsigned length) {
+ auto nameID = endian::readNext<uint32_t, little, unaligned>(data);
+ return nameID;
+ }
+
+ static GlobalFunctionInfo readUnversioned(internal_key_type key,
+ const uint8_t *&data) {
+ GlobalFunctionInfo info;
+ readFunctionInfo(data, info);
+ return info;
+ }
+ };
+
+ /// Used to deserialize the on-disk enumerator table.
+ class EnumConstantTableInfo
+ : public VersionedTableInfo<EnumConstantTableInfo, unsigned,
+ EnumConstantInfo> {
+ public:
+ static internal_key_type ReadKey(const uint8_t *data, unsigned length) {
+ auto nameID = endian::readNext<uint32_t, little, unaligned>(data);
+ return nameID;
+ }
+
+ static EnumConstantInfo readUnversioned(internal_key_type key,
+ const uint8_t *&data) {
+ EnumConstantInfo info;
+ readCommonEntityInfo(data, info);
+ return info;
+ }
+ };
+
+ /// Used to deserialize the on-disk tag table.
+ class TagTableInfo
+ : public VersionedTableInfo<TagTableInfo, unsigned, TagInfo> {
+ public:
+ static internal_key_type ReadKey(const uint8_t *data, unsigned length) {
+ auto nameID = endian::readNext<IdentifierID, little, unaligned>(data);
+ return nameID;
+ }
+
+ static TagInfo readUnversioned(internal_key_type key,
+ const uint8_t *&data) {
+ TagInfo info;
+ readCommonTypeInfo(data, info);
+ return info;
+ }
+ };
+
+ /// Used to deserialize the on-disk typedef table.
+ class TypedefTableInfo
+ : public VersionedTableInfo<TypedefTableInfo, unsigned, TypedefInfo> {
+ public:
+ static internal_key_type ReadKey(const uint8_t *data, unsigned length) {
+ auto nameID = endian::readNext<IdentifierID, little, unaligned>(data);
+ return nameID;
+ }
+
+ static TypedefInfo readUnversioned(internal_key_type key,
+ const uint8_t *&data) {
+ TypedefInfo info;
+
+ uint8_t payload = *data++;
+ if (payload > 0) {
+ info.SwiftWrapper = static_cast<SwiftWrapperKind>((payload & 0x3) - 1);
+ }
+
+ readCommonTypeInfo(data, info);
+ return info;
+ }
+ };
+} // end anonymous namespace
+
+class APINotesReader::Implementation {
+public:
+ /// The input buffer for the API notes data.
+ llvm::MemoryBuffer *InputBuffer;
+
+ /// Whether we own the input buffer.
+ bool OwnsInputBuffer;
+
+ /// The Swift version to use for filtering.
+ VersionTuple SwiftVersion;
+
+ /// The name of the module that we read from the control block.
+ std::string ModuleName;
+
+ // The size and modification time of the source file from
+ // which this API notes file was created, if known.
+ Optional<std::pair<off_t, time_t>> SourceFileSizeAndModTime;
+
+ /// Various options and attributes for the module
+ ModuleOptions ModuleOpts;
+
+ using SerializedIdentifierTable =
+ llvm::OnDiskIterableChainedHashTable<IdentifierTableInfo>;
+
+ /// The identifier table.
+ std::unique_ptr<SerializedIdentifierTable> IdentifierTable;
+
+ using SerializedObjCContextIDTable =
+ llvm::OnDiskIterableChainedHashTable<ObjCContextIDTableInfo>;
+
+ /// The Objective-C context ID table.
+ std::unique_ptr<SerializedObjCContextIDTable> ObjCContextIDTable;
+
+ using SerializedObjCContextInfoTable =
+ llvm::OnDiskIterableChainedHashTable<ObjCContextInfoTableInfo>;
+
+ /// The Objective-C context info table.
+ std::unique_ptr<SerializedObjCContextInfoTable> ObjCContextInfoTable;
+
+ using SerializedObjCPropertyTable =
+ llvm::OnDiskIterableChainedHashTable<ObjCPropertyTableInfo>;
+
+ /// The Objective-C property table.
+ std::unique_ptr<SerializedObjCPropertyTable> ObjCPropertyTable;
+
+ using SerializedObjCMethodTable =
+ llvm::OnDiskIterableChainedHashTable<ObjCMethodTableInfo>;
+
+ /// The Objective-C method table.
+ std::unique_ptr<SerializedObjCMethodTable> ObjCMethodTable;
+
+ using SerializedObjCSelectorTable =
+ llvm::OnDiskIterableChainedHashTable<ObjCSelectorTableInfo>;
+
+ /// The Objective-C selector table.
+ std::unique_ptr<SerializedObjCSelectorTable> ObjCSelectorTable;
+
+ using SerializedGlobalVariableTable =
+ llvm::OnDiskIterableChainedHashTable<GlobalVariableTableInfo>;
+
+ /// The global variable table.
+ std::unique_ptr<SerializedGlobalVariableTable> GlobalVariableTable;
+
+ using SerializedGlobalFunctionTable =
+ llvm::OnDiskIterableChainedHashTable<GlobalFunctionTableInfo>;
+
+ /// The global function table.
+ std::unique_ptr<SerializedGlobalFunctionTable> GlobalFunctionTable;
+
+ using SerializedEnumConstantTable =
+ llvm::OnDiskIterableChainedHashTable<EnumConstantTableInfo>;
+
+ /// The enumerator table.
+ std::unique_ptr<SerializedEnumConstantTable> EnumConstantTable;
+
+ using SerializedTagTable =
+ llvm::OnDiskIterableChainedHashTable<TagTableInfo>;
+
+ /// The tag table.
+ std::unique_ptr<SerializedTagTable> TagTable;
+
+ using SerializedTypedefTable =
+ llvm::OnDiskIterableChainedHashTable<TypedefTableInfo>;
+
+ /// The typedef table.
+ std::unique_ptr<SerializedTypedefTable> TypedefTable;
+
+ /// Retrieve the identifier ID for the given string, or an empty
+ /// optional if the string is unknown.
+ Optional<IdentifierID> getIdentifier(StringRef str);
+
+ /// Retrieve the selector ID for the given selector, or an empty
+ /// optional if the string is unknown.
+ Optional<SelectorID> getSelector(ObjCSelectorRef selector);
+
+ bool readControlBlock(llvm::BitstreamCursor &cursor,
+ SmallVectorImpl<uint64_t> &scratch);
+ bool readIdentifierBlock(llvm::BitstreamCursor &cursor,
+ SmallVectorImpl<uint64_t> &scratch);
+ bool readObjCContextBlock(llvm::BitstreamCursor &cursor,
+ SmallVectorImpl<uint64_t> &scratch);
+ bool readObjCPropertyBlock(llvm::BitstreamCursor &cursor,
+ SmallVectorImpl<uint64_t> &scratch);
+ bool readObjCMethodBlock(llvm::BitstreamCursor &cursor,
+ SmallVectorImpl<uint64_t> &scratch);
+ bool readObjCSelectorBlock(llvm::BitstreamCursor &cursor,
+ SmallVectorImpl<uint64_t> &scratch);
+ bool readGlobalVariableBlock(llvm::BitstreamCursor &cursor,
+ SmallVectorImpl<uint64_t> &scratch);
+ bool readGlobalFunctionBlock(llvm::BitstreamCursor &cursor,
+ SmallVectorImpl<uint64_t> &scratch);
+ bool readEnumConstantBlock(llvm::BitstreamCursor &cursor,
+ SmallVectorImpl<uint64_t> &scratch);
+ bool readTagBlock(llvm::BitstreamCursor &cursor,
+ SmallVectorImpl<uint64_t> &scratch);
+ bool readTypedefBlock(llvm::BitstreamCursor &cursor,
+ SmallVectorImpl<uint64_t> &scratch);
+};
+
+Optional<IdentifierID> APINotesReader::Implementation::getIdentifier(
+ StringRef str) {
+ if (!IdentifierTable)
+ return None;
+
+ if (str.empty())
+ return IdentifierID(0);
+
+ auto known = IdentifierTable->find(str);
+ if (known == IdentifierTable->end())
+ return None;
+
+ return *known;
+}
+
+Optional<SelectorID> APINotesReader::Implementation::getSelector(
+ ObjCSelectorRef selector) {
+ if (!ObjCSelectorTable || !IdentifierTable)
+ return None;
+
+ // Translate the identifiers.
+ StoredObjCSelector key;
+ key.NumPieces = selector.NumPieces;
+ for (auto ident : selector.Identifiers) {
+ if (auto identID = getIdentifier(ident)) {
+ key.Identifiers.push_back(*identID);
+ } else {
+ return None;
+ }
+ }
+
+ auto known = ObjCSelectorTable->find(key);
+ if (known == ObjCSelectorTable->end())
+ return None;
+
+ return *known;
+
+}
+
+bool APINotesReader::Implementation::readControlBlock(
+ llvm::BitstreamCursor &cursor,
+ SmallVectorImpl<uint64_t> &scratch) {
+ if (cursor.EnterSubBlock(CONTROL_BLOCK_ID))
+ return true;
+
+ bool sawMetadata = false;
+
+ auto next = cursor.advance();
+ while (next.Kind != llvm::BitstreamEntry::EndBlock) {
+ if (next.Kind == llvm::BitstreamEntry::Error)
+ return true;
+
+ if (next.Kind == llvm::BitstreamEntry::SubBlock) {
+ // Unknown metadata sub-block, possibly for use by a future version of the
+ // API notes format.
+ if (cursor.SkipBlock())
+ return true;
+
+ next = cursor.advance();
+ continue;
+ }
+
+ scratch.clear();
+ StringRef blobData;
+ unsigned kind = cursor.readRecord(next.ID, scratch, &blobData);
+ switch (kind) {
+ case control_block::METADATA:
+ // Already saw metadata.
+ if (sawMetadata)
+ return true;
+
+ if (scratch[0] != VERSION_MAJOR || scratch[1] != VERSION_MINOR)
+ return true;
+
+ sawMetadata = true;
+ break;
+
+ case control_block::MODULE_NAME:
+ ModuleName = blobData.str();
+ break;
+
+ case control_block::MODULE_OPTIONS:
+ ModuleOpts.SwiftInferImportAsMember = (scratch.front() & 1) != 0;
+ break;
+
+ case control_block::SOURCE_FILE:
+ SourceFileSizeAndModTime = { scratch[0], scratch[1] };
+ break;
+
+ default:
+ // Unknown metadata record, possibly for use by a future version of the
+ // module format.
+ break;
+ }
+
+ next = cursor.advance();
+ }
+
+ return !sawMetadata;
+}
+
+bool APINotesReader::Implementation::readIdentifierBlock(
+ llvm::BitstreamCursor &cursor,
+ SmallVectorImpl<uint64_t> &scratch) {
+ if (cursor.EnterSubBlock(IDENTIFIER_BLOCK_ID))
+ return true;
+
+ auto next = cursor.advance();
+ while (next.Kind != llvm::BitstreamEntry::EndBlock) {
+ if (next.Kind == llvm::BitstreamEntry::Error)
+ return true;
+
+ if (next.Kind == llvm::BitstreamEntry::SubBlock) {
+ // Unknown sub-block, possibly for use by a future version of the
+ // API notes format.
+ if (cursor.SkipBlock())
+ return true;
+
+ next = cursor.advance();
+ continue;
+ }
+
+ scratch.clear();
+ StringRef blobData;
+ unsigned kind = cursor.readRecord(next.ID, scratch, &blobData);
+ switch (kind) {
+ case identifier_block::IDENTIFIER_DATA: {
+ // Already saw identifier table.
+ if (IdentifierTable)
+ return true;
+
+ uint32_t tableOffset;
+ identifier_block::IdentifierDataLayout::readRecord(scratch, tableOffset);
+ auto base = reinterpret_cast<const uint8_t *>(blobData.data());
+
+ IdentifierTable.reset(
+ SerializedIdentifierTable::Create(base + tableOffset,
+ base + sizeof(uint32_t),
+ base));
+ break;
+ }
+
+ default:
+ // Unknown record, possibly for use by a future version of the
+ // module format.
+ break;
+ }
+
+ next = cursor.advance();
+ }
+
+ return false;
+}
+
+bool APINotesReader::Implementation::readObjCContextBlock(
+ llvm::BitstreamCursor &cursor,
+ SmallVectorImpl<uint64_t> &scratch) {
+ if (cursor.EnterSubBlock(OBJC_CONTEXT_BLOCK_ID))
+ return true;
+
+ auto next = cursor.advance();
+ while (next.Kind != llvm::BitstreamEntry::EndBlock) {
+ if (next.Kind == llvm::BitstreamEntry::Error)
+ return true;
+
+ if (next.Kind == llvm::BitstreamEntry::SubBlock) {
+ // Unknown sub-block, possibly for use by a future version of the
+ // API notes format.
+ if (cursor.SkipBlock())
+ return true;
+
+ next = cursor.advance();
+ continue;
+ }
+
+ scratch.clear();
+ StringRef blobData;
+ unsigned kind = cursor.readRecord(next.ID, scratch, &blobData);
+ switch (kind) {
+ case objc_context_block::OBJC_CONTEXT_ID_DATA: {
+ // Already saw Objective-C context ID table.
+ if (ObjCContextIDTable)
+ return true;
+
+ uint32_t tableOffset;
+ objc_context_block::ObjCContextIDLayout::readRecord(scratch, tableOffset);
+ auto base = reinterpret_cast<const uint8_t *>(blobData.data());
+
+ ObjCContextIDTable.reset(
+ SerializedObjCContextIDTable::Create(base + tableOffset,
+ base + sizeof(uint32_t),
+ base));
+ break;
+ }
+
+ case objc_context_block::OBJC_CONTEXT_INFO_DATA: {
+ // Already saw Objective-C context info table.
+ if (ObjCContextInfoTable)
+ return true;
+
+ uint32_t tableOffset;
+ objc_context_block::ObjCContextInfoLayout::readRecord(scratch,
+ tableOffset);
+ auto base = reinterpret_cast<const uint8_t *>(blobData.data());
+
+ ObjCContextInfoTable.reset(
+ SerializedObjCContextInfoTable::Create(base + tableOffset,
+ base + sizeof(uint32_t),
+ base));
+ break;
+ }
+
+ default:
+ // Unknown record, possibly for use by a future version of the
+ // module format.
+ break;
+ }
+
+ next = cursor.advance();
+ }
+
+ return false;
+}
+
+bool APINotesReader::Implementation::readObjCPropertyBlock(
+ llvm::BitstreamCursor &cursor,
+ SmallVectorImpl<uint64_t> &scratch) {
+ if (cursor.EnterSubBlock(OBJC_PROPERTY_BLOCK_ID))
+ return true;
+
+ auto next = cursor.advance();
+ while (next.Kind != llvm::BitstreamEntry::EndBlock) {
+ if (next.Kind == llvm::BitstreamEntry::Error)
+ return true;
+
+ if (next.Kind == llvm::BitstreamEntry::SubBlock) {
+ // Unknown sub-block, possibly for use by a future version of the
+ // API notes format.
+ if (cursor.SkipBlock())
+ return true;
+
+ next = cursor.advance();
+ continue;
+ }
+
+ scratch.clear();
+ StringRef blobData;
+ unsigned kind = cursor.readRecord(next.ID, scratch, &blobData);
+ switch (kind) {
+ case objc_property_block::OBJC_PROPERTY_DATA: {
+ // Already saw Objective-C property table.
+ if (ObjCPropertyTable)
+ return true;
+
+ uint32_t tableOffset;
+ objc_property_block::ObjCPropertyDataLayout::readRecord(scratch,
+ tableOffset);
+ auto base = reinterpret_cast<const uint8_t *>(blobData.data());
+
+ ObjCPropertyTable.reset(
+ SerializedObjCPropertyTable::Create(base + tableOffset,
+ base + sizeof(uint32_t),
+ base));
+ break;
+ }
+
+ default:
+ // Unknown record, possibly for use by a future version of the
+ // module format.
+ break;
+ }
+
+ next = cursor.advance();
+ }
+
+ return false;
+}
+
+bool APINotesReader::Implementation::readObjCMethodBlock(
+ llvm::BitstreamCursor &cursor,
+ SmallVectorImpl<uint64_t> &scratch) {
+ if (cursor.EnterSubBlock(OBJC_METHOD_BLOCK_ID))
+ return true;
+
+ auto next = cursor.advance();
+ while (next.Kind != llvm::BitstreamEntry::EndBlock) {
+ if (next.Kind == llvm::BitstreamEntry::Error)
+ return true;
+
+ if (next.Kind == llvm::BitstreamEntry::SubBlock) {
+ // Unknown sub-block, possibly for use by a future version of the
+ // API notes format.
+ if (cursor.SkipBlock())
+ return true;
+
+ next = cursor.advance();
+ continue;
+ }
+
+ scratch.clear();
+ StringRef blobData;
+ unsigned kind = cursor.readRecord(next.ID, scratch, &blobData);
+ switch (kind) {
+ case objc_method_block::OBJC_METHOD_DATA: {
+ // Already saw Objective-C method table.
+ if (ObjCMethodTable)
+ return true;
+
+ uint32_t tableOffset;
+ objc_method_block::ObjCMethodDataLayout::readRecord(scratch, tableOffset);
+ auto base = reinterpret_cast<const uint8_t *>(blobData.data());
+
+ ObjCMethodTable.reset(
+ SerializedObjCMethodTable::Create(base + tableOffset,
+ base + sizeof(uint32_t),
+ base));
+ break;
+ }
+
+ default:
+ // Unknown record, possibly for use by a future version of the
+ // module format.
+ break;
+ }
+
+ next = cursor.advance();
+ }
+
+ return false;
+}
+
+bool APINotesReader::Implementation::readObjCSelectorBlock(
+ llvm::BitstreamCursor &cursor,
+ SmallVectorImpl<uint64_t> &scratch) {
+ if (cursor.EnterSubBlock(OBJC_SELECTOR_BLOCK_ID))
+ return true;
+
+ auto next = cursor.advance();
+ while (next.Kind != llvm::BitstreamEntry::EndBlock) {
+ if (next.Kind == llvm::BitstreamEntry::Error)
+ return true;
+
+ if (next.Kind == llvm::BitstreamEntry::SubBlock) {
+ // Unknown sub-block, possibly for use by a future version of the
+ // API notes format.
+ if (cursor.SkipBlock())
+ return true;
+
+ next = cursor.advance();
+ continue;
+ }
+
+ scratch.clear();
+ StringRef blobData;
+ unsigned kind = cursor.readRecord(next.ID, scratch, &blobData);
+ switch (kind) {
+ case objc_selector_block::OBJC_SELECTOR_DATA: {
+ // Already saw Objective-C selector table.
+ if (ObjCSelectorTable)
+ return true;
+
+ uint32_t tableOffset;
+ objc_selector_block::ObjCSelectorDataLayout::readRecord(scratch,
+ tableOffset);
+ auto base = reinterpret_cast<const uint8_t *>(blobData.data());
+
+ ObjCSelectorTable.reset(
+ SerializedObjCSelectorTable::Create(base + tableOffset,
+ base + sizeof(uint32_t),
+ base));
+ break;
+ }
+
+ default:
+ // Unknown record, possibly for use by a future version of the
+ // module format.
+ break;
+ }
+
+ next = cursor.advance();
+ }
+
+ return false;
+}
+
+bool APINotesReader::Implementation::readGlobalVariableBlock(
+ llvm::BitstreamCursor &cursor,
+ SmallVectorImpl<uint64_t> &scratch) {
+ if (cursor.EnterSubBlock(GLOBAL_VARIABLE_BLOCK_ID))
+ return true;
+
+ auto next = cursor.advance();
+ while (next.Kind != llvm::BitstreamEntry::EndBlock) {
+ if (next.Kind == llvm::BitstreamEntry::Error)
+ return true;
+
+ if (next.Kind == llvm::BitstreamEntry::SubBlock) {
+ // Unknown sub-block, possibly for use by a future version of the
+ // API notes format.
+ if (cursor.SkipBlock())
+ return true;
+
+ next = cursor.advance();
+ continue;
+ }
+
+ scratch.clear();
+ StringRef blobData;
+ unsigned kind = cursor.readRecord(next.ID, scratch, &blobData);
+ switch (kind) {
+ case global_variable_block::GLOBAL_VARIABLE_DATA: {
+ // Already saw global variable table.
+ if (GlobalVariableTable)
+ return true;
+
+ uint32_t tableOffset;
+ global_variable_block::GlobalVariableDataLayout::readRecord(scratch,
+ tableOffset);
+ auto base = reinterpret_cast<const uint8_t *>(blobData.data());
+
+ GlobalVariableTable.reset(
+ SerializedGlobalVariableTable::Create(base + tableOffset,
+ base + sizeof(uint32_t),
+ base));
+ break;
+ }
+
+ default:
+ // Unknown record, possibly for use by a future version of the
+ // module format.
+ break;
+ }
+
+ next = cursor.advance();
+ }
+
+ return false;
+}
+
+bool APINotesReader::Implementation::readGlobalFunctionBlock(
+ llvm::BitstreamCursor &cursor,
+ SmallVectorImpl<uint64_t> &scratch) {
+ if (cursor.EnterSubBlock(GLOBAL_FUNCTION_BLOCK_ID))
+ return true;
+
+ auto next = cursor.advance();
+ while (next.Kind != llvm::BitstreamEntry::EndBlock) {
+ if (next.Kind == llvm::BitstreamEntry::Error)
+ return true;
+
+ if (next.Kind == llvm::BitstreamEntry::SubBlock) {
+ // Unknown sub-block, possibly for use by a future version of the
+ // API notes format.
+ if (cursor.SkipBlock())
+ return true;
+
+ next = cursor.advance();
+ continue;
+ }
+
+ scratch.clear();
+ StringRef blobData;
+ unsigned kind = cursor.readRecord(next.ID, scratch, &blobData);
+ switch (kind) {
+ case global_function_block::GLOBAL_FUNCTION_DATA: {
+ // Already saw global function table.
+ if (GlobalFunctionTable)
+ return true;
+
+ uint32_t tableOffset;
+ global_function_block::GlobalFunctionDataLayout::readRecord(scratch,
+ tableOffset);
+ auto base = reinterpret_cast<const uint8_t *>(blobData.data());
+
+ GlobalFunctionTable.reset(
+ SerializedGlobalFunctionTable::Create(base + tableOffset,
+ base + sizeof(uint32_t),
+ base));
+ break;
+ }
+
+ default:
+ // Unknown record, possibly for use by a future version of the
+ // module format.
+ break;
+ }
+
+ next = cursor.advance();
+ }
+
+ return false;
+}
+
+bool APINotesReader::Implementation::readEnumConstantBlock(
+ llvm::BitstreamCursor &cursor,
+ SmallVectorImpl<uint64_t> &scratch) {
+ if (cursor.EnterSubBlock(ENUM_CONSTANT_BLOCK_ID))
+ return true;
+
+ auto next = cursor.advance();
+ while (next.Kind != llvm::BitstreamEntry::EndBlock) {
+ if (next.Kind == llvm::BitstreamEntry::Error)
+ return true;
+
+ if (next.Kind == llvm::BitstreamEntry::SubBlock) {
+ // Unknown sub-block, possibly for use by a future version of the
+ // API notes format.
+ if (cursor.SkipBlock())
+ return true;
+
+ next = cursor.advance();
+ continue;
+ }
+
+ scratch.clear();
+ StringRef blobData;
+ unsigned kind = cursor.readRecord(next.ID, scratch, &blobData);
+ switch (kind) {
+ case enum_constant_block::ENUM_CONSTANT_DATA: {
+ // Already saw enumerator table.
+ if (EnumConstantTable)
+ return true;
+
+ uint32_t tableOffset;
+ enum_constant_block::EnumConstantDataLayout::readRecord(scratch,
+ tableOffset);
+ auto base = reinterpret_cast<const uint8_t *>(blobData.data());
+
+ EnumConstantTable.reset(
+ SerializedEnumConstantTable::Create(base + tableOffset,
+ base + sizeof(uint32_t),
+ base));
+ break;
+ }
+
+ default:
+ // Unknown record, possibly for use by a future version of the
+ // module format.
+ break;
+ }
+
+ next = cursor.advance();
+ }
+
+ return false;
+}
+
+bool APINotesReader::Implementation::readTagBlock(
+ llvm::BitstreamCursor &cursor,
+ SmallVectorImpl<uint64_t> &scratch) {
+ if (cursor.EnterSubBlock(TAG_BLOCK_ID))
+ return true;
+
+ auto next = cursor.advance();
+ while (next.Kind != llvm::BitstreamEntry::EndBlock) {
+ if (next.Kind == llvm::BitstreamEntry::Error)
+ return true;
+
+ if (next.Kind == llvm::BitstreamEntry::SubBlock) {
+ // Unknown sub-block, possibly for use by a future version of the
+ // API notes format.
+ if (cursor.SkipBlock())
+ return true;
+
+ next = cursor.advance();
+ continue;
+ }
+
+ scratch.clear();
+ StringRef blobData;
+ unsigned kind = cursor.readRecord(next.ID, scratch, &blobData);
+ switch (kind) {
+ case tag_block::TAG_DATA: {
+ // Already saw tag table.
+ if (TagTable)
+ return true;
+
+ uint32_t tableOffset;
+ tag_block::TagDataLayout::readRecord(scratch, tableOffset);
+ auto base = reinterpret_cast<const uint8_t *>(blobData.data());
+
+ TagTable.reset(
+ SerializedTagTable::Create(base + tableOffset,
+ base + sizeof(uint32_t),
+ base));
+ break;
+ }
+
+ default:
+ // Unknown record, possibly for use by a future version of the
+ // module format.
+ break;
+ }
+
+ next = cursor.advance();
+ }
+
+ return false;
+}
+
+bool APINotesReader::Implementation::readTypedefBlock(
+ llvm::BitstreamCursor &cursor,
+ SmallVectorImpl<uint64_t> &scratch) {
+ if (cursor.EnterSubBlock(TYPEDEF_BLOCK_ID))
+ return true;
+
+ auto next = cursor.advance();
+ while (next.Kind != llvm::BitstreamEntry::EndBlock) {
+ if (next.Kind == llvm::BitstreamEntry::Error)
+ return true;
+
+ if (next.Kind == llvm::BitstreamEntry::SubBlock) {
+ // Unknown sub-block, possibly for use by a future version of the
+ // API notes format.
+ if (cursor.SkipBlock())
+ return true;
+
+ next = cursor.advance();
+ continue;
+ }
+
+ scratch.clear();
+ StringRef blobData;
+ unsigned kind = cursor.readRecord(next.ID, scratch, &blobData);
+ switch (kind) {
+ case typedef_block::TYPEDEF_DATA: {
+ // Already saw typedef table.
+ if (TypedefTable)
+ return true;
+
+ uint32_t tableOffset;
+ typedef_block::TypedefDataLayout::readRecord(scratch, tableOffset);
+ auto base = reinterpret_cast<const uint8_t *>(blobData.data());
+
+ TypedefTable.reset(
+ SerializedTypedefTable::Create(base + tableOffset,
+ base + sizeof(uint32_t),
+ base));
+ break;
+ }
+
+ default:
+ // Unknown record, possibly for use by a future version of the
+ // module format.
+ break;
+ }
+
+ next = cursor.advance();
+ }
+
+ return false;
+}
+
+APINotesReader::APINotesReader(llvm::MemoryBuffer *inputBuffer,
+ bool ownsInputBuffer,
+ VersionTuple swiftVersion,
+ bool &failed)
+ : Impl(*new Implementation)
+{
+ failed = false;
+
+ // Initialize the input buffer.
+ Impl.InputBuffer = inputBuffer;
+ Impl.OwnsInputBuffer = ownsInputBuffer;
+ Impl.SwiftVersion = swiftVersion;
+ llvm::BitstreamCursor cursor(*Impl.InputBuffer);
+
+ // Validate signature.
+ for (auto byte : API_NOTES_SIGNATURE) {
+ if (cursor.AtEndOfStream() || cursor.Read(8) != byte) {
+ failed = true;
+ return;
+ }
+ }
+
+ // Look at all of the blocks.
+ bool hasValidControlBlock = false;
+ SmallVector<uint64_t, 64> scratch;
+ while (!cursor.AtEndOfStream()) {
+ auto topLevelEntry = cursor.advance();
+ if (topLevelEntry.Kind != llvm::BitstreamEntry::SubBlock)
+ break;
+
+ switch (topLevelEntry.ID) {
+ case llvm::bitc::BLOCKINFO_BLOCK_ID:
+ if (!cursor.ReadBlockInfoBlock()) {
+ failed = true;
+ break;
+ }
+ break;
+
+ case CONTROL_BLOCK_ID:
+ // Only allow a single control block.
+ if (hasValidControlBlock || Impl.readControlBlock(cursor, scratch)) {
+ failed = true;
+ return;
+ }
+
+ hasValidControlBlock = true;
+ break;
+
+ case IDENTIFIER_BLOCK_ID:
+ if (!hasValidControlBlock || Impl.readIdentifierBlock(cursor, scratch)) {
+ failed = true;
+ return;
+ }
+ break;
+
+ case OBJC_CONTEXT_BLOCK_ID:
+ if (!hasValidControlBlock || Impl.readObjCContextBlock(cursor, scratch)) {
+ failed = true;
+ return;
+ }
+
+ break;
+
+ case OBJC_PROPERTY_BLOCK_ID:
+ if (!hasValidControlBlock ||
+ Impl.readObjCPropertyBlock(cursor, scratch)) {
+ failed = true;
+ return;
+ }
+ break;
+
+ case OBJC_METHOD_BLOCK_ID:
+ if (!hasValidControlBlock || Impl.readObjCMethodBlock(cursor, scratch)) {
+ failed = true;
+ return;
+ }
+ break;
+
+ case OBJC_SELECTOR_BLOCK_ID:
+ if (!hasValidControlBlock ||
+ Impl.readObjCSelectorBlock(cursor, scratch)) {
+ failed = true;
+ return;
+ }
+ break;
+
+ case GLOBAL_VARIABLE_BLOCK_ID:
+ if (!hasValidControlBlock ||
+ Impl.readGlobalVariableBlock(cursor, scratch)) {
+ failed = true;
+ return;
+ }
+ break;
+
+ case GLOBAL_FUNCTION_BLOCK_ID:
+ if (!hasValidControlBlock ||
+ Impl.readGlobalFunctionBlock(cursor, scratch)) {
+ failed = true;
+ return;
+ }
+ break;
+
+ case ENUM_CONSTANT_BLOCK_ID:
+ if (!hasValidControlBlock ||
+ Impl.readEnumConstantBlock(cursor, scratch)) {
+ failed = true;
+ return;
+ }
+ break;
+
+ case TAG_BLOCK_ID:
+ if (!hasValidControlBlock || Impl.readTagBlock(cursor, scratch)) {
+ failed = true;
+ return;
+ }
+ break;
+
+ case TYPEDEF_BLOCK_ID:
+ if (!hasValidControlBlock || Impl.readTypedefBlock(cursor, scratch)) {
+ failed = true;
+ return;
+ }
+ break;
+
+ default:
+ // Unknown top-level block, possibly for use by a future version of the
+ // module format.
+ if (cursor.SkipBlock()) {
+ failed = true;
+ return;
+ }
+ break;
+ }
+ }
+
+ if (!cursor.AtEndOfStream()) {
+ failed = true;
+ return;
+ }
+}
+
+APINotesReader::~APINotesReader() {
+ if (Impl.OwnsInputBuffer)
+ delete Impl.InputBuffer;
+
+ delete &Impl;
+}
+
+std::unique_ptr<APINotesReader>
+APINotesReader::get(std::unique_ptr<llvm::MemoryBuffer> inputBuffer,
+ VersionTuple swiftVersion) {
+ bool failed = false;
+ std::unique_ptr<APINotesReader>
+ reader(new APINotesReader(inputBuffer.release(), /*ownsInputBuffer=*/true,
+ swiftVersion, failed));
+ if (failed)
+ return nullptr;
+
+ return reader;
+}
+
+std::unique_ptr<APINotesReader>
+APINotesReader::getUnmanaged(llvm::MemoryBuffer *inputBuffer,
+ VersionTuple swiftVersion) {
+ bool failed = false;
+ std::unique_ptr<APINotesReader>
+ reader(new APINotesReader(inputBuffer, /*ownsInputBuffer=*/false,
+ swiftVersion, failed));
+ if (failed)
+ return nullptr;
+
+ return reader;
+}
+
+StringRef APINotesReader::getModuleName() const {
+ return Impl.ModuleName;
+}
+
+Optional<std::pair<off_t, time_t>>
+APINotesReader::getSourceFileSizeAndModTime() const {
+ return Impl.SourceFileSizeAndModTime;
+}
+
+ModuleOptions APINotesReader::getModuleOptions() const {
+ return Impl.ModuleOpts;
+}
+
+template<typename T>
+APINotesReader::VersionedInfo<T>::VersionedInfo(
+ VersionTuple version,
+ SmallVector<std::pair<VersionTuple, T>, 1> results)
+ : Results(std::move(results)) {
+
+ // Look for an exact version match.
+ Optional<unsigned> unversioned;
+ Selected = Results.size();
+ SelectedRole = VersionedInfoRole::Versioned;
+
+ for (unsigned i = 0, n = Results.size(); i != n; ++i) {
+ if (Results[i].first == version) {
+ Selected = i;
+
+ if (version) SelectedRole = VersionedInfoRole::ReplaceSource;
+ else SelectedRole = VersionedInfoRole::AugmentSource;
+ break;
+ }
+
+ if (!Results[i].first) {
+ assert(!unversioned && "Two unversioned entries?");
+ unversioned = i;
+ }
+ }
+
+ // If we didn't find a match but we have an unversioned result, use the
+ // unversioned result.
+ if (Selected == Results.size() && unversioned) {
+ Selected = *unversioned;
+ SelectedRole = VersionedInfoRole::AugmentSource;
+ }
+ }
+
+auto APINotesReader::lookupObjCClassID(StringRef name) -> Optional<ContextID> {
+ if (!Impl.ObjCContextIDTable)
+ return None;
+
+ Optional<IdentifierID> classID = Impl.getIdentifier(name);
+ if (!classID)
+ return None;
+
+ auto knownID = Impl.ObjCContextIDTable->find({*classID, '\0'});
+ if (knownID == Impl.ObjCContextIDTable->end())
+ return None;
+
+ return ContextID(*knownID);
+}
+
+auto APINotesReader::lookupObjCClassInfo(StringRef name)
+ -> VersionedInfo<ObjCContextInfo> {
+ if (!Impl.ObjCContextInfoTable)
+ return None;
+
+ Optional<ContextID> contextID = lookupObjCClassID(name);
+ if (!contextID)
+ return None;
+
+ auto knownInfo = Impl.ObjCContextInfoTable->find(contextID->Value);
+ if (knownInfo == Impl.ObjCContextInfoTable->end())
+ return None;
+
+ return { Impl.SwiftVersion, *knownInfo };
+}
+
+auto APINotesReader::lookupObjCProtocolID(StringRef name)
+ -> Optional<ContextID> {
+ if (!Impl.ObjCContextIDTable)
+ return None;
+
+ Optional<IdentifierID> classID = Impl.getIdentifier(name);
+ if (!classID)
+ return None;
+
+ auto knownID = Impl.ObjCContextIDTable->find({*classID, '\1'});
+ if (knownID == Impl.ObjCContextIDTable->end())
+ return None;
+
+ return ContextID(*knownID);
+}
+
+auto APINotesReader::lookupObjCProtocolInfo(StringRef name)
+ -> VersionedInfo<ObjCContextInfo> {
+ if (!Impl.ObjCContextInfoTable)
+ return None;
+
+ Optional<ContextID> contextID = lookupObjCProtocolID(name);
+ if (!contextID)
+ return None;
+
+ auto knownInfo = Impl.ObjCContextInfoTable->find(contextID->Value);
+ if (knownInfo == Impl.ObjCContextInfoTable->end())
+ return None;
+
+ return { Impl.SwiftVersion, *knownInfo };
+}
+
+
+auto APINotesReader::lookupObjCProperty(ContextID contextID,
+ StringRef name,
+ bool isInstance)
+ -> VersionedInfo<ObjCPropertyInfo> {
+ if (!Impl.ObjCPropertyTable)
+ return None;
+
+ Optional<IdentifierID> propertyID = Impl.getIdentifier(name);
+ if (!propertyID)
+ return None;
+
+ auto known = Impl.ObjCPropertyTable->find(std::make_tuple(contextID.Value,
+ *propertyID,
+ (char)isInstance));
+ if (known == Impl.ObjCPropertyTable->end())
+ return None;
+
+ return { Impl.SwiftVersion, *known };
+}
+
+auto APINotesReader::lookupObjCMethod(
+ ContextID contextID,
+ ObjCSelectorRef selector,
+ bool isInstanceMethod)
+ -> VersionedInfo<ObjCMethodInfo> {
+ if (!Impl.ObjCMethodTable)
+ return None;
+
+ Optional<SelectorID> selectorID = Impl.getSelector(selector);
+ if (!selectorID)
+ return None;
+
+ auto known = Impl.ObjCMethodTable->find(
+ ObjCMethodTableInfo::internal_key_type{
+ contextID.Value, *selectorID, isInstanceMethod});
+ if (known == Impl.ObjCMethodTable->end())
+ return None;
+
+ return { Impl.SwiftVersion, *known };
+}
+
+auto APINotesReader::lookupGlobalVariable(
+ StringRef name)
+ -> VersionedInfo<GlobalVariableInfo> {
+ if (!Impl.GlobalVariableTable)
+ return None;
+
+ Optional<IdentifierID> nameID = Impl.getIdentifier(name);
+ if (!nameID)
+ return None;
+
+ auto known = Impl.GlobalVariableTable->find(*nameID);
+ if (known == Impl.GlobalVariableTable->end())
+ return None;
+
+ return { Impl.SwiftVersion, *known };
+}
+
+auto APINotesReader::lookupGlobalFunction(StringRef name)
+ -> VersionedInfo<GlobalFunctionInfo> {
+ if (!Impl.GlobalFunctionTable)
+ return None;
+
+ Optional<IdentifierID> nameID = Impl.getIdentifier(name);
+ if (!nameID)
+ return None;
+
+ auto known = Impl.GlobalFunctionTable->find(*nameID);
+ if (known == Impl.GlobalFunctionTable->end())
+ return None;
+
+ return { Impl.SwiftVersion, *known };
+}
+
+auto APINotesReader::lookupEnumConstant(StringRef name)
+ -> VersionedInfo<EnumConstantInfo> {
+ if (!Impl.EnumConstantTable)
+ return None;
+
+ Optional<IdentifierID> nameID = Impl.getIdentifier(name);
+ if (!nameID)
+ return None;
+
+ auto known = Impl.EnumConstantTable->find(*nameID);
+ if (known == Impl.EnumConstantTable->end())
+ return None;
+
+ return { Impl.SwiftVersion, *known };
+}
+
+auto APINotesReader::lookupTag(StringRef name) -> VersionedInfo<TagInfo> {
+ if (!Impl.TagTable)
+ return None;
+
+ Optional<IdentifierID> nameID = Impl.getIdentifier(name);
+ if (!nameID)
+ return None;
+
+ auto known = Impl.TagTable->find(*nameID);
+ if (known == Impl.TagTable->end())
+ return None;
+
+ return { Impl.SwiftVersion, *known };
+}
+
+auto APINotesReader::lookupTypedef(StringRef name)
+ -> VersionedInfo<TypedefInfo> {
+ if (!Impl.TypedefTable)
+ return None;
+
+ Optional<IdentifierID> nameID = Impl.getIdentifier(name);
+ if (!nameID)
+ return None;
+
+ auto known = Impl.TypedefTable->find(*nameID);
+ if (known == Impl.TypedefTable->end())
+ return None;
+
+ return { Impl.SwiftVersion, *known };
+}
+
+APINotesReader::Visitor::~Visitor() { }
+
+void APINotesReader::Visitor::visitObjCClass(
+ ContextID contextID,
+ StringRef name,
+ const ObjCContextInfo &info,
+ VersionTuple swiftVersion) { }
+
+void APINotesReader::Visitor::visitObjCProtocol(
+ ContextID contextID,
+ StringRef name,
+ const ObjCContextInfo &info,
+ VersionTuple swiftVersion) { }
+
+void APINotesReader::Visitor::visitObjCMethod(
+ ContextID contextID,
+ StringRef selector,
+ bool isInstanceMethod,
+ const ObjCMethodInfo &info,
+ VersionTuple swiftVersion) { }
+
+void APINotesReader::Visitor::visitObjCProperty(
+ ContextID contextID,
+ StringRef name,
+ bool isInstance,
+ const ObjCPropertyInfo &info,
+ VersionTuple swiftVersion) { }
+
+void APINotesReader::Visitor::visitGlobalVariable(
+ StringRef name,
+ const GlobalVariableInfo &info,
+ VersionTuple swiftVersion) { }
+
+void APINotesReader::Visitor::visitGlobalFunction(
+ StringRef name,
+ const GlobalFunctionInfo &info,
+ VersionTuple swiftVersion) { }
+
+void APINotesReader::Visitor::visitEnumConstant(
+ StringRef name,
+ const EnumConstantInfo &info,
+ VersionTuple swiftVersion) { }
+
+void APINotesReader::Visitor::visitTag(
+ StringRef name,
+ const TagInfo &info,
+ VersionTuple swiftVersion) { }
+
+void APINotesReader::Visitor::visitTypedef(
+ StringRef name,
+ const TypedefInfo &info,
+ VersionTuple swiftVersion) { }
+
+void APINotesReader::visit(Visitor &visitor) {
+ // FIXME: All of these iterations would be significantly more efficient if we
+ // could get the keys and data together, but OnDiskIterableHashTable doesn't
+ // support that.
+
+ // Build an identifier ID -> string mapping, which we'll need when visiting
+ // any of the tables.
+ llvm::DenseMap<unsigned, StringRef> identifiers;
+ if (Impl.IdentifierTable) {
+ for (auto key : Impl.IdentifierTable->keys()) {
+ unsigned ID = *Impl.IdentifierTable->find(key);
+ assert(identifiers.count(ID) == 0);
+ identifiers[ID] = key;
+ }
+ }
+
+ // Visit classes and protocols.
+ if (Impl.ObjCContextIDTable && Impl.ObjCContextInfoTable) {
+ for (auto key : Impl.ObjCContextIDTable->keys()) {
+ auto name = identifiers[key.first];
+ auto contextID = *Impl.ObjCContextIDTable->find(key);
+
+ auto knownInfo = Impl.ObjCContextInfoTable->find(contextID);
+ if (knownInfo == Impl.ObjCContextInfoTable->end()) continue;
+
+ for (const auto &versioned : *knownInfo) {
+ if (key.second)
+ visitor.visitObjCProtocol(ContextID(contextID), name,
+ versioned.second, versioned.first);
+ else
+ visitor.visitObjCClass(ContextID(contextID), name, versioned.second,
+ versioned.first);
+ }
+ }
+ }
+
+ // Build a selector ID -> stored Objective-C selector mapping, which we need
+ // when visiting the method tables.
+ llvm::DenseMap<unsigned, std::string> selectors;
+ if (Impl.ObjCSelectorTable) {
+ for (auto key : Impl.ObjCSelectorTable->keys()) {
+ std::string selector;
+ if (key.NumPieces == 0)
+ selector = identifiers[key.Identifiers[0]];
+ else {
+ for (auto identID : key.Identifiers) {
+ selector += identifiers[identID];
+ selector += ':';
+ }
+ }
+
+ unsigned selectorID = *Impl.ObjCSelectorTable->find(key);
+ selectors[selectorID] = selector;
+ }
+ }
+
+ // Visit methods.
+ if (Impl.ObjCMethodTable) {
+ for (auto key : Impl.ObjCMethodTable->keys()) {
+ ContextID contextID(std::get<0>(key));
+ const auto &selector = selectors[std::get<1>(key)];
+ for (const auto &versioned : *Impl.ObjCMethodTable->find(key))
+ visitor.visitObjCMethod(contextID, selector, std::get<2>(key),
+ versioned.second, versioned.first);
+ }
+ }
+
+ // Visit properties.
+ if (Impl.ObjCPropertyTable) {
+ for (auto key : Impl.ObjCPropertyTable->keys()) {
+ ContextID contextID(std::get<0>(key));
+ auto name = identifiers[std::get<1>(key)];
+ char isInstance = std::get<2>(key);
+ for (const auto &versioned : *Impl.ObjCPropertyTable->find(key)) {
+ visitor.visitObjCProperty(contextID, name, isInstance, versioned.second,
+ versioned.first);
+ }
+ }
+ }
+
+ // Visit global functions.
+ if (Impl.GlobalFunctionTable) {
+ for (auto key : Impl.GlobalFunctionTable->keys()) {
+ auto name = identifiers[key];
+ for (const auto &versioned : *Impl.GlobalFunctionTable->find(key))
+ visitor.visitGlobalFunction(name, versioned.second, versioned.first);
+ }
+ }
+
+ // Visit global variables.
+ if (Impl.GlobalVariableTable) {
+ for (auto key : Impl.GlobalVariableTable->keys()) {
+ auto name = identifiers[key];
+ for (const auto &versioned : *Impl.GlobalVariableTable->find(key))
+ visitor.visitGlobalVariable(name, versioned.second, versioned.first);
+ }
+ }
+
+ // Visit global variables.
+ if (Impl.EnumConstantTable) {
+ for (auto key : Impl.EnumConstantTable->keys()) {
+ auto name = identifiers[key];
+ for (const auto &versioned : *Impl.EnumConstantTable->find(key))
+ visitor.visitEnumConstant(name, versioned.second, versioned.first);
+ }
+ }
+
+ // Visit tags.
+ if (Impl.TagTable) {
+ for (auto key : Impl.TagTable->keys()) {
+ auto name = identifiers[key];
+ for (const auto &versioned : *Impl.TagTable->find(key))
+ visitor.visitTag(name, versioned.second, versioned.first);
+ }
+ }
+
+ // Visit typedefs.
+ if (Impl.TypedefTable) {
+ for (auto key : Impl.TypedefTable->keys()) {
+ auto name = identifiers[key];
+ for (const auto &versioned : *Impl.TypedefTable->find(key))
+ visitor.visitTypedef(name, versioned.second, versioned.first);
+ }
+ }
+}
+
diff --git a/lib/APINotes/APINotesWriter.cpp b/lib/APINotes/APINotesWriter.cpp
new file mode 100644
index 0000000..86b6abd
--- /dev/null
+++ b/lib/APINotes/APINotesWriter.cpp
@@ -0,0 +1,1289 @@
+//===--- APINotesWriter.cpp - API Notes Writer --------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the \c APINotesWriter class that writes out
+// source API notes data providing additional information about source
+// code as a separate input, such as the non-nil/nilable annotations
+// for method parameters.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/APINotes/APINotesWriter.h"
+#include "APINotesFormat.h"
+#include "clang/Basic/FileManager.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/EndianStream.h"
+#include "llvm/Support/OnDiskHashTable.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/DataTypes.h"
+#include <tuple>
+#include <vector>
+using namespace clang;
+using namespace api_notes;
+using namespace llvm::support;
+
+namespace {
+ template<typename T> using VersionedSmallVector =
+ SmallVector<std::pair<VersionTuple, T>, 1>;
+}
+
+class APINotesWriter::Implementation {
+ /// Mapping from strings to identifier IDs.
+ llvm::StringMap<IdentifierID> IdentifierIDs;
+
+ /// Mapping from selectors to selector ID.
+ llvm::DenseMap<StoredObjCSelector, SelectorID> SelectorIDs;
+
+ /// Scratch space for bitstream writing.
+ SmallVector<uint64_t, 64> ScratchRecord;
+
+public:
+ /// The name of the module
+ std::string ModuleName;
+
+ /// The source file from which this binary representation was
+ /// created, if known.
+ const FileEntry *SourceFile;
+
+ bool SwiftInferImportAsMember = false;
+
+ /// Information about Objective-C contexts (classes or protocols).
+ ///
+ /// Indexed by the identifier ID and a bit indication whether we're looking
+ /// for a class (0) or protocol (1) and provides both the context ID and
+ /// information describing the context within that module.
+ llvm::DenseMap<std::pair<unsigned, char>,
+ std::pair<unsigned, VersionedSmallVector<ObjCContextInfo>>>
+ ObjCContexts;
+
+ /// Mapping from context IDs to the identifier ID holding the name.
+ llvm::DenseMap<unsigned, unsigned> ObjCContextNames;
+
+ /// Information about Objective-C properties.
+ ///
+ /// Indexed by the context ID, property name, and whether this is an
+ /// instance property.
+ llvm::DenseMap<std::tuple<unsigned, unsigned, char>,
+ llvm::SmallVector<std::pair<VersionTuple, ObjCPropertyInfo>,
+ 1>>
+ ObjCProperties;
+
+ /// Information about Objective-C methods.
+ ///
+ /// Indexed by the context ID, selector ID, and Boolean (stored as a
+ /// char) indicating whether this is a class or instance method.
+ llvm::DenseMap<std::tuple<unsigned, unsigned, char>,
+ llvm::SmallVector<std::pair<VersionTuple, ObjCMethodInfo>, 1>>
+ ObjCMethods;
+
+ /// Information about global variables.
+ ///
+ /// Indexed by the identifier ID.
+ llvm::DenseMap<unsigned,
+ llvm::SmallVector<std::pair<VersionTuple, GlobalVariableInfo>,
+ 1>>
+ GlobalVariables;
+
+ /// Information about global functions.
+ ///
+ /// Indexed by the identifier ID.
+ llvm::DenseMap<unsigned,
+ llvm::SmallVector<std::pair<VersionTuple, GlobalFunctionInfo>,
+ 1>>
+ GlobalFunctions;
+
+ /// Information about enumerators.
+ ///
+ /// Indexed by the identifier ID.
+ llvm::DenseMap<unsigned,
+ llvm::SmallVector<std::pair<VersionTuple, EnumConstantInfo>,
+ 1>>
+ EnumConstants;
+
+ /// Information about tags.
+ ///
+ /// Indexed by the identifier ID.
+ llvm::DenseMap<unsigned,
+ llvm::SmallVector<std::pair<VersionTuple, TagInfo>, 1>>
+ Tags;
+
+ /// Information about typedefs.
+ ///
+ /// Indexed by the identifier ID.
+ llvm::DenseMap<unsigned,
+ llvm::SmallVector<std::pair<VersionTuple, TypedefInfo>, 1>>
+ Typedefs;
+
+ /// Retrieve the ID for the given identifier.
+ IdentifierID getIdentifier(StringRef identifier) {
+ if (identifier.empty())
+ return 0;
+
+ auto known = IdentifierIDs.find(identifier);
+ if (known != IdentifierIDs.end())
+ return known->second;
+
+ // Add to the identifier table.
+ known = IdentifierIDs.insert({identifier, IdentifierIDs.size() + 1}).first;
+ return known->second;
+ }
+
+ /// Retrieve the ID for the given selector.
+ SelectorID getSelector(ObjCSelectorRef selectorRef) {
+ // Translate the selector reference into a stored selector.
+ StoredObjCSelector selector;
+ selector.NumPieces = selectorRef.NumPieces;
+ selector.Identifiers.reserve(selectorRef.Identifiers.size());
+ for (auto piece : selectorRef.Identifiers) {
+ selector.Identifiers.push_back(getIdentifier(piece));
+ }
+
+ // Look for the stored selector.
+ auto known = SelectorIDs.find(selector);
+ if (known != SelectorIDs.end())
+ return known->second;
+
+ // Add to the selector table.
+ known = SelectorIDs.insert({selector, SelectorIDs.size()}).first;
+ return known->second;
+ }
+
+ void writeToStream(llvm::raw_ostream &os);
+
+private:
+ void writeBlockInfoBlock(llvm::BitstreamWriter &writer);
+ void writeControlBlock(llvm::BitstreamWriter &writer);
+ void writeIdentifierBlock(llvm::BitstreamWriter &writer);
+ void writeObjCContextBlock(llvm::BitstreamWriter &writer);
+ void writeObjCPropertyBlock(llvm::BitstreamWriter &writer);
+ void writeObjCMethodBlock(llvm::BitstreamWriter &writer);
+ void writeObjCSelectorBlock(llvm::BitstreamWriter &writer);
+ void writeGlobalVariableBlock(llvm::BitstreamWriter &writer);
+ void writeGlobalFunctionBlock(llvm::BitstreamWriter &writer);
+ void writeEnumConstantBlock(llvm::BitstreamWriter &writer);
+ void writeTagBlock(llvm::BitstreamWriter &writer);
+ void writeTypedefBlock(llvm::BitstreamWriter &writer);
+};
+
+/// Record the name of a block.
+static void emitBlockID(llvm::BitstreamWriter &out, unsigned ID,
+ StringRef name,
+ SmallVectorImpl<unsigned char> &nameBuffer) {
+ SmallVector<unsigned, 1> idBuffer;
+ idBuffer.push_back(ID);
+ out.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, idBuffer);
+
+ // Emit the block name if present.
+ if (name.empty())
+ return;
+ nameBuffer.resize(name.size());
+ memcpy(nameBuffer.data(), name.data(), name.size());
+ out.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, nameBuffer);
+}
+
+/// Record the name of a record within a block.
+static void emitRecordID(llvm::BitstreamWriter &out, unsigned ID,
+ StringRef name,
+ SmallVectorImpl<unsigned char> &nameBuffer) {
+ assert(ID < 256 && "can't fit record ID in next to name");
+ nameBuffer.resize(name.size()+1);
+ nameBuffer[0] = ID;
+ memcpy(nameBuffer.data()+1, name.data(), name.size());
+ out.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, nameBuffer);
+}
+
+void APINotesWriter::Implementation::writeBlockInfoBlock(
+ llvm::BitstreamWriter &writer) {
+ BCBlockRAII restoreBlock(writer, llvm::bitc::BLOCKINFO_BLOCK_ID, 2);
+
+ SmallVector<unsigned char, 64> nameBuffer;
+#define BLOCK(X) emitBlockID(writer, X ## _ID, #X, nameBuffer)
+#define BLOCK_RECORD(K, X) emitRecordID(writer, K::X, #X, nameBuffer)
+
+ BLOCK(CONTROL_BLOCK);
+ BLOCK_RECORD(control_block, METADATA);
+ BLOCK_RECORD(control_block, MODULE_NAME);
+
+ BLOCK(IDENTIFIER_BLOCK);
+ BLOCK_RECORD(identifier_block, IDENTIFIER_DATA);
+
+ BLOCK(OBJC_CONTEXT_BLOCK);
+ BLOCK_RECORD(objc_context_block, OBJC_CONTEXT_ID_DATA);
+
+ BLOCK(OBJC_PROPERTY_BLOCK);
+ BLOCK_RECORD(objc_property_block, OBJC_PROPERTY_DATA);
+
+ BLOCK(OBJC_METHOD_BLOCK);
+ BLOCK_RECORD(objc_method_block, OBJC_METHOD_DATA);
+
+ BLOCK(OBJC_SELECTOR_BLOCK);
+ BLOCK_RECORD(objc_selector_block, OBJC_SELECTOR_DATA);
+
+ BLOCK(GLOBAL_VARIABLE_BLOCK);
+ BLOCK_RECORD(global_variable_block, GLOBAL_VARIABLE_DATA);
+
+ BLOCK(GLOBAL_FUNCTION_BLOCK);
+ BLOCK_RECORD(global_function_block, GLOBAL_FUNCTION_DATA);
+#undef BLOCK
+#undef BLOCK_RECORD
+}
+
+void APINotesWriter::Implementation::writeControlBlock(
+ llvm::BitstreamWriter &writer) {
+ BCBlockRAII restoreBlock(writer, CONTROL_BLOCK_ID, 3);
+ control_block::MetadataLayout metadata(writer);
+ metadata.emit(ScratchRecord, VERSION_MAJOR, VERSION_MINOR);
+
+ control_block::ModuleNameLayout moduleName(writer);
+ moduleName.emit(ScratchRecord, ModuleName);
+
+ if (SwiftInferImportAsMember) {
+ control_block::ModuleOptionsLayout moduleOptions(writer);
+ moduleOptions.emit(ScratchRecord, SwiftInferImportAsMember);
+ }
+
+ if (SourceFile) {
+ control_block::SourceFileLayout sourceFile(writer);
+ sourceFile.emit(ScratchRecord, SourceFile->getSize(),
+ SourceFile->getModificationTime());
+ }
+}
+
+namespace {
+ /// Used to serialize the on-disk identifier table.
+ class IdentifierTableInfo {
+ public:
+ using key_type = StringRef;
+ using key_type_ref = key_type;
+ using data_type = IdentifierID;
+ using data_type_ref = const data_type &;
+ using hash_value_type = uint32_t;
+ using offset_type = unsigned;
+
+ hash_value_type ComputeHash(key_type_ref key) {
+ return llvm::HashString(key);
+ }
+
+ std::pair<unsigned, unsigned> EmitKeyDataLength(raw_ostream &out,
+ key_type_ref key,
+ data_type_ref data) {
+ uint32_t keyLength = key.size();
+ uint32_t dataLength = sizeof(uint32_t);
+ endian::Writer<little> writer(out);
+ writer.write<uint16_t>(keyLength);
+ writer.write<uint16_t>(dataLength);
+ return { keyLength, dataLength };
+ }
+
+ void EmitKey(raw_ostream &out, key_type_ref key, unsigned len) {
+ out << key;
+ }
+
+ void EmitData(raw_ostream &out, key_type_ref key, data_type_ref data,
+ unsigned len) {
+ endian::Writer<little> writer(out);
+ writer.write<uint32_t>(data);
+ }
+ };
+} // end anonymous namespace
+
+void APINotesWriter::Implementation::writeIdentifierBlock(
+ llvm::BitstreamWriter &writer) {
+ BCBlockRAII restoreBlock(writer, IDENTIFIER_BLOCK_ID, 3);
+
+ if (IdentifierIDs.empty())
+ return;
+
+ llvm::SmallString<4096> hashTableBlob;
+ uint32_t tableOffset;
+ {
+ llvm::OnDiskChainedHashTableGenerator<IdentifierTableInfo> generator;
+ for (auto &entry : IdentifierIDs)
+ generator.insert(entry.first(), entry.second);
+
+ llvm::raw_svector_ostream blobStream(hashTableBlob);
+ // Make sure that no bucket is at offset 0
+ endian::Writer<little>(blobStream).write<uint32_t>(0);
+ tableOffset = generator.Emit(blobStream);
+ }
+
+ identifier_block::IdentifierDataLayout layout(writer);
+ layout.emit(ScratchRecord, tableOffset, hashTableBlob);
+}
+
+namespace {
+ /// Retrieve the serialized size of the given CommonEntityInfo, for use in
+ /// on-disk hash tables.
+ static unsigned getCommonEntityInfoSize(const CommonEntityInfo &info) {
+ return 5 + info.UnavailableMsg.size() + info.SwiftName.size();
+ }
+
+ /// Emit a serialized representation of the common entity information.
+ static void emitCommonEntityInfo(raw_ostream &out,
+ const CommonEntityInfo &info) {
+ endian::Writer<little> writer(out);
+ uint8_t payload = 0;
+ if (auto swiftPrivate = info.isSwiftPrivate()) {
+ payload |= 0x01;
+ if (*swiftPrivate) payload |= 0x02;
+ }
+ payload <<= 1;
+ payload |= info.Unavailable;
+ payload <<= 1;
+ payload |= info.UnavailableInSwift;
+
+ writer.write<uint8_t>(payload);
+
+ writer.write<uint16_t>(info.UnavailableMsg.size());
+ out.write(info.UnavailableMsg.c_str(), info.UnavailableMsg.size());
+ writer.write<uint16_t>(info.SwiftName.size());
+ out.write(info.SwiftName.c_str(), info.SwiftName.size());
+ }
+
+ // Retrieve the serialized size of the given CommonTypeInfo, for use
+ // in on-disk hash tables.
+ static unsigned getCommonTypeInfoSize(const CommonTypeInfo &info) {
+ return 2 + (info.getSwiftBridge() ? info.getSwiftBridge()->size() : 0) +
+ 2 + (info.getNSErrorDomain() ? info.getNSErrorDomain()->size() : 0) +
+ getCommonEntityInfoSize(info);
+ }
+
+ /// Emit a serialized representation of the common type information.
+ static void emitCommonTypeInfo(raw_ostream &out, const CommonTypeInfo &info) {
+ emitCommonEntityInfo(out, info);
+ endian::Writer<little> writer(out);
+ if (auto swiftBridge = info.getSwiftBridge()) {
+ writer.write<uint16_t>(swiftBridge->size() + 1);
+ out.write(swiftBridge->c_str(), swiftBridge->size());
+ } else {
+ writer.write<uint16_t>(0);
+ }
+ if (auto nsErrorDomain = info.getNSErrorDomain()) {
+ writer.write<uint16_t>(nsErrorDomain->size() + 1);
+ out.write(nsErrorDomain->c_str(), info.getNSErrorDomain()->size());
+ } else {
+ writer.write<uint16_t>(0);
+ }
+ }
+
+ /// Used to serialize the on-disk Objective-C context table.
+ class ObjCContextIDTableInfo {
+ public:
+ using key_type = std::pair<unsigned, char>; // identifier ID, is-protocol
+ using key_type_ref = key_type;
+ using data_type = unsigned;
+ using data_type_ref = const data_type &;
+ using hash_value_type = size_t;
+ using offset_type = unsigned;
+
+ hash_value_type ComputeHash(key_type_ref key) {
+ return static_cast<size_t>(llvm::hash_value(key));
+ }
+
+ std::pair<unsigned, unsigned> EmitKeyDataLength(raw_ostream &out,
+ key_type_ref key,
+ data_type_ref data) {
+ uint32_t keyLength = sizeof(uint32_t) + 1;
+ uint32_t dataLength = sizeof(uint32_t);
+ endian::Writer<little> writer(out);
+ writer.write<uint16_t>(keyLength);
+ writer.write<uint16_t>(dataLength);
+ return { keyLength, dataLength };
+ }
+
+ void EmitKey(raw_ostream &out, key_type_ref key, unsigned len) {
+ endian::Writer<little> writer(out);
+ writer.write<uint32_t>(key.first);
+ writer.write<uint8_t>(key.second);
+ }
+
+ void EmitData(raw_ostream &out, key_type_ref key, data_type_ref data,
+ unsigned len) {
+ endian::Writer<little> writer(out);
+ writer.write<uint32_t>(data);
+ }
+ };
+} // end anonymous namespace
+
+namespace {
+ /// Retrieve the serialized size of the given VersionTuple, for use in
+ /// on-disk hash tables.
+ unsigned getVersionTupleSize(const VersionTuple &version) {
+ unsigned size = sizeof(uint8_t) + /*major*/sizeof(uint32_t);
+ if (version.getMinor()) size += sizeof(uint32_t);
+ if (version.getSubminor()) size += sizeof(uint32_t);
+ if (version.getBuild()) size += sizeof(uint32_t);
+ return size;
+ }
+
+ /// Emit a serialized representation of a version tuple.
+ void emitVersionTuple(raw_ostream &out, const VersionTuple &version) {
+ endian::Writer<little> writer(out);
+
+ // First byte contains the number of components beyond the 'major'
+ // component.
+ uint8_t descriptor;
+ if (version.getBuild()) descriptor = 3;
+ else if (version.getSubminor()) descriptor = 2;
+ else if (version.getMinor()) descriptor = 1;
+ else descriptor = 0;
+ assert(!version.usesUnderscores() && "Not a serializable version");
+ writer.write<uint8_t>(descriptor);
+
+ // Write the components.
+ writer.write<uint32_t>(version.getMajor());
+ if (auto minor = version.getMinor())
+ writer.write<uint32_t>(*minor);
+ if (auto subminor = version.getSubminor())
+ writer.write<uint32_t>(*subminor);
+ if (auto build = version.getBuild())
+ writer.write<uint32_t>(*build);
+ }
+
+ /// Localized helper to make a type dependent, thwarting template argument
+ /// deduction.
+ template<typename T>
+ struct MakeDependent {
+ typedef T Type;
+ };
+
+ /// Determine the size of an array of versioned information,
+ template<typename T>
+ unsigned getVersionedInfoSize(
+ const SmallVectorImpl<std::pair<VersionTuple, T>> &infoArray,
+ llvm::function_ref<unsigned(const typename MakeDependent<T>::Type&)>
+ getInfoSize) {
+ unsigned result = sizeof(uint16_t); // # of elements
+ for (const auto &element : infoArray) {
+ result += getVersionTupleSize(element.first);
+ result += getInfoSize(element.second);
+ }
+
+ return result;
+ }
+
+ /// Emit versioned information.
+ template<typename T>
+ void emitVersionedInfo(
+ raw_ostream &out,
+ const SmallVectorImpl<std::pair<VersionTuple, T>> &infoArray,
+ llvm::function_ref<void(raw_ostream &out,
+ const typename MakeDependent<T>::Type& info)>
+ emitInfo) {
+ endian::Writer<little> writer(out);
+ writer.write<uint16_t>(infoArray.size());
+ for (const auto &element : infoArray) {
+ emitVersionTuple(out, element.first);
+ emitInfo(out, element.second);
+ }
+ }
+
+ /// Retrieve the serialized size of the given VariableInfo, for use in
+ /// on-disk hash tables.
+ unsigned getVariableInfoSize(const VariableInfo &info) {
+ return 2 + getCommonEntityInfoSize(info) + 2 + info.getType().size();
+ }
+
+ /// Emit a serialized representation of the variable information.
+ void emitVariableInfo(raw_ostream &out, const VariableInfo &info) {
+ emitCommonEntityInfo(out, info);
+
+ uint8_t bytes[2] = { 0, 0 };
+ if (auto nullable = info.getNullability()) {
+ bytes[0] = 1;
+ bytes[1] = static_cast<uint8_t>(*nullable);
+ } else {
+ // Nothing to do.
+ }
+
+ out.write(reinterpret_cast<const char *>(bytes), 2);
+
+ endian::Writer<little> writer(out);
+ writer.write<uint16_t>(info.getType().size());
+ out.write(info.getType().data(), info.getType().size());
+ }
+
+ /// On-dish hash table info key base for handling versioned data.
+ template<typename Derived, typename KeyType, typename UnversionedDataType>
+ class VersionedTableInfo {
+ Derived &asDerived() {
+ return *static_cast<Derived *>(this);
+ }
+
+ const Derived &asDerived() const {
+ return *static_cast<const Derived *>(this);
+ }
+
+ public:
+ using key_type = KeyType;
+ using key_type_ref = key_type;
+ using data_type =
+ SmallVector<std::pair<VersionTuple, UnversionedDataType>, 1>;
+ using data_type_ref = const data_type &;
+ using hash_value_type = size_t;
+ using offset_type = unsigned;
+
+ hash_value_type ComputeHash(key_type_ref key) {
+ return llvm::hash_value(key);
+ }
+
+ std::pair<unsigned, unsigned> EmitKeyDataLength(raw_ostream &out,
+ key_type_ref key,
+ data_type_ref data) {
+ uint32_t keyLength = asDerived().getKeyLength(key);
+ uint32_t dataLength = getVersionedInfoSize(data,
+ [this](const UnversionedDataType &unversionedInfo) {
+ return asDerived().getUnversionedInfoSize(unversionedInfo);
+ });
+
+ endian::Writer<little> writer(out);
+ writer.write<uint16_t>(keyLength);
+ writer.write<uint16_t>(dataLength);
+ return { keyLength, dataLength };
+ }
+
+ void EmitData(raw_ostream &out, key_type_ref key, data_type_ref data,
+ unsigned len) {
+ emitVersionedInfo(out, data,
+ [this](llvm::raw_ostream &out,
+ const UnversionedDataType &unversionedInfo) {
+ asDerived().emitUnversionedInfo(out, unversionedInfo);
+ });
+ }
+ };
+
+ /// Used to serialize the on-disk Objective-C property table.
+ class ObjCContextInfoTableInfo
+ : public VersionedTableInfo<ObjCContextInfoTableInfo,
+ unsigned,
+ ObjCContextInfo> {
+ public:
+ unsigned getKeyLength(key_type_ref) {
+ return sizeof(uint32_t);
+ }
+
+ void EmitKey(raw_ostream &out, key_type_ref key, unsigned len) {
+ endian::Writer<little> writer(out);
+ writer.write<uint32_t>(key);
+ }
+
+ unsigned getUnversionedInfoSize(const ObjCContextInfo &info) {
+ return getCommonTypeInfoSize(info) + 1;
+ }
+
+ void emitUnversionedInfo(raw_ostream &out, const ObjCContextInfo &info) {
+ emitCommonTypeInfo(out, info);
+
+ uint8_t payload = 0;
+ if (auto nullable = info.getDefaultNullability()) {
+ payload = (0x01 << 2) | static_cast<uint8_t>(*nullable);
+ }
+ payload = (payload << 1) | (info.hasDesignatedInits() ? 1 : 0);
+ out << payload;
+ }
+ };
+
+ /// Used to serialize the on-disk Objective-C property table.
+ class ObjCPropertyTableInfo
+ : public VersionedTableInfo<ObjCPropertyTableInfo,
+ std::tuple<unsigned, unsigned, char>,
+ ObjCPropertyInfo> {
+ public:
+ unsigned getKeyLength(key_type_ref) {
+ return sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint8_t);
+ }
+
+ void EmitKey(raw_ostream &out, key_type_ref key, unsigned len) {
+ endian::Writer<little> writer(out);
+ writer.write<uint32_t>(std::get<0>(key));
+ writer.write<uint32_t>(std::get<1>(key));
+ writer.write<uint8_t>(std::get<2>(key));
+ }
+
+ unsigned getUnversionedInfoSize(const ObjCPropertyInfo &info) {
+ return getVariableInfoSize(info) + 1;
+ }
+
+ void emitUnversionedInfo(raw_ostream &out, const ObjCPropertyInfo &info) {
+ emitVariableInfo(out, info);
+ uint8_t flags = 0;
+ if (Optional<bool> value = info.getSwiftImportAsAccessors()) {
+ flags |= 1 << 0;
+ flags |= value.getValue() << 1;
+ }
+ out << flags;
+ }
+ };
+} // end anonymous namespace
+
+void APINotesWriter::Implementation::writeObjCContextBlock(
+ llvm::BitstreamWriter &writer) {
+ BCBlockRAII restoreBlock(writer, OBJC_CONTEXT_BLOCK_ID, 3);
+
+ if (ObjCContexts.empty())
+ return;
+
+ {
+ llvm::SmallString<4096> hashTableBlob;
+ uint32_t tableOffset;
+ {
+ llvm::OnDiskChainedHashTableGenerator<ObjCContextIDTableInfo> generator;
+ for (auto &entry : ObjCContexts)
+ generator.insert(entry.first, entry.second.first);
+
+ llvm::raw_svector_ostream blobStream(hashTableBlob);
+ // Make sure that no bucket is at offset 0
+ endian::Writer<little>(blobStream).write<uint32_t>(0);
+ tableOffset = generator.Emit(blobStream);
+ }
+
+ objc_context_block::ObjCContextIDLayout layout(writer);
+ layout.emit(ScratchRecord, tableOffset, hashTableBlob);
+ }
+
+ {
+ llvm::SmallString<4096> hashTableBlob;
+ uint32_t tableOffset;
+ {
+ llvm::OnDiskChainedHashTableGenerator<ObjCContextInfoTableInfo>
+ generator;
+ for (auto &entry : ObjCContexts)
+ generator.insert(entry.second.first, entry.second.second);
+
+ llvm::raw_svector_ostream blobStream(hashTableBlob);
+ // Make sure that no bucket is at offset 0
+ endian::Writer<little>(blobStream).write<uint32_t>(0);
+ tableOffset = generator.Emit(blobStream);
+ }
+
+ objc_context_block::ObjCContextInfoLayout layout(writer);
+ layout.emit(ScratchRecord, tableOffset, hashTableBlob);
+ }
+}
+
+void APINotesWriter::Implementation::writeObjCPropertyBlock(
+ llvm::BitstreamWriter &writer) {
+ BCBlockRAII restoreBlock(writer, OBJC_PROPERTY_BLOCK_ID, 3);
+
+ if (ObjCProperties.empty())
+ return;
+
+ llvm::SmallString<4096> hashTableBlob;
+ uint32_t tableOffset;
+ {
+ llvm::OnDiskChainedHashTableGenerator<ObjCPropertyTableInfo> generator;
+ for (auto &entry : ObjCProperties)
+ generator.insert(entry.first, entry.second);
+
+ llvm::raw_svector_ostream blobStream(hashTableBlob);
+ // Make sure that no bucket is at offset 0
+ endian::Writer<little>(blobStream).write<uint32_t>(0);
+ tableOffset = generator.Emit(blobStream);
+ }
+
+ objc_property_block::ObjCPropertyDataLayout layout(writer);
+ layout.emit(ScratchRecord, tableOffset, hashTableBlob);
+}
+
+namespace {
+ static unsigned getParamInfoSize(const ParamInfo &info) {
+ return getVariableInfoSize(info) + 1;
+ }
+
+ static void emitParamInfo(raw_ostream &out, const ParamInfo &info) {
+ emitVariableInfo(out, info);
+
+ endian::Writer<little> writer(out);
+
+ uint8_t payload = 0;
+ if (auto noescape = info.isNoEscape()) {
+ payload |= 0x01;
+ if (*noescape)
+ payload |= 0x02;
+ }
+ writer.write<uint8_t>(payload);
+ }
+
+ /// Retrieve the serialized size of the given FunctionInfo, for use in
+ /// on-disk hash tables.
+ static unsigned getFunctionInfoSize(const FunctionInfo &info) {
+ unsigned size = 2 + sizeof(uint64_t) + getCommonEntityInfoSize(info) + 2;
+
+ for (const auto ¶m : info.Params)
+ size += getParamInfoSize(param);
+
+ size += 2 + info.ResultType.size();
+ return size;
+ }
+
+ /// Emit a serialized representation of the function information.
+ static void emitFunctionInfo(raw_ostream &out, const FunctionInfo &info) {
+ emitCommonEntityInfo(out, info);
+
+ endian::Writer<little> writer(out);
+ writer.write<uint8_t>(info.NullabilityAudited);
+ writer.write<uint8_t>(info.NumAdjustedNullable);
+ writer.write<uint64_t>(info.NullabilityPayload);
+
+ // Parameters.
+ writer.write<uint16_t>(info.Params.size());
+ for (const auto &pi : info.Params)
+ emitParamInfo(out, pi);
+
+ // Result type.
+ writer.write<uint16_t>(info.ResultType.size());
+ out.write(info.ResultType.data(), info.ResultType.size());
+ }
+
+ /// Used to serialize the on-disk Objective-C method table.
+ class ObjCMethodTableInfo
+ : public VersionedTableInfo<ObjCMethodTableInfo,
+ std::tuple<unsigned, unsigned, char>,
+ ObjCMethodInfo> {
+ public:
+ unsigned getKeyLength(key_type_ref) {
+ return sizeof(uint32_t) + sizeof(uint32_t) + 1;
+ }
+
+ void EmitKey(raw_ostream &out, key_type_ref key, unsigned len) {
+ endian::Writer<little> writer(out);
+ writer.write<uint32_t>(std::get<0>(key));
+ writer.write<uint32_t>(std::get<1>(key));
+ writer.write<uint8_t>(std::get<2>(key));
+ }
+
+ unsigned getUnversionedInfoSize(const ObjCMethodInfo &info) {
+ return 1 + getFunctionInfoSize(info);
+ }
+
+ void emitUnversionedInfo(raw_ostream &out, const ObjCMethodInfo &info) {
+ uint8_t payload = info.FactoryAsInit;
+ payload = (payload << 1) | info.DesignatedInit;
+ payload = (payload << 1) | info.Required;
+ endian::Writer<little> writer(out);
+ writer.write<uint8_t>(payload);
+
+ emitFunctionInfo(out, info);
+ }
+ };
+} // end anonymous namespace
+
+void APINotesWriter::Implementation::writeObjCMethodBlock(
+ llvm::BitstreamWriter &writer) {
+ BCBlockRAII restoreBlock(writer, OBJC_METHOD_BLOCK_ID, 3);
+
+ if (ObjCMethods.empty())
+ return;
+
+ llvm::SmallString<4096> hashTableBlob;
+ uint32_t tableOffset;
+ {
+ llvm::OnDiskChainedHashTableGenerator<ObjCMethodTableInfo> generator;
+ for (auto &entry : ObjCMethods) {
+ generator.insert(entry.first, entry.second);
+ }
+
+ llvm::raw_svector_ostream blobStream(hashTableBlob);
+ // Make sure that no bucket is at offset 0
+ endian::Writer<little>(blobStream).write<uint32_t>(0);
+ tableOffset = generator.Emit(blobStream);
+ }
+
+ objc_method_block::ObjCMethodDataLayout layout(writer);
+ layout.emit(ScratchRecord, tableOffset, hashTableBlob);
+}
+
+namespace {
+ /// Used to serialize the on-disk Objective-C selector table.
+ class ObjCSelectorTableInfo {
+ public:
+ using key_type = StoredObjCSelector;
+ using key_type_ref = const key_type &;
+ using data_type = SelectorID;
+ using data_type_ref = data_type;
+ using hash_value_type = unsigned;
+ using offset_type = unsigned;
+
+ hash_value_type ComputeHash(key_type_ref key) {
+ return llvm::DenseMapInfo<StoredObjCSelector>::getHashValue(key);
+ }
+
+ std::pair<unsigned, unsigned> EmitKeyDataLength(raw_ostream &out,
+ key_type_ref key,
+ data_type_ref data) {
+ uint32_t keyLength = sizeof(uint16_t)
+ + sizeof(uint32_t) * key.Identifiers.size();
+ uint32_t dataLength = sizeof(uint32_t);
+ endian::Writer<little> writer(out);
+ writer.write<uint16_t>(keyLength);
+ writer.write<uint16_t>(dataLength);
+ return { keyLength, dataLength };
+ }
+
+ void EmitKey(raw_ostream &out, key_type_ref key, unsigned len) {
+ endian::Writer<little> writer(out);
+ writer.write<uint16_t>(key.NumPieces);
+ for (auto piece : key.Identifiers) {
+ writer.write<uint32_t>(piece);
+ }
+ }
+
+ void EmitData(raw_ostream &out, key_type_ref key, data_type_ref data,
+ unsigned len) {
+ endian::Writer<little> writer(out);
+ writer.write<uint32_t>(data);
+ }
+ };
+} // end anonymous namespace
+
+void APINotesWriter::Implementation::writeObjCSelectorBlock(
+ llvm::BitstreamWriter &writer) {
+ BCBlockRAII restoreBlock(writer, OBJC_SELECTOR_BLOCK_ID, 3);
+
+ if (SelectorIDs.empty())
+ return;
+
+ llvm::SmallString<4096> hashTableBlob;
+ uint32_t tableOffset;
+ {
+ llvm::OnDiskChainedHashTableGenerator<ObjCSelectorTableInfo> generator;
+ for (auto &entry : SelectorIDs)
+ generator.insert(entry.first, entry.second);
+
+ llvm::raw_svector_ostream blobStream(hashTableBlob);
+ // Make sure that no bucket is at offset 0
+ endian::Writer<little>(blobStream).write<uint32_t>(0);
+ tableOffset = generator.Emit(blobStream);
+ }
+
+ objc_selector_block::ObjCSelectorDataLayout layout(writer);
+ layout.emit(ScratchRecord, tableOffset, hashTableBlob);
+}
+
+namespace {
+ /// Used to serialize the on-disk global variable table.
+ class GlobalVariableTableInfo
+ : public VersionedTableInfo<GlobalVariableTableInfo,
+ unsigned,
+ GlobalVariableInfo> {
+ public:
+ unsigned getKeyLength(key_type_ref key) {
+ return sizeof(uint32_t);
+ }
+
+ void EmitKey(raw_ostream &out, key_type_ref key, unsigned len) {
+ endian::Writer<little> writer(out);
+ writer.write<uint32_t>(key);
+ }
+
+ unsigned getUnversionedInfoSize(const GlobalVariableInfo &info) {
+ return getVariableInfoSize(info);
+ }
+
+ void emitUnversionedInfo(raw_ostream &out,
+ const GlobalVariableInfo &info) {
+ emitVariableInfo(out, info);
+ }
+ };
+} // end anonymous namespace
+
+void APINotesWriter::Implementation::writeGlobalVariableBlock(
+ llvm::BitstreamWriter &writer) {
+ BCBlockRAII restoreBlock(writer, GLOBAL_VARIABLE_BLOCK_ID, 3);
+
+ if (GlobalVariables.empty())
+ return;
+
+ llvm::SmallString<4096> hashTableBlob;
+ uint32_t tableOffset;
+ {
+ llvm::OnDiskChainedHashTableGenerator<GlobalVariableTableInfo> generator;
+ for (auto &entry : GlobalVariables)
+ generator.insert(entry.first, entry.second);
+
+ llvm::raw_svector_ostream blobStream(hashTableBlob);
+ // Make sure that no bucket is at offset 0
+ endian::Writer<little>(blobStream).write<uint32_t>(0);
+ tableOffset = generator.Emit(blobStream);
+ }
+
+ global_variable_block::GlobalVariableDataLayout layout(writer);
+ layout.emit(ScratchRecord, tableOffset, hashTableBlob);
+}
+
+namespace {
+ /// Used to serialize the on-disk global function table.
+ class GlobalFunctionTableInfo
+ : public VersionedTableInfo<GlobalFunctionTableInfo,
+ unsigned,
+ GlobalFunctionInfo> {
+ public:
+ unsigned getKeyLength(key_type_ref) {
+ return sizeof(uint32_t);
+ }
+
+ void EmitKey(raw_ostream &out, key_type_ref key, unsigned len) {
+ endian::Writer<little> writer(out);
+ writer.write<uint32_t>(key);
+ }
+
+ unsigned getUnversionedInfoSize(const GlobalFunctionInfo &info) {
+ return getFunctionInfoSize(info);
+ }
+
+ void emitUnversionedInfo(raw_ostream &out,
+ const GlobalFunctionInfo &info) {
+ emitFunctionInfo(out, info);
+ }
+ };
+} // end anonymous namespace
+
+void APINotesWriter::Implementation::writeGlobalFunctionBlock(
+ llvm::BitstreamWriter &writer) {
+ BCBlockRAII restoreBlock(writer, GLOBAL_FUNCTION_BLOCK_ID, 3);
+
+ if (GlobalFunctions.empty())
+ return;
+
+ llvm::SmallString<4096> hashTableBlob;
+ uint32_t tableOffset;
+ {
+ llvm::OnDiskChainedHashTableGenerator<GlobalFunctionTableInfo> generator;
+ for (auto &entry : GlobalFunctions) {
+ generator.insert(entry.first, entry.second);
+ }
+
+ llvm::raw_svector_ostream blobStream(hashTableBlob);
+ // Make sure that no bucket is at offset 0
+ endian::Writer<little>(blobStream).write<uint32_t>(0);
+ tableOffset = generator.Emit(blobStream);
+ }
+
+ global_function_block::GlobalFunctionDataLayout layout(writer);
+ layout.emit(ScratchRecord, tableOffset, hashTableBlob);
+}
+
+namespace {
+ /// Used to serialize the on-disk global enum constant.
+ class EnumConstantTableInfo
+ : public VersionedTableInfo<EnumConstantTableInfo,
+ unsigned,
+ EnumConstantInfo> {
+ public:
+ unsigned getKeyLength(key_type_ref) {
+ return sizeof(uint32_t);
+ }
+
+ void EmitKey(raw_ostream &out, key_type_ref key, unsigned len) {
+ endian::Writer<little> writer(out);
+ writer.write<uint32_t>(key);
+ }
+
+ unsigned getUnversionedInfoSize(const EnumConstantInfo &info) {
+ return getCommonEntityInfoSize(info);
+ }
+
+ void emitUnversionedInfo(raw_ostream &out, const EnumConstantInfo &info) {
+ emitCommonEntityInfo(out, info);
+ }
+ };
+} // end anonymous namespace
+
+void APINotesWriter::Implementation::writeEnumConstantBlock(
+ llvm::BitstreamWriter &writer) {
+ BCBlockRAII restoreBlock(writer, ENUM_CONSTANT_BLOCK_ID, 3);
+
+ if (EnumConstants.empty())
+ return;
+
+ llvm::SmallString<4096> hashTableBlob;
+ uint32_t tableOffset;
+ {
+ llvm::OnDiskChainedHashTableGenerator<EnumConstantTableInfo> generator;
+ for (auto &entry : EnumConstants)
+ generator.insert(entry.first, entry.second);
+
+ llvm::raw_svector_ostream blobStream(hashTableBlob);
+ // Make sure that no bucket is at offset 0
+ endian::Writer<little>(blobStream).write<uint32_t>(0);
+ tableOffset = generator.Emit(blobStream);
+ }
+
+ enum_constant_block::EnumConstantDataLayout layout(writer);
+ layout.emit(ScratchRecord, tableOffset, hashTableBlob);
+}
+
+namespace {
+ template<typename Derived, typename UnversionedDataType>
+ class CommonTypeTableInfo
+ : public VersionedTableInfo<Derived, unsigned, UnversionedDataType> {
+ public:
+ using key_type_ref = typename CommonTypeTableInfo::key_type_ref;
+
+ unsigned getKeyLength(key_type_ref) {
+ return sizeof(IdentifierID);
+ }
+ void EmitKey(raw_ostream &out, key_type_ref key, unsigned len) {
+ endian::Writer<little> writer(out);
+ writer.write<IdentifierID>(key);
+ }
+
+ unsigned getUnversionedInfoSize(const UnversionedDataType &info) {
+ return getCommonTypeInfoSize(info);
+ }
+
+ void emitUnversionedInfo(raw_ostream &out,
+ const UnversionedDataType &info) {
+ emitCommonTypeInfo(out, info);
+ }
+ };
+
+ /// Used to serialize the on-disk tag table.
+ class TagTableInfo : public CommonTypeTableInfo<TagTableInfo, TagInfo> { };
+
+} // end anonymous namespace
+
+void APINotesWriter::Implementation::writeTagBlock(
+ llvm::BitstreamWriter &writer) {
+ BCBlockRAII restoreBlock(writer, TAG_BLOCK_ID, 3);
+
+ if (Tags.empty())
+ return;
+
+ llvm::SmallString<4096> hashTableBlob;
+ uint32_t tableOffset;
+ {
+ llvm::OnDiskChainedHashTableGenerator<TagTableInfo> generator;
+ for (auto &entry : Tags)
+ generator.insert(entry.first, entry.second);
+
+ llvm::raw_svector_ostream blobStream(hashTableBlob);
+ // Make sure that no bucket is at offset 0
+ endian::Writer<little>(blobStream).write<uint32_t>(0);
+ tableOffset = generator.Emit(blobStream);
+ }
+
+ tag_block::TagDataLayout layout(writer);
+ layout.emit(ScratchRecord, tableOffset, hashTableBlob);
+}
+
+namespace {
+ /// Used to serialize the on-disk typedef table.
+ class TypedefTableInfo
+ : public CommonTypeTableInfo<TypedefTableInfo, TypedefInfo> {
+
+ public:
+ unsigned getUnversionedInfoSize(const TypedefInfo &info) {
+ return 1 + getCommonTypeInfoSize(info);
+ }
+
+ void emitUnversionedInfo(raw_ostream &out, const TypedefInfo &info) {
+ endian::Writer<little> writer(out);
+
+ uint8_t payload = 0;
+ if (auto swiftWrapper = info.SwiftWrapper) {
+ payload |= static_cast<uint8_t>(*swiftWrapper) + 1;
+ }
+
+ writer.write<uint8_t>(payload);
+
+ emitCommonTypeInfo(out, info);
+ }
+
+ };
+} // end anonymous namespace
+
+void APINotesWriter::Implementation::writeTypedefBlock(
+ llvm::BitstreamWriter &writer) {
+ BCBlockRAII restoreBlock(writer, TYPEDEF_BLOCK_ID, 3);
+
+ if (Typedefs.empty())
+ return;
+
+ llvm::SmallString<4096> hashTableBlob;
+ uint32_t tableOffset;
+ {
+ llvm::OnDiskChainedHashTableGenerator<TypedefTableInfo> generator;
+ for (auto &entry : Typedefs)
+ generator.insert(entry.first, entry.second);
+
+ llvm::raw_svector_ostream blobStream(hashTableBlob);
+ // Make sure that no bucket is at offset 0
+ endian::Writer<little>(blobStream).write<uint32_t>(0);
+ tableOffset = generator.Emit(blobStream);
+ }
+
+ typedef_block::TypedefDataLayout layout(writer);
+ layout.emit(ScratchRecord, tableOffset, hashTableBlob);
+}
+
+void APINotesWriter::Implementation::writeToStream(llvm::raw_ostream &os) {
+ // Write the API notes file into a buffer.
+ SmallVector<char, 0> buffer;
+ {
+ llvm::BitstreamWriter writer(buffer);
+
+ // Emit the signature.
+ for (unsigned char byte : API_NOTES_SIGNATURE)
+ writer.Emit(byte, 8);
+
+ // Emit the blocks.
+ writeBlockInfoBlock(writer);
+ writeControlBlock(writer);
+ writeIdentifierBlock(writer);
+ writeObjCContextBlock(writer);
+ writeObjCPropertyBlock(writer);
+ writeObjCMethodBlock(writer);
+ writeObjCSelectorBlock(writer);
+ writeGlobalVariableBlock(writer);
+ writeGlobalFunctionBlock(writer);
+ writeEnumConstantBlock(writer);
+ writeTagBlock(writer);
+ writeTypedefBlock(writer);
+ }
+
+ // Write the buffer to the stream.
+ os.write(buffer.data(), buffer.size());
+ os.flush();
+}
+
+APINotesWriter::APINotesWriter(StringRef moduleName, const FileEntry *sourceFile)
+ : Impl(*new Implementation)
+{
+ Impl.ModuleName = moduleName;
+ Impl.SourceFile = sourceFile;
+}
+
+APINotesWriter::~APINotesWriter() {
+ delete &Impl;
+}
+
+
+void APINotesWriter::writeToStream(raw_ostream &os) {
+ Impl.writeToStream(os);
+}
+
+ContextID APINotesWriter::addObjCContext(StringRef name, bool isClass,
+ const ObjCContextInfo &info,
+ VersionTuple swiftVersion) {
+ IdentifierID nameID = Impl.getIdentifier(name);
+
+ std::pair<unsigned, char> key(nameID, isClass ? 0 : 1);
+ auto known = Impl.ObjCContexts.find(key);
+ if (known == Impl.ObjCContexts.end()) {
+ unsigned nextID = Impl.ObjCContexts.size() + 1;
+
+ VersionedSmallVector<ObjCContextInfo> emptyVersionedInfo;
+ known = Impl.ObjCContexts.insert(
+ std::make_pair(key, std::make_pair(nextID, emptyVersionedInfo)))
+ .first;
+
+ Impl.ObjCContextNames[nextID] = nameID;
+ }
+
+ // Add this version information.
+ auto &versionedVec = known->second.second;
+ bool found = false;
+ for (auto &versioned : versionedVec){
+ if (versioned.first == swiftVersion) {
+ versioned.second |= info;
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ versionedVec.push_back({swiftVersion, info});
+
+ return ContextID(known->second.first);
+}
+
+void APINotesWriter::addObjCProperty(ContextID contextID, StringRef name,
+ bool isInstance,
+ const ObjCPropertyInfo &info,
+ VersionTuple swiftVersion) {
+ IdentifierID nameID = Impl.getIdentifier(name);
+ Impl.ObjCProperties[std::make_tuple(contextID.Value, nameID, isInstance)]
+ .push_back({swiftVersion, info});
+}
+
+void APINotesWriter::addObjCMethod(ContextID contextID,
+ ObjCSelectorRef selector,
+ bool isInstanceMethod,
+ const ObjCMethodInfo &info,
+ VersionTuple swiftVersion) {
+ SelectorID selectorID = Impl.getSelector(selector);
+ auto key = std::tuple<unsigned, unsigned, char>{
+ contextID.Value, selectorID, isInstanceMethod};
+ Impl.ObjCMethods[key].push_back({swiftVersion, info});
+
+ // If this method is a designated initializer, update the class to note that
+ // it has designated initializers.
+ if (info.DesignatedInit) {
+ assert(Impl.ObjCContexts.count({Impl.ObjCContextNames[contextID.Value],
+ (char)0}));
+ auto &versionedVec =
+ Impl.ObjCContexts[{Impl.ObjCContextNames[contextID.Value], (char)0}]
+ .second;
+ bool found = false;
+ for (auto &versioned : versionedVec) {
+ if (versioned.first == swiftVersion) {
+ versioned.second.setHasDesignatedInits(true);
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ versionedVec.push_back({swiftVersion, ObjCContextInfo()});
+ versionedVec.back().second.setHasDesignatedInits(true);
+ }
+ }
+}
+
+void APINotesWriter::addGlobalVariable(llvm::StringRef name,
+ const GlobalVariableInfo &info,
+ VersionTuple swiftVersion) {
+ IdentifierID variableID = Impl.getIdentifier(name);
+ Impl.GlobalVariables[variableID].push_back({swiftVersion, info});
+}
+
+void APINotesWriter::addGlobalFunction(llvm::StringRef name,
+ const GlobalFunctionInfo &info,
+ VersionTuple swiftVersion) {
+ IdentifierID nameID = Impl.getIdentifier(name);
+ Impl.GlobalFunctions[nameID].push_back({swiftVersion, info});
+}
+
+void APINotesWriter::addEnumConstant(llvm::StringRef name,
+ const EnumConstantInfo &info,
+ VersionTuple swiftVersion) {
+ IdentifierID enumConstantID = Impl.getIdentifier(name);
+ Impl.EnumConstants[enumConstantID].push_back({swiftVersion, info});
+}
+
+void APINotesWriter::addTag(llvm::StringRef name, const TagInfo &info,
+ VersionTuple swiftVersion) {
+ IdentifierID tagID = Impl.getIdentifier(name);
+ Impl.Tags[tagID].push_back({swiftVersion, info});
+}
+
+void APINotesWriter::addTypedef(llvm::StringRef name, const TypedefInfo &info,
+ VersionTuple swiftVersion) {
+ IdentifierID typedefID = Impl.getIdentifier(name);
+ Impl.Typedefs[typedefID].push_back({swiftVersion, info});
+}
+
+void APINotesWriter::addModuleOptions(ModuleOptions opts) {
+ Impl.SwiftInferImportAsMember = opts.SwiftInferImportAsMember;
+}
+
diff --git a/lib/APINotes/APINotesYAMLCompiler.cpp b/lib/APINotes/APINotesYAMLCompiler.cpp
new file mode 100644
index 0000000..0ac0b6d
--- /dev/null
+++ b/lib/APINotes/APINotesYAMLCompiler.cpp
@@ -0,0 +1,1411 @@
+//===--- APINotesYAMLCompiler.cpp - API Notes YAML format reader *- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file reads API notes specified in YAML format.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/APINotes/APINotesYAMLCompiler.h"
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/APINotes/Types.h"
+#include "clang/APINotes/APINotesWriter.h"
+#include "clang/Basic/VersionTuple.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/YAMLParser.h"
+#include "llvm/Support/YAMLTraits.h"
+#include <algorithm>
+
+/*
+
+ YAML Format specification.
+
+ Nullability should be expressed using one of the following values:
+ O - Optional (or Nullable)
+ N - Not Optional
+ S - Scalar
+ U - Unknown
+ Note, the API is considered 'audited' when at least the return value or a
+ parameter has a nullability value. For 'audited' APIs, we assume the default
+ nullability for any underspecified type.
+
+ FactoryAsInit can have the following values:
+ C - Treat as class method.
+ I - Treat as initializer.
+ A - Automatically infer based on the name and type (default).
+
+---
+ Name: AppKit # The name of the framework
+
+ Availability: OSX # Optional: Specifies which platform the API is
+ # available on. [OSX / iOS / none/
+ # available / nonswift]
+
+ AvailabilityMsg: "" # Optional: Custom availability message to display to
+ # the user, when API is not available.
+
+ Classes: # List of classes
+ ...
+ Protocols: # List of protocols
+ ...
+ Functions: # List of functions
+ ...
+ Globals: # List of globals
+ ...
+ Enumerators: # List of enumerators
+ ...
+ Tags: # List of tags (struct/union/enum/C++ class)
+ ...
+ Typedefs: # List of typedef-names and C++11 type aliases
+ ...
+
+ Each class and protocol is defined as following:
+
+ - Name: NSView # The name of the class
+
+ AuditedForNullability: false # Optional: Specifies if the whole class
+ # has been audited for nullability.
+ # If yes, we assume all the methods and
+ # properties of the class have default
+ # nullability unless it is overwritten by
+ # a method/property specific info below.
+ # This applies to all classes, extensions,
+ # and categories of the class defined in
+ # the current framework/module.
+ # (false/true)
+
+ Availability: OSX
+
+ AvailabilityMsg: ""
+
+ Methods:
+ - Selector: "setSubviews:" # Full name
+
+ MethodKind: Instance # [Class/Instance]
+
+ Nullability: [N, N, O, S] # The nullability of parameters in
+ # the signature.
+
+ NullabilityOfRet: O # The nullability of the return value.
+
+ Availability: OSX
+
+ AvailabilityMsg: ""
+
+ FactoryAsInit: C # Optional: Specifies if this method is a
+ # factory initializer (false/true)
+ DesignatedInit: false # Optional: Specifies if this method is a
+ # designated initializer (false/true)
+
+ Required: false # Optional: Specifies if this method is a
+ # required initializer (false/true)
+
+ Properties:
+ - Name: window
+
+ Nullability: O
+
+ Availability: OSX
+
+ AvailabilityMsg: ""
+
+ The protocol definition format is the same as the class definition.
+
+ Each function definition is of the following form:
+
+ - Name: "myGlobalFunction" # Full name
+
+ Nullability: [N, N, O, S] # The nullability of parameters in
+ # the signature.
+
+ NullabilityOfRet: O # The nullability of the return value.
+
+ Availability: OSX
+
+ AvailabilityMsg: ""
+
+Each global variable definition is of the following form:
+
+ - Name: MyGlobalVar
+
+ Nullability: O
+
+ Availability: OSX
+
+ AvailabilityMsg: ""
+
+*/
+
+using llvm::StringRef;
+using namespace clang;
+namespace {
+ enum class APIAvailability {
+ Available = 0,
+ OSX,
+ IOS,
+ None,
+ NonSwift,
+ };
+
+ enum class MethodKind {
+ Class,
+ Instance,
+ };
+
+ struct AvailabilityItem {
+ APIAvailability Mode = APIAvailability::Available;
+ StringRef Msg;
+ AvailabilityItem() : Mode(APIAvailability::Available), Msg("") {}
+ };
+
+ static llvm::Optional<NullabilityKind> AbsentNullability = llvm::None;
+ static llvm::Optional<NullabilityKind> DefaultNullability =
+ NullabilityKind::NonNull;
+ typedef std::vector<clang::NullabilityKind> NullabilitySeq;
+
+ struct Param {
+ unsigned Position;
+ Optional<bool> NoEscape = false;
+ llvm::Optional<NullabilityKind> Nullability;
+ StringRef Type;
+ };
+ typedef std::vector<Param> ParamsSeq;
+
+ struct Method {
+ StringRef Selector;
+ MethodKind Kind;
+ ParamsSeq Params;
+ NullabilitySeq Nullability;
+ llvm::Optional<NullabilityKind> NullabilityOfRet;
+ AvailabilityItem Availability;
+ Optional<bool> SwiftPrivate;
+ StringRef SwiftName;
+ api_notes::FactoryAsInitKind FactoryAsInit
+ = api_notes::FactoryAsInitKind::Infer;
+ bool DesignatedInit = false;
+ bool Required = false;
+ StringRef ResultType;
+ };
+ typedef std::vector<Method> MethodsSeq;
+
+ struct Property {
+ StringRef Name;
+ llvm::Optional<MethodKind> Kind;
+ llvm::Optional<NullabilityKind> Nullability;
+ AvailabilityItem Availability;
+ Optional<bool> SwiftPrivate;
+ StringRef SwiftName;
+ Optional<bool> SwiftImportAsAccessors;
+ StringRef Type;
+ };
+ typedef std::vector<Property> PropertiesSeq;
+
+ struct Class {
+ StringRef Name;
+ bool AuditedForNullability = false;
+ AvailabilityItem Availability;
+ Optional<bool> SwiftPrivate;
+ StringRef SwiftName;
+ Optional<StringRef> SwiftBridge;
+ Optional<StringRef> NSErrorDomain;
+ MethodsSeq Methods;
+ PropertiesSeq Properties;
+ };
+ typedef std::vector<Class> ClassesSeq;
+
+ struct Function {
+ StringRef Name;
+ ParamsSeq Params;
+ NullabilitySeq Nullability;
+ llvm::Optional<NullabilityKind> NullabilityOfRet;
+ AvailabilityItem Availability;
+ Optional<bool> SwiftPrivate;
+ StringRef SwiftName;
+ StringRef Type;
+ StringRef ResultType;
+ };
+ typedef std::vector<Function> FunctionsSeq;
+
+ struct GlobalVariable {
+ StringRef Name;
+ llvm::Optional<NullabilityKind> Nullability;
+ AvailabilityItem Availability;
+ Optional<bool> SwiftPrivate;
+ StringRef SwiftName;
+ StringRef Type;
+ };
+ typedef std::vector<GlobalVariable> GlobalVariablesSeq;
+
+ struct EnumConstant {
+ StringRef Name;
+ AvailabilityItem Availability;
+ Optional<bool> SwiftPrivate;
+ StringRef SwiftName;
+ };
+ typedef std::vector<EnumConstant> EnumConstantsSeq;
+
+ struct Tag {
+ StringRef Name;
+ AvailabilityItem Availability;
+ StringRef SwiftName;
+ Optional<bool> SwiftPrivate;
+ Optional<StringRef> SwiftBridge;
+ Optional<StringRef> NSErrorDomain;
+ };
+ typedef std::vector<Tag> TagsSeq;
+
+ struct Typedef {
+ StringRef Name;
+ AvailabilityItem Availability;
+ StringRef SwiftName;
+ Optional<bool> SwiftPrivate;
+ Optional<StringRef> SwiftBridge;
+ Optional<StringRef> NSErrorDomain;
+ Optional<api_notes::SwiftWrapperKind> SwiftWrapper;
+ };
+ typedef std::vector<Typedef> TypedefsSeq;
+
+ struct TopLevelItems {
+ ClassesSeq Classes;
+ ClassesSeq Protocols;
+ FunctionsSeq Functions;
+ GlobalVariablesSeq Globals;
+ EnumConstantsSeq EnumConstants;
+ TagsSeq Tags;
+ TypedefsSeq Typedefs;
+ };
+
+ struct Versioned {
+ VersionTuple Version;
+ TopLevelItems Items;
+ };
+
+ typedef std::vector<Versioned> VersionedSeq;
+
+ struct Module {
+ StringRef Name;
+ AvailabilityItem Availability;
+ TopLevelItems TopLevel;
+ VersionedSeq SwiftVersions;
+
+ llvm::Optional<bool> SwiftInferImportAsMember = {llvm::None};
+
+ LLVM_ATTRIBUTE_DEPRECATED(
+ void dump() LLVM_ATTRIBUTE_USED,
+ "only for use within the debugger");
+ };
+}
+
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(clang::NullabilityKind)
+LLVM_YAML_IS_SEQUENCE_VECTOR(Method)
+LLVM_YAML_IS_SEQUENCE_VECTOR(Property)
+LLVM_YAML_IS_SEQUENCE_VECTOR(Param)
+LLVM_YAML_IS_SEQUENCE_VECTOR(Class)
+LLVM_YAML_IS_SEQUENCE_VECTOR(Function)
+LLVM_YAML_IS_SEQUENCE_VECTOR(GlobalVariable)
+LLVM_YAML_IS_SEQUENCE_VECTOR(EnumConstant)
+LLVM_YAML_IS_SEQUENCE_VECTOR(Tag)
+LLVM_YAML_IS_SEQUENCE_VECTOR(Typedef)
+LLVM_YAML_IS_SEQUENCE_VECTOR(Versioned)
+
+namespace llvm {
+ namespace yaml {
+
+ template <>
+ struct ScalarEnumerationTraits<NullabilityKind > {
+ static void enumeration(IO &io, NullabilityKind &value) {
+ io.enumCase(value, "N", NullabilityKind::NonNull);
+ io.enumCase(value, "O", NullabilityKind::Nullable);
+ io.enumCase(value, "U", NullabilityKind::Unspecified);
+ // TODO: Mapping this to it's own value would allow for better cross
+ // checking. Also the default should be Unknown.
+ io.enumCase(value, "S", NullabilityKind::Unspecified);
+ }
+ };
+
+ template <>
+ struct ScalarEnumerationTraits<api_notes::FactoryAsInitKind > {
+ static void enumeration(IO &io, api_notes::FactoryAsInitKind &value) {
+ io.enumCase(value, "A", api_notes::FactoryAsInitKind::Infer);
+ io.enumCase(value, "C", api_notes::FactoryAsInitKind::AsClassMethod);
+ io.enumCase(value, "I", api_notes::FactoryAsInitKind::AsInitializer);
+ }
+ };
+
+ template <>
+ struct ScalarEnumerationTraits<MethodKind> {
+ static void enumeration(IO &io, MethodKind &value) {
+ io.enumCase(value, "Class", MethodKind::Class);
+ io.enumCase(value, "Instance", MethodKind::Instance);
+ }
+ };
+
+ template <>
+ struct ScalarEnumerationTraits<APIAvailability> {
+ static void enumeration(IO &io, APIAvailability &value) {
+ io.enumCase(value, "OSX", APIAvailability::OSX);
+ io.enumCase(value, "iOS", APIAvailability::IOS);
+ io.enumCase(value, "none", APIAvailability::None);
+ io.enumCase(value, "nonswift", APIAvailability::NonSwift);
+ io.enumCase(value, "available", APIAvailability::Available);
+ }
+ };
+
+ template<>
+ struct ScalarEnumerationTraits<api_notes::SwiftWrapperKind> {
+ static void enumeration(IO &io, api_notes::SwiftWrapperKind &value) {
+ io.enumCase(value, "none", api_notes::SwiftWrapperKind::None);
+ io.enumCase(value, "struct", api_notes::SwiftWrapperKind::Struct);
+ io.enumCase(value, "enum", api_notes::SwiftWrapperKind::Enum);
+ }
+ };
+
+ template <>
+ struct ScalarTraits<VersionTuple> {
+ static void output(const VersionTuple &value, void*,
+ llvm::raw_ostream &out) {
+ out << value;
+ }
+ static StringRef input(StringRef scalar, void*, VersionTuple &value) {
+ if (value.tryParse(scalar))
+ return "not a version number in the form XX.YY";
+
+ // Canonicalize on '.' as a separator.
+ value.UseDotAsSeparator();
+ return StringRef();
+ }
+
+ static bool mustQuote(StringRef) { return false; }
+ };
+
+ template <>
+ struct MappingTraits<Param> {
+ static void mapping(IO &io, Param& p) {
+ io.mapRequired("Position", p.Position);
+ io.mapOptional("Nullability", p.Nullability,
+ AbsentNullability);
+ io.mapOptional("NoEscape", p.NoEscape);
+ io.mapOptional("Type", p.Type, StringRef(""));
+ }
+ };
+
+ template <>
+ struct MappingTraits<Property> {
+ static void mapping(IO &io, Property& p) {
+ io.mapRequired("Name", p.Name);
+ io.mapOptional("PropertyKind", p.Kind);
+ io.mapOptional("Nullability", p.Nullability,
+ AbsentNullability);
+ io.mapOptional("Availability", p.Availability.Mode);
+ io.mapOptional("AvailabilityMsg", p.Availability.Msg);
+ io.mapOptional("SwiftPrivate", p.SwiftPrivate);
+ io.mapOptional("SwiftName", p.SwiftName);
+ io.mapOptional("SwiftImportAsAccessors", p.SwiftImportAsAccessors);
+ io.mapOptional("Type", p.Type, StringRef(""));
+ }
+ };
+
+ template <>
+ struct MappingTraits<Method> {
+ static void mapping(IO &io, Method& m) {
+ io.mapRequired("Selector", m.Selector);
+ io.mapRequired("MethodKind", m.Kind);
+ io.mapOptional("Parameters", m.Params);
+ io.mapOptional("Nullability", m.Nullability);
+ io.mapOptional("NullabilityOfRet", m.NullabilityOfRet,
+ AbsentNullability);
+ io.mapOptional("Availability", m.Availability.Mode);
+ io.mapOptional("AvailabilityMsg", m.Availability.Msg);
+ io.mapOptional("SwiftPrivate", m.SwiftPrivate);
+ io.mapOptional("SwiftName", m.SwiftName);
+ io.mapOptional("FactoryAsInit", m.FactoryAsInit,
+ api_notes::FactoryAsInitKind::Infer);
+ io.mapOptional("DesignatedInit", m.DesignatedInit, false);
+ io.mapOptional("Required", m.Required, false);
+ io.mapOptional("ResultType", m.ResultType, StringRef(""));
+ }
+ };
+
+ template <>
+ struct MappingTraits<Class> {
+ static void mapping(IO &io, Class& c) {
+ io.mapRequired("Name", c.Name);
+ io.mapOptional("AuditedForNullability", c.AuditedForNullability, false);
+ io.mapOptional("Availability", c.Availability.Mode);
+ io.mapOptional("AvailabilityMsg", c.Availability.Msg);
+ io.mapOptional("SwiftPrivate", c.SwiftPrivate);
+ io.mapOptional("SwiftName", c.SwiftName);
+ io.mapOptional("SwiftBridge", c.SwiftBridge);
+ io.mapOptional("NSErrorDomain", c.NSErrorDomain);
+ io.mapOptional("Methods", c.Methods);
+ io.mapOptional("Properties", c.Properties);
+ }
+ };
+
+ template <>
+ struct MappingTraits<Function> {
+ static void mapping(IO &io, Function& f) {
+ io.mapRequired("Name", f.Name);
+ io.mapOptional("Parameters", f.Params);
+ io.mapOptional("Nullability", f.Nullability);
+ io.mapOptional("NullabilityOfRet", f.NullabilityOfRet,
+ AbsentNullability);
+ io.mapOptional("Availability", f.Availability.Mode);
+ io.mapOptional("AvailabilityMsg", f.Availability.Msg);
+ io.mapOptional("SwiftPrivate", f.SwiftPrivate);
+ io.mapOptional("SwiftName", f.SwiftName);
+ io.mapOptional("ResultType", f.ResultType, StringRef(""));
+ }
+ };
+
+ template <>
+ struct MappingTraits<GlobalVariable> {
+ static void mapping(IO &io, GlobalVariable& v) {
+ io.mapRequired("Name", v.Name);
+ io.mapOptional("Nullability", v.Nullability,
+ AbsentNullability);
+ io.mapOptional("Availability", v.Availability.Mode);
+ io.mapOptional("AvailabilityMsg", v.Availability.Msg);
+ io.mapOptional("SwiftPrivate", v.SwiftPrivate);
+ io.mapOptional("SwiftName", v.SwiftName);
+ io.mapOptional("Type", v.Type, StringRef(""));
+ }
+ };
+
+ template <>
+ struct MappingTraits<EnumConstant> {
+ static void mapping(IO &io, EnumConstant& v) {
+ io.mapRequired("Name", v.Name);
+ io.mapOptional("Availability", v.Availability.Mode);
+ io.mapOptional("AvailabilityMsg", v.Availability.Msg);
+ io.mapOptional("SwiftPrivate", v.SwiftPrivate);
+ io.mapOptional("SwiftName", v.SwiftName);
+ }
+ };
+
+ template <>
+ struct MappingTraits<Tag> {
+ static void mapping(IO &io, Tag& t) {
+ io.mapRequired("Name", t.Name);
+ io.mapOptional("Availability", t.Availability.Mode);
+ io.mapOptional("AvailabilityMsg", t.Availability.Msg);
+ io.mapOptional("SwiftPrivate", t.SwiftPrivate);
+ io.mapOptional("SwiftName", t.SwiftName);
+ io.mapOptional("SwiftBridge", t.SwiftBridge);
+ io.mapOptional("NSErrorDomain", t.NSErrorDomain);
+ }
+ };
+
+ template <>
+ struct MappingTraits<Typedef> {
+ static void mapping(IO &io, Typedef& t) {
+ io.mapRequired("Name", t.Name);
+ io.mapOptional("Availability", t.Availability.Mode);
+ io.mapOptional("AvailabilityMsg", t.Availability.Msg);
+ io.mapOptional("SwiftPrivate", t.SwiftPrivate);
+ io.mapOptional("SwiftName", t.SwiftName);
+ io.mapOptional("SwiftBridge", t.SwiftBridge);
+ io.mapOptional("NSErrorDomain", t.NSErrorDomain);
+ io.mapOptional("SwiftWrapper", t.SwiftWrapper);
+ }
+ };
+
+ static void mapTopLevelItems(IO &io, TopLevelItems &i) {
+ io.mapOptional("Classes", i.Classes);
+ io.mapOptional("Protocols", i.Protocols);
+ io.mapOptional("Functions", i.Functions);
+ io.mapOptional("Globals", i.Globals);
+ io.mapOptional("Enumerators", i.EnumConstants);
+ io.mapOptional("Tags", i.Tags);
+ io.mapOptional("Typedefs", i.Typedefs);
+ }
+
+ template <>
+ struct MappingTraits<Versioned> {
+ static void mapping(IO &io, Versioned& v) {
+ io.mapRequired("Version", v.Version);
+ mapTopLevelItems(io, v.Items);
+ }
+ };
+
+ template <>
+ struct MappingTraits<Module> {
+ static void mapping(IO &io, Module& m) {
+ io.mapRequired("Name", m.Name);
+ io.mapOptional("Availability", m.Availability.Mode);
+ io.mapOptional("AvailabilityMsg", m.Availability.Msg);
+ io.mapOptional("SwiftInferImportAsMember", m.SwiftInferImportAsMember);
+
+ mapTopLevelItems(io, m.TopLevel);
+
+ io.mapOptional("SwiftVersions", m.SwiftVersions);
+ }
+ };
+ }
+}
+
+using llvm::yaml::Input;
+using llvm::yaml::Output;
+
+void Module::dump() {
+ Output yout(llvm::errs());
+ yout << *this;
+}
+
+static bool parseAPINotes(StringRef yamlInput, Module &module,
+ llvm::SourceMgr::DiagHandlerTy diagHandler,
+ void *diagHandlerCtxt) {
+ Input yin(yamlInput, nullptr, diagHandler, diagHandlerCtxt);
+ yin >> module;
+
+ return static_cast<bool>(yin.error());
+}
+
+namespace {
+ using namespace api_notes;
+
+ class YAMLConverter {
+ const Module &TheModule;
+ const FileEntry *SourceFile;
+ APINotesWriter *Writer;
+ OSType TargetOS;
+ llvm::raw_ostream &OS;
+ llvm::SourceMgr::DiagHandlerTy DiagHandler;
+ void *DiagHandlerCtxt;
+ bool ErrorOccured;
+
+ /// Emit a diagnostic
+ bool emitError(llvm::Twine message) {
+ DiagHandler(llvm::SMDiagnostic("", llvm::SourceMgr::DK_Error,
+ message.str()),
+ DiagHandlerCtxt);
+ ErrorOccured = true;
+ return true;
+ }
+
+ public:
+ YAMLConverter(const Module &module,
+ const FileEntry *sourceFile,
+ OSType targetOS,
+ llvm::raw_ostream &os,
+ llvm::SourceMgr::DiagHandlerTy diagHandler,
+ void *diagHandlerCtxt) :
+ TheModule(module), SourceFile(sourceFile), Writer(0), TargetOS(targetOS), OS(os),
+ DiagHandler(diagHandler), DiagHandlerCtxt(diagHandlerCtxt),
+ ErrorOccured(false) {}
+
+ bool isAvailable(const AvailabilityItem &in) {
+ // Check if the API is available on the OS for which we are building.
+ if (in.Mode == APIAvailability::OSX && TargetOS != OSType::OSX)
+ return false;
+ if (in.Mode == APIAvailability::IOS && TargetOS != OSType::IOS)
+ return false;
+ return true;
+ }
+
+ bool convertAvailability(const AvailabilityItem &in,
+ CommonEntityInfo &outInfo,
+ llvm::StringRef apiName) {
+ // Populate the unavailability information.
+ outInfo.Unavailable = (in.Mode == APIAvailability::None);
+ outInfo.UnavailableInSwift = (in.Mode == APIAvailability::NonSwift);
+ if (outInfo.Unavailable || outInfo.UnavailableInSwift) {
+ outInfo.UnavailableMsg = in.Msg;
+ } else {
+ if (!in.Msg.empty()) {
+ emitError("availability message for available API '" +
+ apiName + "' will not be used");
+ }
+ }
+ return false;
+ }
+
+ void convertParams(const ParamsSeq ¶ms, FunctionInfo &outInfo) {
+ for (const auto &p : params) {
+ ParamInfo pi;
+ if (p.Nullability)
+ pi.setNullabilityAudited(*p.Nullability);
+ pi.setNoEscape(p.NoEscape);
+ pi.setType(p.Type);
+ while (outInfo.Params.size() <= p.Position) {
+ outInfo.Params.push_back(ParamInfo());
+ }
+ outInfo.Params[p.Position] |= pi;
+ }
+ }
+
+ void convertNullability(const NullabilitySeq &nullability,
+ Optional<NullabilityKind> nullabilityOfRet,
+ FunctionInfo &outInfo,
+ llvm::StringRef apiName) {
+ if (nullability.size() > FunctionInfo::getMaxNullabilityIndex()) {
+ emitError("nullability info for " + apiName + " does not fit");
+ return;
+ }
+
+ bool audited = false;
+ unsigned int idx = 1;
+ for (auto i = nullability.begin(),
+ e = nullability.end(); i != e; ++i, ++idx){
+ outInfo.addTypeInfo(idx, *i);
+ audited = true;
+ }
+ if (nullabilityOfRet) {
+ outInfo.addTypeInfo(0, *nullabilityOfRet);
+ audited = true;
+ } else if (audited) {
+ outInfo.addTypeInfo(0, *DefaultNullability);
+ }
+ if (audited) {
+ outInfo.NullabilityAudited = audited;
+ outInfo.NumAdjustedNullable = idx;
+ }
+ }
+
+ /// Convert the common parts of an entity from YAML.
+ template<typename T>
+ bool convertCommon(const T& common, CommonEntityInfo &info,
+ StringRef apiName) {
+ if (!isAvailable(common.Availability))
+ return true;
+
+ convertAvailability(common.Availability, info, apiName);
+ info.setSwiftPrivate(common.SwiftPrivate);
+ info.SwiftName = common.SwiftName;
+ return false;
+ }
+
+ /// Convert the common parts of a type entity from YAML.
+ template<typename T>
+ bool convertCommonType(const T& common, CommonTypeInfo &info,
+ StringRef apiName) {
+ if (convertCommon(common, info, apiName))
+ return true;
+
+ info.setSwiftBridge(common.SwiftBridge);
+ info.setNSErrorDomain(common.NSErrorDomain);
+ return false;
+ }
+
+ // Translate from Method into ObjCMethodInfo and write it out.
+ void convertMethod(const Method &meth,
+ ContextID classID, StringRef className,
+ VersionTuple swiftVersion) {
+ ObjCMethodInfo mInfo;
+
+ if (convertCommon(meth, mInfo, meth.Selector))
+ return;
+
+ // Check if the selector ends with ':' to determine if it takes arguments.
+ bool takesArguments = meth.Selector.endswith(":");
+
+ // Split the selector into pieces.
+ llvm::SmallVector<StringRef, 4> a;
+ meth.Selector.split(a, ":", /*MaxSplit*/ -1, /*KeepEmpty*/ false);
+ if (!takesArguments && a.size() > 1 ) {
+ emitError("selector " + meth.Selector + "is missing a ':' at the end");
+ return;
+ }
+
+ // Construct ObjCSelectorRef.
+ api_notes::ObjCSelectorRef selectorRef;
+ selectorRef.NumPieces = !takesArguments ? 0 : a.size();
+ selectorRef.Identifiers = a;
+
+ // Translate the initializer info.
+ mInfo.DesignatedInit = meth.DesignatedInit;
+ mInfo.Required = meth.Required;
+ if (meth.FactoryAsInit != FactoryAsInitKind::Infer)
+ mInfo.setFactoryAsInitKind(meth.FactoryAsInit);
+ mInfo.ResultType = meth.ResultType;
+
+ // Translate parameter information.
+ convertParams(meth.Params, mInfo);
+
+ // Translate nullability info.
+ convertNullability(meth.Nullability, meth.NullabilityOfRet,
+ mInfo, meth.Selector);
+
+ // Write it.
+ Writer->addObjCMethod(classID, selectorRef,
+ meth.Kind == MethodKind::Instance,
+ mInfo, swiftVersion);
+ }
+
+ void convertContext(const Class &cl, bool isClass,
+ VersionTuple swiftVersion) {
+ // Write the class.
+ ObjCContextInfo cInfo;
+
+ if (convertCommonType(cl, cInfo, cl.Name))
+ return;
+
+ if (cl.AuditedForNullability)
+ cInfo.setDefaultNullability(*DefaultNullability);
+
+ ContextID clID = Writer->addObjCContext(cl.Name, isClass, cInfo,
+ swiftVersion);
+
+ // Write all methods.
+ llvm::StringMap<std::pair<bool, bool>> knownMethods;
+ for (const auto &method : cl.Methods) {
+ // Check for duplicate method definitions.
+ bool isInstanceMethod = method.Kind == MethodKind::Instance;
+ bool &known = isInstanceMethod ? knownMethods[method.Selector].first
+ : knownMethods[method.Selector].second;
+ if (known) {
+ emitError(llvm::Twine("duplicate definition of method '") +
+ (isInstanceMethod? "-" : "+") + "[" + cl.Name + " " +
+ method.Selector + "]'");
+ continue;
+ }
+ known = true;
+
+ convertMethod(method, clID, cl.Name, swiftVersion);
+ }
+
+ // Write all properties.
+ llvm::StringSet<> knownInstanceProperties;
+ llvm::StringSet<> knownClassProperties;
+ for (const auto &prop : cl.Properties) {
+ // Check for duplicate property definitions.
+ if ((!prop.Kind || *prop.Kind == MethodKind::Instance) &&
+ !knownInstanceProperties.insert(prop.Name).second) {
+ emitError("duplicate definition of instance property '" + cl.Name +
+ "." + prop.Name + "'");
+ continue;
+ }
+
+ if ((!prop.Kind || *prop.Kind == MethodKind::Class) &&
+ !knownClassProperties.insert(prop.Name).second) {
+ emitError("duplicate definition of class property '" + cl.Name + "." +
+ prop.Name + "'");
+ continue;
+ }
+
+ // Translate from Property into ObjCPropertyInfo.
+ ObjCPropertyInfo pInfo;
+ if (!isAvailable(prop.Availability))
+ continue;
+ convertAvailability(prop.Availability, pInfo, prop.Name);
+ pInfo.setSwiftPrivate(prop.SwiftPrivate);
+ pInfo.SwiftName = prop.SwiftName;
+ if (prop.Nullability)
+ pInfo.setNullabilityAudited(*prop.Nullability);
+ if (prop.SwiftImportAsAccessors)
+ pInfo.setSwiftImportAsAccessors(*prop.SwiftImportAsAccessors);
+ pInfo.setType(prop.Type);
+ if (prop.Kind) {
+ Writer->addObjCProperty(clID, prop.Name,
+ *prop.Kind == MethodKind::Instance, pInfo,
+ swiftVersion);
+ } else {
+ // Add both instance and class properties with this name.
+ Writer->addObjCProperty(clID, prop.Name, true, pInfo, swiftVersion);
+ Writer->addObjCProperty(clID, prop.Name, false, pInfo, swiftVersion);
+ }
+ }
+ }
+
+ void convertTopLevelItems(const TopLevelItems &items,
+ VersionTuple swiftVersion) {
+ // Write all classes.
+ llvm::StringSet<> knownClasses;
+ for (const auto &cl : items.Classes) {
+ // Check for duplicate class definitions.
+ if (!knownClasses.insert(cl.Name).second) {
+ emitError("multiple definitions of class '" + cl.Name + "'");
+ continue;
+ }
+
+ convertContext(cl, /*isClass*/ true, swiftVersion);
+ }
+
+ // Write all protocols.
+ llvm::StringSet<> knownProtocols;
+ for (const auto &pr : items.Protocols) {
+ // Check for duplicate protocol definitions.
+ if (!knownProtocols.insert(pr.Name).second) {
+ emitError("multiple definitions of protocol '" + pr.Name + "'");
+ continue;
+ }
+
+ convertContext(pr, /*isClass*/ false, swiftVersion);
+ }
+
+ // Write all global variables.
+ llvm::StringSet<> knownGlobals;
+ for (const auto &global : items.Globals) {
+ // Check for duplicate global variables.
+ if (!knownGlobals.insert(global.Name).second) {
+ emitError("multiple definitions of global variable '" +
+ global.Name + "'");
+ continue;
+ }
+
+ GlobalVariableInfo info;
+ if (!isAvailable(global.Availability))
+ continue;
+ convertAvailability(global.Availability, info, global.Name);
+ info.setSwiftPrivate(global.SwiftPrivate);
+ info.SwiftName = global.SwiftName;
+ if (global.Nullability)
+ info.setNullabilityAudited(*global.Nullability);
+ info.setType(global.Type);
+ Writer->addGlobalVariable(global.Name, info, swiftVersion);
+ }
+
+ // Write all global functions.
+ llvm::StringSet<> knownFunctions;
+ for (const auto &function : items.Functions) {
+ // Check for duplicate global functions.
+ if (!knownFunctions.insert(function.Name).second) {
+ emitError("multiple definitions of global function '" +
+ function.Name + "'");
+ continue;
+ }
+
+ GlobalFunctionInfo info;
+ if (!isAvailable(function.Availability))
+ continue;
+ convertAvailability(function.Availability, info, function.Name);
+ info.setSwiftPrivate(function.SwiftPrivate);
+ info.SwiftName = function.SwiftName;
+ convertParams(function.Params, info);
+ convertNullability(function.Nullability,
+ function.NullabilityOfRet,
+ info, function.Name);
+ info.ResultType = function.ResultType;
+ Writer->addGlobalFunction(function.Name, info, swiftVersion);
+ }
+
+ // Write all enumerators.
+ llvm::StringSet<> knownEnumConstants;
+ for (const auto &enumConstant : items.EnumConstants) {
+ // Check for duplicate enumerators
+ if (!knownEnumConstants.insert(enumConstant.Name).second) {
+ emitError("multiple definitions of enumerator '" +
+ enumConstant.Name + "'");
+ continue;
+ }
+
+ EnumConstantInfo info;
+ if (!isAvailable(enumConstant.Availability))
+ continue;
+ convertAvailability(enumConstant.Availability, info, enumConstant.Name);
+ info.setSwiftPrivate(enumConstant.SwiftPrivate);
+ info.SwiftName = enumConstant.SwiftName;
+ Writer->addEnumConstant(enumConstant.Name, info, swiftVersion);
+ }
+
+ // Write all tags.
+ llvm::StringSet<> knownTags;
+ for (const auto &t : items.Tags) {
+ // Check for duplicate tag definitions.
+ if (!knownTags.insert(t.Name).second) {
+ emitError("multiple definitions Of tag '" + t.Name + "'");
+ continue;
+ }
+
+ TagInfo tagInfo;
+ if (convertCommonType(t, tagInfo, t.Name))
+ continue;
+
+ Writer->addTag(t.Name, tagInfo, swiftVersion);
+ }
+
+ // Write all typedefs.
+ llvm::StringSet<> knownTypedefs;
+ for (const auto &t : items.Typedefs) {
+ // Check for duplicate typedef definitions.
+ if (!knownTypedefs.insert(t.Name).second) {
+ emitError("multiple definitions of typedef '" + t.Name + "'");
+ continue;
+ }
+
+ TypedefInfo typedefInfo;
+ if (convertCommonType(t, typedefInfo, t.Name))
+ continue;
+ typedefInfo.SwiftWrapper = t.SwiftWrapper;
+
+ Writer->addTypedef(t.Name, typedefInfo, swiftVersion);
+ }
+ }
+
+ bool convertModule() {
+ if (!isAvailable(TheModule.Availability))
+ return false;
+
+ // Set up the writer.
+ // FIXME: This is kindof ugly.
+ APINotesWriter writer(TheModule.Name, SourceFile);
+ Writer = &writer;
+
+ // Write the top-level items.
+ convertTopLevelItems(TheModule.TopLevel, VersionTuple());
+
+ if (TheModule.SwiftInferImportAsMember) {
+ ModuleOptions opts;
+ opts.SwiftInferImportAsMember = true;
+ Writer->addModuleOptions(opts);
+ }
+
+ // Convert the versioned information.
+ for (const auto &versioned : TheModule.SwiftVersions) {
+ convertTopLevelItems(versioned.Items, versioned.Version);
+ }
+
+ if (!ErrorOccured)
+ Writer->writeToStream(OS);
+
+ return ErrorOccured;
+ }
+ };
+}
+
+static bool compile(const Module &module,
+ const FileEntry *sourceFile,
+ llvm::raw_ostream &os,
+ api_notes::OSType targetOS,
+ llvm::SourceMgr::DiagHandlerTy diagHandler,
+ void *diagHandlerCtxt){
+ using namespace api_notes;
+
+ YAMLConverter c(module, sourceFile, targetOS, os, diagHandler, diagHandlerCtxt);
+ return c.convertModule();
+}
+
+bool api_notes::parseAndDumpAPINotes(StringRef yamlInput) {
+ Module module;
+
+ if (parseAPINotes(yamlInput, module, nullptr, nullptr))
+ return true;
+
+ Output yout(llvm::outs());
+ yout << module;
+
+ return false;
+}
+
+/// Simple diagnostic handler that prints diagnostics to standard error.
+static void printDiagnostic(const llvm::SMDiagnostic &diag, void *context) {
+ diag.print(nullptr, llvm::errs());
+}
+
+bool api_notes::compileAPINotes(StringRef yamlInput,
+ const FileEntry *sourceFile,
+ llvm::raw_ostream &os,
+ OSType targetOS,
+ llvm::SourceMgr::DiagHandlerTy diagHandler,
+ void *diagHandlerCtxt) {
+ Module module;
+
+ if (!diagHandler) {
+ diagHandler = &printDiagnostic;
+ }
+
+ if (parseAPINotes(yamlInput, module, diagHandler, diagHandlerCtxt))
+ return true;
+
+ return compile(module, sourceFile, os, targetOS, diagHandler, diagHandlerCtxt);
+}
+
+namespace {
+ // Deserialize the API notes file into a module.
+ class DecompileVisitor : public APINotesReader::Visitor {
+ /// Allocator used to clone those strings that need it.
+ llvm::BumpPtrAllocator Allocator;
+
+ /// The module we're building.
+ Module TheModule;
+
+ /// A known context, which tracks what we know about a context ID.
+ struct KnownContext {
+ /// Whether this is a protocol (vs. a class).
+ bool isProtocol;
+
+ /// The indices into the top-level items for this context at each
+ /// Swift version.
+ SmallVector<std::pair<VersionTuple, unsigned>, 1> indices;
+
+ Class &getContext(const VersionTuple &swiftVersion,
+ TopLevelItems &items) {
+ ClassesSeq &seq = isProtocol ? items.Protocols : items.Classes;
+
+ for (auto &index : indices) {
+ if (index.first == swiftVersion)
+ return seq[index.second];
+ }
+
+ indices.push_back({swiftVersion, seq.size()});
+ seq.push_back(Class());
+ return seq.back();
+ }
+ };
+
+ /// A mapping from context ID to a pair (index, is-protocol) that indicates
+ /// the index of that class or protocol in the global "classes" or
+ /// "protocols" list.
+ llvm::DenseMap<unsigned, KnownContext> knownContexts;
+
+ /// Copy a string into allocated memory so it does disappear on us.
+ StringRef copyString(StringRef string) {
+ if (string.empty()) return StringRef();
+
+ void *ptr = Allocator.Allocate(string.size(), 1);
+ memcpy(ptr, string.data(), string.size());
+ return StringRef(reinterpret_cast<const char *>(ptr), string.size());
+ }
+
+ /// Copy an optional string into allocated memory so it does disappear on us.
+ Optional<StringRef> maybeCopyString(Optional<StringRef> string) {
+ if (!string) return None;
+
+ return copyString(*string);
+ }
+
+ /// Copy an optional string into allocated memory so it does disappear on us.
+ Optional<StringRef> maybeCopyString(Optional<std::string> string) {
+ if (!string) return None;
+
+ return copyString(*string);
+ }
+
+ template<typename T>
+ void handleCommon(T &record, const CommonEntityInfo &info) {
+ handleAvailability(record.Availability, info);
+ record.SwiftPrivate = info.isSwiftPrivate();
+ record.SwiftName = copyString(info.SwiftName);
+ }
+
+ template<typename T>
+ void handleCommonType(T &record, const CommonTypeInfo &info) {
+ handleCommon(record, info);
+ record.SwiftBridge = maybeCopyString(info.getSwiftBridge());
+ record.NSErrorDomain = maybeCopyString(info.getNSErrorDomain());
+ }
+
+ /// Map Objective-C context info.
+ void handleObjCContext(Class &record, StringRef name,
+ const ObjCContextInfo &info) {
+ record.Name = name;
+
+ handleCommonType(record, info);
+
+ if (info.getDefaultNullability()) {
+ record.AuditedForNullability = true;
+ }
+ }
+
+ /// Map availability information, if present.
+ void handleAvailability(AvailabilityItem &availability,
+ const CommonEntityInfo &info) {
+ if (info.Unavailable) {
+ availability.Mode = APIAvailability::None;
+ availability.Msg = copyString(info.UnavailableMsg);
+ }
+
+ if (info.UnavailableInSwift) {
+ availability.Mode = APIAvailability::NonSwift;
+ availability.Msg = copyString(info.UnavailableMsg);
+ }
+ }
+
+ /// Map parameter information for a function.
+ void handleParameters(ParamsSeq ¶ms,
+ const FunctionInfo &info) {
+ unsigned position = 0;
+ for (const auto &pi: info.Params) {
+ Param p;
+ p.Position = position++;
+ p.Nullability = pi.getNullability();
+ p.NoEscape = pi.isNoEscape();
+ p.Type = copyString(pi.getType());
+ params.push_back(p);
+ }
+ }
+
+ /// Map nullability information for a function.
+ void handleNullability(NullabilitySeq &nullability,
+ llvm::Optional<NullabilityKind> &nullabilityOfRet,
+ const FunctionInfo &info,
+ unsigned numParams) {
+ if (info.NullabilityAudited) {
+ nullabilityOfRet = info.getReturnTypeInfo();
+
+ // Figure out the number of parameters from the selector.
+ for (unsigned i = 0; i != numParams; ++i)
+ nullability.push_back(info.getParamTypeInfo(i));
+ }
+ }
+
+ TopLevelItems &getTopLevelItems(VersionTuple swiftVersion) {
+ if (!swiftVersion) return TheModule.TopLevel;
+
+ for (auto &versioned : TheModule.SwiftVersions) {
+ if (versioned.Version == swiftVersion)
+ return versioned.Items;
+ }
+
+ TheModule.SwiftVersions.push_back(Versioned());
+ TheModule.SwiftVersions.back().Version = swiftVersion;
+ return TheModule.SwiftVersions.back().Items;
+ }
+
+ public:
+ virtual void visitObjCClass(ContextID contextID, StringRef name,
+ const ObjCContextInfo &info,
+ VersionTuple swiftVersion) {
+ // Record this known context.
+ auto &items = getTopLevelItems(swiftVersion);
+ auto &known = knownContexts[contextID.Value];
+ known.isProtocol = false;
+
+ handleObjCContext(known.getContext(swiftVersion, items), name, info);
+ }
+
+ virtual void visitObjCProtocol(ContextID contextID, StringRef name,
+ const ObjCContextInfo &info,
+ VersionTuple swiftVersion) {
+ // Record this known context.
+ auto &items = getTopLevelItems(swiftVersion);
+ auto &known = knownContexts[contextID.Value];
+ known.isProtocol = true;
+
+ handleObjCContext(known.getContext(swiftVersion, items), name, info);
+ }
+
+ virtual void visitObjCMethod(ContextID contextID, StringRef selector,
+ bool isInstanceMethod,
+ const ObjCMethodInfo &info,
+ VersionTuple swiftVersion) {
+ Method method;
+ method.Selector = copyString(selector);
+ method.Kind = isInstanceMethod ? MethodKind::Instance : MethodKind::Class;
+
+ handleCommon(method, info);
+ handleParameters(method.Params, info);
+ handleNullability(method.Nullability, method.NullabilityOfRet, info,
+ selector.count(':'));
+ method.FactoryAsInit = info.getFactoryAsInitKind();
+ method.DesignatedInit = info.DesignatedInit;
+ method.Required = info.Required;
+ method.ResultType = copyString(info.ResultType);
+ auto &items = getTopLevelItems(swiftVersion);
+ knownContexts[contextID.Value].getContext(swiftVersion, items)
+ .Methods.push_back(method);
+ }
+
+ virtual void visitObjCProperty(ContextID contextID, StringRef name,
+ bool isInstance,
+ const ObjCPropertyInfo &info,
+ VersionTuple swiftVersion) {
+ Property property;
+ property.Name = name;
+ property.Kind = isInstance ? MethodKind::Instance : MethodKind::Class;
+ handleCommon(property, info);
+
+ // FIXME: No way to represent "not audited for nullability".
+ if (auto nullability = info.getNullability()) {
+ property.Nullability = *nullability;
+ }
+
+ property.SwiftImportAsAccessors = info.getSwiftImportAsAccessors();
+
+ property.Type = copyString(info.getType());
+
+ auto &items = getTopLevelItems(swiftVersion);
+ knownContexts[contextID.Value].getContext(swiftVersion, items)
+ .Properties.push_back(property);
+ }
+
+ virtual void visitGlobalFunction(StringRef name,
+ const GlobalFunctionInfo &info,
+ VersionTuple swiftVersion) {
+ Function function;
+ function.Name = name;
+ handleCommon(function, info);
+ handleParameters(function.Params, info);
+ if (info.NumAdjustedNullable > 0)
+ handleNullability(function.Nullability, function.NullabilityOfRet,
+ info, info.NumAdjustedNullable-1);
+ function.ResultType = copyString(info.ResultType);
+ auto &items = getTopLevelItems(swiftVersion);
+ items.Functions.push_back(function);
+ }
+
+ virtual void visitGlobalVariable(StringRef name,
+ const GlobalVariableInfo &info,
+ VersionTuple swiftVersion) {
+ GlobalVariable global;
+ global.Name = name;
+ handleCommon(global, info);
+
+ // FIXME: No way to represent "not audited for nullability".
+ if (auto nullability = info.getNullability()) {
+ global.Nullability = *nullability;
+ }
+ global.Type = copyString(info.getType());
+
+ auto &items = getTopLevelItems(swiftVersion);
+ items.Globals.push_back(global);
+ }
+
+ virtual void visitEnumConstant(StringRef name,
+ const EnumConstantInfo &info,
+ VersionTuple swiftVersion) {
+ EnumConstant enumConstant;
+ enumConstant.Name = name;
+ handleCommon(enumConstant, info);
+
+ auto &items = getTopLevelItems(swiftVersion);
+ items.EnumConstants.push_back(enumConstant);
+ }
+
+ virtual void visitTag(StringRef name, const TagInfo &info,
+ VersionTuple swiftVersion) {
+ Tag tag;
+ tag.Name = name;
+ handleCommonType(tag, info);
+ auto &items = getTopLevelItems(swiftVersion);
+ items.Tags.push_back(tag);
+ }
+
+ virtual void visitTypedef(StringRef name, const TypedefInfo &info,
+ VersionTuple swiftVersion) {
+ Typedef td;
+ td.Name = name;
+ handleCommonType(td, info);
+ td.SwiftWrapper = info.SwiftWrapper;
+ auto &items = getTopLevelItems(swiftVersion);
+ items.Typedefs.push_back(td);
+ }
+
+ /// Retrieve the module.
+ Module &getModule() { return TheModule; }
+ };
+}
+
+/// Produce a flattened, numeric value for optional method/property kinds.
+static unsigned flattenPropertyKind(llvm::Optional<MethodKind> kind) {
+ return kind ? (*kind == MethodKind::Instance ? 2 : 1) : 0;
+}
+
+/// Sort the items in the given block of "top-level" items.
+static void sortTopLevelItems(TopLevelItems &items) {
+ // Sort classes.
+ std::sort(items.Classes.begin(), items.Classes.end(),
+ [](const Class &lhs, const Class &rhs) -> bool {
+ return lhs.Name < rhs.Name;
+ });
+
+ // Sort protocols.
+ std::sort(items.Protocols.begin(), items.Protocols.end(),
+ [](const Class &lhs, const Class &rhs) -> bool {
+ return lhs.Name < rhs.Name;
+ });
+
+ // Sort methods and properties within each class and protocol.
+ auto sortMembers = [](Class &record) {
+ // Sort properties.
+ std::sort(record.Properties.begin(), record.Properties.end(),
+ [](const Property &lhs, const Property &rhs) -> bool {
+ return lhs.Name < rhs.Name ||
+ (lhs.Name == rhs.Name &&
+ flattenPropertyKind(lhs.Kind) <
+ flattenPropertyKind(rhs.Kind));
+ });
+
+ // Sort methods.
+ std::sort(record.Methods.begin(), record.Methods.end(),
+ [](const Method &lhs, const Method &rhs) -> bool {
+ return lhs.Selector < rhs.Selector ||
+ (lhs.Selector == rhs.Selector &&
+ static_cast<unsigned>(lhs.Kind)
+ < static_cast<unsigned>(rhs.Kind));
+ });
+ };
+ std::for_each(items.Classes.begin(), items.Classes.end(), sortMembers);
+ std::for_each(items.Protocols.begin(), items.Protocols.end(), sortMembers);
+
+ // Sort functions.
+ std::sort(items.Functions.begin(), items.Functions.end(),
+ [](const Function &lhs, const Function &rhs) -> bool {
+ return lhs.Name < rhs.Name;
+ });
+
+ // Sort global variables.
+ std::sort(items.Globals.begin(), items.Globals.end(),
+ [](const GlobalVariable &lhs, const GlobalVariable &rhs) -> bool {
+ return lhs.Name < rhs.Name;
+ });
+
+ // Sort enum constants.
+ std::sort(items.EnumConstants.begin(), items.EnumConstants.end(),
+ [](const EnumConstant &lhs, const EnumConstant &rhs) -> bool {
+ return lhs.Name < rhs.Name;
+ });
+
+ // Sort tags.
+ std::sort(items.Tags.begin(), items.Tags.end(),
+ [](const Tag &lhs, const Tag &rhs) -> bool {
+ return lhs.Name < rhs.Name;
+ });
+
+ // Sort typedefs.
+ std::sort(items.Typedefs.begin(), items.Typedefs.end(),
+ [](const Typedef &lhs, const Typedef &rhs) -> bool {
+ return lhs.Name < rhs.Name;
+ });
+}
+
+bool api_notes::decompileAPINotes(std::unique_ptr<llvm::MemoryBuffer> input,
+ llvm::raw_ostream &os) {
+ // Try to read the file.
+ auto reader = APINotesReader::get(std::move(input), VersionTuple());
+ if (!reader) {
+ llvm::errs() << "not a well-formed API notes binary file\n";
+ return true;
+ }
+
+ DecompileVisitor decompileVisitor;
+ reader->visit(decompileVisitor);
+
+ // Sort the data in the module, because the API notes reader doesn't preserve
+ // order.
+ auto &module = decompileVisitor.getModule();
+
+ // Set module name.
+ module.Name = reader->getModuleName();
+
+ // Set module options
+ auto opts = reader->getModuleOptions();
+ if (opts.SwiftInferImportAsMember)
+ module.SwiftInferImportAsMember = true;
+
+ // Sort the top-level items.
+ sortTopLevelItems(module.TopLevel);
+
+ // Sort the Swift versions.
+ std::sort(module.SwiftVersions.begin(), module.SwiftVersions.end(),
+ [](const Versioned &lhs, const Versioned &rhs) -> bool {
+ return lhs.Version < rhs.Version;
+ });
+
+ // Sort the top-level items within each Swift version.
+ for (auto &versioned : module.SwiftVersions)
+ sortTopLevelItems(versioned.Items);
+
+ // Output the YAML representation.
+ Output yout(os);
+ yout << module;
+
+ return false;
+}
+
diff --git a/lib/APINotes/CMakeLists.txt b/lib/APINotes/CMakeLists.txt
new file mode 100644
index 0000000..da9d0d1
--- /dev/null
+++ b/lib/APINotes/CMakeLists.txt
@@ -0,0 +1,15 @@
+set(LLVM_LINK_COMPONENTS
+ BitReader
+ Support
+ )
+
+add_clang_library(clangAPINotes
+ APINotesManager.cpp
+ APINotesWriter.cpp
+ APINotesReader.cpp
+ APINotesYAMLCompiler.cpp
+ Types.cpp
+
+ LINK_LIBS
+ clangBasic
+)
diff --git a/lib/APINotes/Types.cpp b/lib/APINotes/Types.cpp
new file mode 100644
index 0000000..963780f
--- /dev/null
+++ b/lib/APINotes/Types.cpp
@@ -0,0 +1,55 @@
+//===--- Types.cpp - API Notes Data Types ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines data types used in the representation of API notes data.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/APINotes/Types.h"
+#include "llvm/Support/raw_ostream.h"
+
+void clang::api_notes::ObjCMethodInfo::dump(llvm::raw_ostream &os) {
+ os << DesignatedInit << " " << FactoryAsInit << " " << Unavailable << " "
+ << NullabilityAudited << " " << NumAdjustedNullable << " "
+ << NullabilityPayload << " " << UnavailableMsg << "\n";
+}
+
+void clang::api_notes::ObjCContextInfo::dump(llvm::raw_ostream &os) {
+ os << HasDefaultNullability << " " << DefaultNullability << " "
+ << HasDesignatedInits << "\n";
+}
+
+void clang::api_notes::ObjCMethodInfo::mergePropInfoIntoSetter(
+ const ObjCPropertyInfo &pInfo) {
+ // Set the type of the first argument of the the setter or check that the
+ // value we have is consistent with the property.
+ // TODO: Can we provide proper error handling here?
+ if (auto pNullability = pInfo.getNullability()) {
+ if (!NullabilityAudited) {
+ addParamTypeInfo(0, *pNullability);
+ assert(NumAdjustedNullable == 2);
+ } else {
+ assert(getParamTypeInfo(0) == *pNullability);
+ }
+ }
+}
+
+void clang::api_notes::ObjCMethodInfo::mergePropInfoIntoGetter(
+ const ObjCPropertyInfo &pInfo) {
+ // Set the return type of the getter or check that the value we have is
+ // consistent with the property.
+ // TODO: Can we provide proper error handling here?
+ if (auto pNullability = pInfo.getNullability()) {
+ if (!NullabilityAudited) {
+ addReturnTypeInfo(*pNullability);
+ assert(NumAdjustedNullable == 1);
+ } else {
+ assert(getReturnTypeInfo() == *pNullability);
+ }
+ }
+}
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index b531a66..c8cdc72 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -4078,11 +4078,6 @@
bool allowOnPointerType) const {
hasError = false;
- if (const ObjCTypeParamType *objT =
- dyn_cast<ObjCTypeParamType>(type.getTypePtr())) {
- return getObjCTypeParamType(objT->getDecl(), protocols);
- }
-
// Apply protocol qualifiers to ObjCObjectPointerType.
if (allowOnPointerType) {
if (const ObjCObjectPointerType *objPtr =
@@ -8870,22 +8865,30 @@
return GVA_Internal;
if (VD->isStaticLocal()) {
- GVALinkage StaticLocalLinkage = GVA_DiscardableODR;
const DeclContext *LexicalContext = VD->getParentFunctionOrMethod();
while (LexicalContext && !isa<FunctionDecl>(LexicalContext))
LexicalContext = LexicalContext->getLexicalParent();
- // Let the static local variable inherit its linkage from the nearest
- // enclosing function.
- if (LexicalContext)
- StaticLocalLinkage =
- Context.GetGVALinkageForFunction(cast<FunctionDecl>(LexicalContext));
+ // ObjC Blocks can create local variables that don't have a FunctionDecl
+ // LexicalContext.
+ if (!LexicalContext)
+ return GVA_DiscardableODR;
- // GVA_StrongODR function linkage is stronger than what we need,
- // downgrade to GVA_DiscardableODR.
- // This allows us to discard the variable if we never end up needing it.
- return StaticLocalLinkage == GVA_StrongODR ? GVA_DiscardableODR
- : StaticLocalLinkage;
+ // Otherwise, let the static local variable inherit its linkage from the
+ // nearest enclosing function.
+ auto StaticLocalLinkage =
+ Context.GetGVALinkageForFunction(cast<FunctionDecl>(LexicalContext));
+
+ // Itanium ABI 5.2.2: "Each COMDAT group [for a static local variable] must
+ // be emitted in any object with references to the symbol for the object it
+ // contains, whether inline or out-of-line."
+ // Similar behavior is observed with MSVC. An alternative ABI could use
+ // StrongODR/AvailableExternally to match the function, but none are
+ // known/supported currently.
+ if (StaticLocalLinkage == GVA_StrongODR ||
+ StaticLocalLinkage == GVA_AvailableExternally)
+ return GVA_DiscardableODR;
+ return StaticLocalLinkage;
}
// MSVC treats in-class initialized static data members as definitions.
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 60d05f6..5d894c5 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -1329,12 +1329,8 @@
IdentifierInfo *name,
SourceLocation colonLoc,
TypeSourceInfo *boundInfo) {
- auto *TPDecl =
- new (ctx, dc) ObjCTypeParamDecl(ctx, dc, variance, varianceLoc, index,
- nameLoc, name, colonLoc, boundInfo);
- QualType TPType = ctx.getObjCTypeParamType(TPDecl, {});
- TPDecl->setTypeForDecl(TPType.getTypePtr());
- return TPDecl;
+ return new (ctx, dc) ObjCTypeParamDecl(ctx, dc, variance, varianceLoc, index,
+ nameLoc, name, colonLoc, boundInfo);
}
ObjCTypeParamDecl *ObjCTypeParamDecl::CreateDeserialized(ASTContext &ctx,
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index b8ebe1c..b8d90b0 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -1231,6 +1231,9 @@
return;
}
bool eolnOut = false;
+ prettyPrintAttributes(OID);
+ if (OID->hasAttrs()) Out << "\n";
+
Out << "@interface " << I;
if (auto TypeParams = OID->getTypeParamListAsWritten()) {
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 0d0cd2e..f3724aa 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -1081,24 +1081,13 @@
// Replace an Objective-C type parameter reference with the corresponding
// type argument.
- if (const auto *OTPTy = dyn_cast<ObjCTypeParamType>(splitType.Ty)) {
- if (auto *typeParam = dyn_cast<ObjCTypeParamDecl>(OTPTy->getDecl())) {
+ if (const auto *typedefTy = dyn_cast<TypedefType>(splitType.Ty)) {
+ if (auto *typeParam = dyn_cast<ObjCTypeParamDecl>(typedefTy->getDecl())) {
// If we have type arguments, use them.
if (!typeArgs.empty()) {
+ // FIXME: Introduce SubstObjCTypeParamType ?
QualType argType = typeArgs[typeParam->getIndex()];
- if (OTPTy->qual_empty())
- return ctx.getQualifiedType(argType, splitType.Quals);
-
- // Apply protocol lists if exists.
- bool hasError;
- SmallVector<ObjCProtocolDecl*, 8> protocolsVec;
- protocolsVec.append(OTPTy->qual_begin(),
- OTPTy->qual_end());
- ArrayRef<ObjCProtocolDecl *> protocolsToApply = protocolsVec;
- QualType resultTy = ctx.applyObjCProtocolQualifiers(argType,
- protocolsToApply, hasError, true/*allowOnPointerType*/);
-
- return ctx.getQualifiedType(resultTy, splitType.Quals);
+ return ctx.getQualifiedType(argType, splitType.Quals);
}
switch (context) {
diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt
index 8929ec3..42e0167 100644
--- a/lib/Basic/CMakeLists.txt
+++ b/lib/Basic/CMakeLists.txt
@@ -82,6 +82,7 @@
Sanitizers.cpp
SourceLocation.cpp
SourceManager.cpp
+ SourceMgrAdapter.cpp
TargetInfo.cpp
Targets.cpp
TokenKinds.cpp
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index 7529c47..0c27ae4 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -16,6 +16,7 @@
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/CrashRecoveryContext.h"
@@ -131,13 +132,13 @@
// Clear state related to #pragma diagnostic.
DiagStates.clear();
- DiagStatePoints.clear();
+ DiagStatesByLoc.clear();
DiagStateOnPushStack.clear();
// Create a DiagState and DiagStatePoint representing diagnostic changes
// through command-line.
DiagStates.emplace_back();
- DiagStatePoints.push_back(DiagStatePoint(&DiagStates.back(), FullSourceLoc()));
+ DiagStatesByLoc.appendFirst(&DiagStates.back());
}
void DiagnosticsEngine::SetDelayedDiagnostic(unsigned DiagID, StringRef Arg1,
@@ -157,27 +158,94 @@
DelayedDiagArg2.clear();
}
-DiagnosticsEngine::DiagStatePointsTy::iterator
-DiagnosticsEngine::GetDiagStatePointForLoc(SourceLocation L) const {
- assert(!DiagStatePoints.empty());
- assert(DiagStatePoints.front().Loc.isInvalid() &&
- "Should have created a DiagStatePoint for command-line");
+void DiagnosticsEngine::DiagStateMap::appendFirst(
+ DiagState *State) {
+ assert(Files.empty() && "not first");
+ FirstDiagState = CurDiagState = State;
+ CurDiagStateLoc = SourceLocation();
+}
- if (!SourceMgr)
- return DiagStatePoints.end() - 1;
+void DiagnosticsEngine::DiagStateMap::append(SourceManager &SrcMgr,
+ SourceLocation Loc,
+ DiagState *State) {
+ CurDiagState = State;
+ CurDiagStateLoc = Loc;
- FullSourceLoc Loc(L, *SourceMgr);
- if (Loc.isInvalid())
- return DiagStatePoints.end() - 1;
+ std::pair<FileID, unsigned> Decomp = SrcMgr.getDecomposedLoc(Loc);
+ unsigned Offset = Decomp.second;
+ for (File *F = getFile(SrcMgr, Decomp.first); F;
+ Offset = F->ParentOffset, F = F->Parent) {
+ F->HasLocalTransitions = true;
+ auto &Last = F->StateTransitions.back();
+ assert(Last.Offset <= Offset && "state transitions added out of order");
- DiagStatePointsTy::iterator Pos = DiagStatePoints.end();
- FullSourceLoc LastStateChangePos = DiagStatePoints.back().Loc;
- if (LastStateChangePos.isValid() &&
- Loc.isBeforeInTranslationUnitThan(LastStateChangePos))
- Pos = std::upper_bound(DiagStatePoints.begin(), DiagStatePoints.end(),
- DiagStatePoint(nullptr, Loc));
- --Pos;
- return Pos;
+ if (Last.Offset == Offset) {
+ if (Last.State == State)
+ break;
+ Last.State = State;
+ continue;
+ }
+
+ F->StateTransitions.push_back({State, Offset});
+ }
+}
+
+DiagnosticsEngine::DiagState *
+DiagnosticsEngine::DiagStateMap::lookup(SourceManager &SrcMgr,
+ SourceLocation Loc) const {
+ // Common case: we have not seen any diagnostic pragmas.
+ if (Files.empty())
+ return FirstDiagState;
+
+ std::pair<FileID, unsigned> Decomp = SrcMgr.getDecomposedLoc(Loc);
+ const File *F = getFile(SrcMgr, Decomp.first);
+ return F->lookup(Decomp.second);
+}
+
+DiagnosticsEngine::DiagState *
+DiagnosticsEngine::DiagStateMap::File::lookup(unsigned Offset) const {
+ auto OnePastIt = std::upper_bound(
+ StateTransitions.begin(), StateTransitions.end(), Offset,
+ [](unsigned Offset, const DiagStatePoint &P) {
+ return Offset < P.Offset;
+ });
+ assert(OnePastIt != StateTransitions.begin() && "missing initial state");
+ return OnePastIt[-1].State;
+}
+
+DiagnosticsEngine::DiagStateMap::File *
+DiagnosticsEngine::DiagStateMap::getFile(SourceManager &SrcMgr,
+ FileID ID) const {
+ // Get or insert the File for this ID.
+ auto Range = Files.equal_range(ID);
+ if (Range.first != Range.second)
+ return &Range.first->second;
+ auto &F = Files.insert(Range.first, std::make_pair(ID, File()))->second;
+
+ // We created a new File; look up the diagnostic state at the start of it and
+ // initialize it.
+ if (ID.isValid()) {
+ std::pair<FileID, unsigned> Decomp = SrcMgr.getDecomposedIncludedLoc(ID);
+ F.Parent = getFile(SrcMgr, Decomp.first);
+ F.ParentOffset = Decomp.second;
+ F.StateTransitions.push_back({F.Parent->lookup(Decomp.second), 0});
+ } else {
+ // This is the (imaginary) root file into which we pretend all top-level
+ // files are included; it descends from the initial state.
+ //
+ // FIXME: This doesn't guarantee that we use the same ordering as
+ // isBeforeInTranslationUnit in the cases where someone invented another
+ // top-level file and added diagnostic pragmas to it. See the code at the
+ // end of isBeforeInTranslationUnit for the quirks it deals with.
+ F.StateTransitions.push_back({FirstDiagState, 0});
+ }
+ return &F;
+}
+
+void DiagnosticsEngine::PushDiagStatePoint(DiagState *State,
+ SourceLocation Loc) {
+ assert(Loc.isValid() && "Adding invalid loc point");
+ DiagStatesByLoc.append(*SourceMgr, Loc, State);
}
void DiagnosticsEngine::setSeverity(diag::kind Diag, diag::Severity Map,
@@ -187,11 +255,8 @@
assert((Diags->isBuiltinWarningOrExtension(Diag) ||
(Map == diag::Severity::Fatal || Map == diag::Severity::Error)) &&
"Cannot map errors into warnings!");
- assert(!DiagStatePoints.empty());
assert((L.isInvalid() || SourceMgr) && "No SourceMgr for valid location");
- FullSourceLoc Loc = SourceMgr? FullSourceLoc(L, *SourceMgr) : FullSourceLoc();
- FullSourceLoc LastStateChangePos = DiagStatePoints.back().Loc;
// Don't allow a mapping to a warning override an error/fatal mapping.
if (Map == diag::Severity::Warning) {
DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag);
@@ -202,50 +267,22 @@
DiagnosticMapping Mapping = makeUserMapping(Map, L);
// Common case; setting all the diagnostics of a group in one place.
- if (Loc.isInvalid() || Loc == LastStateChangePos) {
- GetCurDiagState()->setMapping(Diag, Mapping);
+ if ((L.isInvalid() || L == DiagStatesByLoc.getCurDiagStateLoc()) &&
+ DiagStatesByLoc.getCurDiagState()) {
+ // FIXME: This is theoretically wrong: if the current state is shared with
+ // some other location (via push/pop) we will change the state for that
+ // other location as well. This cannot currently happen, as we can't update
+ // the diagnostic state at the same location at which we pop.
+ DiagStatesByLoc.getCurDiagState()->setMapping(Diag, Mapping);
return;
}
- // Another common case; modifying diagnostic state in a source location
- // after the previous one.
- if ((Loc.isValid() && LastStateChangePos.isInvalid()) ||
- LastStateChangePos.isBeforeInTranslationUnitThan(Loc)) {
- // A diagnostic pragma occurred, create a new DiagState initialized with
- // the current one and a new DiagStatePoint to record at which location
- // the new state became active.
- DiagStates.push_back(*GetCurDiagState());
- PushDiagStatePoint(&DiagStates.back(), Loc);
- GetCurDiagState()->setMapping(Diag, Mapping);
- return;
- }
-
- // We allow setting the diagnostic state in random source order for
- // completeness but it should not be actually happening in normal practice.
-
- DiagStatePointsTy::iterator Pos = GetDiagStatePointForLoc(Loc);
- assert(Pos != DiagStatePoints.end());
-
- // Update all diagnostic states that are active after the given location.
- for (DiagStatePointsTy::iterator
- I = Pos+1, E = DiagStatePoints.end(); I != E; ++I) {
- I->State->setMapping(Diag, Mapping);
- }
-
- // If the location corresponds to an existing point, just update its state.
- if (Pos->Loc == Loc) {
- Pos->State->setMapping(Diag, Mapping);
- return;
- }
-
- // Create a new state/point and fit it into the vector of DiagStatePoints
- // so that the vector is always ordered according to location.
- assert(Pos->Loc.isBeforeInTranslationUnitThan(Loc));
- DiagStates.push_back(*Pos->State);
- DiagState *NewState = &DiagStates.back();
- NewState->setMapping(Diag, Mapping);
- DiagStatePoints.insert(Pos+1, DiagStatePoint(NewState,
- FullSourceLoc(Loc, *SourceMgr)));
+ // A diagnostic pragma occurred, create a new DiagState initialized with
+ // the current one and a new DiagStatePoint to record at which location
+ // the new state became active.
+ DiagStates.push_back(*GetCurDiagState());
+ DiagStates.back().setMapping(Diag, Mapping);
+ PushDiagStatePoint(&DiagStates.back(), L);
}
bool DiagnosticsEngine::setSeverityForGroup(diag::Flavor Flavor,
diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp
index 3c370f6..e0580af 100644
--- a/lib/Basic/DiagnosticIDs.cpp
+++ b/lib/Basic/DiagnosticIDs.cpp
@@ -411,11 +411,8 @@
// to error. Errors can only be mapped to fatal.
diag::Severity Result = diag::Severity::Fatal;
- DiagnosticsEngine::DiagStatePointsTy::iterator
- Pos = Diag.GetDiagStatePointForLoc(Loc);
- DiagnosticsEngine::DiagState *State = Pos->State;
-
// Get the mapping information, or compute it lazily.
+ DiagnosticsEngine::DiagState *State = Diag.GetDiagStateForLoc(Loc);
DiagnosticMapping &Mapping = State->getOrAddMapping((diag::kind)DiagID);
// TODO: Can a null severity really get here?
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index af424cd..851b3ab 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -42,7 +42,6 @@
NeedsHandleIdentifier = false;
IsFromAST = false;
ChangedAfterLoad = false;
- FEChangedAfterLoad = false;
RevertedTokenID = false;
OutOfDate = false;
IsModulesImport = false;
diff --git a/lib/Basic/Module.cpp b/lib/Basic/Module.cpp
index 80bbc24..88e5cc2 100644
--- a/lib/Basic/Module.cpp
+++ b/lib/Basic/Module.cpp
@@ -31,7 +31,8 @@
IsMissingRequirement(false), HasIncompatibleModuleFile(false),
IsAvailable(true), IsFromModuleFile(false), IsFramework(IsFramework),
IsExplicit(IsExplicit), IsSystem(false), IsExternC(false),
- IsInferred(false), InferSubmodules(false), InferExplicitSubmodules(false),
+ IsInferred(false), IsSwiftInferImportAsMember(false),
+ InferSubmodules(false), InferExplicitSubmodules(false),
InferExportWildcard(false), ConfigMacrosExhaustive(false),
NoUndeclaredIncludes(false), NameVisibility(Hidden) {
if (Parent) {
@@ -83,11 +84,16 @@
bool Module::isAvailable(const LangOptions &LangOpts, const TargetInfo &Target,
Requirement &Req,
- UnresolvedHeaderDirective &MissingHeader) const {
+ UnresolvedHeaderDirective &MissingHeader,
+ Module *&ShadowingModule) const {
if (IsAvailable)
return true;
for (const Module *Current = this; Current; Current = Current->Parent) {
+ if (Current->ShadowingModule) {
+ ShadowingModule = Current->ShadowingModule;
+ return false;
+ }
for (unsigned I = 0, N = Current->Requirements.size(); I != N; ++I) {
if (hasFeature(Current->Requirements[I].first, LangOpts, Target) !=
Current->Requirements[I].second) {
@@ -341,6 +347,8 @@
OS << " [system]";
if (IsExternC)
OS << " [extern_c]";
+ if (IsSwiftInferImportAsMember)
+ OS << " [swift_infer_import_as_member]";
}
OS << " {\n";
diff --git a/lib/Basic/SourceMgrAdapter.cpp b/lib/Basic/SourceMgrAdapter.cpp
new file mode 100644
index 0000000..1d52a24
--- /dev/null
+++ b/lib/Basic/SourceMgrAdapter.cpp
@@ -0,0 +1,137 @@
+//=== SourceMgrAdapter.cpp - SourceMgr to SourceManager Adapter -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the adapter that maps diagnostics from llvm::SourceMgr
+// to Clang's SourceManager.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/SourceMgrAdapter.h"
+#include "clang/Basic/Diagnostic.h"
+
+using namespace clang;
+
+void SourceMgrAdapter::handleDiag(const llvm::SMDiagnostic &diag,
+ void *context) {
+ static_cast<SourceMgrAdapter *>(context)->handleDiag(diag);
+}
+
+SourceMgrAdapter::SourceMgrAdapter(SourceManager &srcMgr,
+ DiagnosticsEngine &diag,
+ unsigned errorDiagID,
+ unsigned warningDiagID,
+ unsigned noteDiagID,
+ const FileEntry *defaultFile)
+ : SrcMgr(srcMgr), Diag(diag), ErrorDiagID(errorDiagID),
+ WarningDiagID(warningDiagID), NoteDiagID(noteDiagID),
+ DefaultFile(defaultFile) { }
+
+SourceMgrAdapter::~SourceMgrAdapter() { }
+
+SourceLocation SourceMgrAdapter::mapLocation(const llvm::SourceMgr &llvmSrcMgr,
+ llvm::SMLoc loc) {
+ // Map invalid locations.
+ if (!loc.isValid())
+ return SourceLocation();
+
+ // Find the buffer containing the location.
+ unsigned bufferID = llvmSrcMgr.FindBufferContainingLoc(loc);
+ if (!bufferID)
+ return SourceLocation();
+
+
+ // If we haven't seen this buffer before, copy it over.
+ auto buffer = llvmSrcMgr.getMemoryBuffer(bufferID);
+ auto knownBuffer = FileIDMapping.find(std::make_pair(&llvmSrcMgr, bufferID));
+ if (knownBuffer == FileIDMapping.end()) {
+ FileID fileID;
+ if (DefaultFile) {
+ // Map to the default file.
+ fileID = SrcMgr.createFileID(DefaultFile, SourceLocation(),
+ SrcMgr::C_User);
+
+ // Only do this once.
+ DefaultFile = nullptr;
+ } else {
+ // Make a copy of the memory buffer.
+ StringRef bufferName = buffer->getBufferIdentifier();
+ auto bufferCopy
+ = std::unique_ptr<llvm::MemoryBuffer>(
+ llvm::MemoryBuffer::getMemBufferCopy(buffer->getBuffer(),
+ bufferName));
+
+ // Add this memory buffer to the Clang source manager.
+ fileID = SrcMgr.createFileID(std::move(bufferCopy));
+ }
+
+ // Save the mapping.
+ knownBuffer = FileIDMapping.insert(
+ std::make_pair(std::make_pair(&llvmSrcMgr, bufferID),
+ fileID)).first;
+ }
+
+ // Translate the offset into the file.
+ unsigned offset = loc.getPointer() - buffer->getBufferStart();
+ return SrcMgr.getLocForStartOfFile(knownBuffer->second)
+ .getLocWithOffset(offset);
+}
+
+SourceRange SourceMgrAdapter::mapRange(const llvm::SourceMgr &llvmSrcMgr,
+ llvm::SMRange range) {
+ if (!range.isValid())
+ return SourceRange();
+
+ SourceLocation start = mapLocation(llvmSrcMgr, range.Start);
+ SourceLocation end = mapLocation(llvmSrcMgr, range.End);
+ return SourceRange(start, end);
+}
+
+void SourceMgrAdapter::handleDiag(const llvm::SMDiagnostic &diag) {
+ // Map the location.
+ SourceLocation loc;
+ if (auto *llvmSrcMgr = diag.getSourceMgr())
+ loc = mapLocation(*llvmSrcMgr, diag.getLoc());
+
+ // Extract the message.
+ StringRef message = diag.getMessage();
+
+ // Map the diagnostic kind.
+ unsigned diagID;
+ switch (diag.getKind()) {
+ case llvm::SourceMgr::DK_Error:
+ diagID = ErrorDiagID;
+ break;
+
+ case llvm::SourceMgr::DK_Warning:
+ diagID = WarningDiagID;
+ break;
+
+ case llvm::SourceMgr::DK_Note:
+ diagID = NoteDiagID;
+ break;
+ }
+
+ // Report the diagnostic.
+ DiagnosticBuilder builder = Diag.Report(loc, diagID) << message;
+
+ if (auto *llvmSrcMgr = diag.getSourceMgr()) {
+ // Translate ranges.
+ SourceLocation startOfLine = loc.getLocWithOffset(-diag.getColumnNo());
+ for (auto range : diag.getRanges()) {
+ builder << SourceRange(startOfLine.getLocWithOffset(range.first),
+ startOfLine.getLocWithOffset(range.second));
+ }
+
+ // Translate Fix-Its.
+ for (const llvm::SMFixIt &fixIt : diag.getFixIts()) {
+ CharSourceRange range(mapRange(*llvmSrcMgr, fixIt.getRange()), false);
+ builder << FixItHint::CreateReplacement(range, fixIt.getText());
+ }
+ }
+}
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 1a95ff2..fdedd91 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -8976,11 +8976,19 @@
return new SPIR64TargetInfo(Triple, Opts);
}
case llvm::Triple::wasm32:
- if (!(Triple == llvm::Triple("wasm32-unknown-unknown")))
+ if (Triple.getSubArch() != llvm::Triple::NoSubArch ||
+ Triple.getVendor() != llvm::Triple::UnknownVendor ||
+ Triple.getOS() != llvm::Triple::UnknownOS ||
+ Triple.getEnvironment() != llvm::Triple::UnknownEnvironment ||
+ !(Triple.isOSBinFormatELF() || Triple.isOSBinFormatWasm()))
return nullptr;
return new WebAssemblyOSTargetInfo<WebAssembly32TargetInfo>(Triple, Opts);
case llvm::Triple::wasm64:
- if (!(Triple == llvm::Triple("wasm64-unknown-unknown")))
+ if (Triple.getSubArch() != llvm::Triple::NoSubArch ||
+ Triple.getVendor() != llvm::Triple::UnknownVendor ||
+ Triple.getOS() != llvm::Triple::UnknownOS ||
+ Triple.getEnvironment() != llvm::Triple::UnknownEnvironment ||
+ !(Triple.isOSBinFormatELF() || Triple.isOSBinFormatWasm()))
return nullptr;
return new WebAssemblyOSTargetInfo<WebAssembly64TargetInfo>(Triple, Opts);
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index dfd819a..574c511 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -1,5 +1,6 @@
add_subdirectory(Headers)
add_subdirectory(Basic)
+add_subdirectory(APINotes)
add_subdirectory(Lex)
add_subdirectory(Parse)
add_subdirectory(AST)
diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp
index d2ce6ea..328ac5b 100644
--- a/lib/CodeGen/BackendUtil.cpp
+++ b/lib/CodeGen/BackendUtil.cpp
@@ -996,6 +996,7 @@
return "__LLVM,__bitcode";
case Triple::COFF:
case Triple::ELF:
+ case Triple::Wasm:
case Triple::UnknownObjectFormat:
return ".llvmbc";
}
@@ -1008,6 +1009,7 @@
return "__LLVM,__cmdline";
case Triple::COFF:
case Triple::ELF:
+ case Triple::Wasm:
case Triple::UnknownObjectFormat:
return ".llvmcmd";
}
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 0a88b23..b7c1743 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -1022,11 +1022,21 @@
// Emit a lifetime intrinsic if meaningful. There's no point in doing this
// if we don't have a valid insertion point (?).
if (HaveInsertPoint() && !IsMSCatchParam) {
- // goto or switch-case statements can break lifetime into several
- // regions which need more efforts to handle them correctly. PR28267
- // This is rare case, but it's better just omit intrinsics than have
- // them incorrectly placed.
- if (!Bypasses.IsBypassed(&D)) {
+ // If there's a jump into the lifetime of this variable, its lifetime
+ // gets broken up into several regions in IR, which requires more work
+ // to handle correctly. For now, just omit the intrinsics; this is a
+ // rare case, and it's better to just be conservatively correct.
+ // PR28267.
+ //
+ // We have to do this in all language modes if there's a jump past the
+ // declaration. We also have to do it in C if there's a jump to an
+ // earlier point in the current block because non-VLA lifetimes begin as
+ // soon as the containing block is entered, not when its variables
+ // actually come into scope; suppressing the lifetime annotations
+ // completely in this case is unnecessarily pessimistic, but again, this
+ // is rare.
+ if (!Bypasses.IsBypassed(&D) &&
+ !(!getLangOpts().CPlusPlus && hasLabelBeenSeenInCurrentScope())) {
uint64_t size = CGM.getDataLayout().getTypeAllocSize(allocaTy);
emission.SizeForLifetimeMarkers =
EmitLifetimeStart(size, address.getPointer());
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index e5e34a5..d2cd9ed 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -3335,7 +3335,9 @@
AlignmentSource AlignSource;
Address Addr = EmitPointerWithAlignment(BaseExpr, &AlignSource);
QualType PtrTy = BaseExpr->getType()->getPointeeType();
- EmitTypeCheck(TCK_MemberAccess, E->getExprLoc(), Addr.getPointer(), PtrTy);
+ bool SkipNullCheck = isa<llvm::ConstantPointerNull>(Addr.getPointer());
+ EmitTypeCheck(TCK_MemberAccess, E->getExprLoc(), Addr.getPointer(), PtrTy,
+ /*Alignment=*/CharUnits::Zero(), SkipNullCheck);
BaseLV = MakeAddrLValue(Addr, PtrTy, AlignSource);
} else
BaseLV = EmitCheckedLValue(BaseExpr, TCK_MemberAccess);
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 1b85c45..12b14be 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -2751,8 +2751,8 @@
isa<llvm::IntegerType>(Ops.LHS->getType())) {
CodeGenFunction::SanitizerScope SanScope(&CGF);
SmallVector<std::pair<Value *, SanitizerMask>, 2> Checks;
- llvm::Value *WidthMinusOne = GetWidthMinusOneValue(Ops.LHS, RHS);
- llvm::Value *ValidExponent = Builder.CreateICmpULE(RHS, WidthMinusOne);
+ llvm::Value *WidthMinusOne = GetWidthMinusOneValue(Ops.LHS, Ops.RHS);
+ llvm::Value *ValidExponent = Builder.CreateICmpULE(Ops.RHS, WidthMinusOne);
if (SanitizeExponent) {
Checks.push_back(
@@ -2767,12 +2767,14 @@
llvm::BasicBlock *Cont = CGF.createBasicBlock("cont");
llvm::BasicBlock *CheckShiftBase = CGF.createBasicBlock("check");
Builder.CreateCondBr(ValidExponent, CheckShiftBase, Cont);
+ llvm::Value *PromotedWidthMinusOne =
+ (RHS == Ops.RHS) ? WidthMinusOne
+ : GetWidthMinusOneValue(Ops.LHS, RHS);
CGF.EmitBlock(CheckShiftBase);
- llvm::Value *BitsShiftedOff =
- Builder.CreateLShr(Ops.LHS,
- Builder.CreateSub(WidthMinusOne, RHS, "shl.zeros",
- /*NUW*/true, /*NSW*/true),
- "shl.check");
+ llvm::Value *BitsShiftedOff = Builder.CreateLShr(
+ Ops.LHS, Builder.CreateSub(PromotedWidthMinusOne, RHS, "shl.zeros",
+ /*NUW*/ true, /*NSW*/ true),
+ "shl.check");
if (CGF.getLangOpts().CPlusPlus) {
// In C99, we are not permitted to shift a 1 bit into the sign bit.
// Under C++11's rules, shifting a 1 bit into the sign bit is
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 7219592..01793e2 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -7147,7 +7147,12 @@
}
assert(GV->getLinkage() == L);
- return GV;
+
+ if (IsForDefinition ||
+ GV->getValueType() == ObjCTypes.ClassnfABITy)
+ return GV;
+
+ return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.ClassnfABIPtrTy);
}
llvm::Value *
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 5861340..11a2b95 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -212,6 +212,13 @@
/// value. This is invalid iff the function has no return value.
Address ReturnValue;
+ /// Return true if a label was seen in the current scope.
+ bool hasLabelBeenSeenInCurrentScope() const {
+ if (CurLexicalScope)
+ return CurLexicalScope->hasLabels();
+ return !LabelMap.empty();
+ }
+
/// AllocaInsertPoint - This is an instruction in the entry block before which
/// we prefer to insert allocas.
llvm::AssertingVH<llvm::Instruction> AllocaInsertPt;
@@ -620,6 +627,10 @@
rescopeLabels();
}
+ bool hasLabels() const {
+ return !Labels.empty();
+ }
+
void rescopeLabels();
};
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 3600543..a6b2559 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -3341,6 +3341,7 @@
llvm_unreachable("unknown file format");
case llvm::Triple::COFF:
case llvm::Triple::ELF:
+ case llvm::Triple::Wasm:
GV->setSection("cfstring");
break;
case llvm::Triple::MachO:
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index f7a8dd6..490fadb 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -2015,10 +2015,11 @@
// The ABI says: "It is suggested that it be emitted in the same COMDAT
// group as the associated data object." In practice, this doesn't work for
- // non-ELF object formats, so only do it for ELF.
+ // non-ELF and non-Wasm object formats, so only do it for ELF and Wasm.
llvm::Comdat *C = var->getComdat();
if (!D.isLocalVarDecl() && C &&
- CGM.getTarget().getTriple().isOSBinFormatELF()) {
+ (CGM.getTarget().getTriple().isOSBinFormatELF() ||
+ CGM.getTarget().getTriple().isOSBinFormatWasm())) {
guard->setComdat(C);
// An inline variable's guard function is run from the per-TU
// initialization function, not via a dedicated global ctor function, so
@@ -3534,8 +3535,9 @@
return StructorCodegen::RAUW;
if (llvm::GlobalValue::isWeakForLinker(Linkage)) {
- // Only ELF supports COMDATs with arbitrary names (C5/D5).
- if (CGM.getTarget().getTriple().isOSBinFormatELF())
+ // Only ELF and wasm support COMDATs with arbitrary names (C5/D5).
+ if (CGM.getTarget().getTriple().isOSBinFormatELF() ||
+ CGM.getTarget().getTriple().isOSBinFormatWasm())
return StructorCodegen::COMDAT;
return StructorCodegen::Emit;
}
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 15f830d..d8f5bfc 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -3186,7 +3186,8 @@
const JobAction *JA = cast<JobAction>(A);
ActionList CollapsedOffloadActions;
- ToolSelector TS(JA, *TC, C, isSaveTempsEnabled(), embedBitcodeInObject());
+ ToolSelector TS(JA, *TC, C, isSaveTempsEnabled(),
+ embedBitcodeInObject() && !isUsingLTO());
const Tool *T = TS.getTool(Inputs, CollapsedOffloadActions);
if (!T)
diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp
index 9fd8808..595d6e6 100644
--- a/lib/Driver/Job.cpp
+++ b/lib/Driver/Job.cpp
@@ -88,6 +88,8 @@
return HaveCrashVFS ? false : true;
if (FlagRef.startswith("-fmodules-cache-path="))
return true;
+ if (FlagRef.startswith("-fapinotes-cache-path="))
+ return true;
SkipNum = 0;
return false;
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index 9bc9ae4..7e52514 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -1109,10 +1109,6 @@
options::OPT_fno_omit_frame_pointer, false))
getDriver().Diag(clang::diag::warn_drv_unsupported_opt_for_target)
<< "-fomit-frame-pointer" << BoundArch;
- if (Args.hasFlag(options::OPT_momit_leaf_frame_pointer,
- options::OPT_mno_omit_leaf_frame_pointer, false))
- getDriver().Diag(clang::diag::warn_drv_unsupported_opt_for_target)
- << "-momit-leaf-frame-pointer" << BoundArch;
}
return DAL;
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index b4a8334..30d48b7 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -1363,9 +1363,9 @@
options::OPT_mno_global_merge)) {
CmdArgs.push_back("-backend-option");
if (A->getOption().matches(options::OPT_mno_global_merge))
- CmdArgs.push_back("-aarch64-global-merge=false");
+ CmdArgs.push_back("-aarch64-enable-global-merge=false");
else
- CmdArgs.push_back("-aarch64-global-merge=true");
+ CmdArgs.push_back("-aarch64-enable-global-merge=true");
}
}
@@ -3409,7 +3409,7 @@
return false;
}
-static bool mustUseFramePointerForTarget(const llvm::Triple &Triple) {
+static bool mustUseNonLeafFramePointerForTarget(const llvm::Triple &Triple) {
switch (Triple.getArch()){
default:
return false;
@@ -3475,7 +3475,7 @@
if (Arg *A = Args.getLastArg(options::OPT_fno_omit_frame_pointer,
options::OPT_fomit_frame_pointer))
return A->getOption().matches(options::OPT_fno_omit_frame_pointer) ||
- mustUseFramePointerForTarget(Triple);
+ mustUseNonLeafFramePointerForTarget(Triple);
if (Args.hasArg(options::OPT_pg))
return true;
@@ -3487,8 +3487,7 @@
const llvm::Triple &Triple) {
if (Arg *A = Args.getLastArg(options::OPT_mno_omit_leaf_frame_pointer,
options::OPT_momit_leaf_frame_pointer))
- return A->getOption().matches(options::OPT_mno_omit_leaf_frame_pointer) ||
- mustUseFramePointerForTarget(Triple);
+ return A->getOption().matches(options::OPT_mno_omit_leaf_frame_pointer);
if (Args.hasArg(options::OPT_pg))
return true;
@@ -4250,14 +4249,14 @@
}
// Embed-bitcode option.
- if (C.getDriver().embedBitcodeInObject() &&
+ if (C.getDriver().embedBitcodeInObject() && !C.getDriver().isUsingLTO() &&
(isa<BackendJobAction>(JA) || isa<AssembleJobAction>(JA))) {
// Add flags implied by -fembed-bitcode.
Args.AddLastArg(CmdArgs, options::OPT_fembed_bitcode_EQ);
// Disable all llvm IR level optimizations.
CmdArgs.push_back("-disable-llvm-passes");
}
- if (C.getDriver().embedBitcodeMarkerOnly())
+ if (C.getDriver().embedBitcodeMarkerOnly() && !C.getDriver().isUsingLTO())
CmdArgs.push_back("-fembed-bitcode=marker");
// We normally speed up the clang process a bit by skipping destructors at
@@ -5638,6 +5637,42 @@
options::OPT_fno_assume_sane_operator_new))
CmdArgs.push_back("-fno-assume-sane-operator-new");
+ if (Args.hasFlag(options::OPT_fapinotes, options::OPT_fno_apinotes,
+ false) ||
+ Args.hasFlag(options::OPT_fapinotes_modules,
+ options::OPT_fno_apinotes_modules, false) ||
+ Args.hasArg(options::OPT_iapinotes_modules)) {
+ if (Args.hasFlag(options::OPT_fapinotes, options::OPT_fno_apinotes, false))
+ CmdArgs.push_back("-fapinotes");
+ if (Args.hasFlag(options::OPT_fapinotes_modules,
+ options::OPT_fno_apinotes_modules, false))
+ CmdArgs.push_back("-fapinotes-modules");
+
+ SmallString<128> APINotesCachePath;
+ if (Arg *A = Args.getLastArg(options::OPT_fapinotes_cache_path)) {
+ APINotesCachePath = A->getValue();
+ }
+
+ if (C.isForDiagnostics()) {
+ // When generating crash reports, we want to emit the API notes along with
+ // the reproduction sources, so we ignore any provided API notes path.
+ APINotesCachePath = Output.getFilename();
+ llvm::sys::path::replace_extension(APINotesCachePath, ".cache");
+ llvm::sys::path::append(APINotesCachePath, "apinotes");
+ } else if (APINotesCachePath.empty()) {
+ // No API notes path was provided: use the default.
+ llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false,
+ APINotesCachePath);
+ llvm::sys::path::append(APINotesCachePath, "org.llvm.clang");
+ llvm::sys::path::append(APINotesCachePath, "APINotesCache");
+ }
+ const char Arg[] = "-fapinotes-cache-path=";
+ APINotesCachePath.insert(APINotesCachePath.begin(), Arg, Arg + strlen(Arg));
+ CmdArgs.push_back(Args.MakeArgString(APINotesCachePath));
+
+ Args.AddLastArg(CmdArgs, options::OPT_fapinotes_swift_version);
+ }
+
// -fblocks=0 is default.
if (Args.hasFlag(options::OPT_fblocks, options::OPT_fno_blocks,
getToolChain().IsBlocksDefault()) ||
@@ -6449,7 +6484,8 @@
// pristine IR generated by the frontend. Ideally, a new compile action should
// be added so both IR can be captured.
if (C.getDriver().isSaveTempsEnabled() &&
- !C.getDriver().embedBitcodeInObject() && isa<CompileJobAction>(JA))
+ !C.getDriver().embedBitcodeInObject() && !C.getDriver().isUsingLTO() &&
+ isa<CompileJobAction>(JA))
CmdArgs.push_back("-disable-llvm-passes");
if (Output.getType() == types::TY_Dependencies) {
@@ -8422,9 +8458,13 @@
// for embed-bitcode, use -bitcode_bundle in linker command
if (C.getDriver().embedBitcodeEnabled()) {
// Check if the toolchain supports bitcode build flow.
- if (MachOTC.SupportsEmbeddedBitcode())
+ if (MachOTC.SupportsEmbeddedBitcode()) {
CmdArgs.push_back("-bitcode_bundle");
- else
+ if (C.getDriver().embedBitcodeMarkerOnly() && Version[0] >= 278) {
+ CmdArgs.push_back("-bitcode_process_mode");
+ CmdArgs.push_back("marker");
+ }
+ } else
D.Diag(diag::err_drv_bitcode_unsupported_on_toolchain);
}
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index d892996..c29b908 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -619,6 +619,10 @@
StoredDiags.emplace_back(Level, Info);
}
+IntrusiveRefCntPtr<ASTReader> ASTUnit::getASTReader() const {
+ return Reader;
+}
+
ASTMutationListener *ASTUnit::getASTMutationListener() {
if (WriterData)
return &WriterData->Writer;
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index afcaa6e..e391d10 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/CompilerInstance.h"
+#include "clang/APINotes/APINotesReader.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
@@ -615,6 +616,27 @@
CodeCompleteConsumer *CompletionConsumer) {
TheSema.reset(new Sema(getPreprocessor(), getASTContext(), getASTConsumer(),
TUKind, CompletionConsumer));
+
+ // Set up API notes.
+ TheSema->APINotes.setSwiftVersion(getAPINotesOpts().SwiftVersion);
+
+ // If we're building a module and are supposed to load API notes,
+ // notify the API notes manager.
+ if (auto currentModule = getPreprocessor().getCurrentModule()) {
+ (void)TheSema->APINotes.loadCurrentModuleAPINotes(
+ currentModule,
+ getLangOpts().APINotesModules,
+ getAPINotesOpts().ModuleSearchPaths);
+ // Check for any attributes we should add to the module
+ for (auto reader : TheSema->APINotes.getCurrentModuleReaders()) {
+ // swift_infer_import_as_member
+ if (reader->getModuleOptions().SwiftInferImportAsMember) {
+ currentModule->IsSwiftInferImportAsMember = true;
+ break;
+ }
+ }
+ }
+
// Attach the external sema source if there is any.
if (ExternalSemaSrc) {
TheSema->addExternalSource(ExternalSemaSrc.get());
@@ -1016,7 +1038,7 @@
SourceLocation ImportLoc,
Module *Module,
StringRef ModuleFileName) {
- ModuleMap &ModMap
+ ModuleMap &ModMap
= ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap();
// Construct a compiler invocation for creating this module.
@@ -1794,8 +1816,13 @@
// Check whether this module is available.
clang::Module::Requirement Requirement;
clang::Module::UnresolvedHeaderDirective MissingHeader;
+ clang::Module *ShadowingModule = nullptr;
if (!Module->isAvailable(getLangOpts(), getTarget(), Requirement,
- MissingHeader)) {
+ MissingHeader, ShadowingModule)) {
+
+ assert(!ShadowingModule &&
+ "lookup of module by name should never find shadowed module");
+
if (MissingHeader.FileNameLoc.isValid()) {
getDiagnostics().Report(MissingHeader.FileNameLoc,
diag::err_module_header_missing)
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 36f6b0a..7acc5ef 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -1085,6 +1085,7 @@
static void ParseFileSystemArgs(FileSystemOptions &Opts, ArgList &Args) {
Opts.WorkingDir = Args.getLastArgValue(OPT_working_directory);
+ Opts.APINotesCachePath = Args.getLastArgValue(OPT_fapinotes_cache_path);
}
/// Parse the argument to the -ftest-module-file-extension
@@ -1525,6 +1526,18 @@
Opts.AddVFSOverlayFile(A->getValue());
}
+static void ParseAPINotesArgs(APINotesOptions &Opts, ArgList &Args,
+ DiagnosticsEngine &diags) {
+ using namespace options;
+ if (const Arg *A = Args.getLastArg(OPT_fapinotes_swift_version)) {
+ if (Opts.SwiftVersion.tryParse(A->getValue()))
+ diags.Report(diag::err_drv_invalid_value)
+ << A->getAsString(Args) << A->getValue();
+ }
+ for (const Arg *A : Args.filtered(OPT_iapinotes_modules))
+ Opts.ModuleSearchPaths.push_back(A->getValue());
+}
+
static bool isOpenCL(LangStandard::Kind LangStd) {
return LangStd == LangStandard::lang_opencl ||
LangStd == LangStandard::lang_opencl11 ||
@@ -2031,6 +2044,8 @@
// is enabled.
Opts.HalfArgsAndReturns = Args.hasArg(OPT_fallow_half_arguments_and_returns)
| Opts.NativeHalfArgsAndReturns;
+ Opts.APINotes = Args.hasArg(OPT_fapinotes);
+ Opts.APINotesModules = Args.hasArg(OPT_fapinotes_modules);
Opts.GNUAsm = !Args.hasArg(OPT_fno_gnu_inline_asm);
// __declspec is enabled by default for the PS4 by the driver, and also
@@ -2441,6 +2456,8 @@
Success &= ParseCodeGenArgs(Res.getCodeGenOpts(), Args, DashX, Diags,
Res.getTargetOpts());
ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), Args);
+ ParseAPINotesArgs(Res.getAPINotesOpts(), Args, Diags);
+
if (DashX == IK_AST || DashX == IK_LLVM_IR) {
// ObjCAAutoRefCount and Sanitize LangOpts are used to setup the
// PassManager in BackendUtil.cpp. They need to be initializd no matter
@@ -2459,6 +2476,13 @@
Res.getPreprocessorOpts(), Diags);
if (Res.getFrontendOpts().ProgramAction == frontend::RewriteObjC)
LangOpts.ObjCExceptions = 1;
+
+ // -fapinotes and -fapinotes-modules requires -fapinotes-cache-path=<directory>.
+ if ((LangOpts.APINotes || LangOpts.APINotesModules) &&
+ Res.getFileSystemOpts().APINotesCachePath.empty()) {
+ Diags.Report(diag::err_no_apinotes_cache_path);
+ Success = false;
+ }
}
if (LangOpts.CUDA) {
@@ -2566,7 +2590,19 @@
// Extend the signature with the module file extensions.
const FrontendOptions &frontendOpts = getFrontendOpts();
for (const auto &ext : frontendOpts.ModuleFileExtensions) {
- code = ext->hashExtension(code);
+ code = hash_combine(code, ext->hashExtension(code));
+ }
+
+ // Extend the signature with the SWift version for API notes.
+ const APINotesOptions &apiNotesOpts = getAPINotesOpts();
+ if (apiNotesOpts.SwiftVersion) {
+ code = hash_combine(code, apiNotesOpts.SwiftVersion.getMajor());
+ if (auto minor = apiNotesOpts.SwiftVersion.getMinor())
+ code = hash_combine(code, *minor);
+ if (auto subminor = apiNotesOpts.SwiftVersion.getSubminor())
+ code = hash_combine(code, *subminor);
+ if (auto build = apiNotesOpts.SwiftVersion.getBuild())
+ code = hash_combine(code, *build);
}
// Darwin-specific hack: if we have a sysroot, use the contents and
diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp
index 39fc137..f9ad97c 100644
--- a/lib/Frontend/FrontendAction.cpp
+++ b/lib/Frontend/FrontendAction.cpp
@@ -414,6 +414,13 @@
CI.getDiagnostics().Report(diag::err_module_map_not_found) << Filename;
}
+ // Add a module declaration scope so that modules from -fmodule-map-file
+ // arguments may shadow modules found implicitly in search paths.
+ CI.getPreprocessor()
+ .getHeaderSearchInfo()
+ .getModuleMap()
+ .finishModuleDeclarationScope();
+
// If we were asked to load any module files, do so now.
for (const auto &ModuleFile : CI.getFrontendOpts().ModuleFiles)
if (!CI.loadModuleFile(ModuleFile))
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index f795a1d..bfea1df 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -341,8 +341,13 @@
// Check whether we can build this module at all.
clang::Module::Requirement Requirement;
clang::Module::UnresolvedHeaderDirective MissingHeader;
+ clang::Module *ShadowingModule = nullptr;
if (!Module->isAvailable(CI.getLangOpts(), CI.getTarget(), Requirement,
- MissingHeader)) {
+ MissingHeader, ShadowingModule)) {
+
+ assert(!ShadowingModule &&
+ "lookup of module by name should never find shadowed module");
+
if (MissingHeader.FileNameLoc.isValid()) {
CI.getDiagnostics().Report(MissingHeader.FileNameLoc,
diag::err_module_header_missing)
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index 4502c92..e5a0796 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -593,9 +593,6 @@
Builder.defineMacro("OBJC_ZEROCOST_EXCEPTIONS");
}
- Builder.defineMacro("__OBJC_BOOL_IS_BOOL",
- Twine(TI.useSignedCharForObjCBool() ? "0" : "1"));
-
if (LangOpts.getGC() != LangOptions::NonGC)
Builder.defineMacro("__OBJC_GC__");
@@ -626,6 +623,11 @@
Builder.defineMacro("IB_DESIGNABLE", "");
}
+ // Define a macro that describes the Objective-C boolean type even for C
+ // and C++ since BOOL can be used from non Objective-C code.
+ Builder.defineMacro("__OBJC_BOOL_IS_BOOL",
+ Twine(TI.useSignedCharForObjCBool() ? "0" : "1"));
+
if (LangOpts.CPlusPlus)
InitializeCPlusPlusFeatureTestMacros(LangOpts, Builder);
diff --git a/lib/Index/CMakeLists.txt b/lib/Index/CMakeLists.txt
index 8f51ccb..c9fbfaf 100644
--- a/lib/Index/CMakeLists.txt
+++ b/lib/Index/CMakeLists.txt
@@ -24,5 +24,6 @@
clangFormat
clangFrontend
clangRewrite
+ clangSerialization
clangToolingCore
)
diff --git a/lib/Index/IndexSymbol.cpp b/lib/Index/IndexSymbol.cpp
index 84984fc..f3de472 100644
--- a/lib/Index/IndexSymbol.cpp
+++ b/lib/Index/IndexSymbol.cpp
@@ -389,6 +389,20 @@
case SymbolSubKind::CXXMoveConstructor: return "cxx-move-ctor";
case SymbolSubKind::AccessorGetter: return "acc-get";
case SymbolSubKind::AccessorSetter: return "acc-set";
+ case SymbolSubKind::SwiftAccessorWillSet: return "acc-willset";
+ case SymbolSubKind::SwiftAccessorDidSet: return "acc-didset";
+ case SymbolSubKind::SwiftAccessorAddressor: return "acc-addr";
+ case SymbolSubKind::SwiftAccessorMutableAddressor: return "acc-mutaddr";
+ case SymbolSubKind::SwiftExtensionOfStruct: return "ext-struct";
+ case SymbolSubKind::SwiftExtensionOfClass: return "ext-class";
+ case SymbolSubKind::SwiftExtensionOfEnum: return "ext-enum";
+ case SymbolSubKind::SwiftExtensionOfProtocol: return "ext-protocol";
+ case SymbolSubKind::SwiftPrefixOperator: return "prefix-operator";
+ case SymbolSubKind::SwiftPostfixOperator: return "postfix-operator";
+ case SymbolSubKind::SwiftInfixOperator: return "infix-operator";
+ case SymbolSubKind::SwiftSubscript: return "subscript";
+ case SymbolSubKind::SwiftAssociatedType: return "associated-type";
+ case SymbolSubKind::SwiftGenericTypeParam: return "generic-type-param";
}
llvm_unreachable("invalid symbol subkind");
}
@@ -398,6 +412,7 @@
case SymbolLanguage::C: return "C";
case SymbolLanguage::ObjC: return "ObjC";
case SymbolLanguage::CXX: return "C++";
+ case SymbolLanguage::Swift: return "Swift";
}
llvm_unreachable("invalid symbol language kind");
}
diff --git a/lib/Index/IndexingAction.cpp b/lib/Index/IndexingAction.cpp
index d744293..cac24d4 100644
--- a/lib/Index/IndexingAction.cpp
+++ b/lib/Index/IndexingAction.cpp
@@ -13,6 +13,7 @@
#include "clang/Frontend/FrontendAction.h"
#include "clang/Frontend/MultiplexConsumer.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Serialization/ASTReader.h"
using namespace clang;
using namespace clang::index;
@@ -173,4 +174,20 @@
IndexCtx.setASTContext(Unit.getASTContext());
DataConsumer->initialize(Unit.getASTContext());
indexTranslationUnit(Unit, IndexCtx);
+ DataConsumer->finish();
+}
+
+void index::indexModuleFile(serialization::ModuleFile &Mod,
+ ASTReader &Reader,
+ std::shared_ptr<IndexDataConsumer> DataConsumer,
+ IndexingOptions Opts) {
+ ASTContext &Ctx = Reader.getContext();
+ IndexingContext IndexCtx(Opts, *DataConsumer);
+ IndexCtx.setASTContext(Ctx);
+ DataConsumer->initialize(Ctx);
+
+ for (const Decl *D :Reader.getModuleFileLevelDecls(Mod)) {
+ IndexCtx.indexTopLevelDecl(D);
+ }
+ DataConsumer->finish();
}
diff --git a/lib/Index/USRGeneration.cpp b/lib/Index/USRGeneration.cpp
index 58f61c3..f9ed3c4 100644
--- a/lib/Index/USRGeneration.cpp
+++ b/lib/Index/USRGeneration.cpp
@@ -911,21 +911,30 @@
bool clang::index::generateUSRForMacro(const MacroDefinitionRecord *MD,
const SourceManager &SM,
SmallVectorImpl<char> &Buf) {
+ if (!MD)
+ return true;
+ return generateUSRForMacro(MD->getName()->getName(), MD->getLocation(),
+ SM, Buf);
+
+}
+
+bool clang::index::generateUSRForMacro(StringRef MacroName, SourceLocation Loc,
+ const SourceManager &SM,
+ SmallVectorImpl<char> &Buf) {
// Don't generate USRs for things with invalid locations.
- if (!MD || MD->getLocation().isInvalid())
+ if (MacroName.empty() || Loc.isInvalid())
return true;
llvm::raw_svector_ostream Out(Buf);
// Assume that system headers are sane. Don't put source location
// information into the USR if the macro comes from a system header.
- SourceLocation Loc = MD->getLocation();
bool ShouldGenerateLocation = !SM.isInSystemHeader(Loc);
Out << getUSRSpacePrefix();
if (ShouldGenerateLocation)
printLoc(Out, Loc, SM, /*IncludeOffset=*/true);
Out << "@macro@";
- Out << MD->getName()->getName();
+ Out << MacroName;
return false;
}
diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp
index 1488f62..b207a5a 100644
--- a/lib/Lex/ModuleMap.cpp
+++ b/lib/Lex/ModuleMap.cpp
@@ -568,10 +568,25 @@
if (LangOpts.CurrentModule == Name)
SourceModule = Result;
Modules[Name] = Result;
+ ModuleScopeIDs[Result] = CurrentModuleScopeID;
}
return std::make_pair(Result, true);
}
+Module *ModuleMap::createShadowedModule(StringRef Name, bool IsFramework,
+ Module *ShadowingModule) {
+
+ // Create a new module with this name.
+ Module *Result =
+ new Module(Name, SourceLocation(), /*Parent=*/nullptr, IsFramework,
+ /*IsExplicit=*/false, NumCreatedModules++);
+ Result->ShadowingModule = ShadowingModule;
+ Result->IsAvailable = false;
+ ModuleScopeIDs[Result] = CurrentModuleScopeID;
+
+ return Result;
+}
+
Module *ModuleMap::createModuleForInterfaceUnit(SourceLocation Loc,
StringRef Name) {
assert(LangOpts.CurrentModule == Name && "module name mismatch");
@@ -713,6 +728,8 @@
Module *Result = new Module(ModuleName, SourceLocation(), Parent,
/*IsFramework=*/true, /*IsExplicit=*/false,
NumCreatedModules++);
+ if (!Parent)
+ ModuleScopeIDs[Result] = CurrentModuleScopeID;
InferredModuleAllowedBy[Result] = ModuleMapFile;
Result->IsInferred = true;
if (!Parent) {
@@ -1324,6 +1341,8 @@
AT_extern_c,
/// \brief The 'exhaustive' attribute.
AT_exhaustive,
+ // \brief The 'swift_infer_import_as_member' attribute.
+ AT_swift_infer_import_as_member,
/// \brief The 'no_undeclared_includes' attribute.
AT_no_undeclared_includes
};
@@ -1460,6 +1479,7 @@
SourceLocation LBraceLoc = consumeToken();
// Determine whether this (sub)module has already been defined.
+ Module *ShadowingModule = nullptr;
if (Module *Existing = Map.lookupModuleQualified(ModuleName, ActiveModule)) {
if (Existing->DefinitionLoc.isInvalid() && !ActiveModule) {
// Skip the module definition.
@@ -1473,23 +1493,35 @@
}
return;
}
-
- Diags.Report(ModuleNameLoc, diag::err_mmap_module_redefinition)
- << ModuleName;
- Diags.Report(Existing->DefinitionLoc, diag::note_mmap_prev_definition);
-
- // Skip the module definition.
- skipUntil(MMToken::RBrace);
- if (Tok.is(MMToken::RBrace))
- consumeToken();
-
- HadError = true;
- return;
+
+ if (!Existing->Parent && Map.mayShadowNewModule(Existing)) {
+ ShadowingModule = Existing;
+ } else {
+ // This is not a shawdowed module decl, it is an illegal redefinition.
+ Diags.Report(ModuleNameLoc, diag::err_mmap_module_redefinition)
+ << ModuleName;
+ Diags.Report(Existing->DefinitionLoc, diag::note_mmap_prev_definition);
+
+ // Skip the module definition.
+ skipUntil(MMToken::RBrace);
+ if (Tok.is(MMToken::RBrace))
+ consumeToken();
+
+ HadError = true;
+ return;
+ }
}
// Start defining this module.
- ActiveModule = Map.findOrCreateModule(ModuleName, ActiveModule, Framework,
- Explicit).first;
+ if (ShadowingModule) {
+ ActiveModule =
+ Map.createShadowedModule(ModuleName, Framework, ShadowingModule);
+ } else {
+ ActiveModule =
+ Map.findOrCreateModule(ModuleName, ActiveModule, Framework, Explicit)
+ .first;
+ }
+
ActiveModule->DefinitionLoc = ModuleNameLoc;
if (Attrs.IsSystem || IsSystem)
ActiveModule->IsSystem = true;
@@ -2428,6 +2460,7 @@
.Case("extern_c", AT_extern_c)
.Case("no_undeclared_includes", AT_no_undeclared_includes)
.Case("system", AT_system)
+ .Case("swift_infer_import_as_member", AT_swift_infer_import_as_member)
.Default(AT_unknown);
switch (Attribute) {
case AT_unknown:
@@ -2443,6 +2476,10 @@
Attrs.IsExternC = true;
break;
+ case AT_swift_infer_import_as_member:
+ Attrs.IsSwiftInferImportAsMember = true;
+ break;
+
case AT_exhaustive:
Attrs.IsExhaustive = true;
break;
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 322c580..7449b5f 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -1869,13 +1869,17 @@
if (!SuggestedModule.getModule()->isAvailable()) {
Module::Requirement Requirement;
Module::UnresolvedHeaderDirective MissingHeader;
+ Module *ShadowingModule = nullptr;
Module *M = SuggestedModule.getModule();
// Identify the cause.
(void)M->isAvailable(getLangOpts(), getTargetInfo(), Requirement,
- MissingHeader);
+ MissingHeader, ShadowingModule);
if (MissingHeader.FileNameLoc.isValid()) {
Diag(MissingHeader.FileNameLoc, diag::err_module_header_missing)
<< MissingHeader.IsUmbrella << MissingHeader.FileName;
+ } else if (ShadowingModule) {
+ Diag(M->DefinitionLoc, diag::err_module_shadowed) << M->Name;
+ Diag(ShadowingModule->DefinitionLoc, diag::note_previous_definition);
} else {
Diag(M->DefinitionLoc, diag::err_module_unavailable)
<< M->getFullModuleName() << Requirement.second << Requirement.first;
diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp
index 862a471..2e1b5de 100644
--- a/lib/Lex/PPExpressions.cpp
+++ b/lib/Lex/PPExpressions.cpp
@@ -157,51 +157,6 @@
PP.LexNonComment(PeekTok);
}
- // [cpp.cond]p4:
- // Prior to evaluation, macro invocations in the list of preprocessing
- // tokens that will become the controlling constant expression are replaced
- // (except for those macro names modified by the 'defined' unary operator),
- // just as in normal text. If the token 'defined' is generated as a result
- // of this replacement process or use of the 'defined' unary operator does
- // not match one of the two specified forms prior to macro replacement, the
- // behavior is undefined.
- // This isn't an idle threat, consider this program:
- // #define FOO
- // #define BAR defined(FOO)
- // #if BAR
- // ...
- // #else
- // ...
- // #endif
- // clang and gcc will pick the #if branch while Visual Studio will take the
- // #else branch. Emit a warning about this undefined behavior.
- if (beginLoc.isMacroID()) {
- bool IsFunctionTypeMacro =
- PP.getSourceManager()
- .getSLocEntry(PP.getSourceManager().getFileID(beginLoc))
- .getExpansion()
- .isFunctionMacroExpansion();
- // For object-type macros, it's easy to replace
- // #define FOO defined(BAR)
- // with
- // #if defined(BAR)
- // #define FOO 1
- // #else
- // #define FOO 0
- // #endif
- // and doing so makes sense since compilers handle this differently in
- // practice (see example further up). But for function-type macros,
- // there is no good way to write
- // # define FOO(x) (defined(M_ ## x) && M_ ## x)
- // in a different way, and compilers seem to agree on how to behave here.
- // So warn by default on object-type macros, but only warn in -pedantic
- // mode on function-type macros.
- if (IsFunctionTypeMacro)
- PP.Diag(beginLoc, diag::warn_defined_in_function_type_macro);
- else
- PP.Diag(beginLoc, diag::warn_defined_in_object_type_macro);
- }
-
// Invoke the 'defined' callback.
if (PPCallbacks *Callbacks = PP.getPPCallbacks()) {
Callbacks->Defined(macroToken, Macro,
@@ -241,8 +196,8 @@
if (IdentifierInfo *II = PeekTok.getIdentifierInfo()) {
// Handle "defined X" and "defined(X)".
if (II->isStr("defined"))
- return EvaluateDefined(Result, PeekTok, DT, ValueLive, PP);
-
+ return(EvaluateDefined(Result, PeekTok, DT, ValueLive, PP));
+
// If this identifier isn't 'defined' or one of the special
// preprocessor keywords and it wasn't macro expanded, it turns
// into a simple 0, unless it is the C++ keyword "true", in which case it
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index de166c7..822ac8f 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -1106,6 +1106,7 @@
.Case("attribute_availability_with_version_underscores", true)
.Case("attribute_availability_tvos", true)
.Case("attribute_availability_watchos", true)
+ .Case("attribute_availability_swift", true)
.Case("attribute_availability_with_strict", true)
.Case("attribute_availability_with_replacement", true)
.Case("attribute_availability_in_templates", true)
@@ -1130,6 +1131,7 @@
.Case("cxx_exceptions", LangOpts.CXXExceptions)
.Case("cxx_rtti", LangOpts.RTTI && LangOpts.RTTIData)
.Case("enumerator_attributes", true)
+ .Case("generalized_swift_name", true)
.Case("nullability", true)
.Case("nullability_on_arrays", true)
.Case("memory_sanitizer", LangOpts.Sanitize.has(SanitizerKind::Memory))
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index c52b61e..a456c9b 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -47,6 +47,7 @@
VS, ICIS_NoInit);
if (FnD) {
Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs);
+ Actions.ProcessAPINotes(FnD);
if (PureSpecLoc.isValid())
Actions.ActOnPureSpecifier(FnD, PureSpecLoc);
}
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 2d32087..b129394 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -244,6 +244,38 @@
return IL;
}
+void Parser::ParseSwiftNewtypeAttribute(
+ IdentifierInfo &SwiftNewtype, SourceLocation SwiftNewtypeLoc,
+ ParsedAttributes &attrs, SourceLocation *endLoc, IdentifierInfo *ScopeName,
+ SourceLocation ScopeLoc, AttributeList::Syntax Syntax) {
+
+ BalancedDelimiterTracker Parens(*this, tok::l_paren);
+ Parens.consumeOpen();
+
+ if (Tok.is(tok::r_paren)) {
+ Diag(Tok.getLocation(), diag::err_argument_required_after_attribute);
+ Parens.consumeClose();
+ return;
+ }
+ if (Tok.isNot(tok::kw_struct) && Tok.isNot(tok::kw_enum)) {
+ Diag(Tok.getLocation(), diag::warn_attribute_type_not_supported)
+ << &SwiftNewtype << Tok.getIdentifierInfo();
+ if (!isTokenSpecial())
+ ConsumeToken();
+ Parens.consumeClose();
+ return;
+ }
+ auto IL = IdentifierLoc::create(Actions.Context, Tok.getLocation(),
+ Tok.getIdentifierInfo());
+ ConsumeToken();
+ auto identLoc = ArgsUnion(IL);
+
+ attrs.addNew(&SwiftNewtype,
+ SourceRange(SwiftNewtypeLoc, Parens.getCloseLocation()),
+ ScopeName, ScopeLoc, &identLoc, 1, Syntax);
+ Parens.consumeClose();
+}
+
void Parser::ParseAttributeWithTypeArg(IdentifierInfo &AttrName,
SourceLocation AttrNameLoc,
ParsedAttributes &Attrs,
@@ -364,6 +396,10 @@
ParseTypeTagForDatatypeAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc,
ScopeName, ScopeLoc, Syntax);
return;
+ } else if (AttrKind == AttributeList::AT_SwiftNewtype) {
+ ParseSwiftNewtypeAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc,
+ ScopeName, ScopeLoc, Syntax);
+ return;
} else if (attributeIsTypeArgAttr(*AttrName)) {
ParseAttributeWithTypeArg(*AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,
ScopeLoc, Syntax);
@@ -855,7 +891,7 @@
///
/// version-arg:
/// 'introduced' '=' version
-/// 'deprecated' '=' version
+/// 'deprecated' ['=' version]
/// 'obsoleted' = version
/// 'unavailable'
/// opt-replacement:
@@ -943,6 +979,21 @@
continue;
}
+ if (Keyword == Ident_deprecated && Platform->Ident &&
+ Platform->Ident->getName() == "swift") {
+ // For swift, we deprecate for all versions.
+ if (!Changes[Deprecated].KeywordLoc.isInvalid()) {
+ Diag(KeywordLoc, diag::err_availability_redundant)
+ << Keyword
+ << SourceRange(Changes[Deprecated].KeywordLoc);
+ }
+
+ Changes[Deprecated].KeywordLoc = KeywordLoc;
+ // Use a fake version here.
+ Changes[Deprecated].Version = VersionTuple(1);
+ continue;
+ }
+
if (Tok.isNot(tok::equal)) {
Diag(Tok, diag::err_expected_after) << Keyword << tok::equal;
SkipUntil(tok::r_paren, StopAtSemi);
@@ -6553,3 +6604,68 @@
}
return false;
}
+
+TypeResult Parser::parseTypeFromString(StringRef typeStr, StringRef context,
+ SourceLocation includeLoc) {
+ // Consume (unexpanded) tokens up to the end-of-directive.
+ SmallVector<Token, 4> tokens;
+ {
+ // Create a new buffer from which we will parse the type.
+ auto &sourceMgr = PP.getSourceManager();
+ FileID fileID = sourceMgr.createFileID(
+ llvm::MemoryBuffer::getMemBufferCopy(typeStr, context),
+ SrcMgr::C_User, 0, 0, includeLoc);
+
+ // Form a new lexer that references the buffer.
+ Lexer lexer(fileID, sourceMgr.getBuffer(fileID), PP);
+ lexer.setParsingPreprocessorDirective(true);
+ lexer.setIsPragmaLexer(true);
+
+ // Lex the tokens from that buffer.
+ Token tok;
+ do {
+ lexer.Lex(tok);
+ tokens.push_back(tok);
+ } while (tok.isNot(tok::eod));
+ }
+
+ // Replace the "eod" token with an "eof" token identifying the end of
+ // the provided string.
+ Token &endToken = tokens.back();
+ endToken.startToken();
+ endToken.setKind(tok::eof);
+ endToken.setLocation(Tok.getLocation());
+ endToken.setEofData(typeStr.data());
+
+ // Add the current token back.
+ tokens.push_back(Tok);
+
+ // Enter the tokens into the token stream.
+ PP.EnterTokenStream(tokens, /*DisableMacroExpansion=*/false);
+
+ // Consume the current token so that we'll start parsing the tokens we
+ // added to the stream.
+ ConsumeAnyToken();
+
+ // Enter a new scope.
+ ParseScope localScope(this, 0);
+
+ // Parse the type.
+ TypeResult result = ParseTypeName(nullptr);
+
+ // Check if we parsed the whole thing.
+ if (result.isUsable() &&
+ (Tok.isNot(tok::eof) || Tok.getEofData() != typeStr.data())) {
+ Diag(Tok.getLocation(), diag::err_type_unparsed);
+ }
+
+ // There could be leftover tokens (e.g. because of an error).
+ // Skip through until we reach the 'end of directive' token.
+ while (Tok.isNot(tok::eof))
+ ConsumeAnyToken();
+
+ // Consume the end token.
+ if (Tok.is(tok::eof) && Tok.getEofData() == typeStr.data())
+ ConsumeAnyToken();
+ return result;
+}
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 3f1fe7e..02e1f3f 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -2724,8 +2724,10 @@
// initialize it.
ThisDecl = VT->getTemplatedDecl();
- if (ThisDecl && AccessAttrs)
+ if (ThisDecl) {
Actions.ProcessDeclAttributeList(getCurScope(), ThisDecl, AccessAttrs);
+ Actions.ProcessAPINotes(ThisDecl);
+ }
}
// Error recovery might have converted a non-static member into a static
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 81761bf..3a24ad9 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -212,6 +212,8 @@
/// __attribute__((unavailable))
/// __attribute__((objc_exception)) - used by NSException on 64-bit
/// __attribute__((objc_root_class))
+/// __attribute__((objc_subclassing_restricted))
+/// __attribute__((objc_complete_definition))
///
Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
ParsedAttributes &attrs) {
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 52e5194..e1a99fd 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -87,6 +87,11 @@
PP.addCommentHandler(CommentSemaHandler.get());
PP.setCodeCompletionHandler(*this);
+
+ Actions.ParseTypeFromStringCallback =
+ [this](StringRef typeStr, StringRef context, SourceLocation includeLoc) {
+ return this->parseTypeFromString(typeStr, context, includeLoc);
+ };
}
DiagnosticBuilder Parser::Diag(SourceLocation Loc, unsigned DiagID) {
@@ -419,6 +424,9 @@
//===----------------------------------------------------------------------===//
Parser::~Parser() {
+ // Clear out the parse-type-from-string callback.
+ Actions.ParseTypeFromStringCallback = nullptr;
+
// If we still have scopes active, delete the scope tree.
delete getCurScope();
Actions.CurScope = nullptr;
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt
index 7a59732..c92879a 100644
--- a/lib/Sema/CMakeLists.txt
+++ b/lib/Sema/CMakeLists.txt
@@ -20,6 +20,7 @@
Sema.cpp
SemaAccess.cpp
SemaAttr.cpp
+ SemaAPINotes.cpp
SemaCXXScopeSpec.cpp
SemaCast.cpp
SemaChecking.cpp
@@ -61,4 +62,5 @@
clangBasic
clangEdit
clangLex
+ clangAPINotes
)
diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp
index 0bdb194..53263ba 100644
--- a/lib/Sema/IdentifierResolver.cpp
+++ b/lib/Sema/IdentifierResolver.cpp
@@ -381,7 +381,7 @@
PP.getExternalSource()->updateOutOfDateIdentifier(II);
if (II.isFromAST())
- II.setFETokenInfoChangedSinceDeserialization();
+ II.setChangedSinceDeserialization();
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Sema/ScopeInfo.cpp b/lib/Sema/ScopeInfo.cpp
index 3970b41..58d44ba 100644
--- a/lib/Sema/ScopeInfo.cpp
+++ b/lib/Sema/ScopeInfo.cpp
@@ -184,7 +184,7 @@
}
// Has this weak object been seen before?
- FunctionScopeInfo::WeakObjectUseMap::iterator Uses;
+ FunctionScopeInfo::WeakObjectUseMap::iterator Uses = WeakObjectUses.end();
if (const ObjCPropertyRefExpr *RefExpr = dyn_cast<ObjCPropertyRefExpr>(E)) {
if (!RefExpr->isObjectReceiver())
return;
@@ -197,10 +197,10 @@
}
else if (const ObjCIvarRefExpr *IvarE = dyn_cast<ObjCIvarRefExpr>(E))
Uses = WeakObjectUses.find(WeakObjectProfileTy(IvarE));
- else if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
- Uses = WeakObjectUses.find(WeakObjectProfileTy(DRE));
- else if (const ObjCMessageExpr *MsgE = dyn_cast<ObjCMessageExpr>(E)) {
- Uses = WeakObjectUses.end();
+ else if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
+ if (isa<VarDecl>(DRE->getDecl()))
+ Uses = WeakObjectUses.find(WeakObjectProfileTy(DRE));
+ } else if (const ObjCMessageExpr *MsgE = dyn_cast<ObjCMessageExpr>(E)) {
if (const ObjCMethodDecl *MD = MsgE->getMethodDecl()) {
if (const ObjCPropertyDecl *Prop = MD->findPropertyDecl()) {
Uses =
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 412f944..221058c 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -77,7 +77,8 @@
isMultiplexExternalSource(false), FPFeatures(pp.getLangOpts()),
LangOpts(pp.getLangOpts()), PP(pp), Context(ctxt), Consumer(consumer),
Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
- CollectStats(false), CodeCompleter(CodeCompleter),
+ APINotes(SourceMgr, LangOpts), CollectStats(false),
+ CodeCompleter(CodeCompleter),
CurContext(nullptr), OriginalLexicalContext(nullptr),
MSStructPragmaOn(false),
MSPointerToMemberRepresentationMethod(
diff --git a/lib/Sema/SemaAPINotes.cpp b/lib/Sema/SemaAPINotes.cpp
new file mode 100644
index 0000000..078445e
--- /dev/null
+++ b/lib/Sema/SemaAPINotes.cpp
@@ -0,0 +1,840 @@
+//===--- SemaAPINotes.cpp - API Notes Handling ----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the mapping from API notes to declaration attributes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/SemaInternal.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/APINotes/APINotesReader.h"
+using namespace clang;
+using clang::api_notes::VersionedInfoRole;
+
+namespace {
+ struct VersionedInfoMetadata {
+ VersionTuple Version;
+ VersionedInfoRole Role;
+
+ /*implicit*/ VersionedInfoMetadata(VersionedInfoRole role) : Role(role) {
+ assert(role != VersionedInfoRole::Versioned &&
+ "explicit version required");
+ }
+
+ /*implicit*/ VersionedInfoMetadata(VersionTuple version)
+ : Version(version), Role(VersionedInfoRole::Versioned) {}
+ };
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType type) {
+ QualType pointee = type->getPointeeType();
+ if (pointee.isNull())
+ return false;
+
+ return pointee->isAnyPointerType() || pointee->isObjCObjectPointerType() ||
+ pointee->isMemberPointerType();
+}
+
+// Apply nullability to the given declaration.
+static void applyNullability(Sema &S, Decl *decl, NullabilityKind nullability,
+ VersionedInfoMetadata metadata) {
+ bool overrideExisting;
+ switch (metadata.Role) {
+ case VersionedInfoRole::AugmentSource:
+ overrideExisting = false;
+ break;
+
+ case VersionedInfoRole::ReplaceSource:
+ overrideExisting = true;
+ break;
+
+ case VersionedInfoRole::Versioned:
+ // FIXME: Record versioned info?
+ return;
+ }
+
+ QualType type;
+
+ // Nullability for a function/method appertains to the retain type.
+ if (auto function = dyn_cast<FunctionDecl>(decl)) {
+ type = function->getReturnType();
+ } else if (auto method = dyn_cast<ObjCMethodDecl>(decl)) {
+ type = method->getReturnType();
+ } else if (auto value = dyn_cast<ValueDecl>(decl)) {
+ type = value->getType();
+ } else if (auto property = dyn_cast<ObjCPropertyDecl>(decl)) {
+ type = property->getType();
+ } else {
+ return;
+ }
+
+ // Check the nullability specifier on this type.
+ QualType origType = type;
+ S.checkNullabilityTypeSpecifier(type, nullability, decl->getLocation(),
+ /*isContextSensitive=*/false,
+ isa<ParmVarDecl>(decl), /*implicit=*/true,
+ overrideExisting);
+ if (type.getTypePtr() == origType.getTypePtr())
+ return;
+
+ if (auto function = dyn_cast<FunctionDecl>(decl)) {
+ const FunctionType *fnType = function->getType()->castAs<FunctionType>();
+ if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(fnType)) {
+ function->setType(S.Context.getFunctionType(type, proto->getParamTypes(),
+ proto->getExtProtoInfo()));
+ } else {
+ function->setType(S.Context.getFunctionNoProtoType(type,
+ fnType->getExtInfo()));
+ }
+ } else if (auto method = dyn_cast<ObjCMethodDecl>(decl)) {
+ method->setReturnType(type);
+
+ // Make it a context-sensitive keyword if we can.
+ if (!isMultiLevelPointerType(type)) {
+ method->setObjCDeclQualifier(
+ Decl::ObjCDeclQualifier(method->getObjCDeclQualifier() |
+ Decl::OBJC_TQ_CSNullability));
+ }
+ } else if (auto value = dyn_cast<ValueDecl>(decl)) {
+ value->setType(type);
+
+ // Make it a context-sensitive keyword if we can.
+ if (auto parm = dyn_cast<ParmVarDecl>(decl)) {
+ if (parm->isObjCMethodParameter() && !isMultiLevelPointerType(type)) {
+ parm->setObjCDeclQualifier(
+ Decl::ObjCDeclQualifier(parm->getObjCDeclQualifier() |
+ Decl::OBJC_TQ_CSNullability));
+ }
+ }
+ } else if (auto property = dyn_cast<ObjCPropertyDecl>(decl)) {
+ property->setType(type, property->getTypeSourceInfo());
+
+ // Make it a property attribute if we can.
+ if (!isMultiLevelPointerType(type)) {
+ property->setPropertyAttributes(
+ ObjCPropertyDecl::OBJC_PR_null_resettable);
+ }
+ } else {
+ llvm_unreachable("cannot handle nullability here");
+ }
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef CopyString(ASTContext &ctx, StringRef string) {
+ void *mem = ctx.Allocate(string.size(), alignof(char));
+ memcpy(mem, string.data(), string.size());
+ return StringRef(static_cast<char *>(mem), string.size());
+}
+
+namespace {
+ template <typename A>
+ struct AttrKindFor {};
+
+#define ATTR(X) \
+ template <> struct AttrKindFor<X##Attr> { \
+ static const attr::Kind value = attr::X; \
+ };
+#include "clang/Basic/AttrList.inc"
+
+ /// Handle an attribute introduced by API notes.
+ ///
+ /// \param shouldAddAttribute Whether we should add a new attribute
+ /// (otherwise, we might remove an existing attribute).
+ /// \param createAttr Create the new attribute to be added.
+ template<typename A>
+ void handleAPINotedAttribute(
+ Sema &S, Decl *D, bool shouldAddAttribute,
+ VersionedInfoMetadata metadata,
+ llvm::function_ref<A *()> createAttr,
+ llvm::function_ref<specific_attr_iterator<A>(Decl*)> getExistingAttr) {
+ switch (metadata.Role) {
+ case VersionedInfoRole::AugmentSource:
+ // If we're not adding an attribute, there's nothing to do.
+ if (!shouldAddAttribute) return;
+
+ // If the attribute is already present, we're done.
+ if (getExistingAttr(D) != D->specific_attr_end<A>()) return;
+
+ // Add the attribute.
+ if (auto attr = createAttr())
+ D->addAttr(attr);
+ break;
+
+ case VersionedInfoRole::ReplaceSource: {
+ auto end = D->specific_attr_end<A>();
+ auto existing = getExistingAttr(D);
+ if (existing != end) {
+ // Remove the existing attribute, and treat it as a superseded
+ // non-versioned attribute.
+ auto *versioned =
+ SwiftVersionedAttr::CreateImplicit(S.Context, clang::VersionTuple(),
+ *existing);
+
+ D->getAttrs().erase(existing.getCurrent());
+ D->addAttr(versioned);
+ }
+
+ // If we're supposed to add a new attribute, do so.
+ if (shouldAddAttribute) {
+ if (auto attr = createAttr()) {
+ D->addAttr(attr);
+ }
+ }
+ break;
+ }
+
+ case VersionedInfoRole::Versioned:
+ // FIXME: Include the actual version instead of making one up.
+ if (shouldAddAttribute) {
+ if (auto attr = createAttr()) {
+ auto *versioned =
+ SwiftVersionedAttr::CreateImplicit(S.Context, metadata.Version,
+ attr);
+ D->addAttr(versioned);
+ }
+ } else {
+ // FIXME: This isn't preserving enough information for things like
+ // availability, where we're trying to remove a /specific/ kind of
+ // attribute.
+ auto *versioned =
+ SwiftVersionedRemovalAttr::CreateImplicit(S.Context,
+ metadata.Version,
+ AttrKindFor<A>::value);
+ D->addAttr(versioned);
+ }
+ break;
+ }
+ }
+
+ template<typename A>
+ void handleAPINotedAttribute(
+ Sema &S, Decl *D, bool shouldAddAttribute,
+ VersionedInfoMetadata metadata,
+ llvm::function_ref<A *()> createAttr) {
+ handleAPINotedAttribute<A>(S, D, shouldAddAttribute, metadata, createAttr,
+ [](Decl *decl) {
+ return decl->specific_attr_begin<A>();
+ });
+ }
+}
+
+static void ProcessAPINotes(Sema &S, Decl *D,
+ const api_notes::CommonEntityInfo &info,
+ VersionedInfoMetadata metadata) {
+ // Availability
+ if (info.Unavailable) {
+ handleAPINotedAttribute<UnavailableAttr>(S, D, true, metadata,
+ [&] {
+ return UnavailableAttr::CreateImplicit(S.Context,
+ CopyString(S.Context,
+ info.UnavailableMsg));
+ });
+ }
+
+ if (info.UnavailableInSwift) {
+ handleAPINotedAttribute<AvailabilityAttr>(S, D, true, metadata, [&] {
+ return AvailabilityAttr::CreateImplicit(
+ S.Context,
+ &S.Context.Idents.get("swift"),
+ VersionTuple(),
+ VersionTuple(),
+ VersionTuple(),
+ /*Unavailable=*/true,
+ CopyString(S.Context, info.UnavailableMsg),
+ /*Strict=*/false,
+ /*Replacement=*/StringRef());
+ },
+ [](Decl *decl) {
+ auto existing = decl->specific_attr_begin<AvailabilityAttr>(),
+ end = decl->specific_attr_end<AvailabilityAttr>();
+ while (existing != end) {
+ if (auto platform = (*existing)->getPlatform()) {
+ if (platform->isStr("swift"))
+ break;
+ }
+
+ ++existing;
+ }
+
+ return existing;
+ });
+ }
+
+ // swift_private
+ if (auto swiftPrivate = info.isSwiftPrivate()) {
+ handleAPINotedAttribute<SwiftPrivateAttr>(S, D, *swiftPrivate, metadata,
+ [&] {
+ return SwiftPrivateAttr::CreateImplicit(S.Context);
+ });
+ }
+
+ // swift_name
+ if (!info.SwiftName.empty()) {
+ handleAPINotedAttribute<SwiftNameAttr>(S, D, true, metadata,
+ [&]() -> SwiftNameAttr * {
+ auto &APINoteName = S.getASTContext().Idents.get("SwiftName API Note");
+
+ if (!S.DiagnoseSwiftName(D, info.SwiftName, D->getLocation(),
+ &APINoteName)) {
+ return nullptr;
+ }
+
+ return SwiftNameAttr::CreateImplicit(S.Context,
+ CopyString(S.Context,
+ info.SwiftName));
+ });
+ }
+}
+
+static void ProcessAPINotes(Sema &S, Decl *D,
+ const api_notes::CommonTypeInfo &info,
+ VersionedInfoMetadata metadata) {
+ // swift_bridge
+ if (auto swiftBridge = info.getSwiftBridge()) {
+ handleAPINotedAttribute<SwiftBridgeAttr>(S, D, !swiftBridge->empty(),
+ metadata, [&] {
+ return SwiftBridgeAttr::CreateImplicit(S.Context,
+ CopyString(S.Context,
+ *swiftBridge));
+ });
+ }
+
+ // ns_error_domain
+ if (auto nsErrorDomain = info.getNSErrorDomain()) {
+ handleAPINotedAttribute<NSErrorDomainAttr>(S, D, !nsErrorDomain->empty(),
+ metadata, [&] {
+ return NSErrorDomainAttr::CreateImplicit(
+ S.Context,
+ &S.Context.Idents.get(*nsErrorDomain));
+ });
+ }
+
+ ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(info),
+ metadata);
+}
+
+/// Check that the replacement type provided by API notes is reasonable.
+///
+/// This is a very weak form of ABI check.
+static bool checkAPINotesReplacementType(Sema &S, SourceLocation loc,
+ QualType origType,
+ QualType replacementType) {
+ if (S.Context.getTypeSize(origType) !=
+ S.Context.getTypeSize(replacementType)) {
+ S.Diag(loc, diag::err_incompatible_replacement_type)
+ << replacementType << origType;
+ return true;
+ }
+
+ return false;
+}
+
+/// Process API notes for a variable or property.
+static void ProcessAPINotes(Sema &S, Decl *D,
+ const api_notes::VariableInfo &info,
+ VersionedInfoMetadata metadata) {
+ // Type override.
+ if (metadata.Role != VersionedInfoRole::Versioned &&
+ !info.getType().empty() && S.ParseTypeFromStringCallback) {
+ auto parsedType = S.ParseTypeFromStringCallback(info.getType(),
+ "<API Notes>",
+ D->getLocation());
+ if (parsedType.isUsable()) {
+ QualType type = Sema::GetTypeFromParser(parsedType.get());
+ auto typeInfo =
+ S.Context.getTrivialTypeSourceInfo(type, D->getLocation());
+
+ if (auto var = dyn_cast<VarDecl>(D)) {
+ // Make adjustments to parameter types.
+ if (isa<ParmVarDecl>(var)) {
+ type = S.adjustParameterTypeForObjCAutoRefCount(type,
+ D->getLocation());
+ type = S.Context.getAdjustedParameterType(type);
+ }
+
+ if (!checkAPINotesReplacementType(S, var->getLocation(), var->getType(),
+ type)) {
+ var->setType(type);
+ var->setTypeSourceInfo(typeInfo);
+ }
+ } else if (auto property = dyn_cast<ObjCPropertyDecl>(D)) {
+ if (!checkAPINotesReplacementType(S, property->getLocation(),
+ property->getType(),
+ type)) {
+ property->setType(type, typeInfo);
+ }
+ } else {
+ llvm_unreachable("API notes allowed a type on an unknown declaration");
+ }
+ }
+ }
+
+ // Nullability.
+ if (auto Nullability = info.getNullability()) {
+ applyNullability(S, D, *Nullability, metadata);
+ }
+
+ // Handle common entity information.
+ ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(info),
+ metadata);
+}
+
+/// Process API notes for a parameter.
+static void ProcessAPINotes(Sema &S, ParmVarDecl *D,
+ const api_notes::ParamInfo &info,
+ VersionedInfoMetadata metadata) {
+ // noescape
+ if (auto noescape = info.isNoEscape()) {
+ handleAPINotedAttribute<NoEscapeAttr>(S, D, *noescape, metadata, [&] {
+ return NoEscapeAttr::CreateImplicit(S.Context);
+ });
+ }
+
+ // Handle common entity information.
+ ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(info),
+ metadata);
+}
+
+/// Process API notes for a global variable.
+static void ProcessAPINotes(Sema &S, VarDecl *D,
+ const api_notes::GlobalVariableInfo &info,
+ VersionedInfoMetadata metadata) {
+ // Handle common entity information.
+ ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(info),
+ metadata);
+}
+
+/// Process API notes for an Objective-C property.
+static void ProcessAPINotes(Sema &S, ObjCPropertyDecl *D,
+ const api_notes::ObjCPropertyInfo &info,
+ VersionedInfoMetadata metadata) {
+ // Handle common entity information.
+ ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(info),
+ metadata);
+ if (auto asAccessors = info.getSwiftImportAsAccessors()) {
+ handleAPINotedAttribute<SwiftImportPropertyAsAccessorsAttr>(S, D,
+ *asAccessors,
+ metadata, [&] {
+ return SwiftImportPropertyAsAccessorsAttr::CreateImplicit(S.Context);
+ });
+ }
+}
+
+namespace {
+ typedef llvm::PointerUnion<FunctionDecl *, ObjCMethodDecl *> FunctionOrMethod;
+}
+
+/// Process API notes for a function or method.
+static void ProcessAPINotes(Sema &S, FunctionOrMethod AnyFunc,
+ const api_notes::FunctionInfo &info,
+ VersionedInfoMetadata metadata) {
+ // Find the declaration itself.
+ FunctionDecl *FD = AnyFunc.dyn_cast<FunctionDecl *>();
+ Decl *D = FD;
+ ObjCMethodDecl *MD = 0;
+ if (!D) {
+ MD = AnyFunc.get<ObjCMethodDecl *>();
+ D = MD;
+ }
+
+ // Nullability of return type.
+ if (info.NullabilityAudited) {
+ applyNullability(S, D, info.getReturnTypeInfo(), metadata);
+ }
+
+ // Parameters.
+ unsigned NumParams;
+ if (FD)
+ NumParams = FD->getNumParams();
+ else
+ NumParams = MD->param_size();
+
+ bool anyTypeChanged = false;
+ for (unsigned I = 0; I != NumParams; ++I) {
+ ParmVarDecl *Param;
+ if (FD)
+ Param = FD->getParamDecl(I);
+ else
+ Param = MD->param_begin()[I];
+
+ QualType paramTypeBefore = Param->getType();
+
+ if (I < info.Params.size()) {
+ ProcessAPINotes(S, Param, info.Params[I], metadata);
+ }
+
+ // Nullability.
+ if (info.NullabilityAudited)
+ applyNullability(S, Param, info.getParamTypeInfo(I), metadata);
+
+ if (paramTypeBefore.getAsOpaquePtr() != Param->getType().getAsOpaquePtr())
+ anyTypeChanged = true;
+ }
+
+ // Result type override.
+ QualType overriddenResultType;
+ if (metadata.Role != VersionedInfoRole::Versioned &&
+ !info.ResultType.empty() && S.ParseTypeFromStringCallback) {
+ auto parsedType = S.ParseTypeFromStringCallback(info.ResultType,
+ "<API Notes>",
+ D->getLocation());
+ if (parsedType.isUsable()) {
+ QualType resultType = Sema::GetTypeFromParser(parsedType.get());
+
+ if (MD) {
+ if (!checkAPINotesReplacementType(S, D->getLocation(),
+ MD->getReturnType(), resultType)) {
+ auto resultTypeInfo =
+ S.Context.getTrivialTypeSourceInfo(resultType, D->getLocation());
+ MD->setReturnType(resultType);
+ MD->setReturnTypeSourceInfo(resultTypeInfo);
+ }
+ } else if (!checkAPINotesReplacementType(S, FD->getLocation(),
+ FD->getReturnType(),
+ resultType)) {
+ overriddenResultType = resultType;
+ anyTypeChanged = true;
+ }
+ }
+ }
+
+ // If the result type or any of the parameter types changed for a function
+ // declaration, we have to rebuild the type.
+ if (FD && anyTypeChanged) {
+ if (const auto *fnProtoType = FD->getType()->getAs<FunctionProtoType>()) {
+ if (overriddenResultType.isNull())
+ overriddenResultType = fnProtoType->getReturnType();
+
+ SmallVector<QualType, 4> paramTypes;
+ for (auto param : FD->parameters()) {
+ paramTypes.push_back(param->getType());
+ }
+ FD->setType(S.Context.getFunctionType(overriddenResultType,
+ paramTypes,
+ fnProtoType->getExtProtoInfo()));
+ } else if (!overriddenResultType.isNull()) {
+ const auto *fnNoProtoType = FD->getType()->castAs<FunctionNoProtoType>();
+ FD->setType(
+ S.Context.getFunctionNoProtoType(overriddenResultType,
+ fnNoProtoType->getExtInfo()));
+ }
+ }
+
+ // Handle common entity information.
+ ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(info),
+ metadata);
+}
+
+/// Process API notes for a global function.
+static void ProcessAPINotes(Sema &S, FunctionDecl *D,
+ const api_notes::GlobalFunctionInfo &info,
+ VersionedInfoMetadata metadata) {
+
+ // Handle common function information.
+ ProcessAPINotes(S, FunctionOrMethod(D),
+ static_cast<const api_notes::FunctionInfo &>(info), metadata);
+}
+
+/// Process API notes for an enumerator.
+static void ProcessAPINotes(Sema &S, EnumConstantDecl *D,
+ const api_notes::EnumConstantInfo &info,
+ VersionedInfoMetadata metadata) {
+
+ // Handle common information.
+ ProcessAPINotes(S, D,
+ static_cast<const api_notes::CommonEntityInfo &>(info),
+ metadata);
+}
+
+/// Process API notes for an Objective-C method.
+static void ProcessAPINotes(Sema &S, ObjCMethodDecl *D,
+ const api_notes::ObjCMethodInfo &info,
+ VersionedInfoMetadata metadata) {
+ // Designated initializers.
+ if (info.DesignatedInit) {
+ handleAPINotedAttribute<ObjCDesignatedInitializerAttr>(S, D, true, metadata,
+ [&] {
+ if (ObjCInterfaceDecl *IFace = D->getClassInterface()) {
+ IFace->setHasDesignatedInitializers();
+ }
+ return ObjCDesignatedInitializerAttr::CreateImplicit(S.Context);
+ });
+ }
+
+ // FIXME: This doesn't work well with versioned API notes.
+ if (metadata.Role == VersionedInfoRole::AugmentSource &&
+ info.getFactoryAsInitKind()
+ == api_notes::FactoryAsInitKind::AsClassMethod &&
+ !D->getAttr<SwiftNameAttr>()) {
+ D->addAttr(SwiftSuppressFactoryAsInitAttr::CreateImplicit(S.Context));
+ }
+
+ // Handle common function information.
+ ProcessAPINotes(S, FunctionOrMethod(D),
+ static_cast<const api_notes::FunctionInfo &>(info), metadata);
+}
+
+/// Process API notes for a tag.
+static void ProcessAPINotes(Sema &S, TagDecl *D,
+ const api_notes::TagInfo &info,
+ VersionedInfoMetadata metadata) {
+ // Handle common type information.
+ ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(info),
+ metadata);
+}
+
+/// Process API notes for a typedef.
+static void ProcessAPINotes(Sema &S, TypedefNameDecl *D,
+ const api_notes::TypedefInfo &info,
+ VersionedInfoMetadata metadata) {
+ // swift_wrapper
+ using SwiftWrapperKind = api_notes::SwiftWrapperKind;
+
+ if (auto swiftWrapper = info.SwiftWrapper) {
+ handleAPINotedAttribute<SwiftNewtypeAttr>(S, D,
+ *swiftWrapper != SwiftWrapperKind::None, metadata,
+ [&] {
+ SwiftNewtypeAttr::NewtypeKind kind;
+ switch (*swiftWrapper) {
+ case SwiftWrapperKind::None:
+ llvm_unreachable("Shouldn't build an attribute");
+
+ case SwiftWrapperKind::Struct:
+ kind = SwiftNewtypeAttr::NK_Struct;
+ break;
+
+ case SwiftWrapperKind::Enum:
+ kind = SwiftNewtypeAttr::NK_Enum;
+ break;
+ }
+ return SwiftNewtypeAttr::CreateImplicit(
+ S.Context,
+ SwiftNewtypeAttr::GNU_swift_wrapper,
+ kind);
+ });
+ }
+
+ // Handle common type information.
+ ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(info),
+ metadata);
+}
+
+/// Process API notes for an Objective-C class or protocol.
+static void ProcessAPINotes(Sema &S, ObjCContainerDecl *D,
+ const api_notes::ObjCContextInfo &info,
+ VersionedInfoMetadata metadata) {
+
+ // Handle common type information.
+ ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(info),
+ metadata);
+}
+
+/// Process API notes for an Objective-C class.
+static void ProcessAPINotes(Sema &S, ObjCInterfaceDecl *D,
+ const api_notes::ObjCContextInfo &info,
+ VersionedInfoMetadata metadata) {
+ // Handle information common to Objective-C classes and protocols.
+ ProcessAPINotes(S, static_cast<clang::ObjCContainerDecl *>(D), info,
+ metadata);
+}
+
+/// Processes all versions of versioned API notes.
+///
+/// Just dispatches to the various ProcessAPINotes functions in this file.
+template <typename SpecificDecl, typename SpecificInfo>
+static void ProcessVersionedAPINotes(
+ Sema &S, SpecificDecl *D,
+ const api_notes::APINotesReader::VersionedInfo<SpecificInfo> Info) {
+ unsigned Selected = Info.getSelected().getValueOr(Info.size());
+
+ VersionTuple Version;
+ SpecificInfo InfoSlice;
+ for (unsigned i = 0, e = Info.size(); i != e; ++i) {
+ std::tie(Version, InfoSlice) = Info[i];
+ if (i != Selected) {
+ ProcessAPINotes(S, D, InfoSlice, Version);
+ } else {
+ ProcessAPINotes(S, D, InfoSlice, Info.getSelectedRole());
+ }
+ }
+}
+
+/// Process API notes that are associated with this declaration, mapping them
+/// to attributes as appropriate.
+void Sema::ProcessAPINotes(Decl *D) {
+ if (!D)
+ return;
+
+ // Globals.
+ if (D->getDeclContext()->isFileContext()) {
+ // Global variables.
+ if (auto VD = dyn_cast<VarDecl>(D)) {
+ for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
+ auto Info = Reader->lookupGlobalVariable(VD->getName());
+ ProcessVersionedAPINotes(*this, VD, Info);
+ }
+
+ return;
+ }
+
+ // Global functions.
+ if (auto FD = dyn_cast<FunctionDecl>(D)) {
+ if (FD->getDeclName().isIdentifier()) {
+ for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
+ auto Info = Reader->lookupGlobalFunction(FD->getName());
+ ProcessVersionedAPINotes(*this, FD, Info);
+ }
+ }
+
+ return;
+ }
+
+ // Objective-C classes.
+ if (auto Class = dyn_cast<ObjCInterfaceDecl>(D)) {
+ for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
+ auto Info = Reader->lookupObjCClassInfo(Class->getName());
+ ProcessVersionedAPINotes(*this, Class, Info);
+ }
+
+ return;
+ }
+
+ // Objective-C protocols.
+ if (auto Protocol = dyn_cast<ObjCProtocolDecl>(D)) {
+ for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
+ auto Info = Reader->lookupObjCProtocolInfo(Protocol->getName());
+ ProcessVersionedAPINotes(*this, Protocol, Info);
+ }
+
+ return;
+ }
+
+ // Tags
+ if (auto Tag = dyn_cast<TagDecl>(D)) {
+ for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
+ auto Info = Reader->lookupTag(Tag->getName());
+ ProcessVersionedAPINotes(*this, Tag, Info);
+ }
+
+ return;
+ }
+
+ // Typedefs
+ if (auto Typedef = dyn_cast<TypedefNameDecl>(D)) {
+ for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
+ auto Info = Reader->lookupTypedef(Typedef->getName());
+ ProcessVersionedAPINotes(*this, Typedef, Info);
+ }
+
+ return;
+ }
+
+ return;
+ }
+
+ // Enumerators.
+ if (D->getDeclContext()->getRedeclContext()->isFileContext()) {
+ if (auto EnumConstant = dyn_cast<EnumConstantDecl>(D)) {
+ for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
+ auto Info = Reader->lookupEnumConstant(EnumConstant->getName());
+ ProcessVersionedAPINotes(*this, EnumConstant, Info);
+ }
+
+ return;
+ }
+ }
+
+ if (auto ObjCContainer = dyn_cast<ObjCContainerDecl>(D->getDeclContext())) {
+ // Location function that looks up an Objective-C context.
+ auto GetContext = [&](api_notes::APINotesReader *Reader)
+ -> Optional<api_notes::ContextID> {
+ if (auto Protocol = dyn_cast<ObjCProtocolDecl>(ObjCContainer)) {
+ if (auto Found = Reader->lookupObjCProtocolID(Protocol->getName()))
+ return *Found;
+
+ return None;
+ }
+
+ if (auto Impl = dyn_cast<ObjCCategoryImplDecl>(ObjCContainer)) {
+ if (auto Cat = Impl->getCategoryDecl())
+ ObjCContainer = Cat;
+ else
+ return None;
+ }
+
+ if (auto Category = dyn_cast<ObjCCategoryDecl>(ObjCContainer)) {
+ if (Category->getClassInterface())
+ ObjCContainer = Category->getClassInterface();
+ else
+ return None;
+ }
+
+ if (auto Impl = dyn_cast<ObjCImplDecl>(ObjCContainer)) {
+ if (Impl->getClassInterface())
+ ObjCContainer = Impl->getClassInterface();
+ else
+ return None;
+ }
+
+ if (auto Class = dyn_cast<ObjCInterfaceDecl>(ObjCContainer)) {
+ if (auto Found = Reader->lookupObjCClassID(Class->getName()))
+ return *Found;
+
+ return None;
+
+ }
+
+ return None;
+ };
+
+ // Objective-C methods.
+ if (auto Method = dyn_cast<ObjCMethodDecl>(D)) {
+ for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
+ if (auto Context = GetContext(Reader)) {
+ // Map the selector.
+ Selector Sel = Method->getSelector();
+ SmallVector<StringRef, 2> SelPieces;
+ if (Sel.isUnarySelector())
+ SelPieces.push_back(Sel.getNameForSlot(0));
+ else {
+ for (unsigned i = 0, n = Sel.getNumArgs(); i != n; ++i)
+ SelPieces.push_back(Sel.getNameForSlot(i));
+ }
+
+ api_notes::ObjCSelectorRef SelectorRef;
+ SelectorRef.NumPieces = Sel.getNumArgs();
+ SelectorRef.Identifiers = SelPieces;
+
+ auto Info = Reader->lookupObjCMethod(*Context, SelectorRef,
+ Method->isInstanceMethod());
+ ProcessVersionedAPINotes(*this, Method, Info);
+ }
+ }
+ }
+
+ // Objective-C properties.
+ if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) {
+ for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
+ if (auto Context = GetContext(Reader)) {
+ bool isInstanceProperty =
+ (Property->getPropertyAttributesAsWritten() &
+ ObjCPropertyDecl::OBJC_PR_class) == 0;
+ auto Info = Reader->lookupObjCProperty(*Context, Property->getName(),
+ isInstanceProperty);
+ ProcessVersionedAPINotes(*this, Property, Info);
+ }
+ }
+
+ return;
+ }
+
+ return;
+ }
+}
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 3aedb2a..2565f0c 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -4623,20 +4623,6 @@
return SLCT_NotALiteral;
}
- case Stmt::ObjCMessageExprClass: {
- const auto *ME = cast<ObjCMessageExpr>(E);
- if (const auto *ND = ME->getMethodDecl()) {
- if (const auto *FA = ND->getAttr<FormatArgAttr>()) {
- unsigned ArgIndex = FA->getFormatIdx();
- const Expr *Arg = ME->getArg(ArgIndex - 1);
- return checkFormatStringExpr(
- S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type,
- CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset);
- }
- }
-
- return SLCT_NotALiteral;
- }
case Stmt::ObjCStringLiteralClass:
case Stmt::StringLiteralClass: {
const StringLiteral *StrE = nullptr;
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index 94cfc4b..85343cd 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -5230,24 +5230,22 @@
/// when it has the same number of parameters as we have selector identifiers.
///
/// \param Results the structure into which we'll add results.
-static void AddObjCMethods(ObjCContainerDecl *Container,
- bool WantInstanceMethods,
- ObjCMethodKind WantKind,
+static void AddObjCMethods(ObjCContainerDecl *Container,
+ bool WantInstanceMethods, ObjCMethodKind WantKind,
ArrayRef<IdentifierInfo *> SelIdents,
DeclContext *CurContext,
- VisitedSelectorSet &Selectors,
- bool AllowSameLength,
- ResultBuilder &Results,
- bool InOriginalClass = true) {
+ VisitedSelectorSet &Selectors, bool AllowSameLength,
+ ResultBuilder &Results, bool InOriginalClass = true,
+ bool IsRootClass = false) {
typedef CodeCompletionResult Result;
Container = getContainerDef(Container);
ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container);
- bool isRootClass = IFace && !IFace->getSuperClass();
+ IsRootClass = IsRootClass || (IFace && !IFace->getSuperClass());
for (auto *M : Container->methods()) {
// The instance methods on the root class can be messaged via the
// metaclass.
if (M->isInstanceMethod() == WantInstanceMethods ||
- (isRootClass && !WantInstanceMethods)) {
+ (IsRootClass && !WantInstanceMethods)) {
// Check whether the selector identifiers we've been given are a
// subset of the identifiers for this particular method.
if (!isAcceptableObjCMethod(M, WantKind, SelIdents, AllowSameLength))
@@ -5273,8 +5271,8 @@
for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
E = Protocols.end();
I != E; ++I)
- AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents,
- CurContext, Selectors, AllowSameLength, Results, false);
+ AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents, CurContext,
+ Selectors, AllowSameLength, Results, false, IsRootClass);
}
}
@@ -5283,43 +5281,43 @@
// Add methods in protocols.
for (auto *I : IFace->protocols())
- AddObjCMethods(I, WantInstanceMethods, WantKind, SelIdents,
- CurContext, Selectors, AllowSameLength, Results, false);
-
+ AddObjCMethods(I, WantInstanceMethods, WantKind, SelIdents, CurContext,
+ Selectors, AllowSameLength, Results, false, IsRootClass);
+
// Add methods in categories.
for (auto *CatDecl : IFace->known_categories()) {
AddObjCMethods(CatDecl, WantInstanceMethods, WantKind, SelIdents,
- CurContext, Selectors, AllowSameLength,
- Results, InOriginalClass);
-
+ CurContext, Selectors, AllowSameLength, Results,
+ InOriginalClass, IsRootClass);
+
// Add a categories protocol methods.
const ObjCList<ObjCProtocolDecl> &Protocols
= CatDecl->getReferencedProtocols();
for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
E = Protocols.end();
I != E; ++I)
- AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents,
- CurContext, Selectors, AllowSameLength,
- Results, false);
-
+ AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents, CurContext,
+ Selectors, AllowSameLength, Results, false, IsRootClass);
+
// Add methods in category implementations.
if (ObjCCategoryImplDecl *Impl = CatDecl->getImplementation())
- AddObjCMethods(Impl, WantInstanceMethods, WantKind, SelIdents,
- CurContext, Selectors, AllowSameLength,
- Results, InOriginalClass);
+ AddObjCMethods(Impl, WantInstanceMethods, WantKind, SelIdents, CurContext,
+ Selectors, AllowSameLength, Results, InOriginalClass,
+ IsRootClass);
}
// Add methods in superclass.
+ // Avoid passing in IsRootClass since root classes won't have super classes.
if (IFace->getSuperClass())
- AddObjCMethods(IFace->getSuperClass(), WantInstanceMethods, WantKind,
- SelIdents, CurContext, Selectors,
- AllowSameLength, Results, false);
+ AddObjCMethods(IFace->getSuperClass(), WantInstanceMethods, WantKind,
+ SelIdents, CurContext, Selectors, AllowSameLength, Results,
+ /*IsRootClass=*/false);
// Add methods in our implementation, if any.
if (ObjCImplementationDecl *Impl = IFace->getImplementation())
- AddObjCMethods(Impl, WantInstanceMethods, WantKind, SelIdents,
- CurContext, Selectors, AllowSameLength,
- Results, InOriginalClass);
+ AddObjCMethods(Impl, WantInstanceMethods, WantKind, SelIdents, CurContext,
+ Selectors, AllowSameLength, Results, InOriginalClass,
+ IsRootClass);
}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index adcf2ee..eff3aeb 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2307,6 +2307,10 @@
NewAttr = S.mergeMinSizeAttr(D, MA->getRange(), AttrSpellingListIndex);
else if (const auto *OA = dyn_cast<OptimizeNoneAttr>(Attr))
NewAttr = S.mergeOptimizeNoneAttr(D, OA->getRange(), AttrSpellingListIndex);
+ else if (const auto *SNA = dyn_cast<SwiftNameAttr>(Attr))
+ NewAttr = S.mergeSwiftNameAttr(D, SNA->getRange(), SNA->getName(),
+ AMK == Sema::AMK_Override,
+ AttrSpellingListIndex);
else if (const auto *InternalLinkageA = dyn_cast<InternalLinkageAttr>(Attr))
NewAttr = S.mergeInternalLinkageAttr(
D, InternalLinkageA->getRange(),
@@ -2324,6 +2328,8 @@
(AMK == Sema::AMK_Override ||
AMK == Sema::AMK_ProtocolImplementation))
NewAttr = nullptr;
+ else if (isa<SwiftPrivateAttr>(Attr) && AMK == Sema::AMK_Override)
+ NewAttr = nullptr;
else if (const auto *UA = dyn_cast<UuidAttr>(Attr))
NewAttr = S.mergeUuidAttr(D, UA->getRange(), AttrSpellingListIndex,
UA->getGuid());
@@ -11370,10 +11376,8 @@
}
}
-ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
- SourceLocation NameLoc, IdentifierInfo *Name,
- QualType T, TypeSourceInfo *TSInfo,
- StorageClass SC) {
+QualType Sema::adjustParameterTypeForObjCAutoRefCount(QualType T,
+ SourceLocation Loc) {
// In ARC, infer a lifetime qualifier for appropriate parameter types.
if (getLangOpts().ObjCAutoRefCount &&
T.getObjCLifetime() == Qualifiers::OCL_None &&
@@ -11388,7 +11392,7 @@
if (!T.isConstQualified()) {
DelayedDiagnostics.add(
sema::DelayedDiagnostic::makeForbiddenType(
- NameLoc, diag::err_arc_array_param_no_ownership, T, false));
+ Loc, diag::err_arc_array_param_no_ownership, T, false));
}
lifetime = Qualifiers::OCL_ExplicitNone;
} else {
@@ -11397,6 +11401,16 @@
T = Context.getLifetimeQualifiedType(T, lifetime);
}
+ return T;
+}
+
+ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation NameLoc, IdentifierInfo *Name,
+ QualType T, TypeSourceInfo *TSInfo,
+ StorageClass SC) {
+ // Perform Objective-C ARC adjustments.
+ T = adjustParameterTypeForObjCAutoRefCount(T, NameLoc);
+
ParmVarDecl *New = ParmVarDecl::Create(Context, DC, StartLoc, NameLoc, Name,
Context.getAdjustedParameterType(T),
TSInfo, SC, nullptr);
@@ -12149,7 +12163,9 @@
// Always attach attributes to the underlying decl.
if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D))
D = TD->getTemplatedDecl();
- ProcessDeclAttributeList(S, D, Attrs.getList());
+
+ ProcessDeclAttributeList(S, D, Attrs.getList());
+ ProcessAPINotes(D);
if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(D))
if (Method->isStatic())
@@ -13491,6 +13507,7 @@
if (Attr)
ProcessDeclAttributeList(S, New, Attr);
+ ProcessAPINotes(New);
// Set the lexical context. If the tag has a C++ scope specifier, the
// lexical context will be different from the semantic context.
@@ -14721,6 +14738,7 @@
if (Attr)
ProcessDeclAttributeList(S, Record, Attr);
+ ProcessAPINotes(Record);
}
/// \brief Determine whether the given integral value is representable within
@@ -15020,6 +15038,8 @@
// Process attributes.
if (Attr) ProcessDeclAttributeList(S, New, Attr);
+ ProcessAPINotes(New);
+
// Register this decl in the current scope stack.
New->setAccess(TheEnumDecl->getAccess());
PushOnScopeChains(New, S);
@@ -15243,6 +15263,7 @@
if (Attr)
ProcessDeclAttributeList(S, Enum, Attr);
+ ProcessAPINotes(Enum);
if (Enum->isDependentType()) {
for (unsigned i = 0, e = Elements.size(); i != e; ++i) {
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index c6a5bc7..fba9aea 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -1476,6 +1476,26 @@
Attr.getAttributeSpellingListIndex()));
}
+static void handleNoEscapeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ ParmVarDecl *PD = dyn_cast<ParmVarDecl>(D);
+ if (!PD)
+ return;
+
+ // noescape only applies to pointer types.
+ QualType T = PD->getType();
+ if (!T->isAnyPointerType() && !T->isBlockPointerType() &&
+ !T->isReferenceType() && !T->isArrayType() &&
+ !T->isMemberPointerType()) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_noescape_non_pointer)
+ << T;
+ return;
+ }
+
+ D->addAttr(::new (S.Context) NoEscapeAttr(
+ Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
+}
+
static void handleAssumeAlignedAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
Expr *E = Attr.getArgAsExpr(0),
@@ -2322,6 +2342,15 @@
dyn_cast_or_null<StringLiteral>(Attr.getReplacementExpr()))
Replacement = SE->getString();
+ if (II->getName() == "swift") {
+ if (Introduced.isValid() || Obsoleted.isValid() ||
+ (!IsUnavailable && !Deprecated.isValid())) {
+ S.Diag(Attr.getLoc(),
+ diag::warn_availability_swift_unavailable_deprecated_only);
+ return;
+ }
+ }
+
AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, Attr.getRange(), II,
false/*Implicit*/,
Introduced.Version,
@@ -3845,6 +3874,27 @@
AttrSpellingListIndex);
}
+SwiftNameAttr *Sema::mergeSwiftNameAttr(Decl *D, SourceRange Range,
+ StringRef Name, bool Override,
+ unsigned AttrSpellingListIndex) {
+ if (SwiftNameAttr *Inline = D->getAttr<SwiftNameAttr>()) {
+ if (Override) {
+ // FIXME: Warn about an incompatible override.
+ return nullptr;
+ }
+
+ if (Inline->getName() != Name && !Inline->isImplicit()) {
+ Diag(Inline->getLocation(), diag::warn_attribute_ignored) << Inline;
+ Diag(Range.getBegin(), diag::note_conflicting_attribute);
+ }
+
+ D->dropAttr<SwiftNameAttr>();
+ }
+
+ return ::new (Context) SwiftNameAttr(Range, Context, Name,
+ AttrSpellingListIndex);
+}
+
static void handleAlwaysInlineAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
if (checkAttrMutualExclusion<NotTailCalledAttr>(S, D, Attr.getRange(),
@@ -4622,6 +4672,40 @@
attr.getAttributeSpellingListIndex()));
}
+static void handleNSErrorDomain(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (!isa<TagDecl>(D)) {
+ S.Diag(D->getLocStart(), diag::err_nserrordomain_not_tagdecl)
+ << S.getLangOpts().CPlusPlus;
+ return;
+ }
+ IdentifierLoc *identLoc =
+ Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : nullptr;
+ if (!identLoc || !identLoc->Ident) {
+ // Try to locate the argument directly
+ SourceLocation loc = Attr.getLoc();
+ if (Attr.isArgExpr(0) && Attr.getArgAsExpr(0))
+ loc = Attr.getArgAsExpr(0)->getLocStart();
+
+ S.Diag(loc, diag::err_nserrordomain_requires_identifier);
+ return;
+ }
+
+ // Verify that the identifier is a valid decl in the C decl namespace
+ LookupResult lookupResult(S, DeclarationName(identLoc->Ident),
+ SourceLocation(),
+ Sema::LookupNameKind::LookupOrdinaryName);
+ if (!S.LookupName(lookupResult, S.TUScope) ||
+ !lookupResult.getAsSingle<VarDecl>()) {
+ S.Diag(identLoc->Loc, diag::err_nserrordomain_invalid_decl)
+ << identLoc->Ident;
+ return;
+ }
+
+ D->addAttr(::new (S.Context)
+ NSErrorDomainAttr(Attr.getRange(), S.Context, identLoc->Ident,
+ Attr.getAttributeSpellingListIndex()));
+}
+
static void handleCFAuditedTransferAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
if (checkAttrMutualExclusion<CFUnknownTransferAttr>(S, D, Attr.getRange(),
@@ -4811,6 +4895,421 @@
Attr.getAttributeSpellingListIndex()));
}
+static Optional<unsigned>
+validateSwiftFunctionName(StringRef Name,
+ unsigned &SwiftParamCount,
+ bool &IsSingleParamInit) {
+ SwiftParamCount = 0;
+
+ // Check whether this will be mapped to a getter or setter of a
+ // property.
+ bool isGetter = false;
+ bool isSetter = false;
+ if (Name.startswith("getter:")) {
+ isGetter = true;
+ Name = Name.substr(7);
+ } else if (Name.startswith("setter:")) {
+ isSetter = true;
+ Name = Name.substr(7);
+ }
+
+ if (Name.back() != ')')
+ return diag::warn_attr_swift_name_function;
+
+ StringRef BaseName, Parameters;
+ std::tie(BaseName, Parameters) = Name.split('(');
+
+ // Split at the first '.', if it exists, which separates the context
+ // name from the base name.
+ StringRef ContextName;
+ bool IsMember = false;
+ std::tie(ContextName, BaseName) = BaseName.split('.');
+ if (BaseName.empty()) {
+ BaseName = ContextName;
+ ContextName = StringRef();
+ } else if (ContextName.empty() || !isValidIdentifier(ContextName)) {
+ return diag::warn_attr_swift_name_context_name_invalid_identifier;
+ } else {
+ IsMember = true;
+ }
+
+ if (!isValidIdentifier(BaseName) || BaseName == "_")
+ return diag::warn_attr_swift_name_basename_invalid_identifier;
+
+ bool IsSubscript = BaseName == "subscript";
+ // A subscript accessor must be a getter or setter.
+ if (IsSubscript && !isGetter && !isSetter)
+ return diag::warn_attr_swift_name_subscript_not_accessor;
+
+ if (Parameters.empty())
+ return diag::warn_attr_swift_name_missing_parameters;
+ Parameters = Parameters.drop_back(); // ')'
+
+ if (Parameters.empty()) {
+ // Setters and subscripts must have at least one parameter.
+ if (IsSubscript)
+ return diag::warn_attr_swift_name_subscript_no_parameter;
+ if (isSetter)
+ return diag::warn_attr_swift_name_setter_parameters;
+
+ return None;
+ }
+
+ if (Parameters.back() != ':')
+ return diag::warn_attr_swift_name_function;
+
+ Optional<unsigned> SelfLocation;
+ Optional<unsigned> NewValueLocation;
+ unsigned NewValueCount = 0;
+ StringRef NextParam;
+ do {
+ std::tie(NextParam, Parameters) = Parameters.split(':');
+
+ if (!isValidIdentifier(NextParam))
+ return diag::warn_attr_swift_name_parameter_invalid_identifier;
+
+ // "self" indicates the "self" argument for a member.
+ if (IsMember && NextParam == "self") {
+ // More than one "self"?
+ if (SelfLocation) return diag::warn_attr_swift_name_multiple_selfs;
+
+ // The "self" location is the current parameter.
+ SelfLocation = SwiftParamCount;
+ }
+
+ // "newValue" indicates the "newValue" argument for a setter.
+ if (NextParam == "newValue") {
+ // There should only be one 'newValue', but it's only significant for
+ // subscript accessors, so don't error right away.
+ ++NewValueCount;
+
+ NewValueLocation = SwiftParamCount;
+ }
+ ++SwiftParamCount;
+ } while (!Parameters.empty());
+
+ // Only instance subscripts are currently supported.
+ if (IsSubscript && !SelfLocation)
+ return diag::warn_attr_swift_name_static_subscript;
+
+ IsSingleParamInit =
+ (SwiftParamCount == 1 && BaseName == "init" && NextParam != "_");
+
+ // Check the number of parameters for a getter/setter.
+ if (isGetter || isSetter) {
+ // Setters have one parameter for the new value.
+ unsigned NumExpectedParams;
+ unsigned ParamDiag;
+
+ if (isSetter) {
+ NumExpectedParams = 1;
+ ParamDiag = diag::warn_attr_swift_name_setter_parameters;
+ } else {
+ NumExpectedParams = 0;
+ ParamDiag = diag::warn_attr_swift_name_getter_parameters;
+ }
+
+ // Instance methods have one parameter for "self".
+ if (SelfLocation) ++NumExpectedParams;
+
+ // Subscripts may have additional parameters beyond the expected params for
+ // the index.
+ if (IsSubscript) {
+ if (SwiftParamCount < NumExpectedParams)
+ return ParamDiag;
+ // A subscript setter must explicitly label its newValue parameter to
+ // distinguish it from index parameters.
+ if (isSetter) {
+ if (!NewValueLocation)
+ return diag::warn_attr_swift_name_subscript_setter_no_newValue;
+ // There can only be one.
+ if (NewValueCount > 1)
+ return diag::warn_attr_swift_name_subscript_setter_multiple_newValues;
+ } else {
+ // Subscript getters should have no 'newValue:' parameter.
+ if (NewValueLocation)
+ return diag::warn_attr_swift_name_subscript_getter_newValue;
+ }
+ } else {
+ // Property accessors must have exactly the number of expected params.
+ if (SwiftParamCount != NumExpectedParams)
+ return ParamDiag;
+ }
+ }
+
+ return None;
+}
+
+/// Do a check to make sure \p Name looks like a legal swift_name
+/// attribute for the decl \p D. Raise a diagnostic if the name is invalid
+/// for the given declaration.
+///
+/// For a function, this will validate a compound Swift name,
+/// e.g. <code>init(foo:bar:baz:)</code> or <code>controllerForName(_:)</code>,
+/// and the function will output the number of parameter names, and whether this
+/// is a single-arg initializer.
+///
+/// For a type, enum constant, property, or variable declaration, this will
+/// validate either a simple identifier, or a qualified
+/// <code>context.identifier</code> name.
+///
+/// \returns true if the name is a valid swift name for \p D, false otherwise.
+bool Sema::DiagnoseSwiftName(Decl *D, StringRef Name,
+ SourceLocation ArgLoc,
+ IdentifierInfo *AttrName) {
+ if (isa<ObjCMethodDecl>(D) || isa<FunctionDecl>(D)) {
+ ArrayRef<ParmVarDecl*> Params;
+ unsigned ParamCount;
+
+ if (const auto *Method = dyn_cast<ObjCMethodDecl>(D)) {
+ ParamCount = Method->getSelector().getNumArgs();
+ Params = Method->parameters().slice(0, ParamCount);
+ } else {
+ const auto *Function = cast<FunctionDecl>(D);
+ ParamCount = Function->getNumParams();
+ Params = Function->parameters();
+
+ if (!Function->hasWrittenPrototype()) {
+ Diag(ArgLoc, diag::warn_attr_swift_name_function_no_prototype)
+ << AttrName;
+ return false;
+ }
+ }
+
+ unsigned SwiftParamCount;
+ bool IsSingleParamInit;
+ if (auto diagID = validateSwiftFunctionName(Name, SwiftParamCount,
+ IsSingleParamInit)) {
+ Diag(ArgLoc, *diagID) << AttrName;
+ return false;
+ }
+
+ bool ParamsOK;
+ if (SwiftParamCount == ParamCount) {
+ ParamsOK = true;
+ } else if (SwiftParamCount > ParamCount) {
+ ParamsOK = IsSingleParamInit && ParamCount == 0;
+ } else {
+ // We have fewer Swift parameters than Objective-C parameters, but that
+ // might be because we've transformed some of them. Check for potential
+ // "out" parameters and err on the side of not warning.
+ unsigned MaybeOutParamCount =
+ std::count_if(Params.begin(), Params.end(),
+ [](const ParmVarDecl *Param) -> bool {
+ QualType ParamTy = Param->getType();
+ if (ParamTy->isReferenceType() || ParamTy->isPointerType())
+ return !ParamTy->getPointeeType().isConstQualified();
+ return false;
+ });
+ ParamsOK = (SwiftParamCount + MaybeOutParamCount >= ParamCount);
+ }
+
+ if (!ParamsOK) {
+ Diag(ArgLoc, diag::warn_attr_swift_name_num_params)
+ << (SwiftParamCount > ParamCount) << AttrName
+ << ParamCount << SwiftParamCount;
+ return false;
+ }
+
+ } else if (isa<EnumConstantDecl>(D) || isa<ObjCProtocolDecl>(D) ||
+ isa<ObjCInterfaceDecl>(D) || isa<ObjCPropertyDecl>(D) ||
+ isa<VarDecl>(D) || isa<TypedefNameDecl>(D) || isa<TagDecl>(D) ||
+ isa<IndirectFieldDecl>(D) || isa<FieldDecl>(D)) {
+ StringRef ContextName, BaseName;
+ std::tie(ContextName, BaseName) = Name.split('.');
+ if (BaseName.empty()) {
+ BaseName = ContextName;
+ ContextName = StringRef();
+ } else if (!isValidIdentifier(ContextName)) {
+ Diag(ArgLoc, diag::warn_attr_swift_name_context_name_invalid_identifier)
+ << AttrName;
+ return false;
+ }
+
+ if (!isValidIdentifier(BaseName)) {
+ Diag(ArgLoc, diag::warn_attr_swift_name_basename_invalid_identifier)
+ << AttrName;
+ return false;
+ }
+
+ } else {
+ Diag(ArgLoc, diag::warn_attr_swift_name_decl_kind) << AttrName;
+ return false;
+ }
+ return true;
+}
+
+static void handleSwiftName(Sema &S, Decl *D, const AttributeList &Attr) {
+ StringRef Name;
+ SourceLocation ArgLoc;
+ if (!S.checkStringLiteralArgumentAttr(Attr, 0, Name, &ArgLoc))
+ return;
+
+ if (!S.DiagnoseSwiftName(D, Name, ArgLoc, Attr.getName()))
+ return;
+
+ D->addAttr(::new (S.Context) SwiftNameAttr(Attr.getRange(), S.Context, Name,
+ Attr.getAttributeSpellingListIndex()));
+}
+
+static bool isErrorParameter(Sema &S, QualType paramType) {
+ if (auto ptr = paramType->getAs<PointerType>()) {
+ auto outerPointee = ptr->getPointeeType();
+
+ // NSError**.
+ if (auto objcPtr = outerPointee->getAs<ObjCObjectPointerType>()) {
+ if (auto iface = objcPtr->getInterfaceDecl())
+ if (iface->getIdentifier() == S.getNSErrorIdent())
+ return true;
+ }
+
+ // CFErrorRef*.
+ if (auto cPtr = outerPointee->getAs<PointerType>()) {
+ auto innerPointee = cPtr->getPointeeType();
+ if (auto recordType = innerPointee->getAs<RecordType>()) {
+ if (S.isCFError(recordType->getDecl()))
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static void handleSwiftError(Sema &S, Decl *D, const AttributeList &attr) {
+ SwiftErrorAttr::ConventionKind convention;
+ IdentifierLoc *conventionLoc = attr.getArgAsIdent(0);
+ StringRef conventionStr = conventionLoc->Ident->getName();
+ if (!SwiftErrorAttr::ConvertStrToConventionKind(conventionStr, convention)) {
+ S.Diag(attr.getLoc(), diag::warn_attribute_type_not_supported)
+ << attr.getName() << conventionLoc->Ident;
+ return;
+ }
+
+ auto requireErrorParameter = [&]() -> bool {
+ if (D->isInvalidDecl()) return true;
+
+ for (unsigned i = 0, e = getFunctionOrMethodNumParams(D); i != e; ++i) {
+ if (isErrorParameter(S, getFunctionOrMethodParamType(D, i)))
+ return true;
+ }
+
+ S.Diag(attr.getLoc(), diag::err_attr_swift_error_no_error_parameter)
+ << attr.getName() << isa<ObjCMethodDecl>(D);
+ return false;
+ };
+
+ auto requirePointerResult = [&] {
+ if (D->isInvalidDecl()) return true;
+
+ // C, ObjC, and block pointers are definitely okay.
+ // References are definitely not okay.
+ // nullptr_t is weird but acceptable.
+ QualType returnType = getFunctionOrMethodResultType(D);
+ if (returnType->hasPointerRepresentation() &&
+ !returnType->isReferenceType()) return true;
+
+ S.Diag(attr.getLoc(), diag::err_attr_swift_error_return_type)
+ << attr.getName() << conventionStr
+ << isa<ObjCMethodDecl>(D) << /*pointer*/ 1;
+ return false;
+ };
+
+ auto requireIntegerResult = [&] {
+ if (D->isInvalidDecl()) return true;
+
+ QualType returnType = getFunctionOrMethodResultType(D);
+ if (returnType->isIntegralType(S.Context)) return true;
+
+ S.Diag(attr.getLoc(), diag::err_attr_swift_error_return_type)
+ << attr.getName() << conventionStr
+ << isa<ObjCMethodDecl>(D) << /*integral*/ 0;
+ return false;
+ };
+
+ switch (convention) {
+ case SwiftErrorAttr::None:
+ // No additional validation required.
+ break;
+
+ case SwiftErrorAttr::NonNullError:
+ if (!requireErrorParameter()) return;
+ break;
+
+ case SwiftErrorAttr::NullResult:
+ if (!requireErrorParameter()) return;
+ if (!requirePointerResult()) return;
+ break;
+
+ case SwiftErrorAttr::NonZeroResult:
+ case SwiftErrorAttr::ZeroResult:
+ if (!requireErrorParameter()) return;
+ if (!requireIntegerResult()) return;
+ break;
+ }
+
+ D->addAttr(::new (S.Context)
+ SwiftErrorAttr(attr.getRange(), S.Context, convention,
+ attr.getAttributeSpellingListIndex()));
+}
+
+static void handleSwiftBridgeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ // Make sure that there is a string literal as the annotation's single
+ // argument.
+ StringRef Str;
+ if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str))
+ return;
+
+ // Don't duplicate annotations that are already set.
+ if (D->hasAttr<SwiftBridgeAttr>()) {
+ S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) << Attr.getName();
+ return;
+ }
+
+ D->addAttr(::new (S.Context)
+ SwiftBridgeAttr(Attr.getRange(), S.Context, Str,
+ Attr.getAttributeSpellingListIndex()));
+}
+
+static void handleSwiftNewtypeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ // Make sure that there is an identifier as the annotation's single
+ // argument.
+ if (Attr.getNumArgs() != 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
+ << Attr.getName() << 1;
+ Attr.setInvalid();
+ return;
+ }
+ if (!Attr.isArgIdent(0)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_type)
+ << Attr.getName() << AANT_ArgumentIdentifier;
+ Attr.setInvalid();
+ return;
+ }
+
+ IdentifierInfo *II = Attr.getArgAsIdent(0)->Ident;
+ SwiftNewtypeAttr::NewtypeKind Kind;
+ if (II->isStr("struct"))
+ Kind = SwiftNewtypeAttr::NK_Struct;
+ else if (II->isStr("enum"))
+ Kind = SwiftNewtypeAttr::NK_Enum;
+ else {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported)
+ << Attr.getName() << II;
+ Attr.setInvalid();
+ return;
+ }
+
+ if (!isa<TypedefNameDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_swift_newtype_attribute_non_typedef);
+ return;
+ }
+
+ D->addAttr(::new (S.Context)
+ SwiftNewtypeAttr(Attr.getRange(), S.Context, Kind,
+ Attr.getAttributeSpellingListIndex()));
+}
+
//===----------------------------------------------------------------------===//
// Microsoft specific attribute handlers.
//===----------------------------------------------------------------------===//
@@ -5834,6 +6333,9 @@
case AttributeList::AT_ReturnsNonNull:
handleReturnsNonNullAttr(S, D, Attr);
break;
+ case AttributeList::AT_NoEscape:
+ handleNoEscapeAttr(S, D, Attr);
+ break;
case AttributeList::AT_AssumeAligned:
handleAssumeAlignedAttr(S, D, Attr);
break;
@@ -5897,6 +6399,9 @@
case AttributeList::AT_ObjCBoxable:
handleObjCBoxable(S, D, Attr);
break;
+ case AttributeList::AT_NSErrorDomain:
+ handleNSErrorDomain(S, D, Attr);
+ break;
case AttributeList::AT_CFAuditedTransfer:
handleCFAuditedTransferAttr(S, D, Attr);
break;
@@ -5953,6 +6458,9 @@
case AttributeList::AT_ObjCSubclassingRestricted:
handleSimpleAttribute<ObjCSubclassingRestrictedAttr>(S, D, Attr);
break;
+ case AttributeList::AT_ObjCCompleteDefinition:
+ handleSimpleAttribute<ObjCCompleteDefinitionAttr>(S, D, Attr);
+ break;
case AttributeList::AT_ObjCExplicitProtocolImpl:
handleObjCSuppresProtocolAttr(S, D, Attr);
break;
@@ -6219,6 +6727,22 @@
case AttributeList::AT_RenderScriptKernel:
handleSimpleAttribute<RenderScriptKernelAttr>(S, D, Attr);
break;
+ // Swift attributes.
+ case AttributeList::AT_SwiftPrivate:
+ handleSimpleAttribute<SwiftPrivateAttr>(S, D, Attr);
+ break;
+ case AttributeList::AT_SwiftName:
+ handleSwiftName(S, D, Attr);
+ break;
+ case AttributeList::AT_SwiftError:
+ handleSwiftError(S, D, Attr);
+ break;
+ case AttributeList::AT_SwiftBridge:
+ handleSwiftBridgeAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_SwiftNewtype:
+ handleSwiftNewtypeAttr(S, D, Attr);
+ break;
// XRay attributes.
case AttributeList::AT_XRayInstrument:
handleSimpleAttribute<XRayInstrumentAttr>(S, D, Attr);
@@ -6443,6 +6967,9 @@
// Finally, apply any attributes on the decl itself.
if (const AttributeList *Attrs = PD.getAttributes())
ProcessDeclAttributeList(S, D, Attrs);
+
+ // Look for API notes that map to attributes.
+ ProcessAPINotes(D);
}
/// Is the given declaration allowed to use a forbidden type?
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index f265f4c..b1bec1c 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -8161,6 +8161,7 @@
Namespc->setInvalidDecl();
ProcessDeclAttributeList(DeclRegionScope, Namespc, AttrList);
+ ProcessAPINotes(Namespc);
// FIXME: Should we be merging attributes?
if (const VisibilityAttr *Attr = Namespc->getAttr<VisibilityAttr>())
@@ -8550,6 +8551,7 @@
if (UDir)
ProcessDeclAttributeList(S, UDir, AttrList);
+ ProcessAPINotes(UDir);
return UDir;
}
@@ -9641,6 +9643,7 @@
NewTD->setInvalidDecl();
ProcessDeclAttributeList(S, NewTD, AttrList);
+ ProcessAPINotes(NewTD);
CheckTypedefForVariablyModifiedType(S, NewTD);
Invalid |= NewTD->isInvalidDecl();
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index b43e5b9..8885b09 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -980,6 +980,10 @@
ObjCInterfaceDecl *IDecl
= ObjCInterfaceDecl::Create(Context, CurContext, AtInterfaceLoc, ClassName,
typeParamList, PrevIDecl, ClassLoc);
+ if (AttrList)
+ ProcessDeclAttributeList(TUScope, IDecl, AttrList);
+ ProcessAPINotes(IDecl);
+
if (PrevIDecl) {
// Class already seen. Was it a definition?
if (ObjCInterfaceDecl *Def = PrevIDecl->getDefinition()) {
@@ -990,8 +994,6 @@
}
}
- if (AttrList)
- ProcessDeclAttributeList(TUScope, IDecl, AttrList);
PushOnScopeChains(IDecl, TUScope);
// Start the definition of this class. If we're in a redefinition case, there
@@ -1175,6 +1177,7 @@
if (AttrList)
ProcessDeclAttributeList(TUScope, PDecl, AttrList);
+ ProcessAPINotes(PDecl);
// Merge attributes from previous declarations.
if (PrevDecl)
@@ -1699,12 +1702,14 @@
= ObjCProtocolDecl::Create(Context, CurContext, Ident,
IdentPair.second, AtProtocolLoc,
PrevDecl);
-
+ ProcessAPINotes(PDecl);
+
PushOnScopeChains(PDecl, TUScope);
CheckObjCDeclScope(PDecl);
if (attrList)
ProcessDeclAttributeList(TUScope, PDecl, attrList);
+ ProcessAPINotes(PDecl);
if (PrevDecl)
mergeDeclAttributes(PDecl, PrevDecl);
@@ -3037,7 +3042,8 @@
ClassName, TypeParams, PrevIDecl,
IdentLocs[i]);
IDecl->setAtEndRange(IdentLocs[i]);
-
+ ProcessAPINotes(IDecl);
+
PushOnScopeChains(IDecl, TUScope);
CheckObjCDeclScope(IDecl);
DeclsInGroup.push_back(IDecl);
@@ -3837,7 +3843,7 @@
if (IDecl->getSuperClass() == nullptr) {
// This class has no superclass, so check that it has been marked with
// __attribute((objc_root_class)).
- if (!HasRootClassAttr) {
+ if (!HasRootClassAttr && !IDecl->hasAttr<ObjCCompleteDefinitionAttr>()) {
SourceLocation DeclLoc(IDecl->getLocation());
SourceLocation SuperClassLoc(getLocForEndOfToken(DeclLoc));
Diag(DeclLoc, diag::warn_objc_root_class_missing)
@@ -3932,12 +3938,10 @@
return (Decl::ObjCDeclQualifier) (unsigned) PQTVal;
}
-/// \brief Check whether the declared result type of the given Objective-C
-/// method declaration is compatible with the method's class.
-///
-static Sema::ResultTypeCompatibilityKind
-CheckRelatedResultTypeCompatibility(Sema &S, ObjCMethodDecl *Method,
- ObjCInterfaceDecl *CurrentClass) {
+Sema::ResultTypeCompatibilityKind
+Sema::checkRelatedResultTypeCompatibility(
+ const ObjCMethodDecl *Method,
+ const ObjCInterfaceDecl *CurrentClass) {
QualType ResultType = Method->getReturnType();
// If an Objective-C method inherits its related result type, then its
@@ -4393,6 +4397,7 @@
// Apply the attributes to the parameter.
ProcessDeclAttributeList(TUScope, Param, ArgInfo[i].ArgAttrs);
+ ProcessAPINotes(Param);
if (Param->hasAttr<BlocksAttr>()) {
Diag(Param->getLocation(), diag::err_block_on_nonlocal);
@@ -4423,6 +4428,7 @@
if (AttrList)
ProcessDeclAttributeList(TUScope, ObjCMethod, AttrList);
+ ProcessAPINotes(ObjCMethod);
// Add the method now.
const ObjCMethodDecl *PrevMethod = nullptr;
@@ -4478,7 +4484,7 @@
}
ResultTypeCompatibilityKind RTC
- = CheckRelatedResultTypeCompatibility(*this, ObjCMethod, CurrentClass);
+ = checkRelatedResultTypeCompatibility(ObjCMethod, CurrentClass);
CheckObjCMethodOverrides(ObjCMethod, CurrentClass, RTC);
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 0077d6c..267dbe4 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -7531,22 +7531,6 @@
return IncompatibleVectors;
}
}
-
- // When the RHS comes from another lax conversion (e.g. binops between
- // scalars and vectors) the result is canonicalized as a vector. When the
- // LHS is also a vector, the lax is allowed by the condition above. Handle
- // the case where LHS is a scalar.
- if (LHSType->isScalarType()) {
- const VectorType *VecType = RHSType->getAs<VectorType>();
- if (VecType && VecType->getNumElements() == 1 &&
- isLaxVectorConversion(RHSType, LHSType)) {
- ExprResult *VecExpr = &RHS;
- *VecExpr = ImpCastExprToType(VecExpr->get(), LHSType, CK_BitCast);
- Kind = CK_BitCast;
- return Compatible;
- }
- }
-
return Incompatible;
}
@@ -8081,7 +8065,6 @@
// If there's an ext-vector type and a scalar, try to convert the scalar to
// the vector element type and splat.
- // FIXME: this should also work for regular vector types as supported in GCC.
if (!RHSVecType && isa<ExtVectorType>(LHSVecType)) {
if (!tryVectorConvertAndSplat(*this, &RHS, RHSType,
LHSVecType->getElementType(), LHSType))
@@ -8094,31 +8077,14 @@
return RHSType;
}
- // FIXME: The code below also handles convertion between vectors and
- // non-scalars, we should break this down into fine grained specific checks
- // and emit proper diagnostics.
- QualType VecType = LHSVecType ? LHSType : RHSType;
- const VectorType *VT = LHSVecType ? LHSVecType : RHSVecType;
- QualType OtherType = LHSVecType ? RHSType : LHSType;
- ExprResult *OtherExpr = LHSVecType ? &RHS : &LHS;
- if (isLaxVectorConversion(OtherType, VecType)) {
- // If we're allowing lax vector conversions, only the total (data) size
- // needs to be the same. For non compound assignment, if one of the types is
- // scalar, the result is always the vector type.
- if (!IsCompAssign) {
- *OtherExpr = ImpCastExprToType(OtherExpr->get(), VecType, CK_BitCast);
- return VecType;
- // In a compound assignment, lhs += rhs, 'lhs' is a lvalue src, forbidding
- // any implicit cast. Here, the 'rhs' should be implicit casted to 'lhs'
- // type. Note that this is already done by non-compound assignments in
- // CheckAssignmentConstraints. If it's a scalar type, only bitcast for
- // <1 x T> -> T. The result is also a vector type.
- } else if (OtherType->isExtVectorType() ||
- (OtherType->isScalarType() && VT->getNumElements() == 1)) {
- ExprResult *RHSExpr = &RHS;
- *RHSExpr = ImpCastExprToType(RHSExpr->get(), LHSType, CK_BitCast);
- return VecType;
- }
+ // If we're allowing lax vector conversions, only the total (data) size
+ // needs to be the same.
+ // FIXME: Should we really be allowing this?
+ // FIXME: We really just pick the LHS type arbitrarily?
+ if (isLaxVectorConversion(RHSType, LHSType)) {
+ QualType resultType = LHSType;
+ RHS = ImpCastExprToType(RHS.get(), resultType, CK_BitCast);
+ return resultType;
}
// Okay, the expression is invalid.
@@ -9724,7 +9690,7 @@
}
// Return a signed type for the vector.
- return GetSignedVectorType(vType);
+ return GetSignedVectorType(LHSType);
}
QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS,
@@ -13577,11 +13543,28 @@
}
// Warn about implicitly autoreleasing indirect parameters captured by blocks.
- if (auto *PT = dyn_cast<PointerType>(CaptureType)) {
+ if (const auto *PT = CaptureType->getAs<PointerType>()) {
+ // This function finds out whether there is an AttributedType of kind
+ // attr_objc_ownership in Ty. The existence of AttributedType of kind
+ // attr_objc_ownership implies __autoreleasing was explicitly specified
+ // rather than being added implicitly by the compiler.
+ auto IsObjCOwnershipAttributedType = [](QualType Ty) {
+ while (const auto *AttrTy = Ty->getAs<AttributedType>()) {
+ if (AttrTy->getAttrKind() == AttributedType::attr_objc_ownership)
+ return true;
+
+ // Peel off AttributedTypes that are not of kind objc_ownership.
+ Ty = AttrTy->getModifiedType();
+ }
+
+ return false;
+ };
+
QualType PointeeTy = PT->getPointeeType();
- if (isa<ObjCObjectPointerType>(PointeeTy.getCanonicalType()) &&
+
+ if (PointeeTy->getAs<ObjCObjectPointerType>() &&
PointeeTy.getObjCLifetime() == Qualifiers::OCL_Autoreleasing &&
- !isa<AttributedType>(PointeeTy)) {
+ !IsObjCOwnershipAttributedType(PointeeTy)) {
if (BuildAndDiagnose) {
SourceLocation VarLoc = Var->getLocation();
S.Diag(Loc, diag::warn_block_capture_autoreleasing);
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 3afa95f..9b5fe9a 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -6402,6 +6402,23 @@
return false;
}
+/// \brief Check if it's ok to try and recover dot pseudo destructor calls on
+/// pointer objects.
+static bool
+canRecoverDotPseudoDestructorCallsOnPointerObjects(Sema &SemaRef,
+ QualType DestructedType) {
+ // If this is a record type, check if its destructor is callable.
+ if (auto *RD = DestructedType->getAsCXXRecordDecl()) {
+ if (CXXDestructorDecl *D = SemaRef.LookupDestructor(RD))
+ return SemaRef.CanUseDecl(D, /*TreatUnavailableAsInvalid=*/false);
+ return false;
+ }
+
+ // Otherwise, check if it's a type for which it's valid to use a pseudo-dtor.
+ return DestructedType->isDependentType() || DestructedType->isScalarType() ||
+ DestructedType->isVectorType();
+}
+
ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
@@ -6436,15 +6453,36 @@
= DestructedTypeInfo->getTypeLoc().getLocalSourceRange().getBegin();
if (!DestructedType->isDependentType() && !ObjectType->isDependentType()) {
if (!Context.hasSameUnqualifiedType(DestructedType, ObjectType)) {
- Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch)
- << ObjectType << DestructedType << Base->getSourceRange()
- << DestructedTypeInfo->getTypeLoc().getLocalSourceRange();
+ // Detect dot pseudo destructor calls on pointer objects, e.g.:
+ // Foo *foo;
+ // foo.~Foo();
+ if (OpKind == tok::period && ObjectType->isPointerType() &&
+ Context.hasSameUnqualifiedType(DestructedType,
+ ObjectType->getPointeeType())) {
+ auto Diagnostic =
+ Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
+ << ObjectType << /*IsArrow=*/0 << Base->getSourceRange();
- // Recover by setting the destructed type to the object type.
- DestructedType = ObjectType;
- DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType,
- DestructedTypeStart);
- Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo);
+ // Issue a fixit only when the destructor is valid.
+ if (canRecoverDotPseudoDestructorCallsOnPointerObjects(
+ *this, DestructedType))
+ Diagnostic << FixItHint::CreateReplacement(OpLoc, "->");
+
+ // Recover by setting the object type to the destructed type and the
+ // operator to '->'.
+ ObjectType = DestructedType;
+ OpKind = tok::arrow;
+ } else {
+ Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch)
+ << ObjectType << DestructedType << Base->getSourceRange()
+ << DestructedTypeInfo->getTypeLoc().getLocalSourceRange();
+
+ // Recover by setting the destructed type to the object type.
+ DestructedType = ObjectType;
+ DestructedTypeInfo =
+ Context.getTrivialTypeSourceInfo(ObjectType, DestructedTypeStart);
+ Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo);
+ }
} else if (DestructedType.getObjCLifetime() !=
ObjectType.getObjCLifetime()) {
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index b053c83..aae08a9 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -2237,6 +2237,10 @@
}
unsigned FieldIndex = 0;
+
+ if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RT->getDecl()))
+ FieldIndex = CXXRD->getNumBases();
+
for (auto *FI : RT->getDecl()->fields()) {
if (FI->isUnnamedBitfield())
continue;
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 38a7b8c..43147b0 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -3427,6 +3427,12 @@
SM == ShadowMaps.rbegin())
continue;
+ // A shadow declaration that's created by a resolved using declaration
+ // is not hidden by the same using declaration.
+ if (isa<UsingShadowDecl>(ND) && isa<UsingDecl>(D) &&
+ cast<UsingShadowDecl>(ND)->getUsingDecl() == D)
+ continue;
+
// We've found a declaration that hides this one.
return D;
}
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index 3481b82..eea44eb 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -636,8 +636,6 @@
PDecl->setInvalidDecl();
}
- ProcessDeclAttributes(S, PDecl, FD.D);
-
// Regardless of setter/getter attribute, we save the default getter/setter
// selector names in anticipation of declaration of setter/getter methods.
PDecl->setGetterName(GetterSel);
@@ -645,6 +643,8 @@
PDecl->setPropertyAttributesAsWritten(
makePropertyAttributesAsWritten(AttributesAsWritten));
+ ProcessDeclAttributes(S, PDecl, FD.D);
+
if (Attributes & ObjCDeclSpec::DQ_PR_readonly)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly);
@@ -2250,6 +2250,8 @@
SectionAttr::CreateImplicit(Context, SectionAttr::GNU_section,
SA->getName(), Loc));
+ ProcessAPINotes(GetterMethod);
+
if (getLangOpts().ObjCAutoRefCount)
CheckARCMethodDecl(GetterMethod);
} else
@@ -2315,6 +2317,9 @@
SetterMethod->addAttr(
SectionAttr::CreateImplicit(Context, SectionAttr::GNU_section,
SA->getName(), Loc));
+
+ ProcessAPINotes(SetterMethod);
+
// It's possible for the user to have set a very odd custom
// setter selector that causes it to have a method family.
if (getLangOpts().ObjCAutoRefCount)
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index ad1e89a..7dfac4e 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -1288,6 +1288,7 @@
if (Attr)
ProcessDeclAttributeList(S, NewClass, Attr);
+ ProcessAPINotes(NewClass);
if (PrevClassTemplate)
mergeDeclAttributes(NewClass, PrevClassTemplate->getTemplatedDecl());
@@ -6763,6 +6764,7 @@
if (Attr)
ProcessDeclAttributeList(S, Specialization, Attr);
+ ProcessAPINotes(Specialization);
// Add alignment attributes if necessary; these attributes are checked when
// the ASTContext lays out the structure.
@@ -7796,6 +7798,7 @@
bool PreviouslyDLLExported = Specialization->hasAttr<DLLExportAttr>();
if (Attr)
ProcessDeclAttributeList(S, Specialization, Attr);
+ ProcessAPINotes(Specialization);
// Add the explicit instantiation into its lexical context. However,
// since explicit instantiations are never found by name lookup, we
@@ -8215,6 +8218,7 @@
// Merge attributes.
if (AttributeList *Attr = D.getDeclSpec().getAttributes().getList())
ProcessDeclAttributeList(S, Prev, Attr);
+ ProcessAPINotes(Prev);
}
if (TSK == TSK_ExplicitInstantiationDefinition)
InstantiateVariableDefinition(D.getIdentifierLoc(), Prev);
@@ -8374,6 +8378,7 @@
Specialization->setTemplateSpecializationKind(TSK, D.getIdentifierLoc());
if (Attr)
ProcessDeclAttributeList(S, Specialization, Attr);
+ ProcessAPINotes(Specialization);
if (Specialization->isDefined()) {
// Let the ASTConsumer know that this function has been explicitly
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 29b2142..ffc965e 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -1159,20 +1159,6 @@
ResultTL = ObjCObjectPointerTL.getPointeeLoc();
}
- if (auto OTPTL = ResultTL.getAs<ObjCTypeParamTypeLoc>()) {
- // Protocol qualifier information.
- if (OTPTL.getNumProtocols() > 0) {
- assert(OTPTL.getNumProtocols() == Protocols.size());
- OTPTL.setProtocolLAngleLoc(ProtocolLAngleLoc);
- OTPTL.setProtocolRAngleLoc(ProtocolRAngleLoc);
- for (unsigned i = 0, n = Protocols.size(); i != n; ++i)
- OTPTL.setProtocolLoc(i, ProtocolLocs[i]);
- }
-
- // We're done. Return the completed type to the parser.
- return CreateParsedType(Result, ResultTInfo);
- }
-
auto ObjCObjectTL = ResultTL.castAs<ObjCObjectTypeLoc>();
// Type argument information.
@@ -3355,25 +3341,9 @@
if (auto recordType = type->getAs<RecordType>()) {
RecordDecl *recordDecl = recordType->getDecl();
- bool isCFError = false;
- if (S.CFError) {
- // If we already know about CFError, test it directly.
- isCFError = (S.CFError == recordDecl);
- } else {
- // Check whether this is CFError, which we identify based on its bridge
- // to NSError.
- if (recordDecl->getTagKind() == TTK_Struct && numNormalPointers > 0) {
- if (auto bridgeAttr = recordDecl->getAttr<ObjCBridgeAttr>()) {
- if (bridgeAttr->getBridgedType() == S.getNSErrorIdent()) {
- S.CFError = recordDecl;
- isCFError = true;
- }
- }
- }
- }
-
// If this is CFErrorRef*, report it as such.
- if (isCFError && numNormalPointers == 2 && numTypeSpecifierPointers < 2) {
+ if (numNormalPointers == 2 && numTypeSpecifierPointers < 2 &&
+ S.isCFError(recordDecl)) {
return PointerDeclaratorKind::CFErrorRefPointer;
}
break;
@@ -3397,6 +3367,26 @@
}
}
+bool Sema::isCFError(RecordDecl *recordDecl) {
+ // If we already know about CFError, test it directly.
+ if (CFError) {
+ return (CFError == recordDecl);
+ }
+
+ // Check whether this is CFError, which we identify based on being
+ // bridged to NSError.
+ if (recordDecl->getTagKind() == TTK_Struct) {
+ if (auto bridgeAttr = recordDecl->getAttr<ObjCBridgeAttr>()) {
+ if (bridgeAttr->getBridgedType() == getNSErrorIdent()) {
+ CFError = recordDecl;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
static FileID getNullabilityCompletenessCheckFileID(Sema &S,
SourceLocation loc) {
// If we're anywhere in a function, method, or closure context, don't perform
@@ -5979,12 +5969,34 @@
return false;
}
+/// Rebuild an attributed type without the nullability attribute on it.
+static QualType rebuildAttributedTypeWithoutNullability(ASTContext &ctx,
+ QualType type) {
+ auto attributed = dyn_cast<AttributedType>(type.getTypePtr());
+ if (!attributed) return type;
+
+ // Skip the nullability attribute; we're done.
+ if (attributed->getImmediateNullability()) {
+ return attributed->getModifiedType();
+ }
+
+ // Build the modified type.
+ auto modified = rebuildAttributedTypeWithoutNullability(
+ ctx, attributed->getModifiedType());
+ assert(modified.getTypePtr() != attributed->getModifiedType().getTypePtr());
+ return ctx.getAttributedType(attributed->getAttrKind(), modified,
+ attributed->getEquivalentType());
+}
+
bool Sema::checkNullabilityTypeSpecifier(QualType &type,
NullabilityKind nullability,
SourceLocation nullabilityLoc,
bool isContextSensitive,
- bool allowOnArrayType) {
- recordNullabilitySeen(*this, nullabilityLoc);
+ bool allowOnArrayType,
+ bool implicit,
+ bool overrideExisting) {
+ if (!implicit)
+ recordNullabilitySeen(*this, nullabilityLoc);
// Check for existing nullability attributes on the type.
QualType desugared = type;
@@ -5993,6 +6005,9 @@
if (auto existingNullability = attributed->getImmediateNullability()) {
// Duplicated nullability.
if (nullability == *existingNullability) {
+ if (implicit)
+ break;
+
Diag(nullabilityLoc, diag::warn_nullability_duplicate)
<< DiagNullabilityKind(nullability, isContextSensitive)
<< FixItHint::CreateRemoval(nullabilityLoc);
@@ -6000,11 +6015,16 @@
break;
}
- // Conflicting nullability.
- Diag(nullabilityLoc, diag::err_nullability_conflicting)
- << DiagNullabilityKind(nullability, isContextSensitive)
- << DiagNullabilityKind(*existingNullability, false);
- return true;
+ if (!overrideExisting) {
+ // Conflicting nullability.
+ Diag(nullabilityLoc, diag::err_nullability_conflicting)
+ << DiagNullabilityKind(nullability, isContextSensitive)
+ << DiagNullabilityKind(*existingNullability, false);
+ return true;
+ }
+
+ // Rebuild the attributed type, dropping the existing nullability.
+ type = rebuildAttributedTypeWithoutNullability(Context, type);
}
desugared = attributed->getModifiedType();
@@ -6015,7 +6035,7 @@
// have nullability specifiers on them, which means we cannot
// provide a useful Fix-It.
if (auto existingNullability = desugared->getNullability(Context)) {
- if (nullability != *existingNullability) {
+ if (nullability != *existingNullability && !implicit) {
Diag(nullabilityLoc, diag::err_nullability_conflicting)
<< DiagNullabilityKind(nullability, isContextSensitive)
<< DiagNullabilityKind(*existingNullability, false);
@@ -6040,15 +6060,16 @@
// If this definitely isn't a pointer type, reject the specifier.
if (!desugared->canHaveNullability() &&
!(allowOnArrayType && desugared->isArrayType())) {
- Diag(nullabilityLoc, diag::err_nullability_nonpointer)
- << DiagNullabilityKind(nullability, isContextSensitive) << type;
+ if (!implicit) {
+ Diag(nullabilityLoc, diag::err_nullability_nonpointer)
+ << DiagNullabilityKind(nullability, isContextSensitive) << type;
+ }
return true;
}
// For the context-sensitive keywords/Objective-C property
// attributes, require that the type be a single-level pointer.
if (isContextSensitive) {
- // Make sure that the pointee isn't itself a pointer type.
const Type *pointeeType;
if (desugared->isArrayType())
pointeeType = desugared->getArrayElementTypeNoTypeQual();
@@ -6077,13 +6098,6 @@
}
bool Sema::checkObjCKindOfType(QualType &type, SourceLocation loc) {
- if (isa<ObjCTypeParamType>(type)) {
- // Build the attributed type to record where __kindof occurred.
- type = Context.getAttributedType(AttributedType::attr_objc_kindof,
- type, type);
- return false;
- }
-
// Find out if it's an Objective-C object or object pointer type;
const ObjCObjectPointerType *ptrType = type->getAs<ObjCObjectPointerType>();
const ObjCObjectType *objType = ptrType ? ptrType->getObjectType()
@@ -6829,7 +6843,7 @@
mapNullabilityAttrKind(attr.getKind()),
attr.getLoc(),
attr.isContextSensitiveKeywordAttribute(),
- allowOnArrayType)) {
+ allowOnArrayType, /*implicit=*/false)) {
attr.setInvalid();
}
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 53224e2..00db74a 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -2513,6 +2513,7 @@
F.InputFileOffsets =
(const llvm::support::unaligned_uint64_t *)Blob.data();
F.InputFilesLoaded.resize(NumInputs);
+ F.NumUserInputFiles = NumUserInputs;
break;
}
}
@@ -3245,8 +3246,11 @@
for (unsigned I = 0, N = Record.size(); I != N; /**/) {
unsigned GlobalID = getGlobalSubmoduleID(F, Record[I++]);
SourceLocation Loc = ReadSourceLocation(F, Record, I);
- if (GlobalID)
+ if (GlobalID) {
ImportedModules.push_back(ImportedSubmodule(GlobalID, Loc));
+ if (DeserializationListener)
+ DeserializationListener->ModuleImportRead(GlobalID, Loc);
+ }
}
}
break;
@@ -4617,6 +4621,7 @@
bool IsExplicit = Record[Idx++];
bool IsSystem = Record[Idx++];
bool IsExternC = Record[Idx++];
+ bool IsSwiftInferImportAsMember = Record[Idx++];
bool InferSubmodules = Record[Idx++];
bool InferExplicitSubmodules = Record[Idx++];
bool InferExportWildcard = Record[Idx++];
@@ -4661,6 +4666,7 @@
CurrentModule->IsFromModuleFile = true;
CurrentModule->IsSystem = IsSystem || CurrentModule->IsSystem;
CurrentModule->IsExternC = IsExternC;
+ CurrentModule->IsSwiftInferImportAsMember = IsSwiftInferImportAsMember;
CurrentModule->InferSubmodules = InferSubmodules;
CurrentModule->InferExplicitSubmodules = InferExplicitSubmodules;
CurrentModule->InferExportWildcard = InferExportWildcard;
@@ -5288,48 +5294,84 @@
}
void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) {
- // FIXME: Make it work properly with modules.
- SmallVector<DiagnosticsEngine::DiagState *, 32> DiagStates;
+ using DiagState = DiagnosticsEngine::DiagState;
+ SmallVector<DiagState *, 32> DiagStates;
+
for (ModuleIterator I = ModuleMgr.begin(), E = ModuleMgr.end(); I != E; ++I) {
ModuleFile &F = *(*I);
unsigned Idx = 0;
- DiagStates.clear();
- assert(!Diag.DiagStates.empty());
- DiagStates.push_back(&Diag.DiagStates.front()); // the command-line one.
- while (Idx < F.PragmaDiagMappings.size()) {
- SourceLocation Loc = ReadSourceLocation(F, F.PragmaDiagMappings[Idx++]);
- unsigned DiagStateID = F.PragmaDiagMappings[Idx++];
- if (DiagStateID != 0) {
- Diag.DiagStatePoints.push_back(
- DiagnosticsEngine::DiagStatePoint(DiagStates[DiagStateID-1],
- FullSourceLoc(Loc, SourceMgr)));
- continue;
- }
+ auto &Record = F.PragmaDiagMappings;
+ if (Record.empty())
+ continue;
- assert(DiagStateID == 0);
+ DiagStates.clear();
+
+ auto ReadDiagState =
+ [&](const DiagState &BasedOn, SourceLocation Loc,
+ bool IncludeNonPragmaStates) -> DiagnosticsEngine::DiagState * {
+ unsigned BackrefID = Record[Idx++];
+ if (BackrefID != 0)
+ return DiagStates[BackrefID - 1];
+
// A new DiagState was created here.
- Diag.DiagStates.push_back(*Diag.GetCurDiagState());
- DiagnosticsEngine::DiagState *NewState = &Diag.DiagStates.back();
+ Diag.DiagStates.push_back(BasedOn);
+ DiagState *NewState = &Diag.DiagStates.back();
DiagStates.push_back(NewState);
- Diag.DiagStatePoints.push_back(
- DiagnosticsEngine::DiagStatePoint(NewState,
- FullSourceLoc(Loc, SourceMgr)));
- while (true) {
- assert(Idx < F.PragmaDiagMappings.size() &&
- "Invalid data, didn't find '-1' marking end of diag/map pairs");
- if (Idx >= F.PragmaDiagMappings.size()) {
- break; // Something is messed up but at least avoid infinite loop in
- // release build.
- }
- unsigned DiagID = F.PragmaDiagMappings[Idx++];
- if (DiagID == (unsigned)-1) {
- break; // no more diag/map pairs for this location.
- }
- diag::Severity Map = (diag::Severity)F.PragmaDiagMappings[Idx++];
+ while (Idx + 1 < Record.size() && Record[Idx] != unsigned(-1)) {
+ unsigned DiagID = Record[Idx++];
+ diag::Severity Map = (diag::Severity)Record[Idx++];
DiagnosticMapping Mapping = Diag.makeUserMapping(Map, Loc);
- Diag.GetCurDiagState()->setMapping(DiagID, Mapping);
+ if (Mapping.isPragma() || IncludeNonPragmaStates)
+ NewState->setMapping(DiagID, Mapping);
+ }
+ assert(Idx != Record.size() && Record[Idx] == unsigned(-1) &&
+ "Invalid data, didn't find '-1' marking end of diag/map pairs");
+ ++Idx;
+ return NewState;
+ };
+
+ auto *FirstState = ReadDiagState(
+ F.isModule() ? DiagState() : *Diag.DiagStatesByLoc.CurDiagState,
+ SourceLocation(), F.isModule());
+ SourceLocation CurStateLoc =
+ ReadSourceLocation(F, F.PragmaDiagMappings[Idx++]);
+ auto *CurState = ReadDiagState(*FirstState, CurStateLoc, false);
+
+ if (!F.isModule()) {
+ Diag.DiagStatesByLoc.CurDiagState = CurState;
+ Diag.DiagStatesByLoc.CurDiagStateLoc = CurStateLoc;
+
+ // Preserve the property that the imaginary root file describes the
+ // current state.
+ auto &T = Diag.DiagStatesByLoc.Files[FileID()].StateTransitions;
+ if (T.empty())
+ T.push_back({CurState, 0});
+ else
+ T[0].State = CurState;
+ }
+
+ while (Idx < Record.size()) {
+ SourceLocation Loc = ReadSourceLocation(F, Record[Idx++]);
+ auto IDAndOffset = SourceMgr.getDecomposedLoc(Loc);
+ assert(IDAndOffset.second == 0 && "not a start location for a FileID");
+ unsigned Transitions = Record[Idx++];
+
+ // Note that we don't need to set up Parent/ParentOffset here, because
+ // we won't be changing the diagnostic state within imported FileIDs
+ // (other than perhaps appending to the main source file, which has no
+ // parent).
+ auto &F = Diag.DiagStatesByLoc.Files[IDAndOffset.first];
+ F.StateTransitions.reserve(F.StateTransitions.size() + Transitions);
+ for (unsigned I = 0; I != Transitions; ++I) {
+ unsigned Offset = Record[Idx++];
+ auto *State =
+ ReadDiagState(*FirstState, Loc.getLocWithOffset(Offset), false);
+ F.StateTransitions.push_back({State, Offset});
}
}
+
+ // Don't try to read these mappings again.
+ Record.clear();
}
}
@@ -8493,6 +8535,21 @@
}
}
+void ASTReader::visitInputFiles(serialization::ModuleFile &MF,
+ bool IncludeSystem, bool Complain,
+ llvm::function_ref<void(const serialization::InputFile &IF,
+ bool isSystem)> Visitor) {
+ unsigned NumUserInputs = MF.NumUserInputFiles;
+ unsigned NumInputs = MF.InputFilesLoaded.size();
+ assert(NumUserInputs <= NumInputs);
+ unsigned N = IncludeSystem ? NumInputs : NumUserInputs;
+ for (unsigned I = 0; I < N; ++I) {
+ bool IsSystem = I >= NumUserInputs;
+ InputFile IF = getInputFile(MF, I+1, Complain);
+ Visitor(IF, IsSystem);
+ }
+}
+
std::string ASTReader::getOwningModuleNameForDiagnostic(const Decl *D) {
// If we know the owning module, use it.
if (Module *M = D->getImportedOwningModule())
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index 886523e..3d8ecfa 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -2558,6 +2558,7 @@
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsExplicit
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsSystem
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsExternC
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsSwiftInferIAM...
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferSubmodules...
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExplicit...
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExportWild...
@@ -2652,9 +2653,9 @@
{
RecordData::value_type Record[] = {
SUBMODULE_DEFINITION, ID, ParentID, Mod->IsFramework, Mod->IsExplicit,
- Mod->IsSystem, Mod->IsExternC, Mod->InferSubmodules,
- Mod->InferExplicitSubmodules, Mod->InferExportWildcard,
- Mod->ConfigMacrosExhaustive};
+ Mod->IsSystem, Mod->IsExternC, Mod->IsSwiftInferImportAsMember,
+ Mod->InferSubmodules, Mod->InferExplicitSubmodules,
+ Mod->InferExportWildcard, Mod->ConfigMacrosExhaustive};
Stream.EmitRecordWithBlob(DefinitionAbbrev, Record, Mod->Name);
}
@@ -2789,38 +2790,43 @@
void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag,
bool isModule) {
- // Make sure set diagnostic pragmas don't affect the translation unit that
- // imports the module.
- // FIXME: Make diagnostic pragma sections work properly with modules.
- if (isModule)
- return;
-
llvm::SmallDenseMap<const DiagnosticsEngine::DiagState *, unsigned, 64>
DiagStateIDMap;
unsigned CurrID = 0;
- DiagStateIDMap[&Diag.DiagStates.front()] = ++CurrID; // the command-line one.
RecordData Record;
- for (DiagnosticsEngine::DiagStatePointsTy::const_iterator
- I = Diag.DiagStatePoints.begin(), E = Diag.DiagStatePoints.end();
- I != E; ++I) {
- const DiagnosticsEngine::DiagStatePoint &point = *I;
- if (point.Loc.isInvalid())
- continue;
- AddSourceLocation(point.Loc, Record);
- unsigned &DiagStateID = DiagStateIDMap[point.State];
+ auto AddDiagState = [&](const DiagnosticsEngine::DiagState *State,
+ bool IncludeNonPragmaStates) {
+ unsigned &DiagStateID = DiagStateIDMap[State];
Record.push_back(DiagStateID);
-
+
if (DiagStateID == 0) {
DiagStateID = ++CurrID;
- for (const auto &I : *(point.State)) {
- if (I.second.isPragma()) {
+ for (const auto &I : *State) {
+ if (I.second.isPragma() || IncludeNonPragmaStates) {
Record.push_back(I.first);
Record.push_back((unsigned)I.second.getSeverity());
}
}
- Record.push_back(-1); // mark the end of the diag/map pairs for this
- // location.
+ // Add a sentinel to mark the end of the diag IDs.
+ Record.push_back(unsigned(-1));
+ }
+ };
+
+ AddDiagState(Diag.DiagStatesByLoc.FirstDiagState, isModule);
+ AddSourceLocation(Diag.DiagStatesByLoc.CurDiagStateLoc, Record);
+ AddDiagState(Diag.DiagStatesByLoc.CurDiagState, false);
+
+ for (auto &FileIDAndFile : Diag.DiagStatesByLoc.Files) {
+ if (!FileIDAndFile.first.isValid() ||
+ !FileIDAndFile.second.HasLocalTransitions)
+ continue;
+ AddSourceLocation(Diag.SourceMgr->getLocForStartOfFile(FileIDAndFile.first),
+ Record);
+ Record.push_back(FileIDAndFile.second.StateTransitions.size());
+ for (auto &StatePoint : FileIDAndFile.second.StateTransitions) {
+ Record.push_back(StatePoint.Offset);
+ AddDiagState(StatePoint.State, false);
}
}
@@ -3283,8 +3289,6 @@
NeedDecls(!IsModule || !Writer.getLangOpts().CPlusPlus),
InterestingIdentifierOffsets(InterestingIdentifierOffsets) {}
- bool needDecls() const { return NeedDecls; }
-
static hash_value_type ComputeHash(const IdentifierInfo* II) {
return llvm::HashString(II->getName());
}
@@ -3434,10 +3438,8 @@
assert(II && "NULL identifier in identifier table");
// Write out identifiers if either the ID is local or the identifier has
// changed since it was loaded.
- if (ID >= FirstIdentID || !Chain || !II->isFromAST()
- || II->hasChangedSinceDeserialization() ||
- (Trait.needDecls() &&
- II->hasFETokenInfoChangedSinceDeserialization()))
+ if (ID >= FirstIdentID || !Chain || !II->isFromAST() ||
+ II->hasChangedSinceDeserialization())
Generator.insert(II, ID, Trait);
}
diff --git a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
index 0891ea8..26fd83f 100644
--- a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
+++ b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
@@ -626,7 +626,7 @@
: public RecursiveASTVisitor<IsObjCTypeParamDependentTypeVisitor> {
public:
IsObjCTypeParamDependentTypeVisitor() : Result(false) {}
- bool VisitObjCTypeParamType(const ObjCTypeParamType *Type) {
+ bool VisitTypedefType(const TypedefType *Type) {
if (isa<ObjCTypeParamDecl>(Type->getDecl())) {
Result = true;
return false;
diff --git a/test/APINotes/Inputs/APINotes/SomeOtherKit.apinotes b/test/APINotes/Inputs/APINotes/SomeOtherKit.apinotes
new file mode 100644
index 0000000..ccdc4e1
--- /dev/null
+++ b/test/APINotes/Inputs/APINotes/SomeOtherKit.apinotes
@@ -0,0 +1,8 @@
+Name: SomeOtherKit
+Classes:
+ - Name: A
+ Methods:
+ - Selector: "methodB"
+ MethodKind: Instance
+ Availability: none
+ AvailabilityMsg: "anything but this"
diff --git a/test/APINotes/Inputs/BrokenHeaders/APINotes.apinotes b/test/APINotes/Inputs/BrokenHeaders/APINotes.apinotes
new file mode 100644
index 0000000..d547317
--- /dev/null
+++ b/test/APINotes/Inputs/BrokenHeaders/APINotes.apinotes
@@ -0,0 +1,4 @@
+Name: SomeBrokenLib
+Functions:
+ - Name: do_something_with_pointers
+ Nu llabilityOfRet: O
diff --git a/test/APINotes/Inputs/BrokenHeaders/SomeBrokenLib.h b/test/APINotes/Inputs/BrokenHeaders/SomeBrokenLib.h
new file mode 100644
index 0000000..b09c6f6
--- /dev/null
+++ b/test/APINotes/Inputs/BrokenHeaders/SomeBrokenLib.h
@@ -0,0 +1,6 @@
+#ifndef SOME_BROKEN_LIB_H
+#define SOME_BROKEN_LIB_H
+
+void do_something_with_pointers(int *ptr1, int *ptr2);
+
+#endif // SOME_BROKEN_LIB_H
diff --git a/test/APINotes/Inputs/BrokenHeaders2/APINotes.apinotes b/test/APINotes/Inputs/BrokenHeaders2/APINotes.apinotes
new file mode 100644
index 0000000..33eeaaa
--- /dev/null
+++ b/test/APINotes/Inputs/BrokenHeaders2/APINotes.apinotes
@@ -0,0 +1,7 @@
+Name: SomeBrokenLib
+Functions:
+ - Name: do_something_with_pointers
+ NullabilityOfRet: O
+ - Name: do_something_with_pointers
+ NullabilityOfRet: O
+
diff --git a/test/APINotes/Inputs/BrokenHeaders2/SomeBrokenLib.h b/test/APINotes/Inputs/BrokenHeaders2/SomeBrokenLib.h
new file mode 100644
index 0000000..b09c6f6
--- /dev/null
+++ b/test/APINotes/Inputs/BrokenHeaders2/SomeBrokenLib.h
@@ -0,0 +1,6 @@
+#ifndef SOME_BROKEN_LIB_H
+#define SOME_BROKEN_LIB_H
+
+void do_something_with_pointers(int *ptr1, int *ptr2);
+
+#endif // SOME_BROKEN_LIB_H
diff --git a/test/APINotes/Inputs/Frameworks/SomeKit.framework/APINotes/SomeKit.apinotes b/test/APINotes/Inputs/Frameworks/SomeKit.framework/APINotes/SomeKit.apinotes
new file mode 100644
index 0000000..817af12
--- /dev/null
+++ b/test/APINotes/Inputs/Frameworks/SomeKit.framework/APINotes/SomeKit.apinotes
@@ -0,0 +1,74 @@
+Name: SomeKit
+Classes:
+ - Name: A
+ Methods:
+ - Selector: "transform:"
+ MethodKind: Instance
+ Availability: none
+ AvailabilityMsg: "anything but this"
+ - Selector: "transform:integer:"
+ MethodKind: Instance
+ NullabilityOfRet: N
+ Nullability: [ N, S ]
+ Properties:
+ - Name: intValue
+ PropertyKind: Instance
+ Availability: none
+ AvailabilityMsg: "wouldn't work anyway"
+ - Name: nonnullAInstance
+ PropertyKind: Instance
+ Nullability: N
+ - Name: nonnullAClass
+ PropertyKind: Class
+ Nullability: N
+ - Name: nonnullABoth
+ Nullability: N
+ - Name: B
+ Availability: none
+ AvailabilityMsg: "just don't"
+ - Name: C
+ Methods:
+ - Selector: "initWithA:"
+ MethodKind: Instance
+ DesignatedInit: true
+ - Name: OverriddenTypes
+ Methods:
+ - Selector: "methodToMangle:second:"
+ MethodKind: Instance
+ ResultType: 'char *'
+ Parameters:
+ - Position: 0
+ Type: 'SOMEKIT_DOUBLE *'
+ - Position: 1
+ Type: 'float *'
+ Properties:
+ - Name: intPropertyToMangle
+ PropertyKind: Instance
+ Type: 'double *'
+Functions:
+ - Name: global_int_fun
+ ResultType: 'char *'
+ Parameters:
+ - Position: 0
+ Type: 'double *'
+ - Position: 1
+ Type: 'float *'
+Globals:
+ - Name: global_int_ptr
+ Type: 'double *'
+SwiftVersions:
+ - Version: 3.0
+ Classes:
+ - Name: A
+ Methods:
+ - Selector: "transform:integer:"
+ MethodKind: Instance
+ NullabilityOfRet: O
+ Nullability: [ O, S ]
+ Properties:
+ - Name: explicitNonnullInstance
+ PropertyKind: Instance
+ Nullability: O
+ - Name: explicitNullableInstance
+ PropertyKind: Instance
+ Nullability: N
diff --git a/test/APINotes/Inputs/Frameworks/SomeKit.framework/APINotes/SomeKit_private.apinotes b/test/APINotes/Inputs/Frameworks/SomeKit.framework/APINotes/SomeKit_private.apinotes
new file mode 100644
index 0000000..28ede9d
--- /dev/null
+++ b/test/APINotes/Inputs/Frameworks/SomeKit.framework/APINotes/SomeKit_private.apinotes
@@ -0,0 +1,15 @@
+Name: SomeKit
+Classes:
+ - Name: A
+ Methods:
+ - Selector: "privateTransform:input:"
+ MethodKind: Instance
+ NullabilityOfRet: N
+ Nullability: [ N, S ]
+ Properties:
+ - Name: internalProperty
+ Nullability: N
+Protocols:
+ - Name: InternalProtocol
+ Availability: none
+ AvailabilityMsg: "not for you"
diff --git a/test/APINotes/Inputs/Frameworks/SomeKit.framework/Headers/SomeKit.apinotes b/test/APINotes/Inputs/Frameworks/SomeKit.framework/Headers/SomeKit.apinotes
new file mode 100644
index 0000000..ff88fdb
--- /dev/null
+++ b/test/APINotes/Inputs/Frameworks/SomeKit.framework/Headers/SomeKit.apinotes
@@ -0,0 +1,98 @@
+Name: SomeKit
+Classes:
+ - Name: A
+ Methods:
+ - Selector: "transform:"
+ MethodKind: Instance
+ Availability: none
+ AvailabilityMsg: "anything but this"
+ - Selector: "transform:integer:"
+ MethodKind: Instance
+ NullabilityOfRet: N
+ Nullability: [ N, S ]
+ - Selector: "implicitGetOnlyInstance"
+ MethodKind: Instance
+ Availability: none
+ AvailabilityMsg: "getter gone"
+ - Selector: "implicitGetOnlyClass"
+ MethodKind: Class
+ Availability: none
+ AvailabilityMsg: "getter gone"
+ - Selector: "implicitGetSetInstance"
+ MethodKind: Instance
+ Availability: none
+ AvailabilityMsg: "getter gone"
+ - Selector: "implicitGetSetClass"
+ MethodKind: Class
+ Availability: none
+ AvailabilityMsg: "getter gone"
+ - Selector: "setImplicitGetSetInstance:"
+ MethodKind: Instance
+ Availability: none
+ AvailabilityMsg: "setter gone"
+ - Selector: "setImplicitGetSetClass:"
+ MethodKind: Class
+ Availability: none
+ AvailabilityMsg: "setter gone"
+ Properties:
+ - Name: intValue
+ PropertyKind: Instance
+ Availability: none
+ AvailabilityMsg: "wouldn't work anyway"
+ - Name: nonnullAInstance
+ PropertyKind: Instance
+ Nullability: N
+ - Name: nonnullAClass
+ PropertyKind: Class
+ Nullability: N
+ - Name: nonnullABoth
+ Nullability: N
+ - Name: B
+ Availability: none
+ AvailabilityMsg: "just don't"
+ - Name: C
+ Methods:
+ - Selector: "initWithA:"
+ MethodKind: Instance
+ DesignatedInit: true
+ - Name: OverriddenTypes
+ Methods:
+ - Selector: "methodToMangle:second:"
+ MethodKind: Instance
+ ResultType: 'char *'
+ Parameters:
+ - Position: 0
+ Type: 'SOMEKIT_DOUBLE *'
+ - Position: 1
+ Type: 'float *'
+ Properties:
+ - Name: intPropertyToMangle
+ PropertyKind: Instance
+ Type: 'double *'
+Functions:
+ - Name: global_int_fun
+ ResultType: 'char *'
+ Parameters:
+ - Position: 0
+ Type: 'double *'
+ - Position: 1
+ Type: 'float *'
+Globals:
+ - Name: global_int_ptr
+ Type: 'double (*)(int, int)'
+SwiftVersions:
+ - Version: 3.0
+ Classes:
+ - Name: A
+ Methods:
+ - Selector: "transform:integer:"
+ MethodKind: Instance
+ NullabilityOfRet: O
+ Nullability: [ O, S ]
+ Properties:
+ - Name: explicitNonnullInstance
+ PropertyKind: Instance
+ Nullability: O
+ - Name: explicitNullableInstance
+ PropertyKind: Instance
+ Nullability: N
diff --git a/test/APINotes/Inputs/Frameworks/SomeKit.framework/Headers/SomeKit.h b/test/APINotes/Inputs/Frameworks/SomeKit.framework/Headers/SomeKit.h
new file mode 100644
index 0000000..1a192f5
--- /dev/null
+++ b/test/APINotes/Inputs/Frameworks/SomeKit.framework/Headers/SomeKit.h
@@ -0,0 +1,60 @@
+#ifndef SOMEKIT_H
+#define SOMEKIT_H
+
+__attribute__((objc_root_class))
+@interface A
+-(A*)transform:(A*)input;
+-(A*)transform:(A*)input integer:(int)integer;
+
+@property (nonatomic, readonly, retain) A* someA;
+@property (nonatomic, retain) A* someOtherA;
+
+@property (nonatomic) int intValue;
+@end
+
+@interface B : A
+@end
+
+@interface C : A
+- (instancetype)init;
+- (instancetype)initWithA:(A*)a;
+@end
+
+@interface ProcessInfo : A
++(instancetype)processInfo;
+@end
+
+@interface A(NonNullProperties)
+@property (nonatomic, readwrite, retain) A *nonnullAInstance;
+@property (class, nonatomic, readwrite, retain) A *nonnullAInstance;
+
+@property (nonatomic, readwrite, retain) A *nonnullAClass;
+@property (class, nonatomic, readwrite, retain) A *nonnullAClass;
+
+@property (nonatomic, readwrite, retain) A *nonnullABoth;
+@property (class, nonatomic, readwrite, retain) A *nonnullABoth;
+@end
+
+#import <SomeKit/SomeKitExplicitNullability.h>
+
+extern int *global_int_ptr;
+
+int *global_int_fun(int *ptr, int *ptr2);
+
+#define SOMEKIT_DOUBLE double
+
+__attribute__((objc_root_class))
+@interface OverriddenTypes
+-(int *)methodToMangle:(int *)ptr1 second:(int *)ptr2;
+@property int *intPropertyToMangle;
+@end
+
+@interface A(ImplicitGetterSetters)
+@property (nonatomic, readonly, retain) A *implicitGetOnlyInstance;
+@property (class, nonatomic, readonly, retain) A *implicitGetOnlyClass;
+
+@property (nonatomic, readwrite, retain) A *implicitGetSetInstance;
+@property (class, nonatomic, readwrite, retain) A *implicitGetSetClass;
+@end
+
+#endif
diff --git a/test/APINotes/Inputs/Frameworks/SomeKit.framework/Headers/SomeKitExplicitNullability.h b/test/APINotes/Inputs/Frameworks/SomeKit.framework/Headers/SomeKitExplicitNullability.h
new file mode 100644
index 0000000..40be241
--- /dev/null
+++ b/test/APINotes/Inputs/Frameworks/SomeKit.framework/Headers/SomeKitExplicitNullability.h
@@ -0,0 +1,5 @@
+@interface A(ExplicitNullabilityProperties)
+@property (nonatomic, readwrite, retain, nonnull) A *explicitNonnullInstance;
+@property (nonatomic, readwrite, retain, nullable) A *explicitNullableInstance;
+@end
+
diff --git a/test/APINotes/Inputs/Frameworks/SomeKit.framework/Headers/SomeKitForNullAnnotation.h b/test/APINotes/Inputs/Frameworks/SomeKit.framework/Headers/SomeKitForNullAnnotation.h
new file mode 100644
index 0000000..d1eeb61
--- /dev/null
+++ b/test/APINotes/Inputs/Frameworks/SomeKit.framework/Headers/SomeKitForNullAnnotation.h
@@ -0,0 +1,55 @@
+#ifndef SOMEKIT_H
+#define SOMEKIT_H
+
+#define ROOT_CLASS __attribute__((objc_root_class))
+
+ROOT_CLASS
+@interface A
+-(A*)transform:(A*)input;
+-(A*)transform:(A*)input integer:(int)integer;
+
+@property (nonatomic, readonly, retain) A* someA;
+@property (nonatomic, retain) A* someOtherA;
+
+@property (nonatomic) int intValue;
+@end
+
+@interface B : A
+@end
+
+@interface C : A
+- (instancetype)init;
+- (instancetype)initWithA:(A*)a;
+@end
+
+
+@interface MyClass : A
+- Inst;
++ Clas;
+@end
+
+struct CGRect {
+ float origin;
+ float size;
+};
+typedef struct CGRect NSRect;
+
+@interface I
+- (void) Meth : (NSRect[4])exposedRects;
+- (void) Meth1 : (const I*)exposedRects;
+- (void) Meth2 : (const I*)exposedRects;
+- (void) Meth3 : (I*)exposedRects;
+- (const I*) Meth4;
+- (const I*) Meth5 : (int) Arg1 : (const I*)Arg2 : (double)Arg3 : (const I*) Arg4 :(const volatile id) Arg5;
+- (volatile const I*) Meth6 : (const char *)Arg1 : (const char *)Arg2 : (double)Arg3 : (const I*) Arg4 :(const volatile id) Arg5;
+@end
+
+@class NSURL, NSArray, NSError;
+@interface INTF_BLOCKS
+ + (void)getNonLocalVersionsOfItemAtURL:(NSURL *)url completionHandler:(void (^)(NSArray *nonLocalFileVersions, NSError *error))completionHandler;
+ + (void *)getNonLocalVersionsOfItemAtURL2:(NSURL *)url completionHandler:(void (^)(NSArray *nonLocalFileVersions, NSError *error))completionHandler;
+ + (NSError **)getNonLocalVersionsOfItemAtURL3:(int)url completionHandler:(void (^)(NSArray *nonLocalFileVersions, NSError *error))completionHandler;
+ + (id)getNonLocalVersionsOfItemAtURL4:(NSURL *)url completionHandler:(void (^)(int nonLocalFileVersions, NSError *error, NSURL*))completionHandler;
+@end
+
+#endif
diff --git a/test/APINotes/Inputs/Frameworks/SomeKit.framework/Modules/module.modulemap b/test/APINotes/Inputs/Frameworks/SomeKit.framework/Modules/module.modulemap
new file mode 100644
index 0000000..3abee2d
--- /dev/null
+++ b/test/APINotes/Inputs/Frameworks/SomeKit.framework/Modules/module.modulemap
@@ -0,0 +1,5 @@
+framework module SomeKit {
+ umbrella header "SomeKit.h"
+ export *
+ module * { export * }
+}
diff --git a/test/APINotes/Inputs/Frameworks/SomeKit.framework/Modules/module.private.modulemap b/test/APINotes/Inputs/Frameworks/SomeKit.framework/Modules/module.private.modulemap
new file mode 100644
index 0000000..bbda9d0
--- /dev/null
+++ b/test/APINotes/Inputs/Frameworks/SomeKit.framework/Modules/module.private.modulemap
@@ -0,0 +1,8 @@
+module SomeKit.Private {
+ header "SomeKit_Private.h"
+ export *
+
+ explicit module NullAnnotation {
+ header "SomeKit_PrivateForNullAnnotation.h"
+ }
+}
diff --git a/test/APINotes/Inputs/Frameworks/SomeKit.framework/Modules/module_private.modulemap b/test/APINotes/Inputs/Frameworks/SomeKit.framework/Modules/module_private.modulemap
new file mode 100644
index 0000000..e310343
--- /dev/null
+++ b/test/APINotes/Inputs/Frameworks/SomeKit.framework/Modules/module_private.modulemap
@@ -0,0 +1,8 @@
+explicit framework module SomeKit.Private {
+ header "SomeKit_Private.h"
+ explicit NullAnnotation { header "SomeKit_PrivateForNullAnnotation.h" }
+ export *
+ module * { export * }
+syntax error
+
+}
diff --git a/test/APINotes/Inputs/Frameworks/SomeKit.framework/PrivateHeaders/SomeKit_Private.h b/test/APINotes/Inputs/Frameworks/SomeKit.framework/PrivateHeaders/SomeKit_Private.h
new file mode 100644
index 0000000..c761112
--- /dev/null
+++ b/test/APINotes/Inputs/Frameworks/SomeKit.framework/PrivateHeaders/SomeKit_Private.h
@@ -0,0 +1,16 @@
+#ifndef SOMEKIT_PRIVATE_H
+#define SOMEKIT_PRIVATE_H
+
+#import <SomeKit/SomeKit.h>
+
+@interface A(Private)
+-(A*)privateTransform:(A*)input;
+
+@property (nonatomic) A* internalProperty;
+@end
+
+@protocol InternalProtocol
+@end
+
+#endif
+
diff --git a/test/APINotes/Inputs/Frameworks/SomeKit.framework/PrivateHeaders/SomeKit_PrivateForNullAnnotation.h b/test/APINotes/Inputs/Frameworks/SomeKit.framework/PrivateHeaders/SomeKit_PrivateForNullAnnotation.h
new file mode 100644
index 0000000..bae4456
--- /dev/null
+++ b/test/APINotes/Inputs/Frameworks/SomeKit.framework/PrivateHeaders/SomeKit_PrivateForNullAnnotation.h
@@ -0,0 +1,17 @@
+#ifndef SOMEKIT_PRIVATE_H
+#define SOMEKIT_PRIVATE_H
+
+#import <SomeKit/SomeKitForNullAnnotation.h>
+
+@interface A(Private)
+-(A*)privateTransform:(A*)input;
+
+@property (nonatomic) A* internalProperty;
+@end
+
+@protocol InternalProtocol
+- (id) MomeMethod;
+@end
+
+#endif
+
diff --git a/test/APINotes/Inputs/Frameworks/SomeKit.framework/PrivateHeaders/SomeKit_private.apinotes b/test/APINotes/Inputs/Frameworks/SomeKit.framework/PrivateHeaders/SomeKit_private.apinotes
new file mode 100644
index 0000000..28ede9d
--- /dev/null
+++ b/test/APINotes/Inputs/Frameworks/SomeKit.framework/PrivateHeaders/SomeKit_private.apinotes
@@ -0,0 +1,15 @@
+Name: SomeKit
+Classes:
+ - Name: A
+ Methods:
+ - Selector: "privateTransform:input:"
+ MethodKind: Instance
+ NullabilityOfRet: N
+ Nullability: [ N, S ]
+ Properties:
+ - Name: internalProperty
+ Nullability: N
+Protocols:
+ - Name: InternalProtocol
+ Availability: none
+ AvailabilityMsg: "not for you"
diff --git a/test/APINotes/Inputs/Frameworks/SomeOtherKit.framework/APINotes/SomeOtherKit.apinotes b/test/APINotes/Inputs/Frameworks/SomeOtherKit.framework/APINotes/SomeOtherKit.apinotes
new file mode 100644
index 0000000..2ad546b
--- /dev/null
+++ b/test/APINotes/Inputs/Frameworks/SomeOtherKit.framework/APINotes/SomeOtherKit.apinotes
@@ -0,0 +1,8 @@
+Name: SomeOtherKit
+Classes:
+ - Name: A
+ Methods:
+ - Selector: "methodA"
+ MethodKind: Instance
+ Availability: none
+ AvailabilityMsg: "anything but this"
diff --git a/test/APINotes/Inputs/Frameworks/SomeOtherKit.framework/Headers/SomeOtherKit.apinotes b/test/APINotes/Inputs/Frameworks/SomeOtherKit.framework/Headers/SomeOtherKit.apinotes
new file mode 100644
index 0000000..2ad546b
--- /dev/null
+++ b/test/APINotes/Inputs/Frameworks/SomeOtherKit.framework/Headers/SomeOtherKit.apinotes
@@ -0,0 +1,8 @@
+Name: SomeOtherKit
+Classes:
+ - Name: A
+ Methods:
+ - Selector: "methodA"
+ MethodKind: Instance
+ Availability: none
+ AvailabilityMsg: "anything but this"
diff --git a/test/APINotes/Inputs/Frameworks/SomeOtherKit.framework/Headers/SomeOtherKit.h b/test/APINotes/Inputs/Frameworks/SomeOtherKit.framework/Headers/SomeOtherKit.h
new file mode 100644
index 0000000..3911d76
--- /dev/null
+++ b/test/APINotes/Inputs/Frameworks/SomeOtherKit.framework/Headers/SomeOtherKit.h
@@ -0,0 +1,9 @@
+#ifndef SOME_OTHER_KIT_H
+
+__attribute__((objc_root_class))
+@interface A
+-(void)methodA;
+-(void)methodB;
+@end
+
+#endif
diff --git a/test/APINotes/Inputs/Frameworks/SomeOtherKit.framework/Modules/module.modulemap b/test/APINotes/Inputs/Frameworks/SomeOtherKit.framework/Modules/module.modulemap
new file mode 100644
index 0000000..0aaad92
--- /dev/null
+++ b/test/APINotes/Inputs/Frameworks/SomeOtherKit.framework/Modules/module.modulemap
@@ -0,0 +1,5 @@
+framework module SomeOtherKit {
+ umbrella header "SomeOtherKit.h"
+ export *
+ module * { export * }
+}
diff --git a/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.apinotes b/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.apinotes
new file mode 100644
index 0000000..c3b70b6
--- /dev/null
+++ b/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.apinotes
@@ -0,0 +1,53 @@
+Name: VersionedKit
+Classes:
+ - Name: TestProperties
+ Properties:
+ - Name: accessorsOnly
+ PropertyKind: Instance
+ SwiftImportAsAccessors: true
+ - Name: accessorsOnlyForClass
+ PropertyKind: Class
+ SwiftImportAsAccessors: true
+ - Name: accessorsOnlyExceptInVersion3
+ PropertyKind: Instance
+ SwiftImportAsAccessors: true
+ - Name: accessorsOnlyForClassExceptInVersion3
+ PropertyKind: Class
+ SwiftImportAsAccessors: true
+SwiftVersions:
+ - Version: 3.0
+ Classes:
+ - Name: MyReferenceType
+ SwiftBridge: ''
+ - Name: TestProperties
+ Properties:
+ - Name: accessorsOnlyInVersion3
+ PropertyKind: Instance
+ SwiftImportAsAccessors: true
+ - Name: accessorsOnlyForClassInVersion3
+ PropertyKind: Class
+ SwiftImportAsAccessors: true
+ - Name: accessorsOnlyExceptInVersion3
+ PropertyKind: Instance
+ SwiftImportAsAccessors: false
+ - Name: accessorsOnlyForClassExceptInVersion3
+ PropertyKind: Class
+ SwiftImportAsAccessors: false
+ Functions:
+ - Name: moveToPoint
+ SwiftName: 'moveTo(a:b:)'
+ - Name: acceptClosure
+ Parameters:
+ - Position: 0
+ NoEscape: false
+ - Name: privateFunc
+ SwiftPrivate: false
+ Tags:
+ - Name: MyErrorCode
+ NSErrorDomain: ''
+ Typedefs:
+ - Name: MyDoubleWrapper
+ SwiftWrapper: none
+
+
+
\ No newline at end of file
diff --git a/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.h b/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.h
new file mode 100644
index 0000000..ffbc7df
--- /dev/null
+++ b/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.h
@@ -0,0 +1,30 @@
+void moveToPoint(double x, double y) __attribute__((swift_name("moveTo(x:y:)")));
+
+void acceptClosure(void (^ __attribute__((noescape)) block)(void));
+
+@class NSString;
+
+extern NSString *MyErrorDomain;
+
+enum __attribute__((ns_error_domain(MyErrorDomain))) MyErrorCode {
+ MyErrorCodeFailed = 1
+};
+
+__attribute__((swift_bridge("MyValueType")))
+@interface MyReferenceType
+@end
+
+void privateFunc(void) __attribute__((swift_private));
+
+typedef double MyDoubleWrapper __attribute__((swift_wrapper(struct)));
+
+@interface TestProperties
+@property (nonatomic, readwrite, retain) id accessorsOnly;
+@property (nonatomic, readwrite, retain, class) id accessorsOnlyForClass;
+
+@property (nonatomic, readwrite, retain) id accessorsOnlyInVersion3;
+@property (nonatomic, readwrite, retain, class) id accessorsOnlyForClassInVersion3;
+
+@property (nonatomic, readwrite, retain) id accessorsOnlyExceptInVersion3;
+@property (nonatomic, readwrite, retain, class) id accessorsOnlyForClassExceptInVersion3;
+@end
diff --git a/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Modules/module.modulemap b/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Modules/module.modulemap
new file mode 100644
index 0000000..6d957fd
--- /dev/null
+++ b/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Modules/module.modulemap
@@ -0,0 +1,5 @@
+framework module VersionedKit {
+ umbrella header "VersionedKit.h"
+ export *
+ module * { export * }
+}
diff --git a/test/APINotes/Inputs/Headers/APINotes.apinotes b/test/APINotes/Inputs/Headers/APINotes.apinotes
new file mode 100644
index 0000000..08210fc
--- /dev/null
+++ b/test/APINotes/Inputs/Headers/APINotes.apinotes
@@ -0,0 +1,18 @@
+Name: HeaderLib
+SwiftInferImportAsMember: true
+Functions:
+ - Name: custom_realloc
+ NullabilityOfRet: N
+ Nullability: [ N, S ]
+ - Name: unavailable_function
+ Availability: none
+ AvailabilityMsg: "I beg you not to use this"
+ - Name: do_something_with_pointers
+ NullabilityOfRet: O
+ Nullability: [ N, O ]
+
+Globals:
+ - Name: global_int
+ Nullability: N
+ - Name: unavailable_global_int
+ Availability: none
diff --git a/test/APINotes/Inputs/Headers/BrokenTypes.apinotes b/test/APINotes/Inputs/Headers/BrokenTypes.apinotes
new file mode 100644
index 0000000..00f7b50
--- /dev/null
+++ b/test/APINotes/Inputs/Headers/BrokenTypes.apinotes
@@ -0,0 +1,10 @@
+Name: BrokenTypes
+Functions:
+ - Name: break_me_function
+ ResultType: 'int * with extra junk'
+ Parameters:
+ - Position: 0
+ Type: 'not_a_type'
+Globals:
+ - Name: break_me_variable
+ Type: 'double'
diff --git a/test/APINotes/Inputs/Headers/BrokenTypes.h b/test/APINotes/Inputs/Headers/BrokenTypes.h
new file mode 100644
index 0000000..fee054b
--- /dev/null
+++ b/test/APINotes/Inputs/Headers/BrokenTypes.h
@@ -0,0 +1,8 @@
+#ifndef BROKEN_TYPES_H
+#define BROKEN_TYPES_H
+
+char break_me_function(void *ptr);
+
+extern char break_me_variable;
+
+#endif // BROKEN_TYPES_H
diff --git a/test/APINotes/Inputs/Headers/HeaderLib.apinotes b/test/APINotes/Inputs/Headers/HeaderLib.apinotes
new file mode 100644
index 0000000..c822964
--- /dev/null
+++ b/test/APINotes/Inputs/Headers/HeaderLib.apinotes
@@ -0,0 +1,37 @@
+Name: HeaderLib
+SwiftInferImportAsMember: true
+Functions:
+ - Name: custom_realloc
+ NullabilityOfRet: N
+ Nullability: [ N, S ]
+ - Name: unavailable_function
+ Availability: none
+ AvailabilityMsg: "I beg you not to use this"
+ - Name: do_something_with_pointers
+ NullabilityOfRet: O
+ Nullability: [ N, O ]
+ - Name: do_something_with_arrays
+ Parameters:
+ - Position: 0
+ Nullability: N
+ - Position: 1
+ Nullability: N
+ - Name: take_pointer_and_int
+ Parameters:
+ - Position: 0
+ Nullability: N
+ NoEscape: true
+ - Position: 1
+ NoEscape: true
+Globals:
+ - Name: global_int
+ Nullability: N
+ - Name: unavailable_global_int
+ Availability: none
+Tags:
+ - Name: unavailable_struct
+ Availability: none
+
+Typedefs:
+ - Name: unavailable_typedef
+ Availability: none
\ No newline at end of file
diff --git a/test/APINotes/Inputs/Headers/HeaderLib.h b/test/APINotes/Inputs/Headers/HeaderLib.h
new file mode 100644
index 0000000..8065249
--- /dev/null
+++ b/test/APINotes/Inputs/Headers/HeaderLib.h
@@ -0,0 +1,19 @@
+#ifndef HEADER_LIB_H
+#define HEADER_LIB_H
+
+void *custom_realloc(void *member, unsigned size);
+
+int *global_int;
+
+int unavailable_function(void);
+int unavailable_global_int;
+
+void do_something_with_pointers(int *ptr1, int *ptr2);
+void do_something_with_arrays(int simple[], int nested[][2]);
+
+typedef int unavailable_typedef;
+struct unavailable_struct { int x, y, z; };
+
+void take_pointer_and_int(int *ptr1, int value);
+
+#endif
diff --git a/test/APINotes/Inputs/Headers/module.modulemap b/test/APINotes/Inputs/Headers/module.modulemap
new file mode 100644
index 0000000..54af0f5
--- /dev/null
+++ b/test/APINotes/Inputs/Headers/module.modulemap
@@ -0,0 +1,7 @@
+module HeaderLib {
+ header "HeaderLib.h"
+}
+
+module BrokenTypes {
+ header "BrokenTypes.h"
+}
diff --git a/test/APINotes/Inputs/os-availability.apinotes b/test/APINotes/Inputs/os-availability.apinotes
new file mode 100644
index 0000000..d59e79c
--- /dev/null
+++ b/test/APINotes/Inputs/os-availability.apinotes
@@ -0,0 +1,53 @@
+Name: Foundation
+Classes:
+ - Name: NSCountedSet
+ Availability: iOS
+ Methods:
+ - Selector: 'initWithCapacity:'
+ MethodKind: Instance
+ DesignatedInit: true
+ - Name: NSArray
+ Methods:
+ - Selector: 'init'
+ MethodKind: Instance
+ DesignatedInit: true
+ - Selector: 'initWithObjects:'
+ MethodKind: Instance
+ DesignatedInit: true
+ Availability: iOS
+ - Selector: 'initWithObjects:count:'
+ MethodKind: Instance
+ DesignatedInit: true
+ Availability: iOS
+ Properties:
+ - Name: 'familyNameios'
+ Nullability: N
+ Availability: iOS
+ - Name: 'fontName'
+ Nullability: N
+Protocols:
+ - Name: UIApplicationDelegate
+ AuditedForNullability: true
+ Methods:
+ - Selector: 'application:willFinishLaunchingWithOptions:'
+ MethodKind: Instance
+ Nullability: [ N, U ]
+ - Name: UIApplicationDelegateIOS
+ Availability: iOS
+ AuditedForNullability: true
+ Methods:
+ - Selector: 'application:willFinishLaunchingWithOptions:'
+ MethodKind: Instance
+ Nullability: [ N, U ]
+Functions:
+ - Name: NSAvailableWindowDepthsiOS
+ NullabilityOfRet: N
+ Availability: iOS
+ - Name: NSAvailableWindowDepths
+ NullabilityOfRet: N
+Globals:
+ - Name: NSCalibratedWhiteColorSpace
+ Nullability: N
+ Availability: OSX
+ AvailabilityMsg: ''
+
diff --git a/test/APINotes/Inputs/roundtrip.apinotes b/test/APINotes/Inputs/roundtrip.apinotes
new file mode 100644
index 0000000..05599a7
--- /dev/null
+++ b/test/APINotes/Inputs/roundtrip.apinotes
@@ -0,0 +1,181 @@
+---
+Name: AppKit
+Availability: available
+AvailabilityMsg: ''
+SwiftInferImportAsMember: true
+Classes:
+ - Name: NSCell
+ Availability: available
+ AvailabilityMsg: ''
+ SwiftPrivate: false
+ SwiftName: ''
+ Methods:
+ - Selector: 'cellWithImage:'
+ MethodKind: Class
+ Availability: available
+ AvailabilityMsg: ''
+ SwiftPrivate: false
+ SwiftName: ''
+ FactoryAsInit: C
+ ResultType: id
+ - Selector: init
+ MethodKind: Instance
+ NullabilityOfRet: U
+ Availability: available
+ AvailabilityMsg: ''
+ SwiftPrivate: true
+ SwiftName: ''
+ DesignatedInit: true
+ - Selector: 'initImageCell:'
+ MethodKind: Instance
+ Nullability: [ N ]
+ NullabilityOfRet: U
+ Availability: available
+ AvailabilityMsg: ''
+ SwiftPrivate: false
+ SwiftName: ''
+ DesignatedInit: true
+ - Selector: 'initTextCell:'
+ MethodKind: Instance
+ Nullability: [ N ]
+ NullabilityOfRet: U
+ Availability: available
+ AvailabilityMsg: ''
+ SwiftPrivate: false
+ SwiftName: ''
+ DesignatedInit: true
+ - Selector: 'initWithCoder:'
+ MethodKind: Instance
+ Nullability: [ N ]
+ NullabilityOfRet: U
+ Availability: available
+ AvailabilityMsg: ''
+ SwiftPrivate: false
+ SwiftName: ''
+ DesignatedInit: true
+ Required: true
+ - Name: NSView
+ AuditedForNullability: true
+ Availability: available
+ AvailabilityMsg: ''
+ SwiftPrivate: false
+ SwiftName: ''
+ SwiftBridge: View
+ Methods:
+ - Selector: 'addSubview:'
+ MethodKind: Instance
+ Nullability: [ N ]
+ NullabilityOfRet: N
+ Availability: available
+ AvailabilityMsg: ''
+ SwiftPrivate: false
+ SwiftName: ''
+ - Selector: 'addSubview:positioned:relativeTo:'
+ MethodKind: Instance
+ Parameters:
+ - Position: 0
+ NoEscape: false
+ - Position: 1
+ - Position: 2
+ NoEscape: true
+ Type: id
+ Nullability: [ N, N, O ]
+ NullabilityOfRet: N
+ Availability: available
+ AvailabilityMsg: ''
+ SwiftName: ''
+ - Selector: 'beginDraggingSessionWithItems:event:source:'
+ MethodKind: Instance
+ Nullability: [ U, U, N ]
+ NullabilityOfRet: N
+ Availability: available
+ AvailabilityMsg: ''
+ SwiftPrivate: false
+ SwiftName: 'beginDragginSession(_:event:source:)'
+ Properties:
+ - Name: enclosingScrollView
+ PropertyKind: Instance
+ Nullability: O
+ Availability: available
+ AvailabilityMsg: ''
+ SwiftName: enclosing
+ Type: id
+ - Name: makeBackingLayer
+ PropertyKind: Class
+ Nullability: N
+ Availability: available
+ AvailabilityMsg: ''
+ SwiftPrivate: false
+ SwiftName: ''
+ SwiftImportAsAccessors: false
+Functions:
+ - Name: NSAvailableWindowDepths
+ NullabilityOfRet: N
+ Availability: available
+ AvailabilityMsg: ''
+ SwiftName: 'availableWindowDepths()'
+ ResultType: NSInteger
+Globals:
+ - Name: NSCalibratedWhiteColorSpace
+ Nullability: N
+ Availability: available
+ AvailabilityMsg: ''
+ SwiftPrivate: false
+ SwiftName: calibratedWhite
+ Type: id
+Enumerators:
+ - Name: NSColorRed
+ Availability: available
+ AvailabilityMsg: ''
+ SwiftPrivate: false
+ SwiftName: Red
+Tags:
+ - Name: NSSomeEnum
+ Availability: available
+ AvailabilityMsg: ''
+ SwiftPrivate: false
+ SwiftName: SomeEnum
+ NSErrorDomain: some_error_domain
+ - Name: NSSomeStruct
+ Availability: available
+ AvailabilityMsg: ''
+ SwiftPrivate: false
+ SwiftName: SomeStruct
+ NSErrorDomain: ''
+Typedefs:
+ - Name: NSTypedef
+ Availability: available
+ AvailabilityMsg: ''
+ SwiftPrivate: false
+ SwiftName: Typedef
+ SwiftBridge: ''
+ SwiftWrapper: struct
+SwiftVersions:
+ - Version: 3.0
+ Classes:
+ - Name: NSCell
+ Availability: available
+ AvailabilityMsg: ''
+ SwiftPrivate: false
+ SwiftName: NSBox
+ SwiftBridge: ''
+ Methods:
+ - Selector: init
+ MethodKind: Instance
+ NullabilityOfRet: N
+ Availability: available
+ AvailabilityMsg: ''
+ SwiftPrivate: true
+ SwiftName: ''
+ DesignatedInit: true
+ - Name: NSView
+ Availability: available
+ AvailabilityMsg: ''
+ SwiftName: ''
+ Properties:
+ - Name: makeBackingLayer
+ PropertyKind: Class
+ Availability: available
+ AvailabilityMsg: ''
+ SwiftName: ''
+ SwiftImportAsAccessors: true
diff --git a/test/APINotes/availability.m b/test/APINotes/availability.m
new file mode 100644
index 0000000..f9bee1a
--- /dev/null
+++ b/test/APINotes/availability.m
@@ -0,0 +1,48 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -verify
+
+#include "HeaderLib.h"
+#import <SomeKit/SomeKit.h>
+#import <SomeKit/SomeKit_Private.h>
+
+int main() {
+ int i;
+ i = unavailable_function(); // expected-error{{'unavailable_function' is unavailable: I beg you not to use this}}
+ // expected-note@HeaderLib.h:8{{'unavailable_function' has been explicitly marked unavailable here}}
+ i = unavailable_global_int; // expected-error{{'unavailable_global_int' is unavailable}}
+ // expected-note@HeaderLib.h:9{{'unavailable_global_int' has been explicitly marked unavailable here}}
+
+ unavailable_typedef t; // expected-error{{'unavailable_typedef' is unavailable}}
+ // expected-note@HeaderLib.h:14{{'unavailable_typedef' has been explicitly marked unavailable here}}
+
+ struct unavailable_struct s; // expected-error{{'unavailable_struct' is unavailable}}
+ // expected-note@HeaderLib.h:15{{'unavailable_struct' has been explicitly marked unavailable here}}
+
+ B *b = 0; // expected-error{{'B' is unavailable: just don't}}
+ // expected-note@SomeKit/SomeKit.h:15{{'B' has been explicitly marked unavailable here}}
+
+ id<InternalProtocol> proto = 0; // expected-error{{'InternalProtocol' is unavailable: not for you}}
+ // expected-note@SomeKit/SomeKit_Private.h:12{{'InternalProtocol' has been explicitly marked unavailable here}}
+
+ A *a = 0;
+ i = a.intValue; // expected-error{{intValue' is unavailable: wouldn't work anyway}}
+ // expected-note@SomeKit/SomeKit.h:12{{'intValue' has been explicitly marked unavailable here}}
+
+ [a transform:a]; // expected-error{{'transform:' is unavailable: anything but this}}
+ // expected-note@SomeKit/SomeKit.h:6{{'transform:' has been explicitly marked unavailable here}}
+
+ [a implicitGetOnlyInstance]; // expected-error{{'implicitGetOnlyInstance' is unavailable: getter gone}}
+ // expected-note@SomeKit/SomeKit.h:53{{'implicitGetOnlyInstance' has been explicitly marked unavailable here}}
+ [A implicitGetOnlyClass]; // expected-error{{'implicitGetOnlyClass' is unavailable: getter gone}}
+ // expected-note@SomeKit/SomeKit.h:54{{'implicitGetOnlyClass' has been explicitly marked unavailable here}}
+ [a implicitGetSetInstance]; // expected-error{{'implicitGetSetInstance' is unavailable: getter gone}}
+ // expected-note@SomeKit/SomeKit.h:56{{'implicitGetSetInstance' has been explicitly marked unavailable here}}
+ [a setImplicitGetSetInstance: a]; // expected-error{{'setImplicitGetSetInstance:' is unavailable: setter gone}}
+ // expected-note@SomeKit/SomeKit.h:56{{'setImplicitGetSetInstance:' has been explicitly marked unavailable here}}
+ [A implicitGetSetClass]; // expected-error{{'implicitGetSetClass' is unavailable: getter gone}}
+ // expected-note@SomeKit/SomeKit.h:57{{'implicitGetSetClass' has been explicitly marked unavailable here}}
+ [A setImplicitGetSetClass: a]; // expected-error{{'setImplicitGetSetClass:' is unavailable: setter gone}}
+ // expected-note@SomeKit/SomeKit.h:57{{'setImplicitGetSetClass:' has been explicitly marked unavailable here}}
+ return 0;
+}
+
diff --git a/test/APINotes/broken_types.m b/test/APINotes/broken_types.m
new file mode 100644
index 0000000..164ae79
--- /dev/null
+++ b/test/APINotes/broken_types.m
@@ -0,0 +1,19 @@
+// RUN: rm -rf %t && mkdir -p %t
+// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s 2> %t.err
+// RUN: FileCheck %s < %t.err
+
+#include "BrokenTypes.h"
+
+// CHECK: <API Notes>:1:1: error: unknown type name 'not_a_type'
+// CHECK-NEXT: not_a_type
+// CHECK-NEXT: ^
+
+// CHECK: <API Notes>:1:7: error: unparsed tokens following type
+// CHECK-NEXT: int * with extra junk
+// CHECK-NEXT: ^
+
+// CHECK: BrokenTypes.h:4:6: error: API notes replacement type 'int *' has a different size from original type 'char'
+
+// CHECK: BrokenTypes.h:6:13: error: API notes replacement type 'double' has a different size from original type 'char'
+
+// CHECK: 5 errors generated.
diff --git a/test/APINotes/cache.m b/test/APINotes/cache.m
new file mode 100644
index 0000000..b87bdf1
--- /dev/null
+++ b/test/APINotes/cache.m
@@ -0,0 +1,32 @@
+// RUN: rm -rf %t/APINotesCache
+// RUN: %clang_cc1 -fapinotes -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -verify
+
+// Check for the presence of the cached compiled form.
+// RUN: ls %t/APINotesCache | grep "APINotes-.*.apinotesc"
+// RUN: ls %t/APINotesCache | grep "SomeKit-.*.apinotesc"
+
+// Run test again to ensure that caching doesn't cause problems.
+// RUN: %clang_cc1 -fapinotes -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -verify
+
+// Check that the driver provides a default -fapinotes-cache-path=
+// RUN: %clang -fsyntax-only -fapinotes -fapinotes-modules -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -### 2>&1 | FileCheck --check-prefix=CHECK-DEFAULT-PATH %s
+// CHECK-DEFAULT-PATH: -fapinotes-cache-path={{.*}}org.llvm.clang/APINotesCache
+
+// Check that the driver passes through a provided -fapinotes-cache-path=
+// RUN: %clang -fsyntax-only -fapinotes -fapinotes-modules -fapinotes-cache-path=/wobble -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -### 2>&1 | FileCheck --check-prefix=CHECK-PATH %s
+// CHECK-PATH: -fapinotes-cache-path=/wobble
+
+#include "HeaderLib.h"
+#import <SomeKit/SomeKit.h>
+
+int main() {
+ int i;
+ i = unavailable_function(); // expected-error{{'unavailable_function' is unavailable: I beg you not to use this}}
+ // expected-note@HeaderLib.h:8{{'unavailable_function' has been explicitly marked unavailable here}}
+
+ A *a = 0;
+ [a transform:a]; // expected-error{{'transform:' is unavailable: anything but this}}
+ // expected-note@SomeKit/SomeKit.h:6{{'transform:' has been explicitly marked unavailable here}}
+
+ return 0;
+}
diff --git a/test/APINotes/cache_pruning.m b/test/APINotes/cache_pruning.m
new file mode 100644
index 0000000..1a36570
--- /dev/null
+++ b/test/APINotes/cache_pruning.m
@@ -0,0 +1,49 @@
+// We need 'touch' and 'find' for this test to work.
+// REQUIRES: shell
+
+// RUN: rm -rf %t/APINotesCache
+
+// Run Clang. This should generated the cached versions of both and a timestamp.
+// RUN: %clang_cc1 -fapinotes -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -DINCLUDE_HEADERLIB
+// RUN: ls %t/APINotesCache | grep "APINotes-.*.apinotesc"
+// RUN: ls %t/APINotesCache | grep "SomeKit-.*.apinotesc"
+// RUN: ls %t/APINotesCache | grep "APINotes.timestamp"
+
+// Set the timestamp back a very long time. We should try to prune,
+// but nothing gets pruned because the API Notes files are new enough.
+// RUN: touch -m -a -t 201101010000 %t/APINotes.timestamp
+// RUN: %clang_cc1 -fapinotes -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s
+// RUN: ls %t/APINotesCache | grep "APINotes-.*.apinotesc"
+// RUN: ls %t/APINotesCache | grep "SomeKit-.*.apinotesc"
+// RUN: ls %t/APINotesCache | grep "APINotes.timestamp"
+
+// Set the HeaderLib access time back a very long time.
+// This shouldn't prune anything, because the timestamp has been updated, so
+// the pruning mechanism won't fire.
+// RUN: find %t/APINotesCache -name APINotes-*.apinotesc | xargs touch -a -t 201101010000
+// RUN: %clang_cc1 -fapinotes -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s
+// RUN: ls %t/APINotesCache | grep "APINotes-.*.apinotesc"
+// RUN: ls %t/APINotesCache | grep "SomeKit-.*.apinotesc"
+// RUN: ls %t/APINotesCache | grep "APINotes.timestamp"
+
+// Set the timestack back a very long time. This should prune the
+// HeaderLib file, because the pruning mechanism should fire and
+// HeaderLib is both old and not used.
+// RUN: touch -m -a -t 201101010000 %t/APINotesCache/APINotes.timestamp
+// RUN: %clang_cc1 -fapinotes -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s
+// RUN: ls %t/APINotesCache | not grep "APINotes-.*.apinotesc"
+// RUN: ls %t/APINotesCache | grep "SomeKit-.*.apinotesc"
+// RUN: ls %t/APINotesCache | grep "APINotes.timestamp"
+
+// Run Clang. This should generated the cached versions of both and a timestamp.
+// RUN: %clang_cc1 -fapinotes -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -DINCLUDE_HEADERLIB
+// RUN: ls %t/APINotesCache | grep "APINotes-.*.apinotesc"
+// RUN: ls %t/APINotesCache | grep "SomeKit-.*.apinotesc"
+// RUN: ls %t/APINotesCache | grep "APINotes.timestamp"
+
+#ifdef INCLUDE_HEADERLIB
+#include "HeaderLib.h"
+#endif
+#include <SomeKit/SomeKit.h>
+
+int main() { return 0; }
diff --git a/test/APINotes/module-cache.m b/test/APINotes/module-cache.m
new file mode 100644
index 0000000..2324697
--- /dev/null
+++ b/test/APINotes/module-cache.m
@@ -0,0 +1,90 @@
+// RUN: rm -rf %t
+
+// Set up a directory with API notes
+// RUN: mkdir -p %t/APINotes
+// RUN: cp %S/Inputs/APINotes/SomeOtherKit.apinotes %t/APINotes/SomeOtherKit.apinotes
+
+// First build: check that 'methodB' is unavailable but 'methodA' is available.
+// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -Rmodule-build -fmodules-cache-path=%t/ModulesCache -iapinotes-modules %t/APINotes -fapinotes-cache-path=%t/APINotesCache -F %S/Inputs/Frameworks %s > %t/before.log 2>&1
+// RUN: FileCheck -check-prefix=CHECK-METHODB %s < %t/before.log
+// RUN: FileCheck -check-prefix=CHECK-REBUILD %s < %t/before.log
+// RUN: FileCheck -check-prefix=CHECK-ONE-ERROR %s < %t/before.log
+
+// Do it again; now we're using caches.
+// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -Rmodule-build -fmodules-cache-path=%t/ModulesCache -iapinotes-modules %t/APINotes -fapinotes-cache-path=%t/APINotesCache -F %S/Inputs/Frameworks %s > %t/before.log 2>&1
+// RUN: FileCheck -check-prefix=CHECK-METHODB %s < %t/before.log
+// RUN: FileCheck -check-prefix=CHECK-WITHOUT-REBUILD %s < %t/before.log
+// RUN: FileCheck -check-prefix=CHECK-ONE-ERROR %s < %t/before.log
+
+// Change the API notes file.
+// RUN: echo ' - Selector: "methodA"' >> %t/APINotes/SomeOtherKit.apinotes
+// RUN: echo ' MethodKind: Instance' >> %t/APINotes/SomeOtherKit.apinotes
+// RUN: echo ' Availability: none' >> %t/APINotes/SomeOtherKit.apinotes
+// RUN: echo ' AvailabilityMsg: "not here either"' >> %t/APINotes/SomeOtherKit.apinotes
+
+// Build again: check that both methods are now unavailable and that the module rebuilt.
+// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -Rmodule-build -fmodules-cache-path=%t/ModulesCache -iapinotes-modules %t/APINotes -fapinotes-cache-path=%t/APINotesCache -F %S/Inputs/Frameworks %s > %t/after.log 2>&1
+// RUN: FileCheck -check-prefix=CHECK-METHODA %s < %t/after.log
+// RUN: FileCheck -check-prefix=CHECK-METHODB %s < %t/after.log
+// RUN: FileCheck -check-prefix=CHECK-REBUILD %s < %t/after.log
+// RUN: FileCheck -check-prefix=CHECK-TWO-ERRORS %s < %t/after.log
+
+// Run the build again: check that both methods are now unavailable
+// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -Rmodule-build -fmodules-cache-path=%t/ModulesCache -iapinotes-modules %t/APINotes -fapinotes-cache-path=%t/APINotesCache -F %S/Inputs/Frameworks %s > %t/after.log 2>&1
+// RUN: FileCheck -check-prefix=CHECK-METHODA %s < %t/after.log
+// RUN: FileCheck -check-prefix=CHECK-METHODB %s < %t/after.log
+// RUN: FileCheck -check-prefix=CHECK-WITHOUT-REBUILD %s < %t/after.log
+// RUN: FileCheck -check-prefix=CHECK-TWO-ERRORS %s < %t/after.log
+
+// Set up a directory with pre-compiled API notes.
+// RUN: mkdir -p %t/CompiledAPINotes
+// RUN: rm -rf %t/ModulesCache
+// RUN: rm -rf %t/APINotesCache
+// RUN: %clang -cc1apinotes -yaml-to-binary -o %t/CompiledAPINotes/SomeOtherKit.apinotesc %S/Inputs/APINotes/SomeOtherKit.apinotes
+
+// First build: check that 'methodB' is unavailable but 'methodA' is available.
+// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -Rmodule-build -fmodules-cache-path=%t/ModulesCache -iapinotes-modules %t/CompiledAPINotes -fapinotes-cache-path=%t/APINotesCache -F %S/Inputs/Frameworks %s > %t/compiled-before.log 2>&1
+// RUN: FileCheck -check-prefix=CHECK-METHODB %s < %t/compiled-before.log
+// RUN: FileCheck -check-prefix=CHECK-REBUILD %s < %t/compiled-before.log
+// RUN: FileCheck -check-prefix=CHECK-ONE-ERROR %s < %t/compiled-before.log
+
+// Do it again; now we're using caches.
+// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -Rmodule-build -fmodules-cache-path=%t/ModulesCache -iapinotes-modules %t/CompiledAPINotes -fapinotes-cache-path=%t/APINotesCache -F %S/Inputs/Frameworks %s > %t/compiled-before.log 2>&1
+// RUN: FileCheck -check-prefix=CHECK-METHODB %s < %t/compiled-before.log
+// RUN: FileCheck -check-prefix=CHECK-WITHOUT-REBUILD %s < %t/compiled-before.log
+// RUN: FileCheck -check-prefix=CHECK-ONE-ERROR %s < %t/compiled-before.log
+
+// Compile a new API notes file to replace the old one.
+// RUN: %clang -cc1apinotes -yaml-to-binary -o %t/CompiledAPINotes/SomeOtherKit.apinotesc %t/APINotes/SomeOtherKit.apinotes
+
+// Build again: check that both methods are now unavailable and that the module rebuilt.
+// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -Rmodule-build -fmodules-cache-path=%t/ModulesCache -iapinotes-modules %t/CompiledAPINotes -fapinotes-cache-path=%t/APINotesCache -F %S/Inputs/Frameworks %s > %t/compiled-after.log 2>&1
+// RUN: FileCheck -check-prefix=CHECK-METHODA %s < %t/compiled-after.log
+// RUN: FileCheck -check-prefix=CHECK-METHODB %s < %t/compiled-after.log
+// RUN: FileCheck -check-prefix=CHECK-REBUILD %s < %t/compiled-after.log
+// RUN: FileCheck -check-prefix=CHECK-TWO-ERRORS %s < %t/compiled-after.log
+
+// Run the build again: check that both methods are now unavailable
+// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -Rmodule-build -fmodules-cache-path=%t/ModulesCache -iapinotes-modules %t/CompiledAPINotes -fapinotes-cache-path=%t/APINotesCache -F %S/Inputs/Frameworks %s > %t/compiled-after.log 2>&1
+// RUN: FileCheck -check-prefix=CHECK-METHODA %s < %t/compiled-after.log
+// RUN: FileCheck -check-prefix=CHECK-METHODB %s < %t/compiled-after.log
+// RUN: FileCheck -check-prefix=CHECK-WITHOUT-REBUILD %s < %t/compiled-after.log
+// RUN: FileCheck -check-prefix=CHECK-TWO-ERRORS %s < %t/compiled-after.log
+
+@import SomeOtherKit;
+
+void test(A *a) {
+ // CHECK-METHODA: error: 'methodA' is unavailable: not here either
+ [a methodA];
+
+ // CHECK-METHODB: error: 'methodB' is unavailable: anything but this
+ [a methodB];
+}
+
+// CHECK-REBUILD: remark: building module{{.*}}SomeOtherKit
+
+// CHECK-WITHOUT-REBUILD-NOT: remark: building module{{.*}}SomeOtherKit
+
+// CHECK-ONE-ERROR: 1 error generated.
+// CHECK-TWO-ERRORS: 2 errors generated.
+
diff --git a/test/APINotes/nullability.c b/test/APINotes/nullability.c
new file mode 100644
index 0000000..1fcd0ee
--- /dev/null
+++ b/test/APINotes/nullability.c
@@ -0,0 +1,21 @@
+// RUN: rm -rf %t && mkdir -p %t
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -verify
+
+#include "HeaderLib.h"
+
+int main() {
+ custom_realloc(0, 0); // expected-warning{{null passed to a callee that requires a non-null argument}}
+ int i = 0;
+ do_something_with_pointers(&i, 0);
+ do_something_with_pointers(0, &i); // expected-warning{{null passed to a callee that requires a non-null argument}}
+
+ extern void *p;
+ do_something_with_arrays(0, p); // expected-warning{{null passed to a callee that requires a non-null argument}}
+ do_something_with_arrays(p, 0); // expected-warning{{null passed to a callee that requires a non-null argument}}
+
+ take_pointer_and_int(0, 0); // expected-warning{{null passed to a callee that requires a non-null argument}}
+
+ float *fp = global_int; // expected-warning{{incompatible pointer types initializing 'float *' with an expression of type 'int * _Nonnull'}}
+ return 0;
+}
+
diff --git a/test/APINotes/nullability.m b/test/APINotes/nullability.m
new file mode 100644
index 0000000..f70c363
--- /dev/null
+++ b/test/APINotes/nullability.m
@@ -0,0 +1,44 @@
+// RUN: rm -rf %t && mkdir -p %t
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -verify
+
+// Test with Swift version 3.0. This should only affect the few APIs that have an entry in the 3.0 tables.
+
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -fapinotes-swift-version=3.0 -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -verify -DSWIFT_VERSION_3_0 -fmodules-ignore-macro=SWIFT_VERSION_3_0
+
+#import <SomeKit/SomeKit.h>
+
+int main() {
+ A *a;
+
+#if SWIFT_VERSION_3_0
+ float *fp = // expected-warning{{incompatible pointer types initializing 'float *' with an expression of type 'A * _Nullable'}}
+ [a transform: 0 integer: 0];
+#else
+ float *fp = // expected-warning{{incompatible pointer types initializing 'float *' with an expression of type 'A *'}}
+ [a transform: 0 integer: 0]; // expected-warning{{null passed to a callee that requires a non-null argument}}
+#endif
+
+ [a setNonnullAInstance: 0]; // expected-warning{{null passed to a callee that requires a non-null argument}}
+ [A setNonnullAInstance: 0]; // no warning
+
+ [a setNonnullAClass: 0]; // no warning
+ [A setNonnullAClass: 0]; // expected-warning{{null passed to a callee that requires a non-null argument}}
+
+ [a setNonnullABoth: 0]; // expected-warning{{null passed to a callee that requires a non-null argument}}
+ [A setNonnullABoth: 0]; // expected-warning{{null passed to a callee that requires a non-null argument}}
+
+ [a setInternalProperty: 0]; // expected-warning{{null passed to a callee that requires a non-null argument}}
+
+#if SWIFT_VERSION_3_0
+ // Version 3 information overrides header information.
+ [a setExplicitNonnullInstance: 0]; // okay
+ [a setExplicitNullableInstance: 0]; // expected-warning{{null passed to a callee that requires a non-null argument}}
+#else
+ // Header information overrides unversioned information.
+ [a setExplicitNonnullInstance: 0]; // expected-warning{{null passed to a callee that requires a non-null argument}}
+ [a setExplicitNullableInstance: 0]; // okay
+#endif
+
+ return 0;
+}
+
diff --git a/test/APINotes/objc_designated_inits.m b/test/APINotes/objc_designated_inits.m
new file mode 100644
index 0000000..1df8cf8
--- /dev/null
+++ b/test/APINotes/objc_designated_inits.m
@@ -0,0 +1,17 @@
+// RUN: rm -rf %t && mkdir -p %t
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -verify
+
+#include "HeaderLib.h"
+#import <SomeKit/SomeKit.h>
+
+@interface CSub : C
+-(instancetype)initWithA:(A*)a;
+@end
+
+@implementation CSub
+-(instancetype)initWithA:(A*)a { // expected-warning{{designated initializer missing a 'super' call to a designated initializer of the super class}}
+ // expected-note@SomeKit/SomeKit.h:20 2{{method marked as designated initializer of the class here}}
+ self = [super init]; // expected-warning{{designated initializer invoked a non-designated initializer}}
+ return self;
+}
+@end
diff --git a/test/APINotes/properties.m b/test/APINotes/properties.m
new file mode 100644
index 0000000..b1559b9
--- /dev/null
+++ b/test/APINotes/properties.m
@@ -0,0 +1,45 @@
+// RUN: rm -rf %t && mkdir -p %t
+
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -fblocks -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -ast-dump -ast-dump-filter 'TestProperties::' | FileCheck -check-prefix=CHECK -check-prefix=CHECK-4 %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -fblocks -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -ast-dump -ast-dump-filter 'TestProperties::' -fapinotes-swift-version=3 | FileCheck -check-prefix=CHECK -check-prefix=CHECK-3 %s
+
+// I know, FileChecking an AST dump is brittle. However, the attributes being
+// tested aren't used for anything by Clang, and don't even have a spelling.
+
+@import VersionedKit;
+
+// CHECK-LABEL: ObjCPropertyDecl {{.+}} accessorsOnly 'id'
+// CHECK-NEXT: SwiftImportPropertyAsAccessorsAttr {{.+}} Implicit
+// CHECK-NOT: Attr
+
+// CHECK-LABEL: ObjCPropertyDecl {{.+}} accessorsOnlyForClass 'id'
+// CHECK-NEXT: SwiftImportPropertyAsAccessorsAttr {{.+}} Implicit
+// CHECK-NOT: Attr
+
+// CHECK-LABEL: ObjCPropertyDecl {{.+}} accessorsOnlyInVersion3 'id'
+// CHECK-3-NEXT: SwiftImportPropertyAsAccessorsAttr {{.+}} Implicit
+// CHECK-4-NEXT: SwiftVersionedAttr {{.+}} 3.0
+// CHECK-4-NEXT: SwiftImportPropertyAsAccessorsAttr {{.+}} Implicit
+// CHECK-NOT: Attr
+
+// CHECK-LABEL: ObjCPropertyDecl {{.+}} accessorsOnlyForClassInVersion3 'id'
+// CHECK-3-NEXT: SwiftImportPropertyAsAccessorsAttr {{.+}} Implicit
+// CHECK-4-NEXT: SwiftVersionedAttr {{.+}} 3.0
+// CHECK-4-NEXT: SwiftImportPropertyAsAccessorsAttr {{.+}} Implicit
+// CHECK-NOT: Attr
+
+// CHECK-LABEL: ObjCPropertyDecl {{.+}} accessorsOnlyExceptInVersion3 'id'
+// CHECK-3-NEXT: SwiftVersionedAttr {{.+}} 0{{$}}
+// CHECK-3-NEXT: SwiftImportPropertyAsAccessorsAttr {{.+}} Implicit
+// CHECK-4-NEXT: SwiftImportPropertyAsAccessorsAttr {{.+}} Implicit
+// CHECK-4-NEXT: SwiftVersionedRemovalAttr {{.+}} Implicit 3.0 {{[0-9]+}}
+// CHECK-NOT: Attr
+
+// CHECK-LABEL: ObjCPropertyDecl {{.+}} accessorsOnlyForClassExceptInVersion3 'id'
+// CHECK-3-NEXT: SwiftVersionedAttr {{.+}} 0{{$}}
+// CHECK-3-NEXT: SwiftImportPropertyAsAccessorsAttr {{.+}} Implicit
+// CHECK-4-NEXT: SwiftImportPropertyAsAccessorsAttr {{.+}} Implicit
+// CHECK-4-NEXT: SwiftVersionedRemovalAttr {{.+}} Implicit 3.0 {{[0-9]+}}
+// CHECK-NOT: Attr
+
+// CHECK-LABEL: Decl
diff --git a/test/APINotes/search-order.m b/test/APINotes/search-order.m
new file mode 100644
index 0000000..2c667be
--- /dev/null
+++ b/test/APINotes/search-order.m
@@ -0,0 +1,25 @@
+// RUN: rm -rf %t && mkdir -p %t
+
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -DFROM_FRAMEWORK=1 -verify
+
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -iapinotes-modules %S/Inputs/APINotes -fapinotes-cache-path=%t/APINotesCache -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -DFROM_SEARCH_PATH=1 -verify
+
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fapinotes-modules -iapinotes-modules %S/Inputs/APINotes -fapinotes-cache-path=%t/APINotesCache -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -DFROM_FRAMEWORK=1 -verify
+
+@import SomeOtherKit;
+
+void test(A *a) {
+#if FROM_FRAMEWORK
+ [a methodA]; // expected-error{{unavailable}}
+ [a methodB];
+
+ // expected-note@SomeOtherKit/SomeOtherKit.h:5{{'methodA' has been explicitly marked unavailable here}}
+#elif FROM_SEARCH_PATH
+ [a methodA];
+ [a methodB]; // expected-error{{unavailable}}
+
+ // expected-note@SomeOtherKit/SomeOtherKit.h:6{{'methodB' has been explicitly marked unavailable here}}
+#else
+# error Not something we need to test
+#endif
+}
diff --git a/test/APINotes/types.m b/test/APINotes/types.m
new file mode 100644
index 0000000..fccff80
--- /dev/null
+++ b/test/APINotes/types.m
@@ -0,0 +1,23 @@
+// RUN: rm -rf %t && mkdir -p %t
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -verify
+
+#import <SomeKit/SomeKit.h>
+
+void test(OverriddenTypes *overridden) {
+ int *ip1 = global_int_ptr; // expected-warning{{incompatible pointer types initializing 'int *' with an expression of type 'double (*)(int, int)'}}
+
+ int *ip2 = global_int_fun( // expected-warning{{incompatible pointer types initializing 'int *' with an expression of type 'char *'}}
+ ip2, // expected-warning{{incompatible pointer types passing 'int *' to parameter of type 'double *'}}
+ ip2); // expected-warning{{incompatible pointer types passing 'int *' to parameter of type 'float *'}}
+
+ int *ip3 = [overridden // expected-warning{{incompatible pointer types initializing 'int *' with an expression of type 'char *'}}
+ methodToMangle: ip3 // expected-warning{{incompatible pointer types sending 'int *' to parameter of type 'double *'}}
+ second: ip3]; // expected-warning{{incompatible pointer types sending 'int *' to parameter of type 'float *'}}
+
+ int *ip4 = overridden.intPropertyToMangle; // expected-warning{{incompatible pointer types initializing 'int *' with an expression of type 'double *'}}
+}
+
+// expected-note@SomeKit/SomeKit.h:42{{passing argument to parameter 'ptr' here}}
+// expected-note@SomeKit/SomeKit.h:42{{passing argument to parameter 'ptr2' here}}
+// expected-note@SomeKit/SomeKit.h:48{{passing argument to parameter 'ptr1' here}}
+// expected-note@SomeKit/SomeKit.h:48{{passing argument to parameter 'ptr2' here}}
diff --git a/test/APINotes/versioned.m b/test/APINotes/versioned.m
new file mode 100644
index 0000000..38690fe
--- /dev/null
+++ b/test/APINotes/versioned.m
@@ -0,0 +1,50 @@
+// RUN: rm -rf %t && mkdir -p %t
+
+// Build and check the unversioned module file.
+// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/Unversioned -fdisable-module-hash -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s
+// RUN: %clang_cc1 -ast-print %t/ModulesCache/Unversioned/VersionedKit.pcm | FileCheck -check-prefix=CHECK-UNVERSIONED %s
+// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/Unversioned -fdisable-module-hash -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -ast-dump -ast-dump-filter 'moveToPoint' | FileCheck -check-prefix=CHECK-DUMP -check-prefix=CHECK-UNVERSIONED-DUMP %s
+
+// Build and check the versioned module file.
+// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/Versioned -fdisable-module-hash -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -fapinotes-swift-version=3 -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s
+// RUN: %clang_cc1 -ast-print %t/ModulesCache/Versioned/VersionedKit.pcm | FileCheck -check-prefix=CHECK-VERSIONED %s
+// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/Versioned -fdisable-module-hash -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -fapinotes-swift-version=3 -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -ast-dump -ast-dump-filter 'moveToPoint' | FileCheck -check-prefix=CHECK-DUMP -check-prefix=CHECK-VERSIONED-DUMP %s
+
+#import <VersionedKit/VersionedKit.h>
+
+// CHECK-UNVERSIONED: void moveToPoint(double x, double y) __attribute__((swift_name("moveTo(x:y:)")));
+// CHECK-VERSIONED: void moveToPoint(double x, double y) __attribute__((swift_name("moveTo(a:b:)")));
+
+// CHECK-DUMP-LABEL: Dumping moveToPoint
+// CHECK-VERSIONED-DUMP: SwiftVersionedAttr {{.+}} Implicit 0
+// CHECK-VERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} "moveTo(x:y:)"
+// CHECK-VERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} Implicit "moveTo(a:b:)"
+// CHECK-UNVERSIONED-DUMP: SwiftNameAttr {{.+}} "moveTo(x:y:)"
+// CHECK-UNVERSIONED-DUMP-NEXT: SwiftVersionedAttr {{.+}} Implicit 3.0
+// CHECK-UNVERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} Implicit "moveTo(a:b:)"
+// CHECK-DUMP-NOT: Dumping
+
+// CHECK-UNVERSIONED: void acceptClosure(void (^block)(void) __attribute__((noescape)));
+// CHECK-VERSIONED: void acceptClosure(void (^block)(void));
+
+// CHECK-UNVERSIONED: enum MyErrorCode {
+// CHECK-UNVERSIONED-NEXT: MyErrorCodeFailed = 1
+// CHECK-UNVERSIONED-NEXT: } __attribute__((ns_error_domain(MyErrorDomain)));
+
+// CHECK-UNVERSIONED: __attribute__((swift_bridge("MyValueType")))
+// CHECK-UNVERSIONED: @interface MyReferenceType
+
+// CHECK-UNVERSIONED: void privateFunc() __attribute__((swift_private));
+
+// CHECK-UNVERSIONED: typedef double MyDoubleWrapper __attribute__((swift_wrapper("struct")));
+
+// CHECK-VERSIONED: enum MyErrorCode {
+// CHECK-VERSIONED-NEXT: MyErrorCodeFailed = 1
+// CHECK-VERSIONED-NEXT: };
+
+// CHECK-VERSIONED-NOT: __attribute__((swift_bridge("MyValueType")))
+// CHECK-VERSIONED: @interface MyReferenceType
+
+// CHECK-VERSIONED: void privateFunc();
+
+// CHECK-VERSIONED: typedef double MyDoubleWrapper;
diff --git a/test/APINotes/yaml-convert-diags.c b/test/APINotes/yaml-convert-diags.c
new file mode 100644
index 0000000..e8767f2
--- /dev/null
+++ b/test/APINotes/yaml-convert-diags.c
@@ -0,0 +1,6 @@
+// RUN: rm -rf %t
+// RUN: not %clang_cc1 -fsyntax-only -fapinotes -fapinotes-cache-path=%t %s -I %S/Inputs/BrokenHeaders2 2>&1 | FileCheck %s
+
+#include "SomeBrokenLib.h"
+
+// CHECK: error: multiple definitions of global function 'do_something_with_pointers'
diff --git a/test/APINotes/yaml-os-availability.c b/test/APINotes/yaml-os-availability.c
new file mode 100644
index 0000000..62301af
--- /dev/null
+++ b/test/APINotes/yaml-os-availability.c
@@ -0,0 +1,31 @@
+# RUN: %clang -cc1apinotes -yaml-to-binary -target i386-apple-ios7 -o %t-ios.apinotesc %S/Inputs/os-availability.apinotes
+# RUN: %clang -cc1apinotes -binary-to-yaml %t-ios.apinotesc -o %t.os-availability-ios.apinotes
+# RUN: FileCheck %s -check-prefix=IOS < %t.os-availability-ios.apinotes
+
+# RUN: %clang -cc1apinotes -yaml-to-binary -target x86_64-apple-macosx10.9 -o %t-osx.apinotesc %S/Inputs/os-availability.apinotes
+# RUN: %clang -cc1apinotes -binary-to-yaml %t-osx.apinotesc -o %t.os-availability-osx.apinotes
+# RUN: FileCheck %s -check-prefix=OSX < %t.os-availability-osx.apinotes
+
+# IOS: Foundation
+# IOS: NSArray
+# IOS: initWithObjects
+# IOS: familyNameios
+# IOS: fontName
+# IOS: NSCountedSet
+# IOS: UIApplicationDelegate
+# IOS: UIApplicationDelegateIOS
+# IOS: NSAvailableWindowDepths
+# IOS: NSAvailableWindowDepthsiOS
+# IOS-NOT: NSCalibratedWhiteColorSpace
+
+# OSX: Foundation
+# qqOSX: NSArray
+# OSX-NOT: initWithObjects
+# OSX-NOT: familyNameios
+# OSX: fontName
+# OSX-NOT: NSCountedSet
+# OSX: UIApplicationDelegate
+# OSX-NOT: UIApplicationDelegateIOS
+# OSX: NSAvailableWindowDepths
+# OSX-NOT: NSAvailableWindowDepthsiOS
+# OSX: NSCalibratedWhiteColorSpace
diff --git a/test/APINotes/yaml-parse-diags.c b/test/APINotes/yaml-parse-diags.c
new file mode 100644
index 0000000..4505e29
--- /dev/null
+++ b/test/APINotes/yaml-parse-diags.c
@@ -0,0 +1,6 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fsyntax-only -fapinotes -fapinotes-cache-path=%t %s -I %S/Inputs/BrokenHeaders -verify
+
+#include "SomeBrokenLib.h"
+
+// expected-error@APINotes.apinotes:4{{unknown key 'Nu llabilityOfRet'}}
diff --git a/test/APINotes/yaml-reader-errors.c b/test/APINotes/yaml-reader-errors.c
new file mode 100644
index 0000000..3e01eaa
--- /dev/null
+++ b/test/APINotes/yaml-reader-errors.c
@@ -0,0 +1,65 @@
+# RUN: not %clang -cc1apinotes -yaml-to-binary -target i386-apple-ios7 -o %t.apinotesc %s > %t.err 2>&1
+# RUN: FileCheck %s < %t.err
+
+---
+Name: UIKit
+Availability: iOS
+AvailabilityMsg: iOSOnly
+Classes:
+ - Name: UIFont
+ Availability: iOS
+ AvailabilityMsg: iOSOnly
+ Methods:
+ - Selector: 'fontWithName:size:'
+ MethodKind: Instance
+ Nullability: [ N ]
+ NullabilityOfRet: O
+ Availability: iOS
+ AvailabilityMsg: iOSOnly
+ DesignatedInit: true
+# CHECK: duplicate definition of method '-[UIFont fontWithName:size:]'
+ - Selector: 'fontWithName:size:'
+ MethodKind: Instance
+ Nullability: [ N ]
+ NullabilityOfRet: O
+ Availability: iOS
+ AvailabilityMsg: iOSOnly
+ DesignatedInit: true
+ Properties:
+ - Name: familyName
+ Nullability: N
+ Availability: iOS
+ AvailabilityMsg: iOSOnly
+ - Name: fontName
+ Nullability: N
+ Availability: iOS
+ AvailabilityMsg: iOSOnly
+# CHECK: duplicate definition of instance property 'UIFont.familyName'
+ - Name: familyName
+ Nullability: N
+ Availability: iOS
+ AvailabilityMsg: iOSOnly
+# CHECK: multiple definitions of class 'UIFont'
+ - Name: UIFont
+Protocols:
+ - Name: MyProto
+ AuditedForNullability: true
+# CHECK: multiple definitions of protocol 'MyProto'
+ - Name: MyProto
+ AuditedForNullability: true
+Functions:
+ - Name: 'globalFoo'
+ Nullability: [ N, N, O, S ]
+ NullabilityOfRet: O
+ Availability: iOS
+ AvailabilityMsg: iOSOnly
+ - Name: 'globalFoo2'
+ Nullability: [ N, N, O, S ]
+ NullabilityOfRet: O
+Globals:
+ - Name: globalVar
+ Nullability: O
+ Availability: iOS
+ AvailabilityMsg: iOSOnly
+ - Name: globalVar2
+ Nullability: O
diff --git a/test/APINotes/yaml-reader-test.c b/test/APINotes/yaml-reader-test.c
new file mode 100644
index 0000000..01ad90a
--- /dev/null
+++ b/test/APINotes/yaml-reader-test.c
@@ -0,0 +1,102 @@
+# RUN: %clang -cc1apinotes -dump %s | FileCheck %s
+---
+Name: UIKit
+Availability: iOS
+AvailabilityMsg: iOSOnly
+Classes:
+ - Name: UIFont
+ Availability: iOS
+ AvailabilityMsg: iOSOnly
+ Methods:
+ - Selector: 'fontWithName:size:'
+ MethodKind: Instance
+ Nullability: [ N ]
+ NullabilityOfRet: O
+ Availability: iOS
+ AvailabilityMsg: iOSOnly
+ DesignatedInit: true
+ Properties:
+ - Name: familyName
+ Nullability: N
+ Availability: iOS
+ AvailabilityMsg: iOSOnly
+ - Name: fontName
+ Nullability: N
+ Availability: iOS
+ AvailabilityMsg: iOSOnly
+Protocols:
+ - Name: MyProto
+ AuditedForNullability: true
+ - Name: MyProto2
+ AuditedForNullability: true
+Functions:
+ - Name: 'globalFoo'
+ Nullability: [ N, N, O, S ]
+ NullabilityOfRet: O
+ Availability: iOS
+ AvailabilityMsg: iOSOnly
+ - Name: 'globalFoo2'
+ Nullability: [ N, N, O, S ]
+ NullabilityOfRet: O
+Globals:
+ - Name: globalVar
+ Nullability: O
+ Availability: iOS
+ AvailabilityMsg: iOSOnly
+ - Name: globalVar2
+ Nullability: O
+
+
+# CHECK: Name: UIKit
+# CHECK: Availability: iOS
+# CHECK: AvailabilityMsg: iOSOnly
+# CHECK: Classes:
+# CHECK: - Name: UIFont
+# CHECK: Availability: iOS
+# CHECK: AvailabilityMsg: iOSOnly
+# CHECK: Methods:
+# CHECK: - Selector: 'fontWithName:size:'
+# CHECK: MethodKind: Instance
+# CHECK: Nullability: [ N ]
+# CHECK: NullabilityOfRet: O
+# CHECK: Availability: iOS
+# CHECK: AvailabilityMsg: iOSOnly
+# CHECK: DesignatedInit: true
+# CHECK: Properties:
+# CHECK: - Name: familyName
+# CHECK: Nullability: N
+# CHECK: Availability: iOS
+# CHECK: AvailabilityMsg: iOSOnly
+# CHECK: - Name: fontName
+# CHECK: Nullability: N
+# CHECK: Availability: iOS
+# CHECK: AvailabilityMsg: iOSOnly
+# CHECK:Protocols:
+# CHECK: - Name: MyProto
+# CHECK: AuditedForNullability: true
+# CHECK: Availability: available
+# CHECK: AvailabilityMsg: ''
+# CHECK: - Name: MyProto2
+# CHECK: AuditedForNullability: true
+# CHECK: Availability: available
+# CHECK: AvailabilityMsg: ''
+# CHECK:Functions:
+# CHECK: - Name: globalFoo
+# CHECK: Nullability: [ N, N, O, U ]
+# CHECK: NullabilityOfRet: O
+# CHECK: Availability: iOS
+# CHECK: AvailabilityMsg: iOSOnly
+# CHECK: - Name: globalFoo2
+# CHECK: Nullability: [ N, N, O, U ]
+# CHECK: NullabilityOfRet: O
+# CHECK: Availability: available
+# CHECK: AvailabilityMsg: ''
+# CHECK:Globals:
+# CHECK: - Name: globalVar
+# CHECK: Nullability: O
+# CHECK: Availability: iOS
+# CHECK: AvailabilityMsg: iOSOnly
+# CHECK: - Name: globalVar2
+# CHECK: Nullability: O
+# CHECK: Availability: available
+# CHECK: AvailabilityMsg:
diff --git a/test/APINotes/yaml-roundtrip.c b/test/APINotes/yaml-roundtrip.c
new file mode 100644
index 0000000..b721b6a
--- /dev/null
+++ b/test/APINotes/yaml-roundtrip.c
@@ -0,0 +1,10 @@
+# RUN: %clang -cc1apinotes -yaml-to-binary -o %t.apinotesc %S/Inputs/roundtrip.apinotes
+# RUN: %clang -cc1apinotes -binary-to-yaml -o %t.apinotes %t.apinotesc
+
+# Handle the infurating '...' the YAML writer adds but the parser
+# can't read.
+
+# RUN: cp %S/Inputs/roundtrip.apinotes %t-reference.apinotes
+# RUN: echo "..." >> %t-reference.apinotes
+# RUN: diff %t-reference.apinotes %t.apinotes
+
diff --git a/test/Analysis/ns_error_enum.m b/test/Analysis/ns_error_enum.m
new file mode 100644
index 0000000..bf61629
--- /dev/null
+++ b/test/Analysis/ns_error_enum.m
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -verify %s
+
+#define CF_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
+#define NS_ENUM(_type, _name) CF_ENUM(_type, _name)
+
+#define NS_ERROR_ENUM(_type, _name, _domain) \
+ enum _name : _type _name; enum __attribute__((ns_error_domain(_domain))) _name : _type
+
+typedef NS_ENUM(unsigned, MyEnum) {
+ MyFirst,
+ MySecond,
+};
+
+typedef NS_ENUM(invalidType, MyInvalidEnum) {
+// expected-error@-1{{unknown type name 'invalidType'}}
+// expected-error@-2{{unknown type name 'invalidType'}}
+ MyFirstInvalid,
+ MySecondInvalid,
+};
+
+const char *MyErrorDomain;
+typedef NS_ERROR_ENUM(unsigned char, MyErrorEnum, MyErrorDomain) {
+ MyErrFirst,
+ MyErrSecond,
+};
+struct __attribute__((ns_error_domain(MyErrorDomain))) MyStructErrorDomain {};
+
+typedef NS_ERROR_ENUM(unsigned char, MyErrorEnumInvalid, InvalidDomain) {
+ // expected-error@-1{{domain argument 'InvalidDomain' does not refer to global constant}}
+ MyErrFirstInvalid,
+ MyErrSecondInvalid,
+};
+
+typedef NS_ERROR_ENUM(unsigned char, MyErrorEnumInvalid, "domain-string");
+ // expected-error@-1{{domain argument must be an identifier}}
+
+int __attribute__((ns_error_domain(MyErrorDomain))) NotTagDecl;
+ // expected-error@-1{{ns_error_domain attribute only valid on enums, structs, and unions}}
+
+void foo() {}
+typedef NS_ERROR_ENUM(unsigned char, MyErrorEnumInvalidFunction, foo);
+ // expected-error@-1{{domain argument 'foo' does not refer to global constant}}
diff --git a/test/CXX/special/class.dtor/p10-0x.cpp b/test/CXX/special/class.dtor/p10-0x.cpp
index 3b8a0ad..3be0a98 100644
--- a/test/CXX/special/class.dtor/p10-0x.cpp
+++ b/test/CXX/special/class.dtor/p10-0x.cpp
@@ -33,7 +33,7 @@
expected-error{{the type of object expression ('int') does not match the type being destroyed ('decltype(intp())' (aka 'int *')) in pseudo-destructor expression}}
i.~decltype(intp())(); // expected-error{{the type of object expression ('int') does not match the type being destroyed ('decltype(intp())' (aka 'int *')) in pseudo-destructor expression}}
pi->~decltype(int())();
- pi.~decltype(int())(); // expected-error{{the type of object expression ('int *') does not match the type being destroyed ('decltype(int())' (aka 'int')) in pseudo-destructor expression}}
+ pi.~decltype(int())(); // expected-error{{member reference type 'int *' is a pointer; did you mean to use '->'?}}
pi.~decltype(intp())();
pi->~decltype(intp())(); // expected-error{{the type of object expression ('int') does not match the type being destroyed ('decltype(intp())' (aka 'int *')) in pseudo-destructor expression}}
}
diff --git a/test/CodeGen/lifetime2.c b/test/CodeGen/lifetime2.c
index 4374b3c..55c6d91 100644
--- a/test/CodeGen/lifetime2.c
+++ b/test/CodeGen/lifetime2.c
@@ -1,7 +1,7 @@
-// RUN: %clang -S -emit-llvm -o - -O2 %s | FileCheck %s -check-prefixes=CHECK,O2
-// RUN: %clang -S -emit-llvm -o - -O2 -Xclang -disable-lifetime-markers %s \
+// RUN: %clang_cc1 -S -emit-llvm -o - -O2 -disable-llvm-passes %s | FileCheck %s -check-prefixes=CHECK,O2
+// RUN: %clang_cc1 -S -emit-llvm -o - -O2 -disable-lifetime-markers %s \
// RUN: | FileCheck %s -check-prefixes=CHECK,O0
-// RUN: %clang -S -emit-llvm -o - -O0 %s | FileCheck %s -check-prefixes=CHECK,O0
+// RUN: %clang_cc1 -S -emit-llvm -o - -O0 %s | FileCheck %s -check-prefixes=CHECK,O0
extern int bar(char *A, int n);
@@ -25,13 +25,11 @@
char x;
l1:
bar(&x, 1);
- // O2: @llvm.lifetime.start(i64 5
- // O2: @llvm.lifetime.end(i64 5
char y[5];
bar(y, 5);
goto l1;
// Infinite loop
- // O2-NOT: @llvm.lifetime.end(i64 1
+ // O2-NOT: @llvm.lifetime.end(
}
// CHECK-LABEL: @goto_bypass
@@ -91,3 +89,27 @@
L:
bar(&x, 1);
}
+
+// O2-LABEL: @jump_backward_over_declaration(
+// O2: %[[p:.*]] = alloca i32*
+// O2: %[[v0:.*]] = bitcast i32** %[[p]] to i8*
+// O2: call void @llvm.lifetime.start(i64 {{.*}}, i8* %[[v0]])
+// O2-NOT: call void @llvm.lifetime.start(
+
+extern void foo2(int p);
+
+int jump_backward_over_declaration(int a) {
+ int *p = 0;
+label1:
+ if (p) {
+ foo2(*p);
+ return 0;
+ }
+
+ int i = 999;
+ if (a != 2) {
+ p = &i;
+ goto label1;
+ }
+ return -1;
+}
diff --git a/test/CodeGen/ubsan-null.c b/test/CodeGen/ubsan-null.c
new file mode 100644
index 0000000..6ddae8a
--- /dev/null
+++ b/test/CodeGen/ubsan-null.c
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fsanitize=null -emit-llvm %s -o - | FileCheck %s
+
+struct A {
+ int a[2];
+ int b;
+};
+
+// CHECK-LABEL: @f1
+int *f1() {
+// CHECK-NOT: __ubsan_handle_type_mismatch
+// CHECK: ret
+// CHECK-SAME: getelementptr inbounds (%struct.A, %struct.A* null, i32 0, i32 1)
+ return &((struct A *)0)->b;
+}
+
+// CHECK-LABEL: @f2
+int f2() {
+// CHECK: __ubsan_handle_type_mismatch
+// CHECK: load
+// CHECK-SAME: getelementptr inbounds (%struct.A, %struct.A* null, i32 0, i32 1)
+// CHECK: ret
+ return ((struct A *)0)->b;
+}
diff --git a/test/CodeGen/ubsan-shift.c b/test/CodeGen/ubsan-shift.c
new file mode 100644
index 0000000..90c15d8
--- /dev/null
+++ b/test/CodeGen/ubsan-shift.c
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -triple=x86_64-apple-darwin -fsanitize=shift-exponent,shift-base -emit-llvm %s -o - | FileCheck %s
+
+// CHECK-LABEL: define i32 @f1
+int f1(int c, int shamt) {
+// CHECK: icmp ule i32 %{{.*}}, 31, !nosanitize
+// CHECK: icmp ule i32 %{{.*}}, 31, !nosanitize
+ return 1 << (c << shamt);
+}
+
+// CHECK-LABEL: define i32 @f2
+int f2(long c, int shamt) {
+// CHECK: icmp ule i32 %{{.*}}, 63, !nosanitize
+// CHECK: icmp ule i64 %{{.*}}, 31, !nosanitize
+ return 1 << (c << shamt);
+}
+
+// CHECK-LABEL: define i32 @f3
+unsigned f3(unsigned c, int shamt) {
+// CHECK: icmp ule i32 %{{.*}}, 31, !nosanitize
+// CHECK: icmp ule i32 %{{.*}}, 31, !nosanitize
+ return 1U << (c << shamt);
+}
+
+// CHECK-LABEL: define i32 @f4
+unsigned f4(unsigned long c, int shamt) {
+// CHECK: icmp ule i32 %{{.*}}, 63, !nosanitize
+// CHECK: icmp ule i64 %{{.*}}, 31, !nosanitize
+ return 1U << (c << shamt);
+}
+
+// CHECK-LABEL: define i32 @f5
+int f5(int c, long long shamt) {
+// CHECK: icmp ule i64 %{{[0-9]+}}, 31, !nosanitize
+//
+// CHECK: sub nuw nsw i32 31, %sh_prom, !nosanitize
+// CHECK: lshr i32 %{{.*}}, %shl.zeros, !nosanitize
+ return c << shamt;
+}
+
+// CHECK-LABEL: define i32 @f6
+int f6(int c, int shamt) {
+// CHECK: icmp ule i32 %[[WIDTH:.*]], 31, !nosanitize
+//
+// CHECK: sub nuw nsw i32 31, %[[WIDTH]], !nosanitize
+// CHECK: lshr i32 %{{.*}}, %shl.zeros, !nosanitize
+ return c << shamt;
+}
diff --git a/test/CodeGen/vector.c b/test/CodeGen/vector.c
index ebaea84..2e36dcc 100644
--- a/test/CodeGen/vector.c
+++ b/test/CodeGen/vector.c
@@ -60,23 +60,3 @@
extern __typeof(_mm_extract_epi16(_mm_setzero_si128(), 3)) check_result_int;
extern __typeof(_mm_extract_epi32(_mm_setzero_si128(), 3)) check_result_int;
}
-
-// Test some logic around our lax vector comparison rules with integers.
-
-typedef int vec_int1 __attribute__((vector_size(4)));
-vec_int1 lax_vector_compare1(int x, vec_int1 y) {
- y = x == y;
- return y;
-}
-
-// CHECK: define i32 @lax_vector_compare1(i32 {{.*}}, i32 {{.*}})
-// CHECK: icmp eq <1 x i32>
-
-typedef int vec_int2 __attribute__((vector_size(8)));
-vec_int2 lax_vector_compare2(long long x, vec_int2 y) {
- y = x == y;
- return y;
-}
-
-// CHECK: define void @lax_vector_compare2(<2 x i32>* {{.*sret.*}}, i64 {{.*}}, i64 {{.*}})
-// CHECK: icmp eq <2 x i32>
diff --git a/test/CodeGenCXX/explicit-instantiation.cpp b/test/CodeGenCXX/explicit-instantiation.cpp
index fb57118..85857fb 100644
--- a/test/CodeGenCXX/explicit-instantiation.cpp
+++ b/test/CodeGenCXX/explicit-instantiation.cpp
@@ -5,6 +5,9 @@
// This check logically is attached to 'template int S<int>::i;' below.
// CHECK: @_ZN1SIiE1iE = weak_odr global i32
+// This check is logically attached to 'template int ExportedStaticLocal::f<int>()' below.
+// CHECK-OPT: @_ZZN19ExportedStaticLocal1fIiEEvvE1i = linkonce_odr global
+
template<typename T, typename U, typename Result>
struct plus {
Result operator()(const T& t, const U& u) const;
@@ -153,3 +156,17 @@
template <typename T> void S<T>::g() {}
template <typename T> int S<T>::i;
template <typename T> void S<T>::S2::h() {}
+
+namespace ExportedStaticLocal {
+void sink(int&);
+template <typename T>
+inline void f() {
+ static int i;
+ sink(i);
+}
+// See the check line at the top of the file.
+extern template void f<int>();
+void use() {
+ f<int>();
+}
+}
diff --git a/test/Driver/embed-bitcode.c b/test/Driver/embed-bitcode.c
index 36314e6..fa86c2c3 100644
--- a/test/Driver/embed-bitcode.c
+++ b/test/Driver/embed-bitcode.c
@@ -34,6 +34,13 @@
// CHECK-LTO-NOT: warning: argument unused during compilation: '-fembed-bitcode'
// CHECK-LTO-NOT: -cc1
// CHECK-LTO-NOT: -fembed-bitcode=all
+// RUN: touch %t.o
+// RUN: %clang -target armv7-apple-darwin -miphoneos-version-min=6.0 %t.o -fembed-bitcode -fembed-bitcode-marker -mlinker-version=277 2>&1 -### | FileCheck %s -check-prefix=CHECK-LTO-MARKER-277
+// RUN: %clang -target armv7-apple-darwin -miphoneos-version-min=6.0 %t.o -fembed-bitcode -fembed-bitcode-marker -mlinker-version=278 2>&1 -### | FileCheck %s -check-prefix=CHECK-LTO-MARKER-278
+// CHECK-LTO-MARKER-277-NOT: bitcode_process_mode
+// CHECK-LTO-MARKER-278: bitcode_process_mode
+
+
// RUN: %clang -c %s -fembed-bitcode-marker -fintegrated-as 2>&1 -### | FileCheck %s -check-prefix=CHECK-MARKER
// CHECK-MARKER: -cc1
diff --git a/test/Driver/frame-pointer-elim.c b/test/Driver/frame-pointer-elim.c
index e1d816e..e39499a 100644
--- a/test/Driver/frame-pointer-elim.c
+++ b/test/Driver/frame-pointer-elim.c
@@ -49,9 +49,9 @@
// RUN: %clang -### -target armv7s-apple-ios8.0 -momit-leaf-frame-pointer %s 2>&1 | \
// RUN: FileCheck --check-prefix=WARN-OMIT-LEAF-7S %s
-// WARN-OMIT-LEAF-7S: warning: optimization flag '-momit-leaf-frame-pointer' is not supported for target 'armv7s'
+// WARN-OMIT-LEAF-7S-NOT: warning: optimization flag '-momit-leaf-frame-pointer' is not supported for target 'armv7s'
// WARN-OMIT-LEAF-7S: "-mdisable-fp-elim"
-// WARN-OMIT-LEAF-7S-NOT: "-momit-leaf-frame-pointer"
+// WARN-OMIT-LEAF-7S: "-momit-leaf-frame-pointer"
// On the PS4, we default to omitting the frame pointer on leaf functions
// (OMIT_LEAF check line is above)
diff --git a/test/Driver/mglobal-merge.c b/test/Driver/mglobal-merge.c
index ad76736..271011e 100644
--- a/test/Driver/mglobal-merge.c
+++ b/test/Driver/mglobal-merge.c
@@ -11,7 +11,7 @@
// RUN: FileCheck --check-prefix=CHECK-NONE < %t %s
// CHECK-NGM-ARM: "-backend-option" "-arm-global-merge=false"
-// CHECK-NGM-AARCH64: "-backend-option" "-aarch64-global-merge=false"
+// CHECK-NGM-AARCH64: "-backend-option" "-aarch64-enable-global-merge=false"
// RUN: %clang -target armv7-unknown-unknown -### -fsyntax-only %s 2> %t \
// RUN: -mglobal-merge
@@ -26,7 +26,7 @@
// RUN: FileCheck --check-prefix=CHECK-NONE < %t %s
// CHECK-GM-ARM: "-backend-option" "-arm-global-merge=true"
-// CHECK-GM-AARCH64: "-backend-option" "-aarch64-global-merge=true"
+// CHECK-GM-AARCH64: "-backend-option" "-aarch64-enable-global-merge=true"
// RUN: %clang -target armv7-unknown-unknown -### -fsyntax-only %s 2> %t
// RUN: FileCheck --check-prefix=CHECK-NONE < %t %s
diff --git a/test/FixIt/fixit.cpp b/test/FixIt/fixit.cpp
index c43aac9..0b7fc62 100644
--- a/test/FixIt/fixit.cpp
+++ b/test/FixIt/fixit.cpp
@@ -409,3 +409,14 @@
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:26-[[@LINE-1]]:26}:"{}"
int use_czi = czi.a;
+namespace dotPointerDestructor {
+
+struct Bar {
+ ~Bar();
+};
+
+void bar(Bar *o) {
+ o.~Bar(); // expected-error {{member reference type 'dotPointerDestructor::Bar *' is a pointer; did you mean to use '->'}}
+} // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:4-[[@LINE-1]]:5}:"->"
+
+}
diff --git a/test/FixIt/no-fixit.cpp b/test/FixIt/no-fixit.cpp
index 7e8e1fb..2dad28d 100644
--- a/test/FixIt/no-fixit.cpp
+++ b/test/FixIt/no-fixit.cpp
@@ -11,3 +11,15 @@
(void)&i;
}
} x;
+
+namespace dotPointerDestructor {
+
+struct Bar {
+ ~Bar() = delete;
+};
+
+void bar(Bar *o) {
+ o.~Bar(); // no fixit
+}
+
+}
diff --git a/test/Frontend/objc-bool-is-bool.m b/test/Frontend/objc-bool-is-bool.m
index 464fe2e..ee4fb58 100644
--- a/test/Frontend/objc-bool-is-bool.m
+++ b/test/Frontend/objc-bool-is-bool.m
@@ -1,6 +1,8 @@
// RUN: %clang_cc1 -fsyntax-only -E -dM -triple=armv7k-apple-watchos %s | FileCheck --check-prefix=BOOL %s
// RUN: %clang_cc1 -fsyntax-only -E -dM -triple=x86_64-apple-darwin16 %s | FileCheck --check-prefix=CHAR %s
-// RUN: %clang_cc1 -x c -fsyntax-only -E -dM -triple=x86_64-apple-darwin16 %s | FileCheck --check-prefix=NONE %s
+// RUN: %clang_cc1 -x c -fsyntax-only -E -dM -triple=x86_64-apple-darwin16 %s | FileCheck --check-prefix=CHAR %s
+// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -E -dM -triple=x86_64-apple-darwin16 %s | FileCheck --check-prefix=CHAR %s
+// RUN: %clang_cc1 -x c++ -fsyntax-only -E -dM -triple=x86_64-apple-darwin16 %s | FileCheck --check-prefix=CHAR %s
// rdar://21170440
@@ -9,5 +11,3 @@
// CHAR: #define __OBJC_BOOL_IS_BOOL 0
// CHAR-NOT: #define __OBJC_BOOL_IS_BOOL 1
-
-// NONE-NOT: __OBJC_BOOL_IS_BOOL
diff --git a/test/Index/Core/index-pch.c b/test/Index/Core/index-pch.c
new file mode 100644
index 0000000..773cfc5
--- /dev/null
+++ b/test/Index/Core/index-pch.c
@@ -0,0 +1,13 @@
+// RUN: c-index-test core -print-source-symbols -- %s | FileCheck %s
+// RUN: %clang_cc1 -emit-pch %s -o %t.pch
+// RUN: c-index-test core -print-source-symbols -module-file %t.pch | FileCheck %s
+
+// CHECK: [[@LINE+1]]:6 | function/C | test1 | [[TEST1_USR:.*]] | [[TEST1_CG:.*]] | Decl | rel: 0
+void test1();
+
+// CHECK: [[@LINE+1]]:20 | function/C | test2 | [[TEST2_USR:.*]] | {{.*}} | Def | rel: 0
+static inline void test2() {
+ // CHECK: [[@LINE+2]]:3 | function/C | test1 | [[TEST1_USR]] | [[TEST1_CG]] | Ref,Call,RelCall,RelCont | rel: 1
+ // CHECK-NEXT: RelCall,RelCont | test2 | [[TEST2_USR]]
+ test1();
+}
diff --git a/test/Index/Core/index-with-module.m b/test/Index/Core/index-with-module.m
index e50b247..c83de63 100644
--- a/test/Index/Core/index-with-module.m
+++ b/test/Index/Core/index-with-module.m
@@ -1,5 +1,5 @@
// RUN: rm -rf %t.mcp
-// RUN: c-index-test core -print-source-symbols -- %s -I %S/Inputs/module -fmodules -fmodules-cache-path=%t.mcp | FileCheck %s
+// RUN: c-index-test core -print-source-symbols -dump-imported-module-files -- %s -I %S/Inputs/module -fmodules -fmodules-cache-path=%t.mcp | FileCheck %s
// CHECK: [[@LINE+1]]:9 | module/C | ModA | Decl |
@import ModA;
@@ -10,3 +10,9 @@
// CHECK: [[@LINE+1]]:3 | function/C | ModA_func | c:@F@ModA_func | {{.*}} | Ref,Call,RelCall,RelCont | rel: 1
ModA_func();
}
+
+// CHECK: ==== Module ModA ====
+// CHECK: 2:6 | function/C | ModA_func | c:@F@ModA_func | {{.*}} | Decl | rel: 0
+// CHECK: ---- Module Inputs ----
+// CHECK: user | {{.*}}ModA.h
+// CHECK: user | {{.*}}module.modulemap
diff --git a/test/Index/complete-cached-globals.cpp b/test/Index/complete-cached-globals.cpp
new file mode 100644
index 0000000..791faf2
--- /dev/null
+++ b/test/Index/complete-cached-globals.cpp
@@ -0,0 +1,25 @@
+// Note: the run lines follow their respective tests, since line/column
+// matter in this test.
+
+namespace SomeNamespace {
+ class SomeClass {
+ };
+ void SomeFunction();
+}
+
+using SomeNamespace::SomeClass;
+using SomeNamespace::SomeFunction;
+
+static void foo() {
+ return;
+}
+
+// rdar://23454249
+
+// RUN: c-index-test -code-completion-at=%s:14:3 %s | FileCheck -check-prefix=CHECK-CC1 %s
+// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:14:3 %s | FileCheck -check-prefix=CHECK-CC1 %s
+
+// CHECK-CC1: ClassDecl:{TypedText SomeClass} (50)
+// CHECK-CC1: FunctionDecl:{ResultType void}{TypedText SomeFunction}{LeftParen (}{RightParen )} (50)
+// CHECK-CC1-NOT: {Text SomeNamespace::}{TypedText SomeClass}
+// CHECK-CC1-NOT: {Text SomeNamespace::}{TypedText SomeFunction}
diff --git a/test/Index/complete-objc-message.m b/test/Index/complete-objc-message.m
index e3fce6b..c2b0670 100644
--- a/test/Index/complete-objc-message.m
+++ b/test/Index/complete-objc-message.m
@@ -346,3 +346,54 @@
// RUN: c-index-test -code-completion-at=%s:197:6 %s | FileCheck -check-prefix=CHECK-NULLABLE %s
// CHECK-NULLABLE: ObjCInstanceMethodDecl:{ResultType A * _Nonnull}{TypedText method:}{Placeholder (nullable A *)}
+
+// rdar://28012953
+// Code completion results should include instance methods from RootProtocol and
+// RootClass when completing a method invocation for a RootClass object because
+// RootClasses metaclass subclasses from RootClass (i.e. RootClass is actually
+// an instance of RootClass).
+
+@protocol SubRootProtocol
+
+- (void)subProtocolInstanceMethod;
+
+@end
+
+@protocol RootProtocol <SubRootProtocol>
+
+- (void)protocolInstanceMethod;
++ (void)protocolClassMethod;
+
+@end
+
+@interface RootClass <RootProtocol>
+
+- (void)instanceMethod;
++ (void)classMethod;
+
+@end
+
+@protocol RootCategoryProtocol
+
+- (void)categoryProtocolInstanceMethod;
+
+@end
+
+@interface RootClass (Cat) <RootCategoryProtocol>
+
+- (void)categoryInstanceMethod;
+
+@end
+
+void completeAllTheRootThings() {
+ [RootClass classMethod];
+}
+
+// RUN: c-index-test -code-completion-at=%s:389:14 %s | FileCheck -check-prefix=CHECK-ROOT %s
+// CHECK-ROOT: ObjCInstanceMethodDecl:{ResultType void}{TypedText categoryInstanceMethod} (35)
+// CHECK-ROOT-NEXT: ObjCInstanceMethodDecl:{ResultType void}{TypedText categoryProtocolInstanceMethod} (37)
+// CHECK-ROOT-NEXT: ObjCClassMethodDecl:{ResultType void}{TypedText classMethod} (35)
+// CHECK-ROOT-NEXT: ObjCInstanceMethodDecl:{ResultType void}{TypedText instanceMethod} (35)
+// CHECK-ROOT-NEXT: ObjCClassMethodDecl:{ResultType void}{TypedText protocolClassMethod} (37)
+// CHECK-ROOT-NEXT: ObjCInstanceMethodDecl:{ResultType void}{TypedText protocolInstanceMethod} (37)
+// CHECK-ROOT-NEXT: ObjCInstanceMethodDecl:{ResultType void}{TypedText subProtocolInstanceMethod} (37)
diff --git a/test/Lexer/cxx-features.cpp b/test/Lexer/cxx-features.cpp
index 5fc1722..0af42dc 100644
--- a/test/Lexer/cxx-features.cpp
+++ b/test/Lexer/cxx-features.cpp
@@ -9,7 +9,6 @@
// expected-no-diagnostics
-// FIXME using `defined` in a macro has undefined behavior.
#if __cplusplus < 201103L
#define check(macro, cxx98, cxx11, cxx14, cxx1z) cxx98 == 0 ? defined(__cpp_##macro) : __cpp_##macro != cxx98
#elif __cplusplus < 201402L
diff --git a/test/Modules/Inputs/diag_pragma.h b/test/Modules/Inputs/diag_pragma.h
index a8f9589..59c73ea 100644
--- a/test/Modules/Inputs/diag_pragma.h
+++ b/test/Modules/Inputs/diag_pragma.h
@@ -1,3 +1,13 @@
#define DIAG_PRAGMA_MACRO 1
#pragma clang diagnostic ignored "-Wparentheses"
+
+#ifdef __cplusplus
+template<typename T> const char *f(T t) {
+ return "foo" + t;
+}
+#pragma clang diagnostic ignored "-Wstring-plus-int"
+template<typename T> const char *g(T t) {
+ return "foo" + t;
+}
+#endif
diff --git a/test/Modules/Inputs/incomplete-type/A.h b/test/Modules/Inputs/incomplete-type/A.h
new file mode 100644
index 0000000..6943aaf
--- /dev/null
+++ b/test/Modules/Inputs/incomplete-type/A.h
@@ -0,0 +1 @@
+#define __P(protos) ()
diff --git a/test/Modules/Inputs/incomplete-type/B.h b/test/Modules/Inputs/incomplete-type/B.h
new file mode 100644
index 0000000..51df71e
--- /dev/null
+++ b/test/Modules/Inputs/incomplete-type/B.h
@@ -0,0 +1,2 @@
+#import "A.h"
+#import "B2.h"
diff --git a/test/Modules/Inputs/incomplete-type/B2.h b/test/Modules/Inputs/incomplete-type/B2.h
new file mode 100644
index 0000000..def109f
--- /dev/null
+++ b/test/Modules/Inputs/incomplete-type/B2.h
@@ -0,0 +1,2 @@
+void test(int __P) {
+}
diff --git a/test/Modules/Inputs/incomplete-type/C.h b/test/Modules/Inputs/incomplete-type/C.h
new file mode 100644
index 0000000..ea6a2ee
--- /dev/null
+++ b/test/Modules/Inputs/incomplete-type/C.h
@@ -0,0 +1,2 @@
+#import "A.h"
+#import "B.h"
diff --git a/test/Modules/Inputs/incomplete-type/module.modulemap b/test/Modules/Inputs/incomplete-type/module.modulemap
new file mode 100644
index 0000000..17c8d7d
--- /dev/null
+++ b/test/Modules/Inputs/incomplete-type/module.modulemap
@@ -0,0 +1,15 @@
+module X {
+ header "A.h"
+ export *
+}
+
+// Y imports X
+module Y {
+ header "B.h"
+ export *
+}
+
+// Z imports X and Y
+module Z {
+ header "C.h"
+}
diff --git a/test/Modules/Inputs/shadow/A1/A.h b/test/Modules/Inputs/shadow/A1/A.h
new file mode 100644
index 0000000..f07c681
--- /dev/null
+++ b/test/Modules/Inputs/shadow/A1/A.h
@@ -0,0 +1 @@
+#define A1_A_h
diff --git a/test/Modules/Inputs/shadow/A1/module.modulemap b/test/Modules/Inputs/shadow/A1/module.modulemap
new file mode 100644
index 0000000..9439a43
--- /dev/null
+++ b/test/Modules/Inputs/shadow/A1/module.modulemap
@@ -0,0 +1,5 @@
+module A {
+ header "A.h"
+}
+
+module A1 {}
diff --git a/test/Modules/Inputs/shadow/A2/A.h b/test/Modules/Inputs/shadow/A2/A.h
new file mode 100644
index 0000000..9880ed0
--- /dev/null
+++ b/test/Modules/Inputs/shadow/A2/A.h
@@ -0,0 +1 @@
+#define A2_A_h
diff --git a/test/Modules/Inputs/shadow/A2/module.modulemap b/test/Modules/Inputs/shadow/A2/module.modulemap
new file mode 100644
index 0000000..935d89b
--- /dev/null
+++ b/test/Modules/Inputs/shadow/A2/module.modulemap
@@ -0,0 +1,5 @@
+module A {
+ header "A.h"
+}
+
+module A2 {}
diff --git a/test/Modules/Inputs/swift_name/module.modulemap b/test/Modules/Inputs/swift_name/module.modulemap
new file mode 100644
index 0000000..b7ec6b1
--- /dev/null
+++ b/test/Modules/Inputs/swift_name/module.modulemap
@@ -0,0 +1,2 @@
+module SwiftNameInferred [swift_infer_import_as_member] {
+}
\ No newline at end of file
diff --git a/test/Modules/diag-pragma.cpp b/test/Modules/diag-pragma.cpp
new file mode 100644
index 0000000..347401f
--- /dev/null
+++ b/test/Modules/diag-pragma.cpp
@@ -0,0 +1,47 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -emit-module -fmodules-cache-path=%t -fmodule-name=diag_pragma -x c++ %S/Inputs/module.map -fmodules-ts
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -emit-module -fmodule-name=diag_pragma -x c++ %S/Inputs/module.map -fmodules-ts -o %t/explicit.pcm -Werror=string-plus-int
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DEXPLICIT_FLAG -fmodule-file=%t/explicit.pcm
+
+import diag_pragma;
+
+int foo(int x) {
+ // Diagnostics from templates in the module follow the diagnostic state from
+ // when the module was built.
+#ifdef EXPLICIT_FLAG
+ // expected-error@diag_pragma.h:7 {{adding 'int' to a string}}
+#else
+ // expected-warning@diag_pragma.h:7 {{adding 'int' to a string}}
+#endif
+ // expected-note@diag_pragma.h:7 {{use array indexing}}
+ f(0); // expected-note {{instantiation of}}
+
+ g(0); // ok, warning was ignored when building module
+
+ // Diagnostics from this source file ignore the diagnostic state from the
+ // module.
+ void("foo" + x); // expected-warning {{adding 'int' to a string}}
+ // expected-note@-1 {{use array indexing}}
+
+#pragma clang diagnostic ignored "-Wstring-plus-int"
+
+ // Diagnostics from the module ignore diagnostic state changes from this
+ // source file.
+#ifdef EXPLICIT_FLAG
+ // expected-error@diag_pragma.h:7 {{adding 'long' to a string}}
+#else
+ // expected-warning@diag_pragma.h:7 {{adding 'long' to a string}}
+#endif
+ // expected-note@diag_pragma.h:7 {{use array indexing}}
+ f(0L); // expected-note {{instantiation of}}
+
+ g(0L);
+
+ void("bar" + x);
+
+ if (x = DIAG_PRAGMA_MACRO) // expected-warning {{using the result of an assignment as a condition without parentheses}} \
+ // expected-note {{place parentheses}} expected-note {{use '=='}}
+ return 0;
+ return 1;
+}
diff --git a/test/Modules/incomplete-type-void.c b/test/Modules/incomplete-type-void.c
new file mode 100644
index 0000000..2ce00f7
--- /dev/null
+++ b/test/Modules/incomplete-type-void.c
@@ -0,0 +1,9 @@
+// RUN: rm -rf %t.cache
+// RUN: %clang_cc1 -fmodules %s -fmodules-cache-path=%t.cache \
+// RUN: -fsyntax-only -I %S/Inputs/incomplete-type -verify
+
+// expected-no-diagnostics
+
+#import "C.h"
+#import "A.h"
+void foo __P(());
diff --git a/test/Modules/infer_swift_name.m b/test/Modules/infer_swift_name.m
new file mode 100644
index 0000000..d4b4a5d
--- /dev/null
+++ b/test/Modules/infer_swift_name.m
@@ -0,0 +1,6 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -I %S/Inputs/swift_name %s -verify
+// REQUIRES: shell
+
+@import SwiftNameInferred; // ok
+@import SwiftName; // expected-error{{module 'SwiftName' not found}}
diff --git a/test/Modules/minimal-identifier-tables.cpp b/test/Modules/minimal-identifier-tables.cpp
deleted file mode 100644
index 0674746..0000000
--- a/test/Modules/minimal-identifier-tables.cpp
+++ /dev/null
@@ -1,10 +0,0 @@
-// RUN: rm -rf %t
-// RUN: mkdir %t
-// RUN: echo 'extern int some_long_variable_name;' > %t/x.h
-// RUN: echo 'extern int some_long_variable_name;' > %t/y.h
-// RUN: echo 'module X { header "x.h" } module Y { header "y.h" }' > %t/map
-// RUN: %clang_cc1 -fmodules -x c++ -fmodule-name=X %t/map -emit-module -o %t/x.pcm
-// RUN: %clang_cc1 -fmodules -x c++ -fmodule-name=Y %t/map -fmodule-file=%t/x.pcm -emit-module -o %t/y.pcm
-// RUN: cat %t/y.pcm | FileCheck %s
-//
-// CHECK-NOT: some_long_variable_name
diff --git a/test/Modules/shadow.m b/test/Modules/shadow.m
new file mode 100644
index 0000000..44320af
--- /dev/null
+++ b/test/Modules/shadow.m
@@ -0,0 +1,21 @@
+// RUN: rm -rf %t
+// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs/shadow/A1 -I %S/Inputs/shadow/A2 %s -fsyntax-only 2>&1 | FileCheck %s -check-prefix=REDEFINITION
+// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -fmodule-map-file=%S/Inputs/shadow/A1/module.modulemap -fmodule-map-file=%S/Inputs/shadow/A2/module.modulemap %s -fsyntax-only 2>&1 | FileCheck %s -check-prefix=REDEFINITION
+// REDEFINITION: error: redefinition of module 'A'
+// REDEFINITION: note: previously defined
+
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -fmodule-map-file=%S/Inputs/shadow/A1/module.modulemap -I %S/Inputs/shadow %s -verify
+
+@import A1;
+@import A2;
+@import A;
+
+#import "A2/A.h" // expected-note {{implicitly imported}}
+// expected-error@A2/module.modulemap:1 {{import of shadowed module 'A'}}
+// expected-note@A1/module.modulemap:1 {{previous definition}}
+
+#if defined(A2_A_h)
+#error got the wrong definition of module A
+#elif !defined(A1_A_h)
+#error missing definition from A1
+#endif
diff --git a/test/Preprocessor/expr_define_expansion.c b/test/Preprocessor/expr_define_expansion.c
index 23cb435..3e5a2c4 100644
--- a/test/Preprocessor/expr_define_expansion.c
+++ b/test/Preprocessor/expr_define_expansion.c
@@ -1,28 +1,6 @@
-// RUN: %clang_cc1 %s -E -CC -verify
-// RUN: %clang_cc1 %s -E -CC -DPEDANTIC -pedantic -verify
+// RUN: %clang_cc1 %s -E -CC -pedantic -verify
+// expected-no-diagnostics
#define FOO && 1
#if defined FOO FOO
#endif
-
-#define A
-#define B defined(A)
-#if B // expected-warning{{macro expansion producing 'defined' has undefined behavior}}
-#endif
-
-#define m_foo
-#define TEST(a) (defined(m_##a) && a)
-
-#if defined(PEDANTIC)
-// expected-warning@+4{{macro expansion producing 'defined' has undefined behavior}}
-#endif
-
-// This shouldn't warn by default, only with pedantic:
-#if TEST(foo)
-#endif
-
-
-// Only one diagnostic for this case:
-#define INVALID defined(
-#if INVALID // expected-error{{macro name missing}}
-#endif
diff --git a/test/Preprocessor/init.c b/test/Preprocessor/init.c
index 8b89019..1d3e9fb 100644
--- a/test/Preprocessor/init.c
+++ b/test/Preprocessor/init.c
@@ -8705,6 +8705,7 @@
// WEBASSEMBLY32-NEXT:#define __LONG_MAX__ 2147483647L
// WEBASSEMBLY32-NOT:#define __LP64__
// WEBASSEMBLY32-NEXT:#define __NO_INLINE__ 1
+// WEBASSEMBLY32-NEXT:#define __OBJC_BOOL_IS_BOOL 0
// WEBASSEMBLY32-NEXT:#define __ORDER_BIG_ENDIAN__ 4321
// WEBASSEMBLY32-NEXT:#define __ORDER_LITTLE_ENDIAN__ 1234
// WEBASSEMBLY32-NEXT:#define __ORDER_PDP_ENDIAN__ 3412
@@ -9020,6 +9021,7 @@
// WEBASSEMBLY64-NEXT:#define __LONG_MAX__ 9223372036854775807L
// WEBASSEMBLY64-NEXT:#define __LP64__ 1
// WEBASSEMBLY64-NEXT:#define __NO_INLINE__ 1
+// WEBASSEMBLY64-NEXT:#define __OBJC_BOOL_IS_BOOL 0
// WEBASSEMBLY64-NEXT:#define __ORDER_BIG_ENDIAN__ 4321
// WEBASSEMBLY64-NEXT:#define __ORDER_LITTLE_ENDIAN__ 1234
// WEBASSEMBLY64-NEXT:#define __ORDER_PDP_ENDIAN__ 3412
diff --git a/test/Sema/attr-availability-swift.c b/test/Sema/attr-availability-swift.c
new file mode 100644
index 0000000..42e7524
--- /dev/null
+++ b/test/Sema/attr-availability-swift.c
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fsyntax-only -fblocks -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fsyntax-only -ast-dump %s | FileCheck %s
+//
+
+#if !__has_feature(attribute_availability_with_message)
+# error "Missing __has_feature"
+#endif
+
+#if __has_feature(attribute_availability_swift)
+# warning "okay"
+// expected-warning@-1{{okay}}
+#else
+# error "Missing __has_feature"
+#endif
+
+extern int noSwiftGlobal1 __attribute__((availability(swift, unavailable)));
+// CHECK: AvailabilityAttr {{.*}}swift 0 0 0 Unavailable "" ""
+extern int noSwiftGlobal1 __attribute__((availability(macosx, introduced=10.1))); // okay
+// CHECK: AvailabilityAttr {{.*}}macos 10.1 0 0 "" ""
+// CHECK: AvailabilityAttr {{.*}}Inherited swift 0 0 0 Unavailable "" ""
+extern int noSwiftGlobal1 __attribute__((availability(swift, unavailable, message="and this one has a message"))); // okay
+// CHECK: AvailabilityAttr {{.*}}swift 0 0 0 Unavailable "and this one has a message" ""
+// CHECK: AvailabilityAttr {{.*}}Inherited macos 10.1 0 0 "" ""
+extern int noSwiftGlobal2 __attribute__((availability(swift, introduced=5))); // expected-warning{{only 'unavailable' and 'deprecated' are supported for Swift availability}}
+// CHECK: VarDecl
+// CHECK-NOT: AvailabilityAttr
+extern int noSwiftGlobal3 __attribute__((availability(swift, deprecated, message="t")));
+// CHECK: VarDecl
+// CHECK: AvailabilityAttr {{.*}}swift 0 1 0 "t" ""
diff --git a/test/Sema/attr-availability.c b/test/Sema/attr-availability.c
index a4b40ff..e7a800f 100644
--- a/test/Sema/attr-availability.c
+++ b/test/Sema/attr-availability.c
@@ -80,7 +80,6 @@
extern int x2 __attribute__((availability(macosx,introduced=10.2))); // expected-note {{previous attribute is here}}
extern int x2 __attribute__((availability(macosx,introduced=10.5))); // expected-warning {{availability does not match previous declaration}}
-
enum Original {
OriginalDeprecated __attribute__((availability(macosx, deprecated=10.2))), // expected-note + {{'OriginalDeprecated' has been explicitly marked deprecated here}}
OriginalUnavailable __attribute__((availability(macosx, unavailable))) // expected-note + {{'OriginalUnavailable' has been explicitly marked unavailable here}}
diff --git a/test/Sema/attr-noescape.c b/test/Sema/attr-noescape.c
new file mode 100644
index 0000000..ec367b6
--- /dev/null
+++ b/test/Sema/attr-noescape.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -fblocks -verify -fsyntax-only
+
+#if !__has_attribute(noescape)
+# error "missing noescape attribute"
+#endif
+
+int *global_var __attribute((noescape)); // expected-warning{{'noescape' attribute only applies to parameters}}
+
+void foo(__attribute__((noescape)) int *int_ptr,
+ __attribute__((noescape)) int (^block)(int),
+ __attribute((noescape)) int integer) { // expected-warning{{'noescape' attribute ignored on parameter of non-pointer type 'int'}}
+}
diff --git a/test/Sema/format-strings.c b/test/Sema/format-strings.c
index 5465122..ca3132e 100644
--- a/test/Sema/format-strings.c
+++ b/test/Sema/format-strings.c
@@ -653,6 +653,33 @@
}
#pragma GCC diagnostic warning "-Wformat-nonliteral"
+void test_os_log_format(char c, const char *pc, int i, int *pi, void *p, void *buf) {
+ __builtin_os_log_format(buf, "");
+ __builtin_os_log_format(buf, "%d"); // expected-warning {{more '%' conversions than data arguments}}
+ __builtin_os_log_format(buf, "%d", i);
+ __builtin_os_log_format(buf, "%P", p); // expected-warning {{using '%P' format specifier without precision}}
+ __builtin_os_log_format(buf, "%.10P", p);
+ __builtin_os_log_format(buf, "%.*P", p); // expected-warning {{field precision should have type 'int', but argument has type 'void *'}}
+ __builtin_os_log_format(buf, "%.*P", i, p);
+ __builtin_os_log_format(buf, "%.*P", i, i); // expected-warning {{format specifies type 'void *' but the argument has type 'int'}}
+ __builtin_os_log_format(buf, pc); // expected-error {{os_log() format argument is not a string constant}}
+
+ printf("%{private}s", pc); // expected-warning {{using 'private' format specifier annotation outside of os_log()/os_trace()}}
+ __builtin_os_log_format(buf, "%{private}s", pc);
+
+ // <rdar://problem/23835805>
+ __builtin_os_log_format_buffer_size("no-args");
+ __builtin_os_log_format(buf, "%s", "hi");
+
+ // <rdar://problem/24828090>
+ wchar_t wc = 'a';
+ __builtin_os_log_format(buf, "%C", wc);
+ printf("%C", wc);
+ wchar_t wcs[] = {'a', 0};
+ __builtin_os_log_format(buf, "%S", wcs);
+ printf("%S", wcs);
+}
+
void test_char_pointer_arithmetic(int b) {
const char s1[] = "string";
const char s2[] = "%s string";
diff --git a/test/Sema/vector-cast.c b/test/Sema/vector-cast.c
index ea4acfa..03db540 100644
--- a/test/Sema/vector-cast.c
+++ b/test/Sema/vector-cast.c
@@ -45,24 +45,12 @@
}
typedef float float2 __attribute__ ((vector_size (8)));
-typedef __attribute__((vector_size(8))) double float64x1_t;
-typedef __attribute__((vector_size(16))) double float64x2_t;
-float64x1_t vget_low_f64(float64x2_t __p0);
void f4() {
float2 f2;
- double d, a, b, c;
- float64x2_t v = {0.0, 1.0};
- // FIXME: These diagnostics are inaccurate: should complain that 'double' to vector 'float2' involves truncation
- f2 += d; // expected-error {{cannot convert between vector values of different size ('float2' (vector of 2 'float' values) and 'double')}}
- d += f2; // expected-error {{cannot convert between vector values of different size}}
- a = 3.0 + vget_low_f64(v);
- b = vget_low_f64(v) + 3.0;
- c = vget_low_f64(v);
- c -= vget_low_f64(v);
- // LAX conversions between scalar and vector types require same size and one element sized vectors.
- d = f2; // expected-error {{assigning to 'double' from incompatible type 'float2'}}
- d = d + f2; // expected-error {{assigning to 'double' from incompatible type 'float2'}}
+ double d;
+ f2 += d;
+ d += f2;
}
// rdar://15931426
diff --git a/test/Sema/vector-compound-assign-lax.cpp b/test/Sema/vector-compound-assign-lax.cpp
new file mode 100644
index 0000000..296cfb7
--- /dev/null
+++ b/test/Sema/vector-compound-assign-lax.cpp
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -ffreestanding -triple armv7 -target-feature +neon -fsyntax-only %s -verify -Wvector-conversion -DNEON
+// RUN: %clang_cc1 -ffreestanding -triple=x86_64-apple-darwin -target-feature +sse2 -fsyntax-only %s -verify -Wvector-conversion -DSSE2
+
+// Test that there are no diagnostics for vector compound assignments where we
+// support lax conversions from the RHS type to the LHS type. For context, see:
+//
+// <rdar://problem/30112602> cannot convert between vector values ...
+// <rdar://problem/28639522> Cannot create binary operator with two ...
+// <rdar://problem/30110333> Invalid conversion from int64x2 to uint32x4 ...
+
+// expected-no-diagnostics
+
+#include <stdint.h>
+
+typedef int v_int32x4_t __attribute__((__vector_size__(16)));
+typedef unsigned v_uint32x4_t __attribute__((__vector_size__(16)));
+
+#ifdef NEON
+typedef __attribute__((neon_vector_type(8))) int16_t n_int16x8_t;
+typedef __attribute__((neon_vector_type(8))) uint16_t n_uint16x8_t;
+
+void fn1() {
+ n_int16x8_t i;
+ n_uint16x8_t u;
+ i += u;
+}
+#endif
+
+void fn2() {
+ v_int32x4_t i;
+ v_uint32x4_t u;
+ i += u;
+}
+
+#ifdef SSE2
+#include <x86intrin.h>
+
+typedef __attribute__((__ext_vector_type__(4))) unsigned int ev_uint32x4_t;
+
+void fn3() {
+ __m128i i;
+ ev_uint32x4_t u;
+ i += u; // FIXME: Converting uint32x4 to int64x2 should *not* be allowed.
+}
+#endif
diff --git a/test/SemaCXX/designated-initializers-base-class.cpp b/test/SemaCXX/designated-initializers-base-class.cpp
new file mode 100644
index 0000000..9c2e61e
--- /dev/null
+++ b/test/SemaCXX/designated-initializers-base-class.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -std=c++1z -fsyntax-only -verify -Winitializer-overrides
+// expected-no-diagnostics
+
+struct B {
+ int x;
+};
+
+struct D : B {
+ int y;
+};
+
+void test() { D d = {1, .y = 2}; }
diff --git a/test/SemaCXX/pseudo-destructors.cpp b/test/SemaCXX/pseudo-destructors.cpp
index 45f1eaf..bc0d7b2 100644
--- a/test/SemaCXX/pseudo-destructors.cpp
+++ b/test/SemaCXX/pseudo-destructors.cpp
@@ -89,3 +89,26 @@
void AliasTemplate(int *p) {
p->~Id<int>();
}
+
+namespace dotPointerAccess {
+struct Base {
+ virtual ~Base() {}
+};
+
+struct Derived : Base {
+ ~Derived() {}
+};
+
+void test() {
+ Derived d;
+ static_cast<Base *>(&d).~Base(); // expected-error {{member reference type 'dotPointerAccess::Base *' is a pointer; did you mean to use '->'}}
+ d->~Derived(); // expected-error {{member reference type 'dotPointerAccess::Derived' is not a pointer; did you mean to use '.'}}
+}
+
+typedef Derived *Foo;
+
+void test2(Foo d) {
+ d.~Foo(); // This is ok
+ d.~Derived(); // expected-error {{member reference type 'Foo' (aka 'dotPointerAccess::Derived *') is a pointer; did you mean to use '->'}}
+}
+}
diff --git a/test/SemaObjC/arc-repeated-weak.mm b/test/SemaObjC/arc-repeated-weak.mm
index 11161a0..8e2828f 100644
--- a/test/SemaObjC/arc-repeated-weak.mm
+++ b/test/SemaObjC/arc-repeated-weak.mm
@@ -462,3 +462,16 @@
use(NSBundle.foo2.weakProp); // expected-warning{{weak property 'weakProp' may be accessed multiple times}}
use(NSBundle2.foo2.weakProp); // expected-note{{also accessed here}}
}
+
+// This used to crash in the constructor of WeakObjectProfileTy when a
+// DeclRefExpr was passed that didn't reference a VarDecl.
+
+typedef INTF * INTFPtrTy;
+
+enum E {
+ e1
+};
+
+void foo1() {
+ INTFPtrTy tmp = (INTFPtrTy)e1; // expected-error{{cast of 'E' to 'INTFPtrTy' (aka 'INTF *') is disallowed with ARC}}
+}
diff --git a/test/SemaObjC/arc.m b/test/SemaObjC/arc.m
index f463bb0..72c07a9 100644
--- a/test/SemaObjC/arc.m
+++ b/test/SemaObjC/arc.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -fblocks -verify -Wno-objc-root-class -Wblock-capture-autoreleasing %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -fblocks -verify -Wno-objc-root-class %s
typedef unsigned long NSUInteger;
typedef const void * CFTypeRef;
@@ -809,9 +809,30 @@
TKAssertEqual(object, (id)nil);
}
-void block_capture_autoreleasing(A * __autoreleasing *a, A **b) { // expected-note {{declare the parameter __autoreleasing explicitly to suppress this warning}} expected-note {{declare the parameter __strong or capture a __block __strong variable to keep values alive across autorelease pools}}
+void block_capture_autoreleasing(A * __autoreleasing *a,
+ A **b, // expected-note {{declare the parameter __autoreleasing explicitly to suppress this warning}} expected-note {{declare the parameter __strong or capture a __block __strong variable to keep values alive across autorelease pools}}
+ A * _Nullable *c, // expected-note {{declare the parameter __autoreleasing explicitly to suppress this warning}} expected-note {{declare the parameter __strong or capture a __block __strong variable to keep values alive across autorelease pools}}
+ A * _Nullable __autoreleasing *d,
+ A ** _Nullable e, // expected-note {{declare the parameter __autoreleasing explicitly to suppress this warning}} expected-note {{declare the parameter __strong or capture a __block __strong variable to keep values alive across autorelease pools}}
+ A * __autoreleasing * _Nullable f,
+ id __autoreleasing *g,
+ id *h, // expected-note {{declare the parameter __autoreleasing explicitly to suppress this warning}} expected-note {{declare the parameter __strong or capture a __block __strong variable to keep values alive across autorelease pools}}
+ id _Nullable *i, // expected-note {{declare the parameter __autoreleasing explicitly to suppress this warning}} expected-note {{declare the parameter __strong or capture a __block __strong variable to keep values alive across autorelease pools}}
+ id _Nullable __autoreleasing *j,
+ id * _Nullable k, // expected-note {{declare the parameter __autoreleasing explicitly to suppress this warning}} expected-note {{declare the parameter __strong or capture a __block __strong variable to keep values alive across autorelease pools}}
+ id __autoreleasing * _Nullable l) {
^{
(void)*a;
(void)*b; // expected-warning {{block captures an autoreleasing out-parameter, which may result in use-after-free bugs}}
+ (void)*c; // expected-warning {{block captures an autoreleasing out-parameter, which may result in use-after-free bugs}}
+ (void)*d;
+ (void)*e; // expected-warning {{block captures an autoreleasing out-parameter, which may result in use-after-free bugs}}
+ (void)*f;
+ (void)*g;
+ (void)*h; // expected-warning {{block captures an autoreleasing out-parameter, which may result in use-after-free bugs}}
+ (void)*i; // expected-warning {{block captures an autoreleasing out-parameter, which may result in use-after-free bugs}}
+ (void)*j;
+ (void)*k; // expected-warning {{block captures an autoreleasing out-parameter, which may result in use-after-free bugs}}
+ (void)*l;
}();
}
diff --git a/test/SemaObjC/attr-swift.m b/test/SemaObjC/attr-swift.m
new file mode 100644
index 0000000..bdcbbd0
--- /dev/null
+++ b/test/SemaObjC/attr-swift.m
@@ -0,0 +1,217 @@
+// RUN: %clang_cc1 -verify -fsyntax-only -fobjc-arc -fblocks %s
+
+// --- swift_private ---
+
+__attribute__((swift_private))
+@protocol FooProto
+@end
+
+__attribute__((swift_private))
+@interface Foo
+@end
+
+@interface Bar
+@property id prop __attribute__((swift_private));
+- (void)instMethod __attribute__((swift_private));
++ (instancetype)bar __attribute__((swift_private));
+@end
+
+void function(id) __attribute__((swift_private));
+
+struct __attribute__((swift_private)) Point {
+ int x;
+ int y;
+};
+
+enum __attribute__((swift_private)) Colors {
+ Red, Green, Blue
+};
+
+typedef struct {
+ float x, y, z;
+} Point3D __attribute__((swift_private));
+
+
+// --- swift_name ---
+
+__attribute__((swift_name("SNFooType")))
+@protocol SNFoo
+@end
+
+__attribute__((swift_name("SNFooClass")))
+@interface SNFoo <SNFoo>
+- (instancetype)init __attribute__((swift_name("init()")));
+- (instancetype)initWithValue:(int)value __attribute__((swift_name("fooWithValue(_:)")));
+
++ (void)refresh __attribute__((swift_name("refresh()")));
+
++ (instancetype)foo __attribute__((swift_name("foo()")));
++ (SNFoo *)fooWithValue:(int)value __attribute__((swift_name("foo(value:)")));
++ (SNFoo *)fooWithValue:(int)value value:(int)value2 __attribute__((swift_name("foo(value:extra:)")));
++ (SNFoo *)fooWithConvertingValue:(int)value value:(int)value2 __attribute__((swift_name("init(_:extra:)")));
+
++ (SNFoo *)fooWithOtherValue:(int)value __attribute__((swift_name("init"))); // expected-warning {{parameter of 'swift_name' attribute must be a Swift function name string}}
++ (SNFoo *)fooWithAnotherValue:(int)value __attribute__((swift_name("foo()"))); // expected-warning {{too few parameters in 'swift_name' attribute (expected 1; got 0)}}
++ (SNFoo *)fooWithYetAnotherValue:(int)value __attribute__((swift_name("foo(value:extra:)"))); // expected-warning {{too many parameters in 'swift_name' attribute (expected 1; got 2)}}
+
++ (SNFoo *)fooAndReturnErrorCode:(int *)errorCode __attribute__((swift_name("foo()"))); // no-warning
++ (SNFoo *)fooWithValue:(int)value andReturnErrorCode:(int *)errorCode __attribute__((swift_name("foo(value:)"))); // no-warning
++ (SNFoo *)fooFromErrorCode:(const int *)errorCode __attribute__((swift_name("foo()"))); // expected-warning {{too few parameters in 'swift_name' attribute (expected 1; got 0)}}
++ (SNFoo *)fooWithValue:(int)value fromErrorCode:(const int *)errorCode __attribute__((swift_name("foo(value:)"))); // expected-warning {{too few parameters in 'swift_name' attribute (expected 2; got 1)}}
++ (SNFoo *)fooWithPointerA:(int *)value andReturnErrorCode:(int *)errorCode __attribute__((swift_name("foo()"))); // no-warning
++ (SNFoo *)fooWithPointerB:(int *)value andReturnErrorCode:(int *)errorCode __attribute__((swift_name("foo(pointer:)"))); // no-warning
++ (SNFoo *)fooWithPointerC:(int *)value andReturnErrorCode:(int *)errorCode __attribute__((swift_name("foo(pointer:errorCode:)"))); // no-warning
++ (SNFoo *)fooWithOtherFoo:(SNFoo *)other __attribute__((swift_name("foo()"))); // expected-warning {{too few parameters in 'swift_name' attribute (expected 1; got 0)}}
+
++ (instancetype)specialFoo __attribute__((swift_name("init(options:)")));
++ (instancetype)specialBar __attribute__((swift_name("init(options:extra:)"))); // expected-warning {{too many parameters in 'swift_name' attribute (expected 0; got 2)}}
++ (instancetype)specialBaz __attribute__((swift_name("init(_:)"))); // expected-warning {{too many parameters in 'swift_name' attribute (expected 0; got 1)}}
++ (instancetype)specialGarply __attribute__((swift_name("foo(options:)"))); // expected-warning {{too many parameters in 'swift_name' attribute (expected 0; got 1)}}
+
++ (instancetype)trailingParen __attribute__((swift_name("foo("))); // expected-warning {{parameter of 'swift_name' attribute must be a Swift function name string}}
++ (instancetype)trailingColon:(int)value __attribute__((swift_name("foo(value)"))); // expected-warning {{parameter of 'swift_name' attribute must be a Swift function name string}}
++ (instancetype)initialIgnore:(int)value __attribute__((swift_name("_(value:)"))); // expected-warning {{'swift_name' attribute has invalid identifier for base name}}
++ (instancetype)middleOmitted:(int)value __attribute__((swift_name("foo(:)"))); // expected-warning {{'swift_name' attribute has invalid identifier for parameter name}}
+
+@property(strong) id someProp __attribute__((swift_name("prop")));
+@end
+
+enum __attribute__((swift_name("MoreColors"))) MoreColors {
+ Cyan,
+ Magenta,
+ Yellow __attribute__((swift_name("RoseGold"))),
+ Black __attribute__((swift_name("SpaceGrey()"))) // expected-warning {{'swift_name' attribute has invalid identifier for base name}}
+};
+
+struct __attribute__((swift_name("FooStruct"))) BarStruct {
+ int x, y, z __attribute__((swift_name("zed")));
+};
+
+int global_int __attribute__((swift_name("GlobalInt")));
+
+void foo1(int i) __attribute__((swift_name("foo"))); // expected-warning{{parameter of 'swift_name' attribute must be a Swift function name string}}
+void foo2(int i) __attribute__((swift_name("foo()"))); // expected-warning{{too few parameters in 'swift_name' attribute (expected 1; got 0)}}
+void foo2(int i) __attribute__((swift_name("foo(a:b:)"))); // expected-warning{{too many parameters in 'swift_name' attribute (expected 1; got 2)}}
+void foo3(int i, int j) __attribute__((swift_name("fooWithX(_:y:)"))); // okay
+void foo4(int i, int *error) __attribute__((swift_name("fooWithA(_:)"))); // okay
+
+typedef int some_int_type __attribute__((swift_name("SomeInt")));
+
+struct Point3D createPoint3D(float x, float y, float z) __attribute__((swift_name("Point3D.init(x:y:z:)")));
+struct Point3D rotatePoint3D(Point3D point, float radians) __attribute__((swift_name("Point3D.rotate(self:radians:)")));
+struct Point3D badRotatePoint3D(Point3D point, float radians) __attribute__((swift_name("Point3D.rotate(radians:)"))); // expected-warning {{too few parameters in 'swift_name' attribute (expected 2; got 1)}}
+
+extern struct Point3D identityPoint __attribute__((swift_name("Point3D.identity")));
+
+// Getters and setters.
+float Point3DGetMagnitude(Point3D point) __attribute__((swift_name("getter:Point3D.magnitude(self:)")));
+
+float Point3DGetMagnitudeAndSomethingElse(Point3D point, float wat) __attribute__((swift_name("getter:Point3D.magnitude(self:wat:)"))); // expected-warning {{'swift_name' attribute for getter must not take any parameters besides 'self:'}}
+
+float Point3DGetRadius(Point3D point) __attribute__((swift_name("getter:Point3D.radius(self:)")));
+void Point3DSetRadius(Point3D point, float radius) __attribute__((swift_name("setter:Point3D.radius(self:newValue:)")));
+
+float Point3DPreGetRadius(Point3D point) __attribute__((swift_name("getter:Point3D.preRadius(self:)")));
+void Point3DPreSetRadius(float radius, Point3D point) __attribute__((swift_name("setter:Point3D.preRadius(newValue:self:)")));
+
+void Point3DSetRadiusAndSomethingElse(Point3D point, float radius, float wat) __attribute__((swift_name("setter:Point3D.radius(self:newValue:wat:)"))); // expected-warning {{'swift_name' attribute for setter must take one parameter for new value}}
+
+float Point3DGetComponent(Point3D point, unsigned index) __attribute__((swift_name("getter:Point3D.subscript(self:_:)")));
+float Point3DSetComponent(Point3D point, unsigned index, float value) __attribute__((swift_name("setter:Point3D.subscript(self:_:newValue:)")));
+
+float Point3DGetMatrixComponent(Point3D point, unsigned x, unsigned y) __attribute__((swift_name("getter:Point3D.subscript(self:x:y:)")));
+void Point3DSetMatrixComponent(Point3D point, unsigned x, float value, unsigned y) __attribute__((swift_name("setter:Point3D.subscript(self:x:newValue:y:)")));
+
+float Point3DSetWithoutNewValue(Point3D point, unsigned x, unsigned y) __attribute__((swift_name("setter:Point3D.subscript(self:x:y:)"))); // expected-warning {{'swift_name' attribute for 'subscript' setter must take a 'newValue:' parameter}}
+
+float Point3DSubscriptButNotGetterSetter(Point3D point, unsigned x) __attribute__((swift_name("Point3D.subscript(self:_:)"))); // expected-warning {{'swift_name' attribute for 'subscript' must be a getter or setter}}
+
+void Point3DSubscriptSetterTwoNewValues(Point3D point, unsigned x, float a, float b) __attribute__((swift_name("setter:Point3D.subscript(self:_:newValue:newValue:)"))); // expected-warning {{'swift_name' attribute for 'subscript' setter cannot take multiple 'newValue:' parameters}}
+float Point3DSubscriptGetterNewValue(Point3D point, unsigned x, float a, float b) __attribute__((swift_name("getter:Point3D.subscript(self:_:newValue:newValue:)"))); // expected-warning {{'swift_name' attribute for 'subscript' getter cannot take a 'newValue:' parameter}}
+
+void Point3DMethodWithNewValue(Point3D point, float newValue) __attribute__((swift_name("Point3D.method(self:newValue:)")));
+void Point3DMethodWithNewValues(Point3D point, float newValue, float newValueB) __attribute__((swift_name("Point3D.method(self:newValue:newValue:)")));
+
+float Point3DStaticSubscript(unsigned x) __attribute__((swift_name("getter:Point3D.subscript(_:)"))); // expected-warning {{'swift_name' attribute for 'subscript' must take a 'self:' parameter}}
+float Point3DStaticSubscriptNoArgs(void) __attribute__((swift_name("getter:Point3D.subscript()"))); // expected-warning {{'swift_name' attribute for 'subscript' must take at least one parameter}}
+
+float Point3DPreGetComponent(Point3D point, unsigned index) __attribute__((swift_name("getter:Point3D.subscript(self:_:)")));
+
+Point3D getCurrentPoint3D(void) __attribute__((swift_name("getter:currentPoint3D()")));
+
+void setCurrentPoint3D(Point3D point) __attribute__((swift_name("setter:currentPoint3D(newValue:)")));
+
+Point3D getLastPoint3D(void) __attribute__((swift_name("getter:lastPoint3D()")));
+
+void setLastPoint3D(Point3D point) __attribute__((swift_name("setter:lastPoint3D(newValue:)")));
+
+Point3D getZeroPoint(void) __attribute__((swift_name("getter:Point3D.zero()")));
+Point3D getZeroPointNoPrototype() __attribute__((swift_name("getter:Point3D.zeroNoPrototype()"))); // expected-warning{{'swift_name' attribute can only be applied to function declarations with prototypes}}
+void setZeroPoint(Point3D point) __attribute__((swift_name("setter:Point3D.zero(newValue:)")));
+
+Point3D badGetter1(int x) __attribute__((swift_name("getter:bad1(_:))"))); // expected-warning{{parameter of 'swift_name' attribute must be a Swift function name string}}
+void badSetter1(void) __attribute__((swift_name("getter:bad1())"))); // expected-warning{{parameter of 'swift_name' attribute must be a Swift function name string}}
+
+Point3D badGetter2(Point3D point) __attribute__((swift_name("getter:bad2(_:))"))); // expected-warning{{parameter of 'swift_name' attribute must be a Swift function name string}}
+
+void badSetter2(Point3D point) __attribute__((swift_name("setter:bad2(self:))"))); // expected-warning{{parameter of 'swift_name' attribute must be a Swift function name string}}
+
+// --- swift_error ---
+
+@class NSError;
+
+typedef struct __attribute__((objc_bridge(NSError))) __CFError *CFErrorRef;
+
+@interface Erroneous
+- (_Bool) tom0: (NSError**) err __attribute__((swift_error(none)));
+- (_Bool) tom1: (NSError**) err __attribute__((swift_error(nonnull_error)));
+- (_Bool) tom2: (NSError**) err __attribute__((swift_error(null_result))); // expected-error {{'swift_error' attribute with 'null_result' convention can only be applied to a method returning a pointer}}
+- (_Bool) tom3: (NSError**) err __attribute__((swift_error(nonzero_result)));
+- (_Bool) tom4: (NSError**) err __attribute__((swift_error(zero_result)));
+
+- (Undeclared) richard0: (NSError**) err __attribute__((swift_error(none))); // expected-error {{expected a type}}
+- (Undeclared) richard1: (NSError**) err __attribute__((swift_error(nonnull_error))); // expected-error {{expected a type}}
+- (Undeclared) richard2: (NSError**) err __attribute__((swift_error(null_result))); // expected-error {{expected a type}}
+// FIXME: the follow-on warnings should really be suppressed, but apparently having an ill-formed return type doesn't mark anything as invalid
+- (Undeclared) richard3: (NSError**) err __attribute__((swift_error(nonzero_result))); // expected-error {{expected a type}} expected-error {{can only be applied}}
+- (Undeclared) richard4: (NSError**) err __attribute__((swift_error(zero_result))); // expected-error {{expected a type}} expected-error {{can only be applied}}
+
+- (instancetype) harry0: (NSError**) err __attribute__((swift_error(none)));
+- (instancetype) harry1: (NSError**) err __attribute__((swift_error(nonnull_error)));
+- (instancetype) harry2: (NSError**) err __attribute__((swift_error(null_result)));
+- (instancetype) harry3: (NSError**) err __attribute__((swift_error(nonzero_result))); // expected-error {{'swift_error' attribute with 'nonzero_result' convention can only be applied to a method returning an integral type}}
+- (instancetype) harry4: (NSError**) err __attribute__((swift_error(zero_result))); // expected-error {{'swift_error' attribute with 'zero_result' convention can only be applied to a method returning an integral type}}
+
+- (instancetype) harry0 __attribute__((swift_error(none)));
+- (instancetype) harry1 __attribute__((swift_error(nonnull_error))); // expected-error {{'swift_error' attribute can only be applied to a method with an error parameter}}
+- (instancetype) harry2 __attribute__((swift_error(null_result))); // expected-error {{'swift_error' attribute can only be applied to a method with an error parameter}}
+- (instancetype) harry3 __attribute__((swift_error(nonzero_result))); // expected-error {{'swift_error' attribute can only be applied to a method with an error parameter}}
+- (instancetype) harry4 __attribute__((swift_error(zero_result))); // expected-error {{'swift_error' attribute can only be applied to a method with an error parameter}}
+@end
+
+extern _Bool tom0(CFErrorRef *) __attribute__((swift_error(none)));
+extern _Bool tom1(CFErrorRef *) __attribute__((swift_error(nonnull_error)));
+extern _Bool tom2(CFErrorRef *) __attribute__((swift_error(null_result))); // expected-error {{'swift_error' attribute with 'null_result' convention can only be applied to a function returning a pointer}}
+extern _Bool tom3(CFErrorRef *) __attribute__((swift_error(nonzero_result)));
+extern _Bool tom4(CFErrorRef *) __attribute__((swift_error(zero_result)));
+
+extern Undeclared richard0(CFErrorRef *) __attribute__((swift_error(none))); // expected-error {{unknown type name 'Undeclared'}}
+extern Undeclared richard1(CFErrorRef *) __attribute__((swift_error(nonnull_error))); // expected-error {{unknown type name 'Undeclared'}}
+extern Undeclared richard2(CFErrorRef *) __attribute__((swift_error(null_result))); // expected-error {{unknown type name 'Undeclared'}}
+extern Undeclared richard3(CFErrorRef *) __attribute__((swift_error(nonzero_result))); // expected-error {{unknown type name 'Undeclared'}}
+extern Undeclared richard4(CFErrorRef *) __attribute__((swift_error(zero_result))); // expected-error {{unknown type name 'Undeclared'}}
+
+extern void *harry0(CFErrorRef *) __attribute__((swift_error(none)));
+extern void *harry1(CFErrorRef *) __attribute__((swift_error(nonnull_error)));
+extern void *harry2(CFErrorRef *) __attribute__((swift_error(null_result)));
+extern void *harry3(CFErrorRef *) __attribute__((swift_error(nonzero_result))); // expected-error {{'swift_error' attribute with 'nonzero_result' convention can only be applied to a function returning an integral type}}
+extern void *harry4(CFErrorRef *) __attribute__((swift_error(zero_result))); // expected-error {{'swift_error' attribute with 'zero_result' convention can only be applied to a function returning an integral type}}
+
+extern void *wilma0(void) __attribute__((swift_error(none)));
+extern void *wilma1(void) __attribute__((swift_error(nonnull_error))); // expected-error {{'swift_error' attribute can only be applied to a function with an error parameter}}
+extern void *wilma2(void) __attribute__((swift_error(null_result))); // expected-error {{'swift_error' attribute can only be applied to a function with an error parameter}}
+extern void *wilma3(void) __attribute__((swift_error(nonzero_result))); // expected-error {{'swift_error' attribute can only be applied to a function with an error parameter}}
+extern void *wilma4(void) __attribute__((swift_error(zero_result))); // expected-error {{'swift_error' attribute can only be applied to a function with an error parameter}}
+
+
+extern _Bool suzanne __attribute__((swift_error(none))); // expected-error {{'swift_error' attribute only applies to functions and methods}}
diff --git a/test/SemaObjC/attr-swift_newtype.c b/test/SemaObjC/attr-swift_newtype.c
new file mode 100644
index 0000000..61e4d89
--- /dev/null
+++ b/test/SemaObjC/attr-swift_newtype.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -verify -fsyntax-only %s
+
+typedef int T1 __attribute__((swift_newtype(struct)));
+typedef int T2 __attribute__((swift_newtype(enum)));
+
+typedef int T3 __attribute__((swift_wrapper(struct)));
+typedef int T4 __attribute__((swift_wrapper(enum)));
+
+
+typedef int Bad1 __attribute__((swift_newtype(bad))); // expected-warning{{'swift_newtype' attribute argument not supported: 'bad'}}
+typedef int Bad2 __attribute__((swift_newtype())); // expected-error{{argument required after attribute}}
+typedef int Bad3 __attribute__((swift_newtype(bad, badder)));
+ // expected-error@-1{{expected ')'}}
+ // expected-note@-2{{to match this '('}}
+ // expected-warning@-3{{'swift_newtype' attribute argument not supported: 'bad'}}
+
+
+// TODO: better error message below
+// FIXME: why is this a parse error, rather than Sema error triggering?
+struct Bad4 __attribute__((swift_newtype(struct))) { }; // expected-error{{expected identifier or '('}}
diff --git a/test/SemaObjC/format-strings-objc.m b/test/SemaObjC/format-strings-objc.m
index 767d5ac..d5e3220 100644
--- a/test/SemaObjC/format-strings-objc.m
+++ b/test/SemaObjC/format-strings-objc.m
@@ -265,40 +265,17 @@
NSLog(@"%2$[tt]@ %1$[tt]s", @"Foo", @"Bar"); // expected-warning {{object format flags cannot be used with 's' conversion specifier}}
}
-// rdar://23622446
-@interface RD23622446_Tester: NSObject
+// Test os_log_format primitive with ObjC string literal format argument.
+void test_os_log_format(char c, const char *pc, int i, int *pi, void *p, void *buf, NSString *nss) {
+ __builtin_os_log_format(buf, @"");
+ __builtin_os_log_format(buf, @"%d"); // expected-warning {{more '%' conversions than data arguments}}
+ __builtin_os_log_format(buf, @"%d", i);
+ __builtin_os_log_format(buf, @"%P", p); // expected-warning {{using '%P' format specifier without precision}}
+ __builtin_os_log_format(buf, @"%.10P", p);
+ __builtin_os_log_format(buf, @"%.*P", p); // expected-warning {{field precision should have type 'int', but argument has type 'void *'}}
+ __builtin_os_log_format(buf, @"%.*P", i, p);
+ __builtin_os_log_format(buf, @"%.*P", i, i); // expected-warning {{format specifies type 'void *' but the argument has type 'int'}}
-+ (void)stringWithFormat:(const char *)format, ... __attribute__((format(__printf__, 1, 2)));
-
-@end
-
-@implementation RD23622446_Tester
-
-__attribute__ ((format_arg(1)))
-const char *rd23622446(const char *format) {
- return format;
+ __builtin_os_log_format(buf, @"%{private}s", pc);
+ __builtin_os_log_format(buf, @"%@", nss);
}
-
-+ (void)stringWithFormat:(const char *)format, ... {
- return;
-}
-
-- (const char *)test:(const char *)format __attribute__ ((format_arg(1))) {
- return format;
-}
-
-- (NSString *)str:(NSString *)format __attribute__ ((format_arg(1))) {
- return format;
-}
-
-- (void)foo {
- [RD23622446_Tester stringWithFormat:rd23622446("%u"), 1, 2]; // expected-warning {{data argument not used by format string}}
- [RD23622446_Tester stringWithFormat:[self test: "%u"], 1, 2]; // expected-warning {{data argument not used by format string}}
- [RD23622446_Tester stringWithFormat:[self test: "%s %s"], "name"]; // expected-warning {{more '%' conversions than data arguments}}
- NSLog([self str: @"%@ %@"], @"name"); // expected-warning {{more '%' conversions than data arguments}}
- [RD23622446_Tester stringWithFormat:rd23622446("%d"), 1]; // ok
- [RD23622446_Tester stringWithFormat:[self test: "%d %d"], 1, 2]; // ok
- NSLog([self str: @"%@"], @"string"); // ok
-}
-
-@end
diff --git a/test/SemaObjC/kindof.m b/test/SemaObjC/kindof.m
index 9d758d3..63ba18f 100644
--- a/test/SemaObjC/kindof.m
+++ b/test/SemaObjC/kindof.m
@@ -385,7 +385,7 @@
@end
@interface NSGeneric<ObjectType> : NSObject
-- (void)test:(__kindof ObjectType)T; // expected-note{{passing argument to parameter 'T' here}}
+- (void)test:(__kindof ObjectType)T;
- (void)mapUsingBlock:(id (^)(__kindof ObjectType))block;
@end
@implementation NSGeneric
@@ -395,14 +395,6 @@
}
@end
-void testGeneric(NSGeneric<NSString*> *generic) {
- NSObject *NSObject_obj;
- // Assign from NSObject_obj to __kindof NSString*.
- [generic test:NSObject_obj]; // expected-warning{{incompatible pointer types sending 'NSObject *' to parameter of type '__kindof NSString *'}}
- NSString *NSString_str;
- [generic test:NSString_str];
-}
-
// Check that clang doesn't crash when a type parameter is illegal.
@interface Array1<T> : NSObject
@end
diff --git a/test/SemaObjC/parameterized_classes_subst.m b/test/SemaObjC/parameterized_classes_subst.m
index da2d56f..f90ee90 100644
--- a/test/SemaObjC/parameterized_classes_subst.m
+++ b/test/SemaObjC/parameterized_classes_subst.m
@@ -426,36 +426,3 @@
// warning about likely protocol/class name typos.
// --------------------------------------------------------------------------
typedef NSArray<NSObject> ArrayOfNSObjectWarning; // expected-warning{{parameterized class 'NSArray' already conforms to the protocols listed; did you forget a '*'?}}
-
-// rdar://25060179
-@interface MyMutableDictionary<KeyType, ObjectType> : NSObject
-- (void)setObject:(ObjectType)obj forKeyedSubscript:(KeyType <NSCopying>)key; // expected-note{{passing argument to parameter 'obj' here}} \
- // expected-note{{passing argument to parameter 'key' here}}
-@end
-
-void bar(MyMutableDictionary<NSString *, NSString *> *stringsByString,
- NSNumber *n1, NSNumber *n2) {
- // We warn here when the key types do not match.
- stringsByString[n1] = n2; // expected-warning{{incompatible pointer types sending 'NSNumber *' to parameter of type 'NSString *'}} \
- // expected-warning{{incompatible pointer types sending 'NSNumber *' to parameter of type 'NSString<NSCopying> *'}}
-}
-
-@interface MyTest<K, V> : NSObject <NSCopying>
-- (V)test:(K)key;
-- (V)test2:(K)key; // expected-note{{previous definition is here}}
-- (void)mapUsingBlock:(id (^)(V))block;
-- (void)mapUsingBlock2:(id (^)(V))block; // expected-note{{previous definition is here}}
-@end
-
-@implementation MyTest
-- (id)test:(id)key {
- return key;
-}
-- (int)test2:(id)key{ // expected-warning{{conflicting return type in implementation}}
- return 0;
-}
-- (void)mapUsingBlock:(id (^)(id))block {
-}
-- (void)mapUsingBlock2:(id)block { // expected-warning{{conflicting parameter types in implementation}}
-}
-@end
diff --git a/tools/c-index-test/CMakeLists.txt b/tools/c-index-test/CMakeLists.txt
index e0df503..7244e2c 100644
--- a/tools/c-index-test/CMakeLists.txt
+++ b/tools/c-index-test/CMakeLists.txt
@@ -24,8 +24,10 @@
libclang
clangAST
clangBasic
+ clangCodeGen
clangFrontend
clangIndex
+ clangSerialization
)
endif()
diff --git a/tools/c-index-test/core_main.cpp b/tools/c-index-test/core_main.cpp
index 0ab24fb..f371870 100644
--- a/tools/c-index-test/core_main.cpp
+++ b/tools/c-index-test/core_main.cpp
@@ -7,6 +7,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
@@ -15,6 +16,7 @@
#include "clang/Index/IndexDataConsumer.h"
#include "clang/Index/USRGeneration.h"
#include "clang/Index/CodegenNameGenerator.h"
+#include "clang/Serialization/ASTReader.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/raw_ostream.h"
@@ -49,6 +51,17 @@
"invocation\n"
);
+static cl::opt<bool>
+DumpModuleImports("dump-imported-module-files",
+ cl::desc("Print symbols and input files from imported modules"));
+
+static cl::opt<std::string>
+ModuleFilePath("module-file",
+ cl::desc("Path to module file to print symbols from"));
+static cl::opt<std::string>
+ ModuleFormat("fmodule-format", cl::init("raw"),
+ cl::desc("Container format for clang modules and PCH, 'raw' or 'obj'"));
+
}
} // anonymous namespace
@@ -134,7 +147,19 @@
// Print Source Symbols
//===----------------------------------------------------------------------===//
-static bool printSourceSymbols(ArrayRef<const char *> Args) {
+static void dumpModuleFileInputs(serialization::ModuleFile &Mod,
+ ASTReader &Reader,
+ raw_ostream &OS) {
+ OS << "---- Module Inputs ----\n";
+ Reader.visitInputFiles(Mod, /*IncludeSystem=*/true, /*Complain=*/false,
+ [&](const serialization::InputFile &IF, bool isSystem) {
+ OS << (isSystem ? "system" : "user") << " | ";
+ OS << IF.getFile()->getName() << '\n';
+ });
+}
+
+static bool printSourceSymbols(ArrayRef<const char *> Args,
+ bool dumpModuleImports) {
SmallVector<const char *, 4> ArgsWithProgName;
ArgsWithProgName.push_back("clang");
ArgsWithProgName.append(Args.begin(), Args.end());
@@ -144,7 +169,8 @@
if (!CInvok)
return true;
- auto DataConsumer = std::make_shared<PrintIndexDataConsumer>(outs());
+ raw_ostream &OS = outs();
+ auto DataConsumer = std::make_shared<PrintIndexDataConsumer>(OS);
IndexingOptions IndexOpts;
std::unique_ptr<FrontendAction> IndexAction;
IndexAction = createIndexingAction(DataConsumer, IndexOpts,
@@ -157,6 +183,50 @@
if (!Unit)
return true;
+ if (dumpModuleImports) {
+ if (auto Reader = Unit->getASTReader()) {
+ Reader->getModuleManager().visit([&](serialization::ModuleFile &Mod) -> bool {
+ OS << "==== Module " << Mod.ModuleName << " ====\n";
+ indexModuleFile(Mod, *Reader, DataConsumer, IndexOpts);
+ dumpModuleFileInputs(Mod, *Reader, OS);
+ return true; // skip module dependencies.
+ });
+ }
+ }
+
+ return false;
+}
+
+static bool printSourceSymbolsFromModule(StringRef modulePath,
+ StringRef format) {
+ FileSystemOptions FileSystemOpts;
+ auto pchContOps = std::make_shared<PCHContainerOperations>();
+ // Register the support for object-file-wrapped Clang modules.
+ pchContOps->registerReader(llvm::make_unique<ObjectFilePCHContainerReader>());
+ auto pchRdr = pchContOps->getReaderOrNull(format);
+ if (!pchRdr) {
+ errs() << "unknown module format: " << format << '\n';
+ return true;
+ }
+
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
+ CompilerInstance::createDiagnostics(new DiagnosticOptions());
+ std::unique_ptr<ASTUnit> AU = ASTUnit::LoadFromASTFile(
+ modulePath, *pchRdr, Diags,
+ FileSystemOpts, /*UseDebugInfo=*/false,
+ /*OnlyLocalDecls=*/true, None,
+ /*CaptureDiagnostics=*/false,
+ /*AllowPCHWithCompilerErrors=*/true,
+ /*UserFilesAreVolatile=*/false);
+ if (!AU) {
+ errs() << "failed to create TU for: " << modulePath << '\n';
+ return true;
+ }
+
+ auto DataConsumer = std::make_shared<PrintIndexDataConsumer>(outs());
+ IndexingOptions IndexOpts;
+ indexASTUnit(*AU, DataConsumer, IndexOpts);
+
return false;
}
@@ -219,11 +289,15 @@
}
if (options::Action == ActionType::PrintSourceSymbols) {
+ if (!options::ModuleFilePath.empty()) {
+ return printSourceSymbolsFromModule(options::ModuleFilePath,
+ options::ModuleFormat);
+ }
if (CompArgs.empty()) {
errs() << "error: missing compiler args; pass '-- <compiler arguments>'\n";
return 1;
}
- return printSourceSymbols(CompArgs);
+ return printSourceSymbols(CompArgs, options::DumpModuleImports);
}
return 0;
diff --git a/tools/clang-check/CMakeLists.txt b/tools/clang-check/CMakeLists.txt
index 04151a8..233f981 100644
--- a/tools/clang-check/CMakeLists.txt
+++ b/tools/clang-check/CMakeLists.txt
@@ -9,6 +9,7 @@
)
target_link_libraries(clang-check
+ clangAPINotes
clangAST
clangBasic
clangDriver
diff --git a/tools/clang-offload-bundler/ClangOffloadBundler.cpp b/tools/clang-offload-bundler/ClangOffloadBundler.cpp
index 20988b4..f37868f 100644
--- a/tools/clang-offload-bundler/ClangOffloadBundler.cpp
+++ b/tools/clang-offload-bundler/ClangOffloadBundler.cpp
@@ -514,7 +514,10 @@
// Dump the contents of the temporary file if that was requested.
if (DumpTemporaryFiles) {
errs() << ";\n; Object file bundler IR file.\n;\n";
- AuxModule.get()->dump();
+ AuxModule.get()->print(errs(), nullptr,
+ /*ShouldPreserveUseListOrder=*/false,
+ /*IsForDebug=*/true);
+ errs() << '\n';
}
// Find clang in order to create the bundle binary.
diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt
index f6e26fa..9dfe8cf 100644
--- a/tools/driver/CMakeLists.txt
+++ b/tools/driver/CMakeLists.txt
@@ -32,6 +32,7 @@
driver.cpp
cc1_main.cpp
cc1as_main.cpp
+ apinotes_main.cpp
DEPENDS
${tablegen_deps}
@@ -39,6 +40,7 @@
target_link_libraries(clang
clangBasic
+ clangAPINotes
clangCodeGen
clangDriver
clangFrontend
diff --git a/tools/driver/apinotes_main.cpp b/tools/driver/apinotes_main.cpp
new file mode 100644
index 0000000..930dc39
--- /dev/null
+++ b/tools/driver/apinotes_main.cpp
@@ -0,0 +1,154 @@
+//===-- api_notes.cpp - API Notes Driver ----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file provides conversion between the YAML (source) and binary forms
+/// of API notes.
+///
+//===----------------------------------------------------------------------===//
+#include "clang/APINotes/APINotesYAMLCompiler.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/Triple.h"
+
+using namespace llvm;
+namespace api_notes = clang::api_notes;
+
+int cc1apinotes_main(ArrayRef<const char *> Argv, const char *Argv0,
+ void *MainAddr) {
+
+ // Mark all our options with this category, everything else (except for
+ // -version and -help) will be hidden.
+ static cl::OptionCategory APINotesCategory("API Notes options");
+
+ static cl::opt<api_notes::ActionType>
+ Action(cl::desc("Mode:"), cl::init(api_notes::ActionType::None),
+ cl::values(
+ clEnumValN(api_notes::ActionType::YAMLToBinary,
+ "yaml-to-binary",
+ "Convert YAML to binary format"),
+ clEnumValN(api_notes::ActionType::BinaryToYAML,
+ "binary-to-yaml",
+ "Convert binary format to YAML"),
+ clEnumValN(api_notes::ActionType::Dump,
+ "dump",
+ "Parse and dump the output")),
+ cl::cat(APINotesCategory));
+
+ static cl::opt<std::string>
+ InputFilename(cl::Positional, cl::desc("<input file>"),
+ cl::Required, cl::cat(APINotesCategory));
+
+ static cl::opt<std::string>
+ Target("target", cl::desc("Generate binary format for the given target"),
+ cl::cat(APINotesCategory));
+
+ static cl::opt<std::string>
+ OutputFilename("o", cl::desc("Output file name"), cl::cat(APINotesCategory));
+
+ cl::HideUnrelatedOptions(APINotesCategory);
+
+ SmallVector<const char *, 4> Args;
+ Args.push_back(Argv0);
+ Args.append(Argv.begin(), Argv.end());
+ cl::ParseCommandLineOptions(Args.size(),
+ Args.data(),
+ "Clang API Notes Tool\n");
+
+ if (Action == clang::api_notes::ActionType::None) {
+ errs() << "action required\n";
+ cl::PrintHelpMessage();
+ return 1;
+ }
+
+ auto fileBufOrErr = MemoryBuffer::getFile(InputFilename);
+ if (std::error_code EC = fileBufOrErr.getError()) {
+ llvm::errs() << "\n Could not open input file: " + EC.message() << '\n';
+ return true;
+ }
+ StringRef input = fileBufOrErr.get()->getBuffer();
+
+ switch (Action) {
+ case api_notes::ActionType::None:
+ llvm_unreachable("handled above");
+
+ case api_notes::ActionType::YAMLToBinary: {
+ if (OutputFilename.empty()) {
+ errs() << "output file is required\n";
+ cl::PrintHelpMessage();
+ return 1;
+ }
+
+ api_notes::OSType targetOS = api_notes::OSType::Absent;
+ // TODO: Check that we've specified the target.
+ if (!Target.empty()) {
+ llvm::Triple target(llvm::Triple::normalize(Target));
+ switch (target.getOS()) {
+ case llvm::Triple::Darwin:
+ case llvm::Triple::MacOSX:
+ targetOS = api_notes::OSType::OSX;
+ break;
+ case llvm::Triple::IOS:
+ targetOS = api_notes::OSType::IOS;
+ break;
+ case llvm::Triple::WatchOS:
+ targetOS = api_notes::OSType::WatchOS;
+ break;
+ case llvm::Triple::TvOS:
+ targetOS = api_notes::OSType::TvOS;
+ break;
+ default:
+ errs() << "target is not supported\n";
+ return 1;
+ }
+ }
+ std::error_code EC;
+ llvm::raw_fd_ostream os(OutputFilename, EC,
+ llvm::sys::fs::OpenFlags::F_None);
+
+ if (api_notes::compileAPINotes(input, /*sourceFile=*/nullptr, os, targetOS))
+ return 1;
+
+ os.flush();
+
+ return os.has_error();
+ }
+
+ case api_notes::ActionType::BinaryToYAML: {
+ if (OutputFilename.empty()) {
+ errs() << "output file required\n";
+ cl::PrintHelpMessage();
+ return 1;
+ }
+
+ std::error_code EC;
+ llvm::raw_fd_ostream os(OutputFilename, EC,
+ llvm::sys::fs::OpenFlags::F_None);
+
+ if (api_notes::decompileAPINotes(std::move(fileBufOrErr.get()), os))
+ return 1;
+
+ os.flush();
+
+ return os.has_error();
+ }
+
+ case api_notes::ActionType::Dump:
+ return api_notes::parseAndDumpAPINotes(input);
+ }
+
+ return 1;
+}
+
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp
index 6161302..45b1ad3 100644
--- a/tools/driver/driver.cpp
+++ b/tools/driver/driver.cpp
@@ -198,6 +198,8 @@
void *MainAddr);
extern int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0,
void *MainAddr);
+extern int cc1apinotes_main(ArrayRef<const char *> Argv, const char *Argv0,
+ void *MainAddr);
static void insertTargetAndModeArgs(StringRef Target, StringRef Mode,
SmallVectorImpl<const char *> &ArgVector,
@@ -299,6 +301,8 @@
return cc1_main(argv.slice(2), argv[0], GetExecutablePathVP);
if (Tool == "as")
return cc1as_main(argv.slice(2), argv[0], GetExecutablePathVP);
+ if (Tool == "apinotes")
+ return cc1apinotes_main(argv.slice(2), argv[0], GetExecutablePathVP);
// Reject unknown tools.
llvm::errs() << "error: unknown integrated tool '" << Tool << "'\n";
diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt
index 2dd6703..5cad9dc 100644
--- a/tools/libclang/CMakeLists.txt
+++ b/tools/libclang/CMakeLists.txt
@@ -35,6 +35,7 @@
set(LIBS
clangAST
+ clangAPINotes
clangBasic
clangFrontend
clangIndex
diff --git a/tools/libclang/CXIndexDataConsumer.cpp b/tools/libclang/CXIndexDataConsumer.cpp
index cb8aebf..6231742 100644
--- a/tools/libclang/CXIndexDataConsumer.cpp
+++ b/tools/libclang/CXIndexDataConsumer.cpp
@@ -1314,6 +1314,7 @@
case SymbolLanguage::C: return CXIdxEntityLang_C;
case SymbolLanguage::ObjC: return CXIdxEntityLang_ObjC;
case SymbolLanguage::CXX: return CXIdxEntityLang_CXX;
+ case SymbolLanguage::Swift: llvm_unreachable("unexpected Swift symbol language");;
}
llvm_unreachable("invalid symbol language");
}
diff --git a/unittests/AST/DeclTest.cpp b/unittests/AST/DeclTest.cpp
index 87aeef4..67b80ac 100644
--- a/unittests/AST/DeclTest.cpp
+++ b/unittests/AST/DeclTest.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "MatchVerifier.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Tooling/Tooling.h"
#include "gtest/gtest.h"
@@ -57,3 +58,53 @@
"constexpr _Complex __uint128_t c = 0xffffffffffffffff;",
Args));
}
+
+TEST(Decl, Availability) {
+ const char *CodeStr = "int x __attribute__((availability(macosx, "
+ "introduced=10.2, deprecated=10.8, obsoleted=10.10)));";
+ auto Matcher = varDecl(hasName("x"));
+ std::vector<std::string> Args = {"-target", "x86_64-apple-macosx10.9"};
+
+ class AvailabilityVerifier : public MatchVerifier<clang::VarDecl> {
+ public:
+ void verify(const MatchFinder::MatchResult &Result,
+ const clang::VarDecl &Node) override {
+ if (Node.getAvailability(nullptr, clang::VersionTuple(10, 1)) !=
+ clang::AR_NotYetIntroduced) {
+ setFailure("failed introduced");
+ }
+ if (Node.getAvailability(nullptr, clang::VersionTuple(10, 2)) !=
+ clang::AR_Available) {
+ setFailure("failed available (exact)");
+ }
+ if (Node.getAvailability(nullptr, clang::VersionTuple(10, 3)) !=
+ clang::AR_Available) {
+ setFailure("failed available");
+ }
+ if (Node.getAvailability(nullptr, clang::VersionTuple(10, 8)) !=
+ clang::AR_Deprecated) {
+ setFailure("failed deprecated (exact)");
+ }
+ if (Node.getAvailability(nullptr, clang::VersionTuple(10, 9)) !=
+ clang::AR_Deprecated) {
+ setFailure("failed deprecated");
+ }
+ if (Node.getAvailability(nullptr, clang::VersionTuple(10, 10)) !=
+ clang::AR_Unavailable) {
+ setFailure("failed obsoleted (exact)");
+ }
+ if (Node.getAvailability(nullptr, clang::VersionTuple(10, 11)) !=
+ clang::AR_Unavailable) {
+ setFailure("failed obsoleted");
+ }
+
+ if (Node.getAvailability() != clang::AR_Deprecated)
+ setFailure("did not default to target OS version");
+
+ setSuccess();
+ }
+ };
+
+ AvailabilityVerifier Verifier;
+ EXPECT_TRUE(Verifier.match(CodeStr, Matcher, Args, Lang_C));
+}
diff --git a/unittests/Lex/CMakeLists.txt b/unittests/Lex/CMakeLists.txt
index ef0f06c..2002fbf 100644
--- a/unittests/Lex/CMakeLists.txt
+++ b/unittests/Lex/CMakeLists.txt
@@ -13,6 +13,7 @@
clangAST
clangBasic
clangLex
+ clangAPINotes
clangParse
clangSema
)
diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp
index 27ab34c..8ba2ebc 100644
--- a/utils/TableGen/ClangAttrEmitter.cpp
+++ b/utils/TableGen/ClangAttrEmitter.cpp
@@ -1160,6 +1160,32 @@
}
};
+ class AttrArgument : public SimpleArgument {
+ public:
+ AttrArgument(const Record &Arg, StringRef Attr)
+ : SimpleArgument(Arg, Attr, "Attr *")
+ {}
+
+ void writePCHReadDecls(raw_ostream &OS) const override {
+ OS << " AttrVec vec;\n"
+ " ReadAttributes(F, vec, Record, Idx);\n"
+ " assert(vec.size() == 1);\n"
+ " Attr *" << getLowerName() << " = vec.front();";
+ }
+
+ void writePCHWrite(raw_ostream &OS) const override {
+ OS << " AddAttributes(SA->get" << getUpperName() << "());";
+ }
+
+ void writeDump(raw_ostream &OS) const override {}
+
+ void writeDumpChildren(raw_ostream &OS) const override {
+ OS << " dumpAttr(SA->get" << getUpperName() << "());\n";
+ }
+
+ void writeHasChildren(raw_ostream &OS) const override { OS << "true"; }
+ };
+
} // end anonymous namespace
static std::unique_ptr<Argument>
@@ -1207,6 +1233,8 @@
Ptr = llvm::make_unique<VariadicExprArgument>(Arg, Attr);
else if (ArgName == "VersionArgument")
Ptr = llvm::make_unique<VersionArgument>(Arg, Attr);
+ else if (ArgName == "AttrArgument")
+ Ptr = llvm::make_unique<AttrArgument>(Arg, Attr);
if (!Ptr) {
// Search in reverse order so that the most-derived type is handled first.
diff --git a/utils/perf-training/lit.cfg b/utils/perf-training/lit.cfg
index edae551..16c9367 100644
--- a/utils/perf-training/lit.cfg
+++ b/utils/perf-training/lit.cfg
@@ -7,7 +7,7 @@
def getSysrootFlagsOnDarwin(config, lit_config):
# On Darwin, support relocatable SDKs by providing Clang with a
# default system root path.
- if 'darwin' in config.target_triple:
+ if lit.util.isMacOSTriple(config.target_triple):
try:
out = lit.util.capture(['xcrun', '--show-sdk-path']).strip()
res = 0
diff --git a/utils/perf-training/order-files.lit.cfg b/utils/perf-training/order-files.lit.cfg
index a4fd812..3ea3c9e 100644
--- a/utils/perf-training/order-files.lit.cfg
+++ b/utils/perf-training/order-files.lit.cfg
@@ -8,7 +8,7 @@
def getSysrootFlagsOnDarwin(config, lit_config):
# On Darwin, support relocatable SDKs by providing Clang with a
# default system root path.
- if 'darwin' in config.target_triple:
+ if lit.util.isMacOSTriple(config.target_triple):
try:
out = lit.util.capture(['xcrun', '--show-sdk-path']).strip()
res = 0