Merge pull request #23741 from xedin/verify-kp-subscript-hashable-via-solver
[CSSolver] Move keypath subscript index Hashable conformance verification to solver
diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt
index 1479ab9..6063c62 100644
--- a/benchmark/CMakeLists.txt
+++ b/benchmark/CMakeLists.txt
@@ -253,6 +253,10 @@
"-whole-module-optimization" "-num-threads" "4")
set(BENCHOPTS_SINGLEFILE "")
+option(SWIFT_BENCHMARK_USE_OS_LIBRARIES
+ "Runtime link against the Swift libraries on the target (/usr/lib/swift)."
+ FALSE)
+
configure_build()
#===-----------------------------------------------------------------------===#
@@ -268,10 +272,18 @@
message("--")
message("-- Swift Benchmark Suite:")
message("-- SWIFT_BENCHMARK_BUILT_STANDALONE = ${SWIFT_BENCHMARK_BUILT_STANDALONE}")
-message("-- SWIFT_EXEC = ${SWIFT_EXEC}")
-message("-- SWIFT_BENCHMARK_EXTRA_FLAGS = ${SWIFT_BENCHMARK_EXTRA_FLAGS}")
+message("-- SWIFT_BENCHMARK_USE_OS_LIBRARIES = ${SWIFT_BENCHMARK_USE_OS_LIBRARIES}")
+message("-- SWIFT_EXEC = ${SWIFT_EXEC}")
message("-- SWIFT_LIBRARY_PATH = ${SWIFT_LIBRARY_PATH}")
-message("-- CLANG_EXEC = ${CLANG_EXEC}")
+if (SWIFT_RPATH_BASE)
+message("-- SWIFT_RPATH_BASE = ${SWIFT_RPATH_BASE}")
+endif()
+if (SWIFT_RPATH)
+message("-- SWIFT_RPATH = ${SWIFT_RPATH}")
+message("--- ** WARNING ** Benchmarking against Swift-in-the-OS")
+endif()
+message("-- CLANG_EXEC = ${CLANG_EXEC}")
+message("-- SWIFT_BENCHMARK_EXTRA_FLAGS = ${SWIFT_BENCHMARK_EXTRA_FLAGS}")
message("-- SWIFT_OPTIMIZATION_LEVELS = ${SWIFT_OPTIMIZATION_LEVELS}")
message("-- ONLY_PLATFORMS = ${ONLY_PLATFORMS}")
message("-- PAGE_ALIGNMENT_OPTION = ${PAGE_ALIGNMENT_OPTION}")
diff --git a/benchmark/README.md b/benchmark/README.md
index 44ba62b..657863f 100644
--- a/benchmark/README.md
+++ b/benchmark/README.md
@@ -28,6 +28,11 @@
OS X benchmark driver binaries are placed in `bin` alongside `swiftc`.
Additional platform binaries are placed in the `benchmark/bin` build directory.
+The required Swift standard library dylibs are placed in `lib`. The
+drivers dynamically link Swift standard library dylibs from a path
+relative to their run-time location (../lib/swift) so the standard
+library should be distributed alongside them.
+
Building Independently
----------------------
@@ -43,15 +48,19 @@
* `-DSWIFT_LIBRARY_PATH`
* An absolute path to the Swift standard library to use during compilation
(default: `swiftc_directory`/../lib/swift)
+* `-DSWIFT_DARWIN_XCRUN_TOOLCHAIN`
+ * The Xcode toolchain to use when invoking `xcrun` to find `clang`.
+ (default: XcodeDefault)
* `-DONLY_PLATFORMS`
* A list of platforms to build the benchmarks for
(default: "macosx;iphoneos;appletvos;watchos")
* `-DSWIFT_OPTIMIZATION_LEVELS`
* A list of Swift optimization levels to build against
(default: "O;Onone;Osize")
-* `-DSWIFT_BENCHMARK_EMIT_SIB`
- * A boolean value indicating whether .sib files should be generated
- alongside .o files (default: FALSE)
+* `-DSWIFT_BENCHMARK_USE_OS_LIBRARIES`
+ * Enable this option to link the benchmark binaries against the target
+ machine's Swift standard library and runtime installed with the OS.
+ (default: OFF)
The following build targets are available:
@@ -66,13 +75,40 @@
1. `$ cd benchmark`
2. `$ mkdir build`
3. `$ cd build`
-4. `$ cmake ..`
-5. `$ make -j8 swift-benchmark-macosx-x86_64`
+4. `$ cmake ../benchmark -G Ninja -DSWIFT_EXEC=[path to built swiftc]`
+5. `$ ninja swift-benchmark-macosx-x86_64`
-Benchmark driver binaries are placed in `build/bin` and the required Swift
-standard library dylibs are placed in `build/lib`. The drivers dynamically link
-Swift standard library dylibs from a path relative to their location
-(../lib/swift) so the standard library should be distributed alongside them.
+Benchmark binaries are placed in `bin`.
+
+The binaries dynamically link Swift standard library dylibs from a
+path determined by the configuration. If `SWIFT_LIBRARY_PATH` is set,
+they link against the absolute path provided, regardless of where the
+binaries are installed. Otherwise, the runtime library path is
+relative to the benchmark binary at the time it was executed
+(`@executable_path/../lib/swift/<platform>`).
+
+For example, to benchmark against a locally built `swiftc`, including
+any standard library changes in that build, you might configure using:
+
+ cmake ../benchmark -G Ninja -DSWIFT_EXEC=<src>/swift/build/swift-macosx-x86_64/bin/swiftc
+ ninja swift-benchmark-iphoneos-arm64
+
+To build against the installed Xcode, simply omit SWIFT_EXEC:
+
+ cmake ../benchmark -G Ninja
+ ninja swift-benchmark-iphoneos-arm64
+
+In both examples above, to run the benchmarks on a device, the dynamic
+libraries must then be copied onto the device into the library path
+relative to `swiftc`. To benchmark against the target machine's
+installed libraries instead, enable
+`SWIFT_BENCHMARK_USE_OS_LIBRARIES`.
+
+ cmake ../benchmark -G Ninja -DSWIFT_BENCHMARK_USE_OS_LIBRARIES=ON
+ ninja swift-benchmark-iphoneos-arm64
+
+This will reflect the performance of the Swift standard library
+installed on the device, not the one included in the Swift root.
Using the Benchmark Driver
--------------------------
diff --git a/benchmark/cmake/modules/AddSwiftBenchmarkSuite.cmake b/benchmark/cmake/modules/AddSwiftBenchmarkSuite.cmake
index 953eeae..bc05c8f 100644
--- a/benchmark/cmake/modules/AddSwiftBenchmarkSuite.cmake
+++ b/benchmark/cmake/modules/AddSwiftBenchmarkSuite.cmake
@@ -24,6 +24,9 @@
if(${c_compiler} STREQUAL "clang")
set(CLANG_EXEC ${CMAKE_C_COMPILER})
else()
+ if(NOT SWIFT_DARWIN_XCRUN_TOOLCHAIN)
+ set(SWIFT_DARWIN_XCRUN_TOOLCHAIN "XcodeDefault")
+ endif()
runcmd(COMMAND "xcrun" "-toolchain" "${SWIFT_DARWIN_XCRUN_TOOLCHAIN}" "-f" "clang"
VARIABLE CLANG_EXEC
ERROR "Unable to find Clang driver")
@@ -57,12 +60,47 @@
endif()
endif()
- # We always infer the SWIFT_LIBRARY_PATH from SWIFT_EXEC unless
- # SWIFT_LIBRARY_PATH is specified explicitly.
- if(NOT SWIFT_LIBRARY_PATH)
- get_filename_component(tmp_dir "${SWIFT_EXEC}" DIRECTORY)
- get_filename_component(tmp_dir "${tmp_dir}" DIRECTORY)
- set(SWIFT_LIBRARY_PATH "${tmp_dir}/lib/swift")
+ # Set LIBRARY_PATH and either RPATH or RPATH_BASE. To build and run
+ # for multiple platforms, RPATH_BASE must be set instead of RPATH. It
+ # is the platform-independent runtime library directory. The platform
+ # subdirectory name will be appended to form a different RPATH for
+ # on platform.
+
+ # If requested, use Swift-in-the-OS. This way, the benchmarks may be built
+ # standalone on the host, and the binaries can run directly from a temp dir
+ # on any target machine. Of course, this factors out performance changes in
+ # stdlib or overlays.
+ if(SWIFT_BENCHMARK_USE_OS_LIBRARIES)
+ set(SWIFT_RPATH "/usr/lib/swift")
+ endif()
+
+ # When SWIFT_LIBRARY_PATH is specified explicitly for a standalone
+ # build, use it as an absolute RPATH_BASE. This only works when
+ # running benchmarks on the host machine. Otherwise, RPATH is set
+ # assuming that libraries will be installed later (manually)
+ # relative to the benchmark binaries.
+ #
+ # When not building standalone, SWIFT_LIBRARY_PATH is set by LLVM
+ # cmake to the build directory for Swift dylibs. Otherwise, assume
+ # that the dylibs are built relative to SWIFT_EXEC.
+ if(SWIFT_LIBRARY_PATH AND SWIFT_BENCHMARK_BUILT_STANDALONE)
+ if (NOT SWIFT_RPATH)
+ set(SWIFT_RPATH_BASE ${SWIFT_LIBRARY_PATH})
+ endif()
+ else()
+ if (NOT SWIFT_LIBRARY_PATH)
+ get_filename_component(tmp_dir "${SWIFT_EXEC}" DIRECTORY)
+ get_filename_component(tmp_dir "${tmp_dir}" DIRECTORY)
+ set(SWIFT_LIBRARY_PATH "${tmp_dir}/lib/swift")
+ endif()
+ if (NOT SWIFT_RPATH)
+ # If the benchmarks are built against a local swift build, assume that
+ # either the benchmarks will be installed in the swift build dir,
+ # or the swift libraries will be installed in the benchmark location in
+ # a platform specific subdirectory.
+ # This way, performance always factors in changes to the libraries.
+ set(SWIFT_RPATH_BASE "@executable_path/../lib/swift")
+ endif()
endif()
endmacro()
@@ -571,6 +609,11 @@
# both do exactly the same thing with both sets of arguments. It also lets us
# avoid issues around code-signing.
if (is_darwin)
+ if (SWIFT_RPATH)
+ set(SWIFT_LINK_RPATH "${SWIFT_RPATH}")
+ else()
+ set(SWIFT_LINK_RPATH "${SWIFT_RPATH_BASE}/${BENCH_COMPILE_ARCHOPTS_PLATFORM}")
+ endif()
add_custom_command(
OUTPUT "${OUTPUT_EXEC}"
DEPENDS
@@ -593,7 +636,7 @@
"-lobjc"
"-L${SWIFT_LIBRARY_PATH}/${BENCH_COMPILE_ARCHOPTS_PLATFORM}"
"-Xlinker" "-rpath"
- "-Xlinker" "@executable_path/../lib/swift/${BENCH_COMPILE_ARCHOPTS_PLATFORM}"
+ "-Xlinker" "${SWIFT_LINK_RPATH}"
${bench_library_objects}
${bench_driver_objects}
${SWIFT_BENCH_OBJFILES}
@@ -612,7 +655,7 @@
"${SWIFT_EXEC}"
"-O"
"-target" "${target}"
- "-L${SWIFT_LIBRARY_PATH}/${BENCH_COMPILE_ARCHOPTS_PLATFORM}"
+ "-L${SWIFT_LIBRARY_PATH}"
${bench_library_objects}
${bench_driver_objects}
${SWIFT_BENCH_OBJFILES}
diff --git a/benchmark/scripts/build_script_helper.py b/benchmark/scripts/build_script_helper.py
new file mode 100755
index 0000000..1cd61ce
--- /dev/null
+++ b/benchmark/scripts/build_script_helper.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+
+from __future__ import print_function
+
+import argparse
+import os
+import shutil
+import subprocess
+
+
+def perform_build(args, swiftbuild_path, config, binary_name, opt_flag):
+ assert(config in ['debug', 'release'])
+ assert(binary_name in ['Benchmark_O', 'Benchmark_Onone'])
+ assert(opt_flag in ['-O', '-Onone'])
+
+ inner_build_dir = os.path.join(args.build_path, binary_name)
+ swiftbuild_args = [
+ swiftbuild_path,
+ '--package-path', args.package_path,
+ '--build-path', inner_build_dir,
+ '--configuration', config,
+ '-Xswiftc', '-Xllvm',
+ '-Xswiftc', '-align-module-to-page-size',
+ '-Xswiftc', opt_flag,
+ ]
+ if args.verbose:
+ swiftbuild_args.append('--verbose')
+ subprocess.call(swiftbuild_args)
+
+ # Copy the benchmark file into the final ./bin directory.
+ binpath = os.path.join(inner_build_dir, config, 'SwiftBench')
+ finalpath = os.path.join(args.build_path, 'bin', binary_name)
+ shutil.copy(binpath, finalpath)
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--verbose', '-v', action='store_true')
+ parser.add_argument('--package-path', type=str, required=True)
+ parser.add_argument('--build-path', type=str, required=True)
+ parser.add_argument('--toolchain', type=str, required=True)
+
+ args = parser.parse_args()
+
+ # Create our bin directory so we can copy in the binaries.
+ bin_dir = os.path.join(args.build_path, 'bin')
+ if not os.path.isdir(bin_dir):
+ os.makedirs(bin_dir)
+
+ swiftbuild_path = os.path.join(args.toolchain, 'usr', 'bin', 'swift-build')
+ perform_build(args, swiftbuild_path, 'debug', 'Benchmark_Onone', '-Onone')
+ perform_build(args, swiftbuild_path, 'release', 'Benchmark_O', '-O')
+
+
+if __name__ == "__main__":
+ main()
diff --git a/benchmark/utils/build_script_helper.py b/benchmark/utils/build_script_helper.py
deleted file mode 100755
index e5b873f..0000000
--- a/benchmark/utils/build_script_helper.py
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/usr/bin/env python
-
-from __future__ import print_function
-
-import argparse
-import os
-import subprocess
-
-
-def main():
- parser = argparse.ArgumentParser()
- parser.add_argument('--verbose', '-v', action='store_true')
- parser.add_argument('--package-path', type=str, required=True)
- parser.add_argument('--build-path', type=str, required=True)
- parser.add_argument('--toolchain', type=str, required=True)
-
- # Build the debug/release versions.
- args = parser.parse_args()
- swiftbuild_path = os.path.join(args.toolchain, 'usr', 'bin', 'swift-build')
- swiftbuild_args = [
- swiftbuild_path,
- '--package-path', args.package_path,
- '--build-path', args.build_path,
- '--configuration', 'debug',
- ]
- if args.verbose:
- swiftbuild_args.append('--verbose')
- subprocess.call(swiftbuild_args)
-
- swiftbuild_args = [
- swiftbuild_path,
- '--package-path', args.package_path,
- '--build-path', args.build_path,
- '--configuration', 'release',
- '-Xswiftc', '-Xllvm',
- '-Xswiftc', '-align-module-to-page-size',
- ]
- if args.verbose:
- swiftbuild_args.append('--verbose')
- subprocess.call(swiftbuild_args)
-
-
-if __name__ == "__main__":
- main()
diff --git a/cmake/modules/AddSwift.cmake b/cmake/modules/AddSwift.cmake
index f9e079e..368f717 100644
--- a/cmake/modules/AddSwift.cmake
+++ b/cmake/modules/AddSwift.cmake
@@ -1312,7 +1312,7 @@
# doing so will result in incorrect symbol resolution and linkage. We created
# import library targets when the library was added. Use that to adjust the
# link libraries.
- if(SWIFTLIB_SINGLE_SDK STREQUAL WINDOWS AND NOT CMAKE_HOST_SYSTEM_NAME STREQUAL Windows)
+ if(SWIFTLIB_SINGLE_SDK STREQUAL WINDOWS AND NOT CMAKE_SYSTEM_NAME STREQUAL Windows)
foreach(library_list LINK_LIBRARIES INTERFACE_LINK_LIBRARIES PRIVATE_LINK_LIBRARIES)
set(import_libraries)
foreach(library ${SWIFTLIB_SINGLE_${library_list}})
diff --git a/cmake/modules/SwiftComponents.cmake b/cmake/modules/SwiftComponents.cmake
index a637e31..cae4d32 100644
--- a/cmake/modules/SwiftComponents.cmake
+++ b/cmake/modules/SwiftComponents.cmake
@@ -84,6 +84,7 @@
else()
list(REMOVE_ITEM _SWIFT_DEFAULT_COMPONENTS "sourcekit-xpc-service")
endif()
+list(REMOVE_ITEM _SWIFT_DEFAULT_COMPONENTS "stdlib-experimental")
macro(swift_configure_components)
# Set the SWIFT_INSTALL_COMPONENTS variable to the default value if it is not passed in via -D
diff --git a/cmake/modules/SwiftSharedCMakeConfig.cmake b/cmake/modules/SwiftSharedCMakeConfig.cmake
index 76a731b..790d6cb 100644
--- a/cmake/modules/SwiftSharedCMakeConfig.cmake
+++ b/cmake/modules/SwiftSharedCMakeConfig.cmake
@@ -62,32 +62,34 @@
set(${product}_NATIVE_LLVM_TOOLS_PATH "${LLVM_TOOLS_BINARY_DIR}")
endif()
- if(CMAKE_CROSSCOMPILING)
- set(LLVM_NATIVE_BUILD_DIR "${LLVM_BINARY_DIR}/NATIVE")
- if(NOT EXISTS "${LLVM_NATIVE_BUILD_DIR}")
- message(FATAL_ERROR
- "Attempting to cross-compile swift standalone but no native LLVM build
- found. Please cross-compile LLVM as well.")
- endif()
+ if(SWIFT_INCLUDE_TOOLS)
+ if(CMAKE_CROSSCOMPILING)
+ set(LLVM_NATIVE_BUILD_DIR "${LLVM_BINARY_DIR}/NATIVE")
+ if(NOT EXISTS "${LLVM_NATIVE_BUILD_DIR}")
+ message(FATAL_ERROR
+ "Attempting to cross-compile swift standalone but no native LLVM build
+ found. Please cross-compile LLVM as well.")
+ endif()
- if(CMAKE_HOST_SYSTEM_NAME MATCHES Windows)
- set(HOST_EXECUTABLE_SUFFIX ".exe")
- endif()
+ if(CMAKE_HOST_SYSTEM_NAME MATCHES Windows)
+ set(HOST_EXECUTABLE_SUFFIX ".exe")
+ endif()
- if(NOT CMAKE_CONFIGURATION_TYPES)
- set(LLVM_TABLEGEN_EXE
- "${LLVM_NATIVE_BUILD_DIR}/bin/llvm-tblgen${HOST_EXECUTABLE_SUFFIX}")
+ if(NOT CMAKE_CONFIGURATION_TYPES)
+ set(LLVM_TABLEGEN_EXE
+ "${LLVM_NATIVE_BUILD_DIR}/bin/llvm-tblgen${HOST_EXECUTABLE_SUFFIX}")
+ else()
+ # NOTE: LLVM NATIVE build is always built Release, as is specified in
+ # CrossCompile.cmake
+ set(LLVM_TABLEGEN_EXE
+ "${LLVM_NATIVE_BUILD_DIR}/Release/bin/llvm-tblgen${HOST_EXECUTABLE_SUFFIX}")
+ endif()
else()
- # NOTE: LLVM NATIVE build is always built Release, as is specified in
- # CrossCompile.cmake
- set(LLVM_TABLEGEN_EXE
- "${LLVM_NATIVE_BUILD_DIR}/Release/bin/llvm-tblgen${HOST_EXECUTABLE_SUFFIX}")
- endif()
- else()
- find_program(LLVM_TABLEGEN_EXE "llvm-tblgen" HINTS ${LLVM_TOOLS_BINARY_DIR}
- NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
- if(LLVM_TABLEGEN_EXE STREQUAL "LLVM_TABLEGEN_EXE-NOTFOUND")
- message(FATAL_ERROR "Failed to find tablegen in ${LLVM_TOOLS_BINARY_DIR}")
+ find_program(LLVM_TABLEGEN_EXE "llvm-tblgen" HINTS ${LLVM_TOOLS_BINARY_DIR}
+ NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
+ if(LLVM_TABLEGEN_EXE STREQUAL "LLVM_TABLEGEN_EXE-NOTFOUND")
+ message(FATAL_ERROR "Failed to find tablegen in ${LLVM_TOOLS_BINARY_DIR}")
+ endif()
endif()
endif()
diff --git a/docs/WindowsBuild.md b/docs/WindowsBuild.md
index afc01ac..0f6d4fd 100644
--- a/docs/WindowsBuild.md
+++ b/docs/WindowsBuild.md
@@ -359,6 +359,7 @@
```cmd
md S:\b\llbuild
cd S:\b\llbuild
+set AR=llvm-ar
cmake -G Ninja^
-DCMAKE_BUILD_TYPE=RelWithDebInfo^
-DCMAKE_C_COMPILER=cl^
diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def
index 056beca..03320e3 100644
--- a/include/swift/AST/DiagnosticsParse.def
+++ b/include/swift/AST/DiagnosticsParse.def
@@ -1377,21 +1377,6 @@
"unexpected version number in '%0' attribute for non-specific platform "
"'*'", (StringRef))
-// autoclosure
-ERROR(attr_autoclosure_expected_r_paren,PointsToFirstBadToken,
- "expected ')' in @autoclosure", ())
-ERROR(attr_noescape_conflicts_escaping_autoclosure,none,
- "@noescape conflicts with @autoclosure(escaping)", ())
-ERROR(attr_noescape_implied_by_autoclosure,none,
- "@noescape is implied by @autoclosure and should not be "
- "redundantly specified", ())
-ERROR(attr_autoclosure_escaping_deprecated,none,
- "@autoclosure(escaping) has been removed; use @autoclosure @escaping instead",
- ())
-ERROR(attr_noescape_deprecated,none,
- "@noescape is the default and has been removed",
- ())
-
// convention
ERROR(convention_attribute_expected_lparen,none,
"expected '(' after 'convention' attribute", ())
diff --git a/include/swift/AST/DiagnosticsSIL.def b/include/swift/AST/DiagnosticsSIL.def
index 8943975..180a9cd 100644
--- a/include/swift/AST/DiagnosticsSIL.def
+++ b/include/swift/AST/DiagnosticsSIL.def
@@ -116,6 +116,33 @@
ERROR(objc_selector_malformed,none,"the type ObjectiveC.Selector is malformed",
())
+// Invalid escaping capture diagnostics.
+ERROR(escaping_inout_capture,none,
+ "escaping closure captures 'inout' parameter %0", (Identifier))
+NOTE(inout_param_defined_here,none,
+ "parameter %0 is declared 'inout'", (Identifier))
+ERROR(escaping_mutable_self_capture,none,
+ "escaping closure captures mutating 'self' parameter", ())
+
+ERROR(escaping_noescape_param_capture,none,
+ "escaping closure captures non-escaping parameter %0", (Identifier))
+NOTE(noescape_param_defined_here,none,
+ "parameter %0 is implicitly non-escaping", (Identifier))
+
+ERROR(escaping_noescape_var_capture,none,
+ "escaping closure captures non-escaping value", ())
+
+NOTE(value_captured_here,none,"captured here", ())
+
+NOTE(value_captured_transitively,none,
+ "captured indirectly by this call", ())
+
+ERROR(err_noescape_param_call,none,
+ "passing a %select{|closure which captures a }1non-escaping function "
+ "parameter %0 to a call to a non-escaping function parameter can allow "
+ "re-entrant modification of a variable",
+ (DeclName, unsigned))
+
// Definite initialization diagnostics.
NOTE(variable_defined_here,none,
"%select{variable|constant}0 defined here", (bool))
diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def
index f2bf2c6..cdc22f3 100644
--- a/include/swift/AST/DiagnosticsSema.def
+++ b/include/swift/AST/DiagnosticsSema.def
@@ -289,11 +289,6 @@
"declared closure result %0 is incompatible with contextual type %1",
(Type, Type))
-ERROR(err_noescape_param_call,none,
- "passing a %select{|closure which captures a }1non-escaping function "
- "parameter %0 to a call to a non-escaping function parameter can allow "
- "re-entrant modification of a variable",
- (DeclName, unsigned))
ERROR(cannot_call_function_value,none,
"cannot invoke value of function type with argument list '%0'",
(StringRef))
@@ -2900,21 +2895,6 @@
"%0, declared here, captures %1",
(Identifier, Identifier))
-ERROR(closure_implicit_capture_without_noescape,none,
- "escaping closures can only capture inout parameters explicitly by value",
- ())
-ERROR(closure_implicit_capture_mutating_self,none,
- "escaping closure cannot capture a mutating self parameter",
- ())
-NOTE(create_mutating_copy_or_capture_self,none,
- "create a mutating copy of self, or explicitly capture self for immutability",
- ())
-ERROR(nested_function_with_implicit_capture_argument,none,
- "nested function with %select{an |}0implicitly captured inout "
- "parameter%select{|s}0 can only be used as a non-escaping argument", (bool))
-ERROR(nested_function_escaping_inout_capture,none,
- "nested function cannot capture inout parameter and escape", ())
-
WARNING(recursive_accessor_reference,none,
"attempting to %select{access|modify}1 %0 within its own "
"%select{getter|setter}1", (Identifier, bool))
@@ -3039,19 +3019,10 @@
NOTE(silence_debug_description_in_interpolation_segment_call,none,
"use 'String(describing:)' to silence this warning", ())
-ERROR(invalid_noescape_use,none,
- "non-escaping %select{value|parameter}1 %0 may only be called",
- (Identifier, bool))
NOTE(noescape_parameter,none,
"parameter %0 is implicitly non-escaping",
(Identifier))
-ERROR(closure_noescape_use,none,
- "closure use of non-escaping parameter %0 may allow it to escape",
- (Identifier))
-ERROR(decl_closure_noescape_use,none,
- "declaration closing over non-escaping parameter %0 may allow it to escape",
- (Identifier))
ERROR(passing_noescape_to_escaping,none,
"passing non-escaping parameter %0 to function expecting an @escaping closure",
(Identifier))
@@ -3524,8 +3495,6 @@
// Functions
ERROR(attribute_requires_function_type,none,
"@%0 attribute only applies to function types", (StringRef))
-ERROR(attribute_not_supported,none,
- "this attribute is not supported", ())
ERROR(unsupported_convention,none,
"convention '%0' not supported", (StringRef))
ERROR(unreferenced_generic_parameter,none,
diff --git a/include/swift/AST/Pattern.h b/include/swift/AST/Pattern.h
index 869fd2b..e5655da 100644
--- a/include/swift/AST/Pattern.h
+++ b/include/swift/AST/Pattern.h
@@ -221,7 +221,9 @@
void print(llvm::raw_ostream &OS,
const PrintOptions &Options = PrintOptions()) const;
- void dump() const;
+ LLVM_ATTRIBUTE_DEPRECATED(
+ void dump() const LLVM_ATTRIBUTE_USED,
+ "only for use within the debugger");
/// walk - This recursively walks the AST rooted at this pattern.
Pattern *walk(ASTWalker &walker);
diff --git a/include/swift/AST/TypeRepr.h b/include/swift/AST/TypeRepr.h
index 188dc2f..e31d9f7 100644
--- a/include/swift/AST/TypeRepr.h
+++ b/include/swift/AST/TypeRepr.h
@@ -160,7 +160,9 @@
void print(raw_ostream &OS, const PrintOptions &Opts = PrintOptions()) const;
void print(ASTPrinter &Printer, const PrintOptions &Opts) const;
- void dump() const;
+ LLVM_ATTRIBUTE_DEPRECATED(
+ void dump() const LLVM_ATTRIBUTE_USED,
+ "only for use within the debugger");
/// Clone the given type representation.
TypeRepr *clone(const ASTContext &ctx) const;
diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h
index af96e0e..0c49b95 100644
--- a/include/swift/AST/Types.h
+++ b/include/swift/AST/Types.h
@@ -622,10 +622,14 @@
return getRecursiveProperties().isLValue();
}
- /// Is a type with these properties materializable: that is, is it a
- /// first-class value type?
+ /// Is this a first-class value type, meaning it is not an InOutType or a
+ /// tuple type containing an InOutType?
bool isMaterializable();
+ /// Is this a non-escaping type, that is, a non-escaping function type or a
+ /// tuple type containing a non-escaping type?
+ bool isNoEscape() const;
+
/// Determine whether the type is dependent on DynamicSelf.
bool hasDynamicSelfType() const {
return getRecursiveProperties().hasDynamicSelf();
@@ -647,11 +651,6 @@
return getRecursiveProperties().hasDependentMember();
}
- /// Check if this type is a valid type for the LHS of an assignment.
- /// This mainly means hasLValueType(), but empty tuples and tuples of empty
- /// tuples also qualify.
- bool isAssignableType();
-
/// isExistentialType - Determines whether this type is an existential type,
/// whose real (runtime) type is unknown but which is known to conform to
/// some set of protocols. Protocol and protocol-conformance types are
diff --git a/include/swift/Migrator/FixitFilter.h b/include/swift/Migrator/FixitFilter.h
index b6c64d6..cf5e705 100644
--- a/include/swift/Migrator/FixitFilter.h
+++ b/include/swift/Migrator/FixitFilter.h
@@ -127,8 +127,6 @@
Info.ID == diag::where_inside_brackets.ID ||
Info.ID == diag::selector_construction_suggest.ID ||
Info.ID == diag::selector_literal_deprecated_suggest.ID ||
- Info.ID == diag::attr_noescape_deprecated.ID ||
- Info.ID == diag::attr_autoclosure_escaping_deprecated.ID ||
Info.ID == diag::attr_warn_unused_result_removed.ID ||
Info.ID == diag::any_as_anyobject_fixit.ID ||
Info.ID == diag::deprecated_protocol_composition.ID ||
diff --git a/include/swift/Reflection/ReflectionContext.h b/include/swift/Reflection/ReflectionContext.h
index 84392c1..656ff88 100644
--- a/include/swift/Reflection/ReflectionContext.h
+++ b/include/swift/Reflection/ReflectionContext.h
@@ -202,7 +202,7 @@
RangeEnd - RangeStart);
auto findMachOSectionByName = [&](std::string Name)
- -> std::pair<std::pair<const char *, const char *>, uint64_t> {
+ -> std::pair<const char *, const char *> {
for (unsigned I = 0; I < NumSect; ++I) {
auto S = reinterpret_cast<typename T::Section *>(
SectionsBuf + (I * sizeof(typename T::Section)));
@@ -213,9 +213,9 @@
auto LocalSectStart =
reinterpret_cast<const char *>(SectBufData + RemoteSecStart - RangeStart);
auto LocalSectEnd = reinterpret_cast<const char *>(LocalSectStart + S->size);
- return {{LocalSectStart, LocalSectEnd}, 0};
+ return {LocalSectStart, LocalSectEnd};
}
- return {{nullptr, nullptr}, 0};
+ return {nullptr, nullptr};
};
auto FieldMdSec = findMachOSectionByName("__swift5_fieldmd");
@@ -225,24 +225,24 @@
auto TypeRefMdSec = findMachOSectionByName("__swift5_typeref");
auto ReflStrMdSec = findMachOSectionByName("__swift5_reflstr");
- if (FieldMdSec.first.first == nullptr &&
- AssocTySec.first.first == nullptr &&
- BuiltinTySec.first.first == nullptr &&
- CaptureSec.first.first == nullptr &&
- TypeRefMdSec.first.first == nullptr &&
- ReflStrMdSec.first.first == nullptr)
+ if (FieldMdSec.first == nullptr &&
+ AssocTySec.first == nullptr &&
+ BuiltinTySec.first == nullptr &&
+ CaptureSec.first == nullptr &&
+ TypeRefMdSec.first == nullptr &&
+ ReflStrMdSec.first == nullptr)
return false;
auto LocalStartAddress = reinterpret_cast<uint64_t>(SectBuf.get());
auto RemoteStartAddress = static_cast<uint64_t>(RangeStart);
ReflectionInfo info = {
- {{FieldMdSec.first.first, FieldMdSec.first.second}, 0},
- {{AssocTySec.first.first, AssocTySec.first.second}, 0},
- {{BuiltinTySec.first.first, BuiltinTySec.first.second}, 0},
- {{CaptureSec.first.first, CaptureSec.first.second}, 0},
- {{TypeRefMdSec.first.first, TypeRefMdSec.first.second}, 0},
- {{ReflStrMdSec.first.first, ReflStrMdSec.first.second}, 0},
+ {{FieldMdSec.first, FieldMdSec.second}, 0},
+ {{AssocTySec.first, AssocTySec.second}, 0},
+ {{BuiltinTySec.first, BuiltinTySec.second}, 0},
+ {{CaptureSec.first, CaptureSec.second}, 0},
+ {{TypeRefMdSec.first, TypeRefMdSec.second}, 0},
+ {{ReflStrMdSec.first, ReflStrMdSec.second}, 0},
LocalStartAddress,
RemoteStartAddress};
@@ -310,7 +310,7 @@
sizeof(llvm::object::coff_section) * COFFFileHdr->NumberOfSections);
auto findCOFFSectionByName = [&](llvm::StringRef Name)
- -> std::pair<std::pair<const char *, const char *>, uint32_t> {
+ -> std::pair<const char *, const char *> {
for (size_t i = 0; i < COFFFileHdr->NumberOfSections; ++i) {
const llvm::object::coff_section *COFFSec =
reinterpret_cast<const llvm::object::coff_section *>(
@@ -336,45 +336,43 @@
End -= 8;
}
- return {{Begin, End}, 0};
+ return {Begin, End};
}
- return {{nullptr, nullptr}, 0};
+ return {nullptr, nullptr};
};
- std::pair<std::pair<const char *, const char *>, uint32_t> CaptureSec =
+ std::pair<const char *, const char *> CaptureSec =
findCOFFSectionByName(".sw5cptr");
- std::pair<std::pair<const char *, const char *>, uint32_t> TypeRefMdSec =
+ std::pair<const char *, const char *> TypeRefMdSec =
findCOFFSectionByName(".sw5tyrf");
- std::pair<std::pair<const char *, const char *>, uint32_t> FieldMdSec =
+ std::pair<const char *, const char *> FieldMdSec =
findCOFFSectionByName(".sw5flmd");
- std::pair<std::pair<const char *, const char *>, uint32_t> AssocTySec =
+ std::pair<const char *, const char *> AssocTySec =
findCOFFSectionByName(".sw5asty");
- std::pair<std::pair<const char *, const char *>, uint32_t> BuiltinTySec =
+ std::pair<const char *, const char *> BuiltinTySec =
findCOFFSectionByName(".sw5bltn");
- std::pair<std::pair<const char *, const char *>, uint32_t> ReflStrMdSec =
+ std::pair<const char *, const char *> ReflStrMdSec =
findCOFFSectionByName(".sw5rfst");
- if (FieldMdSec.first.first == nullptr &&
- AssocTySec.first.first == nullptr &&
- BuiltinTySec.first.first == nullptr &&
- CaptureSec.first.first == nullptr &&
- TypeRefMdSec.first.first == nullptr &&
- ReflStrMdSec.first.first == nullptr)
+ if (FieldMdSec.first == nullptr &&
+ AssocTySec.first == nullptr &&
+ BuiltinTySec.first == nullptr &&
+ CaptureSec.first == nullptr &&
+ TypeRefMdSec.first == nullptr &&
+ ReflStrMdSec.first == nullptr)
return false;
+
auto LocalStartAddress = reinterpret_cast<uintptr_t>(DOSHdrBuf.get());
auto RemoteStartAddress =
static_cast<uintptr_t>(ImageStart.getAddressData());
ReflectionInfo Info = {
- {{FieldMdSec.first.first, FieldMdSec.first.second}, FieldMdSec.second},
- {{AssocTySec.first.first, AssocTySec.first.second}, AssocTySec.second},
- {{BuiltinTySec.first.first, BuiltinTySec.first.second},
- BuiltinTySec.second},
- {{CaptureSec.first.first, CaptureSec.first.second}, CaptureSec.second},
- {{TypeRefMdSec.first.first, TypeRefMdSec.first.second},
- TypeRefMdSec.second},
- {{ReflStrMdSec.first.first, ReflStrMdSec.first.second},
- ReflStrMdSec.second},
+ {{FieldMdSec.first, FieldMdSec.second}, 0},
+ {{AssocTySec.first, AssocTySec.second}, 0},
+ {{BuiltinTySec.first, BuiltinTySec.second}, 0},
+ {{CaptureSec.first, CaptureSec.second}, 0},
+ {{TypeRefMdSec.first, TypeRefMdSec.second}, 0},
+ {{ReflStrMdSec.first, ReflStrMdSec.second}, 0},
LocalStartAddress,
RemoteStartAddress};
this->addReflectionInfo(Info);
@@ -450,7 +448,7 @@
auto StrTab = reinterpret_cast<const char *>(StrTabBuf.get());
auto findELFSectionByName = [&](std::string Name)
- -> std::pair<std::pair<const char *, const char *>, uint64_t> {
+ -> std::pair<const char *, const char *> {
// Now for all the sections, find their name.
for (const typename T::Section *Hdr : SecHdrVec) {
uint32_t Offset = Hdr->sh_name;
@@ -462,9 +460,9 @@
auto SecSize = Hdr->sh_size;
auto SecBuf = this->getReader().readBytes(SecStart, SecSize);
auto SecContents = reinterpret_cast<const char *>(SecBuf.get());
- return {{SecContents, SecContents + SecSize}, 0};
+ return {SecContents, SecContents + SecSize};
}
- return {{nullptr, nullptr}, 0};
+ return {nullptr, nullptr};
};
auto FieldMdSec = findELFSectionByName("swift5_fieldmd");
@@ -476,12 +474,12 @@
// We succeed if at least one of the sections is present in the
// ELF executable.
- if (FieldMdSec.first.first == nullptr &&
- AssocTySec.first.first == nullptr &&
- BuiltinTySec.first.first == nullptr &&
- CaptureSec.first.first == nullptr &&
- TypeRefMdSec.first.first == nullptr &&
- ReflStrMdSec.first.first == nullptr)
+ if (FieldMdSec.first == nullptr &&
+ AssocTySec.first == nullptr &&
+ BuiltinTySec.first == nullptr &&
+ CaptureSec.first == nullptr &&
+ TypeRefMdSec.first == nullptr &&
+ ReflStrMdSec.first == nullptr)
return false;
auto LocalStartAddress = reinterpret_cast<uint64_t>(Buf.get());
@@ -489,15 +487,12 @@
static_cast<uint64_t>(ImageStart.getAddressData());
ReflectionInfo info = {
- {{FieldMdSec.first.first, FieldMdSec.first.second}, FieldMdSec.second},
- {{AssocTySec.first.first, AssocTySec.first.second}, AssocTySec.second},
- {{BuiltinTySec.first.first, BuiltinTySec.first.second},
- BuiltinTySec.second},
- {{CaptureSec.first.first, CaptureSec.first.second}, CaptureSec.second},
- {{TypeRefMdSec.first.first, TypeRefMdSec.first.second},
- TypeRefMdSec.second},
- {{ReflStrMdSec.first.first, ReflStrMdSec.first.second},
- ReflStrMdSec.second},
+ {{FieldMdSec.first, FieldMdSec.second}, 0},
+ {{AssocTySec.first, AssocTySec.second}, 0},
+ {{BuiltinTySec.first, BuiltinTySec.second}, 0},
+ {{CaptureSec.first, CaptureSec.second}, 0},
+ {{TypeRefMdSec.first, TypeRefMdSec.second}, 0},
+ {{ReflStrMdSec.first, ReflStrMdSec.second}, 0},
LocalStartAddress,
RemoteStartAddress};
diff --git a/include/swift/SIL/SILLocation.h b/include/swift/SIL/SILLocation.h
index 126bb60..1a86a4d 100644
--- a/include/swift/SIL/SILLocation.h
+++ b/include/swift/SIL/SILLocation.h
@@ -687,6 +687,8 @@
: SILLocation(D, MandatoryInlinedKind, F) {}
MandatoryInlinedLocation(SourceLoc L, unsigned F)
: SILLocation(L, MandatoryInlinedKind, F) {}
+ MandatoryInlinedLocation(DebugLoc L, unsigned F)
+ : SILLocation(L, MandatoryInlinedKind, F) {}
};
/// Used on the instruction performing auto-generated cleanup such as
diff --git a/include/swift/SILOptimizer/PassManager/Passes.def b/include/swift/SILOptimizer/PassManager/Passes.def
index 605e470..e048e0b 100644
--- a/include/swift/SILOptimizer/PassManager/Passes.def
+++ b/include/swift/SILOptimizer/PassManager/Passes.def
@@ -134,6 +134,8 @@
"Indirect Call Devirtualization")
PASS(DiagnoseInfiniteRecursion, "diagnose-infinite-recursion",
"Diagnose Infinitely-Recursive Code")
+PASS(DiagnoseInvalidEscapingCaptures, "diagnose-invalid-escaping-captures",
+ "Diagnose Invalid Escaping Captures")
PASS(DiagnoseStaticExclusivity, "diagnose-static-exclusivity",
"Static Enforcement of Law of Exclusivity")
PASS(DiagnoseUnreachable, "diagnose-unreachable",
diff --git a/include/swift/SILOptimizer/Utils/PerformanceInlinerUtils.h b/include/swift/SILOptimizer/Utils/PerformanceInlinerUtils.h
index 27da047..6a6e221 100644
--- a/include/swift/SILOptimizer/Utils/PerformanceInlinerUtils.h
+++ b/include/swift/SILOptimizer/Utils/PerformanceInlinerUtils.h
@@ -312,6 +312,7 @@
SILLoopInfo *LI;
llvm::DenseMap<const SILBasicBlock *, BlockInfo *> BlockInfos;
std::vector<BlockInfo> BlockInfoStorage;
+ bool valid = false;
BlockInfo *getBlockInfo(const SILBasicBlock *BB) {
BlockInfo *BI = BlockInfos[BB];
@@ -381,15 +382,22 @@
public:
ShortestPathAnalysis(SILFunction *F, SILLoopInfo *LI) : F(F), LI(LI) { }
- bool isValid() const { return !BlockInfos.empty(); }
+ bool isValid() const { return valid; }
/// Compute the distances. The function \p getApplyLength returns the length
/// of a function call.
template <typename Func>
void analyze(ColdBlockInfo &CBI, Func getApplyLength) {
assert(!isValid());
+ valid = true;
+ unsigned numBlocks = F->size();
- BlockInfoStorage.resize(F->size());
+ // As the complexity of the analysis is more than linear with the number of blocks,
+ // disable it for huge functions. In this case inlining will be less aggressive.
+ if (numBlocks > 2000)
+ return;
+
+ BlockInfoStorage.resize(numBlocks);
// First step: compute the length of the blocks.
unsigned BlockIdx = 0;
@@ -433,6 +441,11 @@
/// shortest path in the function.
int getScopeLength(SILBasicBlock *BB, int LoopDepth) {
assert(BB->getParent() == F);
+
+ // Return a conservative default if the analysis was not done due to a high number of blocks.
+ if (BlockInfos.empty())
+ return ColdBlockLength;
+
if (LoopDepth >= MaxNumLoopLevels)
LoopDepth = MaxNumLoopLevels - 1;
return getBlockInfo(BB)->getScopeLength(LoopDepth);
diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp
index cd4581f..a6a1d45 100644
--- a/lib/AST/ASTPrinter.cpp
+++ b/lib/AST/ASTPrinter.cpp
@@ -985,6 +985,33 @@
printTypeLoc(TP->getTypeLoc());
}
+/// Determines if we are required to print the name of a property declaration,
+/// or if we can elide it by printing a '_' instead.
+static bool mustPrintPropertyName(VarDecl *decl, PrintOptions opts) {
+ // If we're not allowed to omit the name, we must print it.
+ if (!opts.OmitNameOfInaccessibleProperties) return true;
+
+ // If it contributes to the parent's storage, we must print it because clients
+ // need to be able to directly access the storage.
+ // FIXME: We might be able to avoid printing names for some of these
+ // if we serialized references to them using field indices.
+ if (contributesToParentTypeStorage(decl)) return true;
+
+ // If it's public or @usableFromInline, we must print the name because it's a
+ // visible entry-point.
+ if (isPublicOrUsableFromInline(decl)) return true;
+
+ // If it has an initial value, we must print the name because it's used in
+ // the mangled name of the initializer expression generator function.
+ // FIXME: We _could_ figure out a way to generate an entry point
+ // for the initializer expression without revealing the name. We just
+ // don't have a mangling for it.
+ if (decl->hasInitialValue()) return true;
+
+ // If none of those are true, we can elide the name of the variable.
+ return false;
+}
+
void PrintAST::printPattern(const Pattern *pattern) {
switch (pattern->getKind()) {
case PatternKind::Any:
@@ -995,16 +1022,13 @@
auto named = cast<NamedPattern>(pattern);
auto decl = named->getDecl();
recordDeclLoc(decl, [&]{
- if (Options.OmitNameOfInaccessibleProperties &&
- contributesToParentTypeStorage(decl) &&
- !isPublicOrUsableFromInline(decl) &&
- // FIXME: We need to figure out a way to generate an entry point
- // for the initializer expression without revealing the name.
- !decl->hasInitialValue())
- Printer << "_";
- else
+ // FIXME: This always returns true now, because of the FIXMEs listed in
+ // mustPrintPropertyName.
+ if (mustPrintPropertyName(decl, Options))
Printer.printName(named->getBoundName());
- });
+ else
+ Printer << "_";
+ });
break;
}
diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp
index 81c5283..748dde7 100644
--- a/lib/AST/DeclContext.cpp
+++ b/lib/AST/DeclContext.cpp
@@ -309,7 +309,8 @@
/// domains, this ensures that only sufficiently-conservative access patterns
/// are used.
ResilienceExpansion DeclContext::getResilienceExpansion() const {
- for (const auto *dc = this; dc->isLocalContext(); dc = dc->getParent()) {
+ for (const auto *dc = getLocalContext(); dc && dc->isLocalContext();
+ dc = dc->getParent()) {
// Default argument initializer contexts have their resilience expansion
// set when they're type checked.
if (isa<DefaultArgumentInitializer>(dc)) {
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 59226e5..da9a401 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -543,19 +543,6 @@
return false;
}
-
-bool TypeBase::isAssignableType() {
- if (hasLValueType()) return true;
- if (auto tuple = getAs<TupleType>()) {
- for (auto eltType : tuple->getElementTypes()) {
- if (!eltType->isAssignableType())
- return false;
- }
- return true;
- }
- return false;
-}
-
Type TypeBase::getRValueType() {
// If the type is not an lvalue, this is a no-op.
if (!hasLValueType())
@@ -3079,6 +3066,24 @@
return unresolvedDepMemTy;
}
+bool TypeBase::isNoEscape() const {
+ auto type = getCanonicalType();
+
+ if (auto silFuncTy = dyn_cast<SILFunctionType>(type))
+ return silFuncTy->isNoEscape();
+
+ if (auto funcTy = dyn_cast<FunctionType>(type))
+ return funcTy->isNoEscape();
+
+ if (auto tupleTy = dyn_cast<TupleType>(type)) {
+ for (auto eltTy : tupleTy.getElementTypes())
+ if (eltTy->isNoEscape())
+ return true;
+ }
+
+ return false;
+}
+
static Type getConcreteTypeForSuperclassTraversing(Type t) {
if (t->isExistentialType()) {
return t->getExistentialLayout().getSuperclass();
diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp
index 15222c1..5752c36 100644
--- a/lib/ClangImporter/ImportType.cpp
+++ b/lib/ClangImporter/ImportType.cpp
@@ -515,6 +515,7 @@
type->getElementType(), ImportTypeKind::Abstract,
false /* No NSUIntegerAsInt */, Bridgeability::None,
OptionalTypeKind::OTK_None);
+ if (!element) { return Type(); }
unsigned count = type->getNumElements();
// Import vector-of-one as the element type.
if (count == 1) { return element; }
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 3fa1141..8d1f51c 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -1999,31 +1999,10 @@
StringRef Text = Tok.getText();
SourceLoc Loc = consumeToken();
- bool isAutoclosureEscaping = false;
- SourceRange autoclosureEscapingParenRange;
StringRef conventionName;
StringRef witnessMethodProtocol;
- // Handle @autoclosure(escaping)
- if (attr == TAK_autoclosure) {
- // We need to do a bit of lookahead here to make sure we parse a (weird)
- // type like: "@autoclosure (escaping) -> Int" correctly (escaping is the
- // name of a type here). We also want to support the case where the
- // function type coming up is a typealias, e.g. "@autoclosure (escaping) T".
- if (Tok.is(tok::l_paren) && peekToken().getText() == "escaping") {
- Parser::BacktrackingScope Backtrack(*this);
- consumeToken(tok::l_paren);
- consumeToken(tok::identifier);
- isAutoclosureEscaping =
- Tok.is(tok::r_paren) && peekToken().isNot(tok::arrow);
- }
-
- if (isAutoclosureEscaping) {
- autoclosureEscapingParenRange.Start = consumeToken(tok::l_paren);
- consumeToken(tok::identifier);
- autoclosureEscapingParenRange.End = consumeToken(tok::r_paren);
- }
- } else if (attr == TAK_convention) {
+ if (attr == TAK_convention) {
SourceLoc LPLoc;
if (!consumeIfNotAtStartOfLine(tok::l_paren)) {
if (!justChecking)
@@ -2086,48 +2065,10 @@
switch (attr) {
default: break;
case TAK_autoclosure:
- // Handle @autoclosure(escaping)
- if (isAutoclosureEscaping) {
- // @noescape @autoclosure(escaping) makes no sense.
- if (Attributes.has(TAK_noescape)) {
- diagnose(Loc, diag::attr_noescape_conflicts_escaping_autoclosure);
- } else {
- diagnose(Loc, diag::attr_autoclosure_escaping_deprecated)
- .fixItReplace(autoclosureEscapingParenRange, " @escaping ");
- }
- Attributes.setAttr(TAK_escaping, Loc);
- } else if (Attributes.has(TAK_noescape) && !isInSILMode()) {
- diagnose(Loc, diag::attr_noescape_implied_by_autoclosure);
- }
- break;
-
- case TAK_noescape:
- // You can't specify @noescape and @escaping together.
- if (Attributes.has(TAK_escaping)) {
- diagnose(Loc, diag::attr_escaping_conflicts_noescape);
- return false;
- }
-
- // @noescape after @autoclosure is redundant.
- if (Attributes.has(TAK_autoclosure) && !isInSILMode()) {
- diagnose(Loc, diag::attr_noescape_implied_by_autoclosure);
- }
-
- // @noescape is deprecated and no longer used
- // In SIL, the polarity of @escaping is reversed.
- // @escaping is the default and @noescape is explicit.
- if (!isInSILMode()) {
- diagnose(Loc, diag::attr_noescape_deprecated)
- .fixItRemove({Attributes.AtLoc, Loc});
- }
- break;
case TAK_escaping:
- // You can't specify @noescape and @escaping together.
- if (Attributes.has(TAK_noescape)) {
- diagnose(Loc, diag::attr_escaping_conflicts_noescape);
- return false;
- }
+ case TAK_noescape:
break;
+
case TAK_out:
case TAK_in:
case TAK_owned:
diff --git a/lib/SIL/LinearLifetimeChecker.cpp b/lib/SIL/LinearLifetimeChecker.cpp
index 661fff4..09d630f 100644
--- a/lib/SIL/LinearLifetimeChecker.cpp
+++ b/lib/SIL/LinearLifetimeChecker.cpp
@@ -486,6 +486,25 @@
// have been detected by initializing our consuming uses. So we are done.
if (consumingUses.size() == 1 &&
consumingUses[0].getParent() == value->getParentBlock()) {
+ // Check if any of our non consuming uses are not in the parent block. We
+ // flag those as additional use after frees. Any in the same block, we would
+ // have flagged.
+ if (llvm::any_of(nonConsumingUses, [&](BranchPropagatedUser user) {
+ return user.getParent() != value->getParentBlock();
+ })) {
+ state.error.handleUseAfterFree([&] {
+ llvm::errs() << "Function: '" << value->getFunction()->getName()
+ << "'\n"
+ << "Found use after free due to unvisited non lifetime "
+ "ending uses?!\n"
+ << "Value: " << *value << " Remaining Users:\n";
+ for (const auto &user : nonConsumingUses) {
+ llvm::errs() << "User: " << *user.getInst();
+ }
+ llvm::errs() << "\n";
+ });
+ }
+
return state.error;
}
diff --git a/lib/SIL/SILLocation.cpp b/lib/SIL/SILLocation.cpp
index 7a86050..015c415 100644
--- a/lib/SIL/SILLocation.cpp
+++ b/lib/SIL/SILLocation.cpp
@@ -217,6 +217,9 @@
if (L.isInTopLevel())
return MandatoryInlinedLocation::getModuleLocation(L.getSpecialFlags());
+ if (L.isDebugInfoLoc())
+ return MandatoryInlinedLocation(L.getDebugInfoLoc(), L.getSpecialFlags());
+
llvm_unreachable("Cannot construct Inlined loc from the given location.");
}
diff --git a/lib/SILGen/SILGenPattern.cpp b/lib/SILGen/SILGenPattern.cpp
index 19448f5..ed0ea22 100644
--- a/lib/SILGen/SILGenPattern.cpp
+++ b/lib/SILGen/SILGenPattern.cpp
@@ -2497,11 +2497,48 @@
PatternMatchEmission &Emission;
};
+namespace {
+
+struct UnexpectedEnumCaseInfo {
+ CanType subjectTy;
+ ManagedValue metatype;
+ ManagedValue rawValue;
+ NullablePtr<const EnumDecl> singleObjCEnum;
+
+ UnexpectedEnumCaseInfo(CanType subjectTy, ManagedValue metatype,
+ ManagedValue rawValue, const EnumDecl *singleObjCEnum)
+ : subjectTy(subjectTy), metatype(metatype), rawValue(rawValue),
+ singleObjCEnum(singleObjCEnum) {
+ assert(isa<MetatypeInst>(metatype));
+ assert(bool(rawValue) && isa<UncheckedTrivialBitCastInst>(rawValue));
+ assert(singleObjCEnum->hasRawType());
+ }
+
+ UnexpectedEnumCaseInfo(CanType subjectTy, ManagedValue valueMetatype)
+ : subjectTy(subjectTy), metatype(valueMetatype), rawValue(),
+ singleObjCEnum() {
+ assert(isa<ValueMetatypeInst>(valueMetatype));
+ }
+
+ bool isSingleObjCEnum() const { return singleObjCEnum.isNonNull(); }
+
+ void cleanupInstsIfUnused() {
+ auto f = [](SILValue v) {
+ if (!v->use_empty())
+ return;
+ cast<SingleValueInstruction>(v)->eraseFromParent();
+ };
+ f(metatype.getValue());
+ if (rawValue)
+ f(rawValue.getValue());
+ }
+};
+
+} // end anonymous namespace
+
static void emitDiagnoseOfUnexpectedEnumCaseValue(SILGenFunction &SGF,
SILLocation loc,
- ManagedValue value,
- Type subjectTy,
- const EnumDecl *enumDecl) {
+ UnexpectedEnumCaseInfo ueci) {
ASTContext &ctx = SGF.getASTContext();
auto diagnoseFailure = ctx.getDiagnoseUnexpectedEnumCaseValue();
if (!diagnoseFailure) {
@@ -2509,25 +2546,6 @@
return;
}
- assert(enumDecl->isObjC());
- assert(enumDecl->hasRawType());
- assert(value.getType().isTrivial(SGF.F));
-
- // Get the enum type as an Any.Type value.
- SILType metatypeType = SGF.getLoweredType(
- AbstractionPattern::getOpaque(),
- MetatypeType::get(subjectTy));
- SILValue metatype = SGF.B.createMetatype(loc, metatypeType);
-
- // Bitcast the enum value to its raw type. (This is only safe for @objc
- // enums.)
- SILType loweredRawType = SGF.getLoweredType(enumDecl->getRawType());
- assert(loweredRawType.isTrivial(SGF.F));
- assert(loweredRawType.isObject());
- auto rawValue = SGF.B.createUncheckedTrivialBitCast(loc, value,
- loweredRawType);
- auto materializedRawValue = rawValue.materialize(SGF, loc);
-
auto genericSig = diagnoseFailure->getGenericSignature();
auto subs = SubstitutionMap::get(
genericSig,
@@ -2537,10 +2555,10 @@
assert(genericParam->getIndex() < 2);
switch (genericParam->getIndex()) {
case 0:
- return subjectTy;
+ return ueci.subjectTy;
case 1:
- return enumDecl->getRawType();
+ return ueci.singleObjCEnum.get()->getRawType();
default:
llvm_unreachable("wrong generic signature for expected case value");
@@ -2548,16 +2566,14 @@
},
LookUpConformanceInSignature(*genericSig));
- SGF.emitApplyOfLibraryIntrinsic(loc, diagnoseFailure, subs,
- {ManagedValue::forUnmanaged(metatype),
- materializedRawValue},
- SGFContext());
+ SGF.emitApplyOfLibraryIntrinsic(
+ loc, diagnoseFailure, subs,
+ {ueci.metatype, ueci.rawValue.materialize(SGF, loc)}, SGFContext());
}
static void emitDiagnoseOfUnexpectedEnumCase(SILGenFunction &SGF,
SILLocation loc,
- ManagedValue value,
- Type subjectTy) {
+ UnexpectedEnumCaseInfo ueci) {
ASTContext &ctx = SGF.getASTContext();
auto diagnoseFailure = ctx.getDiagnoseUnexpectedEnumCase();
if (!diagnoseFailure) {
@@ -2565,21 +2581,14 @@
return;
}
- // Get the switched-upon value's type.
- SILType metatypeType = SGF.getLoweredType(
- AbstractionPattern::getOpaque(),
- MetatypeType::get(subjectTy)->getCanonicalType());
- ManagedValue metatype = SGF.B.createValueMetatype(loc, metatypeType, value);
-
auto diagnoseSignature = diagnoseFailure->getGenericSignature();
auto genericArgsMap = SubstitutionMap::get(
diagnoseSignature,
- [&](SubstitutableType *type) -> Type { return subjectTy; },
+ [&](SubstitutableType *type) -> Type { return ueci.subjectTy; },
LookUpConformanceInSignature(*diagnoseSignature));
SGF.emitApplyOfLibraryIntrinsic(loc, diagnoseFailure, genericArgsMap,
- metatype,
- SGFContext());
+ ueci.metatype, SGFContext());
}
static void switchCaseStmtSuccessCallback(SILGenFunction &SGF,
@@ -2778,6 +2787,38 @@
return {subjectMV.copy(*this, S), CastConsumptionKind::TakeAlways};
}());
+ // If we need to diagnose an unexpected enum case or unexpected enum case
+ // value, we need access to a value metatype for the subject. Emit this state
+ // now before we emit the actual switch to ensure that the subject has not
+ // been consumed.
+ auto unexpectedEnumCaseInfo = ([&]() -> UnexpectedEnumCaseInfo {
+ SILLocation loc = RegularLocation::getAutoGeneratedLocation();
+ CanType canSubjectTy = subjectTy->getCanonicalType();
+ CanType metatypeType = MetatypeType::get(canSubjectTy)->getCanonicalType();
+ SILType loweredMetatypeType =
+ getLoweredType(AbstractionPattern::getOpaque(), metatypeType);
+ ManagedValue value = subject.getFinalManagedValue();
+
+ if (auto *singleEnumDecl = canSubjectTy->getEnumOrBoundGenericEnum()) {
+ if (singleEnumDecl->isObjC()) {
+ auto metatype = ManagedValue::forUnmanaged(
+ B.createMetatype(loc, loweredMetatypeType));
+
+ // Bitcast the enum value to its raw type. (This is only safe for @objc
+ // enums.)
+ SILType loweredRawType = getLoweredType(singleEnumDecl->getRawType());
+ assert(loweredRawType.isTrivial(F));
+ assert(loweredRawType.isObject());
+ auto rawValue =
+ B.createUncheckedTrivialBitCast(loc, value, loweredRawType);
+ return {canSubjectTy, metatype, rawValue, singleEnumDecl};
+ }
+ }
+
+ return {canSubjectTy,
+ B.createValueMetatype(loc, loweredMetatypeType, value)};
+ }());
+
auto failure = [&](SILLocation location) {
// If we fail to match anything, we trap. This can happen with a switch
// over an @objc enum, which may contain any value of its underlying type,
@@ -2786,18 +2827,12 @@
SWIFT_DEFER { B.createUnreachable(location); };
// Special case: if it's a single @objc enum, we can print the raw value.
- CanType ty = S->getSubjectExpr()->getType()->getCanonicalType();
- if (auto *singleEnumDecl = ty->getEnumOrBoundGenericEnum()) {
- if (singleEnumDecl->isObjC()) {
- emitDiagnoseOfUnexpectedEnumCaseValue(*this, location,
- subject.getFinalManagedValue(),
- subjectTy, singleEnumDecl);
- return;
- }
+ if (unexpectedEnumCaseInfo.isSingleObjCEnum()) {
+ emitDiagnoseOfUnexpectedEnumCaseValue(*this, location,
+ unexpectedEnumCaseInfo);
+ return;
}
- emitDiagnoseOfUnexpectedEnumCase(*this, location,
- subject.getFinalManagedValue(),
- subjectTy);
+ emitDiagnoseOfUnexpectedEnumCase(*this, location, unexpectedEnumCaseInfo);
};
// Set up an initial clause matrix.
@@ -2823,6 +2858,10 @@
} else {
B.emitBlock(contBB);
}
+
+ // Now that we have emitted everything, see if our unexpected enum case info
+ // metatypes were actually used. If not, delete them.
+ unexpectedEnumCaseInfo.cleanupInstsIfUnused();
}
void SILGenFunction::emitSwitchFallthrough(FallthroughStmt *S) {
diff --git a/lib/SILOptimizer/Mandatory/CMakeLists.txt b/lib/SILOptimizer/Mandatory/CMakeLists.txt
index 2eb58e0..58b5537 100644
--- a/lib/SILOptimizer/Mandatory/CMakeLists.txt
+++ b/lib/SILOptimizer/Mandatory/CMakeLists.txt
@@ -7,6 +7,7 @@
DIMemoryUseCollector.cpp
DataflowDiagnostics.cpp
DiagnoseInfiniteRecursion.cpp
+ DiagnoseInvalidEscapingCaptures.cpp
DiagnoseStaticExclusivity.cpp
DiagnoseUnreachable.cpp
GuaranteedARCOpts.cpp
diff --git a/lib/SILOptimizer/Mandatory/DiagnoseInvalidEscapingCaptures.cpp b/lib/SILOptimizer/Mandatory/DiagnoseInvalidEscapingCaptures.cpp
new file mode 100644
index 0000000..f0a7fe2
--- /dev/null
+++ b/lib/SILOptimizer/Mandatory/DiagnoseInvalidEscapingCaptures.cpp
@@ -0,0 +1,455 @@
+//===--- DiagnoseInvalidEscapingCaptures.cpp ------------------------------===//
+//
+// 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 implements a diagnostic pass to diagnose escaping closures that
+// capture mutable storage locations or noescape function values.
+//
+//===----------------------------------------------------------------------===//
+
+#include "swift/AST/ASTContext.h"
+#include "swift/AST/DiagnosticsSIL.h"
+#include "swift/AST/Types.h"
+#include "swift/SIL/ApplySite.h"
+#include "swift/SIL/InstructionUtils.h"
+#include "swift/SIL/SILArgument.h"
+#include "swift/SIL/SILBasicBlock.h"
+#include "swift/SIL/SILInstruction.h"
+#include "swift/SILOptimizer/PassManager/Transforms.h"
+#include "llvm/Support/Debug.h"
+
+using namespace swift;
+
+template <typename... T, typename... U>
+static InFlightDiagnostic diagnose(ASTContext &Context, SILLocation loc,
+ Diag<T...> diag, U &&... args) {
+ return Context.Diags.diagnose(loc.getSourceLoc(), diag,
+ std::forward<U>(args)...);
+}
+
+template <typename... T, typename... U>
+static InFlightDiagnostic diagnose(ASTContext &Context, SourceLoc loc,
+ Diag<T...> diag, U &&... args) {
+ return Context.Diags.diagnose(loc, diag,
+ std::forward<U>(args)...);
+}
+
+// Check if a use of a value derived from a partial_apply can cause the
+// closure to escape. For "pass-through" uses that build a new value from
+// the partial_apply, followUses() is called to evaluate the uses of the
+// derived value.
+template <typename FollowUse>
+static bool checkNoEscapePartialApplyUse(Operand *oper, FollowUse followUses) {
+ SILInstruction *user = oper->getUser();
+
+ if (isa<ConvertEscapeToNoEscapeInst>(user) ||
+ isa<CopyBlockWithoutEscapingInst>(user))
+ return false;
+
+ // Ignore uses that are totally uninteresting. partial_apply [stack] is
+ // terminated by a dealloc_stack instruction.
+ if (isIncidentalUse(user) || onlyAffectsRefCount(user) ||
+ isa<DeallocStackInst>(user))
+ return false;
+
+ // Before checking conversions in general below (getSingleValueCopyOrCast),
+ // check for convert_function to [without_actually_escaping]. Assume such
+ // conversion are not actually escaping without following their uses.
+ if (auto *CFI = dyn_cast<ConvertFunctionInst>(user)) {
+ if (CFI->withoutActuallyEscaping())
+ return false;
+ }
+
+ // Look through copies, borrows, and conversions.
+ if (SingleValueInstruction *copy = getSingleValueCopyOrCast(user)) {
+ // Only follow the copied operand. Other operands are incidental,
+ // as in the second operand of mark_dependence.
+ if (oper->getOperandNumber() == 0)
+ followUses(copy);
+
+ return false;
+ }
+
+ // @noescape block storage can be passed as an Optional (Nullable).
+ if (auto *EI = dyn_cast<EnumInst>(user)) {
+ followUses(EI);
+ return false;
+ }
+
+ // Look through Phis.
+ if (auto *BI = dyn_cast<BranchInst>(user)) {
+ const SILPhiArgument *arg = BI->getArgForOperand(oper);
+ followUses(arg);
+ return false;
+ }
+
+ if (auto *CBI = dyn_cast<CondBranchInst>(user)) {
+ const SILPhiArgument *arg = CBI->getArgForOperand(oper);
+ if (arg) // If the use isn't the branch condition, follow it.
+ followUses(arg);
+ return false;
+ }
+
+ // Look through ObjC closures.
+ if (auto *SI = dyn_cast<StoreInst>(user)) {
+ if (oper->getOperandNumber() == StoreInst::Src) {
+ if (auto *PBSI = dyn_cast<ProjectBlockStorageInst>(
+ SI->getDest())) {
+ SILValue storageAddr = PBSI->getOperand();
+ // The closure is stored to block storage. Recursively visit all
+ // uses of any initialized block storage values derived from this
+ // storage address..
+ for (Operand *oper : storageAddr->getUses()) {
+ if (auto *IBS = dyn_cast<InitBlockStorageHeaderInst>(oper->getUser()))
+ followUses(IBS);
+ }
+ return false;
+ }
+ }
+ }
+
+ if (auto *PAI = dyn_cast<PartialApplyInst>(user)) {
+ // Recurse through partial_apply chains.
+ if (oper->get() == PAI->getCallee()) {
+ followUses(PAI);
+ return false;
+ }
+
+ // Look through re-abstraction thunks.
+ if (isPartialApplyOfReabstractionThunk(PAI)) {
+ // However, first check for withoutActuallyEscaping, which is always
+ // a valid non-escaping use.
+ SILFunction *thunkDef = PAI->getReferencedFunction();
+ if (!thunkDef->isWithoutActuallyEscapingThunk())
+ followUses(PAI);
+ return false;
+ }
+ }
+
+ // Anything else is flagged as an escaping use.
+ return true;
+}
+
+const ParamDecl *getParamDeclFromOperand(SILValue value) {
+ if (auto *arg = dyn_cast<SILArgument>(value))
+ if (auto *decl = dyn_cast_or_null<ParamDecl>(arg->getDecl()))
+ return decl;
+
+ return nullptr;
+}
+
+static bool checkForEscapingPartialApplyUses(PartialApplyInst *PAI) {
+ // Avoid exponential path exploration.
+ SmallVector<Operand *, 8> uses;
+ llvm::SmallDenseSet<Operand *, 8> visited;
+ auto uselistInsert = [&](Operand *operand) {
+ if (visited.insert(operand).second)
+ uses.push_back(operand);
+ };
+
+ for (Operand *use : PAI->getUses())
+ uselistInsert(use);
+
+
+ // Search for any uses of the closure that might potentially escape.
+ bool foundEscapingUse = false;
+ while (!uses.empty()) {
+ Operand *oper = uses.pop_back_val();
+ foundEscapingUse |= checkNoEscapePartialApplyUse(oper, [&](SILValue V) {
+ for (Operand *use : V->getUses())
+ uselistInsert(use);
+ });
+ }
+
+ // If there aren't any, we're fine.
+ return foundEscapingUse;
+}
+
+// Given a partial_apply forming a closure, together with one of its operands,
+// find a usage of the corresponding argument inside the closure body, and
+// diagnose it as a capture use.
+//
+// This makes a best-effort attempt at finding a "good" capture usage; it may
+// not emit anything.
+//
+// The \c DC parameter is the DeclContext of the original function being
+// analyzed by this diagnostic pass. We use it to distinguish calls of closures
+// from calls of other unrelated functions, by checking the DeclContext of the
+// called closure.
+static void diagnoseCaptureLoc(ASTContext &Context, DeclContext *DC,
+ PartialApplyInst *PAI, Operand *oper) {
+ assert(DC != nullptr &&
+ "Invalid capture in function with no source location information");
+
+ SmallVector<Operand *, 8> uses;
+ llvm::SmallDenseSet<Operand *, 8> visited;
+ auto uselistInsert = [&](Operand *operand) {
+ if (visited.insert(operand).second)
+ uses.push_back(operand);
+ };
+
+ auto lookInsideClosure = [&](ApplySite site, Operand *oper) -> bool {
+ auto *F = site.getCalleeFunction();
+ if (F == nullptr || F->empty())
+ return false;
+
+ auto *otherDC = F->getDeclContext();
+ if (otherDC == nullptr || DC == nullptr ||
+ !otherDC->isChildContextOf(DC))
+ return false;
+
+ // Map an operand of an apply instruction to an argument inside
+ // the callee.
+ auto args = F->getArguments();
+ auto argIndex = site.getCalleeArgIndex(*oper);
+ auto arg = args[argIndex];
+
+ // Look for a usage of the callee argument.
+ for (Operand *use : arg->getUses())
+ uselistInsert(use);
+
+ return true;
+ };
+
+ lookInsideClosure(PAI, oper);
+
+ while (!uses.empty()) {
+ Operand *oper = uses.pop_back_val();
+ SILInstruction *user = oper->getUser();
+
+ if (isIncidentalUse(user) || onlyAffectsRefCount(user))
+ continue;
+
+ // Look through copies, borrows, and conversions.
+ if (SingleValueInstruction *copy = getSingleValueCopyOrCast(user)) {
+ // Only follow the copied operand. Other operands are incidental,
+ // as in the second operand of mark_dependence.
+ if (oper->getOperandNumber() == 0) {
+ for (auto *use : copy->getUses())
+ uselistInsert(use);
+ continue;
+ }
+ }
+
+ // If the usage is a capture of the value by another closure, look inside
+ // the body of that closure.
+ if (auto site = ApplySite::isa(user)) {
+ if (lookInsideClosure(site, oper)) {
+ diagnose(Context, site.getLoc(), diag::value_captured_transitively);
+ continue;
+ }
+ }
+
+ // Otherwise, we might have found one of the "real" usages of the capture.
+ // Diagnose it here.
+ SILValue val = oper->get();
+ SILLocation loc = val.getLoc();
+ if (loc.isASTNode<VarDecl>())
+ loc = user->getLoc();
+ diagnose(Context, loc, diag::value_captured_here);
+ }
+}
+
+// Diagnose this partial_apply if it captures a non-escaping value and has
+// an escaping use.
+static void checkPartialApply(ASTContext &Context, DeclContext *DC,
+ PartialApplyInst *PAI) {
+ // Re-abstraction thunks are not useful to look at. We'll diagnose the
+ // original closure instead.
+ if (isPartialApplyOfReabstractionThunk(PAI))
+ return;
+
+ ApplySite apply(PAI);
+
+ // Collect any non-escaping captures.
+ SmallVector<Operand *, 2> inoutCaptures;
+ SmallVector<Operand *, 2> noEscapeCaptures;
+
+ for (auto &oper : apply.getArgumentOperands()) {
+ SILValue value = oper.get();
+
+ // Captures of inout parameters cannot escape.
+ if (apply.getArgumentConvention(oper)
+ == SILArgumentConvention::Indirect_InoutAliasable)
+ inoutCaptures.push_back(&oper);
+
+ // Captures of noescape function types or tuples containing noescape
+ // function types cannot escape.
+ if (value->getType().getASTType()->isNoEscape()) {
+ noEscapeCaptures.push_back(&oper);
+ }
+ }
+
+ // A partial_apply without non-escaping captures is always valid.
+ if (inoutCaptures.empty() && noEscapeCaptures.empty())
+ return;
+
+ // A partial_apply without escaping uses is always valid.
+ if (!checkForEscapingPartialApplyUses(PAI))
+ return;
+
+ // Otherwise, we have at least one escaping use of a partial_apply
+ // capturing a non-escaping value. We need to emit diagnostics.
+
+ // First, diagnose the inout captures, if any.
+ for (auto inoutCapture : inoutCaptures) {
+ auto *param = getParamDeclFromOperand(inoutCapture->get());
+ if (param->isSelfParameter())
+ diagnose(Context, PAI->getLoc(), diag::escaping_mutable_self_capture);
+ else {
+ diagnose(Context, PAI->getLoc(), diag::escaping_inout_capture,
+ param->getName());
+ diagnose(Context, param->getLoc(), diag::inout_param_defined_here,
+ param->getName());
+ }
+
+ diagnoseCaptureLoc(Context, DC, PAI, inoutCapture);
+ }
+
+ // Finally, diagnose captures of values with noescape type.
+ for (auto noEscapeCapture : noEscapeCaptures) {
+ if (auto *param = getParamDeclFromOperand(noEscapeCapture->get())) {
+ diagnose(Context, PAI->getLoc(), diag::escaping_noescape_param_capture,
+ param->getName());
+ diagnose(Context, param->getLoc(), diag::noescape_param_defined_here,
+ param->getName());
+ } else {
+ diagnose(Context, PAI->getLoc(), diag::escaping_noescape_var_capture);
+ }
+
+ diagnoseCaptureLoc(Context, DC, PAI, noEscapeCapture);
+ }
+}
+
+// Enforce exclusivity restrictions on recursive uses of non-escaping closures.
+// Exclusivity requires a Non-Escaping Recursion Restriction rule (SE-0176):
+// A non-escaping closure A may not be recursively invoked during the
+// execution of a non-escaping closure B which captures the same local
+// variable or inout parameter unless:
+// - A is defined within B or
+// - A is a local function declaration which is referenced directly by B.
+//
+// This is conservatively approximated with a Non-Escaping Parameter Call
+// Restriction rule (NPCR), as implemented below:
+// A function may not call a non-escaping function parameter passing a
+// non-escaping function parameter as an argument.
+// For the purposes of this rule, a closure which captures a non-escaping
+// function parameter is treated the same as the parameter.
+//
+// Note: The compiler does not enforce recursion via
+// withoutActuallyEscaping. This undefined behavior is exposed to programmers.
+//
+// TODO: Verify that all uses of noescaping function arguments are SIL patterns
+// that are recognized below to prove that this diagnostic is complete.
+static void checkApply(ASTContext &Context, FullApplySite site) {
+ auto isNoEscapeParam = [&](SILValue value) -> const ParamDecl * {
+ // If the value is an escaping, do not enforce any restrictions.
+ if (!value->getType().getASTType()->isNoEscape())
+ return nullptr;
+
+ // If the value is not a function parameter, do not enforce any restrictions.
+ return getParamDeclFromOperand(value);
+ };
+
+ // If the callee is not a no-escape parameter, there is nothing to check.
+ auto callee = site.getCalleeOrigin();
+ if (!isNoEscapeParam(callee))
+ return;
+
+ // See if any of our arguments are noescape parameters, or closures capturing
+ // noescape parameters.
+ SmallVector<std::pair<SILValue, bool>, 4> args;
+ llvm::SmallDenseSet<SILValue, 4> visited;
+ auto arglistInsert = [&](SILValue arg, bool capture) {
+ if (visited.insert(arg).second)
+ args.emplace_back(arg, capture);
+ };
+
+ for (auto arg : site.getArguments())
+ arglistInsert(arg, /*capture=*/false);
+
+ while (!args.empty()) {
+ auto pair = args.pop_back_val();
+ auto arg = pair.first;
+ bool capture = pair.second;
+
+ if (auto *CI = dyn_cast<ConversionInst>(arg)) {
+ arglistInsert(CI->getConverted(), /*capture=*/false);
+ continue;
+ }
+
+ // If one of our call arguments is a noescape parameter, diagnose the
+ // violation.
+ if (auto *param = isNoEscapeParam(arg)) {
+ diagnose(Context, site.getLoc(), diag::err_noescape_param_call,
+ param->getName(), capture);
+ return;
+ }
+
+ // If one of our call arguments is a closure, recursively visit all of
+ // the closure's captures.
+ if (auto *PAI = dyn_cast<PartialApplyInst>(arg)) {
+ ApplySite site(PAI);
+ for (auto arg : site.getArguments())
+ arglistInsert(arg, /*capture=*/true);
+ continue;
+ }
+ }
+}
+
+static void checkForViolationsAtInstruction(ASTContext &Context,
+ DeclContext *DC,
+ SILInstruction *I) {
+ if (auto *PAI = dyn_cast<PartialApplyInst>(I))
+ checkPartialApply(Context, DC, PAI);
+
+ if (isa<ApplyInst>(I) || isa<TryApplyInst>(I)) {
+ FullApplySite site(I);
+ checkApply(Context, site);
+ }
+}
+
+static void checkEscapingCaptures(SILFunction *F) {
+ if (F->empty())
+ return;
+
+ auto &Context =F->getASTContext();
+ auto *DC = F->getDeclContext();
+
+ for (auto &BB : *F) {
+ for (auto &I : BB)
+ checkForViolationsAtInstruction(Context, DC, &I);
+ }
+}
+
+namespace {
+
+class DiagnoseInvalidEscapingCaptures : public SILFunctionTransform {
+public:
+ DiagnoseInvalidEscapingCaptures() {}
+
+private:
+ void run() override {
+ SILFunction *F = getFunction();
+
+ // Don't rerun diagnostics on deserialized functions.
+ if (F->wasDeserializedCanonical())
+ return;
+
+ checkEscapingCaptures(F);
+ }
+};
+
+} // end anonymous namespace
+
+SILTransform *swift::createDiagnoseInvalidEscapingCaptures() {
+ return new DiagnoseInvalidEscapingCaptures();
+}
diff --git a/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp b/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp
index e8afc71..df09c54 100644
--- a/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp
+++ b/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp
@@ -672,10 +672,7 @@
// =============================================================================
// The data flow algorithm that drives diagnostics.
-// Forward declare verification entry points.
-#ifndef NDEBUG
-static void checkNoEscapePartialApply(PartialApplyInst *PAI);
-#endif
+// Forward declare verification entry point.
static void checkAccessedAddress(Operand *memOper, StorageMap &Accesses);
namespace {
@@ -863,20 +860,7 @@
checkForViolationAtApply(TAI, State);
return;
}
-#ifndef NDEBUG
- // FIXME: Once AllocBoxToStack is fixed to correctly set noescape
- // closure types, move this PartialApply verification into the
- // SILVerifier to better pinpoint the offending pass.
- if (auto *PAI = dyn_cast<PartialApplyInst>(&I)) {
- ApplySite apply(PAI);
- if (llvm::any_of(apply.getArgumentOperands(), [apply](Operand &oper) {
- return apply.getArgumentConvention(oper)
- == SILArgumentConvention::Indirect_InoutAliasable;
- })) {
- checkNoEscapePartialApply(PAI);
- }
- }
-#endif
+
// Sanity check to make sure entries are properly removed.
assert((!isa<ReturnInst>(&I) || State.Accesses->empty())
&& "Entries were not properly removed?!");
@@ -949,159 +933,6 @@
// =============================================================================
// Verification
-#ifndef NDEBUG
-// This must handle exactly the same SIL patterns as
-// swift::funcClosureForAppliedArg but in forward order.
-template <typename FollowUse>
-static void checkNoEscapePartialApplyUse(Operand *oper, FollowUse followUses) {
- SILInstruction *user = oper->getUser();
-
- // Ignore uses that are totally uninteresting. partial_apply [stack] is
- // terminated by a dealloc_stack instruction.
- if (isIncidentalUse(user) || onlyAffectsRefCount(user) ||
- isa<DeallocStackInst>(user))
- return;
-
- // Before checking conversions in general below (getSingleValueCopyOrCast),
- // check for convert_function to [without_actually_escaping]. Assume such
- // conversion are not actually escaping without following their uses.
- if (auto *CFI = dyn_cast<ConvertFunctionInst>(user)) {
- if (CFI->withoutActuallyEscaping())
- return;
- }
-
- // Look through copies, borrows, and conversions.
- if (SingleValueInstruction *copy = getSingleValueCopyOrCast(user)) {
- // Only follow the copied operand. Other operands are incidental,
- // as in the second operand of mark_dependence.
- if (oper->getOperandNumber() == 0)
- followUses(copy);
-
- return;
- }
-
- switch (user->getKind()) {
- default:
- break;
-
- // Look through Optionals.
- case SILInstructionKind::EnumInst:
- // @noescape block storage can be passed as an Optional (Nullable).
- followUses(cast<EnumInst>(user));
- return;
-
- // Look through Phis.
- case SILInstructionKind::BranchInst: {
- const SILPhiArgument *arg = cast<BranchInst>(user)->getArgForOperand(oper);
- followUses(arg);
- return;
- }
- case SILInstructionKind::CondBranchInst: {
- const SILPhiArgument *arg =
- cast<CondBranchInst>(user)->getArgForOperand(oper);
- if (arg) // If the use isn't the branch condition, follow it.
- followUses(arg);
- return;
- }
- // Look through ObjC closures.
- case SILInstructionKind::StoreInst:
- if (oper->getOperandNumber() == StoreInst::Src) {
- if (auto *PBSI = dyn_cast<ProjectBlockStorageInst>(
- cast<StoreInst>(user)->getDest())) {
- SILValue storageAddr = PBSI->getOperand();
- // The closure is stored to block storage. Recursively visit all
- // uses of any initialized block storage values derived from this
- // storage address..
- for (Operand *oper : storageAddr->getUses()) {
- if (auto *IBS = dyn_cast<InitBlockStorageHeaderInst>(oper->getUser()))
- followUses(IBS);
- }
- return;
- }
- }
- break;
-
- case SILInstructionKind::IsEscapingClosureInst:
- // May be generated by withoutActuallyEscaping.
- return;
-
- case SILInstructionKind::PartialApplyInst: {
- // Recurse through partial_apply to handle special cases before handling
- // ApplySites in general below.
- PartialApplyInst *PAI = cast<PartialApplyInst>(user);
- // Use the same logic as checkForViolationAtApply applied to a def-use
- // traversal.
- //
- // checkForViolationAtApply recurses through partial_apply chains.
- if (oper->get() == PAI->getCallee()) {
- followUses(PAI);
- return;
- }
- // checkForViolationAtApply also uses findClosuresForAppliedArg which in
- // turn checks isPartialApplyOfReabstractionThunk.
- //
- // A closure with @inout_aliasable arguments may be applied to a
- // thunk as "escaping", but as long as the thunk is only used as a
- // '@noescape" type then it is safe.
- if (isPartialApplyOfReabstractionThunk(PAI)) {
- // Don't follow thunks that were generated by withoutActuallyEscaping.
- SILFunction *thunkDef = PAI->getReferencedFunction();
- if (!thunkDef->isWithoutActuallyEscapingThunk())
- followUses(PAI);
- return;
- }
- // Handle this use like a normal applied argument.
- break;
- }
- };
-
- // Handle ApplySites in general after checking PartialApply above.
- if (isa<ApplySite>(user)) {
- SILValue arg = oper->get();
- auto argumentFnType = getSILFunctionTypeForValue(arg);
- if (argumentFnType && argumentFnType->isNoEscape()) {
- // Verify that the inverse operation, finding a partial_apply from a
- // @noescape argument, is consistent.
- TinyPtrVector<PartialApplyInst *> partialApplies;
- findClosuresForFunctionValue(arg, partialApplies);
- assert(!partialApplies.empty()
- && "cannot find partial_apply from @noescape function argument");
- return;
- }
- llvm::dbgs() << "Applied argument must be @noescape function type: " << *arg;
- }
- else
- llvm::dbgs() << "Unexpected partial_apply use: " << *user;
-
- llvm_unreachable("A partial_apply with @inout_aliasable may only be "
- "used as a @noescape function type argument.");
-}
-
-// If a partial apply has @inout_aliasable arguments, it may only be used as
-// a @noescape function type in a way that is recognized by
-// DiagnoseStaticExclusivity.
-static void checkNoEscapePartialApply(PartialApplyInst *PAI) {
- SmallVector<Operand *, 8> uses;
- // Avoid exponential path exploration.
- llvm::SmallDenseSet<Operand *, 8> visited;
- auto uselistInsert = [&](Operand *operand) {
- if (visited.insert(operand).second)
- uses.push_back(operand);
- };
-
- for (Operand *use : PAI->getUses())
- uselistInsert(use);
-
- while (!uses.empty()) {
- Operand *oper = uses.pop_back_val();
- checkNoEscapePartialApplyUse(oper, [&](SILValue V) {
- for (Operand *use : V->getUses())
- uselistInsert(use);
- });
- }
-}
-#endif
-
// Check that the given address-type operand is guarded by begin/end access
// markers.
static void checkAccessedAddress(Operand *memOper, StorageMap &Accesses) {
diff --git a/lib/SILOptimizer/PassManager/PassPipeline.cpp b/lib/SILOptimizer/PassManager/PassPipeline.cpp
index ca06e8b..0eaea4f 100644
--- a/lib/SILOptimizer/PassManager/PassPipeline.cpp
+++ b/lib/SILOptimizer/PassManager/PassPipeline.cpp
@@ -81,6 +81,7 @@
static void addMandatoryOptPipeline(SILPassPipelinePlan &P) {
P.startPipeline("Guaranteed Passes");
+ P.addDiagnoseInvalidEscapingCaptures();
P.addDiagnoseStaticExclusivity();
P.addCapturePromotion();
diff --git a/lib/SILOptimizer/Transforms/SimplifyCFG.cpp b/lib/SILOptimizer/Transforms/SimplifyCFG.cpp
index 638af9a..2a77459 100644
--- a/lib/SILOptimizer/Transforms/SimplifyCFG.cpp
+++ b/lib/SILOptimizer/Transforms/SimplifyCFG.cpp
@@ -81,6 +81,10 @@
ConstantFolder ConstFolder;
+ // True if the function has a large amount of blocks. In this case we turn off some expensive
+ // optimizations.
+ bool isVeryLargeFunction = false;
+
void constFoldingCallback(SILInstruction *I) {
// If a terminal instruction gets constant folded (like cond_br), it
// enables further simplify-CFG optimizations.
@@ -1226,11 +1230,13 @@
if (DestBB->getArgument(i) != BI->getArg(i)) {
SILValue Val = BI->getArg(i);
DestBB->getArgument(i)->replaceAllUsesWith(Val);
- if (auto *I = dyn_cast<SingleValueInstruction>(Val)) {
- // Replacing operands may trigger constant folding which then could
- // trigger other simplify-CFG optimizations.
- ConstFolder.addToWorklist(I);
- ConstFolder.processWorkList();
+ if (!isVeryLargeFunction) {
+ if (auto *I = dyn_cast<SingleValueInstruction>(Val)) {
+ // Replacing operands may trigger constant folding which then could
+ // trigger other simplify-CFG optimizations.
+ ConstFolder.addToWorklist(I);
+ ConstFolder.processWorkList();
+ }
}
} else {
// We must be processing an unreachable part of the cfg with a cycle.
@@ -1290,7 +1296,7 @@
// If this unconditional branch has BBArgs, check to see if duplicating the
// destination would allow it to be simplified. This is a simple form of jump
// threading.
- if (!BI->getArgs().empty() &&
+ if (!isVeryLargeFunction && !BI->getArgs().empty() &&
tryJumpThreading(BI))
return true;
@@ -3067,6 +3073,9 @@
LLVM_DEBUG(llvm::dbgs() << "### Run SimplifyCFG on " << Fn.getName() << '\n');
+ // Disable some expensive optimizations if the function is huge.
+ isVeryLargeFunction = (Fn.size() > 10000);
+
// First remove any block not reachable from the entry.
bool Changed = removeUnreachableBlocks(Fn);
diff --git a/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp b/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp
index 25ba688..72724f4 100644
--- a/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp
+++ b/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp
@@ -418,6 +418,10 @@
getWeight(SILBasicBlock *BB, Weight CallerWeight) {
assert(BB->getParent() == F);
+ // Return a conservative default if the analysis was not done due to a high number of blocks.
+ if (BlockInfos.empty())
+ return Weight(CallerWeight.ScopeLength + ColdBlockLength, CallerWeight.LoopWeight);
+
SILLoop *Loop = LI->getLoopFor(BB);
if (!Loop) {
// We are not in a loop. So just account the length of our function scope
diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp
index 4e6f3ad..616386f 100644
--- a/lib/Sema/CSApply.cpp
+++ b/lib/Sema/CSApply.cpp
@@ -2856,10 +2856,8 @@
auto tupleTy =
TupleType::get(TupleTypeElt(paramTy, ctx.Id_dynamicMember), ctx);
- auto loc = nameLoc;
- Expr *index = TupleExpr::create(ctx, loc, argExpr, ctx.Id_dynamicMember,
- loc, loc, /*hasTrailingClosure*/ false,
- /*implicit*/ true);
+ Expr *index =
+ TupleExpr::createImplicit(ctx, argExpr, ctx.Id_dynamicMember);
index->setType(tupleTy);
cs.cacheType(index);
@@ -2867,7 +2865,7 @@
return buildSubscript(
base, index, ctx.Id_dynamicMember,
/*trailingClosure*/ false, cs.getConstraintLocator(expr),
- /*isImplicit*/ false, AccessSemantics::Ordinary, overload);
+ /*isImplicit*/ true, AccessSemantics::Ordinary, overload);
}
Type getTypeOfDynamicMemberIndex(const SelectedOverload &overload) {
@@ -7222,46 +7220,6 @@
// Try closing the existential, if there is one.
closeExistential(result, locator);
- // Extract all arguments.
- auto *CEA = arg;
-
- // The argument is either a ParenExpr or TupleExpr.
- ArrayRef<Expr *> arguments;
-
- SmallVector<Expr *, 1> Scratch;
- if (auto *TE = dyn_cast<TupleExpr>(CEA))
- arguments = TE->getElements();
- else if (auto *PE = dyn_cast<ParenExpr>(CEA)) {
- Scratch.push_back(PE->getSubExpr());
- arguments = makeArrayRef(Scratch);
- }
- else {
- Scratch.push_back(apply->getArg());
- arguments = makeArrayRef(Scratch);
- }
-
- for (auto arg: arguments) {
- bool isNoEscape = false;
- while (1) {
- if (auto AFT = cs.getType(arg)->getAs<AnyFunctionType>()) {
- isNoEscape = isNoEscape || AFT->isNoEscape();
- }
-
- if (auto conv = dyn_cast<ImplicitConversionExpr>(arg))
- arg = conv->getSubExpr();
- else if (auto *PE = dyn_cast<ParenExpr>(arg))
- arg = PE->getSubExpr();
- else
- break;
- }
- if (!isNoEscape) {
- if (auto DRE = dyn_cast<DeclRefExpr>(arg))
- if (auto FD = dyn_cast<FuncDecl>(DRE->getDecl())) {
- tc.addEscapingFunctionAsArgument(FD, apply);
- }
- }
- }
-
if (unwrapResult)
return forceUnwrapResult(result);
diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp
index 873c0ed..7f74879 100644
--- a/lib/Sema/CSSimplify.cpp
+++ b/lib/Sema/CSSimplify.cpp
@@ -1641,12 +1641,12 @@
return getTypeMatchFailure(locator);
// FIXME; Feels like a hack...nothing actually "conforms" here, and
- // we need to disallow conversions from @noescape functions to Any.
+ // we need to disallow conversions from types containing @noescape
+ // functions to Any.
// Conformance to 'Any' always holds.
if (type2->isAny()) {
- auto *fnTy = type1->getAs<FunctionType>();
- if (!fnTy || !fnTy->isNoEscape())
+ if (!type1->isNoEscape())
return getTypeMatchSuccess();
if (shouldAttemptFixes()) {
@@ -1835,21 +1835,19 @@
return getTypeMatchFailure(locator);
}
- // Disallow bindings of noescape functions to type variables that
- // represent an opened archetype. If we allowed this it would allow
- // the noescape function to potentially escape.
- if (auto *fnTy = type->getAs<FunctionType>()) {
- if (fnTy->isNoEscape() && typeVar->getImpl().getGenericParameter()) {
- if (shouldAttemptFixes()) {
- auto *fix = MarkExplicitlyEscaping::create(
- *this, getConstraintLocator(locator));
- if (recordFix(fix))
- return getTypeMatchFailure(locator);
-
- // Allow no-escape function to be bound with recorded fix.
- } else {
+ // Disallow bindings of types containing noescape functions to type
+ // variables that represent an opened generic parameter. If we allowed
+ // this it would allow noescape functions to potentially escape.
+ if (type->isNoEscape() && typeVar->getImpl().getGenericParameter()) {
+ if (shouldAttemptFixes()) {
+ auto *fix = MarkExplicitlyEscaping::create(
+ *this, getConstraintLocator(locator));
+ if (recordFix(fix))
return getTypeMatchFailure(locator);
- }
+
+ // Allow no-escape function to be bound with recorded fix.
+ } else {
+ return getTypeMatchFailure(locator);
}
}
@@ -2413,23 +2411,21 @@
type2->isExistentialType()) {
// Penalize conversions to Any, and disallow conversions of
- // noescape functions to Any.
+ // types containing noescape functions to Any.
if (kind >= ConstraintKind::Conversion && type2->isAny()) {
- if (auto *fnTy = type1->getAs<FunctionType>()) {
- if (fnTy->isNoEscape()) {
- if (shouldAttemptFixes()) {
- auto &ctx = getASTContext();
- auto *fix = MarkExplicitlyEscaping::create(
- *this, getConstraintLocator(locator), ctx.TheAnyType);
- if (recordFix(fix))
- return getTypeMatchFailure(locator);
-
- // Allow 'no-escape' functions to be converted to 'Any'
- // with a recorded fix that helps us to properly diagnose
- // such situations.
- } else {
+ if (type1->isNoEscape()) {
+ if (shouldAttemptFixes()) {
+ auto &ctx = getASTContext();
+ auto *fix = MarkExplicitlyEscaping::create(
+ *this, getConstraintLocator(locator), ctx.TheAnyType);
+ if (recordFix(fix))
return getTypeMatchFailure(locator);
- }
+
+ // Allow 'no-escape' functions to be converted to 'Any'
+ // with a recorded fix that helps us to properly diagnose
+ // such situations.
+ } else {
+ return getTypeMatchFailure(locator);
}
}
diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp
index 6ceaf46..f4d7fc4 100644
--- a/lib/Sema/MiscDiagnostics.cpp
+++ b/lib/Sema/MiscDiagnostics.cpp
@@ -63,7 +63,6 @@
bool isExprStmt) {
class DiagnoseWalker : public ASTWalker {
SmallPtrSet<Expr*, 4> AlreadyDiagnosedMetatypes;
- SmallPtrSet<DeclRefExpr*, 4> AlreadyDiagnosedNoEscapes;
SmallPtrSet<DeclRefExpr*, 4> AlreadyDiagnosedBitCasts;
// Keep track of acceptable DiscardAssignmentExpr's.
@@ -84,23 +83,6 @@
DiagnoseWalker(TypeChecker &TC, const DeclContext *DC, bool isExprStmt)
: IsExprStmt(isExprStmt), TC(TC), DC(DC) {}
- // Selector for the partial_application_of_function_invalid diagnostic
- // message.
- struct PartialApplication {
- enum : unsigned {
- MutatingMethod,
- SuperInit,
- SelfInit,
- };
- enum : unsigned {
- Error,
- CompatibilityWarning,
- };
- unsigned compatibilityWarning: 1;
- unsigned kind : 2;
- unsigned level : 29;
- };
-
// Not interested in going outside a basic expression.
std::pair<bool, Stmt *> walkToStmtPre(Stmt *S) override {
return { false, S };
@@ -129,9 +111,6 @@
checkUseOfMetaTypeName(Base);
}
- // Verify noescape parameter uses.
- checkNoEscapeParameterUse(DRE, Parent.getAsExpr(), OperandKind::None);
-
// Verify warn_unqualified_access uses.
checkUnqualifiedAccessUse(DRE);
@@ -155,12 +134,6 @@
if (auto *IOE = dyn_cast<InOutExpr>(SE->getBase()))
if (IOE->isImplicit())
AcceptableInOutExprs.insert(IOE);
-
- visitIndices(SE, [&](unsigned argIndex, Expr *arg) {
- arg = lookThroughArgument(arg);
- if (auto *DRE = dyn_cast<DeclRefExpr>(arg))
- checkNoEscapeParameterUse(DRE, SE, OperandKind::Argument);
- });
}
if (auto *KPE = dyn_cast<KeyPathExpr>(E)) {
@@ -170,21 +143,6 @@
}
}
- if (auto *AE = dyn_cast<CollectionExpr>(E)) {
- visitCollectionElements(AE, [&](unsigned argIndex, Expr *arg) {
- arg = lookThroughArgument(arg);
- if (auto *DRE = dyn_cast<DeclRefExpr>(arg))
- checkNoEscapeParameterUse(DRE, AE, OperandKind::Argument);
- });
- }
-
- // Check decl refs in withoutActuallyEscaping blocks.
- if (auto MakeEsc = dyn_cast<MakeTemporarilyEscapableExpr>(E)) {
- if (auto DRE =
- dyn_cast<DeclRefExpr>(MakeEsc->getNonescapingClosureValue()))
- checkNoEscapeParameterUse(DRE, MakeEsc, OperandKind::MakeEscapable);
- }
-
// Check function calls, looking through implicit conversions on the
// function and inspecting the arguments directly.
if (auto *Call = dyn_cast<ApplyExpr>(E)) {
@@ -221,7 +179,6 @@
ConcreteDeclRef callee;
if (auto *calleeDRE = dyn_cast<DeclRefExpr>(base)) {
- checkNoEscapeParameterUse(calleeDRE, Call, OperandKind::Callee);
checkForSuspiciousBitCasts(calleeDRE, Call);
callee = calleeDRE->getDeclRef();
@@ -267,12 +224,6 @@
unwrapped, operand);
}
}
-
- // Also give special treatment to noescape function arguments.
- arg = lookThroughArgument(arg);
-
- if (auto *DRE = dyn_cast<DeclRefExpr>(arg))
- checkNoEscapeParameterUse(DRE, Call, OperandKind::Argument);
});
}
@@ -339,25 +290,12 @@
}
}
- static void visitIndices(SubscriptExpr *subscript,
- llvm::function_ref<void(unsigned, Expr*)> fn) {
- auto *indexArgs = subscript->getIndex();
- argExprVisitArguments(indexArgs, fn);
- }
-
static void visitArguments(ApplyExpr *apply,
llvm::function_ref<void(unsigned, Expr*)> fn) {
auto *arg = apply->getArg();
argExprVisitArguments(arg, fn);
}
- static void visitCollectionElements(CollectionExpr *collection,
- llvm::function_ref<void(unsigned, Expr*)> fn) {
- auto elts = collection->getElements();
- for (auto i : indices(elts))
- fn(i, elts[i]);
- }
-
static Expr *lookThroughArgument(Expr *arg) {
while (1) {
if (auto conv = dyn_cast<ImplicitConversionExpr>(arg))
@@ -474,159 +412,6 @@
TC.diagnose(E->getStartLoc(), diag::value_of_module_type);
}
- class NoEscapeArgument {
- llvm::PointerIntPair<ParamDecl*, 1, bool> ParamAndIsCapture;
- public:
- NoEscapeArgument() {}
- NoEscapeArgument(ParamDecl *param, bool isCapture)
- : ParamAndIsCapture(param, isCapture) {
- assert(param);
- }
-
- explicit operator bool() const {
- return ParamAndIsCapture.getPointer() != nullptr;
- }
-
- ParamDecl *getDecl() const { return ParamAndIsCapture.getPointer(); }
- bool isDeclACapture() const { return ParamAndIsCapture.getInt(); }
-
- static NoEscapeArgument find(TypeChecker &tc, ValueDecl *decl,
- bool isCapture) {
- if (auto param = dyn_cast<ParamDecl>(decl)) {
- if (auto fnType =
- param->getInterfaceType()->getAs<AnyFunctionType>()) {
- if (fnType->isNoEscape())
- return { param, isCapture };
- }
- return {};
- }
-
- if (auto fn = dyn_cast<AbstractFunctionDecl>(decl)) {
- if (fn->getDeclContext()->isLocalContext()) {
- return findInCaptures(tc, fn);
- }
- return {};
- }
-
- // FIXME: captures of computed local vars? Can these be non-escaping?
- return {};
- }
-
- static NoEscapeArgument findInCaptures(TypeChecker &tc,
- AnyFunctionRef fn) {
- // Ensure we have accurate capture information for the function.
- tc.computeCaptures(fn);
-
- for (const auto &capture : fn.getCaptureInfo().getCaptures()) {
- if (capture.isDynamicSelfMetadata()) continue;
- if (auto param = find(tc, capture.getDecl(), true))
- return param;
- }
- return {};
- }
- };
-
- /// Enforce the exclusivity rule against calling a non-escaping
- /// function parameter with another non-escaping function parameter
- /// as an argument.
- void checkNoEscapeParameterCall(ApplyExpr *apply) {
- NoEscapeArgument noescapeArgument;
- Expr *problematicArg = nullptr;
-
- visitArguments(apply, [&](unsigned argIndex, Expr *arg) {
- // Just find the first problematic argument.
- if (noescapeArgument) return;
-
- // Remember the expression which used the argument.
- problematicArg = arg;
-
- // Look through the same set of nodes that we look through when
- // checking for no-escape functions.
- arg = lookThroughArgument(arg);
-
- // If the argument isn't noescape, ignore it.
- auto fnType = arg->getType()->getAs<AnyFunctionType>();
- if (!fnType || !fnType->isNoEscape())
- return;
-
- // Okay, it should be a closure or a decl ref.
- if (auto declRef = dyn_cast<DeclRefExpr>(arg)) {
- noescapeArgument =
- NoEscapeArgument::find(TC, declRef->getDecl(), false);
- } else if (auto closure = dyn_cast<AbstractClosureExpr>(arg)) {
- noescapeArgument =
- NoEscapeArgument::findInCaptures(TC, closure);
- } else {
- // This can happen with withoutActuallyEscaping.
- assert(isa<OpaqueValueExpr>(arg) &&
- "unexpected expression yielding noescape closure");
- }
- });
-
- if (!noescapeArgument) return;
-
- TC.diagnose(apply->getLoc(),
- diag::err_noescape_param_call,
- noescapeArgument.getDecl()->getName(),
- noescapeArgument.isDeclACapture())
- .highlight(problematicArg->getSourceRange());
- }
-
- enum class OperandKind {
- None,
- Callee,
- Argument,
- MakeEscapable,
- };
-
- /// The DRE argument is a reference to a noescape parameter. Verify that
- /// its uses are ok.
- void checkNoEscapeParameterUse(DeclRefExpr *DRE, Expr *parent,
- OperandKind useKind) {
- // This only cares about declarations of noescape function type.
- auto AFT = DRE->getType()->getAs<FunctionType>();
- if (!AFT || !AFT->isNoEscape())
- return;
-
- // Only diagnose this once. If we check and accept this use higher up in
- // the AST, don't recheck here.
- if (!AlreadyDiagnosedNoEscapes.insert(DRE).second)
- return;
-
- // The only valid use of the noescape parameter is an immediate call,
- // either as the callee or as an argument (in which case, the typechecker
- // validates that the noescape bit didn't get stripped off), or as
- // a special case, e.g. in the binding of a withoutActuallyEscaping block
- // or the argument of a type(of: ...).
- if (parent) {
- if (auto apply = dyn_cast<ApplyExpr>(parent)) {
- if (isa<ParamDecl>(DRE->getDecl()) && useKind == OperandKind::Callee)
- checkNoEscapeParameterCall(apply);
- return;
- } else if (isa<SubscriptExpr>(parent)
- && useKind == OperandKind::Argument) {
- return;
- } else if (isa<MakeTemporarilyEscapableExpr>(parent)) {
- return;
- } else if (isa<DynamicTypeExpr>(parent)) {
- return;
- }
- }
-
- TC.diagnose(DRE->getStartLoc(), diag::invalid_noescape_use,
- cast<VarDecl>(DRE->getDecl())->getName(),
- isa<ParamDecl>(DRE->getDecl()));
-
- // If we're a parameter, emit a helpful fixit to add @escaping
- auto paramDecl = dyn_cast<ParamDecl>(DRE->getDecl());
- if (paramDecl) {
- TC.diagnose(paramDecl->getStartLoc(), diag::noescape_parameter,
- paramDecl->getName())
- .fixItInsert(paramDecl->getTypeLoc().getSourceRange().Start,
- "@escaping ");
- }
- }
-
// Diagnose metatype values that don't appear as part of a property,
// method, or constructor reference.
void checkUseOfMetaTypeName(Expr *E) {
@@ -2276,7 +2061,8 @@
vdi->second |= Flag;
}
- void markBaseOfAbstractStorageDeclStore(Expr *E, ConcreteDeclRef decl);
+ void markBaseOfStorageUse(Expr *E, ConcreteDeclRef decl, unsigned flags);
+ void markBaseOfStorageUse(Expr *E, bool isMutating);
void markStoredOrInOutExpr(Expr *E, unsigned Flags);
@@ -2655,29 +2441,57 @@
}
}
-/// Handle a store to "x.y" where 'base' is the expression for x and 'decl' is
-/// the decl for 'y'.
-void VarDeclUsageChecker::
-markBaseOfAbstractStorageDeclStore(Expr *base, ConcreteDeclRef decl) {
- // If the base is a class or an rvalue, then this store just loads the base.
- if (base->getType()->isAnyClassReferenceType() ||
- !(base->getType()->hasLValueType() || base->isSemanticallyInOutExpr())) {
+/// Handle a use of "x.y" or "x[0]" where 'base' is the expression for x and
+/// 'decl' is the property or subscript.
+///
+/// TODO: Rip this out and just rely on LValueAccessKind.
+void VarDeclUsageChecker::markBaseOfStorageUse(Expr *base, ConcreteDeclRef decl,
+ unsigned flags) {
+ // If the base is an rvalue, then we know that this is a non-mutating access.
+ // Note that we can have mutating accesses even when the base has class or
+ // metatype type due to protocols and protocol extensions.
+ if (!base->getType()->hasLValueType() &&
+ !base->isSemanticallyInOutExpr()) {
base->walk(*this);
return;
}
- // If the store is to a non-mutating member, then this is just a load, even
- // if the base is an inout expr.
- auto *ASD = cast<AbstractStorageDecl>(decl.getDecl());
- if (ASD->isSettable(nullptr) && !ASD->isSetterMutating()) {
- // Sema conservatively converts the base to inout expr when it is an lvalue.
- // Look through it because we know it isn't actually doing a load/store.
- if (auto *ioe = dyn_cast<InOutExpr>(base))
- base = ioe->getSubExpr();
+ // Compute whether this access is to a mutating member.
+ auto *ASD = dyn_cast_or_null<AbstractStorageDecl>(decl.getDecl());
+ bool isMutating = false;
+ if (!ASD) {
+ // If there's no abstract storage declaration (which should hopefully
+ // only happen with invalid code), treat the base access as mutating if
+ // the subobject is being mutated and the base type is not a class
+ // or metatype.
+ if (flags & RK_Written) {
+ Type type = base->getType()->getRValueType()->getInOutObjectType();
+ if (!type->isAnyClassReferenceType() && !type->is<AnyMetatypeType>())
+ isMutating = true;
+ }
+ } else {
+ // Otherwise, consider whether the accessors are mutating.
+ if (flags & RK_Read)
+ isMutating |= ASD->isGetterMutating();
+ if (flags & RK_Written)
+ isMutating |= ASD->isSettable(nullptr) && ASD->isSetterMutating();
+ }
+
+ markBaseOfStorageUse(base, isMutating);
+}
+
+void VarDeclUsageChecker::markBaseOfStorageUse(Expr *base, bool isMutating) {
+ // CSApply sometimes wraps the base in an InOutExpr just because the
+ // base is an l-value; look through that so we can get more precise
+ // checking.
+ if (auto *ioe = dyn_cast<InOutExpr>(base))
+ base = ioe->getSubExpr();
+
+ if (!isMutating) {
base->walk(*this);
return;
}
-
+
// Otherwise this is a read and write of the base.
return markStoredOrInOutExpr(base, RK_Written|RK_Read);
}
@@ -2712,25 +2526,22 @@
if (auto *SE = dyn_cast<SubscriptExpr>(E)) {
// The index of the subscript is evaluated as an rvalue.
SE->getIndex()->walk(*this);
- if (SE->hasDecl())
- markBaseOfAbstractStorageDeclStore(SE->getBase(), SE->getDecl());
- else // FIXME: Should not be needed!
- markStoredOrInOutExpr(SE->getBase(), RK_Written|RK_Read);
-
+ markBaseOfStorageUse(SE->getBase(), SE->getDecl(), Flags);
return;
}
// Likewise for key path applications. An application of a WritableKeyPath
- // reads and writes its base.
+ // reads and writes its base; an application of a ReferenceWritableKeyPath
+ // only reads its base; the other KeyPath types cannot be written at all.
if (auto *KPA = dyn_cast<KeyPathApplicationExpr>(E)) {
auto &C = KPA->getType()->getASTContext();
KPA->getKeyPath()->walk(*this);
- if (KPA->getKeyPath()->getType()->getAnyNominal()
- == C.getWritableKeyPathDecl())
- markStoredOrInOutExpr(KPA->getBase(), RK_Written|RK_Read);
- if (KPA->getKeyPath()->getType()->getAnyNominal()
- == C.getReferenceWritableKeyPathDecl())
- markStoredOrInOutExpr(KPA->getBase(), RK_Read);
+
+ bool isMutating =
+ (Flags & RK_Written) &&
+ KPA->getKeyPath()->getType()->getAnyNominal()
+ == C.getWritableKeyPathDecl();
+ markBaseOfStorageUse(KPA->getBase(), isMutating);
return;
}
@@ -2738,10 +2549,10 @@
return markStoredOrInOutExpr(ioe->getSubExpr(), RK_Written|RK_Read);
if (auto *MRE = dyn_cast<MemberRefExpr>(E)) {
- markBaseOfAbstractStorageDeclStore(MRE->getBase(), MRE->getMember());
+ markBaseOfStorageUse(MRE->getBase(), MRE->getMember(), Flags);
return;
}
-
+
if (auto *TEE = dyn_cast<TupleElementExpr>(E))
return markStoredOrInOutExpr(TEE->getBase(), Flags);
@@ -2750,6 +2561,12 @@
if (auto *BOE = dyn_cast<BindOptionalExpr>(E))
return markStoredOrInOutExpr(BOE->getSubExpr(), Flags);
+
+ // Bind existential expressions.
+ if (auto *OEE = dyn_cast<OpenExistentialExpr>(E)) {
+ OpaqueValueMap[OEE->getOpaqueValue()] = OEE->getExistentialValue();
+ return markStoredOrInOutExpr(OEE->getSubExpr(), Flags);
+ }
// If this is an OpaqueValueExpr that we've seen a mapping for, jump to the
// mapped value.
@@ -2788,8 +2605,16 @@
if (auto VD = dyn_cast<VarDecl>(MRE->getMember().getDecl())) {
if (AssociatedGetter == VD && AssociatedGetterRefExpr == nullptr)
AssociatedGetterRefExpr = MRE;
+ markBaseOfStorageUse(MRE->getBase(), MRE->getMember(), RK_Read);
+ return { false, E };
}
}
+ if (auto SE = dyn_cast<SubscriptExpr>(E)) {
+ SE->getIndex()->walk(*this);
+ markBaseOfStorageUse(SE->getBase(), SE->getDecl(), RK_Read);
+ return { false, E };
+ }
+
// If this is an AssignExpr, see if we're mutating something that we know
// about.
if (auto *assign = dyn_cast<AssignExpr>(E)) {
@@ -2810,6 +2635,13 @@
// If we see an OpenExistentialExpr, remember the mapping for its OpaqueValue.
if (auto *oee = dyn_cast<OpenExistentialExpr>(E))
OpaqueValueMap[oee->getOpaqueValue()] = oee->getExistentialValue();
+
+ // Visit bindings.
+ if (auto ove = dyn_cast<OpaqueValueExpr>(E)) {
+ if (auto mapping = OpaqueValueMap.lookup(ove))
+ mapping->walk(*this);
+ return { false, E };
+ }
// If we saw an ErrorExpr, take note of this.
if (isa<ErrorExpr>(E))
diff --git a/lib/Sema/ResilienceDiagnostics.cpp b/lib/Sema/ResilienceDiagnostics.cpp
index 10bc318..27c31b8 100644
--- a/lib/Sema/ResilienceDiagnostics.cpp
+++ b/lib/Sema/ResilienceDiagnostics.cpp
@@ -25,7 +25,8 @@
std::pair<FragileFunctionKind, bool>
TypeChecker::getFragileFunctionKind(const DeclContext *DC) {
- for (; DC->isLocalContext(); DC = DC->getParent()) {
+ for (DC = DC->getLocalContext(); DC && DC->isLocalContext();
+ DC = DC->getParent()) {
if (isa<DefaultArgumentInitializer>(DC)) {
// Default argument generators of public functions cannot reference
// @usableFromInline declarations; all other fragile function kinds
@@ -176,6 +177,11 @@
diagName = accessor->getStorage()->getFullName();
}
+ // Swift 5.0 did not check the underlying types of local typealiases.
+ // FIXME: Conditionalize this once we have a new language mode.
+ if (isa<TypeAliasDecl>(DC))
+ downgradeToWarning = DowngradeToWarning::Yes;
+
auto diagID = diag::resilience_decl_unavailable;
if (downgradeToWarning == DowngradeToWarning::Yes)
diagID = diag::resilience_decl_unavailable_warn;
diff --git a/lib/Sema/TypeCheckAccess.cpp b/lib/Sema/TypeCheckAccess.cpp
index faf5e84..1c1ac6e 100644
--- a/lib/Sema/TypeCheckAccess.cpp
+++ b/lib/Sema/TypeCheckAccess.cpp
@@ -1494,12 +1494,12 @@
offendingType->getFullName(), M->getName());
highlightOffendingType(TC, diag, complainRepr);
}
-
- static_assert(std::is_convertible<DiagnoseGenerically,
- CheckImplementationOnlyCallback>::value,
- "DiagnoseGenerically has wrong call signature");
};
+ static_assert(std::is_convertible<DiagnoseGenerically,
+ CheckImplementationOnlyCallback>::value,
+ "DiagnoseGenerically has wrong call signature");
+
DiagnoseGenerically getDiagnoseCallback(const Decl *D) {
return DiagnoseGenerically(TC, D);
}
diff --git a/lib/Sema/TypeCheckCaptures.cpp b/lib/Sema/TypeCheckCaptures.cpp
index 2fc3b0e..8828920 100644
--- a/lib/Sema/TypeCheckCaptures.cpp
+++ b/lib/Sema/TypeCheckCaptures.cpp
@@ -199,34 +199,6 @@
|| !isa<VarDecl>(VD)
|| !cast<VarDecl>(VD)->getType()->hasRetainablePointerRepresentation()))
checkType(VD->getInterfaceType(), VD->getLoc());
-
- // If VD is a noescape decl, then the closure we're computing this for
- // must also be noescape.
- if (AFR.hasType() &&
- !AFR.getType()->hasError() &&
- VD->hasInterfaceType() &&
- VD->getInterfaceType()->is<AnyFunctionType>() &&
- VD->getInterfaceType()->castTo<AnyFunctionType>()->isNoEscape() &&
- !capture.isNoEscape() &&
- // Don't repeatedly diagnose the same thing.
- Diagnosed.insert(VD).second) {
-
- // Otherwise, diagnose this as an invalid capture.
- bool isDecl = AFR.getAbstractFunctionDecl() != nullptr;
-
- TC.diagnose(Loc, isDecl ? diag::decl_closure_noescape_use
- : diag::closure_noescape_use,
- VD->getBaseName().getIdentifier());
-
- // If we're a parameter, emit a helpful fixit to add @escaping
- auto paramDecl = dyn_cast<ParamDecl>(VD);
- if (paramDecl) {
- TC.diagnose(paramDecl->getStartLoc(), diag::noescape_parameter,
- paramDecl->getName())
- .fixItInsert(paramDecl->getTypeLoc().getSourceRange().Start,
- "@escaping ");
- }
- }
}
bool shouldWalkIntoLazyInitializers() override {
@@ -393,24 +365,6 @@
if (!validateForwardCapture(DRE->getDecl()))
return { false, DRE };
- bool isInOut = (isa<ParamDecl>(D) && cast<ParamDecl>(D)->isInOut());
- bool isNested = false;
- if (auto f = AFR.getAbstractFunctionDecl())
- isNested = f->getDeclContext()->isLocalContext();
-
- if (isInOut && !AFR.isKnownNoEscape() && !isNested) {
- if (D->getBaseName() == D->getASTContext().Id_self) {
- TC.diagnose(DRE->getLoc(),
- diag::closure_implicit_capture_mutating_self);
- TC.diagnose(DRE->getLoc(),
- diag::create_mutating_copy_or_capture_self);
- } else {
- TC.diagnose(DRE->getLoc(),
- diag::closure_implicit_capture_without_noescape);
- }
- return { false, DRE };
- }
-
// We're going to capture this, compute flags for the capture.
unsigned Flags = 0;
@@ -734,28 +688,6 @@
if (AFR.getBody())
AFR.getBody()->walk(finder);
- unsigned inoutCount = 0;
- for (auto C : Captures) {
- if (auto PD = dyn_cast<ParamDecl>(C.getDecl()))
- if (PD->isInOut())
- inoutCount++;
- }
-
- if (inoutCount > 0) {
- if (auto e = AFR.getAbstractFunctionDecl()) {
- for (auto returnOccurrence : getEscapingFunctionAsReturnValue(e)) {
- diagnose(returnOccurrence->getReturnLoc(),
- diag::nested_function_escaping_inout_capture);
- }
- auto occurrences = getEscapingFunctionAsArgument(e);
- for (auto occurrence : occurrences) {
- diagnose(occurrence->getLoc(),
- diag::nested_function_with_implicit_capture_argument,
- inoutCount > 1);
- }
- }
- }
-
if (AFR.hasType() && !AFR.isObjC()) {
finder.checkType(AFR.getType(), getCaptureLoc(AFR));
}
diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp
index e3d5c55..6121eab 100644
--- a/lib/Sema/TypeCheckStmt.cpp
+++ b/lib/Sema/TypeCheckStmt.cpp
@@ -472,11 +472,7 @@
tryDiagnoseUnnecessaryCastOverOptionSet(TC.Context, E, ResultTy,
DC->getParentModule());
}
- while (auto ICE = dyn_cast<ImplicitConversionExpr>(E))
- E = ICE->getSubExpr();
- if (auto DRE = dyn_cast<DeclRefExpr>(E))
- if (auto FD = dyn_cast<FuncDecl>(DRE->getDecl()))
- TC.addEscapingFunctionAsReturnValue(FD, RS);
+
return RS;
}
diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp
index 6767a8b..6d2443b 100644
--- a/lib/Sema/TypeCheckType.cpp
+++ b/lib/Sema/TypeCheckType.cpp
@@ -24,6 +24,7 @@
#include "swift/Strings.h"
#include "swift/AST/ASTVisitor.h"
#include "swift/AST/ASTWalker.h"
+#include "swift/AST/DiagnosticsParse.h"
#include "swift/AST/ExistentialLayout.h"
#include "swift/AST/ForeignErrorConvention.h"
#include "swift/AST/GenericEnvironment.h"
@@ -2053,7 +2054,8 @@
auto checkUnsupportedAttr = [&](TypeAttrKind attr) {
if (attrs.has(attr)) {
- diagnose(attrs.getLoc(attr), diag::attribute_not_supported);
+ diagnose(attrs.getLoc(attr), diag::unknown_attribute,
+ TypeAttributes::getAttrName(attr));
attrs.clearAttribute(attr);
}
};
@@ -2061,7 +2063,12 @@
// Some function representation attributes are not supported at source level;
// only SIL knows how to handle them. Reject them unless this is a SIL input.
if (!(options & TypeResolutionFlags::SILType)) {
- for (auto silOnlyAttr : {TAK_callee_owned, TAK_callee_guaranteed}) {
+ for (auto silOnlyAttr : {TAK_pseudogeneric,
+ TAK_callee_owned,
+ TAK_callee_guaranteed,
+ TAK_noescape,
+ TAK_yield_once,
+ TAK_yield_many}) {
checkUnsupportedAttr(silOnlyAttr);
}
}
@@ -2181,7 +2188,7 @@
}
// Resolve the function type directly with these attributes.
- FunctionType::ExtInfo extInfo(rep, attrs.has(TAK_noescape),
+ FunctionType::ExtInfo extInfo(rep, /*noescape=*/false,
fnRepr->throws());
ty = resolveASTFunctionType(fnRepr, options, extInfo);
@@ -2208,7 +2215,7 @@
}
// Handle @escaping
- if (hasFunctionAttr && ty->is<FunctionType>()) {
+ if (ty->is<FunctionType>()) {
if (attrs.has(TAK_escaping)) {
// The attribute is meaningless except on non-variadic parameter types.
if (!isParam || options.getBaseContext() == TypeResolverContext::EnumElementDecl) {
@@ -2233,9 +2240,6 @@
if (hasFunctionAttr && !fnRepr) {
if (attrs.has(TAK_autoclosure)) {
- // @autoclosure usually auto-implies @noescape,
- // don't complain about both of them.
- attrs.clearAttribute(TAK_noescape);
// @autoclosure is going to be diagnosed when type of
// the parameter is validated, because that attribute
// applies to the declaration now.
diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h
index 7aabd5d..b76b4eb 100644
--- a/lib/Sema/TypeChecker.h
+++ b/lib/Sema/TypeChecker.h
@@ -606,61 +606,9 @@
llvm::DenseMap<AnyFunctionRef, std::vector<Expr*>> LocalCFunctionPointers;
private:
- /// Return statements with functions as return values.
- llvm::DenseMap<AbstractFunctionDecl *, llvm::DenseSet<ReturnStmt *>>
- FunctionAsReturnValue;
-
- /// Function apply expressions with a certain function as an argument.
- llvm::DenseMap<AbstractFunctionDecl *, llvm::DenseSet<ApplyExpr *>>
- FunctionAsEscapingArg;
-
/// The # of times we have performed typo correction.
unsigned NumTypoCorrections = 0;
-public:
- /// Record an occurrence of a function that captures inout values as an
- /// argument.
- ///
- /// \param decl the function that occurs as an argument.
- ///
- /// \param apply the expression in which the function appears.
- void addEscapingFunctionAsArgument(AbstractFunctionDecl *decl,
- ApplyExpr *apply) {
- FunctionAsEscapingArg[decl].insert(apply);
- }
-
- /// Find occurrences of a function that captures inout values as arguments.
- ///
- /// \param decl the function that occurs as an argument.
- ///
- /// \returns Expressions in which the function appears as arguments.
- llvm::DenseSet<ApplyExpr *> &
- getEscapingFunctionAsArgument(AbstractFunctionDecl *decl) {
- return FunctionAsEscapingArg[decl];
- }
-
- /// Record an occurrence of a function that captures inout values as a return
- /// value
- ///
- /// \param decl the function that occurs as a return value.
- ///
- /// \param stmt the expression in which the function appears.
- void addEscapingFunctionAsReturnValue(AbstractFunctionDecl *decl,
- ReturnStmt *stmt) {
- FunctionAsReturnValue[decl].insert(stmt);
- }
-
- /// Find occurrences of a function that captures inout values as return
- /// values.
- ///
- /// \param decl the function that occurs as a return value.
- ///
- /// \returns Expressions in which the function appears as arguments.
- llvm::DenseSet<ReturnStmt *> &
- getEscapingFunctionAsReturnValue(AbstractFunctionDecl *decl) {
- return FunctionAsReturnValue[decl];
- }
-
private:
Type MaxIntegerType;
Type NSObjectType;
diff --git a/stdlib/CMakeLists.txt b/stdlib/CMakeLists.txt
index ecf078b..95ecb33 100644
--- a/stdlib/CMakeLists.txt
+++ b/stdlib/CMakeLists.txt
@@ -143,7 +143,7 @@
"swift-stdlib-${platform}-${arch}"
"copy-legacy-layouts-${platform}-${arch}")
- swift_install_in_component(stdlib
+ swift_install_in_component(compiler
FILES ${input}
DESTINATION "lib/swift/${platform}/")
else()
diff --git a/stdlib/private/StdlibUnittest/StdlibUnittest.swift b/stdlib/private/StdlibUnittest/StdlibUnittest.swift
index 55a89e0..3bbe192 100644
--- a/stdlib/private/StdlibUnittest/StdlibUnittest.swift
+++ b/stdlib/private/StdlibUnittest/StdlibUnittest.swift
@@ -1777,7 +1777,7 @@
}
public func _parseDottedVersionTriple(_ s: String) -> (Int, Int, Int) {
- var array = _parseDottedVersion(s)
+ let array = _parseDottedVersion(s)
if array.count >= 4 {
fatalError("unexpected version")
}
diff --git a/stdlib/public/SwiftShims/CMakeLists.txt b/stdlib/public/SwiftShims/CMakeLists.txt
index 88a51ce..5fe05a0 100644
--- a/stdlib/public/SwiftShims/CMakeLists.txt
+++ b/stdlib/public/SwiftShims/CMakeLists.txt
@@ -105,7 +105,7 @@
COMMENT "Symlinking Clang resource headers into ${SWIFTLIB_DIR}/clang")
add_dependencies(copy_shim_headers symlink_clang_headers)
-swift_install_in_component(compiler
+swift_install_in_component(stdlib
FILES ${sources}
DESTINATION "lib/swift/shims")
diff --git a/stdlib/public/core/Builtin.swift b/stdlib/public/core/Builtin.swift
index 446b924..87067619 100644
--- a/stdlib/public/core/Builtin.swift
+++ b/stdlib/public/core/Builtin.swift
@@ -301,17 +301,6 @@
_ = Builtin.assume_Int1(condition._value)
}
-// This function is no longer used but must be kept for ABI compatibility
-// because references to it may have been inlined.
-@usableFromInline
-internal func _branchHint(_ actual: Bool, expected: Bool) -> Bool {
- // The LLVM intrinsic underlying int_expect_Int1 now requires an immediate
- // argument for the expected value so we cannot call it here. This should
- // never be called in cases where performance matters, so just return the
- // value without any branch hint.
- return actual
-}
-
//===--- Runtime shim wrappers --------------------------------------------===//
/// Returns `true` iff the class indicated by `theClass` uses native
diff --git a/stdlib/public/core/LegacyABI.swift b/stdlib/public/core/LegacyABI.swift
index 604a86b..05b783b 100644
--- a/stdlib/public/core/LegacyABI.swift
+++ b/stdlib/public/core/LegacyABI.swift
@@ -60,3 +60,14 @@
return try copy.withUTF8(body)
}
}
+
+// This function is no longer used but must be kept for ABI compatibility
+// because references to it may have been inlined.
+@usableFromInline
+internal func _branchHint(_ actual: Bool, expected: Bool) -> Bool {
+ // The LLVM intrinsic underlying int_expect_Int1 now requires an immediate
+ // argument for the expected value so we cannot call it here. This should
+ // never be called in cases where performance matters, so just return the
+ // value without any branch hint.
+ return actual
+}
diff --git a/stdlib/public/core/SIMDVector.swift b/stdlib/public/core/SIMDVector.swift
index dce9b33..2d8aa80 100644
--- a/stdlib/public/core/SIMDVector.swift
+++ b/stdlib/public/core/SIMDVector.swift
@@ -33,7 +33,7 @@
/// conform to `SIMD`.
public protocol SIMDStorage {
/// The type of scalars in the vector space.
- associatedtype Scalar : Codable, Hashable
+ associatedtype Scalar: Codable, Hashable
/// The number of scalars, or elements, in the vector.
var scalarCount: Int { get }
@@ -48,26 +48,37 @@
subscript(index: Int) -> Scalar { get set }
}
+extension SIMDStorage {
+ /// The number of scalars, or elements, in a vector of this type.
+ @_alwaysEmitIntoClient
+ public static var scalarCount: Int {
+ // Wouldn't it make more sense to define the instance var in terms of the
+ // static var? Yes, probably, but by doing it this way we make the static
+ // var backdeployable.
+ return Self().scalarCount
+ }
+}
+
/// A type that can be used as an element in a SIMD vector.
public protocol SIMDScalar {
- associatedtype SIMDMaskScalar : SIMDScalar & FixedWidthInteger & SignedInteger
- associatedtype SIMD2Storage : SIMDStorage where SIMD2Storage.Scalar == Self
- associatedtype SIMD4Storage : SIMDStorage where SIMD4Storage.Scalar == Self
- associatedtype SIMD8Storage : SIMDStorage where SIMD8Storage.Scalar == Self
- associatedtype SIMD16Storage : SIMDStorage where SIMD16Storage.Scalar == Self
- associatedtype SIMD32Storage : SIMDStorage where SIMD32Storage.Scalar == Self
- associatedtype SIMD64Storage : SIMDStorage where SIMD64Storage.Scalar == Self
+ associatedtype SIMDMaskScalar: SIMDScalar & FixedWidthInteger & SignedInteger
+ associatedtype SIMD2Storage: SIMDStorage where SIMD2Storage.Scalar == Self
+ associatedtype SIMD4Storage: SIMDStorage where SIMD4Storage.Scalar == Self
+ associatedtype SIMD8Storage: SIMDStorage where SIMD8Storage.Scalar == Self
+ associatedtype SIMD16Storage: SIMDStorage where SIMD16Storage.Scalar == Self
+ associatedtype SIMD32Storage: SIMDStorage where SIMD32Storage.Scalar == Self
+ associatedtype SIMD64Storage: SIMDStorage where SIMD64Storage.Scalar == Self
}
/// A SIMD vector of a fixed number of elements.
-public protocol SIMD : SIMDStorage,
- Codable,
- Hashable,
- CustomStringConvertible,
- ExpressibleByArrayLiteral {
+public protocol SIMD: SIMDStorage,
+ Codable,
+ Hashable,
+ CustomStringConvertible,
+ ExpressibleByArrayLiteral {
/// The mask type resulting from pointwise comparisons of this vector type.
- associatedtype MaskStorage : SIMD
- where MaskStorage.Scalar : FixedWidthInteger & SignedInteger
+ associatedtype MaskStorage: SIMD
+ where MaskStorage.Scalar: FixedWidthInteger & SignedInteger
}
extension SIMD {
@@ -176,8 +187,10 @@
/// Creates a vector from the given sequence.
///
- /// - Parameter scalars: The elements to use in the vector. `scalars` must
- /// have the same number of elements as the vector type.
+ /// - Precondition: `scalars` must have the same number of elements as the
+ /// vector type.
+ ///
+ /// - Parameter scalars: The elements to use in the vector.
@inlinable
public init<S: Sequence>(_ scalars: S) where S.Element == Scalar {
self.init()
@@ -193,11 +206,116 @@
_preconditionFailure("Not enough elements in sequence.")
}
}
+
+ /// Extracts the scalars at specified indices to form a SIMD2.
+ ///
+ /// The elements of the index vector are wrapped modulo the count of elements
+ /// in this vector. Because of this, the index is always in-range and no trap
+ /// can occur.
+ @_alwaysEmitIntoClient
+ public subscript<Index>(index: SIMD2<Index>) -> SIMD2<Scalar>
+ where Index: FixedWidthInteger {
+ var result = SIMD2<Scalar>()
+ for i in result.indices {
+ result[i] = self[Int(index[i]) % scalarCount]
+ }
+ return result
+ }
+
+ /// Extracts the scalars at specified indices to form a SIMD3.
+ ///
+ /// The elements of the index vector are wrapped modulo the count of elements
+ /// in this vector. Because of this, the index is always in-range and no trap
+ /// can occur.
+ @_alwaysEmitIntoClient
+ public subscript<Index>(index: SIMD3<Index>) -> SIMD3<Scalar>
+ where Index: FixedWidthInteger {
+ var result = SIMD3<Scalar>()
+ for i in result.indices {
+ result[i] = self[Int(index[i]) % scalarCount]
+ }
+ return result
+ }
+
+ /// Extracts the scalars at specified indices to form a SIMD4.
+ ///
+ /// The elements of the index vector are wrapped modulo the count of elements
+ /// in this vector. Because of this, the index is always in-range and no trap
+ /// can occur.
+ @_alwaysEmitIntoClient
+ public subscript<Index>(index: SIMD4<Index>) -> SIMD4<Scalar>
+ where Index: FixedWidthInteger {
+ var result = SIMD4<Scalar>()
+ for i in result.indices {
+ result[i] = self[Int(index[i]) % scalarCount]
+ }
+ return result
+ }
+
+ /// Extracts the scalars at specified indices to form a SIMD8.
+ ///
+ /// The elements of the index vector are wrapped modulo the count of elements
+ /// in this vector. Because of this, the index is always in-range and no trap
+ /// can occur.
+ @_alwaysEmitIntoClient
+ public subscript<Index>(index: SIMD8<Index>) -> SIMD8<Scalar>
+ where Index: FixedWidthInteger {
+ var result = SIMD8<Scalar>()
+ for i in result.indices {
+ result[i] = self[Int(index[i]) % scalarCount]
+ }
+ return result
+ }
+
+ /// Extracts the scalars at specified indices to form a SIMD16.
+ ///
+ /// The elements of the index vector are wrapped modulo the count of elements
+ /// in this vector. Because of this, the index is always in-range and no trap
+ /// can occur.
+ @_alwaysEmitIntoClient
+ public subscript<Index>(index: SIMD16<Index>) -> SIMD16<Scalar>
+ where Index: FixedWidthInteger {
+ var result = SIMD16<Scalar>()
+ for i in result.indices {
+ result[i] = self[Int(index[i]) % scalarCount]
+ }
+ return result
+ }
+
+ /// Extracts the scalars at specified indices to form a SIMD32.
+ ///
+ /// The elements of the index vector are wrapped modulo the count of elements
+ /// in this vector. Because of this, the index is always in-range and no trap
+ /// can occur.
+ @_alwaysEmitIntoClient
+ public subscript<Index>(index: SIMD32<Index>) -> SIMD32<Scalar>
+ where Index: FixedWidthInteger {
+ var result = SIMD32<Scalar>()
+ for i in result.indices {
+ result[i] = self[Int(index[i]) % scalarCount]
+ }
+ return result
+ }
+
+ /// Extracts the scalars at specified indices to form a SIMD64.
+ ///
+ /// The elements of the index vector are wrapped modulo the count of elements
+ /// in this vector. Because of this, the index is always in-range and no trap
+ /// can occur.
+ @_alwaysEmitIntoClient
+ public subscript<Index>(index: SIMD64<Index>) -> SIMD64<Scalar>
+ where Index: FixedWidthInteger {
+ var result = SIMD64<Scalar>()
+ for i in result.indices {
+ result[i] = self[Int(index[i]) % scalarCount]
+ }
+ return result
+ }
}
// Implementations of comparison operations. These should eventually all
// be replaced with @_semantics to lower directly to vector IR nodes.
-extension SIMD where Scalar : Comparable {
+extension SIMD where Scalar: Comparable {
/// Returns a vector mask with the result of a pointwise less than
/// comparison.
@_transparent
@@ -215,6 +333,18 @@
for i in result.indices { result[i] = lhs[i] <= rhs[i] }
return result
}
+
+ /// The least element in the vector.
+ @_alwaysEmitIntoClient
+ public func min() -> Scalar {
+ return indices.reduce(into: self[0]) { $0 = Swift.min($0, self[$1]) }
+ }
+
+ /// The greatest element in the vector.
+ @_alwaysEmitIntoClient
+ public func max() -> Scalar {
+ return indices.reduce(into: self[0]) { $0 = Swift.max($0, self[$1]) }
+ }
}
// These operations should never need @_semantics; they should be trivial
@@ -268,7 +398,7 @@
}
}
-extension SIMD where Scalar : Comparable {
+extension SIMD where Scalar: Comparable {
/// Returns a vector mask with the result of a pointwise greater than or
/// equal comparison.
@_transparent
@@ -336,15 +466,31 @@
public static func .>(lhs: Self, rhs: Scalar) -> SIMDMask<MaskStorage> {
return lhs .> Self(repeating: rhs)
}
+
+ @_alwaysEmitIntoClient
+ public mutating func clamp(lowerBound: Self, upperBound: Self) {
+ self = self.clamped(lowerBound: lowerBound, upperBound: upperBound)
+ }
+
+ @_alwaysEmitIntoClient
+ public func clamped(lowerBound: Self, upperBound: Self) -> Self {
+ return Swift.min(upperBound, Swift.max(lowerBound, self))
+ }
}
-extension SIMD where Scalar : FixedWidthInteger {
+extension SIMD where Scalar: FixedWidthInteger {
/// A vector with zero in all lanes.
@_transparent
public static var zero: Self {
return Self()
}
+ /// A vector with one in all lanes.
+ @_alwaysEmitIntoClient
+ public static var one: Self {
+ return Self(repeating: 1)
+ }
+
/// Returns a vector with random values from within the specified range in
/// all lanes, using the given generator as a source for randomness.
@inlinable
@@ -390,16 +536,22 @@
}
}
-extension SIMD where Scalar : FloatingPoint {
+extension SIMD where Scalar: FloatingPoint {
/// A vector with zero in all lanes.
@_transparent
public static var zero: Self {
return Self()
}
+
+ /// A vector with one in all lanes.
+ @_alwaysEmitIntoClient
+ public static var one: Self {
+ return Self(repeating: 1)
+ }
}
extension SIMD
-where Scalar : BinaryFloatingPoint, Scalar.RawSignificand : FixedWidthInteger {
+where Scalar: BinaryFloatingPoint, Scalar.RawSignificand: FixedWidthInteger {
/// Returns a vector with random values from within the specified range in
/// all lanes, using the given generator as a source for randomness.
@inlinable
@@ -446,11 +598,11 @@
}
@_fixed_layout
-public struct SIMDMask<Storage> : SIMD
- where Storage : SIMD,
- Storage.Scalar : FixedWidthInteger & SignedInteger {
+public struct SIMDMask<Storage>: SIMD
+ where Storage: SIMD,
+ Storage.Scalar: FixedWidthInteger & SignedInteger {
- public var _storage : Storage
+ public var _storage: Storage
public typealias MaskStorage = Storage
@@ -506,7 +658,7 @@
// Implementations of integer operations. These should eventually all
// be replaced with @_semantics to lower directly to vector IR nodes.
-extension SIMD where Scalar : FixedWidthInteger {
+extension SIMD where Scalar: FixedWidthInteger {
@_transparent
public var leadingZeroBitCount: Self {
var result = Self()
@@ -604,11 +756,20 @@
for i in result.indices { result[i] = lhs[i] % rhs[i] }
return result
}
+
+ /// Returns the sum of the scalars in the vector, computed with wrapping
+ /// addition.
+ ///
+ /// Equivalent to indices.reduce(into: 0) { $0 &+= self[$1] }.
+ @_alwaysEmitIntoClient
+ public func wrappedSum() -> Scalar {
+ return indices.reduce(into: 0) { $0 &+= self[$1] }
+ }
}
// Implementations of floating-point operations. These should eventually all
// be replaced with @_semantics to lower directly to vector IR nodes.
-extension SIMD where Scalar : FloatingPoint {
+extension SIMD where Scalar: FloatingPoint {
@_transparent
public static func +(lhs: Self, rhs: Self) -> Self {
var result = Self()
@@ -657,6 +818,28 @@
for i in result.indices { result[i] = self[i].rounded(rule) }
return result
}
+
+ /// Returns the least scalar in the vector.
+ @_alwaysEmitIntoClient
+ public func min() -> Scalar {
+ return indices.reduce(into: self[0]) { $0 = Scalar.minimum($0, self[$1]) }
+ }
+
+ /// Returns the greatest scalar in the vector.
+ @_alwaysEmitIntoClient
+ public func max() -> Scalar {
+ return indices.reduce(into: self[0]) { $0 = Scalar.maximum($0, self[$1]) }
+ }
+
+ /// Returns the sum of the scalars in the vector.
+ @_alwaysEmitIntoClient
+ public func sum() -> Scalar {
+ // Implementation note: this eventually be defined to lower to either
+ // llvm.experimental.vector.reduce.fadd or an explicit tree-sum. Open-
+ // coding the tree sum is problematic, we probably need to define a
+ // Swift Builtin to support it.
+ return indices.reduce(into: 0) { $0 += self[$1] }
+ }
}
extension SIMDMask {
@@ -683,7 +866,7 @@
// These operations should never need @_semantics; they should be trivial
// wrappers around the core operations defined above.
-extension SIMD where Scalar : FixedWidthInteger {
+extension SIMD where Scalar: FixedWidthInteger {
@_transparent
public static func &(lhs: Scalar, rhs: Self) -> Self {
@@ -961,7 +1144,7 @@
}
}
-extension SIMD where Scalar : FloatingPoint {
+extension SIMD where Scalar: FloatingPoint {
@_transparent
public static prefix func -(rhs: Self) -> Self {
@@ -1085,7 +1268,6 @@
}
extension SIMDMask {
-
@_transparent
public static func .&(lhs: Bool, rhs: SIMDMask) -> SIMDMask {
return SIMDMask(repeating: lhs) .& rhs
@@ -1146,3 +1328,72 @@
lhs = lhs .| rhs
}
}
+
+/// True if any lane of mask is true.
+@_alwaysEmitIntoClient
+public func any<Storage>(_ mask: SIMDMask<Storage>) -> Bool {
+ return mask._storage.min() < 0
+}
+
+/// True if every lane of mask is true.
+@_alwaysEmitIntoClient
+public func all<Storage>(_ mask: SIMDMask<Storage>) -> Bool {
+ return mask._storage.max() < 0
+}
+
+/// The lanewise minimum of two vectors.
+///
+/// Each element of the result is the minimum of the corresponding elements
+/// of the inputs.
+@_alwaysEmitIntoClient
+public func min<V>(_ lhs: V, _ rhs: V) -> V
+where V: SIMD, V.Scalar: Comparable {
+ var result = V()
+ for i in result.indices {
+ result[i] = min(lhs[i], rhs[i])
+ }
+ return result
+}
+
+/// The lanewise maximum of two vectors.
+///
+/// Each element of the result is the maximum of the corresponding elements
+/// of the inputs.
+@_alwaysEmitIntoClient
+public func max<V>(_ lhs: V, _ rhs: V) -> V
+where V: SIMD, V.Scalar: Comparable {
+ var result = V()
+ for i in result.indices {
+ result[i] = max(lhs[i], rhs[i])
+ }
+ return result
+}
+
+
+/// The lanewise minimum of two vectors.
+///
+/// Each element of the result is the minimum of the corresponding elements
+/// of the inputs.
+@_alwaysEmitIntoClient
+public func min<V>(_ lhs: V, _ rhs: V) -> V
+where V: SIMD, V.Scalar: FloatingPoint {
+ var result = V()
+ for i in result.indices {
+ result[i] = V.Scalar.minimum(lhs[i], rhs[i])
+ }
+ return result
+}
+
+/// The lanewise maximum of two vectors.
+///
+/// Each element of the result is the maximum of the corresponding elements
+/// of the inputs.
+@_alwaysEmitIntoClient
+public func max<V>(_ lhs: V, _ rhs: V) -> V
+where V: SIMD, V.Scalar: FloatingPoint {
+ var result = V()
+ for i in result.indices {
+ result[i] = V.Scalar.maximum(lhs[i], rhs[i])
+ }
+ return result
+}
diff --git a/stdlib/public/core/SIMDVectorTypes.swift.gyb b/stdlib/public/core/SIMDVectorTypes.swift.gyb
index 76cb579..c245561 100644
--- a/stdlib/public/core/SIMDVectorTypes.swift.gyb
+++ b/stdlib/public/core/SIMDVectorTypes.swift.gyb
@@ -26,7 +26,7 @@
% storageN = 4 if n == 3 else n
/// A vector of ${spelledNumbers[n]} scalar values.
@_fixed_layout
-public struct SIMD${n}<Scalar> : SIMD where Scalar: SIMDScalar {
+public struct SIMD${n}<Scalar>: SIMD where Scalar: SIMDScalar {
public var _storage: Scalar.SIMD${storageN}Storage
@@ -69,9 +69,9 @@
/// Creates a new vector from the given elements.
///
/// - Parameters:
- % for i in range(n):
+% for i in range(n):
/// - ${'xyzw'[i]}: The ${ordinalPositions[i]} element of the vector.
- % end
+% end
@_transparent
public init(${', '.join([c + ': Scalar' for c in 'xyzw'[:n]])}) {
self.init(${', '.join('xyzw'[:n])})
@@ -113,14 +113,14 @@
% end
}
-extension SIMD${n} where Scalar : FixedWidthInteger {
+extension SIMD${n} where Scalar: FixedWidthInteger {
/// Creates a new vector from the given vector, truncating the bit patterns
/// of the given vector's elements if necessary.
///
/// - Parameter other: The vector to convert.
@inlinable
public init<Other>(truncatingIfNeeded other: SIMD${n}<Other>)
- where Other : FixedWidthInteger {
+ where Other: FixedWidthInteger {
self.init()
for i in indices { self[i] = Scalar(truncatingIfNeeded: other[i]) }
}
@@ -131,7 +131,7 @@
/// - Parameter other: The vector to convert.
@inlinable
public init<Other>(clamping other: SIMD${n}<Other>)
- where Other : FixedWidthInteger {
+ where Other: FixedWidthInteger {
self.init()
for i in indices { self[i] = Scalar(clamping: other[i]) }
}
@@ -148,14 +148,14 @@
_ other: SIMD${n}<Other>,
rounding rule: FloatingPointRoundingRule = .towardZero
)
- where Other : BinaryFloatingPoint {
+ where Other: BinaryFloatingPoint {
self.init()
// TODO: this should clamp
for i in indices { self[i] = Scalar(other[i].rounded(rule)) }
}
}
-extension SIMD${n} : CustomDebugStringConvertible {
+extension SIMD${n}: CustomDebugStringConvertible {
public var debugDescription: String {
return "SIMD${n}<\(Scalar.self)>(${', '.join(map(lambda c:
'\\(self['+ str(c) + '])',
@@ -163,13 +163,13 @@
}
}
-extension SIMD${n} where Scalar : BinaryFloatingPoint {
+extension SIMD${n} where Scalar: BinaryFloatingPoint {
/// Creates a new vector from the given vector of integers.
///
/// - Parameter other: The vector to convert.
@inlinable
public init<Other>(_ other: SIMD${n}<Other>)
- where Other : FixedWidthInteger {
+ where Other: FixedWidthInteger {
self.init()
for i in indices { self[i] = Scalar(other[i]) }
}
@@ -179,7 +179,7 @@
/// - Parameter other: The vector to convert.
@inlinable
public init<Other>(_ other: SIMD${n}<Other>)
- where Other : BinaryFloatingPoint {
+ where Other: BinaryFloatingPoint {
self.init()
for i in indices { self[i] = Scalar(other[i]) }
}
@@ -187,11 +187,27 @@
%end
+extension SIMD3 {
+ /// A three-element vector created by appending a scalar to a two-element vector.
+ @_alwaysEmitIntoClient
+ public init(_ xy: SIMD2<Scalar>, _ z: Scalar) {
+ self.init(xy.x, xy.y, z)
+ }
+}
+
+extension SIMD4 {
+ /// A four-element vector created by appending a scalar to a three-element vector.
+ @_alwaysEmitIntoClient
+ public init(_ xyz: SIMD3<Scalar>, _ w: Scalar) {
+ self.init(xyz.x, xyz.y, xyz.z, w)
+ }
+}
+
%for self_type in all_integer_types(word_bits):
% Self = self_type.stdlib_name
% BuiltinName = self_type.builtin_name
% Mask = Self if self_type.is_signed else self_type.get_opposite_signedness().stdlib_name
-extension ${Self} : SIMDScalar {
+extension ${Self}: SIMDScalar {
public typealias SIMDMaskScalar = ${Mask}
@@ -200,7 +216,7 @@
/// Storage for a vector of ${spelledNumbers[n]} integers.
@_fixed_layout
@_alignment(${bytes if bytes <= 16 else 16})
- public struct SIMD${n}Storage : SIMDStorage {
+ public struct SIMD${n}Storage: SIMDStorage {
public var _value: Builtin.Vec${n}x${BuiltinName}
@@ -236,7 +252,7 @@
%end
%for (Self, bits) in [('Float',32), ('Double',64)]:
-extension ${Self} : SIMDScalar {
+extension ${Self}: SIMDScalar {
public typealias SIMDMaskScalar = Int${bits}
@@ -245,7 +261,7 @@
/// Storage for a vector of ${spelledNumbers[n]} floating-point values.
@_fixed_layout
@_alignment(${bytes if bytes <= 16 else 16})
- public struct SIMD${n}Storage : SIMDStorage {
+ public struct SIMD${n}Storage: SIMDStorage {
public var _value: Builtin.Vec${n}xFPIEEE${bits}
diff --git a/stdlib/public/core/SmallString.swift b/stdlib/public/core/SmallString.swift
index 9d4570c..c3a973a 100644
--- a/stdlib/public/core/SmallString.swift
+++ b/stdlib/public/core/SmallString.swift
@@ -32,10 +32,8 @@
@usableFromInline
internal var _storage: RawBitPattern
- @inlinable
- internal var rawBits: RawBitPattern {
- @inline(__always) get { return _storage }
- }
+ @inlinable @inline(__always)
+ internal var rawBits: RawBitPattern { return _storage }
@inlinable
internal var leadingRawBits: UInt64 {
@@ -76,15 +74,13 @@
}
extension _SmallString {
- @inlinable
+ @inlinable @inline(__always)
internal static var capacity: Int {
- @inline(__always) get {
#if arch(i386) || arch(arm)
- return 10
+ return 10
#else
- return 15
+ return 15
#endif
- }
}
// Get an integer equivalent to the _StringObject.discriminatedObjectRawBits
@@ -95,30 +91,20 @@
return _storage.1.littleEndian
}
- @inlinable
- internal var capacity: Int {
- @inline(__always) get {
- return _SmallString.capacity
- }
- }
+ @inlinable @inline(__always)
+ internal var capacity: Int { return _SmallString.capacity }
- @inlinable
+ @inlinable @inline(__always)
internal var count: Int {
- @inline(__always) get {
- return _StringObject.getSmallCount(fromRaw: rawDiscriminatedObject)
- }
+ return _StringObject.getSmallCount(fromRaw: rawDiscriminatedObject)
}
- @inlinable
- internal var unusedCapacity: Int {
- @inline(__always) get { return capacity &- count }
- }
+ @inlinable @inline(__always)
+ internal var unusedCapacity: Int { return capacity &- count }
- @inlinable
+ @inlinable @inline(__always)
internal var isASCII: Bool {
- @inline(__always) get {
- return _StringObject.getSmallIsASCII(fromRaw: rawDiscriminatedObject)
- }
+ return _StringObject.getSmallIsASCII(fromRaw: rawDiscriminatedObject)
}
// Give raw, nul-terminated code units. This is only for limited internal
@@ -170,11 +156,11 @@
@usableFromInline
internal typealias SubSequence = _SmallString
- @inlinable
- internal var startIndex: Int { @inline(__always) get { return 0 } }
+ @inlinable @inline(__always)
+ internal var startIndex: Int { return 0 }
- @inlinable
- internal var endIndex: Int { @inline(__always) get { return count } }
+ @inlinable @inline(__always)
+ internal var endIndex: Int { return count }
@inlinable
internal subscript(_ idx: Int) -> UInt8 {
@@ -196,15 +182,12 @@
}
}
- @inlinable // FIXME(inline-always) was usableFromInline
- // testable
+ @inlinable @inline(__always)
internal subscript(_ bounds: Range<Index>) -> SubSequence {
- @inline(__always) get {
- // TODO(String performance): In-vector-register operation
- return self.withUTF8 { utf8 in
- let rebased = UnsafeBufferPointer(rebasing: utf8[bounds])
- return _SmallString(rebased)._unsafelyUnwrappedUnchecked
- }
+ // TODO(String performance): In-vector-register operation
+ return self.withUTF8 { utf8 in
+ let rebased = UnsafeBufferPointer(rebasing: utf8[bounds])
+ return _SmallString(rebased)._unsafelyUnwrappedUnchecked
}
}
}
diff --git a/stdlib/public/core/StringCharacterView.swift b/stdlib/public/core/StringCharacterView.swift
index d25e984..826cce9 100644
--- a/stdlib/public/core/StringCharacterView.swift
+++ b/stdlib/public/core/StringCharacterView.swift
@@ -35,25 +35,20 @@
/// The position of the first character in a nonempty string.
///
/// In an empty string, `startIndex` is equal to `endIndex`.
- @inlinable
- public var startIndex: Index {
- @inline(__always) get { return _guts.startIndex }
- }
+ @inlinable @inline(__always)
+ public var startIndex: Index { return _guts.startIndex }
/// A string's "past the end" position---that is, the position one greater
/// than the last valid subscript argument.
///
/// In an empty string, `endIndex` is equal to `startIndex`.
- @inlinable
- public var endIndex: Index {
- @inline(__always) get { return _guts.endIndex }
- }
+ @inlinable @inline(__always)
+ public var endIndex: Index { return _guts.endIndex }
/// The number of characters in a string.
+ @inline(__always)
public var count: Int {
- @inline(__always) get {
- return distance(from: startIndex, to: endIndex)
- }
+ return distance(from: startIndex, to: endIndex)
}
/// Returns the position immediately after the given index.
@@ -190,16 +185,14 @@
///
/// - Parameter i: A valid index of the string. `i` must be less than the
/// string's end index.
- @inlinable
+ @inlinable @inline(__always)
public subscript(i: Index) -> Character {
- @inline(__always) get {
- _boundsCheck(i)
+ _boundsCheck(i)
- let i = _guts.scalarAlign(i)
- let distance = _characterStride(startingAt: i)
- return _guts.errorCorrectedCharacter(
- startingAt: i._encodedOffset, endingAt: i._encodedOffset &+ distance)
- }
+ let i = _guts.scalarAlign(i)
+ let distance = _characterStride(startingAt: i)
+ return _guts.errorCorrectedCharacter(
+ startingAt: i._encodedOffset, endingAt: i._encodedOffset &+ distance)
}
@inlinable @inline(__always)
diff --git a/stdlib/public/core/StringGuts.swift b/stdlib/public/core/StringGuts.swift
index 0b4b580..773f1e2 100644
--- a/stdlib/public/core/StringGuts.swift
+++ b/stdlib/public/core/StringGuts.swift
@@ -37,9 +37,9 @@
// Raw
extension _StringGuts {
- @inlinable
+ @inlinable @inline(__always)
internal var rawBits: _StringObject.RawBitPattern {
- @inline(__always) get { return _object.rawBits }
+ return _object.rawBits
}
}
@@ -78,34 +78,33 @@
// Queries
extension _StringGuts {
// The number of code units
- @inlinable
- internal var count: Int { @inline(__always) get { return _object.count } }
+ @inlinable @inline(__always)
+ internal var count: Int { return _object.count }
- @inlinable
- internal var isEmpty: Bool { @inline(__always) get { return count == 0 } }
+ @inlinable @inline(__always)
+ internal var isEmpty: Bool { return count == 0 }
- @inlinable
- internal var isSmall: Bool {
- @inline(__always) get { return _object.isSmall }
- }
+ @inlinable @inline(__always)
+ internal var isSmall: Bool { return _object.isSmall }
+ @inline(__always)
internal var isSmallASCII: Bool {
- @inline(__always) get { return _object.isSmall && _object.smallIsASCII }
+ return _object.isSmall && _object.smallIsASCII
}
- @inlinable
+ @inlinable @inline(__always)
internal var asSmall: _SmallString {
- @inline(__always) get { return _SmallString(_object) }
+ return _SmallString(_object)
}
- @inlinable
+ @inlinable @inline(__always)
internal var isASCII: Bool {
- @inline(__always) get { return _object.isASCII }
+ return _object.isASCII
}
- @inlinable
+ @inlinable @inline(__always)
internal var isFastASCII: Bool {
- @inline(__always) get { return isFastUTF8 && _object.isASCII }
+ return isFastUTF8 && _object.isASCII
}
@inline(__always)
@@ -134,9 +133,9 @@
internal var isFastUTF8: Bool { return _fastPath(_object.providesFastUTF8) }
// A String which does not provide fast access to contiguous UTF-8 code units
- @inlinable
+ @inlinable @inline(__always)
internal var isForeign: Bool {
- @inline(__always) get { return _slowPath(_object.isForeign) }
+ return _slowPath(_object.isForeign)
}
@inlinable @inline(__always)
@@ -259,11 +258,10 @@
return numWritten
}
+ @inline(__always)
internal var utf8Count: Int {
- @inline(__always) get {
- if _fastPath(self.isFastUTF8) { return count }
- return String(self).utf8.count
- }
+ if _fastPath(self.isFastUTF8) { return count }
+ return String(self).utf8.count
}
}
@@ -272,13 +270,13 @@
@usableFromInline
internal typealias Index = String.Index
- @inlinable
+ @inlinable @inline(__always)
internal var startIndex: String.Index {
- @inline(__always) get { return Index(_encodedOffset: 0) }
+ return Index(_encodedOffset: 0)
}
- @inlinable
+ @inlinable @inline(__always)
internal var endIndex: String.Index {
- @inline(__always) get { return Index(_encodedOffset: self.count) }
+ return Index(_encodedOffset: self.count)
}
}
diff --git a/stdlib/public/core/StringIndex.swift b/stdlib/public/core/StringIndex.swift
index 7974004..78dbb7e 100644
--- a/stdlib/public/core/StringIndex.swift
+++ b/stdlib/public/core/StringIndex.swift
@@ -49,18 +49,13 @@
}
extension String.Index {
- @inlinable
- internal var orderingValue: UInt64 {
- // TODO(String micro-performance): Consider mask instead of shift
- @inline(__always) get { return _rawBits &>> 14 }
- }
+ @inlinable @inline(__always)
+ internal var orderingValue: UInt64 { return _rawBits &>> 14 }
// Whether this is at the canonical "start" position, that is encoded AND
// transcoded offset of 0.
- @inlinable
- internal var isZeroPosition: Bool {
- @inline(__always) get { return orderingValue == 0 }
- }
+ @inlinable @inline(__always)
+ internal var isZeroPosition: Bool { return orderingValue == 0 }
/// The UTF-16 code unit offset corresponding to this Index
public func utf16Offset<S: StringProtocol>(in s: S) -> Int {
@@ -80,11 +75,9 @@
return Int(truncatingIfNeeded: _rawBits &>> 16)
}
- @inlinable
+ @inlinable @inline(__always)
internal var transcodedOffset: Int {
- @inline(__always) get {
- return Int(truncatingIfNeeded: orderingValue & 0x3)
- }
+ return Int(truncatingIfNeeded: orderingValue & 0x3)
}
@usableFromInline
@@ -164,45 +157,35 @@
// Creation helpers, which will make migration easier if we decide to use and
// propagate the reserved bits.
extension String.Index {
- @inlinable
+ @inlinable @inline(__always)
internal var strippingTranscoding: String.Index {
- @inline(__always) get {
- return String.Index(_encodedOffset: self._encodedOffset)
- }
+ return String.Index(_encodedOffset: self._encodedOffset)
}
- @inlinable
+ @inlinable @inline(__always)
internal var nextEncoded: String.Index {
- @inline(__always) get {
- _internalInvariant(self.transcodedOffset == 0)
- return String.Index(_encodedOffset: self._encodedOffset &+ 1)
- }
+ _internalInvariant(self.transcodedOffset == 0)
+ return String.Index(_encodedOffset: self._encodedOffset &+ 1)
}
- @inlinable
+ @inlinable @inline(__always)
internal var priorEncoded: String.Index {
- @inline(__always) get {
- _internalInvariant(self.transcodedOffset == 0)
- return String.Index(_encodedOffset: self._encodedOffset &- 1)
- }
+ _internalInvariant(self.transcodedOffset == 0)
+ return String.Index(_encodedOffset: self._encodedOffset &- 1)
}
- @inlinable
+ @inlinable @inline(__always)
internal var nextTranscoded: String.Index {
- @inline(__always) get {
- return String.Index(
- encodedOffset: self._encodedOffset,
- transcodedOffset: self.transcodedOffset &+ 1)
- }
+ return String.Index(
+ encodedOffset: self._encodedOffset,
+ transcodedOffset: self.transcodedOffset &+ 1)
}
- @inlinable
+ @inlinable @inline(__always)
internal var priorTranscoded: String.Index {
- @inline(__always) get {
- return String.Index(
- encodedOffset: self._encodedOffset,
- transcodedOffset: self.transcodedOffset &- 1)
- }
+ return String.Index(
+ encodedOffset: self._encodedOffset,
+ transcodedOffset: self.transcodedOffset &- 1)
}
// Get an index with an encoded offset relative to this one.
diff --git a/stdlib/public/core/StringObject.swift b/stdlib/public/core/StringObject.swift
index 3351fc0..c5db9f5 100644
--- a/stdlib/public/core/StringObject.swift
+++ b/stdlib/public/core/StringObject.swift
@@ -90,12 +90,10 @@
return .immortal(biased)
}
- @inlinable
+ @inlinable @inline(__always)
internal var isImmortal: Bool {
- @inline(__always) get {
- if case .immortal = self { return true }
- return false
- }
+ if case .immortal = self { return true }
+ return false
}
}
@@ -191,11 +189,9 @@
}
}
#else
- @inlinable
+ @inlinable @inline(__always)
internal var rawBits: RawBitPattern {
- @inline(__always) get {
- return (_countAndFlagsBits, discriminatedObjectRawBits)
- }
+ return (_countAndFlagsBits, discriminatedObjectRawBits)
}
@inlinable @inline(__always)
@@ -298,9 +294,9 @@
*/
extension _StringObject.Nibbles {
// The canonical empty sting is an empty small string
- @inlinable
+ @inlinable @inline(__always)
internal static var emptyString: UInt64 {
- @inline(__always) get { return _StringObject.Nibbles.small(isASCII: true) }
+ return _StringObject.Nibbles.small(isASCII: true)
}
}
@@ -381,9 +377,7 @@
// Discriminator for large, mortal (i.e. managed), swift-native strings
@inlinable @inline(__always)
- internal static func largeMortal() -> UInt64 {
- return 0x0000_0000_0000_0000
- }
+ internal static func largeMortal() -> UInt64 { return 0x0000_0000_0000_0000 }
internal static func largeCocoa(providesFastUTF8: Bool) -> UInt64 {
return providesFastUTF8 ? 0x4000_0000_0000_0000 : 0x5000_0000_0000_0000
@@ -391,38 +385,30 @@
}
extension _StringObject {
- @inlinable
+ @inlinable @inline(__always)
internal static var nativeBias: UInt {
- @inline(__always) get {
#if arch(i386) || arch(arm)
- return 20
+ return 20
#else
- return 32
+ return 32
#endif
- }
}
- @inlinable
+ @inlinable @inline(__always)
internal var isImmortal: Bool {
- @inline(__always) get {
- return (discriminatedObjectRawBits & 0x8000_0000_0000_0000) != 0
- }
+ return (discriminatedObjectRawBits & 0x8000_0000_0000_0000) != 0
}
- @inlinable
- internal var isMortal: Bool {
- @inline(__always) get { return !isImmortal }
- }
+ @inlinable @inline(__always)
+ internal var isMortal: Bool { return !isImmortal }
- @inlinable
+ @inlinable @inline(__always)
internal var isSmall: Bool {
- @inline(__always) get {
- return (discriminatedObjectRawBits & 0x2000_0000_0000_0000) != 0
- }
+ return (discriminatedObjectRawBits & 0x2000_0000_0000_0000) != 0
}
- @inlinable
- internal var isLarge: Bool { @inline(__always) get { return !isSmall } }
+ @inlinable @inline(__always)
+ internal var isLarge: Bool { return !isSmall }
// Whether this string can provide access to contiguous UTF-8 code units:
// - Small strings can by spilling to the stack
@@ -430,17 +416,13 @@
// - Shared strings can:
// - Cocoa strings which respond to e.g. CFStringGetCStringPtr()
// - Non-Cocoa shared strings
- @inlinable
+ @inlinable @inline(__always)
internal var providesFastUTF8: Bool {
- @inline(__always) get {
- return (discriminatedObjectRawBits & 0x1000_0000_0000_0000) == 0
- }
+ return (discriminatedObjectRawBits & 0x1000_0000_0000_0000) == 0
}
- @inlinable
- internal var isForeign: Bool {
- @inline(__always) get { return !providesFastUTF8 }
- }
+ @inlinable @inline(__always)
+ internal var isForeign: Bool { return !providesFastUTF8 }
// Whether we are native or shared, i.e. we have a backing class which
// conforms to `_AbstractStringStorage`
@@ -555,26 +537,20 @@
return Int(truncatingIfNeeded: (x & 0x0F00_0000_0000_0000) &>> 56)
}
- @inlinable
+ @inlinable @inline(__always)
internal var smallCount: Int {
- @inline(__always)
- get {
- _internalInvariant(isSmall)
- return _StringObject.getSmallCount(fromRaw: discriminatedObjectRawBits)
- }
+ _internalInvariant(isSmall)
+ return _StringObject.getSmallCount(fromRaw: discriminatedObjectRawBits)
}
@inlinable
internal static func getSmallIsASCII(fromRaw x: UInt64) -> Bool {
return x & 0x4000_0000_0000_0000 != 0
}
- @inlinable
+ @inlinable @inline(__always)
internal var smallIsASCII: Bool {
- @inline(__always)
- get {
- _internalInvariant(isSmall)
- return _StringObject.getSmallIsASCII(fromRaw: discriminatedObjectRawBits)
- }
+ _internalInvariant(isSmall)
+ return _StringObject.getSmallIsASCII(fromRaw: discriminatedObjectRawBits)
}
@inlinable @inline(__always)
@@ -797,31 +773,25 @@
return _countAndFlags.count
}
- @inlinable
+ @inlinable @inline(__always)
internal var largeAddressBits: UInt {
- @inline(__always) get {
- _internalInvariant(isLarge)
- return UInt(truncatingIfNeeded:
- discriminatedObjectRawBits & Nibbles.largeAddressMask)
- }
+ _internalInvariant(isLarge)
+ return UInt(truncatingIfNeeded:
+ discriminatedObjectRawBits & Nibbles.largeAddressMask)
}
- @inlinable
+ @inlinable @inline(__always)
internal var nativeUTF8Start: UnsafePointer<UInt8> {
- @inline(__always) get {
- _internalInvariant(largeFastIsTailAllocated)
- return UnsafePointer(
- bitPattern: largeAddressBits &+ _StringObject.nativeBias
- )._unsafelyUnwrappedUnchecked
- }
+ _internalInvariant(largeFastIsTailAllocated)
+ return UnsafePointer(
+ bitPattern: largeAddressBits &+ _StringObject.nativeBias
+ )._unsafelyUnwrappedUnchecked
}
- @inlinable
+ @inlinable @inline(__always)
internal var nativeUTF8: UnsafeBufferPointer<UInt8> {
- @inline(__always) get {
- _internalInvariant(largeFastIsTailAllocated)
- return UnsafeBufferPointer(start: nativeUTF8Start, count: largeCount)
- }
+ _internalInvariant(largeFastIsTailAllocated)
+ return UnsafeBufferPointer(start: nativeUTF8Start, count: largeCount)
}
// Resilient way to fetch a pointer
@@ -847,47 +817,44 @@
}
}
+ @inline(__always)
internal var nativeStorage: __StringStorage {
- @inline(__always) get {
#if arch(i386) || arch(arm)
- guard case .native(let storage) = _variant else {
- _internalInvariantFailure()
- }
- return _unsafeUncheckedDowncast(storage, to: __StringStorage.self)
-#else
- _internalInvariant(hasNativeStorage)
- return Builtin.reinterpretCast(largeAddressBits)
-#endif
+ guard case .native(let storage) = _variant else {
+ _internalInvariantFailure()
}
+ return _unsafeUncheckedDowncast(storage, to: __StringStorage.self)
+#else
+ _internalInvariant(hasNativeStorage)
+ return Builtin.reinterpretCast(largeAddressBits)
+#endif
}
+ @inline(__always)
internal var sharedStorage: __SharedStringStorage {
- @inline(__always) get {
#if arch(i386) || arch(arm)
- guard case .native(let storage) = _variant else {
- _internalInvariantFailure()
- }
- return _unsafeUncheckedDowncast(storage, to: __SharedStringStorage.self)
-#else
- _internalInvariant(largeFastIsShared && !largeIsCocoa)
- _internalInvariant(hasSharedStorage)
- return Builtin.reinterpretCast(largeAddressBits)
-#endif
+ guard case .native(let storage) = _variant else {
+ _internalInvariantFailure()
}
+ return _unsafeUncheckedDowncast(storage, to: __SharedStringStorage.self)
+#else
+ _internalInvariant(largeFastIsShared && !largeIsCocoa)
+ _internalInvariant(hasSharedStorage)
+ return Builtin.reinterpretCast(largeAddressBits)
+#endif
}
+ @inline(__always)
internal var cocoaObject: AnyObject {
- @inline(__always) get {
#if arch(i386) || arch(arm)
- guard case .bridged(let object) = _variant else {
- _internalInvariantFailure()
- }
- return object
-#else
- _internalInvariant(largeIsCocoa && !isImmortal)
- return Builtin.reinterpretCast(largeAddressBits)
-#endif
+ guard case .bridged(let object) = _variant else {
+ _internalInvariantFailure()
}
+ return object
+#else
+ _internalInvariant(largeIsCocoa && !isImmortal)
+ return Builtin.reinterpretCast(largeAddressBits)
+#endif
}
}
@@ -896,20 +863,16 @@
// The number of code units stored
//
// TODO(String micro-performance): Check generated code
- @inlinable
- internal var count: Int {
- @inline(__always) get { return isSmall ? smallCount : largeCount }
- }
+ @inlinable @inline(__always)
+ internal var count: Int { return isSmall ? smallCount : largeCount }
//
// Whether the string is all ASCII
//
- @inlinable
+ @inlinable @inline(__always)
internal var isASCII: Bool {
- @inline(__always) get {
- if isSmall { return smallIsASCII }
- return _countAndFlags.isASCII
- }
+ if isSmall { return smallIsASCII }
+ return _countAndFlags.isASCII
}
@inline(__always)
diff --git a/stdlib/public/core/StringStorage.swift b/stdlib/public/core/StringStorage.swift
index a1e1fca..1c9e2ac 100644
--- a/stdlib/public/core/StringStorage.swift
+++ b/stdlib/public/core/StringStorage.swift
@@ -423,8 +423,9 @@
private var mutableStart: UnsafeMutablePointer<UInt8> {
return UnsafeMutablePointer(Builtin.projectTailElems(self, UInt8.self))
}
+ @inline(__always)
private var mutableEnd: UnsafeMutablePointer<UInt8> {
- @inline(__always) get { return mutableStart + count }
+ return mutableStart + count
}
@inline(__always)
@@ -432,19 +433,20 @@
return UnsafePointer(mutableStart)
}
+ @inline(__always)
private final var end: UnsafePointer<UInt8> {
- @inline(__always) get { return UnsafePointer(mutableEnd) }
+ return UnsafePointer(mutableEnd)
}
// Point to the nul-terminator.
+ @inline(__always)
private final var terminator: UnsafeMutablePointer<UInt8> {
- @inline(__always) get { return mutableEnd }
+ return mutableEnd
}
+ @inline(__always)
private var codeUnits: UnsafeBufferPointer<UInt8> {
- @inline(__always) get {
- return UnsafeBufferPointer(start: start, count: count)
- }
+ return UnsafeBufferPointer(start: start, count: count)
}
// @opaque
@@ -467,18 +469,15 @@
// required nul-terminator.
//
// NOTE: Callers who wish to mutate this storage should enfore nul-termination
+ @inline(__always)
private var unusedStorage: UnsafeMutableBufferPointer<UInt8> {
- @inline(__always) get {
- return UnsafeMutableBufferPointer(
- start: mutableEnd, count: unusedCapacity)
- }
+ return UnsafeMutableBufferPointer(
+ start: mutableEnd, count: unusedCapacity)
}
// The capacity available for appending. Note that this excludes the required
// nul-terminator.
- internal var unusedCapacity: Int {
- get { return _realCapacity &- count &- 1 }
- }
+ internal var unusedCapacity: Int { return _realCapacity &- count &- 1 }
#if !INTERNAL_CHECKS_ENABLED
@inline(__always) internal func _invariantCheck() {}
diff --git a/stdlib/public/core/StringUTF16View.swift b/stdlib/public/core/StringUTF16View.swift
index 6cb85b9..9e9ed6e 100644
--- a/stdlib/public/core/StringUTF16View.swift
+++ b/stdlib/public/core/StringUTF16View.swift
@@ -128,19 +128,15 @@
/// The position of the first code unit if the `String` is
/// nonempty; identical to `endIndex` otherwise.
- @inlinable
- public var startIndex: Index {
- @inline(__always) get { return _guts.startIndex }
- }
+ @inlinable @inline(__always)
+ public var startIndex: Index { return _guts.startIndex }
/// The "past the end" position---that is, the position one greater than
/// the last valid subscript argument.
///
/// In an empty UTF-16 view, `endIndex` is equal to `startIndex`.
- @inlinable
- public var endIndex: Index {
- @inline(__always) get { return _guts.endIndex }
- }
+ @inlinable @inline(__always)
+ public var endIndex: Index { return _guts.endIndex }
@inlinable @inline(__always)
public func index(after i: Index) -> Index {
@@ -242,22 +238,20 @@
///
/// - Parameter position: A valid index of the view. `position` must be
/// less than the view's end index.
- @inlinable
+ @inlinable @inline(__always)
public subscript(i: Index) -> UTF16.CodeUnit {
- @inline(__always) get {
- String(_guts)._boundsCheck(i)
+ String(_guts)._boundsCheck(i)
- if _fastPath(_guts.isFastUTF8) {
- let scalar = _guts.fastUTF8Scalar(
- startingAt: _guts.scalarAlign(i)._encodedOffset)
- if scalar.value <= 0xFFFF {
- return UInt16(truncatingIfNeeded: scalar.value)
- }
- return scalar.utf16[i.transcodedOffset]
+ if _fastPath(_guts.isFastUTF8) {
+ let scalar = _guts.fastUTF8Scalar(
+ startingAt: _guts.scalarAlign(i)._encodedOffset)
+ if scalar.value <= 0xFFFF {
+ return UInt16(truncatingIfNeeded: scalar.value)
}
-
- return _foreignSubscript(position: i)
+ return scalar.utf16[i.transcodedOffset]
}
+
+ return _foreignSubscript(position: i)
}
}
@@ -314,10 +308,8 @@
extension String.UTF16View: CustomStringConvertible {
- @inlinable
- public var description: String {
- @inline(__always) get { return String(_guts) }
- }
+ @inlinable @inline(__always)
+ public var description: String { return String(_guts) }
}
extension String.UTF16View: CustomDebugStringConvertible {
@@ -500,8 +492,8 @@
// Breadcrumb-aware acceleration
extension String.UTF16View {
// A simple heuristic we can always tweak later. Not needed for correctness
- @inlinable
- internal var _shortHeuristic: Int { @inline(__always) get { return 32 } }
+ @inlinable @inline(__always)
+ internal var _shortHeuristic: Int { return 32 }
@usableFromInline
@_effects(releasenone)
diff --git a/stdlib/public/core/StringUTF8View.swift b/stdlib/public/core/StringUTF8View.swift
index 81b8bdb..c641a08 100644
--- a/stdlib/public/core/StringUTF8View.swift
+++ b/stdlib/public/core/StringUTF8View.swift
@@ -121,19 +121,15 @@
/// nonempty.
///
/// If the UTF-8 view is empty, `startIndex` is equal to `endIndex`.
- @inlinable
- public var startIndex: Index {
- @inline(__always) get { return _guts.startIndex }
- }
+ @inlinable @inline(__always)
+ public var startIndex: Index { return _guts.startIndex }
/// The "past the end" position---that is, the position one
/// greater than the last valid subscript argument.
///
/// In an empty UTF-8 view, `endIndex` is equal to `startIndex`.
- @inlinable
- public var endIndex: Index {
- @inline(__always) get { return _guts.endIndex }
- }
+ @inlinable @inline(__always)
+ public var endIndex: Index { return _guts.endIndex }
/// Returns the next consecutive position after `i`.
///
@@ -209,30 +205,26 @@
///
/// - Parameter position: A valid index of the view. `position`
/// must be less than the view's end index.
- @inlinable
+ @inlinable @inline(__always)
public subscript(i: Index) -> UTF8.CodeUnit {
- @inline(__always) get {
- String(_guts)._boundsCheck(i)
- if _fastPath(_guts.isFastUTF8) {
- return _guts.withFastUTF8 { utf8 in utf8[_unchecked: i._encodedOffset] }
- }
-
- return _foreignSubscript(position: i)
+ String(_guts)._boundsCheck(i)
+ if _fastPath(_guts.isFastUTF8) {
+ return _guts.withFastUTF8 { utf8 in utf8[_unchecked: i._encodedOffset] }
}
+
+ return _foreignSubscript(position: i)
}
}
extension String.UTF8View: CustomStringConvertible {
- @inlinable
- public var description: String {
- @inline(__always) get { return String(String(_guts)) }
- }
+ @inlinable @inline(__always)
+ public var description: String { return String(_guts) }
}
extension String.UTF8View: CustomDebugStringConvertible {
- public var debugDescription: String {
- return "UTF8View(\(self.description.debugDescription))"
- }
+ public var debugDescription: String {
+ return "UTF8View(\(self.description.debugDescription))"
+ }
}
@@ -289,14 +281,12 @@
}
extension String.UTF8View {
- @inlinable
+ @inlinable @inline(__always)
public var count: Int {
- @inline(__always) get {
- if _fastPath(_guts.isFastUTF8) {
- return _guts.count
- }
- return _foreignCount()
+ if _fastPath(_guts.isFastUTF8) {
+ return _guts.count
}
+ return _foreignCount()
}
}
diff --git a/stdlib/public/core/StringUnicodeScalarView.swift b/stdlib/public/core/StringUnicodeScalarView.swift
index d46792d..5a9a589 100644
--- a/stdlib/public/core/StringUnicodeScalarView.swift
+++ b/stdlib/public/core/StringUnicodeScalarView.swift
@@ -91,19 +91,15 @@
/// nonempty.
///
/// If the string is empty, `startIndex` is equal to `endIndex`.
- @inlinable
- public var startIndex: Index {
- @inline(__always) get { return _guts.startIndex }
- }
+ @inlinable @inline(__always)
+ public var startIndex: Index { return _guts.startIndex }
/// The "past the end" position---that is, the position one greater than
/// the last valid subscript argument.
///
/// In an empty Unicode scalars view, `endIndex` is equal to `startIndex`.
- @inlinable
- public var endIndex: Index {
- @inline(__always) get { return _guts.endIndex }
- }
+ @inlinable @inline(__always)
+ public var endIndex: Index { return _guts.endIndex }
/// Returns the next consecutive location after `i`.
///
@@ -156,13 +152,11 @@
///
/// - Parameter position: A valid index of the character view. `position`
/// must be less than the view's end index.
- @inlinable
+ @inlinable @inline(__always)
public subscript(position: Index) -> Unicode.Scalar {
- @inline(__always) get {
- String(_guts)._boundsCheck(position)
- let i = _guts.scalarAlign(position)
- return _guts.errorCorrectedScalar(startingAt: i._encodedOffset).0
- }
+ String(_guts)._boundsCheck(position)
+ let i = _guts.scalarAlign(position)
+ return _guts.errorCorrectedScalar(startingAt: i._encodedOffset).0
}
}
@@ -201,10 +195,8 @@
}
extension String.UnicodeScalarView: CustomStringConvertible {
- @inlinable
- public var description: String {
- @inline(__always) get { return String(_guts) }
- }
+ @inlinable @inline(__always)
+ public var description: String { return String(_guts) }
}
extension String.UnicodeScalarView: CustomDebugStringConvertible {
diff --git a/stdlib/public/core/Substring.swift b/stdlib/public/core/Substring.swift
index 1d89c3b..809a25d 100644
--- a/stdlib/public/core/Substring.swift
+++ b/stdlib/public/core/Substring.swift
@@ -148,14 +148,11 @@
public typealias Index = String.Index
public typealias SubSequence = Substring
- @inlinable
- public var startIndex: Index {
- @inline(__always) get { return _slice.startIndex }
- }
- @inlinable
- public var endIndex: Index {
- @inline(__always) get { return _slice.endIndex }
- }
+ @inlinable @inline(__always)
+ public var startIndex: Index { return _slice.startIndex }
+
+ @inlinable @inline(__always)
+ public var endIndex: Index { return _slice.endIndex }
@inlinable @inline(__always)
public func index(after i: Index) -> Index {
@@ -309,10 +306,8 @@
}
extension Substring : CustomStringConvertible {
- @inlinable
- public var description: String {
- @inline(__always) get { return String(self) }
- }
+ @inlinable @inline(__always)
+ public var description: String { return String(self) }
}
extension Substring : CustomDebugStringConvertible {
diff --git a/test/Constraints/anyhashable-collection-cast.swift b/test/Constraints/anyhashable-collection-cast.swift
index 2465dcb..a951761 100644
--- a/test/Constraints/anyhashable-collection-cast.swift
+++ b/test/Constraints/anyhashable-collection-cast.swift
@@ -18,6 +18,6 @@
func testLValueCoerce() {
var lvalue = "lvalue"
- var map: [AnyHashable : Any] = [lvalue: lvalue]
+ let map: [AnyHashable : Any] = [lvalue: lvalue]
lvalue = map[lvalue] as! String
}
diff --git a/test/Generics/non_generic_derived_class.swift b/test/Generics/non_generic_derived_class.swift
index bb89992..1934011 100644
--- a/test/Generics/non_generic_derived_class.swift
+++ b/test/Generics/non_generic_derived_class.swift
@@ -9,3 +9,10 @@
class Derived : Base<Int> {}
var a = Derived.f(42)
+
+protocol SR9160_EmptyProtocol {}
+class SR9160_AbstractFoobar<Foo> {}
+// This used to cause the swift compiler to never finish compiling.
+final class SR9160_SomeFoobar: SR9160_AbstractFoobar<SR9160_SomeFoobar.Foo> {
+ enum Foo: SR9160_EmptyProtocol {}
+}
diff --git a/test/IRGen/pic.swift b/test/IRGen/pic.swift
index e38c587..da75ae9 100644
--- a/test/IRGen/pic.swift
+++ b/test/IRGen/pic.swift
@@ -1,7 +1,7 @@
// <rdar://problem/15358345> Check that we always use PIC relocations on all
// platforms.
-// RUN: %target-swift-frontend %s -module-name main -S -o - | %FileCheck -check-prefix=%target-cpu %s
+// RUN: %target-swift-frontend %s -module-name main -S -o - | %FileCheck -check-prefix=%target-cpu -check-prefix=%target-cpu-%target-sdk-name %s
var global: Int = 0
@@ -20,12 +20,26 @@
// armv7-LABEL: {{_?}}$s4main10use_globalSiyF:
// Check for the runtime memory enforcement call. The global address may be
// materialized in a different register prior to that call.
-// armv7: bl _swift_beginAccess
-// armv7: movw [[R_ADR:r.*]], :lower16:(_$s4main6globalSivp-([[PIC_0:L.*]]+4))
-// armv7: movt [[R_ADR]], :upper16:(_$s4main6globalSivp-([[PIC_0]]+4))
-// armv7: [[PIC_0]]:{{$}}
-// armv7: add [[R_ADR]], pc
-// armv7: ldr [[R_ADR]], {{\[}}[[R_ADR]]{{\]}}
+// armv7: bl {{_?}}swift_beginAccess
+// armv7-iphoneos: movw [[R_ADR:r.*]], :lower16:(_$s4main6globalSivp-([[PIC_0:L.*]]+4))
+// armv7-iphoneos: movt [[R_ADR]], :upper16:(_$s4main6globalSivp-([[PIC_0]]+4))
+// armv7-iphoneos: [[PIC_0]]:{{$}}
+// armv7-iphoneos: ldr [[R_ADR]], {{\[}}[[R_ADR]]{{\]}}
+
+// armv7-android: ldr [[R_ADR:r.*]], .LCPI[[PIC_0:[0-9]_[0-9]]]
+// armv7-android: .LPC[[PIC_0]]:{{$}}
+// armv7-android: add [[R_ADR]], pc
+// armv7-android: bl {{_?}}swift_endAccess
+// armv7-android: .LCPI[[PIC_0]]:{{$}}
+// armv7-android: .long ($s4main6globalSivp)-(.LPC[[PIC_0]]+8)
+
+// armv7-linux: ldr [[R_ADR:r.*]], .LCPI[[PIC_0:[0-9]_[0-9]]]
+// armv7-linux: .LPC[[PIC_0]]:{{$}}
+// armv7-linux: add [[R_ADR]], pc
+// armv7-linux: bl {{_?}}swift_endAccess
+// armv7-linux: .LCPI[[PIC_0]]:{{$}}
+// armv7-linux: .long ($s4main6globalSivp)-(.LPC[[PIC_0]]+8)
+
// armv7s-LABEL: {{_?}}$s4main10use_globalSiyF:
// armv7s: bl _swift_beginAccess
@@ -53,13 +67,15 @@
// arm64: ldr x0, [sp]
// aarch64-LABEL: $s4main10use_globalSiyF:
-// aarch64: adrp [[REG1:x[0-9]+]], ($s4main6globalSivp@PAGE)
-// aarch64: add [[REG1]], [[REG1]], :lo12:($s4main6globalSivp)
-// aarch64: bl swift_beginAccess
-// aarch64: ldr [[REG2:x[0-9]+]], {{\[}}[[REG1]]{{\]}}
-// aarch64: str [[REG2]], [sp]
-// aarch64: bl swift_endAccess
-// aarch64: ldr x0, [sp]
+// aarch64: bl swift_beginAccess
+// aarch64-windows: adrp [[REG1:x[0-9]+]], ($s4main6globalSivp@PAGE)
+// aarch64-linux: adrp [[REG1:x[0-9]+]], ($s4main6globalSivp)
+// aarch64-android: adrp [[REG1:x[0-9]+]], ($s4main6globalSivp)
+// aarch64: add [[REG1]], [[REG1]], :lo12:($s4main6globalSivp)
+// aarch64: ldr [[REG2:x[0-9]+]], {{\[}}[[REG1]]{{\]}}
+// aarch64: str [[REG2]], [sp]
+// aarch64: bl swift_endAccess
+// aarch64: ldr x0, [sp]
// powerpc64le-LABEL: {{_?}}$s4main10use_globalSiyF:
// powerpc64le: bl swift_beginAccess
diff --git a/test/Misc/fatal_error.swift b/test/Misc/fatal_error.swift
index e5e14f5..154da6a 100644
--- a/test/Misc/fatal_error.swift
+++ b/test/Misc/fatal_error.swift
@@ -1,5 +1,6 @@
// RUN: not %target-swift-frontend -typecheck %s -sdk "" 2>&1 | %FileCheck -check-prefix=CHECK -check-prefix=NO-MODULE %s
// RUN: not %target-swift-frontend -typecheck %s -resource-dir / 2>&1 | %FileCheck -check-prefix=CHECK -check-prefix=NO-STDLIB %s
+// REQUIRES: rdar49665477
// NO-MODULE: error: no such module 'NonExistent'
diff --git a/test/Parse/swift3_warnings_swift4_errors_version_4.swift b/test/Parse/swift3_warnings_swift4_errors_version_4.swift
index 661190d..ef715e6 100644
--- a/test/Parse/swift3_warnings_swift4_errors_version_4.swift
+++ b/test/Parse/swift3_warnings_swift4_errors_version_4.swift
@@ -13,9 +13,12 @@
let y: protocol<P1> // expected-error {{'protocol<...>' composition syntax has been removed and is not needed here}}}
let z: protocol<P1, P2> // expected-error {{'protocol<...>' composition syntax has been removed; join the protocols using '&'}}
-func bar(f: @noescape () -> ()) {} // expected-error {{@noescape is the default and has been removed}}
+func bar(f: @noescape () -> ()) {} // expected-error {{unknown attribute 'noescape'}}
-func baz(f: @autoclosure(escaping) () -> ()) {} // expected-error {{@autoclosure(escaping) has been removed; use @autoclosure @escaping instead}}
+func baz(f: @autoclosure(escaping) () -> ()) {}
+// expected-error @-1 {{use of undeclared type 'escaping'}}
+// expected-error @-2 {{unnamed parameters must be written with the empty name '_'}}
+// expected-error @-3 {{expected ',' separator}}
prefix operator +++ {} // expected-error {{operator should no longer be declared with body}}
postfix operator +++ {} // expected-error {{operator should no longer be declared with body}}
diff --git a/test/ParseableInterface/private-stored-members.swift b/test/ParseableInterface/private-stored-members.swift
index 8ccb6cd..2c21f68 100644
--- a/test/ParseableInterface/private-stored-members.swift
+++ b/test/ParseableInterface/private-stored-members.swift
@@ -21,12 +21,12 @@
// COMMON-NEXT: let publicLet: [[BOOL:(Swift\.)?Bool]]{{$}}
public let publicLet: Bool
-// CHECK-NEXT: internal var _: [[INT64]]{{$}}
-// RESILIENT-NOT: internal var _: [[INT64]]{{$}}
+// CHECK-NEXT: internal var internalVar: [[INT64]]{{$}}
+// RESILIENT-NOT: internal var internalVar: [[INT64]]{{$}}
var internalVar: Int64
-// CHECK-NEXT: internal let _: [[BOOL]]{{$}}
-// RESILIENT-NOT: internal let _: [[BOOL]]{{$}}
+// CHECK-NEXT: internal let internalLet: [[BOOL]]{{$}}
+// RESILIENT-NOT: internal let internalLet: [[BOOL]]{{$}}
let internalLet: Bool
// COMMON-NEXT: @usableFromInline
@@ -37,12 +37,12 @@
// COMMON-NEXT: internal let ufiLet: [[BOOL]]{{$}}
@usableFromInline let ufiLet: Bool
-// CHECK-NEXT: private var _: [[INT64]]{{$}}
-// RESILIENT-NOT: private var _: [[INT64]]{{$}}
+// CHECK-NEXT: private var privateVar: [[INT64]]{{$}}
+// RESILIENT-NOT: private var privateVar: [[INT64]]{{$}}
private var privateVar: Int64
-// CHECK-NEXT: private let _: [[BOOL]]{{$}}
-// RESILIENT-NOT: private let _: [[BOOL]]{{$}}
+// CHECK-NEXT: private let privateLet: [[BOOL]]{{$}}
+// RESILIENT-NOT: private let privateLet: [[BOOL]]{{$}}
private let privateLet: Bool
// CHECK-NOT: private var
diff --git a/test/ParseableInterface/stored-properties.swift b/test/ParseableInterface/stored-properties.swift
index 03ecbbb..e139b54 100644
--- a/test/ParseableInterface/stored-properties.swift
+++ b/test/ParseableInterface/stored-properties.swift
@@ -49,7 +49,8 @@
// COMMON-NEXT: }
public private(set) var storedPrivateSet: Int
- // CHECK: private var _: [[BOOL]]
+ // CHECK: private var privateVar: [[BOOL]]
+ // RESILIENT-NOT: private var privateVar: [[BOOL]]
private var privateVar: Bool
// CHECK: @_hasStorage @_hasInitialValue public var storedWithObserversInitialValue: [[INT]] {
diff --git a/test/SIL/ownership-verifier/over_consume.sil b/test/SIL/ownership-verifier/over_consume.sil
index 7cd4fbf..42a12b1 100644
--- a/test/SIL/ownership-verifier/over_consume.sil
+++ b/test/SIL/ownership-verifier/over_consume.sil
@@ -22,6 +22,13 @@
case none
}
+protocol Error {}
+
+struct NativeObjectPair {
+ var obj1 : Builtin.NativeObject
+ var obj2 : Builtin.NativeObject
+}
+
class SuperKlass {
func doSomething()
}
@@ -485,3 +492,35 @@
%5 = tuple(%3 : $ClassProt, %4 : $ClassProt)
return %5 : $(ClassProt, ClassProt)
}
+
+sil [ossa] @eliminate_copy_try_apple_callee : $@convention(thin) (@owned Builtin.NativeObject) -> @error Error {
+entry(%0 : @owned $Builtin.NativeObject):
+ %9999 = tuple()
+ return %9999 : $()
+}
+
+
+// CHECK-LABEL: Function: 'use_after_free_consume_in_same_block'
+// CHECK: Found use after free due to unvisited non lifetime ending uses?!
+// CHECK: Value: %3 = copy_value %2 : $Builtin.NativeObject
+// CHECK: Remaining Users:
+// CHECK: User: %10 = apply %7(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
+sil [ossa] @use_after_free_consume_in_same_block : $@convention(thin) (@owned NativeObjectPair) -> @error Error {
+bb0(%0 : @owned $NativeObjectPair):
+ %1 = begin_borrow %0 : $NativeObjectPair
+ %2 = struct_extract %1 : $NativeObjectPair, #NativeObjectPair.obj1
+ %3 = copy_value %2 : $Builtin.NativeObject
+ end_borrow %1 : $NativeObjectPair
+ destroy_value %0 : $NativeObjectPair
+ %4 = function_ref @eliminate_copy_try_apple_callee : $@convention(thin) (@owned Builtin.NativeObject) -> @error Error
+ %5 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
+ try_apply %4(%3) : $@convention(thin) (@owned Builtin.NativeObject) -> @error Error, normal bb1, error bb2
+
+bb1(%errorEmptyTup: $()):
+ apply %5(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
+ %9999 = tuple()
+ return %9999 : $()
+
+bb2(%error : @owned $Error):
+ throw %error : $Error
+}
diff --git a/test/SILGen/enum.swift b/test/SILGen/enum.swift
index ac064f4..7f1fd19 100644
--- a/test/SILGen/enum.swift
+++ b/test/SILGen/enum.swift
@@ -249,8 +249,8 @@
// CHECK: bb0(%0 : $Optional<SR7799>):
// CHECK-NEXT: debug_value %0 : $Optional<SR7799>, let, name "bar", argno 1
// CHECK-NEXT: switch_enum %0 : $Optional<SR7799>, case #Optional.some!enumelt.1: bb1, default bb4
-// CHECK: bb1(%3 : $SR7799):
-// CHECK-NEXT: switch_enum %3 : $SR7799, case #SR7799.one!enumelt: bb2, case #SR7799.two!enumelt: bb3
+// CHECK: bb1([[PHI_ARG:%.*]] : $SR7799):
+// CHECK-NEXT: switch_enum [[PHI_ARG]] : $SR7799, case #SR7799.one!enumelt: bb2, case #SR7799.two!enumelt: bb3
func sr7799(bar: SR7799?) {
switch bar {
case .one: print("one")
diff --git a/test/SILGen/enum_resilience.swift b/test/SILGen/enum_resilience.swift
index 5b6e1cc..c27f773 100644
--- a/test/SILGen/enum_resilience.swift
+++ b/test/SILGen/enum_resilience.swift
@@ -12,6 +12,7 @@
// CHECK-LABEL: sil hidden [ossa] @$s15enum_resilience15resilientSwitchyy0c1_A06MediumOF : $@convention(thin) (@in_guaranteed Medium) -> ()
// CHECK: [[BOX:%.*]] = alloc_stack $Medium
// CHECK-NEXT: copy_addr %0 to [initialization] [[BOX]]
+// CHECK-NEXT: [[METATYPE:%.+]] = value_metatype $@thick Medium.Type, [[BOX]] : $*Medium
// CHECK-NEXT: switch_enum_addr [[BOX]] : $*Medium, case #Medium.Paper!enumelt: bb1, case #Medium.Canvas!enumelt: bb2, case #Medium.Pamphlet!enumelt.1: bb3, case #Medium.Postcard!enumelt.1: bb4, default bb5
// CHECK: bb1:
// CHECK-NEXT: dealloc_stack [[BOX]]
@@ -32,7 +33,6 @@
// CHECK-NEXT: dealloc_stack [[BOX]]
// CHECK-NEXT: br bb6
// CHECK: bb5:
-// CHECK-NEXT: [[METATYPE:%.+]] = value_metatype $@thick Medium.Type, [[BOX]] : $*Medium
// CHECK-NEXT: // function_ref
// CHECK-NEXT: [[DIAGNOSE:%.+]] = function_ref @$ss27_diagnoseUnexpectedEnumCase
// CHECK-NEXT: = apply [[DIAGNOSE]]<Medium>([[METATYPE]]) : $@convention(thin) <τ_0_0> (@thick τ_0_0.Type) -> Never
diff --git a/test/SILGen/enum_resilience_testable.swift b/test/SILGen/enum_resilience_testable.swift
index c1b3a46..75260ea 100644
--- a/test/SILGen/enum_resilience_testable.swift
+++ b/test/SILGen/enum_resilience_testable.swift
@@ -17,6 +17,7 @@
// CHECK-LABEL: sil hidden [ossa] @$s24enum_resilience_testable15resilientSwitchyy0d1_A06MediumOF : $@convention(thin) (@in_guaranteed Medium) -> ()
// CHECK: [[BOX:%.*]] = alloc_stack $Medium
// CHECK-NEXT: copy_addr %0 to [initialization] [[BOX]]
+// CHECK-NEXT: [[METATYPE:%.+]] = value_metatype $@thick Medium.Type, [[BOX]] : $*Medium
// CHECK-NEXT: switch_enum_addr [[BOX]] : $*Medium, case #Medium.Paper!enumelt: bb1, case #Medium.Canvas!enumelt: bb2, case #Medium.Pamphlet!enumelt.1: bb3, case #Medium.Postcard!enumelt.1: bb4, default bb5
// CHECK: bb1:
// CHECK-NEXT: dealloc_stack [[BOX]]
@@ -37,7 +38,6 @@
// CHECK-NEXT: dealloc_stack [[BOX]]
// CHECK-NEXT: br bb6
// CHECK: bb5:
-// CHECK-NEXT: [[METATYPE:%.+]] = value_metatype $@thick Medium.Type, [[BOX]] : $*Medium
// CHECK-NEXT: // function_ref
// CHECK-NEXT: [[DIAGNOSE:%.+]] = function_ref @$ss27_diagnoseUnexpectedEnumCase
// CHECK-NEXT: = apply [[DIAGNOSE]]<Medium>([[METATYPE]]) : $@convention(thin) <τ_0_0> (@thick τ_0_0.Type) -> Never
diff --git a/test/SILGen/switch.swift b/test/SILGen/switch.swift
index c5c14ff..6bf6335 100644
--- a/test/SILGen/switch.swift
+++ b/test/SILGen/switch.swift
@@ -1029,8 +1029,8 @@
case let x?:
return 0
- // CHECK: [[SOMEBB]](%3 : $Int):
- // CHECK-NEXT: debug_value %3 : $Int, let, name "x"
+ // CHECK: [[SOMEBB]]([[X:%.*]] : $Int):
+ // CHECK-NEXT: debug_value [[X]] : $Int, let, name "x"
// CHECK: integer_literal $Builtin.IntLiteral, 0
case .none:
@@ -1051,8 +1051,8 @@
case let x?:
return 0
- // CHECK: [[SOMEBB]](%3 : $Int):
- // CHECK-NEXT: debug_value %3 : $Int, let, name "x"
+ // CHECK: [[SOMEBB]]([[X:%.*]] : $Int):
+ // CHECK-NEXT: debug_value [[X]] : $Int, let, name "x"
// CHECK: integer_literal $Builtin.IntLiteral, 0
case nil:
diff --git a/test/SILGen/switch_objc.swift b/test/SILGen/switch_objc.swift
index 72fe068..914bc41 100644
--- a/test/SILGen/switch_objc.swift
+++ b/test/SILGen/switch_objc.swift
@@ -25,3 +25,30 @@
return false
}
}
+
+@objc enum ObjCEnum : UInt8 {
+case first
+case second
+}
+
+// CHECK-LABEL: sil hidden [ossa] @$s11switch_objc44checkObjCEnumUnhandledCaseDiagnosticEmission1xyAA0dE0O_tF : $@convention(thin) (ObjCEnum) -> () {
+// CHECK: bb0([[ARG:%.*]] :
+// CHECK: [[METATYPE:%.*]] = metatype $@thick ObjCEnum.Type
+// CHECK: [[ARG_INT_REPR:%.*]] = unchecked_trivial_bit_cast [[ARG]]
+// CHECK: switch_enum [[ARG]] : $ObjCEnum, {{.*}}, default [[DEFAULT_BB:bb[0-9]+]]
+//
+// CHECK: [[DEFAULT_BB]](
+// CHECK: [[STACK_SLOT:%.*]] = alloc_stack $UInt8
+// CHECK: store [[ARG_INT_REPR]] to [trivial] [[STACK_SLOT]]
+// CHECK: [[DIAGNOSE_FUNC:%.*]] = function_ref @$ss32_diagnoseUnexpectedEnumCaseValue4type03rawE0s5NeverOxm_q_tr0_lF : $@convention(thin) <τ_0_0, τ_0_1> (@thick τ_0_0.Type, @in_guaranteed τ_0_1) -> Never
+// CHECK: apply [[DIAGNOSE_FUNC]]<ObjCEnum, UInt8>([[METATYPE]], [[STACK_SLOT]])
+// CHECK: unreachable
+// CHECK: } // end sil function '$s11switch_objc44checkObjCEnumUnhandledCaseDiagnosticEmission1xyAA0dE0O_tF'
+func checkObjCEnumUnhandledCaseDiagnosticEmission(x: ObjCEnum) {
+ switch x {
+ case .first:
+ break
+ case .second:
+ break
+ }
+}
diff --git a/test/SILOptimizer/allocbox_to_stack_not_crash.swift b/test/SILOptimizer/allocbox_to_stack_not_crash.swift
deleted file mode 100644
index 3441124..0000000
--- a/test/SILOptimizer/allocbox_to_stack_not_crash.swift
+++ /dev/null
@@ -1,15 +0,0 @@
-// RUN: %target-swift-frontend %s -emit-ir -verify
-
-// Verify we don't crash on this.
-// rdar://15595118
-infix operator ~>
-protocol Target {}
-
-func ~> <Target, Arg0, Result>(x: inout Target, f: @escaping (_: inout Target, _: Arg0) -> Result) -> (Arg0) -> Result {
- return { f(&x, $0) } // expected-error {{escaping closures can only capture inout parameters explicitly by value}}
-}
-
-func ~> (x: inout Int, f: @escaping (_: inout Int, _: Target) -> Target) -> (Target) -> Target {
- return { f(&x, $0) } // expected-error {{escaping closures can only capture inout parameters explicitly by value}}
-}
-
diff --git a/test/SILOptimizer/allocbox_to_stack_not_crash_ownership.swift b/test/SILOptimizer/allocbox_to_stack_not_crash_ownership.swift
deleted file mode 100644
index 3441124..0000000
--- a/test/SILOptimizer/allocbox_to_stack_not_crash_ownership.swift
+++ /dev/null
@@ -1,15 +0,0 @@
-// RUN: %target-swift-frontend %s -emit-ir -verify
-
-// Verify we don't crash on this.
-// rdar://15595118
-infix operator ~>
-protocol Target {}
-
-func ~> <Target, Arg0, Result>(x: inout Target, f: @escaping (_: inout Target, _: Arg0) -> Result) -> (Arg0) -> Result {
- return { f(&x, $0) } // expected-error {{escaping closures can only capture inout parameters explicitly by value}}
-}
-
-func ~> (x: inout Int, f: @escaping (_: inout Int, _: Target) -> Target) -> (Target) -> Target {
- return { f(&x, $0) } // expected-error {{escaping closures can only capture inout parameters explicitly by value}}
-}
-
diff --git a/test/SILOptimizer/exclusivity_static_diagnostics.swift b/test/SILOptimizer/exclusivity_static_diagnostics.swift
index 7d73d30..9e4dca5 100644
--- a/test/SILOptimizer/exclusivity_static_diagnostics.swift
+++ b/test/SILOptimizer/exclusivity_static_diagnostics.swift
@@ -607,10 +607,10 @@
}
}
-// TODO: A conflict should also be detected here. However, the
-// typechecker does not allow it. Enable the following test if we ever
-// remove this case from the typechecker test:
-// diag_invalid_inout_captures.swift.
-// public func nestedConflict(x: inout Int) {
-// doit(x: &x, x == 0 ? { x = 1 } : { x = 2})
-// }
+func doit(x: inout Int, _ fn: () -> ()) {}
+
+func nestedConflict(x: inout Int) {
+ doit(x: &x, x == 0 ? { x = 1 } : { x = 2})
+ // expected-error@-1 2{{overlapping accesses to 'x', but modification requires exclusive access; consider copying to a local variable}}
+ // expected-note@-2 2{{conflicting access is here}}
+}
diff --git a/test/SILOptimizer/inout_capture_diagnostics.swift b/test/SILOptimizer/inout_capture_diagnostics.swift
deleted file mode 100644
index 1d91dc0..0000000
--- a/test/SILOptimizer/inout_capture_diagnostics.swift
+++ /dev/null
@@ -1,28 +0,0 @@
-// RUN: %target-swift-frontend -enforce-exclusivity=checked -Onone -emit-sil -swift-version 4 -verify -parse-as-library %s
-//
-// This is an adjunct to access_enforcement_noescape.swift to cover early static diagnostics.
-
-// Helper
-func doOneInout(_: ()->(), _: inout Int) {}
-
-// Error: Cannot capture nonescaping closure.
-// expected-note@+1{{parameter 'fn' is implicitly non-escaping}}
-func reentrantCapturedNoescape(fn: (() -> ()) -> ()) {
- // expected-error@+1{{closure use of non-escaping parameter 'fn' may allow it to escape}}
- let c = { fn {} }
- fn(c)
-}
-
-// Error: inout cannot be captured.
-func inoutReadBoxWriteInout(x: inout Int) {
- // expected-error@+1{{escaping closures can only capture inout parameters explicitly by value}}
- let c = { _ = x }
- doOneInout(c, &x)
-}
-
-// Error: Cannot capture inout
-func inoutWriteBoxWriteInout(x: inout Int) {
- // expected-error@+1{{escaping closures can only capture inout parameters explicitly by value}}
- let c = { x = 42 }
- doOneInout(c, &x)
-}
diff --git a/test/SILOptimizer/invalid_escaping_captures.swift b/test/SILOptimizer/invalid_escaping_captures.swift
new file mode 100644
index 0000000..e11e8f9
--- /dev/null
+++ b/test/SILOptimizer/invalid_escaping_captures.swift
@@ -0,0 +1,178 @@
+// RUN: %target-swift-frontend -emit-sil %s -verify
+
+func takesEscaping(_: @escaping () -> ()) {}
+
+func takesNonEscaping(_ fn: () -> ()) { fn() }
+
+func badClosureCaptureInOut1(x: inout Int) { // expected-note {{parameter 'x' is declared 'inout'}}
+ takesEscaping { // expected-error {{escaping closure captures 'inout' parameter 'x'}}
+ x += 1 // expected-note {{captured here}}
+ }
+}
+
+func badClosureCaptureInOut2(x: inout Int, b: Bool) { // expected-note 2{{parameter 'x' is declared 'inout'}}
+ takesEscaping(b ? { // expected-error {{escaping closure captures 'inout' parameter 'x'}}
+ x += 1 // expected-note {{captured here}}
+ } : { // expected-error {{escaping closure captures 'inout' parameter 'x'}}
+ x -= 1 // expected-note {{captured here}}
+ })
+}
+
+func badClosureCaptureNoEscape1(y: () -> ()) { // expected-note {{parameter 'y' is implicitly non-escaping}}
+ takesEscaping { // expected-error {{escaping closure captures non-escaping parameter 'y'}}
+ y() // expected-note {{captured here}}
+ }
+}
+
+func badClosureCaptureNoEscape2(y: () -> (), b: Bool) { // expected-note 2{{parameter 'y' is implicitly non-escaping}}
+ takesEscaping(b ? { // expected-error {{escaping closure captures non-escaping parameter 'y'}}
+ y() // expected-note {{captured here}}
+ } : { // expected-error {{escaping closure captures non-escaping parameter 'y'}}
+ y() // expected-note {{captured here}}
+ })
+}
+
+func badClosureCaptureNoEscape3(y: () -> ()) {
+ let yy = (y, y)
+
+ takesEscaping { // expected-error {{escaping closure captures non-escaping value}}
+ yy.0() // expected-note {{captured here}}
+ }
+}
+
+func badClosureCaptureNoEscape4(y: () -> (), z: () -> (), b: Bool) {
+ let x = b ? y : z
+
+ takesEscaping { // expected-error {{escaping closure captures non-escaping value}}
+ x() // expected-note {{captured here}}
+ }
+}
+
+func badLocalFunctionCaptureInOut1(x: inout Int) { // expected-note {{parameter 'x' is declared 'inout'}}
+ func local() {
+ x += 1 // expected-note {{captured here}}
+ }
+
+ takesEscaping(local) // expected-error {{escaping closure captures 'inout' parameter 'x'}}
+}
+
+func badLocalFunctionCaptureInOut2(x: inout Int) { // expected-note {{parameter 'x' is declared 'inout'}}
+ func local() {
+ x += 1 // expected-note {{captured here}}
+ }
+
+ takesEscaping { // expected-error {{escaping closure captures 'inout' parameter 'x'}}
+ local() // expected-note {{captured indirectly by this call}}
+ }
+}
+
+func badLocalFunctionCaptureInOut3(x: inout Int) { // expected-note {{parameter 'x' is declared 'inout'}}
+ func local1() {
+ x += 1 // expected-note {{captured here}}
+ }
+
+ func local2() {
+ local1() // expected-note {{captured indirectly by this call}}
+ }
+
+ takesEscaping(local2) // expected-error {{escaping closure captures 'inout' parameter 'x'}}
+}
+
+func badLocalFunctionCaptureNoEscape1(y: () -> ()) { // expected-note {{parameter 'y' is implicitly non-escaping}}
+ func local() {
+ y() // expected-note {{captured here}}
+ }
+
+ takesEscaping(local) // expected-error {{escaping closure captures non-escaping parameter 'y'}}
+}
+
+func badLocalFunctionCaptureNoEscape2(y: () -> ()) { // expected-note {{parameter 'y' is implicitly non-escaping}}
+ func local() {
+ y() // expected-note {{captured here}}
+ }
+
+ takesEscaping { // expected-error {{escaping closure captures non-escaping parameter 'y'}}
+ local() // expected-note {{captured indirectly by this call}}
+ }
+}
+
+func badLocalFunctionCaptureNoEscape3(y: () -> ()) { // expected-note {{parameter 'y' is implicitly non-escaping}}
+ func local1() {
+ y() // expected-note {{captured here}}
+ }
+
+ func local2() {
+ local1() // expected-note {{captured indirectly by this call}}
+ }
+
+ takesEscaping(local2) // expected-error {{escaping closure captures non-escaping parameter 'y'}}
+}
+
+func badLocalFunctionCaptureNoEscape4(y: () -> ()) { // expected-note {{parameter 'y' is implicitly non-escaping}}
+ func local1() {
+ takesNonEscaping(y) // expected-note {{captured here}}
+ }
+
+ func local2() {
+ local1() // expected-note {{captured indirectly by this call}}
+ }
+
+ takesEscaping(local2) // expected-error {{escaping closure captures non-escaping parameter 'y'}}
+}
+
+// Capturing 'self' produces a different diagnostic.
+struct SelfCapture {
+ var a: Int
+ mutating func badLocalFunctionCaptureInOut() {
+ // FIXME: The 'captured here' location chosen here is not ideal, because
+ // the original closure is formed in a closure that is nested inside the
+ // local function. That's a funny edge case that trips up the heuristics.
+ func _foo() {
+ a += 1
+ takesEscaping { // expected-error {{escaping closure captures mutating 'self' parameter}}
+ _foo() // expected-note {{captured here}}
+ }
+ }
+ }
+}
+
+// Make sure reabstraction thunks don't cause problems.
+func takesEscapingGeneric<T>(_: @escaping () -> T) {}
+
+func testGenericClosureReabstraction(x: inout Int) { // expected-note {{parameter 'x' is declared 'inout'}}
+ takesEscapingGeneric { () -> Int in // expected-error {{escaping closure captures 'inout' parameter 'x'}}
+ x += 1 // expected-note {{captured here}}
+ return 0
+ }
+}
+
+func testGenericLocalFunctionReabstraction(x: inout Int) { // expected-note {{parameter 'x' is declared 'inout'}}
+ func local() -> Int {
+ x += 1 // expected-note {{captured here}}
+ return 0
+ }
+ takesEscapingGeneric(local) // expected-error {{escaping closure captures 'inout' parameter 'x'}}
+}
+
+// Make sure that withoutActuallyEscaping counts as a safe use.
+func goodUseOfNoEscapeClosure(fn: () -> (), fn2: () -> ()) {
+ withoutActuallyEscaping(fn) { _fn in
+ takesEscaping(_fn)
+ }
+}
+
+// Some random regression tests
+infix operator ~>
+protocol Target {}
+
+func ~> <Target, Arg0, Result>(x: inout Target, f: @escaping (_: inout Target, _: Arg0) -> Result) -> (Arg0) -> Result {
+ // expected-note@-1 {{parameter 'x' is declared 'inout'}}
+ return { f(&x, $0) } // expected-note {{captured here}}
+ // expected-error@-1 {{escaping closure captures 'inout' parameter 'x'}}
+}
+
+func ~> (x: inout Int, f: @escaping (_: inout Int, _: Target) -> Target) -> (Target) -> Target {
+ // expected-note@-1 {{parameter 'x' is declared 'inout'}}
+ return { f(&x, $0) } // expected-note {{captured here}}
+ // expected-error@-1 {{escaping closure captures 'inout' parameter 'x'}}
+}
\ No newline at end of file
diff --git a/test/SILOptimizer/noescape_param_exclusivity.swift b/test/SILOptimizer/noescape_param_exclusivity.swift
new file mode 100644
index 0000000..5d4c74a
--- /dev/null
+++ b/test/SILOptimizer/noescape_param_exclusivity.swift
@@ -0,0 +1,48 @@
+// RUN: %target-swift-frontend -emit-sil %s -verify
+
+func test0(a: (() -> ()) -> (), b: () -> ()) {
+ a(b) // expected-error {{passing a non-escaping function parameter 'b' to a call to a non-escaping function parameter can allow re-entrant modification of a variable}}
+}
+
+func test0(fn: (() -> ()) -> ()) {
+ fn { fn {} } // expected-error {{passing a closure which captures a non-escaping function parameter 'fn' to a call to a non-escaping function parameter can allow re-entrant modification of a variable}}
+}
+
+func test1(fn: (() -> ()) -> ()) {
+ func foo() {
+ fn { fn {} } // expected-error {{passing a closure which captures a non-escaping function parameter 'fn' to a call to a non-escaping function parameter can allow re-entrant modification of a variable}}
+ }
+}
+
+func test2(x: inout Int, fn: (() -> ()) -> ()) {
+ func foo(myfn: () -> ()) {
+ x += 1
+ myfn()
+ }
+
+ // Make sure we only complain about calls to noescape parameters.
+ foo { fn {} }
+}
+
+func test3(fn: (() -> ()) -> ()) {
+ { myfn in myfn { fn {} } }(fn) // expected-error {{passing a closure which captures a non-escaping function parameter 'fn' to a call to a non-escaping function parameter can allow re-entrant modification of a variable}}
+}
+
+func test4(fn: (() -> ()) -> ()) {
+ func foo() {
+ fn {}
+ }
+
+ fn(foo) // expected-error {{passing a closure which captures a non-escaping function parameter 'fn' to a call to a non-escaping function parameter can allow re-entrant modification of a variable}}
+}
+
+// rdar://problem/34496304
+func test5(outer: (() throws -> Int) throws -> Int) throws -> Int {
+ func descend(_ inner: (() throws -> Int) throws -> Int) throws -> Int {
+ return try inner { // expected-error {{passing a closure which captures a non-escaping function parameter 'inner' to a call to a non-escaping function parameter can allow re-entrant modification of a variable}}
+ try descend(inner)
+ }
+ }
+
+ return try descend(outer)
+}
\ No newline at end of file
diff --git a/test/SILOptimizer/verify_noescape_closure.sil b/test/SILOptimizer/verify_noescape_closure.sil
deleted file mode 100644
index 872b86f..0000000
--- a/test/SILOptimizer/verify_noescape_closure.sil
+++ /dev/null
@@ -1,37 +0,0 @@
-// RUN: %empty-directory(%t)
-// RUN: not --crash %target-sil-opt -enable-sil-verify-all -enforce-exclusivity=unchecked -diagnose-static-exclusivity %s 2> %t/err.txt
-// RUN: %FileCheck %s < %t/err.txt
-
-// REQUIRES: asserts
-
-// The test in this file is meant to fail during verification which currently
-// only runs in the diagnose-static-exclusivity pass, but will eventually run in
-// SIL verification.
-
-import Builtin
-import Swift
-
-// CHECK: Applied argument must be @noescape function type: %{{.*}} = partial_apply
-// CHECK: A partial_apply with @inout_aliasable may only be used as a @noescape function type argument.
-
-sil @takesEscapingClosure : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
-
-sil hidden [ossa] @closureWithArgument : $@convention(thin) (@inout_aliasable Int) -> () {
-bb0(%1 : $*Int):
- %3 = tuple ()
- return %3 : $()
-}
-
-sil [ossa] @missingNoescape : $@convention(thin) (Int) ->() {
-bb0(%0 : $Int):
- %2 = alloc_box ${ var Int }
- %3 = project_box %2 : ${ var Int }, 0
- store %0 to [trivial] %3 : $*Int
- %4 = function_ref @takesEscapingClosure : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
- %5 = function_ref @closureWithArgument : $@convention(thin) (@inout_aliasable Int) -> ()
- %6 = partial_apply %5(%3) : $@convention(thin) (@inout_aliasable Int) -> ()
- %8 = apply %4(%6) : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
- destroy_value %2 : ${ var Int }
- %9 = tuple ()
- return %9 : $()
-}
diff --git a/test/Sema/diag_invalid_inout_captures.swift b/test/Sema/diag_invalid_inout_captures.swift
deleted file mode 100644
index 354dfb8..0000000
--- a/test/Sema/diag_invalid_inout_captures.swift
+++ /dev/null
@@ -1,63 +0,0 @@
-// RUN: %target-typecheck-verify-swift
-
-func no_escape(_ you_say_price_of_my_love_is: () -> ()) {}
-func do_escape(_ not_a_price_you_are_willing_to_pay: @escaping () -> ()) {}
-
-struct you_cry_in_your_tea {
- mutating func which_you_hurl_in_the_sea_when_you_see_me_go_by() {
- no_escape { _ = self } // OK
- do_escape { _ = self } // expected-error {{escaping closure cannot capture a mutating self parameter}}
- // expected-note@-1 {{create a mutating copy of self, or explicitly capture self for immutability}}
- do_escape {
- [self] in
- _ = self // OK
- self.other_mutator() // expected-error {{cannot use mutating member on immutable value: 'self' is an immutable capture}}
- }
- }
-
- mutating func other_mutator() {}
-}
-
-func why_so_sad(line: inout String) {
- no_escape { line = "Remember we made an arrangement when you went away" } // OK
- do_escape { line = "now you're making me mad" } // expected-error {{escaping closures can only capture inout parameters explicitly by value}}
- do_escape { [line] in _ = line } // OK
-}
-
-func remember(line: inout String) -> () -> Void {
- func despite_our_estrangement() {
- line = "I'm your man"
- }
- no_escape(despite_our_estrangement)
- do_escape(despite_our_estrangement) // expected-error {{nested function with an implicitly captured inout parameter can only be used as a non-escaping argument}}
-
- return despite_our_estrangement // expected-error {{nested function cannot capture inout parameter and escape}}
-}
-
-// This arrangement should be legal, but the type checker does not currently allow it.
-//
-// TODO: If the type checker is ever fixed, we should enable the corresponding test in
-// SILOptimizer/exclusivity_static_diagnostics.swift.
-func its_complicated(condition: inout Int) {
- no_escape(condition == 0 ? { condition = 1 } : { condition = 2}) // expected-error 2 {{escaping closures can only capture inout parameters explicitly by value}}
-}
-
-// rdar://problem/46322943 - Improve error message about mutating self capture in escaping closures
-func rdar46322943() {
- struct S {
- var bar = 1
-
- func foo(_ fn: () -> Void) {
- fn()
- }
-
- mutating func main() {
- let fn = {
- self.bar += 1
- // expected-error@-1 {{escaping closure cannot capture a mutating self parameter}}
- // expected-note@-2 {{create a mutating copy of self, or explicitly capture self for immutability}}
- }
- self.foo(fn)
- }
- }
-}
diff --git a/test/api-digester/Inputs/stdlib-stable-abi.json b/test/api-digester/Inputs/stdlib-stable-abi.json
index b8a3605..c45369c 100644
--- a/test/api-digester/Inputs/stdlib-stable-abi.json
+++ b/test/api-digester/Inputs/stdlib-stable-abi.json
@@ -223181,81 +223181,6 @@
]
}
]
- },
- {
- "kind": "Conformance",
- "name": "RandomAccessCollection",
- "printedName": "RandomAccessCollection",
- "children": [
- {
- "kind": "TypeWitness",
- "name": "Element",
- "printedName": "Element",
- "children": [
- {
- "kind": "TypeNominal",
- "name": "UInt",
- "printedName": "UInt",
- "usr": "s:Su"
- }
- ]
- },
- {
- "kind": "TypeWitness",
- "name": "Index",
- "printedName": "Index",
- "children": [
- {
- "kind": "TypeNominal",
- "name": "Int",
- "printedName": "Int",
- "usr": "s:Si"
- }
- ]
- },
- {
- "kind": "TypeWitness",
- "name": "SubSequence",
- "printedName": "SubSequence",
- "children": [
- {
- "kind": "TypeNominal",
- "name": "Slice",
- "printedName": "Slice<UInt.Words>",
- "children": [
- {
- "kind": "TypeNominal",
- "name": "Words",
- "printedName": "UInt.Words",
- "usr": "s:Su5WordsV"
- }
- ],
- "usr": "s:s5SliceV"
- }
- ]
- },
- {
- "kind": "TypeWitness",
- "name": "Indices",
- "printedName": "Indices",
- "children": [
- {
- "kind": "TypeNominal",
- "name": "Range",
- "printedName": "Range<Int>",
- "children": [
- {
- "kind": "TypeNominal",
- "name": "Int",
- "printedName": "Int",
- "usr": "s:Si"
- }
- ],
- "usr": "s:Sn"
- }
- ]
- }
- ]
}
]
},
@@ -227320,81 +227245,6 @@
]
}
]
- },
- {
- "kind": "Conformance",
- "name": "RandomAccessCollection",
- "printedName": "RandomAccessCollection",
- "children": [
- {
- "kind": "TypeWitness",
- "name": "Element",
- "printedName": "Element",
- "children": [
- {
- "kind": "TypeNominal",
- "name": "UInt",
- "printedName": "UInt",
- "usr": "s:Su"
- }
- ]
- },
- {
- "kind": "TypeWitness",
- "name": "Index",
- "printedName": "Index",
- "children": [
- {
- "kind": "TypeNominal",
- "name": "Int",
- "printedName": "Int",
- "usr": "s:Si"
- }
- ]
- },
- {
- "kind": "TypeWitness",
- "name": "SubSequence",
- "printedName": "SubSequence",
- "children": [
- {
- "kind": "TypeNominal",
- "name": "Slice",
- "printedName": "Slice<Int.Words>",
- "children": [
- {
- "kind": "TypeNominal",
- "name": "Words",
- "printedName": "Int.Words",
- "usr": "s:Si5WordsV"
- }
- ],
- "usr": "s:s5SliceV"
- }
- ]
- },
- {
- "kind": "TypeWitness",
- "name": "Indices",
- "printedName": "Indices",
- "children": [
- {
- "kind": "TypeNominal",
- "name": "Range",
- "printedName": "Range<Int>",
- "children": [
- {
- "kind": "TypeNominal",
- "name": "Int",
- "printedName": "Int",
- "usr": "s:Si"
- }
- ],
- "usr": "s:Sn"
- }
- ]
- }
- ]
}
]
},
diff --git a/test/api-digester/Inputs/stdlib-stable.json b/test/api-digester/Inputs/stdlib-stable.json
index 532686c..5cbab5c 100644
--- a/test/api-digester/Inputs/stdlib-stable.json
+++ b/test/api-digester/Inputs/stdlib-stable.json
@@ -156358,109 +156358,6 @@
]
}
]
- },
- {
- "kind": "Conformance",
- "name": "RandomAccessCollection",
- "printedName": "RandomAccessCollection",
- "children": [
- {
- "kind": "TypeWitness",
- "name": "Element",
- "printedName": "Element",
- "children": [
- {
- "kind": "TypeNameAlias",
- "name": "Element",
- "printedName": "UInt.Words.Element",
- "children": [
- {
- "kind": "TypeNominal",
- "name": "UInt",
- "printedName": "UInt",
- "usr": "s:Su"
- }
- ]
- }
- ]
- },
- {
- "kind": "TypeWitness",
- "name": "Index",
- "printedName": "Index",
- "children": [
- {
- "kind": "TypeNameAlias",
- "name": "Index",
- "printedName": "UInt.Words.Index",
- "children": [
- {
- "kind": "TypeNominal",
- "name": "Int",
- "printedName": "Int",
- "usr": "s:Si"
- }
- ]
- }
- ]
- },
- {
- "kind": "TypeWitness",
- "name": "SubSequence",
- "printedName": "SubSequence",
- "children": [
- {
- "kind": "TypeNameAlias",
- "name": "SubSequence",
- "printedName": "UInt.Words.SubSequence",
- "children": [
- {
- "kind": "TypeNominal",
- "name": "Slice",
- "printedName": "Slice<UInt.Words>",
- "children": [
- {
- "kind": "TypeNominal",
- "name": "Words",
- "printedName": "UInt.Words",
- "usr": "s:Su5WordsV"
- }
- ],
- "usr": "s:s5SliceV"
- }
- ]
- }
- ]
- },
- {
- "kind": "TypeWitness",
- "name": "Indices",
- "printedName": "Indices",
- "children": [
- {
- "kind": "TypeNameAlias",
- "name": "Indices",
- "printedName": "UInt.Words.Indices",
- "children": [
- {
- "kind": "TypeNominal",
- "name": "Range",
- "printedName": "Range<Int>",
- "children": [
- {
- "kind": "TypeNominal",
- "name": "Int",
- "printedName": "Int",
- "usr": "s:Si"
- }
- ],
- "usr": "s:Sn"
- }
- ]
- }
- ]
- }
- ]
}
]
},
@@ -160153,109 +160050,6 @@
]
}
]
- },
- {
- "kind": "Conformance",
- "name": "RandomAccessCollection",
- "printedName": "RandomAccessCollection",
- "children": [
- {
- "kind": "TypeWitness",
- "name": "Element",
- "printedName": "Element",
- "children": [
- {
- "kind": "TypeNameAlias",
- "name": "Element",
- "printedName": "Int.Words.Element",
- "children": [
- {
- "kind": "TypeNominal",
- "name": "UInt",
- "printedName": "UInt",
- "usr": "s:Su"
- }
- ]
- }
- ]
- },
- {
- "kind": "TypeWitness",
- "name": "Index",
- "printedName": "Index",
- "children": [
- {
- "kind": "TypeNameAlias",
- "name": "Index",
- "printedName": "Int.Words.Index",
- "children": [
- {
- "kind": "TypeNominal",
- "name": "Int",
- "printedName": "Int",
- "usr": "s:Si"
- }
- ]
- }
- ]
- },
- {
- "kind": "TypeWitness",
- "name": "SubSequence",
- "printedName": "SubSequence",
- "children": [
- {
- "kind": "TypeNameAlias",
- "name": "SubSequence",
- "printedName": "Int.Words.SubSequence",
- "children": [
- {
- "kind": "TypeNominal",
- "name": "Slice",
- "printedName": "Slice<Int.Words>",
- "children": [
- {
- "kind": "TypeNominal",
- "name": "Words",
- "printedName": "Int.Words",
- "usr": "s:Si5WordsV"
- }
- ],
- "usr": "s:s5SliceV"
- }
- ]
- }
- ]
- },
- {
- "kind": "TypeWitness",
- "name": "Indices",
- "printedName": "Indices",
- "children": [
- {
- "kind": "TypeNameAlias",
- "name": "Indices",
- "printedName": "Int.Words.Indices",
- "children": [
- {
- "kind": "TypeNominal",
- "name": "Range",
- "printedName": "Range<Int>",
- "children": [
- {
- "kind": "TypeNominal",
- "name": "Int",
- "printedName": "Int",
- "usr": "s:Si"
- }
- ],
- "usr": "s:Sn"
- }
- ]
- }
- ]
- }
- ]
}
]
},
diff --git a/test/attr/attr_autoclosure.swift b/test/attr/attr_autoclosure.swift
index 14ded18..67aa6d7 100644
--- a/test/attr/attr_autoclosure.swift
+++ b/test/attr/attr_autoclosure.swift
@@ -68,40 +68,22 @@
@autoclosure let delayed: () -> Int // expected-error {{attribute can only be applied to types, not declarations}}
}
-// @autoclosure(escaping)
+// @autoclosure(escaping) is no longer a thing; just make sure we don't crash
// expected-error @+1 {{attribute can only be applied to types, not declarations}}
func func10(@autoclosure(escaping _: () -> ()) { } // expected-error{{expected parameter name followed by ':'}}
-func func11(_: @autoclosure(escaping) @noescape () -> ()) { } // expected-error{{@escaping conflicts with @noescape}}
- // expected-error@-1{{@autoclosure(escaping) has been removed; use @autoclosure @escaping instead}} {{28-38= @escaping}}
-
-class Super {
- func f1(_ x: @autoclosure(escaping) () -> ()) { }
- // expected-error@-1{{@autoclosure(escaping) has been removed; use @autoclosure @escaping instead}} {{28-38= @escaping}}
- func f2(_ x: @autoclosure(escaping) () -> ()) { } // expected-note {{potential overridden instance method 'f2' here}}
- // expected-error@-1{{@autoclosure(escaping) has been removed; use @autoclosure @escaping instead}} {{28-38= @escaping}}
- func f3(x: @autoclosure () -> ()) { }
-}
-
-class Sub : Super {
- override func f1(_ x: @autoclosure(escaping)() -> ()) { }
- // expected-error@-1{{@autoclosure(escaping) has been removed; use @autoclosure @escaping instead}} {{37-47= @escaping }}
- override func f2(_ x: @autoclosure () -> ()) { } // expected-error{{does not override any method}} // expected-note{{type does not match superclass instance method with type '(@autoclosure @escaping () -> ()) -> ()'}}
- override func f3(_ x: @autoclosure(escaping) () -> ()) { } // expected-error{{does not override any method}}
- // expected-error@-1{{@autoclosure(escaping) has been removed; use @autoclosure @escaping instead}} {{37-47= @escaping}}
-}
+func func11(_: @autoclosure(escaping) @noescape () -> ()) { } // expected-error{{use of undeclared type 'escaping'}}
+// expected-error @-1 {{attribute can only be applied to types, not declarations}}
+// expected-error @-2 {{expected ',' separator}}
+// expected-error @-3 {{expected parameter name followed by ':'}}
func func12_sink(_ x: @escaping () -> Int) { }
func func12a(_ x: @autoclosure () -> Int) {
- // expected-note@-1{{parameter 'x' is implicitly non-escaping}}
+ // expected-note@-1{{parameter 'x' is implicitly non-escaping}}
func12_sink(x) // expected-error {{passing non-escaping parameter 'x' to function expecting an @escaping closure}}
}
-func func12b(_ x: @autoclosure(escaping) () -> Int) {
- // expected-error@-1{{@autoclosure(escaping) has been removed; use @autoclosure @escaping instead}} {{31-41= @escaping}}
- func12_sink(x) // ok
-}
func func12c(_ x: @autoclosure @escaping () -> Int) {
func12_sink(x) // ok
}
@@ -116,7 +98,7 @@
func test() {
func12a(x + foo()) // okay
- func12b(x + foo())
+ func12c(x + foo())
// expected-error@-1{{reference to property 'x' in closure requires explicit 'self.' to make capture semantics explicit}} {{13-13=self.}}
// expected-error@-2{{call to method 'foo' in closure requires explicit 'self.' to make capture semantics explicit}} {{17-17=self.}}
}
@@ -131,8 +113,6 @@
let _ : AutoclosureFailableOf<Int> = .Success(42)
let _ : (@autoclosure () -> ()) -> ()
-let _ : (@autoclosure(escaping) () -> ()) -> ()
- // expected-error@-1{{@autoclosure(escaping) has been removed; use @autoclosure @escaping instead}} {{22-32= @escaping}}
// escaping is the name of param type
let _ : (@autoclosure(escaping) -> ()) -> () // expected-error {{use of undeclared type 'escaping'}}
@@ -210,10 +190,9 @@
func same<T>(_: T, _: T) {}
func takesAnAutoclosure(_ fn: @autoclosure () -> Int, _ efn: @escaping @autoclosure () -> Int) {
- // expected-note@-1 2{{parameter 'fn' is implicitly non-escaping}}
-
- var _ = fn // expected-error {{non-escaping parameter 'fn' may only be called}}
- let _ = fn // expected-error {{non-escaping parameter 'fn' may only be called}}
+ // These are OK -- they count as non-escaping uses
+ var _ = fn
+ let _ = fn
var _ = efn
let _ = efn
diff --git a/test/attr/attr_escaping.swift b/test/attr/attr_escaping.swift
index 9c62c45..b51a230 100644
--- a/test/attr/attr_escaping.swift
+++ b/test/attr/attr_escaping.swift
@@ -5,17 +5,17 @@
func wrongParamType(a: @escaping Int) {} // expected-error {{@escaping attribute only applies to function types}}
-func conflictingAttrs(_ fn: @noescape @escaping () -> Int) {} // expected-error {{@escaping conflicts with @noescape}}
- // expected-error@-1{{@noescape is the default and has been removed}} {{29-39=}}
+func conflictingAttrs(_ fn: @noescape @escaping () -> Int) {} // expected-error {{unknown attribute 'noescape'}}
func takesEscaping(_ fn: @escaping () -> Int) {} // ok
func callEscapingWithNoEscape(_ fn: () -> Int) {
// expected-note@-1{{parameter 'fn' is implicitly non-escaping}} {{37-37=@escaping }}
- // expected-note@-2{{parameter 'fn' is implicitly non-escaping}} {{37-37=@escaping }}
takesEscaping(fn) // expected-error{{passing non-escaping parameter 'fn' to function expecting an @escaping closure}}
- let _ = fn // expected-error{{non-escaping parameter 'fn' may only be called}}
+
+ // This is a non-escaping use:
+ let _ = fn
}
typealias IntSugar = Int
@@ -60,16 +60,6 @@
func callEscapingAutoclosureWithNoEscape(_ fn: () -> Int) {
takesEscapingAutoclosure(1+1)
}
-func callEscapingAutoclosureWithNoEscape_2(_ fn: () -> Int) {
- // expected-note@-1{{parameter 'fn' is implicitly non-escaping}}
-
- takesEscapingAutoclosure(fn()) // expected-error{{closure use of non-escaping parameter 'fn' may allow it to escape}}
-}
-func callEscapingAutoclosureWithNoEscape_3(_ fn: @autoclosure () -> Int) {
- // expected-note@-1{{parameter 'fn' is implicitly non-escaping}}
-
- takesEscapingAutoclosure(fn()) // expected-error{{closure use of non-escaping parameter 'fn' may allow it to escape}}
-}
let foo: @escaping (Int) -> Int // expected-error{{@escaping attribute may only be used in function parameter position}} {{10-20=}}
diff --git a/test/attr/attr_inlinable_typealias.swift b/test/attr/attr_inlinable_typealias.swift
index 850ad8b..2c2488c 100644
--- a/test/attr/attr_inlinable_typealias.swift
+++ b/test/attr/attr_inlinable_typealias.swift
@@ -5,6 +5,7 @@
internal typealias InternalAlias = Int
// expected-note@-1 {{type alias 'InternalAlias' is not '@usableFromInline' or public}}
+// expected-note@-2 * {{type alias 'InternalAlias' is not '@usableFromInline' or public}}
@usableFromInline typealias UsableFromInlineAlias = Int
@@ -21,3 +22,8 @@
_ = PublicAlias.self
}
+
+@inlinable public func localTypealiases() {
+ typealias LocalAlias = InternalAlias // expected-warning {{type alias 'InternalAlias' is internal and should not be referenced from an '@inlinable' function}}
+ typealias GenericAlias<T> = (T, InternalAlias) // expected-warning {{type alias 'InternalAlias' is internal and should not be referenced from an '@inlinable' function}}
+}
diff --git a/test/attr/attr_noescape.swift b/test/attr/attr_noescape.swift
index 737a5cb..dad2f0d 100644
--- a/test/attr/attr_noescape.swift
+++ b/test/attr/attr_noescape.swift
@@ -2,12 +2,11 @@
@noescape var fn : () -> Int = { 4 } // expected-error {{attribute can only be applied to types, not declarations}}
-func conflictingAttrs(_ fn: @noescape @escaping () -> Int) {} // expected-error {{@escaping conflicts with @noescape}}
-// expected-error@-1{{@noescape is the default and has been removed}} {{29-39=}}
+func conflictingAttrs(_ fn: @noescape @escaping () -> Int) {} // expected-error {{unknown attribute 'noescape'}}
func doesEscape(_ fn : @escaping () -> Int) {}
-func takesGenericClosure<T>(_ a : Int, _ fn : @noescape () -> T) {} // expected-error{{@noescape is the default and has been removed}} {{47-57=}}
+func takesGenericClosure<T>(_ a : Int, _ fn : @noescape () -> T) {} // expected-error 2{{unknown attribute 'noescape'}}
var globalAny: Any = 0
@@ -25,33 +24,14 @@
}
func takesNoEscapeClosure(_ fn : () -> Int) {
- // expected-note@-1{{parameter 'fn' is implicitly non-escaping}} {{34-34=@escaping }}
- // expected-note@-2{{parameter 'fn' is implicitly non-escaping}} {{34-34=@escaping }}
- // expected-note@-3{{parameter 'fn' is implicitly non-escaping}} {{34-34=@escaping }}
- // expected-note@-4{{parameter 'fn' is implicitly non-escaping}} {{34-34=@escaping }}
- // expected-note@-5{{parameter 'fn' is implicitly non-escaping}} {{34-34=@escaping }}
- // expected-note@-6{{parameter 'fn' is implicitly non-escaping}} {{34-34=@escaping }}
- // expected-note@-7{{parameter 'fn' is implicitly non-escaping}} {{34-34=@escaping }}
- // expected-note@-8{{parameter 'fn' is implicitly non-escaping}} {{34-34=@escaping }}
+ // expected-note@-1 5{{parameter 'fn' is implicitly non-escaping}} {{34-34=@escaping }}
takesNoEscapeClosure { 4 } // ok
_ = fn() // ok
- var x = fn // expected-error {{non-escaping parameter 'fn' may only be called}}
-
// This is ok, because the closure itself is noescape.
takesNoEscapeClosure { fn() }
- // This is not ok, because it escapes the 'fn' closure.
- doesEscape { fn() } // expected-error {{closure use of non-escaping parameter 'fn' may allow it to escape}}
-
- // This is not ok, because it escapes the 'fn' closure.
- func nested_function() {
- _ = fn() // expected-error {{declaration closing over non-escaping parameter 'fn' may allow it to escape}}
- }
-
- takesNoEscapeClosure(fn) // ok
-
doesEscape(fn) // expected-error {{passing non-escaping parameter 'fn' to function expecting an @escaping closure}}
takesGenericClosure(4, fn) // ok
takesGenericClosure(4) { fn() } // ok.
@@ -64,6 +44,7 @@
_ = "\(takesArray([fn]))" // expected-error {{using non-escaping parameter 'fn' in a context expecting an @escaping closure}}
assignToGlobal(fn) // expected-error {{converting non-escaping value to 'T' may allow it to escape}}
+ assignToGlobal((fn, fn)) // expected-error {{converting non-escaping value to 'T' may allow it to escape}}
}
class SomeClass {
@@ -190,22 +171,21 @@
// Implicit conversions (in this case to @convention(block)) are ok.
@_silgen_name("whatever")
-func takeNoEscapeAsObjCBlock(_: @noescape @convention(block) () -> Void) // expected-error{{@noescape is the default and has been removed}} {{33-43=}}
-func takeNoEscapeTest2(_ fn : @noescape () -> ()) { // expected-error{{@noescape is the default and has been removed}} {{31-41=}}
+func takeNoEscapeAsObjCBlock(_: @noescape @convention(block) () -> Void) // expected-error{{unknown attribute 'noescape'}}
+func takeNoEscapeTest2(_ fn : @noescape () -> ()) { // expected-error{{unknown attribute 'noescape'}}
takeNoEscapeAsObjCBlock(fn)
}
-// Autoclosure implies noescape, but produce nice diagnostics so people know
-// why noescape problems happen.
+// Autoclosure implies noescape..
func testAutoclosure(_ a : @autoclosure () -> Int) { // expected-note{{parameter 'a' is implicitly non-escaping}}
- doesEscape { a() } // expected-error {{closure use of non-escaping parameter 'a' may allow it to escape}}
+ doesEscape(a) // expected-error {{passing non-escaping parameter 'a' to function expecting an @escaping closure}}
}
// <rdar://problem/19470858> QoI: @autoclosure implies @noescape, so you shouldn't be allowed to specify both
-func redundant(_ fn : @noescape // expected-error @+1 {{@noescape is implied by @autoclosure and should not be redundantly specified}}
+func redundant(_ fn : @noescape
@autoclosure () -> Int) {
- // expected-error@-2{{@noescape is the default and has been removed}} {{23-33=}}
+ // expected-error@-2{{unknown attribute 'noescape'}}
}
@@ -222,26 +202,26 @@
struct S : P2 {
typealias Element = Int
- func each(_ transform: @noescape (Int) -> ()) { // expected-error{{@noescape is the default and has been removed}} {{26-36=}}
- overloadedEach(self, // expected-error {{cannot invoke 'overloadedEach' with an argument list of type '(S, (Int) -> (), Int)'}}
+ func each(_ transform: @noescape (Int) -> ()) { // expected-error{{unknown attribute 'noescape'}}
+ overloadedEach(self, // expected-error {{cannot invoke 'overloadedEach' with an argument list of type '(S, (Int) -> (), Int)'}}
+ // expected-note @-1 {{overloads for 'overloadedEach' exist with these partially matching parameter lists: (O, @escaping (O.Element) -> (), T), (P, @escaping (P.Element) -> (), T)}}
transform, 1)
- // expected-note @-2 {{overloads for 'overloadedEach' exist with these partially matching parameter lists: (O, @escaping (O.Element) -> (), T), (P, @escaping (P.Element) -> (), T)}}
}
}
// rdar://19763676 - False positive in @noescape analysis triggered by parameter label
-func r19763676Callee(_ f: @noescape (_ param: Int) -> Int) {} // expected-error{{@noescape is the default and has been removed}} {{27-37=}}
+func r19763676Callee(_ f: @noescape (_ param: Int) -> Int) {} // expected-error{{unknown attribute 'noescape'}}
-func r19763676Caller(_ g: @noescape (Int) -> Int) { // expected-error{{@noescape is the default and has been removed}} {{27-37=}}
+func r19763676Caller(_ g: @noescape (Int) -> Int) { // expected-error{{unknown attribute 'noescape'}}
r19763676Callee({ _ in g(1) })
}
// <rdar://problem/19763732> False positive in @noescape analysis triggered by default arguments
-func calleeWithDefaultParameters(_ f: @noescape () -> (), x : Int = 1) {} // expected-error{{@noescape is the default and has been removed}} {{39-49=}}
-func callerOfDefaultParams(_ g: @noescape () -> ()) { // expected-error{{@noescape is the default and has been removed}} {{33-43=}}
+func calleeWithDefaultParameters(_ f: @noescape () -> (), x : Int = 1) {} // expected-error{{unknown attribute 'noescape'}}
+func callerOfDefaultParams(_ g: @noescape () -> ()) { // expected-error{{unknown attribute 'noescape'}}
calleeWithDefaultParameters(g)
}
@@ -269,22 +249,22 @@
/// SR-770 - Currying and `noescape`/`rethrows` don't work together anymore
-func curriedFlatMap<A, B>(_ x: [A]) -> (@noescape (A) -> [B]) -> [B] { // expected-error{{@noescape is the default and has been removed}} {{41-50=}}
+func curriedFlatMap<A, B>(_ x: [A]) -> (@noescape (A) -> [B]) -> [B] { // expected-error 2{{unknown attribute 'noescape'}}
return { f in
x.flatMap(f)
}
}
-func curriedFlatMap2<A, B>(_ x: [A]) -> (@noescape (A) -> [B]) -> [B] { // expected-error{{@noescape is the default and has been removed}} {{42-51=}}
- return { (f : @noescape (A) -> [B]) in // expected-error{{@noescape is the default and has been removed}} {{17-27=}}
+func curriedFlatMap2<A, B>(_ x: [A]) -> (@noescape (A) -> [B]) -> [B] { // expected-error 2{{unknown attribute 'noescape'}}
+ return { (f : @noescape (A) -> [B]) in // expected-error{{unknown attribute 'noescape'}}
x.flatMap(f)
}
}
func bad(_ a : @escaping (Int)-> Int) -> Int { return 42 }
-func escapeNoEscapeResult(_ x: [Int]) -> (@noescape (Int) -> Int) -> Int { // expected-error{{@noescape is the default and has been removed}} {{43-52=}}
- return { f in // expected-note{{parameter 'f' is implicitly non-escaping}}
- bad(f) // expected-error {{passing non-escaping parameter 'f' to function expecting an @escaping closure}}
+func escapeNoEscapeResult(_ x: [Int]) -> (@noescape (Int) -> Int) -> Int { // expected-error{{unknown attribute 'noescape'}}
+ return { f in // expected-note {{parameter 'f' is implicitly non-escaping}}
+ bad(f) // expected-error {{passing non-escaping parameter 'f' to function expecting an @escaping closure}}
}
}
@@ -293,7 +273,7 @@
//
// Old syntax -- @noescape is the default, and is redundant
-typealias CompletionHandlerNE = @noescape (_ success: Bool) -> () // expected-error{{@noescape is the default and has been removed}} {{33-43=}}
+typealias CompletionHandlerNE = @noescape (_ success: Bool) -> () // expected-error{{unknown attribute 'noescape'}}
// Explicit @escaping is not allowed here
typealias CompletionHandlerE = @escaping (_ success: Bool) -> () // expected-error{{@escaping attribute may only be used in function parameter position}} {{32-42=}}
@@ -304,19 +284,16 @@
var escape : CompletionHandlerNE
var escapeOther : CompletionHandler
func doThing1(_ completion: (_ success: Bool) -> ()) {
- // expected-note@-1{{parameter 'completion' is implicitly non-escaping}}
- // expected-error @+1 {{non-escaping parameter 'completion' may only be called}}
- escape = completion // expected-error {{declaration closing over non-escaping parameter 'escape' may allow it to escape}}
+ // expected-note@-1 {{parameter 'completion' is implicitly non-escaping}}
+ escape = completion // expected-error {{assigning non-escaping parameter 'completion' to an @escaping closure}}
}
func doThing2(_ completion: CompletionHandlerNE) {
- // expected-note@-1{{parameter 'completion' is implicitly non-escaping}}
- // expected-error @+1 {{non-escaping parameter 'completion' may only be called}}
- escape = completion // expected-error {{declaration closing over non-escaping parameter 'escape' may allow it to escape}}
+ // expected-note@-1 {{parameter 'completion' is implicitly non-escaping}}
+ escape = completion // expected-error {{assigning non-escaping parameter 'completion' to an @escaping closure}}
}
func doThing3(_ completion: CompletionHandler) {
- // expected-note@-1{{parameter 'completion' is implicitly non-escaping}}
- // expected-error @+1 {{non-escaping parameter 'completion' may only be called}}
- escape = completion // expected-error {{declaration closing over non-escaping parameter 'escape' may allow it to escape}}
+ // expected-note@-1 {{parameter 'completion' is implicitly non-escaping}}
+ escape = completion // expected-error {{assigning non-escaping parameter 'completion' to an @escaping closure}}
}
func doThing4(_ completion: @escaping CompletionHandler) {
escapeOther = completion
@@ -324,11 +301,8 @@
// <rdar://problem/19997680> @noescape doesn't work on parameters of function type
func apply<T, U>(_ f: @noescape (T) -> U, g: @noescape (@noescape (T) -> U) -> U) -> U {
- // expected-error@-1{{@noescape is the default and has been removed}} {{23-33=}}
- // expected-error@-2{{@noescape is the default and has been removed}} {{46-56=}}
- // expected-error@-3{{@noescape is the default and has been removed}} {{57-66=}}
+ // expected-error@-1 6{{unknown attribute 'noescape'}}
return g(f)
- // expected-error@-1{{passing a non-escaping function parameter 'f' to a call to a non-escaping function parameter}}
}
// <rdar://problem/19997577> @noescape cannot be applied to locals, leading to duplication of code
@@ -337,8 +311,8 @@
case Function(() -> r19997577Type, () -> r19997577Type)
case Sum(() -> r19997577Type, () -> r19997577Type)
- func reduce<Result>(_ initial: Result, _ combine: @noescape (Result, r19997577Type) -> Result) -> Result { // expected-error{{@noescape is the default and has been removed}} {{53-63=}}
- let binary: @noescape (r19997577Type, r19997577Type) -> Result = { combine(combine(combine(initial, self), $0), $1) } // expected-error{{@noescape is the default and has been removed}} {{17-27=}}
+ func reduce<Result>(_ initial: Result, _ combine: @noescape (Result, r19997577Type) -> Result) -> Result { // expected-error 2{{unknown attribute 'noescape'}}
+ let binary: @noescape (r19997577Type, r19997577Type) -> Result = { combine(combine(combine(initial, self), $0), $1) } // expected-error{{unknown attribute 'noescape'}}
switch self {
case .Unit:
return combine(initial, self)
@@ -352,7 +326,7 @@
// type attribute and decl attribute
func noescapeD(@noescape f: @escaping () -> Bool) {} // expected-error {{attribute can only be applied to types, not declarations}}
-func noescapeT(f: @noescape () -> Bool) {} // expected-error{{@noescape is the default and has been removed}} {{19-29=}}
+func noescapeT(f: @noescape () -> Bool) {} // expected-error{{unknown attribute 'noescape'}}
func noescapeG<T>(@noescape f: () -> T) {} // expected-error{{attribute can only be applied to types, not declarations}}
func autoclosureD(@autoclosure f: () -> Bool) {} // expected-error {{attribute can only be applied to types, not declarations}}
@@ -360,7 +334,7 @@
func autoclosureG<T>(@autoclosure f: () -> T) {} // expected-error{{attribute can only be applied to types, not declarations}}
func noescapeD_noescapeT(@noescape f: @noescape () -> Bool) {} // expected-error {{attribute can only be applied to types, not declarations}}
- // expected-error@-1{{@noescape is the default and has been removed}} {{39-49=}}
+ // expected-error@-1{{unknown attribute 'noescape'}}
func autoclosureD_noescapeT(@autoclosure f: @noescape () -> Bool) {} // expected-error {{attribute can only be applied to types, not declarations}}
- // expected-error@-1{{@noescape is the default and has been removed}} {{45-55=}}
+ // expected-error@-1{{unknown attribute 'noescape'}}
diff --git a/test/attr/attributes.swift b/test/attr/attributes.swift
index 5905819..2eb337e 100644
--- a/test/attr/attributes.swift
+++ b/test/attr/attributes.swift
@@ -210,8 +210,9 @@
func func_type_attribute_with_space(x: @convention (c) () -> Int) {} // OK. Known attributes can have space before its paren.
-// @thin is not supported except in SIL.
-var thinFunc : @thin () -> () // expected-error {{attribute is not supported}}
+// @thin and @pseudogeneric are not supported except in SIL.
+var thinFunc : @thin () -> () // expected-error {{unknown attribute 'thin'}}
+var pseudoGenericFunc : @pseudogeneric () -> () // expected-error {{unknown attribute 'pseudogeneric'}}
@inline(never) func nolineFunc() {}
@inline(never) var noinlineVar : Int { return 0 }
diff --git a/test/decl/protocol/conforms/circular_validation.swift b/test/decl/protocol/conforms/circular_validation.swift
index ecb234e..055f3ea 100644
--- a/test/decl/protocol/conforms/circular_validation.swift
+++ b/test/decl/protocol/conforms/circular_validation.swift
@@ -11,3 +11,8 @@
static var x = 0 // expected-note {{candidate operates on a type, not an instance as required}}
var x = S.x // expected-note {{candidate references itself}}
}
+
+// FIXME: Lousy diagnostics on this case.
+protocol SR9224_Foo: SR9224_Foobar {} // expected-error 2 {{protocol 'SR9224_Foo' refines itself}}
+protocol SR9224_Bar: SR9224_Foobar {} // expected-error {{protocol 'SR9224_Bar' refines itself}} expected-note {{protocol 'SR9224_Bar' declared here}}
+typealias SR9224_Foobar = SR9224_Foo & SR9224_Bar
\ No newline at end of file
diff --git a/test/decl/var/usage.swift b/test/decl/var/usage.swift
index 22121ce..c577041 100644
--- a/test/decl/var/usage.swift
+++ b/test/decl/var/usage.swift
@@ -96,8 +96,24 @@
struct TestStruct {
var property = 42
-}
+ var mutatingProperty: Int {
+ mutating get { return 0 }
+ mutating set {}
+ }
+ var nonmutatingProperty: Int {
+ nonmutating get { return 0 }
+ nonmutating set {}
+ }
+ subscript(mutating index: Int) -> Int {
+ mutating get { return 0 }
+ mutating set {}
+ }
+ subscript(nonmutating index: Int) -> Int {
+ nonmutating get { return 0 }
+ nonmutating set {}
+ }
+}
func testStructMember() -> TestStruct {
var x = TestStruct() // ok
@@ -105,6 +121,53 @@
return x
}
+func testMutatingProperty_get() -> TestStruct {
+ var x = TestStruct() // ok
+ _ = x.mutatingProperty
+ return x
+}
+
+func testMutatingProperty_set() -> TestStruct {
+ var x = TestStruct() // ok
+ x.mutatingProperty = 17
+ return x
+}
+
+func testNonmutatingProperty_get() -> TestStruct {
+ var x = TestStruct() // expected-warning {{variable 'x' was never mutated; consider changing to 'let' constant}}
+ _ = x.nonmutatingProperty
+ return x
+}
+
+func testNonmutatingProperty_set() -> TestStruct {
+ var x = TestStruct() // expected-warning {{variable 'x' was never mutated; consider changing to 'let' constant}}
+ x.nonmutatingProperty = 17
+ return x
+}
+
+func testMutatingSubscript_get() -> TestStruct {
+ var x = TestStruct() // ok
+ _ = x[mutating: 4]
+ return x
+}
+
+func testMutatingSubscript_set() -> TestStruct {
+ var x = TestStruct() // ok
+ x[mutating: 4] = 17
+ return x
+}
+
+func testNonmutatingSubscript_get() -> TestStruct {
+ var x = TestStruct() // expected-warning {{variable 'x' was never mutated; consider changing to 'let' constant}}
+ _ = x[nonmutating: 4]
+ return x
+}
+
+func testNonmutatingSubscript_set() -> TestStruct {
+ var x = TestStruct() // expected-warning {{variable 'x' was never mutated; consider changing to 'let' constant}}
+ x[nonmutating: 4] = 17
+ return x
+}
func testSubscript() -> [Int] {
var x = [1,2,3] // ok
@@ -112,6 +175,11 @@
return x
}
+func testSubscriptNeverMutated() -> [Int] {
+ var x = [1,2,3] // expected-warning {{variable 'x' was never mutated; consider changing to 'let' constant}}
+ _ = x[1]
+ return x
+}
func testTuple(_ x : Int) -> Int {
var x = x
@@ -178,7 +246,10 @@
protocol Fooable {
mutating func mutFoo()
func immutFoo()
+ var mutatingProperty: Int { mutating get mutating set }
+ var nonmutatingProperty: Int { nonmutating get nonmutating set }
}
+
func testOpenExistential(_ x: Fooable,
y: Fooable) {
var x = x
@@ -187,6 +258,25 @@
y.immutFoo()
}
+func testOpenExistential_mutatingProperty_get(p: Fooable) {
+ var x = p
+ _ = x.mutatingProperty
+}
+
+func testOpenExistential_mutatingProperty_set(p: Fooable) {
+ var x = p
+ x.mutatingProperty = 4
+}
+
+func testOpenExistential_nonmutatingProperty_get(p: Fooable) {
+ var x = p // expected-warning {{variable 'x' was never mutated; consider changing to 'let' constant}}
+ _ = x.nonmutatingProperty
+}
+
+func testOpenExistential_nonmutatingProperty_set(p: Fooable) {
+ var x = p // expected-warning {{variable 'x' was never mutated; consider changing to 'let' constant}}
+ x.nonmutatingProperty = 4
+}
func couldThrow() throws {}
diff --git a/test/expr/postfix/call/noescape-param-exclusivity.swift b/test/expr/postfix/call/noescape-param-exclusivity.swift
deleted file mode 100644
index 0c658d3..0000000
--- a/test/expr/postfix/call/noescape-param-exclusivity.swift
+++ /dev/null
@@ -1,40 +0,0 @@
-// RUN: %target-typecheck-verify-swift -swift-version 4
-
-// FIXME: make these errors
-
-func test0(fn: (() -> ()) -> ()) {
- fn { fn {} } // expected-error {{passing a closure which captures a non-escaping function parameter 'fn' to a call to a non-escaping function parameter can allow re-entrant modification of a variable}}
-}
-
-func test1(fn: (() -> ()) -> ()) { // expected-note {{parameter 'fn' is implicitly non-escaping}}
- // TODO: infer that this function is noescape from its captures
- func foo() {
- fn { fn {} } // expected-error {{can allow re-entrant modification}}
- // expected-error@-1 {{declaration closing over non-escaping parameter 'fn' may allow it to escape}}
- }
-}
-
-func test2(x: inout Int, fn: (() -> ()) -> ()) {
- func foo(myfn: () -> ()) {
- x += 1
- myfn()
- }
-
- // Make sure we only complain about calls to noescape parameters.
- foo { fn {} }
-}
-
-func test3(fn: (() -> ()) -> ()) {
- { myfn in myfn { fn {} } }(fn) // expected-error {{can allow re-entrant modification}}
-}
-
-func test4(fn: (() -> ()) -> ()) { // expected-note {{parameter 'fn' is implicitly non-escaping}}
- // TODO: infer that this function is noescape from its captures
- func foo() {
- fn {}
- // expected-error@-1 {{declaration closing over non-escaping parameter 'fn' may allow it to escape}}
- // FIXME: if the above is ever not an error, we should diagnose at the call below
- }
-
- fn(foo)
-}
diff --git a/test/lit.cfg b/test/lit.cfg
index 945a8b6..b6cd795 100644
--- a/test/lit.cfg
+++ b/test/lit.cfg
@@ -170,9 +170,12 @@
# Choose between lit's internal shell pipeline runner and a real shell. If
# LIT_USE_INTERNAL_SHELL is in the environment, we use that as an override.
-use_lit_shell = os.environ.get('LIT_USE_INTERNAL_SHELL', not kIsWindows)
+use_lit_shell = os.environ.get('LIT_USE_INTERNAL_SHELL', kIsWindows)
+if not use_lit_shell:
+ config.available_features.add('shell')
+
config.test_format = swift_test.SwiftTest(coverage_mode=config.coverage_mode,
- execute_external=use_lit_shell)
+ execute_external=not use_lit_shell)
# suffixes: A list of file extensions to treat as test files.
config.suffixes = ['.swift', '.ll', '.sil', '.gyb', '.m', '.swiftinterface',
diff --git a/test/multifile/lazy.swift b/test/multifile/lazy.swift
index 9d7c478..63c7729 100644
--- a/test/multifile/lazy.swift
+++ b/test/multifile/lazy.swift
@@ -9,3 +9,9 @@
func test2(s: Test2) {
_ = s.property
}
+
+// rdar://49482742 - shouldn't warn about 's' never being mutated
+func test3() {
+ var s = Test1()
+ _ = s.property
+}
diff --git a/test/stdlib/StringCompatibilityDiagnostics4.swift b/test/stdlib/StringCompatibilityDiagnostics4.swift
index fcd3665..f1b4682 100644
--- a/test/stdlib/StringCompatibilityDiagnostics4.swift
+++ b/test/stdlib/StringCompatibilityDiagnostics4.swift
@@ -1,7 +1,7 @@
// RUN: %target-swift-frontend -typecheck -swift-version 4 %s -verify
func testPopFirst() {
- var str = "abc"
+ let str = "abc"
var charView: String.CharacterView // expected-warning{{'CharacterView' is deprecated: Please use String directly}}
charView = str.characters // expected-warning{{'characters' is deprecated: Please use String directly}}
dump(charView)
diff --git a/test/stdlib/TestJSONEncoder.swift b/test/stdlib/TestJSONEncoder.swift
index ff6fde8..9850c5d 100644
--- a/test/stdlib/TestJSONEncoder.swift
+++ b/test/stdlib/TestJSONEncoder.swift
@@ -256,7 +256,7 @@
/// our precision requests in every case. This bug effects Darwin, FreeBSD, and Linux currently
/// causing this test (which uses the current time) to fail occasionally.
let evalEdgeCase: (Date, Date) -> () = { decodedDate, expectedDate in
- if formattedLength(of: decodedDate.timeIntervalSinceReferenceDate) > DBL_DECIMAL_DIG + 2 {
+ if formattedLength(of: decodedDate.timeIntervalSinceReferenceDate) > DBL_DECIMAL_DIG {
let adjustedTimeIntervalSinceReferenceDate: (Date) -> Double = {
let adjustment = pow(10, Double(DBL_DECIMAL_DIG))
return Double(floor(adjustment * $0.timeIntervalSinceReferenceDate) / adjustment)
@@ -286,9 +286,15 @@
}
}
- // Test the above `snprintf` edge case evaluation with a known triggering case
- let knownBadDate = Date(timeIntervalSinceReferenceDate: 0.0021413276231263384)
- localTestRoundTrip(of: TopLevelWrapper(knownBadDate))
+ // Test the above `snprintf` edge case evaluation with known triggering cases
+
+ // Tests the two precision digits larger case
+ let knownBadDateTwoExtraDigits = Date(timeIntervalSinceReferenceDate: 0.0021413276231263384)
+ localTestRoundTrip(of: TopLevelWrapper(knownBadDateTwoExtraDigits))
+
+ // Tests the one precision digit larger case
+ let knownBadDateOneExtraDigit = Date(timeIntervalSinceReferenceDate: 576487829.7193049)
+ localTestRoundTrip(of: TopLevelWrapper(knownBadDateOneExtraDigit))
// We can't encode a top-level Date, so it'll be wrapped in a dictionary.
localTestRoundTrip(of: TopLevelWrapper(Date()))
diff --git a/test/type/infer/local_variables.swift b/test/type/infer/local_variables.swift
index a60335c..35bd6f6 100644
--- a/test/type/infer/local_variables.swift
+++ b/test/type/infer/local_variables.swift
@@ -20,11 +20,11 @@
func infer_generic_args() {
// Simple types
- var x : Dictionary = ["Hello" : 1]
+ let x : Dictionary = ["Hello" : 1]
var i : Int = x["Hello"]!
// Tuples
- var (d, s) : (Dictionary, Array) = ( ["Hello" : 1], [1, 2, 3] )
+ let (d, s) : (Dictionary, Array) = ( ["Hello" : 1], [1, 2, 3] )
i = d["Hello"]!
i = s[i]
diff --git a/tools/swift-api-digester/ModuleAnalyzerNodes.cpp b/tools/swift-api-digester/ModuleAnalyzerNodes.cpp
index 05d9d00..3b98998 100644
--- a/tools/swift-api-digester/ModuleAnalyzerNodes.cpp
+++ b/tools/swift-api-digester/ModuleAnalyzerNodes.cpp
@@ -1024,27 +1024,34 @@
}
}
+static
+StringRef printGenericSignature(SDKContext &Ctx, ArrayRef<Requirement> AllReqs) {
+ llvm::SmallString<32> Result;
+ llvm::raw_svector_ostream OS(Result);
+ if (AllReqs.empty())
+ return StringRef();
+ OS << "<";
+ bool First = true;
+ for (auto Req: AllReqs) {
+ if (!First) {
+ OS << ", ";
+ } else {
+ First = false;
+ }
+ if (Ctx.checkingABI())
+ getCanonicalRequirement(Req).print(OS, PrintOptions::printInterface());
+ else
+ Req.print(OS, PrintOptions::printInterface());
+ }
+ OS << ">";
+ return Ctx.buffer(OS.str());
+}
+
static StringRef printGenericSignature(SDKContext &Ctx, Decl *D) {
llvm::SmallString<32> Result;
llvm::raw_svector_ostream OS(Result);
if (auto *PD = dyn_cast<ProtocolDecl>(D)) {
- if (PD->getRequirementSignature().empty())
- return StringRef();
- OS << "<";
- bool First = true;
- for (auto Req: PD->getRequirementSignature()) {
- if (!First) {
- OS << ", ";
- } else {
- First = false;
- }
- if (Ctx.checkingABI())
- getCanonicalRequirement(Req).print(OS, PrintOptions::printInterface());
- else
- Req.print(OS, PrintOptions::printInterface());
- }
- OS << ">";
- return Ctx.buffer(OS.str());
+ return printGenericSignature(Ctx, PD->getRequirementSignature());
}
if (auto *GC = D->getAsGenericContext()) {
@@ -1059,6 +1066,11 @@
return StringRef();
}
+static
+StringRef printGenericSignature(SDKContext &Ctx, ProtocolConformance *Conf) {
+ return printGenericSignature(Ctx, Conf->getConditionalRequirements());
+}
+
static Optional<uint8_t> getSimilarMemberCount(NominalTypeDecl *NTD,
ValueDecl *VD,
llvm::function_ref<bool(Decl*)> Check) {
@@ -1161,6 +1173,9 @@
SDKNodeInitInfo::SDKNodeInitInfo(SDKContext &Ctx, ProtocolConformance *Conform):
SDKNodeInitInfo(Ctx, Conform->getProtocol()) {
+ // The conformance can be conditional. The generic signature keeps track of
+ // the requirements.
+ GenericSig = printGenericSignature(Ctx, Conform);
// Whether this conformance is ABI placeholder depends on the decl context
// of this conformance.
IsABIPlaceholder = isABIPlaceholderRecursive(Conform->getDeclContext()->
@@ -1562,9 +1577,12 @@
void swift::ide::api::
SwiftDeclCollector::addConformancesToTypeDecl(SDKNodeDeclType *Root,
NominalTypeDecl *NTD) {
+ // Avoid adding the same conformance twice.
+ SmallPtrSet<ProtocolConformance*, 4> Seen;
for (auto &Conf: NTD->getAllConformances()) {
- if (!Ctx.shouldIgnore(Conf->getProtocol()))
+ if (!Ctx.shouldIgnore(Conf->getProtocol()) && !Seen.count(Conf))
Root->addConformance(constructConformanceNode(Conf));
+ Seen.insert(Conf);
}
}
diff --git a/unittests/runtime/Mutex.cpp b/unittests/runtime/Mutex.cpp
index 6e67cec..7d5dac15 100644
--- a/unittests/runtime/Mutex.cpp
+++ b/unittests/runtime/Mutex.cpp
@@ -555,10 +555,12 @@
template <typename RW> void readLockWhileReadLockedThreaded(RW &lock) {
lock.readLock();
- std::vector<std::atomic<bool>> results(10);
+ const int threadCount = 10;
+
+ std::atomic<bool> results[threadCount] = {};
std::atomic<bool> done(false);
- threadedExecute(10,
+ threadedExecute(threadCount,
[&](int index) {
// Always perform at least one iteration of this loop to
// avoid spurious failures if this thread is slow to run.
@@ -596,10 +598,12 @@
template <typename RW> void readLockWhileWriteLockedThreaded(RW &lock) {
lock.writeLock();
- std::vector<std::atomic<int>> results(10);
+ const int threadCount = 10;
+
+ std::atomic<int> results[threadCount] = {};
std::atomic<bool> done(false);
- threadedExecute(10,
+ threadedExecute(threadCount,
[&](int index) {
// Always perform at least one iteration of this loop to
// avoid spurious failures if this thread is slow to run.
@@ -638,7 +642,7 @@
const int threadCount = 10;
- std::vector<std::atomic<int>> results(threadCount);
+ std::atomic<int> results[threadCount] = {};
std::atomic<bool> done(false);
threadedExecute(threadCount,
@@ -680,7 +684,7 @@
const int threadCount = 10;
- std::vector<std::atomic<int>> results(threadCount);
+ std::atomic<int> results[threadCount] = {};
std::atomic<bool> done(false);
threadedExecute(threadCount,
@@ -753,7 +757,7 @@
const int threadCount = 10;
- std::vector<std::atomic<bool>> results(threadCount);
+ std::atomic<bool> results[threadCount] = {};
std::atomic<bool> done(false);
threadedExecute(threadCount,
diff --git a/utils/WindowsSDKVFSOverlay.yaml.in b/utils/WindowsSDKVFSOverlay.yaml.in
index f2faf48..6147459 100644
--- a/utils/WindowsSDKVFSOverlay.yaml.in
+++ b/utils/WindowsSDKVFSOverlay.yaml.in
@@ -29,6 +29,9 @@
- name: "@UniversalCRTSdkDir@/Include/@UCRTVersion@/um"
type: directory
contents:
+ - name: accctrl.h
+ type: file
+ external-contents: "@UniversalCRTSdkDir@/Include/@UCRTVersion@/um/AccCtrl.h"
- name: commctrl.h
type: file
external-contents: "@UniversalCRTSdkDir@/Include/@UCRTVersion@/um/CommCtrl.h"
diff --git a/utils/build-script b/utils/build-script
index 6fd36fa..2d0cbd0 100755
--- a/utils/build-script
+++ b/utils/build-script
@@ -328,87 +328,98 @@
# FIXME: We should move the platform-derived arguments to be entirely
# data driven, so that we can eliminate this code duplication and just
# iterate over all supported platforms.
+ self.platforms_to_skip_build = self.__platforms_to_skip_build(args)
+ self.platforms_to_skip_test = self.__platforms_to_skip_test(args)
+ self.platforms_archs_to_skip_test = \
+ self.__platforms_archs_to_skip_test(args)
+ self.platforms_to_skip_test_host = \
+ self.__platforms_to_skip_test_host(args)
- self.platforms_to_skip_build = set()
+ self.build_libparser_only = args.build_libparser_only
+
+ def __platforms_to_skip_build(self, args):
+ platforms_to_skip_build = set()
if not args.build_linux:
- self.platforms_to_skip_build.add(StdlibDeploymentTarget.Linux)
+ platforms_to_skip_build.add(StdlibDeploymentTarget.Linux)
if not args.build_freebsd:
- self.platforms_to_skip_build.add(StdlibDeploymentTarget.FreeBSD)
+ platforms_to_skip_build.add(StdlibDeploymentTarget.FreeBSD)
if not args.build_cygwin:
- self.platforms_to_skip_build.add(StdlibDeploymentTarget.Cygwin)
+ platforms_to_skip_build.add(StdlibDeploymentTarget.Cygwin)
if not args.build_osx:
- self.platforms_to_skip_build.add(StdlibDeploymentTarget.OSX)
+ platforms_to_skip_build.add(StdlibDeploymentTarget.OSX)
if not args.build_ios_device:
- self.platforms_to_skip_build.add(StdlibDeploymentTarget.iOS)
+ platforms_to_skip_build.add(StdlibDeploymentTarget.iOS)
if not args.build_ios_simulator:
- self.platforms_to_skip_build.add(
- StdlibDeploymentTarget.iOSSimulator)
+ platforms_to_skip_build.add(StdlibDeploymentTarget.iOSSimulator)
if not args.build_tvos_device:
- self.platforms_to_skip_build.add(StdlibDeploymentTarget.AppleTV)
+ platforms_to_skip_build.add(StdlibDeploymentTarget.AppleTV)
if not args.build_tvos_simulator:
- self.platforms_to_skip_build.add(
+ platforms_to_skip_build.add(
StdlibDeploymentTarget.AppleTVSimulator)
if not args.build_watchos_device:
- self.platforms_to_skip_build.add(StdlibDeploymentTarget.AppleWatch)
+ platforms_to_skip_build.add(StdlibDeploymentTarget.AppleWatch)
if not args.build_watchos_simulator:
- self.platforms_to_skip_build.add(
+ platforms_to_skip_build.add(
StdlibDeploymentTarget.AppleWatchSimulator)
if not args.build_android:
- self.platforms_to_skip_build.add(StdlibDeploymentTarget.Android)
+ platforms_to_skip_build.add(StdlibDeploymentTarget.Android)
+ return platforms_to_skip_build
- self.platforms_to_skip_test = set()
- self.platforms_archs_to_skip_test = set()
+ def __platforms_to_skip_test(self, args):
+ platforms_to_skip_test = set()
if not args.test_linux:
- self.platforms_to_skip_test.add(StdlibDeploymentTarget.Linux)
+ platforms_to_skip_test.add(StdlibDeploymentTarget.Linux)
if not args.test_freebsd:
- self.platforms_to_skip_test.add(StdlibDeploymentTarget.FreeBSD)
+ platforms_to_skip_test.add(StdlibDeploymentTarget.FreeBSD)
if not args.test_cygwin:
- self.platforms_to_skip_test.add(StdlibDeploymentTarget.Cygwin)
+ platforms_to_skip_test.add(StdlibDeploymentTarget.Cygwin)
if not args.test_osx:
- self.platforms_to_skip_test.add(StdlibDeploymentTarget.OSX)
+ platforms_to_skip_test.add(StdlibDeploymentTarget.OSX)
if not args.test_ios_host:
- self.platforms_to_skip_test.add(StdlibDeploymentTarget.iOS)
+ platforms_to_skip_test.add(StdlibDeploymentTarget.iOS)
else:
exit_rejecting_arguments("error: iOS device tests are not " +
"supported in open-source Swift.")
if not args.test_ios_simulator:
- self.platforms_to_skip_test.add(
- StdlibDeploymentTarget.iOSSimulator)
- if not args.test_ios_32bit_simulator:
- self.platforms_archs_to_skip_test.add(
- StdlibDeploymentTarget.iOSSimulator.i386)
+ platforms_to_skip_test.add(StdlibDeploymentTarget.iOSSimulator)
if not args.test_tvos_host:
- self.platforms_to_skip_test.add(StdlibDeploymentTarget.AppleTV)
+ platforms_to_skip_test.add(StdlibDeploymentTarget.AppleTV)
else:
exit_rejecting_arguments("error: tvOS device tests are not " +
"supported in open-source Swift.")
if not args.test_tvos_simulator:
- self.platforms_to_skip_test.add(
- StdlibDeploymentTarget.AppleTVSimulator)
+ platforms_to_skip_test.add(StdlibDeploymentTarget.AppleTVSimulator)
if not args.test_watchos_host:
- self.platforms_to_skip_test.add(StdlibDeploymentTarget.AppleWatch)
+ platforms_to_skip_test.add(StdlibDeploymentTarget.AppleWatch)
else:
exit_rejecting_arguments("error: watchOS device tests are not " +
"supported in open-source Swift.")
if not args.test_watchos_simulator:
- self.platforms_to_skip_test.add(
+ platforms_to_skip_test.add(
StdlibDeploymentTarget.AppleWatchSimulator)
if not args.test_android:
- self.platforms_to_skip_test.add(StdlibDeploymentTarget.Android)
+ platforms_to_skip_test.add(StdlibDeploymentTarget.Android)
- self.platforms_to_skip_test_host = set()
+ return platforms_to_skip_test
+
+ def __platforms_archs_to_skip_test(self, args):
+ platforms_archs_to_skip_test = set()
+ if not args.test_ios_32bit_simulator:
+ platforms_archs_to_skip_test.add(
+ StdlibDeploymentTarget.iOSSimulator.i386)
+ return platforms_archs_to_skip_test
+
+ def __platforms_to_skip_test_host(self, args):
+ platforms_to_skip_test_host = set()
if not args.test_android_host:
- self.platforms_to_skip_test_host.add(
- StdlibDeploymentTarget.Android)
+ platforms_to_skip_test_host.add(StdlibDeploymentTarget.Android)
if not args.test_ios_host:
- self.platforms_to_skip_test_host.add(StdlibDeploymentTarget.iOS)
+ platforms_to_skip_test_host.add(StdlibDeploymentTarget.iOS)
if not args.test_tvos_host:
- self.platforms_to_skip_test_host.add(
- StdlibDeploymentTarget.AppleTV)
+ platforms_to_skip_test_host.add(StdlibDeploymentTarget.AppleTV)
if not args.test_watchos_host:
- self.platforms_to_skip_test_host.add(
- StdlibDeploymentTarget.AppleWatch)
- self.build_libparser_only = args.build_libparser_only
+ platforms_to_skip_test_host.add(StdlibDeploymentTarget.AppleWatch)
+ return platforms_to_skip_test_host
def initialize_runtime_environment(self):
"""Change the program environment for building."""
@@ -440,7 +451,7 @@
toolchain=self.toolchain,
source_dir=self.workspace.source_dir("ninja"),
build_dir=self.workspace.build_dir("build", "ninja"))
- ninja_build.do_build()
+ ninja_build.build()
self.toolchain.ninja = ninja_build.ninja_bin_path
def convert_to_impl_arguments(self):
@@ -893,35 +904,18 @@
"""Execute the invocation with the configured arguments."""
# Convert to a build-script-impl invocation.
- (impl_env, impl_args) = self.convert_to_impl_arguments()
+ (self.impl_env, self.impl_args) = self.convert_to_impl_arguments()
# If using the legacy implementation, delegate all behavior to
# `build-script-impl`.
if self.args.legacy_impl:
# Execute the underlying build script implementation.
- shell.call_without_sleeping([build_script_impl] + impl_args,
- env=impl_env, echo=True)
+ shell.call_without_sleeping([build_script_impl] + self.impl_args,
+ env=self.impl_env, echo=True)
return
# Otherwise, we compute and execute the individual actions ourselves.
- def execute_one_impl_action(host=None, product_class=None, name=None):
- if host is None:
- assert (product_class is None and
- name == "merged-hosts-lipo"), "invalid action"
- action_name = name
- elif product_class is None:
- assert name in ("package", "extractsymbols"), "invalid action"
- action_name = "{}-{}".format(host.name, name)
- else:
- assert name is not None, "invalid action"
- action_name = "{}-{}-{}".format(
- host.name, product_class.product_name(), name)
- shell.call_without_sleeping(
- [build_script_impl] + impl_args + [
- "--only-execute", action_name],
- env=impl_env, echo=self.args.verbose_build)
-
# Compute the list of hosts to operate on.
all_host_names = [
self.args.host_target] + self.args.cross_compile_hosts
@@ -954,17 +948,17 @@
" ".join(config.swift_benchmark_run_targets)))
for product_class in impl_product_classes:
- execute_one_impl_action(host_target, product_class, "build")
+ self._execute_build_action(host_target, product_class)
# Test...
for host_target in all_hosts:
for product_class in impl_product_classes:
- execute_one_impl_action(host_target, product_class, "test")
+ self._execute_test_action(host_target, product_class)
# Install...
for host_target in all_hosts:
for product_class in impl_product_classes:
- execute_one_impl_action(host_target, product_class, "install")
+ self._execute_install_action(host_target, product_class)
# Non-build-script-impl products...
# Note: currently only supports building for the host.
@@ -980,19 +974,51 @@
source_dir=self.workspace.source_dir(product_source),
build_dir=self.workspace.build_dir(
host_target, product_name))
- product.do_build(host_target)
- product.do_test(host_target)
+ product.build(host_target)
+ product.test(host_target)
# Extract symbols...
for host_target in all_hosts:
- execute_one_impl_action(host_target, name="extractsymbols")
+ self._execute_extract_symbols_action(host_target)
# Package...
for host_target in all_hosts:
- execute_one_impl_action(host_target, name="package")
+ self._execute_package_action(host_target)
# Lipo...
- execute_one_impl_action(name="merged-hosts-lipo")
+ self._execute_merged_host_lipo_action()
+
+ def _execute_build_action(self, host_target, product_class):
+ action_name = "{}-{}-build".format(host_target.name,
+ product_class.product_name())
+ self._execute_action(action_name)
+
+ def _execute_test_action(self, host_target, product_class):
+ action_name = "{}-{}-test".format(host_target.name,
+ product_class.product_name())
+ self._execute_action(action_name)
+
+ def _execute_install_action(self, host_target, product_class):
+ action_name = "{}-{}-install".format(host_target.name,
+ product_class.product_name())
+ self._execute_action(action_name)
+
+ def _execute_extract_symbols_action(self, host_target):
+ action_name = "{}-extractsymbols".format(host_target.name)
+ self._execute_action(action_name)
+
+ def _execute_package_action(self, host_target):
+ action_name = "{}-package".format(host_target.name)
+ self._execute_action(action_name)
+
+ def _execute_merged_host_lipo_action(self):
+ self._execute_action("merged-hosts-lipo")
+
+ def _execute_action(self, action_name):
+ shell.call_without_sleeping(
+ [build_script_impl] + self.impl_args +
+ ["--only-execute", action_name],
+ env=self.impl_env, echo=self.args.verbose_build)
# Provide a short delay so accidentally invoked clean builds can be canceled.
diff --git a/utils/build-script-impl b/utils/build-script-impl
index 449130c..fa7c1a5 100755
--- a/utils/build-script-impl
+++ b/utils/build-script-impl
@@ -3091,8 +3091,8 @@
LIBDISPATCH_BUILD_DIR="$(build_directory ${host} libdispatch)"
FOUNDATION_BUILD_DIR=$(build_directory ${host} foundation)
DOTEST_EXTRA="-I${FOUNDATION_BUILD_DIR}"
- DOTEST_EXTRA="-Xcc -F${FOUNDATION_BUILD_DIR}"
- DOTEST_EXTRA="-Xcc -F${FOUNDATION_BUILD_DIR}/CoreFoundation-prefix/System/Library/Frameworks"
+ DOTEST_EXTRA="${DOTEST_EXTRA} -Xcc -F${FOUNDATION_BUILD_DIR}"
+ DOTEST_EXTRA="${DOTEST_EXTRA} -Xcc -F${FOUNDATION_BUILD_DIR}/CoreFoundation-prefix/System/Library/Frameworks"
DOTEST_EXTRA="${DOTEST_EXTRA} -I${FOUNDATION_BUILD_DIR}/swift"
DOTEST_EXTRA="${DOTEST_EXTRA} -I${LIBDISPATCH_SOURCE_DIR}"
DOTEST_EXTRA="${DOTEST_EXTRA} -L${FOUNDATION_BUILD_DIR}"
diff --git a/utils/swift_build_support/swift_build_support/products/benchmarks.py b/utils/swift_build_support/swift_build_support/products/benchmarks.py
index aa1efd1..e62fe41 100644
--- a/utils/swift_build_support/swift_build_support/products/benchmarks.py
+++ b/utils/swift_build_support/swift_build_support/products/benchmarks.py
@@ -28,19 +28,19 @@
def is_build_script_impl_product(cls):
return False
- def do_build(self, host_target):
+ def build(self, host_target):
run_build_script_helper(host_target, self, self.args)
- def do_test(self, host_target):
+ def test(self, host_target):
"""Just run a single instance of the command for both .debug and
.release.
"""
cmdline = ['--num-iters=1', 'XorLoop']
- debug_bench = os.path.join(self.build_dir, 'debug', 'SwiftBench')
- shell.call([debug_bench] + cmdline)
+ bench_Onone = os.path.join(self.build_dir, 'bin', 'Benchmark_Onone')
+ shell.call([bench_Onone] + cmdline)
- release_bench = os.path.join(self.build_dir, 'release', 'SwiftBench')
- shell.call([release_bench] + cmdline)
+ bench_O = os.path.join(self.build_dir, 'bin', 'Benchmark_O')
+ shell.call([bench_O] + cmdline)
def run_build_script_helper(host_target, product, args):
@@ -59,7 +59,8 @@
# We use a separate python helper to enable quicker iteration when working
# on this by avoiding going through build-script to test small changes.
- helper_path = os.path.join(package_path, 'utils', 'build_script_helper.py')
+ helper_path = os.path.join(package_path, 'scripts',
+ 'build_script_helper.py')
build_cmd = [
helper_path,
diff --git a/utils/swift_build_support/swift_build_support/products/indexstoredb.py b/utils/swift_build_support/swift_build_support/products/indexstoredb.py
index 41b464a..2927038 100644
--- a/utils/swift_build_support/swift_build_support/products/indexstoredb.py
+++ b/utils/swift_build_support/swift_build_support/products/indexstoredb.py
@@ -27,10 +27,10 @@
def is_build_script_impl_product(cls):
return False
- def do_build(self, host_target):
+ def build(self, host_target):
run_build_script_helper('build', host_target, self, self.args)
- def do_test(self, host_target):
+ def test(self, host_target):
if self.args.test and self.args.test_indexstoredb:
run_build_script_helper('test', host_target, self, self.args)
diff --git a/utils/swift_build_support/swift_build_support/products/ninja.py b/utils/swift_build_support/swift_build_support/products/ninja.py
index d01ca29..8f4bcaa 100644
--- a/utils/swift_build_support/swift_build_support/products/ninja.py
+++ b/utils/swift_build_support/swift_build_support/products/ninja.py
@@ -32,7 +32,7 @@
def ninja_bin_path(self):
return os.path.join(self.build_dir, 'ninja')
- def do_build(self):
+ def build(self):
if os.path.exists(self.ninja_bin_path):
return
diff --git a/utils/swift_build_support/swift_build_support/products/product.py b/utils/swift_build_support/swift_build_support/products/product.py
index 6fb917f..db8b6f6 100644
--- a/utils/swift_build_support/swift_build_support/products/product.py
+++ b/utils/swift_build_support/swift_build_support/products/product.py
@@ -38,15 +38,15 @@
"""
return True
- def do_build(self, host_target):
- """do_build() -> void
+ def build(self, host_target):
+ """build() -> void
Perform the build, for a non-build-script-impl product.
"""
raise NotImplementedError
- def do_test(self, host_target):
- """do_build() -> void
+ def test(self, host_target):
+ """test() -> void
Run the tests, for a non-build-script-impl product.
"""
diff --git a/utils/swift_build_support/swift_build_support/products/sourcekitlsp.py b/utils/swift_build_support/swift_build_support/products/sourcekitlsp.py
index 61b141f..794a29f 100644
--- a/utils/swift_build_support/swift_build_support/products/sourcekitlsp.py
+++ b/utils/swift_build_support/swift_build_support/products/sourcekitlsp.py
@@ -23,11 +23,11 @@
def is_build_script_impl_product(cls):
return False
- def do_build(self, host_target):
+ def build(self, host_target):
indexstoredb.run_build_script_helper(
'build', host_target, self, self.args)
- def do_test(self, host_target):
+ def test(self, host_target):
if self.args.test and self.args.test_sourcekitlsp:
indexstoredb.run_build_script_helper(
'test', host_target, self, self.args)
diff --git a/utils/swift_build_support/tests/products/test_ninja.py b/utils/swift_build_support/tests/products/test_ninja.py
index 74cbbe4..3edc659 100644
--- a/utils/swift_build_support/tests/products/test_ninja.py
+++ b/utils/swift_build_support/tests/products/test_ninja.py
@@ -79,14 +79,14 @@
self.assertEqual(ninja_build.ninja_bin_path, '/path/to/build/ninja')
- def test_do_build(self):
+ def test_build(self):
ninja_build = Ninja(
args=self.args,
toolchain=self.toolchain,
source_dir=self.workspace.source_dir('ninja'),
build_dir=self.workspace.build_dir('build', 'ninja'))
- ninja_build.do_build()
+ ninja_build.build()
expect_env = ""
if platform.system() == "Darwin":