Merge pull request #14893 from jckarter/keypath-resilience-silgen-refactor
SILGen: Refactor key path component lowering.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ab7572c..59149f7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -42,6 +42,8 @@
conditionally conforms to `P`, will succeed when the conditional
requirements are met.
+**Add new entries to the top of this file, not here!**
+
Swift 4.1
---------
@@ -167,8 +169,6 @@
If you wish to provide your own implementation of `==`/`hashValue`, you still can; a custom implementation will replace the one synthesized by the compiler.
- **Add new entries to the top of this file, not here!**
-
Swift 4.0
---------
@@ -6875,3 +6875,9 @@
[SE-0191]: <https://github.com/apple/swift-evolution/blob/master/proposals/0191-eliminate-indexdistance.md>
[SE-0192]: <https://github.com/apple/swift-evolution/blob/master/proposals/0192-non-exhaustive-enums.md>
[SE-0193]: <https://github.com/apple/swift-evolution/blob/master/proposals/0193-cross-module-inlining-and-specialization.md>
+[SE-0194]: <https://github.com/apple/swift-evolution/blob/master/proposals/0194-derived-collection-of-enum-cases.md>
+[SE-0195]: <https://github.com/apple/swift-evolution/blob/master/proposals/0195-dynamic-member-lookup.md>
+[SE-0196]: <https://github.com/apple/swift-evolution/blob/master/proposals/0196-diagnostic-directives.md>
+[SE-0197]: <https://github.com/apple/swift-evolution/blob/master/proposals/0197-remove-where.md>
+[SE-0198]: <https://github.com/apple/swift-evolution/blob/master/proposals/0198-playground-quicklook-api-revamp.md>
+[SE-0199]: <https://github.com/apple/swift-evolution/blob/master/proposals/0199-bool-toggle.md>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 717f920..e9281bf 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -194,14 +194,16 @@
#
foreach(sdk ANDROID;FREEBSD;LINUX;WINDOWS;HAIKU)
- set(SWIFT_${sdk}_ICU_UC "" CACHE STRING
- "Path to a directory containing the icuuc library for ${sdk}")
- set(SWIFT_${sdk}_ICU_UC_INCLUDE "" CACHE STRING
- "Path to a directory containing headers for icuuc for ${sdk}")
- set(SWIFT_${sdk}_ICU_I18N "" CACHE STRING
- "Path to a directory containing the icui18n library for ${sdk}")
- set(SWIFT_${sdk}_ICU_I18N_INCLUDE "" CACHE STRING
- "Path to a directory containing headers icui18n for ${sdk}")
+ foreach(arch aarch64;armv6;armv7;i686;powerpc64;powerpc64le;s390x;x86_64)
+ set(SWIFT_${sdk}_${arch}_ICU_UC "" CACHE STRING
+ "Path to a directory containing the icuuc library for ${sdk}")
+ set(SWIFT_${sdk}_${arch}_ICU_UC_INCLUDE "" CACHE STRING
+ "Path to a directory containing headers for icuuc for ${sdk}")
+ set(SWIFT_${sdk}_${arch}_ICU_I18N "" CACHE STRING
+ "Path to a directory containing the icui18n library for ${sdk}")
+ set(SWIFT_${sdk}_${arch}_ICU_I18N_INCLUDE "" CACHE STRING
+ "Path to a directory containing headers icui18n for ${sdk}")
+ endforeach()
endforeach()
#
diff --git a/cmake/modules/AddSwift.cmake b/cmake/modules/AddSwift.cmake
index 19bf777..f489be3 100644
--- a/cmake/modules/AddSwift.cmake
+++ b/cmake/modules/AddSwift.cmake
@@ -396,11 +396,11 @@
endif()
endif()
- if(NOT "${SWIFT_${LFLAGS_SDK}_ICU_UC}" STREQUAL "")
- list(APPEND library_search_directories "${SWIFT_${sdk}_ICU_UC}")
+ if(NOT "${SWIFT_${LFLAGS_SDK}_${LFLAGS_ARCH}_ICU_UC}" STREQUAL "")
+ list(APPEND library_search_directories "${SWIFT_${sdk}_${arch}_ICU_UC}")
endif()
- if(NOT "${SWIFT_${LFLAGS_SDK}_ICU_I18N}" STREQUAL "")
- list(APPEND library_search_directories "${SWIFT_${sdk}_ICU_I18N}")
+ if(NOT "${SWIFT_${LFLAGS_SDK}_${LFLAGS_ARCH}_ICU_I18N}" STREQUAL "")
+ list(APPEND library_search_directories "${SWIFT_${sdk}_${arch}_ICU_I18N}")
endif()
if(NOT SWIFT_COMPILER_IS_MSVC_LIKE)
@@ -852,17 +852,17 @@
_set_target_prefix_and_suffix("${target}" "${libkind}" "${SWIFTLIB_SINGLE_SDK}")
if(SWIFTLIB_SINGLE_TARGET_LIBRARY)
- if(NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_ICU_UC_INCLUDE}" STREQUAL "" AND
- NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_ICU_UC_INCLUDE}" STREQUAL "/usr/include" AND
- NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_ICU_UC_INCLUDE}" STREQUAL "/usr/${SWIFT_SDK_${SWIFTLIB_SINGLE_SDK}_ARCH_${SWIFTLIB_SINGLE_ARCHITECTURE}_TRIPLE}/include" AND
- NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_ICU_UC_INCLUDE}" STREQUAL "/usr/${SWIFT_SDK_${SWIFT_HOST_VARIANT_SDK}_ARCH_${SWIFT_HOST_VARIANT_ARCH}_TRIPLE}/include")
- target_include_directories("${target}" SYSTEM PRIVATE "${SWIFT_${SWIFTLIB_SINGLE_SDK}_ICU_UC_INCLUDE}")
+ if(NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_${SWIFTLIB_SINGLE_ARCHITECTURE}_ICU_UC_INCLUDE}" STREQUAL "" AND
+ NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_${SWIFTLIB_SINGLE_ARCHITECTURE}_ICU_UC_INCLUDE}" STREQUAL "/usr/include" AND
+ NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_${SWIFTLIB_SINGLE_ARCHITECTURE}_ICU_UC_INCLUDE}" STREQUAL "/usr/${SWIFT_SDK_${SWIFTLIB_SINGLE_SDK}_ARCH_${SWIFTLIB_SINGLE_ARCHITECTURE}_TRIPLE}/include" AND
+ NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_${SWIFTLIB_SINGLE_ARCHITECTURE}_ICU_UC_INCLUDE}" STREQUAL "/usr/${SWIFT_SDK_${SWIFT_HOST_VARIANT_SDK}_ARCH_${SWIFT_HOST_VARIANT_ARCH}_TRIPLE}/include")
+ target_include_directories("${target}" SYSTEM PRIVATE "${SWIFT_${SWIFTLIB_SINGLE_SDK}_${SWIFTLIB_SINGLE_ARCHITECTURE}_ICU_UC_INCLUDE}")
endif()
- if(NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_ICU_I18N_INCLUDE}" STREQUAL "" AND
- NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_ICU_I18N_INCLUDE}" STREQUAL "/usr/include" AND
- NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_ICU_I18N_INCLUDE}" STREQUAL "/usr/${SWIFT_SDK_${SWIFTLIB_SINGLE_SDK}_ARCH_${SWIFTLIB_SINGLE_ARCHITECTURE}_TRIPLE}/include" AND
- NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_ICU_I18N_INCLUDE}" STREQUAL "/usr/${SWIFT_SDK_${SWIFT_HOST_VARIANT_SDK}_ARCH_${SWIFT_HOST_VARIANT_ARCH}_TRIPLE}/include")
- target_include_directories("${target}" SYSTEM PRIVATE "${SWIFT_${SWIFTLIB_SINGLE_SDK}_ICU_I18N_INCLUDE}")
+ if(NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_${SWIFTLIB_SINGLE_ARCHITECTURE}_ICU_I18N_INCLUDE}" STREQUAL "" AND
+ NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_${SWIFTLIB_SINGLE_ARCHITECTURE}_ICU_I18N_INCLUDE}" STREQUAL "/usr/include" AND
+ NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_${SWIFTLIB_SINGLE_ARCHITECTURE}_ICU_I18N_INCLUDE}" STREQUAL "/usr/${SWIFT_SDK_${SWIFTLIB_SINGLE_SDK}_ARCH_${SWIFTLIB_SINGLE_ARCHITECTURE}_TRIPLE}/include" AND
+ NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_${SWIFTLIB_SINGLE_ARCHITECTURE}_ICU_I18N_INCLUDE}" STREQUAL "/usr/${SWIFT_SDK_${SWIFT_HOST_VARIANT_SDK}_ARCH_${SWIFT_HOST_VARIANT_ARCH}_TRIPLE}/include")
+ target_include_directories("${target}" SYSTEM PRIVATE "${SWIFT_${SWIFTLIB_SINGLE_SDK}_${SWIFTLIB_SINGLE_ARCHITECTURE}_ICU_I18N_INCLUDE}")
endif()
endif()
@@ -1539,7 +1539,7 @@
foreach(lib ${SWIFTLIB_PRIVATE_LINK_LIBRARIES})
if("${lib}" STREQUAL "ICU_UC")
list(APPEND swiftlib_private_link_libraries_targets
- "${SWIFT_${sdk}_ICU_UC}")
+ "${SWIFT_${sdk}_${arch}_ICU_UC}")
# temporary fix for atomic needing to be
# after object files for libswiftCore.so
if("${sdk}" STREQUAL "ANDROID")
@@ -1553,7 +1553,7 @@
endif()
elseif("${lib}" STREQUAL "ICU_I18N")
list(APPEND swiftlib_private_link_libraries_targets
- "${SWIFT_${sdk}_ICU_I18N}")
+ "${SWIFT_${sdk}_${arch}_ICU_I18N}")
elseif(TARGET "${lib}${VARIANT_SUFFIX}")
list(APPEND swiftlib_private_link_libraries_targets
"${lib}${VARIANT_SUFFIX}")
diff --git a/cmake/modules/FindICU.cmake b/cmake/modules/FindICU.cmake
index 4f380c8..e40a128 100644
--- a/cmake/modules/FindICU.cmake
+++ b/cmake/modules/FindICU.cmake
@@ -34,11 +34,11 @@
foreach(sdk ANDROID;FREEBSD;LINUX;WINDOWS;HAIKU)
foreach(MODULE ${ICU_FIND_COMPONENTS})
string(TOUPPER "${MODULE}" MODULE)
- if("${SWIFT_${sdk}_ICU_${MODULE}_INCLUDE}" STREQUAL "")
- set(SWIFT_${sdk}_ICU_${MODULE}_INCLUDE ${ICU_${MODULE}_INCLUDE_DIRS})
+ if("${SWIFT_${sdk}_${SWIFT_HOST_VARIANT_ARCH}_ICU_${MODULE}_INCLUDE}" STREQUAL "")
+ set(SWIFT_${sdk}_${SWIFT_HOST_VARIANT_ARCH}_ICU_${MODULE}_INCLUDE ${ICU_${MODULE}_INCLUDE_DIRS} CACHE STRING "" FORCE)
endif()
- if("${SWIFT_${sdk}_ICU_${MODULE}}" STREQUAL "")
- set(SWIFT_${sdk}_ICU_${MODULE} ${ICU_${MODULE}_LIBRARY})
+ if("${SWIFT_${sdk}_${SWIFT_HOST_VARIANT_ARCH}_ICU_${MODULE}}" STREQUAL "")
+ set(SWIFT_${sdk}_${SWIFT_HOST_VARIANT_ARCH}_ICU_${MODULE} ${ICU_${MODULE}_LIBRARY} CACHE STRING "" FORCE)
endif()
endforeach()
endforeach()
diff --git a/include/swift/ABI/MetadataValues.h b/include/swift/ABI/MetadataValues.h
index 271f0bc..aed6000 100644
--- a/include/swift/ABI/MetadataValues.h
+++ b/include/swift/ABI/MetadataValues.h
@@ -21,6 +21,7 @@
#include "swift/AST/Ownership.h"
#include "swift/Basic/LLVM.h"
+#include "swift/Basic/FlagSet.h"
#include "swift/Runtime/Unreachable.h"
#include <stdlib.h>
@@ -981,19 +982,67 @@
/// Flags for nominal type context descriptors. These values are used as the
/// kindSpecificFlags of the ContextDescriptorFlags for the type.
-enum class TypeContextDescriptorFlags: uint16_t {
- /// Set if the context descriptor is includes metadata for dynamically
- /// constructing a class's vtables at metadata instantiation time.
- HasVTable = 0x8000u,
-
- /// Set if the context descriptor is for a class with resilient ancestry.
- HasResilientSuperclass = 0x4000u,
-
- /// Set if the type represents an imported C tag type.
- IsCTag = 0x2000u,
-
- /// Set if the type represents an imported C typedef type.
- IsCTypedef = 0x1000u,
+class TypeContextDescriptorFlags : public FlagSet<uint16_t> {
+ enum {
+ // All of these values are bit offsets or widths.
+ // Generic flags build upwards from 0.
+ // Type-specific flags build downwards from 15.
+
+ /// Set if the type represents an imported C tag type.
+ ///
+ /// Meaningful for all type-descriptor kinds.
+ IsCTag = 0,
+
+ /// Set if the type represents an imported C typedef type.
+ ///
+ /// Meaningful for all type-descriptor kinds.
+ IsCTypedef = 1,
+
+ /// Set if the type supports reflection. C and Objective-C enums
+ /// currently don't.
+ ///
+ /// Meaningful for all type-descriptor kinds.
+ IsReflectable = 2,
+
+ /// Set if the context descriptor is includes metadata for dynamically
+ /// constructing a class's vtables at metadata instantiation time.
+ ///
+ /// Only meaningful for class descriptors.
+ Class_HasVTable = 15,
+
+ /// Set if the context descriptor is for a class with resilient ancestry.
+ ///
+ /// Only meaningful for class descriptors.
+ Class_HasResilientSuperclass = 14,
+
+ /// The kind of reference that this class makes to its superclass
+ /// descriptor. A TypeMetadataRecordKind.
+ ///
+ /// Only meaningful for class descriptors.
+ Class_SuperclassReferenceKind = 12,
+ Class_SuperclassReferenceKind_width = 2,
+ };
+
+public:
+ explicit TypeContextDescriptorFlags(uint16_t bits) : FlagSet(bits) {}
+ constexpr TypeContextDescriptorFlags() {}
+
+ FLAGSET_DEFINE_FLAG_ACCESSORS(IsCTag, isCTag, setIsCTag)
+ FLAGSET_DEFINE_FLAG_ACCESSORS(IsCTypedef, isCTypedef, setIsCTypedef)
+ FLAGSET_DEFINE_FLAG_ACCESSORS(IsReflectable, isReflectable, setIsReflectable)
+
+ FLAGSET_DEFINE_FLAG_ACCESSORS(Class_HasVTable,
+ class_hasVTable,
+ class_setHasVTable)
+ FLAGSET_DEFINE_FLAG_ACCESSORS(Class_HasResilientSuperclass,
+ class_hasResilientSuperclass,
+ class_setHasResilientSuperclass)
+
+ FLAGSET_DEFINE_FIELD_ACCESSORS(Class_SuperclassReferenceKind,
+ Class_SuperclassReferenceKind_width,
+ TypeMetadataRecordKind,
+ class_getSuperclassReferenceKind,
+ class_setSuperclassReferenceKind)
};
enum class GenericParamKind : uint8_t {
diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h
index 7f6bafc..2d43a1f 100644
--- a/include/swift/AST/Decl.h
+++ b/include/swift/AST/Decl.h
@@ -1712,7 +1712,9 @@
return D->getKind() == DeclKind::Extension;
}
static bool classof(const DeclContext *C) {
- return C->getContextKind() == DeclContextKind::ExtensionDecl;
+ if (auto D = C->getAsDeclOrDeclExtensionContext())
+ return classof(D);
+ return false;
}
static bool classof(const IterableDeclContext *C) {
return C->getIterableContextKind()
@@ -2003,7 +2005,9 @@
return D->getKind() == DeclKind::TopLevelCode;
}
static bool classof(const DeclContext *C) {
- return C->getContextKind() == DeclContextKind::TopLevelCodeDecl;
+ if (auto D = C->getAsDeclOrDeclExtensionContext())
+ return classof(D);
+ return false;
}
using DeclContext::operator new;
@@ -2465,7 +2469,9 @@
using TypeDecl::getDeclaredInterfaceType;
static bool classof(const DeclContext *C) {
- return C->getContextKind() == DeclContextKind::GenericTypeDecl;
+ if (auto D = C->getAsDeclOrDeclExtensionContext())
+ return classof(D);
+ return false;
}
static bool classof(const Decl *D) {
return D->getKind() >= DeclKind::First_GenericTypeDecl &&
@@ -2533,8 +2539,9 @@
return D->getKind() == DeclKind::TypeAlias;
}
static bool classof(const DeclContext *C) {
- auto GTD = dyn_cast<GenericTypeDecl>(C);
- return GTD && classof(GTD);
+ if (auto D = C->getAsDeclOrDeclExtensionContext())
+ return classof(D);
+ return false;
}
};
@@ -3038,8 +3045,9 @@
}
static bool classof(const DeclContext *C) {
- auto GTD = dyn_cast<GenericTypeDecl>(C);
- return GTD && classof(GTD);
+ if (auto D = C->getAsDeclOrDeclExtensionContext())
+ return classof(D);
+ return false;
}
static bool classof(const IterableDeclContext *C) {
return C->getIterableContextKind()
@@ -3183,8 +3191,9 @@
return D->getKind() == DeclKind::Enum;
}
static bool classof(const DeclContext *C) {
- auto GTD = dyn_cast<GenericTypeDecl>(C);
- return GTD && classof(static_cast<const Decl*>(GTD));
+ if (auto D = C->getAsDeclOrDeclExtensionContext())
+ return classof(D);
+ return false;
}
static bool classof(const IterableDeclContext *C) {
auto NTD = dyn_cast<NominalTypeDecl>(C);
@@ -3252,8 +3261,9 @@
return D->getKind() == DeclKind::Struct;
}
static bool classof(const DeclContext *C) {
- auto GTD = dyn_cast<GenericTypeDecl>(C);
- return GTD && classof(static_cast<const Decl*>(GTD));
+ if (auto D = C->getAsDeclOrDeclExtensionContext())
+ return classof(D);
+ return false;
}
static bool classof(const IterableDeclContext *C) {
auto NTD = dyn_cast<NominalTypeDecl>(C);
@@ -3509,8 +3519,9 @@
return D->getKind() == DeclKind::Class;
}
static bool classof(const DeclContext *C) {
- auto GTD = dyn_cast<GenericTypeDecl>(C);
- return GTD && classof(static_cast<const Decl*>(GTD));
+ if (auto D = C->getAsDeclOrDeclExtensionContext())
+ return classof(D);
+ return false;
}
static bool classof(const IterableDeclContext *C) {
auto NTD = dyn_cast<NominalTypeDecl>(C);
@@ -3827,8 +3838,9 @@
return D->getKind() == DeclKind::Protocol;
}
static bool classof(const DeclContext *C) {
- auto GTD = dyn_cast<GenericTypeDecl>(C);
- return GTD && classof(static_cast<const Decl*>(GTD));
+ if (auto D = C->getAsDeclOrDeclExtensionContext())
+ return classof(D);
+ return false;
}
static bool classof(const IterableDeclContext *C) {
auto NTD = dyn_cast<NominalTypeDecl>(C);
@@ -4333,13 +4345,13 @@
/// Given that this is an Objective-C property or subscript declaration,
/// produce its getter selector.
- ObjCSelector getObjCGetterSelector(LazyResolver *resolver = nullptr,
- Identifier preferredName = Identifier()) const;
+ ObjCSelector
+ getObjCGetterSelector(Identifier preferredName = Identifier()) const;
/// Given that this is an Objective-C property or subscript declaration,
/// produce its setter selector.
- ObjCSelector getObjCSetterSelector(LazyResolver *resolver = nullptr,
- Identifier preferredName = Identifier()) const;
+ ObjCSelector
+ getObjCSetterSelector(Identifier preferredName = Identifier()) const;
AbstractStorageDecl *getOverriddenDecl() const {
return OverriddenDecl;
@@ -4835,7 +4847,7 @@
/// Determine the kind of Objective-C subscripting this declaration
/// implies.
- ObjCSubscriptKind getObjCSubscriptKind(LazyResolver *resolver) const;
+ ObjCSubscriptKind getObjCSubscriptKind() const;
SubscriptDecl *getOverriddenDecl() const {
return cast_or_null<SubscriptDecl>(
@@ -4847,7 +4859,9 @@
}
static bool classof(const DeclContext *DC) {
- return DC->getContextKind() == DeclContextKind::SubscriptDecl;
+ if (auto D = DC->getAsDeclOrDeclExtensionContext())
+ return classof(D);
+ return false;
}
using DeclContext::operator new;
@@ -5121,8 +5135,7 @@
const CaptureInfo &getCaptureInfo() const { return Captures; }
/// Retrieve the Objective-C selector that names this method.
- ObjCSelector getObjCSelector(LazyResolver *resolver = nullptr,
- DeclName preferredName = DeclName()) const;
+ ObjCSelector getObjCSelector(DeclName preferredName = DeclName()) const;
/// Determine whether the given method would produce an Objective-C
/// instance method.
@@ -5230,7 +5243,9 @@
}
static bool classof(const DeclContext *DC) {
- return DC->getContextKind() == DeclContextKind::AbstractFunctionDecl;
+ if (auto D = DC->getAsDeclOrDeclExtensionContext())
+ return classof(D);
+ return false;
}
/// True if the declaration is forced to be statically dispatched.
@@ -5496,8 +5511,8 @@
return classof(static_cast<const Decl*>(D));
}
static bool classof(const DeclContext *DC) {
- if (auto fn = dyn_cast<AbstractFunctionDecl>(DC))
- return classof(fn);
+ if (auto D = DC->getAsDeclOrDeclExtensionContext())
+ return classof(D);
return false;
}
@@ -5617,8 +5632,8 @@
return classof(static_cast<const Decl*>(D));
}
static bool classof(const DeclContext *DC) {
- if (auto fn = dyn_cast<AbstractFunctionDecl>(DC))
- return classof(fn);
+ if (auto D = DC->getAsDeclOrDeclExtensionContext())
+ return classof(D);
return false;
}
};
@@ -6036,8 +6051,8 @@
return classof(static_cast<const Decl*>(D));
}
static bool classof(const DeclContext *DC) {
- if (auto fn = dyn_cast<AbstractFunctionDecl>(DC))
- return classof(fn);
+ if (auto D = DC->getAsDeclOrDeclExtensionContext())
+ return classof(D);
return false;
}
};
@@ -6080,8 +6095,8 @@
return classof(static_cast<const Decl*>(D));
}
static bool classof(const DeclContext *DC) {
- if (auto fn = dyn_cast<AbstractFunctionDecl>(DC))
- return classof(fn);
+ if (auto D = DC->getAsDeclOrDeclExtensionContext())
+ return classof(D);
return false;
}
};
@@ -6584,6 +6599,12 @@
}
}
+inline bool DeclContext::isExtensionContext() const {
+ if (auto D = getAsDeclOrDeclExtensionContext())
+ return ExtensionDecl::classof(D);
+ return false;
+}
+
inline bool DeclContext::classof(const Decl *D) {
switch (D->getKind()) { //
default: return false;
diff --git a/include/swift/AST/DeclContext.h b/include/swift/AST/DeclContext.h
index d23d9ee..27e3bec 100644
--- a/include/swift/AST/DeclContext.h
+++ b/include/swift/AST/DeclContext.h
@@ -262,25 +262,18 @@
}
/// isModuleContext - Return true if this is a subclass of Module.
- bool isModuleContext() const {
- return getContextKind() == DeclContextKind::Module;
- }
+ bool isModuleContext() const; // see swift/AST/Module.h
/// \returns true if this is a context with module-wide scope, e.g. a module
/// or a source file.
- bool isModuleScopeContext() const {
- return getContextKind() == DeclContextKind::Module ||
- getContextKind() == DeclContextKind::FileUnit;
- }
+ bool isModuleScopeContext() const; // see swift/AST/Module.h
/// \returns true if this is a type context, e.g., a struct, a class, an
/// enum, a protocol, or an extension.
bool isTypeContext() const;
/// \brief Determine whether this is an extension context.
- bool isExtensionContext() const {
- return getContextKind() == DeclContextKind::ExtensionDecl;
- }
+ bool isExtensionContext() const; // see swift/AST/Decl.h
/// If this DeclContext is a NominalType declaration or an
/// extension thereof, return the NominalTypeDecl.
diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def
index f693f84..70531ab 100644
--- a/include/swift/AST/DiagnosticsSema.def
+++ b/include/swift/AST/DiagnosticsSema.def
@@ -1371,6 +1371,8 @@
"generic parameters at runtime", ())
NOTE(objc_generic_extension_using_type_parameter_here,none,
"generic parameter used here", ())
+NOTE(objc_generic_extension_using_type_parameter_try_objc,none,
+ "add '@objc' to allow uses of 'self' within the function body", ())
// Protocols
ERROR(type_does_not_conform,none,
diff --git a/include/swift/AST/Module.h b/include/swift/AST/Module.h
index 83ce624..01a760d 100644
--- a/include/swift/AST/Module.h
+++ b/include/swift/AST/Module.h
@@ -492,7 +492,9 @@
SourceRange getSourceRange() const { return SourceRange(); }
static bool classof(const DeclContext *DC) {
- return DC->getContextKind() == DeclContextKind::Module;
+ if (auto D = DC->getAsDeclOrDeclExtensionContext())
+ return classof(D);
+ return false;
}
static bool classof(const Decl *D) {
@@ -1219,6 +1221,18 @@
explicit operator bool() const { return !Mod.isNull(); }
};
+inline bool DeclContext::isModuleContext() const {
+ if (auto D = getAsDeclOrDeclExtensionContext())
+ return ModuleDecl::classof(D);
+ return false;
+}
+
+inline bool DeclContext::isModuleScopeContext() const {
+ if (ParentAndKind.getInt() == ASTHierarchy::FileUnit)
+ return true;
+ return isModuleContext();
+}
+
} // end namespace swift
namespace llvm {
diff --git a/include/swift/AST/Type.h b/include/swift/AST/Type.h
index f741f48..2619c78 100644
--- a/include/swift/AST/Type.h
+++ b/include/swift/AST/Type.h
@@ -368,15 +368,19 @@
/// class D { }
/// \endcode
///
- /// The join of B and C is A, the join of A and B is A. However, there is no
- /// join of D and A (or D and B, or D and C) because there is no common
- /// superclass. One would have to jump to an existential (e.g., \c AnyObject)
- /// to find a common type.
+ /// The join of B and C is A, the join of A and B is A.
+ ///
+ /// The Any type is considered the common supertype by default when no
+ /// closer common supertype exists.
+ ///
+ /// In unsupported cases where we cannot yet compute an accurate join,
+ /// we return None.
///
/// \returns the join of the two types, if there is a concrete type
/// that can express the join, or Any if the only join would be a
- /// more-general existential type
- static Type join(Type first, Type second);
+ /// more-general existential type, or None if we cannot yet compute a
+ /// correct join but one better than Any may exist.
+ static Optional<Type> join(Type first, Type second);
private:
// Direct comparison is disabled for types, because they may not be canonical.
diff --git a/include/swift/Basic/FlagSet.h b/include/swift/Basic/FlagSet.h
new file mode 100644
index 0000000..e58bf08
--- /dev/null
+++ b/include/swift/Basic/FlagSet.h
@@ -0,0 +1,111 @@
+//===--- FlagSet.h - Helper class for opaque flag types ---------*- C++ -*-===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the FlagSet template, a class which makes it easier to
+// define opaque flag types.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SWIFT_BASIC_FLAGSET_H
+#define SWIFT_BASIC_FLAGSET_H
+
+#include <type_traits>
+#include <assert.h>
+
+namespace swift {
+
+/// A template designed to simplify the task of defining a wrapper type
+/// for a flags bitfield.
+///
+/// Unfortunately, this doesn't currently support functional-style
+/// building patterns, which means this can't practically be used for
+/// types that need to be used in constant expressions.
+template <typename IntType>
+class FlagSet {
+ static_assert(std::is_integral<IntType>::value,
+ "storage type for FlagSet must be an integral type");
+ IntType Bits;
+
+protected:
+ template <unsigned BitWidth>
+ static constexpr IntType lowMaskFor() {
+ return IntType((1 << BitWidth) - 1);
+ }
+
+ template <unsigned FirstBit, unsigned BitWidth = 1>
+ static constexpr IntType maskFor() {
+ return lowMaskFor<BitWidth>() << FirstBit;
+ }
+
+ constexpr FlagSet(IntType bits = 0) : Bits(bits) {}
+
+ /// Read a single-bit flag.
+ template <unsigned Bit>
+ bool getFlag() const {
+ return Bits & maskFor<Bit>();
+ }
+
+ /// Set a single-bit flag.
+ template <unsigned Bit>
+ void setFlag(bool value) {
+ if (value) {
+ Bits |= maskFor<Bit>();
+ } else {
+ Bits |= ~maskFor<Bit>();
+ }
+ }
+
+ /// Read a multi-bit field.
+ template <unsigned FirstBit, unsigned BitWidth, typename FieldType = IntType>
+ FieldType getField() const {
+ return FieldType((Bits >> FirstBit) & lowMaskFor<BitWidth>());
+ }
+
+ /// Assign to a multi-bit field.
+ template <unsigned FirstBit, unsigned BitWidth, typename FieldType = IntType>
+ void setField(typename std::enable_if<true, FieldType>::type value) {
+ // Note that we suppress template argument deduction for FieldType.
+ assert(IntType(value) <= lowMaskFor<BitWidth>() && "value out of range");
+ Bits = (Bits & ~maskFor<FirstBit, BitWidth>())
+ | (IntType(value) << FirstBit);
+ }
+
+ // A convenient macro for defining a getter and setter for a flag.
+ // Intended to be used in the body of a subclass of FlagSet.
+#define FLAGSET_DEFINE_FLAG_ACCESSORS(BIT, GETTER, SETTER) \
+ bool GETTER() const { \
+ return getFlag<BIT>(); \
+ } \
+ void SETTER(bool value) { \
+ setFlag<BIT>(value); \
+ }
+
+ // A convenient macro for defining a getter and setter for a field.
+ // Intended to be used in the body of a subclass of FlagSet.
+#define FLAGSET_DEFINE_FIELD_ACCESSORS(BIT, WIDTH, TYPE, GETTER, SETTER) \
+ TYPE GETTER() const { \
+ return getField<BIT, WIDTH, TYPE>(); \
+ } \
+ void SETTER(TYPE value) { \
+ setField<BIT, WIDTH, TYPE>(value); \
+ }
+
+public:
+ /// Get the bits as an opaque integer value.
+ IntType getOpaqueValue() const {
+ return Bits;
+ }
+};
+
+} // end namespace swift
+
+#endif
diff --git a/include/swift/Basic/LLVMInitialize.h b/include/swift/Basic/LLVMInitialize.h
index 4d44f5a..bba5e0e 100644
--- a/include/swift/Basic/LLVMInitialize.h
+++ b/include/swift/Basic/LLVMInitialize.h
@@ -10,34 +10,33 @@
//
//===----------------------------------------------------------------------===//
//
-// A file that declares a macro for initializing all parts of LLVM that various
-// binaries in swift use. Please call the macro in the main routine of all
-// binaries.
+// A file that declares macros for initializing all parts of LLVM that various
+// binaries in swift use. Please call PROGRAM_START in the main routine of all
+// binaries, and INITIALIZE_LLVM in anything that uses Clang or LLVM IR.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_BASIC_LLVMINITIALIZE_H
#define SWIFT_BASIC_LLVMINITIALIZE_H
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Host.h"
#include "llvm/Support/ManagedStatic.h"
-#include "llvm/Support/Path.h"
#include "llvm/Support/PrettyStackTrace.h"
-#include "llvm/Support/Process.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/TargetSelect.h"
-#include "llvm/Support/raw_ostream.h"
-#define INITIALIZE_LLVM(argc, argv) \
+#define PROGRAM_START(argc, argv) \
llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); \
llvm::PrettyStackTraceProgram _INITIALIZE_LLVM_STACKTRACE(argc, argv); \
- llvm::llvm_shutdown_obj _INITIALIZE_LLVM_SHUTDOWN_OBJ; \
- llvm::InitializeAllTargets(); \
- llvm::InitializeAllTargetMCs(); \
- llvm::InitializeAllAsmPrinters(); \
- llvm::InitializeAllAsmParsers(); \
- llvm::InitializeAllDisassemblers(); \
- llvm::InitializeAllTargetInfos();
+ llvm::llvm_shutdown_obj _INITIALIZE_LLVM_SHUTDOWN_OBJ
+
+#define INITIALIZE_LLVM() \
+ do { \
+ llvm::InitializeAllTargets(); \
+ llvm::InitializeAllTargetMCs(); \
+ llvm::InitializeAllAsmPrinters(); \
+ llvm::InitializeAllAsmParsers(); \
+ llvm::InitializeAllDisassemblers(); \
+ llvm::InitializeAllTargetInfos(); \
+ } while (0)
#endif // SWIFT_BASIC_LLVMINITIALIZE_H
diff --git a/include/swift/Basic/PrimarySpecificPaths.h b/include/swift/Basic/PrimarySpecificPaths.h
index c950405..b645a49 100644
--- a/include/swift/Basic/PrimarySpecificPaths.h
+++ b/include/swift/Basic/PrimarySpecificPaths.h
@@ -15,26 +15,39 @@
#include "swift/Basic/LLVM.h"
#include "swift/Basic/SupplementaryOutputPaths.h"
+#include "llvm/ADT/StringRef.h"
#include <string>
namespace swift {
+
+/// Holds all of the output paths, and debugging-info path that are
+/// specific to which primary file is being compiled at the moment.
+
class PrimarySpecificPaths {
public:
+ /// The name of the main output file,
+ /// that is, the .o file for this input. If there is no such file, contains an
+ /// empty string. If the output is to be written to stdout, contains "-".
std::string OutputFilename;
+
SupplementaryOutputPaths SupplementaryOutputs;
/// The name of the "main" input file, used by the debug info.
std::string MainInputFilenameForDebugInfo;
- PrimarySpecificPaths(
- std::string OutputFilename = std::string(),
- std::string MainInputFilenameForDebugInfo = std::string(),
- SupplementaryOutputPaths SupplementaryOutputs =
- SupplementaryOutputPaths())
+ PrimarySpecificPaths(StringRef OutputFilename = StringRef(),
+ StringRef MainInputFilenameForDebugInfo = StringRef(),
+ SupplementaryOutputPaths SupplementaryOutputs =
+ SupplementaryOutputPaths())
: OutputFilename(OutputFilename),
SupplementaryOutputs(SupplementaryOutputs),
MainInputFilenameForDebugInfo(MainInputFilenameForDebugInfo) {}
+
+ bool haveModuleOrModuleDocOutputPaths() const {
+ return !SupplementaryOutputs.ModuleOutputPath.empty() ||
+ !SupplementaryOutputs.ModuleDocOutputPath.empty();
+ }
};
} // namespace swift
diff --git a/include/swift/Basic/SupplementaryOutputPaths.h b/include/swift/Basic/SupplementaryOutputPaths.h
index 943ace0..95098da 100644
--- a/include/swift/Basic/SupplementaryOutputPaths.h
+++ b/include/swift/Basic/SupplementaryOutputPaths.h
@@ -21,18 +21,28 @@
namespace swift {
struct SupplementaryOutputPaths {
/// The path to which we should emit an Objective-C header for the module.
+ /// Currently only makes sense when the compiler has whole module knowledge.
+ /// The modes for which it makes sense incuide both WMO and the "merge
+ /// modules" job that happens after the normal compilation jobs. That's where
+ /// the header is emitted in single-file mode, since it needs whole-module
+ /// information.
+
std::string ObjCHeaderOutputPath;
/// The path to which we should emit a serialized module.
+ /// It is valid whenever there are any inputs.
std::string ModuleOutputPath;
/// The path to which we should emit a module documentation file.
+ /// It is valid whenever there are any inputs.
std::string ModuleDocOutputPath;
/// The path to which we should output a Make-style dependencies file.
+ /// It is valid whenever there are any inputs.
std::string DependenciesFilePath;
/// The path to which we should output a Swift reference dependencies file.
+ /// It is valid whenever there are any inputs.
std::string ReferenceDependenciesFilePath;
/// Path to a file which should contain serialized diagnostics for this
@@ -40,9 +50,11 @@
std::string SerializedDiagnosticsPath;
/// The path to which we should output a loaded module trace file.
+ /// It is currently only used with WMO, but could be generalized.
std::string LoadedModuleTracePath;
/// The path to which we should output a TBD file.
+ /// It is currently only used with WMO, but could be generalized.
std::string TBDPath;
SupplementaryOutputPaths() = default;
diff --git a/include/swift/Driver/Job.h b/include/swift/Driver/Job.h
index d2f32ee..f449f41 100644
--- a/include/swift/Driver/Job.h
+++ b/include/swift/Driver/Job.h
@@ -96,6 +96,13 @@
/// derived from the BaseInput it is related to. Also used as a key into
/// the DerivedOutputFileMap.
StringRef Primary;
+
+ /// Construct a CommandInputPair from a Base Input and, optionally, a Primary;
+ /// if the Primary is empty, use the Base value for it.
+ explicit CommandInputPair(StringRef BaseInput, StringRef PrimaryInput)
+ : Base(BaseInput),
+ Primary(PrimaryInput.empty() ? BaseInput : PrimaryInput)
+ {}
};
class CommandOutput {
@@ -162,8 +169,14 @@
StringRef getPrimaryOutputFilename() const;
/// Return a all of the outputs of type \c getPrimaryOutputType() associated
- /// with a primary input. Note that the returned \c StringRef vector may be
- /// invalidated by subsequent mutations to the \c CommandOutput.
+ /// with a primary input. The return value will contain one \c StringRef per
+ /// primary input, _even if_ the primary output type is TY_Nothing, and the
+ /// primary output filenames are therefore all empty strings.
+ ///
+ /// FIXME: This is not really ideal behaviour -- it would be better to return
+ /// only nonempty strings in all cases, and have the callers differentiate
+ /// contexts with absent primary outputs another way -- but this is currently
+ /// assumed at several call sites.
SmallVector<StringRef, 16> getPrimaryOutputFilenames() const;
/// Assuming (and asserting) that there are one or more input pairs, associate
@@ -177,6 +190,17 @@
/// first primary input.
StringRef getAdditionalOutputForType(types::ID type) const;
+ /// Return a vector of additional (not primary) outputs of type \p type
+ /// associated with the primary inputs.
+ ///
+ /// In contrast to \c getPrimaryOutputFilenames, this method does _not_ return
+ /// any empty strings or ensure the return vector is matched in size with the
+ /// set of primary inputs; however it _does_ assert that the return vector's
+ /// length is _either_ zero, one, or equal to the size of the set of inputs,
+ /// as these are the only valid arity relationships between primary and
+ /// additional outputs.
+ SmallVector<StringRef, 16> getAdditionalOutputsForType(types::ID type) const;
+
/// Assuming (and asserting) that there is only one input pair, return any
/// output -- primary or additional -- of type \p type associated with that
/// the sole primary input.
@@ -187,6 +211,10 @@
void print(raw_ostream &Stream) const;
void dump() const LLVM_ATTRIBUTE_USED;
+
+ /// For use in assertions: check the CommandOutput's state is consistent with
+ /// its invariants.
+ void checkInvariants() const;
};
class Job {
diff --git a/include/swift/Frontend/ArgsToFrontendOutputsConverter.h b/include/swift/Frontend/ArgsToFrontendOutputsConverter.h
index 0f62f70..1b2ecd0 100644
--- a/include/swift/Frontend/ArgsToFrontendOutputsConverter.h
+++ b/include/swift/Frontend/ArgsToFrontendOutputsConverter.h
@@ -43,7 +43,7 @@
Diags(diags) {}
bool convert(std::vector<std::string> &mainOutputs,
- SupplementaryOutputPaths &supplementaryOutputs);
+ std::vector<SupplementaryOutputPaths> &supplementaryOutputs);
/// Try to read an output file list file.
/// \returns `None` if it could not open the filelist.
@@ -57,7 +57,7 @@
const FrontendInputsAndOutputs &InputsAndOutputs;
const std::vector<std::string> OutputFileArguments;
const std::string OutputDirectoryArgument;
- const StringRef FirstInput;
+ const std::string FirstInput;
const FrontendOptions::ActionType RequestedAction;
const llvm::opt::Arg *const ModuleNameArg;
const StringRef Suffix;
diff --git a/include/swift/Frontend/Frontend.h b/include/swift/Frontend/Frontend.h
index e3ff790..46aef96 100644
--- a/include/swift/Frontend/Frontend.h
+++ b/include/swift/Frontend/Frontend.h
@@ -174,15 +174,6 @@
return SearchPathOpts.SDKPath;
}
- void setSerializedDiagnosticsPath(StringRef Path) {
- FrontendOpts.InputsAndOutputs.supplementaryOutputs()
- .SerializedDiagnosticsPath = Path;
- }
- StringRef getSerializedDiagnosticsPath() const {
- return FrontendOpts.InputsAndOutputs.supplementaryOutputs()
- .SerializedDiagnosticsPath;
- }
-
LangOptions &getLangOptions() {
return LangOpts;
}
@@ -245,8 +236,7 @@
return FrontendOpts.ModuleName;
}
-
- StringRef getOutputFilename() const {
+ std::string getOutputFilename() const {
return FrontendOpts.InputsAndOutputs.getSingleOutputFilename();
}
@@ -302,11 +292,25 @@
return FrontendOpts.InputKind == InputFileKind::IFK_Swift_Library;
}
- PrimarySpecificPaths getPrimarySpecificPathsForAtMostOnePrimary() const;
- PrimarySpecificPaths
+ const PrimarySpecificPaths &
+ getPrimarySpecificPathsForAtMostOnePrimary() const;
+ const PrimarySpecificPaths &
getPrimarySpecificPathsForPrimary(StringRef filename) const;
- PrimarySpecificPaths
+ const PrimarySpecificPaths &
getPrimarySpecificPathsForSourceFile(const SourceFile &SF) const;
+
+ std::string getOutputFilenameForAtMostOnePrimary() const;
+ std::string getMainInputFilenameForDebugInfoForAtMostOnePrimary() const;
+ std::string getObjCHeaderOutputPathForAtMostOnePrimary() const;
+ std::string getModuleOutputPathForAtMostOnePrimary() const;
+ std::string
+ getReferenceDependenciesFilePathForPrimary(StringRef filename) const;
+ std::string getSerializedDiagnosticsPathForAtMostOnePrimary() const;
+
+ /// TBDPath only makes sense in whole module compilation mode,
+ /// so return the TBDPath when in that mode and fail an assert
+ /// if not in that mode.
+ std::string getTBDPathForWholeModule() const;
};
/// A class which manages the state and execution of the compiler.
@@ -584,12 +588,13 @@
void finishTypeChecking(OptionSet<TypeCheckingFlags> TypeCheckOptions);
public:
- PrimarySpecificPaths
+ const PrimarySpecificPaths &
getPrimarySpecificPathsForWholeModuleOptimizationMode() const;
- PrimarySpecificPaths
+ const PrimarySpecificPaths &
getPrimarySpecificPathsForPrimary(StringRef filename) const;
- PrimarySpecificPaths getPrimarySpecificPathsForAtMostOnePrimary() const;
- PrimarySpecificPaths
+ const PrimarySpecificPaths &
+ getPrimarySpecificPathsForAtMostOnePrimary() const;
+ const PrimarySpecificPaths &
getPrimarySpecificPathsForSourceFile(const SourceFile &SF) const;
};
diff --git a/include/swift/Frontend/FrontendInputsAndOutputs.h b/include/swift/Frontend/FrontendInputsAndOutputs.h
index 06ea15a..be87323 100644
--- a/include/swift/Frontend/FrontendInputsAndOutputs.h
+++ b/include/swift/Frontend/FrontendInputsAndOutputs.h
@@ -35,8 +35,8 @@
friend class ArgsToFrontendInputsConverter;
std::vector<InputFile> AllInputs;
-
- llvm::StringMap<unsigned> PrimaryInputs;
+ llvm::StringMap<unsigned> PrimaryInputsByName;
+ std::vector<unsigned> PrimaryInputsInOrder;
/// In Single-threaded WMO mode, all inputs are used
/// both for importing and compiling.
@@ -45,25 +45,10 @@
/// Punt where needed to enable batch mode experiments.
bool AreBatchModeChecksBypassed = false;
- SupplementaryOutputPaths SupplementaryOutputs;
-
public:
bool areBatchModeChecksBypassed() const { return AreBatchModeChecksBypassed; }
void setBypassBatchModeChecks(bool bbc) { AreBatchModeChecksBypassed = bbc; }
- const SupplementaryOutputPaths &supplementaryOutputs() const {
- return SupplementaryOutputs;
- }
- SupplementaryOutputPaths &supplementaryOutputs() {
- return SupplementaryOutputs;
- }
-
- /// When performing a compilation for zero or one primary input file,
- /// this will hold the PrimarySpecificPaths.
- /// In a future PR, each InputFile will hold its own PrimarySpecificPaths and
- /// this will go away.
- PrimarySpecificPaths PrimarySpecificPathsForAtMostOnePrimary;
-
FrontendInputsAndOutputs() = default;
FrontendInputsAndOutputs(const FrontendInputsAndOutputs &other);
FrontendInputsAndOutputs &operator=(const FrontendInputsAndOutputs &other);
@@ -88,6 +73,9 @@
std::vector<std::string> getInputFilenames() const;
+ /// \return nullptr if not a primary input file.
+ const InputFile *primaryInputNamed(StringRef name) const;
+
unsigned inputCount() const { return AllInputs.size(); }
bool hasInputs() const { return !AllInputs.empty(); }
@@ -99,21 +87,23 @@
const InputFile &lastInput() const { return AllInputs.back(); }
- StringRef getFilenameOfFirstInput() const;
+ const std::string &getFilenameOfFirstInput() const;
bool isReadingFromStdin() const;
- void forEachInput(llvm::function_ref<void(const InputFile &)> fn) const;
+ /// If \p fn returns true, exits early and returns true.
+ bool forEachInput(llvm::function_ref<bool(const InputFile &)> fn) const;
// Primaries:
const InputFile &firstPrimaryInput() const;
const InputFile &lastPrimaryInput() const;
- void
- forEachPrimaryInput(llvm::function_ref<void(const InputFile &)> fn) const;
+ /// If \p fn returns true, exit early and return true.
+ bool
+ forEachPrimaryInput(llvm::function_ref<bool(const InputFile &)> fn) const;
- unsigned primaryInputCount() const { return PrimaryInputs.size(); }
+ unsigned primaryInputCount() const { return PrimaryInputsInOrder.size(); }
// Primary count readers:
@@ -143,11 +133,8 @@
const InputFile &getRequiredUniquePrimaryInput() const;
- /// \return the name of the unique primary input, or an empty StrinRef if
- /// there isn't one.
- StringRef getNameOfUniquePrimaryInputFile() const;
-
- /// Combines all primaries for stats reporter
+ /// FIXME: Should combine all primaries for the result
+ /// instead of just answering "batch" if there is more than one primary.
std::string getStatsFileMangledInputName() const;
bool isInputPrimary(StringRef file) const;
@@ -181,9 +168,9 @@
private:
friend class ArgsToFrontendOptionsConverter;
- void
- setMainAndSupplementaryOutputs(ArrayRef<std::string> outputFiles,
- SupplementaryOutputPaths supplementaryOutputs);
+ void setMainAndSupplementaryOutputs(
+ ArrayRef<std::string> outputFiles,
+ ArrayRef<SupplementaryOutputPaths> supplementaryOutputs);
public:
unsigned countOfInputsProducingMainOutputs() const;
@@ -198,17 +185,18 @@
/// Under single-threaded WMO, we pretend that the first input
/// generates the main output, even though it will include code
/// generated from all of them.
- void forEachInputProducingAMainOutputFile(
- llvm::function_ref<void(const InputFile &)> fn) const;
+ ///
+ /// If \p fn returns true, return early and return true.
+ bool forEachInputProducingAMainOutputFile(
+ llvm::function_ref<bool(const InputFile &)> fn) const;
std::vector<std::string> copyOutputFilenames() const;
- void
- forEachOutputFilename(llvm::function_ref<void(const std::string &)> fn) const;
+ void forEachOutputFilename(llvm::function_ref<void(StringRef)> fn) const;
/// Gets the name of the specified output filename.
/// If multiple files are specified, the last one is returned.
- StringRef getSingleOutputFilename() const;
+ std::string getSingleOutputFilename() const;
bool isOutputFilenameStdout() const;
bool isOutputFileDirectory() const;
@@ -218,17 +206,22 @@
unsigned countOfFilesProducingSupplementaryOutput() const;
- void forEachInputProducingSupplementaryOutput(
- llvm::function_ref<void(const InputFile &)> fn) const;
+ /// If \p fn returns true, exit early and return true.
+ bool forEachInputProducingSupplementaryOutput(
+ llvm::function_ref<bool(const InputFile &)> fn) const;
/// Assumes there is not more than one primary input file, if any.
/// Otherwise, you would need to call getPrimarySpecificPathsForPrimary
/// to tell it which primary input you wanted the outputs for.
+ const PrimarySpecificPaths &
+ getPrimarySpecificPathsForAtMostOnePrimary() const;
- PrimarySpecificPaths getPrimarySpecificPathsForAtMostOnePrimary() const;
+ const PrimarySpecificPaths &
+ getPrimarySpecificPathsForPrimary(StringRef) const;
- PrimarySpecificPaths
- getPrimarySpecificPathsForPrimary(StringRef filename) const;
+ bool hasSupplementaryOutputPath(
+ llvm::function_ref<const std::string &(const SupplementaryOutputPaths &)>
+ extractorFn) const;
bool hasDependenciesPath() const;
bool hasReferenceDependenciesPath() const;
diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h
index 05552ae..0e8146d 100644
--- a/include/swift/Frontend/FrontendOptions.h
+++ b/include/swift/Frontend/FrontendOptions.h
@@ -39,7 +39,7 @@
InputFileKind InputKind = InputFileKind::IFK_Swift;
void forAllOutputPaths(const InputFile &input,
- std::function<void(const std::string &)> fn) const;
+ std::function<void(StringRef)> fn) const;
bool isOutputFileDirectory() const;
@@ -273,8 +273,6 @@
return llvm::hash_value(0);
}
- StringRef originalPath() const;
-
StringRef determineFallbackModuleName() const;
bool isCompilingExactlyOneSwiftFile() const {
@@ -282,8 +280,10 @@
InputsAndOutputs.hasSingleInput();
}
- PrimarySpecificPaths getPrimarySpecificPathsForAtMostOnePrimary() const;
- PrimarySpecificPaths getPrimarySpecificPathsForPrimary(StringRef) const;
+ const PrimarySpecificPaths &
+ getPrimarySpecificPathsForAtMostOnePrimary() const;
+ const PrimarySpecificPaths &
+ getPrimarySpecificPathsForPrimary(StringRef) const;
private:
static bool canActionEmitDependencies(ActionType);
diff --git a/include/swift/Frontend/InputFile.h b/include/swift/Frontend/InputFile.h
index 309df35..484a08c 100644
--- a/include/swift/Frontend/InputFile.h
+++ b/include/swift/Frontend/InputFile.h
@@ -13,6 +13,8 @@
#ifndef SWIFT_FRONTEND_INPUTFILE_H
#define SWIFT_FRONTEND_INPUTFILE_H
+#include "swift/Basic/PrimarySpecificPaths.h"
+#include "swift/Basic/SupplementaryOutputPaths.h"
#include "llvm/Support/MemoryBuffer.h"
#include <string>
#include <vector>
@@ -37,10 +39,12 @@
/// none.
llvm::MemoryBuffer *Buffer;
- /// Contains the name of the main output file, that is, the .o file for this
- /// input. If there is no such file, contains an empty string. If the output
- /// is to be written to stdout, contains "-".
- std::string OutputFilename;
+ /// If there are explicit primary inputs (i.e. designated with -primary-input
+ /// or -primary-filelist), the paths specific to those inputs (other than the
+ /// input file path itself) are kept here. If there are no explicit primary
+ /// inputs (for instance for whole module optimization), the corresponding
+ /// paths are kept in the first input file.
+ PrimarySpecificPaths PSPs;
public:
/// Does not take ownership of \p buffer. Does take ownership of (copy) a
@@ -50,13 +54,13 @@
StringRef outputFilename = StringRef())
: Filename(
convertBufferNameFromLLVM_getFileOrSTDIN_toSwiftConventions(name)),
- IsPrimary(isPrimary), Buffer(buffer), OutputFilename(outputFilename) {
+ IsPrimary(isPrimary), Buffer(buffer), PSPs(PrimarySpecificPaths()) {
assert(!name.empty());
}
bool isPrimary() const { return IsPrimary; }
llvm::MemoryBuffer *buffer() const { return Buffer; }
- StringRef file() const {
+ const std::string &file() const {
assert(!Filename.empty());
return Filename;
}
@@ -68,13 +72,26 @@
return filename.equals("<stdin>") ? "-" : filename;
}
- const std::string &outputFilename() const { return OutputFilename; }
+ std::string outputFilename() const { return PSPs.OutputFilename; }
- void setOutputFilename(StringRef outputFilename) {
- OutputFilename = outputFilename;
+ const PrimarySpecificPaths &getPrimarySpecificPaths() const { return PSPs; }
+
+ void setPrimarySpecificPaths(const PrimarySpecificPaths &PSPs) {
+ this->PSPs = PSPs;
+ }
+
+ // The next set of functions provides access to those primary-specific paths
+ // accessed directly from an InputFile, as opposed to via
+ // FrontendInputsAndOutputs. They merely make the call sites
+ // a bit shorter. Add more forwarding methods as needed.
+
+ std::string dependenciesFilePath() const {
+ return getPrimarySpecificPaths().SupplementaryOutputs.DependenciesFilePath;
+ }
+ std::string loadedModuleTracePath() const {
+ return getPrimarySpecificPaths().SupplementaryOutputs.LoadedModuleTracePath;
}
};
-
} // namespace swift
#endif /* SWIFT_FRONTEND_INPUTFILE_H */
diff --git a/include/swift/Remote/MetadataReader.h b/include/swift/Remote/MetadataReader.h
index 029c36c..9e365cf 100644
--- a/include/swift/Remote/MetadataReader.h
+++ b/include/swift/Remote/MetadataReader.h
@@ -983,8 +983,8 @@
case ContextDescriptorKind::Class:
baseSize = sizeof(TargetClassDescriptor<Runtime>);
genericHeaderSize = sizeof(TypeGenericContextDescriptorHeader);
- hasVTable = flags.getKindSpecificFlags()
- & (uint16_t)TypeContextDescriptorFlags::HasVTable;
+ hasVTable = TypeContextDescriptorFlags(flags.getKindSpecificFlags())
+ .class_hasVTable();
break;
case ContextDescriptorKind::Enum:
baseSize = sizeof(TargetEnumDescriptor<Runtime>);
@@ -1082,21 +1082,25 @@
return Reader->readString(RemoteAddress(nameAddress), nodeName);
};
+ bool isTypeContext = false;
switch (auto contextKind = parent->getKind()) {
case ContextDescriptorKind::Class:
if (!getTypeName())
return nullptr;
nodeKind = Demangle::Node::Kind::Class;
+ isTypeContext = true;
break;
case ContextDescriptorKind::Struct:
if (!getTypeName())
return nullptr;
nodeKind = Demangle::Node::Kind::Structure;
+ isTypeContext = true;
break;
case ContextDescriptorKind::Enum:
if (!getTypeName())
return nullptr;
nodeKind = Demangle::Node::Kind::Enum;
+ isTypeContext = true;
break;
case ContextDescriptorKind::Extension:
@@ -1125,11 +1129,15 @@
}
// Override the node kind if this was a Clang-imported type.
- auto flags = parent->Flags.getKindSpecificFlags();
- if (flags & (uint16_t)TypeContextDescriptorFlags::IsCTag)
- nodeKind = Demangle::Node::Kind::Structure;
- else if (flags & (uint16_t)TypeContextDescriptorFlags::IsCTypedef)
- nodeKind = Demangle::Node::Kind::TypeAlias;
+ if (isTypeContext) {
+ auto typeFlags =
+ TypeContextDescriptorFlags(parent->Flags.getKindSpecificFlags());
+
+ if (typeFlags.isCTag())
+ nodeKind = Demangle::Node::Kind::Structure;
+ else if (typeFlags.isCTypedef())
+ nodeKind = Demangle::Node::Kind::TypeAlias;
+ }
nameComponents.emplace_back(nodeKind, nodeName);
diff --git a/include/swift/Runtime/Metadata.h b/include/swift/Runtime/Metadata.h
index ebf9f3f..cb5b1eb 100644
--- a/include/swift/Runtime/Metadata.h
+++ b/include/swift/Runtime/Metadata.h
@@ -2303,7 +2303,7 @@
switch (getTypeKind()) {
case TypeMetadataRecordKind::IndirectObjCClass:
break;
-
+
case TypeMetadataRecordKind::Reserved:
return nullptr;
@@ -3004,6 +3004,10 @@
return MetadataAccessFunction(AccessFunctionPtr.get());
}
+ TypeContextDescriptorFlags getTypeContextDescriptorFlags() const {
+ return TypeContextDescriptorFlags(this->Flags.getKindSpecificFlags());
+ }
+
const TargetTypeGenericContextDescriptorHeader<Runtime> &
getFullGenericContextHeader() const;
@@ -3061,16 +3065,14 @@
using TrailingGenericContextObjects::getGenericContextHeader;
using TrailingGenericContextObjects::getFullGenericContextHeader;
- /// This bit is set in the context descriptor header's kind-specific flags
- /// if this is a class descriptor with a vtable descriptor for runtime
- /// vtable instantiation.
- static constexpr const uint16_t HasVTableFlag =
- uint16_t(TypeContextDescriptorFlags::HasVTable);
- /// This bit is set in the context descriptor header's kind-specific flags
- /// if this is a class descriptor with a resilient superclass.
- static constexpr const uint16_t HasResilientSuperclassFlag =
- uint16_t(TypeContextDescriptorFlags::HasResilientSuperclass);
-
+ /// The superclass of this class. This pointer can be interpreted
+ /// using the superclass reference kind stored in the type context
+ /// descriptor flags. It is null if the class has no formal superclass.
+ ///
+ /// Note that SwiftObject, the implicit superclass of all Swift root
+ /// classes when building with ObjC compatibility, does not appear here.
+ TargetRelativeDirectPointer<Runtime, const void, /*nullable*/true> SuperClass;
+
/// The number of stored properties in the class, not including its
/// superclasses. If there is a field offset vector, this is its length.
uint32_t NumFields;
@@ -3103,12 +3105,6 @@
}
public:
- /// Indicates if the type represented by this descriptor
- /// supports reflection (C and Obj-C enums currently don't).
- /// FIXME: This is temporarily left as 32-bit integer to avoid
- /// changing layout of context descriptor.
- uint32_t IsReflectable;
-
/// True if metadata records for this type have a field offset vector for
/// its stored properties.
bool hasFieldOffsetVector() const { return FieldOffsetVectorOffset != 0; }
@@ -3123,12 +3119,11 @@
}
bool hasVTable() const {
- return (this->Flags.getKindSpecificFlags() & HasVTableFlag) != 0;
+ return this->getTypeContextDescriptorFlags().class_hasVTable();
}
bool hasResilientSuperclass() const {
- return (this->Flags.getKindSpecificFlags() & HasResilientSuperclassFlag)
- != 0;
+ return this->getTypeContextDescriptorFlags().class_hasResilientSuperclass();
}
const VTableDescriptorHeader *getVTableDescriptor() const {
@@ -3220,12 +3215,6 @@
/// vector.
uint32_t FieldOffsetVectorOffset;
- /// Indicates if the type represented by this descriptor
- /// supports reflection (C and Obj-C enums currently don't).
- /// FIXME: This is temporarily left as 32-bit integer to avoid
- /// changing layout of context descriptor.
- uint32_t IsReflectable;
-
/// True if metadata records for this type have a field offset vector for
/// its stored properties.
bool hasFieldOffsetVector() const { return FieldOffsetVectorOffset != 0; }
@@ -3268,12 +3257,6 @@
/// The number of empty cases in the enum.
uint32_t NumEmptyCases;
- /// Indicates if the type represented by this descriptor
- /// supports reflection (C and Obj-C enums currently don't).
- /// FIXME: This is temporarily left as 32-bit integer to avoid
- /// changing layout of context descriptor.
- uint32_t IsReflectable;
-
uint32_t getNumPayloadCases() const {
return NumPayloadCasesAndPayloadSizeOffset & 0x00FFFFFFU;
}
diff --git a/include/swift/SIL/SILArgumentConvention.h b/include/swift/SIL/SILArgumentConvention.h
index 51f594f..b3d5276 100644
--- a/include/swift/SIL/SILArgumentConvention.h
+++ b/include/swift/SIL/SILArgumentConvention.h
@@ -87,6 +87,24 @@
return Value <= SILArgumentConvention::Indirect_Out;
}
+ bool isOwnedConvention() const {
+ switch (Value) {
+ case SILArgumentConvention::Indirect_In:
+ case SILArgumentConvention::Direct_Owned:
+ return true;
+ case SILArgumentConvention::Indirect_In_Guaranteed:
+ case SILArgumentConvention::Direct_Guaranteed:
+ case SILArgumentConvention::Indirect_Inout:
+ case SILArgumentConvention::Indirect_In_Constant:
+ case SILArgumentConvention::Indirect_Out:
+ case SILArgumentConvention::Indirect_InoutAliasable:
+ case SILArgumentConvention::Direct_Unowned:
+ case SILArgumentConvention::Direct_Deallocating:
+ return false;
+ }
+ llvm_unreachable("covered switch isn't covered?!");
+ }
+
bool isGuaranteedConvention() const {
switch (Value) {
case SILArgumentConvention::Indirect_In_Guaranteed:
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 84d9a8a..659a6ec 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -2515,7 +2515,7 @@
// Note: This should be treated as a lookup for intra-module dependency
// purposes, but a subclass already depends on its superclasses and any
// extensions for many other reasons.
- auto selector = method->getObjCSelector(nullptr);
+ auto selector = method->getObjCSelector();
AbstractFunctionDecl *overriddenMethod
= lookupObjCMethodInType(classDecl->getSuperclass(),
selector,
diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp
index 8e659c5..f01ad7c 100644
--- a/lib/AST/ASTPrinter.cpp
+++ b/lib/AST/ASTPrinter.cpp
@@ -1762,7 +1762,13 @@
assert(Nominal && "extension of non-nominal type");
if (auto nt = ExtendedType->getAs<NominalType>()) {
if (auto ParentType = nt->getParent()) {
- ParentType.print(Printer, Options);
+ if (auto *ParentNT = ParentType->getAs<NominalOrBoundGenericNominalType>()) {
+ // Avoid using the parent type directly because it can be bound
+ // generic type and sugared.
+ ParentNT->getDecl()->getDeclaredType().print(Printer, Options);
+ } else {
+ ParentType.print(Printer, Options);
+ }
Printer << ".";
}
}
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 62c0314..44c79c1 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -3908,8 +3908,8 @@
return None;
}
-ObjCSelector AbstractStorageDecl::getObjCGetterSelector(
- LazyResolver *resolver, Identifier preferredName) const {
+ObjCSelector
+AbstractStorageDecl::getObjCGetterSelector(Identifier preferredName) const {
// If the getter has an @objc attribute with a name, use that.
if (auto getter = getGetter()) {
if (auto name = getNameFromObjcAttribute(getter->getAttrs().
@@ -3920,7 +3920,7 @@
// Subscripts use a specific selector.
auto &ctx = getASTContext();
if (auto *SD = dyn_cast<SubscriptDecl>(this)) {
- switch (SD->getObjCSubscriptKind(resolver)) {
+ switch (SD->getObjCSubscriptKind()) {
case ObjCSubscriptKind::None:
llvm_unreachable("Not an Objective-C subscript");
case ObjCSubscriptKind::Indexed:
@@ -3940,8 +3940,8 @@
return VarDecl::getDefaultObjCGetterSelector(ctx, name);
}
-ObjCSelector AbstractStorageDecl::getObjCSetterSelector(
- LazyResolver *resolver, Identifier preferredName) const {
+ObjCSelector
+AbstractStorageDecl::getObjCSetterSelector(Identifier preferredName) const {
// If the setter has an @objc attribute with a name, use that.
auto setter = getSetter();
auto objcAttr = setter ? setter->getAttrs().getAttribute<ObjCAttr>()
@@ -3953,7 +3953,7 @@
// Subscripts use a specific selector.
auto &ctx = getASTContext();
if (auto *SD = dyn_cast<SubscriptDecl>(this)) {
- switch (SD->getObjCSubscriptKind(resolver)) {
+ switch (SD->getObjCSubscriptKind()) {
case ObjCSubscriptKind::None:
llvm_unreachable("Not an Objective-C subscript");
@@ -4554,8 +4554,7 @@
return elementTy->castTo<AnyFunctionType>()->getResult();
}
-ObjCSubscriptKind SubscriptDecl::getObjCSubscriptKind(
- LazyResolver *resolver) const {
+ObjCSubscriptKind SubscriptDecl::getObjCSubscriptKind() const {
auto indexTy = getIndicesInterfaceType();
// Look through a named 1-tuple.
@@ -4741,8 +4740,8 @@
return getNameLoc();
}
-ObjCSelector AbstractFunctionDecl::getObjCSelector(
- LazyResolver *resolver, DeclName preferredName) const {
+ObjCSelector
+AbstractFunctionDecl::getObjCSelector(DeclName preferredName) const {
// If there is an @objc attribute with a name, use that name.
auto *objc = getAttrs().getAttribute<ObjCAttr>();
if (auto name = getNameFromObjcAttribute(objc, preferredName)) {
@@ -4780,9 +4779,9 @@
// For a getter or setter, go through the variable or subscript decl.
auto asd = accessor->getStorage();
if (accessor->isGetter())
- return asd->getObjCGetterSelector(resolver, baseName);
+ return asd->getObjCGetterSelector(baseName);
if (accessor->isSetter())
- return asd->getObjCSetterSelector(resolver, baseName);
+ return asd->getObjCSetterSelector(baseName);
}
// If this is a zero-parameter initializer with a long selector
diff --git a/lib/AST/SwiftNameTranslation.cpp b/lib/AST/SwiftNameTranslation.cpp
index 2d741c8..4996f2a 100644
--- a/lib/AST/SwiftNameTranslation.cpp
+++ b/lib/AST/SwiftNameTranslation.cpp
@@ -73,9 +73,8 @@
std::pair<Identifier, ObjCSelector> swift::objc_translation::
getObjCNameForSwiftDecl(const ValueDecl *VD, DeclName PreferredName){
ASTContext &Ctx = VD->getASTContext();
- LazyResolver *Resolver = Ctx.getLazyResolver();
if (auto *FD = dyn_cast<AbstractFunctionDecl>(VD)) {
- return {Identifier(), FD->getObjCSelector(Resolver, PreferredName)};
+ return {Identifier(), FD->getObjCSelector(PreferredName)};
} else if (auto *VAD = dyn_cast<VarDecl>(VD)) {
if (PreferredName)
return {PreferredName.getBaseIdentifier(), ObjCSelector()};
diff --git a/lib/AST/TypeJoinMeet.cpp b/lib/AST/TypeJoinMeet.cpp
index f54597f..266c29c 100644
--- a/lib/AST/TypeJoinMeet.cpp
+++ b/lib/AST/TypeJoinMeet.cpp
@@ -19,36 +19,59 @@
#include "swift/AST/Decl.h"
#include "swift/AST/Type.h"
#include "swift/AST/Types.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallPtrSet.h"
using namespace swift;
+namespace {
+
// FIXME: This is currently woefully incomplete, and is only currently
// used for optimizing away extra exploratory work in the constraint
// solver. It should eventually encompass all of the subtyping rules
// of the language.
struct TypeJoin : CanTypeVisitor<TypeJoin, CanType> {
+ // The type we're joining with another type (the latter of which is
+ // passed as an argument in the visitor.
CanType First;
- TypeJoin(CanType First) : First(First) {
+ // Always null. Used as a marker for places where we can improve the
+ // implementation.
+ CanType Unimplemented;
+
+ // For convenience, TheAnyType from ASTContext;
+ CanType TheAnyType;
+
+ TypeJoin(CanType First) : First(First), Unimplemented(CanType()) {
assert(First && "Unexpected null type!");
+ TheAnyType = First->getASTContext().TheAnyType;
}
static CanType getSuperclassJoin(CanType first, CanType second);
+ CanType visitErrorType(CanType second);
+ CanType visitTupleType(CanType second);
+ CanType visitEnumType(CanType second);
+ CanType visitStructType(CanType second);
CanType visitClassType(CanType second);
+ CanType visitProtocolType(CanType second);
CanType visitBoundGenericClassType(CanType second);
- CanType visitArchetypeType(CanType second);
- CanType visitDynamicSelfType(CanType second);
+ CanType visitBoundGenericEnumType(CanType second);
+ CanType visitBoundGenericStructType(CanType second);
CanType visitMetatypeType(CanType second);
CanType visitExistentialMetatypeType(CanType second);
- CanType visitBoundGenericEnumType(CanType second);
-
- CanType visitOptionalType(CanType second);
+ CanType visitModuleType(CanType second);
+ CanType visitDynamicSelfType(CanType second);
+ CanType visitArchetypeType(CanType second);
+ CanType visitGenericTypeParamType(CanType second);
+ CanType visitDependentMemberType(CanType second);
+ CanType visitFunctionType(CanType second);
+ CanType visitGenericFunctionType(CanType second);
+ CanType visitProtocolCompositionType(CanType second);
+ CanType visitLValueType(CanType second);
+ CanType visitInOutType(CanType second);
CanType visitType(CanType second) {
- // FIXME: Implement all the visitors.
- // llvm_unreachable("Unimplemented type visitor!");
- return First->getASTContext().TheAnyType;
+ llvm_unreachable("Unimplemented type visitor!");
}
public:
@@ -65,18 +88,37 @@
if (first == second)
return first;
- // Until we handle all the combinations of joins, we need to make
- // sure we visit the optional side.
+ // Optionals broadly interact with all the other types since
+ // T <: T? for any T (including Any)
+ // So we'll always attempt to dispatch Optional here rather than
+ // make every visitor check for it explicitly.
+ if (first->getOptionalObjectType())
+ return TypeJoin(second).visit(first);
+
if (second->getOptionalObjectType())
return TypeJoin(first).visit(second);
+ // Likewise, rather than making every visitor deal with Any, just
+ // handle it here.
+ // join with Any is always Any
+ if (first->isAny())
+ return first;
+
+ if (second->isAny())
+ return second;
+
+ // Otherwise the first type might be an optional (or not), so
+ // dispatch there.
return TypeJoin(second).visit(first);
}
};
CanType TypeJoin::getSuperclassJoin(CanType first, CanType second) {
+ assert(first != second);
+
+ // FIXME: Handle joins of classes and a single protocol?
if (!first->mayHaveSuperclass() || !second->mayHaveSuperclass())
- return first->getASTContext().TheAnyType;
+ return CanType();
/// Walk the superclasses of `first` looking for `second`. Record them
/// for our second step.
@@ -101,128 +143,222 @@
return canSuper;
}
- // There is no common superclass; we're done.
- return first->getASTContext().TheAnyType;
+ // FIXME: Unimplemented.
+ return CanType();
+}
+
+CanType TypeJoin::visitErrorType(CanType second) {
+ llvm_unreachable("join with ErrorType not supported");
+ return second;
+}
+
+CanType TypeJoin::visitTupleType(CanType second) {
+ assert(First != second);
+
+ return TheAnyType;
+}
+
+CanType TypeJoin::visitEnumType(CanType second) {
+ assert(First != second);
+
+ return Unimplemented;
+}
+
+CanType TypeJoin::visitStructType(CanType second) {
+ assert(First != second);
+
+ // Deal with inout cases in visitInOutType.
+ if (auto inoutTy = First->getAs<InOutType>())
+ return TypeJoin(second).visit(First);
+
+ // FIXME: When possible we should return a protocol or protocol
+ // composition.
+ return TheAnyType;
}
CanType TypeJoin::visitClassType(CanType second) {
return getSuperclassJoin(First, second);
}
+CanType TypeJoin::visitProtocolType(CanType second) {
+ assert(First != second);
+
+ // FIXME: We should compute a tighter bound and/or return nullptr if
+ // we cannot. We do this now because existing tests rely on
+ // producing Any for the join of protocols that have a common
+ // supertype.
+ return TheAnyType;
+}
+
CanType TypeJoin::visitBoundGenericClassType(CanType second) {
return getSuperclassJoin(First, second);
}
+/// The subtype relationship of Optionals is as follows:
+/// S <: S?
+/// S? <: T? if S <: T (covariant)
+static Optional<CanType> joinOptional(CanType first, CanType second) {
+ auto firstObject = first.getOptionalObjectType();
+ auto secondObject = second.getOptionalObjectType();
+
+ // If neither is any kind of Optional, we're done.
+ if (!firstObject && !secondObject)
+ return None;
+
+ first = (firstObject ? firstObject : first);
+ second = (secondObject ? secondObject : second);
+
+ auto join = TypeJoin::join(first, second);
+ if (!join)
+ return None;
+
+ return OptionalType::get(join)->getCanonicalType();
+}
+
+CanType TypeJoin::visitBoundGenericEnumType(CanType second) {
+ // Deal with either First or second (or both) being optionals.
+ if (auto joined = joinOptional(First, second))
+ return joined.getValue();
+
+ assert(First != second);
+
+ return Unimplemented;
+}
+
+CanType TypeJoin::visitBoundGenericStructType(CanType second) {
+ assert(First != second);
+
+ // Deal with inout cases in visitInOutType.
+ if (auto inoutTy = First->getAs<InOutType>())
+ return TypeJoin(second).visit(First);
+
+ return Unimplemented;
+}
+
+CanType TypeJoin::visitMetatypeType(CanType second) {
+ assert(First != second);
+
+ if (First->getKind() != second->getKind())
+ return TheAnyType;
+
+ auto firstInstance =
+ First->castTo<AnyMetatypeType>()->getInstanceType()->getCanonicalType();
+ auto secondInstance =
+ second->castTo<AnyMetatypeType>()->getInstanceType()->getCanonicalType();
+
+ auto joinInstance = join(firstInstance, secondInstance);
+ if (!joinInstance)
+ return CanType();
+
+ return MetatypeType::get(joinInstance)->getCanonicalType();
+}
+
+CanType TypeJoin::visitExistentialMetatypeType(CanType second) {
+ assert(First != second);
+
+ if (First->getKind() != second->getKind())
+ return TheAnyType;
+
+ auto firstInstance =
+ First->castTo<AnyMetatypeType>()->getInstanceType()->getCanonicalType();
+ auto secondInstance =
+ second->castTo<AnyMetatypeType>()->getInstanceType()->getCanonicalType();
+
+ auto joinInstance = join(firstInstance, secondInstance);
+ if (!joinInstance)
+ return CanType();
+
+ return ExistentialMetatypeType::get(joinInstance)->getCanonicalType();
+}
+
+CanType TypeJoin::visitModuleType(CanType second) {
+ assert(First != second);
+
+ return TheAnyType;
+}
+
+CanType TypeJoin::visitDynamicSelfType(CanType second) {
+ return getSuperclassJoin(First, second);
+}
+
CanType TypeJoin::visitArchetypeType(CanType second) {
return getSuperclassJoin(First, second);
}
-CanType TypeJoin::visitDynamicSelfType(CanType second) {
- return getSuperclassJoin(First, second);
+CanType TypeJoin::visitGenericTypeParamType(CanType second) {
+ llvm_unreachable("Saw GenericTypeParamType in TypeJoin::join");
}
-CanType TypeJoin::visitMetatypeType(CanType second) {
+CanType TypeJoin::visitDependentMemberType(CanType second) {
+ assert(First != second);
+
if (First->getKind() != second->getKind())
- return First->getASTContext().TheAnyType;
+ return TheAnyType;
- auto firstInstance =
- First->castTo<AnyMetatypeType>()->getInstanceType()->getCanonicalType();
- auto secondInstance =
- second->castTo<AnyMetatypeType>()->getInstanceType()->getCanonicalType();
-
- auto joinInstance = join(firstInstance, secondInstance);
-
- if (!joinInstance)
- return First->getASTContext().TheAnyType;
-
- return MetatypeType::get(joinInstance)->getCanonicalType();
+ return Unimplemented;
}
-CanType TypeJoin::visitExistentialMetatypeType(CanType second) {
+CanType TypeJoin::visitFunctionType(CanType second) {
+ assert(First != second);
+
if (First->getKind() != second->getKind())
- return First->getASTContext().TheAnyType;
+ return TheAnyType;
- auto firstInstance =
- First->castTo<AnyMetatypeType>()->getInstanceType()->getCanonicalType();
- auto secondInstance =
- second->castTo<AnyMetatypeType>()->getInstanceType()->getCanonicalType();
+ auto firstFnTy = First->castTo<FunctionType>();
+ auto secondFnTy = second->castTo<FunctionType>();
- auto joinInstance = join(firstInstance, secondInstance);
+ // FIXME: Properly handle these attributes.
+ if (firstFnTy->getExtInfo() != secondFnTy->getExtInfo())
+ return Unimplemented;
- if (!joinInstance)
- return First->getASTContext().TheAnyType;
+ // FIXME: Properly compute parameter types from getParams().
+ if (firstFnTy->getInput()->getCanonicalType() !=
+ secondFnTy->getInput()->getCanonicalType())
+ return Unimplemented;
- return ExistentialMetatypeType::get(joinInstance)->getCanonicalType();
+ auto firstResult = firstFnTy->getResult()->getCanonicalType();
+ auto secondResult = secondFnTy->getResult()->getCanonicalType();
+
+ auto result = join(firstResult, secondResult);
+ if (!result)
+ return Unimplemented;
+
+ return FunctionType::get(firstFnTy->getInput(), result,
+ firstFnTy->getExtInfo())->getCanonicalType();
}
-CanType TypeJoin::visitBoundGenericEnumType(CanType second) {
+CanType TypeJoin::visitGenericFunctionType(CanType second) {
+ assert(First != second);
+
if (First->getKind() != second->getKind())
- return First->getASTContext().TheAnyType;
+ return TheAnyType;
- bool firstIsOptional, secondIsOptional;
- auto firstObject = First->getOptionalObjectType(firstIsOptional);
- auto secondObject = second->getOptionalObjectType(secondIsOptional);
- if (firstIsOptional || secondIsOptional) {
- CanType canFirst;
- CanType canSecond;
-
- if (firstObject)
- canFirst = firstObject->getCanonicalType();
- if (secondObject)
- canSecond = secondObject->getCanonicalType();
-
- // Compute the join of the unwrapped type. If there is none, we're done.
- auto unwrappedJoin =
- join(canFirst ? canFirst : First, canSecond ? canSecond : second);
- // FIXME: More general joins of enums need to be handled.
- if (!unwrappedJoin)
- return First->getASTContext().TheAnyType;
-
- return OptionalType::get(unwrappedJoin)->getCanonicalType();
- }
-
- // FIXME: More general joins of enums need to be handled.
- return First->getASTContext().TheAnyType;
+ return Unimplemented;
}
-Type Type::join(Type first, Type second) {
+CanType TypeJoin::visitProtocolCompositionType(CanType second) {
+ if (second->isAny())
+ return second;
+
+ return Unimplemented;
+}
+
+CanType TypeJoin::visitLValueType(CanType second) { return Unimplemented; }
+
+CanType TypeJoin::visitInOutType(CanType second) { return Unimplemented; }
+
+} // namespace
+
+Optional<Type> Type::join(Type first, Type second) {
assert(first && second && "Unexpected null type!");
- if (!first || !second) {
- if (first)
- return Type(ErrorType::get(first->getASTContext()));
+ if (!first || !second)
+ return None;
- if (second)
- return Type(ErrorType::get(second->getASTContext()));
+ auto join =
+ TypeJoin::join(first->getCanonicalType(), second->getCanonicalType());
+ if (!join)
+ return None;
- return Type();
- }
-
- // FIXME: Remove this once all of the cases are implemented.
- // If one or both of the types are optional types,
- // look at the underlying object type.
- bool isFirstOptional, isSecondOptional;
- Type objectType1 = first->getOptionalObjectType(isFirstOptional);
- Type objectType2 = second->getOptionalObjectType(isSecondOptional);
-
- if (isFirstOptional || isSecondOptional) {
- auto &ctx = first->getASTContext();
- // Compute the join of the unwrapped type. If there is none, we're done.
- Type unwrappedJoin = join(objectType1 ? objectType1 : first,
- objectType2 ? objectType2 : second);
-
- auto isAnyType = [&](Type candidate) -> bool {
- return candidate && candidate->isEqual(ctx.TheAnyType);
- };
-
- // If join produced 'Any' but neither type was itself 'Any',
- // let's return empty type to indicate that there is no join.
- if (!unwrappedJoin || (isAnyType(unwrappedJoin) &&
- !isAnyType(objectType1) && !isAnyType(objectType2)))
- return nullptr;
-
- return OptionalType::get(unwrappedJoin);
- }
-
- return TypeJoin::join(first->getCanonicalType(), second->getCanonicalType());
+ return join;
}
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index e23d936..9abdd59 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -1966,7 +1966,16 @@
} else if (!outputPath.empty()) {
output.setAdditionalOutputForType(outputType, outputPath);
} else {
- // Put the auxiliary output file next to the primary output file.
+ // Put the auxiliary output file next to "the" primary output file.
+ //
+ // FIXME: when we're in WMO and have multiple primary outputs, we derive the
+ // additional filename here from the _first_ primary output name, which
+ // means that in the derived OFM (in Job.cpp) the additional output will
+ // have a possibly-surprising name. But that's only half the problem: it
+ // also get associated with the first primary _input_, even when there are
+ // multiple primary inputs; really it should be associated with the build as
+ // a whole -- derived OFM input "" -- but that's a more general thing to
+ // fix.
llvm::SmallString<128> path;
if (output.getPrimaryOutputType() != types::TY_Nothing)
path = output.getPrimaryOutputFilenames()[0];
@@ -1976,6 +1985,7 @@
formFilenameFromBaseAndExt(OI.ModuleName, /*newExt=*/"", workingDirectory,
path);
}
+ assert(!path.empty());
bool isTempFile = C.isTemporaryFile(path);
llvm::sys::path::replace_extension(path,
@@ -2290,7 +2300,7 @@
OutputFile = getOutputFilename(C, JA, OI, OMForInput, workingDirectory,
TC.getTriple(), C.getArgs(), AtTopLevel,
Base, Primary, Diags, Buf);
- Output->addPrimaryOutput(CommandInputPair{Base, Primary},
+ Output->addPrimaryOutput(CommandInputPair(Base, Primary),
OutputFile);
};
// Add an output file for each input action.
@@ -2312,9 +2322,8 @@
OutputFile = getOutputFilename(C, JA, OI, OutputMap, workingDirectory,
TC.getTriple(), C.getArgs(), AtTopLevel,
BaseInput, PrimaryInput, Diags, Buf);
- Output->addPrimaryOutput(
- CommandInputPair{BaseInput, PrimaryInput},
- OutputFile);
+ Output->addPrimaryOutput(CommandInputPair(BaseInput, PrimaryInput),
+ OutputFile);
}
}
@@ -2369,10 +2378,11 @@
llvm::sys::path::replace_extension(Path, SERIALIZED_MODULE_EXTENSION);
Output->setAdditionalOutputForType(types::TY_SwiftModuleFile, Path);
}
- } else {
+ } else if (Output->getPrimaryOutputType() != types::TY_Nothing) {
// We're only generating the module as an intermediate, so put it next
// to the primary output of the compile command.
llvm::SmallString<128> Path(Output->getPrimaryOutputFilenames()[0]);
+ assert(!Path.empty());
bool isTempFile = C.isTemporaryFile(Path);
llvm::sys::path::replace_extension(Path, SERIALIZED_MODULE_EXTENSION);
Output->setAdditionalOutputForType(types::ID::TY_SwiftModuleFile, Path);
@@ -2399,7 +2409,7 @@
// Prefer a path from the OutputMap.
Output->setAdditionalOutputForType(types::TY_SwiftModuleDocFile,
OFMModuleDocOutputPath);
- } else {
+ } else if (Output->getPrimaryOutputType() != types::TY_Nothing) {
// Otherwise, put it next to the swiftmodule file.
llvm::SmallString<128> Path(
Output->getAnyOutputForType(types::TY_SwiftModuleFile));
diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp
index c53f052..a2668b3 100644
--- a/lib/Driver/Job.cpp
+++ b/lib/Driver/Job.cpp
@@ -25,19 +25,39 @@
StringRef CommandOutput::getOutputForInputAndType(StringRef PrimaryInputFile,
types::ID Type) const {
+ if (Type == types::TY_Nothing)
+ return StringRef();
auto const *M = DerivedOutputMap.getOutputMapForInput(PrimaryInputFile);
if (!M)
return StringRef();
auto const Out = M->find(Type);
if (Out == M->end())
return StringRef();
+ assert(!Out->second.empty());
return StringRef(Out->second);
}
+struct CommandOutputInvariantChecker {
+ CommandOutput const &Out;
+ CommandOutputInvariantChecker(CommandOutput const &CO) : Out(CO) {
+#ifndef NDEBUG
+ Out.checkInvariants();
+#endif
+ }
+ ~CommandOutputInvariantChecker() {
+#ifndef NDEBUG
+ Out.checkInvariants();
+#endif
+ }
+};
+
void CommandOutput::ensureEntry(StringRef PrimaryInputFile,
types::ID Type,
StringRef OutputFile,
bool Overwrite) {
+ assert(!PrimaryInputFile.empty());
+ assert(!OutputFile.empty());
+ assert(Type != types::TY_Nothing);
auto &M = DerivedOutputMap.getOrCreateOutputMapForInput(PrimaryInputFile);
if (Overwrite) {
M[Type] = OutputFile;
@@ -52,6 +72,35 @@
}
}
+void CommandOutput::checkInvariants() const {
+ types::forAllTypes([&](types::ID Type) {
+ size_t numOutputsOfType = 0;
+ for (auto const &I : Inputs) {
+ // FIXME: At the moment, empty primary input names correspond to
+ // corner cases in the driver where it is doing TY_Nothing work
+ // and isn't even given a primary input; but at some point we
+ // ought to enable storing derived OFM entries under the empty
+ // name in general, for "whole build" additional outputs. They
+ // are presently (arbitrarily and wrongly) stored in entries
+ // associated with the first primary input of the CommandOutput
+ // that they were derived from.
+ assert(PrimaryOutputType == types::TY_Nothing || !I.Primary.empty());
+ auto const *M = DerivedOutputMap.getOutputMapForInput(I.Primary);
+ if (!M)
+ continue;
+ auto const Out = M->find(Type);
+ if (Out == M->end())
+ continue;
+ assert(!Out->second.empty());
+ ++numOutputsOfType;
+ }
+ assert(numOutputsOfType == 0 ||
+ numOutputsOfType == 1 ||
+ numOutputsOfType == Inputs.size());
+ });
+ assert(AdditionalOutputTypes.count(PrimaryOutputType) == 0);
+}
+
bool CommandOutput::hasSameAdditionalOutputTypes(
CommandOutput const &other) const {
bool sameAdditionalOutputTypes = true;
@@ -65,6 +114,7 @@
}
void CommandOutput::addOutputs(CommandOutput const &other) {
+ CommandOutputInvariantChecker Check(*this);
assert(PrimaryOutputType == other.PrimaryOutputType);
assert(&DerivedOutputMap == &other.DerivedOutputMap);
Inputs.append(other.Inputs.begin(),
@@ -80,7 +130,9 @@
CommandOutput::CommandOutput(types::ID PrimaryOutputType,
OutputFileMap &Derived)
- : PrimaryOutputType(PrimaryOutputType), DerivedOutputMap(Derived) {}
+ : PrimaryOutputType(PrimaryOutputType), DerivedOutputMap(Derived) {
+ CommandOutputInvariantChecker Check(*this);
+}
types::ID CommandOutput::getPrimaryOutputType() const {
return PrimaryOutputType;
@@ -88,23 +140,45 @@
void CommandOutput::addPrimaryOutput(CommandInputPair Input,
StringRef PrimaryOutputFile) {
- Inputs.push_back(Input);
PrettyStackTraceDriverCommandOutputAddition CrashInfo(
- "primary", this, Input.Primary, PrimaryOutputType, PrimaryOutputFile);
+ "primary", this, Input.Primary, PrimaryOutputType, PrimaryOutputFile);
+ if (PrimaryOutputType == types::TY_Nothing) {
+ // For TY_Nothing, we accumulate the inputs but do not add any outputs.
+ // The invariant holds on either side of this action because all primary
+ // outputs for this command will be absent (so the length == 0 case in the
+ // invariant holds).
+ CommandOutputInvariantChecker Check(*this);
+ Inputs.push_back(Input);
+ return;
+ }
+ // The invariant holds in the non-TY_Nothing case before an input is added and
+ // _after the corresponding output is added_, but not inbetween. Don't try to
+ // merge these two cases, they're different.
+ CommandOutputInvariantChecker Check(*this);
+ Inputs.push_back(Input);
+ assert(!PrimaryOutputFile.empty());
+ assert(AdditionalOutputTypes.count(PrimaryOutputType) == 0);
ensureEntry(Input.Primary, PrimaryOutputType, PrimaryOutputFile, false);
}
StringRef CommandOutput::getPrimaryOutputFilename() const {
+ // FIXME: ideally this shouldn't exist, or should at least assert size() == 1,
+ // and callers should handle cases with multiple primaries explicitly.
assert(Inputs.size() >= 1);
return getOutputForInputAndType(Inputs[0].Primary, PrimaryOutputType);
}
SmallVector<StringRef, 16> CommandOutput::getPrimaryOutputFilenames() const {
SmallVector<StringRef, 16> V;
+ size_t NonEmpty = 0;
for (auto const &I : Inputs) {
auto Out = getOutputForInputAndType(I.Primary, PrimaryOutputType);
V.push_back(Out);
+ if (!Out.empty())
+ ++NonEmpty;
+ assert(!Out.empty() || PrimaryOutputType == types::TY_Nothing);
}
+ assert(NonEmpty == 0 || NonEmpty == Inputs.size());
return V;
}
@@ -112,25 +186,54 @@
StringRef OutputFilename) {
PrettyStackTraceDriverCommandOutputAddition CrashInfo(
"additional", this, Inputs[0].Primary, Type, OutputFilename);
+ CommandOutputInvariantChecker Check(*this);
assert(Inputs.size() >= 1);
+ assert(!OutputFilename.empty());
+ assert(Type != types::TY_Nothing);
// If we're given an "additional" output with the same type as the primary,
// and we've not yet had such an additional type added, we treat it as a
// request to overwrite the primary choice (which happens early and is
// sometimes just inferred) with a refined value (eg. -emit-module-path).
- bool Overwrite = (Type == PrimaryOutputType &&
- AdditionalOutputTypes.count(Type) == 0);
+ bool Overwrite = Type == PrimaryOutputType;
+ if (Overwrite) {
+ assert(AdditionalOutputTypes.count(Type) == 0);
+ } else {
+ AdditionalOutputTypes.insert(Type);
+ }
ensureEntry(Inputs[0].Primary, Type, OutputFilename, Overwrite);
- AdditionalOutputTypes.insert(Type);
}
StringRef CommandOutput::getAdditionalOutputForType(types::ID Type) const {
if (AdditionalOutputTypes.count(Type) == 0)
return StringRef();
assert(Inputs.size() >= 1);
+ // FIXME: ideally this shouldn't associate the additional output with the
+ // first primary, but with a specific primary (and/or possibly the primary "",
+ // for build-wide outputs) specified by the caller.
+ assert(Inputs.size() >= 1);
return getOutputForInputAndType(Inputs[0].Primary, Type);
}
+SmallVector<StringRef, 16>
+CommandOutput::getAdditionalOutputsForType(types::ID Type) const {
+ SmallVector<StringRef, 16> V;
+ if (AdditionalOutputTypes.count(Type) != 0) {
+ for (auto const &I : Inputs) {
+ auto Out = getOutputForInputAndType(I.Primary, Type);
+ // FIXME: In theory this should always be non-empty -- and V.size() would
+ // always be either 0 or N like with primary outputs -- but in practice
+ // WMO currently associates additional outputs with the _first primary_ in
+ // a multi-primary job, which means that the 2nd..Nth primaries will have
+ // an empty result from getOutputForInputAndType, and V.size() will be 1.
+ if (!Out.empty())
+ V.push_back(Out);
+ }
+ }
+ assert(V.empty() || V.size() == 1 || V.size() == Inputs.size());
+ return V;
+}
+
StringRef CommandOutput::getAnyOutputForType(types::ID Type) const {
if (PrimaryOutputType == Type)
return getPrimaryOutputFilename();
diff --git a/lib/Driver/PrettyStackTrace.cpp b/lib/Driver/PrettyStackTrace.cpp
index a195dc6..b2c9226 100644
--- a/lib/Driver/PrettyStackTrace.cpp
+++ b/lib/Driver/PrettyStackTrace.cpp
@@ -48,6 +48,7 @@
out << "While adding " << Description
<< " output named " << NewOutputName
<< " of type " << types::getTypeName(NewOutputType)
+ << " for input " << PrimaryInput
<< " to driver CommandOutput\n";
TheCommandOutput->print(out);
out << '\n';
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index d251cc1..37d50c7 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -85,6 +85,23 @@
}
}
+static bool
+addOutputsOfType(ArgStringList &Arguments,
+ CommandOutput const &Output,
+ const llvm::opt::ArgList &Args,
+ types::ID OutputType,
+ const char *PrefixArgument = nullptr) {
+ bool Added = false;
+ for (auto Output : Output.getAdditionalOutputsForType(OutputType)) {
+ assert(!Output.empty());
+ if (PrefixArgument)
+ Arguments.push_back(PrefixArgument);
+ Arguments.push_back(Args.MakeArgString(Output));
+ Added = true;
+ }
+ return Added;
+}
+
/// Handle arguments common to all invocations of the frontend (compilation,
/// module-merging, LLDB's REPL, etc).
static void addCommonFrontendArgs(const ToolChain &TC,
@@ -197,23 +214,16 @@
inputArgs.AddAllArgs(arguments, options::OPT_Xllvm);
inputArgs.AddAllArgs(arguments, options::OPT_Xcc);
- auto moduleDocOutputPath =
- output.getAdditionalOutputForType(types::TY_SwiftModuleDocFile);
- if (!moduleDocOutputPath.empty()) {
- arguments.push_back("-emit-module-doc-path");
- arguments.push_back(inputArgs.MakeArgString(moduleDocOutputPath));
- }
+ addOutputsOfType(arguments, output, inputArgs,
+ types::TY_SwiftModuleDocFile,
+ "-emit-module-doc-path");
if (llvm::sys::Process::StandardErrHasColors())
arguments.push_back("-color-diagnostics");
- auto SerializedDiagnosticsPath =
- output.getAdditionalOutputForType(types::TY_SerializedDiagnostics);
- if (!SerializedDiagnosticsPath.empty()) {
- arguments.push_back("-serialize-diagnostics-path");
- arguments.push_back(
- inputArgs.MakeArgString(SerializedDiagnosticsPath));
- }
+ addOutputsOfType(arguments, output, inputArgs,
+ types::TY_SerializedDiagnostics,
+ "-serialize-diagnostics-path");
}
@@ -443,72 +453,44 @@
Arguments.push_back("-module-name");
Arguments.push_back(context.Args.MakeArgString(context.OI.ModuleName));
- auto ModuleOutputPath =
- context.Output.getAdditionalOutputForType(types::ID::TY_SwiftModuleFile);
- if (!ModuleOutputPath.empty()) {
- Arguments.push_back("-emit-module-path");
- Arguments.push_back(context.Args.MakeArgString(ModuleOutputPath));
+ addOutputsOfType(Arguments, context.Output, context.Args,
+ types::ID::TY_SwiftModuleFile,
+ "-emit-module-path");
+
+ if (addOutputsOfType(Arguments, context.Output, context.Args,
+ types::ID::TY_ObjCHeader, "-emit-objc-header-path")) {
+ assert(context.OI.CompilerMode == OutputInfo::Mode::SingleCompile &&
+ "The Swift tool should only emit an Obj-C header in single compile"
+ "mode!");
}
- auto ObjCHeaderOutputPath =
- context.Output.getAdditionalOutputForType(types::ID::TY_ObjCHeader);
- if (!ObjCHeaderOutputPath.empty()) {
- assert(context.OI.CompilerMode == OutputInfo::Mode::SingleCompile &&
- "The Swift tool should only emit an Obj-C header in single compile"
- "mode!");
+ addOutputsOfType(Arguments, context.Output, context.Args,
+ types::TY_Dependencies,
+ "-emit-dependencies-path");
- Arguments.push_back("-emit-objc-header-path");
- Arguments.push_back(
- context.Args.MakeArgString(ObjCHeaderOutputPath));
- }
+ addOutputsOfType(Arguments, context.Output, context.Args,
+ types::TY_SwiftDeps,
+ "-emit-reference-dependencies-path");
- auto DependenciesPath =
- context.Output.getAdditionalOutputForType(types::TY_Dependencies);
- if (!DependenciesPath.empty()) {
- Arguments.push_back("-emit-dependencies-path");
- Arguments.push_back(context.Args.MakeArgString(DependenciesPath));
- }
+ addOutputsOfType(Arguments, context.Output, context.Args,
+ types::TY_ModuleTrace,
+ "-emit-loaded-module-trace-path");
- auto ReferenceDependenciesPath =
- context.Output.getAdditionalOutputForType(types::TY_SwiftDeps);
- if (!ReferenceDependenciesPath.empty()) {
- Arguments.push_back("-emit-reference-dependencies-path");
- Arguments.push_back(
- context.Args.MakeArgString(ReferenceDependenciesPath));
- }
+ addOutputsOfType(Arguments, context.Output, context.Args,
+ types::TY_TBD,
+ "-emit-tbd-path");
- auto LoadedModuleTracePath =
- context.Output.getAdditionalOutputForType(types::TY_ModuleTrace);
- if (!LoadedModuleTracePath.empty()) {
- Arguments.push_back("-emit-loaded-module-trace-path");
- Arguments.push_back(
- context.Args.MakeArgString(LoadedModuleTracePath));
- }
-
- auto TBDPath =
- context.Output.getAdditionalOutputForType(types::TY_TBD);
- if (!TBDPath.empty()) {
- Arguments.push_back("-emit-tbd-path");
- Arguments.push_back(context.Args.MakeArgString(TBDPath));
- }
-
- auto OptRecordPath =
- context.Output.getAdditionalOutputForType(types::TY_OptRecord);
- if (!OptRecordPath.empty()) {
- Arguments.push_back("-save-optimization-record-path");
- Arguments.push_back(context.Args.MakeArgString(OptRecordPath));
- }
+ addOutputsOfType(Arguments, context.Output, context.Args,
+ types::TY_OptRecord,
+ "-save-optimization-record-path");
if (context.Args.hasArg(options::OPT_migrate_keep_objc_visibility)) {
Arguments.push_back("-migrate-keep-objc-visibility");
}
- auto FixitsPath =
- context.Output.getAdditionalOutputForType(types::TY_Remapping);
- if (!FixitsPath.empty()) {
- Arguments.push_back("-emit-remap-file-path");
- Arguments.push_back(context.Args.MakeArgString(FixitsPath));
- }
+ addOutputsOfType(Arguments, context.Output, context.Args,
+ types::TY_Remapping,
+ "-emit-remap-file-path");
if (context.OI.numThreads > 0) {
Arguments.push_back("-num-threads");
@@ -743,8 +725,10 @@
addInputsOfType(Arguments, context.Inputs, context.Args, types::TY_SwiftModuleFile);
addInputsOfType(Arguments, context.InputActions, types::TY_SwiftModuleFile);
assert(Arguments.size() - origLen >=
- context.Inputs.size() + context.InputActions.size());
+ context.Inputs.size() + context.InputActions.size() ||
+ context.OI.CompilerOutputType == types::TY_Nothing);
assert((Arguments.size() - origLen == context.Inputs.size() ||
+ context.OI.CompilerOutputType == types::TY_Nothing ||
!context.InputActions.empty()) &&
"every input to MergeModule must generate a swiftmodule");
}
diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp
index 2013a98..68c583a 100644
--- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp
+++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp
@@ -427,12 +427,12 @@
OutputFilesComputer::getOutputFilenamesFromCommandLineOrFilelist(Args,
Diags);
- auto nameToStem =
+ std::string nameToStem =
outputFilenames && outputFilenames->size() == 1 &&
outputFilenames->front() != "-" &&
!llvm::sys::fs::is_directory(outputFilenames->front())
? outputFilenames->front()
- : Opts.InputsAndOutputs.getFilenameOfFirstInput().str();
+ : Opts.InputsAndOutputs.getFilenameOfFirstInput();
Opts.ModuleName = llvm::sys::path::stem(nameToStem);
return false;
@@ -441,7 +441,7 @@
bool ArgsToFrontendOptionsConverter::
computeMainAndSupplementaryOutputFilenames() {
std::vector<std::string> mainOutputs;
- SupplementaryOutputPaths supplementaryOutputs;
+ std::vector<SupplementaryOutputPaths> supplementaryOutputs;
const bool hadError = ArgsToFrontendOutputsConverter(
Args, Opts.ModuleName, Opts.InputsAndOutputs, Diags)
.convert(mainOutputs, supplementaryOutputs);
@@ -487,9 +487,7 @@
using namespace options;
if (const Arg *A = Args.getLastArgNoClaim(OPT_import_objc_header)) {
Opts.ImplicitObjCHeaderPath = A->getValue();
- Opts.SerializeBridgingHeader |=
- !Opts.InputsAndOutputs.hasPrimaryInputs() &&
- !Opts.InputsAndOutputs.supplementaryOutputs().ModuleOutputPath.empty();
+ Opts.SerializeBridgingHeader |= !Opts.InputsAndOutputs.hasPrimaryInputs();
}
}
void ArgsToFrontendOptionsConverter::computeImplicitImportModuleNames() {
diff --git a/lib/Frontend/ArgsToFrontendOutputsConverter.cpp b/lib/Frontend/ArgsToFrontendOutputsConverter.cpp
index 20fec23..6fd74ee 100644
--- a/lib/Frontend/ArgsToFrontendOutputsConverter.cpp
+++ b/lib/Frontend/ArgsToFrontendOutputsConverter.cpp
@@ -33,7 +33,7 @@
bool ArgsToFrontendOutputsConverter::convert(
std::vector<std::string> &mainOutputs,
- SupplementaryOutputPaths &supplementaryOutputs) {
+ std::vector<SupplementaryOutputPaths> &supplementaryOutputs) {
Optional<OutputFilesComputer> ofc =
OutputFilesComputer::create(Args, Diags, InputsAndOutputs);
@@ -51,10 +51,7 @@
return true;
mainOutputs = std::move(*mains);
- assert(supplementaries->size() <= 1 &&
- "Have not implemented multiple primaries yet");
- if (!supplementaries->empty())
- supplementaryOutputs = std::move(supplementaries->front());
+ supplementaryOutputs = std::move(*supplementaries);
return false;
}
@@ -103,9 +100,10 @@
ArrayRef<std::string> outputFileArguments =
outputDirectoryArgument.empty() ? ArrayRef<std::string>(*outputArguments)
: ArrayRef<std::string>();
- const StringRef firstInput = inputsAndOutputs.hasSingleInput()
- ? inputsAndOutputs.getFilenameOfFirstInput()
- : StringRef();
+ const StringRef firstInput =
+ inputsAndOutputs.hasSingleInput()
+ ? StringRef(inputsAndOutputs.getFilenameOfFirstInput())
+ : StringRef();
const FrontendOptions::ActionType requestedAction =
ArgsToFrontendOptionsConverter::determineRequestedAction(args);
@@ -143,21 +141,19 @@
Optional<std::vector<std::string>>
OutputFilesComputer::computeOutputFiles() const {
std::vector<std::string> outputFiles;
- bool hadError = false;
unsigned i = 0;
- InputsAndOutputs.forEachInputProducingAMainOutputFile(
- [&](const InputFile &input) -> void {
+ bool hadError = InputsAndOutputs.forEachInputProducingAMainOutputFile(
+ [&](const InputFile &input) -> bool {
StringRef outputArg = OutputFileArguments.empty()
? StringRef()
: StringRef(OutputFileArguments[i++]);
Optional<std::string> outputFile = computeOutputFile(outputArg, input);
- if (!outputFile) {
- hadError = true;
- return;
- }
+ if (!outputFile)
+ return true;
outputFiles.push_back(*outputFile);
+ return false;
});
return hadError ? None : Optional<std::vector<std::string>>(outputFiles);
}
@@ -208,7 +204,7 @@
std::string
OutputFilesComputer::determineBaseNameOfOutput(const InputFile &input) const {
- StringRef nameToStem =
+ std::string nameToStem =
input.isPrimary()
? input.file()
: ModuleNameArg ? ModuleNameArg->getValue() : FirstInput;
@@ -256,15 +252,15 @@
std::vector<SupplementaryOutputPaths> outputPaths;
unsigned i = 0;
- bool hadError = false;
- InputsAndOutputs.forEachInputProducingSupplementaryOutput(
- [&](const InputFile &input) -> void {
+ bool hadError = InputsAndOutputs.forEachInputProducingSupplementaryOutput(
+ [&](const InputFile &input) -> bool {
if (auto suppPaths = computeOutputPathsForOneInput(
- OutputFiles[i], (*pathsFromUser)[i], input))
+ OutputFiles[i], (*pathsFromUser)[i], input)) {
+ ++i;
outputPaths.push_back(*suppPaths);
- else
- hadError = true;
- ++i;
+ return false;
+ }
+ return true;
});
if (hadError)
return None;
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 005665a..f00ba48 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -675,12 +675,12 @@
if (Args.hasArg(OPT_debug_on_sil)) {
// Derive the name of the SIL file for debugging from
// the regular outputfile.
- StringRef BaseName = FEOpts.InputsAndOutputs.getSingleOutputFilename();
+ std::string BaseName = FEOpts.InputsAndOutputs.getSingleOutputFilename();
// If there are no or multiple outputfiles, derive the name
// from the module name.
if (BaseName.empty())
BaseName = FEOpts.ModuleName;
- Opts.SILOutputFileNameForDebugging = BaseName.str();
+ Opts.SILOutputFileNameForDebugging = BaseName;
}
if (const Arg *A = Args.getLastArg(options::OPT_sanitize_EQ)) {
diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp
index 483b501..5c29484 100644
--- a/lib/Frontend/Frontend.cpp
+++ b/lib/Frontend/Frontend.cpp
@@ -56,21 +56,58 @@
return llvm::APInt(64, Code).toString(36, /*Signed=*/false);
}
-PrimarySpecificPaths
+const PrimarySpecificPaths &
CompilerInvocation::getPrimarySpecificPathsForAtMostOnePrimary() const {
return getFrontendOptions().getPrimarySpecificPathsForAtMostOnePrimary();
}
-PrimarySpecificPaths CompilerInvocation::getPrimarySpecificPathsForPrimary(
+const PrimarySpecificPaths &
+CompilerInvocation::getPrimarySpecificPathsForPrimary(
StringRef filename) const {
return getFrontendOptions().getPrimarySpecificPathsForPrimary(filename);
}
-PrimarySpecificPaths CompilerInvocation::getPrimarySpecificPathsForSourceFile(
+const PrimarySpecificPaths &
+CompilerInvocation::getPrimarySpecificPathsForSourceFile(
const SourceFile &SF) const {
return getPrimarySpecificPathsForPrimary(SF.getFilename());
}
+std::string CompilerInvocation::getOutputFilenameForAtMostOnePrimary() const {
+ return getPrimarySpecificPathsForAtMostOnePrimary().OutputFilename;
+}
+std::string
+CompilerInvocation::getMainInputFilenameForDebugInfoForAtMostOnePrimary()
+ const {
+ return getPrimarySpecificPathsForAtMostOnePrimary()
+ .MainInputFilenameForDebugInfo;
+}
+std::string
+CompilerInvocation::getObjCHeaderOutputPathForAtMostOnePrimary() const {
+ return getPrimarySpecificPathsForAtMostOnePrimary()
+ .SupplementaryOutputs.ObjCHeaderOutputPath;
+}
+std::string CompilerInvocation::getModuleOutputPathForAtMostOnePrimary() const {
+ return getPrimarySpecificPathsForAtMostOnePrimary()
+ .SupplementaryOutputs.ModuleOutputPath;
+}
+std::string CompilerInvocation::getReferenceDependenciesFilePathForPrimary(
+ StringRef filename) const {
+ return getPrimarySpecificPathsForPrimary(filename)
+ .SupplementaryOutputs.ReferenceDependenciesFilePath;
+}
+std::string
+CompilerInvocation::getSerializedDiagnosticsPathForAtMostOnePrimary() const {
+ return getPrimarySpecificPathsForAtMostOnePrimary()
+ .SupplementaryOutputs.SerializedDiagnosticsPath;
+}
+std::string CompilerInvocation::getTBDPathForWholeModule() const {
+ assert(getFrontendOptions().InputsAndOutputs.isWholeModule() &&
+ "TBDPath only makes sense in WMO mode");
+ return getPrimarySpecificPathsForAtMostOnePrimary()
+ .SupplementaryOutputs.TBDPath;
+}
+
void CompilerInstance::createSILModule() {
assert(MainModule && "main module not created yet");
// Assume WMO if a -primary-file option was not provided.
@@ -103,9 +140,7 @@
// If we are asked to emit a module documentation file, configure lexing and
// parsing to remember comments.
- if (!Invocation.getFrontendOptions()
- .InputsAndOutputs.supplementaryOutputs()
- .ModuleDocOutputPath.empty())
+ if (Invocation.getFrontendOptions().InputsAndOutputs.hasModuleDocOutputPath())
Invocation.getLangOptions().AttachCommentsToDecls = true;
// If we are doing index-while-building, configure lexing and parsing to
@@ -240,7 +275,6 @@
}
if (input.isPrimary()) {
- assert(PrimaryBufferIDs.empty() && "re-setting PrimaryBufferID");
recordPrimaryInputBuffer(*bufferID);
}
return false;
@@ -849,20 +883,21 @@
void CompilerInstance::freeSILModule() { TheSILModule.reset(); }
-PrimarySpecificPaths
+const PrimarySpecificPaths &
CompilerInstance::getPrimarySpecificPathsForWholeModuleOptimizationMode()
const {
return getPrimarySpecificPathsForAtMostOnePrimary();
}
-PrimarySpecificPaths
+const PrimarySpecificPaths &
CompilerInstance::getPrimarySpecificPathsForAtMostOnePrimary() const {
return Invocation.getPrimarySpecificPathsForAtMostOnePrimary();
}
-PrimarySpecificPaths
+const PrimarySpecificPaths &
CompilerInstance::getPrimarySpecificPathsForPrimary(StringRef filename) const {
return Invocation.getPrimarySpecificPathsForPrimary(filename);
}
-PrimarySpecificPaths CompilerInstance::getPrimarySpecificPathsForSourceFile(
+const PrimarySpecificPaths &
+CompilerInstance::getPrimarySpecificPathsForSourceFile(
const SourceFile &SF) const {
return Invocation.getPrimarySpecificPathsForSourceFile(SF);
}
diff --git a/lib/Frontend/FrontendInputsAndOutputs.cpp b/lib/Frontend/FrontendInputsAndOutputs.cpp
index 47c7be3..f37eec1 100644
--- a/lib/Frontend/FrontendInputsAndOutputs.cpp
+++ b/lib/Frontend/FrontendInputsAndOutputs.cpp
@@ -36,9 +36,6 @@
for (InputFile input : other.AllInputs)
addInput(input);
IsSingleThreadedWMO = other.IsSingleThreadedWMO;
- SupplementaryOutputs = other.SupplementaryOutputs;
- PrimarySpecificPathsForAtMostOnePrimary =
- other.PrimarySpecificPathsForAtMostOnePrimary;
}
FrontendInputsAndOutputs &FrontendInputsAndOutputs::
@@ -47,9 +44,6 @@
for (InputFile input : other.AllInputs)
addInput(input);
IsSingleThreadedWMO = other.IsSingleThreadedWMO;
- SupplementaryOutputs = other.SupplementaryOutputs;
- PrimarySpecificPathsForAtMostOnePrimary =
- other.PrimarySpecificPathsForAtMostOnePrimary;
return *this;
}
@@ -67,43 +61,40 @@
return hasSingleInput() && getFilenameOfFirstInput() == "-";
}
-StringRef FrontendInputsAndOutputs::getFilenameOfFirstInput() const {
+const std::string &FrontendInputsAndOutputs::getFilenameOfFirstInput() const {
assert(hasInputs());
const InputFile &inp = AllInputs[0];
- StringRef f = inp.file();
+ const std::string &f = inp.file();
assert(!f.empty());
return f;
}
-void FrontendInputsAndOutputs::forEachInput(
- llvm::function_ref<void(const InputFile &)> fn) const {
+bool FrontendInputsAndOutputs::forEachInput(
+ llvm::function_ref<bool(const InputFile &)> fn) const {
for (const InputFile &input : AllInputs)
- fn(input);
+ if (fn(input))
+ return true;
+ return false;
}
// Primaries:
const InputFile &FrontendInputsAndOutputs::firstPrimaryInput() const {
- assert(!PrimaryInputs.empty());
- for (const auto &f : AllInputs)
- if (f.isPrimary())
- return f;
- llvm_unreachable("no first primary?!");
+ assert(!PrimaryInputsInOrder.empty());
+ return AllInputs[PrimaryInputsInOrder.front()];
}
const InputFile &FrontendInputsAndOutputs::lastPrimaryInput() const {
- assert(!PrimaryInputs.empty());
- for (const auto &f : reversed(AllInputs))
- if (f.isPrimary())
- return f;
- llvm_unreachable("no last primary?!");
+ assert(!PrimaryInputsInOrder.empty());
+ return AllInputs[PrimaryInputsInOrder.back()];
}
-void FrontendInputsAndOutputs::forEachPrimaryInput(
- llvm::function_ref<void(const InputFile &)> fn) const {
- for (auto &f : AllInputs)
- if (f.isPrimary())
- fn(f);
+bool FrontendInputsAndOutputs::forEachPrimaryInput(
+ llvm::function_ref<bool(const InputFile &)> fn) const {
+ for (unsigned i : PrimaryInputsInOrder)
+ if (fn(AllInputs[i]))
+ return true;
+ return false;
}
void FrontendInputsAndOutputs::assertMustNotBeMoreThanOnePrimaryInput() const {
@@ -120,8 +111,9 @@
const InputFile *FrontendInputsAndOutputs::getUniquePrimaryInput() const {
assertMustNotBeMoreThanOnePrimaryInput();
- const auto b = PrimaryInputs.begin();
- return b == PrimaryInputs.end() ? nullptr : &AllInputs[b->second];
+ return PrimaryInputsInOrder.empty()
+ ? nullptr
+ : &AllInputs[PrimaryInputsInOrder.front()];
}
const InputFile &
@@ -131,11 +123,6 @@
llvm_unreachable("No primary when one is required");
}
-StringRef FrontendInputsAndOutputs::getNameOfUniquePrimaryInputFile() const {
- const auto *input = getUniquePrimaryInput();
- return input == nullptr ? StringRef() : input->file();
-}
-
std::string FrontendInputsAndOutputs::getStatsFileMangledInputName() const {
// FIXME: "batch" should probably be some concatenation of all the primary
// input names, in order to keep the stats file names unique. (Or perhaps just
@@ -146,25 +133,18 @@
}
bool FrontendInputsAndOutputs::isInputPrimary(StringRef file) const {
- StringRef correctedFile =
- InputFile::convertBufferNameFromLLVM_getFileOrSTDIN_toSwiftConventions(
- file);
- auto iterator = PrimaryInputs.find(correctedFile);
- if (iterator == PrimaryInputs.end())
- return false;
- assert(AllInputs[iterator->second].isPrimary() &&
- "PrimaryInputs should only hold primaries");
- return true;
+ return primaryInputNamed(file) != nullptr;
}
unsigned FrontendInputsAndOutputs::numberOfPrimaryInputsEndingWith(
const char *extension) const {
- return count_if(
- PrimaryInputs, [&](const llvm::StringMapEntry<unsigned> &elem) -> bool {
- StringRef filename = AllInputs[elem.second].file();
-
- return llvm::sys::path::extension(filename).endswith(extension);
- });
+ unsigned n = 0;
+ (void)forEachPrimaryInput([&](const InputFile &input) -> bool {
+ if (llvm::sys::path::extension(input.file()).endswith(extension))
+ ++n;
+ return false;
+ });
+ return n;
}
// Input queries
@@ -182,7 +162,7 @@
if (hasSingleInput()) {
// If we have exactly one input filename, and its extension is "sil",
// treat the input as SIL.
- StringRef Input(getFilenameOfFirstInput());
+ const std::string &Input(getFilenameOfFirstInput());
return llvm::sys::path::extension(Input).endswith(SIL_EXTENSION);
}
// If we have one primary input and it's a filename with extension "sil",
@@ -245,13 +225,17 @@
void FrontendInputsAndOutputs::clearInputs() {
AllInputs.clear();
- PrimaryInputs.clear();
+ PrimaryInputsByName.clear();
+ PrimaryInputsInOrder.clear();
}
void FrontendInputsAndOutputs::addInput(const InputFile &input) {
- if (!input.file().empty() && input.isPrimary())
- PrimaryInputs.insert(std::make_pair(input.file(), AllInputs.size()));
+ const unsigned index = AllInputs.size();
AllInputs.push_back(input);
+ if (input.isPrimary()) {
+ PrimaryInputsInOrder.push_back(index);
+ PrimaryInputsByName.insert(std::make_pair(AllInputs.back().file(), index));
+ }
}
void FrontendInputsAndOutputs::addInputFile(StringRef file,
@@ -284,62 +268,77 @@
: hasPrimaryInputs() ? lastPrimaryInput() : lastInput();
}
-void FrontendInputsAndOutputs::forEachInputProducingAMainOutputFile(
- llvm::function_ref<void(const InputFile &)> fn) const {
- isSingleThreadedWMO()
- ? fn(firstInput())
- : hasPrimaryInputs() ? forEachPrimaryInput(fn) : forEachInput(fn);
+bool FrontendInputsAndOutputs::forEachInputProducingAMainOutputFile(
+ llvm::function_ref<bool(const InputFile &)> fn) const {
+ return isSingleThreadedWMO()
+ ? fn(firstInput())
+ : hasPrimaryInputs() ? forEachPrimaryInput(fn) : forEachInput(fn);
}
void FrontendInputsAndOutputs::setMainAndSupplementaryOutputs(
ArrayRef<std::string> outputFiles,
- SupplementaryOutputPaths supplementaryOutputs) {
+ ArrayRef<SupplementaryOutputPaths> supplementaryOutputs) {
+ if (AllInputs.empty()) {
+ assert(outputFiles.empty() && "Cannot have outputs without inputs");
+ assert(supplementaryOutputs.empty() &&
+ "Cannot have supplementary outputs without inputs");
+ return;
+ }
if (hasPrimaryInputs()) {
- unsigned i = 0;
- for (auto index : indices(AllInputs)) {
- InputFile &f = AllInputs[index];
- if (f.isPrimary())
- f.setOutputFilename(outputFiles[i++]);
- }
- } else if (isSingleThreadedWMO()) {
- AllInputs[0].setOutputFilename(outputFiles[0]);
- } else {
- for (auto i : indices(AllInputs))
- AllInputs[i].setOutputFilename(outputFiles[i]);
- }
- SupplementaryOutputs = supplementaryOutputs;
+ const auto N = primaryInputCount();
+ assert(outputFiles.size() == N && "Must have one main output per primary");
+ assert(supplementaryOutputs.size() == N &&
+ "Must have one set of supplementary outputs per primary");
- if (hasUniquePrimaryInput() || (hasInputs() && isWholeModule())) {
- // When batch mode is fully implemented, each InputFile will own
- // a PrimarySpecificPaths.
- PrimarySpecificPathsForAtMostOnePrimary.OutputFilename =
- getSingleOutputFilename();
- PrimarySpecificPathsForAtMostOnePrimary.MainInputFilenameForDebugInfo =
- hasInputsProducingMainOutputs() ? firstInputProducingOutput().file()
- : StringRef();
- PrimarySpecificPathsForAtMostOnePrimary.SupplementaryOutputs =
- supplementaryOutputs;
+ unsigned i = 0;
+ for (auto &input : AllInputs) {
+ if (input.isPrimary()) {
+ input.setPrimarySpecificPaths(PrimarySpecificPaths(
+ outputFiles[i], input.file(), supplementaryOutputs[i]));
+ ++i;
+ }
+ }
+ return;
}
+ assert(supplementaryOutputs.size() == 1 &&
+ "WMO only ever produces one set of supplementary outputs");
+ if (outputFiles.size() == 1) {
+ AllInputs.front().setPrimarySpecificPaths(PrimarySpecificPaths(
+ outputFiles.front(), firstInputProducingOutput().file(),
+ supplementaryOutputs.front()));
+ return;
+ }
+ assert(outputFiles.size() == AllInputs.size() &&
+ "Multi-threaded WMO requires one main output per input");
+ for (auto i : indices(AllInputs))
+ AllInputs[i].setPrimarySpecificPaths(PrimarySpecificPaths(
+ outputFiles[i], outputFiles[i],
+ i == 0 ? supplementaryOutputs.front() : SupplementaryOutputPaths()));
}
std::vector<std::string> FrontendInputsAndOutputs::copyOutputFilenames() const {
std::vector<std::string> outputs;
- forEachInputProducingAMainOutputFile([&](const InputFile &input) -> void {
- outputs.push_back(input.outputFilename());
- });
+ (void)forEachInputProducingAMainOutputFile(
+ [&](const InputFile &input) -> bool {
+ outputs.push_back(input.outputFilename());
+ return false;
+ });
return outputs;
}
void FrontendInputsAndOutputs::forEachOutputFilename(
- llvm::function_ref<void(const std::string &)> fn) const {
- forEachInputProducingAMainOutputFile(
- [&](const InputFile &input) -> void { fn(input.outputFilename()); });
+ llvm::function_ref<void(StringRef)> fn) const {
+ (void)forEachInputProducingAMainOutputFile(
+ [&](const InputFile &input) -> bool {
+ fn(input.outputFilename());
+ return false;
+ });
}
-StringRef FrontendInputsAndOutputs::getSingleOutputFilename() const {
+std::string FrontendInputsAndOutputs::getSingleOutputFilename() const {
assertMustNotBeMoreThanOnePrimaryInputUnlessBatchModeChecksHaveBeenBypassed();
- return hasInputs() ? StringRef(lastInputProducingOutput().outputFilename())
- : StringRef();
+ return hasInputs() ? lastInputProducingOutput().outputFilename()
+ : std::string();
}
bool FrontendInputsAndOutputs::isOutputFilenameStdout() const {
@@ -362,34 +361,63 @@
return hasPrimaryInputs() ? primaryInputCount() : hasInputs() ? 1 : 0;
}
-void FrontendInputsAndOutputs::forEachInputProducingSupplementaryOutput(
- llvm::function_ref<void(const InputFile &)> fn) const {
- if (hasPrimaryInputs())
- forEachPrimaryInput(fn);
- else if (hasInputs())
- fn(firstInput());
+bool FrontendInputsAndOutputs::forEachInputProducingSupplementaryOutput(
+ llvm::function_ref<bool(const InputFile &)> fn) const {
+ return hasPrimaryInputs() ? forEachPrimaryInput(fn)
+ : hasInputs() ? fn(firstInput()) : false;
+}
+
+bool FrontendInputsAndOutputs::hasSupplementaryOutputPath(
+ llvm::function_ref<const std::string &(const SupplementaryOutputPaths &)>
+ extractorFn) const {
+ return forEachInputProducingSupplementaryOutput([&](const InputFile &input)
+ -> bool {
+ return !extractorFn(input.getPrimarySpecificPaths().SupplementaryOutputs)
+ .empty();
+ });
}
bool FrontendInputsAndOutputs::hasDependenciesPath() const {
- return !supplementaryOutputs().DependenciesFilePath.empty();
+ return hasSupplementaryOutputPath(
+ [](const SupplementaryOutputPaths &outs) -> const std::string & {
+ return outs.DependenciesFilePath;
+ });
}
bool FrontendInputsAndOutputs::hasReferenceDependenciesPath() const {
- return !supplementaryOutputs().ReferenceDependenciesFilePath.empty();
+ return hasSupplementaryOutputPath(
+ [](const SupplementaryOutputPaths &outs) -> const std::string & {
+ return outs.ReferenceDependenciesFilePath;
+ });
}
bool FrontendInputsAndOutputs::hasObjCHeaderOutputPath() const {
- return !supplementaryOutputs().ObjCHeaderOutputPath.empty();
+ return hasSupplementaryOutputPath(
+ [](const SupplementaryOutputPaths &outs) -> const std::string & {
+ return outs.ObjCHeaderOutputPath;
+ });
}
bool FrontendInputsAndOutputs::hasLoadedModuleTracePath() const {
- return !supplementaryOutputs().LoadedModuleTracePath.empty();
+ return hasSupplementaryOutputPath(
+ [](const SupplementaryOutputPaths &outs) -> const std::string & {
+ return outs.LoadedModuleTracePath;
+ });
}
bool FrontendInputsAndOutputs::hasModuleOutputPath() const {
- return !supplementaryOutputs().ModuleOutputPath.empty();
+ return hasSupplementaryOutputPath(
+ [](const SupplementaryOutputPaths &outs) -> const std::string & {
+ return outs.ModuleOutputPath;
+ });
}
bool FrontendInputsAndOutputs::hasModuleDocOutputPath() const {
- return !supplementaryOutputs().ModuleDocOutputPath.empty();
+ return hasSupplementaryOutputPath(
+ [](const SupplementaryOutputPaths &outs) -> const std::string & {
+ return outs.ModuleDocOutputPath;
+ });
}
bool FrontendInputsAndOutputs::hasTBDPath() const {
- return !supplementaryOutputs().TBDPath.empty();
+ return hasSupplementaryOutputPath(
+ [](const SupplementaryOutputPaths &outs) -> const std::string & {
+ return outs.TBDPath;
+ });
}
bool FrontendInputsAndOutputs::hasDependencyTrackerPath() const {
@@ -397,13 +425,31 @@
hasLoadedModuleTracePath();
}
-PrimarySpecificPaths
+const PrimarySpecificPaths &
FrontendInputsAndOutputs::getPrimarySpecificPathsForAtMostOnePrimary() const {
- return PrimarySpecificPathsForAtMostOnePrimary;
+ assertMustNotBeMoreThanOnePrimaryInputUnlessBatchModeChecksHaveBeenBypassed();
+ static auto emptyPaths = PrimarySpecificPaths();
+ return hasInputs() ? firstInputProducingOutput().getPrimarySpecificPaths()
+ : emptyPaths;
}
-PrimarySpecificPaths
+const PrimarySpecificPaths &
FrontendInputsAndOutputs::getPrimarySpecificPathsForPrimary(
StringRef filename) const {
- return getPrimarySpecificPathsForAtMostOnePrimary(); // just a stub for now
+ const InputFile *f = primaryInputNamed(filename);
+ return f->getPrimarySpecificPaths();
+}
+
+const InputFile *
+FrontendInputsAndOutputs::primaryInputNamed(StringRef name) const {
+ assert(!name.empty() && "input files have names");
+ StringRef correctedFile =
+ InputFile::convertBufferNameFromLLVM_getFileOrSTDIN_toSwiftConventions(
+ name);
+ auto iterator = PrimaryInputsByName.find(correctedFile);
+ if (iterator == PrimaryInputsByName.end())
+ return nullptr;
+ const InputFile *f = &AllInputs[iterator->second];
+ assert(f->isPrimary() && "PrimaryInputsByName should only include primries");
+ return f;
}
diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp
index e220d53..e801410 100644
--- a/lib/Frontend/FrontendOptions.cpp
+++ b/lib/Frontend/FrontendOptions.cpp
@@ -108,7 +108,7 @@
}
void FrontendOptions::forAllOutputPaths(
- const InputFile &input, std::function<void(const std::string &)> fn) const {
+ const InputFile &input, std::function<void(StringRef)> fn) const {
if (RequestedAction != FrontendOptions::ActionType::EmitModuleOnly &&
RequestedAction != FrontendOptions::ActionType::MergeModules) {
if (InputsAndOutputs.isWholeModule())
@@ -116,28 +116,19 @@
else
fn(input.outputFilename());
}
- const std::string *outputs[] = {
- &InputsAndOutputs.supplementaryOutputs().ModuleOutputPath,
- &InputsAndOutputs.supplementaryOutputs().ModuleDocOutputPath,
- &InputsAndOutputs.supplementaryOutputs().ObjCHeaderOutputPath};
- for (const std::string *next : outputs) {
- if (!next->empty())
- fn(*next);
- }
-}
-
-
-StringRef FrontendOptions::originalPath() const {
- if (InputsAndOutputs.hasNamedOutputFile())
- // Put the serialized diagnostics file next to the output file.
- return InputsAndOutputs.getSingleOutputFilename();
-
- // If we have a primary input, so use that as the basis for the name of the
- // serialized diagnostics file, otherwise fall back on the
- // module name.
- const auto input = InputsAndOutputs.getUniquePrimaryInput();
- return input ? llvm::sys::path::filename(input->file())
- : StringRef(ModuleName);
+ (void)InputsAndOutputs.forEachInputProducingSupplementaryOutput(
+ [&](const InputFile &inp) -> bool {
+ const SupplementaryOutputPaths &outs =
+ inp.getPrimarySpecificPaths().SupplementaryOutputs;
+ const std::string *outputs[] = {&outs.ModuleOutputPath,
+ &outs.ModuleDocOutputPath,
+ &outs.ObjCHeaderOutputPath};
+ for (const std::string *next : outputs) {
+ if (!next->empty())
+ fn(*next);
+ }
+ return false;
+ });
}
const char *
@@ -387,12 +378,12 @@
}
}
-PrimarySpecificPaths
+const PrimarySpecificPaths &
FrontendOptions::getPrimarySpecificPathsForAtMostOnePrimary() const {
return InputsAndOutputs.getPrimarySpecificPathsForAtMostOnePrimary();
}
-PrimarySpecificPaths
+const PrimarySpecificPaths &
FrontendOptions::getPrimarySpecificPathsForPrimary(StringRef filename) const {
return InputsAndOutputs.getPrimarySpecificPathsForPrimary(filename);
}
diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp
index 08022fc..3bce5e8 100644
--- a/lib/FrontendTool/FrontendTool.cpp
+++ b/lib/FrontendTool/FrontendTool.cpp
@@ -40,6 +40,7 @@
#include "swift/Basic/FileSystem.h"
#include "swift/Basic/JSONSerialization.h"
#include "swift/Basic/LLVMContext.h"
+#include "swift/Basic/LLVMInitialize.h"
#include "swift/Basic/SourceManager.h"
#include "swift/Basic/Statistic.h"
#include "swift/Basic/Timer.h"
@@ -99,20 +100,20 @@
}
/// Emits a Make-style dependencies file.
-static bool emitMakeDependencies(DiagnosticEngine &diags,
- DependencyTracker &depTracker,
- const FrontendOptions &opts,
- const InputFile &input) {
+static bool emitMakeDependenciesIfNeeded(DiagnosticEngine &diags,
+ DependencyTracker *depTracker,
+ const FrontendOptions &opts,
+ const InputFile &input) {
+ const std::string &dependenciesFilePath = input.dependenciesFilePath();
+ if (dependenciesFilePath.empty())
+ return false;
+
std::error_code EC;
- llvm::raw_fd_ostream out(
- opts.InputsAndOutputs.supplementaryOutputs().DependenciesFilePath, EC,
- llvm::sys::fs::F_None);
+ llvm::raw_fd_ostream out(dependenciesFilePath, EC, llvm::sys::fs::F_None);
if (out.has_error() || EC) {
- diags.diagnose(
- SourceLoc(), diag::error_opening_output,
- opts.InputsAndOutputs.supplementaryOutputs().DependenciesFilePath,
- EC.message());
+ diags.diagnose(SourceLoc(), diag::error_opening_output,
+ dependenciesFilePath, EC.message());
out.clear_error();
return true;
}
@@ -139,7 +140,7 @@
// FIXME: Xcode can't currently handle multiple targets in a single
// dependency line.
- opts.forAllOutputPaths(input, [&](StringRef targetName) {
+ opts.forAllOutputPaths(input, [&](const StringRef targetName) {
out << escape(targetName) << " :";
// First include all other files in the module. Make-style dependencies
// need to be conservative!
@@ -148,7 +149,7 @@
out << ' ' << escape(path);
// Then print dependencies we've picked up during compilation.
for (auto const &path :
- reversePathSortedFilenames(depTracker.getDependencies()))
+ reversePathSortedFilenames(depTracker->getDependencies()))
out << ' ' << escape(path);
out << '\n';
});
@@ -156,15 +157,13 @@
return false;
}
-static bool emitMakeDependencies(DiagnosticEngine &diags,
- DependencyTracker &depTracker,
- const FrontendOptions &opts) {
- bool hadError = false;
- opts.InputsAndOutputs.forEachInputProducingSupplementaryOutput(
- [&](const InputFile &f) -> void {
- hadError = emitMakeDependencies(diags, depTracker, opts, f) || hadError;
+static bool emitMakeDependenciesIfNeeded(DiagnosticEngine &diags,
+ DependencyTracker *depTracker,
+ const FrontendOptions &opts) {
+ return opts.InputsAndOutputs.forEachInputProducingSupplementaryOutput(
+ [&](const InputFile &f) -> bool {
+ return emitMakeDependenciesIfNeeded(diags, depTracker, opts, f);
});
- return hadError;
}
namespace {
@@ -189,20 +188,16 @@
static bool emitLoadedModuleTraceIfNeeded(ASTContext &ctxt,
DependencyTracker *depTracker,
- const FrontendOptions &opts) {
- if (opts.InputsAndOutputs.supplementaryOutputs()
- .LoadedModuleTracePath.empty())
+ StringRef loadedModuleTracePath,
+ StringRef moduleName) {
+ if (loadedModuleTracePath.empty())
return false;
std::error_code EC;
- llvm::raw_fd_ostream out(
- opts.InputsAndOutputs.supplementaryOutputs().LoadedModuleTracePath, EC,
- llvm::sys::fs::F_Append);
+ llvm::raw_fd_ostream out(loadedModuleTracePath, EC, llvm::sys::fs::F_Append);
if (out.has_error() || EC) {
- ctxt.Diags.diagnose(
- SourceLoc(), diag::error_opening_output,
- opts.InputsAndOutputs.supplementaryOutputs().LoadedModuleTracePath,
- EC.message());
+ ctxt.Diags.diagnose(SourceLoc(), diag::error_opening_output,
+ loadedModuleTracePath, EC.message());
out.clear_error();
return true;
}
@@ -235,7 +230,7 @@
}
LoadedModuleTraceFormat trace = {
- /*name=*/opts.ModuleName,
+ /*name=*/moduleName,
/*arch=*/ctxt.LangOpts.Target.getArchName(),
/*swiftmodules=*/reversePathSortedFilenames(swiftModules)};
@@ -255,6 +250,16 @@
return true;
}
+static bool
+emitLoadedModuleTraceForAllPrimariesIfNeeded(ASTContext &ctxt,
+ DependencyTracker *depTracker,
+ const FrontendOptions &opts) {
+ return opts.InputsAndOutputs.forEachInputProducingSupplementaryOutput(
+ [&](const InputFile &input) -> bool {
+ return emitLoadedModuleTraceIfNeeded(
+ ctxt, depTracker, input.loadedModuleTracePath(), opts.ModuleName);
+ });
+}
/// Gets an output stream for the provided output filename, or diagnoses to the
/// provided AST Context and returns null if there was an error getting the
@@ -306,7 +311,7 @@
PSPs.OutputFilename, opts.EmitSortedSIL);
}
-static bool printAsObjCIfNeeded(const std::string &outputPath, ModuleDecl *M,
+static bool printAsObjCIfNeeded(StringRef outputPath, ModuleDecl *M,
StringRef bridgingHeader, bool moduleIsPublic) {
using namespace llvm::sys;
@@ -739,19 +744,18 @@
static void emitReferenceDependenciesForAllPrimaryInputsIfNeeded(
CompilerInvocation &Invocation, CompilerInstance &Instance) {
if (Invocation.getFrontendOptions()
- .InputsAndOutputs.supplementaryOutputs()
- .ReferenceDependenciesFilePath.empty())
- return;
- if (Instance.getPrimarySourceFiles().empty()) {
+ .InputsAndOutputs.hasReferenceDependenciesPath() &&
+ Instance.getPrimarySourceFiles().empty()) {
Instance.getASTContext().Diags.diagnose(
SourceLoc(), diag::emit_reference_dependencies_without_primary_file);
return;
}
for (auto *SF : Instance.getPrimarySourceFiles()) {
- std::string referenceDependenciesFilePath =
- Invocation.getPrimarySpecificPathsForSourceFile(*SF)
- .SupplementaryOutputs.ReferenceDependenciesFilePath;
- emitReferenceDependenciesIfNeeded(Instance.getASTContext().Diags, SF,
+ const std::string &referenceDependenciesFilePath =
+ Invocation.getReferenceDependenciesFilePathForPrimary(
+ SF->getFilename());
+ if (!referenceDependenciesFilePath.empty())
+ (void)emitReferenceDependencies(Instance.getASTContext().Diags, SF,
*Instance.getDependencyTracker(),
referenceDependenciesFilePath);
}
@@ -759,11 +763,13 @@
static bool writeTBDIfNeeded(CompilerInvocation &Invocation,
CompilerInstance &Instance) {
- StringRef TBDPath = Invocation.getFrontendOptions()
- .InputsAndOutputs.supplementaryOutputs()
- .TBDPath;
- if (TBDPath.empty())
+ if (!Invocation.getFrontendOptions().InputsAndOutputs.hasTBDPath())
return false;
+
+ const std::string &TBDPath = Invocation.getTBDPathForWholeModule();
+ assert(!TBDPath.empty() &&
+ "If not WMO, getTBDPathForWholeModule should have failed");
+
auto installName = Invocation.getFrontendOptions().TBDInstallName.empty()
? "lib" + Invocation.getModuleName().str() + ".dylib"
: Invocation.getFrontendOptions().TBDInstallName;
@@ -805,24 +811,24 @@
// If there are primary source files, build a separate SILModule for
// each source file, and run the remaining SILOpt-Serialize-IRGen-LLVM
// once for each such input.
- if (auto *PrimaryFile = Instance.getPrimarySourceFile()) {
+ std::deque<PostSILGenInputs> PSGIs;
+ for (auto *PrimaryFile : Instance.getPrimarySourceFiles()) {
auto SM = performSILGeneration(*PrimaryFile, SILOpts, None);
- std::deque<PostSILGenInputs> PSGIs;
const PrimarySpecificPaths PSPs =
Instance.getPrimarySpecificPathsForSourceFile(*PrimaryFile);
PSGIs.push_back(PostSILGenInputs{std::move(SM), true, PrimaryFile, PSPs});
- return PSGIs;
}
+ if (!PSGIs.empty())
+ return PSGIs;
// If there are primary inputs but no primary _source files_, there might be
// a primary serialized input.
- std::deque<PostSILGenInputs> PSGIs;
for (FileUnit *fileUnit : mod->getFiles()) {
if (auto SASTF = dyn_cast<SerializedASTFile>(fileUnit))
if (Invocation.getFrontendOptions().InputsAndOutputs.isInputPrimary(
SASTF->getFilename())) {
assert(PSGIs.empty() && "Can only handle one primary AST input");
auto SM = performSILGeneration(*SASTF, SILOpts, None);
- const PrimarySpecificPaths PSPs =
+ const PrimarySpecificPaths &PSPs =
Instance.getPrimarySpecificPathsForPrimary(SASTF->getFilename());
PSGIs.push_back(
PostSILGenInputs{std::move(SM), !fileIsSIB(SASTF), mod, PSPs});
@@ -831,6 +837,18 @@
return PSGIs;
}
+/// Emits index data for all primary inputs, or the main module.
+static bool
+emitIndexData(CompilerInvocation &Invocation, CompilerInstance &Instance) {
+ bool hadEmitIndexDataError = false;
+ if (Instance.getPrimarySourceFiles().empty())
+ return emitIndexDataIfNeeded(nullptr, Invocation, Instance);
+ for (SourceFile *SF : Instance.getPrimarySourceFiles())
+ hadEmitIndexDataError = emitIndexDataIfNeeded(SF, Invocation, Instance) ||
+ hadEmitIndexDataError;
+ return hadEmitIndexDataError;
+}
+
static bool performCompileStepsPostSILGen(
CompilerInstance &Instance, CompilerInvocation &Invocation,
std::unique_ptr<SILModule> SM, bool astGuaranteedToCorrespondToSIL,
@@ -905,20 +923,17 @@
if (opts.PrintClangStats && Context.getClangModuleLoader())
Context.getClangModuleLoader()->printStatistics();
- if (!opts.InputsAndOutputs.supplementaryOutputs()
- .DependenciesFilePath.empty())
- (void)emitMakeDependencies(Context.Diags, *Instance.getDependencyTracker(),
- opts);
+ (void)emitMakeDependenciesIfNeeded(Context.Diags,
+ Instance.getDependencyTracker(), opts);
emitReferenceDependenciesForAllPrimaryInputsIfNeeded(Invocation, Instance);
- (void)emitLoadedModuleTraceIfNeeded(Context, Instance.getDependencyTracker(),
- opts);
+ (void)emitLoadedModuleTraceForAllPrimariesIfNeeded(
+ Context, Instance.getDependencyTracker(), opts);
if (Context.hadError()) {
// Emit the index store data even if there were compiler errors.
- (void)emitIndexDataIfNeeded(Instance.getPrimarySourceFile(), Invocation,
- Instance);
+ (void)emitIndexData(Invocation, Instance);
return true;
}
@@ -932,11 +947,11 @@
// We've just been told to perform a typecheck, so we can return now.
if (Action == FrontendOptions::ActionType::Typecheck) {
const bool hadPrintAsObjCError = printAsObjCIfNeeded(
- opts.InputsAndOutputs.supplementaryOutputs().ObjCHeaderOutputPath,
+ Invocation.getObjCHeaderOutputPathForAtMostOnePrimary(),
Instance.getMainModule(), opts.ImplicitObjCHeaderPath, moduleIsPublic);
- const bool hadEmitIndexDataError = emitIndexDataIfNeeded(
- Instance.getPrimarySourceFile(), Invocation, Instance);
+ const bool hadEmitIndexDataError = emitIndexData(Invocation, Instance);
+
return hadPrintAsObjCError || hadEmitIndexDataError || Context.hadError();
}
@@ -1008,7 +1023,7 @@
serializationOpts.OutputPath = outs.ModuleOutputPath.c_str();
serializationOpts.DocOutputPath = outs.ModuleDocOutputPath.c_str();
serializationOpts.GroupInfoPath = opts.GroupInfoPath.c_str();
- if (opts.SerializeBridgingHeader)
+ if (opts.SerializeBridgingHeader && !outs.ModuleOutputPath.empty())
serializationOpts.ImportedHeader = opts.ImplicitObjCHeaderPath;
serializationOpts.ModuleLinkName = opts.ModuleLinkName;
serializationOpts.ExtraClangOptions =
@@ -1144,7 +1159,7 @@
}
static bool generateCode(CompilerInvocation &Invocation,
- CompilerInstance &Instance, std::string OutputFilename,
+ CompilerInstance &Instance, StringRef OutputFilename,
llvm::Module *IRModule,
llvm::GlobalVariable *HashGlobal,
UnifiedStatsReporter *Stats) {
@@ -1263,21 +1278,21 @@
if (Action == FrontendOptions::ActionType::EmitSIB)
return serializeSIB(SM.get(), PSPs, Instance.getASTContext(), MSF);
- const bool haveModulePath =
- !PSPs.SupplementaryOutputs.ModuleOutputPath.empty() ||
- !PSPs.SupplementaryOutputs.ModuleDocOutputPath.empty();
- if (haveModulePath && !SM->isSerialized())
- SM->serialize();
+ {
+ const bool haveModulePath = PSPs.haveModuleOrModuleDocOutputPaths();
+ if (haveModulePath && !SM->isSerialized())
+ SM->serialize();
- if (haveModulePath) {
- if (Action == FrontendOptions::ActionType::MergeModules ||
- Action == FrontendOptions::ActionType::EmitModuleOnly) {
- // What if MSF is a module?
- // emitIndexDataIfNeeded already handles that case;
- // it'll index everything.
- return emitIndexDataIfNeeded(MSF.dyn_cast<SourceFile *>(), Invocation,
- Instance) ||
- Context.hadError();
+ if (haveModulePath) {
+ if (Action == FrontendOptions::ActionType::MergeModules ||
+ Action == FrontendOptions::ActionType::EmitModuleOnly) {
+ // What if MSF is a module?
+ // emitIndexDataIfNeeded already handles that case;
+ // it'll index everything.
+ return emitIndexDataIfNeeded(MSF.dyn_cast<SourceFile *>(), Invocation,
+ Instance) ||
+ Context.hadError();
+ }
}
}
@@ -1360,15 +1375,18 @@
}
if (PrimarySourceFile) {
- if (index::indexAndRecord(
- PrimarySourceFile, opts.InputsAndOutputs.getSingleOutputFilename(),
- opts.IndexStorePath, opts.IndexSystemModules, isDebugCompilation,
- Invocation.getTargetTriple(), *Instance.getDependencyTracker())) {
+ const PrimarySpecificPaths &PSPs =
+ opts.InputsAndOutputs.getPrimarySpecificPathsForPrimary(
+ PrimarySourceFile->getFilename());
+ if (index::indexAndRecord(PrimarySourceFile, PSPs.OutputFilename,
+ opts.IndexStorePath, opts.IndexSystemModules,
+ isDebugCompilation, Invocation.getTargetTriple(),
+ *Instance.getDependencyTracker())) {
return true;
}
} else {
- StringRef moduleToken =
- opts.InputsAndOutputs.supplementaryOutputs().ModuleOutputPath;
+ std::string moduleToken =
+ Invocation.getModuleOutputPathForAtMostOnePrimary();
if (moduleToken.empty())
moduleToken = opts.InputsAndOutputs.getSingleOutputFilename();
@@ -1472,7 +1490,7 @@
std::string InputName =
FEOpts.InputsAndOutputs.getStatsFileMangledInputName();
StringRef OptType = silOptModeArgStr(SILOpts.OptMode);
- StringRef OutFile =
+ const std::string &OutFile =
FEOpts.InputsAndOutputs.lastInputProducingOutput().outputFilename();
StringRef OutputType = llvm::sys::path::extension(OutFile);
std::string TripleName = LangOpts.Target.normalize();
@@ -1494,10 +1512,7 @@
int swift::performFrontend(ArrayRef<const char *> Args,
const char *Argv0, void *MainAddr,
FrontendObserver *observer) {
- llvm::InitializeAllTargets();
- llvm::InitializeAllTargetMCs();
- llvm::InitializeAllAsmPrinters();
- llvm::InitializeAllAsmParsers();
+ INITIALIZE_LLVM();
PrintingDiagnosticConsumer PDC;
@@ -1606,12 +1621,13 @@
// arguments are generated by the driver, not directly by a user. The driver
// is responsible for emitting diagnostics for its own errors. See SR-2683
// for details.
+ //
+ // FIXME: Do we need one SerializedConsumer per primary? Owned by the
+ // SourceFile?
std::unique_ptr<DiagnosticConsumer> SerializedConsumer;
{
const std::string &SerializedDiagnosticsPath =
- Invocation.getFrontendOptions()
- .InputsAndOutputs.supplementaryOutputs()
- .SerializedDiagnosticsPath;
+ Invocation.getSerializedDiagnosticsPathForAtMostOnePrimary();
if (!SerializedDiagnosticsPath.empty()) {
SerializedConsumer.reset(
serialized_diagnostics::createConsumer(SerializedDiagnosticsPath));
@@ -1646,17 +1662,13 @@
}
DependencyTracker depTracker;
- if (!Invocation.getFrontendOptions()
- .InputsAndOutputs.supplementaryOutputs()
- .DependenciesFilePath.empty() ||
- !Invocation.getFrontendOptions()
- .InputsAndOutputs.supplementaryOutputs()
- .ReferenceDependenciesFilePath.empty() ||
- !Invocation.getFrontendOptions().IndexStorePath.empty() ||
- !Invocation.getFrontendOptions()
- .InputsAndOutputs.supplementaryOutputs()
- .LoadedModuleTracePath.empty()) {
- Instance->setDependencyTracker(&depTracker);
+ {
+ const FrontendInputsAndOutputs &io =
+ Invocation.getFrontendOptions().InputsAndOutputs;
+ if (io.hasDependencyTrackerPath() ||
+ !Invocation.getFrontendOptions().IndexStorePath.empty()) {
+ Instance->setDependencyTracker(&depTracker);
+ }
}
if (Instance->setup(Invocation)) {
diff --git a/lib/FrontendTool/ImportedModules.cpp b/lib/FrontendTool/ImportedModules.cpp
index 8fbed1d..4a6b8f7 100644
--- a/lib/FrontendTool/ImportedModules.cpp
+++ b/lib/FrontendTool/ImportedModules.cpp
@@ -46,7 +46,7 @@
bool swift::emitImportedModules(ASTContext &Context, ModuleDecl *mainModule,
const FrontendOptions &opts) {
- auto path = opts.InputsAndOutputs.getSingleOutputFilename();
+ std::string path = opts.InputsAndOutputs.getSingleOutputFilename();
std::error_code EC;
llvm::raw_fd_ostream out(path, EC, llvm::sys::fs::F_None);
diff --git a/lib/FrontendTool/ReferenceDependencies.cpp b/lib/FrontendTool/ReferenceDependencies.cpp
index 9dfd95b..21a05f9 100644
--- a/lib/FrontendTool/ReferenceDependencies.cpp
+++ b/lib/FrontendTool/ReferenceDependencies.cpp
@@ -123,20 +123,11 @@
return tmp;
}
-bool swift::emitReferenceDependenciesIfNeeded(DiagnosticEngine &diags,
- SourceFile *SF,
- DependencyTracker &depTracker,
- StringRef outputPath) {
+bool swift::emitReferenceDependencies(DiagnosticEngine &diags, SourceFile *SF,
+ DependencyTracker &depTracker,
+ StringRef outputPath) {
assert(SF && "Cannot emit reference dependencies without a SourceFile");
-
- const ReferencedNameTracker *const tracker = SF->getReferencedNameTracker();
- if (!tracker) {
- assert(outputPath.empty());
- return false;
- }
-
- assert(!outputPath.empty());
-
+
// Before writing to the dependencies file path, preserve any previous file
// that may have been there. No error handling -- this is just a nicety, it
// doesn't matter if it fails.
@@ -342,6 +333,9 @@
return pairs;
};
+ const ReferencedNameTracker *const tracker = SF->getReferencedNameTracker();
+ assert(tracker && "Cannot emit reference dependencies without a tracker");
+
out << "depends-top-level:\n";
for (auto &entry : sortedByName(tracker->getTopLevelNames())) {
assert(!entry.first.empty());
diff --git a/lib/FrontendTool/ReferenceDependencies.h b/lib/FrontendTool/ReferenceDependencies.h
index 5dd0f84..16c7c03 100644
--- a/lib/FrontendTool/ReferenceDependencies.h
+++ b/lib/FrontendTool/ReferenceDependencies.h
@@ -32,9 +32,9 @@
reversePathSortedFilenames(const llvm::ArrayRef<std::string> paths);
/// Emit a Swift-style dependencies file for \p SF.
-bool emitReferenceDependenciesIfNeeded(DiagnosticEngine &diags, SourceFile *SF,
- DependencyTracker &depTracker,
- StringRef outputPath);
+bool emitReferenceDependencies(DiagnosticEngine &diags, SourceFile *SF,
+ DependencyTracker &depTracker,
+ StringRef outputPath);
} // end namespace swift
#endif
diff --git a/lib/FrontendTool/TBD.h b/lib/FrontendTool/TBD.h
index 446618a..bda0922 100644
--- a/lib/FrontendTool/TBD.h
+++ b/lib/FrontendTool/TBD.h
@@ -24,8 +24,8 @@
class FileUnit;
class FrontendOptions;
-bool writeTBD(ModuleDecl *M, bool hasMultipleIGMs,
- llvm::StringRef OutputFilename, llvm::StringRef installName);
+bool writeTBD(ModuleDecl *M, bool hasMultipleIGMs, StringRef OutputFilename,
+ llvm::StringRef installName);
bool inputFileKindCanHaveTBDValidated(InputFileKind kind);
bool validateTBD(ModuleDecl *M, llvm::Module &IRModule, bool hasMultipleIGMs,
bool diagnoseExtraSymbolsInTBD);
diff --git a/lib/IDE/Formatting.cpp b/lib/IDE/Formatting.cpp
index 18d7786..7ef1655 100644
--- a/lib/IDE/Formatting.cpp
+++ b/lib/IDE/Formatting.cpp
@@ -843,6 +843,9 @@
auto AddIndentFunc = [&] () {
auto Width = FmtOptions.UseTabs ? FmtOptions.TabWidth
: FmtOptions.IndentWidth;
+ // We don't need to add additional indentation if Width is zero.
+ if (!Width)
+ return;
// Increment indent.
ExpandedIndent += Width;
// Normalize indent to align on proper column indent width.
diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp
index 73f4dad..d635dfb 100644
--- a/lib/IRGen/GenDecl.cpp
+++ b/lib/IRGen/GenDecl.cpp
@@ -2252,6 +2252,17 @@
static llvm::GlobalVariable *createGOTEquivalent(IRGenModule &IGM,
llvm::Constant *global,
StringRef globalName) {
+ if (IGM.Triple.getObjectFormat() == llvm::Triple::COFF) {
+ if (cast<llvm::GlobalValue>(global)->hasDLLImportStorageClass()) {
+ llvm::GlobalVariable *GV =
+ new llvm::GlobalVariable(IGM.Module, global->getType(),
+ /*Constant=*/true,
+ llvm::GlobalValue::ExternalLinkage,
+ nullptr, llvm::Twine("__imp_") + globalName);
+ GV->setExternallyInitialized(true);
+ return GV;
+ }
+ }
auto gotEquivalent = new llvm::GlobalVariable(IGM.Module,
global->getType(),
@@ -2431,14 +2442,20 @@
Alignment alignment,
llvm::Type *defaultType,
ConstantReference::Directness forceIndirectness) {
+ // ObjC class references can always be directly referenced, even in
+ // the weird cases where we don't see a definition.
+ if (entity.isObjCClassRef()) {
+ auto value = getAddrOfObjCClassRef(
+ const_cast<ClassDecl *>(cast<ClassDecl>(entity.getDecl())));
+ return { cast<llvm::Constant>(value.getAddress()),
+ ConstantReference::Direct };
+ }
+
// Ensure the variable is at least forward-declared.
if (entity.isForeignTypeMetadataCandidate()) {
auto foreignCandidate
= getAddrOfForeignTypeMetadataCandidate(entity.getType());
(void)foreignCandidate;
- } else if (entity.isObjCClassRef()) {
- (void)getAddrOfObjCClassRef(
- const_cast<ClassDecl *>(cast<ClassDecl>(entity.getDecl())));
} else {
getAddrOfLLVMVariable(entity, alignment, ConstantInit(),
defaultType, DebugTypeInfo());
@@ -2498,47 +2515,40 @@
return {gotEquivalent, ConstantReference::Indirect};
}
-namespace {
-struct TypeEntityInfo {
- TypeMetadataRecordKind typeKind;
- LinkEntity entity;
- llvm::Type *defaultTy, *defaultPtrTy;
-
- /// Adjust the flags once we know whether the reference to this entity
- /// will be indirect.
- void adjustForKnownRef(ConstantReference &ref) {
- if (ref.isIndirect() &&
- typeKind == TypeMetadataRecordKind::DirectNominalTypeDescriptor)
- typeKind = TypeMetadataRecordKind::IndirectNominalTypeDescriptor;
- }
-};
-} // end anonymous namespace
-
-static TypeEntityInfo
-getTypeEntityInfo(IRGenModule &IGM, NominalTypeDecl *nom) {
- TypeMetadataRecordKind typeKind;
+TypeEntityReference
+IRGenModule::getTypeEntityReference(NominalTypeDecl *decl) {
+ TypeMetadataRecordKind kind;
Optional<LinkEntity> entity;
- llvm::Type *defaultTy, *defaultPtrTy;
+ llvm::Type *defaultTy;
- auto clas = dyn_cast<ClassDecl>(nom);
- if (clas && !clas->isForeign() && !hasKnownSwiftMetadata(IGM, clas)) {
+ auto clas = dyn_cast<ClassDecl>(decl);
+ if (clas && !clas->isForeign() && !hasKnownSwiftMetadata(*this, clas)) {
// A reference to an Objective-C class object.
assert(clas->isObjC() && "Must have an Objective-C class here");
- typeKind = TypeMetadataRecordKind::IndirectObjCClass;
- defaultTy = IGM.TypeMetadataPtrTy;
- defaultPtrTy = IGM.TypeMetadataPtrTy;
+ kind = TypeMetadataRecordKind::IndirectObjCClass;
+ defaultTy = TypeMetadataPtrTy;
entity = LinkEntity::forObjCClassRef(clas);
} else {
- // Conformances for generics and concrete subclasses of generics
- // are represented by referencing the nominal type descriptor.
- typeKind = TypeMetadataRecordKind::DirectNominalTypeDescriptor;
- entity = LinkEntity::forNominalTypeDescriptor(nom);
- defaultTy = IGM.TypeContextDescriptorTy;
- defaultPtrTy = IGM.TypeContextDescriptorPtrTy;
+ // A reference to a concrete type.
+ // TODO: consider using a symbolic reference (i.e. a symbol string
+ // to be looked up dynamically) for types defined outside the module.
+ kind = TypeMetadataRecordKind::DirectNominalTypeDescriptor;
+ entity = LinkEntity::forNominalTypeDescriptor(decl);
+ defaultTy = TypeContextDescriptorTy;
}
- return {typeKind, *entity, defaultTy, defaultPtrTy};
+ auto ref = getAddrOfLLVMVariableOrGOTEquivalent(
+ *entity, getPointerAlignment(), defaultTy);
+
+ // Adjust the flags now that we know whether the reference to this
+ // entity will be indirect.
+ if (ref.isIndirect()) {
+ assert(kind == TypeMetadataRecordKind::DirectNominalTypeDescriptor);
+ kind = TypeMetadataRecordKind::IndirectNominalTypeDescriptor;
+ }
+
+ return TypeEntityReference(kind, ref.getValue());
}
/// Form an LLVM constant for the relative distance between a reference
@@ -2682,16 +2692,12 @@
}
void addConformingType() {
- // Relative reference to the type entity info, with the type reference
- // kind mangled in the lower bits.
- auto typeEntity =
- getTypeEntityInfo(IGM, Conformance->getType()->getAnyNominal());
- auto typeRef =
- IGM.getAddrOfLLVMVariableOrGOTEquivalent(
- typeEntity.entity, IGM.getPointerAlignment(), typeEntity.defaultTy);
- typeEntity.adjustForKnownRef(typeRef);
- B.addRelativeAddress(typeRef.getValue());
- Flags = Flags.withTypeReferenceKind(typeEntity.typeKind);
+ // Add a relative reference to the type, with the type reference
+ // kind stored in the flags.
+ auto ref =
+ IGM.getTypeEntityReference(Conformance->getType()->getAnyNominal());
+ B.addRelativeAddress(ref.getValue());
+ Flags = Flags.withTypeReferenceKind(ref.getKind());
}
void addWitnessTable() {
@@ -2879,16 +2885,13 @@
SmallVector<llvm::Constant *, 8> elts;
for (auto type : RuntimeResolvableTypes) {
- auto typeEntity = getTypeEntityInfo(*this, type);
- auto typeRef = getAddrOfLLVMVariableOrGOTEquivalent(
- typeEntity.entity, getPointerAlignment(), typeEntity.defaultTy);
- typeEntity.adjustForKnownRef(typeRef);
+ auto ref = getTypeEntityReference(type);
// Form the relative address, with the type refernce kind in the low bits.
unsigned arrayIdx = elts.size();
llvm::Constant *relativeAddr =
- emitDirectRelativeReference(typeRef.getValue(), var, { arrayIdx, 0 });
- unsigned lowBits = static_cast<unsigned>(typeEntity.typeKind);
+ emitDirectRelativeReference(ref.getValue(), var, { arrayIdx, 0 });
+ unsigned lowBits = static_cast<unsigned>(ref.getKind());
if (lowBits != 0) {
relativeAddr = llvm::ConstantExpr::getAdd(relativeAddr,
llvm::ConstantInt::get(RelativeAddressTy, lowBits));
diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp
index 67d4113..92a6b49 100644
--- a/lib/IRGen/GenMeta.cpp
+++ b/lib/IRGen/GenMeta.cpp
@@ -2058,6 +2058,10 @@
return emitFromValueWitnessTable(IGF.IGM.Context.TheEmptyTupleType);
}
case MetatypeRepresentation::Thick:
+ if (isa<ExistentialMetatypeType>(type)) {
+ return emitFromTypeMetadata(type);
+ }
+ // Otherwise, this is a metatype that looks like a pointer.
case MetatypeRepresentation::ObjC:
// Thick metatypes look like pointers with spare bits.
return emitFromValueWitnessTable(
@@ -2692,19 +2696,23 @@
/// Flags to indicate Clang-imported declarations so we mangle them
/// consistently at runtime.
- uint16_t getClangImportedFlags() const {
+ void getClangImportedFlags(TypeContextDescriptorFlags &flags) const {
auto clangDecl = Mangle::ASTMangler::getClangDeclForMangling(Type);
if (!clangDecl)
- return 0;
+ return;
- if (isa<clang::TagDecl>(clangDecl))
- return (uint16_t)TypeContextDescriptorFlags::IsCTag;
+ if (isa<clang::TagDecl>(clangDecl)) {
+ flags.setIsCTag(true);
+ return;
+ }
if (isa<clang::TypedefNameDecl>(clangDecl)
- || isa<clang::ObjCCompatibleAliasDecl>(clangDecl))
- return (uint16_t)TypeContextDescriptorFlags::IsCTypedef;
+ || isa<clang::ObjCCompatibleAliasDecl>(clangDecl)) {
+ flags.setIsCTypedef(true);
+ return;
+ }
- return 0;
+ return;
}
// Subclasses should provide:
@@ -2811,15 +2819,23 @@
void addLayoutInfo() {
auto properties = getType()->getStoredProperties();
+
+ // uint32_t NumFields;
B.addInt32(std::distance(properties.begin(), properties.end()));
+
+ // uint32_t FieldOffsetVectorOffset;
B.addInt32(FieldVectorOffset / IGM.getPointerSize());
- B.addInt32(1); // struct always reflectable
addFieldTypes(IGM, getType(), properties);
}
uint16_t getKindSpecificFlags() {
- return getClangImportedFlags();
+ TypeContextDescriptorFlags flags;
+
+ flags.setIsReflectable(true); // struct always reflectable
+
+ getClangImportedFlags(flags);
+ return flags.getOpaqueValue();
}
};
@@ -2834,11 +2850,14 @@
Size GenericParamsOffset;
Size PayloadSizeOffset;
+ const EnumImplStrategy &Strategy;
public:
EnumContextDescriptorBuilder(IRGenModule &IGM, EnumDecl *Type,
RequireMetadata_t requireMetadata)
- : super(IGM, Type, requireMetadata)
+ : super(IGM, Type, requireMetadata),
+ Strategy(getEnumImplStrategy(IGM,
+ getType()->getDeclaredTypeInContext()->getCanonicalType()))
{
auto &layout = IGM.getMetadataLayout(getType());
GenericParamsOffset = layout.getStaticGenericRequirementsOffset();
@@ -2855,12 +2874,8 @@
}
void addLayoutInfo() {
- auto &strategy = getEnumImplStrategy(IGM,
- getType()->getDeclaredTypeInContext()->getCanonicalType());
-
-
// # payload cases in the low 24 bits, payload size offset in the high 8.
- unsigned numPayloads = strategy.getElementsWithPayload().size();
+ unsigned numPayloads = Strategy.getElementsWithPayload().size();
assert(numPayloads < (1<<24) && "too many payload elements for runtime");
assert(PayloadSizeOffset % IGM.getPointerAlignment() == Size(0)
&& "payload size not word-aligned");
@@ -2868,16 +2883,23 @@
= PayloadSizeOffset / IGM.getPointerSize();
assert(PayloadSizeOffsetInWords < 0x100 &&
"payload size offset too far from address point for runtime");
- B.addInt32(numPayloads | (PayloadSizeOffsetInWords << 24));
- // # empty cases
- B.addInt32(strategy.getElementsWithNoPayload().size());
- B.addInt32(strategy.isReflectable());
- addFieldTypes(IGM, strategy.getElementsWithPayload());
+ // uint32_t NumPayloadCasesAndPayloadSizeOffset;
+ B.addInt32(numPayloads | (PayloadSizeOffsetInWords << 24));
+
+ // uint32_t NumEmptyCases;
+ B.addInt32(Strategy.getElementsWithNoPayload().size());
+
+ addFieldTypes(IGM, Strategy.getElementsWithPayload());
}
uint16_t getKindSpecificFlags() {
- return getClangImportedFlags();
+ TypeContextDescriptorFlags flags;
+
+ flags.setIsReflectable(Strategy.isReflectable());
+
+ getClangImportedFlags(flags);
+ return flags.getOpaqueValue();
}
};
@@ -2891,6 +2913,8 @@
return cast<ClassDecl>(Type);
}
+ Optional<TypeEntityReference> SuperClassRef;
+
// Offsets of key fields in the metadata records.
Size FieldVectorOffset, GenericParamsOffset;
@@ -2910,6 +2934,10 @@
return;
}
+ if (auto superclassDecl = getType()->getSuperclassDecl()) {
+ SuperClassRef = IGM.getTypeEntityReference(superclassDecl);
+ }
+
auto &layout = IGM.getClassMetadataLayout(getType());
VTable = IGM.getSILModule().lookUpVTable(getType());
@@ -2936,19 +2964,26 @@
}
uint16_t getKindSpecificFlags() {
- uint16_t flags = 0;
+ TypeContextDescriptorFlags flags;
+
+ flags.setIsReflectable(true); // class is always reflectable
+
if (!getType()->isForeign()) {
if (VTableSize != 0)
- flags |= (uint16_t)TypeContextDescriptorFlags::HasVTable;
+ flags.class_setHasVTable(true);
auto &layout = IGM.getClassMetadataLayout(getType());
if (layout.hasResilientSuperclass())
- flags |= (uint16_t)TypeContextDescriptorFlags::HasResilientSuperclass;
+ flags.class_setHasResilientSuperclass(true);
+ }
+
+ if (SuperClassRef) {
+ flags.class_setSuperclassReferenceKind(SuperClassRef->getKind());
}
- flags |= getClangImportedFlags();
+ getClangImportedFlags(flags);
- return flags;
+ return flags.getOpaqueValue();
}
Size getGenericParamsOffset() {
@@ -3009,9 +3044,19 @@
void addLayoutInfo() {
auto properties = getType()->getStoredProperties();
+
+ // RelativeDirectPointer<const void, /*nullable*/ true> SuperClass;
+ if (SuperClassRef) {
+ B.addRelativeAddress(SuperClassRef->getValue());
+ } else {
+ B.addInt32(0);
+ }
+
+ // uint32_t NumFields;
B.addInt32(std::distance(properties.begin(), properties.end()));
+
+ // uint32_t FieldOffsetVectorOffset;
B.addInt32(FieldVectorOffset / IGM.getPointerSize());
- B.addInt32(1); // class is always reflectable
addFieldTypes(IGM, getType(), properties);
}
diff --git a/lib/IRGen/IRGen.cpp b/lib/IRGen/IRGen.cpp
index 6090a40..353faeb 100644
--- a/lib/IRGen/IRGen.cpp
+++ b/lib/IRGen/IRGen.cpp
@@ -665,8 +665,7 @@
}
std::pair<IRGenerator *, IRGenModule *>
-swift::irgen::createIRGenModule(SILModule *SILMod,
- StringRef OutputFilename,
+swift::irgen::createIRGenModule(SILModule *SILMod, StringRef OutputFilename,
StringRef MainInputFilenameForDebugInfo,
llvm::LLVMContext &LLVMContext) {
diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h
index 5d41c92..5b93a9a 100644
--- a/lib/IRGen/IRGenModule.h
+++ b/lib/IRGen/IRGenModule.h
@@ -97,6 +97,7 @@
class SourceLoc;
class SourceFile;
class Type;
+ enum class TypeMetadataRecordKind : unsigned;
namespace Lowering {
class TypeConverter;
@@ -413,6 +414,18 @@
}
};
+/// A reference to a declared type entity.
+class TypeEntityReference {
+ TypeMetadataRecordKind Kind;
+ llvm::Constant *Value;
+public:
+ TypeEntityReference(TypeMetadataRecordKind kind, llvm::Constant *value)
+ : Kind(kind), Value(value) {}
+
+ TypeMetadataRecordKind getKind() const { return Kind; }
+ llvm::Constant *getValue() const { return Value; }
+};
+
/// IRGenModule - Primary class for emitting IR for global declarations.
///
class IRGenModule {
@@ -1036,11 +1049,9 @@
///
/// The \p SF is the source file for which the llvm module is generated when
/// doing multi-threaded whole-module compilation. Otherwise it is null.
- IRGenModule(IRGenerator &irgen,
- std::unique_ptr<llvm::TargetMachine> &&target,
+ IRGenModule(IRGenerator &irgen, std::unique_ptr<llvm::TargetMachine> &&target,
SourceFile *SF, llvm::LLVMContext &LLVMContext,
- StringRef ModuleName,
- StringRef OutputFilename,
+ StringRef ModuleName, StringRef OutputFilename,
StringRef MainInputFilenameForDebugInfo);
~IRGenModule();
@@ -1112,6 +1123,8 @@
ConstantInitFuture init,
llvm::StringRef section = {});
+ TypeEntityReference getTypeEntityReference(NominalTypeDecl *D);
+
llvm::Constant *getAddrOfTypeMetadata(CanType concreteType);
ConstantReference getAddrOfTypeMetadata(CanType concreteType,
SymbolReferenceKind kind);
diff --git a/lib/Immediate/REPL.cpp b/lib/Immediate/REPL.cpp
index 8abe70d..401baf5 100644
--- a/lib/Immediate/REPL.cpp
+++ b/lib/Immediate/REPL.cpp
@@ -897,10 +897,11 @@
if (!ShouldRun)
return true;
+ const PrimarySpecificPaths PSPs =
+ CI.getPrimarySpecificPathsForAtMostOnePrimary();
// IRGen the current line(s).
// FIXME: We shouldn't need to use the global context here, but
// something is persisting across calls to performIRGeneration.
- const auto PSPs = CI.getPrimarySpecificPathsForAtMostOnePrimary();
auto LineModule = performIRGeneration(
IRGenOpts, REPLInputFile, std::move(sil), "REPLLine", PSPs,
getGlobalLLVMContext(), RC.CurIRGenElem);
diff --git a/lib/SIL/LoopInfo.cpp b/lib/SIL/LoopInfo.cpp
index 65271c9..6258d78 100644
--- a/lib/SIL/LoopInfo.cpp
+++ b/lib/SIL/LoopInfo.cpp
@@ -81,6 +81,9 @@
if (isa<ThrowInst>(I))
return false;
+ if (isa<BeginAccessInst>(I))
+ return false;
+
assert(I->isTriviallyDuplicatable() &&
"Code here must match isTriviallyDuplicatable in SILInstruction");
return true;
diff --git a/lib/SIL/SILFunctionType.cpp b/lib/SIL/SILFunctionType.cpp
index 014cce8..c6cc8c2 100644
--- a/lib/SIL/SILFunctionType.cpp
+++ b/lib/SIL/SILFunctionType.cpp
@@ -1250,6 +1250,7 @@
case SILFunctionType::Representation::WitnessMethod: {
switch (constant ? constant->kind : SILDeclRef::Kind::Func) {
case SILDeclRef::Kind::Initializer:
+ case SILDeclRef::Kind::EnumElement:
return getSILFunctionType(M, origType, substInterfaceType, extInfo,
DefaultInitializerConventions(), ForeignInfo(),
constant, witnessMethodConformance);
@@ -1272,7 +1273,6 @@
case SILDeclRef::Kind::StoredPropertyInitializer:
case SILDeclRef::Kind::IVarInitializer:
case SILDeclRef::Kind::IVarDestroyer:
- case SILDeclRef::Kind::EnumElement:
return getSILFunctionType(M, origType, substInterfaceType, extInfo,
getNormalArgumentConvention(M), ForeignInfo(),
constant, witnessMethodConformance);
diff --git a/lib/SIL/SILInstruction.cpp b/lib/SIL/SILInstruction.cpp
index e867b1e..8f52be8 100644
--- a/lib/SIL/SILInstruction.cpp
+++ b/lib/SIL/SILInstruction.cpp
@@ -1142,9 +1142,6 @@
/// additional handling. It is important to know this information when
/// you perform such optimizations like e.g. jump-threading.
bool SILInstruction::isTriviallyDuplicatable() const {
- if (isa<ThrowInst>(this))
- return false;
-
if (isa<AllocStackInst>(this) || isa<DeallocStackInst>(this)) {
return false;
}
@@ -1152,7 +1149,6 @@
if (ARI->canAllocOnStack())
return false;
}
-
if (isa<OpenExistentialAddrInst>(this) || isa<OpenExistentialRefInst>(this) ||
isa<OpenExistentialMetatypeInst>(this) ||
isa<OpenExistentialValueInst>(this) || isa<OpenExistentialBoxInst>(this) ||
@@ -1169,6 +1165,13 @@
if (MI->getMember().isForeign)
return false;
}
+ if (isa<ThrowInst>(this))
+ return false;
+
+ // BeginAccess defines the access scope entry point. All associated EndAccess
+ // instructions must directly operate on the BeginAccess.
+ if (isa<BeginAccessInst>(this))
+ return false;
return true;
}
diff --git a/lib/SIL/SILVerifier.cpp b/lib/SIL/SILVerifier.cpp
index 5982941..6a5be4e 100644
--- a/lib/SIL/SILVerifier.cpp
+++ b/lib/SIL/SILVerifier.cpp
@@ -329,11 +329,6 @@
delete Dominance;
}
- // Address-type block args must be prohibited whenever access markers are
- // present. Access markers are always present in raw SIL to diagnose exclusive
- // memory access. In canonical SIL, access markers are only present with
- // EnforceExclusivityDynamic.
- //
// FIXME: For sanity, address-type block args should be prohibited at all SIL
// stages. However, the optimizer currently breaks the invariant in three
// places:
@@ -341,8 +336,8 @@
// (sneaky jump threading).
// 2. Simplify CFG via Jump Threading.
// 3. Loop Rotation.
- // Once EnforceExclusivityDynamic is performant enough to be enabled by
- // default at -O, address-type blocks args can be prohibited unconditionally.
+ //
+ //
bool prohibitAddressBlockArgs() {
// If this function was deserialized from canonical SIL, this invariant may
// already have been violated regardless of this module's SIL stage or
@@ -352,12 +347,7 @@
return false;
SILModule &M = F.getModule();
- if (M.getStage() == SILStage::Raw)
- return true;
-
- // If dynamic enforcement is enabled, markers are present at -O so we
- // prohibit address block args.
- return M.getOptions().EnforceExclusivityDynamic;
+ return M.getStage() == SILStage::Raw;
}
void visitSILArgument(SILArgument *arg) {
diff --git a/lib/SILGen/LValue.h b/lib/SILGen/LValue.h
index 8977c80..dd6e015 100644
--- a/lib/SILGen/LValue.h
+++ b/lib/SILGen/LValue.h
@@ -166,6 +166,13 @@
virtual AccessKind getBaseAccessKind(SILGenFunction &SGF,
AccessKind accessKind) const = 0;
+ /// Is loading a value from this component guaranteed to have no observable
+ /// side effects?
+ virtual bool isLoadingPure() const {
+ // By default, don't assume any component is pure; components must opt-in.
+ return false;
+ }
+
virtual bool isRValue() const { return false; }
/// Returns the logical type-as-rvalue of the value addressed by the
@@ -363,6 +370,16 @@
bool isValid() const { return !Path.empty(); }
+ /// Is loading a value from this lvalue guaranteed to have no observable side
+ /// effects?
+ bool isLoadingPure() {
+ assert(isValid());
+ for (auto &component : Path)
+ if (!component->isLoadingPure())
+ return false;
+ return true;
+ }
+
/// Is this lvalue purely physical?
bool isPhysical() const {
assert(isValid());
diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp
index b832956..3f8a2f2 100644
--- a/lib/SILGen/SILGenApply.cpp
+++ b/lib/SILGen/SILGenApply.cpp
@@ -3788,6 +3788,10 @@
auto subs = callee.getSubstitutions();
auto upcastedSelf = uncurriedArgs.back();
+ // Make sure that upcasted self is at +1 since we are going to place it into a
+ // partial_apply.
+ upcastedSelf = upcastedSelf.ensurePlusOne(SGF, loc);
+
auto constantInfo = SGF.getConstantInfo(callee.getMethodName());
auto functionTy = constantInfo.getSILType();
ManagedValue superMethod;
@@ -3813,11 +3817,9 @@
if (constantInfo.SILFnType->isPolymorphic() && !subs.empty())
partialApplyTy = partialApplyTy.substGenericArgs(module, subs);
- SILValue partialApply =
- SGF.B.createPartialApply(loc, superMethod.getValue(), partialApplyTy,
- subs, {upcastedSelf.forward(SGF)}, closureTy);
+ ManagedValue pa = SGF.B.createPartialApply(loc, superMethod, partialApplyTy,
+ subs, {upcastedSelf}, closureTy);
assert(!closureTy.castTo<SILFunctionType>()->isNoEscape());
- ManagedValue pa = SGF.emitManagedRValueWithCleanup(partialApply);
firstLevelResult.value = RValue(SGF, loc, formalApplyType.getResult(), pa);
return firstLevelResult;
}
diff --git a/lib/SILGen/SILGenBridging.cpp b/lib/SILGen/SILGenBridging.cpp
index def5241..710efca 100644
--- a/lib/SILGen/SILGenBridging.cpp
+++ b/lib/SILGen/SILGenBridging.cpp
@@ -801,6 +801,7 @@
assert(formalBlockParams.size() == blockTy->getNumParameters());
assert(formalFuncParams.size() == funcTy->getNumParameters());
+ // Create the arguments for the call.
for (unsigned i : indices(funcTy->getParameters())) {
auto ¶m = funcTy->getParameters()[i];
CanType formalBlockParamTy = formalBlockParams[i];
@@ -808,12 +809,23 @@
auto paramTy = fnConv.getSILType(param);
SILValue v = entry->createFunctionArgument(paramTy);
+
+ // First get the managed parameter for this function.
auto mv = emitManagedParameter(SGF, loc, param, v);
SILType loweredBlockArgTy = blockTy->getParameters()[i].getSILStorageType();
- args.push_back(SGF.emitNativeToBridgedValue(loc, mv, formalFuncParamTy,
- formalBlockParamTy,
- loweredBlockArgTy));
+
+ // Then bridge the native value to its bridged variant.
+ mv = SGF.emitNativeToBridgedValue(loc, mv, formalFuncParamTy,
+ formalBlockParamTy, loweredBlockArgTy);
+
+ // Finally change ownership if we need to. We do not need to care about the
+ // case of a +1 parameter being passed to a +0 function since +1 parameters
+ // can be "instantaneously" borrowed at the call site.
+ if (blockTy->getParameters()[i].isConsumed()) {
+ mv = mv.ensurePlusOne(SGF, loc);
+ }
+ args.push_back(mv);
}
// Add the block argument.
@@ -1094,10 +1106,8 @@
};
auto conformances = getASTContext().AllocateCopy(conformanceArray);
- SILValue nativeError =
- B.createInitExistentialRef(loc, nativeErrorTy, bridgedErrorTy,
- bridgedError.forward(*this), conformances);
- return emitManagedRValueWithCleanup(nativeError);
+ return B.createInitExistentialRef(loc, nativeErrorTy, bridgedErrorTy,
+ bridgedError, conformances);
}
// Otherwise, we need to call a runtime function to potential substitute
diff --git a/lib/SILGen/SILGenConstructor.cpp b/lib/SILGen/SILGenConstructor.cpp
index d2aa8ad..946640b 100644
--- a/lib/SILGen/SILGenConstructor.cpp
+++ b/lib/SILGen/SILGenConstructor.cpp
@@ -57,20 +57,25 @@
RValue tuple(type);
for (auto fieldType : tupleTy.getElementTypes())
tuple.addElement(emitImplicitValueConstructorArg(SGF, loc, fieldType, DC));
-
return tuple;
- } else {
- auto &AC = SGF.getASTContext();
- auto VD = new (AC) ParamDecl(VarDecl::Specifier::Owned, SourceLoc(), SourceLoc(),
- AC.getIdentifier("$implicit_value"),
- SourceLoc(),
- AC.getIdentifier("$implicit_value"), Type(),
- DC);
- VD->setInterfaceType(interfaceType);
- SILValue arg =
- SGF.F.begin()->createFunctionArgument(SGF.getLoweredType(type), VD);
- return RValue(SGF, loc, type, SGF.emitManagedRValueWithCleanup(arg));
}
+
+ auto &AC = SGF.getASTContext();
+ auto VD = new (AC) ParamDecl(VarDecl::Specifier::Owned, SourceLoc(), SourceLoc(),
+ AC.getIdentifier("$implicit_value"),
+ SourceLoc(),
+ AC.getIdentifier("$implicit_value"), Type(),
+ DC);
+ VD->setInterfaceType(interfaceType);
+ SILFunctionArgument *arg =
+ SGF.F.begin()->createFunctionArgument(SGF.getLoweredType(type), VD);
+ ManagedValue mvArg;
+ if (arg->getArgumentConvention().isOwnedConvention()) {
+ mvArg = SGF.emitManagedRValueWithCleanup(arg);
+ } else {
+ mvArg = ManagedValue::forUnmanaged(arg);
+ }
+ return RValue(SGF, loc, type, mvArg);
}
static void emitImplicitValueConstructor(SILGenFunction &SGF,
diff --git a/lib/SILGen/SILGenConvert.cpp b/lib/SILGen/SILGenConvert.cpp
index 1dd9dfd..93f4be4 100644
--- a/lib/SILGen/SILGenConvert.cpp
+++ b/lib/SILGen/SILGenConvert.cpp
@@ -369,6 +369,9 @@
auto isNotPresentBB = createBasicBlock();
auto isPresentBB = createBasicBlock();
+ // All conversions happen at +1.
+ input = input.ensurePlusOne(*this, loc);
+
SwitchEnumBuilder SEBuilder(B, loc, input);
SILType noOptResultTy = resultTy.getOptionalObjectType();
assert(noOptResultTy);
diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp
index f6e935a..72d725b7 100644
--- a/lib/SILGen/SILGenExpr.cpp
+++ b/lib/SILGen/SILGenExpr.cpp
@@ -5371,6 +5371,8 @@
AccessKind kind) const override {
return kind;
}
+
+ virtual bool isLoadingPure() const override { return true; }
void set(SILGenFunction &SGF, SILLocation loc,
ArgumentSource &&value, ManagedValue base) && override {
@@ -5707,9 +5709,10 @@
FormalEvaluationScope scope(*this);
PostponedCleanup postpone(*this);
LValue lv = emitLValue(LE->getSubExpr(), AccessKind::Read);
- // If the lvalue is purely physical, then it won't have any side effects,
- // and we don't need to drill into it.
- if (lv.isPhysical())
+
+ // If loading from the lvalue is guaranteed to have no side effects, we
+ // don't need to drill into it.
+ if (lv.isLoadingPure())
return;
// If the last component is physical, then we just need to drill through
@@ -5725,6 +5728,39 @@
return;
}
+ auto findLoadThroughForceValueExprs = [](Expr *E,
+ SmallVectorImpl<ForceValueExpr *>
+ &forceValueExprs) -> LoadExpr * {
+ while (auto FVE = dyn_cast<ForceValueExpr>(E)) {
+ forceValueExprs.push_back(FVE);
+ E = FVE->getSubExpr();
+ }
+ return dyn_cast<LoadExpr>(E);
+ };
+
+ // Look through force unwrap(s) of an lvalue. If possible, we want to just to
+ // emit the precondition(s) without having to load the value.
+ SmallVector<ForceValueExpr *, 4> forceValueExprs;
+ if (auto *LE = findLoadThroughForceValueExprs(E, forceValueExprs)) {
+ FormalEvaluationScope scope(*this);
+ LValue lv = emitLValue(LE->getSubExpr(), AccessKind::Read);
+
+ ManagedValue value;
+ if (lv.isLastComponentPhysical()) {
+ value = emitAddressOfLValue(LE, std::move(lv), AccessKind::Read);
+ } else {
+ value = emitLoadOfLValue(LE, std::move(lv),
+ SGFContext::AllowImmediatePlusZero).getAsSingleValue(*this, LE);
+ }
+
+ for (auto &FVE : reversed(forceValueExprs)) {
+ const TypeLowering &optTL = getTypeLowering(FVE->getSubExpr()->getType());
+ value = emitCheckedGetOptionalValueFrom(
+ FVE, value, optTL, SGFContext::AllowImmediatePlusZero);
+ }
+ return;
+ }
+
// Otherwise, emit the result (to get any side effects), but produce it at +0
// if that allows simplification.
emitRValue(E, SGFContext::AllowImmediatePlusZero);
diff --git a/lib/SILGen/SILGenLValue.cpp b/lib/SILGen/SILGenLValue.cpp
index 4afdfba..74ac49b 100644
--- a/lib/SILGen/SILGenLValue.cpp
+++ b/lib/SILGen/SILGenLValue.cpp
@@ -581,7 +581,9 @@
: PhysicalPathComponent(typeData, RefElementKind),
Field(field), SubstFieldType(substFieldType),
IsNonAccessing(options.IsNonAccessing) {}
-
+
+ virtual bool isLoadingPure() const override { return true; }
+
ManagedValue offset(SILGenFunction &SGF, SILLocation loc, ManagedValue base,
AccessKind accessKind) && override {
assert(base.getType().isObject() &&
@@ -616,7 +618,9 @@
TupleElementComponent(unsigned elementIndex, LValueTypeData typeData)
: PhysicalPathComponent(typeData, TupleElementKind),
ElementIndex(elementIndex) {}
-
+
+ virtual bool isLoadingPure() const override { return true; }
+
ManagedValue offset(SILGenFunction &SGF, SILLocation loc, ManagedValue base,
AccessKind accessKind) && override {
assert(base && "invalid value for element base");
@@ -640,7 +644,9 @@
LValueTypeData typeData)
: PhysicalPathComponent(typeData, StructElementKind),
Field(field), SubstFieldType(substFieldType) {}
-
+
+ virtual bool isLoadingPure() const override { return true; }
+
ManagedValue offset(SILGenFunction &SGF, SILLocation loc, ManagedValue base,
AccessKind accessKind) && override {
assert(base && "invalid value for element base");
@@ -684,6 +690,8 @@
assert(getSubstFormalType() == openedArchetype);
}
+ virtual bool isLoadingPure() const override { return true; }
+
ManagedValue offset(SILGenFunction &SGF, SILLocation loc, ManagedValue base,
AccessKind accessKind) && override {
assert(base.getType().isExistentialType() &&
@@ -732,6 +740,8 @@
: LogicalPathComponent(typeData, OpenNonOpaqueExistentialKind),
OpenedArchetype(openedArchetype) {}
+ virtual bool isLoadingPure() const override { return true; }
+
AccessKind getBaseAccessKind(SILGenFunction &SGF,
AccessKind kind) const override {
// Always use the same access kind for the base.
@@ -832,6 +842,8 @@
assert(IsRValue || value.getType().isAddress());
}
+ virtual bool isLoadingPure() const override { return true; }
+
ManagedValue offset(SILGenFunction &SGF, SILLocation loc, ManagedValue base,
AccessKind accessKind) && override {
assert(!base && "value component must be root of lvalue path");
@@ -1821,6 +1833,8 @@
OrigType(origType)
{}
+ virtual bool isLoadingPure() const override { return true; }
+
RValue untranslate(SILGenFunction &SGF, SILLocation loc,
RValue &&rv, SGFContext c) && override {
return SGF.emitSubstToOrigValue(loc, std::move(rv), OrigType,
@@ -1860,6 +1874,8 @@
SubstToOrigKind)
{}
+ virtual bool isLoadingPure() const override { return true; }
+
RValue untranslate(SILGenFunction &SGF, SILLocation loc,
RValue &&rv, SGFContext c) && override {
return SGF.emitOrigToSubstValue(loc, std::move(rv), getOrigFormalType(),
@@ -1895,6 +1911,8 @@
: LogicalPathComponent(typeData, OwnershipKind) {
}
+ virtual bool isLoadingPure() const override { return true; }
+
AccessKind getBaseAccessKind(SILGenFunction &SGF,
AccessKind kind) const override {
// Always use the same access kind for the base.
diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp
index 5bcaf7a..23945be 100644
--- a/lib/Sema/CSBindings.cpp
+++ b/lib/Sema/CSBindings.cpp
@@ -134,19 +134,17 @@
!binding.BindingType->hasTypeVariable() && !binding.DefaultedProtocol &&
!binding.isDefaultableBinding() && allowJoinMeet) {
if (lastSupertypeIndex) {
- // Can we compute a join?
auto &lastBinding = Bindings[*lastSupertypeIndex];
auto lastType = lastBinding.BindingType->getWithoutSpecifierType();
auto bindingType = binding.BindingType->getWithoutSpecifierType();
+
auto join = Type::join(lastType, bindingType);
- if (join) {
- auto anyType = join->getASTContext().TheAnyType;
- if (!join->isEqual(anyType) || lastType->isEqual(anyType) ||
- bindingType->isEqual(anyType)) {
- // Replace the last supertype binding with the join. We're done.
- lastBinding.BindingType = join;
- return;
- }
+ if (join && !(*join)->isAny() &&
+ (!(*join)->getOptionalObjectType()
+ || !(*join)->getOptionalObjectType()->isAny())) {
+ // Replace the last supertype binding with the join. We're done.
+ lastBinding.BindingType = *join;
+ return;
}
}
diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp
index 999254c..4ed18d5 100644
--- a/lib/Sema/CSGen.cpp
+++ b/lib/Sema/CSGen.cpp
@@ -2998,15 +2998,10 @@
auto join =
Type::join(lhsMeta->getInstanceType(), rhsMeta->getInstanceType());
- // We will hit this assert today due to implemenation details
- // of Type::join, but the intent is to define join to always
- // result in a type.
- assert(join && "Unexpected null type returned from Type::join!");
-
if (!join)
return ErrorType::get(ctx);
- return MetatypeType::get(join, ctx)->getCanonicalType();
+ return MetatypeType::get(*join, ctx)->getCanonicalType();
}
case TypeOperation::JoinInout: {
@@ -3020,15 +3015,10 @@
auto join =
Type::join(lhsInOut, rhsMeta->getInstanceType());
- // We will hit this assert today due to implemenation details
- // of Type::join, but the intent is to define join to always
- // result in a type.
- assert(join && "Unexpected null type returned from Type::join!");
-
if (!join)
return ErrorType::get(ctx);
- return MetatypeType::get(join, ctx)->getCanonicalType();
+ return MetatypeType::get(*join, ctx)->getCanonicalType();
}
case TypeOperation::JoinMeta: {
@@ -3041,15 +3031,10 @@
auto join = Type::join(lhsMeta, rhsMeta);
- // We will hit this assert today due to implemenation details
- // of Type::join, but the intent is to define join to always
- // result in a type.
- assert(join && "Unexpected null type returned from Type::join!");
-
if (!join)
return ErrorType::get(ctx);
- return join;
+ return *join;
}
}
}
diff --git a/lib/Sema/TypeCheckCaptures.cpp b/lib/Sema/TypeCheckCaptures.cpp
index bf25431..3a8bcef 100644
--- a/lib/Sema/TypeCheckCaptures.cpp
+++ b/lib/Sema/TypeCheckCaptures.cpp
@@ -19,6 +19,7 @@
#include "swift/AST/ASTVisitor.h"
#include "swift/AST/ASTWalker.h"
#include "swift/AST/Decl.h"
+#include "swift/AST/ForeignErrorConvention.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/TypeWalker.h"
#include "swift/Basic/Defer.h"
@@ -743,9 +744,20 @@
// their context.
if (AFD && GenericParamCaptureLoc.isValid()) {
if (auto Clas = AFD->getParent()->getAsClassOrClassExtensionContext()) {
- if (Clas->isGenericContext() && Clas->hasClangNode()) {
+ if (Clas->usesObjCGenericsModel()) {
diagnose(AFD->getLoc(),
diag::objc_generic_extension_using_type_parameter);
+
+ // If it's possible, suggest adding @objc.
+ Optional<ForeignErrorConvention> errorConvention;
+ if (!AFD->isObjC() &&
+ isRepresentableInObjC(AFD, ObjCReason::MemberOfObjCMembersClass,
+ errorConvention)) {
+ diagnose(AFD->getLoc(),
+ diag::objc_generic_extension_using_type_parameter_try_objc)
+ .fixItInsert(AFD->getAttributeInsertionLoc(false), "@objc ");
+ }
+
diagnose(GenericParamCaptureLoc,
diag::objc_generic_extension_using_type_parameter_here);
}
diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp
index a63493c..77b6384 100644
--- a/lib/Sema/TypeCheckDecl.cpp
+++ b/lib/Sema/TypeCheckDecl.cpp
@@ -2627,7 +2627,7 @@
// Handle methods first.
if (auto overriddenFunc = dyn_cast<AbstractFunctionDecl>(overridden)) {
// Determine the selector of the overridden method.
- ObjCSelector overriddenSelector = overriddenFunc->getObjCSelector(&tc);
+ ObjCSelector overriddenSelector = overriddenFunc->getObjCSelector();
// Dig out the @objc attribute on the method, if it exists.
auto attr = decl->getAttrs().getAttribute<ObjCAttr>();
@@ -2867,7 +2867,7 @@
return None;
}
};
- auto sel = method->getObjCSelector(&TC);
+ auto sel = method->getObjCSelector();
if (auto diagID = isForbiddenSelector(sel)) {
auto diagInfo = getObjCMethodDiagInfo(method);
TC.diagnose(method, *diagID,
@@ -6066,14 +6066,13 @@
bool objCMatch = false;
if (parentDecl->isObjC() && decl->isObjC()) {
if (method) {
- if (method->getObjCSelector(&TC)
- == parentMethod->getObjCSelector(&TC))
+ if (method->getObjCSelector() == parentMethod->getObjCSelector())
objCMatch = true;
} else if (auto *parentSubscript =
dyn_cast<SubscriptDecl>(parentStorage)) {
// If the subscript kinds don't match, it's not an override.
- if (subscript->getObjCSubscriptKind(&TC)
- == parentSubscript->getObjCSubscriptKind(&TC))
+ if (subscript->getObjCSubscriptKind()
+ == parentSubscript->getObjCSubscriptKind())
objCMatch = true;
}
@@ -6170,11 +6169,11 @@
if (objCMatch) {
if (method) {
TC.diagnose(decl, diag::override_objc_type_mismatch_method,
- method->getObjCSelector(&TC), declTy);
+ method->getObjCSelector(), declTy);
} else {
TC.diagnose(decl, diag::override_objc_type_mismatch_subscript,
static_cast<unsigned>(
- subscript->getObjCSubscriptKind(&TC)),
+ subscript->getObjCSubscriptKind()),
declTy);
}
TC.diagnose(parentDecl, diag::overridden_here_with_type,
diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp
index 598e5b6..879d0e0 100644
--- a/lib/Sema/TypeCheckType.cpp
+++ b/lib/Sema/TypeCheckType.cpp
@@ -3835,7 +3835,7 @@
return false;
// Make sure we know how to map the selector appropriately.
- if (Result && SD->getObjCSubscriptKind(this) == ObjCSubscriptKind::None) {
+ if (Result && SD->getObjCSubscriptKind() == ObjCSubscriptKind::None) {
SourceRange IndexRange = SD->getIndices()->getSourceRange();
diagnose(SD->getLoc(), diag::objc_invalid_subscript_key_type,
getObjCDiagnosticAttrKind(Reason), IndicesType)
diff --git a/stdlib/public/SwiftShims/LibcShims.h b/stdlib/public/SwiftShims/LibcShims.h
index 398bde1..f964cd5 100644
--- a/stdlib/public/SwiftShims/LibcShims.h
+++ b/stdlib/public/SwiftShims/LibcShims.h
@@ -38,7 +38,7 @@
#elif defined(_WIN32)
#if defined(_M_ARM) || defined(_M_IX86)
typedef int __swift_ssize_t;
-#elif defined(_M_X64)
+#elif defined(_M_X64) || defined(_M_ARM64)
typedef long long int __swift_ssize_t;
#else
#error unsupported machine type
diff --git a/stdlib/public/core/ManagedBuffer.swift b/stdlib/public/core/ManagedBuffer.swift
index e5a8283..4be4a71 100644
--- a/stdlib/public/core/ManagedBuffer.swift
+++ b/stdlib/public/core/ManagedBuffer.swift
@@ -118,9 +118,8 @@
public final func withUnsafeMutablePointers<R>(
_ body: (UnsafeMutablePointer<Header>, UnsafeMutablePointer<Element>) throws -> R
) rethrows -> R {
- let r = try body(headerAddress, firstElementAddress)
- _fixLifetime(self)
- return r
+ defer { _fixLifetime(self) }
+ return try body(headerAddress, firstElementAddress)
}
/// The stored `Header` instance.
@@ -304,9 +303,8 @@
public func withUnsafeMutablePointers<R>(
_ body: (UnsafeMutablePointer<Header>, UnsafeMutablePointer<Element>) throws -> R
) rethrows -> R {
- let r = try body(_headerPointer, _elementPointer)
- _fixLifetime(_nativeBuffer)
- return r
+ defer { _fixLifetime(_nativeBuffer) }
+ return try body(_headerPointer, _elementPointer)
}
/// Returns `true` iff `self` holds the only strong reference to its buffer.
diff --git a/stdlib/public/core/NormalizedCodeUnitIterator.swift b/stdlib/public/core/NormalizedCodeUnitIterator.swift
index cc61452..901ced1 100644
--- a/stdlib/public/core/NormalizedCodeUnitIterator.swift
+++ b/stdlib/public/core/NormalizedCodeUnitIterator.swift
@@ -128,8 +128,7 @@
index += 1
bufferIndex += 1
} while unmanagedString.hasNormalizationBoundary(
- after: index - 1,
- count: unmanagedString.count) == false
+ after: index - 1) == false
return bufferIndex
}
diff --git a/stdlib/public/core/StringComparison.swift b/stdlib/public/core/StringComparison.swift
index 95dbd1b..680130d 100644
--- a/stdlib/public/core/StringComparison.swift
+++ b/stdlib/public/core/StringComparison.swift
@@ -803,7 +803,7 @@
if idx+1 == other.count {
return _lexicographicalCompare(selfASCIIChar, otherCU)
}
- if _fastPath(other.hasNormalizationBoundary(after: idx, count: other.count)) {
+ if _fastPath(other.hasNormalizationBoundary(after: idx)) {
return _lexicographicalCompare(selfASCIIChar, otherCU)
}
}
@@ -843,9 +843,9 @@
}
extension _UnmanagedString where CodeUnit == UInt16 {
- func hasNormalizationBoundary(after index: Int, count: Int) -> Bool {
+ func hasNormalizationBoundary(after index: Int) -> Bool {
let nextIndex = index + 1
- if nextIndex >= count {
+ if nextIndex >= self.count {
return true
}
@@ -1115,8 +1115,8 @@
&selfOutputBuffer, selfLength,
&otherOutputBuffer, otherLength)
{
- let selfSlice = self[selfSegmentEndIdx...]
- let otherSlice = other[otherSegmentEndIdx...]
+ let selfSlice = self[selfSegmentStartIdx...]
+ let otherSlice = other[otherSegmentStartIdx...]
return selfSlice._compareStringsPathological(other: otherSlice)
}
diff --git a/stdlib/public/runtime/CMakeLists.txt b/stdlib/public/runtime/CMakeLists.txt
index 8424276..3522c09 100644
--- a/stdlib/public/runtime/CMakeLists.txt
+++ b/stdlib/public/runtime/CMakeLists.txt
@@ -102,6 +102,10 @@
set_target_properties(swiftImageInspectionShared PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "${SWIFTSTATICLIB_DIR}/${lowercase_sdk}")
+ swift_install_in_component(stdlib
+ TARGETS swiftImageInspectionShared
+ DESTINATION "lib/swift_static/${lowercase_sdk}")
+
# Generate the static-executable-args.lnk file used for ELF systems (eg linux)
set(linkfile "${lowercase_sdk}/static-executable-args.lnk")
add_custom_command_target(swift_static_binary_${sdk}_args
diff --git a/stdlib/public/runtime/Demangle.cpp b/stdlib/public/runtime/Demangle.cpp
index 8130e69..0cf3b33 100644
--- a/stdlib/public/runtime/Demangle.cpp
+++ b/stdlib/public/runtime/Demangle.cpp
@@ -151,10 +151,10 @@
// Override the node kind if this is a Clang-imported type so we give it
// a stable mangling.
- auto typeFlags = type->Flags.getKindSpecificFlags();
- if (typeFlags & (uint16_t)TypeContextDescriptorFlags::IsCTag) {
+ auto typeFlags = type->getTypeContextDescriptorFlags();
+ if (typeFlags.isCTag()) {
nodeKind = Node::Kind::Structure;
- } else if (typeFlags & (uint16_t)TypeContextDescriptorFlags::IsCTypedef) {
+ } else if (typeFlags.isCTypedef()) {
nodeKind = Node::Kind::TypeAlias;
}
diff --git a/stdlib/public/runtime/ImageInspectionCOFF.cpp b/stdlib/public/runtime/ImageInspectionCOFF.cpp
index a14311d..2b60233 100644
--- a/stdlib/public/runtime/ImageInspectionCOFF.cpp
+++ b/stdlib/public/runtime/ImageInspectionCOFF.cpp
@@ -82,6 +82,20 @@
}
}
+void swift::initializeTypeFieldLookup() {
+ const swift::MetadataSections *sections = registered;
+ while (true) {
+ const swift::MetadataSections::Range &fields = sections->swift5_fieldmd;
+ if (fields.length)
+ addImageTypeFieldDescriptorBlockCallback(
+ reinterpret_cast<void *>(fields.start), fields.length);
+
+ if (sections->next == registered)
+ break;
+ sections = sections->next;
+ }
+}
+
SWIFT_RUNTIME_EXPORT
void swift_addNewDSOImage(const void *addr) {
const swift::MetadataSections *sections =
diff --git a/stdlib/public/runtime/MetadataLookup.cpp b/stdlib/public/runtime/MetadataLookup.cpp
index f03716c..273877b 100644
--- a/stdlib/public/runtime/MetadataLookup.cpp
+++ b/stdlib/public/runtime/MetadataLookup.cpp
@@ -187,7 +187,6 @@
default:
if (auto type = llvm::dyn_cast<TypeContextDescriptor>(context)) {
- auto flags = type->Flags.getKindSpecificFlags();
switch (node->getKind()) {
// If the mangled name doesn't indicate a type kind, accept anything.
// Otherwise, try to match them up.
@@ -195,7 +194,7 @@
break;
case Demangle::Node::Kind::Structure:
if (type->getKind() != ContextDescriptorKind::Struct
- && !(flags & (uint16_t)TypeContextDescriptorFlags::IsCTag))
+ && !type->getTypeContextDescriptorFlags().isCTag())
return false;
break;
case Demangle::Node::Kind::Class:
@@ -207,7 +206,7 @@
return false;
break;
case Demangle::Node::Kind::TypeAlias:
- if (!(flags & (uint16_t)TypeContextDescriptorFlags::IsCTypedef))
+ if (!type->getTypeContextDescriptorFlags().isCTypedef())
return false;
break;
diff --git a/stdlib/public/runtime/ReflectionMirror.mm b/stdlib/public/runtime/ReflectionMirror.mm
index 8910654..2781eb3 100644
--- a/stdlib/public/runtime/ReflectionMirror.mm
+++ b/stdlib/public/runtime/ReflectionMirror.mm
@@ -39,6 +39,44 @@
#include <objc/runtime.h>
#endif
+#if defined(_WIN32)
+#include <stdarg.h>
+
+namespace {
+int asprintf(char **strp, const char *fmt, ...) {
+ va_list argp0, argp1;
+
+ va_start(argp0, fmt);
+ va_copy(argp1, argp0);
+
+ int length = _vscprintf(fmt, argp0);
+
+ *strp = reinterpret_cast<char *>(malloc(length + 1));
+ if (*strp == nullptr)
+ return -1;
+
+ length = _vsnprintf(*strp, length, fmt, argp1);
+
+ va_end(argp0);
+ va_end(argp1);
+
+ return length;
+}
+
+char *strndup(const char *s, size_t n) {
+ size_t length = std::min(strlen(s), n);
+
+ char *buffer = reinterpret_cast<char *>(malloc(length + 1));
+ if (buffer == nullptr)
+ return buffer;
+
+ strncpy(buffer, s, length);
+ buffer[length] = '\0';
+ return buffer;
+}
+}
+#endif
+
using namespace swift;
#if SWIFT_OBJC_INTEROP
@@ -268,7 +306,7 @@
bool isReflectable() {
const auto *Enum = static_cast<const EnumMetadata *>(type);
const auto &Description = Enum->getDescription();
- return Description->IsReflectable;
+ return Description->getTypeContextDescriptorFlags().isReflectable();
}
const char *getInfo(unsigned *tagPtr = nullptr,
diff --git a/test/AutolinkExtract/import_archive.swift b/test/AutolinkExtract/import_archive.swift
index 16e7b57..e578bce 100644
--- a/test/AutolinkExtract/import_archive.swift
+++ b/test/AutolinkExtract/import_archive.swift
@@ -1,4 +1,3 @@
-// REQUIRES: rdar37605557
// RUN: %empty-directory(%t)
// RUN: %target-swiftc_driver -emit-library -emit-module -emit-module-path %t/empty.swiftmodule -module-name empty -module-link-name empty %S/empty.swift
// RUN: %target-swiftc_driver -c %s -I %t -o %t/import_experimental.o
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index fefbe22..64800a1 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -236,8 +236,8 @@
# These two directories may contain the same libraries,
# but upload both to device just in case. Duplicates will be
# overwritten, and uploading doesn't take very long anyway.
- "${SWIFT_ANDROID_ICU_UC}"
- "${SWIFT_ANDROID_ICU_I18N}")
+ "${SWIFT_ANDROID_${ARCH}_ICU_UC}"
+ "${SWIFT_ANDROID_${ARCH}_ICU_I18N}")
endif()
add_custom_target("upload-stdlib${VARIANT_SUFFIX}"
${command_upload_stdlib}
diff --git a/test/ClangImporter/objc_bridging_generics.swift b/test/ClangImporter/objc_bridging_generics.swift
index 6fee23f..8ac6c6c 100644
--- a/test/ClangImporter/objc_bridging_generics.swift
+++ b/test/ClangImporter/objc_bridging_generics.swift
@@ -123,7 +123,7 @@
_ = T.self // expected-note{{used here}}
}
// expected-error@+1{{extension of a generic Objective-C class cannot access the class's generic parameters}}
-@objc func usesGenericParamE(_ x: Int) {
+ @objc func usesGenericParamE(_ x: Int) {
_ = x as? T // expected-note{{used here}}
}
// expected-error@+1{{extension of a generic Objective-C class cannot access the class's generic parameters}}
@@ -249,18 +249,22 @@
}
+ // expected-note@+2{{add '@objc' to allow uses of 'self' within the function body}}{{3-3=@objc }}
// expected-error@+1{{extension of a generic Objective-C class cannot access the class's generic parameters}}
func usesGenericParamA(_ x: T) {
_ = T(noise: x) // expected-note{{used here}}
}
+ // expected-note@+2{{add '@objc' to allow uses of 'self' within the function body}}{{3-3=@objc }}
// expected-error@+1{{extension of a generic Objective-C class cannot access the class's generic parameters}}
func usesGenericParamB() {
_ = T.create() // expected-note{{used here}}
}
+ // expected-note@+2{{add '@objc' to allow uses of 'self' within the function body}}{{3-3=@objc }}
// expected-error@+1{{extension of a generic Objective-C class cannot access the class's generic parameters}}
func usesGenericParamC() {
_ = T.apexPredator // expected-note{{used here}}
}
+ // expected-note@+2{{add '@objc' to allow uses of 'self' within the function body}}{{3-3=@objc }}
// expected-error@+1{{extension of a generic Objective-C class cannot access the class's generic parameters}}
func usesGenericParamD(_ x: T) {
T.apexPredator = x // expected-note{{used here}}
@@ -269,6 +273,7 @@
// rdar://problem/27796375 -- allocating init entry points for ObjC
// initializers are generated as true Swift generics, so reify type
// parameters.
+ // expected-note@+2{{add '@objc' to allow uses of 'self' within the function body}}{{3-3=@objc }}
// expected-error@+1{{extension of a generic Objective-C class cannot access the class's generic parameters}}
func usesGenericParamE(_ x: T) {
_ = GenericClass(thing: x) // expected-note{{used here}}
diff --git a/test/Frontend/batch-mode.swift b/test/Frontend/batch-mode.swift
new file mode 100644
index 0000000..8706761f
--- /dev/null
+++ b/test/Frontend/batch-mode.swift
@@ -0,0 +1,16 @@
+// RUN: %empty-directory(%t)
+// RUN: echo 'public func a() { }' >%t/a.swift
+// RUN: echo 'public func b() { }' >%t/b.swift
+// RUN: echo 'public func c() { }' >%t/c.swift
+// RUN: echo 'public func main() {a(); b(); c()}' >%t/main.swift
+// RUN: %target-swift-frontend -c -enable-batch-mode -bypass-batch-mode-checks -module-name foo -primary-file %t/a.swift -primary-file %t/b.swift -primary-file %t/c.swift -primary-file %t/main.swift -o %t/a.o -o %t/b.o -o %t/c.o -o %t/main.o
+//
+// RUN: llvm-objdump -t %t/a.o | swift-demangle | %FileCheck -check-prefix=CHECK-A %s
+// RUN: llvm-objdump -t %t/b.o | swift-demangle | %FileCheck -check-prefix=CHECK-B %s
+// RUN: llvm-objdump -t %t/c.o | swift-demangle | %FileCheck -check-prefix=CHECK-C %s
+// RUN: llvm-objdump -t %t/main.o | swift-demangle | %FileCheck -check-prefix=CHECK-MAIN %s
+//
+// CHECK-A: foo.a() -> ()
+// CHECK-B: foo.b() -> ()
+// CHECK-C: foo.c() -> ()
+// CHECK-MAIN: foo.main() -> ()
diff --git a/test/IRGen/cf.sil b/test/IRGen/cf.sil
index f9cd361..bb9a108 100644
--- a/test/IRGen/cf.sil
+++ b/test/IRGen/cf.sil
@@ -28,7 +28,7 @@
// CHECK-64: @"$SSo24CCMutableRefrigeratorRefaMn" = linkonce_odr hidden constant
// -- is imported C typedef, is class, is nonunique
-// CHECK-64-SAME: <i32 0x1000_0010>
+// CHECK-64-SAME: <i32 0x0006_0010>
// CHECK-64-SAME: [[MUTABLE_REFRIGERATOR_NAME]]
// CHECK-64: @"$SSo24CCMutableRefrigeratorRefaN" = linkonce_odr hidden global <{ {{.*}} }> <{
diff --git a/test/IRGen/class_metadata.swift b/test/IRGen/class_metadata.swift
new file mode 100644
index 0000000..3f927a3
--- /dev/null
+++ b/test/IRGen/class_metadata.swift
@@ -0,0 +1,115 @@
+// RUN: %target-swift-frontend -emit-ir %s | %FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-%target-ptrsize
+
+class A {}
+
+// CHECK: [[A_NAME:@.*]] = private constant [2 x i8] c"A\00"
+// CHECK-LABEL: @"$S14class_metadata1ACMn" =
+// Flags. -2147221424 == 0x8004_0050 == HasVTable | Reflectable | Unique | Class
+// CHECK-SAME: i32 -2147221424,
+// Parent.
+// CHECK-SAME: i32 {{.*}} @"$S14class_metadataMXM"
+// Name.
+// CHECK-SAME: i32 {{.*}} [[A_NAME]]
+// Metadata access function.
+// CHECK-SAME: i32 {{.*}} @"$S14class_metadata1ACMa"
+// Superclass.
+// CHECK-SAME: i32 0,
+// Field count.
+// CHECK-SAME: i32 0,
+// Field offset vector offset.
+// CHECK-32-SAME: i32 14,
+// CHECK-64-SAME: i32 11,
+// V-table offset.
+// CHECK-32-SAME: i32 13,
+// CHECK-64-SAME: i32 10,
+// V-table length.
+// CHECK-SAME: i32 1,
+// V-table entry #1: invocation function.
+// CHECK-SAME: @"$S14class_metadata1ACACycfc"
+// V-table entry #1: flags.
+// CHECK-SAME: i32 1 } }>, section
+
+class B : A {}
+
+// CHECK: [[B_NAME:@.*]] = private constant [2 x i8] c"B\00"
+// CHECK-LABEL: @"$S14class_metadata1BCMn" =
+// Flags. 262224 == 0x0004_0050 == Reflectable | Unique | Class
+// CHECK-SAME: i32 262224,
+// Parent.
+// CHECK-SAME: i32 {{.*}} @"$S14class_metadataMXM"
+// Name.
+// CHECK-SAME: i32 {{.*}} [[B_NAME]]
+// Metadata access function.
+// CHECK-SAME: i32 {{.*}} @"$S14class_metadata1BCMa"
+// Superclass.
+// CHECK-SAME: i32 {{.*}} @"$S14class_metadata1ACMn"
+// Field count.
+// CHECK-SAME: i32 0,
+// Field offset vector offset.
+// CHECK-32-SAME: i32 14 }>, section
+// CHECK-64-SAME: i32 11 }>, section
+
+class C<T> : B {}
+
+// CHECK: [[C_NAME:@.*]] = private constant [2 x i8] c"C\00"
+// CHECK-LABEL: @"$S14class_metadata1CCMn" =
+// Flags. 262352 == 0x0004_00d0 == Reflectable | Generic | Unique | Class
+// CHECK-SAME: i32 262352,
+// Parent.
+// CHECK-SAME: i32 {{.*}} @"$S14class_metadataMXM"
+// Name.
+// CHECK-SAME: i32 {{.*}} [[C_NAME]]
+// Metadata access function.
+// CHECK-SAME: i32 {{.*}} @"$S14class_metadata1CCMa"
+// Superclass.
+// CHECK-SAME: i32 {{.*}} @"$S14class_metadata1BCMn"
+// Field count.
+// CHECK-SAME: i32 0,
+// Field offset vector offset.
+// CHECK-32-SAME: i32 15,
+// CHECK-64-SAME: i32 12,
+// Argument offset.
+// CHECK-32-SAME: i32 14,
+// CHECK-64-SAME: i32 11,
+// Instantiation function.
+// CHECK-SAME: i32 {{.*}} @"$S14class_metadata1CCMi"
+// Instantiation cache.
+// CHECK-SAME: i32 {{.*}} @"$S14class_metadata1CCMI"
+// Generic parameter count.
+// CHECK-SAME: i32 1,
+// Generic requirement count.
+// CHECK-SAME: i32 0,
+// Key generic arguments count.
+// CHECK-SAME: i32 1,
+// Extra generic arguments count.
+// CHECK-SAME: i32 0,
+// Generic parameter descriptor #1: flags. -128 == 0x80 == Key
+// CHECK-SAME: i8 -128,
+/// Padding.
+// CHECK-SAME: i8 0,
+// CHECK-SAME: i8 0,
+// CHECK-SAME: i8 0 }>, section
+
+// For stupid reasons, when we declare the superclass after the subclass,
+// we end up using an indirect reference to the nominal type descriptor.
+class D : E {}
+
+// CHECK: [[D_NAME:@.*]] = private constant [2 x i8] c"D\00"
+// CHECK-LABEL: @"$S14class_metadata1DCMn" =
+// Flags. 268697680 == 0x1004_0050 == Reflectable | IndirectSuperclass | Unique | Class
+// CHECK-SAME: i32 268697680,
+// Parent.
+// CHECK-SAME: i32 {{.*}} @"$S14class_metadataMXM"
+// Name.
+// CHECK-SAME: i32 {{.*}} [[D_NAME]]
+// Metadata access function.
+// CHECK-SAME: i32 {{.*}} @"$S14class_metadata1DCMa"
+// Superclass.
+// CHECK-SAME: i32 {{.*}} @"got.$S14class_metadata1ECMn
+// Field count.
+// CHECK-SAME: i32 0,
+// Field offset vector offset.
+// CHECK-32-SAME: i32 14 }>, section
+// CHECK-64-SAME: i32 11 }>, section
+
+class E {}
diff --git a/test/IRGen/class_resilience.swift b/test/IRGen/class_resilience.swift
index 776eac4..da4709b 100644
--- a/test/IRGen/class_resilience.swift
+++ b/test/IRGen/class_resilience.swift
@@ -29,8 +29,8 @@
// CHECK: [[RESILIENTCHILD_NAME:@.*]] = private constant [15 x i8] c"ResilientChild\00"
// CHECK: @"$S16class_resilience14ResilientChildCMn" = {{(protected )?}}constant <{{.*}}> <{
-// -- flags: class, unique, has vtable, has resilient superclass
-// CHECK-SAME: <i32 0xC000_0050>
+// -- flags: class, unique, reflectable, has vtable, has resilient superclass
+// CHECK-SAME: <i32 0xD004_0050>
// -- name:
// CHECK-SAME: [15 x i8]* [[RESILIENTCHILD_NAME]]
// -- num fields
diff --git a/test/IRGen/dllimport.swift b/test/IRGen/dllimport.swift
index c24285c..b46c279 100644
--- a/test/IRGen/dllimport.swift
+++ b/test/IRGen/dllimport.swift
@@ -52,7 +52,7 @@
// CHECK-OPT-DAG: declare dllimport %swift.refcounted* @swift_retain(%swift.refcounted* returned) local_unnamed_addr
// CHECK-OPT-DAG: @"$SBoWV" = external dllimport global i8*
// CHECK-OPT-DAG: @"$S9dllexport1cCN" = external dllimport global %swift.type
-// CHECK-OPT-DAG: @"$S9dllexport1pMp" = external dllimport global %swift.protocol
+// CHECK-OPT-DAG: @"__imp_$S9dllexport1pMp" = external externally_initialized constant %swift.protocol*
// CHECK-OPT-DAG: declare dllimport swiftcc i8* @"$S9dllexport2ciAA1cCvau"()
// CHECK-OPT-DAG: declare dllimport %swift.type* @"$S9dllexport1cCMa"()
// CHECK-OPT-DAG: declare dllimport void @swift_deallocClassInstance(%swift.refcounted*, i32, i32)
diff --git a/test/IRGen/generic_classes.sil b/test/IRGen/generic_classes.sil
index 2426a4c..3700dc5 100644
--- a/test/IRGen/generic_classes.sil
+++ b/test/IRGen/generic_classes.sil
@@ -15,8 +15,8 @@
// CHECK: [[ROOTGENERIC_NAME:@.*]] = private constant [12 x i8] c"RootGeneric\00"
// CHECK-LABEL: @"$S15generic_classes11RootGenericCMn" =
-// -- flags: class, generic, unique, has vtable
-// CHECK-SAME: <i32 0x8000_00D0>
+// -- flags: class, generic, unique, reflectable, has vtable
+// CHECK-SAME: <i32 0x8004_00D0>
// -- name
// CHECK-SAME: [12 x i8]* [[ROOTGENERIC_NAME]]
// -- num fields
@@ -54,8 +54,8 @@
// FIXME: Strings should be unnamed_addr. rdar://problem/22674524
// CHECK: [[ROOTNONGENERIC_NAME:@.*]] = private constant [15 x i8] c"RootNonGeneric\00"
// CHECK: @"$S15generic_classes14RootNonGenericCMn" = hidden constant <{ {{.*}} %swift.method_descriptor }> <{
-// -- flags: class, unique, has vtable
-// CHECK-SAME: <i32 0x8000_0050>
+// -- flags: class, unique, has vtable, reflectable
+// CHECK-SAME: <i32 0x8004_0050>
// -- name
// CHECK-SAME: [15 x i8]* [[ROOTNONGENERIC_NAME]]
// -- num fields
diff --git a/test/IRGen/generic_structs.sil b/test/IRGen/generic_structs.sil
index caf5d4f..7af64cd 100644
--- a/test/IRGen/generic_structs.sil
+++ b/test/IRGen/generic_structs.sil
@@ -21,8 +21,8 @@
// FIXME: Strings should be unnamed_addr. rdar://problem/22674524
// CHECK: [[SINGLEDYNAMIC_NAME:@.*]] = private constant [14 x i8] c"SingleDynamic\00"
// CHECK: @"$S15generic_structs13SingleDynamicVMn" = hidden constant
-// -- flags: struct, unique, generic
-// CHECK-SAME: <i32 0x0000_00D1>
+// -- flags: struct, unique, generic, reflectable
+// CHECK-SAME: <i32 0x0004_00D1>
// -- name
// CHECK-SAME: [14 x i8]* [[SINGLEDYNAMIC_NAME]]
// -- field count
@@ -51,8 +51,8 @@
// FIXME: Strings should be unnamed_addr. rdar://problem/22674524
// CHECK: [[DYNAMICWITHREQUIREMENTS_NAME:@.*]] = private constant [24 x i8] c"DynamicWithRequirements\00"
// CHECK: @"$S15generic_structs23DynamicWithRequirementsVMn" = hidden constant <{ {{.*}} i32 }> <{
-// -- flags: struct, unique, generic
-// CHECK-SAME: <i32 0x0000_00D1>
+// -- flags: struct, unique, generic, reflectable
+// CHECK-SAME: <i32 0x0004_00D1>
// -- name
// CHECK-SAME: [24 x i8]* [[DYNAMICWITHREQUIREMENTS_NAME]]
// -- field count
diff --git a/test/IRGen/generic_vtable.swift b/test/IRGen/generic_vtable.swift
index 1fb3376..dd5c8f0 100644
--- a/test/IRGen/generic_vtable.swift
+++ b/test/IRGen/generic_vtable.swift
@@ -23,8 +23,8 @@
//// Nominal type descriptor for 'Base' does not have any method descriptors.
// CHECK-LABEL: @"$S14generic_vtable4BaseCMn" = {{(protected )?}}constant
-// -- flags: has vtable, is class, is unique
-// CHECK-SAME: <i32 0x8000_0050>,
+// -- flags: has vtable, reflectable, is class, is unique
+// CHECK-SAME: <i32 0x8004_0050>,
// -- vtable offset
// CHECK-SAME: i32 10,
// -- vtable size
@@ -48,8 +48,8 @@
//// Nominal type descriptor for 'Derived' has method descriptors.
// CHECK-LABEL: @"$S14generic_vtable7DerivedCMn" = {{(protected )?}}constant
-// -- flags: has vtable, is class, is unique, is generic
-// CHECK-SAME: <i32 0x8000_00D0>,
+// -- flags: has vtable, reflectable, is class, is unique, is generic
+// CHECK-SAME: <i32 0x8004_00D0>,
// -- vtable offset
// CHECK-SAME: i32 14,
// -- vtable size
@@ -74,8 +74,8 @@
//// Nominal type descriptor for 'Concrete' has method descriptors.
// CHECK-LABEL: @"$S14generic_vtable8ConcreteCMn" = {{(protected )?}}constant
-// -- flags: has vtable, is class, is unique
-// CHECK-SAME: <i32 0x8000_0050>,
+// -- flags: has vtable, reflectable, is class, is unique
+// CHECK-SAME: <i32 0x8004_0050>,
// -- vtable offset
// CHECK-SAME: i32 15,
// -- vtable size
diff --git a/test/IRGen/type_layout_reference_storage.swift b/test/IRGen/type_layout_reference_storage.swift
index 8c6f954..d7f905d 100644
--- a/test/IRGen/type_layout_reference_storage.swift
+++ b/test/IRGen/type_layout_reference_storage.swift
@@ -91,3 +91,20 @@
// CHECK: store i8** getelementptr inbounds (i8*, i8** @"$S[[UNKNOWN]]SgXwWV", i32 9)
weak var uwi: Unknown!
}
+
+
+public class Base {
+ var a: UInt32 = 0
+}
+// CHECK-LABEL: %swift.type* @{{.*}}7DerivedCMi"(%swift.type_descriptor*, i8**)
+// CHECK-NOT: store {{.*}}getelementptr{{.*}}SBomWV
+// CHECK: call %swift.type* @"$S29type_layout_reference_storage1P_pXmTMa"()
+// CHECK: store {{.*}}getelementptr{{.*}}SBoWV
+// CHECK: ret
+public class Derived<T> : Base {
+ var type : P.Type
+ var k = C()
+ init(_ t: P.Type) {
+ type = t
+ }
+}
diff --git a/test/Interpreter/metatype.swift b/test/Interpreter/metatype.swift
new file mode 100644
index 0000000..f8efb06
--- /dev/null
+++ b/test/Interpreter/metatype.swift
@@ -0,0 +1,29 @@
+// RUN: %target-run-simple-swift | %FileCheck %s
+// REQUIRES: executable_test
+
+protocol Bar : class {
+}
+
+public class Foo : Bar {
+}
+
+public class Base {
+ final fileprivate(set) var a: UInt32 = 0
+}
+
+public class Derived<T> : Base {
+ final var type : Bar.Type
+ final var k = Foo()
+
+ init(_ t: Bar.Type, _ kl: Foo ) {
+ type = t
+ k = kl
+ }
+}
+
+public func dontCrash() {
+ // CHECK: Derived<Swift.Int>
+ print(Derived<Int>(Foo.self, Foo()))
+}
+
+dontCrash()
diff --git a/test/SILGen/expressions.swift b/test/SILGen/expressions.swift
index b3c8da2..5f91200 100644
--- a/test/SILGen/expressions.swift
+++ b/test/SILGen/expressions.swift
@@ -555,7 +555,7 @@
}
-func dynamicTypePlusZero(_ a : Super1) -> Super1.Type {
+func dynamicTypePlusZero(_ a: Super1) -> Super1.Type {
return type(of: a)
}
// CHECK-LABEL: dynamicTypePlusZero
@@ -567,9 +567,15 @@
// CHECK: end_borrow [[BORROWED_ARG]] from [[ARG]]
// CHECK: destroy_value [[ARG]]
-struct NonTrivialStruct { var c : Super1 }
+struct NonTrivialStruct {
+ var c : Super1
+ var x: NonTrivialStruct? {
+ get { return nil }
+ set {}
+ }
+}
-func dontEmitIgnoredLoadExpr(_ a : NonTrivialStruct) -> NonTrivialStruct.Type {
+func dontEmitIgnoredLoadExpr(_ a: NonTrivialStruct) -> NonTrivialStruct.Type {
return type(of: a)
}
// CHECK-LABEL: dontEmitIgnoredLoadExpr
@@ -581,6 +587,118 @@
// CHECK-NEXT: destroy_value %0
// CHECK-NEXT: return %4 : $@thin NonTrivialStruct.Type
+// Test that we evaluate the force unwrap to get its side effects (a potential trap),
+// but don't actually need to perform the load of its value.
+func dontLoadIgnoredLValueForceUnwrap(_ a: inout NonTrivialStruct?) -> NonTrivialStruct.Type {
+ return type(of: a!)
+}
+// CHECK-LABEL: dontLoadIgnoredLValueForceUnwrap
+// CHECK: bb0(%0 : @trivial $*Optional<NonTrivialStruct>):
+// CHECK-NEXT: debug_value_addr %0
+// CHECK-NEXT: [[READ:%[0-9]+]] = begin_access [read] [unknown] %0
+// CHECK-NEXT: switch_enum_addr [[READ]] : $*Optional<NonTrivialStruct>, case #Optional.some!enumelt.1: bb2, case #Optional.none!enumelt: bb1
+// CHECK: bb1:
+// CHECK: unreachable
+// CHECK: bb2:
+// CHECK-NEXT: unchecked_take_enum_data_addr [[READ]] : $*Optional<NonTrivialStruct>, #Optional.some!enumelt.1
+// CHECK-NEXT: end_access [[READ]]
+// CHECK-NEXT: [[METATYPE:%[0-9]+]] = metatype $@thin NonTrivialStruct.Type
+// CHECK-NEXT: return [[METATYPE]]
+
+func dontLoadIgnoredLValueDoubleForceUnwrap(_ a: inout NonTrivialStruct??) -> NonTrivialStruct.Type {
+ return type(of: a!!)
+}
+// CHECK-LABEL: dontLoadIgnoredLValueDoubleForceUnwrap
+// CHECK: bb0(%0 : @trivial $*Optional<Optional<NonTrivialStruct>>):
+// CHECK-NEXT: debug_value_addr %0
+// CHECK-NEXT: [[READ:%[0-9]+]] = begin_access [read] [unknown] %0
+// CHECK-NEXT: switch_enum_addr [[READ]] : $*Optional<Optional<NonTrivialStruct>>, case #Optional.some!enumelt.1: bb2, case #Optional.none!enumelt: bb1
+// CHECK: bb1:
+// CHECK: unreachable
+// CHECK: bb2:
+// CHECK-NEXT: [[UNWRAPPED:%[0-9]+]] = unchecked_take_enum_data_addr [[READ]] : $*Optional<Optional<NonTrivialStruct>>, #Optional.some!enumelt.1
+// CHECK-NEXT: switch_enum_addr [[UNWRAPPED]] : $*Optional<NonTrivialStruct>, case #Optional.some!enumelt.1: bb4, case #Optional.none!enumelt: bb3
+// CHECK: bb3:
+// CHECK: unreachable
+// CHECK: bb4:
+// CHECK-NEXT: unchecked_take_enum_data_addr [[UNWRAPPED]] : $*Optional<NonTrivialStruct>, #Optional.some!enumelt.1
+// CHECK-NEXT: end_access [[READ]]
+// CHECK-NEXT: [[METATYPE:%[0-9]+]] = metatype $@thin NonTrivialStruct.Type
+// CHECK-NEXT: return [[METATYPE]]
+
+func loadIgnoredLValueForceUnwrap(_ a: inout NonTrivialStruct) -> NonTrivialStruct.Type {
+ return type(of: a.x!)
+}
+// CHECK-LABEL: loadIgnoredLValueForceUnwrap
+// CHECK: bb0(%0 : @trivial $*NonTrivialStruct):
+// CHECK-NEXT: debug_value_addr %0
+// CHECK-NEXT: [[READ:%[0-9]+]] = begin_access [read] [unknown] %0
+// CHECK-NEXT: [[BORROW:%[0-9]+]] = load_borrow [[READ]]
+// CHECK-NEXT: // function_ref NonTrivialStruct.x.getter
+// CHECK-NEXT: [[GETTER:%[0-9]+]] = function_ref @$S{{[_0-9a-zA-Z]*}}vg : $@convention(method) (@guaranteed NonTrivialStruct) -> @owned Optional<NonTrivialStruct>
+// CHECK-NEXT: [[X:%[0-9]+]] = apply [[GETTER]]([[BORROW]])
+// CHECK-NEXT: end_borrow [[BORROW]] from [[READ]]
+// CHECK-NEXT: end_access [[READ]]
+// CHECK-NEXT: switch_enum [[X]] : $Optional<NonTrivialStruct>, case #Optional.some!enumelt.1: bb2, case #Optional.none!enumelt: bb1
+// CHECK: bb1:
+// CHECK: unreachable
+// CHECK: bb2([[UNWRAPPED_X:%[0-9]+]] : @owned $NonTrivialStruct):
+// CHECK-NEXT: destroy_value [[UNWRAPPED_X]]
+// CHECK-NEXT: [[METATYPE:%[0-9]+]] = metatype $@thin NonTrivialStruct.Type
+// CHECK-NEXT: return [[METATYPE]]
+
+func loadIgnoredLValueThroughForceUnwrap(_ a: inout NonTrivialStruct?) -> NonTrivialStruct.Type {
+ return type(of: a!.x!)
+}
+// CHECK-LABEL: loadIgnoredLValueThroughForceUnwrap
+// CHECK: bb0(%0 : @trivial $*Optional<NonTrivialStruct>):
+// CHECK-NEXT: debug_value_addr %0
+// CHECK-NEXT: [[READ:%[0-9]+]] = begin_access [read] [unknown] %0
+// CHECK-NEXT: switch_enum_addr [[READ]] : $*Optional<NonTrivialStruct>, case #Optional.some!enumelt.1: bb2, case #Optional.none!enumelt: bb1
+// CHECK: bb1:
+// CHECK: unreachable
+// CHECK: bb2:
+// CHECK-NEXT: [[UNWRAPPED:%[0-9]+]] = unchecked_take_enum_data_addr [[READ]] : $*Optional<NonTrivialStruct>, #Optional.some!enumelt.1
+// CHECK-NEXT: [[BORROW:%[0-9]+]] = load_borrow [[UNWRAPPED]]
+// CHECK-NEXT: // function_ref NonTrivialStruct.x.getter
+// CHECK-NEXT: [[GETTER:%[0-9]+]] = function_ref @$S{{[_0-9a-zA-Z]*}}vg : $@convention(method) (@guaranteed NonTrivialStruct) -> @owned Optional<NonTrivialStruct>
+// CHECK-NEXT: [[X:%[0-9]+]] = apply [[GETTER]]([[BORROW]])
+// CHECK-NEXT: end_borrow [[BORROW]] from [[UNWRAPPED]]
+// CHECK-NEXT: end_access [[READ]]
+// CHECK-NEXT: switch_enum [[X]] : $Optional<NonTrivialStruct>, case #Optional.some!enumelt.1: bb4, case #Optional.none!enumelt: bb3
+// CHECK: bb3:
+// CHECK: unreachable
+// CHECK: bb4([[UNWRAPPED_X:%[0-9]+]] : @owned $NonTrivialStruct):
+// CHECK-NEXT: destroy_value [[UNWRAPPED_X]]
+// CHECK-NEXT: [[METATYPE:%[0-9]+]] = metatype $@thin NonTrivialStruct.Type
+// CHECK-NEXT: return [[METATYPE]]
+
+func evaluateIgnoredKeyPathExpr(_ s: inout NonTrivialStruct, _ kp: WritableKeyPath<NonTrivialStruct, Int>) -> Int.Type {
+ return type(of: s[keyPath: kp])
+}
+// CHECK-LABEL: evaluateIgnoredKeyPathExpr
+// CHECK: bb0(%0 : @trivial $*NonTrivialStruct, %1 : @owned $WritableKeyPath<NonTrivialStruct, Int>):
+// CHECK-NEXT: debug_value_addr %0
+// CHECK-NEXT: debug_value %1
+// CHECK-NEXT: [[S_READ:%[0-9]+]] = begin_access [read] [unknown] %0
+// CHECK-NEXT: [[S_TEMP:%[0-9]+]] = alloc_stack $NonTrivialStruct
+// CHECK-NEXT: copy_addr [[S_READ]] to [initialization] [[S_TEMP]]
+// CHECK-NEXT: [[KP_BORROW:%[0-9]+]] = begin_borrow %1
+// CHECK-NEXT: [[KP_TEMP:%[0-9]+]] = copy_value [[KP_BORROW]]
+// CHECK-NEXT: [[KP:%[0-9]+]] = upcast [[KP_TEMP]]
+// CHECK-NEXT: [[RESULT:%[0-9]+]] = alloc_stack $Int
+// CHECK-NEXT: // function_ref
+// CHECK-NEXT: [[PROJECT_FN:%[0-9]+]] = function_ref @$Ss23_projectKeyPathReadOnly{{[_0-9a-zA-Z]*}}F
+// CHECK-NEXT: apply [[PROJECT_FN]]<NonTrivialStruct, Int>([[RESULT]], [[S_TEMP]], [[KP]])
+// CHECK-NEXT: end_access [[S_READ]]
+// CHECK-NEXT: dealloc_stack [[RESULT]]
+// CHECK-NEXT: end_borrow [[KP_BORROW]] from %1
+// CHECK-NEXT: dealloc_stack [[S_TEMP]]
+// CHECK-NEXT: [[METATYPE:%[0-9]+]] = metatype $@thin Int.Type
+// CHECK-NEXT: destroy_value %1
+// CHECK-NEXT: return [[METATYPE]]
+
+
// <rdar://problem/18851497> Swiftc fails to compile nested destructuring tuple binding
// CHECK-LABEL: sil hidden @$S11expressions21implodeRecursiveTupleyySi_Sit_SitSgF
diff --git a/test/Sema/type_join.swift b/test/Sema/type_join.swift
index 2a469b1..bf5df54 100644
--- a/test/Sema/type_join.swift
+++ b/test/Sema/type_join.swift
@@ -10,6 +10,32 @@
expectEqualType(Builtin.type_join(Int.self, Int.self), Int.self)
expectEqualType(Builtin.type_join_meta(D.self, C.self), C.self)
+expectEqualType(Builtin.type_join(Int?.self, Int?.self), Int?.self)
+expectEqualType(Builtin.type_join(Int.self, Int?.self), Int?.self)
+expectEqualType(Builtin.type_join(Int?.self, Int.self), Int?.self)
+expectEqualType(Builtin.type_join(Int.self, Int??.self), Int??.self)
+expectEqualType(Builtin.type_join(Int??.self, Int.self), Int??.self)
+expectEqualType(Builtin.type_join(Int?.self, Int??.self), Int??.self)
+expectEqualType(Builtin.type_join(Int??.self, Int?.self), Int??.self)
+expectEqualType(Builtin.type_join(D?.self, D?.self), D?.self)
+expectEqualType(Builtin.type_join(C?.self, D?.self), C?.self)
+expectEqualType(Builtin.type_join(D?.self, C?.self), C?.self)
+expectEqualType(Builtin.type_join(D.self, D?.self), D?.self)
+expectEqualType(Builtin.type_join(D?.self, D.self), D?.self)
+expectEqualType(Builtin.type_join(C.self, D?.self), C?.self)
+expectEqualType(Builtin.type_join(D?.self, C.self), C?.self)
+expectEqualType(Builtin.type_join(D.self, C?.self), C?.self)
+expectEqualType(Builtin.type_join(C?.self, D.self), C?.self)
+expectEqualType(Builtin.type_join(Any?.self, D.self), Any?.self)
+expectEqualType(Builtin.type_join(D.self, Any?.self), Any?.self)
+expectEqualType(Builtin.type_join(Any.self, D?.self), Any?.self)
+expectEqualType(Builtin.type_join(D?.self, Any.self), Any?.self)
+expectEqualType(Builtin.type_join(Any?.self, Any.self), Any?.self)
+expectEqualType(Builtin.type_join(Any.self, Any?.self), Any?.self)
+
func rdar37241221(_ a: C?, _ b: D?) {
- let _ = [a!, b] // Should be inferred as `[C?]`
+ let c: C? = C()
+ let array_c_opt = [c]
+ let inferred = [a!, b]
+ expectEqualType(type(of: array_c_opt).self, type(of: inferred).self)
}
diff --git a/test/SourceKit/CodeFormat/indent-zero-width.swift b/test/SourceKit/CodeFormat/indent-zero-width.swift
new file mode 100644
index 0000000..371fd5d
--- /dev/null
+++ b/test/SourceKit/CodeFormat/indent-zero-width.swift
@@ -0,0 +1,22 @@
+class Foo {
+
+var test : Int
+
+ func foo() {
+ test = 1
+ }
+
+}
+func bar(a: Int,
+b: Int) {}
+
+// RUN: %sourcekitd-test -req=format -line=1 -length=1 -req-opts=usetabs=0 -req-opts=indentwidth=0 %s >%t.response
+// RUN: %sourcekitd-test -req=format -line=3 -length=1 -req-opts=usetabs=0 -req-opts=indentwidth=0 %s >>%t.response
+// RUN: %sourcekitd-test -req=format -line=6 -length=1 -req-opts=usetabs=0 -req-opts=indentwidth=0 %s >>%t.response
+// RUN: %sourcekitd-test -req=format -line=11 -length=1 -req-opts=usetabs=0 -req-opts=indentwidth=0 %s >>%t.response
+// RUN: %FileCheck --strict-whitespace %s <%t.response
+
+// CHECK: key.sourcetext: "class Foo {"
+// CHECK: key.sourcetext: "var test : Int"
+// CHECK: key.sourcetext: " test = 1"
+// CHECK: key.sourcetext: " b: Int) {}"
diff --git a/test/SourceKit/DocSupport/Inputs/cake1.swift b/test/SourceKit/DocSupport/Inputs/cake1.swift
index 0b53509..1895342 100644
--- a/test/SourceKit/DocSupport/Inputs/cake1.swift
+++ b/test/SourceKit/DocSupport/Inputs/cake1.swift
@@ -25,3 +25,7 @@
public extension P2 where Self : P3 {
func fooConstraint() {}
}
+
+public extension Dictionary.Keys {
+ public func foo() {}
+}
diff --git a/test/SourceKit/DocSupport/doc_swift_module1.swift.response b/test/SourceKit/DocSupport/doc_swift_module1.swift.response
index 193fea0..9de4a19 100644
--- a/test/SourceKit/DocSupport/doc_swift_module1.swift.response
+++ b/test/SourceKit/DocSupport/doc_swift_module1.swift.response
@@ -41,6 +41,11 @@
func p3Required()
}
+extension Dictionary.Keys where Key : Hashable {
+
+ func foo()
+}
+
[
{
@@ -383,6 +388,52 @@
key.kind: source.lang.swift.syntaxtype.identifier,
key.offset: 439,
key.length: 10
+ },
+ {
+ key.kind: source.lang.swift.syntaxtype.keyword,
+ key.offset: 455,
+ key.length: 9
+ },
+ {
+ key.kind: source.lang.swift.ref.struct,
+ key.name: "Dictionary",
+ key.usr: "s:s10DictionaryV",
+ key.offset: 465,
+ key.length: 10
+ },
+ {
+ key.kind: source.lang.swift.ref.struct,
+ key.name: "Keys",
+ key.usr: "s:s10DictionaryV4KeysV",
+ key.offset: 476,
+ key.length: 4
+ },
+ {
+ key.kind: source.lang.swift.syntaxtype.keyword,
+ key.offset: 481,
+ key.length: 5
+ },
+ {
+ key.kind: source.lang.swift.syntaxtype.typeidentifier,
+ key.offset: 487,
+ key.length: 3
+ },
+ {
+ key.kind: source.lang.swift.ref.protocol,
+ key.name: "Hashable",
+ key.usr: "s:s8HashableP",
+ key.offset: 493,
+ key.length: 8
+ },
+ {
+ key.kind: source.lang.swift.syntaxtype.keyword,
+ key.offset: 509,
+ key.length: 4
+ },
+ {
+ key.kind: source.lang.swift.syntaxtype.identifier,
+ key.offset: 514,
+ key.length: 3
}
]
[
@@ -610,5 +661,38 @@
key.fully_annotated_decl: "<decl.function.method.instance><syntaxtype.keyword>func</syntaxtype.keyword> <decl.name>p3Required</decl.name>()</decl.function.method.instance>"
}
]
+ },
+ {
+ key.kind: source.lang.swift.decl.extension.struct,
+ key.generic_params: [
+ {
+ key.name: "Key"
+ },
+ {
+ key.name: "Value"
+ }
+ ],
+ key.generic_requirements: [
+ {
+ key.description: "Key : Hashable"
+ }
+ ],
+ key.offset: 455,
+ key.length: 66,
+ key.extends: {
+ key.kind: source.lang.swift.ref.struct,
+ key.name: "Keys",
+ key.usr: "s:s10DictionaryV4KeysV"
+ },
+ key.entities: [
+ {
+ key.kind: source.lang.swift.decl.function.method.instance,
+ key.name: "foo()",
+ key.usr: "s:s10DictionaryV4KeysV5cake1E3fooyyF",
+ key.offset: 509,
+ key.length: 10,
+ key.fully_annotated_decl: "<decl.function.method.instance><syntaxtype.keyword>func</syntaxtype.keyword> <decl.name>foo</decl.name>()</decl.function.method.instance>"
+ }
+ ]
}
]
diff --git a/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp b/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp
index d5379b0..5452a25 100644
--- a/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp
+++ b/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp
@@ -439,7 +439,6 @@
ImporterOpts.DetailedPreprocessingRecord = true;
assert(!Invocation.getModuleName().empty());
- Invocation.setSerializedDiagnosticsPath(StringRef());
Invocation.getLangOptions().AttachCommentsToDecls = true;
Invocation.getLangOptions().DiagnosticsEditorMode = true;
Invocation.getLangOptions().CollectParsedToken = true;
@@ -700,7 +699,7 @@
Invok.Opts.Invok.getFrontendOptions().InputsAndOutputs.inputCount());
for (const auto &input :
Invok.Opts.Invok.getFrontendOptions().InputsAndOutputs.getAllInputs()) {
- StringRef File = input.file();
+ const std::string &File = input.file();
bool FoundSnapshot = false;
for (auto &Snap : Snapshots) {
if (Snap->getFilename() == File) {
@@ -887,7 +886,7 @@
const InvocationOptions &Opts = InvokRef->Impl.Opts;
for (const auto &input :
Opts.Invok.getFrontendOptions().InputsAndOutputs.getAllInputs()) {
- StringRef File = input.file();
+ const std::string &File = input.file();
bool IsPrimary = input.isPrimary();
bool FoundSnapshot = false;
for (auto &Snap : Snapshots) {
diff --git a/tools/SourceKit/tools/swift-lang/SourceKitdClient.swift b/tools/SourceKit/tools/swift-lang/SourceKitdClient.swift
index 52c4c1e..2b53977 100644
--- a/tools/SourceKit/tools/swift-lang/SourceKitdClient.swift
+++ b/tools/SourceKit/tools/swift-lang/SourceKitdClient.swift
@@ -23,7 +23,22 @@
deinit {
sourcekitd_shutdown()
}
+
+ /// Send a request synchronously with a handler for its response.
+ /// - Parameter request: The request to send.
+ /// - Returns: The response from the sourcekitd service.
public func sendSyn(request: SourceKitdRequest) -> SourceKitdResponse {
return SourceKitdResponse(resp: sourcekitd_send_request_sync(request.rawRequest))
}
+
+ /// Send a request asynchronously with a handler for its response.
+ /// - Parameter request: The request to send.
+ /// - Parameter handler: The handler for the response in the future.
+ public func send(request: SourceKitdRequest,
+ handler: @escaping (SourceKitdResponse) -> ()) {
+ sourcekitd_send_request(request.rawRequest, nil) { response in
+ guard let response = response else { return }
+ handler(SourceKitdResponse(resp: response))
+ }
+ }
}
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp
index 74421b7..341c880 100644
--- a/tools/driver/driver.cpp
+++ b/tools/driver/driver.cpp
@@ -110,7 +110,7 @@
extern int apinotes_main(ArrayRef<const char *> Args);
int main(int argc_, const char **argv_) {
- INITIALIZE_LLVM(argc_, argv_);
+ PROGRAM_START(argc_, argv_);
SmallVector<const char *, 256> argv;
llvm::SpecificBumpPtrAllocator<char> ArgAllocator;
diff --git a/tools/driver/modulewrap_main.cpp b/tools/driver/modulewrap_main.cpp
index 846a4e7..579e1c0 100644
--- a/tools/driver/modulewrap_main.cpp
+++ b/tools/driver/modulewrap_main.cpp
@@ -18,6 +18,7 @@
//===----------------------------------------------------------------------===//
#include "swift/AST/DiagnosticsFrontend.h"
+#include "swift/Basic/LLVMInitialize.h"
#include "swift/Frontend/Frontend.h"
#include "swift/Frontend/PrintingDiagnosticConsumer.h"
#include "swift/Option/Options.h"
@@ -113,10 +114,7 @@
int modulewrap_main(ArrayRef<const char *> Args, const char *Argv0,
void *MainAddr) {
- llvm::InitializeAllTargets();
- llvm::InitializeAllTargetMCs();
- llvm::InitializeAllAsmPrinters();
- llvm::InitializeAllAsmParsers();
+ INITIALIZE_LLVM();
CompilerInstance Instance;
PrintingDiagnosticConsumer PDC;
diff --git a/tools/lldb-moduleimport-test/lldb-moduleimport-test.cpp b/tools/lldb-moduleimport-test/lldb-moduleimport-test.cpp
index 38a097d..4b5b3f0 100644
--- a/tools/lldb-moduleimport-test/lldb-moduleimport-test.cpp
+++ b/tools/lldb-moduleimport-test/lldb-moduleimport-test.cpp
@@ -62,7 +62,8 @@
}
int main(int argc, char **argv) {
- INITIALIZE_LLVM(argc, argv);
+ PROGRAM_START(argc, argv);
+ INITIALIZE_LLVM();
// Command line handling.
llvm::cl::list<std::string> InputNames(
diff --git a/tools/sil-func-extractor/SILFunctionExtractor.cpp b/tools/sil-func-extractor/SILFunctionExtractor.cpp
index 138013c..a764a08 100644
--- a/tools/sil-func-extractor/SILFunctionExtractor.cpp
+++ b/tools/sil-func-extractor/SILFunctionExtractor.cpp
@@ -225,7 +225,8 @@
}
int main(int argc, char **argv) {
- INITIALIZE_LLVM(argc, argv);
+ PROGRAM_START(argc, argv);
+ INITIALIZE_LLVM();
llvm::cl::ParseCommandLineOptions(argc, argv, "Swift SIL Extractor\n");
diff --git a/tools/sil-llvm-gen/SILLLVMGen.cpp b/tools/sil-llvm-gen/SILLLVMGen.cpp
index c16de4c..b450a81 100644
--- a/tools/sil-llvm-gen/SILLLVMGen.cpp
+++ b/tools/sil-llvm-gen/SILLLVMGen.cpp
@@ -113,7 +113,8 @@
void anchorForGetMainExecutable() {}
int main(int argc, char **argv) {
- INITIALIZE_LLVM(argc, argv);
+ PROGRAM_START(argc, argv);
+ INITIALIZE_LLVM();
llvm::cl::ParseCommandLineOptions(argc, argv, "Swift LLVM IR Generator\n");
diff --git a/tools/sil-nm/SILNM.cpp b/tools/sil-nm/SILNM.cpp
index 6e9d6ce..d914f0c 100644
--- a/tools/sil-nm/SILNM.cpp
+++ b/tools/sil-nm/SILNM.cpp
@@ -139,7 +139,8 @@
}
int main(int argc, char **argv) {
- INITIALIZE_LLVM(argc, argv);
+ PROGRAM_START(argc, argv);
+ INITIALIZE_LLVM();
llvm::cl::ParseCommandLineOptions(argc, argv, "SIL NM\n");
diff --git a/tools/sil-opt/SILOpt.cpp b/tools/sil-opt/SILOpt.cpp
index ab500c1..1467da4 100644
--- a/tools/sil-opt/SILOpt.cpp
+++ b/tools/sil-opt/SILOpt.cpp
@@ -264,7 +264,8 @@
void anchorForGetMainExecutable() {}
int main(int argc, char **argv) {
- INITIALIZE_LLVM(argc, argv);
+ PROGRAM_START(argc, argv);
+ INITIALIZE_LLVM();
llvm::cl::ParseCommandLineOptions(argc, argv, "Swift SIL optimizer\n");
@@ -427,9 +428,9 @@
} else {
auto *SILMod = CI.getSILModule();
{
- const auto PSPs = CI.getPrimarySpecificPathsForAtMostOnePrimary();
auto T = irgen::createIRGenModule(
- SILMod, PSPs.OutputFilename, PSPs.MainInputFilenameForDebugInfo,
+ SILMod, Invocation.getOutputFilenameForAtMostOnePrimary(),
+ Invocation.getMainInputFilenameForDebugInfoForAtMostOnePrimary(),
getGlobalLLVMContext());
runCommandLineSelectedPasses(SILMod, T.second);
irgen::deleteIRGenModule(T);
diff --git a/tools/sil-passpipeline-dumper/SILPassPipelineDumper.cpp b/tools/sil-passpipeline-dumper/SILPassPipelineDumper.cpp
index ee0332f..6ad3313 100644
--- a/tools/sil-passpipeline-dumper/SILPassPipelineDumper.cpp
+++ b/tools/sil-passpipeline-dumper/SILPassPipelineDumper.cpp
@@ -44,7 +44,8 @@
} // namespace llvm
int main(int argc, char **argv) {
- INITIALIZE_LLVM(argc, argv);
+ PROGRAM_START(argc, argv);
+ INITIALIZE_LLVM();
llvm::cl::ParseCommandLineOptions(argc, argv,
"Swift SIL Pass Pipeline Dumper\n");
diff --git a/tools/swift-api-digester/swift-api-digester.cpp b/tools/swift-api-digester/swift-api-digester.cpp
index c1ab72f..bb6927d 100644
--- a/tools/swift-api-digester/swift-api-digester.cpp
+++ b/tools/swift-api-digester/swift-api-digester.cpp
@@ -3610,7 +3610,8 @@
}
int main(int argc, char *argv[]) {
- INITIALIZE_LLVM(argc, argv);
+ PROGRAM_START(argc, argv);
+ INITIALIZE_LLVM();
llvm::cl::ParseCommandLineOptions(argc, argv, "Swift SDK Digester\n");
CompilerInvocation InitInvok;
diff --git a/tools/swift-ide-test/swift-ide-test.cpp b/tools/swift-ide-test/swift-ide-test.cpp
index b84602d..4f37ef7 100644
--- a/tools/swift-ide-test/swift-ide-test.cpp
+++ b/tools/swift-ide-test/swift-ide-test.cpp
@@ -2928,7 +2928,8 @@
void anchorForGetMainExecutable() {}
int main(int argc, char *argv[]) {
- INITIALIZE_LLVM(argc, argv);
+ PROGRAM_START(argc, argv);
+ INITIALIZE_LLVM();
if (argc > 1) {
// Handle integrated test tools which do not use
diff --git a/tools/swift-llvm-opt/LLVMOpt.cpp b/tools/swift-llvm-opt/LLVMOpt.cpp
index cba627f..a744f42 100644
--- a/tools/swift-llvm-opt/LLVMOpt.cpp
+++ b/tools/swift-llvm-opt/LLVMOpt.cpp
@@ -212,7 +212,8 @@
//===----------------------------------------------------------------------===//
int main(int argc, char **argv) {
- INITIALIZE_LLVM(argc, argv);
+ PROGRAM_START(argc, argv);
+ INITIALIZE_LLVM();
// Initialize passes
PassRegistry &Registry = *PassRegistry::getPassRegistry();
diff --git a/tools/swift-refactor/swift-refactor.cpp b/tools/swift-refactor/swift-refactor.cpp
index 71ebf2f..02a6bb7 100644
--- a/tools/swift-refactor/swift-refactor.cpp
+++ b/tools/swift-refactor/swift-refactor.cpp
@@ -10,12 +10,13 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/Support/CommandLine.h"
#include "swift/Basic/LLVMInitialize.h"
#include "swift/Frontend/Frontend.h"
#include "swift/Frontend/PrintingDiagnosticConsumer.h"
#include "swift/IDE/Refactoring.h"
#include "swift/IDE/Utils.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
#include <regex>
@@ -218,7 +219,8 @@
void anchorForGetMainExecutable() {}
int main(int argc, char *argv[]) {
- INITIALIZE_LLVM(argc, argv);
+ PROGRAM_START(argc, argv);
+ INITIALIZE_LLVM();
llvm::cl::ParseCommandLineOptions(argc, argv, "Swift refactor\n");
if (options::SourceFilename.empty()) {
llvm::errs() << "cannot find source filename\n";
diff --git a/tools/swift-reflection-dump/swift-reflection-dump.cpp b/tools/swift-reflection-dump/swift-reflection-dump.cpp
index 53e3e4a..e80b8fe 100644
--- a/tools/swift-reflection-dump/swift-reflection-dump.cpp
+++ b/tools/swift-reflection-dump/swift-reflection-dump.cpp
@@ -293,6 +293,7 @@
}
int main(int argc, char *argv[]) {
+ PROGRAM_START(argc, argv);
llvm::cl::ParseCommandLineOptions(argc, argv, "Swift Reflection Dump\n");
return doDumpReflectionSections(options::BinaryFilename,
options::Architecture,
diff --git a/tools/swift-remoteast-test/swift-remoteast-test.cpp b/tools/swift-remoteast-test/swift-remoteast-test.cpp
index 0096dab..25f9473 100644
--- a/tools/swift-remoteast-test/swift-remoteast-test.cpp
+++ b/tools/swift-remoteast-test/swift-remoteast-test.cpp
@@ -19,6 +19,7 @@
#include "swift/Frontend/Frontend.h"
#include "swift/FrontendTool/FrontendTool.h"
#include "swift/Basic/LLVM.h"
+#include "swift/Basic/LLVMInitialize.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
@@ -143,6 +144,8 @@
} // end anonymous namespace
int main(int argc, const char *argv[]) {
+ PROGRAM_START(argc, argv);
+
unsigned numForwardedArgs = argc
- 1 // we drop argv[0]
+ 1; // -interpret
diff --git a/tools/swift-syntax-test/swift-syntax-test.cpp b/tools/swift-syntax-test/swift-syntax-test.cpp
index b075dc6..f4d00a9 100644
--- a/tools/swift-syntax-test/swift-syntax-test.cpp
+++ b/tools/swift-syntax-test/swift-syntax-test.cpp
@@ -21,6 +21,7 @@
#include "swift/AST/DiagnosticEngine.h"
#include "swift/AST/DiagnosticsFrontend.h"
#include "swift/Basic/LangOptions.h"
+#include "swift/Basic/LLVMInitialize.h"
#include "swift/Basic/SourceManager.h"
#include "swift/Frontend/Frontend.h"
#include "swift/Frontend/PrintingDiagnosticConsumer.h"
@@ -281,6 +282,7 @@
}// end of anonymous namespace
int main(int argc, char *argv[]) {
+ PROGRAM_START(argc, argv);
llvm::cl::ParseCommandLineOptions(argc, argv, "Swift Syntax Test\n");
int ExitCode = EXIT_SUCCESS;
diff --git a/utils/build-script-impl b/utils/build-script-impl
index d9ba30d..9d1fb48 100755
--- a/utils/build-script-impl
+++ b/utils/build-script-impl
@@ -2011,10 +2011,10 @@
-DSWIFT_ANDROID_NDK_PATH:STRING="${ANDROID_NDK}"
-DSWIFT_ANDROID_NDK_GCC_VERSION:STRING="${ANDROID_NDK_GCC_VERSION}"
-DSWIFT_ANDROID_SDK_PATH:STRING="${ANDROID_NDK}/platforms/android-${ANDROID_API_LEVEL}/arch-arm"
- -DSWIFT_ANDROID_ICU_UC:STRING="${ANDROID_ICU_UC}"
- -DSWIFT_ANDROID_ICU_UC_INCLUDE:STRING="${ANDROID_ICU_UC_INCLUDE}"
- -DSWIFT_ANDROID_ICU_I18N:STRING="${ANDROID_ICU_I18N}"
- -DSWIFT_ANDROID_ICU_I18N_INCLUDE:STRING="${ANDROID_ICU_I18N_INCLUDE}"
+ -DSWIFT_ANDROID_${HOST}_ICU_UC:STRING="${ANDROID_ICU_UC}"
+ -DSWIFT_ANDROID_${HOST}_ICU_UC_INCLUDE:STRING="${ANDROID_ICU_UC_INCLUDE}"
+ -DSWIFT_ANDROID_${HOST}_ICU_I18N:STRING="${ANDROID_ICU_I18N}"
+ -DSWIFT_ANDROID_${HOST}_ICU_I18N_INCLUDE:STRING="${ANDROID_ICU_I18N_INCLUDE}"
-DSWIFT_ANDROID_DEPLOY_DEVICE_PATH:STRING="${ANDROID_DEPLOY_DEVICE_PATH}"
)
fi
@@ -2557,9 +2557,9 @@
export PKG_CONFIG_PATH="${ICU_TMPLIBDIR}/pkgconfig"
swift_cmake_options=(
"${swift_cmake_options[@]}"
- -DSWIFT_${SWIFT_HOST_VARIANT_SDK}_ICU_UC_INCLUDE:STRING="${ICU_TMPINSTALL}/include"
- -DSWIFT_${SWIFT_HOST_VARIANT_SDK}_ICU_I18N_INCLUDE:STRING="${ICU_TMPINSTALL}/include"
- -DSWIFT_${SWIFT_HOST_VARIANT_SDK}_ICU_STATICLIB:BOOL=TRUE
+ -DSWIFT_${SWIFT_HOST_VARIANT_SDK}_${SWIFT_HOST_VARIANT_ARCH}_ICU_UC_INCLUDE:STRING="${ICU_TMPINSTALL}/include"
+ -DSWIFT_${SWIFT_HOST_VARIANT_SDK}_${SWIFT_HOST_VARIANT_ARCH}_ICU_I18N_INCLUDE:STRING="${ICU_TMPINSTALL}/include"
+ -DSWIFT_${SWIFT_HOST_VARIANT_SDK}_${SWIFT_HOST_VARIANT_ARCH}_ICU_STATICLIB:BOOL=TRUE
)
# libicu builds itself and doesn't use cmake
continue
diff --git a/validation-test/stdlib/String.swift b/validation-test/stdlib/String.swift
index 7d8885e..2047e64 100644
--- a/validation-test/stdlib/String.swift
+++ b/validation-test/stdlib/String.swift
@@ -2011,6 +2011,7 @@
"a\u{fa1}\u{fb7}\u{fa1}\u{fb7}a\u{fa1}\u{fb7}\u{fa1}\u{fb7}\u{fa1}\u{fb7}\u{fa1}\u{fb7}\u{fa1}\u{fb7}\u{fa1}\u{fb7}"
], .equal),
+ ComparisonTestCase(["a\u{301}\u{0301}", "\u{e1}"], .greater),
ComparisonTestCase(["😀", "😀"], .equal),
ComparisonTestCase(["\u{2f9df}", "\u{8f38}"], .equal),
ComparisonTestCase([